scorm-again 2.0.0 → 2.1.0

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.
Files changed (77) hide show
  1. package/.github/workflows/stale.yml +14 -0
  2. package/.run/{Mocha Unit Tests.run.xml → Mocha Unit Tests (watch).run.xml } +1 -1
  3. package/.run/Template Mocha.run.xml +17 -0
  4. package/README.md +171 -72
  5. package/dist/aicc.js +1441 -1140
  6. package/dist/aicc.js.map +1 -1
  7. package/dist/aicc.min.js +1 -1
  8. package/dist/aicc.min.js.map +1 -1
  9. package/dist/scorm-again.js +2703 -2212
  10. package/dist/scorm-again.js.map +1 -1
  11. package/dist/scorm-again.min.js +1 -1
  12. package/dist/scorm-again.min.js.map +1 -1
  13. package/dist/scorm12.js +1069 -852
  14. package/dist/scorm12.js.map +1 -1
  15. package/dist/scorm12.min.js +1 -1
  16. package/dist/scorm12.min.js.map +1 -1
  17. package/dist/scorm2004.js +1861 -1571
  18. package/dist/scorm2004.js.map +1 -1
  19. package/dist/scorm2004.min.js +1 -1
  20. package/dist/scorm2004.min.js.map +1 -1
  21. package/package.json +10 -6
  22. package/src/AICC.ts +15 -17
  23. package/src/BaseAPI.ts +268 -417
  24. package/src/Scorm12API.ts +65 -38
  25. package/src/Scorm2004API.ts +151 -117
  26. package/src/cmi/aicc/attempts.ts +94 -0
  27. package/src/cmi/aicc/cmi.ts +100 -0
  28. package/src/cmi/aicc/core.ts +360 -0
  29. package/src/cmi/aicc/evaluation.ts +157 -0
  30. package/src/cmi/aicc/paths.ts +180 -0
  31. package/src/cmi/aicc/student_data.ts +86 -0
  32. package/src/cmi/aicc/student_demographics.ts +367 -0
  33. package/src/cmi/aicc/student_preferences.ts +176 -0
  34. package/src/cmi/aicc/tries.ts +116 -0
  35. package/src/cmi/aicc/validation.ts +25 -0
  36. package/src/cmi/common/array.ts +77 -0
  37. package/src/cmi/common/base_cmi.ts +46 -0
  38. package/src/cmi/common/score.ts +203 -0
  39. package/src/cmi/common/validation.ts +60 -0
  40. package/src/cmi/scorm12/cmi.ts +224 -0
  41. package/src/cmi/scorm12/interactions.ts +368 -0
  42. package/src/cmi/scorm12/nav.ts +54 -0
  43. package/src/cmi/scorm12/objectives.ts +112 -0
  44. package/src/cmi/scorm12/student_data.ts +130 -0
  45. package/src/cmi/scorm12/student_preference.ts +158 -0
  46. package/src/cmi/scorm12/validation.ts +48 -0
  47. package/src/cmi/scorm2004/adl.ts +272 -0
  48. package/src/cmi/scorm2004/cmi.ts +599 -0
  49. package/src/cmi/scorm2004/comments.ts +163 -0
  50. package/src/cmi/scorm2004/interactions.ts +466 -0
  51. package/src/cmi/scorm2004/learner_preference.ts +152 -0
  52. package/src/cmi/scorm2004/objectives.ts +212 -0
  53. package/src/cmi/scorm2004/score.ts +78 -0
  54. package/src/cmi/scorm2004/validation.ts +42 -0
  55. package/src/constants/default_settings.ts +81 -0
  56. package/src/constants/enums.ts +5 -0
  57. package/src/constants/regex.ts +2 -2
  58. package/src/constants/response_constants.ts +2 -0
  59. package/src/exceptions.ts +22 -1
  60. package/src/helpers/scheduled_commit.ts +42 -0
  61. package/src/interfaces/IBaseAPI.ts +35 -0
  62. package/src/types/api_types.ts +32 -0
  63. package/src/utilities/debounce.ts +31 -0
  64. package/src/utilities.ts +56 -0
  65. package/test/AICC.spec.ts +11 -1
  66. package/test/Scorm12API.spec.ts +262 -9
  67. package/test/Scorm2004API.spec.ts +488 -2
  68. package/test/cmi/aicc_cmi.spec.ts +188 -11
  69. package/test/cmi/scorm12_cmi.spec.ts +5 -5
  70. package/test/cmi/scorm2004_cmi.spec.ts +8 -8
  71. package/test/cmi_helpers.ts +1 -1
  72. package/test/types/api_types.spec.ts +126 -0
  73. package/test/utilities/debounce.spec.ts +56 -0
  74. package/src/cmi/aicc_cmi.ts +0 -1248
  75. package/src/cmi/common.ts +0 -411
  76. package/src/cmi/scorm12_cmi.ts +0 -1426
  77. package/src/cmi/scorm2004_cmi.ts +0 -1874
