@media-quest/builder 0.0.25 → 0.0.27
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/dist/public-api.d.ts +819 -0
- package/dist/public-api.js +2696 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +20 -6
- package/src/Builder-option.ts +64 -64
- package/src/Builder-question.spec.ts +68 -68
- package/src/Builder-question.ts +98 -102
- package/src/Builder-schema.spec.ts +135 -144
- package/src/Builder-schema.ts +70 -69
- package/src/Builder-text.spec.ts +24 -24
- package/src/Builder-text.ts +57 -57
- package/src/BuilderObject.ts +30 -29
- package/src/builder-compiler.ts +1 -1
- package/src/code-book/codebook-variable.ts +27 -0
- package/src/code-book/codebook.ts +81 -0
- package/src/page/Builder-page-collection.spec.ts +209 -0
- package/src/page/Builder-page-collection.ts +113 -0
- package/src/page/Builder-page.spec.ts +163 -0
- package/src/{Builder-page.ts → page/Builder-page.ts} +74 -95
- package/src/primitives/ID.spec.ts +39 -39
- package/src/primitives/ID.ts +26 -10
- package/src/primitives/page-prefix.ts +59 -59
- package/src/primitives/varID.ts +12 -12
- package/src/public-api.ts +8 -6
- package/src/rulebuilder/Builder-rule.spec.ts +323 -323
- package/src/rulebuilder/Builder-rule.ts +191 -191
- package/src/rulebuilder/RuleAction.ts +105 -106
- package/src/rulebuilder/RuleBuilder-test-utils.ts +320 -320
- package/src/rulebuilder/RuleInput.ts +30 -30
- package/src/rulebuilder/RuleVariable.ts +34 -48
- package/src/rulebuilder/SingleSelectItem.ts +9 -8
- package/src/rulebuilder/condition/Builder-condition-group.ts +14 -6
- package/src/rulebuilder/condition/Builder-condition.spec.ts +12 -12
- package/src/rulebuilder/condition/Builder-condition.ts +17 -13
- package/src/rulebuilder/index.ts +16 -3
- package/src/rulebuilder/page-action-manager.ts +33 -33
- package/src/rulebuilder/rule2/Rule2.ts +211 -215
- package/src/schema-config.ts +25 -25
- package/src/sum-score/sum-score-answer.ts +6 -0
- package/src/sum-score/sum-score-variable-collection.spec.ts +68 -0
- package/src/sum-score/sum-score-variable-collection.ts +101 -0
- package/src/sum-score/sum-score-variable.spec.ts +253 -0
- package/src/sum-score/sum-score-variable.ts +98 -0
- package/src/{variable → sum-score}/sum-score.ts +57 -26
- package/src/tag/BuilderTag.ts +45 -0
- package/src/tag/Tag-Collection.ts +53 -0
- package/src/theme/default-theme-compiler.ts +358 -358
- package/tsconfig.json +19 -15
- package/src/Builder-page.spec.ts +0 -320
- package/src/BuilderTag.ts +0 -96
- package/src/codebook.ts +0 -72
- package/src/variable/b-variable.ts +0 -68
- package/src/variable/mq-variable.spec.ts +0 -147
- package/src/variable/sum-score-variable.ts +0 -50
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { SumScore } from "./sum-score";
|
|
2
|
+
import { SumScoreVariable, SumScoreVariableDto } from "./sum-score-variable";
|
|
3
|
+
import { SchemaID, SumScoreVariableID } from "../primitives/ID";
|
|
4
|
+
import { SumScoreAnswer } from "./sum-score-answer";
|
|
5
|
+
import { BuilderSchema } from "../Builder-schema";
|
|
6
|
+
import { SchemaPrefix } from "../primitives/schema-prefix";
|
|
7
|
+
import { CodeBook } from "../code-book/codebook";
|
|
8
|
+
import { BuilderPage } from "../page/Builder-page";
|
|
9
|
+
import { VarID } from "../primitives/varID";
|
|
10
|
+
|
|
11
|
+
const createAnswer = (value: number): SumScoreAnswer => {
|
|
12
|
+
const varId = "v" + value;
|
|
13
|
+
const varLabel = "label for " + varId;
|
|
14
|
+
const valueLabel = "label for value " + value;
|
|
15
|
+
return {
|
|
16
|
+
varId,
|
|
17
|
+
varLabel,
|
|
18
|
+
value,
|
|
19
|
+
valueLabel,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const createSumScore = () => {
|
|
24
|
+
const id = SumScoreVariableID.create();
|
|
25
|
+
const sumVar1: SumScoreVariableDto = {
|
|
26
|
+
id,
|
|
27
|
+
name: "",
|
|
28
|
+
description: "",
|
|
29
|
+
useAvg: true,
|
|
30
|
+
};
|
|
31
|
+
return sumVar1;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const a0 = createAnswer(0);
|
|
35
|
+
const a1 = createAnswer(1);
|
|
36
|
+
const a2 = createAnswer(2);
|
|
37
|
+
const a3 = createAnswer(3);
|
|
38
|
+
const a4 = createAnswer(4);
|
|
39
|
+
const a5 = createAnswer(5);
|
|
40
|
+
const a6 = createAnswer(6);
|
|
41
|
+
const a7 = createAnswer(7);
|
|
42
|
+
const a8 = createAnswer(8);
|
|
43
|
+
const a9 = createAnswer(9);
|
|
44
|
+
|
|
45
|
+
const all = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9];
|
|
46
|
+
|
|
47
|
+
describe("Sum score sum-score.", () => {
|
|
48
|
+
test("Is allowed SumScoreValue", () => {
|
|
49
|
+
expect(SumScore.isAllowedValue(-1)).toBeFalsy();
|
|
50
|
+
expect(SumScore.isAllowedValue(0)).toBeTruthy();
|
|
51
|
+
expect(SumScore.isAllowedValue(1)).toBeTruthy();
|
|
52
|
+
expect(SumScore.isAllowedValue(2)).toBeTruthy();
|
|
53
|
+
expect(SumScore.isAllowedValue(3)).toBeTruthy();
|
|
54
|
+
expect(SumScore.isAllowedValue(4)).toBeTruthy();
|
|
55
|
+
expect(SumScore.isAllowedValue(5)).toBeTruthy();
|
|
56
|
+
expect(SumScore.isAllowedValue(6)).toBeTruthy();
|
|
57
|
+
expect(SumScore.isAllowedValue(7)).toBeTruthy();
|
|
58
|
+
expect(SumScore.isAllowedValue(8)).toBeTruthy();
|
|
59
|
+
expect(SumScore.isAllowedValue(9)).toBeFalsy();
|
|
60
|
+
expect(SumScore.isAllowedValue(999)).toBeFalsy();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("Will calculate 2", () => {
|
|
64
|
+
const ss1 = createSumScore();
|
|
65
|
+
const basedOn = [
|
|
66
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
67
|
+
{ varId: a2.varId, varLabel: a2.varLabel, weight: 1 },
|
|
68
|
+
{ varId: a9.varId, varLabel: a9.varLabel, weight: 1 },
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const score = SumScore.calculate(ss1, basedOn, all);
|
|
72
|
+
expect(score.sumScore).toBe(3);
|
|
73
|
+
expect(score.basedOn.length).toBe(3);
|
|
74
|
+
expect(score.avg).toBe(1.5);
|
|
75
|
+
expect(score.skippedBy9Count).toBe(1);
|
|
76
|
+
});
|
|
77
|
+
test("Will calculate 5 values", () => {
|
|
78
|
+
const ss1 = createSumScore();
|
|
79
|
+
const basedOn = [
|
|
80
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
81
|
+
{ varId: a2.varId, varLabel: a2.varLabel, weight: 1 },
|
|
82
|
+
{ varId: a4.varId, varLabel: a4.varLabel, weight: 1 },
|
|
83
|
+
{ varId: a5.varId, varLabel: a5.varLabel, weight: 1 },
|
|
84
|
+
{ varId: a6.varId, varLabel: a6.varLabel, weight: 1 },
|
|
85
|
+
{ varId: a9.varId, varLabel: a9.varLabel, weight: 0.5 },
|
|
86
|
+
];
|
|
87
|
+
const score = SumScore.calculate(ss1, basedOn, all);
|
|
88
|
+
expect(score.sumScore).toBe(18);
|
|
89
|
+
expect(score.avg).toBe(3.6);
|
|
90
|
+
const basedOn1 = score.basedOn[0];
|
|
91
|
+
expect(basedOn1.value).toBe(a1.value);
|
|
92
|
+
expect(basedOn1.weight).toBe(1);
|
|
93
|
+
expect(basedOn1.varId).toBe(a1.varId);
|
|
94
|
+
expect(basedOn1.varLabel).toBe(a1.varLabel);
|
|
95
|
+
});
|
|
96
|
+
test("Will not include 9 in includedAnswersCount", () => {
|
|
97
|
+
const ss1 = createSumScore();
|
|
98
|
+
const basedOn = [
|
|
99
|
+
{ varId: a0.varId, varLabel: a0.varLabel, weight: 1 },
|
|
100
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
101
|
+
{ varId: a5.varId, varLabel: a5.varLabel, weight: 1 },
|
|
102
|
+
{ varId: a9.varId, varLabel: a9.varLabel, weight: 1 },
|
|
103
|
+
];
|
|
104
|
+
const score = SumScore.calculate(ss1, basedOn, all);
|
|
105
|
+
expect(score.sumScore).toBe(6);
|
|
106
|
+
expect(score.avg).toBe(2);
|
|
107
|
+
expect(score.includedAnswerCount).toBe(3);
|
|
108
|
+
});
|
|
109
|
+
test("Will calculate weight", () => {
|
|
110
|
+
const ss1 = createSumScore();
|
|
111
|
+
const basedOn = [
|
|
112
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
113
|
+
{ varId: a8.varId, varLabel: a8.varLabel, weight: 0.5 },
|
|
114
|
+
];
|
|
115
|
+
const score = SumScore.calculate(ss1, basedOn, all);
|
|
116
|
+
expect(score.sumScore).toBe(5);
|
|
117
|
+
});
|
|
118
|
+
test("Will calculate many weighted variables.", () => {
|
|
119
|
+
const ss1 = createSumScore();
|
|
120
|
+
const basedOn = [
|
|
121
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
122
|
+
{ varId: a2.varId, varLabel: a2.varLabel, weight: 0.5 },
|
|
123
|
+
{ varId: a5.varId, varLabel: a5.varLabel, weight: 1.2 },
|
|
124
|
+
{ varId: a8.varId, varLabel: a8.varLabel, weight: 2 },
|
|
125
|
+
];
|
|
126
|
+
const score = SumScore.calculate(ss1, basedOn, all);
|
|
127
|
+
expect(score.sumScore).toBe(24);
|
|
128
|
+
});
|
|
129
|
+
test("Will count missing answers (missingAnswersCount)", () => {
|
|
130
|
+
const ss1 = createSumScore();
|
|
131
|
+
const basedOn = [
|
|
132
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
133
|
+
{ varId: a2.varId, varLabel: a2.varLabel, weight: 1 },
|
|
134
|
+
{ varId: a3.varId, varLabel: a3.varLabel, weight: 1 },
|
|
135
|
+
{ varId: a5.varId, varLabel: a5.varLabel, weight: 1 },
|
|
136
|
+
{ varId: a9.varId, varLabel: a9.varLabel, weight: 1 },
|
|
137
|
+
];
|
|
138
|
+
const missing5InDataSet = [a1, a2, a8];
|
|
139
|
+
const score = SumScore.calculate(ss1, basedOn, missing5InDataSet);
|
|
140
|
+
expect(score.sumScore).toBe(3);
|
|
141
|
+
expect(score.includedAnswerCount).toBe(2);
|
|
142
|
+
expect(score.missingAnswerCount).toBe(3);
|
|
143
|
+
expect(score.avg).toBe(1.5);
|
|
144
|
+
expect(score.basedOn.length).toBe(2);
|
|
145
|
+
expect(score.avg).toBe(1.5);
|
|
146
|
+
expect(score.errorMessages.length).toBe(0);
|
|
147
|
+
});
|
|
148
|
+
test("includedAnswerCount + missingAnswerCount + skippedBy9Count = SumScoreVariable.basedOn.length", () => {
|
|
149
|
+
const ss1 = createSumScore();
|
|
150
|
+
const basedOn = [
|
|
151
|
+
{ varId: a0.varId, varLabel: a0.varLabel, weight: 1 },
|
|
152
|
+
{ varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
|
|
153
|
+
{ varId: a2.varId, varLabel: a2.varLabel, weight: 1 },
|
|
154
|
+
{ varId: a9.varId, varLabel: a9.varLabel, weight: 1 },
|
|
155
|
+
];
|
|
156
|
+
const answers = [a1, a7, a8, a9];
|
|
157
|
+
const score = SumScore.calculate(ss1, basedOn, answers);
|
|
158
|
+
|
|
159
|
+
expect(score.includedAnswerCount + score.missingAnswerCount + score.skippedBy9Count).toBe(
|
|
160
|
+
basedOn.length,
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
test("calculateAll", () => {
|
|
164
|
+
const prefix = SchemaPrefix.fromValueOrThrow("angst");
|
|
165
|
+
const schema = BuilderSchema.create(SchemaID.create(), "testing", prefix.value);
|
|
166
|
+
const p1 = schema.addPage("question");
|
|
167
|
+
const p2 = schema.addPage("question");
|
|
168
|
+
const p3 = schema.addPage("question");
|
|
169
|
+
|
|
170
|
+
// Setting question text
|
|
171
|
+
p1.mainText.text = "q1";
|
|
172
|
+
p2.mainText.text = "q2";
|
|
173
|
+
p3.mainText.text = "q3";
|
|
174
|
+
const v1 = schema.sumScoreVariableCreate({
|
|
175
|
+
name: "ss1",
|
|
176
|
+
description: "ss1-desc",
|
|
177
|
+
useAvg: true,
|
|
178
|
+
});
|
|
179
|
+
const v2 = schema.sumScoreVariableCreate({
|
|
180
|
+
name: "ss2",
|
|
181
|
+
description: "ss2-desc",
|
|
182
|
+
useAvg: true,
|
|
183
|
+
});
|
|
184
|
+
const v3 = schema.sumScoreVariableCreate({
|
|
185
|
+
name: "ss3",
|
|
186
|
+
description: "ss3-desc",
|
|
187
|
+
useAvg: true,
|
|
188
|
+
});
|
|
189
|
+
const success_v1_p1 = schema.sumScoreVariableAddToPage(v1, p1, 1);
|
|
190
|
+
const success_v1_p2 = schema.sumScoreVariableAddToPage(v1, p2, 1);
|
|
191
|
+
const success_v2_p2 = schema.sumScoreVariableAddToPage(v2, p2, 1);
|
|
192
|
+
const success_v3_p1 = schema.sumScoreVariableAddToPage(v3, p1, 1);
|
|
193
|
+
const success_v3_p2 = schema.sumScoreVariableAddToPage(v3, p2, 1);
|
|
194
|
+
const success_v3_p3 = schema.sumScoreVariableAddToPage(v3, p3, 1);
|
|
195
|
+
expect(success_v1_p1).toBeTruthy();
|
|
196
|
+
expect(success_v1_p2).toBeTruthy();
|
|
197
|
+
expect(success_v2_p2).toBeTruthy();
|
|
198
|
+
expect(success_v3_p1).toBeTruthy();
|
|
199
|
+
expect(success_v3_p2).toBeTruthy();
|
|
200
|
+
expect(success_v3_p3).toBeTruthy();
|
|
201
|
+
|
|
202
|
+
// const v = schema.
|
|
203
|
+
const p1_questionVariable = p1.getQuestionVariables(prefix, 0)[0];
|
|
204
|
+
const p2_questionVariable = p2.getQuestionVariables(prefix, 1)[0];
|
|
205
|
+
const p3_questionVariable = p3.getQuestionVariables(prefix, 2)[0];
|
|
206
|
+
|
|
207
|
+
const ans1: SumScoreAnswer = {
|
|
208
|
+
varId: p1_questionVariable.varId,
|
|
209
|
+
value: 1,
|
|
210
|
+
varLabel: p1_questionVariable.label,
|
|
211
|
+
valueLabel: "Ja",
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const ans2: SumScoreAnswer = {
|
|
215
|
+
varId: p2_questionVariable.varId,
|
|
216
|
+
value: 2,
|
|
217
|
+
varLabel: p2_questionVariable.label,
|
|
218
|
+
valueLabel: "Ja",
|
|
219
|
+
};
|
|
220
|
+
const ans3: SumScoreAnswer = {
|
|
221
|
+
varId: p3_questionVariable.varId,
|
|
222
|
+
value: 3,
|
|
223
|
+
varLabel: p3_questionVariable.label,
|
|
224
|
+
valueLabel: "Ja",
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const sumScores = SumScore.calculateAll(schema.toJson(), [ans1, ans2, ans3]);
|
|
228
|
+
const ss1 = sumScores[0] as SumScore;
|
|
229
|
+
const ss2 = sumScores[1] as SumScore;
|
|
230
|
+
const ss3 = sumScores[2] as SumScore;
|
|
231
|
+
|
|
232
|
+
expect(sumScores.length).toBe(3);
|
|
233
|
+
// BASED ON IS WORKING.
|
|
234
|
+
expect(ss1.basedOn.length).toBe(2);
|
|
235
|
+
expect(ss2.basedOn.length).toBe(1);
|
|
236
|
+
expect(ss3.basedOn.length).toBe(3);
|
|
237
|
+
const isBasedOn = (sumScore: SumScore, variableId: string, variableLabel: string) => {
|
|
238
|
+
const found = sumScore.basedOn.find((basedOnItem) => basedOnItem.varId === variableId);
|
|
239
|
+
|
|
240
|
+
expect(found?.varId).toBe(variableId);
|
|
241
|
+
expect(found?.varLabel).toBe(variableLabel);
|
|
242
|
+
};
|
|
243
|
+
isBasedOn(ss1, ans1.varId, p1_questionVariable.label);
|
|
244
|
+
isBasedOn(ss1, ans2.varId, p2_questionVariable.label);
|
|
245
|
+
isBasedOn(ss2, ans2.varId, p2_questionVariable.label);
|
|
246
|
+
isBasedOn(ss3, ans1.varId, p1_questionVariable.label);
|
|
247
|
+
isBasedOn(ss3, ans2.varId, p2_questionVariable.label);
|
|
248
|
+
isBasedOn(ss3, ans3.varId, p3_questionVariable.label);
|
|
249
|
+
expect(ss1.sumScore).toBe(3);
|
|
250
|
+
expect(ss2.sumScore).toBe(2);
|
|
251
|
+
expect(ss3.sumScore).toBe(6);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { SumScoreVariableID } from "../primitives/ID";
|
|
2
|
+
import { BuilderObject } from "../BuilderObject";
|
|
3
|
+
import { DUtil } from "@media-quest/engine";
|
|
4
|
+
|
|
5
|
+
export interface SumScoreVariableDto {
|
|
6
|
+
id: SumScoreVariableID;
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
useAvg: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* All variables that the sum-score should be based on.
|
|
12
|
+
*/
|
|
13
|
+
// basedOn: Array<{ varId: string; varLabel: string; weight?: number }>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class SumScoreVariable extends BuilderObject<
|
|
17
|
+
"builder-sum-score-variable",
|
|
18
|
+
SumScoreVariableDto
|
|
19
|
+
> {
|
|
20
|
+
readonly objectType = "builder-sum-score-variable";
|
|
21
|
+
readonly id: SumScoreVariableID;
|
|
22
|
+
private _useAvg = true;
|
|
23
|
+
private _name = "";
|
|
24
|
+
private _description = "";
|
|
25
|
+
private _error = "";
|
|
26
|
+
// private _basedOn = new Map<pageId: Page>()
|
|
27
|
+
|
|
28
|
+
// private _basedOn: Array<{ varId: string }> = [];
|
|
29
|
+
public static readonly create = (data: {
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
useAvg: boolean;
|
|
33
|
+
}): SumScoreVariable => {
|
|
34
|
+
const id = SumScoreVariableID.create();
|
|
35
|
+
return new SumScoreVariable({ id, ...data });
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
get hasErrors() {
|
|
39
|
+
return this._error.length !== 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static fromDto = (dto: SumScoreVariableDto): SumScoreVariable => {
|
|
43
|
+
return new SumScoreVariable(dto);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
private constructor(dto: SumScoreVariableDto) {
|
|
47
|
+
super(dto);
|
|
48
|
+
this.id = dto.id;
|
|
49
|
+
this._name = dto.name;
|
|
50
|
+
this._useAvg = dto.useAvg;
|
|
51
|
+
this._description = dto.description;
|
|
52
|
+
}
|
|
53
|
+
toJson(): SumScoreVariableDto {
|
|
54
|
+
const dto: SumScoreVariableDto = {
|
|
55
|
+
description: this.description,
|
|
56
|
+
id: this.id,
|
|
57
|
+
name: this.name,
|
|
58
|
+
useAvg: this.useAvg,
|
|
59
|
+
};
|
|
60
|
+
return dto;
|
|
61
|
+
}
|
|
62
|
+
clone(): SumScoreVariableDto {
|
|
63
|
+
const id = SumScoreVariableID.create();
|
|
64
|
+
const dto = this.toJson();
|
|
65
|
+
return { ...dto, id };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** @internal*/
|
|
69
|
+
_update(data: { name?: string; description?: string; useAvg?: boolean }) {
|
|
70
|
+
const d = data ?? {};
|
|
71
|
+
if (DUtil.isString(d.name)) {
|
|
72
|
+
this._name = d.name;
|
|
73
|
+
}
|
|
74
|
+
if (DUtil.isString(d.description)) {
|
|
75
|
+
this._description = d.description;
|
|
76
|
+
}
|
|
77
|
+
if (DUtil.isBool(d.useAvg)) {
|
|
78
|
+
this._useAvg = d.useAvg;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @internal - used by sum-score-variable-collection.
|
|
84
|
+
*/
|
|
85
|
+
_setError(error: "" | "Duplicate name") {
|
|
86
|
+
this._error = error;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get name() {
|
|
90
|
+
return this._name;
|
|
91
|
+
}
|
|
92
|
+
get description() {
|
|
93
|
+
return this._description;
|
|
94
|
+
}
|
|
95
|
+
get useAvg() {
|
|
96
|
+
return this._useAvg;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { BVariable } from "./b-variable";
|
|
2
1
|
import { SumScoreVariableDto } from "./sum-score-variable";
|
|
2
|
+
import { SumScoreVariableID } from "../primitives/ID";
|
|
3
|
+
import { SumScoreAnswer } from "./sum-score-answer";
|
|
4
|
+
import { CodeBook } from "../code-book/codebook";
|
|
5
|
+
import { BuilderSchemaDto } from "../Builder-schema";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
*
|
|
@@ -28,12 +31,48 @@ export interface SumScore {
|
|
|
28
31
|
errorMessages: string[];
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
const calculateAll = (
|
|
35
|
+
schemaDto: BuilderSchemaDto,
|
|
36
|
+
answers: Array<SumScoreAnswer>,
|
|
37
|
+
): ReadonlyArray<SumScore> => {
|
|
38
|
+
const vs = schemaDto.sumScoreVariables ?? [];
|
|
39
|
+
|
|
40
|
+
const basedOnMap = new Map<SumScoreVariableID, Array<{ varId: string; weight: number }>>();
|
|
41
|
+
const codeBook = CodeBook.fromSchema(schemaDto);
|
|
42
|
+
// codeBook.pageVariables.find(v => v.pageId === )
|
|
43
|
+
const pages = schemaDto.pages;
|
|
44
|
+
// const a: Array<{pageId: PageID, sumScoreVariableId: SumScoreVariableID, weight: number, varId: string}> = []
|
|
45
|
+
|
|
46
|
+
pages.forEach((page) => {
|
|
47
|
+
page.includedInSumScores.forEach((includedInScores) => {
|
|
48
|
+
const variableId = includedInScores.sumScoreVariableId;
|
|
49
|
+
const weight = includedInScores.weight;
|
|
50
|
+
const p = codeBook.pageVariables.find((v) => v.pageId === page.id);
|
|
51
|
+
if (p) {
|
|
52
|
+
const currentBasedOnArray = basedOnMap.get(variableId) ?? [];
|
|
53
|
+
currentBasedOnArray.push({ varId: p.varId, weight });
|
|
54
|
+
basedOnMap.set(variableId, currentBasedOnArray);
|
|
55
|
+
} else {
|
|
56
|
+
// TODO - Global event-bus for errors?
|
|
57
|
+
console.error("INVALID DATA in calculate all sum-scores.");
|
|
58
|
+
// throw Error("Invalid data...");
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
// const pages = Array.isArray(schemaDto.pages) ? schemaDto.pages : [];
|
|
63
|
+
const results: ReadonlyArray<SumScore> = vs.map((v) => {
|
|
64
|
+
const basedOn = basedOnMap.get(v.id) ?? [];
|
|
65
|
+
return calculate(v, basedOn, answers);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return results;
|
|
69
|
+
};
|
|
31
70
|
const calculate = (
|
|
32
71
|
sumScoreVariable: SumScoreVariableDto,
|
|
33
|
-
|
|
72
|
+
basedOnVariables: Array<{ varId: string; weight: number }>,
|
|
73
|
+
answers: Array<SumScoreAnswer>,
|
|
34
74
|
): SumScore => {
|
|
35
75
|
const legalValues: Array<number> = [...ALLOWED_VALUES];
|
|
36
|
-
|
|
37
76
|
// CALCULATE THESE!!
|
|
38
77
|
let includedAnswerCount = 0;
|
|
39
78
|
let skippedBy9Count = 0;
|
|
@@ -41,27 +80,19 @@ const calculate = (
|
|
|
41
80
|
let sumScore = 0;
|
|
42
81
|
const errorMessages: string[] = [];
|
|
43
82
|
const basedOn: SumScore["basedOn"] = [];
|
|
44
|
-
const useAvg =
|
|
83
|
+
const useAvg = sumScoreVariable.useAvg;
|
|
45
84
|
|
|
46
|
-
const basedOnEntries: BasedOnEntry[] =
|
|
47
|
-
const
|
|
85
|
+
const basedOnEntries: BasedOnEntry[] = basedOnVariables.map((scv) => {
|
|
86
|
+
const maybeAnswer = answers.find((v) => v.varId === scv.varId);
|
|
48
87
|
let result: BasedOnEntry = { kind: "missing", varId: scv.varId };
|
|
49
|
-
if (!
|
|
88
|
+
if (!maybeAnswer) {
|
|
50
89
|
return result;
|
|
51
90
|
}
|
|
52
91
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
kind: "invalid-variable",
|
|
56
|
-
varId: scv.varId,
|
|
57
|
-
message: "The actual variable is not a numeric-variable",
|
|
58
|
-
};
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
const value = maybeVariable.numericValue ?? BVariable.MISSING;
|
|
62
|
-
const varLabel = maybeVariable.label;
|
|
92
|
+
const value = maybeAnswer.value;
|
|
93
|
+
const varLabel = maybeAnswer.varLabel;
|
|
63
94
|
const weight = scv.weight ?? 1;
|
|
64
|
-
const varId =
|
|
95
|
+
const varId = maybeAnswer.varId;
|
|
65
96
|
|
|
66
97
|
result = {
|
|
67
98
|
kind: "has-value",
|
|
@@ -111,20 +142,20 @@ const calculate = (
|
|
|
111
142
|
|
|
112
143
|
return result;
|
|
113
144
|
};
|
|
114
|
-
const createVariable = (
|
|
145
|
+
const createVariable = (): SumScoreVariableDto => {
|
|
146
|
+
const id = SumScoreVariableID.create();
|
|
115
147
|
return {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
varId: "sum-score-variable-id",
|
|
122
|
-
basedOn: [],
|
|
148
|
+
id,
|
|
149
|
+
name: "",
|
|
150
|
+
useAvg: true,
|
|
151
|
+
description: "",
|
|
152
|
+
// basedOn: [],
|
|
123
153
|
};
|
|
124
154
|
};
|
|
125
155
|
export const SumScore = {
|
|
126
156
|
ALLOWED_VALUES,
|
|
127
157
|
calculate,
|
|
158
|
+
calculateAll,
|
|
128
159
|
isAllowedValue,
|
|
129
160
|
createVariable,
|
|
130
161
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BuilderObject } from "../BuilderObject";
|
|
2
|
+
import { TagID } from "../primitives/ID";
|
|
3
|
+
|
|
4
|
+
export interface BuilderTagDto {
|
|
5
|
+
readonly id: TagID;
|
|
6
|
+
readonly tag: string;
|
|
7
|
+
readonly description: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class BuilderTag extends BuilderObject<"builder-tag", BuilderTagDto> {
|
|
11
|
+
readonly objectType: "builder-tag" = "builder-tag";
|
|
12
|
+
readonly id: TagID;
|
|
13
|
+
tagText = "";
|
|
14
|
+
tagDescription = "";
|
|
15
|
+
public static readonly MAX_LENGTH = 20;
|
|
16
|
+
public static readonly MIN_LENGTH = 1;
|
|
17
|
+
|
|
18
|
+
public static readonly create = (tag: string, description: string = "") => {
|
|
19
|
+
const id = TagID.create();
|
|
20
|
+
const dto: BuilderTagDto = {
|
|
21
|
+
id,
|
|
22
|
+
tag,
|
|
23
|
+
description,
|
|
24
|
+
};
|
|
25
|
+
return new BuilderTag(dto);
|
|
26
|
+
};
|
|
27
|
+
public static readonly fromDto = (dto: BuilderTagDto) => {
|
|
28
|
+
return new BuilderTag(dto);
|
|
29
|
+
};
|
|
30
|
+
protected constructor(dto: BuilderTagDto) {
|
|
31
|
+
const id = TagID.validateOrCreate(dto.id);
|
|
32
|
+
const withId = { ...dto, id };
|
|
33
|
+
super(withId);
|
|
34
|
+
this.id = id;
|
|
35
|
+
this.tagText = dto.tag ?? "";
|
|
36
|
+
this.tagDescription = dto.description ?? "";
|
|
37
|
+
}
|
|
38
|
+
clone(): BuilderTagDto {
|
|
39
|
+
return this.toJson();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toJson(): BuilderTagDto {
|
|
43
|
+
return { tag: this.tagText, description: this.tagDescription, id: this.id };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { BuilderTag, BuilderTagDto } from "./BuilderTag";
|
|
2
|
+
|
|
3
|
+
export class TagCollection implements Iterable<BuilderTag> {
|
|
4
|
+
private readonly _tags = new Set<BuilderTag>();
|
|
5
|
+
public static readonly create = () => {
|
|
6
|
+
return new TagCollection([]);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
[Symbol.iterator]() {
|
|
10
|
+
const list = [...this._tags];
|
|
11
|
+
return list[Symbol.iterator]();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private constructor(initialTags: ReadonlyArray<BuilderTag>) {
|
|
15
|
+
initialTags.forEach((tag) => {
|
|
16
|
+
this._tags.add(tag);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
init(tags: ReadonlyArray<BuilderTagDto>) {
|
|
21
|
+
const dtoList: ReadonlyArray<BuilderTagDto> = Array.isArray(tags) ? tags : [];
|
|
22
|
+
const all = dtoList.map(BuilderTag.fromDto);
|
|
23
|
+
all.forEach((tag) => {
|
|
24
|
+
this._tags.add(tag);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
add(tag: BuilderTag) {
|
|
29
|
+
this._tags.add(tag);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Delete this tag from collection;
|
|
34
|
+
* @param tag
|
|
35
|
+
*/
|
|
36
|
+
delete(tag: BuilderTag) {
|
|
37
|
+
this._tags.delete(tag);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
toJson(): ReadonlyArray<BuilderTagDto> {
|
|
41
|
+
const list = [...this._tags];
|
|
42
|
+
const dtoList = list.map((t) => t.toJson());
|
|
43
|
+
return dtoList;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
deleteAll(tags: Iterable<BuilderTag>) {
|
|
47
|
+
const l = tags[Symbol.iterator]();
|
|
48
|
+
const asList = [...tags];
|
|
49
|
+
asList.forEach((t) => {
|
|
50
|
+
this.delete(t);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|