@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.
Files changed (55) hide show
  1. package/dist/public-api.d.ts +819 -0
  2. package/dist/public-api.js +2696 -0
  3. package/dist/public-api.js.map +1 -0
  4. package/package.json +20 -6
  5. package/src/Builder-option.ts +64 -64
  6. package/src/Builder-question.spec.ts +68 -68
  7. package/src/Builder-question.ts +98 -102
  8. package/src/Builder-schema.spec.ts +135 -144
  9. package/src/Builder-schema.ts +70 -69
  10. package/src/Builder-text.spec.ts +24 -24
  11. package/src/Builder-text.ts +57 -57
  12. package/src/BuilderObject.ts +30 -29
  13. package/src/builder-compiler.ts +1 -1
  14. package/src/code-book/codebook-variable.ts +27 -0
  15. package/src/code-book/codebook.ts +81 -0
  16. package/src/page/Builder-page-collection.spec.ts +209 -0
  17. package/src/page/Builder-page-collection.ts +113 -0
  18. package/src/page/Builder-page.spec.ts +163 -0
  19. package/src/{Builder-page.ts → page/Builder-page.ts} +74 -95
  20. package/src/primitives/ID.spec.ts +39 -39
  21. package/src/primitives/ID.ts +26 -10
  22. package/src/primitives/page-prefix.ts +59 -59
  23. package/src/primitives/varID.ts +12 -12
  24. package/src/public-api.ts +8 -6
  25. package/src/rulebuilder/Builder-rule.spec.ts +323 -323
  26. package/src/rulebuilder/Builder-rule.ts +191 -191
  27. package/src/rulebuilder/RuleAction.ts +105 -106
  28. package/src/rulebuilder/RuleBuilder-test-utils.ts +320 -320
  29. package/src/rulebuilder/RuleInput.ts +30 -30
  30. package/src/rulebuilder/RuleVariable.ts +34 -48
  31. package/src/rulebuilder/SingleSelectItem.ts +9 -8
  32. package/src/rulebuilder/condition/Builder-condition-group.ts +14 -6
  33. package/src/rulebuilder/condition/Builder-condition.spec.ts +12 -12
  34. package/src/rulebuilder/condition/Builder-condition.ts +17 -13
  35. package/src/rulebuilder/index.ts +16 -3
  36. package/src/rulebuilder/page-action-manager.ts +33 -33
  37. package/src/rulebuilder/rule2/Rule2.ts +211 -215
  38. package/src/schema-config.ts +25 -25
  39. package/src/sum-score/sum-score-answer.ts +6 -0
  40. package/src/sum-score/sum-score-variable-collection.spec.ts +68 -0
  41. package/src/sum-score/sum-score-variable-collection.ts +101 -0
  42. package/src/sum-score/sum-score-variable.spec.ts +253 -0
  43. package/src/sum-score/sum-score-variable.ts +98 -0
  44. package/src/{variable → sum-score}/sum-score.ts +57 -26
  45. package/src/tag/BuilderTag.ts +45 -0
  46. package/src/tag/Tag-Collection.ts +53 -0
  47. package/src/theme/default-theme-compiler.ts +358 -358
  48. package/tsconfig.json +19 -15
  49. package/src/Builder-page.spec.ts +0 -320
  50. package/src/BuilderTag.ts +0 -96
  51. package/src/codebook.ts +0 -72
  52. package/src/variable/b-variable.ts +0 -68
  53. package/src/variable/mq-variable.spec.ts +0 -147
  54. package/src/variable/sum-score-variable.ts +0 -50
  55. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,163 @@
