@conform-ed/qti-react 0.0.15 → 0.0.17

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
@@ -38,6 +38,9 @@ var v0FlowElements = new Set([
38
38
  "rb",
39
39
  "rt",
40
40
  "rp",
41
+ "rtc",
42
+ "bdo",
43
+ "bdi",
41
44
  "img",
42
45
  "audio",
43
46
  "video",
@@ -64,9 +67,35 @@ var v0FlowElements = new Set([
64
67
  "tfoot",
65
68
  "tr",
66
69
  "th",
67
- "td"
70
+ "td",
71
+ "a",
72
+ "abbr",
73
+ "acronym",
74
+ "address",
75
+ "article",
76
+ "aside",
77
+ "big",
78
+ "code",
79
+ "details",
80
+ "summary",
81
+ "dfn",
82
+ "dl",
83
+ "dt",
84
+ "dd",
85
+ "kbd",
86
+ "label",
87
+ "nav",
88
+ "pre",
89
+ "q",
90
+ "samp",
91
+ "small",
92
+ "tt",
93
+ "var",
94
+ "footer",
95
+ "header"
68
96
  ]);
69
97
  var v0ElementAttributes = new Map([
98
+ ["a", new Set(["href", "type"])],
70
99
  ["img", new Set(["src", "alt", "width", "height"])],
71
100
  ["audio", new Set(["src", "controls", "loop", "muted", "preload"])],
72
101
  ["video", new Set(["src", "controls", "loop", "muted", "preload", "poster", "width", "height"])],
@@ -74,7 +103,7 @@ var v0ElementAttributes = new Map([
74
103
  ["track", new Set(["src", "kind", "srclang", "label", "default"])],
75
104
  ["object", new Set(["data", "type", "width", "height"])]
76
105
  ]);
77
- var v0UrlAttributes = new Set(["src", "poster", "data"]);
106
+ var v0UrlAttributes = new Set(["src", "poster", "data", "href"]);
78
107
  var v0MathRoot = "math";
79
108
  var v0GlobalAttributes = new Set(["id", "class", "lang", "xml:lang", "dir"]);
80
109
  var v0ContentModel = {
@@ -111,7 +140,8 @@ function sanitizeAttributes(model, elementName, attributes) {
111
140
  if (isUnsafeAttribute(name, value)) {
112
141
  continue;
113
142
  }
114
- if (!model.globalAttributes.has(name) && !elementAllowed?.has(name)) {
143
+ const ariaOrData = name === "role" || name.startsWith("aria-") || name.startsWith("data-");
144
+ if (!ariaOrData && !model.globalAttributes.has(name) && !elementAllowed?.has(name)) {
115
145
  continue;
116
146
  }
117
147
  if (typeof value === "string") {
@@ -538,6 +568,9 @@ function convertRpRule(rule) {
538
568
  } : {}
539
569
  };
540
570
  }
571
+ if (kind === "responseProcessingFragment") {
572
+ return { kind, rules: (Array.isArray(record["rules"]) ? record["rules"] : []).map(convertRpRule) };
573
+ }
541
574
  return {
542
575
  kind,
543
576
  ...typeof record["identifier"] === "string" ? { identifier: record["identifier"] } : {},
@@ -580,6 +613,29 @@ function convertResponseDeclaration(declaration) {
580
613
  const areaMapEntries = asRecords(areaMapping["areaMapEntries"]).map((entry) => withNumericCoords(entry));
581
614
  return { ...declaration, areaMapping: { ...areaMapping, areaMapEntries } };
582
615
  }
616
+ function appendCatalogViews(target, value) {
617
+ if (Array.isArray(value)) {
618
+ for (const entry of value) {
619
+ appendCatalogViews(target, entry);
620
+ }
621
+ return;
622
+ }
623
+ if (!isRecord(value)) {
624
+ return;
625
+ }
626
+ const catalogInfo = value["catalogInfo"];
627
+ if (isRecord(catalogInfo) && Array.isArray(catalogInfo["catalogs"])) {
628
+ target.push(...catalogInfo["catalogs"]);
629
+ }
630
+ appendCatalogViews(target, value["content"]);
631
+ appendCatalogViews(target, value["children"]);
632
+ }
633
+ function documentCatalogViews(root, convertedContent) {
634
+ const catalogs = [];
635
+ appendCatalogViews(catalogs, isRecord(root["catalogInfo"]) ? { catalogInfo: convertContentValue(root["catalogInfo"]) } : undefined);
636
+ appendCatalogViews(catalogs, convertedContent);
637
+ return catalogs;
638
+ }
583
639
  function assessmentItemViewFromNormalized(document) {
584
640
  if (!isRecord(document) || !isRecord(document["assessmentItem"])) {
585
641
  return null;
@@ -588,6 +644,8 @@ function assessmentItemViewFromNormalized(document) {
588
644
  const itemBody = isRecord(item["itemBody"]) ? item["itemBody"] : {};
589
645
  const content = Array.isArray(itemBody["content"]) ? itemBody["content"].map(convertContentEntry) : [];
590
646
  const templateRules = isRecord(item["templateProcessing"]) ? item["templateProcessing"]["rules"] : undefined;
647
+ const convertedModalFeedbacks = Array.isArray(item["modalFeedbacks"]) ? item["modalFeedbacks"].map(convertContentValue) : undefined;
648
+ const catalogs = documentCatalogViews(item, [content, convertedModalFeedbacks]);
591
649
  return {
592
650
  responseDeclarations: asRecords(item["responseDeclarations"]).map(convertResponseDeclaration),
593
651
  outcomeDeclarations: item["outcomeDeclarations"] ?? [],
@@ -599,10 +657,29 @@ function assessmentItemViewFromNormalized(document) {
599
657
  }
600
658
  } : {},
601
659
  ...typeof item["adaptive"] === "boolean" ? { adaptive: item["adaptive"] } : {},
602
- ...Array.isArray(item["modalFeedbacks"]) ? { modalFeedbacks: item["modalFeedbacks"].map(convertContentValue) } : {},
660
+ ...convertedModalFeedbacks ? { modalFeedbacks: convertedModalFeedbacks } : {},
661
+ ...catalogs.length ? { catalogs } : {},
662
+ ...isRecord(item["companionMaterialsInfo"]) ? { companionMaterials: item["companionMaterialsInfo"] } : {},
663
+ ...Array.isArray(item["assessmentStimulusRefs"]) ? {
664
+ assessmentStimulusRefs: asRecords(item["assessmentStimulusRefs"]).map((ref) => ({
665
+ identifier: typeof ref["identifier"] === "string" ? ref["identifier"] : "",
666
+ href: typeof ref["href"] === "string" ? ref["href"] : "",
667
+ ...typeof ref["title"] === "string" ? { title: ref["title"] } : {}
668
+ }))
669
+ } : {},
603
670
  itemBody: { content }
604
671
  };
605
672
  }
673
+ function stimulusContentFromNormalized(document) {
674
+ if (!isRecord(document) || !isRecord(document["assessmentStimulus"])) {
675
+ return null;
676
+ }
677
+ const stimulus = document["assessmentStimulus"];
678
+ const body = isRecord(stimulus["stimulusBody"]) ? stimulus["stimulusBody"] : {};
679
+ const content = Array.isArray(body["content"]) ? body["content"].map(convertContentEntry) : [];
680
+ const catalogs = documentCatalogViews(stimulus, content);
681
+ return { content, ...catalogs.length ? { catalogs } : {} };
682
+ }
606
683
  function convertPreConditions(value) {
607
684
  return asRecords(value).map((wrapper) => convertExpression(wrapper["expression"]));
608
685
  }
@@ -628,6 +705,9 @@ function convertOutcomeRule(rule) {
628
705
  } : {}
629
706
  };
630
707
  }
708
+ if (kind === "outcomeProcessingFragment") {
709
+ return { kind, rules: (Array.isArray(record["rules"]) ? record["rules"] : []).map(convertOutcomeRule) };
710
+ }
631
711
  return {
632
712
  kind,
633
713
  ...typeof record["identifier"] === "string" ? { identifier: record["identifier"] } : {},
@@ -651,6 +731,12 @@ function convertItemRef(ref) {
651
731
  ...ref["preConditions"] !== undefined ? { preConditions: convertPreConditions(ref["preConditions"]) } : {},
652
732
  ...ref["branchRules"] !== undefined ? { branchRules: convertBranchRules(ref["branchRules"]) } : {},
653
733
  ...Array.isArray(ref["weights"]) ? { weights: ref["weights"] } : {},
734
+ ...Array.isArray(ref["templateDefaults"]) ? {
735
+ templateDefaults: asRecords(ref["templateDefaults"]).map((entry) => ({
736
+ templateIdentifier: typeof entry["templateIdentifier"] === "string" ? entry["templateIdentifier"] : "",
737
+ expression: convertExpression(entry["expression"])
738
+ }))
739
+ } : {},
654
740
  ...sessionControlAndTimeLimits(ref)
655
741
  };
656
742
  }
@@ -663,6 +749,7 @@ function convertSection(section) {
663
749
  ...typeof section["visible"] === "boolean" ? { visible: section["visible"] } : {},
664
750
  ...typeof section["fixed"] === "boolean" ? { fixed: section["fixed"] } : {},
665
751
  ...typeof section["required"] === "boolean" ? { required: section["required"] } : {},
752
+ ...typeof section["keepTogether"] === "boolean" ? { keepTogether: section["keepTogether"] } : {},
666
753
  ...isRecord(section["selection"]) ? { selection: section["selection"] } : {},
667
754
  ...isRecord(section["ordering"]) ? { ordering: section["ordering"] } : {},
668
755
  ...section["preConditions"] !== undefined ? { preConditions: convertPreConditions(section["preConditions"]) } : {},
@@ -706,6 +793,715 @@ function assessmentTestViewFromNormalized(document) {
706
793
  ...Array.isArray(testDocument["testFeedbacks"]) ? { testFeedbacks: asRecords(testDocument["testFeedbacks"]).map(convertTestFeedback) } : {}
707
794
  };
708
795
  }
796
+ // ../../node_modules/.bun/whynot@5.0.0/node_modules/whynot/dist/whynot.esm.js
797
+ function t(t2, s, r, i) {
798
+ const n = { op: s, func: r, data: i };
799
+ return t2.push(n), n;
800
+ }
801
+ function s(t2, s2) {
802
+ return t2;
803
+ }
804
+
805
+ class r {
806
+ constructor() {
807
+ this.program = [];
808
+ }
809
+ test(s2, r2) {
810
+ return t(this.program, 5, s2, r2 === undefined ? null : r2);
811
+ }
812
+ jump(s2) {
813
+ return t(this.program, 3, null, s2);
814
+ }
815
+ record(r2, i) {
816
+ return t(this.program, 4, i === undefined ? s : i, r2);
817
+ }
818
+ bad(s2 = 1) {
819
+ return t(this.program, 1, null, s2);
820
+ }
821
+ accept() {
822
+ return t(this.program, 0, null, null);
823
+ }
824
+ fail(s2) {
825
+ return t(this.program, 2, s2 || null, null);
826
+ }
827
+ }
828
+
829
+ class i {
830
+ constructor(t2, s2, r2) {
831
+ this.programLength = t2, this.maxFromByPc = s2, this.maxSurvivorFromByPc = r2;
832
+ }
833
+ static fromProgram(t2) {
834
+ const s2 = t2.length, r2 = [], n = [];
835
+ return t2.forEach((t3) => {
836
+ r2.push(0), n.push(0);
837
+ }), t2.forEach((t3, i2) => {
838
+ switch (t3.op) {
839
+ case 2:
840
+ if (t3.func === null)
841
+ return;
842
+ if (i2 + 1 >= s2)
843
+ throw new Error("Invalid program: program could run past end");
844
+ r2[i2 + 1] += 1;
845
+ break;
846
+ case 1:
847
+ case 4:
848
+ if (i2 + 1 >= s2)
849
+ throw new Error("Invalid program: program could run past end");
850
+ r2[i2 + 1] += 1;
851
+ break;
852
+ case 3:
853
+ t3.data.forEach((t4) => {
854
+ if (t4 < 0 || t4 >= s2)
855
+ throw new Error("Invalid program: program could run past end");
856
+ r2[t4] += 1;
857
+ });
858
+ break;
859
+ case 5:
860
+ if (i2 + 1 >= s2)
861
+ throw new Error("Invalid program: program could run past end");
862
+ n[i2 + 1] += 1;
863
+ break;
864
+ case 0:
865
+ n[i2] += 1;
866
+ }
867
+ }), new i(s2, r2, n);
868
+ }
869
+ static createStub(t2) {
870
+ const s2 = [], r2 = [];
871
+ for (let i2 = 0;i2 < t2; ++i2)
872
+ s2.push(t2), r2.push(t2);
873
+ return new i(t2, s2, r2);
874
+ }
875
+ }
876
+
877
+ class n {
878
+ constructor(t2) {
879
+ this.acceptingTraces = t2, this.success = t2.length > 0;
880
+ }
881
+ }
882
+
883
+ class h {
884
+ constructor(t2) {
885
+ this.t = 0, this.i = 0, this.h = new Uint16Array(t2), this.l = new Uint8Array(t2);
886
+ }
887
+ getBadness(t2) {
888
+ return this.l[t2];
889
+ }
890
+ add(t2, s2) {
891
+ this.l[t2] = s2 > 255 ? 255 : s2;
892
+ const r2 = function(t3, s3, r3, i2, n2) {
893
+ let h2 = i2, e = n2;
894
+ for (;h2 < e; ) {
895
+ const i3 = h2 + e >>> 1;
896
+ r3 < s3[t3[i3]] ? e = i3 : h2 = i3 + 1;
897
+ }
898
+ return h2;
899
+ }(this.h, this.l, s2, this.i, this.t);
900
+ this.h.copyWithin(r2 + 1, r2, this.t), this.h[r2] = t2, this.t += 1;
901
+ }
902
+ reschedule(t2, s2) {
903
+ const r2 = Math.max(this.l[t2], s2 > 255 ? 255 : s2);
904
+ if (this.l[t2] !== r2) {
905
+ const s3 = this.h.indexOf(t2, this.i);
906
+ if (s3 < 0 || s3 >= this.t)
907
+ return void (this.l[t2] = r2);
908
+ this.h.copyWithin(s3, s3 + 1, this.t), this.t -= 1, this.add(t2, r2);
909
+ }
910
+ }
911
+ getNextPc() {
912
+ return this.i >= this.t ? null : this.h[this.i++];
913
+ }
914
+ reset() {
915
+ this.t = 0, this.i = 0, this.l.fill(0);
916
+ }
917
+ }
918
+
919
+ class e {
920
+ constructor(t2) {
921
+ this.o = [];
922
+ let s2 = t2.length;
923
+ t2.forEach((t3) => {
924
+ this.o.push(t3 > 0 ? s2 : -1), s2 += t3;
925
+ }), this.u = new Uint16Array(s2);
926
+ }
927
+ clear() {
928
+ this.u.fill(0, 0, this.o.length);
929
+ }
930
+ add(t2, s2) {
931
+ const r2 = this.u[s2], i2 = this.o[s2];
932
+ this.u[s2] += 1, this.u[i2 + r2] = t2;
933
+ }
934
+ has(t2) {
935
+ return this.u[t2] > 0;
936
+ }
937
+ forEach(t2, s2) {
938
+ const r2 = this.u[t2], i2 = this.o[t2];
939
+ for (let t3 = i2;t3 < i2 + r2; ++t3)
940
+ s2(this.u[t3]);
941
+ }
942
+ }
943
+ function l(t2, s2, r2 = false) {
944
+ return t2 === null ? s2 : Array.isArray(t2) ? (t2.indexOf(s2) === -1 && (r2 && (t2 = t2.slice()), t2.push(s2)), t2) : t2 === s2 ? t2 : [t2, s2];
945
+ }
946
+
947
+ class c {
948
+ constructor(t2, s2) {
949
+ this.prefixes = t2, this.record = s2;
950
+ }
951
+ }
952
+ function o(t2, s2) {
953
+ let r2;
954
+ if (s2 === null) {
955
+ if (!Array.isArray(t2))
956
+ return t2;
957
+ r2 = t2;
958
+ } else
959
+ r2 = t2 === c.EMPTY ? [] : Array.isArray(t2) ? t2 : [t2];
960
+ return new c(r2, s2);
961
+ }
962
+ c.EMPTY = new c([], null);
963
+
964
+ class u {
965
+ constructor(t2) {
966
+ this.p = [], this.v = [];
967
+ for (let s2 = 0;s2 < t2; ++s2)
968
+ this.p.push(0), this.v.push(null);
969
+ }
970
+ mergeTraces(t2, s2, r2, i2, n2, h2) {
971
+ let e2 = false;
972
+ return r2.forEach(s2, (s3) => {
973
+ const r3 = this.trace(s3, i2, n2, h2);
974
+ var c2, o2, u2;
975
+ o2 = r3, u2 = e2, t2 = (c2 = t2) === null ? o2 : o2 === null ? c2 : Array.isArray(o2) ? o2.reduce((t3, s4) => l(t3, s4, t3 === o2), c2) : l(c2, o2, u2), e2 = t2 === r3;
976
+ }), t2;
977
+ }
978
+ trace(t2, s2, r2, i2) {
979
+ switch (this.p[t2]) {
980
+ case 2:
981
+ return this.v[t2];
982
+ case 1:
983
+ return null;
984
+ }
985
+ this.p[t2] = 1;
986
+ let n2 = null;
987
+ const h2 = s2[t2];
988
+ if (h2 !== null)
989
+ n2 = h2;
990
+ else if (!r2.has(t2))
991
+ throw new Error("Trace without source at pc " + t2);
992
+ if (n2 = this.mergeTraces(n2, t2, r2, s2, r2, i2), n2 !== null) {
993
+ const s3 = i2[t2];
994
+ s3 !== null && (n2 = o(n2, s3));
995
+ }
996
+ return this.v[t2] = n2, this.p[t2] = 2, n2;
997
+ }
998
+ buildSurvivorTraces(t2, s2, r2, i2, n2) {
999
+ for (let h2 = 0, e2 = t2.length;h2 < e2; ++h2) {
1000
+ if (!r2.has(h2)) {
1001
+ s2[h2] = null;
1002
+ continue;
1003
+ }
1004
+ this.v.fill(null), this.p.fill(0);
1005
+ const e3 = this.mergeTraces(null, h2, r2, t2, i2, n2);
1006
+ if (e3 === null)
1007
+ throw new Error("No non-cyclic paths found to survivor " + h2);
1008
+ s2[h2] = o(e3, null);
1009
+ }
1010
+ this.v.fill(null);
1011
+ }
1012
+ }
1013
+
1014
+ class a {
1015
+ constructor(t2) {
1016
+ this.g = [], this.k = [], this.m = [], this.A = new e(t2.maxFromByPc), this.T = new e(t2.maxSurvivorFromByPc), this.S = new u(t2.programLength);
1017
+ for (let s2 = 0;s2 < t2.programLength; ++s2)
1018
+ this.g.push(null), this.k.push(null), this.m.push(null);
1019
+ this.k[0] = c.EMPTY;
1020
+ }
1021
+ reset(t2) {
1022
+ this.A.clear(), this.T.clear(), this.g.fill(null), t2 && (this.k.fill(null), this.m.fill(null), this.k[0] = c.EMPTY);
1023
+ }
1024
+ record(t2, s2) {
1025
+ this.g[t2] = s2;
1026
+ }
1027
+ has(t2) {
1028
+ return this.A.has(t2) || this.k[t2] !== null;
1029
+ }
1030
+ add(t2, s2) {
1031
+ this.A.add(t2, s2);
1032
+ }
1033
+ hasSurvivor(t2) {
1034
+ return this.T.has(t2);
1035
+ }
1036
+ addSurvivor(t2, s2) {
1037
+ this.T.add(t2, s2);
1038
+ }
1039
+ buildSurvivorTraces() {
1040
+ const t2 = this.k;
1041
+ this.S.buildSurvivorTraces(t2, this.m, this.T, this.A, this.g), this.k = this.m, this.m = t2;
1042
+ }
1043
+ getTraces(t2) {
1044
+ const s2 = t2.reduce((t3, s3) => l(t3, this.k[s3]), null);
1045
+ return s2 === null ? [] : Array.isArray(s2) ? s2 : [s2];
1046
+ }
1047
+ }
1048
+
1049
+ class f {
1050
+ constructor(t2) {
1051
+ this.I = [], this.N = new h(t2.programLength), this.M = new h(t2.programLength), this.P = new a(t2);
1052
+ }
1053
+ reset() {
1054
+ this.N.reset(), this.N.add(0, 0), this.I.length = 0, this.P.reset(true);
1055
+ }
1056
+ getNextThreadPc() {
1057
+ return this.N.getNextPc();
1058
+ }
1059
+ step(t2, s2, r2) {
1060
+ const i2 = this.P.has(s2);
1061
+ this.P.add(t2, s2);
1062
+ const n2 = this.N.getBadness(t2) + r2;
1063
+ i2 ? this.N.reschedule(s2, n2) : this.N.add(s2, n2);
1064
+ }
1065
+ stepToNextGeneration(t2, s2) {
1066
+ const r2 = this.P.hasSurvivor(s2);
1067
+ this.P.addSurvivor(t2, s2);
1068
+ const i2 = this.N.getBadness(t2);
1069
+ r2 ? this.M.reschedule(s2, i2) : this.M.add(s2, i2);
1070
+ }
1071
+ accept(t2) {
1072
+ this.I.push(t2), this.P.addSurvivor(t2, t2);
1073
+ }
1074
+ fail(t2) {}
1075
+ record(t2, s2) {
1076
+ this.P.record(t2, s2);
1077
+ }
1078
+ nextGeneration() {
1079
+ this.P.buildSurvivorTraces(), this.P.reset(false);
1080
+ const t2 = this.N;
1081
+ t2.reset(), this.N = this.M, this.M = t2;
1082
+ }
1083
+ getAcceptingTraces() {
1084
+ return this.P.getTraces(this.I);
1085
+ }
1086
+ }
1087
+
1088
+ class d {
1089
+ constructor(t2) {
1090
+ this.U = [], this.G = t2, this.V = i.fromProgram(t2), this.U.push(new f(this.V));
1091
+ }
1092
+ execute(t2, s2) {
1093
+ const r2 = this.U.pop() || new f(this.V);
1094
+ r2.reset();
1095
+ const i2 = t2.length;
1096
+ let h2, e2 = -1;
1097
+ do {
1098
+ let n2 = r2.getNextThreadPc();
1099
+ if (n2 === null)
1100
+ break;
1101
+ for (++e2, h2 = e2 >= i2 ? null : t2[e2];n2 !== null; ) {
1102
+ const t3 = this.G[n2];
1103
+ switch (t3.op) {
1104
+ case 0:
1105
+ h2 === null ? r2.accept(n2) : r2.fail(n2);
1106
+ break;
1107
+ case 2: {
1108
+ const i3 = t3.func;
1109
+ if (i3 === null || i3(s2)) {
1110
+ r2.fail(n2);
1111
+ break;
1112
+ }
1113
+ r2.step(n2, n2 + 1, 0);
1114
+ break;
1115
+ }
1116
+ case 1:
1117
+ r2.step(n2, n2 + 1, t3.data);
1118
+ break;
1119
+ case 5:
1120
+ if (h2 === null) {
1121
+ r2.fail(n2);
1122
+ break;
1123
+ }
1124
+ if (!(0, t3.func)(h2, t3.data, s2)) {
1125
+ r2.fail(n2);
1126
+ break;
1127
+ }
1128
+ r2.stepToNextGeneration(n2, n2 + 1);
1129
+ break;
1130
+ case 3: {
1131
+ const s3 = t3.data, i3 = s3.length;
1132
+ if (i3 === 0) {
1133
+ r2.fail(n2);
1134
+ break;
1135
+ }
1136
+ for (let t4 = 0;t4 < i3; ++t4)
1137
+ r2.step(n2, s3[t4], 0);
1138
+ break;
1139
+ }
1140
+ case 4: {
1141
+ const i3 = (0, t3.func)(t3.data, e2, s2);
1142
+ i3 != null && r2.record(n2, i3), r2.step(n2, n2 + 1, 0);
1143
+ break;
1144
+ }
1145
+ }
1146
+ n2 = r2.getNextThreadPc();
1147
+ }
1148
+ r2.nextGeneration();
1149
+ } while (h2 !== null);
1150
+ const l2 = new n(r2.getAcceptingTraces());
1151
+ return r2.reset(), this.U.push(r2), l2;
1152
+ }
1153
+ }
1154
+ function w(t2) {
1155
+ const s2 = new r;
1156
+ return t2(s2), new d(s2.program);
1157
+ }
1158
+
1159
+ // ../../node_modules/.bun/xspattern@3.1.0/node_modules/xspattern/dist/xspattern.esm.js
1160
+ function B(A) {
1161
+ return (B2) => B2 === A;
1162
+ }
1163
+ function a2(A, B2) {
1164
+ if (A === null || B2 === null)
1165
+ throw new Error("unescaped hyphen may not be used as a range endpoint");
1166
+ if (B2 < A)
1167
+ throw new Error("character range is in the wrong order");
1168
+ return (a3) => A <= a3 && a3 <= B2;
1169
+ }
1170
+ function n2(A) {
1171
+ return true;
1172
+ }
1173
+ function e2() {
1174
+ return false;
1175
+ }
1176
+ function t2(A, B2) {
1177
+ return (a3) => A(a3) || B2(a3);
1178
+ }
1179
+ function G(A, B2) {
1180
+ switch (B2.kind) {
1181
+ case "predicate":
1182
+ return void A.test(B2.value);
1183
+ case "regexp":
1184
+ return void r2(A, B2.value, false);
1185
+ }
1186
+ }
1187
+ function i2(A, B2) {
1188
+ B2.forEach((B3) => {
1189
+ (function(A2, B4) {
1190
+ const [a3, { min: n3, max: e3 }] = B4;
1191
+ if (e3 !== null) {
1192
+ for (let B5 = 0;B5 < n3; ++B5)
1193
+ G(A2, a3);
1194
+ for (let B5 = n3;B5 < e3; ++B5) {
1195
+ const B6 = A2.jump([]);
1196
+ B6.data.push(A2.program.length), G(A2, a3), B6.data.push(A2.program.length);
1197
+ }
1198
+ } else if (n3 > 0) {
1199
+ for (let B6 = 0;B6 < n3 - 1; ++B6)
1200
+ G(A2, a3);
1201
+ const B5 = A2.program.length;
1202
+ G(A2, a3), A2.jump([B5]).data.push(A2.program.length);
1203
+ } else {
1204
+ const B5 = A2.program.length, n4 = A2.jump([]);
1205
+ n4.data.push(A2.program.length), G(A2, a3), A2.jump([B5]), n4.data.push(A2.program.length);
1206
+ }
1207
+ })(A, B3);
1208
+ });
1209
+ }
1210
+ function r2(A, B2, a3) {
1211
+ const n3 = A.program.length, e3 = A.jump([]);
1212
+ a3 && (e3.data.push(A.program.length), A.test(() => true), A.jump([n3]));
1213
+ const t3 = [];
1214
+ if (B2.forEach((B3) => {
1215
+ e3.data.push(A.program.length), i2(A, B3), t3.push(A.jump([]));
1216
+ }), t3.forEach((B3) => {
1217
+ B3.data.push(A.program.length);
1218
+ }), a3) {
1219
+ const B3 = A.program.length, a4 = A.jump([]);
1220
+ a4.data.push(A.program.length), A.test(() => true), A.jump([B3]), a4.data.push(A.program.length);
1221
+ }
1222
+ }
1223
+ function o2(A, B2) {
1224
+ return { success: true, offset: A, value: B2 };
1225
+ }
1226
+ function l2(A) {
1227
+ return o2(A, undefined);
1228
+ }
1229
+ function H(A, B2, a3 = false) {
1230
+ return { success: false, offset: A, expected: B2, fatal: a3 };
1231
+ }
1232
+ function C(A) {
1233
+ return (B2, a3) => {
1234
+ const n3 = a3 + A.length;
1235
+ return B2.slice(a3, n3) === A ? o2(n3, A) : H(a3, [A]);
1236
+ };
1237
+ }
1238
+ function u2(A, B2) {
1239
+ return (a3, n3) => {
1240
+ const e3 = A(a3, n3);
1241
+ return e3.success ? o2(e3.offset, B2(e3.value)) : e3;
1242
+ };
1243
+ }
1244
+ function s2(A, B2, a3, n3) {
1245
+ return (e3, t3) => {
1246
+ const G2 = A(e3, t3);
1247
+ return G2.success ? B2(G2.value) ? G2 : H(t3, a3, n3) : G2;
1248
+ };
1249
+ }
1250
+ function c2(A, B2) {
1251
+ return (a3, n3) => {
1252
+ let e3 = null;
1253
+ for (const t3 of A) {
1254
+ const A2 = t3(a3, n3);
1255
+ if (A2.success)
1256
+ return A2;
1257
+ if (e3 === null || A2.offset > e3.offset ? e3 = A2 : A2.offset === e3.offset && B2 === undefined && (e3.expected = e3.expected.concat(A2.expected)), A2.fatal)
1258
+ return A2;
1259
+ }
1260
+ return B2 = B2 || (e3 == null ? undefined : e3.expected) || [], e3 && (e3.expected = B2), e3 || H(n3, B2);
1261
+ };
1262
+ }
1263
+ function D(A) {
1264
+ return (B2, a3) => {
1265
+ const n3 = A(B2, a3);
1266
+ return n3.success || n3.fatal ? n3 : o2(a3, null);
1267
+ };
1268
+ }
1269
+ function m(A) {
1270
+ return (B2, a3) => {
1271
+ let n3 = [], e3 = a3;
1272
+ for (;; ) {
1273
+ const a4 = A(B2, e3);
1274
+ if (!a4.success) {
1275
+ if (a4.fatal)
1276
+ return a4;
1277
+ break;
1278
+ }
1279
+ if (n3.push(a4.value), a4.offset === e3)
1280
+ break;
1281
+ e3 = a4.offset;
1282
+ }
1283
+ return o2(e3, n3);
1284
+ };
1285
+ }
1286
+ function I(A, B2, a3) {
1287
+ return (n3, e3) => {
1288
+ const t3 = A(n3, e3);
1289
+ if (!t3.success)
1290
+ return t3;
1291
+ const G2 = B2(n3, t3.offset);
1292
+ return G2.success ? o2(G2.offset, a3(t3.value, G2.value)) : G2;
1293
+ };
1294
+ }
1295
+ function d2(A) {
1296
+ return I(A, m(A), (A2, B2) => [A2].concat(B2));
1297
+ }
1298
+ function h2(A, B2) {
1299
+ return A;
1300
+ }
1301
+ function p(A, B2) {
1302
+ return B2;
1303
+ }
1304
+ function T(A, B2) {
1305
+ return I(A, B2, p);
1306
+ }
1307
+ function F(A, B2) {
1308
+ return I(A, B2, h2);
1309
+ }
1310
+ function E(A, B2, a3, n3 = false) {
1311
+ return T(A, n3 ? f2(F(B2, a3)) : F(B2, a3));
1312
+ }
1313
+ function g(A, B2) {
1314
+ return (a3, n3) => A(a3, n3).success ? H(n3, B2) : l2(n3);
1315
+ }
1316
+ function f2(A) {
1317
+ return (B2, a3) => {
1318
+ const n3 = A(B2, a3);
1319
+ return n3.success ? n3 : H(n3.offset, n3.expected, true);
1320
+ };
1321
+ }
1322
+ var P = (A, B2) => A.length === B2 ? l2(B2) : H(B2, ["end of input"]);
1323
+ var M = ["Lu", "Ll", "Lt", "Lm", "Lo", "Mn", "Mc", "Me", "Nd", "Nl", "No", "Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po", "Zs", "Zl", "Zp", "Sm", "Sc", "Sk", "So", "Cc", "Cf", "Co", "Cn"];
1324
+ var J = {};
1325
+ function S(A) {
1326
+ return A.codePointAt(0);
1327
+ }
1328
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("").forEach((A, B2) => {
1329
+ J[A] = B2;
1330
+ });
1331
+ var K = (A) => A === -1 || A === -2;
1332
+ function b(A) {
1333
+ return (B2) => !K(B2) && !A(B2);
1334
+ }
1335
+ function y(A, B2) {
1336
+ return B2 === null ? A : (a3) => A(a3) && !B2(a3);
1337
+ }
1338
+ var Q = function(A, B2) {
1339
+ const n3 = new Map;
1340
+ let e3 = 0;
1341
+ return A.forEach((A2, G2) => {
1342
+ const i3 = B2[G2];
1343
+ A2 !== null && A2.split("|").forEach((A3) => {
1344
+ const B3 = n3.get(A3), G3 = a2(e3, e3 + i3 - 1);
1345
+ n3.set(A3, B3 ? t2(B3, G3) : G3);
1346
+ }), e3 += i3;
1347
+ }), n3;
1348
+ }(["BasicLatin", "Latin-1Supplement", "LatinExtended-A", "LatinExtended-B", "IPAExtensions", "SpacingModifierLetters", "CombiningDiacriticalMarks", "GreekandCoptic|Greek", "Cyrillic", "CyrillicSupplement", "Armenian", "Hebrew", "Arabic", "Syriac", "ArabicSupplement", "Thaana", "NKo", "Samaritan", "Mandaic", "SyriacSupplement", "ArabicExtended-B", "ArabicExtended-A", "Devanagari", "Bengali", "Gurmukhi", "Gujarati", "Oriya", "Tamil", "Telugu", "Kannada", "Malayalam", "Sinhala", "Thai", "Lao", "Tibetan", "Myanmar", "Georgian", "HangulJamo", "Ethiopic", "EthiopicSupplement", "Cherokee", "UnifiedCanadianAboriginalSyllabics", "Ogham", "Runic", "Tagalog", "Hanunoo", "Buhid", "Tagbanwa", "Khmer", "Mongolian", "UnifiedCanadianAboriginalSyllabicsExtended", "Limbu", "TaiLe", "NewTaiLue", "KhmerSymbols", "Buginese", "TaiTham", "CombiningDiacriticalMarksExtended", "Balinese", "Sundanese", "Batak", "Lepcha", "OlChiki", "CyrillicExtended-C", "GeorgianExtended", "SundaneseSupplement", "VedicExtensions", "PhoneticExtensions", "PhoneticExtensionsSupplement", "CombiningDiacriticalMarksSupplement", "LatinExtendedAdditional", "GreekExtended", "GeneralPunctuation", "SuperscriptsandSubscripts", "CurrencySymbols", "CombiningDiacriticalMarksforSymbols|CombiningMarksforSymbols", "LetterlikeSymbols", "NumberForms", "Arrows", "MathematicalOperators", "MiscellaneousTechnical", "ControlPictures", "OpticalCharacterRecognition", "EnclosedAlphanumerics", "BoxDrawing", "BlockElements", "GeometricShapes", "MiscellaneousSymbols", "Dingbats", "MiscellaneousMathematicalSymbols-A", "SupplementalArrows-A", "BraillePatterns", "SupplementalArrows-B", "MiscellaneousMathematicalSymbols-B", "SupplementalMathematicalOperators", "MiscellaneousSymbolsandArrows", "Glagolitic", "LatinExtended-C", "Coptic", "GeorgianSupplement", "Tifinagh", "EthiopicExtended", "CyrillicExtended-A", "SupplementalPunctuation", "CJKRadicalsSupplement", "KangxiRadicals", null, "IdeographicDescriptionCharacters", "CJKSymbolsandPunctuation", "Hiragana", "Katakana", "Bopomofo", "HangulCompatibilityJamo", "Kanbun", "BopomofoExtended", "CJKStrokes", "KatakanaPhoneticExtensions", "EnclosedCJKLettersandMonths", "CJKCompatibility", "CJKUnifiedIdeographsExtensionA", "YijingHexagramSymbols", "CJKUnifiedIdeographs", "YiSyllables", "YiRadicals", "Lisu", "Vai", "CyrillicExtended-B", "Bamum", "ModifierToneLetters", "LatinExtended-D", "SylotiNagri", "CommonIndicNumberForms", "Phags-pa", "Saurashtra", "DevanagariExtended", "KayahLi", "Rejang", "HangulJamoExtended-A", "Javanese", "MyanmarExtended-B", "Cham", "MyanmarExtended-A", "TaiViet", "MeeteiMayekExtensions", "EthiopicExtended-A", "LatinExtended-E", "CherokeeSupplement", "MeeteiMayek", "HangulSyllables", "HangulJamoExtended-B", "HighSurrogates", "HighPrivateUseSurrogates", "LowSurrogates", "PrivateUseArea|PrivateUse", "CJKCompatibilityIdeographs", "AlphabeticPresentationForms", "ArabicPresentationForms-A", "VariationSelectors", "VerticalForms", "CombiningHalfMarks", "CJKCompatibilityForms", "SmallFormVariants", "ArabicPresentationForms-B", "HalfwidthandFullwidthForms", "Specials", "LinearBSyllabary", "LinearBIdeograms", "AegeanNumbers", "AncientGreekNumbers", "AncientSymbols", "PhaistosDisc", null, "Lycian", "Carian", "CopticEpactNumbers", "OldItalic", "Gothic", "OldPermic", "Ugaritic", "OldPersian", null, "Deseret", "Shavian", "Osmanya", "Osage", "Elbasan", "CaucasianAlbanian", "Vithkuqi", null, "LinearA", "LatinExtended-F", null, "CypriotSyllabary", "ImperialAramaic", "Palmyrene", "Nabataean", null, "Hatran", "Phoenician", "Lydian", null, "MeroiticHieroglyphs", "MeroiticCursive", "Kharoshthi", "OldSouthArabian", "OldNorthArabian", null, "Manichaean", "Avestan", "InscriptionalParthian", "InscriptionalPahlavi", "PsalterPahlavi", null, "OldTurkic", null, "OldHungarian", "HanifiRohingya", null, "RumiNumeralSymbols", "Yezidi", "ArabicExtended-C", "OldSogdian", "Sogdian", "OldUyghur", "Chorasmian", "Elymaic", "Brahmi", "Kaithi", "SoraSompeng", "Chakma", "Mahajani", "Sharada", "SinhalaArchaicNumbers", "Khojki", null, "Multani", "Khudawadi", "Grantha", null, "Newa", "Tirhuta", null, "Siddham", "Modi", "MongolianSupplement", "Takri", null, "Ahom", null, "Dogra", null, "WarangCiti", "DivesAkuru", null, "Nandinagari", "ZanabazarSquare", "Soyombo", "UnifiedCanadianAboriginalSyllabicsExtended-A", "PauCinHau", "DevanagariExtended-A", null, "Bhaiksuki", "Marchen", null, "MasaramGondi", "GunjalaGondi", null, "Makasar", "Kawi", null, "LisuSupplement", "TamilSupplement", "Cuneiform", "CuneiformNumbersandPunctuation", "EarlyDynasticCuneiform", null, "Cypro-Minoan", "EgyptianHieroglyphs", "EgyptianHieroglyphFormatControls", null, "AnatolianHieroglyphs", null, "BamumSupplement", "Mro", "Tangsa", "BassaVah", "PahawhHmong", null, "Medefaidrin", null, "Miao", null, "IdeographicSymbolsandPunctuation", "Tangut", "TangutComponents", "KhitanSmallScript", "TangutSupplement", null, "KanaExtended-B", "KanaSupplement", "KanaExtended-A", "SmallKanaExtension", "Nushu", null, "Duployan", "ShorthandFormatControls", null, "ZnamennyMusicalNotation", null, "ByzantineMusicalSymbols", "MusicalSymbols", "AncientGreekMusicalNotation", null, "KaktovikNumerals", "MayanNumerals", "TaiXuanJingSymbols", "CountingRodNumerals", null, "MathematicalAlphanumericSymbols", "SuttonSignWriting", null, "LatinExtended-G", "GlagoliticSupplement", "CyrillicExtended-D", null, "NyiakengPuachueHmong", null, "Toto", "Wancho", null, "NagMundari", null, "EthiopicExtended-B", "MendeKikakui", null, "Adlam", null, "IndicSiyaqNumbers", null, "OttomanSiyaqNumbers", null, "ArabicMathematicalAlphabeticSymbols", null, "MahjongTiles", "DominoTiles", "PlayingCards", "EnclosedAlphanumericSupplement", "EnclosedIdeographicSupplement", "MiscellaneousSymbolsandPictographs", "Emoticons", "OrnamentalDingbats", "TransportandMapSymbols", "AlchemicalSymbols", "GeometricShapesExtended", "SupplementalArrows-C", "SupplementalSymbolsandPictographs", "ChessSymbols", "SymbolsandPictographsExtended-A", "SymbolsforLegacyComputing", null, "CJKUnifiedIdeographsExtensionB", null, "CJKUnifiedIdeographsExtensionC", "CJKUnifiedIdeographsExtensionD", "CJKUnifiedIdeographsExtensionE", "CJKUnifiedIdeographsExtensionF", null, "CJKCompatibilityIdeographsSupplement", null, "CJKUnifiedIdeographsExtensionG", "CJKUnifiedIdeographsExtensionH", null, "Tags", null, "VariationSelectorsSupplement", null, "SupplementaryPrivateUseArea-A|PrivateUse", "SupplementaryPrivateUseArea-B|PrivateUse"], [128, 128, 128, 208, 96, 80, 112, 144, 256, 48, 96, 112, 256, 80, 48, 64, 64, 64, 32, 16, 48, 96, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 256, 160, 96, 256, 384, 32, 96, 640, 32, 96, 32, 32, 32, 32, 128, 176, 80, 80, 48, 96, 32, 32, 144, 80, 128, 64, 64, 80, 48, 16, 48, 16, 48, 128, 64, 64, 256, 256, 112, 48, 48, 48, 80, 64, 112, 256, 256, 64, 32, 160, 128, 32, 96, 256, 192, 48, 16, 256, 128, 128, 256, 256, 96, 32, 128, 48, 80, 96, 32, 128, 128, 224, 16, 16, 64, 96, 96, 48, 96, 16, 32, 48, 16, 256, 256, 6592, 64, 20992, 1168, 64, 48, 320, 96, 96, 32, 224, 48, 16, 64, 96, 32, 48, 48, 32, 96, 32, 96, 32, 96, 32, 48, 64, 80, 64, 11184, 80, 896, 128, 1024, 6400, 512, 80, 688, 16, 16, 16, 32, 32, 144, 240, 16, 128, 128, 64, 80, 64, 48, 128, 32, 64, 32, 48, 32, 48, 32, 64, 32, 80, 48, 48, 80, 48, 64, 80, 64, 384, 64, 64, 64, 32, 32, 48, 48, 32, 32, 32, 64, 32, 96, 96, 32, 32, 32, 64, 64, 32, 32, 48, 80, 80, 48, 128, 64, 288, 32, 64, 64, 48, 64, 64, 48, 32, 128, 80, 48, 80, 48, 96, 32, 80, 48, 48, 80, 128, 128, 128, 96, 160, 128, 96, 32, 80, 48, 80, 176, 80, 80, 96, 96, 64, 96, 80, 96, 16, 64, 96, 160, 112, 80, 64, 96, 80, 304, 32, 96, 80, 16, 64, 1024, 128, 208, 2624, 112, 1072, 48, 4000, 640, 8576, 576, 48, 96, 48, 144, 688, 96, 96, 160, 64, 32, 6144, 768, 512, 128, 8816, 16, 256, 48, 64, 400, 2304, 160, 16, 4688, 208, 48, 256, 256, 80, 112, 32, 32, 96, 32, 128, 1024, 688, 1104, 256, 48, 96, 112, 80, 320, 48, 64, 464, 48, 736, 32, 224, 32, 96, 784, 80, 64, 80, 176, 256, 256, 48, 112, 96, 256, 256, 768, 80, 48, 128, 128, 128, 256, 256, 112, 144, 256, 1024, 42720, 32, 4160, 224, 5776, 7488, 3088, 544, 1504, 4944, 4192, 711760, 128, 128, 240, 65040, 65536, 65536]);
1349
+ var x = function(A) {
1350
+ const n3 = new Map, G2 = A.split(""), i3 = M.map(() => []);
1351
+ let r3 = 0, o3 = 0;
1352
+ for (;o3 < G2.length; ) {
1353
+ const A2 = J[G2[o3]], n4 = (31 & A2) - 2;
1354
+ let e3 = 1 + J[G2[o3 + 1]];
1355
+ switch (32 & A2 ? (e3 += J[G2[o3 + 2]] << 6, e3 += J[G2[o3 + 3]] << 12, e3 += J[G2[o3 + 4]] << 18, o3 += 5) : o3 += 2, n4) {
1356
+ case -2: {
1357
+ let A3 = 0;
1358
+ for (let a3 = r3;a3 < r3 + e3; ++a3) {
1359
+ i3[A3].push(B(a3)), A3 = (A3 + 1) % 2;
1360
+ }
1361
+ break;
1362
+ }
1363
+ case -1:
1364
+ break;
1365
+ default: {
1366
+ const A3 = i3[n4];
1367
+ e3 === 1 ? A3.push(B(r3)) : A3.push(a2(r3, r3 + e3 - 1));
1368
+ break;
1369
+ }
1370
+ }
1371
+ r3 += e3;
1372
+ }
1373
+ const l3 = new Map;
1374
+ return M.forEach((A2, B2) => {
1375
+ const a3 = i3[B2].reduce(t2, e2);
1376
+ n3.set(A2, a3);
1377
+ const G3 = A2.charAt(0), r4 = l3.get(G3) || [];
1378
+ l3.set(G3, r4), r4.push(a3);
1379
+ }), l3.forEach((A2, B2) => {
1380
+ n3.set(B2, A2.reduce(t2, e2));
1381
+ }), n3;
1382
+ }("bfUATCYATCPAQATAXATAOATBKJTBXCTBCZPATAQAZANAZADZPAXAQAXAbgUATAYDaATAZAaAGARAXAcAaAZAaAXAMBZADATBZAMAGASAMCTACWXACGDXXADHA3DAAPDAAtCAAFDBCAADCAABCCDBCCABCAABCCDCCAABCAAFCAADDAABCAABCBADCBDBGACADCGDCAEADACAEADACAEADAAPDAARDACAEADAABCBA7DFCAABCBDBABCCAJjDBAAGADaFRZDFLZNFEZGFAZAFAZQnvBAAADFAZACADABBFADCTACABDZBCATACCBACABACAABCQBACIDiCADBCCDCAXDDCADAXAABCBDBCyDvAhaAHEJBA1CAANDAgfBAABAClBBFATFDoTAOABBaBYABAHsOAHATAHBTAHBTAHABHGaBDGDTBBKcFXCTBYATBaBHKTAcATCGfFAGJHUKJTDGBHAmiBAATAGAHGcAaAHFFBHBaAHDGBKJGCaBGATNBAcAGAHAGdHaBBmYBAAHKGABNKJGgHIFBaATCFABBHAYBGVHDFAHIFAHCFAHEBBTOBAGYHCBBTABAGKBEGXZAGFBAcBBFHHGoFAHXcAHfIAG1HAIAHAGAICHHIDHAIBGAHGGJHBTBKJTAFAGOHAIBBAGHBBGBBBGVBAGGBAGABCGDBBHAGAICHDBBIBBBIBHAGABHIABDGBBAGCHBBBKJGBYBMFaAYAGATAHABBHBIABAGFBDGBBBGVBAGGBAGBBAGBBAGBBBHABAICHBBDHBBBHCBCHABGGDBAGABGKJHBGCHATABJHBIABAGIBAGCBAGVBAGGBAGBBAGEBBHAGAICHEBAHBIABAIBHABBGABOGBHBBBKJTAYABGGAHFBAHAIBBAGHBBGBBBGVBAGGBAGBBAGEBBHAGAIAHAIAHDBBIBBBIBHABGHBIABDGBBAGCHBBBKJaAGAMFBJHAGABAGFBCGCBAGDBCGBBAGABAGBBCGBBCGCBCGLBDIBHAIBBCICBAICHABBGABFIABNKJMCaFYAaABEHAICHAGHBAGCBAGWBAGPBBHAGAHCIDBAHCBAHDBGHBBAGCBBGABBGBHBBBKJBGTAMGaAGAHAIBTAGHBAGCBAGWBAGJBAGEBBHAGAIAHAIEBAHAIBBAIBHBBGIBBFGBBAGBHBBBKJBAGBIABLHBIBGIBAGCBAGoHBGAICHDBAICBAICHAGAaABDGCIAMGGCHBBBKJMIaAGFBAHAIBBAGRBCGXBAGIBAGABBGGBCHABDICHCBAHABAIHBFKJBBIBTABLGvHAGBHGBDYAGFFAHHTAKJTBBkGBBAGABAGEBAGXBAGABAGJHAGBHIGABBGEBAFABAHGBAKJBBGDBfGAaCTOaATAaCHBaFKJMJaAHAaAHAaAHAPAQAPAQAIBGHBAGjBDHNIAHETAHBGEHKBAHjBAaHHAaFBAaBTEaDTBBkGqIBHDIAHFIAHBIBHBGAKJTFGFIBHBGDHCGAICGBIGGCHDGMHAIBHBIFHAGAIAKJICHAaBClBACABECABBDqTAFADCmIFAABAGDBBGGBAGABAGDBBGoBAGDBBGgBAGDBBGGBAGABAGDBBGOBAG4BAGDBBmCBAABBHCTIMTBCGPaJBFiVBAABBDFBBOAmrJAAaATAGQUAGZPAQABCmKBAATCLCGHBGGRHCIABIGSHBIATBBIGRHBBLGMBAGCBAHBBLGzHBIAHGIHHAIBHKTCFATCYAGAHABBKJBFMJBFTFOATDHCcAHAKJBFGiFAG0BGGEHBGhHAGABEmFBAABJGeBAHCIDHBICBDIBHAIFHCBDaABCTBKJGdBBGEBKGrBDGZBFKJMABCahGWHBIBHABBTBG0IAHAIAHGBAHAIAHAIBHHIFHJBBHAKJBFKJBFTGFATFBBHNJAHPBwHDIAGuHAIAHEIAHAIEHAIBGHBCKJTGaJHIaITBBAHBIAGdIAHDIBHBIAHCGBKJGrHAIAHBICHAIAHCIBBHTDGjIHHHIBHBBCTEKJBCGCKJGdFFTBDIBGCqBBCCTHBHHCTAHMIAHGGDHAGFHAGBIAHBGABEDrF+DMFADhFkH/gVCAADHghBAADHCHDFBBCFBBDHCHDHCHDFBBCFBBDHBACABACABACABACADHCHDNBBDHEHDHEHDHEHDEBADBCDEAZADAZCDCBADBCDEAZCDDBBDBCDBAZCDHCEZCBBDCBADBCDEAZBBAUKcEOFTBRASAPARBSAPARATHVAWAcEUATIRASATDNBTCXAPAQATKXATANATJUAcEBAcJMAFABBMFXCPAQAFAMJXCPAQABAFMBCYgBOHMJDHAJCHLBOaBCAaDCAaBDACCDBCCDAaACAaBXACEaFCAaACAaACAaACDaADACDDAGDDAaBDBCBXECADDaAXAaBDAaAMPLiCADALDMAaBBDXEaEXBaDXAaBXAaBXAaGXAaeXBaBXAaAXAae3LEAAaHPAQAPAQAaTXBaGPAQA6QBAAXAadXYanXF6EBAABYaKBUM76NBAAMV62CAAXAaIXAa1XH6uBAAXA63DAAPAQAPAQAPAQAPAQAPAQAPAQAPAQAMdarXEPAQAXePAQAPAQAPAQAPAQAPAQAXP6/DAA3CCAAPAQAPAQAPAQAPAQAPAQAPAQAPAQAPAQAPAQAPAQAPAQAX+PAQAPAQAXfPAQA3BEAAavXUaBXFamBBafBA6oBAACvDvABCCDBAFCCADDACADFFBCBgjBAADAaFADHCCADABETDMATBDlBADABEDABBG3BGFATABNHAGWBIGGBAGGBAGGBAGGBAGGBAGGBAGGBAGGBAHfTBRASARASATCRASATARASATIOATBOATARASATBRASAPAQAPAQAPAQAPAQATEFATJOBTDOATAPATMaBTCPAQAPAQAPAQAPAQAOABhaZBA6YBAABL6VDAABZaLBDUATCaAFAGALAPAQAPAQAPAQAPAQAPAQAaBPAQAPAQAPAQAPAQAOAPAQBaALIHDIBOAFEaBLCFAGATAaBBAmVBAABBHBZBFBGAOAmZBAATAFCGABEGqBAmdBAABAaBMDaJGfajBLGPaeBAMJadMHaAMOafMJamMO6/EAAm/mBAa/mUIFAFAm2RAABCa2BIGnFFTBmLEAAFATCGPKJGBBTAtGAHAJCTAHJTAFAAbFBHBmFBAALJHBTFBHZWFIZBANDBA9FADHADCAAJFAZBADGAADDBATCDABCDAPCCADBECADABADABADAADBXFCCADAGAFBDAGGHAGCHAGDHAGWIBHBIAaDHABCMFaBYAaABFGzTDBHIBGxIPHBBHTBKJBFHRGFTCGATAGBHAKJGbHHTBGWHKIBBKTAGcBCHCIAGuHAIBHDIBHBICTMBAFAKJBDTBGEHAFAGIKJGEBAGoHFIBHBIBHBBIGCHAGHHAIABBKJBBTDGPFAGFaCGAIAHAIAGxHAGAHCGBHBGEHBGAHAGABXGBFATBGKIAHBIBTBGAFBIAHABJGFBBGFBBGFBIGGBAGGBADqZAFDDIFAZBBDjPBAAGiIBHAIBHAIBTAIAHABBKJBFmjuCABLGWBDGwhDgAA9/jBAmtFAABBmpBAABlDGBLDEBEGAHAGJXAGMBAGEBAGABAGBBAGBBAmrBAAZQBPmqFAAQAPAaPG/BBG1BGaABfGLYAaCHPTGPAQATABFHPTAOBNBPAQAPAQAPAQAPAQAPAQAPAQAPAQAPAQATBPAQATDNCTCBATDOAPAQAPAQAPAQATCXAOAXCBATAYATBBDGEBAmGCAABBcABATCYATCPAQATAXATAOATBKJTBXCTBCZPATAQAZANAZADZPAXAQAXAPAQATAPAQATBGJFAGsFBGeBCGFBBGFBBGFBBGCBCYBXAZAaAYBBAaAXDaBBJcCaBBBGLBAGZBAGSBAGBBAGOBBGNBhm6BAABETCBDMsBCaIL0MDaQMBaCBAaMBCaABuasHAhBCAAGcBCGwBOHAMaBDGfMDBIGTLAGHLABEGlHEBEGdBATAGjBDGHTALEBpCnDnmNBAABBKJBFCjBDDjBDGnBHGzBKTACKBACOBACGBACBBADKBADOBADGBADBhCBAAm2EAABIGVBJGHBXFFBAFpBAFIhEBAAGFBBGABAGrBAGBBCGABBGWBATAMHGWaBMGGeBHMIBvGSBAGBBEMEGVMFBCTAGZBETAB/G3BDMBGBMPBBMtGAHCBAHBBEHDGDBAGCBAGcBBHCBDHAMIBGTIBGGcMBTAGcMCBfGHaAGbHBBDMETGBIG1BCTGGVBBMHGSBEMHGRBGTDBLMGhPBAAmIBAAB2CyBMDyBGMFGjHDBHKJhlEAAMeBAGpBAHBOABBGBhKBAAHCGcMJGABHGVHKMDTEBVGRHDTDBlGUMGBTGWBIIAHAIAG0HOTGBDMTKJHAGBHBGABIHCIAGsICHDIBHBTBcATDHABJcABBGYBGKJBFHCGjHEIAHHBAKJTDGAIBGABHGiHATBGABIHBIAGvICHIIBGDTDHDTAIAHAKJGATAGATCBAMTBKGRBAGYICHCIBHAIAHBTFHAGBHAB9GGBAGABAGDBAGOBAGJTABFGuHAICHHBEKJBFHBIBBAGHBBGBBBGVBAGGBAGBBAGEBAHBGAIBHAIDBBIBBBICBBGABFIABEGEIBBBHGBCHEhKCAAG0ICHHIBHCIAHAGDTEKJTBBATAHAGCBdGvICHFIAHAIDHBIAHBGBTAGABHKJhlCAAGuICHDBBIDHBIAHBTWGDHBBhGvICHHIBHAIAHBTCGABKKJBFTMBSGqHAIAHAIBHFIAHAGATABFKJB1GaBBHCIBHDIAHEBDKJMBTCaAGGh4CAAGrICHIIAHBTAhjBAACfDfKJMIBLGHBBGABBGHBAGBBAGXIFBAIBBBHBIAHAGAIAGAIAHATCBIKJhFBAAGHBBGmICHDBBHBIDHAGATAGAIABaGAHJGnHFIAGAHDTHHABHGAHFIBHCGtHMIAHBTCGATEBMmIBAABGTJh1DAAGIBAGkIAHGBAHFIAHAGATEBJKJMSBCTBGdBBHVBAIAHGIAHBIAHBhIBAAGGBAGBBAGlHFBCHABAHBBAHGGAHABHKJBFGFBAGBBAGfIEBAHBBAIBHAIAHAGABGKJh1EAAGSHBIBTBBGHBGAIAGMBAGhIBHEBCIBHAIAHATMKJhVBAAGABOMUaHYDaQBMTAmZOAAhlBAAruBAABATEBKmDDAAhLpAAmgBAATBBMmvQAAcPHAGFHOhp+AAmGJAAh4GCAm4IAABGGeBAKJBDTBmOBAABAKJBFGdBBHETABJGvHGTEaDFDTAaABJKJBAMGBAGUBEGShvKAACfDfMWTDhkBAAmKBAABDHAGAI2BGHDFMB/FBTAFAHABKIBBNm3fBABHmVTAABpGIhmLCAFDBAFGBAFBBAmiEAABOGABcGCBBGABNGDBHmLGAAhDkAAmqBAABEGMBCGIBGGJBBaAHBTAcDhbJBAHtBBHWBI6zBAAB761DAABJamBBa7IBHCaCIFcHHHaBHGadHDa8BU6BBAAHCaAh5BAAMTBLMTBL6WBAABIMYhGCAACZDZCZDGBADRCZDZCABACBBBCABBCBBBCDBACHDDBADABADGBADKCZDZCBBACDBBCHBACGBADZCBBACDBACEBACABCCGBADZCZDZCZDZCZDZCZDZCZDZCZDbBBCYXADYXADFCYXADYXADFCYXADYXADFCYXADYXADFCYXADYXADFCADABBKx6/HAAH2aDHxaHHAaNHAaBTEBOHEBAHOhPRAADJGADTBFDFhUDAAHGBAHQBBHGBAHBBAHEBEF9BgHAhvBAAGsBCHGFGBBKJBDGAaAh/EAAGdHABQGrHDKJBEYAhPHAAGaFAHDKJhlLAAGGBAGDBAGBBAGOBAmEDAABBMIHGBoChDhHGFABDKJBDTBhQMAAM6aAMCYAMDhLBAAMsaAMOhBDAAGDBAGaBAGBBAGABBGABAGJBAGDBAGABAGABFGABDGABAGABAGABAGCBAGBBAGABBGABAGABAGABAGABAGABAGBBAGABBGDBAGGBAGDBAGDBAGABAGJBAGQBEGCBAGEBAGQBzXBhNEAAarBD6jBAABLaOBBaOBAaOBAakBJMM6gCAAB3acBMarBDaIBGaBBNaFhZCAA66DAAZE6XLAABDaQBCaMBC62BAABD6eBAABFaLBDaABOaLBDa3BHaJBFanBHadBBaBhNBAA6TFAABLaNBBaMBCaIBGatBAaGBHaNBDaIBGaIBG6SCAABAa2BkKJhFQAAmfbKABfm5ABABFmdDAABBmBaBABNmw0BAhewAAmdIAAhhXAAmKNBABEmfBBAhQxtCcABd8fBAAh/BAAnvDAAhP4PA99/PABB99/PA");
1383
+ function L(A) {
1384
+ return A === 32 || A === 9 || A === 10 || A === 13;
1385
+ }
1386
+ var X = [B(S(":")), a2(S("A"), S("Z")), B(S("_")), a2(S("a"), S("z")), a2(192, 214), a2(216, 246), a2(192, 214), a2(216, 246), a2(248, 767), a2(880, 893), a2(895, 8191), a2(8204, 8205), a2(8304, 8591), a2(11264, 12271), a2(12289, 55295), a2(63744, 64975), a2(65008, 65533), a2(65536, 983039)].reduce(t2);
1387
+ var Z = [X, B(S("-")), B(S(".")), a2(S("0"), S("9")), B(183), a2(768, 879), a2(8255, 8256)].reduce(t2);
1388
+ var O = x.get("Nd");
1389
+ var k = b(O);
1390
+ var N = y(a2(0, 1114111), [x.get("P"), x.get("Z"), x.get("C")].reduce(t2));
1391
+ var v = b(N);
1392
+ function w2(A) {
1393
+ return A !== 10 && A !== 13 && !K(A);
1394
+ }
1395
+ var Y = { s: L, S: b(L), i: X, I: b(X), c: Z, C: b(Z), d: O, D: k, w: N, W: v };
1396
+ var U = C("*");
1397
+ var j = C("\\");
1398
+ var R = C("{");
1399
+ var V = C("}");
1400
+ var W = C("[");
1401
+ var q = C("]");
1402
+ var z = C("^");
1403
+ var $ = C("$");
1404
+ var _ = C(",");
1405
+ var AA = C("-");
1406
+ var BA = C("(");
1407
+ var aA = C(")");
1408
+ var nA = C(".");
1409
+ var eA = C("|");
1410
+ var tA = C("+");
1411
+ var GA = C("?");
1412
+ var iA = C("-[");
1413
+ var rA = S("0");
1414
+ function oA(A) {
1415
+ function e3(A2) {
1416
+ return new Set(A2.split("").map((A3) => S(A3)));
1417
+ }
1418
+ function G2(A2, B2) {
1419
+ const a3 = A2.codePointAt(B2);
1420
+ return a3 === undefined ? H(B2, ["any character"]) : o2(B2 + String.fromCodePoint(a3).length, a3);
1421
+ }
1422
+ const i3 = A.language === "xpath" ? T(j, c2([u2(C("n"), () => 10), u2(C("r"), () => 13), u2(C("t"), () => 9), u2(c2([j, eA, nA, AA, z, GA, U, tA, R, V, $, BA, aA, W, q]), (A2) => S(A2))])) : T(j, c2([u2(C("n"), () => 10), u2(C("r"), () => 13), u2(C("t"), () => 9), u2(c2([j, eA, nA, AA, z, GA, U, tA, R, V, BA, aA, W, q]), (A2) => S(A2))]));
1423
+ function r3(A2, B2) {
1424
+ const a3 = e3(B2);
1425
+ return I(C(A2), D(s2(G2, (A3) => a3.has(A3), B2.split(""))), (A3, B3) => function(A4) {
1426
+ const B4 = x.get(A4);
1427
+ if (B4 == null)
1428
+ throw new Error(A4 + " is not a valid unicode category");
1429
+ return B4;
1430
+ }(B3 === null ? A3 : A3 + String.fromCodePoint(B3)));
1431
+ }
1432
+ const l3 = c2([r3("L", "ultmo"), r3("M", "nce"), r3("N", "dlo"), r3("P", "cdseifo"), r3("Z", "slp"), r3("S", "mcko"), r3("C", "cfon")]), p2 = [a2(S("a"), S("z")), a2(S("A"), S("Z")), a2(S("0"), S("9")), B(45)].reduce(t2), M2 = c2([l3, u2(T(C("Is"), function(A2) {
1433
+ return (B2, a3) => {
1434
+ const n3 = A2(B2, a3);
1435
+ return n3.success ? o2(n3.offset, B2.slice(a3, n3.offset)) : n3;
1436
+ };
1437
+ }(d2(s2(G2, p2, ["block identifier"])))), (B2) => function(A2, B3) {
1438
+ const a3 = Q.get(A2);
1439
+ if (a3 === undefined) {
1440
+ if (B3)
1441
+ return n2;
1442
+ throw new Error(`The unicode block identifier "${A2}" is not known.`);
1443
+ }
1444
+ return a3;
1445
+ }(B2, A.language !== "xpath"))]), J2 = E(C("\\p{"), M2, V, true), K2 = u2(E(C("\\P{"), M2, V, true), b), L2 = T(j, u2(c2("sSiIcCdDwW".split("").map((A2) => C(A2))), (A2) => Y[A2])), X2 = u2(nA, () => w2), Z2 = c2([L2, J2, K2]), O2 = e3("\\[]"), k2 = c2([i3, s2(G2, (A2) => !O2.has(A2), ["unescaped character"])]), N2 = c2([u2(AA, () => null), k2]), v2 = I(N2, T(AA, N2), a2);
1446
+ function oA2(A2, B2) {
1447
+ return [A2].concat(B2 || []);
1448
+ }
1449
+ const lA = u2(function(A2) {
1450
+ return (B2, a3) => {
1451
+ const n3 = A2(B2, a3);
1452
+ return n3.success ? o2(a3, n3.value) : n3;
1453
+ };
1454
+ }(c2([q, iA])), () => null), HA = S("-"), CA = c2([u2(F(F(AA, g(W, ["not ["])), lA), () => HA), T(g(AA, ["not -"]), k2)]), uA = c2([I(u2(CA, B), c2([function(A2, B2) {
1455
+ return uA(A2, B2);
1456
+ }, lA]), oA2), I(c2([v2, Z2]), c2([cA, lA]), oA2)]);
1457
+ const sA = c2([I(u2(k2, B), c2([uA, lA]), oA2), I(c2([v2, Z2]), c2([cA, lA]), oA2)]);
1458
+ function cA(A2, B2) {
1459
+ return sA(A2, B2);
1460
+ }
1461
+ const DA = u2(sA, (A2) => A2.reduce(t2)), mA = u2(T(z, DA), b), IA = I(c2([T(g(z, ["not ^"]), DA), mA]), D(T(AA, function(A2, B2) {
1462
+ return dA(A2, B2);
1463
+ })), y), dA = E(W, IA, q, true);
1464
+ const hA = A.language === "xpath" ? c2([u2(i3, B), Z2, dA, X2, u2(z, () => (A2) => A2 === -1), u2($, () => (A2) => A2 === -2)]) : c2([u2(i3, B), Z2, dA, X2]), pA = A.language === "xpath" ? e3(".\\?*+{}()|^$[]") : e3(".\\?*+{}()|[]"), TA = s2(G2, (A2) => !pA.has(A2), ["NormalChar"]), FA = u2(T(j, I(u2(s2(G2, a2(S("1"), S("9")), ["digit"]), (A2) => A2 - rA), m(u2(s2(G2, a2(rA, S("9")), ["digit"]), (A2) => A2 - rA)), (A2, B2) => {
1465
+ B2.reduce((A3, B3) => 10 * A3 + B3, A2);
1466
+ })), (A2) => {
1467
+ throw new Error("Backreferences in XPath patterns are not yet implemented.");
1468
+ }), EA = A.language === "xpath" ? c2([u2(TA, (A2) => ({ kind: "predicate", value: B(A2) })), u2(hA, (A2) => ({ kind: "predicate", value: A2 })), u2(E(BA, T(D(C("?:")), SA), aA, true), (A2) => ({ kind: "regexp", value: A2 })), FA]) : c2([u2(TA, (A2) => ({ kind: "predicate", value: B(A2) })), u2(hA, (A2) => ({ kind: "predicate", value: A2 })), u2(E(BA, SA, aA, true), (A2) => ({ kind: "regexp", value: A2 }))]), gA = u2(d2(u2(s2(G2, a2(rA, S("9")), ["digit"]), (A2) => A2 - rA)), (A2) => A2.reduce((A3, B2) => 10 * A3 + B2)), fA = c2([I(gA, T(_, gA), (A2, B2) => {
1469
+ if (B2 < A2)
1470
+ throw new Error("quantifier range is in the wrong order");
1471
+ return { min: A2, max: B2 };
1472
+ }), I(gA, _, (A2) => ({ min: A2, max: null })), u2(gA, (A2) => ({ min: A2, max: A2 }))]), PA = A.language === "xpath" ? I(c2([u2(GA, () => ({ min: 0, max: 1 })), u2(U, () => ({ min: 0, max: null })), u2(tA, () => ({ min: 1, max: null })), E(R, fA, V, true)]), D(GA), (A2, B2) => A2) : c2([u2(GA, () => ({ min: 0, max: 1 })), u2(U, () => ({ min: 0, max: null })), u2(tA, () => ({ min: 1, max: null })), E(R, fA, V, true)]), MA = m(I(EA, u2(D(PA), (A2) => A2 === null ? { min: 1, max: 1 } : A2), (A2, B2) => [A2, B2])), JA = I(MA, m(T(eA, f2(MA))), (A2, B2) => [A2].concat(B2));
1473
+ function SA(A2, B2) {
1474
+ return JA(A2, B2);
1475
+ }
1476
+ const KA = function(A2) {
1477
+ return I(A2, P, h2);
1478
+ }(JA);
1479
+ return function(A2) {
1480
+ let B2;
1481
+ try {
1482
+ B2 = KA(A2, 0);
1483
+ } catch (B3) {
1484
+ throw new Error(`Error parsing pattern "${A2}": ${B3 instanceof Error ? B3.message : B3}`);
1485
+ }
1486
+ return B2.success ? B2.value : function(A3, B3, a3) {
1487
+ const n3 = a3.map((A4) => `"${A4}"`);
1488
+ throw new Error(`Error parsing pattern "${A3}" at offset ${B3}: expected ${n3.length > 1 ? "one of " + n3.join(", ") : n3[0]} but found "${A3.slice(B3, B3 + 1)}"`);
1489
+ }(A2, B2.offset, B2.expected);
1490
+ };
1491
+ }
1492
+ function lA(A) {
1493
+ return [...A].map((A2) => A2.codePointAt(0));
1494
+ }
1495
+ function HA(B2, a3 = { language: "xsd" }) {
1496
+ const n3 = oA(a3)(B2), e3 = w((A) => {
1497
+ r2(A, n3, a3.language === "xpath"), A.accept();
1498
+ });
1499
+ return function(A) {
1500
+ const B3 = a3.language === "xpath" ? [-1, ...lA(A), -2] : lA(A);
1501
+ return e3.execute(B3).success;
1502
+ };
1503
+ }
1504
+
709
1505
  // src/types.ts
710
1506
  function isResponseRecord(value) {
711
1507
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -772,47 +1568,47 @@ function booleanValue(value) {
772
1568
  function floatValue(value) {
773
1569
  return { cardinality: "single", baseType: "float", values: [value] };
774
1570
  }
775
- function pairsEqual2(a, b, directed) {
776
- const [a1, a2] = a.trim().split(/\s+/u);
777
- const [b1, b2] = b.trim().split(/\s+/u);
778
- if (a1 === undefined || a2 === undefined || b1 === undefined || b2 === undefined) {
1571
+ function pairsEqual2(a3, b2, directed) {
1572
+ const [a1, a22] = a3.trim().split(/\s+/u);
1573
+ const [b1, b22] = b2.trim().split(/\s+/u);
1574
+ if (a1 === undefined || a22 === undefined || b1 === undefined || b22 === undefined) {
779
1575
  return false;
780
1576
  }
781
- if (a1 === b1 && a2 === b2) {
1577
+ if (a1 === b1 && a22 === b22) {
782
1578
  return true;
783
1579
  }
784
- return !directed && a1 === b2 && a2 === b1;
1580
+ return !directed && a1 === b22 && a22 === b1;
785
1581
  }
786
- function scalarsEqual(a, b, baseType, normalize) {
1582
+ function scalarsEqual(a3, b2, baseType, normalize) {
787
1583
  if (baseType === "pair" || baseType === "directedPair") {
788
- return typeof a === "string" && typeof b === "string" && pairsEqual2(a, b, baseType === "directedPair");
1584
+ return typeof a3 === "string" && typeof b2 === "string" && pairsEqual2(a3, b2, baseType === "directedPair");
789
1585
  }
790
1586
  if (baseType === "point") {
791
- if (typeof a !== "string" || typeof b !== "string") {
1587
+ if (typeof a3 !== "string" || typeof b2 !== "string") {
792
1588
  return false;
793
1589
  }
794
- const pointA = parsePoint(a);
795
- const pointB = parsePoint(b);
1590
+ const pointA = parsePoint(a3);
1591
+ const pointB = parsePoint(b2);
796
1592
  return pointA !== null && pointB !== null && pointA.x === pointB.x && pointA.y === pointB.y;
797
1593
  }
798
- if (typeof a === "number" || typeof b === "number") {
799
- return Number(a) === Number(b);
1594
+ if (typeof a3 === "number" || typeof b2 === "number") {
1595
+ return Number(a3) === Number(b2);
800
1596
  }
801
- if (normalize && baseType === "string" && typeof a === "string" && typeof b === "string") {
802
- return normalize(a) === normalize(b);
1597
+ if (normalize && baseType === "string" && typeof a3 === "string" && typeof b2 === "string") {
1598
+ return normalize(a3) === normalize(b2);
803
1599
  }
804
- return a === b;
1600
+ return a3 === b2;
805
1601
  }
806
- function valuesMatch(a, b, normalize) {
807
- const baseType = a.baseType ?? b.baseType;
808
- if (a.values.length !== b.values.length) {
1602
+ function valuesMatch(a3, b2, normalize) {
1603
+ const baseType = a3.baseType ?? b2.baseType;
1604
+ if (a3.values.length !== b2.values.length) {
809
1605
  return false;
810
1606
  }
811
- if (a.cardinality === "ordered" || b.cardinality === "ordered") {
812
- return a.values.every((value, index) => scalarsEqual(value, b.values[index], baseType, normalize));
1607
+ if (a3.cardinality === "ordered" || b2.cardinality === "ordered") {
1608
+ return a3.values.every((value, index) => scalarsEqual(value, b2.values[index], baseType, normalize));
813
1609
  }
814
- const remaining = [...b.values];
815
- for (const value of a.values) {
1610
+ const remaining = [...b2.values];
1611
+ for (const value of a3.values) {
816
1612
  const matchIndex = remaining.findIndex((candidate) => scalarsEqual(candidate, value, baseType, normalize));
817
1613
  if (matchIndex === -1) {
818
1614
  return false;
@@ -844,10 +1640,16 @@ function toOutcomeValue(value) {
844
1640
  // src/rp/evaluate.ts
845
1641
  var deterministicExpressionKinds = new Set([
846
1642
  "and",
1643
+ "anyN",
847
1644
  "baseValue",
1645
+ "containerSize",
1646
+ "contains",
848
1647
  "correct",
1648
+ "default",
849
1649
  "delete",
850
1650
  "divide",
1651
+ "durationGte",
1652
+ "durationLt",
851
1653
  "equal",
852
1654
  "equalRounded",
853
1655
  "fieldValue",
@@ -873,8 +1675,11 @@ var deterministicExpressionKinds = new Set([
873
1675
  "min",
874
1676
  "multiple",
875
1677
  "not",
1678
+ "null",
876
1679
  "or",
877
1680
  "ordered",
1681
+ "patternMatch",
1682
+ "power",
878
1683
  "product",
879
1684
  "repeat",
880
1685
  "round",
@@ -897,68 +1702,94 @@ class RpUnsupportedError extends Error {
897
1702
  }
898
1703
  }
899
1704
  var mathConstants = { pi: Math.PI, e: Math.E };
900
- function applyMathOperator(name, x, y) {
1705
+ var xsdPatternMatchers = new Map;
1706
+ function xsdPatternMatcher(pattern) {
1707
+ const cached = xsdPatternMatchers.get(pattern);
1708
+ if (cached !== undefined) {
1709
+ return cached;
1710
+ }
1711
+ let matcher;
1712
+ try {
1713
+ matcher = HA(pattern);
1714
+ } catch {
1715
+ matcher = null;
1716
+ }
1717
+ xsdPatternMatchers.set(pattern, matcher);
1718
+ return matcher;
1719
+ }
1720
+ var encVariableStringPattern = /^\{[^{}]+\}$/u;
1721
+ function applyMathOperator(name, x2, y2) {
901
1722
  switch (name) {
902
1723
  case "sin":
903
- return Math.sin(x);
1724
+ return Math.sin(x2);
904
1725
  case "cos":
905
- return Math.cos(x);
1726
+ return Math.cos(x2);
906
1727
  case "tan":
907
- return Math.tan(x);
1728
+ return Math.tan(x2);
908
1729
  case "sec":
909
- return 1 / Math.cos(x);
1730
+ return 1 / Math.cos(x2);
910
1731
  case "csc":
911
- return 1 / Math.sin(x);
1732
+ return 1 / Math.sin(x2);
912
1733
  case "cot":
913
- return Math.cos(x) / Math.sin(x);
1734
+ return Math.cos(x2) / Math.sin(x2);
914
1735
  case "asin":
915
- return Math.asin(x);
1736
+ return Math.asin(x2);
916
1737
  case "acos":
917
- return Math.acos(x);
1738
+ return Math.acos(x2);
918
1739
  case "atan":
919
- return Math.atan(x);
1740
+ return Math.atan(x2);
920
1741
  case "atan2":
921
- return Math.atan2(x, y);
1742
+ return Math.atan2(x2, y2);
922
1743
  case "asec":
923
- return Math.acos(1 / x);
1744
+ return Math.acos(1 / x2);
924
1745
  case "acsc":
925
- return Math.asin(1 / x);
1746
+ return Math.asin(1 / x2);
926
1747
  case "acot":
927
- return Math.atan(1 / x);
1748
+ return Math.atan(1 / x2);
928
1749
  case "sinh":
929
- return Math.sinh(x);
1750
+ return Math.sinh(x2);
930
1751
  case "cosh":
931
- return Math.cosh(x);
1752
+ return Math.cosh(x2);
932
1753
  case "tanh":
933
- return Math.tanh(x);
1754
+ return Math.tanh(x2);
934
1755
  case "sech":
935
- return 1 / Math.cosh(x);
1756
+ return 1 / Math.cosh(x2);
936
1757
  case "csch":
937
- return 1 / Math.sinh(x);
1758
+ return 1 / Math.sinh(x2);
938
1759
  case "coth":
939
- return Math.cosh(x) / Math.sinh(x);
1760
+ return Math.cosh(x2) / Math.sinh(x2);
940
1761
  case "log":
941
- return Math.log10(x);
1762
+ return Math.log10(x2);
942
1763
  case "ln":
943
- return Math.log(x);
1764
+ return Math.log(x2);
944
1765
  case "exp":
945
- return Math.exp(x);
1766
+ return Math.exp(x2);
946
1767
  case "abs":
947
- return Math.abs(x);
1768
+ return Math.abs(x2);
948
1769
  case "signum":
949
- return Math.sign(x);
1770
+ return Math.sign(x2);
950
1771
  case "floor":
951
- return Math.floor(x);
1772
+ return Math.floor(x2);
952
1773
  case "ceil":
953
- return Math.ceil(x);
1774
+ return Math.ceil(x2);
954
1775
  case "toDegrees":
955
- return x * 180 / Math.PI;
1776
+ return x2 * 180 / Math.PI;
956
1777
  case "toRadians":
957
- return x * Math.PI / 180;
1778
+ return x2 * Math.PI / 180;
958
1779
  default:
959
1780
  return;
960
1781
  }
961
1782
  }
1783
+ function resolveNumericAttribute(raw, env) {
1784
+ if (raw === undefined) {
1785
+ return;
1786
+ }
1787
+ if (typeof raw === "number") {
1788
+ return raw;
1789
+ }
1790
+ const identifier = raw.startsWith("{") && raw.endsWith("}") ? raw.slice(1, -1) : raw;
1791
+ return singleNumber(env.lookupVariable(identifier));
1792
+ }
962
1793
  function roundToFigures(value, mode, figures) {
963
1794
  if (mode === "decimalPlaces") {
964
1795
  const scale2 = 10 ** figures;
@@ -1010,11 +1841,11 @@ function evaluateExpression(expression, env) {
1010
1841
  return floatValue(mapResponsePoint(declaration, env.responseValue(identifier)));
1011
1842
  }
1012
1843
  case "match": {
1013
- const [a, b] = (expression.expressions ?? []).map(evaluate);
1014
- if (a === undefined || b === undefined || a === null || b === null) {
1844
+ const [a3, b2] = (expression.expressions ?? []).map(evaluate);
1845
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
1015
1846
  return null;
1016
1847
  }
1017
- return booleanValue(valuesMatch(a, b, env.normalization));
1848
+ return booleanValue(valuesMatch(a3, b2, env.normalization));
1018
1849
  }
1019
1850
  case "isNull": {
1020
1851
  const operand = expression.expressions?.[0];
@@ -1034,7 +1865,16 @@ function evaluateExpression(expression, env) {
1034
1865
  case "and":
1035
1866
  case "or": {
1036
1867
  const members = (expression.expressions ?? []).map((child) => singleBoolean(evaluate(child)));
1037
- return booleanValue(expression.kind === "and" ? members.every((member) => member === true) : members.some((member) => member === true));
1868
+ if (expression.kind === "and") {
1869
+ if (members.some((member) => member === false)) {
1870
+ return booleanValue(false);
1871
+ }
1872
+ return members.some((member) => member === null) ? null : booleanValue(true);
1873
+ }
1874
+ if (members.some((member) => member === true)) {
1875
+ return booleanValue(true);
1876
+ }
1877
+ return members.some((member) => member === null) ? null : booleanValue(false);
1038
1878
  }
1039
1879
  case "sum":
1040
1880
  case "product": {
@@ -1055,44 +1895,45 @@ function evaluateExpression(expression, env) {
1055
1895
  }
1056
1896
  case "subtract":
1057
1897
  case "divide": {
1058
- const [a, b] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1059
- if (a === undefined || b === undefined || a === null || b === null) {
1898
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1899
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
1060
1900
  return null;
1061
1901
  }
1062
1902
  if (expression.kind === "divide") {
1063
- return b === 0 ? null : floatValue(a / b);
1903
+ return b2 === 0 ? null : floatValue(a3 / b2);
1064
1904
  }
1065
- return floatValue(a - b);
1905
+ return floatValue(a3 - b2);
1066
1906
  }
1067
1907
  case "gt":
1068
1908
  case "gte":
1069
1909
  case "lt":
1070
1910
  case "lte": {
1071
- const [a, b] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1072
- if (a === undefined || b === undefined || a === null || b === null) {
1911
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1912
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
1073
1913
  return null;
1074
1914
  }
1075
- const comparisons = { gt: a > b, gte: a >= b, lt: a < b, lte: a <= b };
1915
+ const comparisons = { gt: a3 > b2, gte: a3 >= b2, lt: a3 < b2, lte: a3 <= b2 };
1076
1916
  return booleanValue(comparisons[expression.kind]);
1077
1917
  }
1078
1918
  case "equal": {
1079
- const [a, b] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1080
- if (a === undefined || b === undefined || a === null || b === null) {
1919
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1920
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
1081
1921
  return null;
1082
1922
  }
1083
1923
  const mode = expression.toleranceMode ?? "exact";
1084
1924
  if (mode === "exact") {
1085
- return booleanValue(a === b);
1925
+ return booleanValue(a3 === b2);
1086
1926
  }
1087
- const t0 = expression.tolerance?.[0];
1088
- const t1 = expression.tolerance?.[1] ?? t0;
1927
+ const t0 = resolveNumericAttribute(expression.tolerance?.[0], env);
1928
+ const t1raw = expression.tolerance?.[1];
1929
+ const t1 = t1raw === undefined ? t0 : resolveNumericAttribute(t1raw, env);
1089
1930
  if (typeof t0 !== "number" || typeof t1 !== "number") {
1090
- throw new RpUnsupportedError("equal");
1931
+ return null;
1091
1932
  }
1092
- const lower = mode === "absolute" ? a - t0 : a * (1 - t0 / 100);
1093
- const upper = mode === "absolute" ? a + t1 : a * (1 + t1 / 100);
1094
- const aboveLower = expression.includeLowerBound ?? true ? b >= lower : b > lower;
1095
- const belowUpper = expression.includeUpperBound ?? true ? b <= upper : b < upper;
1933
+ const lower = mode === "absolute" ? a3 - t0 : a3 * (1 - t0 / 100);
1934
+ const upper = mode === "absolute" ? a3 + t1 : a3 * (1 + t1 / 100);
1935
+ const aboveLower = expression.includeLowerBound ?? true ? b2 >= lower : b2 > lower;
1936
+ const belowUpper = expression.includeUpperBound ?? true ? b2 <= upper : b2 < upper;
1096
1937
  return booleanValue(aboveLower && belowUpper);
1097
1938
  }
1098
1939
  case "round":
@@ -1106,15 +1947,16 @@ function evaluateExpression(expression, env) {
1106
1947
  return { cardinality: "single", baseType: "integer", values: [rounded] };
1107
1948
  }
1108
1949
  case "index": {
1109
- if (typeof expression.n !== "number") {
1110
- throw new RpUnsupportedError("index");
1950
+ const n3 = resolveNumericAttribute(expression.n, env);
1951
+ if (typeof n3 !== "number") {
1952
+ return null;
1111
1953
  }
1112
1954
  const operand = expression.expressions?.[0];
1113
1955
  const container = operand === undefined ? null : evaluate(operand);
1114
1956
  if (container === null) {
1115
1957
  return null;
1116
1958
  }
1117
- const member = container.values[expression.n - 1];
1959
+ const member = container.values[n3 - 1];
1118
1960
  if (member === undefined) {
1119
1961
  return null;
1120
1962
  }
@@ -1128,11 +1970,11 @@ function evaluateExpression(expression, env) {
1128
1970
  return floatValue(constant);
1129
1971
  }
1130
1972
  case "mathOperator": {
1131
- const [x, y] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1132
- if (x === undefined || x === null || expression.name === "atan2" && (y === undefined || y === null)) {
1973
+ const [x2, y2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1974
+ if (x2 === undefined || x2 === null || expression.name === "atan2" && (y2 === undefined || y2 === null)) {
1133
1975
  return null;
1134
1976
  }
1135
- const result = expression.name === undefined ? undefined : applyMathOperator(expression.name, x, y ?? NaN);
1977
+ const result = expression.name === undefined ? undefined : applyMathOperator(expression.name, x2, y2 ?? NaN);
1136
1978
  if (result === undefined) {
1137
1979
  throw new RpUnsupportedError("mathOperator");
1138
1980
  }
@@ -1140,11 +1982,11 @@ function evaluateExpression(expression, env) {
1140
1982
  }
1141
1983
  case "integerDivide":
1142
1984
  case "integerModulus": {
1143
- const [a, b] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1144
- if (a === undefined || b === undefined || a === null || b === null || b === 0) {
1985
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1986
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null || b2 === 0) {
1145
1987
  return null;
1146
1988
  }
1147
- const result = expression.kind === "integerDivide" ? Math.trunc(a / b) : a % b;
1989
+ const result = expression.kind === "integerDivide" ? Math.trunc(a3 / b2) : a3 % b2;
1148
1990
  return { cardinality: "single", baseType: "integer", values: [result] };
1149
1991
  }
1150
1992
  case "integerToFloat": {
@@ -1190,33 +2032,35 @@ function evaluateExpression(expression, env) {
1190
2032
  if (members.length === 0) {
1191
2033
  return null;
1192
2034
  }
1193
- const gcdOf = (a, b) => b === 0 ? a : gcdOf(b, a % b);
1194
- const result = expression.kind === "gcd" ? members.reduce(gcdOf) : members.reduce((a, b) => a === 0 || b === 0 ? 0 : a / gcdOf(a, b) * b);
2035
+ const gcdOf = (a3, b2) => b2 === 0 ? a3 : gcdOf(b2, a3 % b2);
2036
+ const result = expression.kind === "gcd" ? members.reduce(gcdOf) : members.reduce((a3, b2) => a3 === 0 || b2 === 0 ? 0 : a3 / gcdOf(a3, b2) * b2);
1195
2037
  return { cardinality: "single", baseType: "integer", values: [result] };
1196
2038
  }
1197
2039
  case "roundTo": {
1198
- if (typeof expression.figures !== "number") {
1199
- throw new RpUnsupportedError("roundTo");
2040
+ const figures = resolveNumericAttribute(expression.figures, env);
2041
+ if (typeof figures !== "number") {
2042
+ return null;
1200
2043
  }
1201
2044
  const operand = expression.expressions?.[0];
1202
2045
  const value = operand === undefined ? null : singleNumber(evaluate(operand));
1203
2046
  if (value === null) {
1204
2047
  return null;
1205
2048
  }
1206
- const rounded = roundToFigures(value, expression.roundingMode ?? "significantFigures", expression.figures);
2049
+ const rounded = roundToFigures(value, expression.roundingMode ?? "significantFigures", figures);
1207
2050
  return rounded === null ? null : floatValue(rounded);
1208
2051
  }
1209
2052
  case "equalRounded": {
1210
- if (typeof expression.figures !== "number") {
1211
- throw new RpUnsupportedError("equalRounded");
2053
+ const figures = resolveNumericAttribute(expression.figures, env);
2054
+ if (typeof figures !== "number") {
2055
+ return null;
1212
2056
  }
1213
- const [a, b] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
1214
- if (a === undefined || b === undefined || a === null || b === null) {
2057
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
2058
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
1215
2059
  return null;
1216
2060
  }
1217
2061
  const mode = expression.roundingMode ?? "significantFigures";
1218
- const roundedA = roundToFigures(a, mode, expression.figures);
1219
- const roundedB = roundToFigures(b, mode, expression.figures);
2062
+ const roundedA = roundToFigures(a3, mode, figures);
2063
+ const roundedB = roundToFigures(b2, mode, figures);
1220
2064
  return roundedA === null || roundedB === null ? null : booleanValue(roundedA === roundedB);
1221
2065
  }
1222
2066
  case "statsOperator": {
@@ -1272,15 +2116,13 @@ function evaluateExpression(expression, env) {
1272
2116
  return remaining.length === 0 ? null : rpValue(container.cardinality, remaining, container.baseType);
1273
2117
  }
1274
2118
  case "repeat": {
1275
- if (typeof expression.numberRepeats !== "number") {
1276
- throw new RpUnsupportedError("repeat");
1277
- }
1278
- if (expression.numberRepeats < 1) {
2119
+ const numberRepeats = resolveNumericAttribute(expression.numberRepeats, env);
2120
+ if (typeof numberRepeats !== "number" || numberRepeats < 1) {
1279
2121
  return null;
1280
2122
  }
1281
2123
  const members = [];
1282
2124
  let baseType;
1283
- for (let pass = 0;pass < expression.numberRepeats; pass += 1) {
2125
+ for (let pass = 0;pass < numberRepeats; pass += 1) {
1284
2126
  for (const child of expression.expressions ?? []) {
1285
2127
  const value = evaluate(child);
1286
2128
  if (value === null) {
@@ -1292,21 +2134,112 @@ function evaluateExpression(expression, env) {
1292
2134
  }
1293
2135
  return members.length === 0 ? null : rpValue("ordered", members, baseType);
1294
2136
  }
2137
+ case "null":
2138
+ return null;
2139
+ case "durationGte":
2140
+ case "durationLt": {
2141
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
2142
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
2143
+ return null;
2144
+ }
2145
+ return booleanValue(expression.kind === "durationGte" ? a3 >= b2 : a3 < b2);
2146
+ }
2147
+ case "default":
2148
+ return env.variableDefault?.(expression.identifier ?? "") ?? null;
2149
+ case "patternMatch": {
2150
+ const operand = expression.expressions?.[0];
2151
+ const value = operand === undefined ? null : evaluate(operand);
2152
+ const member = value?.values[0];
2153
+ if (value === null || typeof member !== "string") {
2154
+ return null;
2155
+ }
2156
+ if (expression.pattern === undefined) {
2157
+ throw new RpUnsupportedError("patternMatch");
2158
+ }
2159
+ const pattern = encVariableStringPattern.test(expression.pattern) ? env.lookupVariable(expression.pattern.slice(1, -1))?.values[0] : expression.pattern;
2160
+ if (typeof pattern !== "string") {
2161
+ return null;
2162
+ }
2163
+ const matcher = xsdPatternMatcher(pattern);
2164
+ if (matcher === null) {
2165
+ throw new RpUnsupportedError("patternMatch");
2166
+ }
2167
+ return booleanValue(matcher(member));
2168
+ }
2169
+ case "power": {
2170
+ const [a3, b2] = (expression.expressions ?? []).map((child) => singleNumber(evaluate(child)));
2171
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
2172
+ return null;
2173
+ }
2174
+ const result = a3 ** b2;
2175
+ return Number.isFinite(result) ? floatValue(result) : null;
2176
+ }
2177
+ case "containerSize": {
2178
+ const operand = expression.expressions?.[0];
2179
+ const container = operand === undefined ? null : evaluate(operand);
2180
+ return {
2181
+ cardinality: "single",
2182
+ baseType: "integer",
2183
+ values: [container === null ? 0 : container.values.length]
2184
+ };
2185
+ }
2186
+ case "contains": {
2187
+ const [firstExpression, secondExpression] = expression.expressions ?? [];
2188
+ if (firstExpression === undefined || secondExpression === undefined) {
2189
+ return null;
2190
+ }
2191
+ const first = evaluate(firstExpression);
2192
+ const second = evaluate(secondExpression);
2193
+ if (first === null || second === null || first.cardinality === "record" || second.cardinality === "record") {
2194
+ return null;
2195
+ }
2196
+ const baseType = first.baseType ?? second.baseType;
2197
+ if (first.cardinality === "ordered") {
2198
+ const found = first.values.some((_2, start) => start + second.values.length <= first.values.length && second.values.every((member, offset) => scalarsEqual(first.values[start + offset], member, baseType, env.normalization)));
2199
+ return booleanValue(found);
2200
+ }
2201
+ const remaining = [...first.values];
2202
+ for (const member of second.values) {
2203
+ const at = remaining.findIndex((candidate) => scalarsEqual(candidate, member, baseType, env.normalization));
2204
+ if (at === -1) {
2205
+ return booleanValue(false);
2206
+ }
2207
+ remaining.splice(at, 1);
2208
+ }
2209
+ return booleanValue(true);
2210
+ }
2211
+ case "anyN": {
2212
+ const min = resolveNumericAttribute(expression.min, env);
2213
+ const max = resolveNumericAttribute(expression.max, env);
2214
+ if (typeof min !== "number" || typeof max !== "number") {
2215
+ return null;
2216
+ }
2217
+ const members = (expression.expressions ?? []).map((child) => singleBoolean(evaluate(child)));
2218
+ const trueCount = members.filter((member) => member === true).length;
2219
+ const nullCount = members.filter((member) => member === null).length;
2220
+ if (trueCount >= min && trueCount + nullCount <= max) {
2221
+ return booleanValue(true);
2222
+ }
2223
+ if (trueCount + nullCount < min || trueCount > max) {
2224
+ return booleanValue(false);
2225
+ }
2226
+ return null;
2227
+ }
1295
2228
  case "stringMatch":
1296
2229
  case "substring": {
1297
- const [a, b] = (expression.expressions ?? []).map((child) => {
2230
+ const [a3, b2] = (expression.expressions ?? []).map((child) => {
1298
2231
  const value = evaluate(child);
1299
2232
  const member = value?.values[0];
1300
2233
  return typeof member === "string" ? member : null;
1301
2234
  });
1302
- if (a === undefined || b === undefined || a === null || b === null) {
2235
+ if (a3 === undefined || b2 === undefined || a3 === null || b2 === null) {
1303
2236
  return null;
1304
2237
  }
1305
2238
  const normalize = (input) => {
1306
2239
  const normalized = env.normalization?.(input) ?? input;
1307
2240
  return expression.caseSensitive === false ? normalized.toLowerCase() : normalized;
1308
2241
  };
1309
- const [left, right] = [normalize(a), normalize(b)];
2242
+ const [left, right] = [normalize(a3), normalize(b2)];
1310
2243
  const contains = expression.kind === "substring" || expression.substring === true;
1311
2244
  return booleanValue(contains ? right.includes(left) : left === right);
1312
2245
  }
@@ -1364,9 +2297,9 @@ function evaluateExpression(expression, env) {
1364
2297
  if (!env.random) {
1365
2298
  throw new RpUnsupportedError(expression.kind);
1366
2299
  }
1367
- const min = expression.min ?? 0;
1368
- const max = expression.max ?? min;
1369
- const step = expression.step ?? 1;
2300
+ const min = resolveNumericAttribute(expression.min, env) ?? 0;
2301
+ const max = resolveNumericAttribute(expression.max, env) ?? min;
2302
+ const step = resolveNumericAttribute(expression.step, env) ?? 1;
1370
2303
  const count = Math.max(1, Math.floor((max - min) / step) + 1);
1371
2304
  return { cardinality: "single", baseType: "integer", values: [min + Math.floor(env.random() * count) * step] };
1372
2305
  }
@@ -1374,8 +2307,8 @@ function evaluateExpression(expression, env) {
1374
2307
  if (!env.random) {
1375
2308
  throw new RpUnsupportedError(expression.kind);
1376
2309
  }
1377
- const min = expression.min ?? 0;
1378
- const max = expression.max ?? min;
2310
+ const min = resolveNumericAttribute(expression.min, env) ?? 0;
2311
+ const max = resolveNumericAttribute(expression.max, env) ?? min;
1379
2312
  return floatValue(min + env.random() * (max - min));
1380
2313
  }
1381
2314
  case "testVariables": {
@@ -1395,7 +2328,9 @@ function evaluateExpression(expression, env) {
1395
2328
  case "numberIncorrect":
1396
2329
  case "numberPresented":
1397
2330
  case "numberResponded":
1398
- case "numberSelected": {
2331
+ case "numberSelected":
2332
+ case "outcomeMinimum":
2333
+ case "outcomeMaximum": {
1399
2334
  if (!env.testAggregate) {
1400
2335
  throw new RpUnsupportedError(expression.kind);
1401
2336
  }
@@ -1423,12 +2358,35 @@ function collectExpressionIssues(expression, allowedKinds, report, customOperato
1423
2358
  }
1424
2359
  } else if (!allowedKinds.has(expression.kind)) {
1425
2360
  report(expression.kind);
2361
+ } else if (expression.kind === "patternMatch" && expression.pattern !== undefined && !encVariableStringPattern.test(expression.pattern) && xsdPatternMatcher(expression.pattern) === null) {
2362
+ report(expression.kind);
1426
2363
  }
1427
2364
  for (const child of expression.expressions ?? []) {
1428
2365
  collectExpressionIssues(child, allowedKinds, report, customOperatorClasses);
1429
2366
  }
1430
2367
  }
1431
2368
 
2369
+ // src/rp/lookup-table.ts
2370
+ function hasLookupTable(declaration) {
2371
+ return declaration?.matchTable !== undefined || declaration?.interpolationTable !== undefined;
2372
+ }
2373
+ function lookupTableValue(declaration, source) {
2374
+ const value = singleNumber(source);
2375
+ const table = declaration.matchTable ?? declaration.interpolationTable;
2376
+ const target = value === null ? undefined : matchedTarget(declaration, value);
2377
+ const result = target ?? table?.defaultValue;
2378
+ if (result === undefined) {
2379
+ return null;
2380
+ }
2381
+ return rpValue("single", [coerceScalar(result, declaration.baseType)], declaration.baseType);
2382
+ }
2383
+ function matchedTarget(declaration, value) {
2384
+ if (declaration.matchTable) {
2385
+ return declaration.matchTable.matchTableEntries.find((entry) => entry.sourceValue === value)?.targetValue;
2386
+ }
2387
+ return declaration.interpolationTable?.interpolationTableEntries.find((entry) => entry.includeBoundary ?? true ? entry.sourceValue <= value : entry.sourceValue < value)?.targetValue;
2388
+ }
2389
+
1432
2390
  // src/rp/templates.ts
1433
2391
  var matchCorrectRules = [
1434
2392
  {
@@ -1598,7 +2556,13 @@ function resolveTemplate(uri) {
1598
2556
  }
1599
2557
 
1600
2558
  // src/rp/interpreter.ts
1601
- var supportedRuleKinds = new Set(["responseCondition", "setOutcomeValue", "exitResponse"]);
2559
+ var supportedRuleKinds = new Set([
2560
+ "responseCondition",
2561
+ "setOutcomeValue",
2562
+ "lookupOutcomeValue",
2563
+ "responseProcessingFragment",
2564
+ "exitResponse"
2565
+ ]);
1602
2566
  var rpExpressionKinds = new Set([...deterministicExpressionKinds, "random", "randomInteger", "randomFloat"]);
1603
2567
 
1604
2568
  class ExitResponseSignal extends Error {
@@ -1620,6 +2584,9 @@ function executeResponseProcessing(view, context) {
1620
2584
  const templateDeclarationsById = new Map((context.templateDeclarations ?? []).map((declaration) => [declaration.identifier, declaration]));
1621
2585
  function initialOutcomes() {
1622
2586
  const outcomes2 = defaultOutcomes(context.outcomeDeclarations);
2587
+ if (!outcomes2.has("completionStatus")) {
2588
+ outcomes2.set("completionStatus", rpValue("single", [context.completionStatus ?? "not_attempted"], "identifier"));
2589
+ }
1623
2590
  for (const [identifier, prior] of Object.entries(context.priorOutcomes ?? {})) {
1624
2591
  const declaration = context.outcomeDeclarations.find((entry) => entry.identifier === identifier);
1625
2592
  outcomes2.set(identifier, fromFlatValue(prior, declaration?.cardinality ?? "single", declaration?.baseType));
@@ -1638,6 +2605,12 @@ function executeResponseProcessing(view, context) {
1638
2605
  }
1639
2606
  const env = {
1640
2607
  lookupVariable: (identifier) => {
2608
+ if (identifier === "duration") {
2609
+ return context.duration === undefined ? null : rpValue("single", [context.duration], "duration");
2610
+ }
2611
+ if (identifier === "numAttempts") {
2612
+ return context.numAttempts === undefined ? null : rpValue("single", [context.numAttempts], "integer");
2613
+ }
1641
2614
  const declaration = declarationsById.get(identifier);
1642
2615
  if (declaration) {
1643
2616
  return fromResponse(declaration, context.responses[identifier] ?? null);
@@ -1650,6 +2623,13 @@ function executeResponseProcessing(view, context) {
1650
2623
  },
1651
2624
  responseDeclaration: (identifier) => declarationsById.get(identifier),
1652
2625
  responseValue: (identifier) => context.responses[identifier] ?? null,
2626
+ variableDefault: (identifier) => {
2627
+ const declaration = declarationsById.get(identifier) ?? context.outcomeDeclarations.find((entry) => entry.identifier === identifier) ?? templateDeclarationsById.get(identifier);
2628
+ if (!declaration?.defaultValue) {
2629
+ return null;
2630
+ }
2631
+ return rpValue(declaration.cardinality, declaration.defaultValue.values.map((entry) => coerceScalar(entry.value, declaration.baseType)), declaration.baseType);
2632
+ },
1653
2633
  normalization: context.normalization,
1654
2634
  random: context.random,
1655
2635
  customOperators: context.customOperators
@@ -1675,6 +2655,20 @@ function executeResponseProcessing(view, context) {
1675
2655
  }
1676
2656
  continue;
1677
2657
  }
2658
+ if (rule.kind === "responseProcessingFragment") {
2659
+ executeRules(rule.rules ?? []);
2660
+ continue;
2661
+ }
2662
+ if (rule.kind === "lookupOutcomeValue") {
2663
+ if (rule.identifier !== undefined && rule.expression !== undefined) {
2664
+ const declaration = context.outcomeDeclarations.find((entry) => entry.identifier === rule.identifier);
2665
+ if (!hasLookupTable(declaration)) {
2666
+ throw new RpUnsupportedError("lookupOutcomeValue");
2667
+ }
2668
+ outcomes.set(rule.identifier, lookupTableValue(declaration, evaluateExpression(rule.expression, env)));
2669
+ }
2670
+ continue;
2671
+ }
1678
2672
  if (rule.responseIf && branchTaken(rule.responseIf)) {
1679
2673
  continue;
1680
2674
  }
@@ -1717,9 +2711,18 @@ function collectRpIssues(view, options) {
1717
2711
  report(rule.kind);
1718
2712
  continue;
1719
2713
  }
2714
+ if (rule.kind === "lookupOutcomeValue" && options?.outcomeDeclarations !== undefined) {
2715
+ const declaration = options.outcomeDeclarations.find((entry) => entry.identifier === rule.identifier);
2716
+ if (!hasLookupTable(declaration)) {
2717
+ report("lookupOutcomeValue", "Outcome declaration has no matchTable/interpolationTable.");
2718
+ }
2719
+ }
1720
2720
  if (rule.expression) {
1721
2721
  collectExpressionIssues(rule.expression, rpExpressionKinds, report, options?.customOperatorClasses);
1722
2722
  }
2723
+ if (rule.rules) {
2724
+ walkRules(rule.rules);
2725
+ }
1723
2726
  for (const branch of [rule.responseIf, ...rule.responseElseIfs ?? []]) {
1724
2727
  if (branch) {
1725
2728
  collectExpressionIssues(branch.expression, rpExpressionKinds, report, options?.customOperatorClasses);
@@ -1761,10 +2764,10 @@ function mulberry32(seed) {
1761
2764
  let state = seed >>> 0;
1762
2765
  return () => {
1763
2766
  state = state + 1831565813 >>> 0;
1764
- let t = state;
1765
- t = Math.imul(t ^ t >>> 15, t | 1);
1766
- t ^= t + Math.imul(t ^ t >>> 7, t | 61);
1767
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
2767
+ let t3 = state;
2768
+ t3 = Math.imul(t3 ^ t3 >>> 15, t3 | 1);
2769
+ t3 ^= t3 + Math.imul(t3 ^ t3 >>> 7, t3 | 61);
2770
+ return ((t3 ^ t3 >>> 14) >>> 0) / 4294967296;
1768
2771
  };
1769
2772
  }
1770
2773
  function executeTemplateProcessing(view, context) {
@@ -1784,6 +2787,13 @@ function executeTemplateProcessing(view, context) {
1784
2787
  lookupVariable: (identifier) => templateValues.get(identifier) ?? null,
1785
2788
  responseDeclaration: (identifier) => responseDeclarationsById.get(identifier),
1786
2789
  responseValue: () => null,
2790
+ variableDefault: (identifier) => {
2791
+ const declaration = declarationsById.get(identifier) ?? responseDeclarationsById.get(identifier);
2792
+ if (!declaration?.defaultValue) {
2793
+ return null;
2794
+ }
2795
+ return rpValue(declaration.cardinality, declaration.defaultValue.values.map((entry) => coerceScalar(entry.value, declaration.baseType)), declaration.baseType);
2796
+ },
1787
2797
  random: mulberry32(context.seed),
1788
2798
  customOperators: context.customOperators
1789
2799
  };
@@ -1863,6 +2873,22 @@ function executeTemplateProcessing(view, context) {
1863
2873
  issues
1864
2874
  };
1865
2875
  }
2876
+ function applyTemplateDefaultOverrides(declarations, overrides) {
2877
+ return declarations.map((declaration) => {
2878
+ if (!(declaration.identifier in overrides)) {
2879
+ return declaration;
2880
+ }
2881
+ const value = overrides[declaration.identifier];
2882
+ if (value === null || value === undefined) {
2883
+ const { defaultValue: _cleared, ...rest } = declaration;
2884
+ return rest;
2885
+ }
2886
+ return {
2887
+ ...declaration,
2888
+ defaultValue: { values: (Array.isArray(value) ? value : [value]).map((member) => ({ value: member })) }
2889
+ };
2890
+ });
2891
+ }
1866
2892
  function applyCorrectResponseOverrides(declarations, overrides) {
1867
2893
  return declarations.map((declaration) => {
1868
2894
  const override = overrides[declaration.identifier];
@@ -1904,11 +2930,98 @@ function collectTemplateIssues(view, options) {
1904
2930
  walkRules(view.rules);
1905
2931
  return issues;
1906
2932
  }
2933
+ // src/response-validity.ts
2934
+ var countConstraintKinds = ["minChoices", "maxChoices", "minAssociations", "maxAssociations", "minStrings"];
2935
+ function collectInteractionConstraints(content) {
2936
+ const constraints = [];
2937
+ function walk(node) {
2938
+ const record = node;
2939
+ if (isInteractionKind(v0ContentModel, node.kind) && typeof record["responseIdentifier"] === "string") {
2940
+ const responseIdentifier = record["responseIdentifier"];
2941
+ for (const kind of [...countConstraintKinds, "minPlays"]) {
2942
+ const bound = record[kind];
2943
+ if (typeof bound === "number" && bound > 0) {
2944
+ constraints.push({ responseIdentifier, kind, bound });
2945
+ }
2946
+ }
2947
+ const patternMask = record["patternMask"];
2948
+ if (typeof patternMask === "string" && patternMask !== "") {
2949
+ constraints.push({ responseIdentifier, kind: "patternMask", bound: patternMask });
2950
+ }
2951
+ return;
2952
+ }
2953
+ for (const key of ["content", "children"]) {
2954
+ const nested = record[key];
2955
+ if (Array.isArray(nested)) {
2956
+ for (const child of nested) {
2957
+ walk(child);
2958
+ }
2959
+ }
2960
+ }
2961
+ }
2962
+ for (const node of content ?? []) {
2963
+ walk(node);
2964
+ }
2965
+ return constraints;
2966
+ }
2967
+ function memberCount(value) {
2968
+ if (value === null || value === undefined || value === "") {
2969
+ return 0;
2970
+ }
2971
+ if (Array.isArray(value)) {
2972
+ return value.filter((member) => member !== null && member !== "").length;
2973
+ }
2974
+ return 1;
2975
+ }
2976
+ function stringMembers(value) {
2977
+ if (typeof value === "string") {
2978
+ return value === "" ? [] : [value];
2979
+ }
2980
+ if (Array.isArray(value)) {
2981
+ return value.filter((member) => typeof member === "string" && member !== "");
2982
+ }
2983
+ return [];
2984
+ }
2985
+ function violates(constraint, value) {
2986
+ switch (constraint.kind) {
2987
+ case "minChoices":
2988
+ case "minAssociations":
2989
+ case "minStrings":
2990
+ return memberCount(value) < Number(constraint.bound);
2991
+ case "maxChoices":
2992
+ case "maxAssociations":
2993
+ return memberCount(value) > Number(constraint.bound);
2994
+ case "minPlays": {
2995
+ const plays = typeof value === "number" ? value : 0;
2996
+ return plays < Number(constraint.bound);
2997
+ }
2998
+ case "patternMask": {
2999
+ const members = stringMembers(value);
3000
+ if (members.length === 0) {
3001
+ return false;
3002
+ }
3003
+ try {
3004
+ const matches = HA(String(constraint.bound), { language: "xsd" });
3005
+ return !members.every((member) => matches(member));
3006
+ } catch {
3007
+ return false;
3008
+ }
3009
+ }
3010
+ }
3011
+ }
3012
+ function collectResponseViolations(constraints, responses) {
3013
+ return constraints.filter((constraint) => {
3014
+ const value = responses[constraint.responseIdentifier] ?? null;
3015
+ return !isResponseRecord(value) && violates(constraint, value);
3016
+ });
3017
+ }
3018
+
1907
3019
  // src/store.ts
1908
3020
  function createAttemptStore(declarations, initialResponses, options) {
1909
3021
  const seed = options?.seed ?? Math.floor(Math.random() * 2 ** 31);
3022
+ const templateDeclarations = options?.templateDefaultValues ? applyTemplateDefaultOverrides(options.templateDeclarations ?? [], options.templateDefaultValues) : options?.templateDeclarations ?? [];
1910
3023
  const templateResult = options?.templateProcessing ? executeTemplateProcessing(options.templateProcessing, {
1911
- templateDeclarations: options.templateDeclarations ?? [],
3024
+ templateDeclarations,
1912
3025
  responseDeclarations: declarations,
1913
3026
  seed,
1914
3027
  customOperators: options.customOperators
@@ -1918,13 +3031,30 @@ function createAttemptStore(declarations, initialResponses, options) {
1918
3031
  const listeners = new Set;
1919
3032
  const responseCollectors = new Map;
1920
3033
  const rpRandom = mulberry32((seed ^ 2654435769) >>> 0);
3034
+ const now = options?.now ?? Date.now;
3035
+ let activeMs = 0;
3036
+ let runningSinceMs = now();
3037
+ const activeSeconds = () => (activeMs + (runningSinceMs === null ? 0 : now() - runningSinceMs)) / 1000;
3038
+ const completionStatusDeclared = (options?.outcomeDeclarations ?? []).some((declaration) => declaration.identifier === "completionStatus");
3039
+ const maintainedOutcomes = () => completionStatusDeclared ? {} : { completionStatus: "unknown" };
3040
+ const violationsOf = (responses) => options?.constraints ? collectResponseViolations(options.constraints, responses) : [];
3041
+ const correctResponses = {};
3042
+ for (const declaration of effectiveDeclarations) {
3043
+ const values = declaration.correctResponse?.values;
3044
+ if (values !== undefined) {
3045
+ correctResponses[declaration.identifier] = declaration.cardinality === "single" ? values[0]?.value ?? null : values.map((entry) => entry.value);
3046
+ }
3047
+ }
1921
3048
  let snapshot = {
1922
3049
  responses: { ...initialResponses },
1923
3050
  submitted: false,
1924
3051
  scores: [],
1925
- outcomes: {},
3052
+ outcomes: maintainedOutcomes(),
1926
3053
  templateValues: templateResult?.templateValues ?? {},
1927
- attemptCount: 0
3054
+ attemptCount: 0,
3055
+ durationSeconds: null,
3056
+ responseViolations: violationsOf(initialResponses),
3057
+ correctResponses
1928
3058
  };
1929
3059
  function emit(next) {
1930
3060
  snapshot = next;
@@ -1935,7 +3065,7 @@ function createAttemptStore(declarations, initialResponses, options) {
1935
3065
  function computeScores(responses) {
1936
3066
  return [...declarationsById.values()].map((declaration) => scoreResponse(declaration, responses[declaration.identifier] ?? null, options?.normalization));
1937
3067
  }
1938
- function computeOutcomes(responses, priorOutcomes) {
3068
+ function computeOutcomes(responses, durationSeconds, priorOutcomes) {
1939
3069
  if (!options?.responseProcessing) {
1940
3070
  return {};
1941
3071
  }
@@ -1944,11 +3074,14 @@ function createAttemptStore(declarations, initialResponses, options) {
1944
3074
  outcomeDeclarations: options.outcomeDeclarations ?? [],
1945
3075
  responses,
1946
3076
  normalization: options.normalization,
1947
- templateDeclarations: options.templateDeclarations,
3077
+ templateDeclarations,
1948
3078
  templateValues: snapshot.templateValues,
1949
3079
  priorOutcomes,
1950
3080
  random: rpRandom,
1951
- customOperators: options.customOperators
3081
+ customOperators: options.customOperators,
3082
+ duration: durationSeconds,
3083
+ numAttempts: snapshot.attemptCount + 1,
3084
+ ...typeof snapshot.outcomes["completionStatus"] === "string" ? { completionStatus: snapshot.outcomes["completionStatus"] } : {}
1952
3085
  }).outcomes;
1953
3086
  }
1954
3087
  return {
@@ -1963,9 +3096,11 @@ function createAttemptStore(declarations, initialResponses, options) {
1963
3096
  if (snapshot.submitted) {
1964
3097
  return;
1965
3098
  }
3099
+ const responses = { ...snapshot.responses, [responseIdentifier]: value };
1966
3100
  emit({
1967
3101
  ...snapshot,
1968
- responses: { ...snapshot.responses, [responseIdentifier]: value }
3102
+ responses,
3103
+ responseViolations: violationsOf(responses)
1969
3104
  });
1970
3105
  },
1971
3106
  registerResponseCollector: (responseIdentifier, collector) => {
@@ -1988,11 +3123,17 @@ function createAttemptStore(declarations, initialResponses, options) {
1988
3123
  }
1989
3124
  }
1990
3125
  if (collected !== snapshot.responses) {
1991
- snapshot = { ...snapshot, responses: collected };
3126
+ snapshot = { ...snapshot, responses: collected, responseViolations: violationsOf(collected) };
3127
+ }
3128
+ if (options?.validateResponses && snapshot.responseViolations.length > 0) {
3129
+ emit(snapshot);
3130
+ return snapshot.scores;
1992
3131
  }
1993
3132
  const scores = computeScores(snapshot.responses);
3133
+ const durationSeconds = activeSeconds();
1994
3134
  const priorOutcomes = options?.adaptive && snapshot.attemptCount > 0 ? snapshot.outcomes : undefined;
1995
- const outcomes = computeOutcomes(snapshot.responses, priorOutcomes);
3135
+ const rpOutcomes = computeOutcomes(snapshot.responses, durationSeconds, priorOutcomes);
3136
+ const outcomes = options?.responseProcessing ? rpOutcomes : { ...maintainedOutcomes(), ...rpOutcomes };
1996
3137
  const completionStatus = outcomes["completionStatus"] ?? outcomes["completion_status"];
1997
3138
  const completed = !options?.adaptive || completionStatus === "completed";
1998
3139
  let responses = snapshot.responses;
@@ -2010,27 +3151,200 @@ function createAttemptStore(declarations, initialResponses, options) {
2010
3151
  submitted: completed,
2011
3152
  scores,
2012
3153
  outcomes,
2013
- attemptCount: snapshot.attemptCount + 1
3154
+ attemptCount: snapshot.attemptCount + 1,
3155
+ durationSeconds
2014
3156
  });
2015
3157
  return scores;
2016
3158
  },
3159
+ suspend: () => {
3160
+ if (runningSinceMs !== null) {
3161
+ activeMs += now() - runningSinceMs;
3162
+ runningSinceMs = null;
3163
+ }
3164
+ },
3165
+ resume: () => {
3166
+ runningSinceMs ??= now();
3167
+ },
2017
3168
  reset: () => {
3169
+ activeMs = 0;
3170
+ runningSinceMs = now();
2018
3171
  emit({
2019
3172
  responses: { ...initialResponses },
2020
3173
  submitted: false,
2021
3174
  scores: [],
2022
- outcomes: {},
3175
+ outcomes: maintainedOutcomes(),
2023
3176
  templateValues: snapshot.templateValues,
2024
- attemptCount: 0
3177
+ attemptCount: 0,
3178
+ durationSeconds: null,
3179
+ responseViolations: violationsOf(initialResponses),
3180
+ correctResponses
2025
3181
  });
2026
3182
  }
2027
3183
  };
2028
3184
  }
3185
+ // src/pnp.ts
3186
+ var pnpFeatureFields = {
3187
+ "linguistic-guidance": "linguisticGuidance",
3188
+ "keyword-emphasis": "keywordEmphasis",
3189
+ "keyword-translation": "keywordTranslation",
3190
+ "simplified-language-portions": "simplifiedLanguagePortions",
3191
+ "simplified-graphics": "simplifiedGraphics",
3192
+ "item-translation": "itemTranslation",
3193
+ "sign-language": "signLanguage",
3194
+ encouragement: "encouragement",
3195
+ "additional-testing-time": "additionalTestingTime",
3196
+ "line-reader": "lineReader",
3197
+ "invert-display-polarity": "invertDisplayPolarity",
3198
+ magnification: "magnification",
3199
+ spoken: "spoken",
3200
+ tactile: "tactile",
3201
+ braille: "braille",
3202
+ "answer-masking": "answerMasking",
3203
+ "keyboard-directions": "keyboardDirections",
3204
+ "additional-directions": "additionalDirections",
3205
+ "long-description": "longDescription",
3206
+ captions: "captions",
3207
+ transcript: "transcript",
3208
+ "alternative-text": "alternativeText",
3209
+ "audio-description": "audioDescription",
3210
+ "high-contrast": "highContrast",
3211
+ "input-requirements": "inputRequirements",
3212
+ "language-of-interface": "languageOfInterface",
3213
+ "layout-single-column": "layoutSingleColumn",
3214
+ "text-appearance": "textAppearance",
3215
+ "calculator-on-screen": "calculatorOnScreen",
3216
+ "dictionary-on-screen": "dictionaryOnScreen",
3217
+ "glossary-on-screen": "glossaryOnScreen",
3218
+ "thesaurus-on-screen": "thesaurusOnScreen",
3219
+ "homophone-checker-on-screen": "homophoneCheckerOnScreen",
3220
+ "note-taking-on-screen": "noteTakingOnScreen",
3221
+ "visual-organizer-on-screen": "visualOrganizerOnScreen",
3222
+ "outliner-on-screen": "outlinerOnScreen",
3223
+ "peer-interaction-on-screen": "peerInteractionOnScreen",
3224
+ "spell-checker-on-screen": "spellCheckerOnScreen"
3225
+ };
3226
+ function resolvePnpActivation(pnp) {
3227
+ const prohibited = new Set(pnp?.prohibitSet?.features ?? []);
3228
+ const active = new Set;
3229
+ const optional = new Set;
3230
+ if (!pnp) {
3231
+ return { active, optional, prohibited };
3232
+ }
3233
+ const optedIn = new Set(pnp.activateAsOptionSet?.features ?? []);
3234
+ for (const feature of pnp.activateAtInitializationSet?.features ?? []) {
3235
+ active.add(feature);
3236
+ }
3237
+ for (const [feature, field] of Object.entries(pnpFeatureFields)) {
3238
+ if (pnp[field] === undefined || active.has(feature) || optedIn.has(feature)) {
3239
+ continue;
3240
+ }
3241
+ active.add(feature);
3242
+ }
3243
+ for (const feature of optedIn) {
3244
+ if (!active.has(feature)) {
3245
+ optional.add(feature);
3246
+ }
3247
+ }
3248
+ for (const feature of prohibited) {
3249
+ active.delete(feature);
3250
+ optional.delete(feature);
3251
+ }
3252
+ return { active, optional, prohibited };
3253
+ }
3254
+ function languagesMatch(left, right) {
3255
+ const a3 = left.toLowerCase();
3256
+ const b2 = right.toLowerCase();
3257
+ return a3 === b2 || a3.split("-")[0] === b2.split("-")[0];
3258
+ }
3259
+ function camelCase(name) {
3260
+ return name.replace(/-([a-z])/gu, (_2, letter) => letter.toUpperCase());
3261
+ }
3262
+ function pnpFeaturePreference(pnp, feature) {
3263
+ const field = pnpFeatureFields[feature];
3264
+ if (!pnp || !field) {
3265
+ return;
3266
+ }
3267
+ const value = pnp[field];
3268
+ const first = Array.isArray(value) ? value[0] : value;
3269
+ return typeof first === "object" && first !== null ? first : undefined;
3270
+ }
3271
+ function entryMatches(entry, preference) {
3272
+ if (entry.xmlLang !== undefined) {
3273
+ const preferred = preference?.["xmlLang"];
3274
+ if (typeof preferred !== "string" || !languagesMatch(entry.xmlLang, preferred)) {
3275
+ return false;
3276
+ }
3277
+ }
3278
+ for (const [name, value] of Object.entries(entry.dataAttributes ?? {})) {
3279
+ const preferred = preference?.[camelCase(name)];
3280
+ const comparable = typeof preferred === "string" || typeof preferred === "number" || typeof preferred === "boolean" ? `${preferred}` : undefined;
3281
+ if (comparable === undefined || comparable !== value) {
3282
+ return false;
3283
+ }
3284
+ }
3285
+ return true;
3286
+ }
3287
+ function resolveCard(card, pnp) {
3288
+ if (!card.cardEntries) {
3289
+ const cardLang = card.xmlLang ?? card.htmlContent?.xmlLang;
3290
+ return {
3291
+ support: card.support,
3292
+ ...cardLang !== undefined ? { xmlLang: cardLang } : {},
3293
+ ...card.htmlContent?.content ? { content: card.htmlContent.content } : {},
3294
+ ...card.fileHrefs ? { fileHrefs: card.fileHrefs } : {}
3295
+ };
3296
+ }
3297
+ const preference = pnpFeaturePreference(pnp, card.support);
3298
+ const entry = card.cardEntries.find((candidate) => entryMatches(candidate, preference)) ?? card.cardEntries.find((candidate) => candidate.default === true);
3299
+ if (!entry) {
3300
+ return;
3301
+ }
3302
+ const xmlLang = entry.xmlLang ?? entry.htmlContent?.xmlLang ?? card.xmlLang;
3303
+ return {
3304
+ support: card.support,
3305
+ ...xmlLang !== undefined ? { xmlLang } : {},
3306
+ ...entry.htmlContent?.content ? { content: entry.htmlContent.content } : {},
3307
+ ...entry.fileHrefs ? { fileHrefs: entry.fileHrefs } : {}
3308
+ };
3309
+ }
3310
+ function resolveCatalogSupports(options) {
3311
+ const activation = resolvePnpActivation(options.pnp);
3312
+ const effective = new Set(activation.active);
3313
+ for (const support of options.activeSupports ?? []) {
3314
+ if (!activation.prohibited.has(support)) {
3315
+ effective.add(support);
3316
+ }
3317
+ }
3318
+ const byCatalogId = new Map;
3319
+ for (const catalog of options.catalogs ?? []) {
3320
+ const resolved = [];
3321
+ for (const card of catalog.cards) {
3322
+ if (!effective.has(card.support)) {
3323
+ continue;
3324
+ }
3325
+ const support = resolveCard(card, options.pnp);
3326
+ if (support) {
3327
+ resolved.push(support);
3328
+ }
3329
+ }
3330
+ byCatalogId.set(catalog.id, resolved);
3331
+ }
3332
+ return { activation, byCatalogId };
3333
+ }
3334
+
2029
3335
  // src/test/controller.ts
2030
- var supportedOutcomeRuleKinds = new Set(["outcomeCondition", "setOutcomeValue", "exitTest"]);
3336
+ var supportedOutcomeRuleKinds = new Set([
3337
+ "outcomeCondition",
3338
+ "setOutcomeValue",
3339
+ "lookupOutcomeValue",
3340
+ "outcomeProcessingFragment",
3341
+ "exitTest"
3342
+ ]);
2031
3343
  var testExpressionKinds = new Set([
2032
3344
  ...deterministicExpressionKinds,
2033
3345
  "testVariables",
3346
+ "outcomeMinimum",
3347
+ "outcomeMaximum",
2034
3348
  "numberCorrect",
2035
3349
  "numberIncorrect",
2036
3350
  "numberPresented",
@@ -2071,54 +3385,83 @@ function definedControl(control) {
2071
3385
  return control ? Object.fromEntries(Object.entries(control).filter(([, value]) => value !== undefined)) : {};
2072
3386
  }
2073
3387
  function seededPick(pool, count, random) {
2074
- const indices = pool.map((_, index) => index);
2075
- for (let i = indices.length - 1;i > 0; i -= 1) {
2076
- const j = Math.floor(random() * (i + 1));
2077
- [indices[i], indices[j]] = [indices[j], indices[i]];
3388
+ const indices = pool.map((_2, index) => index);
3389
+ for (let i3 = indices.length - 1;i3 > 0; i3 -= 1) {
3390
+ const j2 = Math.floor(random() * (i3 + 1));
3391
+ [indices[i3], indices[j2]] = [indices[j2], indices[i3]];
2078
3392
  }
2079
- return indices.slice(0, Math.min(count, indices.length)).sort((a, b) => a - b).map((index) => pool[index]);
3393
+ return indices.slice(0, Math.min(count, indices.length)).sort((a3, b2) => a3 - b2).map((index) => pool[index]);
2080
3394
  }
2081
- function applySelection(children, select, random) {
3395
+ function applySelection(children, selection, random) {
2082
3396
  const required = children.filter((child) => child.required === true);
3397
+ const needed = Math.max(0, selection.select - required.length);
3398
+ if (selection.withReplacement === true) {
3399
+ const counts = children.map((child) => child.required === true ? 1 : 0);
3400
+ for (let draw = 0;draw < needed; draw += 1) {
3401
+ const index = Math.floor(random() * children.length);
3402
+ counts[index] = (counts[index] ?? 0) + 1;
3403
+ }
3404
+ return children.flatMap((child, index) => Array.from({ length: counts[index] ?? 0 }, () => child));
3405
+ }
2083
3406
  const optional = children.filter((child) => child.required !== true);
2084
- const needed = Math.max(0, select - required.length);
2085
3407
  const picked = new Set([...required, ...seededPick(optional, needed, random)]);
2086
3408
  return children.filter((child) => picked.has(child));
2087
3409
  }
2088
- function applyOrdering(children, random) {
2089
- const result = children.map((child) => child.fixed === true ? child : null);
2090
- const movable = children.filter((child) => child.fixed !== true);
3410
+ function applyOrdering(units, random) {
3411
+ const result = units.map((unit) => unit.child.fixed === true ? unit : null);
3412
+ const movable = units.filter((unit) => unit.child.fixed !== true);
2091
3413
  const shuffled = seededPick(movable, movable.length, random);
2092
- for (let i = shuffled.length - 1;i > 0; i -= 1) {
2093
- const j = Math.floor(random() * (i + 1));
2094
- [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
3414
+ for (let i3 = shuffled.length - 1;i3 > 0; i3 -= 1) {
3415
+ const j2 = Math.floor(random() * (i3 + 1));
3416
+ [shuffled[i3], shuffled[j2]] = [shuffled[j2], shuffled[i3]];
2095
3417
  }
2096
3418
  let cursor = 0;
2097
3419
  return result.map((slot) => slot ?? shuffled[cursor++]);
2098
3420
  }
2099
- function resolveSection(section, partIdentifier, sectionPath, inheritedPreConditions, inheritedControl, random) {
3421
+ function mixedUnits(children, random, sections) {
3422
+ return children.flatMap((child) => {
3423
+ if (child.kind !== "assessmentSection" || child.visible !== false || child.keepTogether !== false) {
3424
+ return [{ child, via: [] }];
3425
+ }
3426
+ sections[child.identifier] = {
3427
+ identifier: child.identifier,
3428
+ ...child.timeLimits ? { timeLimits: child.timeLimits } : {}
3429
+ };
3430
+ const inner = child.selection ? applySelection(child.children, child.selection, random) : child.children;
3431
+ return mixedUnits(inner, random, sections).map((unit) => ({ child: unit.child, via: [child, ...unit.via] }));
3432
+ });
3433
+ }
3434
+ function resolveSection(section, partIdentifier, sectionPath, inheritedPreConditions, inheritedControl, random, sections) {
2100
3435
  const path = [...sectionPath, section.identifier];
3436
+ sections[section.identifier] = {
3437
+ identifier: section.identifier,
3438
+ ...section.timeLimits ? { timeLimits: section.timeLimits } : {}
3439
+ };
2101
3440
  const preConditions = [...inheritedPreConditions, ...section.preConditions ?? []];
2102
3441
  const control = { ...inheritedControl, ...definedControl(section.itemSessionControl) };
2103
3442
  let children = section.children;
2104
3443
  if (section.selection) {
2105
- children = applySelection(children, section.selection.select, random);
3444
+ children = applySelection(children, section.selection, random);
2106
3445
  }
3446
+ let units = children.map((child) => ({ child, via: [] }));
2107
3447
  if (section.ordering?.shuffle) {
2108
- children = applyOrdering(children, random);
3448
+ units = applyOrdering(mixedUnits(children, random, sections), random);
2109
3449
  }
2110
3450
  const items = [];
2111
- for (const child of children) {
3451
+ for (const { child, via } of units) {
3452
+ const viaPath = [...path, ...via.map((entry) => entry.identifier)];
3453
+ const viaPreConditions = [...preConditions, ...via.flatMap((entry) => entry.preConditions ?? [])];
3454
+ const viaControl = via.reduce((merged, entry) => ({ ...merged, ...definedControl(entry.itemSessionControl) }), control);
2112
3455
  if (child.kind === "assessmentSection") {
2113
- items.push(...resolveSection(child, partIdentifier, path, preConditions, control, random));
3456
+ items.push(...resolveSection(child, partIdentifier, viaPath, viaPreConditions, viaControl, random, sections));
2114
3457
  } else {
2115
3458
  items.push({
2116
3459
  key: child.identifier,
2117
3460
  ref: child,
2118
3461
  partIdentifier,
2119
- sectionPath: path,
2120
- preConditions: [...preConditions, ...child.preConditions ?? []],
2121
- sessionControl: { ...specSessionControlDefaults, ...control, ...definedControl(child.itemSessionControl) },
3462
+ sectionPath: viaPath,
3463
+ preConditions: [...viaPreConditions, ...child.preConditions ?? []],
3464
+ sessionControl: { ...specSessionControlDefaults, ...viaControl, ...definedControl(child.itemSessionControl) },
2122
3465
  ...child.timeLimits ? { timeLimits: child.timeLimits } : {}
2123
3466
  });
2124
3467
  }
@@ -2127,15 +3470,36 @@ function resolveSection(section, partIdentifier, sectionPath, inheritedPreCondit
2127
3470
  }
2128
3471
  function resolvePlan(view, seed) {
2129
3472
  const random = mulberry32(seed);
3473
+ const sections = {};
3474
+ const parts = view.testParts.map((part) => ({
3475
+ identifier: part.identifier,
3476
+ navigationMode: part.navigationMode,
3477
+ submissionMode: part.submissionMode,
3478
+ ...part.timeLimits ? { timeLimits: part.timeLimits } : {},
3479
+ items: part.assessmentSections.flatMap((section) => resolveSection(section, part.identifier, [], [], definedControl(part.itemSessionControl), random, sections))
3480
+ }));
3481
+ const totals = new Map;
3482
+ for (const part of parts) {
3483
+ for (const item of part.items) {
3484
+ totals.set(item.ref.identifier, (totals.get(item.ref.identifier) ?? 0) + 1);
3485
+ }
3486
+ }
3487
+ const ordinals = new Map;
3488
+ const keyedParts = parts.map((part) => ({
3489
+ ...part,
3490
+ items: part.items.map((item) => {
3491
+ if ((totals.get(item.ref.identifier) ?? 0) < 2) {
3492
+ return item;
3493
+ }
3494
+ const instance = (ordinals.get(item.ref.identifier) ?? 0) + 1;
3495
+ ordinals.set(item.ref.identifier, instance);
3496
+ return { ...item, key: `${item.ref.identifier}.${instance}`, instance };
3497
+ })
3498
+ }));
2130
3499
  return {
2131
3500
  ...view.timeLimits ? { timeLimits: view.timeLimits } : {},
2132
- parts: view.testParts.map((part) => ({
2133
- identifier: part.identifier,
2134
- navigationMode: part.navigationMode,
2135
- submissionMode: part.submissionMode,
2136
- ...part.timeLimits ? { timeLimits: part.timeLimits } : {},
2137
- items: part.assessmentSections.flatMap((section) => resolveSection(section, part.identifier, [], [], definedControl(part.itemSessionControl), random))
2138
- }))
3501
+ parts: keyedParts,
3502
+ sections
2139
3503
  };
2140
3504
  }
2141
3505
  function createTestController(view, options) {
@@ -2143,10 +3507,17 @@ function createTestController(view, options) {
2143
3507
  const allItems = plan.parts.flatMap((part) => [...part.items]);
2144
3508
  const partIndexByItemKey = new Map;
2145
3509
  const itemsByKey = new Map;
3510
+ const instancesByRef = new Map;
2146
3511
  plan.parts.forEach((part, partIndex) => {
2147
3512
  for (const item of part.items) {
2148
3513
  partIndexByItemKey.set(item.key, partIndex);
2149
3514
  itemsByKey.set(item.key, item);
3515
+ const siblings = instancesByRef.get(item.ref.identifier);
3516
+ if (siblings) {
3517
+ siblings.push(item);
3518
+ } else {
3519
+ instancesByRef.set(item.ref.identifier, [item]);
3520
+ }
2150
3521
  }
2151
3522
  });
2152
3523
  function attemptsOf(state, itemKey) {
@@ -2167,13 +3538,123 @@ function createTestController(view, options) {
2167
3538
  return !(excludeCategory !== undefined && excludeCategory.some((category) => categories.includes(category)));
2168
3539
  });
2169
3540
  }
2170
- function remainingAttempts(state, itemKey) {
2171
- const item = itemsByKey.get(itemKey);
2172
- if (!item) {
3541
+ function weightOf(item, weightIdentifier) {
3542
+ if (weightIdentifier === undefined) {
3543
+ return 1;
3544
+ }
3545
+ return item.ref.weights?.find((entry) => entry.identifier === weightIdentifier)?.value ?? 1;
3546
+ }
3547
+ function remainingAttempts(state, itemKey) {
3548
+ const item = itemsByKey.get(itemKey);
3549
+ if (!item) {
3550
+ return 0;
3551
+ }
3552
+ const max = item.sessionControl.maxAttempts;
3553
+ return max === 0 ? Number.POSITIVE_INFINITY : Math.max(0, max - attemptsOf(state, itemKey));
3554
+ }
3555
+ const now = options.now ?? Date.now;
3556
+ function touch(state) {
3557
+ if (state.status !== "in-progress") {
3558
+ return state;
3559
+ }
3560
+ const nowMs = now();
3561
+ const timing = state.timing ?? {
3562
+ lastTransitionAtMs: nowMs,
3563
+ testSeconds: 0,
3564
+ partSeconds: {},
3565
+ sectionSeconds: {},
3566
+ itemSeconds: {}
3567
+ };
3568
+ const elapsed = Math.max(0, nowMs - timing.lastTransitionAtMs) / 1000;
3569
+ const bump = (record, key) => ({
3570
+ ...record,
3571
+ [key]: (record[key] ?? 0) + elapsed
3572
+ });
3573
+ const item = state.currentItemKey === null ? undefined : itemsByKey.get(state.currentItemKey);
3574
+ return {
3575
+ ...state,
3576
+ timing: {
3577
+ lastTransitionAtMs: nowMs,
3578
+ testSeconds: timing.testSeconds + elapsed,
3579
+ partSeconds: item ? bump(timing.partSeconds, item.partIdentifier) : timing.partSeconds,
3580
+ sectionSeconds: item ? item.sectionPath.reduce((record, identifier) => bump(record, identifier), timing.sectionSeconds) : timing.sectionSeconds,
3581
+ itemSeconds: item ? bump(timing.itemSeconds, item.key) : timing.itemSeconds
3582
+ }
3583
+ };
3584
+ }
3585
+ function secondsOf(state, scope) {
3586
+ const timing = state.timing;
3587
+ if (!timing) {
2173
3588
  return 0;
2174
3589
  }
2175
- const max = item.sessionControl.maxAttempts;
2176
- return max === 0 ? Number.POSITIVE_INFINITY : Math.max(0, max - attemptsOf(state, itemKey));
3590
+ switch (scope.kind) {
3591
+ case "test":
3592
+ return timing.testSeconds;
3593
+ case "part":
3594
+ return timing.partSeconds[scope.identifier] ?? 0;
3595
+ case "section":
3596
+ return timing.sectionSeconds[scope.identifier] ?? 0;
3597
+ case "item":
3598
+ return timing.itemSeconds[scope.key] ?? 0;
3599
+ }
3600
+ }
3601
+ function timeLimitsOf(scope) {
3602
+ switch (scope.kind) {
3603
+ case "test":
3604
+ return plan.timeLimits;
3605
+ case "part":
3606
+ return plan.parts.find((part) => part.identifier === scope.identifier)?.timeLimits;
3607
+ case "section":
3608
+ return plan.sections[scope.identifier]?.timeLimits;
3609
+ case "item":
3610
+ return itemsByKey.get(scope.key)?.timeLimits;
3611
+ }
3612
+ }
3613
+ const additionalTestingTime = resolvePnpActivation(options.pnp).active.has("additional-testing-time") ? options.pnp?.additionalTestingTime : undefined;
3614
+ function effectiveMaxTime(scope) {
3615
+ if (additionalTestingTime?.unlimited === true) {
3616
+ return;
3617
+ }
3618
+ const declared = timeLimitsOf(scope)?.maxTime;
3619
+ if (declared === undefined) {
3620
+ return;
3621
+ }
3622
+ if (additionalTestingTime?.timeMultiplier !== undefined) {
3623
+ return declared * additionalTestingTime.timeMultiplier;
3624
+ }
3625
+ if (additionalTestingTime?.fixedMinutes !== undefined && scope.kind === "test") {
3626
+ return declared + additionalTestingTime.fixedMinutes * 60;
3627
+ }
3628
+ return declared;
3629
+ }
3630
+ function scopeExpired(state, scope) {
3631
+ const maxTime = effectiveMaxTime(scope);
3632
+ return maxTime !== undefined && secondsOf(state, scope) > maxTime;
3633
+ }
3634
+ function enclosingScopes(item) {
3635
+ return [
3636
+ { kind: "item", key: item.key },
3637
+ ...[...item.sectionPath].reverse().map((identifier) => ({ kind: "section", identifier })),
3638
+ { kind: "part", identifier: item.partIdentifier },
3639
+ { kind: "test" }
3640
+ ];
3641
+ }
3642
+ function navigableInTime(state, item) {
3643
+ return !enclosingScopes(item).some((scope) => scopeExpired(state, scope));
3644
+ }
3645
+ function minTimeBlocked(state, from, to) {
3646
+ const itemMin = from.timeLimits?.minTime;
3647
+ if (itemMin !== undefined && secondsOf(state, { kind: "item", key: from.key }) < itemMin) {
3648
+ return true;
3649
+ }
3650
+ const destinationSections = new Set(to?.sectionPath ?? []);
3651
+ return from.sectionPath.some((identifier) => {
3652
+ if (destinationSections.has(identifier)) {
3653
+ return false;
3654
+ }
3655
+ const minTime = plan.sections[identifier]?.timeLimits?.minTime;
3656
+ return minTime !== undefined && secondsOf(state, { kind: "section", identifier }) < minTime;
3657
+ });
2177
3658
  }
2178
3659
  function defaultTestOutcomes() {
2179
3660
  const outcomes = new Map;
@@ -2186,13 +3667,56 @@ function createTestController(view, options) {
2186
3667
  }
2187
3668
  return outcomes;
2188
3669
  }
3670
+ const durationValue = (seconds) => rpValue("single", [seconds], "duration");
2189
3671
  function makeEnv(state, outcomes) {
2190
3672
  return {
2191
3673
  lookupVariable: (identifier) => {
3674
+ if (identifier === "duration") {
3675
+ return state.timing === undefined ? null : durationValue(state.timing.testSeconds);
3676
+ }
2192
3677
  const dot = identifier.indexOf(".");
2193
3678
  if (dot !== -1) {
2194
- const itemKey = identifier.slice(0, dot);
2195
- const variableName = identifier.slice(dot + 1);
3679
+ let itemKey = identifier.slice(0, dot);
3680
+ let variableName = identifier.slice(dot + 1);
3681
+ const secondDot = identifier.indexOf(".", dot + 1);
3682
+ if (secondDot !== -1 && itemsByKey.has(identifier.slice(0, secondDot))) {
3683
+ itemKey = identifier.slice(0, secondDot);
3684
+ variableName = identifier.slice(secondDot + 1);
3685
+ }
3686
+ const instances = instancesByRef.get(itemKey);
3687
+ if (instances !== undefined && instances.length > 1) {
3688
+ const partIndex = partIndexByItemKey.get(instances[0].key);
3689
+ if (partIndex === undefined || plan.parts[partIndex].submissionMode !== "simultaneous") {
3690
+ return null;
3691
+ }
3692
+ for (let index = instances.length - 1;index >= 0; index -= 1) {
3693
+ const instanceKey = instances[index].key;
3694
+ if (variableName === "duration") {
3695
+ const seconds = state.itemDurationSeconds?.[instanceKey];
3696
+ if (seconds !== undefined) {
3697
+ return durationValue(seconds);
3698
+ }
3699
+ } else if (state.itemOutcomes[instanceKey] !== undefined) {
3700
+ return liftFlat(state.itemOutcomes[instanceKey]?.[variableName] ?? null);
3701
+ }
3702
+ }
3703
+ return null;
3704
+ }
3705
+ if (variableName === "duration") {
3706
+ if (itemsByKey.has(itemKey)) {
3707
+ const seconds = state.itemDurationSeconds?.[itemKey];
3708
+ return seconds === undefined ? null : durationValue(seconds);
3709
+ }
3710
+ const partSeconds = state.timing?.partSeconds[itemKey];
3711
+ if (plan.parts.some((part) => part.identifier === itemKey)) {
3712
+ return partSeconds === undefined ? null : durationValue(partSeconds);
3713
+ }
3714
+ if (plan.sections[itemKey]) {
3715
+ const seconds = state.timing?.sectionSeconds[itemKey];
3716
+ return seconds === undefined ? null : durationValue(seconds);
3717
+ }
3718
+ return null;
3719
+ }
2196
3720
  return liftFlat(state.itemOutcomes[itemKey]?.[variableName] ?? null);
2197
3721
  }
2198
3722
  if (outcomes?.has(identifier)) {
@@ -2219,9 +3743,8 @@ function createTestController(view, options) {
2219
3743
  continue;
2220
3744
  }
2221
3745
  if (weightIdentifier !== undefined && isNumericBaseType(lifted.baseType)) {
2222
- const weight = item.ref.weights?.find((entry) => entry.identifier === weightIdentifier)?.value ?? 1;
2223
3746
  baseType = "float";
2224
- members.push(...lifted.values.map((entry) => Number(entry) * weight));
3747
+ members.push(...lifted.values.map((entry) => Number(entry) * weightOf(item, weightIdentifier)));
2225
3748
  continue;
2226
3749
  }
2227
3750
  baseType ??= lifted.baseType;
@@ -2251,6 +3774,22 @@ function createTestController(view, options) {
2251
3774
  return integer(countIn(state.correctItems));
2252
3775
  case "numberIncorrect":
2253
3776
  return integer(countIn(state.incorrectItems));
3777
+ case "outcomeMinimum":
3778
+ case "outcomeMaximum": {
3779
+ const bound = expression.kind === "outcomeMaximum" ? "normalMaximum" : "normalMinimum";
3780
+ const members = [];
3781
+ for (const item of subset) {
3782
+ const declared = options.itemOutcomeDeclarations?.[item.ref.identifier]?.find((entry) => entry.identifier === expression.outcomeIdentifier)?.[bound];
3783
+ if (declared === undefined) {
3784
+ if (expression.kind === "outcomeMaximum") {
3785
+ return null;
3786
+ }
3787
+ continue;
3788
+ }
3789
+ members.push(declared * weightOf(item, expression.weightIdentifier));
3790
+ }
3791
+ return members.length === 0 ? null : rpValue("multiple", members, "float");
3792
+ }
2254
3793
  default:
2255
3794
  throw new RpUnsupportedError(expression.kind);
2256
3795
  }
@@ -2294,6 +3833,20 @@ function createTestController(view, options) {
2294
3833
  }
2295
3834
  continue;
2296
3835
  }
3836
+ if (rule.kind === "outcomeProcessingFragment") {
3837
+ executeRules(rule.rules ?? []);
3838
+ continue;
3839
+ }
3840
+ if (rule.kind === "lookupOutcomeValue") {
3841
+ if (rule.identifier !== undefined && rule.expression !== undefined) {
3842
+ const declaration = (view.outcomeDeclarations ?? []).find((entry) => entry.identifier === rule.identifier);
3843
+ if (!hasLookupTable(declaration)) {
3844
+ throw new RpUnsupportedError("lookupOutcomeValue");
3845
+ }
3846
+ outcomes.set(rule.identifier, lookupTableValue(declaration, evaluateExpression(rule.expression, env)));
3847
+ }
3848
+ continue;
3849
+ }
2297
3850
  if (rule.outcomeIf && branchTaken(rule.outcomeIf)) {
2298
3851
  continue;
2299
3852
  }
@@ -2315,11 +3868,11 @@ function createTestController(view, options) {
2315
3868
  return Object.fromEntries([...outcomes].map(([identifier, value]) => [identifier, toOutcomeValue(value)]));
2316
3869
  }
2317
3870
  function firstNavigable(state, partIndex, itemIndex) {
2318
- for (let p = partIndex;p < plan.parts.length; p += 1) {
2319
- const items = plan.parts[p].items;
2320
- for (let i = p === partIndex ? itemIndex : 0;i < items.length; i += 1) {
2321
- const item = items[i];
2322
- if (preConditionsPass(item, state)) {
3871
+ for (let p2 = partIndex;p2 < plan.parts.length; p2 += 1) {
3872
+ const items = plan.parts[p2].items;
3873
+ for (let i3 = p2 === partIndex ? itemIndex : 0;i3 < items.length; i3 += 1) {
3874
+ const item = items[i3];
3875
+ if (preConditionsPass(item, state) && navigableInTime(state, item)) {
2323
3876
  return item;
2324
3877
  }
2325
3878
  }
@@ -2352,6 +3905,21 @@ function createTestController(view, options) {
2352
3905
  function markPresented(state, itemKey) {
2353
3906
  return (state.presentedItems ?? []).includes(itemKey) ? state : { ...state, presentedItems: [...state.presentedItems ?? [], itemKey] };
2354
3907
  }
3908
+ function withRecordedAttempt(state, itemKey, result, atMs) {
3909
+ const entry = {
3910
+ atMs,
3911
+ outcomes: result.outcomes,
3912
+ ...result.responses !== undefined ? { responses: result.responses } : {},
3913
+ ...result.durationSeconds !== undefined ? { durationSeconds: result.durationSeconds } : {}
3914
+ };
3915
+ return {
3916
+ ...state,
3917
+ attemptHistory: {
3918
+ ...state.attemptHistory ?? {},
3919
+ [itemKey]: [...state.attemptHistory?.[itemKey] ?? [], entry]
3920
+ }
3921
+ };
3922
+ }
2355
3923
  function flushPending(state, partIndex) {
2356
3924
  const pending = state.pendingItemResults ?? {};
2357
3925
  const keys = Object.keys(pending).filter((key) => partIndex === null || partIndexByItemKey.get(key) === partIndex);
@@ -2360,6 +3928,7 @@ function createTestController(view, options) {
2360
3928
  }
2361
3929
  const itemOutcomes = { ...state.itemOutcomes };
2362
3930
  const attemptCounts = { ...state.attemptCounts ?? {} };
3931
+ const itemDurations = { ...state.itemDurationSeconds ?? {} };
2363
3932
  const remaining = { ...pending };
2364
3933
  let flagged = state;
2365
3934
  for (const key of keys) {
@@ -2367,14 +3936,56 @@ function createTestController(view, options) {
2367
3936
  itemOutcomes[key] = result.outcomes;
2368
3937
  attemptCounts[key] = (attemptCounts[key] ?? 0) + 1;
2369
3938
  delete remaining[key];
2370
- flagged = applyResultFlags(flagged, key, result);
3939
+ if (result.durationSeconds !== undefined) {
3940
+ itemDurations[key] = result.durationSeconds;
3941
+ }
3942
+ flagged = withRecordedAttempt(applyResultFlags(flagged, key, result), key, result, result.submittedAtMs ?? now());
2371
3943
  }
2372
- return { ...flagged, itemOutcomes, attemptCounts, pendingItemResults: remaining };
3944
+ return {
3945
+ ...flagged,
3946
+ itemOutcomes,
3947
+ attemptCounts,
3948
+ itemDurationSeconds: itemDurations,
3949
+ pendingItemResults: remaining
3950
+ };
2373
3951
  }
2374
3952
  function ended(state) {
2375
3953
  const flushed = flushPending(state, null);
2376
3954
  return { ...flushed, status: "ended", currentItemKey: null, testOutcomes: runOutcomeProcessing(flushed) };
2377
3955
  }
3956
+ function evaluateTemplateDefaults(state, item) {
3957
+ const defaults = item.ref.templateDefaults;
3958
+ if (!defaults || defaults.length === 0) {
3959
+ return;
3960
+ }
3961
+ const env = makeEnv(state);
3962
+ const values = {};
3963
+ for (const entry of defaults) {
3964
+ try {
3965
+ values[entry.templateIdentifier] = toOutcomeValue(evaluateExpression(entry.expression, env));
3966
+ } catch (error) {
3967
+ if (!(error instanceof RpUnsupportedError)) {
3968
+ throw error;
3969
+ }
3970
+ }
3971
+ }
3972
+ return values;
3973
+ }
3974
+ function withTemplateDefaults(state, items) {
3975
+ let merged = state.templateDefaultValues ?? {};
3976
+ let changed = false;
3977
+ for (const item of items) {
3978
+ if (merged[item.key] !== undefined) {
3979
+ continue;
3980
+ }
3981
+ const values = evaluateTemplateDefaults(state, item);
3982
+ if (values) {
3983
+ merged = { ...merged, [item.key]: values };
3984
+ changed = true;
3985
+ }
3986
+ }
3987
+ return changed ? { ...state, templateDefaultValues: merged } : state;
3988
+ }
2378
3989
  function moveToItem(state, item) {
2379
3990
  if (item === null) {
2380
3991
  return ended(state);
@@ -2388,10 +3999,14 @@ function createTestController(view, options) {
2388
3999
  next = { ...flushed, testOutcomes: runOutcomeProcessing(flushed) };
2389
4000
  }
2390
4001
  }
4002
+ const part = toPart === undefined ? undefined : plan.parts[toPart];
4003
+ if (part) {
4004
+ next = withTemplateDefaults(next, part.navigationMode === "nonlinear" ? part.items : [item]);
4005
+ }
2391
4006
  return markPresented({ ...next, currentItemKey: item.key }, item.key);
2392
4007
  }
2393
4008
  function nextState(state) {
2394
- if (state.status === "ended" || state.currentItemKey === null) {
4009
+ if (state.status !== "in-progress" || state.currentItemKey === null) {
2395
4010
  return state;
2396
4011
  }
2397
4012
  const current = positionOf(state.currentItemKey);
@@ -2403,6 +4018,9 @@ function createTestController(view, options) {
2403
4018
  if (part.navigationMode === "linear" && !currentItem.sessionControl.allowSkipping && !state.attemptedItems.includes(currentItem.key)) {
2404
4019
  return state;
2405
4020
  }
4021
+ if (part.navigationMode === "linear" && minTimeBlocked(state, currentItem, firstNavigable(state, current.partIndex, current.itemIndex + 1))) {
4022
+ return state;
4023
+ }
2406
4024
  for (const branchRule of currentItem.ref.branchRules ?? []) {
2407
4025
  if (!conditionPasses(branchRule.expression, state)) {
2408
4026
  continue;
@@ -2422,20 +4040,84 @@ function createTestController(view, options) {
2422
4040
  }
2423
4041
  return moveToItem(state, firstNavigable(state, current.partIndex, index));
2424
4042
  }
2425
- const target = positionOf(branchRule.target);
4043
+ const target = positionOf(branchRule.target) ?? (instancesByRef.get(branchRule.target) ?? []).map((instance) => positionOf(instance.key)).find((position) => position !== null && position.partIndex === current.partIndex && position.itemIndex > current.itemIndex) ?? null;
2426
4044
  if (target && target.partIndex === current.partIndex) {
2427
4045
  return moveToItem(state, firstNavigable(state, target.partIndex, target.itemIndex));
2428
4046
  }
2429
4047
  }
2430
4048
  const destination = firstNavigable(state, current.partIndex, current.itemIndex + 1);
2431
4049
  if (part.navigationMode === "nonlinear" && (destination === null || partIndexByItemKey.get(destination.key) !== current.partIndex)) {
2432
- const blocked = part.items.some((item) => !item.sessionControl.allowSkipping && !state.attemptedItems.includes(item.key) && preConditionsPass(item, state));
4050
+ const blocked = part.items.some((item) => !item.sessionControl.allowSkipping && !state.attemptedItems.includes(item.key) && preConditionsPass(item, state) && navigableInTime(state, item));
2433
4051
  if (blocked) {
2434
4052
  return state;
2435
4053
  }
2436
4054
  }
2437
4055
  return moveToItem(state, destination);
2438
4056
  }
4057
+ function reviewBarred(state, item) {
4058
+ return item.sessionControl.allowReview === false && remainingAttempts(state, item.key) <= 0;
4059
+ }
4060
+ function reviewable(state, itemKey) {
4061
+ const item = itemsByKey.get(itemKey);
4062
+ return state.status === "ended" && item !== undefined && item.sessionControl.allowReview && (state.presentedItems ?? []).includes(itemKey);
4063
+ }
4064
+ function commentable(state, itemKey) {
4065
+ return state.status === "in-progress" && itemsByKey.get(itemKey)?.sessionControl.allowComment === true;
4066
+ }
4067
+ function submitBody(state, itemKey, result) {
4068
+ const partIndex = partIndexByItemKey.get(itemKey);
4069
+ if (partIndex !== undefined && plan.parts[partIndex].submissionMode === "simultaneous") {
4070
+ if (attemptsOf(state, itemKey) > 0) {
4071
+ return state;
4072
+ }
4073
+ return {
4074
+ ...state,
4075
+ pendingItemResults: { ...state.pendingItemResults ?? {}, [itemKey]: { ...result, submittedAtMs: now() } },
4076
+ attemptedItems: state.attemptedItems.includes(itemKey) ? state.attemptedItems : [...state.attemptedItems, itemKey]
4077
+ };
4078
+ }
4079
+ if (result.valid === false && itemsByKey.get(itemKey)?.sessionControl.validateResponses === true) {
4080
+ return state;
4081
+ }
4082
+ if (result.adaptive !== true && remainingAttempts(state, itemKey) <= 0) {
4083
+ return state;
4084
+ }
4085
+ const next = {
4086
+ ...withRecordedAttempt(applyResultFlags(state, itemKey, result), itemKey, result, now()),
4087
+ itemOutcomes: { ...state.itemOutcomes, [itemKey]: result.outcomes },
4088
+ attemptedItems: state.attemptedItems.includes(itemKey) ? state.attemptedItems : [...state.attemptedItems, itemKey],
4089
+ attemptCounts: { ...state.attemptCounts ?? {}, [itemKey]: attemptsOf(state, itemKey) + 1 },
4090
+ ...result.durationSeconds !== undefined ? { itemDurationSeconds: { ...state.itemDurationSeconds ?? {}, [itemKey]: result.durationSeconds } } : {}
4091
+ };
4092
+ return { ...next, testOutcomes: runOutcomeProcessing(next) };
4093
+ }
4094
+ function applyExpiries(state) {
4095
+ if (state.status !== "in-progress") {
4096
+ return state;
4097
+ }
4098
+ if (scopeExpired(state, { kind: "test" })) {
4099
+ return ended(state);
4100
+ }
4101
+ const currentKey = state.currentItemKey;
4102
+ const item = currentKey === null ? undefined : itemsByKey.get(currentKey);
4103
+ if (!item || navigableInTime(state, item)) {
4104
+ return state;
4105
+ }
4106
+ const position = positionOf(item.key);
4107
+ return position === null ? ended(state) : moveToItem(state, firstNavigable(state, position.partIndex, position.itemIndex + 1));
4108
+ }
4109
+ function withTransition(state, op) {
4110
+ if (state.status !== "in-progress") {
4111
+ return state;
4112
+ }
4113
+ const touched = touch(state);
4114
+ const settled = applyExpiries(touched);
4115
+ if (settled !== touched) {
4116
+ return settled;
4117
+ }
4118
+ const result = op(settled);
4119
+ return result === settled ? state : result;
4120
+ }
2439
4121
  const issues = [];
2440
4122
  const seenIssues = new Set;
2441
4123
  function report(name) {
@@ -2450,9 +4132,18 @@ function createTestController(view, options) {
2450
4132
  report(rule.kind);
2451
4133
  continue;
2452
4134
  }
4135
+ if (rule.kind === "lookupOutcomeValue") {
4136
+ const declaration = (view.outcomeDeclarations ?? []).find((entry) => entry.identifier === rule.identifier);
4137
+ if (!hasLookupTable(declaration)) {
4138
+ report("lookupOutcomeValue");
4139
+ }
4140
+ }
2453
4141
  if (rule.expression) {
2454
4142
  collectExpressionIssues(rule.expression, testExpressionKinds, report);
2455
4143
  }
4144
+ if (rule.rules) {
4145
+ walkOutcomeRules(rule.rules);
4146
+ }
2456
4147
  for (const branch of [rule.outcomeIf, ...rule.outcomeElseIfs ?? []]) {
2457
4148
  if (branch) {
2458
4149
  collectExpressionIssues(branch.expression, testExpressionKinds, report);
@@ -2472,8 +4163,12 @@ function createTestController(view, options) {
2472
4163
  for (const branchRule of item.ref.branchRules ?? []) {
2473
4164
  collectExpressionIssues(branchRule.expression, testExpressionKinds, report);
2474
4165
  }
4166
+ for (const entry of item.ref.templateDefaults ?? []) {
4167
+ collectExpressionIssues(entry.expression, testExpressionKinds, report);
4168
+ }
2475
4169
  }
2476
4170
  return {
4171
+ test: view,
2477
4172
  plan,
2478
4173
  issues,
2479
4174
  start: () => {
@@ -2488,13 +4183,21 @@ function createTestController(view, options) {
2488
4183
  correctItems: [],
2489
4184
  incorrectItems: [],
2490
4185
  pendingItemResults: {},
2491
- testOutcomes: {}
4186
+ testOutcomes: {},
4187
+ timing: {
4188
+ lastTransitionAtMs: now(),
4189
+ testSeconds: 0,
4190
+ partSeconds: {},
4191
+ sectionSeconds: {},
4192
+ itemSeconds: {}
4193
+ }
2492
4194
  };
2493
- return moveToItem({ ...initial, testOutcomes: runOutcomeProcessing(initial) }, firstNavigable(initial, 0, 0));
4195
+ const opened = { ...initial, testOutcomes: runOutcomeProcessing(initial) };
4196
+ return moveToItem(opened, firstNavigable(opened, 0, 0));
2494
4197
  },
2495
4198
  currentItem: (state) => state.currentItemKey === null ? null : allItems.find((item) => item.key === state.currentItemKey) ?? null,
2496
4199
  canMoveTo: (state, itemKey) => {
2497
- if (state.status === "ended" || state.currentItemKey === null) {
4200
+ if (state.status !== "in-progress" || state.currentItemKey === null) {
2498
4201
  return false;
2499
4202
  }
2500
4203
  const current = positionOf(state.currentItemKey);
@@ -2505,47 +4208,65 @@ function createTestController(view, options) {
2505
4208
  if (plan.parts[current.partIndex].navigationMode !== "nonlinear") {
2506
4209
  return false;
2507
4210
  }
2508
- return preConditionsPass(plan.parts[target.partIndex].items[target.itemIndex], state);
4211
+ const item = plan.parts[target.partIndex].items[target.itemIndex];
4212
+ return preConditionsPass(item, state) && navigableInTime(state, item) && !reviewBarred(state, item);
2509
4213
  },
2510
- moveTo: (state, itemKey) => {
2511
- const current = positionOf(state.currentItemKey ?? "");
4214
+ moveTo: (state, itemKey) => withTransition(state, (settled) => {
4215
+ const current = positionOf(settled.currentItemKey ?? "");
2512
4216
  const target = positionOf(itemKey);
2513
- if (state.status === "ended" || !current || !target || target.partIndex !== current.partIndex || plan.parts[current.partIndex].navigationMode !== "nonlinear") {
2514
- return state;
4217
+ const item = itemsByKey.get(itemKey);
4218
+ if (!current || !target || !item || target.partIndex !== current.partIndex || plan.parts[current.partIndex].navigationMode !== "nonlinear" || !navigableInTime(settled, item) || reviewBarred(settled, item)) {
4219
+ return settled;
2515
4220
  }
2516
- return markPresented({ ...state, currentItemKey: itemKey }, itemKey);
2517
- },
4221
+ return markPresented({ ...settled, currentItemKey: itemKey }, itemKey);
4222
+ }),
2518
4223
  canNext: (state) => nextState(state) !== state,
2519
- next: nextState,
4224
+ next: (state) => withTransition(state, nextState),
2520
4225
  remainingAttempts,
2521
- canSubmitItem: (state, itemKey) => state.status !== "ended" && remainingAttempts(state, itemKey) > 0,
4226
+ canSubmitItem: (state, itemKey) => {
4227
+ if (state.status !== "in-progress" || remainingAttempts(state, itemKey) <= 0) {
4228
+ return false;
4229
+ }
4230
+ const item = itemsByKey.get(itemKey);
4231
+ return item !== undefined && enclosingScopes(item).every((scope) => !scopeExpired(state, scope) || timeLimitsOf(scope)?.allowLateSubmission === true);
4232
+ },
2522
4233
  submitItem: (state, itemKey, result) => {
2523
- if (state.status === "ended") {
4234
+ const item = itemsByKey.get(itemKey);
4235
+ if (state.status !== "in-progress" || !item) {
2524
4236
  return state;
2525
4237
  }
2526
- const partIndex = partIndexByItemKey.get(itemKey);
2527
- if (partIndex !== undefined && plan.parts[partIndex].submissionMode === "simultaneous") {
2528
- if (attemptsOf(state, itemKey) > 0) {
2529
- return state;
2530
- }
2531
- return {
2532
- ...state,
2533
- pendingItemResults: { ...state.pendingItemResults ?? {}, [itemKey]: result },
2534
- attemptedItems: state.attemptedItems.includes(itemKey) ? state.attemptedItems : [...state.attemptedItems, itemKey]
2535
- };
4238
+ const touched = touch(state);
4239
+ const barring = enclosingScopes(item).find((scope) => scopeExpired(touched, scope) && timeLimitsOf(scope)?.allowLateSubmission !== true);
4240
+ if (barring) {
4241
+ return applyExpiries({
4242
+ ...touched,
4243
+ rejectedSubmissions: [
4244
+ ...touched.rejectedSubmissions ?? [],
4245
+ { itemKey, scope: barring, atTestSeconds: touched.timing?.testSeconds ?? 0 }
4246
+ ]
4247
+ });
2536
4248
  }
2537
- if (result.adaptive !== true && remainingAttempts(state, itemKey) <= 0) {
4249
+ const accepted = submitBody(touched, itemKey, result);
4250
+ return accepted === touched ? state : applyExpiries(accepted);
4251
+ },
4252
+ end: (state) => state.status === "ended" ? state : ended(touch(state)),
4253
+ tick: (state) => state.status !== "in-progress" ? state : applyExpiries(touch(state)),
4254
+ suspend: (state) => {
4255
+ if (state.status !== "in-progress") {
2538
4256
  return state;
2539
4257
  }
2540
- const next = {
2541
- ...applyResultFlags(state, itemKey, result),
2542
- itemOutcomes: { ...state.itemOutcomes, [itemKey]: result.outcomes },
2543
- attemptedItems: state.attemptedItems.includes(itemKey) ? state.attemptedItems : [...state.attemptedItems, itemKey],
2544
- attemptCounts: { ...state.attemptCounts ?? {}, [itemKey]: attemptsOf(state, itemKey) + 1 }
2545
- };
2546
- return { ...next, testOutcomes: runOutcomeProcessing(next) };
4258
+ const settled = applyExpiries(touch(state));
4259
+ return settled.status === "in-progress" ? { ...settled, status: "suspended" } : settled;
4260
+ },
4261
+ resume: (state) => state.status !== "suspended" ? state : {
4262
+ ...state,
4263
+ status: "in-progress",
4264
+ ...state.timing ? { timing: { ...state.timing, lastTransitionAtMs: now() } } : {}
2547
4265
  },
2548
- end: (state) => state.status === "ended" ? state : ended(state),
4266
+ canReview: reviewable,
4267
+ review: (state, itemKey) => reviewable(state, itemKey) ? { ...state, currentItemKey: itemKey } : state,
4268
+ canComment: commentable,
4269
+ setItemComment: (state, itemKey, comment) => commentable(state, itemKey) ? { ...state, itemComments: { ...state.itemComments ?? {}, [itemKey]: comment } } : state,
2549
4270
  visibleTestFeedbacks: (state) => (view.testFeedbacks ?? []).filter((feedback) => {
2550
4271
  const accessOk = (feedback.access ?? "atEnd") === (state.status === "ended" ? "atEnd" : "during");
2551
4272
  if (!accessOk) {
@@ -2557,6 +4278,187 @@ function createTestController(view, options) {
2557
4278
  })
2558
4279
  };
2559
4280
  }
4281
+ // src/test/results.ts
4282
+ function iso(ms) {
4283
+ return new Date(ms).toISOString();
4284
+ }
4285
+ function pnpSupports(pnp) {
4286
+ if (!pnp) {
4287
+ return [];
4288
+ }
4289
+ const activation = resolvePnpActivation(pnp);
4290
+ const names = [...new Set([...activation.active, ...activation.optional, ...activation.prohibited])].sort();
4291
+ return names.map((name) => {
4292
+ if (activation.prohibited.has(name)) {
4293
+ return { name, assignment: "prohibited" };
4294
+ }
4295
+ const preference = pnpFeaturePreference(pnp, name);
4296
+ const xmlLang = typeof preference?.["xmlLang"] === "string" ? preference["xmlLang"] : undefined;
4297
+ let value;
4298
+ if (name === "additional-testing-time") {
4299
+ const time = pnp.additionalTestingTime;
4300
+ value = time?.unlimited === true ? "unlimited" : time?.timeMultiplier !== undefined ? String(time.timeMultiplier) : time?.fixedMinutes !== undefined ? String(time.fixedMinutes) : undefined;
4301
+ }
4302
+ return {
4303
+ name,
4304
+ assignment: "assigned",
4305
+ ...value !== undefined ? { value } : {},
4306
+ ...xmlLang !== undefined ? { xmlLang } : {}
4307
+ };
4308
+ });
4309
+ }
4310
+ function valueViews(value) {
4311
+ if (value === null || value === undefined || value === "") {
4312
+ return [];
4313
+ }
4314
+ if (Array.isArray(value)) {
4315
+ return value.filter((member) => member !== null && member !== "").map((member) => ({ value: String(member) }));
4316
+ }
4317
+ if (typeof value === "object") {
4318
+ return Object.entries(value).filter(([, member]) => member !== null && member !== "").map(([fieldIdentifier, member]) => ({ fieldIdentifier, value: String(member) }));
4319
+ }
4320
+ return [{ value: String(value) }];
4321
+ }
4322
+ function inferBaseType2(value, identifier) {
4323
+ const sample = Array.isArray(value) ? value[0] : value;
4324
+ if (typeof sample === "number") {
4325
+ return "float";
4326
+ }
4327
+ if (typeof sample === "boolean") {
4328
+ return "boolean";
4329
+ }
4330
+ if (identifier === "completionStatus" || identifier === "completion_status") {
4331
+ return "identifier";
4332
+ }
4333
+ return typeof sample === "string" ? "string" : undefined;
4334
+ }
4335
+ function outcomeVariablesOf(outcomes, declarations) {
4336
+ return Object.entries(outcomes).map(([identifier, value]) => {
4337
+ const declaration = declarations?.find((entry) => entry.identifier === identifier);
4338
+ const cardinality = declaration?.cardinality ?? (Array.isArray(value) ? "multiple" : "single");
4339
+ const baseType = declaration?.baseType ?? inferBaseType2(value, identifier);
4340
+ return {
4341
+ identifier,
4342
+ cardinality,
4343
+ ...baseType !== undefined && cardinality !== "record" ? { baseType } : {},
4344
+ values: valueViews(value)
4345
+ };
4346
+ });
4347
+ }
4348
+ function durationVariable(identifier, seconds) {
4349
+ return {
4350
+ identifier,
4351
+ cardinality: "single",
4352
+ baseType: "duration",
4353
+ candidateResponse: { values: [{ value: String(seconds) }] }
4354
+ };
4355
+ }
4356
+ function numAttemptsVariable(count) {
4357
+ return {
4358
+ identifier: "numAttempts",
4359
+ cardinality: "single",
4360
+ baseType: "integer",
4361
+ candidateResponse: { values: [{ value: String(count) }] }
4362
+ };
4363
+ }
4364
+ function responseVariablesOf(responses, details) {
4365
+ return Object.entries(responses ?? {}).map(([identifier, value]) => {
4366
+ const declaration = details?.responseDeclarations?.find((entry) => entry.identifier === identifier);
4367
+ const cardinality = declaration?.cardinality ?? (Array.isArray(value) ? "multiple" : "single");
4368
+ const baseType = declaration?.baseType;
4369
+ const correct = details?.correctResponses?.[identifier];
4370
+ const correctValues = correct === undefined ? [] : valueViews(correct);
4371
+ return {
4372
+ identifier,
4373
+ cardinality,
4374
+ ...baseType !== undefined && cardinality !== "record" ? { baseType } : {},
4375
+ candidateResponse: { values: valueViews(value) },
4376
+ ...correctValues.length > 0 ? { correctResponse: { values: correctValues } } : {}
4377
+ };
4378
+ });
4379
+ }
4380
+ function buildAssessmentResult(input) {
4381
+ const { test, plan, state } = input;
4382
+ const nowMs = input.nowMs ?? Date.now();
4383
+ const timing = state.timing;
4384
+ const scopeDurations = timing ? [
4385
+ durationVariable("duration", timing.testSeconds),
4386
+ ...plan.parts.filter((part) => timing.partSeconds[part.identifier] !== undefined).map((part) => durationVariable(`${part.identifier}.duration`, timing.partSeconds[part.identifier])),
4387
+ ...Object.keys(plan.sections).filter((identifier) => timing.sectionSeconds[identifier] !== undefined).map((identifier) => durationVariable(`${identifier}.duration`, timing.sectionSeconds[identifier]))
4388
+ ] : [];
4389
+ const testOutcomes = outcomeVariablesOf(state.testOutcomes, test.outcomeDeclarations);
4390
+ const supports = pnpSupports(input.pnp);
4391
+ const testResult = {
4392
+ identifier: test.identifier,
4393
+ datestamp: iso(nowMs),
4394
+ ...scopeDurations.length > 0 ? { responseVariables: scopeDurations } : {},
4395
+ ...testOutcomes.length > 0 ? { outcomeVariables: testOutcomes } : {},
4396
+ ...supports.length > 0 ? { supports } : {}
4397
+ };
4398
+ const itemResults = [];
4399
+ let sequenceIndex = 0;
4400
+ for (const part of plan.parts) {
4401
+ for (const item of part.items) {
4402
+ sequenceIndex += 1;
4403
+ const details = input.itemDetails?.(item) ?? null;
4404
+ const entries = [];
4405
+ (state.attemptHistory?.[item.key] ?? []).forEach((attempt, index) => {
4406
+ const outcomeVariables = outcomeVariablesOf(attempt.outcomes, details?.outcomeDeclarations);
4407
+ entries.push({
4408
+ identifier: item.key,
4409
+ sequenceIndex,
4410
+ datestamp: iso(attempt.atMs),
4411
+ sessionStatus: "final",
4412
+ responseVariables: [
4413
+ numAttemptsVariable(index + 1),
4414
+ ...attempt.durationSeconds !== undefined ? [durationVariable("duration", attempt.durationSeconds)] : [],
4415
+ ...responseVariablesOf(attempt.responses, details)
4416
+ ],
4417
+ ...outcomeVariables.length > 0 ? { outcomeVariables } : {}
4418
+ });
4419
+ });
4420
+ const pending = state.pendingItemResults?.[item.key];
4421
+ if (pending) {
4422
+ entries.push({
4423
+ identifier: item.key,
4424
+ sequenceIndex,
4425
+ datestamp: iso(pending.submittedAtMs ?? nowMs),
4426
+ sessionStatus: "pendingResponseProcessing",
4427
+ responseVariables: [
4428
+ numAttemptsVariable(1),
4429
+ ...pending.durationSeconds !== undefined ? [durationVariable("duration", pending.durationSeconds)] : [],
4430
+ ...responseVariablesOf(pending.responses, details)
4431
+ ]
4432
+ });
4433
+ }
4434
+ if (entries.length === 0) {
4435
+ const itemSeconds = timing?.itemSeconds[item.key];
4436
+ entries.push({
4437
+ identifier: item.key,
4438
+ sequenceIndex,
4439
+ datestamp: iso(nowMs),
4440
+ sessionStatus: "initial",
4441
+ responseVariables: [
4442
+ numAttemptsVariable(0),
4443
+ ...itemSeconds !== undefined ? [durationVariable("duration", itemSeconds)] : []
4444
+ ]
4445
+ });
4446
+ }
4447
+ const comment = state.itemComments?.[item.key];
4448
+ if (comment !== undefined) {
4449
+ entries[entries.length - 1] = { ...entries[entries.length - 1], candidateComment: comment };
4450
+ }
4451
+ itemResults.push(...entries);
4452
+ }
4453
+ }
4454
+ return {
4455
+ assessmentResult: {
4456
+ context: input.context ?? {},
4457
+ testResult,
4458
+ ...itemResults.length > 0 ? { itemResults } : {}
4459
+ }
4460
+ };
4461
+ }
2560
4462
  // src/test/session-store.ts
2561
4463
  function collectCorrectResponseTargets(rules, into) {
2562
4464
  for (const rule of rules ?? []) {
@@ -2623,9 +4525,22 @@ function createTestSessionStore(controller, options) {
2623
4525
  visibleFeedbacks: controller.visibleTestFeedbacks(state)
2624
4526
  };
2625
4527
  }
4528
+ function activeKeyOf(sessionState) {
4529
+ return sessionState.status === "in-progress" ? sessionState.currentItemKey : null;
4530
+ }
2626
4531
  function emit(next) {
4532
+ const previousActive = activeKeyOf(state);
2627
4533
  state = next;
2628
4534
  snapshot = buildSnapshot();
4535
+ const nextActive = activeKeyOf(next);
4536
+ if (previousActive !== nextActive) {
4537
+ if (previousActive !== null) {
4538
+ itemStores.get(previousActive)?.suspend();
4539
+ }
4540
+ if (nextActive !== null) {
4541
+ itemStores.get(nextActive)?.resume();
4542
+ }
4543
+ }
2629
4544
  for (const listener of listeners) {
2630
4545
  listener();
2631
4546
  }
@@ -2642,11 +4557,15 @@ function createTestSessionStore(controller, options) {
2642
4557
  return itemStores.get(itemKey) ?? null;
2643
4558
  }
2644
4559
  const view = itemView(itemKey);
2645
- if (!view) {
4560
+ const planItem = planItemsByKey.get(itemKey);
4561
+ if (!view || !planItem) {
2646
4562
  itemStores.set(itemKey, null);
2647
4563
  return null;
2648
4564
  }
4565
+ const individual = controller.plan.parts.some((part) => part.identifier === planItem.partIdentifier && part.submissionMode === "individual");
2649
4566
  const store = createAttemptStore(view.responseDeclarations, {}, {
4567
+ constraints: collectInteractionConstraints(view.itemBody.content),
4568
+ validateResponses: planItem.sessionControl.validateResponses && individual,
2650
4569
  outcomeDeclarations: view.outcomeDeclarations,
2651
4570
  responseProcessing: view.responseProcessing,
2652
4571
  templateDeclarations: view.templateDeclarations,
@@ -2654,8 +4573,13 @@ function createTestSessionStore(controller, options) {
2654
4573
  adaptive: view.adaptive,
2655
4574
  seed: deriveItemSeed(options.seed, itemKey),
2656
4575
  normalization: options.normalization,
2657
- customOperators: options.customOperators
4576
+ customOperators: options.customOperators,
4577
+ templateDefaultValues: state.templateDefaultValues?.[itemKey],
4578
+ now: options.now
2658
4579
  });
4580
+ if (activeKeyOf(state) !== itemKey) {
4581
+ store.suspend();
4582
+ }
2659
4583
  const scorable = scorableIdentifiers(view);
2660
4584
  store.subscribe(() => {
2661
4585
  const attempt = store.getSnapshot();
@@ -2664,7 +4588,10 @@ function createTestSessionStore(controller, options) {
2664
4588
  const next = controller.submitItem(state, itemKey, {
2665
4589
  outcomes: attempt.outcomes,
2666
4590
  ...resultFlags(attempt, scorable),
2667
- ...view.adaptive === true ? { adaptive: true } : {}
4591
+ ...view.adaptive === true ? { adaptive: true } : {},
4592
+ ...attempt.durationSeconds !== null ? { durationSeconds: attempt.durationSeconds } : {},
4593
+ valid: attempt.responseViolations.length === 0,
4594
+ responses: attempt.responses
2668
4595
  });
2669
4596
  if (next !== state) {
2670
4597
  emit(next);
@@ -2686,7 +4613,31 @@ function createTestSessionStore(controller, options) {
2686
4613
  next: () => emit(controller.next(state)),
2687
4614
  canMoveTo: (itemKey) => controller.canMoveTo(state, itemKey),
2688
4615
  moveTo: (itemKey) => emit(controller.moveTo(state, itemKey)),
2689
- end: () => emit(controller.end(state))
4616
+ end: () => emit(controller.end(state)),
4617
+ tick: () => emit(controller.tick(state)),
4618
+ review: (itemKey) => emit(controller.review(state, itemKey)),
4619
+ setItemComment: (itemKey, comment) => emit(controller.setItemComment(state, itemKey, comment)),
4620
+ suspend: () => emit(controller.suspend(state)),
4621
+ resume: () => emit(controller.resume(state)),
4622
+ assessmentResult: (resultOptions) => buildAssessmentResult({
4623
+ test: controller.test,
4624
+ plan: controller.plan,
4625
+ state,
4626
+ ...resultOptions?.context !== undefined ? { context: resultOptions.context } : {},
4627
+ nowMs: resultOptions?.nowMs ?? (options.now ?? Date.now)(),
4628
+ ...options.pnp !== undefined ? { pnp: options.pnp } : {},
4629
+ itemDetails: (item) => {
4630
+ const view = itemView(item.key);
4631
+ if (!view) {
4632
+ return null;
4633
+ }
4634
+ return {
4635
+ responseDeclarations: view.responseDeclarations,
4636
+ ...view.outcomeDeclarations !== undefined ? { outcomeDeclarations: view.outcomeDeclarations } : {},
4637
+ correctResponses: itemStore(item.key)?.getSnapshot().correctResponses ?? {}
4638
+ };
4639
+ }
4640
+ })
2690
4641
  };
2691
4642
  }
2692
4643
  // src/runtime.ts
@@ -2741,7 +4692,10 @@ function createStaticStore(outcomes) {
2741
4692
  scores: [],
2742
4693
  outcomes,
2743
4694
  templateValues: {},
2744
- attemptCount: 1
4695
+ attemptCount: 1,
4696
+ durationSeconds: null,
4697
+ responseViolations: [],
4698
+ correctResponses: {}
2745
4699
  };
2746
4700
  return {
2747
4701
  getSnapshot: () => snapshot,
@@ -2749,7 +4703,9 @@ function createStaticStore(outcomes) {
2749
4703
  setResponse: () => {},
2750
4704
  registerResponseCollector: () => () => {},
2751
4705
  submit: () => [],
2752
- reset: () => {}
4706
+ reset: () => {},
4707
+ suspend: () => {},
4708
+ resume: () => {}
2753
4709
  };
2754
4710
  }
2755
4711
  function feedbackVisible(outcome, feedback, submitted) {
@@ -2763,7 +4719,11 @@ function createQtiRuntime(config) {
2763
4719
  const model = config.contentModel ?? v0ContentModel;
2764
4720
  const descriptorsByKind = new Map(config.interactions.map((descriptor) => [descriptor.kind, descriptor]));
2765
4721
  const resolveAsset = config.assetResolver ?? ((href) => href);
4722
+ const ssmlNamespace = "http://www.w3.org/2001/10/synthesis";
2766
4723
  function renderFlow(node, key, overrides, inMath = false) {
4724
+ if (node.namespace === ssmlNamespace) {
4725
+ return createElement(Fragment, { key }, node.value ?? node.children?.map((child, index) => renderNode(child, index, overrides, inMath)));
4726
+ }
2767
4727
  const isMath = inMath || node.name === model.mathRoot;
2768
4728
  if (!isMath && !isAllowedFlowElement(model, node.name)) {
2769
4729
  return null;
@@ -2784,7 +4744,40 @@ function createQtiRuntime(config) {
2784
4744
  }
2785
4745
  return createElement("div", { key, role: "note", "data-qti-unsupported": node.kind }, `This content requires an interaction type (${node.kind}) this runtime does not support.`);
2786
4746
  }
2787
- function renderNode(node, key, overrides, inMath = false) {
4747
+ function catalogIdrefOf(node) {
4748
+ const value = node.kind === "xml" ? node.attributes?.["data-catalog-idref"] : node.dataCatalogIdref;
4749
+ return typeof value === "string" && value !== "" ? value : undefined;
4750
+ }
4751
+ function renderSupportDefault(support, catalogIdref, key, overrides) {
4752
+ return createElement("span", {
4753
+ key: `support-${key}`,
4754
+ role: "note",
4755
+ "data-qti-catalog-idref": catalogIdref,
4756
+ "data-qti-support": support.support,
4757
+ ...support.xmlLang !== undefined ? { lang: support.xmlLang } : {}
4758
+ }, support.content?.map((child, index) => renderNode(child, index, overrides)), support.fileHrefs?.map((file, index) => createElement("a", { key: `file-${index}`, href: resolveAsset(file.href), type: file.mimeType, "data-qti-support-file": true }, support.support)));
4759
+ }
4760
+ function CatalogSupportHost({
4761
+ catalogIdref,
4762
+ node,
4763
+ overrides,
4764
+ inMath
4765
+ }) {
4766
+ const { catalogSupports } = useRuntimeContext();
4767
+ const supports = catalogSupports.get(catalogIdref) ?? [];
4768
+ const original = renderNode(node, 0, overrides, inMath, true);
4769
+ if (!supports.length) {
4770
+ return original;
4771
+ }
4772
+ return createElement(Fragment, null, original, supports.map((support, index) => config.renderCatalogSupport ? createElement(Fragment, { key: `support-${index}` }, config.renderCatalogSupport(support, catalogIdref)) : renderSupportDefault(support, catalogIdref, index, overrides)));
4773
+ }
4774
+ function renderNode(node, key, overrides, inMath = false, skipCatalog = false) {
4775
+ if (!skipCatalog) {
4776
+ const catalogIdref = catalogIdrefOf(node);
4777
+ if (catalogIdref !== undefined) {
4778
+ return createElement(CatalogSupportHost, { key, catalogIdref, node, overrides, inMath });
4779
+ }
4780
+ }
2788
4781
  const override = overrides?.[node.kind];
2789
4782
  if (override) {
2790
4783
  return createElement(Fragment, { key }, override(node, key));
@@ -2836,10 +4829,10 @@ function createQtiRuntime(config) {
2836
4829
  element,
2837
4830
  overrides
2838
4831
  }) {
2839
- const { store } = useRuntimeContext();
4832
+ const { store, suppressFeedback, defaultOutcomes: defaultOutcomes2 } = useRuntimeContext();
2840
4833
  const snapshot = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
2841
- const outcome = snapshot.outcomes[feedback.outcomeIdentifier] ?? null;
2842
- if (!feedbackVisible(outcome, feedback, snapshot.submitted)) {
4834
+ const outcome = suppressFeedback ? defaultOutcomes2[feedback.outcomeIdentifier] ?? null : snapshot.outcomes[feedback.outcomeIdentifier] ?? null;
4835
+ if (!feedbackVisible(outcome, feedback, suppressFeedback || snapshot.submitted)) {
2843
4836
  return null;
2844
4837
  }
2845
4838
  return createElement(element, { "data-qti-feedback": feedback.identifier }, feedback.content?.map((child, index) => renderNode(child, index, overrides)));
@@ -2865,35 +4858,39 @@ function createQtiRuntime(config) {
2865
4858
  return createElement("span", { "data-qti-printed-variable": identifier }, text);
2866
4859
  }
2867
4860
  function ModalFeedbackHost({ feedback }) {
2868
- const { store } = useRuntimeContext();
4861
+ const { store, suppressFeedback } = useRuntimeContext();
2869
4862
  const snapshot = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
2870
4863
  const outcome = snapshot.outcomes[feedback.outcomeIdentifier] ?? null;
2871
- if (!feedbackVisible(outcome, feedback, snapshot.submitted)) {
4864
+ if (suppressFeedback || !feedbackVisible(outcome, feedback, snapshot.submitted)) {
2872
4865
  return null;
2873
4866
  }
2874
4867
  return createElement("div", { role: "status", "data-qti-modal-feedback": feedback.identifier }, feedback.content?.map((child, index) => renderNode(child, index)));
2875
4868
  }
2876
4869
  function InteractionHost({ node }) {
2877
- const { store, declarationsById } = useRuntimeContext();
4870
+ const { store, declarationsById, mode, suppressFeedback, solutionResponses } = useRuntimeContext();
2878
4871
  const snapshot = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
2879
4872
  const responseIdentifier = node.responseIdentifier;
2880
4873
  const declaration = declarationsById.get(responseIdentifier);
2881
4874
  const cardinality = declaration?.cardinality ?? "single";
2882
- const value = snapshot.responses[responseIdentifier] ?? null;
2883
- const disabled = snapshot.submitted;
4875
+ const value = mode === "solution" ? solutionResponses[responseIdentifier] ?? null : snapshot.responses[responseIdentifier] ?? null;
4876
+ const disabled = snapshot.submitted || mode !== "interact";
4877
+ const revealed = mode === "solution" || snapshot.submitted && !suppressFeedback;
2884
4878
  const answered = value !== null && !(typeof value === "string" && value.trim() === "") && !(Array.isArray(value) && value.length === 0);
2885
4879
  let status = answered ? "answered" : "unanswered";
2886
- if (disabled) {
4880
+ if (revealed) {
2887
4881
  const scored = snapshot.scores.find((score) => score.identifier === responseIdentifier);
2888
- status = scored?.correct ? "correct" : "incorrect";
4882
+ status = mode === "solution" || scored?.correct ? "correct" : "incorrect";
2889
4883
  }
2890
4884
  const setValue = (next) => {
4885
+ if (disabled) {
4886
+ return;
4887
+ }
2891
4888
  store.setResponse(responseIdentifier, next);
2892
4889
  };
2893
4890
  const getOptionProps = (optionIdentifier) => {
2894
4891
  const selected = responseIncludes(value, optionIdentifier);
2895
4892
  let status2 = selected ? "selected" : "idle";
2896
- if (disabled) {
4893
+ if (revealed) {
2897
4894
  if (isCorrectOption(declaration, optionIdentifier)) {
2898
4895
  status2 = "correct";
2899
4896
  } else if (selected) {
@@ -2923,6 +4920,14 @@ function createQtiRuntime(config) {
2923
4920
  };
2924
4921
  };
2925
4922
  const renderContent = (nodes, overrides) => nodes ? nodes.map((child, index) => renderNode(child, index, overrides)) : null;
4923
+ const { catalogSupports } = useRuntimeContext();
4924
+ const renderCatalogSupportsForSkin = (catalogIdref) => {
4925
+ const supports = catalogIdref !== undefined ? catalogSupports.get(catalogIdref) ?? [] : [];
4926
+ if (!supports.length) {
4927
+ return null;
4928
+ }
4929
+ return supports.map((support, index) => config.renderCatalogSupport ? createElement(Fragment, { key: `support-${index}` }, config.renderCatalogSupport(support, catalogIdref)) : renderSupportDefault(support, catalogIdref, index));
4930
+ };
2926
4931
  const Skin = config.skin[node.kind];
2927
4932
  if (!Skin) {
2928
4933
  return null;
@@ -2932,8 +4937,9 @@ function createQtiRuntime(config) {
2932
4937
  responseIdentifier,
2933
4938
  value,
2934
4939
  setValue,
4940
+ renderCatalogSupports: renderCatalogSupportsForSkin,
2935
4941
  disabled,
2936
- showFeedback: disabled,
4942
+ showFeedback: revealed,
2937
4943
  status,
2938
4944
  getOptionProps,
2939
4945
  renderContent,
@@ -2945,12 +4951,32 @@ function createQtiRuntime(config) {
2945
4951
  registerResponseCollector: (collector) => store.registerResponseCollector(responseIdentifier, collector)
2946
4952
  });
2947
4953
  }
2948
- function ContentRenderer({ nodes, outcomes }) {
4954
+ function ContentRenderer({ nodes, outcomes, catalogs, pnp, activeSupports }) {
2949
4955
  const store = useMemo(() => createStaticStore(outcomes ?? {}), [outcomes]);
2950
4956
  const declarationsById = useMemo(() => new Map, []);
2951
- return createElement(RuntimeContext.Provider, { value: { store, declarationsById } }, nodes?.map((node, index) => renderNode(node, index)));
2952
- }
2953
- function ItemRenderer({ item, store: externalStore, seed, children }) {
4957
+ const catalogSupports = useMemo(() => resolveCatalogSupports({ catalogs, pnp, activeSupports }).byCatalogId, [catalogs, pnp, activeSupports]);
4958
+ return createElement(RuntimeContext.Provider, {
4959
+ value: {
4960
+ store,
4961
+ declarationsById,
4962
+ mode: "interact",
4963
+ suppressFeedback: false,
4964
+ solutionResponses: {},
4965
+ defaultOutcomes: {},
4966
+ catalogSupports
4967
+ }
4968
+ }, nodes?.map((node, index) => renderNode(node, index)));
4969
+ }
4970
+ function ItemRenderer({
4971
+ item,
4972
+ store: externalStore,
4973
+ seed,
4974
+ mode = "interact",
4975
+ showFeedback,
4976
+ pnp,
4977
+ activeSupports,
4978
+ children
4979
+ }) {
2954
4980
  const store = useMemo(() => externalStore ?? createAttemptStore(item.responseDeclarations, {}, {
2955
4981
  outcomeDeclarations: item.outcomeDeclarations,
2956
4982
  responseProcessing: item.responseProcessing,
@@ -2959,12 +4985,44 @@ function createQtiRuntime(config) {
2959
4985
  adaptive: item.adaptive,
2960
4986
  seed,
2961
4987
  normalization: config.normalization,
2962
- customOperators: config.customOperators
4988
+ customOperators: config.customOperators,
4989
+ constraints: collectInteractionConstraints(item.itemBody.content)
2963
4990
  }), [item, externalStore, seed]);
2964
4991
  const declarationsById = useMemo(() => new Map(item.responseDeclarations.map((declaration) => [declaration.identifier, declaration])), [item]);
4992
+ const suppressFeedback = mode !== "interact" && showFeedback === false && item.adaptive !== true;
4993
+ const defaultOutcomes2 = useMemo(() => {
4994
+ const defaults = {};
4995
+ for (const declaration of item.outcomeDeclarations ?? []) {
4996
+ const values = declaration.defaultValue?.values;
4997
+ if (values !== undefined) {
4998
+ defaults[declaration.identifier] = declaration.cardinality === "single" ? values[0]?.value ?? null : values.map((entry) => entry.value);
4999
+ }
5000
+ }
5001
+ return defaults;
5002
+ }, [item]);
5003
+ const stimulusViews = (item.assessmentStimulusRefs ?? []).map((ref) => ({
5004
+ ref,
5005
+ view: config.resolveStimulus?.(ref) ?? null
5006
+ }));
5007
+ const catalogSupports = resolveCatalogSupports({
5008
+ catalogs: [...item.catalogs ?? [], ...stimulusViews.flatMap(({ view }) => view?.catalogs ?? [])],
5009
+ pnp,
5010
+ activeSupports
5011
+ }).byCatalogId;
5012
+ const stimuli = stimulusViews.map(({ ref, view }, index) => createElement("section", { key: `stimulus-${index}`, "data-qti-stimulus": ref.identifier }, view === null ? createElement("div", { role: "note", "data-qti-unsupported": "assessmentStimulusRef" }, `This content requires a shared stimulus (${ref.href}) this runtime cannot resolve.`) : view.content.map((node, nodeIndex) => renderNode(node, nodeIndex))));
2965
5013
  const body = (item.itemBody.content ?? []).map((node, index) => renderNode(node, index));
2966
5014
  const modals = (item.modalFeedbacks ?? []).map((feedback, index) => createElement(ModalFeedbackHost, { key: index, feedback }));
2967
- return createElement(RuntimeContext.Provider, { value: { store, declarationsById } }, body, modals, children);
5015
+ return createElement(RuntimeContext.Provider, {
5016
+ value: {
5017
+ store,
5018
+ declarationsById,
5019
+ mode,
5020
+ suppressFeedback,
5021
+ solutionResponses: store.getSnapshot().correctResponses,
5022
+ defaultOutcomes: defaultOutcomes2,
5023
+ catalogSupports
5024
+ }
5025
+ }, stimuli, body, modals, children);
2968
5026
  }
2969
5027
  function useAttempt() {
2970
5028
  const { store } = useRuntimeContext();
@@ -2975,6 +5033,11 @@ function createQtiRuntime(config) {
2975
5033
  reset: store.reset
2976
5034
  };
2977
5035
  }
5036
+ const noSupports = [];
5037
+ function useCatalogSupports(catalogIdref) {
5038
+ const { catalogSupports } = useRuntimeContext();
5039
+ return catalogIdref !== undefined ? catalogSupports.get(catalogIdref) ?? noSupports : noSupports;
5040
+ }
2978
5041
  function canDeliver(item) {
2979
5042
  const issues = [];
2980
5043
  const seen = new Set;
@@ -3035,13 +5098,26 @@ function createQtiRuntime(config) {
3035
5098
  for (const node of item.itemBody.content ?? []) {
3036
5099
  walk(node);
3037
5100
  }
5101
+ for (const ref of item.assessmentStimulusRefs ?? []) {
5102
+ const stimulus = config.resolveStimulus?.(ref) ?? null;
5103
+ if (stimulus === null) {
5104
+ report({ type: "unsupported-element", name: "assessmentStimulusRef", detail: ref.href });
5105
+ continue;
5106
+ }
5107
+ for (const node of stimulus.content) {
5108
+ walk(node);
5109
+ }
5110
+ }
3038
5111
  for (const feedback of item.modalFeedbacks ?? []) {
3039
5112
  for (const child of feedback.content ?? []) {
3040
5113
  walk(child);
3041
5114
  }
3042
5115
  }
3043
5116
  const customOperatorClasses = new Set(Object.keys(config.customOperators ?? {}));
3044
- for (const issue of collectRpIssues(item.responseProcessing, { customOperatorClasses })) {
5117
+ for (const issue of collectRpIssues(item.responseProcessing, {
5118
+ customOperatorClasses,
5119
+ outcomeDeclarations: item.outcomeDeclarations ?? []
5120
+ })) {
3045
5121
  report(issue);
3046
5122
  }
3047
5123
  for (const issue of collectTemplateIssues(item.templateProcessing, { customOperatorClasses })) {
@@ -3049,7 +5125,7 @@ function createQtiRuntime(config) {
3049
5125
  }
3050
5126
  return { deliverable: issues.length === 0, issues };
3051
5127
  }
3052
- return { ItemRenderer, ContentRenderer, useAttempt, canDeliver };
5128
+ return { ItemRenderer, ContentRenderer, useAttempt, useCatalogSupports, canDeliver };
3053
5129
  }
3054
5130
  // src/pci/response.ts
3055
5131
  function scalarToString(value) {
@@ -3389,23 +5465,23 @@ async function mountPci(options) {
3389
5465
  };
3390
5466
  }
3391
5467
  // src/pci/interaction.ts
3392
- import { z } from "zod";
3393
- var interactionModuleSchema = z.object({
3394
- id: z.string().min(1),
3395
- primaryPath: z.string().optional(),
3396
- fallbackPath: z.string().optional()
5468
+ import { z as z2 } from "zod";
5469
+ var interactionModuleSchema = z2.object({
5470
+ id: z2.string().min(1),
5471
+ primaryPath: z2.string().optional(),
5472
+ fallbackPath: z2.string().optional()
3397
5473
  });
3398
- var pciNodeSchema = z.object({
3399
- kind: z.literal("portableCustomInteraction"),
3400
- responseIdentifier: z.string().min(1),
3401
- customInteractionTypeIdentifier: z.string().min(1),
3402
- module: z.string().optional(),
3403
- properties: z.record(z.string(), z.string()).optional(),
3404
- interactionMarkup: z.object({ content: z.array(z.unknown()).optional() }).optional(),
3405
- interactionModules: z.object({
3406
- primaryConfiguration: z.string().optional(),
3407
- secondaryConfiguration: z.string().optional(),
3408
- modules: z.array(interactionModuleSchema).optional()
5474
+ var pciNodeSchema = z2.object({
5475
+ kind: z2.literal("portableCustomInteraction"),
5476
+ responseIdentifier: z2.string().min(1),
5477
+ customInteractionTypeIdentifier: z2.string().min(1),
5478
+ module: z2.string().optional(),
5479
+ properties: z2.record(z2.string(), z2.string()).optional(),
5480
+ interactionMarkup: z2.object({ content: z2.array(z2.unknown()).optional() }).optional(),
5481
+ interactionModules: z2.object({
5482
+ primaryConfiguration: z2.string().optional(),
5483
+ secondaryConfiguration: z2.string().optional(),
5484
+ modules: z2.array(interactionModuleSchema).optional()
3409
5485
  }).optional()
3410
5486
  });
3411
5487
  var portableCustomInteraction = defineInteraction({
@@ -3465,12 +5541,12 @@ function createPciSkin(options) {
3465
5541
  };
3466
5542
  }
3467
5543
  // src/interactions/associate.ts
3468
- import { z as z2 } from "zod";
3469
- var associateInteractionNodeSchema = z2.object({
3470
- kind: z2.literal("associateInteraction"),
3471
- responseIdentifier: z2.string().min(1),
3472
- simpleAssociableChoices: z2.array(z2.looseObject({ identifier: z2.string().min(1), matchMax: z2.number().int().optional() })).min(2),
3473
- maxAssociations: z2.number().int().optional()
5544
+ import { z as z3 } from "zod";
5545
+ var associateInteractionNodeSchema = z3.object({
5546
+ kind: z3.literal("associateInteraction"),
5547
+ responseIdentifier: z3.string().min(1),
5548
+ simpleAssociableChoices: z3.array(z3.looseObject({ identifier: z3.string().min(1), matchMax: z3.number().int().optional() })).min(2),
5549
+ maxAssociations: z3.number().int().optional()
3474
5550
  });
3475
5551
  var associateInteraction = defineInteraction({
3476
5552
  kind: "associateInteraction",
@@ -3482,12 +5558,12 @@ var associateInteraction = defineInteraction({
3482
5558
  });
3483
5559
 
3484
5560
  // src/interactions/choice.ts
3485
- import { z as z3 } from "zod";
3486
- var choiceInteractionNodeSchema = z3.object({
3487
- kind: z3.literal("choiceInteraction"),
3488
- responseIdentifier: z3.string().min(1),
3489
- simpleChoices: z3.array(z3.object({ identifier: z3.string().min(1) })).min(1),
3490
- maxChoices: z3.number().int().optional()
5561
+ import { z as z4 } from "zod";
5562
+ var choiceInteractionNodeSchema = z4.object({
5563
+ kind: z4.literal("choiceInteraction"),
5564
+ responseIdentifier: z4.string().min(1),
5565
+ simpleChoices: z4.array(z4.object({ identifier: z4.string().min(1) })).min(1),
5566
+ maxChoices: z4.number().int().optional()
3491
5567
  });
3492
5568
  var choiceInteraction = defineInteraction({
3493
5569
  kind: "choiceInteraction",
@@ -3499,15 +5575,15 @@ var choiceInteraction = defineInteraction({
3499
5575
  });
3500
5576
 
3501
5577
  // src/interactions/drawing.ts
3502
- import { z as z4 } from "zod";
3503
- var drawingInteractionNodeSchema = z4.object({
3504
- kind: z4.literal("drawingInteraction"),
3505
- responseIdentifier: z4.string().min(1),
3506
- object: z4.object({
3507
- data: z4.string().min(1),
3508
- width: z4.number().optional(),
3509
- height: z4.number().optional(),
3510
- type: z4.string().optional()
5578
+ import { z as z5 } from "zod";
5579
+ var drawingInteractionNodeSchema = z5.object({
5580
+ kind: z5.literal("drawingInteraction"),
5581
+ responseIdentifier: z5.string().min(1),
5582
+ object: z5.object({
5583
+ data: z5.string().min(1),
5584
+ width: z5.number().optional(),
5585
+ height: z5.number().optional(),
5586
+ type: z5.string().optional()
3511
5587
  })
3512
5588
  });
3513
5589
  var drawingInteraction = defineInteraction({
@@ -3520,11 +5596,11 @@ var drawingInteraction = defineInteraction({
3520
5596
  });
3521
5597
 
3522
5598
  // src/interactions/end-attempt.ts
3523
- import { z as z5 } from "zod";
3524
- var endAttemptInteractionNodeSchema = z5.object({
3525
- kind: z5.literal("endAttemptInteraction"),
3526
- responseIdentifier: z5.string().min(1),
3527
- title: z5.string().min(1)
5599
+ import { z as z6 } from "zod";
5600
+ var endAttemptInteractionNodeSchema = z6.object({
5601
+ kind: z6.literal("endAttemptInteraction"),
5602
+ responseIdentifier: z6.string().min(1),
5603
+ title: z6.string().min(1)
3528
5604
  });
3529
5605
  var endAttemptInteraction = defineInteraction({
3530
5606
  kind: "endAttemptInteraction",
@@ -3536,13 +5612,13 @@ var endAttemptInteraction = defineInteraction({
3536
5612
  });
3537
5613
 
3538
5614
  // src/interactions/extended-text.ts
3539
- import { z as z6 } from "zod";
3540
- var extendedTextInteractionNodeSchema = z6.object({
3541
- kind: z6.literal("extendedTextInteraction"),
3542
- responseIdentifier: z6.string().min(1),
3543
- expectedLength: z6.number().int().optional(),
3544
- expectedLines: z6.number().int().optional(),
3545
- placeholderText: z6.string().optional()
5615
+ import { z as z7 } from "zod";
5616
+ var extendedTextInteractionNodeSchema = z7.object({
5617
+ kind: z7.literal("extendedTextInteraction"),
5618
+ responseIdentifier: z7.string().min(1),
5619
+ expectedLength: z7.number().int().optional(),
5620
+ expectedLines: z7.number().int().optional(),
5621
+ placeholderText: z7.string().optional()
3546
5622
  });
3547
5623
  var extendedTextInteraction = defineInteraction({
3548
5624
  kind: "extendedTextInteraction",
@@ -3554,12 +5630,12 @@ var extendedTextInteraction = defineInteraction({
3554
5630
  });
3555
5631
 
3556
5632
  // src/interactions/gap-match.ts
3557
- import { z as z7 } from "zod";
3558
- var gapMatchInteractionNodeSchema = z7.object({
3559
- kind: z7.literal("gapMatchInteraction"),
3560
- responseIdentifier: z7.string().min(1),
3561
- gapTexts: z7.array(z7.looseObject({ identifier: z7.string().min(1), matchMax: z7.number().int().optional() })).min(1),
3562
- content: z7.array(z7.looseObject({ kind: z7.string().min(1) })).min(1)
5633
+ import { z as z8 } from "zod";
5634
+ var gapMatchInteractionNodeSchema = z8.object({
5635
+ kind: z8.literal("gapMatchInteraction"),
5636
+ responseIdentifier: z8.string().min(1),
5637
+ gapTexts: z8.array(z8.looseObject({ identifier: z8.string().min(1), matchMax: z8.number().int().optional() })).min(1),
5638
+ content: z8.array(z8.looseObject({ kind: z8.string().min(1) })).min(1)
3563
5639
  });
3564
5640
  var gapMatchInteraction = defineInteraction({
3565
5641
  kind: "gapMatchInteraction",
@@ -3571,99 +5647,99 @@ var gapMatchInteraction = defineInteraction({
3571
5647
  });
3572
5648
 
3573
5649
  // src/interactions/graphic.ts
3574
- import { z as z8 } from "zod";
3575
- var objectSchema = z8.object({
3576
- data: z8.string().min(1),
3577
- width: z8.number().optional(),
3578
- height: z8.number().optional(),
3579
- type: z8.string().optional()
5650
+ import { z as z9 } from "zod";
5651
+ var objectSchema = z9.object({
5652
+ data: z9.string().min(1),
5653
+ width: z9.number().optional(),
5654
+ height: z9.number().optional(),
5655
+ type: z9.string().optional()
3580
5656
  });
3581
- var hotspotSchema = z8.looseObject({
3582
- identifier: z8.string().min(1),
3583
- shape: z8.string().min(1),
3584
- coords: z8.array(z8.number())
5657
+ var hotspotSchema = z9.looseObject({
5658
+ identifier: z9.string().min(1),
5659
+ shape: z9.string().min(1),
5660
+ coords: z9.array(z9.number())
3585
5661
  });
3586
5662
  function nullInitial() {
3587
5663
  return null;
3588
5664
  }
3589
5665
  var hotspotInteraction = defineInteraction({
3590
5666
  kind: "hotspotInteraction",
3591
- schema: z8.object({
3592
- kind: z8.literal("hotspotInteraction"),
3593
- responseIdentifier: z8.string().min(1),
5667
+ schema: z9.object({
5668
+ kind: z9.literal("hotspotInteraction"),
5669
+ responseIdentifier: z9.string().min(1),
3594
5670
  object: objectSchema,
3595
- hotspotChoices: z8.array(hotspotSchema).min(1),
3596
- maxChoices: z8.number().int().optional()
5671
+ hotspotChoices: z9.array(hotspotSchema).min(1),
5672
+ maxChoices: z9.number().int().optional()
3597
5673
  }),
3598
5674
  scoring: "qti-standard",
3599
5675
  initialResponse: nullInitial
3600
5676
  });
3601
5677
  var graphicOrderInteraction = defineInteraction({
3602
5678
  kind: "graphicOrderInteraction",
3603
- schema: z8.object({
3604
- kind: z8.literal("graphicOrderInteraction"),
3605
- responseIdentifier: z8.string().min(1),
5679
+ schema: z9.object({
5680
+ kind: z9.literal("graphicOrderInteraction"),
5681
+ responseIdentifier: z9.string().min(1),
3606
5682
  object: objectSchema,
3607
- hotspotChoices: z8.array(hotspotSchema).min(1)
5683
+ hotspotChoices: z9.array(hotspotSchema).min(1)
3608
5684
  }),
3609
5685
  scoring: "qti-standard",
3610
5686
  initialResponse: nullInitial
3611
5687
  });
3612
5688
  var graphicAssociateInteraction = defineInteraction({
3613
5689
  kind: "graphicAssociateInteraction",
3614
- schema: z8.object({
3615
- kind: z8.literal("graphicAssociateInteraction"),
3616
- responseIdentifier: z8.string().min(1),
5690
+ schema: z9.object({
5691
+ kind: z9.literal("graphicAssociateInteraction"),
5692
+ responseIdentifier: z9.string().min(1),
3617
5693
  object: objectSchema,
3618
- associableHotspots: z8.array(hotspotSchema).min(2),
3619
- maxAssociations: z8.number().int().optional()
5694
+ associableHotspots: z9.array(hotspotSchema).min(2),
5695
+ maxAssociations: z9.number().int().optional()
3620
5696
  }),
3621
5697
  scoring: "qti-standard",
3622
5698
  initialResponse: nullInitial
3623
5699
  });
3624
5700
  var graphicGapMatchInteraction = defineInteraction({
3625
5701
  kind: "graphicGapMatchInteraction",
3626
- schema: z8.object({
3627
- kind: z8.literal("graphicGapMatchInteraction"),
3628
- responseIdentifier: z8.string().min(1),
5702
+ schema: z9.object({
5703
+ kind: z9.literal("graphicGapMatchInteraction"),
5704
+ responseIdentifier: z9.string().min(1),
3629
5705
  object: objectSchema,
3630
- gapImgs: z8.array(z8.looseObject({ identifier: z8.string().min(1), object: objectSchema.optional() })).min(1),
3631
- associableHotspots: z8.array(hotspotSchema).min(1)
5706
+ gapImgs: z9.array(z9.looseObject({ identifier: z9.string().min(1), object: objectSchema.optional() })).min(1),
5707
+ associableHotspots: z9.array(hotspotSchema).min(1)
3632
5708
  }),
3633
5709
  scoring: "qti-standard",
3634
5710
  initialResponse: nullInitial
3635
5711
  });
3636
5712
  var selectPointInteraction = defineInteraction({
3637
5713
  kind: "selectPointInteraction",
3638
- schema: z8.object({
3639
- kind: z8.literal("selectPointInteraction"),
3640
- responseIdentifier: z8.string().min(1),
5714
+ schema: z9.object({
5715
+ kind: z9.literal("selectPointInteraction"),
5716
+ responseIdentifier: z9.string().min(1),
3641
5717
  object: objectSchema,
3642
- maxChoices: z8.number().int().optional()
5718
+ maxChoices: z9.number().int().optional()
3643
5719
  }),
3644
5720
  scoring: "qti-standard",
3645
5721
  initialResponse: nullInitial
3646
5722
  });
3647
5723
  var positionObjectStage = defineInteraction({
3648
5724
  kind: "positionObjectStage",
3649
- schema: z8.object({
3650
- kind: z8.literal("positionObjectStage"),
3651
- responseIdentifier: z8.string().min(1),
5725
+ schema: z9.object({
5726
+ kind: z9.literal("positionObjectStage"),
5727
+ responseIdentifier: z9.string().min(1),
3652
5728
  stageObject: objectSchema,
3653
5729
  object: objectSchema,
3654
- maxChoices: z8.number().int().optional()
5730
+ maxChoices: z9.number().int().optional()
3655
5731
  }),
3656
5732
  scoring: "qti-standard",
3657
5733
  initialResponse: nullInitial
3658
5734
  });
3659
5735
 
3660
5736
  // src/interactions/hottext.ts
3661
- import { z as z9 } from "zod";
3662
- var hottextInteractionNodeSchema = z9.object({
3663
- kind: z9.literal("hottextInteraction"),
3664
- responseIdentifier: z9.string().min(1),
3665
- maxChoices: z9.number().int().optional(),
3666
- content: z9.array(z9.looseObject({ kind: z9.string().min(1) })).min(1)
5737
+ import { z as z10 } from "zod";
5738
+ var hottextInteractionNodeSchema = z10.object({
5739
+ kind: z10.literal("hottextInteraction"),
5740
+ responseIdentifier: z10.string().min(1),
5741
+ maxChoices: z10.number().int().optional(),
5742
+ content: z10.array(z10.looseObject({ kind: z10.string().min(1) })).min(1)
3667
5743
  });
3668
5744
  var hottextInteraction = defineInteraction({
3669
5745
  kind: "hottextInteraction",
@@ -3675,11 +5751,11 @@ var hottextInteraction = defineInteraction({
3675
5751
  });
3676
5752
 
3677
5753
  // src/interactions/inline-choice.ts
3678
- import { z as z10 } from "zod";
3679
- var inlineChoiceInteractionNodeSchema = z10.object({
3680
- kind: z10.literal("inlineChoiceInteraction"),
3681
- responseIdentifier: z10.string().min(1),
3682
- inlineChoices: z10.array(z10.object({ identifier: z10.string().min(1) })).min(1)
5754
+ import { z as z11 } from "zod";
5755
+ var inlineChoiceInteractionNodeSchema = z11.object({
5756
+ kind: z11.literal("inlineChoiceInteraction"),
5757
+ responseIdentifier: z11.string().min(1),
5758
+ inlineChoices: z11.array(z11.object({ identifier: z11.string().min(1) })).min(1)
3683
5759
  });
3684
5760
  var inlineChoiceInteraction = defineInteraction({
3685
5761
  kind: "inlineChoiceInteraction",
@@ -3691,15 +5767,15 @@ var inlineChoiceInteraction = defineInteraction({
3691
5767
  });
3692
5768
 
3693
5769
  // src/interactions/match.ts
3694
- import { z as z11 } from "zod";
3695
- var simpleMatchSetSchema = z11.object({
3696
- simpleAssociableChoices: z11.array(z11.looseObject({ identifier: z11.string().min(1), matchMax: z11.number().int().optional() })).min(1)
5770
+ import { z as z12 } from "zod";
5771
+ var simpleMatchSetSchema = z12.object({
5772
+ simpleAssociableChoices: z12.array(z12.looseObject({ identifier: z12.string().min(1), matchMax: z12.number().int().optional() })).min(1)
3697
5773
  });
3698
- var matchInteractionNodeSchema = z11.object({
3699
- kind: z11.literal("matchInteraction"),
3700
- responseIdentifier: z11.string().min(1),
3701
- simpleMatchSets: z11.array(simpleMatchSetSchema).length(2),
3702
- maxAssociations: z11.number().int().optional()
5774
+ var matchInteractionNodeSchema = z12.object({
5775
+ kind: z12.literal("matchInteraction"),
5776
+ responseIdentifier: z12.string().min(1),
5777
+ simpleMatchSets: z12.array(simpleMatchSetSchema).length(2),
5778
+ maxAssociations: z12.number().int().optional()
3703
5779
  });
3704
5780
  var matchInteraction = defineInteraction({
3705
5781
  kind: "matchInteraction",
@@ -3711,15 +5787,15 @@ var matchInteraction = defineInteraction({
3711
5787
  });
3712
5788
 
3713
5789
  // src/interactions/media.ts
3714
- import { z as z12 } from "zod";
3715
- var mediaInteractionNodeSchema = z12.object({
3716
- kind: z12.literal("mediaInteraction"),
3717
- responseIdentifier: z12.string().min(1),
3718
- autostart: z12.boolean().optional(),
3719
- minPlays: z12.number().int().optional(),
3720
- maxPlays: z12.number().int().optional(),
3721
- loop: z12.boolean().optional(),
3722
- content: z12.array(z12.looseObject({ kind: z12.string().min(1) })).min(1)
5790
+ import { z as z13 } from "zod";
5791
+ var mediaInteractionNodeSchema = z13.object({
5792
+ kind: z13.literal("mediaInteraction"),
5793
+ responseIdentifier: z13.string().min(1),
5794
+ autostart: z13.boolean().optional(),
5795
+ minPlays: z13.number().int().optional(),
5796
+ maxPlays: z13.number().int().optional(),
5797
+ loop: z13.boolean().optional(),
5798
+ content: z13.array(z13.looseObject({ kind: z13.string().min(1) })).min(1)
3723
5799
  });
3724
5800
  var mediaInteraction = defineInteraction({
3725
5801
  kind: "mediaInteraction",
@@ -3731,13 +5807,13 @@ var mediaInteraction = defineInteraction({
3731
5807
  });
3732
5808
 
3733
5809
  // src/interactions/order.ts
3734
- import { z as z13 } from "zod";
3735
- var orderInteractionNodeSchema = z13.object({
3736
- kind: z13.literal("orderInteraction"),
3737
- responseIdentifier: z13.string().min(1),
3738
- simpleChoices: z13.array(z13.looseObject({ identifier: z13.string().min(1) })).min(1),
3739
- shuffle: z13.boolean().optional(),
3740
- orientation: z13.enum(["horizontal", "vertical"]).optional()
5810
+ import { z as z14 } from "zod";
5811
+ var orderInteractionNodeSchema = z14.object({
5812
+ kind: z14.literal("orderInteraction"),
5813
+ responseIdentifier: z14.string().min(1),
5814
+ simpleChoices: z14.array(z14.looseObject({ identifier: z14.string().min(1) })).min(1),
5815
+ shuffle: z14.boolean().optional(),
5816
+ orientation: z14.enum(["horizontal", "vertical"]).optional()
3741
5817
  });
3742
5818
  var orderInteraction = defineInteraction({
3743
5819
  kind: "orderInteraction",
@@ -3749,16 +5825,16 @@ var orderInteraction = defineInteraction({
3749
5825
  });
3750
5826
 
3751
5827
  // src/interactions/slider.ts
3752
- import { z as z14 } from "zod";
3753
- var sliderInteractionNodeSchema = z14.object({
3754
- kind: z14.literal("sliderInteraction"),
3755
- responseIdentifier: z14.string().min(1),
3756
- lowerBound: z14.number(),
3757
- upperBound: z14.number(),
3758
- step: z14.number().optional(),
3759
- stepLabel: z14.boolean().optional(),
3760
- orientation: z14.enum(["horizontal", "vertical"]).optional(),
3761
- reverse: z14.boolean().optional()
5828
+ import { z as z15 } from "zod";
5829
+ var sliderInteractionNodeSchema = z15.object({
5830
+ kind: z15.literal("sliderInteraction"),
5831
+ responseIdentifier: z15.string().min(1),
5832
+ lowerBound: z15.number(),
5833
+ upperBound: z15.number(),
5834
+ step: z15.number().optional(),
5835
+ stepLabel: z15.boolean().optional(),
5836
+ orientation: z15.enum(["horizontal", "vertical"]).optional(),
5837
+ reverse: z15.boolean().optional()
3762
5838
  });
3763
5839
  var sliderInteraction = defineInteraction({
3764
5840
  kind: "sliderInteraction",
@@ -3770,13 +5846,13 @@ var sliderInteraction = defineInteraction({
3770
5846
  });
3771
5847
 
3772
5848
  // src/interactions/text-entry.ts
3773
- import { z as z15 } from "zod";
3774
- var textEntryInteractionNodeSchema = z15.object({
3775
- kind: z15.literal("textEntryInteraction"),
3776
- responseIdentifier: z15.string().min(1),
3777
- expectedLength: z15.number().int().optional(),
3778
- placeholderText: z15.string().optional(),
3779
- patternMask: z15.string().optional()
5849
+ import { z as z16 } from "zod";
5850
+ var textEntryInteractionNodeSchema = z16.object({
5851
+ kind: z16.literal("textEntryInteraction"),
5852
+ responseIdentifier: z16.string().min(1),
5853
+ expectedLength: z16.number().int().optional(),
5854
+ placeholderText: z16.string().optional(),
5855
+ patternMask: z16.string().optional()
3780
5856
  });
3781
5857
  var textEntryInteraction = defineInteraction({
3782
5858
  kind: "textEntryInteraction",
@@ -3788,11 +5864,11 @@ var textEntryInteraction = defineInteraction({
3788
5864
  });
3789
5865
 
3790
5866
  // src/interactions/upload.ts
3791
- import { z as z16 } from "zod";
3792
- var uploadInteractionNodeSchema = z16.object({
3793
- kind: z16.literal("uploadInteraction"),
3794
- responseIdentifier: z16.string().min(1),
3795
- type: z16.string().optional()
5867
+ import { z as z17 } from "zod";
5868
+ var uploadInteractionNodeSchema = z17.object({
5869
+ kind: z17.literal("uploadInteraction"),
5870
+ responseIdentifier: z17.string().min(1),
5871
+ type: z17.string().optional()
3796
5872
  });
3797
5873
  var uploadInteraction = defineInteraction({
3798
5874
  kind: "uploadInteraction",
@@ -3879,8 +5955,8 @@ function AssociateReferenceSkin(props) {
3879
5955
  }, createElement3("option", { key: "", value: "" }, ""), choices.map((choice) => createElement3("option", { key: choice.identifier, value: choice.identifier }, labelFor(choice.identifier))));
3880
5956
  }
3881
5957
  return createElement3("div", { "data-qti-interaction": "associateInteraction", "data-status": props.status }, node.prompt ? createElement3("div", { "data-qti-prompt": true }, props.renderContent(node.prompt.content)) : null, picker(first, setFirst, "First member"), picker(second, setSecond, "Second member"), createElement3("button", { type: "button", disabled: props.disabled, onClick: addPair }, "Add pair"), createElement3("ul", null, pairs.map((pair) => {
3882
- const [a, b] = pair.split(/\s+/u);
3883
- return createElement3("li", { key: pair, "data-qti-pair": pair }, `${labelFor(a ?? "")} ↔ ${labelFor(b ?? "")} `, createElement3("button", {
5958
+ const [a3, b2] = pair.split(/\s+/u);
5959
+ return createElement3("li", { key: pair, "data-qti-pair": pair }, `${labelFor(a3 ?? "")} ↔ ${labelFor(b2 ?? "")} `, createElement3("button", {
3884
5960
  type: "button",
3885
5961
  disabled: props.disabled,
3886
5962
  "aria-label": `Remove pair ${pair}`,
@@ -3901,7 +5977,7 @@ function ChoiceReferenceSkin(props) {
3901
5977
  "data-status": props.status
3902
5978
  }, node.prompt ? createElement4("div", { "data-qti-prompt": true }, props.renderContent(node.prompt.content)) : null, choices.map((choice) => {
3903
5979
  const optionProps = props.getOptionProps(choice.identifier);
3904
- return createElement4("button", { key: choice.identifier, type: "button", disabled: props.disabled, ...optionProps }, props.renderContent(choice.content) ?? choice.identifier);
5980
+ return createElement4("button", { key: choice.identifier, type: "button", disabled: props.disabled, ...optionProps }, props.renderContent(choice.content) ?? choice.identifier, props.renderCatalogSupports(choice.dataCatalogIdref));
3905
5981
  }));
3906
5982
  }
3907
5983
 
@@ -3958,12 +6034,12 @@ function DrawingReferenceSkin(props) {
3958
6034
  }
3959
6035
  drawingRef.current = true;
3960
6036
  event.currentTarget.setPointerCapture(event.pointerId);
3961
- const { x, y } = pointerPosition(event);
6037
+ const { x: x2, y: y2 } = pointerPosition(event);
3962
6038
  context.strokeStyle = strokeStyle;
3963
6039
  context.lineWidth = strokeWidth;
3964
6040
  context.lineCap = "round";
3965
6041
  context.beginPath();
3966
- context.moveTo(x, y);
6042
+ context.moveTo(x2, y2);
3967
6043
  };
3968
6044
  const handlePointerMove = (event) => {
3969
6045
  if (!drawingRef.current) {
@@ -3973,8 +6049,8 @@ function DrawingReferenceSkin(props) {
3973
6049
  if (!context) {
3974
6050
  return;
3975
6051
  }
3976
- const { x, y } = pointerPosition(event);
3977
- context.lineTo(x, y);
6052
+ const { x: x2, y: y2 } = pointerPosition(event);
6053
+ context.lineTo(x2, y2);
3978
6054
  context.stroke();
3979
6055
  };
3980
6056
  const handlePointerUp = (event) => {
@@ -4075,14 +6151,14 @@ function shapeCenter(shape, coords) {
4075
6151
  case "rect":
4076
6152
  return { x: ((coords[0] ?? 0) + (coords[2] ?? 0)) / 2, y: ((coords[1] ?? 0) + (coords[3] ?? 0)) / 2 };
4077
6153
  case "poly": {
4078
- let x = 0;
4079
- let y = 0;
6154
+ let x2 = 0;
6155
+ let y2 = 0;
4080
6156
  const pointCount = Math.floor(coords.length / 2);
4081
- for (let i = 0;i < pointCount * 2; i += 2) {
4082
- x += coords[i] ?? 0;
4083
- y += coords[i + 1] ?? 0;
6157
+ for (let i3 = 0;i3 < pointCount * 2; i3 += 2) {
6158
+ x2 += coords[i3] ?? 0;
6159
+ y2 += coords[i3 + 1] ?? 0;
4084
6160
  }
4085
- return pointCount === 0 ? { x: 0, y: 0 } : { x: x / pointCount, y: y / pointCount };
6161
+ return pointCount === 0 ? { x: 0, y: 0 } : { x: x2 / pointCount, y: y2 / pointCount };
4086
6162
  }
4087
6163
  default:
4088
6164
  return { x: 0, y: 0 };
@@ -4105,8 +6181,8 @@ function shapeElement(shape, coords, key, props) {
4105
6181
  return createElement9("ellipse", { ...base, cx: coords[0], cy: coords[1], rx: coords[2], ry: coords[3] });
4106
6182
  case "poly": {
4107
6183
  const points = [];
4108
- for (let i = 0;i + 1 < coords.length; i += 2) {
4109
- points.push(`${coords[i]},${coords[i + 1]}`);
6184
+ for (let i3 = 0;i3 + 1 < coords.length; i3 += 2) {
6185
+ points.push(`${coords[i3]},${coords[i3 + 1]}`);
4110
6186
  }
4111
6187
  return createElement9("polygon", { ...base, points: points.join(" ") });
4112
6188
  }
@@ -4172,9 +6248,9 @@ function GraphicAssociateReferenceSkin(props) {
4172
6248
  status: props.status,
4173
6249
  prompt: node.prompt ? createElement10("div", { "data-qti-prompt": true }, props.renderContent(node.prompt.content)) : null,
4174
6250
  overlay: createElement10(Fragment2, null, pairs.map((pair) => {
4175
- const [a, b] = pair.split(/\s+/u);
4176
- const from = centersById.get(a ?? "");
4177
- const to = centersById.get(b ?? "");
6251
+ const [a3, b2] = pair.split(/\s+/u);
6252
+ const from = centersById.get(a3 ?? "");
6253
+ const to = centersById.get(b2 ?? "");
4178
6254
  if (!from || !to) {
4179
6255
  return null;
4180
6256
  }
@@ -4558,10 +6634,10 @@ function SelectPointReferenceSkin(props) {
4558
6634
  onStageClick: stageClick,
4559
6635
  prompt: node.prompt ? createElement20("div", { "data-qti-prompt": true }, props.renderContent(node.prompt.content)) : null,
4560
6636
  overlay: points.map((value, index) => {
4561
- const [x, y] = value.split(/\s+/u).map(Number);
6637
+ const [x2, y2] = value.split(/\s+/u).map(Number);
4562
6638
  return createElement20(Fragment5, { key: `${value}-${index}` }, createElement20("circle", {
4563
- cx: x,
4564
- cy: y,
6639
+ cx: x2,
6640
+ cy: y2,
4565
6641
  r: 5,
4566
6642
  fill: "currentColor",
4567
6643
  "data-qti-point": value,
@@ -4673,12 +6749,15 @@ export {
4673
6749
  uploadInteraction,
4674
6750
  textOf,
4675
6751
  textEntryInteraction,
6752
+ stimulusContentFromNormalized,
4676
6753
  sliderInteraction,
4677
6754
  serializePciMarkup,
4678
6755
  selectPointInteraction,
4679
6756
  scoreResponse,
4680
6757
  sanitizeAttributes,
4681
6758
  resolveTemplate,
6759
+ resolvePnpActivation,
6760
+ resolveCatalogSupports,
4682
6761
  referenceSkin,
4683
6762
  qtiReactPackageName,
4684
6763
  qtiCoreInteractions,
@@ -4721,6 +6800,8 @@ export {
4721
6800
  createAttemptStore,
4722
6801
  collectTemplateIssues,
4723
6802
  collectRpIssues,
6803
+ collectResponseViolations,
6804
+ collectInteractionConstraints,
4724
6805
  choiceInteraction,
4725
6806
  associateInteraction,
4726
6807
  assessmentTestViewFromNormalized,