@media-quest/builder 0.0.22 → 0.0.23

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 (56) hide show
  1. package/package.json +1 -1
  2. package/src/Builder-option.ts +66 -66
  3. package/src/Builder-page.spec.ts +320 -320
  4. package/src/Builder-page.ts +257 -257
  5. package/src/Builder-question.spec.ts +68 -68
  6. package/src/Builder-question.ts +101 -101
  7. package/src/Builder-schema.spec.ts +357 -306
  8. package/src/Builder-schema.ts +287 -254
  9. package/src/Builder-text.spec.ts +24 -24
  10. package/src/Builder-text.ts +57 -57
  11. package/src/BuilderMainImageDto.ts +7 -7
  12. package/src/BuilderMainText.ts +81 -81
  13. package/src/BuilderMainVideoDto.ts +10 -10
  14. package/src/BuilderObject.ts +61 -61
  15. package/src/BuilderTag.ts +97 -97
  16. package/src/builder-compiler.ts +14 -0
  17. package/src/codebook.ts +72 -72
  18. package/src/media-files.ts +28 -28
  19. package/src/primitives/page-prefix.ts +58 -58
  20. package/src/primitives/prefix.spec.ts +5 -5
  21. package/src/primitives/schema-prefix.ts +52 -52
  22. package/src/primitives/varID.ts +11 -11
  23. package/src/public-api.ts +3 -1
  24. package/src/rulebuilder/Builder-rule.spec.ts +322 -322
  25. package/src/rulebuilder/Builder-rule.ts +190 -190
  26. package/src/rulebuilder/RuleAction.ts +106 -106
  27. package/src/rulebuilder/RuleBuilder-test-utils.ts +316 -316
  28. package/src/rulebuilder/RuleInput.ts +44 -44
  29. package/src/rulebuilder/RuleVariable.ts +49 -49
  30. package/src/rulebuilder/SingleSelectItem.ts +135 -135
  31. package/src/rulebuilder/condition/Builder-condition-group.spec.ts +47 -47
  32. package/src/rulebuilder/condition/Builder-condition-group.ts +118 -118
  33. package/src/rulebuilder/condition/Builder-condition.spec.ts +195 -195
  34. package/src/rulebuilder/condition/Builder-condition.ts +208 -208
  35. package/src/rulebuilder/condition/Builder-operator.spec.ts +9 -9
  36. package/src/rulebuilder/condition/Builder-operator.ts +31 -31
  37. package/src/rulebuilder/index.ts +22 -22
  38. package/src/rulebuilder/jump-to-action-manager.ts +33 -33
  39. package/src/rulebuilder/multi-select-item.ts +73 -73
  40. package/src/rulebuilder/page-action-manager.ts +31 -31
  41. package/src/rulebuilder/rule2/Rule2.ts +211 -211
  42. package/src/rulebuilder/tag-action-manager.spec.ts +44 -44
  43. package/src/rulebuilder/tag-action-manager.ts +28 -28
  44. package/src/schema-config.ts +25 -25
  45. package/src/theme/AbstractThemeCompiler.ts +7 -7
  46. package/src/theme/IDefaultTheme.ts +226 -226
  47. package/src/theme/css-theme.ts +7 -7
  48. package/src/theme/default-theme-compiler.ts +358 -358
  49. package/src/theme/icon-urls.ts +29 -29
  50. package/src/theme/theme-utils.ts +57 -57
  51. package/src/theme/theme1.spec.ts +52 -52
  52. package/src/variable/mq-variable.spec.ts +91 -0
  53. package/src/{mq-variable.ts → variable/mq-variable.ts} +63 -61
  54. package/src/variable/sum-score-variable.ts +56 -0
  55. package/tsconfig.json +15 -15
  56. package/tsconfig.tsbuildinfo +1 -1