1
+ import { BuilderPage } from "./Builder-page";
2
+ import type { BuilderPageDto } from "./Builder-page";
3
+ import type { BuilderQuestionDto } from "../Builder-question";
4
+ import { DUtil } from "@media-quest/engine";
5
+ import { PagePrefix } from "../primitives/page-prefix";
6
+ import { SchemaPrefix } from "../primitives/schema-prefix";
7
+ import { OptionID, PageID, QuestionID } from "../primitives/ID";
8
+
9
+ const U = DUtil;
10
+ const deleteIdsFromPage = (page: BuilderPageDto) => {
11
+ const deleteIdsFromQuestion = (q: BuilderQuestionDto) => {
12
+ U.deleteProp(q, "id");
13
+ q.options.forEach((o) => {
14
+ U.deleteProp(o, "id");
15
+ });
16
+ };
17
+ U.deleteProp(page, "id");
18
+ deleteIdsFromQuestion(page.defaultQuestion);
19
+ return page;
20
+ };
21
+
22
+ const pxx = PagePrefix.fromStringOrThrow("pxx");
23
+ const questionPageDto: BuilderPageDto = {
24
+ _type: "question",
25
+ autoplaySequence: [],
26
+ includedInSumScores: [],
27
+ mainText: {
28
+ text: "Velkommen til denne undersøkelsen.",
29
+ audioFile: false,
30
+ autoplayDelay: 0,
31
+ autoplay: false,
32
+ },
33
+ tags: [],
34
+
35
+ nextButton: {
36
+ id: OptionID.dummy.a,
37
+ label: "Neste",
38
+ value: -1,
39
+ },
40
+ defaultQuestion: {
41
+ id: QuestionID.validateOrThrow("default-question-id"),
42
+ prefix: "q1",
43
+ text: "sadf",
44
+ options: [
45
+ {
46
+ id: "q1-opt1" as OptionID,
47
+ value: 0,
48
+ label: "Nei",
49
+ },
50
+ {
51
+ id: "q1-opt2" as OptionID,
52
+ value: 1,
53
+ label: "Ja",
54
+ },
55
+ {
56
+ id: "q1-opt3" as OptionID,
57
+ value: 9,
58
+ label: "Vet ikke",
59
+ },
60
+ ],
61
+ _type: "select-one",
62
+ },
63
+ // id: "p1" as BuilderObjectId.PageID,
64
+ id: PageID.create(),
65
+ prefix: PagePrefix.fromStringOrThrow("pxx"),
66
+ };
67
+
68
+ const multiQuestionPageDto: BuilderPageDto = {
69
+ _type: "question",
70
+ includedInSumScores: [],
71
+ mainText: {
72
+ text: "Velkommen til denne undersøkelsen.",
73
+ audioFile: false,
74
+ autoplay: false,
75
+ autoplayDelay: 0,
76
+ },
77
+ autoplaySequence: [],
78
+ defaultQuestion: {
79
+ id: QuestionID.create(),
80
+ prefix: "",
81
+ text: "",
82
+ options: [],
83
+ _type: "select-one",
84
+ },
85
+ tags: [],
86
+ nextButton: {
87
+ id: "next-button-id-3" as OptionID,
88
+ label: "Neste",
89
+ value: -1,
90
+ },
91
+
92
+ id: PageID.create(),
93
+ prefix: PagePrefix.fromStringOrThrow("pxx"),
94
+ };
95
+
96
+ let page = BuilderPage.create("info-page", PagePrefix.fromStringOrThrow("a"));
97
+
98
+ beforeEach(() => {
99
+ page = BuilderPage.create("info-page", PagePrefix.fromStringOrThrow("a"));
100
+ });
101
+
102
+ describe("Builder Page", () => {
103
+ test("Can create page, and convert to json, and back", () => {
104
+ const page1 = BuilderPage.fromJson(questionPageDto);
105
+ const asJson = page1.toJson();
106
+ expect(questionPageDto).toStrictEqual(asJson);
107
+ const page2 = BuilderPage.fromJson(multiQuestionPageDto);
108
+ const asJson2 = page2.toJson();
109
+ expect(multiQuestionPageDto).toStrictEqual(asJson2);
110
+ // expect(page1.prefix).toBe(pageDto.prefix);
111
+ });
112
+ test("Can clone a page and everything except id is equal ", () => {
113
+ const page1 = BuilderPage.create("info-page", PagePrefix.fromStringOrThrow("as"));
114
+ const clone1 = BuilderPage.fromJson(page1.clone());
115
+ const page1Json = deleteIdsFromPage(page1.clone());
116
+ const clone1Json = deleteIdsFromPage(page1.clone());
117
+ expect(page1Json).toStrictEqual(clone1Json);
118
+
119
+ const page2 = BuilderPage.fromJson(questionPageDto);
120
+ const clone2 = BuilderPage.fromJson(page2.clone());
121
+ const page2Json = deleteIdsFromPage(page2.toJson());
122
+ const clone2Json = deleteIdsFromPage(clone2.toJson());
123
+ expect(page2Json).toStrictEqual(clone2Json);
124
+
125
+ const page3 = BuilderPage.fromJson(multiQuestionPageDto);
126
+ const clone3 = BuilderPage.fromJson(page3.clone());
127
+ const page3Json = deleteIdsFromPage(page3.toJson());
128
+ const clone3Json = deleteIdsFromPage(clone3.toJson());
129
+ expect(page3Json).toStrictEqual(clone3Json);
130
+ });
131
+ test("Can clone a page and no id is equal", () => {
132
+ const page1 = BuilderPage.create("info-page", pxx);
133
+ const clone1 = BuilderPage.fromJson(page1.clone());
134
+ expect(page1.id).not.toBe(clone1.id);
135
+
136
+ const testDtoIds = (dto: BuilderPageDto) => {
137
+ const instance = BuilderPage.fromJson(dto);
138
+ const clone = BuilderPage.fromJson(instance.clone());
139
+
140
+ testDtoIds(questionPageDto);
141
+ testDtoIds(multiQuestionPageDto);
142
+ };
143
+ });
144
+
145
+ test("Can get all rule-variables.", () => {
146
+ const prefix = PagePrefix.fromStringOrThrow("as1");
147
+ const page = BuilderPage.create("question", prefix);
148
+ page.mainText.text = "Hva heter du?";
149
+ page.defaultQuestion.addOption("Ja", 1);
150
+ page.defaultQuestion.addOption("Nei", 0);
151
+ const shemaPrefix = SchemaPrefix.fromValueOrThrow("ax");
152
+ const variables = page.getQuestionVariables(shemaPrefix, 1);
153
+ const first = variables[0];
154
+ expect(variables.length).toBe(1);
155
+ expect(first.options.length).toBe(2);
156
+ expect(first.options[0].value).toBe(1);
157
+ expect(first.kind === "question-variable").toBe(true);
158
+ // const newQuestion = BuilderQuestion.create('select-one');
159
+ // const m1 = page1.moveQuestion(newQuestion, 0);
160
+ // expect(page1.questions.length).toBe(3);
161
+ // expect(m1).toBe(false);
162
+ });
163
+ });
@@ -1,21 +1,22 @@
1
- import type { BuilderQuestionDto, BuilderQuestionType } from "./Builder-question";
2
- import { BuilderQuestion } from "./Builder-question";
3
- import { BuilderObject } from "./BuilderObject";
4
- import type { BuilderOptionDto } from "./Builder-option";
5
- import { BuilderOption } from "./Builder-option";
6
- import type { BuilderMainVideoDto } from "./BuilderMainVideoDto";
7
- import type { BuilderMainImageDto } from "./BuilderMainImageDto";
8
- import type { BuilderMainTextDto } from "./BuilderMainText";
9
- import { BuilderMainText } from "./BuilderMainText";
10
- import { BuilderVariableOption, QuestionVariable } from "./rulebuilder/RuleVariable";
1
+ import type { BuilderQuestionDto, BuilderQuestionType } from "../Builder-question";
2
+ import { BuilderQuestion } from "../Builder-question";
3
+ import { BuilderObject } from "../BuilderObject";
4
+ import type { BuilderOptionDto } from "../Builder-option";
5
+ import { BuilderOption } from "../Builder-option";
6
+ import type { BuilderMainVideoDto } from "../BuilderMainVideoDto";
7
+ import type { BuilderMainImageDto } from "../BuilderMainImageDto";
8
+ import type { BuilderMainTextDto } from "../BuilderMainText";
9
+ import { BuilderMainText } from "../BuilderMainText";
10
+ import { RuleVariableOption, RuleQuestionVariable } from "../rulebuilder";
11
11
  import { DUtil } from "@media-quest/engine";
