scorm-again 2.6.3 → 2.6.5
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/.claude/.claude/settings.local.json +13 -0
- package/.claude/settings.local.json +33 -0
- package/dist/aicc.js +38 -22
- package/dist/aicc.js.map +1 -1
- package/dist/aicc.min.js +1 -1
- package/dist/aicc.min.js.map +1 -1
- package/dist/esm/aicc.js +38 -22
- package/dist/esm/aicc.js.map +1 -1
- package/dist/esm/aicc.min.js +1 -1
- package/dist/esm/aicc.min.js.map +1 -1
- package/dist/esm/scorm-again.js +79 -47
- package/dist/esm/scorm-again.js.map +1 -1
- package/dist/esm/scorm-again.min.js +1 -1
- package/dist/esm/scorm-again.min.js.map +1 -1
- package/dist/esm/scorm12.js +35 -20
- package/dist/esm/scorm12.js.map +1 -1
- package/dist/esm/scorm12.min.js +1 -1
- package/dist/esm/scorm12.min.js.map +1 -1
- package/dist/esm/scorm2004.js +69 -41
- package/dist/esm/scorm2004.js.map +1 -1
- package/dist/esm/scorm2004.min.js +1 -1
- package/dist/esm/scorm2004.min.js.map +1 -1
- package/dist/scorm-again.js +79 -47
- package/dist/scorm-again.js.map +1 -1
- package/dist/scorm-again.min.js +1 -1
- package/dist/scorm-again.min.js.map +1 -1
- package/dist/scorm12.js +35 -20
- package/dist/scorm12.js.map +1 -1
- package/dist/scorm12.min.js +1 -1
- package/dist/scorm12.min.js.map +1 -1
- package/dist/scorm2004.js +69 -41
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +1 -1
- package/dist/scorm2004.min.js.map +1 -1
- package/dist/types/cmi/scorm2004/adl.d.ts +8 -2
- package/dist/types/cmi/scorm2004/cmi.d.ts +1 -1
- package/package.json +1 -1
- package/src/BaseAPI.ts +56 -33
- package/src/Scorm12API.ts +3 -2
- package/src/Scorm2004API.ts +31 -24
- package/src/cmi/aicc/attempts.ts +3 -3
- package/src/cmi/aicc/core.ts +30 -12
- package/src/cmi/aicc/evaluation.ts +1 -1
- package/src/cmi/aicc/student_data.ts +1 -1
- package/src/cmi/aicc/student_demographics.ts +13 -13
- package/src/cmi/aicc/student_preferences.ts +1 -1
- package/src/cmi/aicc/tries.ts +3 -3
- package/src/cmi/aicc/validation.ts +1 -1
- package/src/cmi/common/array.ts +1 -1
- package/src/cmi/common/score.ts +3 -3
- package/src/cmi/common/validation.ts +2 -2
- package/src/cmi/scorm12/cmi.ts +12 -4
- package/src/cmi/scorm12/interactions.ts +27 -11
- package/src/cmi/scorm12/objectives.ts +4 -4
- package/src/cmi/scorm12/student_data.ts +12 -4
- package/src/cmi/scorm12/student_preference.ts +3 -1
- package/src/cmi/scorm12/validation.ts +5 -3
- package/src/cmi/scorm2004/adl.ts +39 -22
- package/src/cmi/scorm2004/cmi.ts +47 -17
- package/src/cmi/scorm2004/comments.ts +11 -5
- package/src/cmi/scorm2004/interactions.ts +25 -23
- package/src/cmi/scorm2004/learner_preference.ts +3 -1
- package/src/cmi/scorm2004/objectives.ts +5 -5
- package/src/cmi/scorm2004/score.ts +3 -3
- package/src/cmi/scorm2004/validation.ts +2 -2
- package/src/exceptions/aicc_exceptions.ts +4 -4
- package/src/exceptions/scorm12_exceptions.ts +4 -4
- package/src/exceptions/scorm2004_exceptions.ts +4 -4
- package/src/utilities.ts +3 -3
- package/test/BaseAPI.requestHandler.spec.ts +126 -0
- package/test/Scorm12API.spec.ts +45 -0
- package/test/Scorm2004API.spec.ts +43 -0
- package/tsconfig.json +1 -0
package/src/cmi/scorm2004/cmi.ts
CHANGED
|
@@ -107,7 +107,9 @@ export class CMI extends BaseRootCMI {
|
|
|
107
107
|
* @private
|
|
108
108
|
*/
|
|
109
109
|
set _version(_version: string) {
|
|
110
|
-
throw new Scorm2004ValidationError(
|
|
110
|
+
throw new Scorm2004ValidationError(
|
|
111
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
112
|
+
);
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
/**
|
|
@@ -121,11 +123,13 @@ export class CMI extends BaseRootCMI {
|
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
125
|
* Setter for __children. Just throws an error.
|
|
124
|
-
* @param {
|
|
126
|
+
* @param {string} _children
|
|
125
127
|
* @private
|
|
126
128
|
*/
|
|
127
|
-
set _children(_children:
|
|
128
|
-
throw new Scorm2004ValidationError(
|
|
129
|
+
set _children(_children: string) {
|
|
130
|
+
throw new Scorm2004ValidationError(
|
|
131
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
132
|
+
);
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
/**
|
|
@@ -160,7 +164,9 @@ export class CMI extends BaseRootCMI {
|
|
|
160
164
|
*/
|
|
161
165
|
set completion_threshold(completion_threshold: string) {
|
|
162
166
|
if (this.initialized) {
|
|
163
|
-
throw new Scorm2004ValidationError(
|
|
167
|
+
throw new Scorm2004ValidationError(
|
|
168
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
169
|
+
);
|
|
164
170
|
} else {
|
|
165
171
|
this._completion_threshold = completion_threshold;
|
|
166
172
|
}
|
|
@@ -180,7 +186,9 @@ export class CMI extends BaseRootCMI {
|
|
|
180
186
|
*/
|
|
181
187
|
set credit(credit: string) {
|
|
182
188
|
if (this.initialized) {
|
|
183
|
-
throw new Scorm2004ValidationError(
|
|
189
|
+
throw new Scorm2004ValidationError(
|
|
190
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
191
|
+
);
|
|
184
192
|
} else {
|
|
185
193
|
this._credit = credit;
|
|
186
194
|
}
|
|
@@ -200,7 +208,9 @@ export class CMI extends BaseRootCMI {
|
|
|
200
208
|
*/
|
|
201
209
|
set entry(entry: string) {
|
|
202
210
|
if (this.initialized) {
|
|
203
|
-
throw new Scorm2004ValidationError(
|
|
211
|
+
throw new Scorm2004ValidationError(
|
|
212
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
213
|
+
);
|
|
204
214
|
} else {
|
|
205
215
|
this._entry = entry;
|
|
206
216
|
}
|
|
@@ -212,7 +222,9 @@ export class CMI extends BaseRootCMI {
|
|
|
212
222
|
*/
|
|
213
223
|
get exit(): string {
|
|
214
224
|
if (!this.jsonString) {
|
|
215
|
-
throw new Scorm2004ValidationError(
|
|
225
|
+
throw new Scorm2004ValidationError(
|
|
226
|
+
scorm2004_errors.WRITE_ONLY_ELEMENT as number,
|
|
227
|
+
);
|
|
216
228
|
}
|
|
217
229
|
return this._exit;
|
|
218
230
|
}
|
|
@@ -241,7 +253,9 @@ export class CMI extends BaseRootCMI {
|
|
|
241
253
|
*/
|
|
242
254
|
set launch_data(launch_data: string) {
|
|
243
255
|
if (this.initialized) {
|
|
244
|
-
throw new Scorm2004ValidationError(
|
|
256
|
+
throw new Scorm2004ValidationError(
|
|
257
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
258
|
+
);
|
|
245
259
|
} else {
|
|
246
260
|
this._launch_data = launch_data;
|
|
247
261
|
}
|
|
@@ -261,7 +275,9 @@ export class CMI extends BaseRootCMI {
|
|
|
261
275
|
*/
|
|
262
276
|
set learner_id(learner_id: string) {
|
|
263
277
|
if (this.initialized) {
|
|
264
|
-
throw new Scorm2004ValidationError(
|
|
278
|
+
throw new Scorm2004ValidationError(
|
|
279
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
280
|
+
);
|
|
265
281
|
} else {
|
|
266
282
|
this._learner_id = learner_id;
|
|
267
283
|
}
|
|
@@ -281,7 +297,9 @@ export class CMI extends BaseRootCMI {
|
|
|
281
297
|
*/
|
|
282
298
|
set learner_name(learner_name: string) {
|
|
283
299
|
if (this.initialized) {
|
|
284
|
-
throw new Scorm2004ValidationError(
|
|
300
|
+
throw new Scorm2004ValidationError(
|
|
301
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
302
|
+
);
|
|
285
303
|
} else {
|
|
286
304
|
this._learner_name = learner_name;
|
|
287
305
|
}
|
|
@@ -319,7 +337,9 @@ export class CMI extends BaseRootCMI {
|
|
|
319
337
|
*/
|
|
320
338
|
set max_time_allowed(max_time_allowed: string) {
|
|
321
339
|
if (this.initialized) {
|
|
322
|
-
throw new Scorm2004ValidationError(
|
|
340
|
+
throw new Scorm2004ValidationError(
|
|
341
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
342
|
+
);
|
|
323
343
|
} else {
|
|
324
344
|
this._max_time_allowed = max_time_allowed;
|
|
325
345
|
}
|
|
@@ -339,7 +359,9 @@ export class CMI extends BaseRootCMI {
|
|
|
339
359
|
*/
|
|
340
360
|
set mode(mode: string) {
|
|
341
361
|
if (this.initialized) {
|
|
342
|
-
throw new Scorm2004ValidationError(
|
|
362
|
+
throw new Scorm2004ValidationError(
|
|
363
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
364
|
+
);
|
|
343
365
|
} else {
|
|
344
366
|
this._mode = mode;
|
|
345
367
|
}
|
|
@@ -380,7 +402,9 @@ export class CMI extends BaseRootCMI {
|
|
|
380
402
|
*/
|
|
381
403
|
set scaled_passing_score(scaled_passing_score: string) {
|
|
382
404
|
if (this.initialized) {
|
|
383
|
-
throw new Scorm2004ValidationError(
|
|
405
|
+
throw new Scorm2004ValidationError(
|
|
406
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
407
|
+
);
|
|
384
408
|
} else {
|
|
385
409
|
this._scaled_passing_score = scaled_passing_score;
|
|
386
410
|
}
|
|
@@ -392,7 +416,9 @@ export class CMI extends BaseRootCMI {
|
|
|
392
416
|
*/
|
|
393
417
|
get session_time(): string {
|
|
394
418
|
if (!this.jsonString) {
|
|
395
|
-
throw new Scorm2004ValidationError(
|
|
419
|
+
throw new Scorm2004ValidationError(
|
|
420
|
+
scorm2004_errors.WRITE_ONLY_ELEMENT as number,
|
|
421
|
+
);
|
|
396
422
|
}
|
|
397
423
|
return this._session_time;
|
|
398
424
|
}
|
|
@@ -459,7 +485,9 @@ export class CMI extends BaseRootCMI {
|
|
|
459
485
|
*/
|
|
460
486
|
set time_limit_action(time_limit_action: string) {
|
|
461
487
|
if (this.initialized) {
|
|
462
|
-
throw new Scorm2004ValidationError(
|
|
488
|
+
throw new Scorm2004ValidationError(
|
|
489
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
490
|
+
);
|
|
463
491
|
} else {
|
|
464
492
|
this._time_limit_action = time_limit_action;
|
|
465
493
|
}
|
|
@@ -479,7 +507,9 @@ export class CMI extends BaseRootCMI {
|
|
|
479
507
|
*/
|
|
480
508
|
set total_time(total_time: string) {
|
|
481
509
|
if (this.initialized) {
|
|
482
|
-
throw new Scorm2004ValidationError(
|
|
510
|
+
throw new Scorm2004ValidationError(
|
|
511
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
512
|
+
);
|
|
483
513
|
} else {
|
|
484
514
|
this._total_time = total_time;
|
|
485
515
|
}
|
|
@@ -17,7 +17,7 @@ export class CMICommentsFromLMS extends CMIArray {
|
|
|
17
17
|
constructor() {
|
|
18
18
|
super({
|
|
19
19
|
children: scorm2004_constants.comments_children,
|
|
20
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
20
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
21
21
|
errorClass: Scorm2004ValidationError,
|
|
22
22
|
});
|
|
23
23
|
}
|
|
@@ -34,7 +34,7 @@ export class CMICommentsFromLearner extends CMIArray {
|
|
|
34
34
|
constructor() {
|
|
35
35
|
super({
|
|
36
36
|
children: scorm2004_constants.comments_children,
|
|
37
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
37
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
38
38
|
errorClass: Scorm2004ValidationError,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
@@ -83,7 +83,9 @@ export class CMICommentsObject extends BaseCMI {
|
|
|
83
83
|
*/
|
|
84
84
|
set comment(comment: string) {
|
|
85
85
|
if (this.initialized && this._readOnlyAfterInit) {
|
|
86
|
-
throw new Scorm2004ValidationError(
|
|
86
|
+
throw new Scorm2004ValidationError(
|
|
87
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
88
|
+
);
|
|
87
89
|
} else {
|
|
88
90
|
if (
|
|
89
91
|
check2004ValidFormat(comment, scorm2004_regex.CMILangString4000, true)
|
|
@@ -107,7 +109,9 @@ export class CMICommentsObject extends BaseCMI {
|
|
|
107
109
|
*/
|
|
108
110
|
set location(location: string) {
|
|
109
111
|
if (this.initialized && this._readOnlyAfterInit) {
|
|
110
|
-
throw new Scorm2004ValidationError(
|
|
112
|
+
throw new Scorm2004ValidationError(
|
|
113
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
114
|
+
);
|
|
111
115
|
} else {
|
|
112
116
|
if (check2004ValidFormat(location, scorm2004_regex.CMIString250)) {
|
|
113
117
|
this._location = location;
|
|
@@ -129,7 +133,9 @@ export class CMICommentsObject extends BaseCMI {
|
|
|
129
133
|
*/
|
|
130
134
|
set timestamp(timestamp: string) {
|
|
131
135
|
if (this.initialized && this._readOnlyAfterInit) {
|
|
132
|
-
throw new Scorm2004ValidationError(
|
|
136
|
+
throw new Scorm2004ValidationError(
|
|
137
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
138
|
+
);
|
|
133
139
|
} else {
|
|
134
140
|
if (check2004ValidFormat(timestamp, scorm2004_regex.CMITime)) {
|
|
135
141
|
this._timestamp = timestamp;
|
|
@@ -17,7 +17,7 @@ export class CMIInteractions extends CMIArray {
|
|
|
17
17
|
constructor() {
|
|
18
18
|
super({
|
|
19
19
|
children: scorm2004_constants.interactions_children,
|
|
20
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
20
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
21
21
|
errorClass: Scorm2004ValidationError,
|
|
22
22
|
});
|
|
23
23
|
}
|
|
@@ -43,12 +43,12 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
43
43
|
constructor() {
|
|
44
44
|
super();
|
|
45
45
|
this.objectives = new CMIArray({
|
|
46
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
46
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
47
47
|
errorClass: Scorm2004ValidationError,
|
|
48
48
|
children: scorm2004_constants.objectives_children,
|
|
49
49
|
});
|
|
50
50
|
this.correct_responses = new CMIArray({
|
|
51
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
51
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
52
52
|
errorClass: Scorm2004ValidationError,
|
|
53
53
|
children: scorm2004_constants.correct_responses_children,
|
|
54
54
|
});
|
|
@@ -80,12 +80,12 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
80
80
|
this._latency = "";
|
|
81
81
|
this._description = "";
|
|
82
82
|
this.objectives = new CMIArray({
|
|
83
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
83
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
84
84
|
errorClass: Scorm2004ValidationError,
|
|
85
85
|
children: scorm2004_constants.objectives_children,
|
|
86
86
|
});
|
|
87
87
|
this.correct_responses = new CMIArray({
|
|
88
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
88
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
89
89
|
errorClass: Scorm2004ValidationError,
|
|
90
90
|
children: scorm2004_constants.correct_responses_children,
|
|
91
91
|
});
|
|
@@ -124,7 +124,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
124
124
|
set type(type: string) {
|
|
125
125
|
if (this.initialized && this._id === "") {
|
|
126
126
|
throw new Scorm2004ValidationError(
|
|
127
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
127
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
128
128
|
);
|
|
129
129
|
} else {
|
|
130
130
|
if (check2004ValidFormat(type, scorm2004_regex.CMIType)) {
|
|
@@ -148,7 +148,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
148
148
|
set timestamp(timestamp: string) {
|
|
149
149
|
if (this.initialized && this._id === "") {
|
|
150
150
|
throw new Scorm2004ValidationError(
|
|
151
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
151
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
152
152
|
);
|
|
153
153
|
} else {
|
|
154
154
|
if (check2004ValidFormat(timestamp, scorm2004_regex.CMITime)) {
|
|
@@ -172,7 +172,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
172
172
|
set weighting(weighting: string) {
|
|
173
173
|
if (this.initialized && this._id === "") {
|
|
174
174
|
throw new Scorm2004ValidationError(
|
|
175
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
175
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
176
176
|
);
|
|
177
177
|
} else {
|
|
178
178
|
if (check2004ValidFormat(weighting, scorm2004_regex.CMIDecimal)) {
|
|
@@ -197,7 +197,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
197
197
|
set learner_response(learner_response: string) {
|
|
198
198
|
if (this.initialized && (this._type === "" || this._id === "")) {
|
|
199
199
|
throw new Scorm2004ValidationError(
|
|
200
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
200
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
201
201
|
);
|
|
202
202
|
} else {
|
|
203
203
|
let nodes = [];
|
|
@@ -215,39 +215,39 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
215
215
|
|
|
216
216
|
for (let i = 0; i < nodes.length; i++) {
|
|
217
217
|
if (response_type?.delimiter2) {
|
|
218
|
-
const values = nodes[i]
|
|
218
|
+
const values = nodes[i]?.split(response_type.delimiter2);
|
|
219
219
|
|
|
220
|
-
if (values
|
|
221
|
-
if (!values[0]
|
|
220
|
+
if (values?.length === 2) {
|
|
221
|
+
if (!values[0]?.match(formatRegex)) {
|
|
222
222
|
throw new Scorm2004ValidationError(
|
|
223
|
-
scorm2004_errors.TYPE_MISMATCH,
|
|
223
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
224
224
|
);
|
|
225
225
|
} else {
|
|
226
226
|
if (
|
|
227
227
|
!response_type.format2 ||
|
|
228
|
-
!values[1]
|
|
228
|
+
!values[1]?.match(new RegExp(response_type.format2))
|
|
229
229
|
) {
|
|
230
230
|
throw new Scorm2004ValidationError(
|
|
231
|
-
scorm2004_errors.TYPE_MISMATCH,
|
|
231
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
232
232
|
);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
} else {
|
|
236
236
|
throw new Scorm2004ValidationError(
|
|
237
|
-
scorm2004_errors.TYPE_MISMATCH,
|
|
237
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
238
238
|
);
|
|
239
239
|
}
|
|
240
240
|
} else {
|
|
241
|
-
if (!nodes[i]
|
|
241
|
+
if (!nodes[i]?.match(formatRegex)) {
|
|
242
242
|
throw new Scorm2004ValidationError(
|
|
243
|
-
scorm2004_errors.TYPE_MISMATCH,
|
|
243
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
244
244
|
);
|
|
245
245
|
} else {
|
|
246
246
|
if (nodes[i] !== "" && response_type.unique) {
|
|
247
247
|
for (let j = 0; j < i; j++) {
|
|
248
248
|
if (nodes[i] === nodes[j]) {
|
|
249
249
|
throw new Scorm2004ValidationError(
|
|
250
|
-
scorm2004_errors.TYPE_MISMATCH,
|
|
250
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
251
251
|
);
|
|
252
252
|
}
|
|
253
253
|
}
|
|
@@ -257,13 +257,15 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
257
257
|
}
|
|
258
258
|
} else {
|
|
259
259
|
throw new Scorm2004ValidationError(
|
|
260
|
-
scorm2004_errors.GENERAL_SET_FAILURE,
|
|
260
|
+
scorm2004_errors.GENERAL_SET_FAILURE as number,
|
|
261
261
|
);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
this._learner_response = learner_response;
|
|
265
265
|
} else {
|
|
266
|
-
throw new Scorm2004ValidationError(
|
|
266
|
+
throw new Scorm2004ValidationError(
|
|
267
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
268
|
+
);
|
|
267
269
|
}
|
|
268
270
|
}
|
|
269
271
|
}
|
|
@@ -301,7 +303,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
301
303
|
set latency(latency: string) {
|
|
302
304
|
if (this.initialized && this._id === "") {
|
|
303
305
|
throw new Scorm2004ValidationError(
|
|
304
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
306
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
305
307
|
);
|
|
306
308
|
} else {
|
|
307
309
|
if (check2004ValidFormat(latency, scorm2004_regex.CMITimespan)) {
|
|
@@ -325,7 +327,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
|
|
325
327
|
set description(description: string) {
|
|
326
328
|
if (this.initialized && this._id === "") {
|
|
327
329
|
throw new Scorm2004ValidationError(
|
|
328
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
330
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
329
331
|
);
|
|
330
332
|
} else {
|
|
331
333
|
if (
|
|
@@ -44,7 +44,9 @@ export class CMILearnerPreference extends BaseCMI {
|
|
|
44
44
|
* @private
|
|
45
45
|
*/
|
|
46
46
|
set _children(_children: string) {
|
|
47
|
-
throw new Scorm2004ValidationError(
|
|
47
|
+
throw new Scorm2004ValidationError(
|
|
48
|
+
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
49
|
+
);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
@@ -18,7 +18,7 @@ export class CMIObjectives extends CMIArray {
|
|
|
18
18
|
constructor() {
|
|
19
19
|
super({
|
|
20
20
|
children: scorm2004_constants.objectives_children,
|
|
21
|
-
errorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
21
|
+
errorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
22
22
|
errorClass: Scorm2004ValidationError,
|
|
23
23
|
});
|
|
24
24
|
}
|
|
@@ -110,7 +110,7 @@ export class CMIObjectivesObject extends BaseCMI {
|
|
|
110
110
|
set success_status(success_status: string) {
|
|
111
111
|
if (this.initialized && this._id === "") {
|
|
112
112
|
throw new Scorm2004ValidationError(
|
|
113
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
113
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
114
114
|
);
|
|
115
115
|
} else {
|
|
116
116
|
if (check2004ValidFormat(success_status, scorm2004_regex.CMISStatus)) {
|
|
@@ -134,7 +134,7 @@ export class CMIObjectivesObject extends BaseCMI {
|
|
|
134
134
|
set completion_status(completion_status: string) {
|
|
135
135
|
if (this.initialized && this._id === "") {
|
|
136
136
|
throw new Scorm2004ValidationError(
|
|
137
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
137
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
138
138
|
);
|
|
139
139
|
} else {
|
|
140
140
|
if (check2004ValidFormat(completion_status, scorm2004_regex.CMICStatus)) {
|
|
@@ -158,7 +158,7 @@ export class CMIObjectivesObject extends BaseCMI {
|
|
|
158
158
|
set progress_measure(progress_measure: string) {
|
|
159
159
|
if (this.initialized && this._id === "") {
|
|
160
160
|
throw new Scorm2004ValidationError(
|
|
161
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
161
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
162
162
|
);
|
|
163
163
|
} else {
|
|
164
164
|
if (
|
|
@@ -185,7 +185,7 @@ export class CMIObjectivesObject extends BaseCMI {
|
|
|
185
185
|
set description(description: string) {
|
|
186
186
|
if (this.initialized && this._id === "") {
|
|
187
187
|
throw new Scorm2004ValidationError(
|
|
188
|
-
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED,
|
|
188
|
+
scorm2004_errors.DEPENDENCY_NOT_ESTABLISHED as number,
|
|
189
189
|
);
|
|
190
190
|
} else {
|
|
191
191
|
if (
|
|
@@ -18,9 +18,9 @@ export class Scorm2004CMIScore extends CMIScore {
|
|
|
18
18
|
super({
|
|
19
19
|
score_children: scorm2004_constants.score_children,
|
|
20
20
|
max: "",
|
|
21
|
-
invalidErrorCode: scorm2004_errors.READ_ONLY_ELEMENT,
|
|
22
|
-
invalidTypeCode: scorm2004_errors.TYPE_MISMATCH,
|
|
23
|
-
invalidRangeCode: scorm2004_errors.VALUE_OUT_OF_RANGE,
|
|
21
|
+
invalidErrorCode: scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
22
|
+
invalidTypeCode: scorm2004_errors.TYPE_MISMATCH as number,
|
|
23
|
+
invalidRangeCode: scorm2004_errors.VALUE_OUT_OF_RANGE as number,
|
|
24
24
|
decimalRegex: scorm2004_regex.CMIDecimal,
|
|
25
25
|
errorClass: Scorm2004ValidationError,
|
|
26
26
|
});
|
|
@@ -17,7 +17,7 @@ export function check2004ValidFormat(
|
|
|
17
17
|
return checkValidFormat(
|
|
18
18
|
value,
|
|
19
19
|
regexPattern,
|
|
20
|
-
scorm2004_errors.TYPE_MISMATCH,
|
|
20
|
+
scorm2004_errors.TYPE_MISMATCH as number,
|
|
21
21
|
Scorm2004ValidationError,
|
|
22
22
|
allowEmptyString,
|
|
23
23
|
);
|
|
@@ -36,7 +36,7 @@ export function check2004ValidRange(
|
|
|
36
36
|
return checkValidRange(
|
|
37
37
|
value,
|
|
38
38
|
rangePattern,
|
|
39
|
-
scorm2004_errors.VALUE_OUT_OF_RANGE,
|
|
39
|
+
scorm2004_errors.VALUE_OUT_OF_RANGE as number,
|
|
40
40
|
Scorm2004ValidationError,
|
|
41
41
|
);
|
|
42
42
|
}
|
|
@@ -15,14 +15,14 @@ export class AICCValidationError extends ValidationError {
|
|
|
15
15
|
if ({}.hasOwnProperty.call(aicc_errors, String(errorCode))) {
|
|
16
16
|
super(
|
|
17
17
|
errorCode,
|
|
18
|
-
aicc_errors[String(errorCode)]
|
|
19
|
-
aicc_errors[String(errorCode)]
|
|
18
|
+
aicc_errors[String(errorCode)]?.basicMessage || "Unknown rror",
|
|
19
|
+
aicc_errors[String(errorCode)]?.detailMessage,
|
|
20
20
|
);
|
|
21
21
|
} else {
|
|
22
22
|
super(
|
|
23
23
|
101,
|
|
24
|
-
aicc_errors["101"]
|
|
25
|
-
aicc_errors["101"]
|
|
24
|
+
aicc_errors["101"]?.basicMessage || "General error",
|
|
25
|
+
aicc_errors["101"]?.detailMessage,
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -15,14 +15,14 @@ export class Scorm12ValidationError extends ValidationError {
|
|
|
15
15
|
if ({}.hasOwnProperty.call(scorm12_errors, String(errorCode))) {
|
|
16
16
|
super(
|
|
17
17
|
errorCode,
|
|
18
|
-
scorm12_errors[String(errorCode)]
|
|
19
|
-
scorm12_errors[String(errorCode)]
|
|
18
|
+
scorm12_errors[String(errorCode)]?.basicMessage || "Unknown error",
|
|
19
|
+
scorm12_errors[String(errorCode)]?.detailMessage,
|
|
20
20
|
);
|
|
21
21
|
} else {
|
|
22
22
|
super(
|
|
23
23
|
101,
|
|
24
|
-
scorm12_errors["101"]
|
|
25
|
-
scorm12_errors["101"]
|
|
24
|
+
scorm12_errors["101"]?.basicMessage ?? "General error",
|
|
25
|
+
scorm12_errors["101"]?.detailMessage,
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -15,14 +15,14 @@ export class Scorm2004ValidationError extends ValidationError {
|
|
|
15
15
|
if ({}.hasOwnProperty.call(scorm2004_errors, String(errorCode))) {
|
|
16
16
|
super(
|
|
17
17
|
errorCode,
|
|
18
|
-
scorm2004_errors[String(errorCode)]
|
|
19
|
-
scorm2004_errors[String(errorCode)]
|
|
18
|
+
scorm2004_errors[String(errorCode)]?.basicMessage || "Unknown error",
|
|
19
|
+
scorm2004_errors[String(errorCode)]?.detailMessage,
|
|
20
20
|
);
|
|
21
21
|
} else {
|
|
22
22
|
super(
|
|
23
23
|
101,
|
|
24
|
-
scorm2004_errors["101"]
|
|
25
|
-
scorm2004_errors["101"]
|
|
24
|
+
scorm2004_errors["101"]?.basicMessage || "General error",
|
|
25
|
+
scorm2004_errors["101"]?.detailMessage,
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
}
|
package/src/utilities.ts
CHANGED
|
@@ -68,7 +68,7 @@ export function getSecondsAsISODuration(seconds: number | null): string {
|
|
|
68
68
|
let duration = "P";
|
|
69
69
|
let remainder = seconds;
|
|
70
70
|
for (const designationsKey in designations) {
|
|
71
|
-
const current_seconds = designations[designationsKey];
|
|
71
|
+
const current_seconds = designations[designationsKey] || 1;
|
|
72
72
|
let value = Math.floor(remainder / current_seconds);
|
|
73
73
|
remainder = remainder % current_seconds;
|
|
74
74
|
|
|
@@ -259,7 +259,7 @@ export function unflatten(data: StringKeyMap): object {
|
|
|
259
259
|
|
|
260
260
|
while (m) {
|
|
261
261
|
cur = cur[prop] || (cur[prop] = m[2] ? [] : {});
|
|
262
|
-
prop = m[2] || m[1];
|
|
262
|
+
prop = m[2] || m[1] || "";
|
|
263
263
|
m = regex.exec(p);
|
|
264
264
|
}
|
|
265
265
|
|
|
@@ -278,7 +278,7 @@ export function unflatten(data: StringKeyMap): object {
|
|
|
278
278
|
export function countDecimals(num: number): number {
|
|
279
279
|
if (Math.floor(num) === num || String(num).indexOf(".") < 0) return 0;
|
|
280
280
|
const parts = num.toString().split(".")[1];
|
|
281
|
-
return parts
|
|
281
|
+
return parts?.length || 0;
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
/**
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { expect } from "expect";
|
|
2
|
+
import * as sinon from "sinon";
|
|
3
|
+
import { Scorm12API } from "../src/Scorm12API";
|
|
4
|
+
import { global_constants } from "../src/constants/api_constants";
|
|
5
|
+
|
|
6
|
+
describe("BaseAPI requestHandler Tests", () => {
|
|
7
|
+
let api: Scorm12API;
|
|
8
|
+
let requestHandlerSpy: sinon.SinonSpy;
|
|
9
|
+
let fetchStub: sinon.SinonStub;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// Stub the global fetch to prevent actual HTTP requests
|
|
13
|
+
fetchStub = sinon.stub(global, "fetch");
|
|
14
|
+
fetchStub.resolves(
|
|
15
|
+
new Response(
|
|
16
|
+
JSON.stringify({
|
|
17
|
+
result: global_constants.SCORM_TRUE,
|
|
18
|
+
errorCode: 0,
|
|
19
|
+
}),
|
|
20
|
+
{
|
|
21
|
+
status: 200,
|
|
22
|
+
headers: { "Content-Type": "application/json" },
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Create a spy for requestHandler
|
|
28
|
+
requestHandlerSpy = sinon.spy((params) => {
|
|
29
|
+
// Add a marker to verify the handler was called
|
|
30
|
+
if (typeof params === "object" && !Array.isArray(params)) {
|
|
31
|
+
params._requestHandlerCalled = true;
|
|
32
|
+
}
|
|
33
|
+
return params;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Initialize API with requestHandler
|
|
37
|
+
api = new Scorm12API({
|
|
38
|
+
lmsCommitUrl: "http://example.com/commit",
|
|
39
|
+
requestHandler: requestHandlerSpy,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
sinon.restore();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("requestHandler with immediate requests", () => {
|
|
48
|
+
it("should call requestHandler during normal commit", async () => {
|
|
49
|
+
api.lmsInitialize();
|
|
50
|
+
api.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
51
|
+
|
|
52
|
+
// Force a commit
|
|
53
|
+
await api.lmsCommit();
|
|
54
|
+
|
|
55
|
+
// Wait a bit for async operations
|
|
56
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
57
|
+
|
|
58
|
+
expect(requestHandlerSpy.calledOnce).toBe(true);
|
|
59
|
+
|
|
60
|
+
// Verify the params were transformed
|
|
61
|
+
const callArgs = fetchStub.firstCall.args[1];
|
|
62
|
+
const bodyData = JSON.parse(callArgs.body);
|
|
63
|
+
expect(bodyData._requestHandlerCalled).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should call requestHandler during terminate (immediate request)", async () => {
|
|
67
|
+
api.lmsInitialize();
|
|
68
|
+
api.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
69
|
+
|
|
70
|
+
// Call finish which triggers immediate commit
|
|
71
|
+
const result = api.lmsFinish();
|
|
72
|
+
expect(result).toBe(global_constants.SCORM_TRUE);
|
|
73
|
+
|
|
74
|
+
// Wait a bit for async operations
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
76
|
+
|
|
77
|
+
// requestHandler should have been called
|
|
78
|
+
expect(requestHandlerSpy.called).toBe(true);
|
|
79
|
+
|
|
80
|
+
// Verify the params were transformed even for immediate request
|
|
81
|
+
const callArgs = fetchStub.firstCall.args[1];
|
|
82
|
+
const bodyData = JSON.parse(callArgs.body);
|
|
83
|
+
expect(bodyData._requestHandlerCalled).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should pass through params when no requestHandler is provided", async () => {
|
|
87
|
+
// Create API without requestHandler
|
|
88
|
+
const apiNoHandler = new Scorm12API({
|
|
89
|
+
lmsCommitUrl: "http://example.com/commit",
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
apiNoHandler.lmsInitialize();
|
|
93
|
+
apiNoHandler.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
94
|
+
|
|
95
|
+
// Call finish
|
|
96
|
+
const result = apiNoHandler.lmsFinish();
|
|
97
|
+
expect(result).toBe(global_constants.SCORM_TRUE);
|
|
98
|
+
|
|
99
|
+
// Wait a bit for async operations
|
|
100
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
101
|
+
|
|
102
|
+
// Verify fetch was called but params don't have the marker
|
|
103
|
+
expect(fetchStub.called).toBe(true);
|
|
104
|
+
const callArgs = fetchStub.firstCall.args[1];
|
|
105
|
+
const bodyData = JSON.parse(callArgs.body);
|
|
106
|
+
expect(bodyData._requestHandlerCalled).toBeUndefined();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should handle requestHandler errors gracefully", async () => {
|
|
110
|
+
// Create API with error-throwing requestHandler
|
|
111
|
+
const errorApi = new Scorm12API({
|
|
112
|
+
lmsCommitUrl: "http://example.com/commit",
|
|
113
|
+
requestHandler: () => {
|
|
114
|
+
throw new Error("RequestHandler error");
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
errorApi.lmsInitialize();
|
|
119
|
+
errorApi.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
120
|
+
|
|
121
|
+
// Call finish - should not throw
|
|
122
|
+
const result = errorApi.lmsFinish();
|
|
123
|
+
expect(result).toBe(global_constants.SCORM_TRUE);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|