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
package/src/Scorm12API.ts CHANGED
@@ -1,20 +1,19 @@
1
- import BaseAPI, { RefObject, ResultObject, Settings } from "./BaseAPI";
1
+ import BaseAPI from "./BaseAPI";
2
+ import { CMI } from "./cmi/scorm12/cmi";
3
+ import * as Utilities from "./utilities";
4
+ import APIConstants from "./constants/api_constants";
5
+ import ErrorCodes from "./constants/error_codes";
6
+
7
+ import { BaseCMI } from "./cmi/common/base_cmi";
8
+ import { CMIObjectivesObject } from "./cmi/scorm12/objectives";
2
9
  import {
3
- CMI,
4
10
  CMIInteractionsCorrectResponsesObject,
5
11
  CMIInteractionsObject,
6
12
  CMIInteractionsObjectivesObject,
7
- CMIObjectivesObject,
8
- NAV,
9
- } from "./cmi/scorm12_cmi";
10
- import * as Utilities from "./utilities";
11
- import APIConstants from "./constants/api_constants";
12
- import ErrorCodes, { ErrorCode } from "./constants/error_codes";
13
- import { BaseCMI } from "./cmi/common";
14
-
15
- const scorm12_constants = APIConstants.scorm12;
16
- const global_constants = APIConstants.global;
17
- const scorm12_error_codes: ErrorCode = ErrorCodes.scorm12;
13
+ } from "./cmi/scorm12/interactions";
14
+ import { NAV } from "./cmi/scorm12/nav";
15
+ import { RefObject, ResultObject, Settings } from "./types/api_types";
16
+ import { stringMatches } from "./utilities";
18
17
 
19
18
  /**
20
19
  * API class for SCORM 1.2
@@ -31,7 +30,7 @@ export default class Scorm12API extends BaseAPI {
31
30
  }
32
31
  }
33
32
 
34
- super(scorm12_error_codes, settings);
33
+ super(ErrorCodes.scorm12, settings);
35
34
 
36
35
  this.cmi = new CMI();
37
36
  this.nav = new NAV();
@@ -47,6 +46,8 @@ export default class Scorm12API extends BaseAPI {
47
46
  this.LMSGetDiagnostic = this.lmsGetDiagnostic;
48
47
  }
49
48
 
49
+ public statusSetByModule = false;
50
+
50
51
  public cmi: CMI;
51
52
  public nav: NAV;
52
53
 
@@ -59,6 +60,16 @@ export default class Scorm12API extends BaseAPI {
59
60
  public LMSGetErrorString: (CMIErrorCode: string) => string;
60
61
  public LMSGetDiagnostic: (CMIErrorCode: string) => string;
61
62
 
63
+ /**
64
+ * Called when the API needs to be reset
65
+ */
66
+ reset(settings?: Settings) {
67
+ this.commonReset(settings);
68
+
69
+ this.cmi = new CMI();
70
+ this.nav = new NAV();
71
+ }
72
+
62
73
  /**
63
74
  * lmsInitialize function from SCORM 1.2 Spec
64
75
  *
@@ -66,6 +77,11 @@ export default class Scorm12API extends BaseAPI {
66
77
  */