12
- import { PagePrefix, PagePrefixValue } from "./primitives/page-prefix";
13
- import { VarID } from "./primitives/varID";
14
- import { SchemaPrefix } from "./primitives/schema-prefix";
15
- import { PageID } from "./primitives/ID";
12
+ import { PagePrefix, PagePrefixValue } from "../primitives/page-prefix";
13
+ import { VarID } from "../primitives/varID";
14
+ import { SchemaPrefix } from "../primitives/schema-prefix";
15
+ import { PageID, SumScoreVariableID } from "../primitives/ID";
16
+ import { SumScoreVariable } from "../sum-score/sum-score-variable";
16
17
 
17
18
  const U = DUtil;
18
- export type BuilderPageType = "info-page" | "question" | "multi-select" | "form";
19
+ export type BuilderPageType = "info-page" | "question";
19
20
 
20
21
  export interface BuilderPageDto {
21
22
  readonly id: PageID;
@@ -24,11 +25,10 @@ export interface BuilderPageDto {
24
25
  mainText: BuilderMainTextDto;
25
26
  nextButton: BuilderOptionDto;
26
27
  defaultQuestion: BuilderQuestionDto;
27
- questions: Array<BuilderQuestionDto>;
28
28
  mainMedia?: BuilderMainImageDto | BuilderMainVideoDto;
29
+ includedInSumScores: Array<{ sumScoreVariableId: SumScoreVariableID; weight: number }>;
29
30
  autoplaySequence: Array<string>;
30
31
  tags: ReadonlyArray<string>;
31
- // sumScoreVariables: Array<BuilderObjectId.SumScoreVariableId>
32
32
  }
33
33
 
34
34
  export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
@@ -36,9 +36,18 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
36
36
  readonly id: PageID;
37
37
  private _pageType: BuilderPageType;
38
38
  private _prefix: PagePrefix;
39
- private _questions: Array<BuilderQuestion> = [];
40
39
  private readonly _tags: Set<string>;
41
40
  private _backgroundColor = "#FFFFFF";
41
+ private _includedInSumScores: Map<
42
+ SumScoreVariableID,
43
+ {
44
+ sumScoreVariableId: SumScoreVariableID;
45
+ weight: number;
46
+ name: string;
47
+ description: string;
48
+ }
49
+ > = new Map();
50
+
42
51
  mainMedia: BuilderMainVideoDto | BuilderMainImageDto | false = false;
43
52
  defaultQuestion: BuilderQuestion;
44
53
  mainText: BuilderMainText;
@@ -63,7 +72,7 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
63
72
  nextButton: nextButtonDto,
64
73
  mainText: mainTextDto,
65
74
  prefix: _prefix,
66
- questions: [],
75
+ includedInSumScores: [],
67
76
  tags: [],
68
77
  };
