scorm-again 1.7.1 → 2.0.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 (85) hide show
  1. package/.babelrc +18 -7
  2. package/.github/dependabot.yml +5 -0
  3. package/.github/workflows/main.yml +79 -0
  4. package/.jsdoc.json +4 -5
  5. package/.mocharc.json +8 -0
  6. package/.run/Mocha Unit Tests.run.xml +5 -2
  7. package/CONTRIBUTING.md +1 -1
  8. package/README.md +14 -1
  9. package/dist/aicc.js +3661 -7170
  10. package/dist/aicc.js.map +1 -1
  11. package/dist/aicc.min.js +2 -40
  12. package/dist/aicc.min.js.map +1 -0
  13. package/dist/scorm-again.js +5671 -10695
  14. package/dist/scorm-again.js.map +1 -1
  15. package/dist/scorm-again.min.js +2 -52
  16. package/dist/scorm-again.min.js.map +1 -0
  17. package/dist/scorm12.js +2871 -5433
  18. package/dist/scorm12.js.map +1 -1
  19. package/dist/scorm12.min.js +2 -34
  20. package/dist/scorm12.min.js.map +1 -0
  21. package/dist/scorm2004.js +3868 -6797
  22. package/dist/scorm2004.js.map +1 -1
  23. package/dist/scorm2004.min.js +2 -40
  24. package/dist/scorm2004.min.js.map +1 -0
  25. package/eslint.config.js +21 -0
  26. package/package.json +72 -34
  27. package/results.json +34254 -0
  28. package/src/{AICC.js → AICC.ts} +27 -21
  29. package/src/BaseAPI.ts +1449 -0
  30. package/src/Scorm12API.ts +360 -0
  31. package/src/{Scorm2004API.js → Scorm2004API.ts} +245 -163
  32. package/src/cmi/aicc_cmi.ts +1248 -0
  33. package/src/cmi/common.ts +411 -0
  34. package/src/cmi/scorm12_cmi.ts +1426 -0
  35. package/src/cmi/scorm2004_cmi.ts +1874 -0
  36. package/src/constants/api_constants.ts +318 -0
  37. package/src/constants/error_codes.ts +88 -0
  38. package/src/constants/language_constants.ts +394 -0
  39. package/src/constants/regex.ts +97 -0
  40. package/src/constants/{response_constants.js → response_constants.ts} +67 -62
  41. package/src/exceptions.ts +133 -0
  42. package/src/exports/aicc.js +1 -1
  43. package/src/exports/scorm-again.js +3 -3
  44. package/src/exports/scorm12.js +1 -1
  45. package/src/exports/scorm2004.js +1 -1
  46. package/src/{utilities.js → utilities.ts} +114 -74
  47. package/tea.yaml +6 -0
  48. package/test/{AICC.spec.js → AICC.spec.ts} +70 -72
  49. package/test/Scorm12API.spec.ts +580 -0
  50. package/test/Scorm2004API.spec.ts +812 -0
  51. package/test/api_helpers.ts +176 -0
  52. package/test/cmi/{aicc_cmi.spec.js → aicc_cmi.spec.ts} +193 -209
  53. package/test/cmi/{scorm12_cmi.spec.js → scorm12_cmi.spec.ts} +251 -269
  54. package/test/cmi/scorm2004_cmi.spec.ts +1031 -0
  55. package/test/cmi_helpers.ts +207 -0
  56. package/test/exceptions.spec.ts +79 -0
  57. package/test/field_values.ts +202 -0
  58. package/test/utilities.spec.ts +322 -0
  59. package/tsconfig.json +18 -0
  60. package/webpack.config.js +65 -0
  61. package/.circleci/config.yml +0 -99
  62. package/.codeclimate.yml +0 -7
  63. package/.eslintrc.js +0 -36
  64. package/src/.flowconfig +0 -11
  65. package/src/BaseAPI.js +0 -1275
  66. package/src/Scorm12API.js +0 -308
  67. package/src/cmi/aicc_cmi.js +0 -1141
  68. package/src/cmi/common.js +0 -328
  69. package/src/cmi/scorm12_cmi.js +0 -1312
  70. package/src/cmi/scorm2004_cmi.js +0 -1692
  71. package/src/constants/api_constants.js +0 -218
  72. package/src/constants/error_codes.js +0 -87
  73. package/src/constants/language_constants.js +0 -76
  74. package/src/constants/regex.js +0 -84
  75. package/src/exceptions.js +0 -104
  76. package/test/Scorm12API.spec.js +0 -528
  77. package/test/Scorm2004API.spec.js +0 -775
  78. package/test/abstract_classes.spec.js +0 -17
  79. package/test/api_helpers.js +0 -128
  80. package/test/cmi/scorm2004_cmi.spec.js +0 -1066
  81. package/test/cmi_helpers.js +0 -161
  82. package/test/exceptions.spec.js +0 -71
  83. package/test/field_values.js +0 -353
  84. package/test/utilities.spec.js +0 -339
  85. package/webpack.js +0 -78
