@media-quest/builder 0.0.23 → 0.0.25
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/package.json +2 -2
- package/src/Builder-option.ts +64 -66
- package/src/Builder-page.spec.ts +320 -320
- package/src/Builder-page.ts +259 -257
- package/src/Builder-question.spec.ts +68 -68
- package/src/Builder-question.ts +102 -101
- package/src/Builder-schema.spec.ts +357 -357
- package/src/Builder-schema.ts +292 -287
- package/src/Builder-text.spec.ts +24 -24
- package/src/Builder-text.ts +57 -57
- package/src/BuilderObject.ts +29 -61
- package/src/BuilderTag.ts +96 -97
- package/src/codebook.ts +72 -72
- package/src/primitives/ID.spec.ts +39 -0
- package/src/primitives/ID.ts +119 -0
- package/src/primitives/page-prefix.ts +59 -58
- package/src/primitives/varID.ts +12 -11
- package/src/public-api.ts +4 -2
- package/src/rulebuilder/Builder-rule.spec.ts +323 -322
- package/src/rulebuilder/Builder-rule.ts +191 -190
- package/src/rulebuilder/RuleBuilder-test-utils.ts +320 -316
- package/src/rulebuilder/RuleVariable.ts +48 -49
- package/src/rulebuilder/page-action-manager.ts +33 -31
- package/src/rulebuilder/rule2/Rule2.ts +215 -211
- package/src/schema-config.ts +25 -25
- package/src/variable/{mq-variable.ts → b-variable.ts} +68 -63
- package/src/variable/mq-variable.spec.ts +147 -91
- package/src/variable/sum-score-variable.ts +50 -56
- package/src/variable/sum-score.ts +130 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,63 +1,68 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
readonly kind: "numeric-variable" | "numeric-range-variable" | "string-variable";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| "
|
|
21
|
-
| "
|
|
22
|
-
| "
|
|
23
|
-
| "
|
|
24
|
-
| "
|
|
25
|
-
| "
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
modulePrefix?: string;
|
|
32
|
-
moduleID?: string;
|
|
33
|
-
pageNumber?: number;
|
|
34
|
-
|
|
35
|
-
// Validations
|
|
36
|
-
min?: number;
|
|
37
|
-
max?: number;
|
|
38
|
-
stepSize?: number;
|
|
39
|
-
minLength?: number;
|
|
40
|
-
maxLength?: number;
|
|
41
|
-
rangeFloor?: number;
|
|
42
|
-
rangeCeiling?: number;
|
|
43
|
-
|
|
44
|
-
// Analytics
|
|
45
|
-
options?: Array<{ label: string; value: number }>;
|
|
46
|
-
basedOn?: Array<{ varId: string; weight?: number }>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
readonly
|
|
59
|
-
readonly
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
export interface BVariable {
|
|
2
|
+
readonly kind: "numeric-variable" | "numeric-range-variable" | "string-variable";
|
|
3
|
+
label: string;
|
|
4
|
+
varId: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
|
|
7
|
+
// Values - The actual value of the variable.
|
|
8
|
+
stringValue?: string;
|
|
9
|
+
numericValue?: number;
|
|
10
|
+
minValue?: number;
|
|
11
|
+
initialValue?: number;
|
|
12
|
+
maxValue?: number;
|
|
13
|
+
defaultValue?: number | string;
|
|
14
|
+
defaultMinValue?: number;
|
|
15
|
+
defaultMaxValue?: number;
|
|
16
|
+
|
|
17
|
+
// Context
|
|
18
|
+
origin:
|
|
19
|
+
| "question"
|
|
20
|
+
| "form-field"
|
|
21
|
+
| "predefined"
|
|
22
|
+
| "event"
|
|
23
|
+
| "calculated"
|
|
24
|
+
| "sum-score"
|
|
25
|
+
| "predefined-or-question";
|
|
26
|
+
|
|
27
|
+
pageId?: string;
|
|
28
|
+
eventSource?: string;
|
|
29
|
+
pagePrefix?: string;
|
|
30
|
+
questionPrefix?: string;
|
|
31
|
+
modulePrefix?: string;
|
|
32
|
+
moduleID?: string;
|
|
33
|
+
pageNumber?: number;
|
|
34
|
+
|
|
35
|
+
// Validations
|
|
36
|
+
min?: number;
|
|
37
|
+
max?: number;
|
|
38
|
+
stepSize?: number;
|
|
39
|
+
minLength?: number;
|
|
40
|
+
maxLength?: number;
|
|
41
|
+
rangeFloor?: number;
|
|
42
|
+
rangeCeiling?: number;
|
|
43
|
+
|
|
44
|
+
// Analytics
|
|
45
|
+
options?: Array<{ label: string; value: number }>;
|
|
46
|
+
basedOn?: Array<{ varId: string; weight?: number }>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const MISSING = 999;
|
|
50
|
+
export const BVariable = {
|
|
51
|
+
MISSING,
|
|
52
|
+
} as const;
|
|
53
|
+
|
|
54
|
+
export interface PageVariable extends BVariable {
|
|
55
|
+
readonly pageId: string;
|
|
56
|
+
readonly pagePrefix: string;
|
|
57
|
+
readonly pagePosition: number;
|
|
58
|
+
readonly modulePrefix: string;
|
|
59
|
+
readonly origin: "question" | "form-field";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface PredefinedVariable extends BVariable {
|
|
63
|
+
readonly origin: "predefined";
|
|
64
|
+
readonly modulePrefix: string;
|
|
65
|
+
readonly moduleID: string;
|
|
66
|
+
defaultValue: number;
|
|
67
|
+
options: Array<{ label: string; value: number }>;
|
|
68
|
+
}
|
|
@@ -1,91 +1,147 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
expect(
|
|
46
|
-
expect(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
expect(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1
|
+
import { BVariable } from "./b-variable";
|
|
2
|
+
import { SumScore } from "./sum-score";
|
|
3
|
+
import { SumScoreVariableDto } from "./sum-score-variable";
|
|
4
|
+
const createVariable = (value: number): BVariable => {
|
|
5
|
+
return {
|
|
6
|
+
varId: "v" + value,
|
|
7
|
+
label: "label for v" + value,
|
|
8
|
+
numericValue: value,
|
|
9
|
+
origin: "question",
|
|
10
|
+
kind: "numeric-variable",
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const createSumScore = (basedOn: Array<{ variable: BVariable; weight?: number }>) => {
|
|
15
|
+
const sumVar1: SumScoreVariableDto = {
|
|
16
|
+
kind: "numeric-variable",
|
|
17
|
+
initialValue: 0,
|
|
18
|
+
min: 0,
|
|
19
|
+
origin: "sum-score",
|
|
20
|
+
label: "Sum 123",
|
|
21
|
+
varId: "sum-score-variable-id",
|
|
22
|
+
basedOn: basedOn.map((v) => ({ varId: v.variable.varId, weight: v.weight })),
|
|
23
|
+
};
|
|
24
|
+
return sumVar1;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const v0 = createVariable(0);
|
|
28
|
+
const v1 = createVariable(1);
|
|
29
|
+
const v2 = createVariable(2);
|
|
30
|
+
const v3 = createVariable(3);
|
|
31
|
+
const v4 = createVariable(4);
|
|
32
|
+
const v5 = createVariable(5);
|
|
33
|
+
const v6 = createVariable(6);
|
|
34
|
+
const v7 = createVariable(7);
|
|
35
|
+
const v8 = createVariable(8);
|
|
36
|
+
const v9 = createVariable(9);
|
|
37
|
+
|
|
38
|
+
const all = [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9];
|
|
39
|
+
describe("Sum score variable.", () => {
|
|
40
|
+
test("Is allowed SumScoreValue", () => {
|
|
41
|
+
expect(SumScore.isAllowedValue(-1)).toBeFalsy();
|
|
42
|
+
expect(SumScore.isAllowedValue(0)).toBeTruthy();
|
|
43
|
+
expect(SumScore.isAllowedValue(1)).toBeTruthy();
|
|
44
|
+
expect(SumScore.isAllowedValue(2)).toBeTruthy();
|
|
45
|
+
expect(SumScore.isAllowedValue(3)).toBeTruthy();
|
|
46
|
+
expect(SumScore.isAllowedValue(4)).toBeTruthy();
|
|
47
|
+
expect(SumScore.isAllowedValue(5)).toBeTruthy();
|
|
48
|
+
expect(SumScore.isAllowedValue(6)).toBeTruthy();
|
|
49
|
+
expect(SumScore.isAllowedValue(7)).toBeTruthy();
|
|
50
|
+
expect(SumScore.isAllowedValue(8)).toBeTruthy();
|
|
51
|
+
expect(SumScore.isAllowedValue(9)).toBeFalsy();
|
|
52
|
+
expect(SumScore.isAllowedValue(999)).toBeFalsy();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("Will calculate 2", () => {
|
|
56
|
+
const ss1 = createSumScore([
|
|
57
|
+
{ variable: v1, weight: 1 },
|
|
58
|
+
{ variable: v2, weight: 1 },
|
|
59
|
+
{ variable: v9, weight: 1 },
|
|
60
|
+
]);
|
|
61
|
+
const score = SumScore.calculate(ss1, all);
|
|
62
|
+
expect(score.sumScore).toBe(3);
|
|
63
|
+
expect(score.basedOn.length).toBe(3);
|
|
64
|
+
expect(score.avg).toBe(1.5);
|
|
65
|
+
expect(score.skippedBy9Count).toBe(1);
|
|
66
|
+
});
|
|
67
|
+
test("Will calculate 5 values", () => {
|
|
68
|
+
const ss1 = createSumScore([
|
|
69
|
+
{ variable: v1, weight: 1 },
|
|
70
|
+
{ variable: v2, weight: 1 },
|
|
71
|
+
{ variable: v4, weight: 1 },
|
|
72
|
+
{ variable: v5, weight: 1 },
|
|
73
|
+
{ variable: v6, weight: 1 },
|
|
74
|
+
{ variable: v9, weight: 0.5 },
|
|
75
|
+
]);
|
|
76
|
+
const score = SumScore.calculate(ss1, all);
|
|
77
|
+
expect(score.sumScore).toBe(18);
|
|
78
|
+
expect(score.avg).toBe(3.6);
|
|
79
|
+
const basedOn1 = score.basedOn[0];
|
|
80
|
+
expect(basedOn1.value).toBe(v1.numericValue);
|
|
81
|
+
expect(basedOn1.weight).toBe(1);
|
|
82
|
+
expect(basedOn1.varId).toBe(v1.varId);
|
|
83
|
+
expect(basedOn1.varLabel).toBe(v1.label);
|
|
84
|
+
});
|
|
85
|
+
test("Will not include 9 in includedAnswersCount", () => {
|
|
86
|
+
const ss1 = createSumScore([
|
|
87
|
+
{ variable: v0, weight: 1 },
|
|
88
|
+
{ variable: v1, weight: 1 },
|
|
89
|
+
{ variable: v5, weight: 1 },
|
|
90
|
+
{ variable: v9, weight: 1 },
|
|
91
|
+
]);
|
|
92
|
+
const score = SumScore.calculate(ss1, all);
|
|
93
|
+
expect(score.sumScore).toBe(6);
|
|
94
|
+
expect(score.avg).toBe(2);
|
|
95
|
+
expect(score.includedAnswerCount).toBe(3);
|
|
96
|
+
});
|
|
97
|
+
test("Will calculate weight", () => {
|
|
98
|
+
const ss1 = createSumScore([
|
|
99
|
+
{ variable: v1, weight: 1 },
|
|
100
|
+
{ variable: v8, weight: 0.5 },
|
|
101
|
+
]);
|
|
102
|
+
const score = SumScore.calculate(ss1, all);
|
|
103
|
+
expect(score.sumScore).toBe(5);
|
|
104
|
+
});
|
|
105
|
+
test("Will calculate many weighted variables.", () => {
|
|
106
|
+
const ss1 = createSumScore([
|
|
107
|
+
{ variable: v1, weight: 1 },
|
|
108
|
+
{ variable: v2, weight: 0.5 },
|
|
109
|
+
{ variable: v5, weight: 1.2 },
|
|
110
|
+
{ variable: v8, weight: 2 },
|
|
111
|
+
]);
|
|
112
|
+
const score = SumScore.calculate(ss1, all);
|
|
113
|
+
expect(score.sumScore).toBe(24);
|
|
114
|
+
});
|
|
115
|
+
test("Will count missing answers (missingAnswersCount)", () => {
|
|
116
|
+
const ss1 = createSumScore([
|
|
117
|
+
{ variable: v1 },
|
|
118
|
+
{ variable: v2 },
|
|
119
|
+
{ variable: v3 },
|
|
120
|
+
{ variable: v5 },
|
|
121
|
+
{ variable: v9 },
|
|
122
|
+
]);
|
|
123
|
+
const missing5InDataSet = [v1, v2, v8];
|
|
124
|
+
const score = SumScore.calculate(ss1, missing5InDataSet);
|
|
125
|
+
expect(score.sumScore).toBe(3);
|
|
126
|
+
expect(score.includedAnswerCount).toBe(2);
|
|
127
|
+
expect(score.missingAnswerCount).toBe(3);
|
|
128
|
+
expect(score.avg).toBe(1.5);
|
|
129
|
+
expect(score.basedOn.length).toBe(2);
|
|
130
|
+
expect(score.avg).toBe(1.5);
|
|
131
|
+
expect(score.errorMessages.length).toBe(0);
|
|
132
|
+
});
|
|
133
|
+
test("includedAnswerCount + missingAnswerCount + skippedBy9Count = SumScoreVariable.basedOn.length", () => {
|
|
134
|
+
const ss1 = createSumScore([
|
|
135
|
+
{ variable: v0 },
|
|
136
|
+
{ variable: v1 },
|
|
137
|
+
{ variable: v2 },
|
|
138
|
+
{ variable: v9 },
|
|
139
|
+
]);
|
|
140
|
+
const answers = [v1, v7, v8, v9];
|
|
141
|
+
const score = SumScore.calculate(ss1, answers);
|
|
142
|
+
|
|
143
|
+
expect(score.includedAnswerCount + score.missingAnswerCount + score.skippedBy9Count).toBe(
|
|
144
|
+
ss1.basedOn.length,
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -1,56 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return result;
|
|
52
|
-
};
|
|
53
|
-
export const SumScoreVariable = {
|
|
54
|
-
ALLOWED_SUM_SCORE_VALUES,
|
|
55
|
-
calculate,
|
|
56
|
-
};
|
|
1
|
+
import { BVariable } from "./b-variable";
|
|
2
|
+
import { BuilderObjectId } from "../BuilderObject";
|
|
3
|
+
// import { PageID } from "@media-quest/engine";
|
|
4
|
+
// import { BuilderObject, BuilderObjectId } from "../BuilderObject";
|
|
5
|
+
//
|
|
6
|
+
// export class SumScoreVariable {}
|
|
7
|
+
export interface SumScoreVariableDto extends BVariable {
|
|
8
|
+
readonly origin: "sum-score";
|
|
9
|
+
useAvg?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* All variables that the sum-score should be based on.
|
|
12
|
+
*/
|
|
13
|
+
basedOn: Array<{ varId: string; weight?: number }>;
|
|
14
|
+
}
|
|
15
|
+
export interface SumScoreEntry {
|
|
16
|
+
sumScoreId: BuilderObjectId.SumScoreVariableId;
|
|
17
|
+
// pageId: PageID;
|
|
18
|
+
}
|
|
19
|
+
// export class SumScoreVariable extends BuilderObject<
|
|
20
|
+
// "builder-sum-score-variable",
|
|
21
|
+
// SumScoreVariableDto
|
|
22
|
+
// > {
|
|
23
|
+
// readonly useAvg = false;
|
|
24
|
+
// readonly basedOn: Array<{ varId: string; weight?: number }>;
|
|
25
|
+
// readonly id: BuilderObjectId.SumScoreVariableId;
|
|
26
|
+
// label = ""
|
|
27
|
+
// description = ""
|
|
28
|
+
// toJson(): SumScoreVariableDto {
|
|
29
|
+
// const basedOn = [...this.basedOn]
|
|
30
|
+
// const varId = this.id
|
|
31
|
+
// const label = this.label;
|
|
32
|
+
//
|
|
33
|
+
// return {
|
|
34
|
+
// origin: "sum-score",
|
|
35
|
+
// varId,
|
|
36
|
+
// label,
|
|
37
|
+
// useAvg: this.useAvg,
|
|
38
|
+
// basedOn,
|
|
39
|
+
// };
|
|
40
|
+
// }
|
|
41
|
+
// clone(): SumScoreVariableDto {
|
|
42
|
+
// throw new Error("Method not implemented.");
|
|
43
|
+
// }
|
|
44
|
+
// readonly objectType = "builder-sum-score-variable";
|
|
45
|
+
// constructor(dto: SumScoreVariableDto) {
|
|
46
|
+
// super(dto);
|
|
47
|
+
// this.useAvg = dto.useAvg;
|
|
48
|
+
// this.basedOn = dto.basedOn;
|
|
49
|
+
// }
|
|
50
|
+
// }
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { BVariable } from "./b-variable";
|
|
2
|
+
import { SumScoreVariableDto } from "./sum-score-variable";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* A constant Array that contains all legal
|
|
7
|
+
*/
|
|
8
|
+
const ALLOWED_VALUES = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
9
|
+
const isAllowedValue = (num: number) => {
|
|
10
|
+
const notNegative = num >= 0;
|
|
11
|
+
const lessThanNine = num < 9;
|
|
12
|
+
return notNegative && lessThanNine;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type BasedOnEntry =
|
|
16
|
+
| { kind: "missing"; varId: string }
|
|
17
|
+
| { kind: "invalid-variable"; varId: string; message: string }
|
|
18
|
+
| { kind: "has-value"; varId: string; value: number; weight: number; varLabel: string };
|
|
19
|
+
|
|
20
|
+
export interface SumScore {
|
|
21
|
+
sumScore: number;
|
|
22
|
+
avg: number; // Alle besvarte spørsmål som ikke er 9.
|
|
23
|
+
useAvg: boolean;
|
|
24
|
+
includedAnswerCount: number;
|
|
25
|
+
missingAnswerCount: number;
|
|
26
|
+
skippedBy9Count: number; // Antall vetikke / hopp over
|
|
27
|
+
basedOn: Array<{ varId: string; value: number; weight: number; varLabel: string }>;
|
|
28
|
+
errorMessages: string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const calculate = (
|
|
32
|
+
sumScoreVariable: SumScoreVariableDto,
|
|
33
|
+
allVariables: Array<Pick<BVariable, "varId" | "numericValue" | "kind" | "label">>,
|
|
34
|
+
): SumScore => {
|
|
35
|
+
const legalValues: Array<number> = [...ALLOWED_VALUES];
|
|
36
|
+
|
|
37
|
+
// CALCULATE THESE!!
|
|
38
|
+
let includedAnswerCount = 0;
|
|
39
|
+
let skippedBy9Count = 0;
|
|
40
|
+
let missingAnswerCount = 0;
|
|
41
|
+
let sumScore = 0;
|
|
42
|
+
const errorMessages: string[] = [];
|
|
43
|
+
const basedOn: SumScore["basedOn"] = [];
|
|
44
|
+
const useAvg = !!sumScoreVariable.useAvg;
|
|
45
|
+
|
|
46
|
+
const basedOnEntries: BasedOnEntry[] = sumScoreVariable.basedOn.map((scv) => {
|
|
47
|
+
const maybeVariable = allVariables.find((v) => v.varId === scv.varId);
|
|
48
|
+
let result: BasedOnEntry = { kind: "missing", varId: scv.varId };
|
|
49
|
+
if (!maybeVariable) {
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (maybeVariable.kind !== "numeric-variable") {
|
|
54
|
+
result = {
|
|
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;
|
|
63
|
+
const weight = scv.weight ?? 1;
|
|
64
|
+
const varId = maybeVariable.varId;
|
|
65
|
+
|
|
66
|
+
result = {
|
|
67
|
+
kind: "has-value",
|
|
68
|
+
varId,
|
|
69
|
+
weight,
|
|
70
|
+
value,
|
|
71
|
+
varLabel,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return result;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
basedOnEntries.forEach((entry) => {
|
|
78
|
+
if (entry.kind === "missing") {
|
|
79
|
+
missingAnswerCount++;
|
|
80
|
+
}
|
|
81
|
+
if (entry.kind === "has-value") {
|
|
82
|
+
const { varId, varLabel, weight, value } = { ...entry };
|
|
83
|
+
const isAllowed = isAllowedValue(value);
|
|
84
|
+
if (isAllowed) {
|
|
85
|
+
basedOn.push({ varId, weight, value, varLabel });
|
|
86
|
+
sumScore += entry.value * entry.weight;
|
|
87
|
+
includedAnswerCount++;
|
|
88
|
+
}
|
|
89
|
+
if (value === 9) {
|
|
90
|
+
skippedBy9Count++;
|
|
91
|
+
basedOn.push({ varId, weight, value, varLabel });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (entry.kind === "invalid-variable") {
|
|
95
|
+
errorMessages.push(entry.message);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const avg = sumScore / includedAnswerCount;
|
|
100
|
+
const result: SumScore = {
|
|
101
|
+
avg,
|
|
102
|
+
useAvg,
|
|
103
|
+
includedAnswerCount,
|
|
104
|
+
skippedBy9Count,
|
|
105
|
+
sumScore,
|
|
106
|
+
basedOn,
|
|
107
|
+
missingAnswerCount,
|
|
108
|
+
errorMessages,
|
|
109
|
+
};
|
|
110
|
+
// Calculate avg
|
|
111
|
+
|
|
112
|
+
return result;
|
|
113
|
+
};
|
|
114
|
+
const createVariable = (varId: string): SumScoreVariableDto => {
|
|
115
|
+
return {
|
|
116
|
+
origin: "sum-score",
|
|
117
|
+
kind: "numeric-variable",
|
|
118
|
+
initialValue: 0,
|
|
119
|
+
min: 0,
|
|
120
|
+
label: "Sum 123",
|
|
121
|
+
varId: "sum-score-variable-id",
|
|
122
|
+
basedOn: [],
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
export const SumScore = {
|
|
126
|
+
ALLOWED_VALUES,
|
|
127
|
+
calculate,
|
|
128
|
+
isAllowedValue,
|
|
129
|
+
createVariable,
|
|
130
|
+
};
|