69
78
 
@@ -84,74 +93,20 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
84
93
  this.mainText = BuilderMainText.fromJson(dto.mainText);
85
94
  this.nextButton = BuilderOption.fromJson(dto.nextButton);
86
95
  this.defaultQuestion = BuilderQuestion.fromJson(dto.defaultQuestion);
87
- this._questions = dto.questions.map((q) => BuilderQuestion.fromJson(q));
88
96
  const tagList: string[] = Array.isArray(dto.tags) ? dto.tags : [];
97
+ const sumScores = Array.isArray(dto.includedInSumScores) ? dto.includedInSumScores : [];
98
+ sumScores.forEach((item) => {
99
+ this._includedInSumScores.set(item.sumScoreVariableId, {
100
+ sumScoreVariableId: item.sumScoreVariableId,
101
+ weight: item.weight,
102
+ name: "",
103
+ description: "",
104
+ });
105
+ });
89
106
  this._tags = new Set(tagList);
90
107
  if (dto.mainMedia) {
91
108
  this.mainMedia = dto.mainMedia;
92
109
  }
93
- this.updateRows();
94
- }
95
-
96
- insertQuestion(question: BuilderQuestion, atIndex: number): boolean {
97
- const validIndexFn = U.isInRange(0, this._questions.length);
98
- if (!validIndexFn(atIndex)) {
99
- return false;
100
- }
101
- const hasQuestion = !!this._questions.find((q) => q.id === question.id);
102
- if (hasQuestion) {
103
- return false;
104
- }
105
- this._questions.splice(atIndex, 0, question);
106
- return true;
107
- }
108
-
109
- addQuestion(type: BuilderQuestionType, atIndex = -1): BuilderQuestion {
110
- const question = BuilderQuestion.create(type);
111
- if (atIndex < this._questions.length && atIndex >= 0) {
112
- this._questions.splice(atIndex, 0, question);
113
- } else {
114
- this._questions.push(question);
115
- }
116
- return question;
117
- }
118
-
119
- /**
120
- * Move a question in questions-array
121
- * @param question (reference)
122
- * @param toIndex
123
- */
124
- moveQuestion(question: BuilderQuestion, toIndex: number): boolean {
125
- const validToIndexFn = U.isInRange(0, this._questions.length);
126
- if (!validToIndexFn(toIndex)) {
127
- return false;
128
- }
129
- const currentIndex = this._questions.indexOf(question);
130
- if (currentIndex < 0) {
131
- return false;
132
- }
133
- this._questions.splice(currentIndex, 1);
134
- this._questions.splice(toIndex, 0, question);
135
- return true;
136
- }
137
-
138
- deleteQuestion(question: BuilderQuestion) {
139
- this._questions = this._questions.filter((q) => q !== question);
140
- // TODO EMIT DELETED QUESTION.
141
- this.updateRows();
142
- }
143
- private updateRows() {
144
- if (this._pageType === "question" || this._pageType === "info-page") {
145
- this._questions = [];
146
- }
147
- if (this._pageType === "form" && this._questions.length === 0) {
148
- this._questions = [];
149
- this.addQuestion("text");
150
- }
151
- if (this._pageType === "multi-select" && this._questions.length === 0) {
152
- this._questions = [];
153
- this.addQuestion("text");
154
- }
155
110
  }
