@conform-ed/qti-react 0.0.15 → 0.0.16
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.d.ts +6 -4
- package/dist/index.js +2486 -405
- package/dist/normalized-item.d.ts +7 -5
- package/dist/pnp.d.ts +115 -0
- package/dist/response-validity.d.ts +28 -0
- package/dist/rp/evaluate.d.ts +6 -1
- package/dist/rp/index.d.ts +2 -2
- package/dist/rp/interpreter.d.ts +7 -1
- package/dist/rp/lookup-table.d.ts +17 -0
- package/dist/rp/template-processing.d.ts +5 -0
- package/dist/rp/types.d.ts +71 -7
- package/dist/runtime.d.ts +95 -0
- package/dist/store.d.ts +47 -0
- package/dist/test/controller.d.ts +22 -0
- package/dist/test/index.d.ts +2 -1
- package/dist/test/results.d.ts +102 -0
- package/dist/test/session-store.d.ts +32 -0
- package/dist/test/types.d.ts +173 -5
- package/dist/types.d.ts +5 -0
- package/package.json +5 -1
- package/src/content-model.ts +44 -4
- package/src/index.ts +43 -1
- package/src/normalized-item.ts +106 -4
- package/src/pnp.ts +333 -0
- package/src/reference-skin/choice.ts +3 -0
- package/src/response-validity.ts +163 -0
- package/src/rp/evaluate.ts +280 -32
- package/src/rp/index.ts +5 -0
- package/src/rp/interpreter.ts +81 -1
- package/src/rp/lookup-table.ts +46 -0
- package/src/rp/template-processing.ts +41 -0
- package/src/rp/types.ts +75 -7
- package/src/runtime.ts +397 -20
- package/src/store.ts +146 -8
- package/src/test/controller.ts +856 -82
- package/src/test/index.ts +23 -0
- package/src/test/results.ts +378 -0
- package/src/test/session-store.ts +109 -1
- package/src/test/types.ts +172 -5
- package/src/types.ts +1 -0
- package/src/xspattern.d.ts +11 -0
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
|
-
|
|
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
|
-
...
|
|
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(
|
|
776
|
-
const [a1,
|
|
777
|
-
const [b1,
|
|
778
|
-
if (a1 === 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 &&
|
|
1577
|
+
if (a1 === b1 && a22 === b22) {
|
|
782
1578
|
return true;
|
|
783
1579
|
}
|
|
784
|
-
return !directed && a1 ===
|
|
1580
|
+
return !directed && a1 === b22 && a22 === b1;
|
|
785
1581
|
}
|
|
786
|
-
function scalarsEqual(
|
|
1582
|
+
function scalarsEqual(a3, b2, baseType, normalize) {
|
|
787
1583
|
if (baseType === "pair" || baseType === "directedPair") {
|
|
788
|
-
return typeof
|
|
1584
|
+
return typeof a3 === "string" && typeof b2 === "string" && pairsEqual2(a3, b2, baseType === "directedPair");
|
|
789
1585
|
}
|
|
790
1586
|
if (baseType === "point") {
|
|
791
|
-
if (typeof
|
|
1587
|
+
if (typeof a3 !== "string" || typeof b2 !== "string") {
|
|
792
1588
|
return false;
|
|
793
1589
|
}
|
|
794
|
-
const pointA = parsePoint(
|
|
795
|
-
const pointB = parsePoint(
|
|
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
|
|
799
|
-
return Number(
|
|
1594
|
+
if (typeof a3 === "number" || typeof b2 === "number") {
|
|
1595
|
+
return Number(a3) === Number(b2);
|
|
800
1596
|
}
|
|
801
|
-
if (normalize && baseType === "string" && typeof
|
|
802
|
-
return normalize(
|
|
1597
|
+
if (normalize && baseType === "string" && typeof a3 === "string" && typeof b2 === "string") {
|
|
1598
|
+
return normalize(a3) === normalize(b2);
|
|
803
1599
|
}
|
|
804
|
-
return
|
|
1600
|
+
return a3 === b2;
|
|
805
1601
|
}
|
|
806
|
-
function valuesMatch(
|
|
807
|
-
const baseType =
|
|
808
|
-
if (
|
|
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 (
|
|
812
|
-
return
|
|
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 = [...
|
|
815
|
-
for (const value of
|
|
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
|
-
|
|
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(
|
|
1724
|
+
return Math.sin(x2);
|
|
904
1725
|
case "cos":
|
|
905
|
-
return Math.cos(
|
|
1726
|
+
return Math.cos(x2);
|
|
906
1727
|
case "tan":
|
|
907
|
-
return Math.tan(
|
|
1728
|
+
return Math.tan(x2);
|
|
908
1729
|
case "sec":
|
|
909
|
-
return 1 / Math.cos(
|
|
1730
|
+
return 1 / Math.cos(x2);
|
|
910
1731
|
case "csc":
|
|
911
|
-
return 1 / Math.sin(
|
|
1732
|
+
return 1 / Math.sin(x2);
|
|
912
1733
|
case "cot":
|
|
913
|
-
return Math.cos(
|
|
1734
|
+
return Math.cos(x2) / Math.sin(x2);
|
|
914
1735
|
case "asin":
|
|
915
|
-
return Math.asin(
|
|
1736
|
+
return Math.asin(x2);
|
|
916
1737
|
case "acos":
|
|
917
|
-
return Math.acos(
|
|
1738
|
+
return Math.acos(x2);
|
|
918
1739
|
case "atan":
|
|
919
|
-
return Math.atan(
|
|
1740
|
+
return Math.atan(x2);
|
|
920
1741
|
case "atan2":
|
|
921
|
-
return Math.atan2(
|
|
1742
|
+
return Math.atan2(x2, y2);
|
|
922
1743
|
case "asec":
|
|
923
|
-
return Math.acos(1 /
|
|
1744
|
+
return Math.acos(1 / x2);
|
|
924
1745
|
case "acsc":
|
|
925
|
-
return Math.asin(1 /
|
|
1746
|
+
return Math.asin(1 / x2);
|
|
926
1747
|
case "acot":
|
|
927
|
-
return Math.atan(1 /
|
|
1748
|
+
return Math.atan(1 / x2);
|
|
928
1749
|
case "sinh":
|
|
929
|
-
return Math.sinh(
|
|
1750
|
+
return Math.sinh(x2);
|
|
930
1751
|
case "cosh":
|
|
931
|
-
return Math.cosh(
|
|
1752
|
+
return Math.cosh(x2);
|
|
932
1753
|
case "tanh":
|
|
933
|
-
return Math.tanh(
|
|
1754
|
+
return Math.tanh(x2);
|
|
934
1755
|
case "sech":
|
|
935
|
-
return 1 / Math.cosh(
|
|
1756
|
+
return 1 / Math.cosh(x2);
|
|
936
1757
|
case "csch":
|
|
937
|
-
return 1 / Math.sinh(
|
|
1758
|
+
return 1 / Math.sinh(x2);
|
|
938
1759
|
case "coth":
|
|
939
|
-
return Math.cosh(
|
|
1760
|
+
return Math.cosh(x2) / Math.sinh(x2);
|
|
940
1761
|
case "log":
|
|
941
|
-
return Math.log10(
|
|
1762
|
+
return Math.log10(x2);
|
|
942
1763
|
case "ln":
|
|
943
|
-
return Math.log(
|
|
1764
|
+
return Math.log(x2);
|
|
944
1765
|
case "exp":
|
|
945
|
-
return Math.exp(
|
|
1766
|
+
return Math.exp(x2);
|
|
946
1767
|
case "abs":
|
|
947
|
-
return Math.abs(
|
|
1768
|
+
return Math.abs(x2);
|
|
948
1769
|
case "signum":
|
|
949
|
-
return Math.sign(
|
|
1770
|
+
return Math.sign(x2);
|
|
950
1771
|
case "floor":
|
|
951
|
-
return Math.floor(
|
|
1772
|
+
return Math.floor(x2);
|
|
952
1773
|
case "ceil":
|
|
953
|
-
return Math.ceil(
|
|
1774
|
+
return Math.ceil(x2);
|
|
954
1775
|
case "toDegrees":
|
|
955
|
-
return
|
|
1776
|
+
return x2 * 180 / Math.PI;
|
|
956
1777
|
case "toRadians":
|
|
957
|
-
return
|
|
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 [
|
|
1014
|
-
if (
|
|
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(
|
|
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
|
-
|
|
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 [
|
|
1059
|
-
if (
|
|
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
|
|
1903
|
+
return b2 === 0 ? null : floatValue(a3 / b2);
|
|
1064
1904
|
}
|
|
1065
|
-
return floatValue(
|
|
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 [
|
|
1072
|
-
if (
|
|
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:
|
|
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 [
|
|
1080
|
-
if (
|
|
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(
|
|
1925
|
+
return booleanValue(a3 === b2);
|
|
1086
1926
|
}
|
|
1087
|
-
const t0 = expression.tolerance?.[0];
|
|
1088
|
-
const
|
|
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
|
-
|
|
1931
|
+
return null;
|
|
1091
1932
|
}
|
|
1092
|
-
const lower = mode === "absolute" ?
|
|
1093
|
-
const upper = mode === "absolute" ?
|
|
1094
|
-
const aboveLower = expression.includeLowerBound ?? true ?
|
|
1095
|
-
const belowUpper = expression.includeUpperBound ?? true ?
|
|
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
|
-
|
|
1110
|
-
|
|
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[
|
|
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 [
|
|
1132
|
-
if (
|
|
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,
|
|
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 [
|
|
1144
|
-
if (
|
|
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(
|
|
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 = (
|
|
1194
|
-
const result = expression.kind === "gcd" ? members.reduce(gcdOf) : members.reduce((
|
|
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
|
-
|
|
1199
|
-
|
|
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",
|
|
2049
|
+
const rounded = roundToFigures(value, expression.roundingMode ?? "significantFigures", figures);
|
|
1207
2050
|
return rounded === null ? null : floatValue(rounded);
|
|
1208
2051
|
}
|
|
1209
2052
|
case "equalRounded": {
|
|
1210
|
-
|
|
1211
|
-
|
|
2053
|
+
const figures = resolveNumericAttribute(expression.figures, env);
|
|
2054
|
+
if (typeof figures !== "number") {
|
|
2055
|
+
return null;
|
|
1212
2056
|
}
|
|
1213
|
-
const [
|
|
1214
|
-
if (
|
|
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(
|
|
1219
|
-
const roundedB = roundToFigures(
|
|
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
|
-
|
|
1276
|
-
|
|
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 <
|
|
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 [
|
|
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 (
|
|
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(
|
|
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([
|
|
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
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
return ((
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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([
|
|
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((
|
|
2075
|
-
for (let
|
|
2076
|
-
const
|
|
2077
|
-
[indices[
|
|
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((
|
|
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,
|
|
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(
|
|
2089
|
-
const result =
|
|
2090
|
-
const movable =
|
|
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
|
|
2093
|
-
const
|
|
2094
|
-
[shuffled[
|
|
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
|
|
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
|
|
3444
|
+
children = applySelection(children, section.selection, random);
|
|
2106
3445
|
}
|
|
3446
|
+
let units = children.map((child) => ({ child, via: [] }));
|
|
2107
3447
|
if (section.ordering?.shuffle) {
|
|
2108
|
-
|
|
3448
|
+
units = applyOrdering(mixedUnits(children, random, sections), random);
|
|
2109
3449
|
}
|
|
2110
3450
|
const items = [];
|
|
2111
|
-
for (const child of
|
|
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,
|
|
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:
|
|
2120
|
-
preConditions: [...
|
|
2121
|
-
sessionControl: { ...specSessionControlDefaults, ...
|
|
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:
|
|
2133
|
-
|
|
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
|
|
2171
|
-
|
|
2172
|
-
|
|
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
|
-
|
|
2176
|
-
|
|
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
|
-
|
|
2195
|
-
|
|
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) *
|
|
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
|
|
2319
|
-
const items = plan.parts[
|
|
2320
|
-
for (let
|
|
2321
|
-
const item = items[
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
4214
|
+
moveTo: (state, itemKey) => withTransition(state, (settled) => {
|
|
4215
|
+
const current = positionOf(settled.currentItemKey ?? "");
|
|
2512
4216
|
const target = positionOf(itemKey);
|
|
2513
|
-
|
|
2514
|
-
|
|
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({ ...
|
|
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) =>
|
|
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
|
-
|
|
4234
|
+
const item = itemsByKey.get(itemKey);
|
|
4235
|
+
if (state.status !== "in-progress" || !item) {
|
|
2524
4236
|
return state;
|
|
2525
4237
|
}
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
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
|
-
|
|
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
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
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, {
|
|
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, {
|
|
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 =
|
|
3394
|
-
id:
|
|
3395
|
-
primaryPath:
|
|
3396
|
-
fallbackPath:
|
|
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 =
|
|
3399
|
-
kind:
|
|
3400
|
-
responseIdentifier:
|
|
3401
|
-
customInteractionTypeIdentifier:
|
|
3402
|
-
module:
|
|
3403
|
-
properties:
|
|
3404
|
-
interactionMarkup:
|
|
3405
|
-
interactionModules:
|
|
3406
|
-
primaryConfiguration:
|
|
3407
|
-
secondaryConfiguration:
|
|
3408
|
-
modules:
|
|
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
|
|
3469
|
-
var associateInteractionNodeSchema =
|
|
3470
|
-
kind:
|
|
3471
|
-
responseIdentifier:
|
|
3472
|
-
simpleAssociableChoices:
|
|
3473
|
-
maxAssociations:
|
|
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
|
|
3486
|
-
var choiceInteractionNodeSchema =
|
|
3487
|
-
kind:
|
|
3488
|
-
responseIdentifier:
|
|
3489
|
-
simpleChoices:
|
|
3490
|
-
maxChoices:
|
|
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
|
|
3503
|
-
var drawingInteractionNodeSchema =
|
|
3504
|
-
kind:
|
|
3505
|
-
responseIdentifier:
|
|
3506
|
-
object:
|
|
3507
|
-
data:
|
|
3508
|
-
width:
|
|
3509
|
-
height:
|
|
3510
|
-
type:
|
|
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
|
|
3524
|
-
var endAttemptInteractionNodeSchema =
|
|
3525
|
-
kind:
|
|
3526
|
-
responseIdentifier:
|
|
3527
|
-
title:
|
|
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
|
|
3540
|
-
var extendedTextInteractionNodeSchema =
|
|
3541
|
-
kind:
|
|
3542
|
-
responseIdentifier:
|
|
3543
|
-
expectedLength:
|
|
3544
|
-
expectedLines:
|
|
3545
|
-
placeholderText:
|
|
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
|
|
3558
|
-
var gapMatchInteractionNodeSchema =
|
|
3559
|
-
kind:
|
|
3560
|
-
responseIdentifier:
|
|
3561
|
-
gapTexts:
|
|
3562
|
-
content:
|
|
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
|
|
3575
|
-
var objectSchema =
|
|
3576
|
-
data:
|
|
3577
|
-
width:
|
|
3578
|
-
height:
|
|
3579
|
-
type:
|
|
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 =
|
|
3582
|
-
identifier:
|
|
3583
|
-
shape:
|
|
3584
|
-
coords:
|
|
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:
|
|
3592
|
-
kind:
|
|
3593
|
-
responseIdentifier:
|
|
5667
|
+
schema: z9.object({
|
|
5668
|
+
kind: z9.literal("hotspotInteraction"),
|
|
5669
|
+
responseIdentifier: z9.string().min(1),
|
|
3594
5670
|
object: objectSchema,
|
|
3595
|
-
hotspotChoices:
|
|
3596
|
-
maxChoices:
|
|
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:
|
|
3604
|
-
kind:
|
|
3605
|
-
responseIdentifier:
|
|
5679
|
+
schema: z9.object({
|
|
5680
|
+
kind: z9.literal("graphicOrderInteraction"),
|
|
5681
|
+
responseIdentifier: z9.string().min(1),
|
|
3606
5682
|
object: objectSchema,
|
|
3607
|
-
hotspotChoices:
|
|
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:
|
|
3615
|
-
kind:
|
|
3616
|
-
responseIdentifier:
|
|
5690
|
+
schema: z9.object({
|
|
5691
|
+
kind: z9.literal("graphicAssociateInteraction"),
|
|
5692
|
+
responseIdentifier: z9.string().min(1),
|
|
3617
5693
|
object: objectSchema,
|
|
3618
|
-
associableHotspots:
|
|
3619
|
-
maxAssociations:
|
|
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:
|
|
3627
|
-
kind:
|
|
3628
|
-
responseIdentifier:
|
|
5702
|
+
schema: z9.object({
|
|
5703
|
+
kind: z9.literal("graphicGapMatchInteraction"),
|
|
5704
|
+
responseIdentifier: z9.string().min(1),
|
|
3629
5705
|
object: objectSchema,
|
|
3630
|
-
gapImgs:
|
|
3631
|
-
associableHotspots:
|
|
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:
|
|
3639
|
-
kind:
|
|
3640
|
-
responseIdentifier:
|
|
5714
|
+
schema: z9.object({
|
|
5715
|
+
kind: z9.literal("selectPointInteraction"),
|
|
5716
|
+
responseIdentifier: z9.string().min(1),
|
|
3641
5717
|
object: objectSchema,
|
|
3642
|
-
maxChoices:
|
|
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:
|
|
3650
|
-
kind:
|
|
3651
|
-
responseIdentifier:
|
|
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:
|
|
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
|
|
3662
|
-
var hottextInteractionNodeSchema =
|
|
3663
|
-
kind:
|
|
3664
|
-
responseIdentifier:
|
|
3665
|
-
maxChoices:
|
|
3666
|
-
content:
|
|
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
|
|
3679
|
-
var inlineChoiceInteractionNodeSchema =
|
|
3680
|
-
kind:
|
|
3681
|
-
responseIdentifier:
|
|
3682
|
-
inlineChoices:
|
|
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
|
|
3695
|
-
var simpleMatchSetSchema =
|
|
3696
|
-
simpleAssociableChoices:
|
|
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 =
|
|
3699
|
-
kind:
|
|
3700
|
-
responseIdentifier:
|
|
3701
|
-
simpleMatchSets:
|
|
3702
|
-
maxAssociations:
|
|
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
|
|
3715
|
-
var mediaInteractionNodeSchema =
|
|
3716
|
-
kind:
|
|
3717
|
-
responseIdentifier:
|
|
3718
|
-
autostart:
|
|
3719
|
-
minPlays:
|
|
3720
|
-
maxPlays:
|
|
3721
|
-
loop:
|
|
3722
|
-
content:
|
|
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
|
|
3735
|
-
var orderInteractionNodeSchema =
|
|
3736
|
-
kind:
|
|
3737
|
-
responseIdentifier:
|
|
3738
|
-
simpleChoices:
|
|
3739
|
-
shuffle:
|
|
3740
|
-
orientation:
|
|
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
|
|
3753
|
-
var sliderInteractionNodeSchema =
|
|
3754
|
-
kind:
|
|
3755
|
-
responseIdentifier:
|
|
3756
|
-
lowerBound:
|
|
3757
|
-
upperBound:
|
|
3758
|
-
step:
|
|
3759
|
-
stepLabel:
|
|
3760
|
-
orientation:
|
|
3761
|
-
reverse:
|
|
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
|
|
3774
|
-
var textEntryInteractionNodeSchema =
|
|
3775
|
-
kind:
|
|
3776
|
-
responseIdentifier:
|
|
3777
|
-
expectedLength:
|
|
3778
|
-
placeholderText:
|
|
3779
|
-
patternMask:
|
|
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
|
|
3792
|
-
var uploadInteractionNodeSchema =
|
|
3793
|
-
kind:
|
|
3794
|
-
responseIdentifier:
|
|
3795
|
-
type:
|
|
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 [
|
|
3883
|
-
return createElement3("li", { key: pair, "data-qti-pair": pair }, `${labelFor(
|
|
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(
|
|
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(
|
|
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
|
|
4079
|
-
let
|
|
6154
|
+
let x2 = 0;
|
|
6155
|
+
let y2 = 0;
|
|
4080
6156
|
const pointCount = Math.floor(coords.length / 2);
|
|
4081
|
-
for (let
|
|
4082
|
-
|
|
4083
|
-
|
|
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:
|
|
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
|
|
4109
|
-
points.push(`${coords[
|
|
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 [
|
|
4176
|
-
const from = centersById.get(
|
|
4177
|
-
const to = centersById.get(
|
|
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 [
|
|
6637
|
+
const [x2, y2] = value.split(/\s+/u).map(Number);
|
|
4562
6638
|
return createElement20(Fragment5, { key: `${value}-${index}` }, createElement20("circle", {
|
|
4563
|
-
cx:
|
|
4564
|
-
cy:
|
|
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,
|