@citolab/qti-components 8.0.1 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/index.global.js +1 -1
- package/cdn/index.js +648 -816
- package/dist/base.d.ts +61 -4
- package/dist/base.js +7 -1
- package/dist/{chunk-V5G7X53Y.js → chunk-3IACYIU2.js} +2 -2
- package/dist/chunk-4DB4SC5K.js +100 -0
- package/dist/chunk-4DB4SC5K.js.map +1 -0
- package/dist/{chunk-F4BNJWYN.js → chunk-4XR2JHCP.js} +646 -677
- package/dist/chunk-4XR2JHCP.js.map +1 -0
- package/dist/{chunk-7V4HJFHW.js → chunk-6ITD55QE.js} +2 -2
- package/dist/{chunk-3AJOQCDU.js → chunk-6V3A7NQP.js} +2 -2
- package/dist/{chunk-WVVMNF74.js → chunk-6XJUP55A.js} +248 -234
- package/dist/chunk-6XJUP55A.js.map +1 -0
- package/dist/{chunk-XU7HNT4F.js → chunk-CF3DXJWM.js} +145 -119
- package/dist/{chunk-XU7HNT4F.js.map → chunk-CF3DXJWM.js.map} +1 -1
- package/dist/chunk-EKXZI26R.js +917 -0
- package/dist/chunk-EKXZI26R.js.map +1 -0
- package/dist/{chunk-IJD53WY6.js → chunk-HDEG6BAZ.js} +15 -15
- package/dist/{chunk-IJD53WY6.js.map → chunk-HDEG6BAZ.js.map} +1 -1
- package/dist/{chunk-LVBIQDPM.js → chunk-IXPDMYKH.js} +147 -101
- package/dist/chunk-IXPDMYKH.js.map +1 -0
- package/dist/chunk-IYC7LZV6.js +7 -0
- package/dist/chunk-IYC7LZV6.js.map +1 -0
- package/dist/{chunk-NA2N2WSG.js → chunk-MK2I3MQB.js} +244 -193
- package/dist/chunk-MK2I3MQB.js.map +1 -0
- package/dist/{chunk-CAO4JRLY.js → chunk-NZLW6EX7.js} +2 -2
- package/dist/{chunk-RXGDQDOV.js → chunk-Q52IJELT.js} +479 -393
- package/dist/chunk-Q52IJELT.js.map +1 -0
- package/dist/{chunk-QECOPVPO.js → chunk-TXIB3SKC.js} +60 -59
- package/dist/chunk-TXIB3SKC.js.map +1 -0
- package/dist/{computed.types.d-rKLSPvVG.d.ts → computed.types.d-DpKIYO6e.d.ts} +2 -0
- package/dist/corrections.d.ts +12 -29
- package/dist/corrections.js +9 -10
- package/dist/elements.d.ts +86 -87
- package/dist/elements.js +5 -6
- package/dist/index.d.ts +8 -39
- package/dist/index.js +29 -16
- package/dist/{interaction.d-D4MstYRz.d.ts → interaction.d-CJiMv8H7.d.ts} +13 -2
- package/dist/interactions.d.ts +11 -1299
- package/dist/interactions.js +4 -5
- package/dist/item.css +370 -532
- package/dist/item.d.ts +3 -3
- package/dist/item.js +6 -6
- package/dist/loader.js +2 -2
- package/dist/processing.d.ts +61 -11
- package/dist/processing.js +10 -2
- package/dist/qti-components-jsx.d.ts +293 -69
- package/dist/qti-test.d-_YAlhDbt.d.ts +702 -0
- package/dist/qti-text-entry-interaction.d-BGdfV9qG.d.ts +1567 -0
- package/dist/test.d.ts +11 -678
- package/dist/test.js +7 -8
- package/dist/transformers.d.ts +1 -1
- package/dist/transformers.js +1 -1
- package/package.json +11 -10
- package/dist/chunk-64XSIBGO.js +0 -241
- package/dist/chunk-64XSIBGO.js.map +0 -1
- package/dist/chunk-7HC5SMCU.js +0 -102
- package/dist/chunk-7HC5SMCU.js.map +0 -1
- package/dist/chunk-F4BNJWYN.js.map +0 -1
- package/dist/chunk-H3J7LFRO.js +0 -2243
- package/dist/chunk-H3J7LFRO.js.map +0 -1
- package/dist/chunk-LVBIQDPM.js.map +0 -1
- package/dist/chunk-NA2N2WSG.js.map +0 -1
- package/dist/chunk-QECOPVPO.js.map +0 -1
- package/dist/chunk-RXGDQDOV.js.map +0 -1
- package/dist/chunk-WVVMNF74.js.map +0 -1
- package/dist/chunk-X3E5HXG2.js +0 -20
- package/dist/chunk-X3E5HXG2.js.map +0 -1
- /package/dist/{chunk-V5G7X53Y.js.map → chunk-3IACYIU2.js.map} +0 -0
- /package/dist/{chunk-7V4HJFHW.js.map → chunk-6ITD55QE.js.map} +0 -0
- /package/dist/{chunk-3AJOQCDU.js.map → chunk-6V3A7NQP.js.map} +0 -0
- /package/dist/{chunk-CAO4JRLY.js.map → chunk-NZLW6EX7.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../qti-base/src/utils/custom-state-set.ts","../../qti-base/src/context/computed-item.context.ts","../../qti-base/src/context/computed.context.ts","../../qti-base/src/context/config.context.ts","../../qti-base/src/context/interaction.context.ts","../../qti-base/src/context/item.context.ts","../../qti-base/src/context/types/item.types.ts","../../qti-base/src/context/qti.context.ts","../../qti-base/src/context/session.context.ts","../../qti-base/src/context/test.context.ts","../../qti-base/src/styles/box-sizing.styles.ts","../../qti-base/src/styles/drop-region.styles.ts","../../qti-base/src/styles/validation-message.styles.ts","../../qti-base/src/abstract/interaction.ts","../../qti-base/src/abstract/qti-variable-declaration.ts","../../qti-base/src/abstract/qti-expression.ts","../../qti-base/src/abstract/qti-condition-expression.ts","../../qti-base/src/utils/utils.ts","../../qti-base/src/abstract/qti-feedback.ts","../../qti-base/src/lib/response.ts","../../qti-base/src/lib/qti-rule-base.ts","../../qti-base/src/utils/scoring-helper.ts","../../qti-base/src/elements.ts","../../qti-base/src/register.ts"],"sourcesContent":["/**\n * Custom-state support shim for browsers this library cannot use natively.\n *\n * Interactions track selection and correct/incorrect marking through\n * `internals.states`, with bare state names (`checked`, `radio`,\n * `correct-response`, …). Two browser profiles cannot service that:\n *\n * - Safari 16.4–17.3 implement `ElementInternals` but not `CustomStateSet`, so\n * `internals.states` is `undefined` and reading it throws — \"undefined is not\n * an object (evaluating 'internals.states.has')\".\n * - Chrome and Edge before the CSS custom-state spec change expose `states` but\n * reject names that do not start with `--`, so `states.add('radio')` throws\n * \"The specified value 'radio' must start with '--'\".\n *\n * On both, picking a choice throws rather than registering. `attachInternals`\n * itself is unguarded throughout the interaction base classes, which puts the\n * hard support floor at Safari 16.4 — inside the range that breaks.\n *\n * The shim replaces `states` with a permissive `Set` and mirrors its contents to\n * a space-separated `data-state` attribute on the host, because these browsers'\n * CSS parsers also drop any selector list containing `:state()`. The theme's\n * built stylesheets pair every `:state(x)` with a `[data-state~='x']` arm (see\n * `tools/postcss/custom-state-fallback.mjs`), so styling survives too.\n *\n * Support is classified by behaviour rather than by browser version, and the\n * shim is not installed at all where `states` works.\n */\n\n/** A permissive `CustomStateSet` that mirrors its contents to `data-state`. */\nexport class CustomStateSetShim extends Set<string> {\n readonly #host: HTMLElement;\n\n constructor(host: HTMLElement) {\n super();\n this.#host = host;\n }\n\n override add(state: string): this {\n super.add(state);\n this.#reflect();\n return this;\n }\n\n override delete(state: string): boolean {\n const deleted = super.delete(state);\n this.#reflect();\n return deleted;\n }\n\n override clear(): void {\n super.clear();\n this.#reflect();\n }\n\n #reflect(): void {\n // A custom element must not gain attributes while it is upgrading, so defer\n // the write until the element is connected.\n if (this.#host.isConnected) this.#write();\n else queueMicrotask(() => this.#write());\n }\n\n #write(): void {\n if (this.size === 0) this.#host.removeAttribute('data-state');\n else this.#host.setAttribute('data-state', Array.from(this).join(' '));\n }\n}\n\nexport type CustomStateSupport = 'missing' | 'legacy' | 'modern';\n\nconst PROBE_TAG = 'custom-state-support-probe';\n\n/**\n * Classify native custom-state support by behaviour:\n *\n * - `missing`: `ElementInternals` carries no `states` at all.\n * - `legacy`: `states` exists but rejects a bare name.\n * - `modern`: `states` exists and accepts a bare name — no shim wanted.\n *\n * `attachInternals` only works on a custom element, so the probe registers a\n * throwaway one. That happens solely when `states` is present, so the `missing`\n * path never defines anything.\n */\nexport function classifyCustomStateSupport(\n attachInternals: (this: HTMLElement) => ElementInternals\n): CustomStateSupport {\n if (!('states' in ElementInternals.prototype)) return 'missing';\n if (typeof customElements === 'undefined') return 'modern';\n\n try {\n if (!customElements.get(PROBE_TAG)) customElements.define(PROBE_TAG, class extends HTMLElement {});\n const states = attachInternals.call(document.createElement(PROBE_TAG)).states;\n if (!states) return 'missing';\n // A bare name throws SyntaxError under the legacy spec and never does under\n // the current one, so classify on the throw alone — not on whether the value\n // sticks, which some environments do not honour on a detached element.\n states.add('probe');\n states.delete('probe');\n return 'modern';\n } catch {\n return 'legacy';\n }\n}\n\nlet installed = false;\n\n/**\n * Patch `HTMLElement.prototype.attachInternals` so every element's `states` is\n * the shim, on the two profiles that need it. Idempotent, and a no-op where\n * native support is usable.\n *\n * Returns the classification that was acted on, which is what the tests assert.\n */\nexport function installCustomStateSetFallback(): CustomStateSupport | 'already-installed' {\n if (installed) return 'already-installed';\n if (typeof HTMLElement === 'undefined' || typeof ElementInternals === 'undefined') return 'modern';\n\n const native = HTMLElement.prototype.attachInternals;\n if (!native) return 'modern';\n\n const support = classifyCustomStateSupport(native);\n if (support === 'modern') return support;\n\n installed = true;\n HTMLElement.prototype.attachInternals = function attachInternals(this: HTMLElement): ElementInternals {\n const internals = native.call(this);\n Object.defineProperty(internals, 'states', {\n configurable: true,\n enumerable: true,\n value: new CustomStateSetShim(this)\n });\n return internals;\n };\n\n return support;\n}\n","import { createContext } from '@lit/context';\n\nimport type { ComputedItemContext } from './types/computed-item.types';\n\nexport const computedItemContext = createContext<Readonly<ComputedItemContext>>(Symbol('computedItemContext'));\n","import { createContext } from '@lit/context';\n\nimport type { ComputedContext } from './types/computed.types';\n\nexport const computedContext = createContext<Readonly<ComputedContext>>(Symbol('computedContext'));\n","import { createContext } from '@lit/context';\n\nexport type ValidationDisplayMode = 'inline' | 'native' | 'both' | 'none';\n\n/**\n * Configuration context for QTI components. Provides runtime options for assessment item and\n * interaction behavior.\n *\n * ── Three ways to set it, in the order you should reach for them ─────────────────────────────\n *\n * 1. **On a provider**, for real delivery. `qti-test` and `qti-item` both provide it, so setting\n * `item.configContext = {…}` configures every interaction inside.\n *\n * 2. **On one interaction, directly** — the development-time route, and the reason\n * `Interaction.configContext` is public:\n *\n * orderInteraction.configContext = { allowReorder: false };\n *\n * or, in a lit-html template, as a property binding — which lands before `connectedCallback`:\n *\n * html`<qti-order-interaction .configContext=${{ allowReorder: false }}>…`\n *\n * An interaction has to work standalone, so in a story or a spec there is usually no provider\n * above it, and then nothing ever overwrites what you set. Where a provider DOES exist it wins on\n * its next emit, because `@consume` writes that same field.\n *\n * A `qti-config-test-provider` element used to exist for scoping config to a subtree. It is gone:\n * it was test-only yet registered itself into every consumer's element registry via an unguarded\n * `@customElement`, which threw whenever two copies of this package ended up in one module graph.\n * Bind the property on each interaction instead, or provide from `qti-item`.\n *\n * There is no merging at any level: @lit/context resolves to the nearest provider and that object\n * replaces the ancestor's wholesale. A deeper provider therefore has to restate anything from above\n * that it still wants.\n *\n * Note what is NOT here. Options an item author chooses per question are attributes on the\n * interaction (`auto-size-dropzones`, `max-associations`, `disable-animations`); options only a\n * developer chooses are mixin factory arguments or method overrides. This context is for what a\n * delivery environment decides across items. `interactionContext` and `dragDropContext` are neither\n * — they publish derived state (what a choice IS, what a drop HOLDS), never configuration.\n */\nexport interface ConfigContext {\n /**\n * Optional category label for info items, used for reporting or display purposes.\n * Example: \"General Information\", \"Instructions\".\n */\n infoItemCategory?: string;\n\n /**\n * If true, calls reportValidity() on interactions after scoring to show validation feedback.\n * Used to trigger UI validation after a scoring event.\n */\n reportValidityAfterScoring?: boolean;\n\n /**\n * Controls how validation feedback is displayed by interactions:\n * - 'inline': render message in #validation-message (default behavior)\n * - 'native': use browser-native reportValidity popup behavior\n * - 'both': show both inline and native feedback\n * - 'none': keep validity state only, without visual feedback\n */\n validationDisplayMode?: ValidationDisplayMode;\n\n /**\n * If true, disables further user actions when an interaction reaches its configured maximum.\n * Applies to both choice-based and drag/drop interactions.\n */\n disableAfterMaxReached?: boolean;\n\n /**\n * If false, chips already placed in a drop target cannot be reordered or moved between targets in\n * drag/drop sortable interactions (order, match, gap-match). Defaults to true. A per-interaction\n * `allowReorder` property overrides this.\n */\n allowReorder?: boolean;\n\n /**\n * If true, disables further selection in choice interactions after the maximum number of choices is reached.\n * @deprecated Legacy alias for choice interactions. Prefer disableAfterMaxReached.\n */\n disableAfterIfMaxChoicesReached?: boolean;\n\n /**\n * Optional prompt text to display in inline choice interactions when no option is selected.\n * Example: \"Select an answer...\"\n */\n inlineChoicePrompt?: string;\n\n /**\n * If true, the inline choice interaction automatically measures the widest option and sizes the\n * trigger button to match. Defaults to false.\n * When a `qti-input-width-*` class is present on the interaction, that class width always takes\n * precedence and autosizing is skipped regardless of this setting.\n */\n inlineChoiceAutosize?: boolean;\n}\n\nexport const configContext = createContext<Readonly<ConfigContext>>(Symbol('configContext'));\n","import { createContext } from '@lit/context';\n\n/**\n * What a choice element should render and behave as. The same element — `qti-simple-choice`,\n * `qti-hottext` — is a radio in one interaction and a checkbox in another. It cannot know this\n * by itself.\n *\n * Note \"drag\" is deliberately *not* a choiceRole. In `qti-match-interaction` the same element\n * type is a drag in one match-set and a drop target in the other, so draggability is positional,\n * not a property of the interaction. It is derived from `draggablesSelector` instead. It is also\n * not a valid ARIA role, so it may only ever be a custom state.\n */\nexport type ChoiceRole = 'radio' | 'checkbox';\n\n/**\n * State an interaction publishes to the choice elements inside it.\n *\n * Provided by the `qti-*-interaction`, never by `qti-assessment-item`: interactions must work\n * standalone — in a plain form, in a story, in a vendor's app — with no QTI ancestor. Consumers\n * must therefore tolerate its absence and fall back to a sensible default:\n *\n * const role = this.interactionContext?.choiceRole ?? null;\n */\nexport interface InteractionContext {\n /** `null` when the interaction assigns no particular role to its choices. */\n choiceRole: ChoiceRole | null;\n\n /**\n * The selector this interaction uses to recognise its draggable chips. An element tests\n * itself with `this.matches(draggablesSelector)` and takes `:state(chip)` if it matches.\n *\n * Published rather than pushed because draggability can be positional: match-interaction's\n * selector distinguishes the source match-set from the target one, so two elements of the\n * same tag get different answers.\n */\n draggablesSelector: string | null;\n}\n\nexport const interactionContext = createContext<Readonly<InteractionContext>>(Symbol('interactionContext'));\n","import { createContext } from '@lit/context';\n\nimport type { ItemContext } from './types/item.types';\n\nexport const itemContext = createContext<ItemContext>(Symbol('item'));\n","import type { VariableDeclaration } from '../../lib/variables';\n\nexport interface ItemContext {\n identifier?: string;\n href?: string;\n variables?: ReadonlyArray<VariableDeclaration<string | string[] | null>>;\n /**\n * Optional per-interaction opaque state, keyed by responseIdentifier.\n * Used for interactions that support state save/restore (e.g. PCI).\n */\n state?: Record<string, string | null>;\n}\n\nexport const itemContextVariables = [\n {\n identifier: 'completionStatus',\n cardinality: 'single',\n baseType: 'string',\n value: 'unknown',\n type: 'outcome'\n },\n {\n identifier: 'numAttempts',\n cardinality: 'single',\n baseType: 'integer',\n value: '0',\n type: 'response'\n }\n] as VariableDeclaration<string | string[]>[];\n","import { createContext } from '@lit/context';\n\n/**\n * A validated deterministic shuffle seed.\n *\n * Branded so that only values verified through {@link isSeed} (or constructed via\n * {@link asSeed}) can be assigned where a seed is expected. This prevents arbitrary\n * strings from silently being used as a seed.\n *\n * A usable seed is a non-empty string of letters, digits and hyphens (e.g. a GUID\n * \"N\" format like `8f14e45fceea167a5a36dedd4bea2543`, or a readable label like\n * `delivery-2026-06-05`). Whitespace and other characters are rejected.\n */\nexport type Seed = string & { readonly __seedBrand: 'Seed' };\n\n/** Format a value must match to be usable as a {@link Seed}. */\nconst SEED_PATTERN = /^[A-Za-z0-9-]+$/;\n\n/**\n * Runtime type guard that narrows an unknown value to a {@link Seed}.\n * Use this at boundaries (e.g. values coming from XML, a host application or a\n * backend) before treating a string as a seed.\n */\nexport const isSeed = (value: unknown): value is Seed => typeof value === 'string' && SEED_PATTERN.test(value);\n\n/**\n * Validates and brands a value as a {@link Seed}, returning `undefined` when the\n * value is missing or not in a usable seed format.\n */\nexport const asSeed = (value: unknown): Seed | undefined => (isSeed(value) ? value : undefined);\n\nexport type QtiContextType = {\n testIdentifier: string;\n candidateIdentifier: string;\n environmentIdentifier: string;\n /**\n * Optional deterministic seed for shuffling.\n *\n * When set, it is used to reproduce a stable shuffle order across reloads/restarts:\n * - test ordering in `test-container` (`<qti-ordering shuffle=\"true\">`),\n * - seeded item interaction shuffling in `item-container` and during test navigation.\n *\n * Typically generated once per session by the host/backend and passed in via\n * `QTI_CONTEXT`. When omitted, each item falls back to its own URI-derived seed.\n */\n seed?: Seed;\n [key: string]: string | string[]; // Allow for additional context variables\n};\n\nexport interface QtiContext {\n QTI_CONTEXT: QtiContextType;\n}\n\nexport const qtiContext = createContext<Readonly<QtiContext>>(Symbol('qtiContext'));\n","import { createContext } from '@lit/context';\n\nexport type View = 'author' | 'candidate' | 'proctor' | 'scorer' | 'testConstructor' | 'tutor' | '';\n\nexport interface SessionContext {\n navPartId?: string | null;\n navSectionId?: string | null;\n navItemRefId?: string | null;\n navItemLoading?: boolean;\n navTestLoading?: boolean;\n view?: View;\n}\n\nexport const INITIAL_SESSION_CONTEXT: Readonly<SessionContext> = { view: 'candidate' };\n\nexport const sessionContext = createContext<Readonly<SessionContext>>(Symbol('testContext'));\n","import { createContext } from '@lit/context';\n\nimport type { ItemContext } from './types/item.types';\nimport type { VariableDeclaration } from '../lib/variables';\n\nexport interface TestContext {\n items: (ItemContext & { category?: string })[];\n testOutcomeVariables?: VariableDeclaration<string | string[] | null>[];\n}\n\nexport const INITIAL_TEST_CONTEXT: Readonly<TestContext> = { items: [], testOutcomeVariables: [] };\n\nexport const testContext = createContext<Readonly<TestContext>>(Symbol('testContext'));\n","import { css } from 'lit';\n\n/**\n * The border-box reset, for shadow trees.\n *\n * `modern-normalize` applies `*, ::before, ::after { box-sizing: border-box }` to the document,\n * but a universal selector never crosses a shadow boundary: every shadow root starts over at\n * the UA default, `content-box`. So each component has to opt in, and until now 15 of them did\n * so ad hoc — one of them with `content-box`, one with `!important`.\n *\n * Why this matters beyond tidiness: under `content-box`, padding and border are *size*. A rule\n * that only means to repaint a chip — `:state(dragging) { border: none }` — silently shrinks it\n * by two pixels per axis, the drag bank rewraps, and a drop target slides out from under the\n * user's pointer mid-drag. Border-box is what makes \"a state may repaint but never re-lay-out\"\n * a rule the CSS can actually keep.\n *\n * `:host` is set explicitly and descendants inherit, so a component that genuinely needs\n * `content-box` for a subtree (an image map, say) can opt out at one node and have it hold for\n * everything below it.\n */\nexport const boxSizing = css`\n :host {\n box-sizing: border-box;\n }\n\n *,\n *::before,\n *::after {\n box-sizing: inherit;\n }\n`;\n","import { css } from 'lit';\n\n/**\n * The `drop` region of every drop target.\n *\n * One rule: **a drop container hosts a chip, it never sizes one.** No `flex: 1`, no stretch, no\n * centring. The chip's box is decided by the chip — in the drag bank, mid-flight as a clone, and\n * once dropped — and a container that centres or stretches it makes the drop the one place where\n * that stops being true. That is felt as the chip jumping the instant it lands.\n *\n * `flex: 0 1 auto` on the children says \"intrinsic size, no growing, shrink if you must\".\n * `align-items: flex-start` stops the cross axis stretching them, which is the flex default and\n * the reason a chip in a tall dropzone used to grow to fill it.\n *\n * The shrink half used to be 0 as well, on the reading that a drop must not resize a chip. It does\n * not say that. `flex-shrink: 0` does not preserve the chip's size, it preserves the chip's\n * UNCONSTRAINED max-content size — and those are the same number only while the bank is wide enough\n * to give the chip its full width. Once the bank is narrower, the bank chip (`flex: 0 1 auto`, like\n * any flex item) shrinks and wraps, the placed chip does not, and the two disagree.\n *\n * Measured on the order fixture, bank vs placed: 209x36 / 209x36 at a 480px interaction, but\n * 204x55 / 209x36 at 440px and 154x55 / 209x36 at 340px — the placed chip a fixed 209px wide,\n * overflowing a drop that had correctly reserved 156px for it. It reached CI as a font difference:\n * the same label measures ~227px under the Linux fonts, which puts 480px on the wrong side of the\n * boundary too.\n *\n * Shrinking cannot make a placed chip smaller than the reservation, because the reservation IS the\n * measured chip (`--qti-dropzone-min-*`, applied to this region's content box). So the floor a\n * shrink stops at is the chip's own size, which is the rule above, not an exception to it.\n * `flex-grow: 0` is what actually prevents the stretch this block cares about, and it is untouched.\n *\n * A container that wants a *minimum* size still declares one (see `--qti-dropzone-min-*`). That\n * sizes the container, never its contents.\n *\n * Verified by drag-drop.invariance.spec.ts: \"a chip is the same chip wherever it lives\" — including\n * the narrow-bank order fixture, which is there because the wide one passes either way.\n */\nexport const dropRegion = css`\n [part~='drop'] {\n /*\n * The one deliberate opt-out from the border-box reset.\n *\n * --qti-dropzone-min-* is the border-box of the largest chip, and what has to hold that chip is\n * this region's *content* area. Under border-box a theme's dashed drop border is subtracted\n * from the chip's own size, the content comes up short, and the drop grows the moment a chip\n * lands in it. Order's drop did exactly that: 64px empty, 66px full, for a 1px border.\n */\n box-sizing: content-box;\n\n /*\n * No padding, and no token for one.\n *\n * A drop reserves --qti-dropzone-min-*, which is the chip's BORDER-box, as this region's CONTENT\n * area — so the chip already fits exactly, with nothing to spare and nothing squeezed. An inset\n * on top would only make the drop bigger than the thing it holds.\n *\n * There was a 1px one, to make the drop read as a frame a hair outside the chip. It never painted:\n * an EMPTY slot has nothing inside the inset to separate from, and a FILLED one hides its edge\n * (DROP-SIZING.md §4), so both states spent 2px on an invisible ring. The one drop that genuinely\n * wants breathing room — match's category card — declares padding on its own rule, which a\n * theme reaches with ::part(drop). A token in between bought nothing.\n */\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n justify-content: flex-start;\n /* No gap either: 0 is the flex initial value, so the declaration only existed to host a token.\n A drop that wants space between chips sets gap on its own rule. */\n /* Containing block for anything a theme draws over the drop. Was 'position: relative' in the\n theme's 'drop' mixin, which put a document stylesheet in charge of a shadow node's position. */\n position: relative;\n }\n\n [part~='drop'] > * {\n flex: 0 1 auto;\n align-self: flex-start;\n }\n`;\n","import { css } from 'lit';\n\n/**\n * The `#validation-message` region every interaction renders, hidden until there is a message.\n *\n * `Interaction` owns showing and hiding it: `reportValidity` sets\n * `display: block !important` inline when `_internals.validationMessage` is non-empty, and clears the\n * text and sets `display: none` inline again when it is not (see interaction.ts). An inline\n * `!important` beats this rule, so the JS still wins whenever it speaks.\n *\n * What it did not own was the *initial* state. Before first validation the div has no inline style,\n * so it needs a stylesheet to start hidden — otherwise it paints as an empty box with the theme's\n * warning border and padding. That hide used to be a `display: none` inside the theme's\n * `validation-message` mixin, which made a document stylesheet responsible for a shadow node's box.\n * Two components had already noticed and worked around it with `style=\"display:none\"` in their\n * template; the other five relied on the theme.\n *\n * The theme still paints the message — colour, border, padding, radius — via `::part(message)`.\n */\nexport const validationMessage = css`\n [part~='message'] {\n display: none;\n }\n`;\n","import { consume, provide } from '@lit/context';\nimport { LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { configContext } from '../context/config.context';\nimport { interactionContext } from '../context/interaction.context';\nimport { itemContext } from '../context/item.context';\n\nimport type { PropertyValues } from 'lit';\nimport type { InteractionContext } from '../context/interaction.context';\nimport type { ConfigContext, ValidationDisplayMode } from '../context/config.context';\nimport type { ItemContext } from '../context/types/item.types';\nimport type { ValidatableInteraction } from '../lib/interaction.interface';\nimport type { ResponseVariable } from '../lib/variables';\n\n/**\n * Shared QTI interaction base. Formative correction behavior is supplied by the\n * `@qti-components/corrections` package.\n */\nexport abstract class Interaction extends LitElement implements ValidatableInteraction {\n @consume({ context: itemContext, subscribe: true })\n private _context: ItemContext;\n\n /**\n * Delivery configuration, from the nearest provider — `qti-test` or `qti-item`.\n *\n * **Public so it can be assigned directly, which is the development-time route.** An interaction\n * has to work standalone, and in a story or a spec there is usually no provider above it — so\n * setting the field is all that is needed:\n *\n * orderInteraction.configContext = { allowReorder: false, validationDisplayMode: 'none' };\n *\n * With no provider, nothing ever overwrites it. That is the whole contract, and its limit: where a\n * provider DOES exist it re-emits on its next update and wins, because `@consume` writes this same\n * field. There is no merging — set the value on the provider in that case.\n *\n * In a lit-html template, bind it as a property rather than assigning after the fact:\n *\n * html`<qti-order-interaction .configContext=${{ allowReorder: false }}>…`\n *\n * The binding is committed on the detached template clone, before the fragment is inserted, so it\n * is in place by `connectedCallback` — which matters for anything that reads config on connect.\n *\n * It was `protected`, which fooled nobody: every caller reached it anyway through an\n * `as any` / `as { configContext?: … }` cast. Public says what was already true and removes the\n * casts, rather than pretending at an encapsulation the type system was the only thing enforcing.\n */\n @consume({ context: configContext, subscribe: true })\n public configContext: ConfigContext;\n\n #didLogDisableAfterIfMaxChoicesReachedDeprecation = false;\n\n /*\n * Published to the choice elements inside this interaction — their role, and how to tell\n * whether they are draggable. Provided here on the base rather than in a mixin so that\n * ChoicesMixin and the drag-drop mixins can each contribute without two providers of the same\n * context competing on one element.\n *\n * Reassign, never mutate: an in-place change does not notify consumers.\n */\n @provide({ context: interactionContext })\n protected _interactionContext: Readonly<InteractionContext> = { choiceRole: null, draggablesSelector: null };\n\n static formAssociated = true;\n protected _internals: ElementInternals;\n\n get internals(): ElementInternals {\n return this._internals;\n }\n\n @property({ type: String, attribute: 'response-identifier' }) responseIdentifier: string;\n\n @property({ reflect: true, type: Boolean }) disabled = false;\n\n @property({ reflect: true, type: Boolean }) readonly = false;\n\n @property({ type: String }) name;\n\n /** Extension point used by wrappers that should not register as candidate inputs. */\n protected get registersWithItem(): boolean {\n return true;\n }\n\n get isInline(): boolean {\n return false;\n }\n\n get responseVariable(): ResponseVariable | undefined {\n if (!this._context?.variables) {\n return undefined;\n }\n const responseVariables = this._context.variables.filter(v => v.type === 'response') as ResponseVariable[];\n const responseIdentifier = this.getAttribute('response-identifier');\n return responseVariables.find(v => v.identifier === responseIdentifier);\n }\n\n abstract validate(): boolean;\n\n get value(): string | null {\n return JSON.stringify(this.response);\n }\n\n set value(val: string | null) {\n this.response = val ? JSON.parse(val) : null;\n }\n\n abstract get response(): string | string[] | null;\n abstract set response(val: string | string[] | null);\n\n public reportValidity(): boolean {\n const isValid = this._internals.validity.valid;\n const mode = this.validationDisplayMode;\n\n if (mode === 'native' || mode === 'both') {\n this._internals.reportValidity();\n }\n\n if (mode === 'inline' || mode === 'both') {\n this.updateInlineValidationMessage();\n } else {\n this.clearInlineValidationMessage();\n }\n\n if (mode === 'none') {\n this.clearInlineValidationMessage();\n }\n\n return isValid;\n }\n\n protected get validationDisplayMode(): ValidationDisplayMode {\n return this.configContext?.validationDisplayMode ?? 'inline';\n }\n\n protected resolveAllowReorder(options?: { defaultWhenUnset?: boolean }): boolean {\n const defaultWhenUnset = options?.defaultWhenUnset ?? true;\n const config = this.configContext;\n if (!config) {\n return defaultWhenUnset;\n }\n if (config.allowReorder !== undefined) {\n return config.allowReorder;\n }\n return defaultWhenUnset;\n }\n\n protected resolveDisableAfterMaxReached(options?: { defaultWhenUnset?: boolean }): boolean {\n const defaultWhenUnset = options?.defaultWhenUnset ?? false;\n const config = this.configContext;\n\n if (!config) {\n return defaultWhenUnset;\n }\n\n if (config.disableAfterMaxReached !== undefined) {\n return config.disableAfterMaxReached;\n }\n\n if (config.disableAfterIfMaxChoicesReached !== undefined) {\n if (!this.#didLogDisableAfterIfMaxChoicesReachedDeprecation) {\n this.#didLogDisableAfterIfMaxChoicesReachedDeprecation = true;\n console.log(\n '[QTI Config] `disableAfterIfMaxChoicesReached` is deprecated. Use `disableAfterMaxReached` instead.'\n );\n }\n return config.disableAfterIfMaxChoicesReached;\n }\n\n return defaultWhenUnset;\n }\n\n protected setInteractionValidity(\n isValid: boolean,\n validityMessage = '',\n anchor?: HTMLElement | null,\n options?: { suppressInline?: boolean }\n ): void {\n const validityAnchor = anchor ?? this;\n this._internals.setValidity(isValid ? {} : { customError: true }, validityMessage, validityAnchor);\n\n if (\n options?.suppressInline !== true &&\n (this.validationDisplayMode === 'inline' || this.validationDisplayMode === 'both')\n ) {\n this.updateInlineValidationMessage();\n }\n }\n\n protected updateInlineValidationMessage(): void {\n const validationMessageElement = this.getValidationMessageElement();\n if (!validationMessageElement) {\n return;\n }\n\n if (!this._internals.validity.valid) {\n validationMessageElement.textContent = this._internals.validationMessage;\n validationMessageElement.style.setProperty('display', 'block', 'important');\n return;\n }\n\n validationMessageElement.textContent = '';\n validationMessageElement.style.display = 'none';\n }\n\n protected clearInlineValidationMessage(): void {\n const validationMessageElement = this.getValidationMessageElement();\n if (!validationMessageElement) {\n return;\n }\n\n validationMessageElement.textContent = '';\n validationMessageElement.style.display = 'none';\n }\n\n protected getValidationMessageElement(): HTMLElement | null {\n return this.shadowRoot?.querySelector('#validation-message') as HTMLElement | null;\n }\n\n public reset(): void {\n this.response = null;\n }\n\n public formResetCallback(): void {\n this.reset();\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n\n if (!this.registersWithItem) {\n return;\n }\n\n this.dispatchEvent(\n new CustomEvent('qti-register-interaction', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n interactionElement: this,\n responseIdentifier: this.responseIdentifier\n }\n })\n );\n }\n\n public saveResponse(value: string | string[], state?: string | null): void {\n this.dispatchEvent(\n new CustomEvent('qti-interaction-response', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n responseIdentifier: this.responseIdentifier,\n response: Array.isArray(value) ? [...value] : value,\n ...(state !== undefined ? { state } : {})\n }\n })\n );\n }\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n }\n\n /**\n * Optional lifecycle bridge for interaction subclasses that do not need changed-property data.\n *\n * The parameter is `PropertyValues`, matching LitElement, and NOT `PropertyValues<this>`.\n * The polymorphic `this` narrowed the parameter per subclass, which made every interaction\n * class structurally incompatible with `LitElement` — so `Constructor<LitElement>`, the\n * standard constraint for a Lit mixin, rejected all of them and consumers could not wrap an\n * interaction in a mixin without casting. `this` buys nothing in a parameter position and\n * costs contravariant compatibility with the base class.\n *\n * Still optional, so subclasses that ignore the argument can override with `firstUpdated()`.\n */\n protected override firstUpdated(_changedProperties?: PropertyValues): void {}\n}\n","import { html, LitElement } from 'lit';\n\nimport type { Cardinality } from '../lib/expression-result';\n\nexport abstract class QtiVariableDeclaration extends LitElement {\n override render() {\n return html`<slot></slot>`;\n }\n\n protected defaultValues(cardinality: Cardinality) {\n const htmlValues = Array.from(this.querySelectorAll('qti-default-value > qti-value'));\n\n if (htmlValues.length === 0) {\n return null;\n }\n\n const defaultValues = htmlValues.map(n => n.innerHTML.trim());\n if (defaultValues.length > 1 || cardinality === 'multiple' || cardinality === 'ordered') {\n return defaultValues;\n }\n return defaultValues[0];\n }\n}\n","import { consume } from '@lit/context';\nimport { css, html, LitElement } from 'lit';\nimport { state } from 'lit/decorators.js';\n\nimport { itemContext } from '../context/item.context';\nimport { qtiContext } from '../context/qti.context';\n\nimport type { ItemContext } from '../context/types/item.types';\nimport type { QtiContext, QtiContextType } from '../context/qti.context';\nimport type { ResponseVariable, VariableDeclaration } from '../lib/variables';\n\nexport interface QtiExpressionBase<T> {\n // get assessmentItem(): QtiAssessmentItem;\n\n // getVariables(): VariableDeclaration<number | string | (number | string)[] | null>[];\n calculate(): Readonly<T>;\n}\n\nexport abstract class QtiExpression<T> extends LitElement implements QtiExpressionBase<T> {\n @state()\n protected result: any;\n\n /*\n * Written here rather than imported from a .css file, and that is a packaging constraint rather\n * than a style preference.\n *\n * The rule used to live in qti-expression.css, imported with Vite's inline-stylesheet query so\n * DevTools could show source-file provenance. That query is a VITE specifier, and tsc copies it\n * verbatim into dist — so the published package shipped an import only a Vite-based consumer\n * could resolve. Every other consumer broke on it: plain Node, tsx, any non-Vite bundler. It was\n * the single such specifier reachable from this package, and it took down QTI-Editor's schema\n * check, which loads the components under tsx to build the real ProseMirror schema\n * (ERR_UNKNOWN_FILE_EXTENSION on a file that has nothing to do with schemas).\n *\n * A `build:assets` step used to copy the .css into dist beside it. That went too — it existed\n * only to give the unresolvable import something to point at.\n *\n * Two lines of CSS are not worth a dist that only one bundler can consume. If this ever grows\n * into a real stylesheet, give it a `.styles.ts` exporting a `css` template — the house pattern\n * everywhere else in this repo — rather than reintroducing a bundler-specific import.\n *\n * The element renders a debug <pre> of its computed result plus a <slot>; hiding the slot is all\n * the styling it has ever had.\n */\n static override styles = css`\n slot {\n display: none;\n }\n `;\n\n override render() {\n return html`<pre>${JSON.stringify(this.result, null, 2)}</pre>\n <slot></slot>`;\n }\n\n public calculate(): Readonly<T> {\n this.result = this.getResult();\n return this.result;\n }\n\n protected getResult(): Readonly<T> {\n throw new Error('Not implemented');\n }\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n @consume({ context: qtiContext, subscribe: true })\n @state()\n protected qtiContext?: QtiContext;\n\n getVariables = (): (ResponseVariable | VariableDeclaration<QtiContextType>)[] =>\n // FIXME: if this itself is multiple, this will never enter the qti-multiple switch\n // See this example here: https://github.com/1EdTech/qti-examples/blob/master/qtiv3-examples/packaging/items/Example05-feedbackBlock-adaptive.xml\n\n Array.from(this.children)\n .map((e: Element) => {\n console.debug('getVariables', e.tagName.toLowerCase());\n switch (e.tagName.toLowerCase()) {\n case 'qti-base-value': {\n return {\n baseType: e.getAttribute('base-type'),\n value: e.textContent.trim(),\n cardinality: 'single'\n } as ResponseVariable;\n }\n case 'qti-variable': {\n const identifier = e.getAttribute('identifier') || '';\n\n // Special handling for QTI_CONTEXT\n if (identifier === 'QTI_CONTEXT') {\n if (!this.qtiContext?.QTI_CONTEXT) {\n console.warn('QTI_CONTEXT not available');\n return {\n identifier: 'QTI_CONTEXT',\n baseType: 'record',\n value: this.qtiContext.QTI_CONTEXT,\n cardinality: 'record',\n type: 'context'\n } as VariableDeclaration<QtiContextType>;\n }\n return {\n identifier: 'QTI_CONTEXT',\n baseType: 'record',\n value: this.qtiContext.QTI_CONTEXT,\n cardinality: 'record',\n type: 'context'\n } as VariableDeclaration<QtiContextType>;\n }\n\n const variable = this.context.variables.find(v => v.identifier === identifier) || null;\n return variable;\n }\n case 'qti-multiple': {\n const multiple = e as QtiExpression<ResponseVariable[]>;\n\n const values = multiple.getResult();\n console.debug('values', values);\n if (values?.length > 0) {\n return {\n identifier: '',\n baseType: values[0].baseType,\n value: values.map(v => v.value),\n cardinality: 'multiple',\n type: 'response'\n } as ResponseVariable;\n }\n return null;\n }\n case 'qti-ordered': {\n const multiple = e as QtiExpression<ResponseVariable[]>;\n const values = multiple.getResult();\n if (values?.length > 0) {\n return {\n identifier: '',\n baseType: values[0].baseType,\n value: values.map(v => v.value),\n cardinality: 'ordered',\n type: 'response'\n } as ResponseVariable;\n }\n return null;\n }\n case 'qti-repeat': {\n const repeat = e as QtiExpression<ResponseVariable[]>;\n const values = repeat.getResult();\n if (values?.length > 0) {\n return values;\n }\n return null;\n }\n case 'qti-correct': {\n const identifier = e.getAttribute('identifier') || '';\n const responseVariable: ResponseVariable =\n this.context?.variables?.find(v => v.identifier === identifier) || null;\n return {\n baseType: responseVariable.baseType,\n value: responseVariable.correctResponse,\n cardinality: responseVariable.cardinality\n } as ResponseVariable;\n }\n default: {\n // added for use of qti-equal-rounded\n try {\n const expression = e as QtiExpression<number>;\n const value = expression.getResult();\n return {\n baseType: 'integer',\n value: value?.toString() || null,\n cardinality: 'single'\n } as ResponseVariable;\n } catch (error) {\n console.warn('default not sufficient');\n }\n return null;\n }\n }\n })\n .flatMap(v => (Array.isArray(v) ? v : [v]))\n .filter(v => v !== null);\n}\n","import { QtiExpression } from './qti-expression';\n\nexport abstract class QtiConditionExpression extends QtiExpression<boolean> {\n public override calculate(): Readonly<boolean> {\n this.result = this.getResult();\n return this.result;\n }\n\n public override getResult(): Readonly<boolean> {\n throw new Error('Not implemented');\n }\n}\n","export const decimalSeparator = () => {\n return new Intl.NumberFormat().format(0.1).replace(/\\d/g, '');\n};\n\nexport const convertNumberToUniversalFormat = (number: number | string) => {\n // check if type is string\n if (typeof number === 'string') {\n return number;\n }\n const dSep = decimalSeparator();\n if (dSep === '.') {\n return number.toLocaleString();\n } else {\n return number.toString().replace('.', '').replace(dSep, '.');\n }\n};\n\nexport function IsNullOrUndefined(value: unknown) {\n return value === null || value === undefined;\n}\n\nexport function removeDoubleSlashes(str: string) {\n const singleForwardSlashes = str\n .replace(/([^:]\\/)\\/+/g, '$1')\n .replace(/\\/\\//g, '/')\n .replace('http:/', 'http://')\n .replace('https:/', 'https://');\n return singleForwardSlashes;\n}\n","import { consume } from '@lit/context';\nimport { LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport { itemContext } from '../context/item.context';\nimport { IsNullOrUndefined } from '../utils/utils';\n\nimport type { ItemContext } from '../context/types/item.types';\n\nexport abstract class QtiFeedback extends LitElement {\n @property({ type: String, attribute: 'show-hide' })\n protected showHide: 'show' | 'hide' = 'show';\n\n @property({ type: String, attribute: 'outcome-identifier' })\n public outcomeIdentifier: string;\n\n @property({ type: String })\n protected identifier: string;\n\n @property({ type: String, attribute: false })\n public showStatus: string;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n private _context?: ItemContext;\n\n public override connectedCallback() {\n super.connectedCallback();\n this.dispatchEvent(\n new CustomEvent<QtiFeedback>('qti-register-feedback', {\n bubbles: true,\n composed: true,\n detail: this\n })\n );\n }\n\n public checkShowFeedback(outcomeIdentifier: string) {\n const outcomeVariable = this._context.variables.find(v => v.identifier === outcomeIdentifier) || null;\n if (this.outcomeIdentifier !== outcomeIdentifier || !outcomeVariable) return;\n let isFound = false;\n if (Array.isArray(outcomeVariable.value)) {\n isFound = outcomeVariable.value.includes(this.identifier);\n } else {\n isFound =\n (!IsNullOrUndefined(this.identifier) &&\n !IsNullOrUndefined(outcomeVariable?.value) &&\n this.identifier === outcomeVariable.value) ||\n false;\n }\n\n this.#showFeedback(isFound);\n }\n\n #showFeedback(value: boolean) {\n this.showStatus = (value && this.showHide === 'show') || (!value && this.showHide === 'hide') ? 'on' : 'off';\n }\n}\n","/**\n * Canonical `response=\"...\"` / `correct-response=\"...\"` attribute codec.\n *\n * Authors put a single string on an interaction element. This module is the\n * single source of truth for how that string parses into the runtime's\n * internal value AND how an editor serializes the internal value back to the\n * attribute. Both `@qti-components/*` interactions and `@citolab/prose-qti`\n * (the editor) import from here — no per-codebase parsers, no drift.\n *\n * The two attributes share the same grammar; the codec is agnostic about\n * which of them is being parsed.\n *\n * ---\n *\n * Format reference (per interaction):\n *\n * | Interaction | base-type | cardinality | attribute value |\n * |----------------------|---------------|----------------------|---------------------------|\n * | choice | identifier | single / multiple | \"A\" / \"A,B,C\" |\n * | inline-choice | identifier | single | \"Y\" |\n * | hottext | identifier | single / multiple | \"h1\" / \"h1,h2\" |\n * | hotspot | identifier | single / multiple | \"spot1\" / \"spot1,spot2\" |\n * | order | identifier | ordered | \"a,b,c\" (order matters) |\n * | graphic-order | identifier | ordered | \"spot1,spot2,spot3\" |\n * | match | directedPair | multiple | \"src1 tgt1,src2 tgt2\" |\n * | associate | directedPair | multiple | \"A B,C D\" |\n * | gap-match | directedPair | multiple | \"gtext1 gap1,...\" |\n * | graphic-associate | directedPair | multiple | \"spot1 spot2,...\" |\n * | graphic-gap-match | directedPair | multiple | \"gimg1 spot1,...\" |\n * | select-point | point | single / multiple | \"100 150\" / \"100 150,…\" |\n * | slider | integer | single | \"50\" |\n * | text-entry | string | single | \"paris\" |\n *\n * Rules:\n * - Comma `,` separates VALUES (different identifiers / pairs / points).\n * - Space ` ` separates PARTS within one value (pair members or point coords).\n * - Each value is trimmed on parse.\n * - No escape mechanism. Identifiers that contain commas cannot round-trip.\n */\n\n// ─── parsed shape ────────────────────────────────────────────────────────────\n\n/** Canonical parsed value of a `response` / `correct-response` attribute. */\nexport type ResponseValue = string | string[] | null;\n\n// ─── per-shape branded types (advisory at compile time) ──────────────────────\n\n/** Identifier literal — opaque QTI identifier (e.g. `\"choice1\"`). */\nexport type Identifier = string;\n\n/** Directed pair literal — `\"sourceId targetId\"`. Used by match / associate / gap-match. */\nexport type DirectedPair = `${string} ${string}`;\n\n/** Point literal — `\"x y\"` integer coordinates. Used by select-point / graphic-*. */\nexport type Point = `${number} ${number}`;\n\n// ─── attribute-level parser / serializer ─────────────────────────────────────\n\n/**\n * Parse a raw `response` / `correct-response` attribute string into the\n * canonical value.\n *\n * - `null` / `undefined` / empty → `null`\n * - no comma → trimmed string\n * - one or more commas → trimmed array (single-element collapses to a string)\n */\nexport function parseResponseAttribute(raw: string | null | undefined): ResponseValue {\n if (raw == null) return null;\n if (!raw.includes(',')) {\n const trimmed = raw.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n const tokens = raw\n .split(',')\n .map(token => token.trim())\n .filter(token => token.length > 0);\n if (tokens.length === 0) return null;\n if (tokens.length === 1) return tokens[0];\n return tokens;\n}\n\n/**\n * Serialize a canonical value back to the attribute string. Returns `null` for\n * empty inputs so a Lit `@property({ reflect: true })` drops the attribute.\n */\nexport function serializeResponseAttribute(value: ResponseValue): string | null {\n if (value == null) return null;\n if (Array.isArray(value)) {\n const tokens = value.map(token => token.trim()).filter(token => token.length > 0);\n return tokens.length > 0 ? tokens.join(',') : null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\n// ─── value-shape helpers (per interaction type) ──────────────────────────────\n\n/**\n * Iterate over the comma-separated entries in a response value, regardless of\n * whether the caller has the raw string, the parsed string, or a string[].\n * Yields trimmed non-empty entries.\n */\nexport function* iterResponseValues(raw: ResponseValue): Generator<string> {\n if (raw == null) return;\n if (Array.isArray(raw)) {\n for (const v of raw) {\n const t = v.trim();\n if (t) yield t;\n }\n return;\n }\n if (!raw.includes(',')) {\n const t = raw.trim();\n if (t) yield t;\n return;\n }\n for (const v of raw.split(',')) {\n const t = v.trim();\n if (t) yield t;\n }\n}\n\n/** Parse a directed-pair value into `{ source, target }`. Throws on malformed input. */\nexport function parsePair(value: string): { source: string; target: string } {\n const [source, target, ...rest] = value.trim().split(/\\s+/);\n if (!source || !target || rest.length > 0) {\n throw new Error(`malformed directed-pair value: \"${value}\" (expected \"source target\")`);\n }\n return { source, target };\n}\n\n/** Serialize a directed pair to canonical `\"source target\"` form. */\nexport function serializePair(source: string, target: string): DirectedPair {\n return `${source} ${target}`;\n}\n\n/** Parse a point value into `{ x, y }`. Throws on malformed input. */\nexport function parsePoint(value: string): { x: number; y: number } {\n const [xStr, yStr, ...rest] = value.trim().split(/\\s+/);\n const x = Number(xStr);\n const y = Number(yStr);\n if (!Number.isFinite(x) || !Number.isFinite(y) || rest.length > 0) {\n throw new Error(`malformed point value: \"${value}\" (expected \"x y\" numeric coords)`);\n }\n return { x, y };\n}\n\n/** Serialize a point to canonical `\"x y\"` form. */\nexport function serializePoint(x: number, y: number): Point {\n return `${x} ${y}`;\n}\n\n// ─── Lit converter factory ───────────────────────────────────────────────────\n\n/**\n * Ready-to-use Lit `converter` for `response` / `correct-response` attributes.\n * Assign to the `converter` option:\n *\n * @property({ attribute: 'response', converter: responseAttributeConverter({ emptyAs: [] }) })\n *\n * `emptyAs` picks the sentinel returned when the attribute is absent / blank.\n * Three sentinels exist across the codebase — match the one your call site\n * already uses. Future work may normalize to a single sentinel.\n *\n * - '' (empty string) — ChoicesMixin convention\n * - [] — DragDropSlottedMixin / graphic-associate convention\n * - null — base interaction / select-point convention\n *\n * On the serialize side, the `emptyAs` value roundtrips back to `null` so a\n * `reflect: true` property drops the attribute rather than emitting `\"\"`.\n */\nexport function responseAttributeConverter<E extends '' | null | readonly unknown[]>(opts: {\n emptyAs: E;\n}): {\n fromAttribute: (value: string | null) => ResponseValue | E;\n toAttribute: (value: ResponseValue | E) => string | null;\n} {\n const { emptyAs } = opts;\n const isEmptySentinel = (value: unknown): boolean =>\n value === emptyAs || value == null || value === '' || (Array.isArray(value) && value.length === 0);\n\n return {\n fromAttribute: (value: string | null): ResponseValue | E => {\n const parsed = parseResponseAttribute(value);\n return parsed === null ? emptyAs : parsed;\n },\n toAttribute: (value: ResponseValue | E): string | null => {\n if (isEmptySentinel(value)) return null;\n return serializeResponseAttribute(value as ResponseValue);\n }\n };\n}\n","import { LitElement } from 'lit';\n\n/**\n * Interface for any object that can process QTI rules\n */\nexport interface QtiRuleBase {\n process(): any;\n}\n\n/**\n * Abstract base class for QTI rule DOM elements\n */\nexport abstract class QtiRuleElement extends LitElement implements QtiRuleBase {\n abstract process(): any;\n}\n","import type { BaseType } from '../lib/expression-result';\n\nexport class ScoringHelper {\n /**\n * Checks if a given point is within a specified area.\n * @param point The point to test, represented as a string \"x y\" (e.g., \"102 113\").\n * @param areaKey The area definition, including shape and coordinates (e.g., \"circle,102,113,16\").\n * @param baseType The base type of the response, must be \"point\" for this method to proceed.\n * @returns True if the point is within the area; false otherwise.\n */\n public static isPointInArea(point: string, areaKey: string, baseType: string): boolean {\n if (baseType !== 'point') {\n console.warn(`Base type ${baseType} is not supported for point area mapping.`);\n return false;\n }\n\n // Parse the point as x and y coordinates\n const [px, py] = point.split(' ').map(Number);\n\n // Parse the area definition\n const [shape, ...coords] = areaKey.split(',');\n const coordinates = coords.map(Number);\n\n switch (shape.toLowerCase()) {\n case 'circle':\n case 'default': {\n const [cx, cy, radius] = coordinates;\n if (coordinates.length !== 3) {\n console.warn(`Invalid circle definition: ${areaKey}`);\n return false;\n }\n const distance = Math.sqrt((px - cx) ** 2 + (py - cy) ** 2);\n return distance <= radius;\n }\n\n case 'rect': {\n const [x1, y1, x2, y2] = coordinates;\n if (coordinates.length !== 4) {\n console.warn(`Invalid rectangle definition: ${areaKey}`);\n return false;\n }\n return px >= x1 && px <= x2 && py >= y1 && py <= y2;\n }\n\n case 'ellipse': {\n const [cx, cy, rx, ry] = coordinates;\n if (coordinates.length !== 4) {\n console.warn(`Invalid ellipse definition: ${areaKey}`);\n return false;\n }\n // Ellipse equation: ((px - cx)² / rx²) + ((py - cy)² / ry²) <= 1\n const normalizedX = (px - cx) ** 2 / rx ** 2;\n const normalizedY = (py - cy) ** 2 / ry ** 2;\n return normalizedX + normalizedY <= 1;\n }\n\n case 'poly': {\n if (coordinates.length < 6 || coordinates.length % 2 !== 0) {\n console.warn(`Invalid polygon definition: ${areaKey}`);\n return false;\n }\n const vertices = [];\n for (let i = 0; i < coordinates.length; i += 2) {\n vertices.push({ x: coordinates[i], y: coordinates[i + 1] });\n }\n return this.isPointInPolygon({ x: px, y: py }, vertices);\n }\n\n default:\n console.warn(`Unsupported shape type: ${shape}`);\n return false;\n }\n }\n\n /**\n * Checks if a point is inside a polygon using the ray-casting algorithm.\n * @param point The point to test.\n * @param vertices The vertices of the polygon in order (array of {x, y} objects).\n * @returns True if the point is inside the polygon; false otherwise.\n */\n static isPointInPolygon(point: { x: number; y: number }, vertices: { x: number; y: number }[]): boolean {\n let inside = false;\n for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {\n const xi = vertices[i].x,\n yi = vertices[i].y;\n const xj = vertices[j].x,\n yj = vertices[j].y;\n\n const intersect = yi > point.y !== yj > point.y && point.x < ((xj - xi) * (point.y - yi)) / (yj - yi) + xi;\n\n if (intersect) inside = !inside;\n }\n return inside;\n }\n\n public static compareSingleValues(value1: Readonly<string>, value2: Readonly<string>, baseType: BaseType): boolean {\n switch (baseType) {\n case 'identifier':\n case 'string':\n return value1 === value2;\n case 'integer': {\n const int1 = parseInt(value1, 10);\n const int2 = parseInt(value2, 10);\n if (!isNaN(int1) && !isNaN(int2)) {\n return int1 === int2;\n } else {\n console.error(`Cannot convert ${value1} and/or ${value2} to int.`);\n }\n break;\n }\n case 'float': {\n const float1 = parseFloat(value1);\n const float2 = parseFloat(value2);\n if (!isNaN(float1) && !isNaN(float2)) {\n return float1 === float2;\n } else {\n console.error(`couldn't convert ${value1} and/or ${value2} to float.`);\n }\n break;\n }\n case 'pair':\n case 'directedPair': {\n const pair1 = value1.split(' ').sort();\n const pair2 = value2.split(' ').sort();\n if (pair1.length === 2 && pair2.length === 2) {\n if (baseType === 'pair') {\n pair1.sort();\n pair2.sort();\n }\n return pair1.join(' ') === pair2.join(' ');\n } else {\n console.error(`compared two pair but one of the values does not have 2 values: 1: ${value1} 2: ${value2}`);\n }\n break;\n }\n }\n\n return false;\n }\n}\n","/**\n * Custom elements this package registers into an application's registry.\n *\n * Empty, deliberately. `qti-base` is abstractions and context — it contributes no elements to a\n * delivery application.\n *\n * The one entry that used to be here, `qti-config-test-provider`, is gone entirely. It was a\n * TEST-ONLY wrapper that every consumer of `import '@qti-components/base'` registered transitively,\n * and it carried `@customElement(...)` on top of this list — an UNGUARDED `customElements.define()`\n * at module-evaluation time. A module graph holding two copies of this package (a workspace build\n * alongside a published dist, which is what the editor resolves) evaluated it twice and the second\n * threw `NotSupportedError: ... already been used with this registry`, aborting module evaluation\n * and taking down every test file that imported it — 34 suites in the editor, none of which used\n * the element. `register.ts` had the guard right all along; the decorator bypassed it.\n *\n * Config for a single interaction is a property binding now — see config.context.ts.\n *\n * The array and `register.ts` stay so the elements + guarded-register convention the other 30\n * packages follow is already in place the day this package does own an element.\n */\nexport const qtiBaseElements: readonly { tag: string; ctor: CustomElementConstructor }[] = [];\n","import { qtiBaseElements } from './elements';\nimport { installCustomStateSetFallback } from './utils/custom-state-set';\n\n// Before any element is defined, so the patched `attachInternals` is in place by\n// the time the first interaction upgrades. No-op where `states` works natively.\ninstallCustomStateSetFallback();\n\nfor (const { tag, ctor } of qtiBaseElements) {\n if (!customElements.get(tag)) {\n customElements.define(tag, ctor);\n }\n}\n"],"mappings":"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","names":["state","createContext","createContext","createContext","createContext","createContext","createContext","createContext","css","css","state","LitElement","consume","css","html","LitElement","LitElement","css","html","__decorate","consume","consume","LitElement","property","state","LitElement","__decorate","property","consume","state","LitElement"]}
|
|
@@ -521,13 +521,13 @@ var qtiTransformItem = () => {
|
|
|
521
521
|
var qtiTransformManifest = () => {
|
|
522
522
|
let xmlFragment;
|
|
523
523
|
const api = {
|
|
524
|
+
// Awaits loadXML so a failed fetch (network, CORS, non-2xx) rejects this
|
|
525
|
+
// promise. Callers own the failure: they can render it, retry it or let it
|
|
526
|
+
// bubble — rather than it escaping as an unhandled rejection while their
|
|
527
|
+
// own `await` never settles.
|
|
524
528
|
async load(uri, signal) {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
xmlFragment = xml;
|
|
528
|
-
return resolve(api);
|
|
529
|
-
});
|
|
530
|
-
});
|
|
529
|
+
xmlFragment = await loadXML(uri, signal);
|
|
530
|
+
return api;
|
|
531
531
|
},
|
|
532
532
|
parse(xmlString) {
|
|
533
533
|
xmlFragment = parseXML(xmlString);
|
|
@@ -655,15 +655,15 @@ var qtiTransformTest = () => {
|
|
|
655
655
|
let xmlFragment;
|
|
656
656
|
let xmlUri = "";
|
|
657
657
|
const api = {
|
|
658
|
+
// Awaits loadXML so a failed fetch (network, CORS, non-2xx) rejects this
|
|
659
|
+
// promise. Callers own the failure: they can render it, retry it or let it
|
|
660
|
+
// bubble — rather than it escaping as an unhandled rejection while their
|
|
661
|
+
// own `await` never settles.
|
|
658
662
|
async load(uri, signal) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
api.path(uri.substring(0, uri.lastIndexOf("/")));
|
|
664
|
-
return resolve(api);
|
|
665
|
-
});
|
|
666
|
-
});
|
|
663
|
+
xmlFragment = await loadXML(uri, signal);
|
|
664
|
+
xmlUri = uri;
|
|
665
|
+
api.path(uri.substring(0, uri.lastIndexOf("/")));
|
|
666
|
+
return api;
|
|
667
667
|
},
|
|
668
668
|
parse(xmlString) {
|
|
669
669
|
xmlFragment = parseXML(xmlString);
|
|
@@ -716,4 +716,4 @@ export {
|
|
|
716
716
|
qtiTransformManifest,
|
|
717
717
|
qtiTransformTest
|
|
718
718
|
};
|
|
719
|
-
//# sourceMappingURL=chunk-
|
|
719
|
+
//# sourceMappingURL=chunk-HDEG6BAZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../qti-transformers/src/item/cdata.ts","../../qti-transformers/src/item/configure-pci.ts","../../qti-transformers/src/item/extend.ts","../../qti-transformers/src/item/pci-hooks.ts","../../qti-transformers/src/shared/prng.ts","../../qti-transformers/src/shared/shuffle.ts","../../qti-transformers/src/item/shuffle-interactions.ts","../../qti-transformers/src/item/stylesheets.ts","../../qti-transformers/src/shared/missing-seed-warning.ts","../../qti-transformers/src/shared/xml.ts","../../qti-transformers/src/qti-transform-item.ts","../../qti-transformers/src/qti-transform-manifest.ts","../../qti-transformers/src/test/items.ts","../../qti-transformers/src/test/shuffle-sections.ts","../../qti-transformers/src/qti-transform-test.ts"],"sourcesContent":["export function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n","// Type definition for module resolution config\nexport interface ModuleResolutionConfig {\n waitSeconds?: number;\n context?: string;\n catchError?: boolean;\n urlArgs?: string;\n paths: {\n [key: string]: string | string[];\n };\n shim?: {\n [key: string]: {\n deps?: string[]; // Array of dependencies\n exports?: string; // The global variable to use as the module's value\n };\n };\n}\n\nexport async function configurePci(\n xmlFragment: XMLDocument,\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector = 'qti-portable-custom-interaction'\n): Promise<void> {\n const customInteractionTypeIdentifiers: string[] = [];\n const portableCustomInteractions = xmlFragment.querySelectorAll(selector);\n\n // Avoid fetching module resolution configs for items that do not contain any PCIs.\n // This prevents unnecessary network requests when configurePci() is called for every item.\n if (portableCustomInteractions.length === 0) {\n return;\n }\n\n // Lazily load (and cache) the default module resolution configs.\n let moduleResolutionConfig: ModuleResolutionConfig | null = null;\n let moduleResolutionFallbackConfig: ModuleResolutionConfig | null = null;\n const ensureDefaultModuleResolutionConfigs = async () => {\n if (moduleResolutionConfig === null) {\n try {\n moduleResolutionConfig = await getModuleResolutionConfig(baseUrl, '/modules/module_resolution.js');\n } catch {\n moduleResolutionConfig = null;\n }\n }\n if (moduleResolutionFallbackConfig === null) {\n try {\n moduleResolutionFallbackConfig = await getModuleResolutionConfig(\n baseUrl,\n '/modules/fallback_module_resolution.js'\n );\n } catch {\n moduleResolutionFallbackConfig = null;\n }\n }\n };\n\n for (const interaction of Array.from(portableCustomInteractions)) {\n // set data-base-url\n interaction.setAttribute('data-base-url', baseUrl);\n\n let customInteractionTypeIdentifier = interaction.getAttribute('custom-interaction-type-identifier');\n if (customInteractionTypeIdentifier && customInteractionTypeIdentifiers.includes(customInteractionTypeIdentifier)) {\n customInteractionTypeIdentifier = customInteractionTypeIdentifier + customInteractionTypeIdentifiers.length;\n interaction.setAttribute('custom-interaction-type-identifier', customInteractionTypeIdentifier);\n customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);\n }\n if (customInteractionTypeIdentifier) {\n customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);\n }\n\n // Check if qti-interaction-modules already exists\n let modulesElement = interaction.querySelector('qti-interaction-modules');\n\n // If it exists and has primary-configuration, handle that format\n if (modulesElement && modulesElement.getAttribute('primary-configuration')) {\n await ensureDefaultModuleResolutionConfigs();\n const primaryConfigPath = modulesElement.getAttribute('primary-configuration');\n if (primaryConfigPath) {\n try {\n // Load the primary configuration\n const primaryConfig = await getModuleResolutionConfig(baseUrl, `/${primaryConfigPath}`);\n\n // Get existing module elements that only have id attributes\n const existingModules = Array.from(modulesElement.querySelectorAll('qti-interaction-module'));\n\n // Update existing modules with paths from config\n for (const moduleEl of existingModules) {\n const moduleId = moduleEl.getAttribute('id');\n if (moduleId && primaryConfig.paths && primaryConfig.paths[moduleId]) {\n const primaryPath = primaryConfig.paths[moduleId];\n const primaryPathString = Array.isArray(primaryPath) ? primaryPath[0] : primaryPath;\n moduleEl.setAttribute('primary-path', primaryPathString);\n\n // Check for fallback path\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[moduleId]\n ) {\n const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];\n if (Array.isArray(fallbackPath)) {\n moduleEl.setAttribute('fallback-path', fallbackPath[0]);\n } else {\n moduleEl.setAttribute('fallback-path', fallbackPath);\n }\n }\n }\n }\n\n // Add any additional modules from primary config that aren't already present\n if (primaryConfig.paths) {\n for (const moduleId in primaryConfig.paths) {\n const existingModule = modulesElement.querySelector(`qti-interaction-module[id=\"${moduleId}\"]`);\n if (!existingModule) {\n const newModuleElement = xmlFragment.createElement('qti-interaction-module');\n newModuleElement.setAttribute('id', moduleId);\n const primaryPathString = Array.isArray(primaryConfig.paths[moduleId])\n ? primaryConfig.paths[moduleId][0]\n : primaryConfig.paths[moduleId];\n newModuleElement.setAttribute('primary-path', primaryPathString);\n\n // Check for fallback path\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[moduleId]\n ) {\n const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];\n if (Array.isArray(fallbackPath)) {\n newModuleElement.setAttribute('fallback-path', fallbackPath[0]);\n } else {\n newModuleElement.setAttribute('fallback-path', fallbackPath);\n }\n }\n\n modulesElement.appendChild(newModuleElement);\n }\n }\n }\n\n // Apply urlArgs if present in config\n if (primaryConfig.urlArgs) {\n modulesElement.setAttribute('url-args', primaryConfig.urlArgs);\n }\n } catch (error) {\n console.warn(`Failed to load primary configuration: ${primaryConfigPath}`, error);\n }\n }\n } else {\n // Original logic for when there's no existing qti-interaction-modules or no primary-configuration\n await ensureDefaultModuleResolutionConfigs();\n if (moduleResolutionConfig) {\n // Create qti-interaction-modules if it doesn't exist\n if (interaction.querySelector('qti-interaction-modules') === null) {\n modulesElement = xmlFragment.createElement('qti-interaction-modules');\n interaction.appendChild(modulesElement);\n } else {\n modulesElement = interaction.querySelector('qti-interaction-modules');\n }\n\n for (const module in moduleResolutionConfig.paths) {\n const path = moduleResolutionConfig.paths[module];\n let fallbackPath: string | string[] = '';\n\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[module]\n ) {\n fallbackPath = moduleResolutionFallbackConfig.paths[module];\n }\n\n const primaryArray = Array.isArray(path) ? path : [path];\n const fallbackPathArray = Array.isArray(fallbackPath) ? fallbackPath : [fallbackPath];\n\n // create an array with primary and fallback paths.\n const paths = primaryArray.map((primaryPath, i) => {\n const fallbackPath = fallbackPathArray.length > i ? fallbackPathArray[i] : '';\n return {\n primaryPath,\n fallbackPath\n };\n });\n\n // check if all fallbackPath elements are in the array: paths, otherwise add\n for (const fallbackPath of fallbackPathArray) {\n if (!paths.some(p => p.fallbackPath === fallbackPath)) {\n paths.push({\n primaryPath: primaryArray.length > 0 ? primaryArray[0] : fallbackPath,\n fallbackPath\n });\n }\n }\n\n // add the paths to the qti-interaction-modules\n for (const path of paths) {\n const moduleElement = xmlFragment.createElement('qti-interaction-module');\n if (path.fallbackPath) {\n moduleElement.setAttribute('fallback-path', path.fallbackPath);\n }\n moduleElement.setAttribute('id', module);\n moduleElement.setAttribute('primary-path', path.primaryPath);\n\n if (modulesElement) {\n modulesElement.appendChild(moduleElement);\n }\n }\n }\n }\n }\n }\n}\n","// Function to extend elements with a specific tag name by adding an extension suffix\n// Uses localName matching to handle namespaced XML documents where querySelectorAll may not work\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n // Use getElementsByTagName with '*' to find all elements, then filter by localName\n // This works correctly for both namespaced and non-namespaced XML documents\n const allElements = Array.from(xmlFragment.getElementsByTagName('*'));\n const matchingElements = allElements.filter(\n element => element.localName === tagName || element.localName?.toLowerCase() === tagName.toLowerCase()\n );\n\n matchingElements.forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element: Element, newTagName: string) {\n // create Elements on the ownerDocument which is usually the XMLDocument\n const newElement = element.ownerDocument.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n","export function pciHooks(xmlFragment: XMLDocument, uri: string): void {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute('module', documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js')));\n }\n });\n }\n}\n","export interface SeededRandomSource {\n random(): number;\n}\n\n/**\n * Small, dependency-free seeded PRNG used for deterministic QTI shuffling\n * (sections and interactions). It intentionally exposes a `random()` method,\n * matching the TC39 seeded-random proposal shape so this can be swapped when a\n * standard implementation is available.\n *\n * xmur3-style seed hashing feeds mulberry32 (fast 32-bit generator).\n */\nexport class SeededRandom implements SeededRandomSource {\n #state: number;\n\n constructor(seed: Uint8Array) {\n if (!(seed instanceof Uint8Array)) {\n throw new TypeError('SeededRandom seed must be a Uint8Array.');\n }\n if (seed.length > 32) {\n throw new RangeError('SeededRandom seed must be 32 bytes or less.');\n }\n\n const paddedSeed = new Uint8Array(32);\n paddedSeed.set(seed, 32 - seed.length);\n this.#state = hashBytes(paddedSeed);\n }\n\n static fromSeed(seed: Uint8Array): SeededRandom {\n if (seed.length !== 32) {\n throw new RangeError('SeededRandom.fromSeed requires a 32-byte seed.');\n }\n return new SeededRandom(seed);\n }\n\n static fromFixed(byte: number): SeededRandom {\n if (typeof byte !== 'number') {\n throw new TypeError('SeededRandom.fromFixed requires a number.');\n }\n if (!Number.isInteger(byte) || byte < 0 || byte > 255) {\n throw new RangeError('SeededRandom.fromFixed requires an integer from 0 to 255.');\n }\n\n const seed = new Uint8Array(32);\n seed[31] = byte;\n return new SeededRandom(seed);\n }\n\n static fromSeedKey(seedKey: string | number): SeededRandom {\n const random = new SeededRandom(new Uint8Array());\n random.#state = hashString(`${seedKey}`);\n return random;\n }\n\n random(): number {\n this.#state |= 0;\n this.#state = (this.#state + 0x6d2b79f5) | 0;\n let t = Math.imul(this.#state ^ (this.#state >>> 15), 1 | this.#state);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n}\n\nexport function createSeededRandom(seedKey: string | number): SeededRandomSource {\n return SeededRandom.fromSeedKey(seedKey);\n}\n\nfunction hashString(seedKey: string): number {\n let h = 1779033703 ^ seedKey.length;\n for (let i = 0; i < seedKey.length; i++) {\n h = Math.imul(h ^ seedKey.charCodeAt(i), 3432918353);\n h = (h << 13) | (h >>> 19);\n }\n return finalizeHash(h);\n}\n\nfunction hashBytes(seed: Uint8Array): number {\n let h = 1779033703 ^ seed.length;\n for (let i = 0; i < seed.length; i++) {\n h = Math.imul(h ^ seed[i], 3432918353);\n h = (h << 13) | (h >>> 19);\n }\n return finalizeHash(h);\n}\n\nfunction finalizeHash(hash: number): number {\n let h = Math.imul(hash ^ (hash >>> 16), 2246822507);\n h = Math.imul(h ^ (h >>> 13), 3266489909);\n return (h ^ (h >>> 16)) >>> 0;\n}\n","import type { SeededRandomSource } from './prng';\n\nexport type RandomSource = SeededRandomSource | (() => number);\n\nconst randomValue = (source: RandomSource): number => (typeof source === 'function' ? source() : source.random());\n\n/**\n * Fisher-Yates over non-fixed units only. Fixed units keep their authored slot\n * index while movable units are shuffled into the remaining slots.\n */\nexport function shuffleKeepingFixed<T extends { fixed: boolean }>(units: T[], random: RandomSource): T[] {\n const movable = units.filter(unit => !unit.fixed);\n\n for (let i = movable.length - 1; i > 0; i--) {\n const j = Math.floor(randomValue(random) * (i + 1));\n [movable[i], movable[j]] = [movable[j], movable[i]];\n }\n\n let movableIndex = 0;\n return units.map(unit => (unit.fixed ? unit : movable[movableIndex++]));\n}\n","import { createSeededRandom } from '../shared/prng';\nimport { shuffleKeepingFixed } from '../shared/shuffle';\n\nfunction getShuffleQuerySelectorByTagName(tagName: string): string | string[] | null {\n switch (tagName) {\n case 'qti-choice-interaction':\n case 'qti-order-interaction':\n return 'qti-simple-choice';\n case 'qti-inline-choice-interaction':\n return 'qti-inline-choice';\n case 'qti-match-interaction':\n return [\n 'qti-simple-match-set:first-of-type qti-simple-associable-choice',\n 'qti-simple-match-set:last-of-type > qti-simple-associable-choice'\n ];\n case 'qti-gap-match-interaction':\n return 'qti-gap-text';\n case 'qti-associate-interaction':\n return 'qti-simple-associable-choice';\n default:\n return null;\n }\n}\n\n/**\n * Shuffles the choices inside every interaction marked `shuffle=\"true\"`. When\n * `seed` is supplied, shuffling is deterministic and reproducible across\n * reloads; each interaction/group draws its own stream so they are independent\n * and stable even if siblings change. When `seed` is null/undefined, falls back\n * to Math.random.\n */\nexport function shuffleInteractions(xmlFragment: XMLDocument, seed?: string | number | null): void {\n const shuffleElements = xmlFragment.querySelectorAll(`[shuffle=\"true\"]`);\n const shuffleInteractions = Array.from(shuffleElements).filter(e =>\n e.tagName?.toLowerCase().endsWith('-interaction')\n );\n\n const seeded = seed != null && `${seed}`.length > 0;\n const itemId = xmlFragment.querySelector?.('qti-assessment-item')?.getAttribute('identifier') ?? '';\n\n let interactionIndex = 0;\n for (const shuffleInteraction of shuffleInteractions) {\n const responseId = shuffleInteraction.getAttribute('response-identifier') ?? `${interactionIndex}`;\n interactionIndex++;\n const query = getShuffleQuerySelectorByTagName(shuffleInteraction.tagName.toLowerCase());\n const queries = Array.isArray(query) ? query : [query];\n let shuffledAny = false;\n\n let queryIndex = 0;\n for (const q of queries) {\n if (!q) continue;\n const random = seeded ? createSeededRandom(`${seed}:${itemId}:${responseId}:${queryIndex}`) : Math.random;\n queryIndex++;\n const choices = (Array.from(shuffleInteraction.querySelectorAll(q)) as HTMLElement[]).filter(\n choice => choice.parentElement !== null\n );\n\n if (choices.filter(choice => choice.getAttribute('fixed') !== 'true').length <= 1) {\n console.warn('Shuffling is not possible with fewer than 2 non-fixed elements.');\n continue;\n }\n\n const parent = choices[0].parentElement;\n if (!parent || choices.some(choice => choice.parentElement !== parent)) {\n console.warn('Shuffling is not possible when choices do not share the same parent element.');\n continue;\n }\n\n const anchor = choices[choices.length - 1].nextSibling;\n const orderedChoices = shuffleKeepingFixed(\n choices.map(choice => ({\n element: choice,\n fixed: choice.getAttribute('fixed') === 'true'\n })),\n random\n );\n\n for (const choice of choices) {\n choice.remove();\n }\n for (const { element } of orderedChoices) {\n parent.insertBefore(element, anchor);\n }\n\n shuffledAny = true;\n }\n\n if (shuffledAny) {\n shuffleInteraction.removeAttribute('shuffle');\n }\n }\n}\n","export function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n","/**\n * The missing-seed warning is advice about configuration, not about the document being\n * transformed — say it once per session, shared by the item and test transformers since\n * both are pointing at the same missing `QTI_CONTEXT.seed`.\n *\n * Deliberately not re-exported from the package entry: `resetMissingSeedWarning` exists so\n * tests can restore the once-per-session state, not as public API.\n */\nlet missingSeedWarned = false;\n\nexport function warnMissingSeed(scope: string, fallbackSeed: string): void {\n if (missingSeedWarned) return;\n missingSeedWarned = true;\n console.warn(`[${scope}] No QTI_CONTEXT.seed provided; using \"${fallbackSeed}\" as deterministic fallback seed.`);\n}\n\nexport function resetMissingSeedWarning(): void {\n missingSeedWarned = false;\n}\n","export function loadXML(url: string, signal?: AbortSignal): Promise<XMLDocument | null> {\n return fetch(url, { signal })\n .then(response => {\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return response.text();\n })\n .then(text => {\n const parser = new DOMParser();\n return parser.parseFromString(text, 'text/xml');\n })\n .catch(error => {\n if (error.name === 'AbortError') {\n throw error;\n }\n throw new Error(`Failed to load XML: ${error.message}`);\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\n// Function to strip unsupported namespaces (qti) from the nodes sent to the browser\nfunction stripNamespaces(node: Node, doc: Document, registry?: CustomElementRegistry): Node {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n let newEl: Element;\n\n if (\n !el.namespaceURI ||\n el.namespaceURI.startsWith('http://www.imsglobal.org/xsd/qti/') ||\n el.namespaceURI.startsWith('http://www.imsglobal.org/xsd/imsqti')\n ) {\n newEl = registry\n ? doc.createElement(el.localName, { customElementRegistry: registry })\n : doc.createElement(el.localName);\n } else {\n newEl = doc.createElementNS(el.namespaceURI, el.tagName);\n }\n\n for (let i = 0; i < el.attributes.length; i++) {\n const attr = el.attributes[i];\n newEl.setAttribute(attr.localName, attr.value);\n }\n for (let i = 0; i < el.childNodes.length; i++) {\n newEl.appendChild(stripNamespaces(el.childNodes[i], doc, registry));\n }\n return newEl;\n }\n return node.cloneNode(false);\n}\n\nexport function toHTML(xmlFragment: Document, registry?: CustomElementRegistry): DocumentFragment {\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < xmlFragment.childNodes.length; i++) {\n fragment.appendChild(stripNamespaces(xmlFragment.childNodes[i], document, registry));\n }\n return fragment;\n}\n\n// Updates src and href attributes with the base location\n// Uses querySelectorAll('*') to find all elements, then checks attributes manually\n// This handles namespaced XML documents where attribute selectors like [href] may not work\n// Note: primary-path is NOT processed here because it is resolved separately\n// by the PCI component using data-base-url in the iframe's module resolution\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n // querySelectorAll('*') finds all descendant elements regardless of namespace\n const allElements = xmlFragment.querySelectorAll('*');\n\n allElements.forEach(el => {\n // Check each attribute we care about\n // src, srcset and poster are URLDType or xs:anyURI everywhere they're used, so we care about them\n // Note: primary-path is excluded - PCI handles module path resolution via data-base-url\n for (const attr of ['src', 'href', 'srcset', 'poster'] as const) {\n const attrValue = el.getAttribute(attr)?.trim();\n\n if (attrValue && !/^(data:|https?:|blob:)/.test(attrValue)) {\n const newValue = location + encodeURI(attrValue);\n el.setAttribute(attr, newValue);\n }\n }\n });\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\nimport { convertCDATAtoComment } from './item/cdata';\nimport { configurePci, type ModuleResolutionConfig } from './item/configure-pci';\nimport { extendElementName, extendElementsWithClass } from './item/extend';\nimport { pciHooks } from './item/pci-hooks';\nimport { shuffleInteractions } from './item/shuffle-interactions';\nimport { stripStyleSheets } from './item/stylesheets';\nimport { warnMissingSeed } from './shared/missing-seed-warning';\nimport { loadXML, parseXML, setLocation, toHTML } from './shared/xml';\n\nexport type { ModuleResolutionConfig };\n\nexport type transformItemApi = {\n load: (uri: string, signal?: AbortSignal) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n configurePci: (\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector?: string\n ) => Promise<transformItemApi>;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n shuffleInteractions: (seed?: string | number | null) => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: (registry?: CustomElementRegistry) => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = () => {\n let xmlFragment: XMLDocument;\n let xmlUri = '';\n\n const api: transformItemApi = {\n load(uri: string, signal?: AbortSignal) {\n xmlUri = uri;\n return loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n return api;\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n xmlUri = '';\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n xmlUri = null;\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n pciHooks(xmlFragment, uri);\n return api;\n },\n async configurePci(\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector = 'qti-portable-custom-interaction'\n ): Promise<typeof api> {\n await configurePci(xmlFragment, baseUrl, getModuleResolutionConfig, selector);\n return api;\n },\n shuffleInteractions(seed?: string | number | null): typeof api {\n const normalizedSeed = typeof seed === 'string' ? seed.trim() : seed;\n\n if (normalizedSeed === null || normalizedSeed === undefined || normalizedSeed === '') {\n const fallbackSeed = xmlUri || 'default-item-seed';\n warnMissingSeed('qtiTransformItem', fallbackSeed);\n shuffleInteractions(xmlFragment, fallbackSeed);\n return api;\n }\n\n shuffleInteractions(xmlFragment, normalizedSeed);\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n if (xmlUri !== null) {\n setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf('/')));\n }\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc(registry?: CustomElementRegistry) {\n if (xmlUri !== null) {\n setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf('/')));\n }\n return toHTML(xmlFragment, registry);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './shared/xml';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string, signal?: AbortSignal) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n async load(uri: string, signal: AbortSignal) {\n return new Promise<typeof api>(resolve => {\n loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","export function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n","import { createSeededRandom } from '../shared/prng';\nimport { shuffleKeepingFixed } from '../shared/shuffle';\n\nconst isLocal = (el: Element, ...names: string[]): boolean =>\n names.includes(el.localName) || names.includes(el.localName?.toLowerCase?.());\n\nconst isItemRef = (el: Element): boolean => isLocal(el, 'qti-assessment-item-ref', 'assessmentitemref');\n\nconst isSection = (el: Element): boolean => isLocal(el, 'qti-assessment-section', 'assessmentsection');\n\nconst attrIsTrue = (el: Element, ...names: string[]): boolean =>\n names.some(n => {\n const v = (el.getAttribute(n) ?? '').trim().toLowerCase();\n return v === 'true' || v === '1';\n });\n\nconst attrIsFalse = (el: Element, ...names: string[]): boolean =>\n names.some(n => {\n const v = (el.getAttribute(n) ?? '').trim().toLowerCase();\n return v === 'false' || v === '0';\n });\n\nconst isOrdering = (el: Element): boolean => isLocal(el, 'qti-ordering', 'ordering');\n\nconst isSelection = (el: Element): boolean => isLocal(el, 'qti-selection', 'selection');\n\nconst shuffleOrderingElements = (section: Element): Element[] =>\n Array.from(section.children).filter(child => isOrdering(child) && attrIsTrue(child, 'shuffle'));\n\nconst rngFor = (seed: string | number, key: string) => createSeededRandom(`${seed}:${key}`);\n\n/** A movable unit in a section: one or more sibling nodes that move together. */\ntype Unit = { nodes: Element[]; fixed: boolean };\n\n/**\n * The item refs of a subsection, in document order, plus the element children\n * that consuming the wrapper would discard.\n *\n * Descendant subsections are collected transitively: `orderSection` returns\n * early for a section without <qti-ordering>, so a wrapper nested inside a\n * non-shuffling subsection is never consumed there and has to be gathered here.\n */\nfunction collectItemRefsDeep(section: Element): { itemRefs: Element[]; dropped: string[] } {\n const itemRefs: Element[] = [];\n const dropped: string[] = [];\n\n const walk = (el: Element): void => {\n for (const child of Array.from(el.children)) {\n if (isItemRef(child)) {\n itemRefs.push(child);\n } else if (isSection(child)) {\n walk(child);\n } else if (!isOrdering(child) && !isSelection(child)) {\n // Ordering/selection directives are transform config; anything else\n // (a rubric block, say) is authored content that the lift loses.\n dropped.push(child.localName);\n }\n }\n };\n walk(section);\n\n return { itemRefs, dropped };\n}\n\nfunction warnDroppedChildren(section: Element, dropped: string[]): void {\n if (dropped.length === 0) return;\n const identifier = section.getAttribute('identifier') ?? '(no identifier)';\n console.warn(\n `[qtiTransformTest] Subsection \"${identifier}\" is consumed by section ordering; ` +\n `discarding its ${[...new Set(dropped)].join(', ')}.`\n );\n}\n\n/**\n * Seed-deterministic QTI section shuffling.\n *\n * Reorders the children of every <qti-assessment-section> that carries a\n * <qti-ordering shuffle=\"true\">, following QTI 3.0 ordering rules:\n *\n * - Depth-first: a subsection orders its own children before the parent\n * reorders it.\n * - Item refs with fixed=\"true\" stay in their authored position; the other\n * units shuffle around them.\n * - A subsection is a grouping device, not a delivered section: its item refs\n * are lifted into the parent and the wrapper is consumed, just as the\n * <qti-ordering> directive itself is. Nothing nested survives into the DOM,\n * so the player only ever sees the authored top-level sections.\n * - By default (QTI 3.0 defaults keep-together to true) a subsection travels as\n * one unit: its items stay contiguous and keep their authored order, while\n * the parent's remaining items shuffle around the block. Add fixed=\"true\" to\n * pin the block itself to its authored slot.\n * - Only an explicit keep-together=\"false\" dissolves a subsection: its\n * (already internally ordered) item refs are poured into the parent pool and\n * interleaved with the parent's own units.\n *\n * The same `seed` always produces the same order, so a restarted session keeps\n * its sequence. Each section draws from its own PRNG stream (seed + section id)\n * so sibling sections are independent and stable.\n */\nfunction orderSection(section: Element, seed: string | number): void {\n // Depth-first: let every child section order itself first.\n for (const child of Array.from(section.children)) {\n if (isSection(child)) {\n orderSection(child, seed);\n }\n }\n\n const orderingEls = shuffleOrderingElements(section);\n if (orderingEls.length === 0) {\n return;\n }\n\n // Build the pool of movable units in document order. Config/structural\n // children (qti-ordering, qti-selection, rubric-block, …) are left in place.\n const units: Unit[] = [];\n const toDetach: Element[] = [];\n\n for (const child of Array.from(section.children)) {\n if (isItemRef(child)) {\n units.push({ nodes: [child], fixed: attrIsTrue(child, 'fixed') });\n toDetach.push(child);\n } else if (isSection(child)) {\n // Internal order is already settled: the depth-first pass above shuffled\n // this subsection if it carried its own <qti-ordering shuffle=\"true\">, and\n // left the authored order alone otherwise.\n const { itemRefs, dropped } = collectItemRefsDeep(child);\n warnDroppedChildren(child, dropped);\n\n if (attrIsFalse(child, 'keep-together', 'keeptogether')) {\n // Explicitly dissolved: the items join the parent pool individually and\n // interleave with the parent's own items.\n for (const itemRef of itemRefs) {\n units.push({ nodes: [itemRef], fixed: attrIsTrue(itemRef, 'fixed') });\n }\n } else if (itemRefs.length > 0) {\n // One multi-node unit, so the items stay contiguous and keep their order\n // wherever the block lands.\n units.push({ nodes: itemRefs, fixed: attrIsTrue(child, 'fixed') });\n }\n\n toDetach.push(child); // the grouping wrapper is consumed\n }\n }\n\n // Where the reordered units go back in: after the last node we took out, so\n // any trailing structural children (a rubric block, say) keep their position.\n // Captured before detaching, and never itself a detached node.\n const anchor = toDetach.length > 0 ? toDetach[toDetach.length - 1].nextSibling : null;\n\n const sectionKey = section.getAttribute('identifier') ?? '';\n // A no-op for 0 or 1 movable units, but the re-insertion below still has to\n // run so consumed wrappers are lifted rather than left in the DOM.\n const ordered = shuffleKeepingFixed(units, rngFor(seed, sectionKey));\n\n for (const el of toDetach) {\n el.remove();\n }\n for (const unit of ordered) {\n for (const node of unit.nodes) {\n section.insertBefore(node, anchor);\n }\n }\n\n // Ordering directives are consumed by this transform step.\n for (const orderingEl of orderingEls) {\n orderingEl.remove();\n }\n}\n\n/** Whether anything in `doc` asks to be shuffled at all. */\nexport function hasShuffleOrdering(doc: XMLDocument): boolean {\n return Array.from(doc.getElementsByTagName('*')).some(el => isOrdering(el) && attrIsTrue(el, 'shuffle'));\n}\n\n/**\n * Mutates `doc` in place: shuffles every section flagged with\n * <qti-ordering shuffle=\"true\">, deterministically from `seed`.\n */\nexport function shuffleSectionsOrdering(doc: XMLDocument, seed: string | number): void {\n const sections = Array.from(doc.getElementsByTagName('*')).filter(el => isSection(el));\n // Kick off recursion only for top-level sections; orderSection handles nesting\n // depth-first, so descendants are not double-processed.\n for (const section of sections) {\n // The snapshot above can contain wrappers that an ancestor has since\n // consumed. A detached element has no parentNode; a document element still\n // has one (the document), so this does not skip a section-rooted document.\n if (!section.parentNode) continue;\n\n const parent = section.parentElement;\n if (parent && isSection(parent)) continue;\n\n orderSection(section, seed);\n }\n}\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { warnMissingSeed } from './shared/missing-seed-warning';\nimport { loadXML, parseXML, setLocation, toHTML } from './shared/xml';\nimport { itemsFromTest } from './test/items';\nimport { hasShuffleOrdering, shuffleSectionsOrdering } from './test/shuffle-sections';\n\nexport type transformTestApi = {\n load: (uri: string, signal?: AbortSignal) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n path: (location: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n /**\n * Deterministically shuffle the children of every section that carries a\n * <qti-ordering shuffle=\"true\">, honoring fixed items and nested\n * keep-together / visible rules. The same seed reproduces the same order.\n */\n shuffleOrdering: (seed?: string | number | null) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: (registry?: CustomElementRegistry) => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n let xmlUri = '';\n\n const api: transformTestApi = {\n async load(uri, signal) {\n return new Promise<transformTestApi>((resolve, _) => {\n loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n xmlUri = uri;\n\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n xmlUri = '';\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n shuffleOrdering(seed?: string | number | null) {\n // No section asks to be shuffled: leave the test alone, and stay quiet\n // about a missing seed that would never have been used.\n if (!hasShuffleOrdering(xmlFragment)) {\n return api;\n }\n\n const normalizedSeed = typeof seed === 'string' ? seed.trim() : seed;\n\n if (normalizedSeed === null || normalizedSeed === undefined || normalizedSeed === '') {\n const fallbackSeed = xmlUri || 'default-test-seed';\n warnMissingSeed('qtiTransformTest', fallbackSeed);\n shuffleSectionsOrdering(xmlFragment, fallbackSeed);\n return api;\n }\n\n shuffleSectionsOrdering(xmlFragment, normalizedSeed);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc(registry?: CustomElementRegistry) {\n return toHTML(xmlFragment, registry);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n"],"mappings":"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","names":["fallbackPath","path","shuffleInteractions"]}
|
|
1
|
+
{"version":3,"sources":["../../qti-transformers/src/item/cdata.ts","../../qti-transformers/src/item/configure-pci.ts","../../qti-transformers/src/item/extend.ts","../../qti-transformers/src/item/pci-hooks.ts","../../qti-transformers/src/shared/prng.ts","../../qti-transformers/src/shared/shuffle.ts","../../qti-transformers/src/item/shuffle-interactions.ts","../../qti-transformers/src/item/stylesheets.ts","../../qti-transformers/src/shared/missing-seed-warning.ts","../../qti-transformers/src/shared/xml.ts","../../qti-transformers/src/qti-transform-item.ts","../../qti-transformers/src/qti-transform-manifest.ts","../../qti-transformers/src/test/items.ts","../../qti-transformers/src/test/shuffle-sections.ts","../../qti-transformers/src/qti-transform-test.ts"],"sourcesContent":["export function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n","// Type definition for module resolution config\nexport interface ModuleResolutionConfig {\n waitSeconds?: number;\n context?: string;\n catchError?: boolean;\n urlArgs?: string;\n paths: {\n [key: string]: string | string[];\n };\n shim?: {\n [key: string]: {\n deps?: string[]; // Array of dependencies\n exports?: string; // The global variable to use as the module's value\n };\n };\n}\n\nexport async function configurePci(\n xmlFragment: XMLDocument,\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector = 'qti-portable-custom-interaction'\n): Promise<void> {\n const customInteractionTypeIdentifiers: string[] = [];\n const portableCustomInteractions = xmlFragment.querySelectorAll(selector);\n\n // Avoid fetching module resolution configs for items that do not contain any PCIs.\n // This prevents unnecessary network requests when configurePci() is called for every item.\n if (portableCustomInteractions.length === 0) {\n return;\n }\n\n // Lazily load (and cache) the default module resolution configs.\n let moduleResolutionConfig: ModuleResolutionConfig | null = null;\n let moduleResolutionFallbackConfig: ModuleResolutionConfig | null = null;\n const ensureDefaultModuleResolutionConfigs = async () => {\n if (moduleResolutionConfig === null) {\n try {\n moduleResolutionConfig = await getModuleResolutionConfig(baseUrl, '/modules/module_resolution.js');\n } catch {\n moduleResolutionConfig = null;\n }\n }\n if (moduleResolutionFallbackConfig === null) {\n try {\n moduleResolutionFallbackConfig = await getModuleResolutionConfig(\n baseUrl,\n '/modules/fallback_module_resolution.js'\n );\n } catch {\n moduleResolutionFallbackConfig = null;\n }\n }\n };\n\n for (const interaction of Array.from(portableCustomInteractions)) {\n // set data-base-url\n interaction.setAttribute('data-base-url', baseUrl);\n\n let customInteractionTypeIdentifier = interaction.getAttribute('custom-interaction-type-identifier');\n if (customInteractionTypeIdentifier && customInteractionTypeIdentifiers.includes(customInteractionTypeIdentifier)) {\n customInteractionTypeIdentifier = customInteractionTypeIdentifier + customInteractionTypeIdentifiers.length;\n interaction.setAttribute('custom-interaction-type-identifier', customInteractionTypeIdentifier);\n customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);\n }\n if (customInteractionTypeIdentifier) {\n customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);\n }\n\n // Check if qti-interaction-modules already exists\n let modulesElement = interaction.querySelector('qti-interaction-modules');\n\n // If it exists and has primary-configuration, handle that format\n if (modulesElement && modulesElement.getAttribute('primary-configuration')) {\n await ensureDefaultModuleResolutionConfigs();\n const primaryConfigPath = modulesElement.getAttribute('primary-configuration');\n if (primaryConfigPath) {\n try {\n // Load the primary configuration\n const primaryConfig = await getModuleResolutionConfig(baseUrl, `/${primaryConfigPath}`);\n\n // Get existing module elements that only have id attributes\n const existingModules = Array.from(modulesElement.querySelectorAll('qti-interaction-module'));\n\n // Update existing modules with paths from config\n for (const moduleEl of existingModules) {\n const moduleId = moduleEl.getAttribute('id');\n if (moduleId && primaryConfig.paths && primaryConfig.paths[moduleId]) {\n const primaryPath = primaryConfig.paths[moduleId];\n const primaryPathString = Array.isArray(primaryPath) ? primaryPath[0] : primaryPath;\n moduleEl.setAttribute('primary-path', primaryPathString);\n\n // Check for fallback path\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[moduleId]\n ) {\n const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];\n if (Array.isArray(fallbackPath)) {\n moduleEl.setAttribute('fallback-path', fallbackPath[0]);\n } else {\n moduleEl.setAttribute('fallback-path', fallbackPath);\n }\n }\n }\n }\n\n // Add any additional modules from primary config that aren't already present\n if (primaryConfig.paths) {\n for (const moduleId in primaryConfig.paths) {\n const existingModule = modulesElement.querySelector(`qti-interaction-module[id=\"${moduleId}\"]`);\n if (!existingModule) {\n const newModuleElement = xmlFragment.createElement('qti-interaction-module');\n newModuleElement.setAttribute('id', moduleId);\n const primaryPathString = Array.isArray(primaryConfig.paths[moduleId])\n ? primaryConfig.paths[moduleId][0]\n : primaryConfig.paths[moduleId];\n newModuleElement.setAttribute('primary-path', primaryPathString);\n\n // Check for fallback path\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[moduleId]\n ) {\n const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];\n if (Array.isArray(fallbackPath)) {\n newModuleElement.setAttribute('fallback-path', fallbackPath[0]);\n } else {\n newModuleElement.setAttribute('fallback-path', fallbackPath);\n }\n }\n\n modulesElement.appendChild(newModuleElement);\n }\n }\n }\n\n // Apply urlArgs if present in config\n if (primaryConfig.urlArgs) {\n modulesElement.setAttribute('url-args', primaryConfig.urlArgs);\n }\n } catch (error) {\n console.warn(`Failed to load primary configuration: ${primaryConfigPath}`, error);\n }\n }\n } else {\n // Original logic for when there's no existing qti-interaction-modules or no primary-configuration\n await ensureDefaultModuleResolutionConfigs();\n if (moduleResolutionConfig) {\n // Create qti-interaction-modules if it doesn't exist\n if (interaction.querySelector('qti-interaction-modules') === null) {\n modulesElement = xmlFragment.createElement('qti-interaction-modules');\n interaction.appendChild(modulesElement);\n } else {\n modulesElement = interaction.querySelector('qti-interaction-modules');\n }\n\n for (const module in moduleResolutionConfig.paths) {\n const path = moduleResolutionConfig.paths[module];\n let fallbackPath: string | string[] = '';\n\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[module]\n ) {\n fallbackPath = moduleResolutionFallbackConfig.paths[module];\n }\n\n const primaryArray = Array.isArray(path) ? path : [path];\n const fallbackPathArray = Array.isArray(fallbackPath) ? fallbackPath : [fallbackPath];\n\n // create an array with primary and fallback paths.\n const paths = primaryArray.map((primaryPath, i) => {\n const fallbackPath = fallbackPathArray.length > i ? fallbackPathArray[i] : '';\n return {\n primaryPath,\n fallbackPath\n };\n });\n\n // check if all fallbackPath elements are in the array: paths, otherwise add\n for (const fallbackPath of fallbackPathArray) {\n if (!paths.some(p => p.fallbackPath === fallbackPath)) {\n paths.push({\n primaryPath: primaryArray.length > 0 ? primaryArray[0] : fallbackPath,\n fallbackPath\n });\n }\n }\n\n // add the paths to the qti-interaction-modules\n for (const path of paths) {\n const moduleElement = xmlFragment.createElement('qti-interaction-module');\n if (path.fallbackPath) {\n moduleElement.setAttribute('fallback-path', path.fallbackPath);\n }\n moduleElement.setAttribute('id', module);\n moduleElement.setAttribute('primary-path', path.primaryPath);\n\n if (modulesElement) {\n modulesElement.appendChild(moduleElement);\n }\n }\n }\n }\n }\n }\n}\n","// Function to extend elements with a specific tag name by adding an extension suffix\n// Uses localName matching to handle namespaced XML documents where querySelectorAll may not work\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n // Use getElementsByTagName with '*' to find all elements, then filter by localName\n // This works correctly for both namespaced and non-namespaced XML documents\n const allElements = Array.from(xmlFragment.getElementsByTagName('*'));\n const matchingElements = allElements.filter(\n element => element.localName === tagName || element.localName?.toLowerCase() === tagName.toLowerCase()\n );\n\n matchingElements.forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element: Element, newTagName: string) {\n // create Elements on the ownerDocument which is usually the XMLDocument\n const newElement = element.ownerDocument.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n","export function pciHooks(xmlFragment: XMLDocument, uri: string): void {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute('module', documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js')));\n }\n });\n }\n}\n","export interface SeededRandomSource {\n random(): number;\n}\n\n/**\n * Small, dependency-free seeded PRNG used for deterministic QTI shuffling\n * (sections and interactions). It intentionally exposes a `random()` method,\n * matching the TC39 seeded-random proposal shape so this can be swapped when a\n * standard implementation is available.\n *\n * xmur3-style seed hashing feeds mulberry32 (fast 32-bit generator).\n */\nexport class SeededRandom implements SeededRandomSource {\n #state: number;\n\n constructor(seed: Uint8Array) {\n if (!(seed instanceof Uint8Array)) {\n throw new TypeError('SeededRandom seed must be a Uint8Array.');\n }\n if (seed.length > 32) {\n throw new RangeError('SeededRandom seed must be 32 bytes or less.');\n }\n\n const paddedSeed = new Uint8Array(32);\n paddedSeed.set(seed, 32 - seed.length);\n this.#state = hashBytes(paddedSeed);\n }\n\n static fromSeed(seed: Uint8Array): SeededRandom {\n if (seed.length !== 32) {\n throw new RangeError('SeededRandom.fromSeed requires a 32-byte seed.');\n }\n return new SeededRandom(seed);\n }\n\n static fromFixed(byte: number): SeededRandom {\n if (typeof byte !== 'number') {\n throw new TypeError('SeededRandom.fromFixed requires a number.');\n }\n if (!Number.isInteger(byte) || byte < 0 || byte > 255) {\n throw new RangeError('SeededRandom.fromFixed requires an integer from 0 to 255.');\n }\n\n const seed = new Uint8Array(32);\n seed[31] = byte;\n return new SeededRandom(seed);\n }\n\n static fromSeedKey(seedKey: string | number): SeededRandom {\n const random = new SeededRandom(new Uint8Array());\n random.#state = hashString(`${seedKey}`);\n return random;\n }\n\n random(): number {\n this.#state |= 0;\n this.#state = (this.#state + 0x6d2b79f5) | 0;\n let t = Math.imul(this.#state ^ (this.#state >>> 15), 1 | this.#state);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n}\n\nexport function createSeededRandom(seedKey: string | number): SeededRandomSource {\n return SeededRandom.fromSeedKey(seedKey);\n}\n\nfunction hashString(seedKey: string): number {\n let h = 1779033703 ^ seedKey.length;\n for (let i = 0; i < seedKey.length; i++) {\n h = Math.imul(h ^ seedKey.charCodeAt(i), 3432918353);\n h = (h << 13) | (h >>> 19);\n }\n return finalizeHash(h);\n}\n\nfunction hashBytes(seed: Uint8Array): number {\n let h = 1779033703 ^ seed.length;\n for (let i = 0; i < seed.length; i++) {\n h = Math.imul(h ^ seed[i], 3432918353);\n h = (h << 13) | (h >>> 19);\n }\n return finalizeHash(h);\n}\n\nfunction finalizeHash(hash: number): number {\n let h = Math.imul(hash ^ (hash >>> 16), 2246822507);\n h = Math.imul(h ^ (h >>> 13), 3266489909);\n return (h ^ (h >>> 16)) >>> 0;\n}\n","import type { SeededRandomSource } from './prng';\n\nexport type RandomSource = SeededRandomSource | (() => number);\n\nconst randomValue = (source: RandomSource): number => (typeof source === 'function' ? source() : source.random());\n\n/**\n * Fisher-Yates over non-fixed units only. Fixed units keep their authored slot\n * index while movable units are shuffled into the remaining slots.\n */\nexport function shuffleKeepingFixed<T extends { fixed: boolean }>(units: T[], random: RandomSource): T[] {\n const movable = units.filter(unit => !unit.fixed);\n\n for (let i = movable.length - 1; i > 0; i--) {\n const j = Math.floor(randomValue(random) * (i + 1));\n [movable[i], movable[j]] = [movable[j], movable[i]];\n }\n\n let movableIndex = 0;\n return units.map(unit => (unit.fixed ? unit : movable[movableIndex++]));\n}\n","import { createSeededRandom } from '../shared/prng';\nimport { shuffleKeepingFixed } from '../shared/shuffle';\n\nfunction getShuffleQuerySelectorByTagName(tagName: string): string | string[] | null {\n switch (tagName) {\n case 'qti-choice-interaction':\n case 'qti-order-interaction':\n return 'qti-simple-choice';\n case 'qti-inline-choice-interaction':\n return 'qti-inline-choice';\n case 'qti-match-interaction':\n return [\n 'qti-simple-match-set:first-of-type qti-simple-associable-choice',\n 'qti-simple-match-set:last-of-type > qti-simple-associable-choice'\n ];\n case 'qti-gap-match-interaction':\n return 'qti-gap-text';\n case 'qti-associate-interaction':\n return 'qti-simple-associable-choice';\n default:\n return null;\n }\n}\n\n/**\n * Shuffles the choices inside every interaction marked `shuffle=\"true\"`. When\n * `seed` is supplied, shuffling is deterministic and reproducible across\n * reloads; each interaction/group draws its own stream so they are independent\n * and stable even if siblings change. When `seed` is null/undefined, falls back\n * to Math.random.\n */\nexport function shuffleInteractions(xmlFragment: XMLDocument, seed?: string | number | null): void {\n const shuffleElements = xmlFragment.querySelectorAll(`[shuffle=\"true\"]`);\n const shuffleInteractions = Array.from(shuffleElements).filter(e =>\n e.tagName?.toLowerCase().endsWith('-interaction')\n );\n\n const seeded = seed != null && `${seed}`.length > 0;\n const itemId = xmlFragment.querySelector?.('qti-assessment-item')?.getAttribute('identifier') ?? '';\n\n let interactionIndex = 0;\n for (const shuffleInteraction of shuffleInteractions) {\n const responseId = shuffleInteraction.getAttribute('response-identifier') ?? `${interactionIndex}`;\n interactionIndex++;\n const query = getShuffleQuerySelectorByTagName(shuffleInteraction.tagName.toLowerCase());\n const queries = Array.isArray(query) ? query : [query];\n let shuffledAny = false;\n\n let queryIndex = 0;\n for (const q of queries) {\n if (!q) continue;\n const random = seeded ? createSeededRandom(`${seed}:${itemId}:${responseId}:${queryIndex}`) : Math.random;\n queryIndex++;\n const choices = (Array.from(shuffleInteraction.querySelectorAll(q)) as HTMLElement[]).filter(\n choice => choice.parentElement !== null\n );\n\n if (choices.filter(choice => choice.getAttribute('fixed') !== 'true').length <= 1) {\n console.warn('Shuffling is not possible with fewer than 2 non-fixed elements.');\n continue;\n }\n\n const parent = choices[0].parentElement;\n if (!parent || choices.some(choice => choice.parentElement !== parent)) {\n console.warn('Shuffling is not possible when choices do not share the same parent element.');\n continue;\n }\n\n const anchor = choices[choices.length - 1].nextSibling;\n const orderedChoices = shuffleKeepingFixed(\n choices.map(choice => ({\n element: choice,\n fixed: choice.getAttribute('fixed') === 'true'\n })),\n random\n );\n\n for (const choice of choices) {\n choice.remove();\n }\n for (const { element } of orderedChoices) {\n parent.insertBefore(element, anchor);\n }\n\n shuffledAny = true;\n }\n\n if (shuffledAny) {\n shuffleInteraction.removeAttribute('shuffle');\n }\n }\n}\n","export function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n","/**\n * The missing-seed warning is advice about configuration, not about the document being\n * transformed — say it once per session, shared by the item and test transformers since\n * both are pointing at the same missing `QTI_CONTEXT.seed`.\n *\n * Deliberately not re-exported from the package entry: `resetMissingSeedWarning` exists so\n * tests can restore the once-per-session state, not as public API.\n */\nlet missingSeedWarned = false;\n\nexport function warnMissingSeed(scope: string, fallbackSeed: string): void {\n if (missingSeedWarned) return;\n missingSeedWarned = true;\n console.warn(`[${scope}] No QTI_CONTEXT.seed provided; using \"${fallbackSeed}\" as deterministic fallback seed.`);\n}\n\nexport function resetMissingSeedWarning(): void {\n missingSeedWarned = false;\n}\n","export function loadXML(url: string, signal?: AbortSignal): Promise<XMLDocument | null> {\n return fetch(url, { signal })\n .then(response => {\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return response.text();\n })\n .then(text => {\n const parser = new DOMParser();\n return parser.parseFromString(text, 'text/xml');\n })\n .catch(error => {\n if (error.name === 'AbortError') {\n throw error;\n }\n throw new Error(`Failed to load XML: ${error.message}`);\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\n// Function to strip unsupported namespaces (qti) from the nodes sent to the browser\nfunction stripNamespaces(node: Node, doc: Document, registry?: CustomElementRegistry): Node {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n let newEl: Element;\n\n if (\n !el.namespaceURI ||\n el.namespaceURI.startsWith('http://www.imsglobal.org/xsd/qti/') ||\n el.namespaceURI.startsWith('http://www.imsglobal.org/xsd/imsqti')\n ) {\n newEl = registry\n ? doc.createElement(el.localName, { customElementRegistry: registry })\n : doc.createElement(el.localName);\n } else {\n newEl = doc.createElementNS(el.namespaceURI, el.tagName);\n }\n\n for (let i = 0; i < el.attributes.length; i++) {\n const attr = el.attributes[i];\n newEl.setAttribute(attr.localName, attr.value);\n }\n for (let i = 0; i < el.childNodes.length; i++) {\n newEl.appendChild(stripNamespaces(el.childNodes[i], doc, registry));\n }\n return newEl;\n }\n return node.cloneNode(false);\n}\n\nexport function toHTML(xmlFragment: Document, registry?: CustomElementRegistry): DocumentFragment {\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < xmlFragment.childNodes.length; i++) {\n fragment.appendChild(stripNamespaces(xmlFragment.childNodes[i], document, registry));\n }\n return fragment;\n}\n\n// Updates src and href attributes with the base location\n// Uses querySelectorAll('*') to find all elements, then checks attributes manually\n// This handles namespaced XML documents where attribute selectors like [href] may not work\n// Note: primary-path is NOT processed here because it is resolved separately\n// by the PCI component using data-base-url in the iframe's module resolution\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n // querySelectorAll('*') finds all descendant elements regardless of namespace\n const allElements = xmlFragment.querySelectorAll('*');\n\n allElements.forEach(el => {\n // Check each attribute we care about\n // src, srcset and poster are URLDType or xs:anyURI everywhere they're used, so we care about them\n // Note: primary-path is excluded - PCI handles module path resolution via data-base-url\n for (const attr of ['src', 'href', 'srcset', 'poster'] as const) {\n const attrValue = el.getAttribute(attr)?.trim();\n\n if (attrValue && !/^(data:|https?:|blob:)/.test(attrValue)) {\n const newValue = location + encodeURI(attrValue);\n el.setAttribute(attr, newValue);\n }\n }\n });\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\nimport { convertCDATAtoComment } from './item/cdata';\nimport { configurePci, type ModuleResolutionConfig } from './item/configure-pci';\nimport { extendElementName, extendElementsWithClass } from './item/extend';\nimport { pciHooks } from './item/pci-hooks';\nimport { shuffleInteractions } from './item/shuffle-interactions';\nimport { stripStyleSheets } from './item/stylesheets';\nimport { warnMissingSeed } from './shared/missing-seed-warning';\nimport { loadXML, parseXML, setLocation, toHTML } from './shared/xml';\n\nexport type { ModuleResolutionConfig };\n\nexport type transformItemApi = {\n load: (uri: string, signal?: AbortSignal) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n configurePci: (\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector?: string\n ) => Promise<transformItemApi>;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n shuffleInteractions: (seed?: string | number | null) => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: (registry?: CustomElementRegistry) => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = () => {\n let xmlFragment: XMLDocument;\n let xmlUri = '';\n\n const api: transformItemApi = {\n load(uri: string, signal?: AbortSignal) {\n xmlUri = uri;\n return loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n return api;\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n xmlUri = '';\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n xmlUri = null;\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n pciHooks(xmlFragment, uri);\n return api;\n },\n async configurePci(\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector = 'qti-portable-custom-interaction'\n ): Promise<typeof api> {\n await configurePci(xmlFragment, baseUrl, getModuleResolutionConfig, selector);\n return api;\n },\n shuffleInteractions(seed?: string | number | null): typeof api {\n const normalizedSeed = typeof seed === 'string' ? seed.trim() : seed;\n\n if (normalizedSeed === null || normalizedSeed === undefined || normalizedSeed === '') {\n const fallbackSeed = xmlUri || 'default-item-seed';\n warnMissingSeed('qtiTransformItem', fallbackSeed);\n shuffleInteractions(xmlFragment, fallbackSeed);\n return api;\n }\n\n shuffleInteractions(xmlFragment, normalizedSeed);\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n if (xmlUri !== null) {\n setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf('/')));\n }\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc(registry?: CustomElementRegistry) {\n if (xmlUri !== null) {\n setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf('/')));\n }\n return toHTML(xmlFragment, registry);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './shared/xml';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string, signal?: AbortSignal) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n // Awaits loadXML so a failed fetch (network, CORS, non-2xx) rejects this\n // promise. Callers own the failure: they can render it, retry it or let it\n // bubble — rather than it escaping as an unhandled rejection while their\n // own `await` never settles.\n async load(uri: string, signal?: AbortSignal) {\n xmlFragment = await loadXML(uri, signal);\n return api;\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","export function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n","import { createSeededRandom } from '../shared/prng';\nimport { shuffleKeepingFixed } from '../shared/shuffle';\n\nconst isLocal = (el: Element, ...names: string[]): boolean =>\n names.includes(el.localName) || names.includes(el.localName?.toLowerCase?.());\n\nconst isItemRef = (el: Element): boolean => isLocal(el, 'qti-assessment-item-ref', 'assessmentitemref');\n\nconst isSection = (el: Element): boolean => isLocal(el, 'qti-assessment-section', 'assessmentsection');\n\nconst attrIsTrue = (el: Element, ...names: string[]): boolean =>\n names.some(n => {\n const v = (el.getAttribute(n) ?? '').trim().toLowerCase();\n return v === 'true' || v === '1';\n });\n\nconst attrIsFalse = (el: Element, ...names: string[]): boolean =>\n names.some(n => {\n const v = (el.getAttribute(n) ?? '').trim().toLowerCase();\n return v === 'false' || v === '0';\n });\n\nconst isOrdering = (el: Element): boolean => isLocal(el, 'qti-ordering', 'ordering');\n\nconst isSelection = (el: Element): boolean => isLocal(el, 'qti-selection', 'selection');\n\nconst shuffleOrderingElements = (section: Element): Element[] =>\n Array.from(section.children).filter(child => isOrdering(child) && attrIsTrue(child, 'shuffle'));\n\nconst rngFor = (seed: string | number, key: string) => createSeededRandom(`${seed}:${key}`);\n\n/** A movable unit in a section: one or more sibling nodes that move together. */\ntype Unit = { nodes: Element[]; fixed: boolean };\n\n/**\n * The item refs of a subsection, in document order, plus the element children\n * that consuming the wrapper would discard.\n *\n * Descendant subsections are collected transitively: `orderSection` returns\n * early for a section without <qti-ordering>, so a wrapper nested inside a\n * non-shuffling subsection is never consumed there and has to be gathered here.\n */\nfunction collectItemRefsDeep(section: Element): { itemRefs: Element[]; dropped: string[] } {\n const itemRefs: Element[] = [];\n const dropped: string[] = [];\n\n const walk = (el: Element): void => {\n for (const child of Array.from(el.children)) {\n if (isItemRef(child)) {\n itemRefs.push(child);\n } else if (isSection(child)) {\n walk(child);\n } else if (!isOrdering(child) && !isSelection(child)) {\n // Ordering/selection directives are transform config; anything else\n // (a rubric block, say) is authored content that the lift loses.\n dropped.push(child.localName);\n }\n }\n };\n walk(section);\n\n return { itemRefs, dropped };\n}\n\nfunction warnDroppedChildren(section: Element, dropped: string[]): void {\n if (dropped.length === 0) return;\n const identifier = section.getAttribute('identifier') ?? '(no identifier)';\n console.warn(\n `[qtiTransformTest] Subsection \"${identifier}\" is consumed by section ordering; ` +\n `discarding its ${[...new Set(dropped)].join(', ')}.`\n );\n}\n\n/**\n * Seed-deterministic QTI section shuffling.\n *\n * Reorders the children of every <qti-assessment-section> that carries a\n * <qti-ordering shuffle=\"true\">, following QTI 3.0 ordering rules:\n *\n * - Depth-first: a subsection orders its own children before the parent\n * reorders it.\n * - Item refs with fixed=\"true\" stay in their authored position; the other\n * units shuffle around them.\n * - A subsection is a grouping device, not a delivered section: its item refs\n * are lifted into the parent and the wrapper is consumed, just as the\n * <qti-ordering> directive itself is. Nothing nested survives into the DOM,\n * so the player only ever sees the authored top-level sections.\n * - By default (QTI 3.0 defaults keep-together to true) a subsection travels as\n * one unit: its items stay contiguous and keep their authored order, while\n * the parent's remaining items shuffle around the block. Add fixed=\"true\" to\n * pin the block itself to its authored slot.\n * - Only an explicit keep-together=\"false\" dissolves a subsection: its\n * (already internally ordered) item refs are poured into the parent pool and\n * interleaved with the parent's own units.\n *\n * The same `seed` always produces the same order, so a restarted session keeps\n * its sequence. Each section draws from its own PRNG stream (seed + section id)\n * so sibling sections are independent and stable.\n */\nfunction orderSection(section: Element, seed: string | number): void {\n // Depth-first: let every child section order itself first.\n for (const child of Array.from(section.children)) {\n if (isSection(child)) {\n orderSection(child, seed);\n }\n }\n\n const orderingEls = shuffleOrderingElements(section);\n if (orderingEls.length === 0) {\n return;\n }\n\n // Build the pool of movable units in document order. Config/structural\n // children (qti-ordering, qti-selection, rubric-block, …) are left in place.\n const units: Unit[] = [];\n const toDetach: Element[] = [];\n\n for (const child of Array.from(section.children)) {\n if (isItemRef(child)) {\n units.push({ nodes: [child], fixed: attrIsTrue(child, 'fixed') });\n toDetach.push(child);\n } else if (isSection(child)) {\n // Internal order is already settled: the depth-first pass above shuffled\n // this subsection if it carried its own <qti-ordering shuffle=\"true\">, and\n // left the authored order alone otherwise.\n const { itemRefs, dropped } = collectItemRefsDeep(child);\n warnDroppedChildren(child, dropped);\n\n if (attrIsFalse(child, 'keep-together', 'keeptogether')) {\n // Explicitly dissolved: the items join the parent pool individually and\n // interleave with the parent's own items.\n for (const itemRef of itemRefs) {\n units.push({ nodes: [itemRef], fixed: attrIsTrue(itemRef, 'fixed') });\n }\n } else if (itemRefs.length > 0) {\n // One multi-node unit, so the items stay contiguous and keep their order\n // wherever the block lands.\n units.push({ nodes: itemRefs, fixed: attrIsTrue(child, 'fixed') });\n }\n\n toDetach.push(child); // the grouping wrapper is consumed\n }\n }\n\n // Where the reordered units go back in: after the last node we took out, so\n // any trailing structural children (a rubric block, say) keep their position.\n // Captured before detaching, and never itself a detached node.\n const anchor = toDetach.length > 0 ? toDetach[toDetach.length - 1].nextSibling : null;\n\n const sectionKey = section.getAttribute('identifier') ?? '';\n // A no-op for 0 or 1 movable units, but the re-insertion below still has to\n // run so consumed wrappers are lifted rather than left in the DOM.\n const ordered = shuffleKeepingFixed(units, rngFor(seed, sectionKey));\n\n for (const el of toDetach) {\n el.remove();\n }\n for (const unit of ordered) {\n for (const node of unit.nodes) {\n section.insertBefore(node, anchor);\n }\n }\n\n // Ordering directives are consumed by this transform step.\n for (const orderingEl of orderingEls) {\n orderingEl.remove();\n }\n}\n\n/** Whether anything in `doc` asks to be shuffled at all. */\nexport function hasShuffleOrdering(doc: XMLDocument): boolean {\n return Array.from(doc.getElementsByTagName('*')).some(el => isOrdering(el) && attrIsTrue(el, 'shuffle'));\n}\n\n/**\n * Mutates `doc` in place: shuffles every section flagged with\n * <qti-ordering shuffle=\"true\">, deterministically from `seed`.\n */\nexport function shuffleSectionsOrdering(doc: XMLDocument, seed: string | number): void {\n const sections = Array.from(doc.getElementsByTagName('*')).filter(el => isSection(el));\n // Kick off recursion only for top-level sections; orderSection handles nesting\n // depth-first, so descendants are not double-processed.\n for (const section of sections) {\n // The snapshot above can contain wrappers that an ancestor has since\n // consumed. A detached element has no parentNode; a document element still\n // has one (the document), so this does not skip a section-rooted document.\n if (!section.parentNode) continue;\n\n const parent = section.parentElement;\n if (parent && isSection(parent)) continue;\n\n orderSection(section, seed);\n }\n}\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { warnMissingSeed } from './shared/missing-seed-warning';\nimport { loadXML, parseXML, setLocation, toHTML } from './shared/xml';\nimport { itemsFromTest } from './test/items';\nimport { hasShuffleOrdering, shuffleSectionsOrdering } from './test/shuffle-sections';\n\nexport type transformTestApi = {\n load: (uri: string, signal?: AbortSignal) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n path: (location: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n /**\n * Deterministically shuffle the children of every section that carries a\n * <qti-ordering shuffle=\"true\">, honoring fixed items and nested\n * keep-together / visible rules. The same seed reproduces the same order.\n */\n shuffleOrdering: (seed?: string | number | null) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: (registry?: CustomElementRegistry) => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n let xmlUri = '';\n\n const api: transformTestApi = {\n // Awaits loadXML so a failed fetch (network, CORS, non-2xx) rejects this\n // promise. Callers own the failure: they can render it, retry it or let it\n // bubble — rather than it escaping as an unhandled rejection while their\n // own `await` never settles.\n async load(uri, signal) {\n xmlFragment = await loadXML(uri, signal);\n xmlUri = uri;\n\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return api;\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n xmlUri = '';\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n shuffleOrdering(seed?: string | number | null) {\n // No section asks to be shuffled: leave the test alone, and stay quiet\n // about a missing seed that would never have been used.\n if (!hasShuffleOrdering(xmlFragment)) {\n return api;\n }\n\n const normalizedSeed = typeof seed === 'string' ? seed.trim() : seed;\n\n if (normalizedSeed === null || normalizedSeed === undefined || normalizedSeed === '') {\n const fallbackSeed = xmlUri || 'default-test-seed';\n warnMissingSeed('qtiTransformTest', fallbackSeed);\n shuffleSectionsOrdering(xmlFragment, fallbackSeed);\n return api;\n }\n\n shuffleSectionsOrdering(xmlFragment, normalizedSeed);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc(registry?: CustomElementRegistry) {\n return toHTML(xmlFragment, registry);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n"],"mappings":"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","names":["fallbackPath","path","shuffleInteractions"]}
|