156
111
 
157
112
  public addTag(tag: string) {
@@ -163,15 +118,17 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
163
118
 
164
119
  set pageType(value: BuilderPageType) {
165
120
  this._pageType = value;
166
- // TODO Emit All questions that are deleted? Listen for removed variables??
167
- this.updateRows();
121
+ }
122
+
123
+ get includedInSumScores() {
124
+ return [...this._includedInSumScores.values()];
168
125
  }
169
126
 
170
127
  getQuestionVariables(
171
128
  modulePrefix: SchemaPrefix,
172
129
  pageNumber: number,
173
- ): ReadonlyArray<QuestionVariable> {
174
- const variables: QuestionVariable[] = [];
130
+ ): ReadonlyArray<RuleQuestionVariable> {
131
+ const variables: RuleQuestionVariable[] = [];
175
132
 
176
133
  if (this._pageType === "question") {
177
134
  const pagePrefix = this.prefix;
@@ -180,9 +137,9 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
180
137
  const op = this.defaultQuestion.options.map((o) => {
181
138
  const label = o.label;
182
139
  const value = o.value;
183
- return new BuilderVariableOption(label, value);
140
+ return new RuleVariableOption(label, value);
184
141
  });
185
- const singleVar = new QuestionVariable(varId, label, op, pageNumber);
142
+ const singleVar = new RuleQuestionVariable(varId, label, op, pageNumber);
186
143
  variables.push(singleVar);
187
144
  }
188
145
  return variables;
@@ -203,11 +160,36 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
203
160
  this._prefix.value = value;
204
161
  }
205
162
 
163
+ sumScoreVariableSet(sumScoreVariable: SumScoreVariable, weight: number) {
164
+ const { id, name, description } = sumScoreVariable;
165
+
166
+ this._includedInSumScores.set(sumScoreVariable.id, {
167
+ sumScoreVariableId: id,
168
+ weight,
169
+ name,
170
+ description,
171
+ });
172
+
173
+ return true;
174
+ }
175
+
176
+ sumScoreVariableUpdateData(variables: ReadonlyArray<SumScoreVariable>) {
177
+ variables.forEach((v) => {
178
+ const sumScoreEntry = this._includedInSumScores.get(v.id);
179
+ if (sumScoreEntry) {
180
+ this.sumScoreVariableSet(v, sumScoreEntry.weight);
181
+ }
182
+ });
183
+ }
184
+
206
185
  toJson(): BuilderPageDto {
207
- const questions = this._questions.map((q) => q.toJson());
208
186
  const mainText = this.mainText.toJson();
209
187
  const nextButton = this.nextButton.toJson();
210
188
  const mainMedia = this.mainMedia;
189
+ const includedInSumScores = this.includedInSumScores.map(({ sumScoreVariableId, weight }) => ({
190
+ sumScoreVariableId,
191
+ weight,
192
+ }));
211
193
  const dto: BuilderPageDto = {
212
194
  _type: this.pageType,
213
195
  mainText,
@@ -215,9 +197,9 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
215
197
  nextButton,
216
198
  id: this.id,
217
199
  tags: [...this.tags],
200
+ includedInSumScores,
218
201
  prefix: this._prefix.value,
219
202
  defaultQuestion: this.defaultQuestion.toJson(),
220
- questions,
221
203
  };
222
204
  if (mainMedia) {
223
205
  dto.mainMedia = mainMedia;
@@ -229,15 +211,12 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
229
211
  const dto = this.toJson();
230
212
  const defaultQuestionClone = this.defaultQuestion.clone();
231
213
  const mainTextClone = JSON.parse(JSON.stringify(this.mainText));
232
- // const pagesClone = this
233
- const questionsClone = this.questions.map((q) => q.clone());
234
214
  const newId = PageID.create();
235
215
  const clone: BuilderPageDto = {
236
216
  ...dto,
237
217
  id: newId,
238
218
  defaultQuestion: defaultQuestionClone,
239
219
  mainText: mainTextClone,
240
- questions: questionsClone,
241
220
  };
242
221
  // const cloneDto
243
222
  return clone;
@@ -253,7 +232,7 @@ export class BuilderPage extends BuilderObject<"builder-page", BuilderPageDto> {
253
232
  }
254
233
  }
255
234
 
256
- get questions(): ReadonlyArray<BuilderQuestion> {
257
- return this._questions;
235
+ sumScoreVariableDelete(sumScoreVariableID: SumScoreVariableID) {
236
+ this._includedInSumScores.delete(sumScoreVariableID);
258
237
  }
259
238
  }
@@ -1,39 +1,39 @@
1
- import { PageID, SchemaID } from "./ID";
2
-
3
- describe("ID Functions work", () => {
4
- //Generate test for schema prefix
5
- test("SCHEMA_ID isFunction works", () => {
6
- const id = SchemaID.create();
7
- expect(SchemaID.is(id)).toBe(true);
8
- expect(SchemaID.is("")).toBe(false);
9
- expect(SchemaID.is("a")).toBe(false);
10
- expect(SchemaID.is("a".repeat(10))).toBe(true);
11
- expect(SchemaID.is("a".repeat(9))).toBe(false);
12
- });
13
- test("SCHEMA_ID ensure works", () => {
14
- const id = SchemaID.create();
15
- expect(SchemaID.validateOrCreate(id)).toBe(id);
16
- expect(SchemaID.validateOrCreate("")).not.toBe("");
17
- expect(SchemaID.validateOrCreate("")).not.toBe("a");
18
- expect(SchemaID.validateOrCreate("a".repeat(10))).toBe("a".repeat(10));
19
- expect(SchemaID.validateOrCreate("a".repeat(9))).not.toBe("a".repeat(9));
20
- expect(SchemaID.validateOrCreate("ABcdefghigKLML")).toBe("ABcdefghigKLML");
21
- });
22
- test("PageID isFunction works", () => {
23
- const id = PageID.create();
24
- expect(PageID.is(id)).toBe(true);
25
- expect(PageID.is("")).toBe(false);
26
- expect(PageID.is("a")).toBe(false);
27
- expect(PageID.is("a".repeat(10))).toBe(true);
28
- expect(PageID.is("a".repeat(9))).toBe(false);
29
- });
30
- test("PageID ensure works", () => {
31
- const id = PageID.create();
32
- expect(PageID.validateOrCreate(id)).toBe(id);
33
- expect(PageID.validateOrCreate("")).not.toBe("");
34
- expect(PageID.validateOrCreate("")).not.toBe("a");
35
- expect(PageID.validateOrCreate("a".repeat(10))).toBe("a".repeat(10));
36
- expect(PageID.validateOrCreate("a".repeat(9))).not.toBe("a".repeat(9));
37
- expect(PageID.validateOrCreate("ABcdefghigKLML")).toBe("ABcdefghigKLML");
38
- });
39
- });
1
+ import { PageID, SchemaID } from "./ID";
2
+
3
+ describe("ID Functions work", () => {
4
+ //Generate test for schema prefix
5
+ test("SCHEMA_ID isFunction works", () => {
6
+ const id = SchemaID.create();
7
+ expect(SchemaID.is(id)).toBe(true);
8
+ expect(SchemaID.is("")).toBe(false);
9
+ expect(SchemaID.is("a")).toBe(false);
10
+ expect(SchemaID.is("a".repeat(10))).toBe(true);
11
+ expect(SchemaID.is("a".repeat(9))).toBe(false);
12
+ });
13
+ test("SCHEMA_ID ensure works", () => {
14
+ const id = SchemaID.create();
15
+ expect(SchemaID.validateOrCreate(id)).toBe(id);
16
+ expect(SchemaID.validateOrCreate("")).not.toBe("");
17
+ expect(SchemaID.validateOrCreate("")).not.toBe("a");
18
+ expect(SchemaID.validateOrCreate("a".repeat(10))).toBe("a".repeat(10));
19
+ expect(SchemaID.validateOrCreate("a".repeat(9))).not.toBe("a".repeat(9));
20
+ expect(SchemaID.validateOrCreate("ABcdefghigKLML")).toBe("ABcdefghigKLML");
21
+ });
22
+ test("PageID isFunction works", () => {
23
+ const id = PageID.create();
24
+ expect(PageID.is(id)).toBe(true);
25
+ expect(PageID.is("")).toBe(false);
26
+ expect(PageID.is("a")).toBe(false);
27
+ expect(PageID.is("a".repeat(10))).toBe(true);
28
+ expect(PageID.is("a".repeat(9))).toBe(false);
29
+ });
30
+ test("PageID ensure works", () => {
31
+ const id = PageID.create();
32
+ expect(PageID.validateOrCreate(id)).toBe(id);
33
+ expect(PageID.validateOrCreate("")).not.toBe("");
34
+ expect(PageID.validateOrCreate("")).not.toBe("a");
35
+ expect(PageID.validateOrCreate("a".repeat(10))).toBe("a".repeat(10));
36
+ expect(PageID.validateOrCreate("a".repeat(9))).not.toBe("a".repeat(9));
37
+ expect(PageID.validateOrCreate("ABcdefghigKLML")).toBe("ABcdefghigKLML");
38
+ });
39
+ });
@@ -86,17 +86,30 @@ export const createTypedIdSingleton = <const B extends string>(idName: B): Id<B>
86
86
  return is(id) ? id : create();
87
87
  };
88
88
 
89
+ const a = createDummyID(idName, "a");
90
+ const b = createDummyID(idName, "b");
91
+ const c = createDummyID(idName, "c");
92
+ const d = createDummyID(idName, "d");
93
+ const e = createDummyID(idName, "e");
94
+ const f = createDummyID(idName, "f");
95
+ const g = createDummyID(idName, "g");
96
+ const h = createDummyID(idName, "h");
97
+ const i = createDummyID(idName, "i");
98
+ const j = createDummyID(idName, "j");
99
+ const list = [a, b, c, d, e, f, g, h, i, j];
100
+
89
101
  const dummy = {
90
- a: createDummyID(idName, "a"),
91
- b: createDummyID(idName, "b"),
92
- c: createDummyID(idName, "c"),
93
- d: createDummyID(idName, "d"),
94
- e: createDummyID(idName, "e"),
95
- f: createDummyID(idName, "f"),
96
- g: createDummyID(idName, "g"),
97
- h: createDummyID(idName, "h"),
98
- i: createDummyID(idName, "i"),
99
- j: createDummyID(idName, "j"),
102
+ a,
103
+ b,
104
+ c,
105
+ d,
106
+ e,
107
+ f,
108
+ g,
109
+ h,
110
+ i,
111
+ j,
112
+ list,
100
113
  };
101
114
 
102
115
  return Object.freeze({ create, is, validateOrCreate, validateOrThrow, name, dummy });
@@ -117,3 +130,6 @@ export type TextID = ID<"TEXT">;
117
130
  export const TextID = createTypedIdSingleton("TEXT");
118
131
  export type QuestionID = ID<"QUESTION">;
119
132
  export const QuestionID = createTypedIdSingleton("QUESTION");
133
+
134
+ export type SumScoreVariableID = ID<"SUM_SCORE_VARIABLE">;
135
+ export const SumScoreVariableID = createTypedIdSingleton("SUM_SCORE_VARIABLE");
@@ -1,59 +1,59 @@
1
- import { SchemaPrefix } from "./schema-prefix";
2
-
3
- export type PagePrefixValue = string & { __PAGE_PREFIX__: true };
4
- export const createRandomPrefix = <const P extends string>(length: number): P => {
5
- const letters = "abcdefghijklmnopqrstuvyz";
6
- const all = letters + letters.toUpperCase();
7
- let result = "";
8
- for (let i = 0; i < length; i++) {
9
- const char = all.charAt(Math.floor(Math.random() * all.length));
10
- result += char;
11
- }
12
- return result as P;
13
- };
14
-
15
- export class PagePrefix {
16
- public static readonly MIN_LENGTH = 1;
17
- private static randomLen = 5;
18
- public static readonly MAX_LENGTH = 16;
19
-
20
- public static create = (): PagePrefix => {
21
- const v = createRandomPrefix<PagePrefixValue>(PagePrefix.randomLen);
22
- return new PagePrefix(v);
23
- };
24
- public static fromString = (value: string): PagePrefix | false => {
25
- if (!PagePrefix.isValid(value)) return false;
26
- return new PagePrefix(value);
27
- };
28
-
29
- public static fromStringOrThrow = (value: string): PagePrefixValue => {
30
- if (!PagePrefix.isValid(value)) throw new Error("Invalid prefix");
31
- return value;
32
- };
33
- public static castOrCreateRandom = (value: string): PagePrefix => {
34
- const v = PagePrefix.isValid(value)
35
- ? value
36
- : createRandomPrefix<PagePrefixValue>(PagePrefix.randomLen);
37
- return new PagePrefix(v);
38
- };
39
-
40
- public static isValid = (prefix: string | 999): prefix is PagePrefixValue => {
41
- if (typeof prefix !== "string") return false;
42
- if (prefix.length < SchemaPrefix.MIN_LENGTH) return false;
43
- return prefix.length <= SchemaPrefix.MAX_LENGTH;
44
- };
45
-
46
- get value(): PagePrefixValue {
47
- return this._value;
48
- }
49
-
50
- set value(value: string) {
51
- if (!PagePrefix.isValid(value)) {
52
- console.log("INVALID PREFIX", value);
53
- } else {
54
- this._value = value;
55
- }
56
- }
57
-
58
- private constructor(private _value: PagePrefixValue) {}
59
- }
1
+ import { SchemaPrefix } from "./schema-prefix";
2
+
3
+ export type PagePrefixValue = string & { __PAGE_PREFIX__: true };
4
+ export const createRandomPrefix = <const P extends string>(length: number): P => {
5
+ const letters = "abcdefghijklmnopqrstuvyz";
6
+ const all = letters + letters.toUpperCase();
7
+ let result = "";
8
+ for (let i = 0; i < length; i++) {
9
+ const char = all.charAt(Math.floor(Math.random() * all.length));
10
+ result += char;
11
+ }
12
+ return result as P;
13
+ };
14
+
15
+ export class PagePrefix {
16
+ public static readonly MIN_LENGTH = 1;
17
+ private static randomLen = 5;
18
+ public static readonly MAX_LENGTH = 16;
19
+
20
+ public static create = (): PagePrefix => {
21
+ const v = createRandomPrefix<PagePrefixValue>(PagePrefix.randomLen);
22
+ return new PagePrefix(v);
23
+ };
24
+ public static fromString = (value: string): PagePrefix | false => {
25
+ if (!PagePrefix.isValid(value)) return false;
26
+ return new PagePrefix(value);
27
+ };
28
+
29
+ public static fromStringOrThrow = (value: string): PagePrefixValue => {
30
+ if (!PagePrefix.isValid(value)) throw new Error("Invalid prefix");
31
+ return value;
32
+ };
33
+ public static castOrCreateRandom = (value: string): PagePrefix => {
34
+ const v = PagePrefix.isValid(value)
35
+ ? value
36
+ : createRandomPrefix<PagePrefixValue>(PagePrefix.randomLen);
37
+ return new PagePrefix(v);
38
+ };
39
+
40
+ public static isValid = (prefix: string | 999): prefix is PagePrefixValue => {
41
+ if (typeof prefix !== "string") return false;
42
+ if (prefix.length < SchemaPrefix.MIN_LENGTH) return false;
43
+ return prefix.length <= SchemaPrefix.MAX_LENGTH;
44
+ };
45
+
46
+ get value(): PagePrefixValue {
47
+ return this._value;
48
+ }
49
+
50
+ set value(value: string) {
51
+ if (!PagePrefix.isValid(value)) {
52
+ console.log("INVALID PREFIX", value);
53
+ } else {
54
+ this._value = value;
55
+ }
56
+ }
57
+
58
+ private constructor(private _value: PagePrefixValue) {}
59
+ }