@media-quest/builder 0.0.24 → 0.0.26
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 +15 -15
- package/src/Builder-option.ts +6 -8
- package/src/Builder-page.spec.ts +162 -320
- package/src/Builder-page.ts +182 -257
- package/src/Builder-question.spec.ts +57 -57
- package/src/Builder-question.ts +83 -82
- package/src/Builder-schema.spec.ts +96 -124
- package/src/Builder-schema.ts +25 -15
- package/src/Builder-text.spec.ts +11 -11
- package/src/Builder-text.ts +13 -13
- package/src/BuilderObject.ts +2 -33
- package/src/BuilderTag.ts +19 -20
- package/src/builder-compiler.ts +1 -1
- package/src/code-book/codebook-variable.ts +29 -0
- package/src/{codebook.ts → code-book/codebook.ts} +16 -16
- package/src/primitives/ID.spec.ts +39 -0
- package/src/primitives/ID.ts +138 -0
- package/src/primitives/page-prefix.ts +4 -3
- package/src/primitives/varID.ts +1 -0
- package/src/public-api.ts +28 -24
- package/src/rulebuilder/Builder-rule.spec.ts +3 -2
- package/src/rulebuilder/Builder-rule.ts +2 -1
- package/src/rulebuilder/RuleBuilder-test-utils.ts +12 -8
- package/src/rulebuilder/RuleInput.ts +30 -30
- package/src/rulebuilder/RuleVariable.ts +11 -26
- package/src/rulebuilder/SingleSelectItem.ts +9 -8
- package/src/rulebuilder/condition/Builder-condition-group.ts +14 -6
- package/src/rulebuilder/condition/Builder-condition.spec.ts +12 -12
- package/src/rulebuilder/condition/Builder-condition.ts +17 -13
- package/src/rulebuilder/index.ts +16 -3
- package/src/rulebuilder/page-action-manager.ts +4 -2
- package/src/rulebuilder/rule2/Rule2.ts +8 -8
- package/src/schema-config.ts +2 -2
- package/src/sum-score/sum-score-answer.ts +6 -0
- package/src/sum-score/sum-score-manager.spec.ts +189 -0
- package/src/sum-score/sum-score-manager.ts +154 -0
- package/src/sum-score/sum-score-membership.ts +45 -0
- package/src/sum-score/sum-score-variable.spec.ts +151 -0
- package/src/sum-score/sum-score-variable.ts +36 -0
- package/src/{variable → sum-score}/sum-score.ts +122 -138
- package/tsconfig.tsbuildinfo +1 -1
- package/src/variable/mq-variable.spec.ts +0 -146
- package/src/variable/mq-variable.ts +0 -68
package/src/Builder-schema.ts
CHANGED
|
@@ -2,25 +2,28 @@ import type { BuilderPageDto, BuilderPageType } from "./Builder-page";
|
|
|
2
2
|
import { BuilderPage } from "./Builder-page";
|
|
3
3
|
import type {
|
|
4
4
|
BuilderRuleDto,
|
|
5
|
-
CustomVariable,
|
|
6
5
|
ExcludeByPageAction,
|
|
7
6
|
ExcludeByTagAction,
|
|
8
7
|
JumpToPageAction,
|
|
8
|
+
RuleCustomVariable,
|
|
9
9
|
} from "./rulebuilder";
|
|
10
10
|
import { BuilderRule, RuleInput } from "./rulebuilder";
|
|
11
|
-
import type {
|
|
11
|
+
import type { RuleQuestionVariable } from "./rulebuilder/RuleVariable";
|
|
12
12
|
import type { BuilderTagDto } from "./BuilderTag";
|
|
13
13
|
import { BuilderTag, TagCollection } from "./BuilderTag";
|
|
14
14
|
import { DefaultThemeCompiler } from "./theme/default-theme-compiler";
|
|
15
15
|
import { ImageFile } from "./media-files";
|
|
16
|
-
import { DUtil
|
|
16
|
+
import { DUtil } from "@media-quest/engine";
|
|
17
17
|
import { PagePrefix } from "./primitives/page-prefix";
|
|
18
18
|
import { SchemaPrefix, SchemaPrefixValue } from "./primitives/schema-prefix";
|
|
19
|
-
import { CodeBook } from "./codebook";
|
|
20
|
-
import {
|
|
19
|
+
import { CodeBook } from "./code-book/codebook";
|
|
20
|
+
import { CodebookPredefinedVariable } from "./code-book/codebook-variable";
|
|
21
21
|
import { SchemaConfig } from "./schema-config";
|
|
22
22
|
import { CompilerOption, CompilerOutput } from "./builder-compiler";
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
import { SumScoreVariableDto } from "./sum-score/sum-score-variable";
|
|
25
|
+
import { SchemaID } from "./primitives/ID";
|
|
26
|
+
import { SumScoreMembershipDto } from "./sum-score/sum-score-membership";
|
|
24
27
|
|
|
25
28
|
const U = DUtil;
|
|
26
29
|
|
|
@@ -33,14 +36,15 @@ export interface BuilderSchemaDto {
|
|
|
33
36
|
readonly pages: BuilderPageDto[];
|
|
34
37
|
readonly baseHeight: number;
|
|
35
38
|
readonly baseWidth: number;
|
|
36
|
-
readonly predefinedVariables?: Array<
|
|
37
|
-
readonly sumScoreVariables?:
|
|
39
|
+
readonly predefinedVariables?: Array<CodebookPredefinedVariable>;
|
|
40
|
+
readonly sumScoreVariables?: ReadonlyArray<SumScoreVariableDto>;
|
|
41
|
+
readonly sumScoreMemberShips?: ReadonlyArray<SumScoreMembershipDto>;
|
|
38
42
|
readonly rules: ReadonlyArray<BuilderRuleDto>;
|
|
39
43
|
readonly tags: ReadonlyArray<BuilderTagDto>;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
class SumScoreVariableCollection {
|
|
43
|
-
private _all: Array<
|
|
47
|
+
private _all: Array<SumScoreVariableDto> = [];
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
export class BuilderSchema {
|
|
@@ -50,13 +54,13 @@ export class BuilderSchema {
|
|
|
50
54
|
backgroundColor = "#000000";
|
|
51
55
|
pages: BuilderPage[] = [];
|
|
52
56
|
mainImage: ImageFile | false = false;
|
|
53
|
-
predefinedVariables:
|
|
57
|
+
predefinedVariables: CodebookPredefinedVariable[] = [];
|
|
54
58
|
private _rules: BuilderRule[] = [];
|
|
55
|
-
private _sumVariables:
|
|
59
|
+
private _sumVariables: SumScoreVariableDto[] = [];
|
|
56
60
|
get rules(): ReadonlyArray<BuilderRule> {
|
|
57
61
|
return [...this._rules];
|
|
58
62
|
}
|
|
59
|
-
get sumScoreVariables(): ReadonlyArray<
|
|
63
|
+
get sumScoreVariables(): ReadonlyArray<SumScoreVariableDto> {
|
|
60
64
|
return [...this._sumVariables];
|
|
61
65
|
}
|
|
62
66
|
|
|
@@ -77,6 +81,7 @@ export class BuilderSchema {
|
|
|
77
81
|
const schemaPrefix = SchemaPrefix.castOrCreateRandom(dto.prefix);
|
|
78
82
|
const schema = new BuilderSchema(dto.id, dto.name, schemaPrefix);
|
|
79
83
|
const pages = dto.pages.map(BuilderPage.fromJson);
|
|
84
|
+
|
|
80
85
|
schema._tagCollection.init(dto.tags);
|
|
81
86
|
schema.backgroundColor = dto.backgroundColor;
|
|
82
87
|
schema.baseHeight = dto.baseHeight;
|
|
@@ -87,6 +92,8 @@ export class BuilderSchema {
|
|
|
87
92
|
schema.mainImage = dto.mainImage ?? false;
|
|
88
93
|
const rulesDto = dto.rules ?? [];
|
|
89
94
|
const ruleInput = schema.getRuleInput();
|
|
95
|
+
|
|
96
|
+
schema._sumVariables = Array.isArray(dto.sumScoreVariables) ? [...dto.sumScoreVariables] : [];
|
|
90
97
|
schema._rules = rulesDto.map((r) => BuilderRule.fromDto(r, ruleInput));
|
|
91
98
|
return schema;
|
|
92
99
|
}
|
|
@@ -106,6 +113,7 @@ export class BuilderSchema {
|
|
|
106
113
|
rules,
|
|
107
114
|
tags,
|
|
108
115
|
predefinedVariables: this.predefinedVariables,
|
|
116
|
+
sumScoreVariables: [...this.sumScoreVariables],
|
|
109
117
|
mainImage: this.mainImage,
|
|
110
118
|
prefix: this.prefix.value,
|
|
111
119
|
};
|
|
@@ -130,9 +138,11 @@ export class BuilderSchema {
|
|
|
130
138
|
return newPage;
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
addSumScoreVariable(variable:
|
|
141
|
+
addSumScoreVariable(variable: SumScoreVariableDto) {
|
|
134
142
|
// TODO VALIDATE.
|
|
135
143
|
this._sumVariables.push({ ...variable });
|
|
144
|
+
|
|
145
|
+
return variable;
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
insertPage(page: BuilderPage, atIndex: number): boolean {
|
|
@@ -204,8 +214,8 @@ export class BuilderSchema {
|
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
getRuleInput(): RuleInput {
|
|
207
|
-
const qVars:
|
|
208
|
-
const cVars:
|
|
217
|
+
const qVars: RuleQuestionVariable[] = [];
|
|
218
|
+
const cVars: RuleCustomVariable[] = [];
|
|
209
219
|
const pageIdActions: ExcludeByPageAction[] = [];
|
|
210
220
|
const tagActions: ExcludeByTagAction[] = this.tags.map((t) => {
|
|
211
221
|
const tag = t.tagText;
|
package/src/Builder-text.spec.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import type { BuilderTextDto } from "./Builder-text";
|
|
2
2
|
import { BuilderText } from "./Builder-text";
|
|
3
|
-
import
|
|
3
|
+
import { TextID } from "./primitives/ID";
|
|
4
4
|
|
|
5
5
|
const textDto: BuilderTextDto = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
id: "dto1" as TextID,
|
|
7
|
+
name: "dto1-name",
|
|
8
|
+
text: "text one",
|
|
9
|
+
translationRequired: true,
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
let text1 = BuilderText.create("text one created");
|
|
13
13
|
|
|
14
14
|
beforeEach(() => {
|
|
15
|
-
|
|
15
|
+
text1 = BuilderText.create("text one created");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
describe("Builder Text", () => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
test("Can serialize", () => {
|
|
20
|
+
const instance1 = BuilderText.fromJson(textDto);
|
|
21
|
+
const json = instance1.toJson();
|
|
22
|
+
expect(textDto).toStrictEqual(json);
|
|
23
|
+
});
|
|
24
24
|
});
|
package/src/Builder-text.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BuilderObject } from "./BuilderObject";
|
|
2
|
+
import { TextID } from "./primitives/ID";
|
|
2
3
|
|
|
3
4
|
export interface BuilderTextDto {
|
|
4
|
-
readonly id:
|
|
5
|
+
readonly id: TextID;
|
|
5
6
|
text: string;
|
|
6
7
|
name: string;
|
|
7
8
|
translationRequired: boolean;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export class BuilderText extends BuilderObject<
|
|
11
|
-
readonly objectType =
|
|
12
|
-
id:
|
|
13
|
-
text =
|
|
14
|
-
name =
|
|
11
|
+
export class BuilderText extends BuilderObject<"builder-text", BuilderTextDto> {
|
|
12
|
+
readonly objectType = "builder-text";
|
|
13
|
+
id: TextID;
|
|
14
|
+
text = "";
|
|
15
|
+
name = "";
|
|
15
16
|
translateRequired = false;
|
|
16
17
|
// audio: {id: B}
|
|
17
18
|
private constructor(dto: BuilderTextDto) {
|
|
@@ -23,12 +24,12 @@ export class BuilderText extends BuilderObject<'builder-text', BuilderTextDto> {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
public static create(name: string) {
|
|
26
|
-
const id =
|
|
27
|
+
const id = TextID.create();
|
|
27
28
|
const dto: BuilderTextDto = {
|
|
28
29
|
id,
|
|
29
30
|
name,
|
|
30
|
-
text:
|
|
31
|
-
translationRequired: false
|
|
31
|
+
text: "",
|
|
32
|
+
translationRequired: false,
|
|
32
33
|
};
|
|
33
34
|
const instance = new BuilderText(dto);
|
|
34
35
|
return instance;
|
|
@@ -39,9 +40,8 @@ export class BuilderText extends BuilderObject<'builder-text', BuilderTextDto> {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
clone(): BuilderTextDto {
|
|
42
|
-
const newId = BuilderObjectId.textId();
|
|
43
43
|
const dto = this.toJson();
|
|
44
|
-
const withNewId: BuilderTextDto = { ...dto, id:
|
|
44
|
+
const withNewId: BuilderTextDto = { ...dto, id: TextID.create() };
|
|
45
45
|
return withNewId;
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -50,7 +50,7 @@ export class BuilderText extends BuilderObject<'builder-text', BuilderTextDto> {
|
|
|
50
50
|
id: this.id,
|
|
51
51
|
name: this.name,
|
|
52
52
|
text: this.text,
|
|
53
|
-
translationRequired: this.translateRequired
|
|
53
|
+
translationRequired: this.translateRequired,
|
|
54
54
|
};
|
|
55
55
|
return dto;
|
|
56
56
|
}
|
package/src/BuilderObject.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { DUtil } from "@media-quest/engine";
|
|
2
|
-
|
|
3
|
-
const U = DUtil;
|
|
4
1
|
/**
|
|
5
2
|
* Builder objects are complex objects that are embedded inside
|
|
6
3
|
* a Builder-schema, and needs to be serialized to json. Often these objects
|
|
@@ -14,40 +11,12 @@ type BuilderObjectType =
|
|
|
14
11
|
| "builder-text"
|
|
15
12
|
| "builder-rule"
|
|
16
13
|
| "builder-tag"
|
|
14
|
+
| "builder-sum-score-variable"
|
|
15
|
+
| "builder-sum-score-membership"
|
|
17
16
|
| "builder-condition"
|
|
18
17
|
| "builder-variable"
|
|
19
18
|
| "builder-condition-group";
|
|
20
19
|
|
|
21
|
-
export namespace BuilderObjectId {
|
|
22
|
-
export type QuestionOptionID = string & { __OPTION__ID__: true };
|
|
23
|
-
export type QuestionID = string & { __QUESTION__ID__: true };
|
|
24
|
-
export type TextID = string & { __TEXT__ID__: true };
|
|
25
|
-
export type MainTextID = string & { __MAIN__TEXT__ID__: true };
|
|
26
|
-
export type TagId = string & { __TAG__ID__: true };
|
|
27
|
-
export const createTagId = (): TagId => {
|
|
28
|
-
return createId("builder-tag") as TagId;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const mainTextId = (): MainTextID => {
|
|
32
|
-
return createId("builder-main-text") as MainTextID;
|
|
33
|
-
};
|
|
34
|
-
export const textId = (): TextID => {
|
|
35
|
-
return createId("builder-text") as TextID;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const questionOptionId = (): QuestionOptionID => {
|
|
39
|
-
return createId("builder-question-option") as QuestionOptionID;
|
|
40
|
-
};
|
|
41
|
-
export const questionId = (): QuestionID => {
|
|
42
|
-
return createId("builder-question") as QuestionID;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const createId = (type: BuilderObjectType): string => {
|
|
46
|
-
const id = U.randomString(24);
|
|
47
|
-
return type + "-" + id;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
20
|
export abstract class BuilderObject<T extends BuilderObjectType, Dto extends {}> {
|
|
52
21
|
// abstract readonly id: string;
|
|
53
22
|
abstract readonly objectType: T;
|
package/src/BuilderTag.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BuilderObject } from "./BuilderObject";
|
|
2
|
+
import { TagID } from "./primitives/ID";
|
|
2
3
|
|
|
3
4
|
export interface BuilderTagDto {
|
|
4
|
-
readonly id:
|
|
5
|
+
readonly id: TagID;
|
|
5
6
|
readonly tag: string;
|
|
6
7
|
readonly description: string;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
export class BuilderTag extends BuilderObject<
|
|
10
|
-
readonly objectType:
|
|
11
|
-
readonly id:
|
|
12
|
-
tagText =
|
|
13
|
-
tagDescription =
|
|
10
|
+
export class BuilderTag extends BuilderObject<"builder-tag", BuilderTagDto> {
|
|
11
|
+
readonly objectType: "builder-tag" = "builder-tag";
|
|
12
|
+
readonly id: TagID;
|
|
13
|
+
tagText = "";
|
|
14
|
+
tagDescription = "";
|
|
14
15
|
public static readonly MAX_LENGTH = 20;
|
|
15
16
|
public static readonly MIN_LENGTH = 1;
|
|
16
17
|
|
|
17
|
-
public static readonly create = (tag: string, description: string =
|
|
18
|
-
const id =
|
|
18
|
+
public static readonly create = (tag: string, description: string = "") => {
|
|
19
|
+
const id = TagID.create();
|
|
19
20
|
const dto: BuilderTagDto = {
|
|
20
21
|
id,
|
|
21
22
|
tag,
|
|
22
|
-
description
|
|
23
|
+
description,
|
|
23
24
|
};
|
|
24
25
|
return new BuilderTag(dto);
|
|
25
26
|
};
|
|
@@ -27,12 +28,12 @@ export class BuilderTag extends BuilderObject<'builder-tag', BuilderTagDto> {
|
|
|
27
28
|
return new BuilderTag(dto);
|
|
28
29
|
};
|
|
29
30
|
protected constructor(dto: BuilderTagDto) {
|
|
30
|
-
const id = dto.id
|
|
31
|
+
const id = TagID.validateOrCreate(dto.id);
|
|
31
32
|
const withId = { ...dto, id };
|
|
32
33
|
super(withId);
|
|
33
34
|
this.id = id;
|
|
34
|
-
this.tagText = dto.tag ??
|
|
35
|
-
this.tagDescription = dto.description ??
|
|
35
|
+
this.tagText = dto.tag ?? "";
|
|
36
|
+
this.tagDescription = dto.description ?? "";
|
|
36
37
|
}
|
|
37
38
|
clone(): BuilderTagDto {
|
|
38
39
|
return this.toJson();
|
|
@@ -54,17 +55,15 @@ export class TagCollection implements Iterable<BuilderTag> {
|
|
|
54
55
|
return list[Symbol.iterator]();
|
|
55
56
|
}
|
|
56
57
|
private constructor(initialTags: ReadonlyArray<BuilderTag>) {
|
|
57
|
-
initialTags.forEach(tag => {
|
|
58
|
+
initialTags.forEach((tag) => {
|
|
58
59
|
this._tags.add(tag);
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
init(tags: ReadonlyArray<BuilderTagDto>) {
|
|
63
|
-
const dtoList: ReadonlyArray<BuilderTagDto> = Array.isArray(tags)
|
|
64
|
-
? tags
|
|
65
|
-
: [];
|
|
64
|
+
const dtoList: ReadonlyArray<BuilderTagDto> = Array.isArray(tags) ? tags : [];
|
|
66
65
|
const all = dtoList.map(BuilderTag.fromDto);
|
|
67
|
-
all.forEach(tag => {
|
|
66
|
+
all.forEach((tag) => {
|
|
68
67
|
this._tags.add(tag);
|
|
69
68
|
});
|
|
70
69
|
}
|
|
@@ -83,14 +82,14 @@ export class TagCollection implements Iterable<BuilderTag> {
|
|
|
83
82
|
|
|
84
83
|
toJson(): ReadonlyArray<BuilderTagDto> {
|
|
85
84
|
const list = [...this._tags];
|
|
86
|
-
const dtoList = list.map(t => t.toJson());
|
|
85
|
+
const dtoList = list.map((t) => t.toJson());
|
|
87
86
|
return dtoList;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
deleteAll(tags: Iterable<BuilderTag>) {
|
|
91
90
|
const l = tags[Symbol.iterator]();
|
|
92
91
|
const asList = [...tags];
|
|
93
|
-
asList.forEach(t => {
|
|
92
|
+
asList.forEach((t) => {
|
|
94
93
|
this.delete(t);
|
|
95
94
|
});
|
|
96
95
|
}
|
package/src/builder-compiler.ts
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { PageID } from "../primitives/ID";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface representing a code book question sum-score.
|
|
5
|
+
*
|
|
6
|
+
* @interface
|
|
7
|
+
*/
|
|
8
|
+
export interface CodeBookQuestionVariable {
|
|
9
|
+
readonly kind: "codebook-question-variable";
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly varId: string;
|
|
12
|
+
readonly pageId: PageID;
|
|
13
|
+
readonly pagePrefix: string;
|
|
14
|
+
readonly modulePrefix: string;
|
|
15
|
+
/**
|
|
16
|
+
* Show the position of the question on page (a, b, c, d, ...)
|
|
17
|
+
*/
|
|
18
|
+
readonly questionPrefix: string;
|
|
19
|
+
readonly pagePosition: number;
|
|
20
|
+
readonly options: ReadonlyArray<{ label: string; value: number }>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CodebookPredefinedVariable {
|
|
24
|
+
readonly kind: "codebook-predefined-variable";
|
|
25
|
+
readonly modulePrefix: string;
|
|
26
|
+
readonly moduleID: string;
|
|
27
|
+
defaultValue: number;
|
|
28
|
+
options: Array<{ label: string; value: number }>;
|
|
29
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { BuilderPageDto } from "
|
|
2
|
-
import { BuilderSchemaDto } from "
|
|
3
|
-
import {
|
|
1
|
+
import { BuilderPageDto } from "../Builder-page";
|
|
2
|
+
import { BuilderSchemaDto } from "../Builder-schema";
|
|
3
|
+
import { CodeBookQuestionVariable, CodebookPredefinedVariable } from "./codebook-variable";
|
|
4
4
|
|
|
5
5
|
export interface Codebook {
|
|
6
|
-
readonly predefinedVariables: ReadonlyArray<
|
|
7
|
-
readonly pageVariables: ReadonlyArray<
|
|
6
|
+
readonly predefinedVariables: ReadonlyArray<CodebookPredefinedVariable>;
|
|
7
|
+
readonly pageVariables: ReadonlyArray<CodeBookQuestionVariable>;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const fromPage = (
|
|
11
11
|
page: BuilderPageDto,
|
|
12
12
|
pagePosition: number,
|
|
13
13
|
modulePrefix: string,
|
|
14
|
-
):
|
|
15
|
-
const variables:
|
|
14
|
+
): CodeBookQuestionVariable[] => {
|
|
15
|
+
const variables: CodeBookQuestionVariable[] = [];
|
|
16
16
|
|
|
17
17
|
if (page._type !== "question") {
|
|
18
18
|
// TODO Implement form field variables
|
|
19
19
|
return [];
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const options:
|
|
22
|
+
const options: CodeBookQuestionVariable["options"] = page.defaultQuestion.options.map((o) => {
|
|
23
23
|
return { value: o.value, label: o.label };
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
const variable:
|
|
27
|
-
kind: "
|
|
26
|
+
const variable: CodeBookQuestionVariable = {
|
|
27
|
+
kind: "codebook-question-variable",
|
|
28
28
|
label: page.mainText.text,
|
|
29
|
+
pageId: page.id,
|
|
30
|
+
pagePrefix: page.prefix,
|
|
29
31
|
options,
|
|
30
32
|
modulePrefix,
|
|
31
|
-
origin: "question",
|
|
32
|
-
pageId: page.id,
|
|
33
33
|
pagePosition,
|
|
34
|
-
|
|
34
|
+
questionPrefix: "",
|
|
35
35
|
varId: modulePrefix + "_" + page.prefix,
|
|
36
36
|
};
|
|
37
37
|
|
|
@@ -48,8 +48,8 @@ const fromPage = (
|
|
|
48
48
|
const getPageVariablesFromPages = (
|
|
49
49
|
pages: BuilderPageDto[],
|
|
50
50
|
modulePrefix: string,
|
|
51
|
-
):
|
|
52
|
-
const variables:
|
|
51
|
+
): CodeBookQuestionVariable[] => {
|
|
52
|
+
const variables: CodeBookQuestionVariable[] = [];
|
|
53
53
|
pages.forEach((page, index) => {
|
|
54
54
|
const pageVariables = fromPage(page, index, modulePrefix);
|
|
55
55
|
variables.push(...pageVariables);
|
|
@@ -61,7 +61,7 @@ const fromSchema = (schema: BuilderSchemaDto): Codebook => {
|
|
|
61
61
|
const modulePrefix = schema.prefix;
|
|
62
62
|
const pageVariables = getPageVariablesFromPages(schema.pages, modulePrefix);
|
|
63
63
|
const vs = schema.predefinedVariables;
|
|
64
|
-
const predefinedVariables:
|
|
64
|
+
const predefinedVariables: CodebookPredefinedVariable[] = vs ? [...vs] : [];
|
|
65
65
|
return { pageVariables, predefinedVariables };
|
|
66
66
|
};
|
|
67
67
|
|
|
@@ -0,0 +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
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// The default length of an ID
|
|
2
|
+
const ID_LENGTH = 32;
|
|
3
|
+
|
|
4
|
+
// The minimum length of an ID
|
|
5
|
+
const MIN_LENGTH = 10;
|
|
6
|
+
|
|
7
|
+
export type ID<B extends string> = string & { __ID__: B };
|
|
8
|
+
|
|
9
|
+
const isID = <const B extends string>(idName: B, id?: string): id is ID<B> => {
|
|
10
|
+
if (typeof id !== "string") return false;
|
|
11
|
+
return id.length >= MIN_LENGTH;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const createIDByName = <const B extends string>(idName: B): ID<B> => {
|
|
15
|
+
const letters = "abcdefghijklmnopqrstuvyz";
|
|
16
|
+
const all = letters + letters.toUpperCase();
|
|
17
|
+
let result = "";
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < ID_LENGTH; i++) {
|
|
20
|
+
const char = all.charAt(Math.floor(Math.random() * all.length));
|
|
21
|
+
result += char;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return result as ID<B>;
|
|
25
|
+
};
|
|
26
|
+
const createDummyID = <const B extends string>(idName: B, letter: string): ID<B> => {
|
|
27
|
+
return letter.repeat(ID_LENGTH) as ID<B>;
|
|
28
|
+
};
|
|
29
|
+
interface Id<T extends string> {
|
|
30
|
+
name: T;
|
|
31
|
+
is: (id: string) => id is ID<T>;
|
|
32
|
+
validateOrCreate: (id: string) => ID<T>;
|
|
33
|
+
validateOrThrow: (id: string) => ID<T>;
|
|
34
|
+
create: () => ID<T>;
|
|
35
|
+
dummy: {
|
|
36
|
+
a: ID<T>;
|
|
37
|
+
b: ID<T>;
|
|
38
|
+
c: ID<T>;
|
|
39
|
+
d: ID<T>;
|
|
40
|
+
e: ID<T>;
|
|
41
|
+
f: ID<T>;
|
|
42
|
+
g: ID<T>;
|
|
43
|
+
h: ID<T>;
|
|
44
|
+
i: ID<T>;
|
|
45
|
+
j: ID<T>;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a object with helper functions for a specific ID type
|
|
51
|
+
* @param idName
|
|
52
|
+
*/
|
|
53
|
+
export const createTypedIdSingleton = <const B extends string>(idName: B): Id<B> => {
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new ID of the correct type
|
|
56
|
+
*/
|
|
57
|
+
const create = (): ID<B> => createIDByName(idName);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Checks if the id is of the correct type
|
|
61
|
+
* @param id
|
|
62
|
+
*/
|
|
63
|
+
const is = (id: string): id is ID<B> => isID(idName, id);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the id is of the correct type, if not it throws an error
|
|
67
|
+
* @param id
|
|
68
|
+
*/
|
|
69
|
+
const validateOrThrow = (id: string): ID<B> => {
|
|
70
|
+
if (!is(id)) {
|
|
71
|
+
throw new Error(`Invalid id: ${id}`);
|
|
72
|
+
}
|
|
73
|
+
return id;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The lowercase name of the id (SCHEMA, PAGE, etc)
|
|
78
|
+
*/
|
|
79
|
+
const name: B = idName;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Ensures that the id is of the correct type, if not it creates a new one
|
|
83
|
+
* @param id
|
|
84
|
+
*/
|
|
85
|
+
const validateOrCreate = (id: string): ID<B> => {
|
|
86
|
+
return is(id) ? id : create();
|
|
87
|
+
};
|
|
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
|
+
|
|
101
|
+
const dummy = {
|
|
102
|
+
a,
|
|
103
|
+
b,
|
|
104
|
+
c,
|
|
105
|
+
d,
|
|
106
|
+
e,
|
|
107
|
+
f,
|
|
108
|
+
g,
|
|
109
|
+
h,
|
|
110
|
+
i,
|
|
111
|
+
j,
|
|
112
|
+
list,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return Object.freeze({ create, is, validateOrCreate, validateOrThrow, name, dummy });
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export type SchemaID = ID<"SCHEMA">;
|
|
119
|
+
export const SchemaID = createTypedIdSingleton("SCHEMA");
|
|
120
|
+
|
|
121
|
+
export type PageID = ID<"PAGE">;
|
|
122
|
+
export const PageID = createTypedIdSingleton("PAGE");
|
|
123
|
+
|
|
124
|
+
export type TagID = ID<"TAG">;
|
|
125
|
+
export const TagID = createTypedIdSingleton("TAG");
|
|
126
|
+
export type OptionID = ID<"OPTION">;
|
|
127
|
+
export const OptionID = createTypedIdSingleton("OPTION");
|
|
128
|
+
|
|
129
|
+
export type TextID = ID<"TEXT">;
|
|
130
|
+
export const TextID = createTypedIdSingleton("TEXT");
|
|
131
|
+
export type QuestionID = ID<"QUESTION">;
|
|
132
|
+
export const QuestionID = createTypedIdSingleton("QUESTION");
|
|
133
|
+
|
|
134
|
+
export type SumScoreVariableID = ID<"SUM_SCORE_VARIABLE">;
|
|
135
|
+
export const SumScoreVariableID = createTypedIdSingleton("SUM_SCORE_VARIABLE");
|
|
136
|
+
|
|
137
|
+
export type SumScoreMemberShipID = ID<"SUM_SCORE_MEMBERSHIP">;
|
|
138
|
+
export const SumScoreMemberShipID = createTypedIdSingleton("SUM_SCORE_MEMBERSHIP");
|
|
@@ -31,15 +31,16 @@ export class PagePrefix {
|
|
|
31
31
|
return value;
|
|
32
32
|
};
|
|
33
33
|
public static castOrCreateRandom = (value: string): PagePrefix => {
|
|
34
|
-
const v = PagePrefix.isValid(value)
|
|
34
|
+
const v = PagePrefix.isValid(value)
|
|
35
|
+
? value
|
|
36
|
+
: createRandomPrefix<PagePrefixValue>(PagePrefix.randomLen);
|
|
35
37
|
return new PagePrefix(v);
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
public static isValid = (prefix: string | 999): prefix is PagePrefixValue => {
|
|
39
41
|
if (typeof prefix !== "string") return false;
|
|
40
42
|
if (prefix.length < SchemaPrefix.MIN_LENGTH) return false;
|
|
41
|
-
|
|
42
|
-
return true;
|
|
43
|
+
return prefix.length <= SchemaPrefix.MAX_LENGTH;
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
get value(): PagePrefixValue {
|
package/src/primitives/varID.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { PagePrefixValue } from "./page-prefix";
|
|
|
3
3
|
import { SchemaPrefixValue } from "./schema-prefix";
|
|
4
4
|
|
|
5
5
|
export type VarID = `${SchemaPrefixValue}_${PagePrefixValue}`;
|
|
6
|
+
|
|
6
7
|
export const VarID = {
|
|
7
8
|
create: (schemaPrefix: SchemaPrefixValue, pagePrefix: PagePrefixValue): VarID => {
|
|
8
9
|
const varId = schemaPrefix + "_" + pagePrefix;
|