@timeback/qti 0.2.0 → 0.2.1-beta.20260313210405

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.
@@ -0,0 +1,124 @@
1
+ /**
2
+ * QTI Parse Types
3
+ *
4
+ * Type definitions for QTI XML parsing utilities.
5
+ */
6
+ /** A single choice option extracted from a `<qti-simple-choice>` element. */
7
+ interface QtiChoice {
8
+ identifier: string;
9
+ text: string;
10
+ }
11
+ /** Inline feedback extracted from a `<qti-feedback-inline>` element. */
12
+ interface QtiInlineFeedback {
13
+ outcomeIdentifier: string;
14
+ identifier: string;
15
+ showHide: string;
16
+ content: string;
17
+ }
18
+ /** Modal feedback extracted from a `<qti-modal-feedback>` element. */
19
+ interface QtiModalFeedback {
20
+ outcomeIdentifier: string;
21
+ identifier: string;
22
+ showHide: string;
23
+ content: string;
24
+ }
25
+ /** Attributes from a `<qti-choice-interaction>` element. */
26
+ interface QtiInteractionAttributes {
27
+ responseIdentifier: string;
28
+ shuffle: boolean;
29
+ maxChoices: number;
30
+ }
31
+ /** Response declaration extracted from a `<qti-response-declaration>` element. */
32
+ interface QtiResponseDeclaration {
33
+ identifier: string;
34
+ cardinality: string;
35
+ baseType: string | null;
36
+ }
37
+ /** Complete parsed result from a QTI assessment item XML string. */
38
+ interface ParsedQtiItem {
39
+ prompt: string;
40
+ choices: QtiChoice[];
41
+ correctAnswer: string | null;
42
+ feedback: QtiInlineFeedback[];
43
+ modalFeedback: QtiModalFeedback[];
44
+ interaction: QtiInteractionAttributes | null;
45
+ responseDeclaration: QtiResponseDeclaration | null;
46
+ }
47
+
48
+ /**
49
+ * Extract the prompt text from a `<qti-prompt>` element.
50
+ *
51
+ * @param xml - Raw QTI XML string
52
+ * @returns The inner HTML of the prompt, or an empty string if not found
53
+ */
54
+ declare function extractPrompt(xml: string): string;
55
+ /**
56
+ * Extract simple choices from `<qti-simple-choice>` elements.
57
+ *
58
+ * Inline feedback elements within each choice are stripped from the returned
59
+ * text. Use {@link extractFeedback} to retrieve them separately.
60
+ *
61
+ * @param xml - Raw QTI XML string
62
+ * @returns Array of choices with identifier and cleaned text
63
+ */
64
+ declare function extractChoices(xml: string): QtiChoice[];
65
+ /**
66
+ * Extract the correct answer identifier from `<qti-correct-response>`.
67
+ *
68
+ * @param xml - Raw QTI XML string
69
+ * @returns The correct answer identifier, or null if not found
70
+ */
71
+ declare function extractCorrectResponse(xml: string): string | null;
72
+ /**
73
+ * Extract inline feedback from `<qti-feedback-inline>` elements.
74
+ *
75
+ * @param xml - Raw QTI XML string
76
+ * @returns Array of inline feedback entries
77
+ */
78
+ declare function extractFeedback(xml: string): QtiInlineFeedback[];
79
+ /**
80
+ * Extract modal feedback from `<qti-modal-feedback>` elements.
81
+ *
82
+ * @param xml - Raw QTI XML string
83
+ * @returns Array of modal feedback entries
84
+ */
85
+ declare function extractModalFeedback(xml: string): QtiModalFeedback[];
86
+ /**
87
+ * Extract interaction attributes from `<qti-choice-interaction>`.
88
+ *
89
+ * @param xml - Raw QTI XML string
90
+ * @returns Interaction attributes, or null if no choice interaction found
91
+ */
92
+ declare function extractInteractionAttributes(xml: string): QtiInteractionAttributes | null;
93
+ /**
94
+ * Extract the response declaration from `<qti-response-declaration>`.
95
+ *
96
+ * @param xml - Raw QTI XML string
97
+ * @returns Response declaration, or null if not found
98
+ */
99
+ declare function extractResponseDeclaration(xml: string): QtiResponseDeclaration | null;
100
+ /**
101
+ * Parse a QTI 3.0 assessment item XML string into structured data.
102
+ *
103
+ * Combines all individual extractors into a single result. For more control,
104
+ * use the individual `extract*` functions directly.
105
+ *
106
+ * @param xml - Raw QTI XML string
107
+ * @returns Complete parsed item data
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * import { parseQtiXml } from '@timeback/qti/parse'
112
+ *
113
+ * const item = parseQtiXml(xml)
114
+ * console.log(item.prompt) // "What is 2 + 2?"
115
+ * console.log(item.choices) // [{ identifier: "A", text: "3" }, ...]
116
+ * console.log(item.correctAnswer) // "B"
117
+ * console.log(item.feedback) // [{ identifier: "A", content: "..." }, ...]
118
+ * console.log(item.modalFeedback) // [{ identifier: "CORRECT", content: "..." }, ...]
119
+ * ```
120
+ */
121
+ declare function parseQtiXml(xml: string): ParsedQtiItem;
122
+
123
+ export { extractChoices, extractCorrectResponse, extractFeedback, extractInteractionAttributes, extractModalFeedback, extractPrompt, extractResponseDeclaration, parseQtiXml };
124
+ export type { ParsedQtiItem, QtiChoice, QtiInlineFeedback, QtiInteractionAttributes, QtiModalFeedback, QtiResponseDeclaration };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,wBAAwB,EACxB,gBAAgB,EAChB,sBAAsB,EACtB,MAAM,eAAe,CAAA;AAEtB;;;;;;;;;;;;;;GAcG;AAEH,YAAY,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,wBAAwB,EACxB,gBAAgB,EAChB,sBAAsB,GACtB,MAAM,eAAe,CAAA;AAMtB;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAevD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKjE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAsBhE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA4BpE;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAiBzF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAiBrF;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAUtD"}
package/dist/parse.js ADDED
@@ -0,0 +1,126 @@
1
+ import"./chunk-6jf1natv.js";
2
+
3
+ // src/parse.ts
4
+ function extractPrompt(xml) {
5
+ if (!xml)
6
+ return "";
7
+ const match = xml.match(/<qti-prompt[^>]*>([\s\S]*?)<\/qti-prompt>/i);
8
+ return match?.[1]?.trim() ?? "";
9
+ }
10
+ function extractChoices(xml) {
11
+ if (!xml)
12
+ return [];
13
+ const choices = [];
14
+ const regex = /<qti-simple-choice[^>]*identifier="([^"]+)"[^>]*>([\s\S]*?)<\/qti-simple-choice>/gi;
15
+ let match;
16
+ while ((match = regex.exec(xml)) !== null) {
17
+ let text = match[2] ?? "";
18
+ text = text.replace(/<qti-feedback-inline[\s\S]*?<\/qti-feedback-inline>/gi, "").trim();
19
+ choices.push({ identifier: match[1] ?? "", text });
20
+ }
21
+ return choices;
22
+ }
23
+ function extractCorrectResponse(xml) {
24
+ if (!xml)
25
+ return null;
26
+ const match = xml.match(/<qti-correct-response>\s*<qti-value>([^<]+)<\/qti-value>/i);
27
+ return match?.[1]?.trim() ?? null;
28
+ }
29
+ function extractFeedback(xml) {
30
+ if (!xml)
31
+ return [];
32
+ const feedback = [];
33
+ const regex = /<qti-feedback-inline([^>]*)>([\s\S]*?)<\/qti-feedback-inline>/gi;
34
+ let match;
35
+ while ((match = regex.exec(xml)) !== null) {
36
+ const attrs = match[1] ?? "";
37
+ const outcomeId = attrs.match(/outcome-identifier="([^"]*)"/);
38
+ const id = attrs.match(/(?:^|\s)identifier="([^"]*)"/);
39
+ const showHide = attrs.match(/show-hide="([^"]*)"/);
40
+ feedback.push({
41
+ outcomeIdentifier: outcomeId?.[1] ?? "",
42
+ identifier: id?.[1] ?? "",
43
+ showHide: showHide?.[1] ?? "show",
44
+ content: (match[2] ?? "").trim()
45
+ });
46
+ }
47
+ return feedback;
48
+ }
49
+ function extractModalFeedback(xml) {
50
+ if (!xml)
51
+ return [];
52
+ const modalFeedback = [];
53
+ const regex = /<qti-modal-feedback([^>]*)>([\s\S]*?)<\/qti-modal-feedback>/gi;
54
+ let match;
55
+ while ((match = regex.exec(xml)) !== null) {
56
+ const attrs = match[1] ?? "";
57
+ const outcomeId = attrs.match(/outcome-identifier="([^"]*)"/);
58
+ const id = attrs.match(/(?:^|\s)identifier="([^"]*)"/);
59
+ const showHide = attrs.match(/show-hide="([^"]*)"/);
60
+ let content = match[2] ?? "";
61
+ const bodyMatch = content.match(/<qti-content-body>([\s\S]*?)<\/qti-content-body>/i);
62
+ if (bodyMatch) {
63
+ content = bodyMatch[1] ?? "";
64
+ }
65
+ modalFeedback.push({
66
+ outcomeIdentifier: outcomeId?.[1] ?? "",
67
+ identifier: id?.[1] ?? "",
68
+ showHide: showHide?.[1] ?? "show",
69
+ content: content.trim()
70
+ });
71
+ }
72
+ return modalFeedback;
73
+ }
74
+ function extractInteractionAttributes(xml) {
75
+ if (!xml)
76
+ return null;
77
+ const match = xml.match(/<qti-choice-interaction([^>]*)>/i);
78
+ if (!match)
79
+ return null;
80
+ const attrs = match[1] ?? "";
81
+ const responseId = attrs.match(/response-identifier="([^"]*)"/);
82
+ const shuffle = attrs.match(/shuffle="([^"]*)"/);
83
+ const maxChoices = attrs.match(/max-choices="([^"]*)"/);
84
+ return {
85
+ responseIdentifier: responseId?.[1] ?? "",
86
+ shuffle: shuffle?.[1]?.toLowerCase() === "true",
87
+ maxChoices: maxChoices?.[1] ? parseInt(maxChoices[1], 10) : 1
88
+ };
89
+ }
90
+ function extractResponseDeclaration(xml) {
91
+ if (!xml)
92
+ return null;
93
+ const match = xml.match(/<qti-response-declaration([^>]*)>/i);
94
+ if (!match)
95
+ return null;
96
+ const attrs = match[1] ?? "";
97
+ const identifier = attrs.match(/identifier="([^"]*)"/);
98
+ const cardinality = attrs.match(/cardinality="([^"]*)"/);
99
+ const baseType = attrs.match(/base-type="([^"]*)"/);
100
+ return {
101
+ identifier: identifier?.[1] ?? "",
102
+ cardinality: cardinality?.[1] ?? "",
103
+ baseType: baseType?.[1] ?? null
104
+ };
105
+ }
106
+ function parseQtiXml(xml) {
107
+ return {
108
+ prompt: extractPrompt(xml),
109
+ choices: extractChoices(xml),
110
+ correctAnswer: extractCorrectResponse(xml),
111
+ feedback: extractFeedback(xml),
112
+ modalFeedback: extractModalFeedback(xml),
113
+ interaction: extractInteractionAttributes(xml),
114
+ responseDeclaration: extractResponseDeclaration(xml)
115
+ };
116
+ }
117
+ export {
118
+ parseQtiXml,
119
+ extractResponseDeclaration,
120
+ extractPrompt,
121
+ extractModalFeedback,
122
+ extractInteractionAttributes,
123
+ extractFeedback,
124
+ extractCorrectResponse,
125
+ extractChoices
126
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * QTI Parse Types
3
+ *
4
+ * Type definitions for QTI XML parsing utilities.
5
+ */
6
+ /** A single choice option extracted from a `<qti-simple-choice>` element. */
7
+ export interface QtiChoice {
8
+ identifier: string;
9
+ text: string;
10
+ }
11
+ /** Inline feedback extracted from a `<qti-feedback-inline>` element. */
12
+ export interface QtiInlineFeedback {
13
+ outcomeIdentifier: string;
14
+ identifier: string;
15
+ showHide: string;
16
+ content: string;
17
+ }
18
+ /** Modal feedback extracted from a `<qti-modal-feedback>` element. */
19
+ export interface QtiModalFeedback {
20
+ outcomeIdentifier: string;
21
+ identifier: string;
22
+ showHide: string;
23
+ content: string;
24
+ }
25
+ /** Attributes from a `<qti-choice-interaction>` element. */
26
+ export interface QtiInteractionAttributes {
27
+ responseIdentifier: string;
28
+ shuffle: boolean;
29
+ maxChoices: number;
30
+ }
31
+ /** Response declaration extracted from a `<qti-response-declaration>` element. */
32
+ export interface QtiResponseDeclaration {
33
+ identifier: string;
34
+ cardinality: string;
35
+ baseType: string | null;
36
+ }
37
+ /** Complete parsed result from a QTI assessment item XML string. */
38
+ export interface ParsedQtiItem {
39
+ prompt: string;
40
+ choices: QtiChoice[];
41
+ correctAnswer: string | null;
42
+ feedback: QtiInlineFeedback[];
43
+ modalFeedback: QtiModalFeedback[];
44
+ interaction: QtiInteractionAttributes | null;
45
+ responseDeclaration: QtiResponseDeclaration | null;
46
+ }
47
+ //# sourceMappingURL=parse.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.types.d.ts","sourceRoot":"","sources":["../src/parse.types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;CACZ;AAED,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CACf;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAChC,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CACf;AAED,4DAA4D;AAC5D,MAAM,WAAW,wBAAwB;IACxC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CAClB;AAED,kFAAkF;AAClF,MAAM,WAAW,sBAAsB;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAA;IAC7B,aAAa,EAAE,gBAAgB,EAAE,CAAA;IACjC,WAAW,EAAE,wBAAwB,GAAG,IAAI,CAAA;IAC5C,mBAAmB,EAAE,sBAAsB,GAAG,IAAI,CAAA;CAClD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timeback/qti",
3
- "version": "0.2.0",
3
+ "version": "0.2.1-beta.20260313210405",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -17,6 +17,11 @@
17
17
  "source": "./src/public-types.ts",
18
18
  "types": "./dist/public-types.d.ts",
19
19
  "import": "./dist/public-types.js"
20
+ },
21
+ "./parse": {
22
+ "source": "./src/parse.ts",
23
+ "types": "./dist/parse.d.ts",
24
+ "import": "./dist/parse.js"
20
25
  }
21
26
  },
22
27
  "main": "dist/index.js",