@longsightgroup/qti3-core 0.10.1 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -2
- package/dist/attempt-state.d.ts.map +1 -1
- package/dist/attempt-state.js +18 -0
- package/dist/attempt-state.js.map +1 -1
- package/dist/content-text.d.ts +4 -0
- package/dist/content-text.d.ts.map +1 -1
- package/dist/content-text.js +112 -9
- package/dist/content-text.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/media-definition.d.ts +55 -0
- package/dist/media-definition.d.ts.map +1 -0
- package/dist/media-definition.js +97 -0
- package/dist/media-definition.js.map +1 -0
- package/dist/parser-declarations.d.ts +4 -4
- package/dist/parser-declarations.d.ts.map +1 -1
- package/dist/parser-declarations.js +87 -46
- package/dist/parser-declarations.js.map +1 -1
- package/dist/parser-item-metadata.d.ts.map +1 -1
- package/dist/parser-item-metadata.js +4 -3
- package/dist/parser-item-metadata.js.map +1 -1
- package/dist/parser-processing.js +10 -9
- package/dist/parser-processing.js.map +1 -1
- package/dist/parser-values.d.ts +2 -0
- package/dist/parser-values.d.ts.map +1 -1
- package/dist/parser-values.js +7 -0
- package/dist/parser-values.js.map +1 -1
- package/dist/parser.js +16 -13
- package/dist/parser.js.map +1 -1
- package/dist/processing-evaluator-collection.d.ts.map +1 -1
- package/dist/processing-evaluator-collection.js +8 -2
- package/dist/processing-evaluator-collection.js.map +1 -1
- package/dist/processing-evaluator-comparison.d.ts.map +1 -1
- package/dist/processing-evaluator-comparison.js +6 -0
- package/dist/processing-evaluator-comparison.js.map +1 -1
- package/dist/processing-evaluator-numeric.d.ts.map +1 -1
- package/dist/processing-evaluator-numeric.js +8 -1
- package/dist/processing-evaluator-numeric.js.map +1 -1
- package/dist/processing-expression-children.d.ts.map +1 -1
- package/dist/processing-expression-children.js +2 -1
- package/dist/processing-expression-children.js.map +1 -1
- package/dist/processing-limits.d.ts +3 -0
- package/dist/processing-limits.d.ts.map +1 -0
- package/dist/processing-limits.js +3 -0
- package/dist/processing-limits.js.map +1 -0
- package/dist/processing-mapping.d.ts.map +1 -1
- package/dist/processing-mapping.js +13 -2
- package/dist/processing-mapping.js.map +1 -1
- package/dist/processing-operators.d.ts +2 -0
- package/dist/processing-operators.d.ts.map +1 -1
- package/dist/processing-operators.js +34 -5
- package/dist/processing-operators.js.map +1 -1
- package/dist/response-validation-policy.d.ts.map +1 -1
- package/dist/response-validation-policy.js +5 -6
- package/dist/response-validation-policy.js.map +1 -1
- package/dist/serializer-processing-expressions.js +1 -1
- package/dist/serializer-processing-expressions.js.map +1 -1
- package/dist/slider-definition.d.ts +59 -0
- package/dist/slider-definition.d.ts.map +1 -0
- package/dist/slider-definition.js +198 -0
- package/dist/slider-definition.js.map +1 -0
- package/dist/support-evidence.d.ts +6 -2
- package/dist/support-evidence.d.ts.map +1 -1
- package/dist/support-evidence.js +15 -11
- package/dist/support-evidence.js.map +1 -1
- package/dist/support.d.ts.map +1 -1
- package/dist/support.js +96 -100
- package/dist/support.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validation-declaration-entries.d.ts +13 -0
- package/dist/validation-declaration-entries.d.ts.map +1 -0
- package/dist/validation-declaration-entries.js +136 -0
- package/dist/validation-declaration-entries.js.map +1 -0
- package/dist/validation-interactions.d.ts.map +1 -1
- package/dist/validation-interactions.js +14 -46
- package/dist/validation-interactions.js.map +1 -1
- package/dist/validation-primitives.js +2 -2
- package/dist/validation-primitives.js.map +1 -1
- package/dist/validation-processing.d.ts.map +1 -1
- package/dist/validation-processing.js +125 -1
- package/dist/validation-processing.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +8 -134
- package/dist/validation.js.map +1 -1
- package/dist/xml.d.ts.map +1 -1
- package/dist/xml.js +3 -2
- package/dist/xml.js.map +1 -1
- package/package.json +1 -1
- package/src/attempt-state.ts +20 -0
- package/src/content-text.ts +135 -11
- package/src/index.ts +25 -0
- package/src/media-definition.ts +174 -0
- package/src/parser-declarations.ts +134 -40
- package/src/parser-item-metadata.ts +4 -3
- package/src/parser-processing.ts +10 -9
- package/src/parser-values.ts +7 -0
- package/src/parser.ts +16 -13
- package/src/processing-evaluator-collection.ts +7 -2
- package/src/processing-evaluator-comparison.ts +6 -0
- package/src/processing-evaluator-numeric.ts +5 -1
- package/src/processing-expression-children.ts +2 -1
- package/src/processing-limits.ts +2 -0
- package/src/processing-mapping.ts +10 -2
- package/src/processing-operators.ts +38 -5
- package/src/response-validation-policy.ts +5 -5
- package/src/serializer-processing-expressions.ts +1 -1
- package/src/slider-definition.ts +363 -0
- package/src/support-evidence.ts +15 -17
- package/src/support.ts +106 -102
- package/src/types.ts +8 -1
- package/src/validation-declaration-entries.ts +162 -0
- package/src/validation-interactions.ts +14 -64
- package/src/validation-primitives.ts +2 -2
- package/src/validation-processing.ts +145 -1
- package/src/validation.ts +11 -151
- package/src/xml.ts +3 -4
package/src/support.ts
CHANGED
|
@@ -11,9 +11,14 @@ import type {
|
|
|
11
11
|
import {
|
|
12
12
|
browserFeedbackTests,
|
|
13
13
|
browserHarnessTests,
|
|
14
|
+
coreIntegrationTest,
|
|
14
15
|
interactionSupportFixtures,
|
|
15
16
|
interactionSupportTests,
|
|
16
17
|
processingBrowserEvidence,
|
|
18
|
+
processingMappingTest,
|
|
19
|
+
processingOperatorsTest,
|
|
20
|
+
processingResponseTest,
|
|
21
|
+
processingTemplateTest,
|
|
17
22
|
} from "./support-evidence.js";
|
|
18
23
|
|
|
19
24
|
export const interactionSupport: QtiInteractionElementSupport[] = [
|
|
@@ -52,15 +57,19 @@ export const deprecatedInteractionSupport: QtiInteractionElementSupport[] = [
|
|
|
52
57
|
render: false,
|
|
53
58
|
process: false,
|
|
54
59
|
fixtures: [],
|
|
55
|
-
tests: [
|
|
60
|
+
tests: [coreIntegrationTest],
|
|
56
61
|
notes: "Deprecated in favor of qti-portable-custom-interaction.",
|
|
57
62
|
},
|
|
58
63
|
];
|
|
59
64
|
|
|
65
|
+
const templateProcessingEntry = processingEntryFor(processingTemplateTest);
|
|
66
|
+
const responseProcessingEntry = processingEntryFor(processingResponseTest);
|
|
67
|
+
const mappingProcessingEntry = processingEntryFor(processingMappingTest);
|
|
68
|
+
const operatorProcessingEntry = processingEntryFor(processingOperatorsTest);
|
|
69
|
+
|
|
60
70
|
export const processingSupport: QtiProcessingElementSupport[] = [
|
|
61
|
-
|
|
71
|
+
templateProcessingEntry(
|
|
62
72
|
"qti-template-processing",
|
|
63
|
-
"packages/core/src/core.test.ts",
|
|
64
73
|
[
|
|
65
74
|
"packages/fixtures/xml/template-processing-reference.xml",
|
|
66
75
|
"packages/fixtures/xml/random-integer-template-reference.xml",
|
|
@@ -68,9 +77,8 @@ export const processingSupport: QtiProcessingElementSupport[] = [
|
|
|
68
77
|
],
|
|
69
78
|
[...processingBrowserEvidence["qti-template-processing"]],
|
|
70
79
|
),
|
|
71
|
-
|
|
80
|
+
responseProcessingEntry(
|
|
72
81
|
"qti-response-processing",
|
|
73
|
-
"packages/core/src/core.test.ts",
|
|
74
82
|
[
|
|
75
83
|
"packages/fixtures/xml/mapping-processing-reference.xml",
|
|
76
84
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
@@ -79,64 +87,64 @@ export const processingSupport: QtiProcessingElementSupport[] = [
|
|
|
79
87
|
],
|
|
80
88
|
[...processingBrowserEvidence["qti-response-processing"]],
|
|
81
89
|
),
|
|
82
|
-
|
|
90
|
+
templateProcessingEntry("qti-set-template-value", [
|
|
83
91
|
"packages/fixtures/xml/template-processing-reference.xml",
|
|
84
92
|
"packages/fixtures/xml/random-integer-template-reference.xml",
|
|
85
93
|
"packages/fixtures/xml/template-content-reference.xml",
|
|
86
94
|
]),
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
templateProcessingEntry("qti-set-default-value"),
|
|
96
|
+
templateProcessingEntry("qti-set-correct-response", [
|
|
89
97
|
"packages/fixtures/xml/template-processing-reference.xml",
|
|
90
98
|
"packages/fixtures/xml/random-integer-template-reference.xml",
|
|
91
99
|
]),
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
templateProcessingEntry("qti-template-condition"),
|
|
101
|
+
templateProcessingEntry("qti-template-if"),
|
|
102
|
+
templateProcessingEntry("qti-template-else-if"),
|
|
103
|
+
templateProcessingEntry("qti-template-else"),
|
|
104
|
+
templateProcessingEntry("qti-template-constraint"),
|
|
105
|
+
responseProcessingEntry("qti-response-condition", [
|
|
98
106
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
99
107
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
100
108
|
"packages/fixtures/xml/adaptive-feedback-reference.xml",
|
|
101
109
|
]),
|
|
102
|
-
|
|
110
|
+
responseProcessingEntry("qti-response-if", [
|
|
103
111
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
104
112
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
105
113
|
"packages/fixtures/xml/adaptive-feedback-reference.xml",
|
|
106
114
|
]),
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
responseProcessingEntry("qti-response-else-if"),
|
|
116
|
+
responseProcessingEntry("qti-response-else", [
|
|
109
117
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
110
118
|
]),
|
|
111
|
-
|
|
119
|
+
responseProcessingEntry("qti-set-outcome-value", [
|
|
112
120
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
113
121
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
114
122
|
"packages/fixtures/xml/adaptive-feedback-reference.xml",
|
|
115
123
|
]),
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
mappingProcessingEntry("qti-lookup-outcome-value"),
|
|
125
|
+
responseProcessingEntry("qti-exit-response"),
|
|
126
|
+
templateProcessingEntry("qti-exit-template"),
|
|
127
|
+
responseProcessingEntry("qti-response-processing-fragment"),
|
|
128
|
+
operatorProcessingEntry("qti-base-value", [
|
|
121
129
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
122
130
|
"packages/fixtures/xml/template-processing-reference.xml",
|
|
123
131
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
124
132
|
]),
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
operatorProcessingEntry("qti-null"),
|
|
134
|
+
mappingProcessingEntry("qti-match-table"),
|
|
135
|
+
mappingProcessingEntry("qti-match-table-entry"),
|
|
136
|
+
mappingProcessingEntry("qti-interpolation-table"),
|
|
137
|
+
mappingProcessingEntry("qti-interpolation-table-entry"),
|
|
138
|
+
operatorProcessingEntry("qti-is-null"),
|
|
139
|
+
mappingProcessingEntry("qti-match", [
|
|
132
140
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
133
141
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
134
142
|
]),
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
mappingProcessingEntry("qti-correct"),
|
|
144
|
+
mappingProcessingEntry("qti-default"),
|
|
145
|
+
mappingProcessingEntry("qti-map-response"),
|
|
146
|
+
mappingProcessingEntry("qti-map-response-point"),
|
|
147
|
+
responseProcessingEntry("qti-variable", [
|
|
140
148
|
"packages/fixtures/xml/generic-match-processing-reference.xml",
|
|
141
149
|
"packages/fixtures/xml/template-processing-reference.xml",
|
|
142
150
|
"packages/fixtures/xml/random-integer-template-reference.xml",
|
|
@@ -144,81 +152,74 @@ export const processingSupport: QtiProcessingElementSupport[] = [
|
|
|
144
152
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
145
153
|
"packages/fixtures/xml/adaptive-feedback-reference.xml",
|
|
146
154
|
]),
|
|
147
|
-
|
|
155
|
+
templateProcessingEntry(
|
|
148
156
|
"qti-random-integer",
|
|
149
|
-
"packages/core/src/core.test.ts",
|
|
150
157
|
["packages/fixtures/xml/random-integer-template-reference.xml"],
|
|
151
158
|
[...processingBrowserEvidence["qti-random-integer"]],
|
|
152
159
|
),
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
operatorProcessingEntry("qti-random-float"),
|
|
161
|
+
operatorProcessingEntry("qti-random"),
|
|
162
|
+
operatorProcessingEntry("qti-multiple", [
|
|
156
163
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
157
164
|
]),
|
|
158
|
-
|
|
165
|
+
operatorProcessingEntry("qti-ordered", [
|
|
159
166
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
160
167
|
]),
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
operatorProcessingEntry("qti-index"),
|
|
169
|
+
operatorProcessingEntry("qti-contains"),
|
|
170
|
+
operatorProcessingEntry("qti-container-size", [
|
|
164
171
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
165
172
|
]),
|
|
166
|
-
|
|
173
|
+
operatorProcessingEntry("qti-sum", [
|
|
167
174
|
"packages/fixtures/xml/template-processing-reference.xml",
|
|
168
175
|
"packages/fixtures/xml/random-integer-template-reference.xml",
|
|
169
176
|
]),
|
|
170
|
-
|
|
177
|
+
operatorProcessingEntry("qti-product", [
|
|
171
178
|
"packages/fixtures/xml/random-integer-template-reference.xml",
|
|
172
179
|
]),
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
191
|
-
]),
|
|
192
|
-
processingEntry("qti-field-value", "packages/core/src/core.test.ts"),
|
|
193
|
-
processingEntry("qti-lt", "packages/core/src/core.test.ts"),
|
|
194
|
-
processingEntry("qti-lte", "packages/core/src/core.test.ts"),
|
|
195
|
-
processingEntry("qti-gt", "packages/core/src/core.test.ts"),
|
|
196
|
-
processingEntry("qti-gte", "packages/core/src/core.test.ts"),
|
|
197
|
-
processingEntry("qti-string-match", "packages/core/src/core.test.ts"),
|
|
198
|
-
processingEntry("qti-substring", "packages/core/src/core.test.ts"),
|
|
199
|
-
processingEntry("qti-pattern-match", "packages/core/src/core.test.ts"),
|
|
200
|
-
processingEntry("qti-member", "packages/core/src/core.test.ts"),
|
|
201
|
-
processingEntry("qti-delete", "packages/core/src/core.test.ts"),
|
|
202
|
-
processingEntry("qti-duration-gte", "packages/core/src/core.test.ts"),
|
|
203
|
-
processingEntry("qti-duration-lt", "packages/core/src/core.test.ts"),
|
|
204
|
-
processingEntry("qti-gcd", "packages/core/src/core.test.ts", [
|
|
205
|
-
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
206
|
-
]),
|
|
207
|
-
processingEntry("qti-inside", "packages/core/src/core.test.ts", [
|
|
180
|
+
operatorProcessingEntry("qti-min"),
|
|
181
|
+
operatorProcessingEntry("qti-max"),
|
|
182
|
+
operatorProcessingEntry("qti-subtract"),
|
|
183
|
+
operatorProcessingEntry("qti-divide"),
|
|
184
|
+
operatorProcessingEntry("qti-power"),
|
|
185
|
+
operatorProcessingEntry("qti-integer-divide"),
|
|
186
|
+
operatorProcessingEntry("qti-integer-modulus"),
|
|
187
|
+
operatorProcessingEntry("qti-round"),
|
|
188
|
+
operatorProcessingEntry("qti-round-to"),
|
|
189
|
+
operatorProcessingEntry("qti-truncate"),
|
|
190
|
+
operatorProcessingEntry("qti-integer-to-float"),
|
|
191
|
+
operatorProcessingEntry("qti-and"),
|
|
192
|
+
operatorProcessingEntry("qti-any-n"),
|
|
193
|
+
operatorProcessingEntry("qti-or"),
|
|
194
|
+
operatorProcessingEntry("qti-not"),
|
|
195
|
+
operatorProcessingEntry("qti-equal"),
|
|
196
|
+
operatorProcessingEntry("qti-equal-rounded", [
|
|
208
197
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
209
198
|
]),
|
|
210
|
-
|
|
199
|
+
mappingProcessingEntry("qti-field-value"),
|
|
200
|
+
operatorProcessingEntry("qti-lt"),
|
|
201
|
+
operatorProcessingEntry("qti-lte"),
|
|
202
|
+
operatorProcessingEntry("qti-gt"),
|
|
203
|
+
operatorProcessingEntry("qti-gte"),
|
|
204
|
+
operatorProcessingEntry("qti-string-match"),
|
|
205
|
+
operatorProcessingEntry("qti-substring"),
|
|
206
|
+
operatorProcessingEntry("qti-pattern-match"),
|
|
207
|
+
operatorProcessingEntry("qti-member"),
|
|
208
|
+
operatorProcessingEntry("qti-delete"),
|
|
209
|
+
operatorProcessingEntry("qti-duration-gte"),
|
|
210
|
+
operatorProcessingEntry("qti-duration-lt"),
|
|
211
|
+
operatorProcessingEntry("qti-gcd", ["packages/fixtures/xml/advanced-processing-reference.xml"]),
|
|
212
|
+
mappingProcessingEntry("qti-inside", ["packages/fixtures/xml/advanced-processing-reference.xml"]),
|
|
213
|
+
operatorProcessingEntry("qti-lcm", ["packages/fixtures/xml/advanced-processing-reference.xml"]),
|
|
214
|
+
operatorProcessingEntry("qti-math-constant"),
|
|
215
|
+
operatorProcessingEntry("qti-math-operator"),
|
|
216
|
+
operatorProcessingEntry("qti-repeat", [
|
|
211
217
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
212
218
|
]),
|
|
213
|
-
|
|
214
|
-
processingEntry("qti-math-operator", "packages/core/src/core.test.ts"),
|
|
215
|
-
processingEntry("qti-repeat", "packages/core/src/core.test.ts", [
|
|
219
|
+
operatorProcessingEntry("qti-stats-operator", [
|
|
216
220
|
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
217
221
|
]),
|
|
218
|
-
|
|
219
|
-
"packages/fixtures/xml/advanced-processing-reference.xml",
|
|
220
|
-
]),
|
|
221
|
-
processingEntry("qti-custom-operator", "packages/core/src/core.test.ts"),
|
|
222
|
+
operatorProcessingEntry("qti-custom-operator"),
|
|
222
223
|
];
|
|
223
224
|
|
|
224
225
|
export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
|
|
@@ -234,11 +235,7 @@ export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
|
|
|
234
235
|
fixtures: [
|
|
235
236
|
"packages/fixtures/packages/basic-item-player/valid-item-only/items/tolerance-extra-features.xml",
|
|
236
237
|
],
|
|
237
|
-
tests: [
|
|
238
|
-
"packages/core/src/core.test.ts",
|
|
239
|
-
"packages/core/src/parser-item-metadata.test.ts",
|
|
240
|
-
...browserHarnessTests,
|
|
241
|
-
],
|
|
238
|
+
tests: ["packages/core/src/parser-item-metadata.test.ts", ...browserHarnessTests],
|
|
242
239
|
notes:
|
|
243
240
|
"Parsed by parser-item-metadata.ts and validated by validateCatalogInfo. Duplicate containers emit item.child.duplicate. Manual harness debugger coverage is in player-harness.spec.ts.",
|
|
244
241
|
},
|
|
@@ -255,7 +252,6 @@ export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
|
|
|
255
252
|
"packages/fixtures/packages/basic-item-player/valid-item-only/items/tolerance-extra-features.xml",
|
|
256
253
|
],
|
|
257
254
|
tests: [
|
|
258
|
-
"packages/core/src/core.test.ts",
|
|
259
255
|
"packages/core/src/parser-item-metadata.test.ts",
|
|
260
256
|
"tests/browser/player-package.spec.ts",
|
|
261
257
|
...browserHarnessTests,
|
|
@@ -266,20 +262,20 @@ export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
|
|
|
266
262
|
{
|
|
267
263
|
qtiName: "qti-modal-feedback",
|
|
268
264
|
category: "itemMetadata",
|
|
269
|
-
support: "
|
|
265
|
+
support: "rendered",
|
|
270
266
|
specReference: "QTI 3.0.1 ASI",
|
|
271
267
|
parse: true,
|
|
272
268
|
validate: true,
|
|
273
|
-
render:
|
|
274
|
-
process:
|
|
269
|
+
render: true,
|
|
270
|
+
process: true,
|
|
275
271
|
fixtures: ["packages/fixtures/src/index.ts"],
|
|
276
272
|
tests: [
|
|
277
|
-
|
|
273
|
+
processingResponseTest,
|
|
278
274
|
"packages/core/src/parser-item-metadata.test.ts",
|
|
279
275
|
...browserFeedbackTests,
|
|
280
276
|
],
|
|
281
277
|
notes:
|
|
282
|
-
"Parsed by parser-item-metadata.ts and validated by validateModalFeedback.
|
|
278
|
+
"Parsed by parser-item-metadata.ts and validated by validateModalFeedback. Response processing supplies the outcome value used for visibility, and the player renders the matching feedback in player-feedback.spec.ts.",
|
|
283
279
|
},
|
|
284
280
|
{
|
|
285
281
|
qtiName: "qti-companion-materials-info",
|
|
@@ -430,9 +426,17 @@ function pciEntry(): QtiInteractionElementSupport {
|
|
|
430
426
|
};
|
|
431
427
|
}
|
|
432
428
|
|
|
429
|
+
function processingEntryFor(coreTest: string) {
|
|
430
|
+
return (
|
|
431
|
+
qtiName: string,
|
|
432
|
+
fixtures: string[] = [],
|
|
433
|
+
extraTests: string[] = [],
|
|
434
|
+
): QtiProcessingElementSupport => processingEntry(coreTest, qtiName, fixtures, extraTests);
|
|
435
|
+
}
|
|
436
|
+
|
|
433
437
|
function processingEntry(
|
|
438
|
+
coreTest: string,
|
|
434
439
|
qtiName: string,
|
|
435
|
-
test: string,
|
|
436
440
|
fixtures: string[] = [],
|
|
437
441
|
extraTests: string[] = [],
|
|
438
442
|
): QtiProcessingElementSupport {
|
|
@@ -446,6 +450,6 @@ function processingEntry(
|
|
|
446
450
|
render: false,
|
|
447
451
|
process: true,
|
|
448
452
|
fixtures,
|
|
449
|
-
tests: [
|
|
453
|
+
tests: [coreTest, ...extraTests],
|
|
450
454
|
};
|
|
451
455
|
}
|
package/src/types.ts
CHANGED
|
@@ -687,7 +687,14 @@ export type QtiProcessingExpression = (
|
|
|
687
687
|
| { type: "mathConstant"; name: string }
|
|
688
688
|
| { type: "mathOperator"; name: string; expressions: QtiProcessingExpression[] }
|
|
689
689
|
| { type: "repeat"; numberRepeats: string; expressions: QtiProcessingExpression[] }
|
|
690
|
-
| {
|
|
690
|
+
| {
|
|
691
|
+
type: "statsOperator";
|
|
692
|
+
name: string;
|
|
693
|
+
/** First child retained for compatibility with manually constructed expressions. */
|
|
694
|
+
expression: QtiProcessingExpression;
|
|
695
|
+
/** Authored children, including invalid zero- or multi-child forms, when parsed from XML. */
|
|
696
|
+
expressions?: QtiProcessingExpression[] | undefined;
|
|
697
|
+
}
|
|
691
698
|
| {
|
|
692
699
|
type: "customOperator";
|
|
693
700
|
definition?: string | undefined;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { QtiDiagnostic, QtiLookupTable } from "./types.js";
|
|
2
|
+
import {
|
|
3
|
+
hasValidShapeCoordinateCount,
|
|
4
|
+
isAreaShape,
|
|
5
|
+
isNumericCsv,
|
|
6
|
+
numericCsv,
|
|
7
|
+
} from "./validation-geometry.js";
|
|
8
|
+
import { isFiniteNumber, isInteger } from "./validation-primitives.js";
|
|
9
|
+
|
|
10
|
+
interface DeclarationEntryAttributes {
|
|
11
|
+
attributes: Record<string, string>;
|
|
12
|
+
source?: QtiDiagnostic["source"] | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Append diagnostics for raw qti-map-entry attributes. */
|
|
16
|
+
export function validateMapEntryAttributes(
|
|
17
|
+
declarationIdentifier: string,
|
|
18
|
+
entry: DeclarationEntryAttributes,
|
|
19
|
+
diagnostics: QtiDiagnostic[],
|
|
20
|
+
): void {
|
|
21
|
+
if (!entry.attributes["map-key"]) {
|
|
22
|
+
diagnostics.push({
|
|
23
|
+
code: "mapEntry.mapKey.required",
|
|
24
|
+
severity: "error",
|
|
25
|
+
message: `Response declaration ${declarationIdentifier} map entry requires map-key.`,
|
|
26
|
+
path: entry.source?.path,
|
|
27
|
+
source: entry.source,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const mappedValue = entry.attributes["mapped-value"];
|
|
32
|
+
if (mappedValue === undefined) {
|
|
33
|
+
diagnostics.push({
|
|
34
|
+
code: "mapEntry.mappedValue.required",
|
|
35
|
+
severity: "error",
|
|
36
|
+
message: `Response declaration ${declarationIdentifier} map entry requires mapped-value.`,
|
|
37
|
+
path: entry.source?.path,
|
|
38
|
+
source: entry.source,
|
|
39
|
+
});
|
|
40
|
+
} else if (!isFiniteNumber(mappedValue)) {
|
|
41
|
+
diagnostics.push({
|
|
42
|
+
code: "mapEntry.mappedValue",
|
|
43
|
+
severity: "error",
|
|
44
|
+
message: `Response declaration ${declarationIdentifier} map entry requires numeric mapped-value.`,
|
|
45
|
+
path: entry.source?.path,
|
|
46
|
+
source: entry.source,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Append diagnostics for raw qti-area-map-entry attributes. */
|
|
52
|
+
export function validateAreaMapEntryAttributes(
|
|
53
|
+
declarationIdentifier: string,
|
|
54
|
+
entry: DeclarationEntryAttributes,
|
|
55
|
+
diagnostics: QtiDiagnostic[],
|
|
56
|
+
): void {
|
|
57
|
+
const shape = entry.attributes.shape;
|
|
58
|
+
const coords = entry.attributes.coords;
|
|
59
|
+
const mappedValue = entry.attributes["mapped-value"];
|
|
60
|
+
|
|
61
|
+
if (!shape) {
|
|
62
|
+
diagnostics.push({
|
|
63
|
+
code: "areaMapEntry.shape.required",
|
|
64
|
+
severity: "error",
|
|
65
|
+
message: `Response declaration ${declarationIdentifier} area map entry requires shape.`,
|
|
66
|
+
path: entry.source?.path,
|
|
67
|
+
source: entry.source,
|
|
68
|
+
});
|
|
69
|
+
} else if (!isAreaShape(shape)) {
|
|
70
|
+
diagnostics.push({
|
|
71
|
+
code: "areaMapEntry.shape",
|
|
72
|
+
severity: "error",
|
|
73
|
+
message: `Response declaration ${declarationIdentifier} area map entry has unsupported shape ${shape}.`,
|
|
74
|
+
path: entry.source?.path,
|
|
75
|
+
source: entry.source,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!coords) {
|
|
80
|
+
diagnostics.push({
|
|
81
|
+
code: "areaMapEntry.coords.required",
|
|
82
|
+
severity: "error",
|
|
83
|
+
message: `Response declaration ${declarationIdentifier} area map entry requires coords.`,
|
|
84
|
+
path: entry.source?.path,
|
|
85
|
+
source: entry.source,
|
|
86
|
+
});
|
|
87
|
+
} else if (!isNumericCsv(coords)) {
|
|
88
|
+
diagnostics.push({
|
|
89
|
+
code: "areaMapEntry.coords",
|
|
90
|
+
severity: "error",
|
|
91
|
+
message: `Response declaration ${declarationIdentifier} area map entry requires comma-separated numeric coords.`,
|
|
92
|
+
path: entry.source?.path,
|
|
93
|
+
source: entry.source,
|
|
94
|
+
});
|
|
95
|
+
} else if (
|
|
96
|
+
shape &&
|
|
97
|
+
isAreaShape(shape) &&
|
|
98
|
+
!hasValidShapeCoordinateCount(shape, numericCsv(coords))
|
|
99
|
+
) {
|
|
100
|
+
diagnostics.push({
|
|
101
|
+
code: "areaMapEntry.coords.shape",
|
|
102
|
+
severity: "error",
|
|
103
|
+
message: `Response declaration ${declarationIdentifier} area map entry shape ${shape} has invalid coords arity.`,
|
|
104
|
+
path: entry.source?.path,
|
|
105
|
+
source: entry.source,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (mappedValue === undefined) {
|
|
110
|
+
diagnostics.push({
|
|
111
|
+
code: "areaMapEntry.mappedValue.required",
|
|
112
|
+
severity: "error",
|
|
113
|
+
message: `Response declaration ${declarationIdentifier} area map entry requires mapped-value.`,
|
|
114
|
+
path: entry.source?.path,
|
|
115
|
+
source: entry.source,
|
|
116
|
+
});
|
|
117
|
+
} else if (!isFiniteNumber(mappedValue)) {
|
|
118
|
+
diagnostics.push({
|
|
119
|
+
code: "areaMapEntry.mappedValue",
|
|
120
|
+
severity: "error",
|
|
121
|
+
message: `Response declaration ${declarationIdentifier} area map entry requires numeric mapped-value.`,
|
|
122
|
+
path: entry.source?.path,
|
|
123
|
+
source: entry.source,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Append diagnostics for raw lookup-table entry attributes. */
|
|
129
|
+
export function validateLookupTableEntryAttributes(
|
|
130
|
+
tableType: QtiLookupTable["type"],
|
|
131
|
+
entry: DeclarationEntryAttributes,
|
|
132
|
+
diagnostics: QtiDiagnostic[],
|
|
133
|
+
): void {
|
|
134
|
+
const sourceValue = entry.attributes["source-value"];
|
|
135
|
+
if (sourceValue === undefined || !isFiniteNumber(sourceValue)) {
|
|
136
|
+
diagnostics.push({
|
|
137
|
+
code: "lookupTable.entry.sourceValue",
|
|
138
|
+
severity: "error",
|
|
139
|
+
message: "Lookup table entry requires numeric source-value.",
|
|
140
|
+
path: entry.source?.path,
|
|
141
|
+
source: entry.source,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (entry.attributes["target-value"] === undefined) {
|
|
145
|
+
diagnostics.push({
|
|
146
|
+
code: "lookupTable.entry.targetValue",
|
|
147
|
+
severity: "error",
|
|
148
|
+
message: "Lookup table entry requires target-value.",
|
|
149
|
+
path: entry.source?.path,
|
|
150
|
+
source: entry.source,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (tableType === "match" && sourceValue !== undefined && !isInteger(sourceValue)) {
|
|
154
|
+
diagnostics.push({
|
|
155
|
+
code: "lookupTable.match.sourceValue",
|
|
156
|
+
severity: "error",
|
|
157
|
+
message: "qti-match-table-entry source-value must be an integer.",
|
|
158
|
+
path: entry.source?.path,
|
|
159
|
+
source: entry.source,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -9,6 +9,8 @@ import type {
|
|
|
9
9
|
} from "./types.js";
|
|
10
10
|
import { assertNever } from "./assert-never.js";
|
|
11
11
|
import { isValidQtiPatternMask } from "./pattern-mask.js";
|
|
12
|
+
import { parseQtiMediaDefinition } from "./media-definition.js";
|
|
13
|
+
import { parseQtiSliderDefinition } from "./slider-definition.js";
|
|
12
14
|
import { validateInteractionSharedVocabulary } from "./shared-vocabulary-interaction-validation.js";
|
|
13
15
|
import { qtiValueToStringList } from "./value-format.js";
|
|
14
16
|
import {
|
|
@@ -17,7 +19,6 @@ import {
|
|
|
17
19
|
} from "./validation-geometry.js";
|
|
18
20
|
import {
|
|
19
21
|
isBooleanAttribute,
|
|
20
|
-
isFiniteNumber,
|
|
21
22
|
isNonNegativeInteger,
|
|
22
23
|
requireIdentifier,
|
|
23
24
|
} from "./validation-primitives.js";
|
|
@@ -104,7 +105,11 @@ function validateInteractionResponseShape(
|
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
if (
|
|
108
|
+
if (
|
|
109
|
+
interaction.type !== "slider" &&
|
|
110
|
+
interaction.responseBaseType &&
|
|
111
|
+
!expected.baseTypes.includes(interaction.responseBaseType)
|
|
112
|
+
) {
|
|
108
113
|
diagnostics.push({
|
|
109
114
|
code: "interaction.baseType",
|
|
110
115
|
severity: "error",
|
|
@@ -305,46 +310,13 @@ function validateInteractionRequiredAttributes(
|
|
|
305
310
|
}
|
|
306
311
|
|
|
307
312
|
if (interaction.type === "slider") {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
);
|
|
316
|
-
requireInteractionAttribute(
|
|
317
|
-
interaction,
|
|
318
|
-
"upper-bound",
|
|
319
|
-
"interaction.slider.upperBound",
|
|
320
|
-
diagnostics,
|
|
321
|
-
);
|
|
322
|
-
if (lower !== undefined && !isFiniteNumber(lower)) {
|
|
323
|
-
invalidNumber(interaction, "lower-bound", lower, diagnostics);
|
|
324
|
-
}
|
|
325
|
-
if (upper !== undefined && !isFiniteNumber(upper)) {
|
|
326
|
-
invalidNumber(interaction, "upper-bound", upper, diagnostics);
|
|
327
|
-
}
|
|
328
|
-
if (
|
|
329
|
-
lower !== undefined &&
|
|
330
|
-
upper !== undefined &&
|
|
331
|
-
isFiniteNumber(lower) &&
|
|
332
|
-
isFiniteNumber(upper)
|
|
333
|
-
) {
|
|
334
|
-
if (Number(lower) >= Number(upper)) {
|
|
335
|
-
diagnostics.push({
|
|
336
|
-
code: "interaction.slider.bounds",
|
|
337
|
-
severity: "error",
|
|
338
|
-
message: `${interaction.qtiName} requires lower-bound to be less than upper-bound.`,
|
|
339
|
-
path: interaction.source?.path,
|
|
340
|
-
source: interaction.source,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
const step = interaction.attributes.step;
|
|
345
|
-
if (step !== undefined && (!isFiniteNumber(step) || Number(step) <= 0)) {
|
|
346
|
-
invalidNumber(interaction, "step", step, diagnostics);
|
|
347
|
-
}
|
|
313
|
+
const definition = parseQtiSliderDefinition(interaction);
|
|
314
|
+
if (!definition.ok) diagnostics.push(...definition.diagnostics);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (interaction.type === "media") {
|
|
318
|
+
const definition = parseQtiMediaDefinition(interaction);
|
|
319
|
+
if (!definition.ok) diagnostics.push(...definition.diagnostics);
|
|
348
320
|
}
|
|
349
321
|
}
|
|
350
322
|
|
|
@@ -497,21 +469,6 @@ function warnExternalPortableCustomUrl(
|
|
|
497
469
|
});
|
|
498
470
|
}
|
|
499
471
|
|
|
500
|
-
function invalidNumber(
|
|
501
|
-
interaction: QtiInteraction,
|
|
502
|
-
attribute: string,
|
|
503
|
-
value: string,
|
|
504
|
-
diagnostics: QtiDiagnostic[],
|
|
505
|
-
): void {
|
|
506
|
-
diagnostics.push({
|
|
507
|
-
code: "interaction.numericAttribute",
|
|
508
|
-
severity: "error",
|
|
509
|
-
message: `${interaction.qtiName} requires numeric ${attribute}, got ${value}.`,
|
|
510
|
-
path: interaction.source?.path,
|
|
511
|
-
source: interaction.source,
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
|
|
515
472
|
function validatePatternMaskAttribute(
|
|
516
473
|
interaction: QtiInteraction,
|
|
517
474
|
diagnostics: QtiDiagnostic[],
|
|
@@ -542,13 +499,6 @@ function validateInteractionLimitAttributes(
|
|
|
542
499
|
validateMinMaxPair(interaction, "min-choices", "max-choices", diagnostics);
|
|
543
500
|
validateMinMaxPair(interaction, "min-associations", "max-associations", diagnostics);
|
|
544
501
|
validateBooleanAttribute(interaction, "required", diagnostics);
|
|
545
|
-
if (interaction.type === "media") {
|
|
546
|
-
validateNonNegativeIntegerAttribute(interaction, "max-plays", diagnostics);
|
|
547
|
-
validateNonNegativeIntegerAttribute(interaction, "min-plays", diagnostics);
|
|
548
|
-
validateBooleanAttribute(interaction, "autostart", diagnostics);
|
|
549
|
-
validateBooleanAttribute(interaction, "loop", diagnostics);
|
|
550
|
-
validateMinMaxPair(interaction, "min-plays", "max-plays", diagnostics);
|
|
551
|
-
}
|
|
552
502
|
}
|
|
553
503
|
|
|
554
504
|
function validateChoiceLimitAttributes(choice: QtiChoice, diagnostics: QtiDiagnostic[]): void {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { QtiBaseType, QtiCardinality, QtiDiagnostic } from "./types.js";
|
|
2
|
-
import { parseXmlBoolean } from "./parser-values.js";
|
|
2
|
+
import { parseFiniteNumber, parseXmlBoolean } from "./parser-values.js";
|
|
3
3
|
|
|
4
4
|
export function requireIdentifier(
|
|
5
5
|
qtiName: string,
|
|
@@ -38,7 +38,7 @@ export function isBaseType(value: string): value is QtiBaseType {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export function isFiniteNumber(value: string): boolean {
|
|
41
|
-
return
|
|
41
|
+
return parseFiniteNumber(value) !== undefined;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export function isInteger(value: string): boolean {
|