@superbuilders/incept-renderer 0.1.0 → 0.1.3

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/dist/index.js CHANGED
@@ -3,8 +3,8 @@ import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
7
6
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
7
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
8
8
  import { cva } from 'class-variance-authority';
9
9
  import * as LabelPrimitive from '@radix-ui/react-label';
10
10
  import '@radix-ui/react-separator';
@@ -13,8 +13,10 @@ import { useSensors, useSensor, PointerSensor, KeyboardSensor, defaultDropAnimat
13
13
  import * as SelectPrimitive from '@radix-ui/react-select';
14
14
  import { sortableKeyboardCoordinates, SortableContext, horizontalListSortingStrategy, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
15
15
  import { CSS } from '@dnd-kit/utilities';
16
+ import * as logger from '@superbuilders/slog';
17
+ import * as errors from '@superbuilders/errors';
16
18
  import { XMLParser } from 'fast-xml-parser';
17
- import { z as z$1 } from 'zod';
19
+ import { z } from 'zod';
18
20
 
19
21
  // src/components/qti-renderer.tsx
20
22
  function cn(...inputs) {
@@ -496,26 +498,11 @@ var choiceIndicatorVariants = cva(
496
498
  "[--choice-foreground:var(--color-foreground)]",
497
499
  "[--choice-complement:var(--color-muted-foreground)]"
498
500
  ],
499
- betta: [
500
- "[--choice-foreground:var(--color-betta)]",
501
- "[--choice-complement:var(--color-butterfly)]"
502
- ],
503
- cardinal: [
504
- "[--choice-foreground:var(--color-cardinal)]",
505
- "[--choice-complement:var(--color-fire-ant)]"
506
- ],
507
- bee: [
508
- "[--choice-foreground:var(--color-bee)]",
509
- "[--choice-complement:var(--color-lion)]"
510
- ],
511
- owl: [
512
- "[--choice-foreground:var(--color-owl)]",
513
- "[--choice-complement:var(--color-tree-frog)]"
514
- ],
515
- macaw: [
516
- "[--choice-foreground:var(--color-macaw)]",
517
- "[--choice-complement:var(--color-whale)]"
518
- ]
501
+ betta: ["[--choice-foreground:var(--color-betta)]", "[--choice-complement:var(--color-butterfly)]"],
502
+ cardinal: ["[--choice-foreground:var(--color-cardinal)]", "[--choice-complement:var(--color-fire-ant)]"],
503
+ bee: ["[--choice-foreground:var(--color-bee)]", "[--choice-complement:var(--color-lion)]"],
504
+ owl: ["[--choice-foreground:var(--color-owl)]", "[--choice-complement:var(--color-tree-frog)]"],
505
+ macaw: ["[--choice-foreground:var(--color-macaw)]", "[--choice-complement:var(--color-whale)]"]
519
506
  }
520
507
  },
521
508
  defaultVariants: {
@@ -558,10 +545,7 @@ function ChoiceIndicator({
558
545
  }
559
546
  );
560
547
  }
561
- function Label({
562
- className,
563
- ...props
564
- }) {
548
+ function Label({ className, ...props }) {
565
549
  return /* @__PURE__ */ jsx(
566
550
  LabelPrimitive.Root,
567
551
  {
@@ -601,29 +585,26 @@ function FieldGroup({ className, ...props }) {
601
585
  }
602
586
  );
603
587
  }
604
- var fieldVariants = cva(
605
- "group/field flex w-full gap-3 data-[invalid=true]:text-destructive",
606
- {
607
- variants: {
608
- orientation: {
609
- vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
610
- horizontal: [
611
- "flex-row items-center",
612
- "[&>[data-slot=field-label]]:flex-auto",
613
- "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
614
- ],
615
- responsive: [
616
- "flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
617
- "@md/field-group:[&>[data-slot=field-label]]:flex-auto",
618
- "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
619
- ]
620
- }
621
- },
622
- defaultVariants: {
623
- orientation: "vertical"
588
+ var fieldVariants = cva("group/field flex w-full gap-3 data-[invalid=true]:text-destructive", {
589
+ variants: {
590
+ orientation: {
591
+ vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
592
+ horizontal: [
593
+ "flex-row items-center",
594
+ "[&>[data-slot=field-label]]:flex-auto",
595
+ "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
596
+ ],
597
+ responsive: [
598
+ "flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
599
+ "@md/field-group:[&>[data-slot=field-label]]:flex-auto",
600
+ "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
601
+ ]
624
602
  }
603
+ },
604
+ defaultVariants: {
605
+ orientation: "vertical"
625
606
  }
626
- );
607
+ });
627
608
  function Field({
628
609
  className,
629
610
  orientation = "vertical",
@@ -645,10 +626,7 @@ function FieldContent({ className, ...props }) {
645
626
  "div",
646
627
  {
647
628
  "data-slot": "field-content",
648
- className: cn(
649
- "group/field-content flex flex-1 flex-col gap-1.5 leading-snug",
650
- className
651
- ),
629
+ className: cn("group/field-content flex flex-1 flex-col gap-1.5 leading-snug", className),
652
630
  ...props
653
631
  }
654
632
  );
@@ -751,18 +729,8 @@ cva(
751
729
  }
752
730
  }
753
731
  );
754
- function RadioGroup({
755
- className,
756
- ...props
757
- }) {
758
- return /* @__PURE__ */ jsx(
759
- RadioGroupPrimitive.Root,
760
- {
761
- "data-slot": "radio-group",
762
- className: cn("grid gap-3", className),
763
- ...props
764
- }
765
- );
732
+ function RadioGroup({ className, ...props }) {
733
+ return /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { "data-slot": "radio-group", className: cn("grid gap-3", className), ...props });
766
734
  }
767
735
  function ChoiceInteractionRenderer({
768
736
  interaction,
@@ -1239,6 +1207,46 @@ function GapMatchInteraction({
1239
1207
  }
1240
1208
  );
1241
1209
  }
1210
+
1211
+ // src/shared/shuffle.ts
1212
+ function xmur3(str) {
1213
+ let h = 1779033703 ^ str.length;
1214
+ for (let i = 0; i < str.length; i++) {
1215
+ h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
1216
+ h = h << 13 | h >>> 19;
1217
+ }
1218
+ return () => {
1219
+ h = Math.imul(h ^ h >>> 16, 2246822507);
1220
+ h = Math.imul(h ^ h >>> 13, 3266489909);
1221
+ const shifted = h >>> 16;
1222
+ h = h ^ shifted;
1223
+ return h >>> 0;
1224
+ };
1225
+ }
1226
+ function mulberry32(seed) {
1227
+ let state = seed;
1228
+ return () => {
1229
+ state = state + 1831565813;
1230
+ let t = state;
1231
+ t = Math.imul(t ^ t >>> 15, t | 1);
1232
+ t = t ^ t + Math.imul(t ^ t >>> 7, t | 61);
1233
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
1234
+ };
1235
+ }
1236
+ function shuffleWithSeed(items, seed) {
1237
+ const out = items.slice();
1238
+ const seedFn = xmur3(seed);
1239
+ const rng = mulberry32(seedFn());
1240
+ for (let i = out.length - 1; i > 0; i--) {
1241
+ const j = Math.floor(rng() * (i + 1));
1242
+ const vi = out[i];
1243
+ const vj = out[j];
1244
+ if (vi === void 0 || vj === void 0) continue;
1245
+ out[i] = vj;
1246
+ out[j] = vi;
1247
+ }
1248
+ return out;
1249
+ }
1242
1250
  var selectTriggerVariants = cva(
1243
1251
  [
1244
1252
  "cursor-pointer",
@@ -1297,10 +1305,7 @@ var selectTriggerVariants = cva(
1297
1305
  function Select({ ...props }) {
1298
1306
  return /* @__PURE__ */ jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
1299
1307
  }
1300
- function SelectValue({
1301
- className,
1302
- ...props
1303
- }) {
1308
+ function SelectValue({ className, ...props }) {
1304
1309
  return /* @__PURE__ */ jsx(
1305
1310
  SelectPrimitive.Value,
1306
1311
  {
@@ -1371,11 +1376,7 @@ function SelectContent({
1371
1376
  }
1372
1377
  ) });
1373
1378
  }
1374
- function SelectItem({
1375
- className,
1376
- children,
1377
- ...props
1378
- }) {
1379
+ function SelectItem({ className, children, ...props }) {
1379
1380
  return /* @__PURE__ */ jsxs(
1380
1381
  SelectPrimitive.Item,
1381
1382
  {
@@ -1392,10 +1393,7 @@ function SelectItem({
1392
1393
  }
1393
1394
  );
1394
1395
  }
1395
- function SelectScrollUpButton({
1396
- className,
1397
- ...props
1398
- }) {
1396
+ function SelectScrollUpButton({ className, ...props }) {
1399
1397
  return /* @__PURE__ */ jsx(
1400
1398
  SelectPrimitive.ScrollUpButton,
1401
1399
  {
@@ -1420,46 +1418,6 @@ function SelectScrollDownButton({
1420
1418
  }
1421
1419
  );
1422
1420
  }
1423
-
1424
- // src/shared/shuffle.ts
1425
- function xmur3(str) {
1426
- let h = 1779033703 ^ str.length;
1427
- for (let i = 0; i < str.length; i++) {
1428
- h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
1429
- h = h << 13 | h >>> 19;
1430
- }
1431
- return () => {
1432
- h = Math.imul(h ^ h >>> 16, 2246822507);
1433
- h = Math.imul(h ^ h >>> 13, 3266489909);
1434
- const shifted = h >>> 16;
1435
- h = h ^ shifted;
1436
- return h >>> 0;
1437
- };
1438
- }
1439
- function mulberry32(seed) {
1440
- let state = seed;
1441
- return () => {
1442
- state = state + 1831565813;
1443
- let t = state;
1444
- t = Math.imul(t ^ t >>> 15, t | 1);
1445
- t = t ^ t + Math.imul(t ^ t >>> 7, t | 61);
1446
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
1447
- };
1448
- }
1449
- function shuffleWithSeed(items, seed) {
1450
- const out = items.slice();
1451
- const seedFn = xmur3(seed);
1452
- const rng = mulberry32(seedFn());
1453
- for (let i = out.length - 1; i > 0; i--) {
1454
- const j2 = Math.floor(rng() * (i + 1));
1455
- const vi = out[i];
1456
- const vj = out[j2];
1457
- if (vi === void 0 || vj === void 0) continue;
1458
- out[i] = vj;
1459
- out[j2] = vi;
1460
- }
1461
- return out;
1462
- }
1463
1421
  function SafeInlineHTML2({ html, className, style }) {
1464
1422
  const ref = React3.useRef(null);
1465
1423
  React3.useEffect(() => {
@@ -1768,7 +1726,7 @@ function MatchInteraction({
1768
1726
  const newState = { ...currentState };
1769
1727
  const oldSources = newState[fromTargetId];
1770
1728
  if (oldSources) {
1771
- newState[fromTargetId] = oldSources.filter((_2, i) => i !== fromIndex);
1729
+ newState[fromTargetId] = oldSources.filter((_, i) => i !== fromIndex);
1772
1730
  if (newState[fromTargetId].length === 0) {
1773
1731
  delete newState[fromTargetId];
1774
1732
  }
@@ -1806,7 +1764,7 @@ function MatchInteraction({
1806
1764
  const newState = { ...currentState };
1807
1765
  const oldSources = newState[fromTargetId];
1808
1766
  if (oldSources) {
1809
- newState[fromTargetId] = oldSources.filter((_2, i) => i !== fromIndex);
1767
+ newState[fromTargetId] = oldSources.filter((_, i) => i !== fromIndex);
1810
1768
  if (newState[fromTargetId].length === 0) {
1811
1769
  delete newState[fromTargetId];
1812
1770
  }
@@ -1823,7 +1781,7 @@ function MatchInteraction({
1823
1781
  const newState = { ...currentState };
1824
1782
  const sources = newState[targetId];
1825
1783
  if (sources) {
1826
- newState[targetId] = sources.filter((_2, i) => i !== index);
1784
+ newState[targetId] = sources.filter((_, i) => i !== index);
1827
1785
  if (newState[targetId].length === 0) {
1828
1786
  delete newState[targetId];
1829
1787
  }
@@ -2587,126 +2545,271 @@ function QTIRenderer({
2587
2545
  showFeedback && overallFeedback?.messageHtml && /* @__PURE__ */ jsx("div", { className: "qti-feedback mt-6 p-6", "data-correct": overallFeedback.isCorrect, children: /* @__PURE__ */ jsx(HTMLContent, { html: overallFeedback.messageHtml }) })
2588
2546
  ] });
2589
2547
  }
2590
-
2591
- // ../../node_modules/@superbuilders/errors/dist/index.js
2592
- function z() {
2593
- let k2 = [], j2 = this;
2594
- while (j2 != null) if (k2.push(j2.message), j2.cause instanceof Error) j2 = j2.cause;
2595
- else break;
2596
- return k2.join(": ");
2597
- }
2598
- function A(k2) {
2599
- let j2 = new Error(k2);
2600
- if (Error.captureStackTrace) Error.captureStackTrace(j2, A);
2601
- return j2.toString = z, Object.freeze(j2);
2602
- }
2603
- function B(k2, j2) {
2604
- let x = new Error(j2, { cause: k2 });
2605
- if (Error.captureStackTrace) Error.captureStackTrace(x, B);
2606
- return x.toString = z, Object.freeze(x);
2607
- }
2608
- function I(k2) {
2609
- try {
2610
- return { data: k2(), error: void 0 };
2611
- } catch (j2) {
2612
- return { data: void 0, error: j2 instanceof Error ? j2 : new Error(String(j2)) };
2613
- }
2614
- }
2615
- var QtiCardinalitySchema = z$1.enum(["single", "multiple", "ordered"]);
2616
- var QtiBaseTypeSchema = z$1.enum(["identifier", "string", "float", "integer", "boolean", "directedPair", "pair"]);
2617
- var SimpleChoiceSchema = z$1.object({
2618
- identifier: z$1.string().min(1),
2619
- contentHtml: z$1.string(),
2548
+ function normalizeString(str, caseSensitive) {
2549
+ const s = (str ?? "").trim();
2550
+ return caseSensitive ? s : s.toLowerCase();
2551
+ }
2552
+ function checkCondition(condition, item, responses, responseResults) {
2553
+ if (condition.type === "and") {
2554
+ const results = condition.conditions.map((c) => checkCondition(c, item, responses, responseResults));
2555
+ const allTrue = results.every((r) => r === true);
2556
+ logger.debug("qti evaluator: checking AND condition", {
2557
+ numConditions: condition.conditions.length,
2558
+ results,
2559
+ allTrue
2560
+ });
2561
+ return allTrue;
2562
+ }
2563
+ if (condition.type === "or") {
2564
+ const results = condition.conditions.map((c) => checkCondition(c, item, responses, responseResults));
2565
+ const anyTrue = results.some((r) => r === true);
2566
+ logger.debug("qti evaluator: checking OR condition", {
2567
+ numConditions: condition.conditions.length,
2568
+ results,
2569
+ anyTrue
2570
+ });
2571
+ return anyTrue;
2572
+ }
2573
+ if (condition.type === "not") {
2574
+ const result = checkCondition(condition.condition, item, responses, responseResults);
2575
+ logger.debug("qti evaluator: checking NOT condition", { result, negated: !result });
2576
+ return !result;
2577
+ }
2578
+ if (condition.type === "match") {
2579
+ const result = responseResults[condition.variable];
2580
+ logger.debug("qti evaluator: checking match condition", {
2581
+ variable: condition.variable,
2582
+ isCorrect: result,
2583
+ matches: result === true
2584
+ });
2585
+ return result === true;
2586
+ }
2587
+ if (condition.type === "matchValue") {
2588
+ const userResponse = responses[condition.variable];
2589
+ let userValues;
2590
+ if (Array.isArray(userResponse)) {
2591
+ userValues = userResponse;
2592
+ } else if (userResponse) {
2593
+ userValues = [userResponse];
2594
+ } else {
2595
+ userValues = [];
2596
+ }
2597
+ const matches = userValues.includes(condition.value);
2598
+ logger.debug("qti evaluator: checking matchValue condition", {
2599
+ variable: condition.variable,
2600
+ targetValue: condition.value,
2601
+ userValues,
2602
+ matches
2603
+ });
2604
+ return matches;
2605
+ }
2606
+ if (condition.type === "stringMatch") {
2607
+ const userResponse = responses[condition.variable];
2608
+ const val = Array.isArray(userResponse) ? userResponse[0] : userResponse;
2609
+ if (!val) return false;
2610
+ const u = normalizeString(String(val), condition.caseSensitive);
2611
+ const t = normalizeString(condition.value, condition.caseSensitive);
2612
+ const matches = u === t;
2613
+ logger.debug("qti evaluator: checking stringMatch", {
2614
+ variable: condition.variable,
2615
+ caseSensitive: condition.caseSensitive,
2616
+ matches
2617
+ });
2618
+ return matches;
2619
+ }
2620
+ if (condition.type === "member") {
2621
+ const userResponse = responses[condition.variable];
2622
+ let userValues;
2623
+ if (Array.isArray(userResponse)) {
2624
+ userValues = userResponse;
2625
+ } else if (userResponse) {
2626
+ userValues = [userResponse];
2627
+ } else {
2628
+ userValues = [];
2629
+ }
2630
+ const matches = userValues.includes(condition.value);
2631
+ logger.debug("qti evaluator: checking member", {
2632
+ variable: condition.variable,
2633
+ target: condition.value,
2634
+ userValues,
2635
+ matches
2636
+ });
2637
+ return matches;
2638
+ }
2639
+ if (condition.type === "equalMapResponse") {
2640
+ const responseId = condition.variable;
2641
+ const userResponse = responses[responseId];
2642
+ const responseDecl = item.responseDeclarations.find((rd) => rd.identifier === responseId);
2643
+ if (!userResponse || !responseDecl?.mapping) return false;
2644
+ const userValues = Array.isArray(userResponse) ? userResponse : [userResponse];
2645
+ const valueMap = new Map(responseDecl.mapping.entries.map((e) => [e.key, e.value]));
2646
+ let sum = 0;
2647
+ for (const val of userValues) {
2648
+ sum += valueMap.get(val) ?? responseDecl.mapping.defaultValue;
2649
+ }
2650
+ const target = Number(condition.value);
2651
+ const diff = Math.abs(sum - target);
2652
+ const matches = diff < 1e-4;
2653
+ logger.debug("qti evaluator: checking equalMapResponse", {
2654
+ responseId,
2655
+ userValues,
2656
+ sum,
2657
+ target: condition.value,
2658
+ matches
2659
+ });
2660
+ return matches;
2661
+ }
2662
+ return false;
2663
+ }
2664
+ function evaluateRule(rule, item, responses, responseResults) {
2665
+ const feedbackIds = [];
2666
+ if (rule.type === "action") {
2667
+ const action = rule.action;
2668
+ if (action.type === "setOutcomeValue" && (action.identifier === "FEEDBACK__OVERALL" || action.identifier === "FEEDBACK__PEDAGOGY" || action.identifier === "FEEDBACK")) {
2669
+ logger.debug("qti evaluator: executing action", { id: action.identifier, value: action.value });
2670
+ feedbackIds.push(action.value);
2671
+ }
2672
+ return feedbackIds;
2673
+ }
2674
+ if (rule.type === "condition") {
2675
+ for (const branch of rule.branches) {
2676
+ const isMatch = branch.condition ? checkCondition(branch.condition, item, responses, responseResults) : true;
2677
+ logger.debug("qti evaluator: evaluating branch", {
2678
+ hasCondition: !!branch.condition,
2679
+ isMatch
2680
+ });
2681
+ if (isMatch) {
2682
+ const feedbackActions = branch.actions.filter(
2683
+ (r) => r.type === "setOutcomeValue" && (r.identifier === "FEEDBACK__OVERALL" || r.identifier === "FEEDBACK__PEDAGOGY" || r.identifier === "FEEDBACK")
2684
+ );
2685
+ for (const action of feedbackActions) {
2686
+ feedbackIds.push(action.value);
2687
+ }
2688
+ if (branch.nestedRules) {
2689
+ for (const nested of branch.nestedRules) {
2690
+ const nestedIds = evaluateRule(nested, item, responses, responseResults);
2691
+ feedbackIds.push(...nestedIds);
2692
+ }
2693
+ }
2694
+ break;
2695
+ }
2696
+ }
2697
+ }
2698
+ return feedbackIds;
2699
+ }
2700
+ function evaluateFeedbackIdentifiers(item, responses, responseResults) {
2701
+ const processing = item.responseProcessing;
2702
+ if (!processing) {
2703
+ logger.debug("qti evaluator: no response processing found");
2704
+ return [];
2705
+ }
2706
+ logger.debug("qti evaluator: starting evaluation", {
2707
+ numRules: processing.rules.length,
2708
+ responseResults
2709
+ });
2710
+ const allFeedbackIds = [];
2711
+ for (const rule of processing.rules) {
2712
+ const ids = evaluateRule(rule, item, responses, responseResults);
2713
+ allFeedbackIds.push(...ids);
2714
+ }
2715
+ logger.debug("qti evaluator: selected feedback identifiers", { feedbackIds: allFeedbackIds });
2716
+ return allFeedbackIds;
2717
+ }
2718
+ var QtiCardinalitySchema = z.enum(["single", "multiple", "ordered"]);
2719
+ var QtiBaseTypeSchema = z.enum(["identifier", "string", "float", "integer", "boolean", "directedPair", "pair"]);
2720
+ var SimpleChoiceSchema = z.object({
2721
+ identifier: z.string().min(1),
2722
+ contentHtml: z.string(),
2620
2723
  // Allows "" for empty or image-only content
2621
- inlineFeedbackHtml: z$1.string().optional()
2724
+ inlineFeedbackHtml: z.string().optional()
2622
2725
  // Optional per-choice feedback (qti-feedback-inline)
2623
2726
  });
2624
- var InlineChoiceSchema = z$1.object({
2625
- identifier: z$1.string().min(1),
2626
- contentHtml: z$1.string()
2727
+ var InlineChoiceSchema = z.object({
2728
+ identifier: z.string().min(1),
2729
+ contentHtml: z.string()
2627
2730
  });
2628
- var ChoiceInteractionCoreSchema = z$1.object({
2629
- responseIdentifier: z$1.string().min(1),
2630
- shuffle: z$1.boolean(),
2631
- minChoices: z$1.number().int().min(0),
2632
- maxChoices: z$1.number().int().min(1),
2633
- promptHtml: z$1.string(),
2634
- choices: z$1.array(SimpleChoiceSchema).min(1)
2731
+ var ChoiceInteractionCoreSchema = z.object({
2732
+ responseIdentifier: z.string().min(1),
2733
+ shuffle: z.boolean(),
2734
+ minChoices: z.number().int().min(0),
2735
+ maxChoices: z.number().int().min(1),
2736
+ promptHtml: z.string(),
2737
+ choices: z.array(SimpleChoiceSchema).min(1)
2635
2738
  });
2636
- var ChoiceInteractionSchema = ChoiceInteractionCoreSchema.extend({ type: z$1.literal("choiceInteraction") });
2637
- var InlineChoiceInteractionCoreSchema = z$1.object({
2638
- responseIdentifier: z$1.string().min(1),
2639
- shuffle: z$1.boolean(),
2640
- choices: z$1.array(InlineChoiceSchema).min(1)
2739
+ var ChoiceInteractionSchema = ChoiceInteractionCoreSchema.extend({ type: z.literal("choiceInteraction") });
2740
+ var InlineChoiceInteractionCoreSchema = z.object({
2741
+ responseIdentifier: z.string().min(1),
2742
+ shuffle: z.boolean(),
2743
+ choices: z.array(InlineChoiceSchema).min(1)
2641
2744
  });
2642
2745
  var InlineChoiceInteractionSchema = InlineChoiceInteractionCoreSchema.extend({
2643
- type: z$1.literal("inlineChoiceInteraction")
2746
+ type: z.literal("inlineChoiceInteraction")
2644
2747
  });
2645
- var TextEntryInteractionCoreSchema = z$1.object({
2646
- responseIdentifier: z$1.string().min(1),
2647
- expectedLength: z$1.number().int().min(0).optional(),
2648
- placeholderText: z$1.string().optional(),
2649
- patternMask: z$1.string().optional()
2748
+ var TextEntryInteractionCoreSchema = z.object({
2749
+ responseIdentifier: z.string().min(1),
2750
+ expectedLength: z.number().int().min(0).optional(),
2751
+ placeholderText: z.string().optional(),
2752
+ patternMask: z.string().optional()
2650
2753
  });
2651
2754
  var TextEntryInteractionSchema = TextEntryInteractionCoreSchema.extend({
2652
- type: z$1.literal("textEntryInteraction")
2755
+ type: z.literal("textEntryInteraction")
2653
2756
  });
2654
- var OrderInteractionCoreSchema = z$1.object({
2655
- responseIdentifier: z$1.string().min(1),
2656
- shuffle: z$1.boolean(),
2657
- minChoices: z$1.number().int().min(0),
2658
- maxChoices: z$1.number().int().min(0).optional(),
2757
+ var OrderInteractionCoreSchema = z.object({
2758
+ responseIdentifier: z.string().min(1),
2759
+ shuffle: z.boolean(),
2760
+ minChoices: z.number().int().min(0),
2761
+ maxChoices: z.number().int().min(0).optional(),
2659
2762
  // 0 or undefined usually means "all"
2660
- orientation: z$1.enum(["vertical", "horizontal"]),
2661
- promptHtml: z$1.string(),
2662
- choices: z$1.array(SimpleChoiceSchema).min(1)
2763
+ orientation: z.enum(["vertical", "horizontal"]),
2764
+ promptHtml: z.string(),
2765
+ choices: z.array(SimpleChoiceSchema).min(1)
2663
2766
  });
2664
2767
  var OrderInteractionSchema = OrderInteractionCoreSchema.extend({
2665
- type: z$1.literal("orderInteraction")
2768
+ type: z.literal("orderInteraction")
2666
2769
  });
2667
- var GapTextSchema = z$1.object({
2668
- identifier: z$1.string().min(1),
2669
- contentHtml: z$1.string(),
2670
- matchMax: z$1.number().int().min(0)
2770
+ var GapTextSchema = z.object({
2771
+ identifier: z.string().min(1),
2772
+ contentHtml: z.string(),
2773
+ matchMax: z.number().int().min(0)
2671
2774
  // 0 = unlimited
2672
2775
  });
2673
- var GapSchema = z$1.object({
2674
- identifier: z$1.string().min(1)
2776
+ var GapSchema = z.object({
2777
+ identifier: z.string().min(1)
2675
2778
  });
2676
- var GapMatchInteractionCoreSchema = z$1.object({
2677
- responseIdentifier: z$1.string().min(1),
2678
- shuffle: z$1.boolean(),
2679
- gapTexts: z$1.array(GapTextSchema).min(1),
2779
+ var GapMatchInteractionCoreSchema = z.object({
2780
+ responseIdentifier: z.string().min(1),
2781
+ shuffle: z.boolean(),
2782
+ gapTexts: z.array(GapTextSchema).min(1),
2680
2783
  // Draggable source tokens
2681
- gaps: z$1.array(GapSchema).min(1),
2784
+ gaps: z.array(GapSchema).min(1),
2682
2785
  // Drop target placeholders
2683
- contentHtml: z$1.string()
2786
+ contentHtml: z.string()
2684
2787
  // HTML content with gap placeholders
2685
2788
  });
2686
2789
  var GapMatchInteractionSchema = GapMatchInteractionCoreSchema.extend({
2687
- type: z$1.literal("gapMatchInteraction")
2790
+ type: z.literal("gapMatchInteraction")
2688
2791
  });
2689
- var AssociableChoiceSchema = z$1.object({
2690
- identifier: z$1.string().min(1),
2691
- matchMax: z$1.number().int().min(0),
2792
+ var AssociableChoiceSchema = z.object({
2793
+ identifier: z.string().min(1),
2794
+ matchMax: z.number().int().min(0),
2692
2795
  // 0 = unlimited uses
2693
- contentHtml: z$1.string()
2796
+ contentHtml: z.string()
2694
2797
  });
2695
- var MatchInteractionCoreSchema = z$1.object({
2696
- responseIdentifier: z$1.string().min(1),
2697
- shuffle: z$1.boolean(),
2698
- maxAssociations: z$1.number().int().min(0),
2798
+ var MatchInteractionCoreSchema = z.object({
2799
+ responseIdentifier: z.string().min(1),
2800
+ shuffle: z.boolean(),
2801
+ maxAssociations: z.number().int().min(0),
2699
2802
  // 0 = unlimited total associations
2700
- sourceChoices: z$1.array(AssociableChoiceSchema).min(1),
2803
+ sourceChoices: z.array(AssociableChoiceSchema).min(1),
2701
2804
  // First <qti-simple-match-set>
2702
- targetChoices: z$1.array(AssociableChoiceSchema).min(1),
2805
+ targetChoices: z.array(AssociableChoiceSchema).min(1),
2703
2806
  // Second <qti-simple-match-set>
2704
- promptHtml: z$1.string()
2807
+ promptHtml: z.string()
2705
2808
  });
2706
2809
  var MatchInteractionSchema = MatchInteractionCoreSchema.extend({
2707
- type: z$1.literal("matchInteraction")
2810
+ type: z.literal("matchInteraction")
2708
2811
  });
2709
- var AnyInteractionSchema = z$1.discriminatedUnion("type", [
2812
+ var AnyInteractionSchema = z.discriminatedUnion("type", [
2710
2813
  ChoiceInteractionSchema,
2711
2814
  InlineChoiceInteractionSchema,
2712
2815
  TextEntryInteractionSchema,
@@ -2714,149 +2817,149 @@ var AnyInteractionSchema = z$1.discriminatedUnion("type", [
2714
2817
  GapMatchInteractionSchema,
2715
2818
  MatchInteractionSchema
2716
2819
  ]);
2717
- var CorrectResponseSchema = z$1.object({
2718
- values: z$1.array(z$1.string().min(1)).min(1)
2820
+ var CorrectResponseSchema = z.object({
2821
+ values: z.array(z.string().min(1)).min(1)
2719
2822
  });
2720
- var ResponseDeclarationSchema = z$1.object({
2721
- identifier: z$1.string().min(1),
2823
+ var ResponseDeclarationSchema = z.object({
2824
+ identifier: z.string().min(1),
2722
2825
  cardinality: QtiCardinalitySchema,
2723
2826
  baseType: QtiBaseTypeSchema,
2724
2827
  correctResponse: CorrectResponseSchema,
2725
2828
  // Optional response mapping for map-response processing (used for summed feedback/score)
2726
- mapping: z$1.object({
2727
- defaultValue: z$1.number().default(0),
2728
- lowerBound: z$1.number().optional(),
2729
- upperBound: z$1.number().optional(),
2730
- entries: z$1.array(
2731
- z$1.object({
2732
- key: z$1.string().min(1),
2733
- value: z$1.number()
2829
+ mapping: z.object({
2830
+ defaultValue: z.number().default(0),
2831
+ lowerBound: z.number().optional(),
2832
+ upperBound: z.number().optional(),
2833
+ entries: z.array(
2834
+ z.object({
2835
+ key: z.string().min(1),
2836
+ value: z.number()
2734
2837
  })
2735
2838
  )
2736
2839
  }).optional()
2737
2840
  });
2738
- var OutcomeDefaultValueSchema = z$1.object({
2739
- value: z$1.string()
2841
+ var OutcomeDefaultValueSchema = z.object({
2842
+ value: z.string()
2740
2843
  });
2741
- var OutcomeDeclarationSchema = z$1.object({
2742
- identifier: z$1.string().min(1),
2844
+ var OutcomeDeclarationSchema = z.object({
2845
+ identifier: z.string().min(1),
2743
2846
  cardinality: QtiCardinalitySchema,
2744
2847
  baseType: QtiBaseTypeSchema,
2745
2848
  defaultValue: OutcomeDefaultValueSchema.optional()
2746
2849
  });
2747
- var FeedbackBlockSchema = z$1.object({
2748
- outcomeIdentifier: z$1.string().min(1),
2749
- identifier: z$1.string().min(1),
2750
- showHide: z$1.enum(["show", "hide"]).default("show"),
2751
- contentHtml: z$1.string()
2850
+ var FeedbackBlockSchema = z.object({
2851
+ outcomeIdentifier: z.string().min(1),
2852
+ identifier: z.string().min(1),
2853
+ showHide: z.enum(["show", "hide"]).default("show"),
2854
+ contentHtml: z.string()
2752
2855
  });
2753
- var StimulusBlockSchema = z$1.object({
2754
- type: z$1.literal("stimulus"),
2755
- html: z$1.string()
2856
+ var StimulusBlockSchema = z.object({
2857
+ type: z.literal("stimulus"),
2858
+ html: z.string()
2756
2859
  });
2757
- var RichStimulusBlockSchema = z$1.object({
2758
- type: z$1.literal("richStimulus"),
2759
- html: z$1.string(),
2760
- inlineEmbeds: z$1.record(z$1.string(), InlineChoiceInteractionSchema),
2761
- textEmbeds: z$1.record(z$1.string(), TextEntryInteractionSchema)
2860
+ var RichStimulusBlockSchema = z.object({
2861
+ type: z.literal("richStimulus"),
2862
+ html: z.string(),
2863
+ inlineEmbeds: z.record(z.string(), InlineChoiceInteractionSchema),
2864
+ textEmbeds: z.record(z.string(), TextEntryInteractionSchema)
2762
2865
  });
2763
- var InteractionBlockSchema = z$1.object({
2764
- type: z$1.literal("interaction"),
2866
+ var InteractionBlockSchema = z.object({
2867
+ type: z.literal("interaction"),
2765
2868
  interaction: AnyInteractionSchema
2766
2869
  });
2767
- var ItemBodySchema = z$1.object({
2768
- contentBlocks: z$1.array(z$1.union([StimulusBlockSchema, RichStimulusBlockSchema, InteractionBlockSchema])).min(1),
2769
- feedbackBlocks: z$1.array(FeedbackBlockSchema)
2870
+ var ItemBodySchema = z.object({
2871
+ contentBlocks: z.array(z.union([StimulusBlockSchema, RichStimulusBlockSchema, InteractionBlockSchema])).min(1),
2872
+ feedbackBlocks: z.array(FeedbackBlockSchema)
2770
2873
  });
2771
- var BaseRuleSchema = z$1.object({
2772
- type: z$1.literal("setOutcomeValue"),
2773
- identifier: z$1.string(),
2774
- value: z$1.string()
2874
+ var BaseRuleSchema = z.object({
2875
+ type: z.literal("setOutcomeValue"),
2876
+ identifier: z.string(),
2877
+ value: z.string()
2775
2878
  });
2776
- var MatchConditionSchema = z$1.object({
2777
- type: z$1.literal("match"),
2778
- variable: z$1.string(),
2779
- correct: z$1.literal(true)
2879
+ var MatchConditionSchema = z.object({
2880
+ type: z.literal("match"),
2881
+ variable: z.string(),
2882
+ correct: z.literal(true)
2780
2883
  // Match against correct response
2781
2884
  });
2782
- var MatchValueConditionSchema = z$1.object({
2783
- type: z$1.literal("matchValue"),
2784
- variable: z$1.string(),
2885
+ var MatchValueConditionSchema = z.object({
2886
+ type: z.literal("matchValue"),
2887
+ variable: z.string(),
2785
2888
  // The response identifier from <qti-variable>
2786
- value: z$1.string()
2889
+ value: z.string()
2787
2890
  // The target value from <qti-base-value>
2788
2891
  });
2789
- var StringMatchConditionSchema = z$1.object({
2790
- type: z$1.literal("stringMatch"),
2791
- variable: z$1.string(),
2792
- value: z$1.string(),
2793
- caseSensitive: z$1.boolean()
2892
+ var StringMatchConditionSchema = z.object({
2893
+ type: z.literal("stringMatch"),
2894
+ variable: z.string(),
2895
+ value: z.string(),
2896
+ caseSensitive: z.boolean()
2794
2897
  });
2795
- var MemberConditionSchema = z$1.object({
2796
- type: z$1.literal("member"),
2797
- variable: z$1.string(),
2798
- value: z$1.string()
2898
+ var MemberConditionSchema = z.object({
2899
+ type: z.literal("member"),
2900
+ variable: z.string(),
2901
+ value: z.string()
2799
2902
  });
2800
- var EqualMapResponseConditionSchema = z$1.object({
2801
- type: z$1.literal("equalMapResponse"),
2802
- variable: z$1.string(),
2903
+ var EqualMapResponseConditionSchema = z.object({
2904
+ type: z.literal("equalMapResponse"),
2905
+ variable: z.string(),
2803
2906
  // The response identifier from <qti-map-response>
2804
- value: z$1.string()
2907
+ value: z.string()
2805
2908
  // The target sum value from <qti-base-value>
2806
2909
  });
2807
- var AndConditionSchema = z$1.object({
2808
- type: z$1.literal("and"),
2809
- conditions: z$1.array(z$1.lazy(() => AnyConditionSchema))
2910
+ var AndConditionSchema = z.object({
2911
+ type: z.literal("and"),
2912
+ conditions: z.array(z.lazy(() => AnyConditionSchema))
2810
2913
  });
2811
- var OrConditionSchema = z$1.object({
2812
- type: z$1.literal("or"),
2813
- conditions: z$1.array(z$1.lazy(() => AnyConditionSchema))
2914
+ var OrConditionSchema = z.object({
2915
+ type: z.literal("or"),
2916
+ conditions: z.array(z.lazy(() => AnyConditionSchema))
2814
2917
  });
2815
- var NotConditionSchema = z$1.object({
2816
- type: z$1.literal("not"),
2817
- condition: z$1.lazy(() => AnyConditionSchema)
2918
+ var NotConditionSchema = z.object({
2919
+ type: z.literal("not"),
2920
+ condition: z.lazy(() => AnyConditionSchema)
2818
2921
  });
2819
- var AnyConditionSchema = z$1.union([
2922
+ var AnyConditionSchema = z.union([
2820
2923
  MatchConditionSchema,
2821
2924
  MatchValueConditionSchema,
2822
2925
  StringMatchConditionSchema,
2823
2926
  MemberConditionSchema,
2824
- z$1.lazy(() => AndConditionSchema),
2825
- z$1.lazy(() => OrConditionSchema),
2826
- z$1.lazy(() => NotConditionSchema),
2927
+ z.lazy(() => AndConditionSchema),
2928
+ z.lazy(() => OrConditionSchema),
2929
+ z.lazy(() => NotConditionSchema),
2827
2930
  EqualMapResponseConditionSchema
2828
2931
  ]);
2829
- var ConditionBranchSchema = z$1.object({
2932
+ var ConditionBranchSchema = z.object({
2830
2933
  condition: AnyConditionSchema.optional(),
2831
- actions: z$1.array(BaseRuleSchema),
2832
- nestedRules: z$1.array(z$1.lazy(() => ResponseRuleSchema)).optional()
2934
+ actions: z.array(BaseRuleSchema),
2935
+ nestedRules: z.array(z.lazy(() => ResponseRuleSchema)).optional()
2833
2936
  });
2834
- var ResponseRuleSchema = z$1.union([
2835
- z$1.object({
2836
- type: z$1.literal("condition"),
2837
- branches: z$1.array(ConditionBranchSchema)
2937
+ var ResponseRuleSchema = z.union([
2938
+ z.object({
2939
+ type: z.literal("condition"),
2940
+ branches: z.array(ConditionBranchSchema)
2838
2941
  }),
2839
- z$1.object({
2840
- type: z$1.literal("action"),
2942
+ z.object({
2943
+ type: z.literal("action"),
2841
2944
  action: BaseRuleSchema
2842
2945
  })
2843
2946
  ]);
2844
- var ScoringRuleSchema = z$1.object({
2845
- responseIdentifier: z$1.string().min(1),
2846
- correctScore: z$1.number(),
2847
- incorrectScore: z$1.number()
2947
+ var ScoringRuleSchema = z.object({
2948
+ responseIdentifier: z.string().min(1),
2949
+ correctScore: z.number(),
2950
+ incorrectScore: z.number()
2848
2951
  });
2849
- var ResponseProcessingSchema = z$1.object({
2850
- rules: z$1.array(ResponseRuleSchema),
2952
+ var ResponseProcessingSchema = z.object({
2953
+ rules: z.array(ResponseRuleSchema),
2851
2954
  scoring: ScoringRuleSchema
2852
2955
  });
2853
- var AssessmentItemSchema = z$1.object({
2854
- identifier: z$1.string().min(1),
2855
- title: z$1.string().min(1),
2856
- timeDependent: z$1.boolean(),
2857
- xmlLang: z$1.string().min(1),
2858
- responseDeclarations: z$1.array(ResponseDeclarationSchema).min(1),
2859
- outcomeDeclarations: z$1.array(OutcomeDeclarationSchema).min(1),
2956
+ var AssessmentItemSchema = z.object({
2957
+ identifier: z.string().min(1),
2958
+ title: z.string().min(1),
2959
+ timeDependent: z.boolean(),
2960
+ xmlLang: z.string().min(1),
2961
+ responseDeclarations: z.array(ResponseDeclarationSchema).min(1),
2962
+ outcomeDeclarations: z.array(OutcomeDeclarationSchema).min(1),
2860
2963
  itemBody: ItemBodySchema,
2861
2964
  responseProcessing: ResponseProcessingSchema
2862
2965
  });
@@ -2888,7 +2991,7 @@ function normalizeNode(rawNode) {
2888
2991
  if (textContent != null) {
2889
2992
  return coerceString(textContent);
2890
2993
  }
2891
- const tagName = Object.keys(rawNode).find((k2) => k2 !== ":@");
2994
+ const tagName = Object.keys(rawNode).find((k) => k !== ":@");
2892
2995
  if (!tagName) return "";
2893
2996
  const attrsValue = rawNode[":@"];
2894
2997
  const attrs = isRecord(attrsValue) ? attrsValue : {};
@@ -3146,12 +3249,12 @@ function extractResponseDeclarations(rootChildren) {
3146
3249
  const cardinalityRaw = coerceString(node.attrs.cardinality);
3147
3250
  const cardinalityResult = QtiCardinalitySchema.safeParse(cardinalityRaw);
3148
3251
  if (!cardinalityResult.success) {
3149
- throw A(`invalid cardinality '${cardinalityRaw}' in response declaration`);
3252
+ throw errors.new(`invalid cardinality '${cardinalityRaw}' in response declaration`);
3150
3253
  }
3151
3254
  const baseTypeRaw = coerceString(node.attrs["base-type"]);
3152
3255
  const baseTypeResult = QtiBaseTypeSchema.safeParse(baseTypeRaw);
3153
3256
  if (!baseTypeResult.success) {
3154
- throw A(`invalid base-type '${baseTypeRaw}' in response declaration`);
3257
+ throw errors.new(`invalid base-type '${baseTypeRaw}' in response declaration`);
3155
3258
  }
3156
3259
  return {
3157
3260
  identifier: coerceString(node.attrs.identifier),
@@ -3171,12 +3274,12 @@ function extractOutcomeDeclarations(rootChildren) {
3171
3274
  const cardinalityRaw = coerceString(node.attrs.cardinality);
3172
3275
  const cardinalityResult = QtiCardinalitySchema.safeParse(cardinalityRaw);
3173
3276
  if (!cardinalityResult.success) {
3174
- throw A(`invalid cardinality '${cardinalityRaw}' in outcome declaration`);
3277
+ throw errors.new(`invalid cardinality '${cardinalityRaw}' in outcome declaration`);
3175
3278
  }
3176
3279
  const baseTypeRaw = coerceString(node.attrs["base-type"]);
3177
3280
  const baseTypeResult = QtiBaseTypeSchema.safeParse(baseTypeRaw);
3178
3281
  if (!baseTypeResult.success) {
3179
- throw A(`invalid base-type '${baseTypeRaw}' in outcome declaration`);
3282
+ throw errors.new(`invalid base-type '${baseTypeRaw}' in outcome declaration`);
3180
3283
  }
3181
3284
  return {
3182
3285
  identifier: coerceString(node.attrs.identifier),
@@ -3393,23 +3496,23 @@ function extractResponseProcessing(rootChildren) {
3393
3496
  }
3394
3497
  function parseAssessmentItemXml(xml) {
3395
3498
  if (!xml || typeof xml !== "string") {
3396
- throw A("xml input must be a non-empty string");
3499
+ throw errors.new("xml input must be a non-empty string");
3397
3500
  }
3398
3501
  const parser = createXmlParser();
3399
- const parseResult = I(() => {
3502
+ const parseResult = errors.trySync(() => {
3400
3503
  return parser.parse(xml, true);
3401
3504
  });
3402
3505
  if (parseResult.error) {
3403
- throw B(parseResult.error, "xml parse");
3506
+ throw errors.wrap(parseResult.error, "xml parse");
3404
3507
  }
3405
3508
  const raw = parseResult.data;
3406
3509
  if (!Array.isArray(raw)) {
3407
- throw A("expected xml parser to output an array for preserveOrder");
3510
+ throw errors.new("expected xml parser to output an array for preserveOrder");
3408
3511
  }
3409
3512
  const normalizedTree = raw.map(normalizeNode).filter((n) => typeof n !== "string");
3410
3513
  const rootNode = normalizedTree.find((n) => n.tagName.endsWith("assessment-item"));
3411
3514
  if (!rootNode) {
3412
- throw A("qti assessment item not found in xml document");
3515
+ throw errors.new("qti assessment item not found in xml document");
3413
3516
  }
3414
3517
  const rootChildren = rootNode.children.filter((c) => typeof c !== "string");
3415
3518
  const itemBodyNode = rootChildren.find((n) => n.tagName === "qti-item-body");
@@ -3481,159 +3584,10 @@ function parseAssessmentItemXml(xml) {
3481
3584
  const validation = AssessmentItemSchema.safeParse(normalizedItem);
3482
3585
  if (!validation.success) {
3483
3586
  const errorDetails = validation.error.issues.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
3484
- throw A(`qti item validation: ${errorDetails}`);
3587
+ throw errors.new(`qti item validation: ${errorDetails}`);
3485
3588
  }
3486
3589
  return validation.data;
3487
3590
  }
3488
- var Q = new TextEncoder();
3489
- ({ DEBUG: Q.encode(" DEBUG "), INFO: Q.encode(" INFO "), WARN: Q.encode(" WARN "), ERROR: Q.encode(" ERROR "), NEWLINE: Q.encode(`
3490
- `), SPACE: Q.encode(" "), EQUALS: Q.encode("="), SLASH: Q.encode("/"), COLON: Q.encode(":"), NULL: Q.encode("null"), UNDEFINED: Q.encode("undefined"), TRUE: Q.encode("true"), FALSE: Q.encode("false"), QUOTE: Q.encode('"'), BRACKET_OPEN: Q.encode("["), BRACKET_CLOSE: Q.encode("]"), BRACE_OPEN: Q.encode("{"), BRACE_CLOSE: Q.encode("}"), COMMA: Q.encode(","), ZERO: Q.encode("0"), MINUS: Q.encode("-"), DOT: Q.encode(".") });
3491
- function y(x, G) {
3492
- return;
3493
- }
3494
-
3495
- // src/evaluator.ts
3496
- function normalizeString(str, caseSensitive) {
3497
- const s = (str ?? "").trim();
3498
- return caseSensitive ? s : s.toLowerCase();
3499
- }
3500
- function checkCondition(condition, item, responses, responseResults) {
3501
- if (condition.type === "and") {
3502
- const results = condition.conditions.map((c) => checkCondition(c, item, responses, responseResults));
3503
- const allTrue = results.every((r) => r === true);
3504
- y("qti evaluator: checking AND condition", {
3505
- numConditions: condition.conditions.length});
3506
- return allTrue;
3507
- }
3508
- if (condition.type === "or") {
3509
- const results = condition.conditions.map((c) => checkCondition(c, item, responses, responseResults));
3510
- const anyTrue = results.some((r) => r === true);
3511
- y("qti evaluator: checking OR condition", {
3512
- numConditions: condition.conditions.length});
3513
- return anyTrue;
3514
- }
3515
- if (condition.type === "not") {
3516
- const result = checkCondition(condition.condition, item, responses, responseResults);
3517
- return !result;
3518
- }
3519
- if (condition.type === "match") {
3520
- const result = responseResults[condition.variable];
3521
- y("qti evaluator: checking match condition", {
3522
- variable: condition.variable});
3523
- return result === true;
3524
- }
3525
- if (condition.type === "matchValue") {
3526
- const userResponse = responses[condition.variable];
3527
- let userValues;
3528
- if (Array.isArray(userResponse)) {
3529
- userValues = userResponse;
3530
- } else if (userResponse) {
3531
- userValues = [userResponse];
3532
- } else {
3533
- userValues = [];
3534
- }
3535
- const matches = userValues.includes(condition.value);
3536
- y("qti evaluator: checking matchValue condition", {
3537
- variable: condition.variable,
3538
- targetValue: condition.value});
3539
- return matches;
3540
- }
3541
- if (condition.type === "stringMatch") {
3542
- const userResponse = responses[condition.variable];
3543
- const val = Array.isArray(userResponse) ? userResponse[0] : userResponse;
3544
- if (!val) return false;
3545
- const u = normalizeString(String(val), condition.caseSensitive);
3546
- const t = normalizeString(condition.value, condition.caseSensitive);
3547
- const matches = u === t;
3548
- y("qti evaluator: checking stringMatch", {
3549
- variable: condition.variable,
3550
- caseSensitive: condition.caseSensitive});
3551
- return matches;
3552
- }
3553
- if (condition.type === "member") {
3554
- const userResponse = responses[condition.variable];
3555
- let userValues;
3556
- if (Array.isArray(userResponse)) {
3557
- userValues = userResponse;
3558
- } else if (userResponse) {
3559
- userValues = [userResponse];
3560
- } else {
3561
- userValues = [];
3562
- }
3563
- const matches = userValues.includes(condition.value);
3564
- y("qti evaluator: checking member", {
3565
- variable: condition.variable,
3566
- target: condition.value});
3567
- return matches;
3568
- }
3569
- if (condition.type === "equalMapResponse") {
3570
- const responseId = condition.variable;
3571
- const userResponse = responses[responseId];
3572
- const responseDecl = item.responseDeclarations.find((rd) => rd.identifier === responseId);
3573
- if (!userResponse || !responseDecl?.mapping) return false;
3574
- const userValues = Array.isArray(userResponse) ? userResponse : [userResponse];
3575
- const valueMap = new Map(responseDecl.mapping.entries.map((e) => [e.key, e.value]));
3576
- let sum = 0;
3577
- for (const val of userValues) {
3578
- sum += valueMap.get(val) ?? responseDecl.mapping.defaultValue;
3579
- }
3580
- const target = Number(condition.value);
3581
- const diff = Math.abs(sum - target);
3582
- const matches = diff < 1e-4;
3583
- y("qti evaluator: checking equalMapResponse", {
3584
- target: condition.value});
3585
- return matches;
3586
- }
3587
- return false;
3588
- }
3589
- function evaluateRule(rule, item, responses, responseResults) {
3590
- const feedbackIds = [];
3591
- if (rule.type === "action") {
3592
- const action = rule.action;
3593
- if (action.type === "setOutcomeValue" && (action.identifier === "FEEDBACK__OVERALL" || action.identifier === "FEEDBACK__PEDAGOGY" || action.identifier === "FEEDBACK")) {
3594
- y("qti evaluator: executing action", { id: action.identifier, value: action.value });
3595
- feedbackIds.push(action.value);
3596
- }
3597
- return feedbackIds;
3598
- }
3599
- if (rule.type === "condition") {
3600
- for (const branch of rule.branches) {
3601
- const isMatch = branch.condition ? checkCondition(branch.condition, item, responses, responseResults) : true;
3602
- y("qti evaluator: evaluating branch", {
3603
- hasCondition: !!branch.condition});
3604
- if (isMatch) {
3605
- const feedbackActions = branch.actions.filter(
3606
- (r) => r.type === "setOutcomeValue" && (r.identifier === "FEEDBACK__OVERALL" || r.identifier === "FEEDBACK__PEDAGOGY" || r.identifier === "FEEDBACK")
3607
- );
3608
- for (const action of feedbackActions) {
3609
- feedbackIds.push(action.value);
3610
- }
3611
- if (branch.nestedRules) {
3612
- for (const nested of branch.nestedRules) {
3613
- const nestedIds = evaluateRule(nested, item, responses, responseResults);
3614
- feedbackIds.push(...nestedIds);
3615
- }
3616
- }
3617
- break;
3618
- }
3619
- }
3620
- }
3621
- return feedbackIds;
3622
- }
3623
- function evaluateFeedbackIdentifiers(item, responses, responseResults) {
3624
- const processing = item.responseProcessing;
3625
- if (!processing) {
3626
- return [];
3627
- }
3628
- y("qti evaluator: starting evaluation", {
3629
- numRules: processing.rules.length});
3630
- const allFeedbackIds = [];
3631
- for (const rule of processing.rules) {
3632
- const ids = evaluateRule(rule, item, responses, responseResults);
3633
- allFeedbackIds.push(...ids);
3634
- }
3635
- return allFeedbackIds;
3636
- }
3637
3591
 
3638
3592
  export { AssessmentItemSchema, ContentBlockRenderer, QTIRenderer, detectContentType, evaluateFeedbackIdentifiers, parseAssessmentItemXml, sanitizeForDisplay, sanitizeHtml, serializeInner, serializeNode, serializeNodes };
3639
3593
  //# sourceMappingURL=index.js.map