/** * Canonical `response="..."` / `correct-response="..."` attribute codec. * * Authors put a single string on an interaction element. This module is the * single source of truth for how that string parses into the runtime's * internal value AND how an editor serializes the internal value back to the * attribute. Both `@qti-components/*` interactions and `@citolab/prose-qti` * (the editor) import from here — no per-codebase parsers, no drift. * * The two attributes share the same grammar; the codec is agnostic about * which of them is being parsed. * * --- * * Format reference (per interaction): * * | Interaction | base-type | cardinality | attribute value | * |----------------------|---------------|----------------------|---------------------------| * | choice | identifier | single / multiple | "A" / "A,B,C" | * | inline-choice | identifier | single | "Y" | * | hottext | identifier | single / multiple | "h1" / "h1,h2" | * | hotspot | identifier | single / multiple | "spot1" / "spot1,spot2" | * | order | identifier | ordered | "a,b,c" (order matters) | * | graphic-order | identifier | ordered | "spot1,spot2,spot3" | * | match | directedPair | multiple | "src1 tgt1,src2 tgt2" | * | associate | directedPair | multiple | "A B,C D" | * | gap-match | directedPair | multiple | "gtext1 gap1,..." | * | graphic-associate | directedPair | multiple | "spot1 spot2,..." | * | graphic-gap-match | directedPair | multiple | "gimg1 spot1,..." | * | select-point | point | single / multiple | "100 150" / "100 150,…" | * | slider | integer | single | "50" | * | text-entry | string | single | "paris" | * * Rules: * - Comma `,` separates VALUES (different identifiers / pairs / points). * - Space ` ` separates PARTS within one value (pair members or point coords). * - Each value is trimmed on parse. * - No escape mechanism. Identifiers that contain commas cannot round-trip. */ /** Canonical parsed value of a `response` / `correct-response` attribute. */ type ResponseValue = string | string[] | null; /** Identifier literal — opaque QTI identifier (e.g. `"choice1"`). */ type Identifier = string; /** Directed pair literal — `"sourceId targetId"`. Used by match / associate / gap-match. */ type DirectedPair = `${string} ${string}`; /** Point literal — `"x y"` integer coordinates. Used by select-point / graphic-*. */ type Point = `${number} ${number}`; /** * Parse a raw `response` / `correct-response` attribute string into the * canonical value. * * - `null` / `undefined` / empty → `null` * - no comma → trimmed string * - one or more commas → trimmed array (single-element collapses to a string) */ declare function parseResponseAttribute(raw: string | null | undefined): ResponseValue; /** * Serialize a canonical value back to the attribute string. Returns `null` for * empty inputs so a Lit `@property({ reflect: true })` drops the attribute. */ declare function serializeResponseAttribute(value: ResponseValue): string | null; /** * Iterate over the comma-separated entries in a response value, regardless of * whether the caller has the raw string, the parsed string, or a string[]. * Yields trimmed non-empty entries. */ declare function iterResponseValues(raw: ResponseValue): Generator; /** Parse a directed-pair value into `{ source, target }`. Throws on malformed input. */ declare function parsePair(value: string): { source: string; target: string; }; /** Serialize a directed pair to canonical `"source target"` form. */ declare function serializePair(source: string, target: string): DirectedPair; /** Parse a point value into `{ x, y }`. Throws on malformed input. */ declare function parsePoint(value: string): { x: number; y: number; }; /** Serialize a point to canonical `"x y"` form. */ declare function serializePoint(x: number, y: number): Point; /** * Ready-to-use Lit `converter` for `response` / `correct-response` attributes. * Assign to the `converter` option: * * @property({ attribute: 'response', converter: responseAttributeConverter({ emptyAs: [] }) }) * * `emptyAs` picks the sentinel returned when the attribute is absent / blank. * Three sentinels exist across the codebase — match the one your call site * already uses. Future work may normalize to a single sentinel. * * - '' (empty string) — ChoicesMixin convention * - [] — DragDropSlottedMixin / graphic-associate convention * - null — base interaction / select-point convention * * On the serialize side, the `emptyAs` value roundtrips back to `null` so a * `reflect: true` property drops the attribute rather than emitting `""`. */ declare function responseAttributeConverter(opts: { emptyAs: E; }): { fromAttribute: (value: string | null) => ResponseValue | E; toAttribute: (value: ResponseValue | E) => string | null; }; export { type DirectedPair as D, type Identifier as I, type Point as P, type ResponseValue as R, parsePoint as a, parseResponseAttribute as b, serializePoint as c, serializeResponseAttribute as d, iterResponseValues as i, parsePair as p, responseAttributeConverter as r, serializePair as s };