@@ -1,29 +1,29 @@
1
- export const IconUrls = {
2
- ispeWhitePng:
3
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fispe-hvit.png?alt=media&token=f6fe628b-2d99-472d-a2ea-e062873e2e22',
4
- pauseSvg:
5
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause-24px.svg?alt=media&token=47337491-bb0d-4c56-9c89-a073ce19fad4',
6
- pauseCircleOutlineSvg:
7
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause_circle_outline-24px.svg?alt=media&token=133aabc8-ab9a-4eaa-9914-4f0f82c22ee2',
8
-
9
- pauseCircleFilledSvg:
10
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause_circle_filled-24px.svg?alt=media&token=af3f12c3-3199-4096-8ed2-76347b9a0a0a',
11
- playCircleRegular:
12
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay-circle-regular.svg?alt=media&token=0867b690-d7fd-475c-8e91-b2d7aeca54d1',
13
- playArrowSvg:
14
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay_arrow-24px.svg?alt=media&token=2fa95e1f-61f7-4a18-afb3-210eabae8227',
15
- playCircleOutline:
16
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay_circle_outline-24px.svg?alt=media&token=3a9f62c5-dfa2-40ef-a50e-cf1bdd2d47f2',
17
-
18
- stopCircleSvg:
19
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fstop_circle-24px.svg?alt=media&token=8fbc8b89-29bb-49ad-ae11-b8882ba3ca77',
20
- stopSvg:
21
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fstop-24px.svg?alt=media&token=d2cd41f1-1331-4243-9b7a-dc0f0ccd255d',
22
- replayCircleSvg:
23
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Freplay-24px.svg?alt=media&token=3c35ccf4-b467-4e81-85d6-b36ac64738ad',
24
-
25
- volumeOffSvg:
26
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_off-24px.svg?alt=media&token=4e41cc10-9f4b-4967-b4df-ed0682e657a9',
27
- volumeUpSvg:
28
- 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_up-24px.svg?alt=media&token=551bd0a6-a515-4f87-a245-da433f4833f9'
29
- };
1
+ export const IconUrls = {
2
+ ispeWhitePng:
3
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fispe-hvit.png?alt=media&token=f6fe628b-2d99-472d-a2ea-e062873e2e22',
4
+ pauseSvg:
5
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause-24px.svg?alt=media&token=47337491-bb0d-4c56-9c89-a073ce19fad4',
6
+ pauseCircleOutlineSvg:
7
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause_circle_outline-24px.svg?alt=media&token=133aabc8-ab9a-4eaa-9914-4f0f82c22ee2',
8
+
9
+ pauseCircleFilledSvg:
10
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fpause_circle_filled-24px.svg?alt=media&token=af3f12c3-3199-4096-8ed2-76347b9a0a0a',
11
+ playCircleRegular:
12
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay-circle-regular.svg?alt=media&token=0867b690-d7fd-475c-8e91-b2d7aeca54d1',
13
+ playArrowSvg:
14
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay_arrow-24px.svg?alt=media&token=2fa95e1f-61f7-4a18-afb3-210eabae8227',
15
+ playCircleOutline:
16
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fplay_circle_outline-24px.svg?alt=media&token=3a9f62c5-dfa2-40ef-a50e-cf1bdd2d47f2',
17
+
18
+ stopCircleSvg:
19
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fstop_circle-24px.svg?alt=media&token=8fbc8b89-29bb-49ad-ae11-b8882ba3ca77',
20
+ stopSvg:
21
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fstop-24px.svg?alt=media&token=d2cd41f1-1331-4243-9b7a-dc0f0ccd255d',
22
+ replayCircleSvg:
23
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Freplay-24px.svg?alt=media&token=3c35ccf4-b467-4e81-85d6-b36ac64738ad',
24
+
25
+ volumeOffSvg:
26
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_off-24px.svg?alt=media&token=4e41cc10-9f4b-4967-b4df-ed0682e657a9',
27
+ volumeUpSvg:
28
+ 'https://firebasestorage.googleapis.com/v0/b/ispe-backend-dev.appspot.com/o/public-assets%2Fvolume_up-24px.svg?alt=media&token=551bd0a6-a515-4f87-a245-da433f4833f9'
29
+ };
@@ -1,57 +1,57 @@
1
- import { DStyle } from "@media-quest/engine";
2
- import { DElementDto } from "@media-quest/engine";
3
-
4
- export namespace ThemeUtils {
5
- export const spaceEvenlyX = <T extends Pick<DElementDto, "style">>(
6
- items: ReadonlyArray<T>,
7
- options: { startAt: number; endAt: number; defaultItemWidth: number } = {
8
- startAt: 0,
9
- endAt: 100,
10
- defaultItemWidth: 5,
11
- },
12
- ): ReadonlyArray<T> => {
13
- const startAt = options?.startAt ?? 0;
14
- const endAt = options?.endAt ?? 100;
15
- const range = Math.abs(endAt - startAt);
16
- if (items.length === 0) {
17
- return [];
18
- }
19
- const marginCount = items.length + 1;
20
- const defaultWidth = options.defaultItemWidth ?? 150 / marginCount;
21
-
22
- let totalWidthOfElements = items.reduce((prev, curr) => {
23
- const w = curr.style.w ?? defaultWidth;
24
- return prev + w;
25
- }, 0);
26
-
27
- let cursor = startAt;
28
- const rest = Math.max(range - totalWidthOfElements, 0);
29
- const margin = rest / marginCount;
30
-
31
- items.forEach((item) => {
32
- cursor = cursor + margin;
33
- const w = item.style.w ?? defaultWidth;
34
- const x = cursor;
35
- cursor = cursor + w;
36
- item.style.w = w;
37
- item.style.x = x;
38
- });
39
-
40
- return items;
41
- };
42
-
43
- export const centerY = (): Pick<DStyle, "y" | "transform"> => ({
44
- y: 50,
45
- transform: "translate(0%, 50%)",
46
- });
47
- export const centerX = (): Pick<DStyle, "x" | "transform"> => ({
48
- x: 50,
49
- transform: "translate(-50%, 0%)",
50
- });
51
-
52
- export const centerXY = (): Pick<DStyle, "x" | "y" | "transform"> => ({
53
- x: 50,
54
- y: 50,
55
- transform: "translate(-50%, 50%)",
56
- });
57
- }
1
+ import { DStyle } from "@media-quest/engine";
2
+ import { DElementDto } from "@media-quest/engine";
3
+
4
+ export namespace ThemeUtils {
5
+ export const spaceEvenlyX = <T extends Pick<DElementDto, "style">>(
6
+ items: ReadonlyArray<T>,
7
+ options: { startAt: number; endAt: number; defaultItemWidth: number } = {
8
+ startAt: 0,
9
+ endAt: 100,
10
+ defaultItemWidth: 5,
11
+ },
12
+ ): ReadonlyArray<T> => {
13
+ const startAt = options?.startAt ?? 0;
14
+ const endAt = options?.endAt ?? 100;
15
+ const range = Math.abs(endAt - startAt);
16
+ if (items.length === 0) {
17
+ return [];
18
+ }
19
+ const marginCount = items.length + 1;
20
+ const defaultWidth = options.defaultItemWidth ?? 150 / marginCount;
21
+
22
+ let totalWidthOfElements = items.reduce((prev, curr) => {
23
+ const w = curr.style.w ?? defaultWidth;
24
+ return prev + w;
25
+ }, 0);
26
+
27
+ let cursor = startAt;
28
+ const rest = Math.max(range - totalWidthOfElements, 0);
29
+ const margin = rest / marginCount;
30
+
31
+ items.forEach((item) => {
32
+ cursor = cursor + margin;
33
+ const w = item.style.w ?? defaultWidth;
34
+ const x = cursor;
35
+ cursor = cursor + w;
36
+ item.style.w = w;
37
+ item.style.x = x;
38
+ });
39
+
40
+ return items;
41
+ };
42
+
43
+ export const centerY = (): Pick<DStyle, "y" | "transform"> => ({
44
+ y: 50,
45
+ transform: "translate(0%, 50%)",
46
+ });
47
+ export const centerX = (): Pick<DStyle, "x" | "transform"> => ({
48
+ x: 50,
49
+ transform: "translate(-50%, 0%)",
50
+ });
51
+
52
+ export const centerXY = (): Pick<DStyle, "x" | "y" | "transform"> => ({
53
+ x: 50,
54
+ y: 50,
55
+ transform: "translate(-50%, 50%)",
56
+ });
57
+ }
@@ -1,52 +1,52 @@
1
- import { ThemeUtils } from "./theme-utils";
2
- import { DStyle } from "@media-quest/engine";
3
-
4
- describe("Theme1 works", () => {
5
- test("Can space evenly when all is even", () => {
6
- const btn1 = {};
7
- const els = ThemeUtils.spaceEvenlyX<{ style: Partial<DStyle> }>([
8
- { style: { w: 20 } },
9
- { style: { w: 20 } },
10
- { style: { w: 20 } },
11
- ]);
12
-
13
- const first = els[0];
14
- const second = els[1];
15
- const third = els[2];
16
- expect(first.style.x).toBe(10);
17
- expect(second.style.x).toBe(40);
18
- expect(third.style.x).toBe(70);
19
- // responseButtons.forEach((el) => {
20
- // expect(el._tag === "div").toBe(true);
21
- // expect(el.children.length).toBe(1);
22
- // });
23
- });
24
-
25
- test("Can space evenly even if uneven lengths", () => {
26
- const btn1 = {};
27
- const els = ThemeUtils.spaceEvenlyX([
28
- { style: { w: 10, x: 0 } },
29
- { style: { w: 30, x: 10 } },
30
- { style: { w: 20, x: 30 } },
31
- ]);
32
-
33
- const first = els[0];
34
- const second = els[1];
35
- const third = els[2];
36
- expect(first.style.x).toBe(10);
37
- expect(second.style.x).toBe(30);
38
- expect(third.style.x).toBe(70);
39
- });
40
-
41
- test("Can space evenly on a shorter scale 10-90", () => {
42
- const els = ThemeUtils.spaceEvenlyX([{ style: {} }, { style: {} }, { style: {} }], {
43
- startAt: 10,
44
- endAt: 90,
45
- defaultItemWidth: 20,
46
- }) as ReadonlyArray<{ style: { x: number; w: number } }>;
47
-
48
- expect(els[0].style.x).toBe(15);
49
- // expect(els[1].style.x).toBe(10);
50
- // expect(els[2].style.x).toBe(10);
51
- });
52
- });
1
+ import { ThemeUtils } from "./theme-utils";
2
+ import { DStyle } from "@media-quest/engine";
3
+
4
+ describe("Theme1 works", () => {
5
+ test("Can space evenly when all is even", () => {
6
+ const btn1 = {};
7
+ const els = ThemeUtils.spaceEvenlyX<{ style: Partial<DStyle> }>([
8
+ { style: { w: 20 } },
9
+ { style: { w: 20 } },
10
+ { style: { w: 20 } },
11
+ ]);
12
+
13
+ const first = els[0];
14
+ const second = els[1];
15
+ const third = els[2];
16
+ expect(first.style.x).toBe(10);
17
+ expect(second.style.x).toBe(40);
18
+ expect(third.style.x).toBe(70);
19
+ // responseButtons.forEach((el) => {
20
+ // expect(el._tag === "div").toBe(true);
21
+ // expect(el.children.length).toBe(1);
22
+ // });
23
+ });
24
+
25
+ test("Can space evenly even if uneven lengths", () => {
26
+ const btn1 = {};
27
+ const els = ThemeUtils.spaceEvenlyX([
28
+ { style: { w: 10, x: 0 } },
29
+ { style: { w: 30, x: 10 } },
30
+ { style: { w: 20, x: 30 } },
31
+ ]);
32
+
33
+ const first = els[0];
34
+ const second = els[1];
35
+ const third = els[2];
36
+ expect(first.style.x).toBe(10);
37
+ expect(second.style.x).toBe(30);
38
+ expect(third.style.x).toBe(70);
39
+ });
40
+
41
+ test("Can space evenly on a shorter scale 10-90", () => {
42
+ const els = ThemeUtils.spaceEvenlyX([{ style: {} }, { style: {} }, { style: {} }], {
43
+ startAt: 10,
44
+ endAt: 90,
45
+ defaultItemWidth: 20,
46
+ }) as ReadonlyArray<{ style: { x: number; w: number } }>;
47
+
48
+ expect(els[0].style.x).toBe(15);
49
+ // expect(els[1].style.x).toBe(10);
50
+ // expect(els[2].style.x).toBe(10);
51
+ });
52
+ });
@@ -0,0 +1,91 @@
1
+ import { MqVariable } from "./mq-variable";
2
+ import { SumScoreVariable } from "./sum-score-variable";
3
+ const createVariable = (value: number): MqVariable => {
4
+ return {
5
+ varId: "v" + value,
6
+ label: "label for v" + value,
7
+ numericValue: value,
8
+ origin: "question",
9
+ kind: "numeric-variable",
10
+ };
11
+ };
12
+
13
+ const createSumScore = (basedOn: Array<{ variable: MqVariable; weight?: number }>) => {
14
+ const sumVar1: SumScoreVariable = {
15
+ kind: "numeric-variable",
16
+ initialValue: 0,
17
+ min: 0,
18
+ origin: "sum-score",
19
+ label: "Sum 123",
20
+ varId: "sum-score-variable-id",
21
+ basedOn: basedOn.map((v) => ({ varId: v.variable.varId, weight: v.weight })),
22
+ };
23
+ return sumVar1;
24
+ };
25
+
26
+ const v0 = createVariable(0);
27
+ const v1 = createVariable(1);
28
+ const v2 = createVariable(2);
29
+ const v3 = createVariable(3);
30
+ const v4 = createVariable(4);
31
+ const v5 = createVariable(5);
32
+ const v6 = createVariable(6);
33
+ const v7 = createVariable(7);
34
+ const v8 = createVariable(8);
35
+ const v9 = createVariable(9);
36
+
37
+ const all = [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9];
38
+ describe("Sum score variable.", () => {
39
+ test("Will calculate 2", () => {
40
+ const ss1 = createSumScore([
41
+ { variable: v1, weight: 1 },
42
+ { variable: v2, weight: 1 },
43
+ ]);
44
+ const score = SumScoreVariable.calculate(ss1, all);
45
+ expect(score.sumScore).toBe(3);
46
+ expect(score.basedOn.length).toBe(2);
47
+ });
48
+ test("Will calculate 5 values", () => {
49
+ const ss1 = createSumScore([
50
+ { variable: v1, weight: 1 },
51
+ { variable: v2, weight: 1 },
52
+ { variable: v4, weight: 1 },
53
+ { variable: v5 },
54
+ { variable: v6, weight: 1 },
55
+ ]);
56
+ const score = SumScoreVariable.calculate(ss1, all);
57
+ expect(score.sumScore).toBe(18);
58
+ const basedOn1 = score.basedOn[0];
59
+ expect(basedOn1.value).toBe(v1.numericValue);
60
+ expect(basedOn1.weight).toBe(1);
61
+ expect(basedOn1.varId).toBe(v1.varId);
62
+ expect(basedOn1.varLabel).toBe(v1.label);
63
+ });
64
+ test("Will not include 9", () => {
65
+ const ss1 = createSumScore([
66
+ { variable: v1, weight: 1 },
67
+ { variable: v5, weight: 1 },
68
+ { variable: v9, weight: 1 },
69
+ ]);
70
+ const score = SumScoreVariable.calculate(ss1, all);
71
+ expect(score.sumScore).toBe(6);
72
+ });
73
+ test("Will not calculate weight", () => {
74
+ const ss1 = createSumScore([
75
+ { variable: v1, weight: 1 },
76
+ { variable: v8, weight: 0.5 },
77
+ ]);
78
+ const score = SumScoreVariable.calculate(ss1, all);
79
+ expect(score.sumScore).toBe(5);
80
+ });
81
+ test("Will not calculate many weighted variables.", () => {
82
+ const ss1 = createSumScore([
83
+ { variable: v1, weight: 1 },
84
+ { variable: v2, weight: 0.5 },
85
+ { variable: v5, weight: 1.2 },
86
+ { variable: v8, weight: 2 },
87
+ ]);
88
+ const score = SumScoreVariable.calculate(ss1, all);
89
+ expect(score.sumScore).toBe(24);
90
+ });
91
+ });
@@ -1,61 +1,63 @@
1
- export interface MqVariable {
2
- readonly kind: "numeric-variable" | "numeric-range-variable" | "string-variable";
3
-
4
- label: string;
5
- varId: 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
- modulePrefix?: string;
31
- moduleID?: string;
32
- pageNumber?: number;
33
-
34
- // Validations
35
- min?: number;
36
- max?: number;
37
- stepSize?: number;
38
- minLength?: number;
39
- maxLength?: number;
40
- rangeFloor?: number;
41
- rangeCeiling?: number;
42
-
43
- options?: Array<{ label: string; value: number }>;
44
- }
45
-
46
- export interface PageVariable extends MqVariable {
47
- readonly pageId: string;
48
- readonly pagePrefix: string;
49
- readonly pagePosition: number;
50
- readonly modulePrefix: string;
51
- readonly origin: "question" | "form-field";
52
- }
53
-
54
- export interface PredefinedVariable extends MqVariable {
55
- readonly origin: "predefined";
56
- readonly modulePrefix: string;
57
- readonly moduleID: string;
58
- defaultValue: number;
59
- requireManualSelection: boolean;
60
- options: Array<{ label: string; value: number }>;
61
- }
1
+ export interface MqVariable {
2
+ readonly kind: "numeric-variable" | "numeric-range-variable" | "string-variable";
3
+
4
+ label: string;
5
+ varId: string;
6
+ description?: string;
7
+
8
+ // Values - The actual value of the variable.
9
+ stringValue?: string;
10
+ numericValue?: number;
11
+ minValue?: number;
12
+ initialValue?: number;
13
+ maxValue?: number;
14
+ defaultValue?: number | string;
15
+ defaultMinValue?: number;
16
+ defaultMaxValue?: number;
17
+
18
+ // Context
19
+ origin:
20
+ | "question"
21
+ | "form-field"
22
+ | "predefined"
23
+ | "event"
24
+ | "calculated"
25
+ | "sum-score"
26
+ | "predefined-or-question";
27
+
28
+ pageId?: string;
29
+ eventSource?: string;
30
+ pagePrefix?: 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
+ export interface PageVariable extends MqVariable {
50
+ readonly pageId: string;
51
+ readonly pagePrefix: string;
52
+ readonly pagePosition: number;
53
+ readonly modulePrefix: string;
54
+ readonly origin: "question" | "form-field";
55
+ }
56
+
57
+ export interface PredefinedVariable extends MqVariable {
58
+ readonly origin: "predefined";
59
+ readonly modulePrefix: string;
60
+ readonly moduleID: string;
61
+ defaultValue: number;
62
+ options: Array<{ label: string; value: number }>;
63
+ }
@@ -0,0 +1,56 @@
1
+ import { MqVariable } from "./mq-variable";
2
+
3
+ export interface SumScoreVariable extends MqVariable {
4
+ readonly origin: "sum-score";
5
+ initialValue: number;
6
+ basedOn: Array<{ varId: string; weight?: number }>;
7
+ }
8
+
9
+ /**
10
+ *
11
+ * A constant Array that contains all legal
12
+ */
13
+ const ALLOWED_SUM_SCORE_VALUES = [1, 2, 3, 4, 5, 6, 7, 8] as const;
14
+ export interface SumScoreResult {
15
+ sumScore: number;
16
+ basedOn: Array<{ varId: string; value: number; weight: number; varLabel: string }>;
17
+ }
18
+ const calculate = (
19
+ sumScoreVariable: SumScoreVariable,
20
+ allVariables: Array<Pick<MqVariable, "varId" | "numericValue" | "kind" | "label">>,
21
+ ): SumScoreResult => {
22
+ const basedOnList = sumScoreVariable.basedOn;
23
+ // let sum = sumScoreVariable.initialValue ?? 0;
24
+ const result: SumScoreResult = {
25
+ sumScore: sumScoreVariable.initialValue ?? 0,
26
+ basedOn: [],
27
+ };
28
+ const legalValues: Array<number> = [...ALLOWED_SUM_SCORE_VALUES];
29
+ allVariables.forEach((v) => {
30
+ if (v.kind !== "numeric-variable") return;
31
+ const numValue = v.numericValue;
32
+ if (typeof numValue !== "number") return;
33
+ if (!legalValues.includes(numValue)) return;
34
+
35
+ basedOnList.forEach((item) => {
36
+ if (item.varId === v.varId) {
37
+ const weight = typeof item.weight === "number" ? item.weight : 1;
38
+ const weightedValue = numValue * weight;
39
+
40
+ result.basedOn.push({
41
+ varId: item.varId,
42
+ weight: weight,
43
+ varLabel: v.label,
44
+ value: numValue,
45
+ });
46
+ result.sumScore = result.sumScore + weightedValue;
47
+ // sum = sum + weightedValue;
48
+ }
49
+ });
50
+ });
51
+ return result;
52
+ };
53
+ export const SumScoreVariable = {
54
+ ALLOWED_SUM_SCORE_VALUES,
55
+ calculate,
56
+ };
package/tsconfig.json CHANGED
@@ -1,15 +1,15 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2022",
4
- "module": "commonjs",
5
- "moduleResolution": "node",
6
- "declaration": true,
7
- "strict": true,
8
- "esModuleInterop": true,
9
- "skipLibCheck": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "rootDir": "./src",
12
- "composite": true,
13
- "outDir": "./dist"
14
- },
15
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "module": "commonjs",
5
+ "moduleResolution": "node",
6
+ "declaration": true,
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "rootDir": "./src",
12
+ "composite": true,
13
+ "outDir": "./dist"
14
+ },
15
+ }