@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.
- package/package.json +1 -1
- package/src/Builder-option.ts +66 -66
- package/src/Builder-page.spec.ts +320 -320
- package/src/Builder-page.ts +257 -257
- package/src/Builder-question.spec.ts +68 -68
- package/src/Builder-question.ts +101 -101
- package/src/Builder-schema.spec.ts +357 -306
- package/src/Builder-schema.ts +287 -254
- package/src/Builder-text.spec.ts +24 -24
- package/src/Builder-text.ts +57 -57
- package/src/BuilderMainImageDto.ts +7 -7
- package/src/BuilderMainText.ts +81 -81
- package/src/BuilderMainVideoDto.ts +10 -10
- package/src/BuilderObject.ts +61 -61
- package/src/BuilderTag.ts +97 -97
- package/src/builder-compiler.ts +14 -0
- package/src/codebook.ts +72 -72
- package/src/media-files.ts +28 -28
- package/src/primitives/page-prefix.ts +58 -58
- package/src/primitives/prefix.spec.ts +5 -5
- package/src/primitives/schema-prefix.ts +52 -52
- package/src/primitives/varID.ts +11 -11
- package/src/public-api.ts +3 -1
- package/src/rulebuilder/Builder-rule.spec.ts +322 -322
- package/src/rulebuilder/Builder-rule.ts +190 -190
- package/src/rulebuilder/RuleAction.ts +106 -106
- package/src/rulebuilder/RuleBuilder-test-utils.ts +316 -316
- package/src/rulebuilder/RuleInput.ts +44 -44
- package/src/rulebuilder/RuleVariable.ts +49 -49
- package/src/rulebuilder/SingleSelectItem.ts +135 -135
- package/src/rulebuilder/condition/Builder-condition-group.spec.ts +47 -47
- package/src/rulebuilder/condition/Builder-condition-group.ts +118 -118
- package/src/rulebuilder/condition/Builder-condition.spec.ts +195 -195
- package/src/rulebuilder/condition/Builder-condition.ts +208 -208
- package/src/rulebuilder/condition/Builder-operator.spec.ts +9 -9
- package/src/rulebuilder/condition/Builder-operator.ts +31 -31
- package/src/rulebuilder/index.ts +22 -22
- package/src/rulebuilder/jump-to-action-manager.ts +33 -33
- package/src/rulebuilder/multi-select-item.ts +73 -73
- package/src/rulebuilder/page-action-manager.ts +31 -31
- package/src/rulebuilder/rule2/Rule2.ts +211 -211
- package/src/rulebuilder/tag-action-manager.spec.ts +44 -44
- package/src/rulebuilder/tag-action-manager.ts +28 -28
- package/src/schema-config.ts +25 -25
- package/src/theme/AbstractThemeCompiler.ts +7 -7
- package/src/theme/IDefaultTheme.ts +226 -226
- package/src/theme/css-theme.ts +7 -7
- package/src/theme/default-theme-compiler.ts +358 -358
- package/src/theme/icon-urls.ts +29 -29
- package/src/theme/theme-utils.ts +57 -57
- package/src/theme/theme1.spec.ts +52 -52
- package/src/variable/mq-variable.spec.ts +91 -0
- package/src/{mq-variable.ts → variable/mq-variable.ts} +63 -61
- package/src/variable/sum-score-variable.ts +56 -0
- package/tsconfig.json +15 -15
- package/tsconfig.tsbuildinfo +1 -1
package/src/theme/icon-urls.ts
CHANGED
|
@@ -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
|
+
};
|
package/src/theme/theme-utils.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/theme/theme1.spec.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
readonly
|
|
51
|
-
readonly
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
+
}
|