@conform-ed/qti-react 0.0.13 → 0.0.14
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/capability.d.ts +17 -0
- package/dist/content-model.d.ts +42 -0
- package/dist/graphic.d.ts +23 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +149 -159
- package/dist/interactions/associate.d.ts +2 -0
- package/dist/interactions/choice.d.ts +2 -0
- package/dist/interactions/drawing.d.ts +2 -0
- package/dist/interactions/end-attempt.d.ts +2 -0
- package/dist/interactions/extended-text.d.ts +2 -0
- package/dist/interactions/gap-match.d.ts +2 -0
- package/dist/interactions/graphic.d.ts +13 -0
- package/dist/interactions/hottext.d.ts +2 -0
- package/dist/interactions/index.d.ts +18 -0
- package/dist/interactions/inline-choice.d.ts +2 -0
- package/dist/interactions/match.d.ts +2 -0
- package/dist/interactions/media.d.ts +2 -0
- package/dist/interactions/order.d.ts +2 -0
- package/dist/interactions/slider.d.ts +2 -0
- package/dist/interactions/text-entry.d.ts +2 -0
- package/dist/interactions/upload.d.ts +2 -0
- package/dist/normalized-item.d.ts +30 -0
- package/dist/pci/index.d.ts +6 -0
- package/dist/pci/interaction.d.ts +8 -0
- package/dist/pci/markup.d.ts +10 -0
- package/dist/pci/mount.d.ts +50 -0
- package/dist/pci/registry.d.ts +53 -0
- package/dist/pci/response.d.ts +11 -0
- package/dist/pci/skin.d.ts +12 -0
- package/dist/reference-skin/associate.d.ts +8 -0
- package/dist/reference-skin/choice.d.ts +8 -0
- package/dist/reference-skin/content.d.ts +6 -0
- package/dist/reference-skin/drawing.d.ts +9 -0
- package/dist/reference-skin/end-attempt.d.ts +7 -0
- package/dist/reference-skin/extended-text.d.ts +6 -0
- package/dist/reference-skin/gap-match.d.ts +8 -0
- package/dist/reference-skin/graphic-associate.d.ts +8 -0
- package/dist/reference-skin/graphic-base.d.ts +39 -0
- package/dist/reference-skin/graphic-gap-match.d.ts +8 -0
- package/dist/reference-skin/graphic-order.d.ts +8 -0
- package/dist/reference-skin/hotspot.d.ts +8 -0
- package/dist/reference-skin/hottext.d.ts +8 -0
- package/dist/reference-skin/index.d.ts +30 -0
- package/dist/reference-skin/inline-choice.d.ts +7 -0
- package/dist/reference-skin/match.d.ts +8 -0
- package/dist/reference-skin/media.d.ts +9 -0
- package/dist/reference-skin/order.d.ts +8 -0
- package/dist/reference-skin/position-object.d.ts +9 -0
- package/dist/reference-skin/select-point.d.ts +8 -0
- package/dist/reference-skin/slider.d.ts +8 -0
- package/dist/reference-skin/text-entry.d.ts +6 -0
- package/dist/reference-skin/upload.d.ts +8 -0
- package/dist/response-processing.d.ts +48 -0
- package/dist/rp/evaluate.d.ts +35 -0
- package/dist/rp/index.d.ts +4 -0
- package/dist/rp/interpreter.d.ts +15 -0
- package/dist/rp/template-processing.d.ts +49 -0
- package/dist/rp/templates.d.ts +8 -0
- package/dist/rp/types.d.ts +158 -0
- package/dist/rp/values.d.ts +27 -0
- package/dist/runtime.d.ts +164 -0
- package/dist/store.d.ts +61 -0
- package/dist/test/controller.d.ts +11 -0
- package/dist/test/index.d.ts +3 -0
- package/dist/test/session-store.d.ts +46 -0
- package/dist/test/types.d.ts +194 -0
- package/dist/types.d.ts +58 -0
- package/package.json +6 -6
- package/src/interactions/associate.ts +2 -2
- package/src/interactions/choice.ts +2 -2
- package/src/interactions/drawing.ts +2 -2
- package/src/interactions/end-attempt.ts +2 -2
- package/src/interactions/extended-text.ts +2 -2
- package/src/interactions/gap-match.ts +2 -2
- package/src/interactions/graphic.ts +7 -7
- package/src/interactions/hottext.ts +2 -2
- package/src/interactions/index.ts +0 -1
- package/src/interactions/inline-choice.ts +2 -2
- package/src/interactions/match.ts +2 -2
- package/src/interactions/media.ts +2 -2
- package/src/interactions/order.ts +2 -2
- package/src/interactions/slider.ts +2 -2
- package/src/interactions/text-entry.ts +2 -2
- package/src/interactions/upload.ts +2 -2
- package/src/normalized-item.ts +6 -4
- package/src/pci/interaction.ts +2 -2
- package/src/pci/mount.ts +1 -2
- package/src/pci/skin.ts +0 -1
- package/src/reference-skin/drawing.ts +25 -15
- package/src/reference-skin/index.ts +2 -3
- package/src/rp/evaluate.ts +22 -23
- package/src/rp/interpreter.ts +9 -6
- package/src/rp/template-processing.ts +8 -13
- package/src/rp/types.ts +12 -6
- package/src/rp/values.ts +19 -6
- package/src/runtime.ts +9 -7
- package/src/store.ts +14 -8
- package/src/test/controller.ts +10 -7
- package/src/test/session-store.ts +0 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural views of QTI 3 `assessmentTest` and the Test Controller's session state
|
|
3
|
+
* (ADR-0005). The controller owns the rules; everything in `TestSessionState` is plain
|
|
4
|
+
* JSON so the consumer owns persistence — store the seed and the state, replay the
|
|
5
|
+
* test.
|
|
6
|
+
*/
|
|
7
|
+
import type { CapabilityIssue } from "../capability";
|
|
8
|
+
import type { OutcomeDeclarationView, OutcomeValue, RpExpressionView } from "../rp";
|
|
9
|
+
import type { BodyNode } from "../runtime";
|
|
10
|
+
export interface BranchRuleView {
|
|
11
|
+
/** A target identifier in the same test part, or EXIT_TEST / EXIT_TESTPART / EXIT_SECTION. */
|
|
12
|
+
readonly target: string;
|
|
13
|
+
readonly expression: RpExpressionView;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* QTI `itemSessionControl`: per-level overrides cascading testPart → section → itemRef.
|
|
17
|
+
* The controller enforces `maxAttempts` and `allowSkipping`; the rest is surfaced for
|
|
18
|
+
* delivery chrome (review/solution/comment affordances are UI concerns).
|
|
19
|
+
*/
|
|
20
|
+
export interface ItemSessionControlView {
|
|
21
|
+
/** Attempts allowed per item; 0 means unlimited. Spec default: 1. */
|
|
22
|
+
readonly maxAttempts?: number;
|
|
23
|
+
readonly showFeedback?: boolean;
|
|
24
|
+
readonly allowReview?: boolean;
|
|
25
|
+
readonly showSolution?: boolean;
|
|
26
|
+
readonly allowComment?: boolean;
|
|
27
|
+
/** When false, the candidate must attempt the item before moving past it. */
|
|
28
|
+
readonly allowSkipping?: boolean;
|
|
29
|
+
readonly validateResponses?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* QTI `timeLimits` (seconds). The controller is clock-free by design (ADR-0005): these
|
|
33
|
+
* are data for the consumer's timers, which call `next()`/`end()` when time runs out.
|
|
34
|
+
*/
|
|
35
|
+
export interface TimeLimitsView {
|
|
36
|
+
readonly minTime?: number;
|
|
37
|
+
readonly maxTime?: number;
|
|
38
|
+
readonly allowLateSubmission?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface AssessmentItemRefView {
|
|
41
|
+
readonly kind: "assessmentItemRef";
|
|
42
|
+
readonly identifier: string;
|
|
43
|
+
readonly href?: string;
|
|
44
|
+
readonly categories?: readonly string[];
|
|
45
|
+
readonly fixed?: boolean;
|
|
46
|
+
readonly required?: boolean;
|
|
47
|
+
readonly preConditions?: readonly RpExpressionView[];
|
|
48
|
+
readonly branchRules?: readonly BranchRuleView[];
|
|
49
|
+
readonly itemSessionControl?: ItemSessionControlView;
|
|
50
|
+
readonly timeLimits?: TimeLimitsView;
|
|
51
|
+
/** Named weights for `testVariables`/aggregate weighting (missing names weigh 1). */
|
|
52
|
+
readonly weights?: ReadonlyArray<{
|
|
53
|
+
readonly identifier: string;
|
|
54
|
+
readonly value: number;
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
export interface AssessmentSectionView {
|
|
58
|
+
readonly kind: "assessmentSection";
|
|
59
|
+
readonly identifier: string;
|
|
60
|
+
readonly title?: string;
|
|
61
|
+
readonly visible?: boolean;
|
|
62
|
+
readonly fixed?: boolean;
|
|
63
|
+
readonly required?: boolean;
|
|
64
|
+
readonly selection?: {
|
|
65
|
+
readonly select: number;
|
|
66
|
+
readonly withReplacement?: boolean;
|
|
67
|
+
};
|
|
68
|
+
readonly ordering?: {
|
|
69
|
+
readonly shuffle?: boolean;
|
|
70
|
+
};
|
|
71
|
+
readonly preConditions?: readonly RpExpressionView[];
|
|
72
|
+
readonly branchRules?: readonly BranchRuleView[];
|
|
73
|
+
readonly itemSessionControl?: ItemSessionControlView;
|
|
74
|
+
readonly timeLimits?: TimeLimitsView;
|
|
75
|
+
readonly children: ReadonlyArray<AssessmentSectionView | AssessmentItemRefView>;
|
|
76
|
+
}
|
|
77
|
+
export interface TestPartView {
|
|
78
|
+
readonly identifier: string;
|
|
79
|
+
readonly navigationMode: "linear" | "nonlinear";
|
|
80
|
+
readonly submissionMode: "individual" | "simultaneous";
|
|
81
|
+
readonly preConditions?: readonly RpExpressionView[];
|
|
82
|
+
readonly branchRules?: readonly BranchRuleView[];
|
|
83
|
+
readonly itemSessionControl?: ItemSessionControlView;
|
|
84
|
+
readonly timeLimits?: TimeLimitsView;
|
|
85
|
+
readonly assessmentSections: readonly AssessmentSectionView[];
|
|
86
|
+
}
|
|
87
|
+
export interface TestFeedbackView {
|
|
88
|
+
readonly access?: "atEnd" | "during";
|
|
89
|
+
readonly outcomeIdentifier: string;
|
|
90
|
+
readonly identifier: string;
|
|
91
|
+
readonly showHide?: "show" | "hide";
|
|
92
|
+
readonly content?: readonly BodyNode[];
|
|
93
|
+
}
|
|
94
|
+
export interface OutcomeConditionBranch {
|
|
95
|
+
readonly expression: RpExpressionView;
|
|
96
|
+
readonly rules: readonly OutcomeRuleView[];
|
|
97
|
+
}
|
|
98
|
+
/** One outcome rule: outcomeCondition, setOutcomeValue, or exitTest. */
|
|
99
|
+
export interface OutcomeRuleView {
|
|
100
|
+
readonly kind: string;
|
|
101
|
+
readonly identifier?: string;
|
|
102
|
+
readonly expression?: RpExpressionView;
|
|
103
|
+
readonly outcomeIf?: OutcomeConditionBranch;
|
|
104
|
+
readonly outcomeElseIfs?: readonly OutcomeConditionBranch[];
|
|
105
|
+
readonly outcomeElse?: {
|
|
106
|
+
readonly rules: readonly OutcomeRuleView[];
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export interface AssessmentTestView {
|
|
110
|
+
readonly identifier: string;
|
|
111
|
+
readonly title?: string;
|
|
112
|
+
readonly outcomeDeclarations?: readonly OutcomeDeclarationView[];
|
|
113
|
+
readonly timeLimits?: TimeLimitsView;
|
|
114
|
+
readonly testParts: readonly TestPartView[];
|
|
115
|
+
readonly outcomeProcessing?: {
|
|
116
|
+
readonly rules: readonly OutcomeRuleView[];
|
|
117
|
+
};
|
|
118
|
+
readonly testFeedbacks?: readonly TestFeedbackView[];
|
|
119
|
+
}
|
|
120
|
+
export interface TestPlanItem {
|
|
121
|
+
/** The item ref identifier — unique within the test, used as the session key. */
|
|
122
|
+
readonly key: string;
|
|
123
|
+
readonly ref: AssessmentItemRefView;
|
|
124
|
+
readonly partIdentifier: string;
|
|
125
|
+
readonly sectionPath: readonly string[];
|
|
126
|
+
/** The item's own preconditions plus its ancestor sections' (all must pass). */
|
|
127
|
+
readonly preConditions: readonly RpExpressionView[];
|
|
128
|
+
/** Effective session control: part → section → itemRef cascade over spec defaults. */
|
|
129
|
+
readonly sessionControl: Required<ItemSessionControlView>;
|
|
130
|
+
/** The item ref's own time limits (part/test limits live on their own levels). */
|
|
131
|
+
readonly timeLimits?: TimeLimitsView;
|
|
132
|
+
}
|
|
133
|
+
export interface TestPlanPart {
|
|
134
|
+
readonly identifier: string;
|
|
135
|
+
readonly navigationMode: "linear" | "nonlinear";
|
|
136
|
+
readonly submissionMode: "individual" | "simultaneous";
|
|
137
|
+
readonly timeLimits?: TimeLimitsView;
|
|
138
|
+
readonly items: readonly TestPlanItem[];
|
|
139
|
+
}
|
|
140
|
+
export interface TestPlan {
|
|
141
|
+
readonly timeLimits?: TimeLimitsView;
|
|
142
|
+
readonly parts: readonly TestPlanPart[];
|
|
143
|
+
}
|
|
144
|
+
export interface TestItemResult {
|
|
145
|
+
readonly outcomes: Readonly<Record<string, OutcomeValue>>;
|
|
146
|
+
/**
|
|
147
|
+
* Whether every scorable response variable matched (feeds numberCorrect /
|
|
148
|
+
* numberIncorrect). Omit when the item has nothing to be correct about.
|
|
149
|
+
*/
|
|
150
|
+
readonly correct?: boolean;
|
|
151
|
+
/** The candidate gave at least one non-empty response (feeds numberResponded). */
|
|
152
|
+
readonly responded?: boolean;
|
|
153
|
+
/** Adaptive items manage their own attempt lifecycle, so maxAttempts is ignored (spec). */
|
|
154
|
+
readonly adaptive?: boolean;
|
|
155
|
+
}
|
|
156
|
+
export interface TestSessionState {
|
|
157
|
+
readonly status: "in-progress" | "ended";
|
|
158
|
+
readonly currentItemKey: string | null;
|
|
159
|
+
readonly itemOutcomes: Readonly<Record<string, Readonly<Record<string, OutcomeValue>>>>;
|
|
160
|
+
readonly attemptedItems: readonly string[];
|
|
161
|
+
readonly attemptCounts: Readonly<Record<string, number>>;
|
|
162
|
+
/** Items that have been the current item at least once (feeds numberPresented). */
|
|
163
|
+
readonly presentedItems: readonly string[];
|
|
164
|
+
/** Items whose latest attempt carried a response (feeds numberResponded). */
|
|
165
|
+
readonly respondedItems: readonly string[];
|
|
166
|
+
/** Items whose latest attempt was correct / incorrect (feeds numberCorrect/Incorrect). */
|
|
167
|
+
readonly correctItems: readonly string[];
|
|
168
|
+
readonly incorrectItems: readonly string[];
|
|
169
|
+
/**
|
|
170
|
+
* Results held back in simultaneous-submission parts (QTI: the part's responses are
|
|
171
|
+
* submitted together). They commit when the part is left or the test ends; until
|
|
172
|
+
* then they are invisible to outcome processing and feedback.
|
|
173
|
+
*/
|
|
174
|
+
readonly pendingItemResults: Readonly<Record<string, TestItemResult>>;
|
|
175
|
+
readonly testOutcomes: Readonly<Record<string, OutcomeValue>>;
|
|
176
|
+
}
|
|
177
|
+
export interface TestController {
|
|
178
|
+
readonly plan: TestPlan;
|
|
179
|
+
/** Static capability issues found in outcome processing, preconditions, and branch rules. */
|
|
180
|
+
readonly issues: readonly CapabilityIssue[];
|
|
181
|
+
readonly start: () => TestSessionState;
|
|
182
|
+
readonly currentItem: (state: TestSessionState) => TestPlanItem | null;
|
|
183
|
+
readonly canMoveTo: (state: TestSessionState, itemKey: string) => boolean;
|
|
184
|
+
readonly moveTo: (state: TestSessionState, itemKey: string) => TestSessionState;
|
|
185
|
+
/** Whether `next()` would change state (false when allowSkipping blocks the move). */
|
|
186
|
+
readonly canNext: (state: TestSessionState) => boolean;
|
|
187
|
+
readonly next: (state: TestSessionState) => TestSessionState;
|
|
188
|
+
/** Attempts left for the item under its effective maxAttempts (Infinity when unlimited). */
|
|
189
|
+
readonly remainingAttempts: (state: TestSessionState, itemKey: string) => number;
|
|
190
|
+
readonly canSubmitItem: (state: TestSessionState, itemKey: string) => boolean;
|
|
191
|
+
readonly submitItem: (state: TestSessionState, itemKey: string, result: TestItemResult) => TestSessionState;
|
|
192
|
+
readonly end: (state: TestSessionState) => TestSessionState;
|
|
193
|
+
readonly visibleTestFeedbacks: (state: TestSessionState) => readonly TestFeedbackView[];
|
|
194
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime view types for the headless core. These are structural views of the
|
|
3
|
+
* `@conform-ed/contracts` QTI 3.0.1 shapes — the runtime validates items with the
|
|
4
|
+
* contract schemas, but works against these narrowed types because several contract
|
|
5
|
+
* schemas are `z.lazy` (statically `any`). No React or Mantine here.
|
|
6
|
+
*/
|
|
7
|
+
/** One field of a record response; fields keep their runtime type (PCI JSON typing). */
|
|
8
|
+
export type ResponseFieldValue = string | number | boolean | null;
|
|
9
|
+
/** A record-cardinality response: named, individually-typed fields (PCI contracts). */
|
|
10
|
+
export type ResponseRecordValue = Readonly<Record<string, ResponseFieldValue>>;
|
|
11
|
+
/** A candidate response for one interaction, keyed in state by `responseIdentifier`. */
|
|
12
|
+
export type ResponseValue = string | readonly string[] | ResponseRecordValue | null;
|
|
13
|
+
/** Narrow a ResponseValue to its record variant. */
|
|
14
|
+
export declare function isResponseRecord(value: ResponseValue): value is ResponseRecordValue;
|
|
15
|
+
export type Cardinality = "single" | "multiple" | "ordered" | "record";
|
|
16
|
+
export interface CorrectResponseView {
|
|
17
|
+
readonly values: ReadonlyArray<{
|
|
18
|
+
readonly value: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
export interface MapEntryView {
|
|
22
|
+
readonly mapKey: string;
|
|
23
|
+
readonly mappedValue: number;
|
|
24
|
+
readonly caseSensitive?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface MappingView {
|
|
27
|
+
readonly mapEntries: readonly MapEntryView[];
|
|
28
|
+
readonly lowerBound?: number;
|
|
29
|
+
readonly upperBound?: number;
|
|
30
|
+
readonly defaultValue?: number;
|
|
31
|
+
}
|
|
32
|
+
/** One scored area for point responses (QTI `areaMapEntry`). */
|
|
33
|
+
export interface AreaMapEntryView {
|
|
34
|
+
readonly shape: string;
|
|
35
|
+
readonly coords: readonly number[];
|
|
36
|
+
readonly mappedValue: number;
|
|
37
|
+
}
|
|
38
|
+
export interface AreaMappingView {
|
|
39
|
+
readonly areaMapEntries: readonly AreaMapEntryView[];
|
|
40
|
+
readonly lowerBound?: number;
|
|
41
|
+
readonly upperBound?: number;
|
|
42
|
+
readonly defaultValue?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface ResponseDeclarationView {
|
|
45
|
+
readonly identifier: string;
|
|
46
|
+
readonly cardinality: Cardinality;
|
|
47
|
+
readonly baseType?: string;
|
|
48
|
+
readonly correctResponse?: CorrectResponseView;
|
|
49
|
+
readonly mapping?: MappingView;
|
|
50
|
+
readonly areaMapping?: AreaMappingView;
|
|
51
|
+
}
|
|
52
|
+
/** The scored outcome for one response variable. */
|
|
53
|
+
export interface ScoreResult {
|
|
54
|
+
readonly identifier: string;
|
|
55
|
+
readonly score: number;
|
|
56
|
+
readonly maxScore: number;
|
|
57
|
+
readonly correct: boolean;
|
|
58
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conform-ed/qti-react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"files": [
|
|
5
5
|
"src",
|
|
6
6
|
"dist"
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
"module": "src/index.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"types": "./
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "bun build ./src/index.ts --outdir dist --format esm --target browser --external react --external react-dom --external zod",
|
|
18
|
-
"typecheck": "tsgo --noEmit",
|
|
19
|
-
"lint": "oxlint --config ../../.oxlintrc.jsonc .",
|
|
17
|
+
"build": "bun build ./src/index.ts --outdir dist --format esm --target browser --external react --external react-dom --external zod && tsgo -p tsconfig.build.json",
|
|
20
18
|
"format": "oxfmt --config ../../.oxfmtrc.jsonc --check .",
|
|
21
|
-
"
|
|
19
|
+
"lint": "oxlint --config ../../.oxlintrc.jsonc .",
|
|
20
|
+
"test": "bun test",
|
|
21
|
+
"typecheck": "tsgo --noEmit"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@conform-ed/qti-xml": "0.0.13",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const associateInteractionNodeSchema = z.object({
|
|
@@ -12,7 +12,7 @@ const associateInteractionNodeSchema = z.object({
|
|
|
12
12
|
maxAssociations: z.number().int().optional(),
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
export const associateInteraction = defineInteraction({
|
|
15
|
+
export const associateInteraction: InteractionDescriptor<"associateInteraction"> = defineInteraction({
|
|
16
16
|
kind: "associateInteraction",
|
|
17
17
|
schema: associateInteractionNodeSchema,
|
|
18
18
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
/** Minimal node shape the runtime/skin rely on; whole-item validation uses the contract. */
|
|
@@ -11,7 +11,7 @@ const choiceInteractionNodeSchema = z.object({
|
|
|
11
11
|
maxChoices: z.number().int().optional(),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
export const choiceInteraction = defineInteraction({
|
|
14
|
+
export const choiceInteraction: InteractionDescriptor<"choiceInteraction"> = defineInteraction({
|
|
15
15
|
kind: "choiceInteraction",
|
|
16
16
|
schema: choiceInteractionNodeSchema,
|
|
17
17
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const drawingInteractionNodeSchema = z.object({
|
|
@@ -14,7 +14,7 @@ const drawingInteractionNodeSchema = z.object({
|
|
|
14
14
|
}),
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
export const drawingInteraction = defineInteraction({
|
|
17
|
+
export const drawingInteraction: InteractionDescriptor<"drawingInteraction"> = defineInteraction({
|
|
18
18
|
kind: "drawingInteraction",
|
|
19
19
|
schema: drawingInteractionNodeSchema,
|
|
20
20
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const endAttemptInteractionNodeSchema = z.object({
|
|
@@ -9,7 +9,7 @@ const endAttemptInteractionNodeSchema = z.object({
|
|
|
9
9
|
title: z.string().min(1),
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
export const endAttemptInteraction = defineInteraction({
|
|
12
|
+
export const endAttemptInteraction: InteractionDescriptor<"endAttemptInteraction"> = defineInteraction({
|
|
13
13
|
kind: "endAttemptInteraction",
|
|
14
14
|
schema: endAttemptInteractionNodeSchema,
|
|
15
15
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const extendedTextInteractionNodeSchema = z.object({
|
|
@@ -11,7 +11,7 @@ const extendedTextInteractionNodeSchema = z.object({
|
|
|
11
11
|
placeholderText: z.string().optional(),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
export const extendedTextInteraction = defineInteraction({
|
|
14
|
+
export const extendedTextInteraction: InteractionDescriptor<"extendedTextInteraction"> = defineInteraction({
|
|
15
15
|
kind: "extendedTextInteraction",
|
|
16
16
|
schema: extendedTextInteractionNodeSchema,
|
|
17
17
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const gapMatchInteractionNodeSchema = z.object({
|
|
@@ -12,7 +12,7 @@ const gapMatchInteractionNodeSchema = z.object({
|
|
|
12
12
|
content: z.array(z.looseObject({ kind: z.string().min(1) })).min(1),
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
export const gapMatchInteraction = defineInteraction({
|
|
15
|
+
export const gapMatchInteraction: InteractionDescriptor<"gapMatchInteraction"> = defineInteraction({
|
|
16
16
|
kind: "gapMatchInteraction",
|
|
17
17
|
schema: gapMatchInteractionNodeSchema,
|
|
18
18
|
scoring: "qti-standard",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
|
-
import { defineInteraction } from "../runtime";
|
|
9
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
10
10
|
import type { ResponseValue } from "../types";
|
|
11
11
|
|
|
12
12
|
const objectSchema = z.object({
|
|
@@ -26,7 +26,7 @@ function nullInitial(): ResponseValue {
|
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export const hotspotInteraction = defineInteraction({
|
|
29
|
+
export const hotspotInteraction: InteractionDescriptor<"hotspotInteraction"> = defineInteraction({
|
|
30
30
|
kind: "hotspotInteraction",
|
|
31
31
|
schema: z.object({
|
|
32
32
|
kind: z.literal("hotspotInteraction"),
|
|
@@ -39,7 +39,7 @@ export const hotspotInteraction = defineInteraction({
|
|
|
39
39
|
initialResponse: nullInitial,
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
export const graphicOrderInteraction = defineInteraction({
|
|
42
|
+
export const graphicOrderInteraction: InteractionDescriptor<"graphicOrderInteraction"> = defineInteraction({
|
|
43
43
|
kind: "graphicOrderInteraction",
|
|
44
44
|
schema: z.object({
|
|
45
45
|
kind: z.literal("graphicOrderInteraction"),
|
|
@@ -51,7 +51,7 @@ export const graphicOrderInteraction = defineInteraction({
|
|
|
51
51
|
initialResponse: nullInitial,
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
export const graphicAssociateInteraction = defineInteraction({
|
|
54
|
+
export const graphicAssociateInteraction: InteractionDescriptor<"graphicAssociateInteraction"> = defineInteraction({
|
|
55
55
|
kind: "graphicAssociateInteraction",
|
|
56
56
|
schema: z.object({
|
|
57
57
|
kind: z.literal("graphicAssociateInteraction"),
|
|
@@ -64,7 +64,7 @@ export const graphicAssociateInteraction = defineInteraction({
|
|
|
64
64
|
initialResponse: nullInitial,
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
export const graphicGapMatchInteraction = defineInteraction({
|
|
67
|
+
export const graphicGapMatchInteraction: InteractionDescriptor<"graphicGapMatchInteraction"> = defineInteraction({
|
|
68
68
|
kind: "graphicGapMatchInteraction",
|
|
69
69
|
schema: z.object({
|
|
70
70
|
kind: z.literal("graphicGapMatchInteraction"),
|
|
@@ -77,7 +77,7 @@ export const graphicGapMatchInteraction = defineInteraction({
|
|
|
77
77
|
initialResponse: nullInitial,
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
export const selectPointInteraction = defineInteraction({
|
|
80
|
+
export const selectPointInteraction: InteractionDescriptor<"selectPointInteraction"> = defineInteraction({
|
|
81
81
|
kind: "selectPointInteraction",
|
|
82
82
|
schema: z.object({
|
|
83
83
|
kind: z.literal("selectPointInteraction"),
|
|
@@ -90,7 +90,7 @@ export const selectPointInteraction = defineInteraction({
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
/** The common single-interaction stage; multi-interaction stages fail validation. */
|
|
93
|
-
export const positionObjectStage = defineInteraction({
|
|
93
|
+
export const positionObjectStage: InteractionDescriptor<"positionObjectStage"> = defineInteraction({
|
|
94
94
|
kind: "positionObjectStage",
|
|
95
95
|
schema: z.object({
|
|
96
96
|
kind: z.literal("positionObjectStage"),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const hottextInteractionNodeSchema = z.object({
|
|
@@ -11,7 +11,7 @@ const hottextInteractionNodeSchema = z.object({
|
|
|
11
11
|
content: z.array(z.looseObject({ kind: z.string().min(1) })).min(1),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
export const hottextInteraction = defineInteraction({
|
|
14
|
+
export const hottextInteraction: InteractionDescriptor<"hottextInteraction"> = defineInteraction({
|
|
15
15
|
kind: "hottextInteraction",
|
|
16
16
|
schema: hottextInteractionNodeSchema,
|
|
17
17
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const inlineChoiceInteractionNodeSchema = z.object({
|
|
@@ -9,7 +9,7 @@ const inlineChoiceInteractionNodeSchema = z.object({
|
|
|
9
9
|
inlineChoices: z.array(z.object({ identifier: z.string().min(1) })).min(1),
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
export const inlineChoiceInteraction = defineInteraction({
|
|
12
|
+
export const inlineChoiceInteraction: InteractionDescriptor<"inlineChoiceInteraction"> = defineInteraction({
|
|
13
13
|
kind: "inlineChoiceInteraction",
|
|
14
14
|
schema: inlineChoiceInteractionNodeSchema,
|
|
15
15
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const simpleMatchSetSchema = z.object({
|
|
@@ -17,7 +17,7 @@ const matchInteractionNodeSchema = z.object({
|
|
|
17
17
|
maxAssociations: z.number().int().optional(),
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
export const matchInteraction = defineInteraction({
|
|
20
|
+
export const matchInteraction: InteractionDescriptor<"matchInteraction"> = defineInteraction({
|
|
21
21
|
kind: "matchInteraction",
|
|
22
22
|
schema: matchInteractionNodeSchema,
|
|
23
23
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const mediaInteractionNodeSchema = z.object({
|
|
@@ -14,7 +14,7 @@ const mediaInteractionNodeSchema = z.object({
|
|
|
14
14
|
content: z.array(z.looseObject({ kind: z.string().min(1) })).min(1),
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
export const mediaInteraction = defineInteraction({
|
|
17
|
+
export const mediaInteraction: InteractionDescriptor<"mediaInteraction"> = defineInteraction({
|
|
18
18
|
kind: "mediaInteraction",
|
|
19
19
|
schema: mediaInteractionNodeSchema,
|
|
20
20
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const orderInteractionNodeSchema = z.object({
|
|
@@ -11,7 +11,7 @@ const orderInteractionNodeSchema = z.object({
|
|
|
11
11
|
orientation: z.enum(["horizontal", "vertical"]).optional(),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
export const orderInteraction = defineInteraction({
|
|
14
|
+
export const orderInteraction: InteractionDescriptor<"orderInteraction"> = defineInteraction({
|
|
15
15
|
kind: "orderInteraction",
|
|
16
16
|
schema: orderInteractionNodeSchema,
|
|
17
17
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const sliderInteractionNodeSchema = z.object({
|
|
@@ -14,7 +14,7 @@ const sliderInteractionNodeSchema = z.object({
|
|
|
14
14
|
reverse: z.boolean().optional(),
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
export const sliderInteraction = defineInteraction({
|
|
17
|
+
export const sliderInteraction: InteractionDescriptor<"sliderInteraction"> = defineInteraction({
|
|
18
18
|
kind: "sliderInteraction",
|
|
19
19
|
schema: sliderInteractionNodeSchema,
|
|
20
20
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const textEntryInteractionNodeSchema = z.object({
|
|
@@ -11,7 +11,7 @@ const textEntryInteractionNodeSchema = z.object({
|
|
|
11
11
|
patternMask: z.string().optional(),
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
export const textEntryInteraction = defineInteraction({
|
|
14
|
+
export const textEntryInteraction: InteractionDescriptor<"textEntryInteraction"> = defineInteraction({
|
|
15
15
|
kind: "textEntryInteraction",
|
|
16
16
|
schema: textEntryInteractionNodeSchema,
|
|
17
17
|
scoring: "qti-standard",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const uploadInteractionNodeSchema = z.object({
|
|
@@ -9,7 +9,7 @@ const uploadInteractionNodeSchema = z.object({
|
|
|
9
9
|
type: z.string().optional(),
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
export const uploadInteraction = defineInteraction({
|
|
12
|
+
export const uploadInteraction: InteractionDescriptor<"uploadInteraction"> = defineInteraction({
|
|
13
13
|
kind: "uploadInteraction",
|
|
14
14
|
schema: uploadInteractionNodeSchema,
|
|
15
15
|
scoring: "qti-standard",
|
package/src/normalized-item.ts
CHANGED
|
@@ -266,7 +266,7 @@ function convertExpression(expression: unknown): RpExpressionView {
|
|
|
266
266
|
return {
|
|
267
267
|
...rest,
|
|
268
268
|
...(Array.isArray(children) ? { expressions: children.map(convertExpression) } : {}),
|
|
269
|
-
} as RpExpressionView;
|
|
269
|
+
} as unknown as RpExpressionView;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
function convertBranch(branch: unknown, convertRule: (rule: unknown) => Record<string, unknown>) {
|
|
@@ -472,7 +472,9 @@ function convertItemRef(ref: Record<string, unknown>): AssessmentItemRefView {
|
|
|
472
472
|
...(typeof ref["required"] === "boolean" ? { required: ref["required"] } : {}),
|
|
473
473
|
...(ref["preConditions"] !== undefined ? { preConditions: convertPreConditions(ref["preConditions"]) } : {}),
|
|
474
474
|
...(ref["branchRules"] !== undefined ? { branchRules: convertBranchRules(ref["branchRules"]) } : {}),
|
|
475
|
-
...(Array.isArray(ref["weights"])
|
|
475
|
+
...(Array.isArray(ref["weights"])
|
|
476
|
+
? { weights: ref["weights"] as NonNullable<AssessmentItemRefView["weights"]> }
|
|
477
|
+
: {}),
|
|
476
478
|
...sessionControlAndTimeLimits(ref),
|
|
477
479
|
};
|
|
478
480
|
}
|
|
@@ -493,10 +495,10 @@ function convertSection(section: Record<string, unknown>): AssessmentSectionView
|
|
|
493
495
|
...(typeof section["fixed"] === "boolean" ? { fixed: section["fixed"] } : {}),
|
|
494
496
|
...(typeof section["required"] === "boolean" ? { required: section["required"] } : {}),
|
|
495
497
|
...(isRecord(section["selection"])
|
|
496
|
-
? { selection: section["selection"] as unknown as AssessmentSectionView["selection"] }
|
|
498
|
+
? { selection: section["selection"] as unknown as NonNullable<AssessmentSectionView["selection"]> }
|
|
497
499
|
: {}),
|
|
498
500
|
...(isRecord(section["ordering"])
|
|
499
|
-
? { ordering: section["ordering"] as unknown as AssessmentSectionView["ordering"] }
|
|
501
|
+
? { ordering: section["ordering"] as unknown as NonNullable<AssessmentSectionView["ordering"]> }
|
|
500
502
|
: {}),
|
|
501
503
|
...(section["preConditions"] !== undefined
|
|
502
504
|
? { preConditions: convertPreConditions(section["preConditions"]) }
|
package/src/pci/interaction.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import { defineInteraction } from "../runtime";
|
|
3
|
+
import { defineInteraction, type InteractionDescriptor } from "../runtime";
|
|
4
4
|
import type { ResponseValue } from "../types";
|
|
5
5
|
|
|
6
6
|
const interactionModuleSchema = z.object({
|
|
@@ -32,7 +32,7 @@ const pciNodeSchema = z.object({
|
|
|
32
32
|
* this descriptor plus a skin from `createPciSkin` (ADR-0003 — the capability gate
|
|
33
33
|
* keeps PCI items undeliverable until then).
|
|
34
34
|
*/
|
|
35
|
-
export const portableCustomInteraction = defineInteraction({
|
|
35
|
+
export const portableCustomInteraction: InteractionDescriptor<"portableCustomInteraction"> = defineInteraction({
|
|
36
36
|
kind: "portableCustomInteraction",
|
|
37
37
|
schema: pciNodeSchema,
|
|
38
38
|
scoring: "qti-standard",
|