@legalplace/conditions-runner 1.1.0

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.
@@ -0,0 +1,316 @@
1
+ import { Types } from "@legalplace/referencesparser";
2
+ import type InputsType from "@legalplace/types/dist/inputs";
3
+ import ConditionsRunner from "./ConditionsRunner";
4
+ import { ConditionData, ConditionDataMap } from "./types/conditions.d";
5
+
6
+ class DataPopulator {
7
+ private references: Types.ReferencesType;
8
+
9
+ private ovc: InputsType;
10
+
11
+ private conditionsRunner: ConditionsRunner;
12
+
13
+ private id?: number;
14
+
15
+ private index?: number;
16
+
17
+ private dataMap: ConditionDataMap;
18
+
19
+ private data: ConditionData = {
20
+ o: {},
21
+ v: {},
22
+ c: {
23
+ o: {},
24
+ s: {},
25
+ v: {},
26
+ },
27
+ };
28
+
29
+ constructor(
30
+ conditionsRunner: ConditionsRunner,
31
+ references: Types.ReferencesType,
32
+ ovc: InputsType,
33
+ dataMap: ConditionDataMap,
34
+ id?: number,
35
+ index?: number
36
+ ) {
37
+ this.id = id;
38
+ this.ovc = ovc;
39
+ this.index = index;
40
+ this.dataMap = dataMap;
41
+ this.references = references;
42
+ this.conditionsRunner = conditionsRunner;
43
+
44
+ // Populating variables
45
+ this.populateVariables();
46
+
47
+ // Populating options
48
+ this.populateOptions();
49
+
50
+ // Populating conditions
51
+ this.populateConditions();
52
+ }
53
+
54
+ /**
55
+ * Returns resulting data object
56
+ */
57
+ public getData(): Readonly<ConditionData> {
58
+ return this.data;
59
+ }
60
+
61
+ private populateConditions(): void {
62
+ // Sections
63
+ for (let i = 0; i < this.dataMap.c.s.length; i += 1) {
64
+ const sectionId = this.dataMap.c.s[i];
65
+ const sectionCondition = this.sectionConditionValue(sectionId);
66
+ this.data.c.s[sectionId] = [sectionCondition !== false];
67
+ }
68
+
69
+ // Options
70
+ for (let i = 0; i < this.dataMap.c.o.length; i += 1) {
71
+ const optionId = this.dataMap.c.o[i];
72
+ const optionCondition = [...this.getOptionConditions(optionId)];
73
+ this.data.c.o[optionId] =
74
+ optionCondition === undefined ? [false] : optionCondition;
75
+ }
76
+
77
+ // Variables
78
+ for (let i = 0; i < this.dataMap.c.v.length; i += 1) {
79
+ const variableId = this.dataMap.c.v[i];
80
+ const variableCondition = [...this.getVariablesConditions(variableId)];
81
+ this.data.c.v[variableId] =
82
+ variableCondition === undefined ? [false] : variableCondition;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Returns a give option's conditions
88
+ * @param optionId Option's id
89
+ */
90
+ private getOptionConditions(optionId: number): Readonly<boolean[]> {
91
+ const conditions = this.optionConditionValue(optionId);
92
+ if (conditions === undefined) return [true];
93
+ if (this.id === undefined || this.index === undefined) {
94
+ return conditions;
95
+ }
96
+
97
+ // Getting variable parent option
98
+ const optionRootParent = this.getOptionRootParent(optionId);
99
+ const optionRootRelations =
100
+ this.references.relations.options[optionRootParent];
101
+ if (
102
+ optionRootRelations.children.options.includes(this.id) ||
103
+ optionRootRelations.dependants.includes(this.id) ||
104
+ this.id === optionRootParent
105
+ ) {
106
+ if (conditions !== undefined && conditions[this.index] === false)
107
+ return [false];
108
+ return [conditions[this.index]];
109
+ }
110
+
111
+ return conditions;
112
+ }
113
+
114
+ /**
115
+ * Returns a give variables conditions
116
+ * @param variableId Variable's id
117
+ */
118
+ private getVariablesConditions(variableId: number): Readonly<boolean[]> {
119
+ const conditions = this.variableConditionValue(variableId);
120
+ if (conditions === undefined) return [true];
121
+ if (this.id === undefined || this.index === undefined) {
122
+ return conditions;
123
+ }
124
+
125
+ // Getting variable parent option
126
+ const variableRootParent = this.getVariableRootParent(variableId);
127
+ const variableRootRelations =
128
+ this.references.relations.options[variableRootParent];
129
+ if (
130
+ variableRootRelations.children.options.includes(this.id) ||
131
+ variableRootRelations.dependants.includes(this.id) ||
132
+ this.id === variableRootParent
133
+ ) {
134
+ return [conditions[this.index]];
135
+ }
136
+
137
+ return conditions;
138
+ }
139
+
140
+ /**
141
+ * Populates variables according to the current dataMap object
142
+ */
143
+ private populateVariables(): void {
144
+ for (let i = 0; i < this.dataMap.v.length; i += 1) {
145
+ const variableId = this.dataMap.v[i];
146
+ const variableReference = this.references.variables[variableId];
147
+ let values = this.getVariableValues(variableId);
148
+
149
+ const parseNumber = (v: string) => {
150
+ const result = parseFloat(v);
151
+ return Number.isNaN(result) ? "" : result;
152
+ };
153
+ // If variable is of type number
154
+ if (variableReference.type === "number") {
155
+ values = values.map((v) =>
156
+ typeof v === "number" ? v : parseNumber(v)
157
+ );
158
+ }
159
+
160
+ // Adding variables
161
+ this.data.v[variableId] = [...values];
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Returns a give variables value
167
+ * @param variableId Variable's id
168
+ */
169
+ private getVariableValues(variableId: number): Readonly<(string | number)[]> {
170
+ const value = this.ovc.variables[variableId];
171
+ if (this.id === undefined || this.index === undefined) {
172
+ return value;
173
+ }
174
+
175
+ // Getting variable parent option
176
+ const variableRootParent = this.getVariableRootParent(variableId);
177
+ const variableRootRelations =
178
+ this.references.relations.options[variableRootParent];
179
+ if (
180
+ variableRootRelations.children.options.includes(this.id) ||
181
+ variableRootRelations.dependants.includes(this.id) ||
182
+ this.id === variableRootParent
183
+ ) {
184
+ return [value[this.index]];
185
+ }
186
+
187
+ return this.cleanArrayFromNullValues([...value]);
188
+ }
189
+
190
+ /**
191
+ * Return a given variable root option relations
192
+ * @param variableId Variable's id
193
+ */
194
+ private getVariableRootParent(variableId: number) {
195
+ const variableParents =
196
+ this.references.relations.variables[variableId].parents;
197
+ return variableParents[variableParents.length - 1];
198
+ }
199
+
200
+ /**
201
+ * Cleans values array from any null value by replacing it
202
+ * with an empty string
203
+ * @param arr Values array
204
+ */
205
+ private cleanArrayFromNullValues(
206
+ arr: (string | number | null)[]
207
+ ): (string | number)[] {
208
+ return arr.map((v) => (v === null ? "" : v));
209
+ }
210
+
211
+ /**
212
+ * Populates options data object accodring to current dataMap object
213
+ */
214
+ populateOptions() {
215
+ for (let i = 0; i < this.dataMap.o.length; i += 1) {
216
+ const optionId = this.dataMap.o[i];
217
+ const inputs = this.getOptionInputs(optionId);
218
+
219
+ // Adding option
220
+ this.data.o[optionId] = [...inputs];
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Returns a give option's inputs
226
+ * @param optionId Option's id
227
+ */
228
+ private getOptionInputs(optionId: number): Readonly<boolean[]> {
229
+ const inputs = this.ovc.options[optionId];
230
+ if (this.id === undefined || this.index === undefined) {
231
+ return inputs;
232
+ }
233
+
234
+ // Getting variable parent option
235
+ const optionRootParent = this.getOptionRootParent(optionId);
236
+ const optionRootRelations =
237
+ this.references.relations.options[optionRootParent];
238
+ if (
239
+ optionRootRelations.children.options.includes(this.id) ||
240
+ optionRootRelations.dependants.includes(this.id) ||
241
+ this.id === optionRootParent
242
+ ) {
243
+ return [inputs[this.index]];
244
+ }
245
+
246
+ return inputs;
247
+ }
248
+
249
+ /**
250
+ * Returns option's root parent
251
+ * @param optionId Root parent
252
+ */
253
+ private getOptionRootParent(optionId: number) {
254
+ const optionParents = this.references.relations.options[optionId].parents;
255
+ return optionParents.length > 0
256
+ ? optionParents[optionParents.length - 1]
257
+ : optionId;
258
+ }
259
+
260
+ /**
261
+ * Calculates option's condition
262
+ */
263
+ private optionConditionValue(optionId: number) {
264
+ // Getting option conditions
265
+ const conditions = this.references.conditions.options[optionId];
266
+ if (conditions === undefined) return undefined;
267
+
268
+ // Getting option inputs length
269
+ const inputs = this.ovc.options[optionId];
270
+
271
+ return inputs.map((input, index) =>
272
+ this.conditionsRunner.executeCondition(
273
+ conditions,
274
+ optionId,
275
+ index,
276
+ "options"
277
+ )
278
+ );
279
+ }
280
+
281
+ /**
282
+ * Calculates variable's condition
283
+ */
284
+ private variableConditionValue(variableId: number) {
285
+ // Getting variable conditions
286
+ const conditions = this.references.conditions.variables[variableId];
287
+ if (conditions === undefined) return undefined;
288
+
289
+ // Getting variable inputs length
290
+ const inputs = this.ovc.variables[variableId];
291
+
292
+ const result = inputs.map((input, index) =>
293
+ this.conditionsRunner.executeCondition(
294
+ conditions,
295
+ variableId,
296
+ index,
297
+ "variables"
298
+ )
299
+ );
300
+
301
+ return result;
302
+ }
303
+
304
+ /**
305
+ * Calculates section's condition
306
+ */
307
+ private sectionConditionValue(sectionId: number) {
308
+ // Getting section conditions
309
+ const conditions = this.references.conditions.sections.main[sectionId];
310
+ if (conditions === undefined) return undefined;
311
+
312
+ return this.conditionsRunner.executeCondition(conditions, 0, 0, "sections");
313
+ }
314
+ }
315
+
316
+ export default DataPopulator;