@@ -0,0 +1,133 @@
1
+ import APIConstants from "./constants/api_constants";
2
+ import { BaseScormValidationError } from "./cmi/common";
3
+
4
+ const scorm12_errors = APIConstants.scorm12.error_descriptions;
5
+ const aicc_errors = APIConstants.aicc.error_descriptions;
6
+ const scorm2004_errors = APIConstants.scorm2004.error_descriptions;
7
+
8
+ type APIError = {
9
+ errorCode: number;
10
+ errorMessage: string;
11
+ detailedMessage: string;
12
+ };
13
+
14
+ /**
15
+ * Base Validation Exception
16
+ */
17
+ export class ValidationError
18
+ extends BaseScormValidationError
19
+ implements APIError
20
+ {
21
+ /**
22
+ * Constructor to take in an error message and code
23
+ * @param {number} errorCode
24
+ * @param {string} errorMessage
25
+ * @param {string} detailedMessage
26
+ */
27
+ constructor(
28
+ errorCode: number,
29
+ errorMessage: string,
30
+ detailedMessage?: string,
31
+ ) {
32
+ super(errorCode);
33
+ this.setMessage(errorMessage);
34
+ this._errorMessage = errorMessage;
35
+ if (detailedMessage) {
36
+ this._detailedMessage = detailedMessage;
37
+ }
38
+ }
39
+
40
+ private readonly _errorMessage: string;
41
+ private readonly _detailedMessage: string = "";
42
+
43
+ /**
44
+ * Getter for _errorMessage
45
+ * @return {string}
46
+ */
47
+ get errorMessage(): string {
48
+ return this._errorMessage;
49
+ }
50
+
51
+ /**
52
+ * Getter for _detailedMessage
53
+ * @return {string}
54
+ */
55
+ get detailedMessage(): string {
56
+ return this._detailedMessage;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * SCORM 1.2 Validation Error
62
+ */
63
+ export class Scorm12ValidationError extends ValidationError {
64
+ /**
65
+ * Constructor to take in an error code
66
+ * @param {number} errorCode
67
+ */
68
+ constructor(errorCode: number) {
69
+ if ({}.hasOwnProperty.call(scorm12_errors, String(errorCode))) {
70
+ super(
71
+ errorCode,
72
+ scorm12_errors[String(errorCode)].basicMessage,
73
+ scorm12_errors[String(errorCode)].detailMessage,
74
+ );
75
+ } else {
76
+ super(
77
+ 101,
78
+ scorm12_errors["101"].basicMessage,
79
+ scorm12_errors["101"].detailMessage,
80
+ );
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * AICC Validation Error
87
+ */
88
+ export class AICCValidationError extends ValidationError {
89
+ /**
90
+ * Constructor to take in an error code
91
+ * @param {number} errorCode
92
+ */
93
+ constructor(errorCode: number) {
94
+ if ({}.hasOwnProperty.call(aicc_errors, String(errorCode))) {
95
+ super(
96
+ errorCode,
97
+ aicc_errors[String(errorCode)].basicMessage,
98
+ aicc_errors[String(errorCode)].detailMessage,
99
+ );
100
+ } else {
101
+ super(
102
+ 101,
103
+ aicc_errors["101"].basicMessage,
104
+ aicc_errors["101"].detailMessage,
105
+ );
106
+ }
107
+ }
108
+ }
109
+
110
+ /**
111
+ * SCORM 2004 Validation Error
112
+ */
113
+ export class Scorm2004ValidationError extends ValidationError {
114
+ /**
115
+ * Constructor to take in an error code
116
+ * @param {number} errorCode
117
+ */
118
+ constructor(errorCode: number) {
119
+ if ({}.hasOwnProperty.call(scorm2004_errors, String(errorCode))) {
120
+ super(
121
+ errorCode,
122
+ scorm2004_errors[String(errorCode)].basicMessage,
123
+ scorm2004_errors[String(errorCode)].detailMessage,
124
+ );
125
+ } else {
126
+ super(
127
+ 101,
128
+ scorm2004_errors["101"].basicMessage,
129
+ scorm2004_errors["101"].detailMessage,
130
+ );
131
+ }
132
+ }
133
+ }
@@ -1,3 +1,3 @@
1
- import AICC from '../AICC';
1
+ import AICC from "../AICC.ts";
2
2
 
3
3
  window.AICC = AICC;
@@ -1,6 +1,6 @@
1
- import Scorm2004API from '../Scorm2004API';
2
- import Scorm12API from '../Scorm12API';
3
- import AICC from '../AICC';
1
+ import Scorm2004API from "../Scorm2004API.ts";
2
+ import Scorm12API from "../Scorm12API.ts";
3
+ import AICC from "../AICC.ts";
4
4
 
5
5
  window.Scorm12API = Scorm12API;
6
6
  window.Scorm2004API = Scorm2004API;
@@ -1,3 +1,3 @@
1
- import Scorm12API from '../Scorm12API';
1
+ import Scorm12API from "../Scorm12API.ts";
2
2
 
3
3
  window.Scorm12API = Scorm12API;
@@ -1,3 +1,3 @@
1
- import Scorm2004API from '../Scorm2004API';
1
+ import Scorm2004API from "../Scorm2004API.ts";
2
2
 
3
3
  window.Scorm2004API = Scorm2004API;
@@ -1,87 +1,101 @@
1
- // @flow
2
1
  export const SECONDS_PER_SECOND = 1.0;
3
2
  export const SECONDS_PER_MINUTE = 60;
4
3
  export const SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
5
4
  export const SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
6
5
 
7
- const designations = [
8
- ['D', SECONDS_PER_DAY],
9
- ['H', SECONDS_PER_HOUR],
10
- ['M', SECONDS_PER_MINUTE],
11
- ['S', SECONDS_PER_SECOND],
12
- ];
6
+ type Designation = {
7
+ [key: string]: number;
8
+ };
9
+
10
+ type StringKeyMap = {
11
+ [key: string]: any;
12
+ };
13
+
14
+ const designations: Designation = {
15
+ D: SECONDS_PER_DAY,
16
+ H: SECONDS_PER_HOUR,
17
+ M: SECONDS_PER_MINUTE,
18
+ S: SECONDS_PER_SECOND,
19
+ };
13
20
 
14
21
  /**
15
22
  * Converts a Number to a String of HH:MM:SS
16
23
  *
17
- * @param {Number} totalSeconds
24
+ * @param {number} totalSeconds
18
25
  * @return {string}
19
26
  */
20
- export function getSecondsAsHHMMSS(totalSeconds: Number) {
27
+ export function getSecondsAsHHMMSS(totalSeconds: number | null): string {
21
28
  // SCORM spec does not deal with negative durations, give zero back
22
29
  if (!totalSeconds || totalSeconds <= 0) {
23
- return '00:00:00';
30
+ return "00:00:00";
24
31
  }
25
32
 
26
33
  const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR);
27
-
28
34
  const dateObj = new Date(totalSeconds * 1000);
29
35
  const minutes = dateObj.getUTCMinutes();
30
36
  // make sure we add any possible decimal value
31
37
  const seconds = dateObj.getSeconds();
32
38
  const ms = totalSeconds % 1.0;
33
- let msStr = '';
39
+ let msStr = "";
40
+
34
41
  if (countDecimals(ms) > 0) {
35
42
  if (countDecimals(ms) > 2) {
36
43
  msStr = ms.toFixed(2);
37
44
  } else {
38
45
  msStr = String(ms);
39
46
  }
40
- msStr = '.' + msStr.split('.')[1];
47
+
48
+ msStr = "." + msStr.split(".")[1];
41
49
  }
42
50
 
43
- return (hours + ':' + minutes + ':' + seconds).replace(/\b\d\b/g,
44
- '0$&') + msStr;
51
+ return (
52
+ (hours + ":" + minutes + ":" + seconds).replace(/\b\d\b/g, "0$&") + msStr
53
+ );
45
54
  }
46
55
 
47
56
  /**
48
57
  * Calculate the number of seconds from ISO 8601 Duration
49
58
  *
50
- * @param {Number} seconds
51
- * @return {String}
59
+ * @param {number} seconds
60
+ * @return {string}
52
61
  */
53
- export function getSecondsAsISODuration(seconds: Number) {
62
+ export function getSecondsAsISODuration(seconds: number | null): string {
54
63
  // SCORM spec does not deal with negative durations, give zero back
55
64
  if (!seconds || seconds <= 0) {
56
- return 'PT0S';
65
+ return "PT0S";
57
66
  }
58
67
 
59
- let duration = 'P';
68
+ let duration = "P";
60
69
  let remainder = seconds;
61
-
62
- designations.forEach(([sign, current_seconds]) => {
70
+ for (const designationsKey in designations) {
71
+ const current_seconds = designations[designationsKey];
63
72
  let value = Math.floor(remainder / current_seconds);
64
-
65
73
  remainder = remainder % current_seconds;
74
+
66
75
  if (countDecimals(remainder) > 2) {
67
76
  remainder = Number(Number(remainder).toFixed(2));
68
77
  }
78
+
69
79
  // If we have anything left in the remainder, and we're currently adding
70
80
  // seconds to the duration, go ahead and add the decimal to the seconds
71
- if (sign === 'S' && remainder > 0) {
81
+ if (designationsKey === "S" && remainder > 0) {
72
82
  value += remainder;
73
83
  }
74
84
 
75
85
  if (value) {
76
- if ((duration.indexOf('D') > 0 ||
77
- sign === 'H' || sign === 'M' || sign === 'S') &&
78
- duration.indexOf('T') === -1) {
79
- duration += 'T';
86
+ if (
87
+ (duration.indexOf("D") > 0 ||
88
+ designationsKey === "H" ||
89
+ designationsKey === "M" ||
90
+ designationsKey === "S") &&
91
+ duration.indexOf("T") === -1
92
+ ) {
93
+ duration += "T";
80
94
  }
81
- duration += `${value}${sign}`;
82
- }
83
- });
84
95
 
96
+ duration += `${value}${designationsKey}`;
97
+ }
98
+ }
85
99
  return duration;
86
100
  }
87
101
 
@@ -92,16 +106,25 @@ export function getSecondsAsISODuration(seconds: Number) {
92
106
  * @param {RegExp} timeRegex
93
107
  * @return {number}
94
108
  */
95
- export function getTimeAsSeconds(timeString: String, timeRegex: RegExp) {
96
- if (!timeString || typeof timeString !== 'string' ||
97
- !timeString.match(timeRegex)) {
109
+ export function getTimeAsSeconds(
110
+ timeString: string | number | boolean | null,
111
+ timeRegex: RegExp | string,
112
+ ): number {
113
+ if (typeof timeString === "number" || typeof timeString === "boolean") {
114
+ timeString = String(timeString);
115
+ }
116
+ if (typeof timeRegex === "string") {
117
+ timeRegex = new RegExp(timeRegex);
118
+ }
119
+ if (!timeString || !timeString.match(timeRegex)) {
98
120
  return 0;
99
121
  }
100
- const parts = timeString.split(':');
122
+
123
+ const parts = timeString.split(":");
101
124
  const hours = Number(parts[0]);
102
125
  const minutes = Number(parts[1]);
103
126
  const seconds = Number(parts[2]);
104
- return (hours * 3600) + (minutes * 60) + seconds;
127
+ return hours * 3600 + minutes * 60 + seconds;
105
128
  }
106
129
 
107
130
  /**
@@ -111,22 +134,26 @@ export function getTimeAsSeconds(timeString: String, timeRegex: RegExp) {
111
134
  * @param {RegExp} durationRegex
112
135
  * @return {number}
113
136
  */
114
- export function getDurationAsSeconds(duration: String, durationRegex: RegExp) {
137
+ export function getDurationAsSeconds(
138
+ duration: string | null,
139
+ durationRegex: RegExp | string,
140
+ ): number {
141
+ if (typeof durationRegex === "string") {
142
+ durationRegex = new RegExp(durationRegex);
143
+ }
144
+
115
145
  if (!duration || !duration.match(durationRegex)) {
116
146
  return 0;
117
147
  }
118
148
 
119
- const [, years, months, , days, hours, minutes, seconds] = new RegExp(
120
- durationRegex).exec(duration) || [];
121
-
149
+ const [, years, _, , days, hours, minutes, seconds] =
150
+ new RegExp(durationRegex).exec(duration) || [];
122
151
  let result = 0.0;
123
-
124
- result += (Number(seconds) * 1.0 || 0.0);
125
- result += (Number(minutes) * 60.0 || 0.0);
126
- result += (Number(hours) * 3600.0 || 0.0);
127
- result += (Number(days) * (60 * 60 * 24.0) || 0.0);
128
- result += (Number(years) * (60 * 60 * 24 * 365.0) || 0.0);
129
-
152
+ result += Number(seconds) || 0.0;
153
+ result += Number(minutes) * 60.0 || 0.0;
154
+ result += Number(hours) * 3600.0 || 0.0;
155
+ result += Number(days) * (60 * 60 * 24.0) || 0.0;
156
+ result += Number(years) * (60 * 60 * 24 * 365.0) || 0.0;
130
157
  return result;
131
158
  }
132
159
 
@@ -135,16 +162,20 @@ export function getDurationAsSeconds(duration: String, durationRegex: RegExp) {
135
162
  *
136
163
  * @param {string} first
137
164
  * @param {string} second
138
- * @param {RegExp} durationRegex
165
+ * @param {RegExp|string} durationRegex
139
166
  * @return {string}
140
167
  */
141
168
  export function addTwoDurations(
142
- first: String,
143
- second: String,
144
- durationRegex: RegExp) {
169
+ first: string,
170
+ second: string,
171
+ durationRegex: RegExp | string,
172
+ ): string {
173
+ const regex: RegExp =
174
+ typeof durationRegex === "string"
175
+ ? new RegExp(durationRegex)
176
+ : durationRegex;
145
177
  return getSecondsAsISODuration(
146
- getDurationAsSeconds(first, durationRegex) +
147
- getDurationAsSeconds(second, durationRegex),
178
+ getDurationAsSeconds(first, regex) + getDurationAsSeconds(second, regex),
148
179
  );
149
180
  }
150
181
 
@@ -157,13 +188,15 @@ export function addTwoDurations(
157
188
  * @return {string}
158
189
  */
159
190
  export function addHHMMSSTimeStrings(
160
- first: String,
161
- second: String,
162
- timeRegex: RegExp) {
191
+ first: string,
192
+ second: string,
193
+ timeRegex: RegExp | string,
194
+ ): string {
195
+ if (typeof timeRegex === "string") {
196
+ timeRegex = new RegExp(timeRegex);
197
+ }
163
198
  return getSecondsAsHHMMSS(
164
- getTimeAsSeconds(first, timeRegex) +
165
- getTimeAsSeconds(
166
- second, timeRegex),
199
+ getTimeAsSeconds(first, timeRegex) + getTimeAsSeconds(second, timeRegex),
167
200
  );
168
201
  }
169
202
 
@@ -172,35 +205,37 @@ export function addHHMMSSTimeStrings(
172
205
  * @param {object} data
173
206
  * @return {object}
174
207
  */
175
- export function flatten(data) {
176
- const result = {};
208
+ export function flatten(data: StringKeyMap): object {
209
+ const result: StringKeyMap = {};
177
210
 
178
211
  /**
179
212
  * Recurse through the object
180
213
  * @param {*} cur
181
214
  * @param {*} prop
182
215
  */
183
- function recurse(cur, prop) {
216
+ function recurse(cur: any, prop: any) {
184
217
  if (Object(cur) !== cur) {
185
218
  result[prop] = cur;
186
219
  } else if (Array.isArray(cur)) {
187
220
  for (let i = 0, l = cur.length; i < l; i++) {
188
- recurse(cur[i], prop + '[' + i + ']');
221
+ recurse(cur[i], prop + "[" + i + "]");
189
222
  if (l === 0) result[prop] = [];
190
223
  }
191
224
  } else {
192
225
  let isEmpty = true;
226
+
193
227
  for (const p in cur) {
194
228
  if ({}.hasOwnProperty.call(cur, p)) {
195
229
  isEmpty = false;
196
- recurse(cur[p], prop ? prop + '.' + p : p);
230
+ recurse(cur[p], prop ? prop + "." + p : p);
197
231
  }
198
232
  }
233
+
199
234
  if (isEmpty && prop) result[prop] = {};
200
235
  }
201
236
  }
202
237
 
203
- recurse(data, '');
238
+ recurse(data, "");
204
239
  return result;
205
240
  }
206
241
 
@@ -209,25 +244,30 @@ export function flatten(data) {
209
244
  * @param {object} data
210
245
  * @return {object}
211
246
  */
212
- export function unflatten(data) {
213
- 'use strict';
247
+ export function unflatten(data: StringKeyMap): object {
248
+ "use strict";
249
+
214
250
  if (Object(data) !== data || Array.isArray(data)) return data;
215
251
  const regex = /\.?([^.[\]]+)|\[(\d+)]/g;
216
- const result = {};
252
+ const result: StringKeyMap = {};
253
+
217
254
  for (const p in data) {
218
255
  if ({}.hasOwnProperty.call(data, p)) {
219
256
  let cur = result;
220
- let prop = '';
257
+ let prop = "";
221
258
  let m = regex.exec(p);
259
+
222
260
  while (m) {
223
- cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
261
+ cur = cur[prop] || (cur[prop] = m[2] ? [] : {});
224
262
  prop = m[2] || m[1];
225
263
  m = regex.exec(p);
226
264
  }
265
+
227
266
  cur[prop] = data[p];
228
267
  }
229
268
  }
230
- return result[''] || result;
269
+
270
+ return result[""] || result;
231
271
  }
232
272
 
233
273
  /**
@@ -235,8 +275,8 @@ export function unflatten(data) {
235
275
  * @param {number} num
236
276
  * @return {number}
237
277
  */
238
- export function countDecimals(num: number) {
239
- if (Math.floor(num) === num || String(num).indexOf('.') < 0) return 0;
240
- const parts = num.toString().split('.')[1];
278
+ export function countDecimals(num: number): number {
279
+ if (Math.floor(num) === num || String(num).indexOf(".") < 0) return 0;
280
+ const parts = num.toString().split(".")[1];
241
281
  return parts.length || 0;
242
282
  }
package/tea.yaml ADDED
@@ -0,0 +1,6 @@
1
+ # https://tea.xyz/what-is-this-file
2
+ ---
3
+ version: 1.0.0
4
+ codeOwners:
5
+ - '0x1bfc0b2fc65c3eEE1AfFB43E07fbD8F00E18B93E'
6
+ quorum: 1