@media-quest/builder 0.0.26 → 0.0.28

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.
@@ -1,8 +1,8 @@
1
1
  import type { BuilderSchemaDto } from "./Builder-schema";
2
2
  import { BuilderSchema } from "./Builder-schema";
3
- import { BuilderPage } from "./Builder-page";
4
- import type { BuilderTagDto } from "./BuilderTag";
5
- import { BuilderTag } from "./BuilderTag";
3
+ import { BuilderPage } from "./page/Builder-page";
4
+ import type { BuilderTagDto } from "./tag/BuilderTag";
5
+ import { BuilderTag } from "./tag/BuilderTag";
6
6
  import { PagePrefix } from "./primitives/page-prefix";
7
7
  import { SchemaPrefix } from "./primitives/schema-prefix";
8
8
 
@@ -28,13 +28,14 @@ const schemaDto1: BuilderSchemaDto = {
28
28
  name: "label for dummy sum-score",
29
29
  description: "testId",
30
30
  useAvg: false,
31
- basedOn: [],
31
+ // basedOn: [],
32
32
  },
33
33
  ],
34
34
  pages: [
35
35
  {
36
36
  id: PageID.validateOrCreate("a".repeat(24)),
37
37
  _type: "info-page",
38
+ includedInSumScores: [],
38
39
  prefix: PagePrefix.fromStringOrThrow("p1"),
39
40
  mainText: {
40
41
  text: "hello from test",
@@ -81,9 +82,10 @@ const schemaDto1: BuilderSchemaDto = {
81
82
  },
82
83
  {
83
84
  id: PageID.dummy.b,
84
- _type: "multi-select",
85
+ _type: "question",
85
86
  prefix: PagePrefix.fromStringOrThrow("page2-prefix"),
86
87
  tags: [tag3.tag],
88
+ includedInSumScores: [],
87
89
  mainText: {
88
90
  text: "hello from test",
89
91
  autoplay: false,
@@ -180,30 +182,29 @@ describe("Builder schema", () => {
180
182
  });
181
183
 
182
184
  test("Can add page at concrete index", () => {
183
- const p1 = s1.addPage("form");
184
- expect(p1.pageType).toBe("form");
185
- const p2 = s1.addPage("multi-select", 0);
186
- expect(p2.pageType).toBe("multi-select");
187
- const pages = s1.pages;
188
- expect(pages[0].id).toBe(p2.id);
189
- s1.addPage("form");
190
- s1.addPage("form");
191
- const last = s1.addPage("form");
185
+ const p1 = s1.addPage("question");
186
+ expect(p1.pageType).toBe("question");
187
+ const p2 = s1.addPage("info-page", 0);
188
+ expect(p2.pageType).toBe("info-page");
189
+ // const pages = s1.pages;
190
+ expect(s1.pages[0].id).toBe(p2.id);
191
+ s1.addPage("question");
192
+ s1.addPage("question");
193
+ const last = s1.addPage("question");
192
194
  expect(s1.pages[s1.pages.length - 1]).toBe(last);
193
195
  const p3 = s1.addPage("info-page", 4);
194
- expect(pages[4].id).toBe(p3.id);
196
+ expect(s1.pages[4].id).toBe(p3.id);
195
197
  });
196
198
 
197
199
  test("Can move page up and down", () => {
198
- const p1 = s1.addPage("form");
199
- const p2 = s1.addPage("form");
200
- const p3 = s1.addPage("form");
201
- const p4 = s1.addPage("multi-select");
202
- const last = s1.addPage("form");
203
- const pages = s1.pages;
200
+ const p1 = s1.addPage("question");
201
+ const p2 = s1.addPage("question");
202
+ const p3 = s1.addPage("question");
203
+ const p4 = s1.addPage("info-page");
204
+ const last = s1.addPage("question");
204
205
  s1.movePage(p2, 0);
205
- expect(pages[0]).toBe(p2);
206
- expect(pages[1]).toBe(p1);
206
+ expect(s1.pages[0]).toBe(p2);
207
+ expect(s1.pages[1]).toBe(p1);
207
208
  expect(s1.movePage(p4, 4)).toBeTruthy();
208
209
  expect(s1.movePage(p4, 5)).toBeFalsy();
209
210
  expect(s1.movePage(p4, 10)).toBeFalsy();
@@ -212,11 +213,11 @@ describe("Builder schema", () => {
212
213
  });
213
214
 
214
215
  test("Can clone a page and insert at index", () => {
215
- const p1 = s1.addPage("form");
216
- const p2 = s1.addPage("form");
217
- const p3 = s1.addPage("form");
216
+ const p1 = s1.addPage("question");
217
+ const p2 = s1.addPage("question");
218
+ const p3 = s1.addPage("question");
218
219
  const mainTextContent = "Hello from test";
219
- const p4 = s1.addPage("multi-select");
220
+ const p4 = s1.addPage("info-page");
220
221
  p3.mainText.text = mainTextContent;
221
222
  const p1Clone = BuilderPage.fromJson(p1.clone());
222
223
  const beforeLen = s1.pages.length;
@@ -227,9 +228,9 @@ describe("Builder schema", () => {
227
228
  });
228
229
 
229
230
  test("Will not insert a page that is already in array.", () => {
230
- const p1 = s1.addPage("form");
231
- const p2 = s1.addPage("form");
232
- const p3 = s1.addPage("form");
231
+ const p1 = s1.addPage("question");
232
+ const p2 = s1.addPage("question");
233
+ const p3 = s1.addPage("question");
233
234
  const beforeLen = s1.pages.length;
234
235
  const result = s1.insertPage(p1, 0);
235
236
  const pages = s1.pages;
@@ -292,38 +293,56 @@ describe("Builder schema", () => {
292
293
  });
293
294
  });
294
295
 
295
- test("Can add sum-variables, but not twice", () => {
296
- // p0.prefix = "info_page_prefix_";
297
- const p1 = s1.addPage("question");
298
- const p2 = s1.addPage("question");
299
- p1.prefix = PagePrefix.fromStringOrThrow("p1_prefix");
300
- p2.prefix = PagePrefix.fromStringOrThrow("p2_prefix");
301
-
302
- const ss1: SumScoreVariableDto = {
303
- id: SumScoreVariableID.dummy.a,
304
- name: "ss1",
305
- description: "",
306
- useAvg: false,
307
- basedOn: [],
308
- };
296
+ test("Can add, update and delete sum-variable", () => {
297
+ const ssv = (name: string) =>
298
+ s1.sumScoreVariableCreate({ name, useAvg: true, description: "description for " + name });
309
299
 
310
- s1.addSumScoreVariable(ss1);
311
- s1.addSumScoreVariable(ss1);
300
+ const v1 = ssv("v1");
301
+ const v2 = ssv("v2");
302
+ const v3 = ssv("v3");
303
+ expect(s1.sumScoreVariables.length).toBe(3);
304
+ s1.sumScoreVariableUpdate(v1.id, { name: "updatedName" });
305
+ expect(s1.sumScoreVariables[0].name).toBe("updatedName");
306
+ const success = s1.sumScoreVariableDelete(v2.id);
307
+ expect(success).toBeTruthy();
308
+ expect(s1.sumScoreVariables.length).toBe(2);
309
+ const failure = s1.sumScoreVariableDelete(SumScoreVariableID.create());
310
+ expect(failure).toBeFalsy();
311
+ // s1.sumScoreVariableDelete(v2.id);
312
+ });
312
313
 
313
- // expect(s1.sumScoreVariables.length).toBe(1);
314
+ test("When a sum-score updates, then the pages update as well", () => {
315
+ const p1 = s1.addPage("question");
316
+ const v1 = s1.sumScoreVariableCreate({
317
+ name: "v1",
318
+ useAvg: true,
319
+ description: "description for v1",
320
+ });
321
+ expect(s1.sumScoreVariables.length).toBe(1);
322
+ expect(s1.pages.length).toBe(1);
323
+ const success = s1.sumScoreVariableAddToPage(v1, p1, 1);
324
+ expect(success).toBe(true);
325
+ expect(p1.includedInSumScores.length).toBe(1);
326
+ const updateSuccess = s1.sumScoreVariableUpdate(v1.id, {
327
+ name: "updated_name",
328
+ description: "updated_description",
329
+ useAvg: !v1.useAvg,
330
+ });
331
+ expect(updateSuccess).toBe(true);
332
+ expect(p1.includedInSumScores[0].name).toBe("updated_name");
333
+ expect(p1.includedInSumScores[0].description).toBe("updated_description");
334
+ });
314
335
 
315
- // TODO add TAGS!!
316
- // expect(ruleInput.excludeByTagActions.length).toBe(0);
317
- // expect(ruleInput.excludeByPageIdActions.length).toBe(3);
318
- // const allPageIds = new Set(ruleInput.jumpToPageActions.map((a) => a.pageId));
319
- // expect(allPageIds.has(p0.id)).toBe(true);
320
- // expect(allPageIds.has(p1.id)).toBe(true);
321
- // expect(allPageIds.has(p2.id)).toBe(true);
322
- // ruleInput.questionVars.forEach((v) => {
323
- // expect(allPageIds.has(v.varId)).toBe(true);
324
- // });
325
- // ruleInput.jumpToPageActions.forEach((v) => {
326
- // expect(allPageIds.has(v.pageId)).toBe(true);
327
- // });
336
+ test("When a sum-score is deleted, then pages will delete from included in sum-scores.", () => {
337
+ const p1 = s1.addPage("question");
338
+ const v1 = s1.sumScoreVariableCreate({
339
+ name: "v1",
340
+ useAvg: true,
341
+ description: "description for v1",
342
+ });
343
+ const success = s1.sumScoreVariableAddToPage(v1, p1, 1);
344
+ expect(success).toBe(true);
345
+ s1.sumScoreVariableDelete(v1.id);
346
+ expect(p1.includedInSumScores.length).toBe(0);
328
347
  });
329
348
  });
@@ -1,5 +1,5 @@
1
- import type { BuilderPageDto, BuilderPageType } from "./Builder-page";
2
- import { BuilderPage } from "./Builder-page";
1
+ import type { BuilderPageDto, BuilderPageType } from "./page/Builder-page";
2
+ import { BuilderPage } from "./page/Builder-page";
3
3
  import type {
4
4
  BuilderRuleDto,
5
5
  ExcludeByPageAction,
@@ -9,8 +9,8 @@ import type {
9
9
  } from "./rulebuilder";
10
10
  import { BuilderRule, RuleInput } from "./rulebuilder";
11
11
  import type { RuleQuestionVariable } from "./rulebuilder/RuleVariable";
12
- import type { BuilderTagDto } from "./BuilderTag";
13
- import { BuilderTag, TagCollection } from "./BuilderTag";
12
+ import type { BuilderTagDto } from "./tag/BuilderTag";
13
+ import { BuilderTag } from "./tag/BuilderTag";
14
14
  import { DefaultThemeCompiler } from "./theme/default-theme-compiler";
15
15
  import { ImageFile } from "./media-files";
16
16
  import { DUtil } from "@media-quest/engine";
@@ -21,9 +21,11 @@ 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
+ import { SumScoreVariable, SumScoreVariableDto } from "./sum-score/sum-score-variable";
25
+ import { PageID, SchemaID, SumScoreVariableID } from "./primitives/ID";
26
+ import { SumScoreVariableCollection } from "./sum-score/sum-score-variable-collection";
27
+ import { TagCollection } from "./tag/Tag-Collection";
28
+ import { BuilderPageCollection } from "./page/Builder-page-collection";
27
29
 
28
30
  const U = DUtil;
29
31
 
@@ -33,35 +35,34 @@ export interface BuilderSchemaDto {
33
35
  readonly mainImage: ImageFile | false;
34
36
  readonly backgroundColor: string;
35
37
  readonly name: string;
36
- readonly pages: BuilderPageDto[];
38
+ readonly pages: ReadonlyArray<BuilderPageDto>;
37
39
  readonly baseHeight: number;
38
40
  readonly baseWidth: number;
39
41
  readonly predefinedVariables?: Array<CodebookPredefinedVariable>;
40
42
  readonly sumScoreVariables?: ReadonlyArray<SumScoreVariableDto>;
41
- readonly sumScoreMemberShips?: ReadonlyArray<SumScoreMembershipDto>;
42
43
  readonly rules: ReadonlyArray<BuilderRuleDto>;
43
44
  readonly tags: ReadonlyArray<BuilderTagDto>;
44
45
  }
45
46
 
46
- class SumScoreVariableCollection {
47
- private _all: Array<SumScoreVariableDto> = [];
48
- }
49
-
50
47
  export class BuilderSchema {
51
48
  readonly prefix: SchemaPrefix;
52
49
  baseHeight = 1300;
53
50
  baseWidth = 1024;
54
51
  backgroundColor = "#000000";
55
- pages: BuilderPage[] = [];
52
+ private readonly _pageCollection: BuilderPageCollection;
56
53
  mainImage: ImageFile | false = false;
57
54
  predefinedVariables: CodebookPredefinedVariable[] = [];
58
55
  private _rules: BuilderRule[] = [];
59
- private _sumVariables: SumScoreVariableDto[] = [];
56
+ private readonly _sumScoreCollection;
60
57
  get rules(): ReadonlyArray<BuilderRule> {
61
58
  return [...this._rules];
62
59
  }
63
- get sumScoreVariables(): ReadonlyArray<SumScoreVariableDto> {
64
- return [...this._sumVariables];
60
+ get pages(): ReadonlyArray<BuilderPage> {
61
+ return [...this._pageCollection];
62
+ }
63
+
64
+ get sumScoreVariables(): ReadonlyArray<SumScoreVariable> {
65
+ return [...this._sumScoreCollection];
65
66
  }
66
67
 
67
68
  // get prefix(): SchemaPrefixValue {
@@ -80,29 +81,33 @@ export class BuilderSchema {
80
81
  public static fromJson(dto: BuilderSchemaDto): BuilderSchema {
81
82
  const schemaPrefix = SchemaPrefix.castOrCreateRandom(dto.prefix);
82
83
  const schema = new BuilderSchema(dto.id, dto.name, schemaPrefix);
83
- const pages = dto.pages.map(BuilderPage.fromJson);
84
+ const sumScoreVariables = dto.sumScoreVariables ? [...dto.sumScoreVariables] : [];
85
+ const pagesDto = Array.isArray(dto.pages) ? dto.pages : [];
84
86
 
87
+ // Init collections.
85
88
  schema._tagCollection.init(dto.tags);
89
+ schema._sumScoreCollection.init(sumScoreVariables);
90
+
86
91
  schema.backgroundColor = dto.backgroundColor;
87
92
  schema.baseHeight = dto.baseHeight;
88
93
  schema.baseWidth = dto.baseWidth;
89
- schema.pages = pages;
94
+ schema._pageCollection._init(pagesDto);
90
95
  schema.predefinedVariables = dto.predefinedVariables ?? [];
91
96
  schema.backgroundColor = dto.backgroundColor;
92
97
  schema.mainImage = dto.mainImage ?? false;
93
98
  const rulesDto = dto.rules ?? [];
94
99
  const ruleInput = schema.getRuleInput();
95
-
96
- schema._sumVariables = Array.isArray(dto.sumScoreVariables) ? [...dto.sumScoreVariables] : [];
97
100
  schema._rules = rulesDto.map((r) => BuilderRule.fromDto(r, ruleInput));
101
+
102
+ schema.updateSumScoreRelations();
98
103
  return schema;
99
104
  }
100
105
 
101
106
  toJson(): BuilderSchemaDto {
102
- const pages = this.pages.map((p) => p.toJson());
107
+ const pages = this._pageCollection.toJson();
103
108
  const tags = this._tagCollection.toJson();
104
109
  const rules = this._rules.map((rule) => rule.toJson());
105
-
110
+ const sumScoreVariables = this._sumScoreCollection.toJson();
106
111
  const dto: BuilderSchemaDto = {
107
112
  backgroundColor: this.backgroundColor,
108
113
  baseHeight: this.baseHeight,
@@ -113,7 +118,7 @@ export class BuilderSchema {
113
118
  rules,
114
119
  tags,
115
120
  predefinedVariables: this.predefinedVariables,
116
- sumScoreVariables: [...this.sumScoreVariables],
121
+ sumScoreVariables,
117
122
  mainImage: this.mainImage,
118
123
  prefix: this.prefix.value,
119
124
  };
@@ -125,41 +130,50 @@ export class BuilderSchema {
125
130
  prefix: SchemaPrefix,
126
131
  ) {
127
132
  this.prefix = prefix;
133
+ this._sumScoreCollection = SumScoreVariableCollection.create([]);
134
+ this._pageCollection = BuilderPageCollection.create([]);
135
+ // this
128
136
  }
129
137
 
130
138
  addPage(type: BuilderPageType, atIndex = -1): BuilderPage {
131
- const pagePrefix = PagePrefix.create();
132
- const newPage = BuilderPage.create(type, pagePrefix.value);
133
- if (atIndex >= 0 && atIndex < this.pages.length) {
134
- this.pages.splice(atIndex, 0, newPage);
135
- } else {
136
- this.pages.push(newPage);
137
- }
138
- return newPage;
139
+ return this._pageCollection.add(type, atIndex);
139
140
  }
140
141
 
141
- addSumScoreVariable(variable: SumScoreVariableDto) {
142
+ sumScoreVariableCreate(options: { name: string; description: string; useAvg: boolean }) {
142
143
  // TODO VALIDATE.
143
- this._sumVariables.push({ ...variable });
144
+ // this._sumVariables.push({ ...variable });
145
+ const variable = this._sumScoreCollection.addNew(options);
144
146
 
145
147
  return variable;
146
148
  }
149
+ sumScoreVariableAddToPage(sumScoreVariable: SumScoreVariable, page: BuilderPage, weight: number) {
150
+ const added = this._pageCollection.addSumScoreVariable(sumScoreVariable, page.id, weight);
151
+ this.updateSumScoreRelations();
152
+ return added;
153
+ }
154
+
155
+ private updateSumScoreRelations() {
156
+ const sumScoreVariables = this._sumScoreCollection.asArray();
157
+ this._pageCollection.updateRelationShips({ sumScoreVariables });
158
+ }
159
+
160
+ sumScoreVariableUpdate(id: SumScoreVariableID, data: Partial<SumScoreVariableDto>) {
161
+ const didUpdate = this._sumScoreCollection._updateOne(id, data);
162
+ this.updateSumScoreRelations();
163
+ return didUpdate;
164
+ }
165
+
166
+ sumScoreVariableDeleteFromPage(pageId: PageID, sumScoreVariableId: SumScoreVariableID) {
167
+ this._pageCollection.sumScoreVariableDeleteFromPage(pageId, sumScoreVariableId);
168
+ this.updateSumScoreRelations();
169
+ }
147
170
 
148
171
  insertPage(page: BuilderPage, atIndex: number): boolean {
149
172
  return this.insertPageAtIndex(page, atIndex);
150
173
  }
151
174
 
152
175
  private insertPageAtIndex(page: BuilderPage, atIndex: number) {
153
- const isValidIndex = U.isInRange(0, this.pages.length - 1);
154
- if (!isValidIndex(atIndex)) {
155
- return false;
156
- }
157
- const exists = !!this.pages.find((p) => p.id === page.id);
158
- if (exists) {
159
- return false;
160
- }
161
- this.pages.splice(atIndex, 0, page);
162
- return true;
176
+ return this._pageCollection.insertPage(page, atIndex);
163
177
  }
164
178
 
165
179
  addRule() {
@@ -185,25 +199,11 @@ export class BuilderSchema {
185
199
  }
186
200
 
187
201
  movePage(page: BuilderPage, toIndex: number): boolean {
188
- const index = this.pages.indexOf(page);
189
- if (index < 0) {
190
- return false;
191
- }
192
- const isValidIndex = U.isInRange(0, this.pages.length - 1);
193
- if (!isValidIndex(toIndex)) {
194
- return false;
195
- }
196
- // console.log('Moving from :' + index + ' to: ' + toIndex);
197
- this.pages.splice(index, 1);
198
- this.pages.splice(toIndex, 0, page);
199
- return true;
202
+ return this._pageCollection.movePage(page, toIndex);
200
203
  }
201
204
 
202
205
  deletePage(page: BuilderPage): boolean {
203
- const filtered = this.pages.filter((p) => p !== page);
204
- const didDelete = filtered.length === this.pages.length - 1;
205
- this.pages = filtered;
206
- return didDelete;
206
+ return this._pageCollection.deleteById(page.id);
207
207
  }
208
208
 
209
209
  reevaluateRules() {
@@ -219,7 +219,7 @@ export class BuilderSchema {
219
219
  const pageIdActions: ExcludeByPageAction[] = [];
220
220
  const tagActions: ExcludeByTagAction[] = this.tags.map((t) => {
221
221
  const tag = t.tagText;
222
- const pageCount = this.pages.reduce((count, curr) => {
222
+ const pageCount = this._pageCollection.pages.reduce((count, curr) => {
223
223
  return curr.tags.includes(tag) ? count + 1 : count;
224
224
  }, 0);
225
225
  const excludeByTagDto: ExcludeByTagAction = {
@@ -230,8 +230,10 @@ export class BuilderSchema {
230
230
  };
231
231
  return excludeByTagDto;
232
232
  });
233
+
233
234
  const jumpActions: JumpToPageAction[] = [];
234
- this.pages.forEach((page, index) => {
235
+
236
+ this._pageCollection.pages.forEach((page, index) => {
235
237
  const pageVariables = page.getQuestionVariables(this.prefix, index);
236
238
  qVars.push(...pageVariables);
237
239
  const mainText = page.mainText.text;
@@ -273,7 +275,7 @@ export class BuilderSchema {
273
275
  const builderSchema = BuilderSchema.fromJson(this.toJson());
274
276
 
275
277
  // Overriding the
276
- builderSchema.pages.forEach((p) => {
278
+ builderSchema._pageCollection.pages.forEach((p) => {
277
279
  if (options.blockAutoplayQuestion) {
278
280
  p.mainText.autoplay = false;
279
281
  }
@@ -293,4 +295,12 @@ export class BuilderSchema {
293
295
  const output: CompilerOutput = { codebook, schema, schemaConfig };
294
296
  return output;
295
297
  }
298
+
299
+ sumScoreVariableDelete(id: SumScoreVariableID) {
300
+ const didDelete = this._sumScoreCollection._deleteVariable(id);
301
+ const sumScoreVariables = [...this._sumScoreCollection];
302
+ this._pageCollection.updateRelationShips({ sumScoreVariables });
303
+ this._pageCollection.sumScoreVariableDelete(id);
304
+ return didDelete;
305
+ }
296
306
  }
@@ -1,29 +1,27 @@
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
+ import { PageID } from "../primitives/ID";
2
+ import { SumScoreVariableDto } from "../sum-score/sum-score-variable";
3
+
4
+ /**
5
+ * Interface representing a code book question sum-score.
6
+ *
7
+ * @interface
8
+ */
9
+ export interface CodeBookQuestionVariable {
10
+ readonly kind: "codebook-question-variable";
11
+ readonly label: string;
12
+ readonly varId: string;
13
+ readonly pageId: PageID;
14
+ readonly pagePrefix: string;
15
+ readonly modulePrefix: string;
16
+ readonly pagePosition: number;
17
+ readonly options: ReadonlyArray<{ label: string; value: number }>;
18
+ readonly includedInSumScores: ReadonlyArray<SumScoreVariableDto>;
19
+ }
20
+
21
+ export interface CodebookPredefinedVariable {
22
+ readonly kind: "codebook-predefined-variable";
23
+ readonly modulePrefix: string;
24
+ readonly moduleID: string;
25
+ defaultValue: number;
26
+ options: Array<{ label: string; value: number }>;
27
+ }