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.
- package/.github/workflows/stale.yml +14 -0
- package/.run/{Mocha Unit Tests.run.xml → Mocha Unit Tests (watch).run.xml } +1 -1
- package/.run/Template Mocha.run.xml +17 -0
- package/README.md +171 -72
- package/dist/aicc.js +1441 -1140
- package/dist/aicc.js.map +1 -1
- package/dist/aicc.min.js +1 -1
- package/dist/aicc.min.js.map +1 -1
- package/dist/scorm-again.js +2703 -2212
- 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 +1069 -852
- 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 +1861 -1571
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +1 -1
- package/dist/scorm2004.min.js.map +1 -1
- package/package.json +10 -6
- package/src/AICC.ts +15 -17
- package/src/BaseAPI.ts +268 -417
- package/src/Scorm12API.ts +65 -38
- package/src/Scorm2004API.ts +151 -117
- package/src/cmi/aicc/attempts.ts +94 -0
- package/src/cmi/aicc/cmi.ts +100 -0
- package/src/cmi/aicc/core.ts +360 -0
- package/src/cmi/aicc/evaluation.ts +157 -0
- package/src/cmi/aicc/paths.ts +180 -0
- package/src/cmi/aicc/student_data.ts +86 -0
- package/src/cmi/aicc/student_demographics.ts +367 -0
- package/src/cmi/aicc/student_preferences.ts +176 -0
- package/src/cmi/aicc/tries.ts +116 -0
- package/src/cmi/aicc/validation.ts +25 -0
- package/src/cmi/common/array.ts +77 -0
- package/src/cmi/common/base_cmi.ts +46 -0
- package/src/cmi/common/score.ts +203 -0
- package/src/cmi/common/validation.ts +60 -0
- package/src/cmi/scorm12/cmi.ts +224 -0
- package/src/cmi/scorm12/interactions.ts +368 -0
- package/src/cmi/scorm12/nav.ts +54 -0
- package/src/cmi/scorm12/objectives.ts +112 -0
- package/src/cmi/scorm12/student_data.ts +130 -0
- package/src/cmi/scorm12/student_preference.ts +158 -0
- package/src/cmi/scorm12/validation.ts +48 -0
- package/src/cmi/scorm2004/adl.ts +272 -0
- package/src/cmi/scorm2004/cmi.ts +599 -0
- package/src/cmi/scorm2004/comments.ts +163 -0
- package/src/cmi/scorm2004/interactions.ts +466 -0
- package/src/cmi/scorm2004/learner_preference.ts +152 -0
- package/src/cmi/scorm2004/objectives.ts +212 -0
- package/src/cmi/scorm2004/score.ts +78 -0
- package/src/cmi/scorm2004/validation.ts +42 -0
- package/src/constants/default_settings.ts +81 -0
- package/src/constants/enums.ts +5 -0
- package/src/constants/regex.ts +2 -2
- package/src/constants/response_constants.ts +2 -0
- package/src/exceptions.ts +22 -1
- package/src/helpers/scheduled_commit.ts +42 -0
- package/src/interfaces/IBaseAPI.ts +35 -0
- package/src/types/api_types.ts +32 -0
- package/src/utilities/debounce.ts +31 -0
- package/src/utilities.ts +56 -0
- package/test/AICC.spec.ts +11 -1
- package/test/Scorm12API.spec.ts +262 -9
- package/test/Scorm2004API.spec.ts +488 -2
- package/test/cmi/aicc_cmi.spec.ts +188 -11
- package/test/cmi/scorm12_cmi.spec.ts +5 -5
- package/test/cmi/scorm2004_cmi.spec.ts +8 -8
- package/test/cmi_helpers.ts +1 -1
- package/test/types/api_types.spec.ts +126 -0
- package/test/utilities/debounce.spec.ts +56 -0
- package/src/cmi/aicc_cmi.ts +0 -1248
- package/src/cmi/common.ts +0 -411
- package/src/cmi/scorm12_cmi.ts +0 -1426
- package/src/cmi/scorm2004_cmi.ts +0 -1874
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { CMIArray } from "../common/array";
|
|
2
|
+
import { AICCValidationError } from "../../exceptions";
|
|
3
|
+
import { checkAICCValidFormat } from "./validation";
|
|
4
|
+
import ErrorCodes from "../../constants/error_codes";
|
|
5
|
+
import Regex from "../../constants/regex";
|
|
6
|
+
import APIConstants from "../../constants/api_constants";
|
|
7
|
+
import { CMIStudentPreference } from "../scorm12/student_preference";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* StudentPreferences class for AICC
|
|
11
|
+
*/
|
|
12
|
+
export class AICCStudentPreferences extends CMIStudentPreference {
|
|
13
|
+
/**
|
|
14
|
+
* Constructor for AICC Student Preferences object
|
|
15
|
+
*/
|
|
16
|
+
constructor() {
|
|
17
|
+
super(APIConstants.aicc.student_preference_children);
|
|
18
|
+
this.windows = new CMIArray({
|
|
19
|
+
errorCode: ErrorCodes.scorm12.INVALID_SET_VALUE,
|
|
20
|
+
errorClass: AICCValidationError,
|
|
21
|
+
children: "",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public windows: CMIArray;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Called when the API has been initialized after the CMI has been created
|
|
29
|
+
*/
|
|
30
|
+
initialize() {
|
|
31
|
+
super.initialize();
|
|
32
|
+
this.windows?.initialize();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private _lesson_type = "";
|
|
36
|
+
private _text_color = "";
|
|
37
|
+
private _text_location = "";
|
|
38
|
+
private _text_size = "";
|
|
39
|
+
private _video = "";
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Getter for _lesson_type
|
|
43
|
+
* @return {string}
|
|
44
|
+
*/
|
|
45
|
+
get lesson_type(): string {
|
|
46
|
+
return this._lesson_type;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Setter for _lesson_type
|
|
51
|
+
* @param {string} lesson_type
|
|
52
|
+
*/
|
|
53
|
+
set lesson_type(lesson_type: string) {
|
|
54
|
+
if (checkAICCValidFormat(lesson_type, Regex.aicc.CMIString256)) {
|
|
55
|
+
this._lesson_type = lesson_type;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Getter for _text_color
|
|
61
|
+
* @return {string}
|
|
62
|
+
*/
|
|
63
|
+
get text_color(): string {
|
|
64
|
+
return this._text_color;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Setter for _text_color
|
|
69
|
+
* @param {string} text_color
|
|
70
|
+
*/
|
|
71
|
+
set text_color(text_color: string) {
|
|
72
|
+
if (checkAICCValidFormat(text_color, Regex.aicc.CMIString256)) {
|
|
73
|
+
this._text_color = text_color;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Getter for _text_location
|
|
79
|
+
* @return {string}
|
|
80
|
+
*/
|
|
81
|
+
get text_location(): string {
|
|
82
|
+
return this._text_location;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Setter for _text_location
|
|
87
|
+
* @param {string} text_location
|
|
88
|
+
*/
|
|
89
|
+
set text_location(text_location: string) {
|
|
90
|
+
if (checkAICCValidFormat(text_location, Regex.aicc.CMIString256)) {
|
|
91
|
+
this._text_location = text_location;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Getter for _text_size
|
|
97
|
+
* @return {string}
|
|
98
|
+
*/
|
|
99
|
+
get text_size(): string {
|
|
100
|
+
return this._text_size;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Setter for _text_size
|
|
105
|
+
* @param {string} text_size
|
|
106
|
+
*/
|
|
107
|
+
set text_size(text_size: string) {
|
|
108
|
+
if (checkAICCValidFormat(text_size, Regex.aicc.CMIString256)) {
|
|
109
|
+
this._text_size = text_size;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Getter for _video
|
|
115
|
+
* @return {string}
|
|
116
|
+
*/
|
|
117
|
+
get video(): string {
|
|
118
|
+
return this._video;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Setter for _video
|
|
123
|
+
* @param {string} video
|
|
124
|
+
*/
|
|
125
|
+
set video(video: string) {
|
|
126
|
+
if (checkAICCValidFormat(video, Regex.aicc.CMIString256)) {
|
|
127
|
+
this._video = video;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* toJSON for cmi.student_preference
|
|
133
|
+
*
|
|
134
|
+
* @return {
|
|
135
|
+
* {
|
|
136
|
+
* audio: string,
|
|
137
|
+
* language: string,
|
|
138
|
+
* speed: string,
|
|
139
|
+
* text: string,
|
|
140
|
+
* text_color: string,
|
|
141
|
+
* text_location: string,
|
|
142
|
+
* text_size: string,
|
|
143
|
+
* video: string,
|
|
144
|
+
* windows: CMIArray
|
|
145
|
+
* }
|
|
146
|
+
* }
|
|
147
|
+
*/
|
|
148
|
+
toJSON(): {
|
|
149
|
+
audio: string;
|
|
150
|
+
language: string;
|
|
151
|
+
lesson_type: string;
|
|
152
|
+
speed: string;
|
|
153
|
+
text: string;
|
|
154
|
+
text_color: string;
|
|
155
|
+
text_location: string;
|
|
156
|
+
text_size: string;
|
|
157
|
+
video: string;
|
|
158
|
+
windows: CMIArray;
|
|
159
|
+
} {
|
|
160
|
+
this.jsonString = true;
|
|
161
|
+
const result = {
|
|
162
|
+
audio: this.audio,
|
|
163
|
+
language: this.language,
|
|
164
|
+
lesson_type: this.lesson_type,
|
|
165
|
+
speed: this.speed,
|
|
166
|
+
text: this.text,
|
|
167
|
+
text_color: this.text_color,
|
|
168
|
+
text_location: this.text_location,
|
|
169
|
+
text_size: this.text_size,
|
|
170
|
+
video: this.video,
|
|
171
|
+
windows: this.windows,
|
|
172
|
+
};
|
|
173
|
+
delete this.jsonString;
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import {CMIArray} from "../common/array";
|
|
2
|
+
import APIConstants from "../../constants/api_constants";
|
|
3
|
+
import {BaseCMI} from "../common/base_cmi";
|
|
4
|
+
import {CMIScore} from "../common/score";
|
|
5
|
+
import Regex from "../../constants/regex";
|
|
6
|
+
import ErrorCodes from "../../constants/error_codes";
|
|
7
|
+
import {AICCValidationError} from "../../exceptions";
|
|
8
|
+
import {checkAICCValidFormat} from "./validation";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Class representing the AICC cmi.student_data.tries object
|
|
12
|
+
*/
|
|
13
|
+
export class CMITries extends CMIArray {
|
|
14
|
+
/**
|
|
15
|
+
* Constructor for inline Tries Array class
|
|
16
|
+
*/
|
|
17
|
+
constructor() {
|
|
18
|
+
super({
|
|
19
|
+
children: APIConstants.aicc.tries_children,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Class for AICC Tries
|
|
26
|
+
*/
|
|
27
|
+
export class CMITriesObject extends BaseCMI {
|
|
28
|
+
/**
|
|
29
|
+
* Constructor for AICC Tries object
|
|
30
|
+
*/
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
this.score = new CMIScore({
|
|
34
|
+
score_children: APIConstants.aicc.score_children,
|
|
35
|
+
score_range: Regex.aicc.score_range,
|
|
36
|
+
invalidErrorCode: ErrorCodes.scorm12.INVALID_SET_VALUE,
|
|
37
|
+
invalidTypeCode: ErrorCodes.scorm12.TYPE_MISMATCH,
|
|
38
|
+
invalidRangeCode: ErrorCodes.scorm12.VALUE_OUT_OF_RANGE,
|
|
39
|
+
errorClass: AICCValidationError,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public score: CMIScore;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Called when the API has been initialized after the CMI has been created
|
|
47
|
+
*/
|
|
48
|
+
initialize() {
|
|
49
|
+
super.initialize();
|
|
50
|
+
this.score?.initialize();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private _status = "";
|
|
54
|
+
private _time = "";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Getter for _status
|
|
58
|
+
* @return {string}
|
|
59
|
+
*/
|
|
60
|
+
get status(): string {
|
|
61
|
+
return this._status;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Setter for _status
|
|
66
|
+
* @param {string} status
|
|
67
|
+
*/
|
|
68
|
+
set status(status: string) {
|
|
69
|
+
if (checkAICCValidFormat(status, Regex.aicc.CMIStatus2)) {
|
|
70
|
+
this._status = status;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Getter for _time
|
|
76
|
+
* @return {string}
|
|
77
|
+
*/
|
|
78
|
+
get time(): string {
|
|
79
|
+
return this._time;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Setter for _time
|
|
84
|
+
* @param {string} time
|
|
85
|
+
*/
|
|
86
|
+
set time(time: string) {
|
|
87
|
+
if (checkAICCValidFormat(time, Regex.aicc.CMITime)) {
|
|
88
|
+
this._time = time;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* toJSON for cmi.student_data.tries.n object
|
|
94
|
+
* @return {
|
|
95
|
+
* {
|
|
96
|
+
* status: string,
|
|
97
|
+
* time: string,
|
|
98
|
+
* score: CMIScore
|
|
99
|
+
* }
|
|
100
|
+
* }
|
|
101
|
+
*/
|
|
102
|
+
toJSON(): {
|
|
103
|
+
status: string;
|
|
104
|
+
time: string;
|
|
105
|
+
score: CMIScore;
|
|
106
|
+
} {
|
|
107
|
+
this.jsonString = true;
|
|
108
|
+
const result = {
|
|
109
|
+
status: this.status,
|
|
110
|
+
time: this.time,
|
|
111
|
+
score: this.score,
|
|
112
|
+
};
|
|
113
|
+
delete this.jsonString;
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { checkValidFormat } from "../common/validation";
|
|
2
|
+
import { AICCValidationError } from "../../exceptions";
|
|
3
|
+
import ErrorCodes from "../../constants/error_codes";
|
|
4
|
+
const aicc_error_codes = ErrorCodes.scorm12;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Helper method, no reason to have to pass the same error codes every time
|
|
8
|
+
* @param {string} value
|
|
9
|
+
* @param {string} regexPattern
|
|
10
|
+
* @param {boolean} allowEmptyString
|
|
11
|
+
* @return {boolean}
|
|
12
|
+
*/
|
|
13
|
+
export function checkAICCValidFormat(
|
|
14
|
+
value: string,
|
|
15
|
+
regexPattern: string,
|
|
16
|
+
allowEmptyString?: boolean,
|
|
17
|
+
): boolean {
|
|
18
|
+
return checkValidFormat(
|
|
19
|
+
value,
|
|
20
|
+
regexPattern,
|
|
21
|
+
aicc_error_codes.TYPE_MISMATCH,
|
|
22
|
+
AICCValidationError,
|
|
23
|
+
allowEmptyString,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BaseCMI } from "./base_cmi";
|
|
2
|
+
import ErrorCodes from "../../constants/error_codes";
|
|
3
|
+
import { BaseScormValidationError } from "../../exceptions";
|
|
4
|
+
|
|
5
|
+
export const scorm12_error_codes = ErrorCodes.scorm12;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base class for cmi *.n objects
|
|
9
|
+
*/
|
|
10
|
+
export class CMIArray extends BaseCMI {
|
|
11
|
+
private readonly _errorCode: number;
|
|
12
|
+
private readonly _errorClass: typeof BaseScormValidationError;
|
|
13
|
+
private readonly __children: string;
|
|
14
|
+
childArray: any[];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructor cmi *.n arrays
|
|
18
|
+
* @param {object} params
|
|
19
|
+
*/
|
|
20
|
+
constructor(params: {
|
|
21
|
+
children: string;
|
|
22
|
+
errorCode?: number;
|
|
23
|
+
errorClass?: typeof BaseScormValidationError;
|
|
24
|
+
}) {
|
|
25
|
+
super();
|
|
26
|
+
this.__children = params.children;
|
|
27
|
+
this._errorCode = params.errorCode || scorm12_error_codes.GENERAL;
|
|
28
|
+
this._errorClass = params.errorClass || BaseScormValidationError;
|
|
29
|
+
this.childArray = [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Getter for _children
|
|
34
|
+
* @return {string}
|
|
35
|
+
*/
|
|
36
|
+
get _children(): string {
|
|
37
|
+
return this.__children;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Setter for _children. Just throws an error.
|
|
42
|
+
* @param {string} _children
|
|
43
|
+
*/
|
|
44
|
+
set _children(_children: string) {
|
|
45
|
+
throw new this._errorClass(this._errorCode);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Getter for _count
|
|
50
|
+
* @return {number}
|
|
51
|
+
*/
|
|
52
|
+
get _count(): number {
|
|
53
|
+
return this.childArray.length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Setter for _count. Just throws an error.
|
|
58
|
+
* @param {number} _count
|
|
59
|
+
*/
|
|
60
|
+
set _count(_count: number) {
|
|
61
|
+
throw new this._errorClass(this._errorCode);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* toJSON for *.n arrays
|
|
66
|
+
* @return {object}
|
|
67
|
+
*/
|
|
68
|
+
toJSON(): object {
|
|
69
|
+
this.jsonString = true;
|
|
70
|
+
const result: { [key: string]: any } = {};
|
|
71
|
+
for (let i = 0; i < this.childArray.length; i++) {
|
|
72
|
+
result[i + ""] = this.childArray[i];
|
|
73
|
+
}
|
|
74
|
+
delete this.jsonString;
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for API cmi objects
|
|
3
|
+
*/
|
|
4
|
+
export abstract class BaseCMI {
|
|
5
|
+
jsonString? = false;
|
|
6
|
+
private _initialized = false;
|
|
7
|
+
private _start_time: number | undefined;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Getter for _initialized
|
|
11
|
+
* @return {boolean}
|
|
12
|
+
*/
|
|
13
|
+
get initialized(): boolean {
|
|
14
|
+
return this._initialized;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Getter for _start_time
|
|
19
|
+
* @return {number | undefined}
|
|
20
|
+
*/
|
|
21
|
+
get start_time(): number | undefined {
|
|
22
|
+
return this._start_time;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Called when the API has been initialized after the CMI has been created
|
|
27
|
+
*/
|
|
28
|
+
initialize(): void {
|
|
29
|
+
this._initialized = true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Called when the player should override the 'session_time' provided by
|
|
34
|
+
* the module
|
|
35
|
+
*/
|
|
36
|
+
setStartTime(): void {
|
|
37
|
+
this._start_time = new Date().getTime();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Base class for cmi root objects
|
|
43
|
+
*/
|
|
44
|
+
export abstract class BaseRootCMI extends BaseCMI {
|
|
45
|
+
abstract getCurrentTotalTime(): string;
|
|
46
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import APIConstants from "../../constants/api_constants";
|
|
2
|
+
import Regex from "../../constants/regex";
|
|
3
|
+
import { BaseCMI } from "./base_cmi";
|
|
4
|
+
import { checkValidFormat, checkValidRange } from "./validation";
|
|
5
|
+
import ErrorCodes from "../../constants/error_codes";
|
|
6
|
+
import { BaseScormValidationError } from "../../exceptions";
|
|
7
|
+
|
|
8
|
+
const scorm12_constants = APIConstants.scorm12;
|
|
9
|
+
const scorm12_regex = Regex.scorm12;
|
|
10
|
+
export const scorm12_error_codes = ErrorCodes.scorm12;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Base class for cmi *.score objects
|
|
14
|
+
*/
|
|
15
|
+
export class CMIScore extends BaseCMI {
|
|
16
|
+
private readonly __children: string;
|
|
17
|
+
private readonly __score_range: string | false;
|
|
18
|
+
private readonly __invalid_error_code: number;
|
|
19
|
+
private readonly __invalid_type_code: number;
|
|
20
|
+
private readonly __invalid_range_code: number;
|
|
21
|
+
private readonly __decimal_regex: string;
|
|
22
|
+
private readonly __error_class: typeof BaseScormValidationError;
|
|
23
|
+
private _raw = "";
|
|
24
|
+
private _min = "";
|
|
25
|
+
private _max: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Constructor for *.score
|
|
29
|
+
* @param {
|
|
30
|
+
* score_children: string,
|
|
31
|
+
* score_range: string,
|
|
32
|
+
* max: string,
|
|
33
|
+
* invalidErrorCode: number,
|
|
34
|
+
* invalidTypeCode: number,
|
|
35
|
+
* invalidRangeCode: number,
|
|
36
|
+
* decimalRegex: string,
|
|
37
|
+
* errorClass: typeof BaseScormValidationError
|
|
38
|
+
* } params
|
|
39
|
+
*/
|
|
40
|
+
constructor(params: {
|
|
41
|
+
score_children?: string;
|
|
42
|
+
score_range?: string;
|
|
43
|
+
max?: string;
|
|
44
|
+
invalidErrorCode?: number;
|
|
45
|
+
invalidTypeCode?: number;
|
|
46
|
+
invalidRangeCode?: number;
|
|
47
|
+
decimalRegex?: string;
|
|
48
|
+
errorClass: typeof BaseScormValidationError;
|
|
49
|
+
}) {
|
|
50
|
+
super();
|
|
51
|
+
|
|
52
|
+
this.__children = params.score_children || scorm12_constants.score_children;
|
|
53
|
+
this.__score_range = !params.score_range
|
|
54
|
+
? false
|
|
55
|
+
: scorm12_regex.score_range;
|
|
56
|
+
this._max = params.max || params.max === "" ? params.max : "100";
|
|
57
|
+
this.__invalid_error_code =
|
|
58
|
+
params.invalidErrorCode || scorm12_error_codes.INVALID_SET_VALUE;
|
|
59
|
+
this.__invalid_type_code =
|
|
60
|
+
params.invalidTypeCode || scorm12_error_codes.TYPE_MISMATCH;
|
|
61
|
+
this.__invalid_range_code =
|
|
62
|
+
params.invalidRangeCode || scorm12_error_codes.VALUE_OUT_OF_RANGE;
|
|
63
|
+
this.__decimal_regex = params.decimalRegex || scorm12_regex.CMIDecimal;
|
|
64
|
+
this.__error_class = params.errorClass;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Getter for _children
|
|
69
|
+
* @return {string}
|
|
70
|
+
*/
|
|
71
|
+
get _children(): string {
|
|
72
|
+
return this.__children;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Setter for _children. Just throws an error.
|
|
77
|
+
* @param {string} _children
|
|
78
|
+
*/
|
|
79
|
+
set _children(_children: string) {
|
|
80
|
+
throw new this.__error_class(this.__invalid_error_code);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Getter for _raw
|
|
85
|
+
* @return {string}
|
|
86
|
+
*/
|
|
87
|
+
get raw(): string {
|
|
88
|
+
return this._raw;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Setter for _raw
|
|
93
|
+
* @param {string} raw
|
|
94
|
+
*/
|
|
95
|
+
set raw(raw: string) {
|
|
96
|
+
if (
|
|
97
|
+
checkValidFormat(
|
|
98
|
+
raw,
|
|
99
|
+
this.__decimal_regex,
|
|
100
|
+
this.__invalid_type_code,
|
|
101
|
+
this.__error_class,
|
|
102
|
+
) &&
|
|
103
|
+
(!this.__score_range ||
|
|
104
|
+
checkValidRange(
|
|
105
|
+
raw,
|
|
106
|
+
this.__score_range,
|
|
107
|
+
this.__invalid_range_code,
|
|
108
|
+
this.__error_class,
|
|
109
|
+
))
|
|
110
|
+
) {
|
|
111
|
+
this._raw = raw;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Getter for _min
|
|
117
|
+
* @return {string}
|
|
118
|
+
*/
|
|
119
|
+
get min(): string {
|
|
120
|
+
return this._min;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Setter for _min
|
|
125
|
+
* @param {string} min
|
|
126
|
+
*/
|
|
127
|
+
set min(min: string) {
|
|
128
|
+
if (
|
|
129
|
+
checkValidFormat(
|
|
130
|
+
min,
|
|
131
|
+
this.__decimal_regex,
|
|
132
|
+
this.__invalid_type_code,
|
|
133
|
+
this.__error_class,
|
|
134
|
+
) &&
|
|
135
|
+
(!this.__score_range ||
|
|
136
|
+
checkValidRange(
|
|
137
|
+
min,
|
|
138
|
+
this.__score_range,
|
|
139
|
+
this.__invalid_range_code,
|
|
140
|
+
this.__error_class,
|
|
141
|
+
))
|
|
142
|
+
) {
|
|
143
|
+
this._min = min;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Getter for _max
|
|
149
|
+
* @return {string}
|
|
150
|
+
*/
|
|
151
|
+
get max(): string {
|
|
152
|
+
return this._max;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Setter for _max
|
|
157
|
+
* @param {string} max
|
|
158
|
+
*/
|
|
159
|
+
set max(max: string) {
|
|
160
|
+
if (
|
|
161
|
+
checkValidFormat(
|
|
162
|
+
max,
|
|
163
|
+
this.__decimal_regex,
|
|
164
|
+
this.__invalid_type_code,
|
|
165
|
+
this.__error_class,
|
|
166
|
+
) &&
|
|
167
|
+
(!this.__score_range ||
|
|
168
|
+
checkValidRange(
|
|
169
|
+
max,
|
|
170
|
+
this.__score_range,
|
|
171
|
+
this.__invalid_range_code,
|
|
172
|
+
this.__error_class,
|
|
173
|
+
))
|
|
174
|
+
) {
|
|
175
|
+
this._max = max;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* toJSON for *.score
|
|
181
|
+
* @return {
|
|
182
|
+
* {
|
|
183
|
+
* min: string,
|
|
184
|
+
* max: string,
|
|
185
|
+
* raw: string
|
|
186
|
+
* }
|
|
187
|
+
* }
|
|
188
|
+
*/
|
|
189
|
+
toJSON(): {
|
|
190
|
+
min: string;
|
|
191
|
+
max: string;
|
|
192
|
+
raw: string;
|
|
193
|
+
} {
|
|
194
|
+
this.jsonString = true;
|
|
195
|
+
const result = {
|
|
196
|
+
raw: this.raw,
|
|
197
|
+
min: this.min,
|
|
198
|
+
max: this.max,
|
|
199
|
+
};
|
|
200
|
+
delete this.jsonString;
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { BaseScormValidationError } from "../../exceptions";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check if the value matches the proper format. If not, throw proper error code.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} value
|
|
7
|
+
* @param {string} regexPattern
|
|
8
|
+
* @param {number} errorCode
|
|
9
|
+
* @param {typeof BaseScormValidationError} errorClass
|
|
10
|
+
* @param {boolean} [allowEmptyString]
|
|
11
|
+
* @return {boolean}
|
|
12
|
+
*/
|
|
13
|
+
export function checkValidFormat(
|
|
14
|
+
value: string,
|
|
15
|
+
regexPattern: string,
|
|
16
|
+
errorCode: number,
|
|
17
|
+
errorClass: typeof BaseScormValidationError,
|
|
18
|
+
allowEmptyString?: boolean,
|
|
19
|
+
): boolean {
|
|
20
|
+
if (typeof value !== "string") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const formatRegex = new RegExp(regexPattern);
|
|
24
|
+
const matches = value.match(formatRegex);
|
|
25
|
+
if (allowEmptyString && value === "") {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (value === undefined || !matches || matches[0] === "") {
|
|
29
|
+
throw new errorClass(errorCode);
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if the value matches the proper range. If not, throw proper error code.
|
|
36
|
+
*
|
|
37
|
+
* @param {any} value
|
|
38
|
+
* @param {string} rangePattern
|
|
39
|
+
* @param {number} errorCode
|
|
40
|
+
* @param {typeof BaseScormValidationError} errorClass
|
|
41
|
+
* @return {boolean}
|
|
42
|
+
*/
|
|
43
|
+
export function checkValidRange(
|
|
44
|
+
value: any,
|
|
45
|
+
rangePattern: string,
|
|
46
|
+
errorCode: number,
|
|
47
|
+
errorClass: typeof BaseScormValidationError,
|
|
48
|
+
): boolean {
|
|
49
|
+
const ranges = rangePattern.split("#");
|
|
50
|
+
value = value * 1.0;
|
|
51
|
+
if (value >= ranges[0]) {
|
|
52
|
+
if (ranges[1] === "*" || value <= ranges[1]) {
|
|
53
|
+
return true;
|
|
54
|
+
} else {
|
|
55
|
+
throw new errorClass(errorCode);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
throw new errorClass(errorCode);
|
|
59
|
+
}
|
|
60
|
+
}
|