@@ -0,0 +1,163 @@
1
+ import { CMIArray } from "../common/array";
2
+ import APIConstants from "../../constants/api_constants";
3
+ import ErrorCodes from "../../constants/error_codes";
4
+ import { Scorm2004ValidationError } from "../../exceptions";
5
+ import { BaseCMI } from "../common/base_cmi";
6
+ import { check2004ValidFormat } from "./validation";
7
+ import Regex from "../../constants/regex";
8
+
9
+ /**
10
+ * Class representing SCORM 2004's cmi.comments_from_lms object
11
+ * @extends CMIArray
12
+ */
13
+ export class CMICommentsFromLMS extends CMIArray {
14
+ /**
15
+ * Constructor for cmi.comments_from_lms Array
16
+ */
17
+ constructor() {
18
+ super({
19
+ children: APIConstants.scorm2004.comments_children,
20
+ errorCode: ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
21
+ errorClass: Scorm2004ValidationError,
22
+ });
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Class representing SCORM 2004's cmi.comments_from_learner object
28
+ */
29
+
30
+ export class CMICommentsFromLearner extends CMIArray {
31
+ /**
32
+ * Constructor for cmi.comments_from_learner Array
33
+ */
34
+ constructor() {
35
+ super({
36
+ children: APIConstants.scorm2004.comments_children,
37
+ errorCode: ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
38
+ errorClass: Scorm2004ValidationError,
39
+ });
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Class representing SCORM 2004's cmi.comments_from_learner.n and cmi.comments_from_lms.n object
45
+ */
46
+
47
+ export class CMICommentsObject extends BaseCMI {
48
+ private _comment = "";
49
+ private _location = "";
50
+ private _timestamp = "";
51
+ private readonly _readOnlyAfterInit: boolean;
52
+
53
+ /**
54
+ * Constructor for cmi.comments_from_learner.n and cmi.comments_from_lms.n
55
+ * @param {boolean} readOnlyAfterInit
56
+ */
57
+ constructor(readOnlyAfterInit: boolean = false) {
58
+ super();
59
+ this._comment = "";
60
+ this._location = "";
61
+ this._timestamp = "";
62
+ this._readOnlyAfterInit = readOnlyAfterInit;
63
+ }
64
+
65
+ /**
66
+ * Getter for _comment
67
+ * @return {string}
68
+ */
69
+ get comment(): string {
70
+ return this._comment;
71
+ }
72
+
73
+ /**
74
+ * Setter for _comment
75
+ * @param {string} comment
76
+ */
77
+ set comment(comment: string) {
78
+ if (this.initialized && this._readOnlyAfterInit) {
79
+ throw new Scorm2004ValidationError(
80
+ ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
81
+ );
82
+ } else {
83
+ if (
84
+ check2004ValidFormat(comment, Regex.scorm2004.CMILangString4000, true)
85
+ ) {
86
+ this._comment = comment;
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Getter for _location
93
+ * @return {string}
94
+ */
95
+ get location(): string {
96
+ return this._location;
97
+ }
98
+
99
+ /**
100
+ * Setter for _location
101
+ * @param {string} location
102
+ */
103
+ set location(location: string) {
104
+ if (this.initialized && this._readOnlyAfterInit) {
105
+ throw new Scorm2004ValidationError(
106
+ ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
107
+ );
108
+ } else {
109
+ if (check2004ValidFormat(location, Regex.scorm2004.CMIString250)) {
110
+ this._location = location;
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Getter for _timestamp
117
+ * @return {string}
118
+ */
119
+ get timestamp(): string {
120
+ return this._timestamp;
121
+ }
122
+
123
+ /**
124
+ * Setter for _timestamp
125
+ * @param {string} timestamp
126
+ */
127
+ set timestamp(timestamp: string) {
128
+ if (this.initialized && this._readOnlyAfterInit) {
129
+ throw new Scorm2004ValidationError(
130
+ ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
131
+ );
132
+ } else {
133
+ if (check2004ValidFormat(timestamp, Regex.scorm2004.CMITime)) {
134
+ this._timestamp = timestamp;
135
+ }
136
+ }
137
+ }
138
+
139
+ /**
140
+ * toJSON for cmi.comments_from_learner.n object
141
+ * @return {
142
+ * {
143
+ * comment: string,
144
+ * location: string,
145
+ * timestamp: string
146
+ * }
147
+ * }
148
+ */
149
+ toJSON(): {
150
+ comment: string;
151
+ location: string;
152
+ timestamp: string;
153
+ } {
154
+ this.jsonString = true;
155
+ const result = {
156
+ comment: this.comment,
157
+ location: this.location,
158
+ timestamp: this.timestamp,
159
+ };
160
+ delete this.jsonString;
161
+ return result;
162
+ }
163
+ }
@@ -0,0 +1,466 @@
1
+ /**
2
+ * Class representing SCORM 2004's `cmi.interactions` object
3
+ */
4
+ import { BaseCMI } from "../common/base_cmi";
5
+ import { CMIArray } from "../common/array";
6
+ import ErrorCodes from "../../constants/error_codes";
7
+ import { Scorm2004ValidationError } from "../../exceptions";
8
+ import APIConstants from "../../constants/api_constants";
9
+ import { check2004ValidFormat } from "./validation";
10
+ import Regex from "../../constants/regex";
11
+ import { LearnerResponses } from "../../constants/response_constants";
12
+
13
+ export class CMIInteractions extends CMIArray {
14
+ /**
15
+ * Constructor for `cmi.objectives` Array
16
+ */
17
+ constructor() {
18
+ super({
19
+ children: APIConstants.scorm2004.interactions_children,
20
+ errorCode: ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
21
+ errorClass: Scorm2004ValidationError,
22
+ });
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Class for SCORM 2004's cmi.interaction.n object
28
+ */
29
+
30
+ export class CMIInteractionsObject extends BaseCMI {
31
+ private _id = "";
32
+ private _type = "";
33
+ private _timestamp = "";
34
+ private _weighting = "";
35
+ private _learner_response = "";
36
+ private _result = "";
37
+ private _latency = "";
38
+ private _description = "";
39
+
40
+ /**
41
+ * Constructor for cmi.interaction.n
42
+ */
43
+ constructor() {
44
+ super();
45
+ this.objectives = new CMIArray({
46
+ errorCode: ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
47
+ errorClass: Scorm2004ValidationError,
48
+ children: APIConstants.scorm2004.objectives_children,
49
+ });
50
+ this.correct_responses = new CMIArray({
51
+ errorCode: ErrorCodes.scorm2004.READ_ONLY_ELEMENT,
52
+ errorClass: Scorm2004ValidationError,
53
+ children: APIConstants.scorm2004.correct_responses_children,
54
+ });
55
+ }
56
+
57
+ public objectives: CMIArray;
58
+ public correct_responses: CMIArray;
59
+
60
+ /**
61
+ * Called when the API has been initialized after the CMI has been created
62
+ */
63
+ initialize() {
64
+ super.initialize();
65
+ this.objectives?.initialize();
66
+ this.correct_responses?.initialize();
67
+ }
68
+
69
+ /**
70
+ * Getter for _id
71
+ * @return {string}
72
+ */
73
+ get id(): string {
74
+ return this._id;
75
+ }
76
+
77
+ /**
78
+ * Setter for _id
79
+ * @param {string} id
80
+ */
81
+ set id(id: string) {
82
+ if (check2004ValidFormat(id, Regex.scorm2004.CMILongIdentifier)) {
83
+ this._id = id;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Getter for _type
89
+ * @return {string}
90
+ */
91
+ get type(): string {
92
+ return this._type;
93
+ }
94
+
95
+ /**
96
+ * Setter for _type
97
+ * @param {string} type
98
+ */
99
+ set type(type: string) {
100
+ if (this.initialized && this._id === "") {
101
+ throw new Scorm2004ValidationError(
102
+ ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED,
103
+ );
104
+ } else {
105
+ if (check2004ValidFormat(type, Regex.scorm2004.CMIType)) {
106
+ this._type = type;
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Getter for _timestamp
113
+ * @return {string}
114
+ */
115
+ get timestamp(): string {
116
+ return this._timestamp;
117
+ }
118
+
119
+ /**
120
+ * Setter for _timestamp
121
+ * @param {string} timestamp
122
+ */
123
+ set timestamp(timestamp: string) {
124
+ if (this.initialized && this._id === "") {
125
+ throw new Scorm2004ValidationError(
126
+ ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED,
127
+ );
128
+ } else {
129
+ if (check2004ValidFormat(timestamp, Regex.scorm2004.CMITime)) {
130
+ this._timestamp = timestamp;
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Getter for _weighting
137
+ * @return {string}
138
+ */
139
+ get weighting(): string {
140
+ return this._weighting;
141
+ }
142
+
143
+ /**
144
+ * Setter for _weighting
145
+ * @param {string} weighting
146
+ */
147
+ set weighting(weighting: string) {
148
+ if (this.initialized && this._id === "") {
149
+ throw new Scorm2004ValidationError(
150
+ ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED,
151
+ );
152
+ } else {
153
+ if (check2004ValidFormat(weighting, Regex.scorm2004.CMIDecimal)) {
154
+ this._weighting = weighting;
155
+ }
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Getter for _learner_response
161
+ * @return {string}
162
+ */
163
+ get learner_response(): string {
164
+ return this._learner_response;
165
+ }
166
+
167
+ /**
168
+ * Setter for _learner_response. Does type validation to make sure response
169
+ * matches SCORM 2004's spec
170
+ * @param {string} learner_response
171
+ */
172
+ set learner_response(learner_response: string) {
173
+ if (this.initialized && (this._type === "" || this._id === "")) {
174
+ throw new Scorm2004ValidationError(
175
+ ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED,
176
+ );
177
+ } else {
178
+ let nodes = [];
179
+ const response_type = LearnerResponses[this.type];
180
+
181
+ if (response_type) {
182
+ if (response_type?.delimiter) {
183
+ nodes = learner_response.split(response_type.delimiter);
184
+ } else {
185
+ nodes[0] = learner_response;
186
+ }
187
+
188
+ if (nodes.length > 0 && nodes.length <= response_type.max) {
189
+ const formatRegex = new RegExp(response_type.format);
190
+
191
+ for (let i = 0; i < nodes.length; i++) {
192
+ if (response_type?.delimiter2) {
193
+ const values = nodes[i].split(response_type.delimiter2);
194
+
195
+ if (values.length === 2) {
196
+ if (!values[0].match(formatRegex)) {
197
+ throw new Scorm2004ValidationError(
198
+ ErrorCodes.scorm2004.TYPE_MISMATCH,
199
+ );
200
+ } else {
201
+ if (
202
+ !response_type.format2 ||
203
+ !values[1].match(new RegExp(response_type.format2))
204
+ ) {
205
+ throw new Scorm2004ValidationError(
206
+ ErrorCodes.scorm2004.TYPE_MISMATCH,
207
+ );
208
+ }
209
+ }
210
+ } else {
211
+ throw new Scorm2004ValidationError(
212
+ ErrorCodes.scorm2004.TYPE_MISMATCH,
213
+ );
214
+ }
215
+ } else {
216
+ if (!nodes[i].match(formatRegex)) {
217
+ throw new Scorm2004ValidationError(
218
+ ErrorCodes.scorm2004.TYPE_MISMATCH,
219
+ );
220
+ } else {
221
+ if (nodes[i] !== "" && response_type.unique) {
222
+ for (let j = 0; j < i; j++) {
223
+ if (nodes[i] === nodes[j]) {
224
+ throw new Scorm2004ValidationError(
225
+ ErrorCodes.scorm2004.TYPE_MISMATCH,
226
+ );
227
+ }
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ } else {
234
+ throw new Scorm2004ValidationError(
235
+ ErrorCodes.scorm2004.GENERAL_SET_FAILURE,
236
+ );
237
+ }
238
+
239
+ this._learner_response = learner_response;
240
+ } else {
241
+ throw new Scorm2004ValidationError(ErrorCodes.scorm2004.TYPE_MISMATCH);
242
+ }
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Getter for _result
248
+ * @return {string}
249
+ */
250
+ get result(): string {
251
+ return this._result;
252
+ }
253
+
254
+ /**
255
+ * Setter for _result
256
+ * @param {string} result
257
+ */
258
+ set result(result: string) {
259
+ if (check2004ValidFormat(result, Regex.scorm2004.CMIResult)) {
260
+ this._result = result;
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Getter for _latency
266
+ * @return {string}
267
+ */
268
+ get latency(): string {
269
+ return this._latency;
270
+ }
271
+
272
+ /**
273
+ * Setter for _latency
274
+ * @param {string} latency
275
+ */
276
+ set latency(latency: string) {
277
+ if (this.initialized && this._id === "") {
278
+ throw new Scorm2004ValidationError(
279
+ ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED,
280
+ );
281
+ } else {
282
+ if (check2004ValidFormat(latency, Regex.scorm2004.CMITimespan)) {
283
+ this._latency = latency;
284
+ }
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Getter for _description
290
+ * @return {string}
291
+ */
292
+ get description(): string {
293
+ return this._description;
294
+ }
295
+
296
+ /**
297
+ * Setter for _description
298
+ * @param {string} description
299
+ */
300
+ set description(description: string) {
301
+ if (this.initialized && this._id === "") {
302
+ throw new Scorm2004ValidationError(
303
+ ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED,
304
+ );
305
+ } else {
306
+ if (
307
+ check2004ValidFormat(
308
+ description,
309
+ Regex.scorm2004.CMILangString250,
310
+ true,
311
+ )
312
+ ) {
313
+ this._description = description;
314
+ }
315
+ }
316
+ }
317
+
318
+ /**
319
+ * toJSON for cmi.interactions.n
320
+ *
321
+ * @return {
322
+ * {
323
+ * id: string,
324
+ * type: string,
325
+ * objectives: CMIArray,
326
+ * timestamp: string,
327
+ * correct_responses: CMIArray,
328
+ * weighting: string,
329
+ * learner_response: string,
330
+ * result: string,
331
+ * latency: string,
332
+ * description: string
333
+ * }
334
+ * }
335
+ */
336
+ toJSON(): {
337
+ id: string;
338
+ type: string;
339
+ objectives: CMIArray;
340
+ timestamp: string;
341
+ correct_responses: CMIArray;
342
+ weighting: string;
343
+ learner_response: string;
344
+ result: string;
345
+ latency: string;
346
+ description: string;
347
+ } {
348
+ this.jsonString = true;
349
+ const result = {
350
+ id: this.id,
351
+ type: this.type,
352
+ objectives: this.objectives,
353
+ timestamp: this.timestamp,
354
+ weighting: this.weighting,
355
+ learner_response: this.learner_response,
356
+ result: this.result,
357
+ latency: this.latency,
358
+ description: this.description,
359
+ correct_responses: this.correct_responses,
360
+ };
361
+ delete this.jsonString;
362
+ return result;
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Class representing SCORM 2004's cmi.interactions.n.objectives.n object
368
+ */
369
+ export class CMIInteractionsObjectivesObject extends BaseCMI {
370
+ private _id = "";
371
+
372
+ /**
373
+ * Constructor for cmi.interactions.n.objectives.n
374
+ */
375
+ constructor() {
376
+ super();
377
+ }
378
+
379
+ /**
380
+ * Getter for _id
381
+ * @return {string}
382
+ */
383
+ get id(): string {
384
+ return this._id;
385
+ }
386
+
387
+ /**
388
+ * Setter for _id
389
+ * @param {string} id
390
+ */
391
+ set id(id: string) {
392
+ if (check2004ValidFormat(id, Regex.scorm2004.CMILongIdentifier)) {
393
+ this._id = id;
394
+ }
395
+ }
396
+
397
+ /**
398
+ * toJSON for cmi.interactions.n.objectives.n
399
+ * @return {
400
+ * {
401
+ * id: string
402
+ * }
403
+ * }
404
+ */
405
+ toJSON(): {
406
+ id: string;
407
+ } {
408
+ this.jsonString = true;
409
+ const result = {
410
+ id: this.id,
411
+ };
412
+ delete this.jsonString;
413
+ return result;
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Class representing SCORM 2004's cmi.interactions.n.correct_responses.n object
419
+ */
420
+ export class CMIInteractionsCorrectResponsesObject extends BaseCMI {
421
+ private _pattern = "";
422
+
423
+ /**
424
+ * Constructor for cmi.interactions.n.correct_responses.n
425
+ */
426
+ constructor() {
427
+ super();
428
+ }
429
+
430
+ /**
431
+ * Getter for _pattern
432
+ * @return {string}
433
+ */
434
+ get pattern(): string {
435
+ return this._pattern;
436
+ }
437
+
438
+ /**
439
+ * Setter for _pattern
440
+ * @param {string} pattern
441
+ */
442
+ set pattern(pattern: string) {
443
+ if (check2004ValidFormat(pattern, Regex.scorm2004.CMIFeedback)) {
444
+ this._pattern = pattern;
445
+ }
446
+ }
447
+
448
+ /**
449
+ * toJSON cmi.interactions.n.correct_responses.n object
450
+ * @return {
451
+ * {
452
+ * pattern: string
453
+ * }
454
+ * }
455
+ */
456
+ toJSON(): {
457
+ pattern: string;
458
+ } {
459
+ this.jsonString = true;
460
+ const result = {
461
+ pattern: this.pattern,
462
+ };
463
+ delete this.jsonString;
464
+ return result;
465
+ }
466
+ }