67
78
  lmsInitialize(): string {
68
79
  this.cmi.initialize();
80
+ if (this.cmi.core.lesson_status) {
81
+ this.statusSetByModule = true;
82
+ } else {
83
+ this.cmi.core.lesson_status = "not attempted";
84
+ }
69
85
  return this.initialize(
70
86
  "LMSInitialize",
71
87
  "LMS was already initialized!",
@@ -79,9 +95,16 @@ export default class Scorm12API extends BaseAPI {
79
95
  * @return {string} bool
80
96
  */
81
97
  lmsFinish(): string {
82
- const result = this.terminate("LMSFinish", true);
98
+ (async () => {
99
+ await this.internalFinish();
100
+ })();
101
+ return APIConstants.global.SCORM_TRUE;
102
+ }
103
+
104
+ async internalFinish(): Promise<string> {
105
+ const result = await this.terminate("LMSFinish", true);
83
106
 
84
- if (result === global_constants.SCORM_TRUE) {
107
+ if (result === APIConstants.global.SCORM_TRUE) {
85
108
  if (this.nav.event !== "") {
86
109
  if (this.nav.event === "continue") {
87
110
  this.processListeners("SequenceNext");
@@ -114,6 +137,9 @@ export default class Scorm12API extends BaseAPI {
114
137
  * @return {string}
115
138
  */
116
139
  lmsSetValue(CMIElement: string, value: any): string {
140
+ if (CMIElement === "cmi.core.lesson_status") {
141
+ this.statusSetByModule = true;
142
+ }
117
143
  return this.setValue("LMSSetValue", "LMSCommit", false, CMIElement, value);
118
144
  }
119
145
 
@@ -123,7 +149,10 @@ export default class Scorm12API extends BaseAPI {
123
149
  * @return {string} bool
124
150
  */
125
151
  lmsCommit(): string {
126
- return this.commit("LMSCommit", false);
152
+ (async () => {
153
+ await this.commit("LMSCommit", false);
154
+ })();
155
+ return APIConstants.global.SCORM_TRUE;
127
156
  }
128
157
 
129
158
  /**
@@ -189,11 +218,11 @@ export default class Scorm12API extends BaseAPI {
189
218
  _value: any,
190
219
  foundFirstIndex: boolean,
191
220
  ): BaseCMI | null {
192
- if (this.stringMatches(CMIElement, "cmi\\.objectives\\.\\d+")) {
221
+ if (stringMatches(CMIElement, "cmi\\.objectives\\.\\d+")) {
193
222
  return new CMIObjectivesObject();
194
223
  } else if (
195
224
  foundFirstIndex &&
196
- this.stringMatches(
225
+ stringMatches(
197
226
  CMIElement,
198
227
  "cmi\\.interactions\\.\\d+\\.correct_responses\\.\\d+",
199
228
  )
@@ -201,15 +230,12 @@ export default class Scorm12API extends BaseAPI {
201
230
  return new CMIInteractionsCorrectResponsesObject();
202
231
  } else if (
203
232
  foundFirstIndex &&
204
- this.stringMatches(
205
- CMIElement,
206
- "cmi\\.interactions\\.\\d+\\.objectives\\.\\d+",
207
- )
233
+ stringMatches(CMIElement, "cmi\\.interactions\\.\\d+\\.objectives\\.\\d+")
208
234
  ) {
209
235
  return new CMIInteractionsObjectivesObject();
210
236
  } else if (
211
237
  !foundFirstIndex &&
212
- this.stringMatches(CMIElement, "cmi\\.interactions\\.\\d+")
238
+ stringMatches(CMIElement, "cmi\\.interactions\\.\\d+")
213
239
  ) {
214
240
  return new CMIInteractionsObject();
215
241
  }
@@ -243,11 +269,11 @@ export default class Scorm12API extends BaseAPI {
243
269
 
244
270
  // Set error number to string since inconsistent from modules if string or number
245
271
  errorNumber = String(errorNumber);
246
- if (scorm12_constants.error_descriptions[errorNumber]) {
272
+ if (APIConstants.scorm12.error_descriptions[errorNumber]) {
247
273
  basicMessage =
248
- scorm12_constants.error_descriptions[errorNumber].basicMessage;
274
+ APIConstants.scorm12.error_descriptions[errorNumber].basicMessage;
249
275
  detailMessage =
250
- scorm12_constants.error_descriptions[errorNumber].detailMessage;
276
+ APIConstants.scorm12.error_descriptions[errorNumber].detailMessage;
251
277
  }
252
278
 
253
279
  return detail ? detailMessage : basicMessage;
@@ -300,10 +326,14 @@ export default class Scorm12API extends BaseAPI {
300
326
  * @param {boolean} terminateCommit
301
327
  * @return {ResultObject}
302
328
  */
303
- storeData(terminateCommit: boolean): ResultObject {
329
+ async storeData(terminateCommit: boolean): Promise<ResultObject> {
304
330
  if (terminateCommit) {
305
331
  const originalStatus = this.cmi.core.lesson_status;
306
- if (originalStatus === "not attempted") {
332
+ if (
333
+ !this.cmi.core.lesson_status ||
334
+ (!this.statusSetByModule &&
335
+ this.cmi.core.lesson_status === "not attempted")
336
+ ) {
307
337
  this.cmi.core.lesson_status = "completed";
308
338
  }
309
339
 
@@ -314,14 +344,11 @@ export default class Scorm12API extends BaseAPI {
314
344
  this.cmi.student_data.mastery_score !== "" &&
315
345
  this.cmi.core.score.raw !== ""
316
346
  ) {
317
- if (
347
+ this.cmi.core.lesson_status =
318
348
  parseFloat(this.cmi.core.score.raw) >=
319
349
  parseFloat(this.cmi.student_data.mastery_score)
320
- ) {
321
- this.cmi.core.lesson_status = "passed";
322
- } else {
323
- this.cmi.core.lesson_status = "failed";
324
- }
350
+ ? "passed"
351
+ : "failed";
325
352
  }
326
353
  }
327
354
  } else if (this.cmi.core.lesson_mode === "browse") {
@@ -338,21 +365,21 @@ export default class Scorm12API extends BaseAPI {
338
365
  terminateCommit || this.settings.alwaysSendTotalTime,
339
366
  );
340
367
 
341
- if (this.apiLogLevel === global_constants.LOG_LEVEL_DEBUG) {
368
+ if (this.apiLogLevel === APIConstants.global.LOG_LEVEL_DEBUG) {
342
369
  console.debug(
343
370
  "Commit (terminated: " + (terminateCommit ? "yes" : "no") + "): ",
344
371
  );
345
372
  console.debug(commitObject);
346
373
  }
347
374
  if (typeof this.settings.lmsCommitUrl === "string") {
348
- return this.processHttpRequest(
375
+ return await this.processHttpRequest(
349
376
  this.settings.lmsCommitUrl,
350
377
  commitObject,
351
378
  terminateCommit,
352
379
  );
353
380
  } else {
354
381
  return {
355
- result: global_constants.SCORM_TRUE,
382
+ result: APIConstants.global.SCORM_TRUE,
356
383
  errorCode: 0,
357
384
  };
358
385
  }
@@ -1,26 +1,24 @@
1
- import BaseAPI, { RefObject, ResultObject, Settings } from "./BaseAPI";
2
- import {
3
- ADL,
4
- CMI,
5
- CMICommentsObject,
6
- CMIInteractionsCorrectResponsesObject,
7
- CMIInteractionsObject,
8
- CMIInteractionsObjectivesObject,
9
- CMIObjectivesObject,
10
- } from "./cmi/scorm2004_cmi";
1
+ import BaseAPI from "./BaseAPI";
2
+ import { CMI } from "./cmi/scorm2004/cmi";
11
3
  import * as Utilities from "./utilities";
4
+ import { stringMatches } from "./utilities";
12
5
  import APIConstants from "./constants/api_constants";
13
6
  import ErrorCodes from "./constants/error_codes";
14
7
  import { CorrectResponses, ResponseType } from "./constants/response_constants";
15
8
  import ValidLanguages from "./constants/language_constants";
16
9
  import Regex from "./constants/regex";
17
- import { BaseCMI, CMIArray } from "./cmi/common";
18
-
19
- const scorm2004_constants = APIConstants.scorm2004;
20
- const global_constants = APIConstants.global;
21
- const scorm2004_error_codes = ErrorCodes.scorm2004;
22
- const correct_responses = CorrectResponses;
23
- const scorm2004_regex = Regex.scorm2004;
10
+ import regex from "./constants/regex";
11
+ import { CMIArray } from "./cmi/common/array";
12
+ import { BaseCMI } from "./cmi/common/base_cmi";
13
+ import {
14
+ CMIInteractionsCorrectResponsesObject,
15
+ CMIInteractionsObject,
16
+ CMIInteractionsObjectivesObject,
17
+ } from "./cmi/scorm2004/interactions";
18
+ import { CMICommentsObject } from "./cmi/scorm2004/comments";
19
+ import { CMIObjectivesObject } from "./cmi/scorm2004/objectives";
20
+ import { ADL } from "./cmi/scorm2004/adl";
21
+ import { RefObject, ResultObject, Settings } from "./types/api_types";
24
22
 
25
23
  /**
26
24
  * API class for SCORM 2004
@@ -39,7 +37,7 @@ export default class Scorm2004API extends BaseAPI {
39
37
  }
40
38
  }
41
39
 
42
- super(scorm2004_error_codes, settings);
40
+ super(ErrorCodes.scorm2004, settings);
43
41
 
44
42
  this.cmi = new CMI();
45
43
  this.adl = new ADL();
@@ -67,6 +65,16 @@ export default class Scorm2004API extends BaseAPI {
67
65
  public GetErrorString: (CMIErrorCode: string | number) => string;
68
66
  public GetDiagnostic: (CMIErrorCode: string | number) => string;
69
67
 
68
+ /**
69
+ * Called when the API needs to be reset
70
+ */
71
+ reset(settings?: Settings) {
72
+ this.commonReset(settings);
73
+
74
+ this.cmi = new CMI();
75
+ this.adl = new ADL();
76
+ }
77
+
70
78
  /**
71
79
  * Getter for _version
72
80
  * @return {string}
@@ -87,32 +95,39 @@ export default class Scorm2004API extends BaseAPI {
87
95
  * @return {string} bool
88
96
  */
89
97
  lmsFinish(): string {
90
- const result = this.terminate("Terminate", true);
98
+ (async () => {
99
+ await this.internalFinish();
100
+ })();
101
+ return APIConstants.global.SCORM_TRUE;
102
+ }
103
+
104
+ async internalFinish(): Promise<string> {
105
+ const result = await this.terminate("Terminate", true);
91
106
 
92
- if (result === global_constants.SCORM_TRUE) {
107
+ if (result === APIConstants.global.SCORM_TRUE) {
93
108
  if (this.adl.nav.request !== "_none_") {
94
- switch (this.adl.nav.request) {
95
- case "continue":
96
- this.processListeners("SequenceNext");
97
- break;
98
- case "previous":
99
- this.processListeners("SequencePrevious");
100
- break;
101
- case "choice":
102
- this.processListeners("SequenceChoice");
103
- break;
104
- case "exit":
105
- this.processListeners("SequenceExit");
106
- break;
107
- case "exitAll":
108
- this.processListeners("SequenceExitAll");
109
- break;
110
- case "abandon":
111
- this.processListeners("SequenceAbandon");
112
- break;
113
- case "abandonAll":
114
- this.processListeners("SequenceAbandonAll");
115
- break;
109
+ const navActions: { [key: string]: string } = {
110
+ continue: "SequenceNext",
111
+ previous: "SequencePrevious",
112
+ choice: "SequenceChoice",
113
+ jump: "SequenceJump",
114
+ exit: "SequenceExit",
115
+ exitAll: "SequenceExitAll",
116
+ abandon: "SequenceAbandon",
117
+ abandonAll: "SequenceAbandonAll",
118
+ };
119
+
120
+ let request = this.adl.nav.request;
121
+ const choiceJumpRegex = new RegExp(regex.scorm2004.NAVEvent);
122
+ const matches = request.match(choiceJumpRegex);
123
+ let target = "";
124
+ if (matches && matches.length > 2) {
125
+ target = matches[2];
126
+ request = matches[1].replace(target, "");
127
+ }
128
+ const action = navActions[request];
129
+ if (action) {
130
+ this.processListeners(action, "adl.nav.request", target);
116
131
  }
117
132
  } else if (this.settings.autoProgress) {
118
133
  this.processListeners("SequenceNext");
@@ -127,6 +142,19 @@ export default class Scorm2004API extends BaseAPI {
127
142
  * @return {string}
128
143
  */
129
144
  lmsGetValue(CMIElement: string): string {
145
+ const adlNavRequestRegex =
146
+ "^adl\\.nav\\.request_valid\\.(choice|jump)\\.{target=\\S{0,}([a-zA-Z0-9-_]+)}$";
147
+ if (stringMatches(CMIElement, adlNavRequestRegex)) {
148
+ const matches = CMIElement.match(adlNavRequestRegex);
149
+ const request = matches[1];
150
+ const target = matches[2].replace("{target=", "").replace("}", "");
151
+ if (request === "choice" || request === "jump") {
152
+ if (this.settings.scoItemIdValidator) {
153
+ return String(this.settings.scoItemIdValidator(target));
154
+ }
155
+ return String(this.settings.scoItemIds.includes(target));
156
+ }
157
+ }
130
158
  return this.getValue("GetValue", true, CMIElement);
131
159
  }
132
160
 
@@ -145,7 +173,10 @@ export default class Scorm2004API extends BaseAPI {
145
173
  * @return {string} bool
146
174
  */
147
175
  lmsCommit(): string {
148
- return this.commit("Commit");
176
+ (async () => {
177
+ await this.commit("Commit");
178
+ })();
179
+ return APIConstants.global.SCORM_TRUE;
149
180
  }
150
181
 
151
182
  /**
@@ -201,66 +232,71 @@ export default class Scorm2004API extends BaseAPI {
201
232
  value: any,
202
233
  foundFirstIndex: boolean,
203
234
  ): BaseCMI | null {
204
- if (this.stringMatches(CMIElement, "cmi\\.objectives\\.\\d+")) {
235
+ if (stringMatches(CMIElement, "cmi\\.objectives\\.\\d+")) {
205
236
  return new CMIObjectivesObject();
206
- } else if (
207
- foundFirstIndex &&
208
- this.stringMatches(
209
- CMIElement,
210
- "cmi\\.interactions\\.\\d+\\.correct_responses\\.\\d+",
211
- )
212
- ) {
213
- const parts = CMIElement.split(".");
214
- const index = Number(parts[2]);
215
- const interaction = this.cmi.interactions.childArray[index];
216
- if (this.isInitialized()) {
217
- if (!interaction.type) {
218
- this.throwSCORMError(
219
- scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
220
- );
221
- } else {
222
- this.checkDuplicateChoiceResponse(interaction, value);
237
+ }
223
238
 
224
- const response_type = correct_responses[interaction.type];
225
- if (response_type) {
226
- this.checkValidResponseType(response_type, value, interaction.type);
227
- } else {
228
- this.throwSCORMError(
229
- scorm2004_error_codes.GENERAL_SET_FAILURE,
230
- "Incorrect Response Type: " + interaction.type,
231
- );
232
- }
233
- }
234
- }
235
- if (this.lastErrorCode === "0") {
236
- return new CMIInteractionsCorrectResponsesObject();
239
+ if (foundFirstIndex) {
240
+ if (
241
+ stringMatches(
242
+ CMIElement,
243
+ "cmi\\.interactions\\.\\d+\\.correct_responses\\.\\d+",
244
+ )
245
+ ) {
246
+ return this.createCorrectResponsesObject(CMIElement, value);
247
+ } else if (
248
+ stringMatches(
249
+ CMIElement,
250
+ "cmi\\.interactions\\.\\d+\\.objectives\\.\\d+",
251
+ )
252
+ ) {
253
+ return new CMIInteractionsObjectivesObject();
237
254
  }
238
- } else if (
239
- foundFirstIndex &&
240
- this.stringMatches(
241
- CMIElement,
242
- "cmi\\.interactions\\.\\d+\\.objectives\\.\\d+",
243
- )
244
- ) {
245
- return new CMIInteractionsObjectivesObject();
246
- } else if (
247
- !foundFirstIndex &&
248
- this.stringMatches(CMIElement, "cmi\\.interactions\\.\\d+")
249
- ) {
255
+ } else if (stringMatches(CMIElement, "cmi\\.interactions\\.\\d+")) {
250
256
  return new CMIInteractionsObject();
251
- } else if (
252
- this.stringMatches(CMIElement, "cmi\\.comments_from_learner\\.\\d+")
253
- ) {
257
+ }
258
+
259
+ if (stringMatches(CMIElement, "cmi\\.comments_from_learner\\.\\d+")) {
254
260
  return new CMICommentsObject();
255
- } else if (
256
- this.stringMatches(CMIElement, "cmi\\.comments_from_lms\\.\\d+")
257
- ) {
261
+ } else if (stringMatches(CMIElement, "cmi\\.comments_from_lms\\.\\d+")) {
258
262
  return new CMICommentsObject(true);
259
263
  }
260
264
 
261
265
  return null;
262
266
  }
263
267
 
268
+ private createCorrectResponsesObject(
269
+ CMIElement: string,
270
+ value: any,
271
+ ): BaseCMI | null {
272
+ const parts = CMIElement.split(".");
273
+ const index = Number(parts[2]);
274
+ const interaction = this.cmi.interactions.childArray[index];
275
+
276
+ if (this.isInitialized()) {
277
+ if (!interaction.type) {
278
+ this.throwSCORMError(ErrorCodes.scorm2004.DEPENDENCY_NOT_ESTABLISHED);
279
+ } else {
280
+ this.checkDuplicateChoiceResponse(interaction, value);
281
+ const response_type = CorrectResponses[interaction.type];
282
+ if (response_type) {
283
+ this.checkValidResponseType(response_type, value, interaction.type);
284
+ } else {
285
+ this.throwSCORMError(
286
+ ErrorCodes.scorm2004.GENERAL_SET_FAILURE,
287
+ "Incorrect Response Type: " + interaction.type,
288
+ );
289
+ }
290
+ }
291
+ }
292
+
293
+ if (this.lastErrorCode === "0") {
294
+ return new CMIInteractionsCorrectResponsesObject();
295
+ }
296
+
297
+ return null;
298
+ }
299
+
264
300
  /**
265
301
  * Checks for valid response types
266
302
  * @param {object} response_type
@@ -283,7 +319,7 @@ export default class Scorm2004API extends BaseAPI {
283
319
  this.checkCorrectResponseValue(interaction_type, nodes, value);
284
320
  } else if (nodes.length > response_type.max) {
285
321
  this.throwSCORMError(
286
- scorm2004_error_codes.GENERAL_SET_FAILURE,
322
+ ErrorCodes.scorm2004.GENERAL_SET_FAILURE,
287
323
  "Data Model Element Pattern Too Long",
288
324
  );
289
325
  }
@@ -304,7 +340,7 @@ export default class Scorm2004API extends BaseAPI {
304
340
  ) {
305
341
  const response = interaction.correct_responses.childArray[i];
306
342
  if (response.pattern === value) {
307
- this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
343
+ this.throwSCORMError(ErrorCodes.scorm2004.GENERAL_SET_FAILURE);
308
344
  }
309
345
  }
310
346
  }
@@ -324,7 +360,7 @@ export default class Scorm2004API extends BaseAPI {
324
360
  const interaction_count = interaction.correct_responses._count;
325
361
  this.checkDuplicateChoiceResponse(interaction, value);
326
362
 
327
- const response_type = correct_responses[interaction.type];
363
+ const response_type = CorrectResponses[interaction.type];
328
364
  if (
329
365
  typeof response_type.limit === "undefined" ||
330
366
  interaction_count <= response_type.limit
@@ -345,14 +381,14 @@ export default class Scorm2004API extends BaseAPI {
345
381
  } else {
346
382
  if (this.lastErrorCode === "0") {
347
383
  this.throwSCORMError(
348
- scorm2004_error_codes.GENERAL_SET_FAILURE,
384
+ ErrorCodes.scorm2004.GENERAL_SET_FAILURE,
349
385
  "Data Model Element Pattern Already Exists",
350
386
  );
351
387
  }
352
388
  }
353
389
  } else {
354
390
  this.throwSCORMError(
355
- scorm2004_error_codes.GENERAL_SET_FAILURE,
391
+ ErrorCodes.scorm2004.GENERAL_SET_FAILURE,
356
392
  "Data Model Element Collection Limit Reached",
357
393
  );
358
394
  }
@@ -384,11 +420,11 @@ export default class Scorm2004API extends BaseAPI {
384
420
 
385
421
  // Set error number to string since inconsistent from modules if string or number
386
422
  errorNumber = String(errorNumber);
387
- if (scorm2004_constants.error_descriptions[errorNumber]) {
423
+ if (APIConstants.scorm2004.error_descriptions[errorNumber]) {
388
424
  basicMessage =
389
- scorm2004_constants.error_descriptions[errorNumber].basicMessage;
425
+ APIConstants.scorm2004.error_descriptions[errorNumber].basicMessage;
390
426
  detailMessage =
391
- scorm2004_constants.error_descriptions[errorNumber].detailMessage;
427
+ APIConstants.scorm2004.error_descriptions[errorNumber].detailMessage;
392
428
  }
393
429
 
394
430
  return detail ? detailMessage : basicMessage;
@@ -427,7 +463,7 @@ export default class Scorm2004API extends BaseAPI {
427
463
  nodes: Array<any>,
428
464
  value: any,
429
465
  ) {
430
- const response = correct_responses[interaction_type];
466
+ const response = CorrectResponses[interaction_type];
431
467
  const formatRegex = new RegExp(response.format);
432
468
  for (let i = 0; i < nodes.length && this.lastErrorCode === "0"; i++) {
433
469
  if (
@@ -443,17 +479,17 @@ export default class Scorm2004API extends BaseAPI {
443
479
  if (values.length === 2) {
444
480
  const matches = values[0].match(formatRegex);
445
481
  if (!matches) {
446
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
482
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
447
483
  } else {
448
484
  if (
449
485
  !response.format2 ||
450
486
  !values[1].match(new RegExp(response.format2))
451
487
  ) {
452
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
488
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
453
489
  }
454
490
  }
455
491
  } else {
456
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
492
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
457
493
  }
458
494
  } else {
459
495
  const matches = nodes[i].match(formatRegex);
@@ -461,17 +497,17 @@ export default class Scorm2004API extends BaseAPI {
461
497
  (!matches && value !== "") ||
462
498
  (!matches && interaction_type === "true-false")
463
499
  ) {
464
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
500
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
465
501
  } else {
466
502
  if (interaction_type === "numeric" && nodes.length > 1) {
467
503
  if (Number(nodes[0]) > Number(nodes[1])) {
468
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
504
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
469
505
  }
470
506
  } else {
471
507
  if (nodes[i] !== "" && response.unique) {
472
508
  for (let j = 0; j < i && this.lastErrorCode === "0"; j++) {
473
509
  if (nodes[i] === nodes[j]) {
474
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
510
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
475
511
  }
476
512
  }
477
513
  }
@@ -499,12 +535,12 @@ export default class Scorm2004API extends BaseAPI {
499
535
  while (matches) {
500
536
  switch (matches[2]) {
501
537
  case "lang":
502
- langMatches = node.match(scorm2004_regex.CMILangcr);
538
+ langMatches = node.match(Regex.scorm2004.CMILangcr);
503
539
  if (langMatches) {
504
540
  const lang = langMatches[3];
505
541
  if (lang !== undefined && lang.length > 0) {
506
542
  if (!ValidLanguages.includes(lang.toLowerCase())) {
507
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
543
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
508
544
  }
509
545
  }
510
546
  }
@@ -513,7 +549,7 @@ export default class Scorm2004API extends BaseAPI {
513
549
  case "case_matters":
514
550
  if (!seenLang && !seenOrder && !seenCase) {
515
551
  if (matches[3] !== "true" && matches[3] !== "false") {
516
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
552
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
517
553
  }
518
554
  }
519
555
 
@@ -522,14 +558,12 @@ export default class Scorm2004API extends BaseAPI {
522
558
  case "order_matters":
523
559
  if (!seenCase && !seenLang && !seenOrder) {
524
560
  if (matches[3] !== "true" && matches[3] !== "false") {
525
- this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
561
+ this.throwSCORMError(ErrorCodes.scorm2004.TYPE_MISMATCH);
526
562
  }
527
563
  }
528
564
 
529
565
  seenOrder = true;
530
566
  break;
531
- default:
532
- break;
533
567
  }
534
568
  node = node.substring(matches[1].length);
535
569
  matches = node.match(prefixRegex);
@@ -585,7 +619,7 @@ export default class Scorm2004API extends BaseAPI {
585
619
  * @param {boolean} terminateCommit
586
620
  * @return {ResultObject}
587
621
  */
588
- storeData(terminateCommit: boolean): ResultObject {
622
+ async storeData(terminateCommit: boolean): Promise<ResultObject> {
589
623
  if (terminateCommit) {
590
624
  if (this.cmi.mode === "normal") {
591
625
  if (this.cmi.credit === "credit") {
@@ -620,14 +654,14 @@ export default class Scorm2004API extends BaseAPI {
620
654
  terminateCommit || this.settings.alwaysSendTotalTime,
621
655
  );
622
656
 
623
- if (this.apiLogLevel === global_constants.LOG_LEVEL_DEBUG) {
657
+ if (this.apiLogLevel === APIConstants.global.LOG_LEVEL_DEBUG) {
624
658
  console.debug(
625
659
  "Commit (terminated: " + (terminateCommit ? "yes" : "no") + "): ",
626
660
  );
627
661
  console.debug(commitObject);
628
662
  }
629
663
  if (typeof this.settings.lmsCommitUrl === "string") {
630
- const result = this.processHttpRequest(
664
+ const result = await this.processHttpRequest(
631
665
  this.settings.lmsCommitUrl,
632
666
  commitObject,
633
667
  terminateCommit,
@@ -646,7 +680,7 @@ export default class Scorm2004API extends BaseAPI {
646
680
  return result;
647
681
  } else {
648
682
  return {
649
- result: global_constants.SCORM_TRUE,
683
+ result: APIConstants.global.SCORM_TRUE,
650
684
  errorCode: 0,
651
685
  };
652
686
  }