@bolttech/form-engine 3.0.0-beta.11 → 3.0.0-beta.3
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/index.esm.js +3 -263
- package/package.json +1 -2
- package/src/components/AsFormField/AsFormField.d.ts +1 -1
- package/src/components/Form/Form.d.ts +1 -1
- package/src/components/index.d.ts +2 -2
- package/src/context/FormGroupContext.d.ts +1 -1
- package/src/core/index.d.js +2126 -0
- package/src/generators/formBuilder.d.ts +1 -1
- package/src/types/index.d.ts +1 -1
|
@@ -0,0 +1,2126 @@
|
|
|
1
|
+
// libs/form-engine-core/src/types/event.ts
|
|
2
|
+
var TMutationEnum = /* @__PURE__ */ ((TMutationEnum2) => {
|
|
3
|
+
TMutationEnum2["ON_VALUE"] = "value";
|
|
4
|
+
TMutationEnum2["ON_PROPS"] = "props";
|
|
5
|
+
TMutationEnum2["ON_VISIBILITY"] = "visibility";
|
|
6
|
+
TMutationEnum2["ON_API"] = "api";
|
|
7
|
+
TMutationEnum2["ON_IVARS"] = "iVars";
|
|
8
|
+
TMutationEnum2["ON_FIELDS"] = "fields";
|
|
9
|
+
return TMutationEnum2;
|
|
10
|
+
})(TMutationEnum || {});
|
|
11
|
+
|
|
12
|
+
// libs/form-engine-core/src/managers/field.ts
|
|
13
|
+
import {
|
|
14
|
+
combineLatest,
|
|
15
|
+
debounceTime,
|
|
16
|
+
map,
|
|
17
|
+
mergeMap,
|
|
18
|
+
startWith,
|
|
19
|
+
Subject,
|
|
20
|
+
Subscription,
|
|
21
|
+
groupBy
|
|
22
|
+
} from "rxjs";
|
|
23
|
+
|
|
24
|
+
// libs/form-engine-core/src/helpers/helpers.ts
|
|
25
|
+
function makeRequest(method, url2, headers, body) {
|
|
26
|
+
return new Promise(function(resolve, reject) {
|
|
27
|
+
const xhr = new XMLHttpRequest();
|
|
28
|
+
xhr.open(method, url2, true);
|
|
29
|
+
if (headers) {
|
|
30
|
+
Object.keys(headers).forEach((header) => {
|
|
31
|
+
xhr.setRequestHeader(
|
|
32
|
+
header,
|
|
33
|
+
headers[header]
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
xhr.onload = function() {
|
|
38
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
39
|
+
resolve(xhr.responseText);
|
|
40
|
+
} else {
|
|
41
|
+
reject(xhr.statusText);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
xhr.onerror = function() {
|
|
45
|
+
reject(xhr.statusText);
|
|
46
|
+
};
|
|
47
|
+
xhr.send(JSON.stringify(body) || null);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function extractFieldKeys(expression) {
|
|
51
|
+
const regex3 = /\${(.*?)}/g;
|
|
52
|
+
const extractedValues = [];
|
|
53
|
+
let match;
|
|
54
|
+
while ((match = regex3.exec(expression)) !== null) {
|
|
55
|
+
extractedValues.push(match[1]);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
originFieldKeys: Array.from(
|
|
59
|
+
new Set(extractedValues.map((el) => el.split(".")[0]))
|
|
60
|
+
),
|
|
61
|
+
originPropertyKeys: Array.from(
|
|
62
|
+
new Set(extractedValues.map((el) => el.split(".")[1]))
|
|
63
|
+
)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function traverseObject(obj, path) {
|
|
67
|
+
const result = [];
|
|
68
|
+
for (const key in obj) {
|
|
69
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
70
|
+
const value2 = obj[key];
|
|
71
|
+
if (Array.isArray(value2)) {
|
|
72
|
+
value2.forEach((item, index) => {
|
|
73
|
+
if (typeof item === "object") {
|
|
74
|
+
result.push(
|
|
75
|
+
...traverseObject(
|
|
76
|
+
item,
|
|
77
|
+
`${path ? `${path}.` : ``}${key}.${index}`
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
} else if (typeof item === "string") {
|
|
81
|
+
if (String(item).includes("$")) {
|
|
82
|
+
const extractedOriginPath = `${path ? `${path}.` : ``}${key}`.split(".");
|
|
83
|
+
result.push({
|
|
84
|
+
originExpression: item,
|
|
85
|
+
// originFieldKeys: extractFieldKeys(item),
|
|
86
|
+
...extractFieldKeys(item),
|
|
87
|
+
destinationKey: extractedOriginPath[0],
|
|
88
|
+
destinationProperty: extractedOriginPath[1],
|
|
89
|
+
destinationPath: extractedOriginPath.slice(2)
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
} else if (typeof value2 === "object") {
|
|
95
|
+
result.push(
|
|
96
|
+
...traverseObject(value2, `${path ? `${path}.` : ``}${key}`)
|
|
97
|
+
);
|
|
98
|
+
} else if (typeof value2 === "string") {
|
|
99
|
+
if (value2.includes("$")) {
|
|
100
|
+
const destinationPath = `${path ? `${path}.` : ``}${key}`.split(".");
|
|
101
|
+
result.push({
|
|
102
|
+
originExpression: value2,
|
|
103
|
+
...extractFieldKeys(value2),
|
|
104
|
+
destinationKey: destinationPath[0],
|
|
105
|
+
destinationProperty: destinationPath[1],
|
|
106
|
+
destinationPath: destinationPath.slice(2)
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// libs/form-engine-core/src/formatters/splitter.ts
|
|
116
|
+
var splitter = (value2, formatters2) => {
|
|
117
|
+
if (!value2 || !formatters2.splitter || typeof value2 !== "string")
|
|
118
|
+
return value2;
|
|
119
|
+
formatters2.splitter.sort((a, b) => a.position - b.position);
|
|
120
|
+
let result = value2;
|
|
121
|
+
let offset = 0;
|
|
122
|
+
for (const splitter2 of formatters2.splitter) {
|
|
123
|
+
const { position, value: value3 } = splitter2;
|
|
124
|
+
const adjustedPosition = position + offset;
|
|
125
|
+
if (adjustedPosition >= 0 && adjustedPosition <= result.length) {
|
|
126
|
+
result = result.slice(0, adjustedPosition) + value3 + result.slice(adjustedPosition);
|
|
127
|
+
offset += value3.length;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// libs/form-engine-core/src/formatters/string.ts
|
|
134
|
+
var capitalize = (value2) => String(value2).charAt(0).toUpperCase() + String(value2).slice(1);
|
|
135
|
+
var uppercase = (value2) => String(value2).toUpperCase();
|
|
136
|
+
var onlyFloatNumber = (value2, formatters2) => {
|
|
137
|
+
const { onlyFloatNumber: onlyFloatNumber2 } = formatters2;
|
|
138
|
+
if (!onlyFloatNumber2 || typeof value2 !== "string" || !value2)
|
|
139
|
+
return value2;
|
|
140
|
+
const { precision = 2, decimal = "." } = onlyFloatNumber2;
|
|
141
|
+
if (!value2.includes(decimal)) {
|
|
142
|
+
return value2;
|
|
143
|
+
}
|
|
144
|
+
const replacedValue = value2.replace(/[^0-9]/g, "");
|
|
145
|
+
const partOf = replacedValue.slice(0, replacedValue.length - precision);
|
|
146
|
+
const sliceOf = replacedValue.slice(replacedValue.length - precision);
|
|
147
|
+
return parseFloat(`${partOf}.${sliceOf}`).toFixed(precision);
|
|
148
|
+
};
|
|
149
|
+
var trim = (value2, formatters2) => {
|
|
150
|
+
if (!value2 || formatters2?.trim)
|
|
151
|
+
return value2;
|
|
152
|
+
return String(value2).trim();
|
|
153
|
+
};
|
|
154
|
+
var maxLength = (value2, formatters2) => {
|
|
155
|
+
if (!value2 || !formatters2.maxLength)
|
|
156
|
+
return value2;
|
|
157
|
+
const input = String(value2);
|
|
158
|
+
if (input.length > formatters2.maxLength) {
|
|
159
|
+
return input.substring(0, formatters2.maxLength);
|
|
160
|
+
}
|
|
161
|
+
return value2;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// libs/form-engine-core/src/formatters/regex.ts
|
|
165
|
+
var onlyNumbers = (value2) => String(value2).replace(/(\D)+/gim, "");
|
|
166
|
+
var onlyLetters = (value2) => String(value2).replace(/[^\p{L}\s]/gu, "");
|
|
167
|
+
var regex = (value2, formatters2) => {
|
|
168
|
+
if (!formatters2.regex)
|
|
169
|
+
return value2;
|
|
170
|
+
return String(value2).replace(new RegExp(formatters2.regex, "g"), "");
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// libs/form-engine-core/src/helpers/creditCard.ts
|
|
174
|
+
import creditCardType from "credit-card-type";
|
|
175
|
+
var getTypeCard = (value2, availableOptions) => {
|
|
176
|
+
const rawValue = removeGaps(value2?.toString());
|
|
177
|
+
const types = creditCardType(rawValue);
|
|
178
|
+
const selected = availableOptions?.length ? types?.filter(
|
|
179
|
+
({ type: id1 }) => availableOptions.some((id2) => id2 === id1)
|
|
180
|
+
)[0] : types[0];
|
|
181
|
+
return [selected, rawValue];
|
|
182
|
+
};
|
|
183
|
+
var removeGaps = (value2) => value2?.replace(/ /g, "");
|
|
184
|
+
var addGaps = (value2, gaps = []) => {
|
|
185
|
+
const [regexString, replaceString] = gaps.reduce(
|
|
186
|
+
([regexString2, replaceString2], offset, i) => {
|
|
187
|
+
const lastOffset = gaps[i - 1] || 0;
|
|
188
|
+
const digitNumber = offset - lastOffset;
|
|
189
|
+
return [
|
|
190
|
+
`${regexString2}([0-9]{0,${digitNumber}})`,
|
|
191
|
+
`${replaceString2}$${i + 1} `
|
|
192
|
+
];
|
|
193
|
+
},
|
|
194
|
+
["", ""]
|
|
195
|
+
);
|
|
196
|
+
return value2.replace(new RegExp(regexString), replaceString).trim();
|
|
197
|
+
};
|
|
198
|
+
var formatValue = (value2, type) => {
|
|
199
|
+
const DEFAULT_LENGTH = 19;
|
|
200
|
+
return type ? addGaps(value2.slice(0, type?.lengths[0]), type.gaps) : value2?.slice(0, DEFAULT_LENGTH);
|
|
201
|
+
};
|
|
202
|
+
var formatDateCard = (value2, end = 4, prefix = "/") => {
|
|
203
|
+
const fixedValue = value2.replace(/\D/g, "");
|
|
204
|
+
const valZeroTwo = fixedValue.slice(0, 2);
|
|
205
|
+
return fixedValue.length >= 5 ? `${valZeroTwo}${prefix}${fixedValue.slice(2, end)}` : fixedValue.length >= 3 ? `${valZeroTwo}${prefix}${fixedValue.slice(2)}` : fixedValue;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// libs/form-engine-core/src/formatters/creditCard.ts
|
|
209
|
+
var gapsCreditCard = (value2, formatters2) => {
|
|
210
|
+
if (!formatters2.gapsCreditCard)
|
|
211
|
+
return value2;
|
|
212
|
+
const [type, rawValue] = getTypeCard(
|
|
213
|
+
value2,
|
|
214
|
+
formatters2?.gapsCreditCard
|
|
215
|
+
);
|
|
216
|
+
return formatValue(rawValue, type);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// libs/form-engine-core/src/formatters/custom.ts
|
|
220
|
+
var callback = (value2, formatters2) => {
|
|
221
|
+
if (!formatters2?.callback)
|
|
222
|
+
return value2;
|
|
223
|
+
return formatters2.callback(value2);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// libs/form-engine-core/src/formatters/handler.ts
|
|
227
|
+
var formatters = {
|
|
228
|
+
capitalize,
|
|
229
|
+
uppercase,
|
|
230
|
+
onlyNumbers,
|
|
231
|
+
onlyLetters,
|
|
232
|
+
regex,
|
|
233
|
+
splitter,
|
|
234
|
+
maxLength,
|
|
235
|
+
onlyFloatNumber,
|
|
236
|
+
trim,
|
|
237
|
+
gapsCreditCard,
|
|
238
|
+
callback,
|
|
239
|
+
// todo: to be removed
|
|
240
|
+
dotEvery3chars: (value2) => {
|
|
241
|
+
const result = String(value2).replace(/\./g, "").replace(/(.{3})/g, "$1.");
|
|
242
|
+
return result.endsWith(".") ? result.slice(0, -1) : result;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// libs/form-engine-core/src/masks/generic.ts
|
|
247
|
+
var generic_default = (value2, masks2) => {
|
|
248
|
+
if (!masks2?.generic)
|
|
249
|
+
return value2;
|
|
250
|
+
let masked = value2;
|
|
251
|
+
masks2.generic.forEach((item) => {
|
|
252
|
+
const { to = masked.length, mask } = item;
|
|
253
|
+
let { from } = item;
|
|
254
|
+
if (to > value2.length - 1)
|
|
255
|
+
return;
|
|
256
|
+
if (from === 0) {
|
|
257
|
+
from = 1;
|
|
258
|
+
}
|
|
259
|
+
const maskedPortion = new Array(to - from + 2).join(mask);
|
|
260
|
+
masked = masked.slice(0, from - 1) + maskedPortion + masked.slice(to);
|
|
261
|
+
});
|
|
262
|
+
return masked;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// libs/form-engine-core/src/masks/string.ts
|
|
266
|
+
import { isNumber } from "lodash";
|
|
267
|
+
import { getCurrencySymbol } from "@gaignoux/currency";
|
|
268
|
+
var replaceAll = (value2, masks2) => {
|
|
269
|
+
let targetReplaceMask = masks2.replaceAll;
|
|
270
|
+
if (!targetReplaceMask)
|
|
271
|
+
return value2;
|
|
272
|
+
if (typeof targetReplaceMask === "number") {
|
|
273
|
+
targetReplaceMask = targetReplaceMask?.toString();
|
|
274
|
+
}
|
|
275
|
+
return new Array(String(value2).length + 1).join(targetReplaceMask);
|
|
276
|
+
};
|
|
277
|
+
var currency = (value2, masks2) => {
|
|
278
|
+
if (!masks2?.currency)
|
|
279
|
+
return value2;
|
|
280
|
+
const {
|
|
281
|
+
align = "right",
|
|
282
|
+
decimal = ".",
|
|
283
|
+
precision = 2,
|
|
284
|
+
prefix = "BBD",
|
|
285
|
+
thousands = ","
|
|
286
|
+
} = masks2.currency;
|
|
287
|
+
const rawValue = isNumber(value2) ? Number(value2).toFixed(precision) : value2;
|
|
288
|
+
let convertedValue = rawValue.replace(/[^0-9]/g, "");
|
|
289
|
+
if (!convertedValue) {
|
|
290
|
+
return "";
|
|
291
|
+
}
|
|
292
|
+
let integerPart = convertedValue.slice(0, convertedValue.length - precision).replace(/^0*/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, thousands);
|
|
293
|
+
if (integerPart === "") {
|
|
294
|
+
integerPart = "0";
|
|
295
|
+
}
|
|
296
|
+
console.log("Before", { convertedValue });
|
|
297
|
+
if (align === "right" && String(value2).endsWith(" ")) {
|
|
298
|
+
convertedValue = convertedValue.slice(0, -1);
|
|
299
|
+
}
|
|
300
|
+
console.log("After", { value: value2, convertedValue });
|
|
301
|
+
let newRawValue = integerPart;
|
|
302
|
+
let decimalPart = convertedValue.slice(convertedValue.length - precision);
|
|
303
|
+
if (precision > 0) {
|
|
304
|
+
decimalPart = "0".repeat(precision - decimalPart.length) + decimalPart;
|
|
305
|
+
newRawValue += decimal + decimalPart;
|
|
306
|
+
}
|
|
307
|
+
const symbol = getCurrencySymbol(prefix);
|
|
308
|
+
return align === "left" ? `${symbol} ${newRawValue}` : `${newRawValue} ${symbol}`;
|
|
309
|
+
};
|
|
310
|
+
var custom = (value2, masks2) => {
|
|
311
|
+
if (!masks2.custom || !value2)
|
|
312
|
+
return value2;
|
|
313
|
+
let mask = "";
|
|
314
|
+
let index = 0;
|
|
315
|
+
for (let i = 0; i < masks2.custom.length; i++) {
|
|
316
|
+
if (masks2.custom[i] === "#") {
|
|
317
|
+
if (index < value2.length) {
|
|
318
|
+
mask += value2[index];
|
|
319
|
+
index++;
|
|
320
|
+
} else {
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
mask += masks2.custom[i];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return mask;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// libs/form-engine-core/src/masks/creditCard.ts
|
|
331
|
+
var secureCreditCard = (value2) => {
|
|
332
|
+
const maskValue = [
|
|
333
|
+
{
|
|
334
|
+
from: 1,
|
|
335
|
+
to: 4,
|
|
336
|
+
mask: "x"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
from: 6,
|
|
340
|
+
to: 9,
|
|
341
|
+
mask: "x"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
from: 11,
|
|
345
|
+
to: 14,
|
|
346
|
+
mask: "x"
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
from: 16,
|
|
350
|
+
to: 19,
|
|
351
|
+
mask: "x"
|
|
352
|
+
}
|
|
353
|
+
];
|
|
354
|
+
return generic_default(value2, { generic: maskValue });
|
|
355
|
+
};
|
|
356
|
+
var card = (value2) => {
|
|
357
|
+
return value2.replace(/[^\dA-Z]/g, "").replace(/(.{4})/g, "$1 ").trim();
|
|
358
|
+
};
|
|
359
|
+
var cardDate = (value2) => formatDateCard(value2);
|
|
360
|
+
var fein = (value2) => formatDateCard(value2, 9, "-");
|
|
361
|
+
|
|
362
|
+
// libs/form-engine-core/src/masks/handler.ts
|
|
363
|
+
var masks = {
|
|
364
|
+
currency,
|
|
365
|
+
custom,
|
|
366
|
+
callback: (value2, masks2) => masks2?.callback && masks2.callback(value2),
|
|
367
|
+
generic: generic_default,
|
|
368
|
+
secureCreditCard,
|
|
369
|
+
card,
|
|
370
|
+
cardDate,
|
|
371
|
+
fein,
|
|
372
|
+
replaceAll
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// libs/form-engine-core/src/validations/length.ts
|
|
376
|
+
var length_default = (value2, validations3) => {
|
|
377
|
+
if (!validations3.length || !value2)
|
|
378
|
+
return false;
|
|
379
|
+
let targetValue = value2;
|
|
380
|
+
if (typeof targetValue !== "string") {
|
|
381
|
+
targetValue = value2?.toString() || targetValue;
|
|
382
|
+
}
|
|
383
|
+
const condition = {
|
|
384
|
+
equal: targetValue.length !== validations3.length.target,
|
|
385
|
+
notEqual: targetValue.length === validations3.length.target,
|
|
386
|
+
less: targetValue.length >= validations3.length.target,
|
|
387
|
+
lessOrEqual: targetValue.length > validations3.length.target,
|
|
388
|
+
greater: targetValue.length <= validations3.length.target,
|
|
389
|
+
greaterOrEqual: targetValue.length < validations3.length.target
|
|
390
|
+
};
|
|
391
|
+
return condition[validations3.length.rule];
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// libs/form-engine-core/src/validations/document.ts
|
|
395
|
+
var NIF_ES = (value2) => {
|
|
396
|
+
if (value2.length !== 9)
|
|
397
|
+
return true;
|
|
398
|
+
if (!/^\d{8}$/.test(value2.slice(0, 8))) {
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
const validLetters = "TRWAGMYFPDXBNJZSQVHLCKE";
|
|
402
|
+
const numberPart = parseInt(value2.slice(0, 8), 10);
|
|
403
|
+
const expectedLetter = validLetters[numberPart % 23];
|
|
404
|
+
return !(value2[8].toUpperCase() === expectedLetter);
|
|
405
|
+
};
|
|
406
|
+
var NIF_PT = (value2) => {
|
|
407
|
+
const regex3 = /^\d{9}$/;
|
|
408
|
+
if (!regex3.test(value2))
|
|
409
|
+
return false;
|
|
410
|
+
const checkDigit = parseInt(value2[8], 10);
|
|
411
|
+
const sum = Array.from(value2.substring(0, 8)).reduce(
|
|
412
|
+
(acc, digit, index) => acc + parseInt(digit, 10) * (9 - index),
|
|
413
|
+
0
|
|
414
|
+
);
|
|
415
|
+
const calculatedCheckDigit = 11 - sum % 11;
|
|
416
|
+
return calculatedCheckDigit === 10 || calculatedCheckDigit === 11 ? 0 === checkDigit : calculatedCheckDigit === checkDigit;
|
|
417
|
+
};
|
|
418
|
+
var NIF_IT = (value2) => {
|
|
419
|
+
const regex3 = /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/;
|
|
420
|
+
return regex3.test(value2);
|
|
421
|
+
};
|
|
422
|
+
var NIF_DE = (nif) => {
|
|
423
|
+
const regex3 = /^\d{11}$/;
|
|
424
|
+
return regex3.test(nif);
|
|
425
|
+
};
|
|
426
|
+
var NIF_FR = (nif) => {
|
|
427
|
+
const regex3 = /^\d{2} \d{3} \d{3} \d{3} \d{3}$/;
|
|
428
|
+
return regex3.test(nif);
|
|
429
|
+
};
|
|
430
|
+
var NIF_UK = (value2) => {
|
|
431
|
+
const regex3 = /^GB\d{9}|\d{12}|\d{3}[A-Z]{5}$/;
|
|
432
|
+
return regex3.test(value2);
|
|
433
|
+
};
|
|
434
|
+
var NIF_BE = (value2) => {
|
|
435
|
+
const regex3 = /^\d{11}$/;
|
|
436
|
+
if (!regex3.test(value2))
|
|
437
|
+
return false;
|
|
438
|
+
const number = parseInt(value2.substring(0, 9), 10);
|
|
439
|
+
const checkDigits = parseInt(value2.substring(9), 10);
|
|
440
|
+
const mod = 97 - number % 97;
|
|
441
|
+
return mod === checkDigits;
|
|
442
|
+
};
|
|
443
|
+
var NIF_NL = (value2) => {
|
|
444
|
+
const regex3 = /^\d{9}$/;
|
|
445
|
+
if (!regex3.test(value2))
|
|
446
|
+
return false;
|
|
447
|
+
const total = value2.split("").map((digit, index) => parseInt(digit, 10) * (9 - index)).reduce((sum, val) => sum + val, 0);
|
|
448
|
+
return total % 11 === 0;
|
|
449
|
+
};
|
|
450
|
+
var NIF_SE = (value2) => {
|
|
451
|
+
const regex3 = /^\d{10,12}$/;
|
|
452
|
+
if (!regex3.test(value2))
|
|
453
|
+
return false;
|
|
454
|
+
const normalizedNIF = value2.length === 12 ? value2.substring(2) : value2;
|
|
455
|
+
const total = normalizedNIF.split("").map((digit, index) => {
|
|
456
|
+
let num = parseInt(digit, 10) * (index % 2 === 0 ? 2 : 1);
|
|
457
|
+
if (num > 9)
|
|
458
|
+
num -= 9;
|
|
459
|
+
return num;
|
|
460
|
+
}).reduce((sum, val) => sum + val, 0);
|
|
461
|
+
return total % 10 === 0;
|
|
462
|
+
};
|
|
463
|
+
var NIF = (nif, locale) => {
|
|
464
|
+
switch (locale) {
|
|
465
|
+
case "pt-PT":
|
|
466
|
+
return NIF_PT(nif);
|
|
467
|
+
case "es-ES":
|
|
468
|
+
return NIF_ES(nif);
|
|
469
|
+
case "it-IT":
|
|
470
|
+
return NIF_IT(nif);
|
|
471
|
+
case "de-DE":
|
|
472
|
+
return NIF_DE(nif);
|
|
473
|
+
case "fr-FR":
|
|
474
|
+
return NIF_FR(nif);
|
|
475
|
+
case "en-GB":
|
|
476
|
+
return NIF_UK(nif);
|
|
477
|
+
case "nl-BE":
|
|
478
|
+
case "fr-BE":
|
|
479
|
+
return NIF_BE(nif);
|
|
480
|
+
case "nl-NL":
|
|
481
|
+
return NIF_NL(nif);
|
|
482
|
+
case "sv-SE":
|
|
483
|
+
return NIF_SE(nif);
|
|
484
|
+
default:
|
|
485
|
+
throw new Error(`NIF validation not supported for locale: ${locale}`);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
var NIE = (value2) => {
|
|
489
|
+
if (value2.length !== 9)
|
|
490
|
+
return true;
|
|
491
|
+
const nieRegex = /^[XYZ]\d{7}[TRWAGMYFPDXBNJZSQVHLCKE]$/;
|
|
492
|
+
if (!nieRegex.test(value2)) {
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
let fixedDocNumber = value2.toUpperCase().padStart(9, "0");
|
|
496
|
+
fixedDocNumber = fixedDocNumber[0].replace(/[XYZ]/g, (char) => {
|
|
497
|
+
return { X: "0", Y: "1", Z: "2" }[char] || char;
|
|
498
|
+
}) + fixedDocNumber.slice(1);
|
|
499
|
+
return NIF_ES(fixedDocNumber);
|
|
500
|
+
};
|
|
501
|
+
var mod9710 = (validationString) => {
|
|
502
|
+
while (validationString.length > 2) {
|
|
503
|
+
const part = validationString.slice(0, 6);
|
|
504
|
+
const partInt = parseInt(part, 10);
|
|
505
|
+
if (isNaN(partInt)) {
|
|
506
|
+
return NaN;
|
|
507
|
+
}
|
|
508
|
+
validationString = partInt % 97 + validationString.slice(part.length);
|
|
509
|
+
}
|
|
510
|
+
return parseInt(validationString, 10) % 97;
|
|
511
|
+
};
|
|
512
|
+
var IBAN = (value2) => {
|
|
513
|
+
const iban = value2.replace(/\s/g, "");
|
|
514
|
+
if (iban.length !== 24)
|
|
515
|
+
return true;
|
|
516
|
+
const ibanRegex = /^(ES)[0-9]{22}$/;
|
|
517
|
+
if (!ibanRegex.test(iban)) {
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
const ES_ALPHABET_NUMBER = 1428;
|
|
521
|
+
const transformedIban = iban.substring(4) + ES_ALPHABET_NUMBER + iban.substring(2, 4);
|
|
522
|
+
return mod9710(transformedIban) !== 1;
|
|
523
|
+
};
|
|
524
|
+
var CIF = (value2) => {
|
|
525
|
+
const cifRegex = /^[A-Z][0-9]{7}[A-J0-9]$/;
|
|
526
|
+
return !cifRegex.test(value2);
|
|
527
|
+
};
|
|
528
|
+
var document_default = (value2, validations3) => {
|
|
529
|
+
if (!value2 || !validations3.document)
|
|
530
|
+
return true;
|
|
531
|
+
const validation = {
|
|
532
|
+
NIF: (value3, locale) => NIF(value3, locale),
|
|
533
|
+
NIE: (value3) => NIE(value3),
|
|
534
|
+
CIF: (value3) => CIF(value3),
|
|
535
|
+
IBAN: (value3) => IBAN(value3)
|
|
536
|
+
};
|
|
537
|
+
return validation[validations3.document.type](
|
|
538
|
+
value2,
|
|
539
|
+
validations3.document.locale
|
|
540
|
+
);
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
// libs/form-engine-core/src/validations/number.ts
|
|
544
|
+
var max = (value2, validations3) => {
|
|
545
|
+
const number = Number(value2);
|
|
546
|
+
if (!validations3.max || Number.isNaN(number))
|
|
547
|
+
return false;
|
|
548
|
+
return number > Number(validations3.max);
|
|
549
|
+
};
|
|
550
|
+
var min = (value2, validations3) => {
|
|
551
|
+
const number = Number(value2);
|
|
552
|
+
if (!validations3.min || Number.isNaN(number))
|
|
553
|
+
return false;
|
|
554
|
+
return number < Number(validations3.min);
|
|
555
|
+
};
|
|
556
|
+
var between = (value2, validations3) => {
|
|
557
|
+
if (!validations3.between || !value2)
|
|
558
|
+
return false;
|
|
559
|
+
const num = Number(value2);
|
|
560
|
+
return !Number.isNaN(num) && !(+num >= validations3.between.start && +num <= validations3.between.end);
|
|
561
|
+
};
|
|
562
|
+
var sequential = (value2, validations3) => {
|
|
563
|
+
if (!validations3.sequential)
|
|
564
|
+
return false;
|
|
565
|
+
const numbers = "0123456789";
|
|
566
|
+
const numbersRev = "9876543210";
|
|
567
|
+
const replacedValue = String(value2).replace(/[^0-9]/g, "");
|
|
568
|
+
return !(numbers.indexOf(replacedValue) === -1 && numbersRev.indexOf(replacedValue) === -1);
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
// libs/form-engine-core/src/validations/regex.ts
|
|
572
|
+
var regex2 = (value2, validations3) => {
|
|
573
|
+
if (!validations3.regex || !value2)
|
|
574
|
+
return false;
|
|
575
|
+
const regex3 = new RegExp(validations3.regex);
|
|
576
|
+
return !regex3.test(value2);
|
|
577
|
+
};
|
|
578
|
+
var email = (value2, validations3) => {
|
|
579
|
+
if (!validations3.email || !value2)
|
|
580
|
+
return false;
|
|
581
|
+
const regex3 = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
582
|
+
return !regex3.test(value2);
|
|
583
|
+
};
|
|
584
|
+
var url = (value2, validations3) => {
|
|
585
|
+
if (!validations3.url || !value2)
|
|
586
|
+
return false;
|
|
587
|
+
const regex3 = /[(http(s)?)://(www.)?a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi;
|
|
588
|
+
return !regex3.test(value2);
|
|
589
|
+
};
|
|
590
|
+
var onlyLetters2 = (value2, validations3) => {
|
|
591
|
+
if (!validations3.onlyLetters)
|
|
592
|
+
return false;
|
|
593
|
+
return !/^[\p{L}\s]*$/u.test(value2);
|
|
594
|
+
};
|
|
595
|
+
var notAllowSpaces = (value2, validations3) => {
|
|
596
|
+
if (!validations3.notAllowSpaces)
|
|
597
|
+
return false;
|
|
598
|
+
return /\s/.test(value2);
|
|
599
|
+
};
|
|
600
|
+
var isNumber2 = (value2, validations3) => {
|
|
601
|
+
if (!validations3.isNumber)
|
|
602
|
+
return false;
|
|
603
|
+
return !!value2 && !/^[0-9\s]*$/.test(value2);
|
|
604
|
+
};
|
|
605
|
+
var hasNoExtraSpaces = (value2, validations3) => {
|
|
606
|
+
if (!validations3.hasNoExtraSpaces || !value2)
|
|
607
|
+
return false;
|
|
608
|
+
return regex2(value2, {
|
|
609
|
+
regex: "^[A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\xE4\xF6\xFC\xC4\xD6\xDC\xDF0-9]+$"
|
|
610
|
+
});
|
|
611
|
+
};
|
|
612
|
+
var repeated = (value2, validations3) => {
|
|
613
|
+
if (!validations3.repeated)
|
|
614
|
+
return false;
|
|
615
|
+
const numCount = {};
|
|
616
|
+
for (const char of String(value2)) {
|
|
617
|
+
if (/\d/.test(char)) {
|
|
618
|
+
if (numCount[char]) {
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
numCount[char] = 1;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return false;
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
// libs/form-engine-core/src/validations/custom.ts
|
|
628
|
+
var callback2 = (value2, validations3) => {
|
|
629
|
+
if (!validations3.callback || !(validations3?.callback instanceof Function))
|
|
630
|
+
return false;
|
|
631
|
+
return validations3.callback(value2);
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
// libs/form-engine-core/src/validations/list.ts
|
|
635
|
+
var includes = (value2, validations3) => {
|
|
636
|
+
if (!value2 || !Array.isArray(validations3?.includes))
|
|
637
|
+
return false;
|
|
638
|
+
return !validations3.includes.some(
|
|
639
|
+
(code) => code === value2 || JSON.stringify(code) === value2
|
|
640
|
+
);
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// libs/form-engine-core/src/validations/creditCard.ts
|
|
644
|
+
var isCreditCard = (value2, validations3) => {
|
|
645
|
+
if (!value2)
|
|
646
|
+
return true;
|
|
647
|
+
const [type] = getTypeCard(String(value2), validations3.isCreditCard);
|
|
648
|
+
return !type;
|
|
649
|
+
};
|
|
650
|
+
var isCreditCodeMatch = (value2, validations3) => {
|
|
651
|
+
if (!value2 || !validations3.isCreditCodeMatch)
|
|
652
|
+
return false;
|
|
653
|
+
const [type] = getTypeCard(
|
|
654
|
+
validations3.isCreditCodeMatch.numberCard,
|
|
655
|
+
validations3.isCreditCodeMatch.availableOptions
|
|
656
|
+
);
|
|
657
|
+
return type?.code?.size !== value2.length;
|
|
658
|
+
};
|
|
659
|
+
var isCreditCardAndLength = (value2, validations3) => {
|
|
660
|
+
if (!value2 || !validations3.isCreditCardAndLength)
|
|
661
|
+
return false;
|
|
662
|
+
const [type, rawValue] = getTypeCard(
|
|
663
|
+
value2,
|
|
664
|
+
validations3.isCreditCardAndLength
|
|
665
|
+
);
|
|
666
|
+
return type && !type.lengths.includes(rawValue.length);
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// libs/form-engine-core/src/validations/string.ts
|
|
670
|
+
var notEmpty = (value2, validations3) => {
|
|
671
|
+
if (!validations3?.notEmpty || typeof value2 === "undefined")
|
|
672
|
+
return false;
|
|
673
|
+
return value2 === null || value2 === "" || value2 === 0 || !String(value2)?.trim().length;
|
|
674
|
+
};
|
|
675
|
+
var value = (value2, validations3) => {
|
|
676
|
+
if (typeof validations3?.value === "undefined" || validations3?.value === null || typeof value2 === "undefined" || value2 === null)
|
|
677
|
+
return false;
|
|
678
|
+
return value2 != validations3.value;
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
// libs/form-engine-core/src/validations/logical.ts
|
|
682
|
+
var required = (value2, validations3) => !!(validations3.required && (!value2 || typeof value2 === "string" && value2.trim().length === 0));
|
|
683
|
+
var bool = (_, validations3) => {
|
|
684
|
+
if (!validations3?.bool)
|
|
685
|
+
return false;
|
|
686
|
+
let fail = false;
|
|
687
|
+
if (typeof validations3.bool === "boolean") {
|
|
688
|
+
fail = validations3.bool;
|
|
689
|
+
}
|
|
690
|
+
return fail;
|
|
691
|
+
};
|
|
692
|
+
var exists = (value2, validations3) => {
|
|
693
|
+
if (!validations3.exists)
|
|
694
|
+
return false;
|
|
695
|
+
let fail = !validations3.exists;
|
|
696
|
+
if (!fail) {
|
|
697
|
+
fail = !value2;
|
|
698
|
+
}
|
|
699
|
+
return fail;
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
// libs/form-engine-core/src/validations/object.ts
|
|
703
|
+
var conditionResult = (value2, rule) => {
|
|
704
|
+
if (rule.forceDefinedOrigin && rule.origin === void 0 || rule.forceDefinedTarget && rule.target === void 0) {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
const origin = rule.origin === void 0 ? value2 : rule.origin;
|
|
708
|
+
const target = rule.target === void 0 ? value2 : rule.target;
|
|
709
|
+
const conditionMapper = {
|
|
710
|
+
"!==": (origin || value2) !== (target || value2),
|
|
711
|
+
"===": (origin || value2) === (target || value2),
|
|
712
|
+
"<": (origin || value2) < (target || value2),
|
|
713
|
+
">": (origin || value2) > (target || value2),
|
|
714
|
+
"<=": (origin || value2) <= (target || value2),
|
|
715
|
+
">=": (origin || value2) >= (target || value2),
|
|
716
|
+
"!!origin": !!String(origin || value2).trim().length
|
|
717
|
+
};
|
|
718
|
+
return conditionMapper[rule.condition];
|
|
719
|
+
};
|
|
720
|
+
var conditions = (value2, validations3) => {
|
|
721
|
+
if (!validations3.conditions)
|
|
722
|
+
return false;
|
|
723
|
+
const rulesMapper = {
|
|
724
|
+
and: () => !!validations3.conditions?.set.every(
|
|
725
|
+
(validate) => conditionResult(value2, validate)
|
|
726
|
+
),
|
|
727
|
+
or: () => !!validations3.conditions?.set.some(
|
|
728
|
+
(validate) => conditionResult(value2, validate)
|
|
729
|
+
)
|
|
730
|
+
};
|
|
731
|
+
let result = rulesMapper[validations3.conditions.rule]();
|
|
732
|
+
if (validations3.conditions.conditions) {
|
|
733
|
+
if (validations3.conditions.rule === "and") {
|
|
734
|
+
result = result && conditions(value2, {
|
|
735
|
+
conditions: validations3.conditions.conditions
|
|
736
|
+
});
|
|
737
|
+
} else {
|
|
738
|
+
result = result || conditions(value2, {
|
|
739
|
+
conditions: validations3.conditions.conditions
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return !result;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
// libs/form-engine-core/src/validations/date.ts
|
|
747
|
+
var betweenDates = (value2, validations3) => {
|
|
748
|
+
let fail = false;
|
|
749
|
+
if (validations3.betweenDates?.length != 2)
|
|
750
|
+
return false;
|
|
751
|
+
for (const validation of validations3.betweenDates) {
|
|
752
|
+
if (date(value2, { date: validation })) {
|
|
753
|
+
fail = true;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
return fail;
|
|
758
|
+
};
|
|
759
|
+
var getIntervalsDate = (date2, intervals) => {
|
|
760
|
+
const intervalsMapper = {
|
|
761
|
+
years: (date3, value2) => new Date(date3.setUTCFullYear(date3.getUTCFullYear() + value2)),
|
|
762
|
+
months: (date3, value2) => new Date(date3.setUTCMonth(date3.getUTCMonth() + value2)),
|
|
763
|
+
days: (date3, value2) => new Date(date3.setDate(date3.getUTCDate() + value2))
|
|
764
|
+
};
|
|
765
|
+
return Object.keys(intervals).reduce(
|
|
766
|
+
(acc, interval) => intervalsMapper[interval](acc, intervals[interval]),
|
|
767
|
+
new Date(date2)
|
|
768
|
+
);
|
|
769
|
+
};
|
|
770
|
+
var dateRearrangeMapper = {
|
|
771
|
+
DDMMYYYY: (value2) => {
|
|
772
|
+
const dateParts = value2.split(value2.includes("/") ? "/" : "-");
|
|
773
|
+
return `${dateParts[1]}/${dateParts[0]}/${dateParts[2]}`;
|
|
774
|
+
},
|
|
775
|
+
YYYYMMDD: (value2) => {
|
|
776
|
+
const dateParts = value2.split(value2.includes("/") ? "/" : "-");
|
|
777
|
+
return `${dateParts[1]}/${dateParts[2]}/${dateParts[0]}`;
|
|
778
|
+
},
|
|
779
|
+
YYYYDDMM: (value2) => {
|
|
780
|
+
const dateParts = value2.split(value2.includes("/") ? "/" : "-");
|
|
781
|
+
return `${dateParts[2]}/${dateParts[1]}/${dateParts[0]}`;
|
|
782
|
+
},
|
|
783
|
+
MMDDYYYY: (value2) => value2,
|
|
784
|
+
timestamp: (value2) => new Date(value2).toString()
|
|
785
|
+
};
|
|
786
|
+
var date = (value2, validations3) => {
|
|
787
|
+
if (!validations3.date?.target?.value && !validations3.date?.origin?.intervals) {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
const originValue = validations3.date.origin.value || value2;
|
|
791
|
+
let originDate = new Date(
|
|
792
|
+
dateRearrangeMapper[validations3.date?.origin.format](originValue).toString()
|
|
793
|
+
);
|
|
794
|
+
let targetDate = /* @__PURE__ */ new Date();
|
|
795
|
+
let target = /* @__PURE__ */ new Date();
|
|
796
|
+
if (validations3.date?.target?.format) {
|
|
797
|
+
target = new Date(
|
|
798
|
+
dateRearrangeMapper[validations3.date?.target?.format](
|
|
799
|
+
validations3.date.target.value
|
|
800
|
+
).toString()
|
|
801
|
+
);
|
|
802
|
+
targetDate = target;
|
|
803
|
+
}
|
|
804
|
+
if (validations3.date.origin.intervals) {
|
|
805
|
+
targetDate = getIntervalsDate(
|
|
806
|
+
originDate,
|
|
807
|
+
validations3.date.origin.intervals
|
|
808
|
+
);
|
|
809
|
+
const date2 = /* @__PURE__ */ new Date();
|
|
810
|
+
if (validations3.date.target?.value && target) {
|
|
811
|
+
date2.setDate(target.getDate());
|
|
812
|
+
date2.setMonth(target.getMonth());
|
|
813
|
+
}
|
|
814
|
+
originDate = /* @__PURE__ */ new Date(
|
|
815
|
+
`${date2.getUTCMonth() + 1}/${date2.getUTCDate()}/${date2.getUTCFullYear()}`
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
if (validations3.date.onlyValidDate && (!(targetDate instanceof Date && isFinite(targetDate)) || !(targetDate instanceof Date && isFinite(originDate)) || originValue.length < 8)) {
|
|
819
|
+
return true;
|
|
820
|
+
}
|
|
821
|
+
const originTimestamp = originDate.getTime();
|
|
822
|
+
const targetTimestamp = targetDate.getTime();
|
|
823
|
+
const operationsMapper = {
|
|
824
|
+
">": originTimestamp > targetTimestamp,
|
|
825
|
+
">=": originTimestamp >= targetTimestamp,
|
|
826
|
+
"<": originTimestamp < targetTimestamp,
|
|
827
|
+
"<=": originTimestamp <= targetTimestamp,
|
|
828
|
+
"===": originTimestamp === targetTimestamp,
|
|
829
|
+
"!==": originTimestamp !== targetTimestamp
|
|
830
|
+
};
|
|
831
|
+
return operationsMapper[validations3.date?.operator];
|
|
832
|
+
};
|
|
833
|
+
var validDate = (value2, validations3) => {
|
|
834
|
+
if (!validations3.validDate || !value2)
|
|
835
|
+
return false;
|
|
836
|
+
if (/[^a-zA-Z0-9\s-]/.test(value2))
|
|
837
|
+
return true;
|
|
838
|
+
const dateParts = dateRearrangeMapper[validations3.validDate](value2).toString().split(/[/-]/);
|
|
839
|
+
const year = parseInt(dateParts[2], 10);
|
|
840
|
+
const month = parseInt(dateParts[0], 10) - 1;
|
|
841
|
+
const day = parseInt(dateParts[1], 10);
|
|
842
|
+
const date2 = new Date(year, month, day);
|
|
843
|
+
const isValidDate = date2.getFullYear() === year && date2.getMonth() === month && date2.getDate() === day;
|
|
844
|
+
return !isValidDate;
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
// libs/form-engine-core/src/validations/multiple.ts
|
|
848
|
+
var validations = {
|
|
849
|
+
max,
|
|
850
|
+
min,
|
|
851
|
+
length: length_default,
|
|
852
|
+
regex: regex2,
|
|
853
|
+
url,
|
|
854
|
+
email,
|
|
855
|
+
onlyLetters: onlyLetters2,
|
|
856
|
+
notAllowSpaces,
|
|
857
|
+
callback: callback2,
|
|
858
|
+
hasNoExtraSpaces,
|
|
859
|
+
between,
|
|
860
|
+
sequential,
|
|
861
|
+
includes,
|
|
862
|
+
repeated,
|
|
863
|
+
document: document_default,
|
|
864
|
+
isCreditCard,
|
|
865
|
+
isCreditCodeMatch,
|
|
866
|
+
isCreditCardAndLength,
|
|
867
|
+
required,
|
|
868
|
+
value,
|
|
869
|
+
notEmpty,
|
|
870
|
+
bool,
|
|
871
|
+
exists,
|
|
872
|
+
greaterThan: () => true,
|
|
873
|
+
isNumber: isNumber2,
|
|
874
|
+
conditions,
|
|
875
|
+
validDate,
|
|
876
|
+
date,
|
|
877
|
+
betweenDates
|
|
878
|
+
};
|
|
879
|
+
var run = (value2, handlers) => {
|
|
880
|
+
const runner = [];
|
|
881
|
+
Object.keys(handlers).forEach((rule) => {
|
|
882
|
+
runner.push(
|
|
883
|
+
validations[rule](value2, {
|
|
884
|
+
[rule]: handlers[rule]
|
|
885
|
+
})
|
|
886
|
+
);
|
|
887
|
+
});
|
|
888
|
+
return runner;
|
|
889
|
+
};
|
|
890
|
+
var multipleValidations = (value2, validations3) => {
|
|
891
|
+
if (!validations3.multipleValidations)
|
|
892
|
+
return false;
|
|
893
|
+
const runner = run(
|
|
894
|
+
value2,
|
|
895
|
+
validations3.multipleValidations.validations
|
|
896
|
+
);
|
|
897
|
+
const rulesMapper = {
|
|
898
|
+
AND: () => runner.every((validation) => validation),
|
|
899
|
+
OR: () => runner.some((validation) => validation),
|
|
900
|
+
NOT: () => !runner.every((validation) => validation)
|
|
901
|
+
};
|
|
902
|
+
return rulesMapper[validations3.multipleValidations.rule]();
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
// libs/form-engine-core/src/validations/handler.ts
|
|
906
|
+
var validations2 = {
|
|
907
|
+
max,
|
|
908
|
+
min,
|
|
909
|
+
length: length_default,
|
|
910
|
+
regex: regex2,
|
|
911
|
+
url,
|
|
912
|
+
email,
|
|
913
|
+
onlyLetters: onlyLetters2,
|
|
914
|
+
notAllowSpaces,
|
|
915
|
+
callback: callback2,
|
|
916
|
+
hasNoExtraSpaces,
|
|
917
|
+
between,
|
|
918
|
+
sequential,
|
|
919
|
+
includes,
|
|
920
|
+
repeated,
|
|
921
|
+
document: document_default,
|
|
922
|
+
isCreditCard,
|
|
923
|
+
isCreditCodeMatch,
|
|
924
|
+
isCreditCardAndLength,
|
|
925
|
+
required,
|
|
926
|
+
value,
|
|
927
|
+
notEmpty,
|
|
928
|
+
bool,
|
|
929
|
+
exists,
|
|
930
|
+
greaterThan: () => true,
|
|
931
|
+
isNumber: isNumber2,
|
|
932
|
+
conditions,
|
|
933
|
+
multipleValidations,
|
|
934
|
+
date,
|
|
935
|
+
betweenDates,
|
|
936
|
+
validDate
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
// libs/form-engine-core/src/managers/field.ts
|
|
940
|
+
import { get, isEqual, isNil } from "lodash";
|
|
941
|
+
var FormField = class {
|
|
942
|
+
/**
|
|
943
|
+
* Creates an instance of FormField.
|
|
944
|
+
*
|
|
945
|
+
* @param {object} options - Configuration options for the form field.
|
|
946
|
+
* @param {IComponentSchema} options.schemaComponent - The schema definition for the form field.
|
|
947
|
+
* @param {string} [options.path] - The path within the form field (used internally during recursion).
|
|
948
|
+
* @param {string[]} options.children - An array of children fields names.
|
|
949
|
+
* @param {Function} options.validateVisibility - A function to validate the visibility of the field.
|
|
950
|
+
* @param {Function} options.resetValue - A function to reset the field value.
|
|
951
|
+
* @param {unknown} [options.initialValue] - The initial value of the form field.
|
|
952
|
+
* @param {Subject<{ key: string }>} options.templateSubject$ - A subject for template updates.
|
|
953
|
+
*/
|
|
954
|
+
constructor({
|
|
955
|
+
schemaComponent,
|
|
956
|
+
path,
|
|
957
|
+
children,
|
|
958
|
+
validateVisibility,
|
|
959
|
+
resetValue,
|
|
960
|
+
initialValue,
|
|
961
|
+
templateSubject$,
|
|
962
|
+
apiResponseSubject$,
|
|
963
|
+
dataSubject$,
|
|
964
|
+
mapper
|
|
965
|
+
}) {
|
|
966
|
+
this.fieldStateSubscription$ = new Subscription();
|
|
967
|
+
this.name = schemaComponent.name;
|
|
968
|
+
this.component = schemaComponent.component;
|
|
969
|
+
this.path = path;
|
|
970
|
+
this.children = children;
|
|
971
|
+
this.validations = schemaComponent.validations;
|
|
972
|
+
this.errorMessages = schemaComponent.errorMessages;
|
|
973
|
+
this.visibilityConditions = schemaComponent.visibilityConditions;
|
|
974
|
+
this.resetValues = schemaComponent.resetValues;
|
|
975
|
+
this.apiSchema = schemaComponent.api;
|
|
976
|
+
this.formatters = schemaComponent.formatters;
|
|
977
|
+
this.masks = schemaComponent.masks;
|
|
978
|
+
if (mapper.valueChangeEvent)
|
|
979
|
+
this.valueChangeEvent = mapper.valueChangeEvent;
|
|
980
|
+
if (mapper.events?.setValue)
|
|
981
|
+
this.valuePropName = mapper.events.setValue;
|
|
982
|
+
if (mapper.events?.setErrorMessage)
|
|
983
|
+
this.errorMessagePropName = mapper.events.setErrorMessage;
|
|
984
|
+
this.mapper = mapper;
|
|
985
|
+
this.validateVisibility = validateVisibility;
|
|
986
|
+
this.resetValue = resetValue;
|
|
987
|
+
this.templateSubject$ = templateSubject$;
|
|
988
|
+
this.apiResponseSubject$ = apiResponseSubject$;
|
|
989
|
+
this.dataSubject$ = dataSubject$;
|
|
990
|
+
this._props = schemaComponent.props || {};
|
|
991
|
+
this._value = "";
|
|
992
|
+
this._stateValue = "";
|
|
993
|
+
this._metadata = "";
|
|
994
|
+
this.initialValue = initialValue;
|
|
995
|
+
this._visibility = true;
|
|
996
|
+
this._api = {
|
|
997
|
+
default: {
|
|
998
|
+
response: this.apiSchema?.defaultConfig?.config?.fallbackValue || ""
|
|
999
|
+
},
|
|
1000
|
+
named: this.apiSchema?.configs && Object.keys(this.apiSchema?.configs).reduce(
|
|
1001
|
+
(acc, curr) => {
|
|
1002
|
+
acc[curr] = {
|
|
1003
|
+
response: this.apiSchema?.configs?.[curr].config.fallbackValue || ""
|
|
1004
|
+
};
|
|
1005
|
+
return acc;
|
|
1006
|
+
},
|
|
1007
|
+
{}
|
|
1008
|
+
)
|
|
1009
|
+
};
|
|
1010
|
+
this._errorsString = "";
|
|
1011
|
+
this._valid = false;
|
|
1012
|
+
this.initializeObservers();
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* method to initialize all recycled Subjects and initialize Observers on field instance creation or rerender
|
|
1016
|
+
*/
|
|
1017
|
+
initializeObservers() {
|
|
1018
|
+
if (!this.valueSubject$ || this.valueSubject$.closed) {
|
|
1019
|
+
this.valueSubject$ = new Subject();
|
|
1020
|
+
}
|
|
1021
|
+
if (!this.errorSubject$ || this.errorSubject$.closed) {
|
|
1022
|
+
this.errorSubject$ = new Subject();
|
|
1023
|
+
}
|
|
1024
|
+
if (!this.visibilitySubject$ || this.visibilitySubject$.closed) {
|
|
1025
|
+
this.visibilitySubject$ = new Subject();
|
|
1026
|
+
}
|
|
1027
|
+
if (!this.apiSubject$ || this.apiSubject$.closed) {
|
|
1028
|
+
this.apiSubject$ = new Subject();
|
|
1029
|
+
}
|
|
1030
|
+
if (!this.propsSubject$ || this.propsSubject$.closed) {
|
|
1031
|
+
this.propsSubject$ = new Subject();
|
|
1032
|
+
}
|
|
1033
|
+
if (!this.fieldStateSubscription$ || this.fieldStateSubscription$.closed) {
|
|
1034
|
+
this.fieldStateSubscription$ = new Subscription();
|
|
1035
|
+
}
|
|
1036
|
+
if (!this.apiEventQueueSubject$ || this.apiEventQueueSubject$.closed) {
|
|
1037
|
+
this.apiEventQueueSubject$ = new Subject();
|
|
1038
|
+
}
|
|
1039
|
+
this.fieldState$ = combineLatest({
|
|
1040
|
+
errors: this.errorSubject$.pipe(startWith([])),
|
|
1041
|
+
visibility: this.visibilitySubject$.pipe(startWith(this._visibility)),
|
|
1042
|
+
apiResponse: this.apiSubject$.pipe(startWith(this._api)),
|
|
1043
|
+
props: this.propsSubject$.pipe(startWith(this._props))
|
|
1044
|
+
});
|
|
1045
|
+
!this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(this.debounceDistinct(({ event }) => event, 1e3)).subscribe((payload) => {
|
|
1046
|
+
this.apiRequest(payload);
|
|
1047
|
+
});
|
|
1048
|
+
if (!isNil(this.initialValue)) {
|
|
1049
|
+
this.value = this.initialValue;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Observable function to emit api events debounced and distinct for each event type,
|
|
1054
|
+
* avoiding previous events being cancelled by new events if they occur inside the debounce time interval
|
|
1055
|
+
*
|
|
1056
|
+
* @param {(event: { event: TEvents }) => TEvents} keyExtractor function that will pass the event key to the groupBy operator
|
|
1057
|
+
* @param {number} debounceTimeMs time to wait for each individual event emmited
|
|
1058
|
+
* @returns
|
|
1059
|
+
*/
|
|
1060
|
+
debounceDistinct(keyExtractor, debounceTimeMs) {
|
|
1061
|
+
return (source$) => source$.pipe(
|
|
1062
|
+
groupBy(keyExtractor),
|
|
1063
|
+
mergeMap(
|
|
1064
|
+
(group$) => group$.pipe(
|
|
1065
|
+
debounceTime(debounceTimeMs),
|
|
1066
|
+
map(() => ({ event: group$.key }))
|
|
1067
|
+
)
|
|
1068
|
+
)
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Retrieves the properties associated with the form field.
|
|
1073
|
+
*
|
|
1074
|
+
* @returns {Record<string, unknown>} - The properties of the form field.
|
|
1075
|
+
*/
|
|
1076
|
+
get props() {
|
|
1077
|
+
return this._props;
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Sets the properties of the form field and notifies subscribers about the change.
|
|
1081
|
+
*
|
|
1082
|
+
* @param {Record<string, unknown>} props - The new properties to be set.
|
|
1083
|
+
*/
|
|
1084
|
+
set props(props) {
|
|
1085
|
+
if (typeof props === "undefined" || isEqual(props, this.props))
|
|
1086
|
+
return;
|
|
1087
|
+
this._props = props;
|
|
1088
|
+
this.propsSubject$.next(this.props);
|
|
1089
|
+
this.templateSubject$.next({ key: this.name, event: "ON_PROPS" });
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Retrieves the current state value of the form field.
|
|
1093
|
+
*
|
|
1094
|
+
* @returns {unknown} - The current state value of the form field.
|
|
1095
|
+
*/
|
|
1096
|
+
get stateValue() {
|
|
1097
|
+
return this._stateValue;
|
|
1098
|
+
}
|
|
1099
|
+
get metadata() {
|
|
1100
|
+
return this._metadata;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Retrieves the concatenated string of errors associated with the form field.
|
|
1104
|
+
*
|
|
1105
|
+
* @returns {string} - The concatenated string of errors.
|
|
1106
|
+
*/
|
|
1107
|
+
get errorsString() {
|
|
1108
|
+
return this._errorsString;
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Retrieves the current value of the form field.
|
|
1112
|
+
*
|
|
1113
|
+
* @returns {unknown} - The current value of the form field.
|
|
1114
|
+
*/
|
|
1115
|
+
get value() {
|
|
1116
|
+
return this._value;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Sets the value of the form field and notifies subscribers about the change.
|
|
1120
|
+
*
|
|
1121
|
+
* @param {unknown} value - The new value to be set.
|
|
1122
|
+
*/
|
|
1123
|
+
set value(value2) {
|
|
1124
|
+
let val;
|
|
1125
|
+
if (this.valueChangeEvent) {
|
|
1126
|
+
try {
|
|
1127
|
+
val = this.valueChangeEvent(value2, { props: this.props });
|
|
1128
|
+
} catch (e) {
|
|
1129
|
+
val = value2;
|
|
1130
|
+
}
|
|
1131
|
+
} else {
|
|
1132
|
+
val = value2;
|
|
1133
|
+
}
|
|
1134
|
+
if (typeof val === "undefined" || val === null)
|
|
1135
|
+
return;
|
|
1136
|
+
if (typeof val === "object" && "_value" in val && "_metadata" in val) {
|
|
1137
|
+
this._value = this.formatValue(val["_value"]);
|
|
1138
|
+
this._stateValue = this.maskValue(this.formatValue(val["_value"]));
|
|
1139
|
+
this._metadata = val._metadata;
|
|
1140
|
+
} else {
|
|
1141
|
+
this._value = this.formatValue(val);
|
|
1142
|
+
this._stateValue = this.maskValue(this.formatValue(val));
|
|
1143
|
+
this._metadata = val;
|
|
1144
|
+
}
|
|
1145
|
+
if (this.valuePropName)
|
|
1146
|
+
this._props = {
|
|
1147
|
+
...this.props,
|
|
1148
|
+
[this.valuePropName]: this.value
|
|
1149
|
+
};
|
|
1150
|
+
this.valueSubject$.next(this._stateValue);
|
|
1151
|
+
this.templateSubject$.next({ key: this.name, event: "ON_VALUE" });
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Retrieves the visibility status of the form field.
|
|
1155
|
+
*
|
|
1156
|
+
* @returns {boolean} - The visibility status of the form field.
|
|
1157
|
+
*/
|
|
1158
|
+
get visibility() {
|
|
1159
|
+
return this._visibility;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Sets the visibility status of the form field and notifies subscribers about the change.
|
|
1163
|
+
*
|
|
1164
|
+
* @param {boolean} visible - The new visibility status to be set.
|
|
1165
|
+
*/
|
|
1166
|
+
set visibility(visible) {
|
|
1167
|
+
if (typeof visible === "undefined" || visible === this.visibility)
|
|
1168
|
+
return;
|
|
1169
|
+
this._visibility = visible;
|
|
1170
|
+
this.visibilitySubject$.next(this.visibility);
|
|
1171
|
+
this.templateSubject$.next({ key: this.name, event: "ON_VISIBILITY" });
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Retrieves the validity status of the form field.
|
|
1175
|
+
*
|
|
1176
|
+
* @returns {boolean} - The validity status of the form field.
|
|
1177
|
+
*/
|
|
1178
|
+
get valid() {
|
|
1179
|
+
return this._valid;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Retrieves the error messages associated with the form field.
|
|
1183
|
+
*
|
|
1184
|
+
* @returns {TErrorMessages} - The error messages associated with the form field.
|
|
1185
|
+
*/
|
|
1186
|
+
get errors() {
|
|
1187
|
+
return this._errors;
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Sets the error messages associated with the form field and notifies subscribers about the change.
|
|
1191
|
+
*
|
|
1192
|
+
* @param {TErrorMessages} errors - The new error messages to be set.
|
|
1193
|
+
*/
|
|
1194
|
+
set errors(errors) {
|
|
1195
|
+
if (typeof errors === "undefined" || isEqual(errors, this.errors))
|
|
1196
|
+
return;
|
|
1197
|
+
this._errors = errors;
|
|
1198
|
+
this._errorsString = Object.values(this.errors).join(", ");
|
|
1199
|
+
this.errorSubject$.next(Object.values(this.errors));
|
|
1200
|
+
this.templateSubject$.next({ key: this.name, event: "ON_PROPS" });
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Retrieves the API response data associated with the form field.
|
|
1204
|
+
*
|
|
1205
|
+
* @returns {TApiResponse} - The API response data associated with the form field.
|
|
1206
|
+
*/
|
|
1207
|
+
get api() {
|
|
1208
|
+
return this._api;
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Sets the API response data associated with the form field and notifies subscribers about the change.
|
|
1212
|
+
*
|
|
1213
|
+
* @param {TApiResponse} response - The new API response data to be set.
|
|
1214
|
+
*/
|
|
1215
|
+
set api(response) {
|
|
1216
|
+
if (typeof response === "undefined" || isEqual(response, this.api))
|
|
1217
|
+
return;
|
|
1218
|
+
this._api = response;
|
|
1219
|
+
this.apiSubject$.next(this.api);
|
|
1220
|
+
this.templateSubject$.next({ key: this.name, event: "ON_API" });
|
|
1221
|
+
this.emitEvents({ event: "ON_API_FIELD_RESPONSE" });
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
1225
|
+
*
|
|
1226
|
+
* @param {object} mountOpts - Adapter mount options.
|
|
1227
|
+
* @param {string} prop.valuePropName - Adapter value property name.
|
|
1228
|
+
* @param {(event: unknown) => unknown} prop.valueChangeEvent - Adapter change event handler function
|
|
1229
|
+
* @param {(value: unknown) => unknown} prop.valueSubscription - Adapter value change function
|
|
1230
|
+
* @param {(payload: Partial<IState>) => unknown} prop.propsSubscription - Adapter prop change function
|
|
1231
|
+
* @param {string} prop.errorMessagePropName - error message property name to set errors onto component
|
|
1232
|
+
* @returns {void}
|
|
1233
|
+
*/
|
|
1234
|
+
mountField({
|
|
1235
|
+
valueSubscription,
|
|
1236
|
+
propsSubscription
|
|
1237
|
+
}) {
|
|
1238
|
+
this.initializeObservers();
|
|
1239
|
+
this.subscribeValue(valueSubscription);
|
|
1240
|
+
this.subscribeState(propsSubscription);
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Sets the value of the form field and emits associated events.
|
|
1244
|
+
*
|
|
1245
|
+
* @param {unknown} prop.value - The new value to be set.
|
|
1246
|
+
* @param {TEvents} prop.event - The event associated with setting the value.
|
|
1247
|
+
* @returns {void}
|
|
1248
|
+
*/
|
|
1249
|
+
emitValue(prop) {
|
|
1250
|
+
this.value = prop.value;
|
|
1251
|
+
this.emitEvents({ event: prop.event });
|
|
1252
|
+
this.dataSubject$.next({ key: this.name, event: prop.event });
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Emits events to trigger field-related actions such as validation, visibility checks, value resets, and API requests.
|
|
1256
|
+
*
|
|
1257
|
+
* @param {TEvents} event - The event type that triggers the field actions.
|
|
1258
|
+
* @returns {void}
|
|
1259
|
+
*/
|
|
1260
|
+
emitEvents({ event }) {
|
|
1261
|
+
this.setFieldValidity({ event });
|
|
1262
|
+
this.validateVisibility({ event, key: this.name });
|
|
1263
|
+
this.resetValue({ event, key: this.name });
|
|
1264
|
+
this.apiEventQueueSubject$.next({ event });
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Sets the validity state of the field based on the provided validation rules and triggers error message updates.
|
|
1268
|
+
*
|
|
1269
|
+
* @param {TEvents} event - The event type associated with the field action.
|
|
1270
|
+
* @returns {void}
|
|
1271
|
+
*/
|
|
1272
|
+
setFieldValidity({ event }) {
|
|
1273
|
+
if (!this.validations) {
|
|
1274
|
+
this._valid = true;
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
if (!this.validations.events.includes(event) && event !== "ON_FORM_SUBMIT")
|
|
1278
|
+
return;
|
|
1279
|
+
let valid = true;
|
|
1280
|
+
const errors = { ...this.errors };
|
|
1281
|
+
const schemaValidations = this.validations?.config;
|
|
1282
|
+
schemaValidations && Object.keys(schemaValidations).forEach(
|
|
1283
|
+
(validationKey) => {
|
|
1284
|
+
const error = validations2[validationKey](
|
|
1285
|
+
this.value,
|
|
1286
|
+
schemaValidations
|
|
1287
|
+
);
|
|
1288
|
+
valid = !error && valid;
|
|
1289
|
+
if (this.validations?.events.includes(event) || event === "ON_FORM_SUBMIT") {
|
|
1290
|
+
if (error && this.errorMessages?.[validationKey]) {
|
|
1291
|
+
errors[validationKey] = this.errorMessages[validationKey];
|
|
1292
|
+
} else {
|
|
1293
|
+
delete errors[validationKey];
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
);
|
|
1298
|
+
this._valid = valid;
|
|
1299
|
+
this.errors = errors;
|
|
1300
|
+
if (this.errorMessagePropName)
|
|
1301
|
+
this.props = {
|
|
1302
|
+
...this.props,
|
|
1303
|
+
[this.errorMessagePropName]: this.errorsString
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Formats the field value using the specified formatters, if available.
|
|
1308
|
+
*
|
|
1309
|
+
* @param {unknown} value - The value to be formatted.
|
|
1310
|
+
* @returns {unknown} - The formatted value.
|
|
1311
|
+
*/
|
|
1312
|
+
formatValue(value2) {
|
|
1313
|
+
if (this.formatters) {
|
|
1314
|
+
return Object.keys(this.formatters).reduce(
|
|
1315
|
+
(acc, curr) => {
|
|
1316
|
+
return formatters[curr](acc, this.formatters);
|
|
1317
|
+
},
|
|
1318
|
+
value2
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
return value2;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Masks the field value using the specified masks, if available.
|
|
1325
|
+
*
|
|
1326
|
+
* @param {unknown} value - The value to be masked.
|
|
1327
|
+
* @returns {unknown} - The masked value.
|
|
1328
|
+
*/
|
|
1329
|
+
maskValue(value2) {
|
|
1330
|
+
if (this.masks) {
|
|
1331
|
+
return Object.keys(this.masks).reduce((acc, curr) => {
|
|
1332
|
+
return masks[curr](acc, this.masks);
|
|
1333
|
+
}, value2);
|
|
1334
|
+
}
|
|
1335
|
+
return value2;
|
|
1336
|
+
}
|
|
1337
|
+
checkApiRequestValidations(config) {
|
|
1338
|
+
let valid = true;
|
|
1339
|
+
const preConditions = config.preConditions;
|
|
1340
|
+
preConditions && Object.keys(preConditions).forEach(
|
|
1341
|
+
(validationKey) => {
|
|
1342
|
+
const error = validations2[validationKey](this.value, preConditions);
|
|
1343
|
+
valid = valid && !error;
|
|
1344
|
+
}
|
|
1345
|
+
);
|
|
1346
|
+
if (config.blockRequestWhenInvalid) {
|
|
1347
|
+
valid = valid && this.valid;
|
|
1348
|
+
}
|
|
1349
|
+
return valid;
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Makes an API request based on the field's API configuration and event type, updating the field's API response data.
|
|
1353
|
+
*
|
|
1354
|
+
* @param {TEvents} event - The event type associated with the API request.
|
|
1355
|
+
* @returns {Promise<void>}
|
|
1356
|
+
*/
|
|
1357
|
+
async apiRequest({ event }) {
|
|
1358
|
+
if (!this.apiSchema?.defaultConfig?.events.includes(event) && !(this.apiSchema?.configs && Object.keys(this.apiSchema?.configs).some(
|
|
1359
|
+
(key) => this.apiSchema?.configs?.[key].events.includes(event)
|
|
1360
|
+
)))
|
|
1361
|
+
return;
|
|
1362
|
+
const responses = {
|
|
1363
|
+
default: { ...this.api.default },
|
|
1364
|
+
named: { ...this.api.named }
|
|
1365
|
+
};
|
|
1366
|
+
const config = this.apiSchema.defaultConfig?.config;
|
|
1367
|
+
if (config && this.apiSchema?.defaultConfig?.events.includes(event) && this.checkApiRequestValidations(config)) {
|
|
1368
|
+
try {
|
|
1369
|
+
const responseData = await makeRequest(
|
|
1370
|
+
config.method,
|
|
1371
|
+
config.url,
|
|
1372
|
+
config.headers,
|
|
1373
|
+
config.body
|
|
1374
|
+
);
|
|
1375
|
+
const apiResponseData = JSON.parse(String(responseData));
|
|
1376
|
+
const response = config.resultPath ? get(apiResponseData, config.resultPath) : apiResponseData;
|
|
1377
|
+
responses.default = { response };
|
|
1378
|
+
} catch (e) {
|
|
1379
|
+
responses.default = {
|
|
1380
|
+
response: !isNil(config?.fallbackValue) ? config.fallbackValue : "error"
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
if (this.apiSchema?.configs && Object.keys(this.apiSchema?.configs).some(
|
|
1385
|
+
(key) => this.apiSchema?.configs?.[key].events.includes(event)
|
|
1386
|
+
)) {
|
|
1387
|
+
if (this.apiSchema.configs) {
|
|
1388
|
+
const result = await Promise.all(
|
|
1389
|
+
Object.keys(this.apiSchema.configs).map(async (configKey) => {
|
|
1390
|
+
return new Promise((res) => {
|
|
1391
|
+
const config2 = this.apiSchema?.configs?.[configKey].config;
|
|
1392
|
+
if (config2 && this.apiSchema?.configs?.[configKey].events.includes(event) && this.checkApiRequestValidations(config2)) {
|
|
1393
|
+
try {
|
|
1394
|
+
makeRequest(
|
|
1395
|
+
config2.method,
|
|
1396
|
+
config2.url,
|
|
1397
|
+
config2.headers,
|
|
1398
|
+
config2.body
|
|
1399
|
+
).then((responseData) => {
|
|
1400
|
+
const apiResponseData = JSON.parse(String(responseData));
|
|
1401
|
+
const response = get(
|
|
1402
|
+
apiResponseData,
|
|
1403
|
+
config2.resultPath || ""
|
|
1404
|
+
);
|
|
1405
|
+
res({ name: configKey, result: { response } });
|
|
1406
|
+
});
|
|
1407
|
+
} catch (e) {
|
|
1408
|
+
res({
|
|
1409
|
+
name: configKey,
|
|
1410
|
+
result: {
|
|
1411
|
+
response: !isNil(config2.fallbackValue) ? config2.fallbackValue : "error"
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
})
|
|
1418
|
+
);
|
|
1419
|
+
result.forEach(({ name, result: result2 }) => {
|
|
1420
|
+
if (responses.named)
|
|
1421
|
+
responses.named[name] = result2;
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
this.api = responses;
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Unsubscribes from all subject subscriptions associated with the field, cleaning up resources.
|
|
1429
|
+
*
|
|
1430
|
+
* @returns {void}
|
|
1431
|
+
*/
|
|
1432
|
+
destroyField() {
|
|
1433
|
+
this.valueSubject$.unsubscribe();
|
|
1434
|
+
this.visibilitySubject$.unsubscribe();
|
|
1435
|
+
this.fieldStateSubscription$.unsubscribe();
|
|
1436
|
+
this.propsSubject$.unsubscribe();
|
|
1437
|
+
this.errorSubject$.unsubscribe();
|
|
1438
|
+
this.apiSubject$.unsubscribe();
|
|
1439
|
+
this.apiEventQueueSubject$.unsubscribe();
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Subscribes to changes in the field state and executes the provided callback function.
|
|
1443
|
+
*
|
|
1444
|
+
* @param {Function} callback - The callback function to be executed when the field state changes.
|
|
1445
|
+
* @returns {void}
|
|
1446
|
+
*/
|
|
1447
|
+
subscribeState(callback3) {
|
|
1448
|
+
this.fieldStateSubscription$ = this.fieldState$.pipe(debounceTime(100)).subscribe({
|
|
1449
|
+
next: callback3
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Subscribes to changes in the field value and executes the provided callback function.
|
|
1454
|
+
*
|
|
1455
|
+
* @param {Function} callback - The callback function to be executed when the field value changes.
|
|
1456
|
+
* @returns {void}
|
|
1457
|
+
*/
|
|
1458
|
+
subscribeValue(callback3) {
|
|
1459
|
+
this.valueSubject$.subscribe({
|
|
1460
|
+
next: callback3
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
// libs/form-engine-core/src/managers/form.ts
|
|
1466
|
+
import { debounceTime as debounceTime2, map as map2, Subject as Subject2, Subscription as Subscription2 } from "rxjs";
|
|
1467
|
+
import { get as get2, isEqual as isEqual2, isNil as isNil2, set } from "lodash";
|
|
1468
|
+
var IVARPROPNAME = "iVars";
|
|
1469
|
+
var FormCore = class _FormCore {
|
|
1470
|
+
/**
|
|
1471
|
+
* Creates an instance of FormCore.
|
|
1472
|
+
*
|
|
1473
|
+
* @param {TFormEntry & Omit<IFormSchema, 'components'>} entry - Configuration options for the form.
|
|
1474
|
+
* @param {IFormSchema} entry.schema - The schema definition for the form.
|
|
1475
|
+
* @param {Record<string, unknown> | IFormSchema.initialValues} [entry.initialValues] - Initial values for the form fields.
|
|
1476
|
+
* @param {string} [entry.action] - The action attribute of the form.
|
|
1477
|
+
* @param {string} [entry.method] - The method attribute of the form.
|
|
1478
|
+
* @param {IFormSchema.iVars} [entry.iVars] - The internal variables of the form.
|
|
1479
|
+
* @param {(data: TFormValues) => void} [entry.onSubmit] - A callback function to handle form submission.
|
|
1480
|
+
* @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
|
|
1481
|
+
*/
|
|
1482
|
+
constructor(entry) {
|
|
1483
|
+
this.schema = entry.schema;
|
|
1484
|
+
this.fields = /* @__PURE__ */ new Map();
|
|
1485
|
+
this.initialValues = entry.initialValues || entry.schema?.initialValues;
|
|
1486
|
+
this.action = entry.action || entry.schema?.action;
|
|
1487
|
+
this.method = entry.method || entry.schema?.method;
|
|
1488
|
+
this._iVars = entry.iVars || entry.schema?.iVars || {};
|
|
1489
|
+
this.onSubmit = entry.onSubmit;
|
|
1490
|
+
this.mappers = entry.mappers;
|
|
1491
|
+
this.schema && _FormCore.checkIndexes(this.schema.components);
|
|
1492
|
+
this.templateSubject$ = new Subject2();
|
|
1493
|
+
this.submitSubject$ = new Subject2();
|
|
1494
|
+
this.apiResponseSubject$ = new Subject2();
|
|
1495
|
+
this.dataSubject$ = new Subject2();
|
|
1496
|
+
this.dataCallbackSubscription$ = new Subscription2();
|
|
1497
|
+
this.subscribedTemplates = [];
|
|
1498
|
+
this.schema && this.serializeStructure(this.schema.components);
|
|
1499
|
+
this.schema && this.subscribeTemplates();
|
|
1500
|
+
this.templateSubject$.subscribe(this.refreshTemplates.bind(this));
|
|
1501
|
+
this.templateSubject$.next({ key: IVARPROPNAME, event: "ON_IVARS" });
|
|
1502
|
+
this.apiResponseSubject$.subscribe(this.refreshApi.bind(this));
|
|
1503
|
+
entry.onData && this.subscribeData(entry.onData);
|
|
1504
|
+
this.fields.forEach((field, key) => {
|
|
1505
|
+
field.emitEvents({ event: "ON_FIELD_MOUNT" });
|
|
1506
|
+
this.refreshTemplates({ key, event: "ON_FIELDS" });
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1510
|
+
* Retrieves the internal variables (iVars) of the form.
|
|
1511
|
+
*
|
|
1512
|
+
* @returns {Record<string, unknown>} - The internal variables of the form.
|
|
1513
|
+
*/
|
|
1514
|
+
get iVars() {
|
|
1515
|
+
return this._iVars;
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Sets the internal variables (iVars) of the form and notifies subscribers about the change.
|
|
1519
|
+
*
|
|
1520
|
+
* @param {Record<string, unknown>} payload - The new internal variables to be set.
|
|
1521
|
+
*/
|
|
1522
|
+
set iVars(payload) {
|
|
1523
|
+
this._iVars = payload;
|
|
1524
|
+
this.templateSubject$.next({ key: IVARPROPNAME, event: "ON_IVARS" });
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Checks if the form is valid by validating all form fields.
|
|
1528
|
+
*
|
|
1529
|
+
* @returns {boolean} True if the form is valid; otherwise, false.
|
|
1530
|
+
*/
|
|
1531
|
+
get isValid() {
|
|
1532
|
+
for (const [, field] of this.fields) {
|
|
1533
|
+
if (!field.valid)
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
return true;
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Subscribes to templates for dynamic updates.
|
|
1540
|
+
*/
|
|
1541
|
+
subscribeTemplates() {
|
|
1542
|
+
this.fields.forEach(
|
|
1543
|
+
({
|
|
1544
|
+
component,
|
|
1545
|
+
props,
|
|
1546
|
+
name,
|
|
1547
|
+
validations: validations3,
|
|
1548
|
+
visibilityConditions,
|
|
1549
|
+
resetValues,
|
|
1550
|
+
errorMessages,
|
|
1551
|
+
apiSchema,
|
|
1552
|
+
metadata
|
|
1553
|
+
}, key) => {
|
|
1554
|
+
const template = {
|
|
1555
|
+
component,
|
|
1556
|
+
props,
|
|
1557
|
+
name,
|
|
1558
|
+
validations: validations3,
|
|
1559
|
+
visibilityConditions,
|
|
1560
|
+
resetValues,
|
|
1561
|
+
errorMessages,
|
|
1562
|
+
apiSchema,
|
|
1563
|
+
metadata
|
|
1564
|
+
};
|
|
1565
|
+
traverseObject(template, key).forEach(
|
|
1566
|
+
(element) => this.subscribedTemplates.push(element)
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
*
|
|
1573
|
+
* @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call on data
|
|
1574
|
+
*/
|
|
1575
|
+
subscribeData(callback3) {
|
|
1576
|
+
this.dataCallbackSubscription$ = this.dataSubject$.pipe(
|
|
1577
|
+
debounceTime2(100),
|
|
1578
|
+
map2(({ key }) => ({ field: key, data: this.getFormValues() }))
|
|
1579
|
+
).subscribe({
|
|
1580
|
+
next: callback3
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* Gets the value of a property from a field.
|
|
1585
|
+
*
|
|
1586
|
+
* @param {object} options - Options for getting the value.
|
|
1587
|
+
* @param {string} options.key - The key of the field.
|
|
1588
|
+
* @param {string} options.property - The property to retrieve.
|
|
1589
|
+
* @param {string[]} options.path - The path to the property if it's nested.
|
|
1590
|
+
* @returns {unknown | undefined} The value of the property, or undefined if the field doesn't exist.
|
|
1591
|
+
*/
|
|
1592
|
+
getValue({
|
|
1593
|
+
key,
|
|
1594
|
+
property,
|
|
1595
|
+
path
|
|
1596
|
+
}) {
|
|
1597
|
+
if (key === IVARPROPNAME) {
|
|
1598
|
+
const value2 = get2(this.iVars, [property, ...path]);
|
|
1599
|
+
return value2;
|
|
1600
|
+
}
|
|
1601
|
+
if (!this.fields.has(key))
|
|
1602
|
+
return console.warn(`failed to get value from ${key}`);
|
|
1603
|
+
return path.length > 0 ? get2(this.fields.get(key)[property], path) : this.fields.get(key)[property];
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Sets the value of a property in a field.
|
|
1607
|
+
*
|
|
1608
|
+
* @param {object} options - Options for setting the value.
|
|
1609
|
+
* @param {string} options.key - The key of the field.
|
|
1610
|
+
* @param {string} options.property - The property to set.
|
|
1611
|
+
* @param {string[]} options.path - The path to the property if it's nested.
|
|
1612
|
+
* @param {unknown} options.originKey - field that called templating
|
|
1613
|
+
* @param {unknown} options.value - The value to set.
|
|
1614
|
+
* @param {TMutationEvents} options.event - Internal Event for template Handling.
|
|
1615
|
+
*/
|
|
1616
|
+
setValue({
|
|
1617
|
+
key,
|
|
1618
|
+
property,
|
|
1619
|
+
path,
|
|
1620
|
+
originKey,
|
|
1621
|
+
value: value2
|
|
1622
|
+
}) {
|
|
1623
|
+
const field = this.fields.get(key);
|
|
1624
|
+
if (!field) {
|
|
1625
|
+
console.warn(`failed to update field ${key}`);
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
if (path.length > 0) {
|
|
1629
|
+
if (property === "props" && path[0] === field.valuePropName && key !== originKey) {
|
|
1630
|
+
field.emitValue({ event: "ON_FIELD_CHANGE", value: value2 });
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
const fieldProp = field[property];
|
|
1634
|
+
let propState;
|
|
1635
|
+
if (Array.isArray(fieldProp)) {
|
|
1636
|
+
propState = [...fieldProp];
|
|
1637
|
+
} else if (typeof fieldProp === "object" && !isNil2(fieldProp)) {
|
|
1638
|
+
propState = { ...fieldProp };
|
|
1639
|
+
} else {
|
|
1640
|
+
console.warn(
|
|
1641
|
+
`invalid template property, skipping evaluation of ${field.name} with ${fieldProp}`
|
|
1642
|
+
);
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
set(propState, path, value2);
|
|
1646
|
+
field[property] = propState;
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
field[property] = value2;
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
/**
|
|
1653
|
+
* Extracts parameters from an expression.
|
|
1654
|
+
*
|
|
1655
|
+
* @param {string} expression - The expression containing parameters.
|
|
1656
|
+
* @returns {string[]} An array of extracted parameters.
|
|
1657
|
+
*/
|
|
1658
|
+
extractParams(expression) {
|
|
1659
|
+
const regex3 = /\${(.*?)}/g;
|
|
1660
|
+
const extractedValues = [];
|
|
1661
|
+
let match;
|
|
1662
|
+
while (!isNil2(match = regex3.exec(expression))) {
|
|
1663
|
+
extractedValues.push(match[1]);
|
|
1664
|
+
}
|
|
1665
|
+
const operatorRegex = /\s*(\|\||&&|!)\s*/g;
|
|
1666
|
+
const splittedString = extractedValues.map((el) => el.split(operatorRegex));
|
|
1667
|
+
const result = splittedString.map((splittedStringVal) => {
|
|
1668
|
+
return splittedStringVal.filter(Boolean).reduce((acc, curr) => {
|
|
1669
|
+
if (curr.match(/^\|\||&&|!$/)) {
|
|
1670
|
+
return `${acc}${curr}`;
|
|
1671
|
+
}
|
|
1672
|
+
let value2;
|
|
1673
|
+
const element = curr.split(".");
|
|
1674
|
+
const currElementContent = element.length > 1 ? this.getValue({
|
|
1675
|
+
key: element[0],
|
|
1676
|
+
property: element[1],
|
|
1677
|
+
path: element.slice(2)
|
|
1678
|
+
}) : element;
|
|
1679
|
+
let currValue;
|
|
1680
|
+
try {
|
|
1681
|
+
currValue = JSON.parse(currElementContent);
|
|
1682
|
+
} catch (e) {
|
|
1683
|
+
currValue = currElementContent;
|
|
1684
|
+
}
|
|
1685
|
+
switch (typeof currValue) {
|
|
1686
|
+
case "string":
|
|
1687
|
+
value2 = `\`${currValue}\``;
|
|
1688
|
+
break;
|
|
1689
|
+
case "boolean":
|
|
1690
|
+
case "undefined":
|
|
1691
|
+
case "number":
|
|
1692
|
+
value2 = currValue;
|
|
1693
|
+
break;
|
|
1694
|
+
case "object":
|
|
1695
|
+
if (currValue === null) {
|
|
1696
|
+
value2 = null;
|
|
1697
|
+
}
|
|
1698
|
+
value2 = JSON.stringify(currValue);
|
|
1699
|
+
break;
|
|
1700
|
+
default:
|
|
1701
|
+
value2 = currValue;
|
|
1702
|
+
}
|
|
1703
|
+
return `${acc}${value2}`;
|
|
1704
|
+
}, "");
|
|
1705
|
+
});
|
|
1706
|
+
return result.map((el) => {
|
|
1707
|
+
try {
|
|
1708
|
+
return new Function(`return ${el}`)();
|
|
1709
|
+
} catch (e) {
|
|
1710
|
+
console.log(e);
|
|
1711
|
+
return "lil error here.. :(";
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Replaces expressions marked by ${...} in the expression string with the provided values.
|
|
1717
|
+
*
|
|
1718
|
+
* @param {string} expression - The expression string containing the marked expressions.
|
|
1719
|
+
* @param {string[]} values - The values to be inserted into the marked expressions.
|
|
1720
|
+
* @returns {string} The expression string with the replacements made.
|
|
1721
|
+
*/
|
|
1722
|
+
replaceExpression(expression, values) {
|
|
1723
|
+
const regex3 = /\${(.*?)}/g;
|
|
1724
|
+
return expression.replace(regex3, () => values.shift() || "");
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Checks if an expression string contains string concatenation within a marked expression.
|
|
1728
|
+
*
|
|
1729
|
+
* @param {string} expression - The expression string to be checked.
|
|
1730
|
+
* @returns {boolean} True if the expression contains string concatenation, otherwise false.
|
|
1731
|
+
*/
|
|
1732
|
+
hasStringConcatenation(expression) {
|
|
1733
|
+
const regex3 = /^\${[^${}]*}$/;
|
|
1734
|
+
return !regex3.test(expression);
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Refreshes templates with updated values.
|
|
1738
|
+
*
|
|
1739
|
+
* @param {object} options - Options for refreshing templates.
|
|
1740
|
+
* @param {string} options.key - The key of the field triggering the update.
|
|
1741
|
+
* @param {TMutationEvents} options.event - Internal event descriptor to handle templating.
|
|
1742
|
+
*/
|
|
1743
|
+
refreshTemplates({ key, event }) {
|
|
1744
|
+
this.subscribedTemplates.forEach(
|
|
1745
|
+
({
|
|
1746
|
+
destinationKey,
|
|
1747
|
+
destinationPath,
|
|
1748
|
+
destinationProperty,
|
|
1749
|
+
originExpression,
|
|
1750
|
+
originFieldKeys
|
|
1751
|
+
}) => {
|
|
1752
|
+
if (originFieldKeys.includes(key)) {
|
|
1753
|
+
const originExpressions = this.extractParams(originExpression);
|
|
1754
|
+
let originValue;
|
|
1755
|
+
if (this.hasStringConcatenation(originExpression)) {
|
|
1756
|
+
originValue = this.replaceExpression(originExpression, [
|
|
1757
|
+
...originExpressions
|
|
1758
|
+
]);
|
|
1759
|
+
} else {
|
|
1760
|
+
originValue = originExpressions?.[0];
|
|
1761
|
+
}
|
|
1762
|
+
const destinationValue = this.getValue({
|
|
1763
|
+
key: destinationKey,
|
|
1764
|
+
property: destinationProperty,
|
|
1765
|
+
path: destinationPath
|
|
1766
|
+
});
|
|
1767
|
+
if (!isEqual2(destinationValue, originValue)) {
|
|
1768
|
+
this.setValue({
|
|
1769
|
+
key: destinationKey,
|
|
1770
|
+
property: destinationProperty,
|
|
1771
|
+
path: destinationPath,
|
|
1772
|
+
originKey: key,
|
|
1773
|
+
value: originValue,
|
|
1774
|
+
event
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Refreshes api observed fields.
|
|
1783
|
+
*
|
|
1784
|
+
* @param {object} options - Options for refreshing api.
|
|
1785
|
+
* @param {string} options.key - The key of the field triggering the update.
|
|
1786
|
+
*/
|
|
1787
|
+
refreshApi({ key }) {
|
|
1788
|
+
return key;
|
|
1789
|
+
}
|
|
1790
|
+
static {
|
|
1791
|
+
/**
|
|
1792
|
+
* Validates and collects the names of form fields in the provided schema structure.
|
|
1793
|
+
*
|
|
1794
|
+
* @param {IComponentSchema[]} [struct] - The schema structure of the form components.
|
|
1795
|
+
* @param {string[]} [indexes=[]] - An array to collect the names of the form fields.
|
|
1796
|
+
* @returns {string[]} - An array of form field names.
|
|
1797
|
+
* @throws {Error} - Throws an error if a field name matches the reserved name defined by `IVARPROPNAME`.
|
|
1798
|
+
* @private
|
|
1799
|
+
*/
|
|
1800
|
+
this.checkIndexes = (struct, indexes = []) => {
|
|
1801
|
+
if (!struct)
|
|
1802
|
+
return indexes;
|
|
1803
|
+
for (let i = 0; i < struct.length; i++) {
|
|
1804
|
+
const structElement = struct[i];
|
|
1805
|
+
if (structElement.name === IVARPROPNAME) {
|
|
1806
|
+
throw new Error(`reserved ${IVARPROPNAME} name for field names`);
|
|
1807
|
+
}
|
|
1808
|
+
indexes.push(structElement.name);
|
|
1809
|
+
if (structElement.children) {
|
|
1810
|
+
return _FormCore.checkIndexes(structElement.children, indexes);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
return indexes;
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Validates visibility conditions for a given event and updates field visibility accordingly.
|
|
1818
|
+
*
|
|
1819
|
+
* @param {object} options - Options for validating visibility.
|
|
1820
|
+
* @param {TEvents} options.event - The event triggering visibility validation.
|
|
1821
|
+
* @param {string} options.key - The key of the field.
|
|
1822
|
+
*/
|
|
1823
|
+
validateVisibility({ event, key }) {
|
|
1824
|
+
const field = this.fields.get(key);
|
|
1825
|
+
const structVisibility = field?.visibilityConditions;
|
|
1826
|
+
if (!structVisibility || !structVisibility?.some((config) => config.events.includes(event)))
|
|
1827
|
+
return;
|
|
1828
|
+
structVisibility.forEach((structElement) => {
|
|
1829
|
+
if (!structElement.events.includes(event))
|
|
1830
|
+
return;
|
|
1831
|
+
Object.keys(structElement.validations).forEach((validationKey) => {
|
|
1832
|
+
const error = validations2[validationKey](
|
|
1833
|
+
field.value,
|
|
1834
|
+
structElement.validations
|
|
1835
|
+
);
|
|
1836
|
+
if (Array.isArray(structElement.fields)) {
|
|
1837
|
+
structElement.fields.forEach((fieldKey) => {
|
|
1838
|
+
if (!this.fields.has(fieldKey))
|
|
1839
|
+
console.warn(
|
|
1840
|
+
`failed to update visibility onto field ${fieldKey}`
|
|
1841
|
+
);
|
|
1842
|
+
else
|
|
1843
|
+
this.fields.get(fieldKey).visibility = error;
|
|
1844
|
+
});
|
|
1845
|
+
} else if (structElement.fields) {
|
|
1846
|
+
if (!this.fields.has(structElement.fields))
|
|
1847
|
+
console.warn(
|
|
1848
|
+
`failed to update visibility onto field ${structElement.fields}`
|
|
1849
|
+
);
|
|
1850
|
+
else
|
|
1851
|
+
this.fields.get(structElement.fields).visibility = error;
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
/**
|
|
1857
|
+
* Resets field values based on reset conditions defined in the schema.
|
|
1858
|
+
*
|
|
1859
|
+
* @param {object} options - Options for resetting field values.
|
|
1860
|
+
* @param {TEvents} options.event - The event triggering the reset.
|
|
1861
|
+
* @param {string} options.key - The key of the field.
|
|
1862
|
+
*/
|
|
1863
|
+
resetValue({ event, key }) {
|
|
1864
|
+
const field = this.fields.get(key);
|
|
1865
|
+
const structResetValue = field?.resetValues;
|
|
1866
|
+
if (!structResetValue || !structResetValue?.some((config) => config.events.includes(event)))
|
|
1867
|
+
return;
|
|
1868
|
+
structResetValue.forEach((structElement) => {
|
|
1869
|
+
if (!structElement.events.includes(event))
|
|
1870
|
+
return;
|
|
1871
|
+
Object.keys(structElement.validations).forEach((validationKey) => {
|
|
1872
|
+
const error = validations2[validationKey](
|
|
1873
|
+
field.value,
|
|
1874
|
+
structElement.validations
|
|
1875
|
+
);
|
|
1876
|
+
if (!error) {
|
|
1877
|
+
if (Array.isArray(structElement.fields)) {
|
|
1878
|
+
structElement.fields.forEach((fieldKey, index) => {
|
|
1879
|
+
const resettledValue = Array.isArray(structElement.resettledValue) ? structElement.resettledValue[index] : structElement.resettledValue;
|
|
1880
|
+
if (!this.fields.has(fieldKey))
|
|
1881
|
+
console.warn(`failed to reset value onto field ${fieldKey}`);
|
|
1882
|
+
else
|
|
1883
|
+
this.fields.get(fieldKey).emitValue({
|
|
1884
|
+
value: resettledValue,
|
|
1885
|
+
event: "ON_FIELD_CHANGE"
|
|
1886
|
+
});
|
|
1887
|
+
});
|
|
1888
|
+
} else if (structElement.fields) {
|
|
1889
|
+
if (!this.fields.has(structElement.fields))
|
|
1890
|
+
console.warn(
|
|
1891
|
+
`failed to reset value onto field ${structElement.fields}`
|
|
1892
|
+
);
|
|
1893
|
+
else
|
|
1894
|
+
this.fields.get(structElement.fields).emitValue({
|
|
1895
|
+
value: structElement.resettledValue,
|
|
1896
|
+
event: "ON_FIELD_CHANGE"
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
});
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
/**
|
|
1904
|
+
* Serializes the schema structure to create form fields.
|
|
1905
|
+
*
|
|
1906
|
+
* @param {IComponentSchema[]} [struct] - The schema structure to serialize.
|
|
1907
|
+
* @param {string} [path] - The path of the parent component.
|
|
1908
|
+
*/
|
|
1909
|
+
serializeStructure(struct, path) {
|
|
1910
|
+
if (!struct)
|
|
1911
|
+
return;
|
|
1912
|
+
struct.forEach((structElement) => {
|
|
1913
|
+
const currField = this.fields.get(structElement.name);
|
|
1914
|
+
if (!currField) {
|
|
1915
|
+
const mapper = this.mappers.find(
|
|
1916
|
+
(mapEl) => mapEl.componentName === structElement.component
|
|
1917
|
+
);
|
|
1918
|
+
if (!mapper)
|
|
1919
|
+
throw new Error(
|
|
1920
|
+
`mapper not found for ${structElement.component}, add it to the mappers configuration`
|
|
1921
|
+
);
|
|
1922
|
+
this.fields.set(
|
|
1923
|
+
structElement.name,
|
|
1924
|
+
new FormField({
|
|
1925
|
+
schemaComponent: structElement,
|
|
1926
|
+
mapper,
|
|
1927
|
+
path,
|
|
1928
|
+
children: structElement.children ? structElement.children.map((el) => el.name) : [],
|
|
1929
|
+
validateVisibility: this.validateVisibility.bind(this),
|
|
1930
|
+
resetValue: this.resetValue.bind(this),
|
|
1931
|
+
initialValue: this.initialValues?.[structElement.name],
|
|
1932
|
+
templateSubject$: this.templateSubject$,
|
|
1933
|
+
apiResponseSubject$: this.apiResponseSubject$,
|
|
1934
|
+
dataSubject$: this.dataSubject$
|
|
1935
|
+
})
|
|
1936
|
+
);
|
|
1937
|
+
} else {
|
|
1938
|
+
currField.children = structElement?.children?.map((el) => el.name) || currField?.children || [];
|
|
1939
|
+
currField.path = path;
|
|
1940
|
+
currField.templateSubject$ = this.templateSubject$;
|
|
1941
|
+
}
|
|
1942
|
+
if (structElement.children) {
|
|
1943
|
+
return this.serializeStructure(
|
|
1944
|
+
structElement.children,
|
|
1945
|
+
`${path ? `${path}.` : ``}${structElement.name}`
|
|
1946
|
+
);
|
|
1947
|
+
}
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Refreshes form fields based on changes in the schema structure.
|
|
1952
|
+
*
|
|
1953
|
+
* @param {IComponentSchema[]} struct - The updated schema structure.
|
|
1954
|
+
*/
|
|
1955
|
+
refreshFields(struct) {
|
|
1956
|
+
const prevKeys = Array.from(this.fields.keys());
|
|
1957
|
+
this.serializeStructure(struct);
|
|
1958
|
+
const keys = _FormCore.checkIndexes(struct);
|
|
1959
|
+
this.fields.forEach((_, key) => {
|
|
1960
|
+
if (!keys.includes(key)) {
|
|
1961
|
+
this.fields.get(key)?.destroyField();
|
|
1962
|
+
this.fields.delete(key);
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
this.subscribeTemplates();
|
|
1966
|
+
this.fields.forEach((_, key) => {
|
|
1967
|
+
if (!prevKeys.includes(key)) {
|
|
1968
|
+
this.fields.get(key)?.emitEvents({ event: "ON_FIELD_MOUNT" });
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
this.subscribedTemplates.forEach((el) => {
|
|
1972
|
+
el.originFieldKeys.forEach((field) => {
|
|
1973
|
+
this.templateSubject$.next({ key: field, event: "ON_FIELDS" });
|
|
1974
|
+
});
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Gets a form field by its key.
|
|
1979
|
+
*
|
|
1980
|
+
* @param {object} options - Options for getting the form field.
|
|
1981
|
+
* @param {string} options.key - The key of the form field.
|
|
1982
|
+
* @returns {IFormField | undefined} The form field, or undefined if not found.
|
|
1983
|
+
*/
|
|
1984
|
+
getField({ key }) {
|
|
1985
|
+
return this.fields.get(key);
|
|
1986
|
+
}
|
|
1987
|
+
/**
|
|
1988
|
+
* Prints the current values of all form fields.
|
|
1989
|
+
*/
|
|
1990
|
+
printValues() {
|
|
1991
|
+
const values = {};
|
|
1992
|
+
this.fields.forEach((val, key) => {
|
|
1993
|
+
if (val.value) {
|
|
1994
|
+
values[key] = val.value;
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
console.log(values);
|
|
1998
|
+
}
|
|
1999
|
+
/**
|
|
2000
|
+
* Gets the current values of all form fields.
|
|
2001
|
+
*
|
|
2002
|
+
* @returns {TFormValues} The current form values.
|
|
2003
|
+
*/
|
|
2004
|
+
getFormValues() {
|
|
2005
|
+
const values = {};
|
|
2006
|
+
const erroredFields = [];
|
|
2007
|
+
this.fields.forEach((val, key) => {
|
|
2008
|
+
if (val.value) {
|
|
2009
|
+
values[key] = val.value;
|
|
2010
|
+
}
|
|
2011
|
+
if (!val.valid) {
|
|
2012
|
+
erroredFields.push(key);
|
|
2013
|
+
}
|
|
2014
|
+
});
|
|
2015
|
+
return {
|
|
2016
|
+
values,
|
|
2017
|
+
erroredFields,
|
|
2018
|
+
isValid: this.isValid
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* Submits the form by triggering form field events and invoking the onSubmit callback.
|
|
2023
|
+
*/
|
|
2024
|
+
submit() {
|
|
2025
|
+
this.fields.forEach((field) => {
|
|
2026
|
+
field.emitEvents({ event: "ON_FORM_SUBMIT" });
|
|
2027
|
+
});
|
|
2028
|
+
if (!this.isValid)
|
|
2029
|
+
return;
|
|
2030
|
+
const values = this.getFormValues();
|
|
2031
|
+
this.submitSubject$.next(values);
|
|
2032
|
+
this.onSubmit && this.onSubmit(values);
|
|
2033
|
+
}
|
|
2034
|
+
destroy() {
|
|
2035
|
+
this.submitSubject$.unsubscribe();
|
|
2036
|
+
this.templateSubject$.unsubscribe();
|
|
2037
|
+
this.apiResponseSubject$.unsubscribe();
|
|
2038
|
+
this.dataSubject$.unsubscribe();
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
|
|
2042
|
+
// libs/form-engine-core/src/managers/formGroup.ts
|
|
2043
|
+
var FormGroup = class {
|
|
2044
|
+
/**
|
|
2045
|
+
* Creates an instance of FormGroup.
|
|
2046
|
+
*/
|
|
2047
|
+
constructor() {
|
|
2048
|
+
this.forms = /* @__PURE__ */ new Map();
|
|
2049
|
+
}
|
|
2050
|
+
/**
|
|
2051
|
+
* Adds a form instance to the form group.
|
|
2052
|
+
*
|
|
2053
|
+
* @param {object} options - Options for adding a form.
|
|
2054
|
+
* @param {string} options.key - The key associated with the form instance.
|
|
2055
|
+
* @param {TFormCore} options.formInstance - The instance of the form to add.
|
|
2056
|
+
*/
|
|
2057
|
+
addForm({ key, formInstance }) {
|
|
2058
|
+
this.checkIndexes({ key });
|
|
2059
|
+
this.forms.set(key, formInstance);
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Retrieves a form instance from the form group.
|
|
2063
|
+
*
|
|
2064
|
+
* @param {object} options - Options for retrieving a form.
|
|
2065
|
+
* @param {string} options.key - The key associated with the form instance.
|
|
2066
|
+
* @returns {TFormCore | undefined} The instance of the form, if found; otherwise, undefined.
|
|
2067
|
+
*/
|
|
2068
|
+
getForm({ key }) {
|
|
2069
|
+
return this.forms.get(key);
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Removes a form instance from the form group.
|
|
2073
|
+
*
|
|
2074
|
+
* @param {object} options - Options for removing a form.
|
|
2075
|
+
* @param {string} options.key - The key associated with the form instance to remove.
|
|
2076
|
+
*/
|
|
2077
|
+
removeForm({ key }) {
|
|
2078
|
+
this.forms.get(key)?.destroy();
|
|
2079
|
+
this.forms.delete(key);
|
|
2080
|
+
}
|
|
2081
|
+
/**
|
|
2082
|
+
* Checks if the specified key already exists in the form group.
|
|
2083
|
+
*
|
|
2084
|
+
* @param {object} options - Options for checking the key.
|
|
2085
|
+
* @param {string} options.key - The key to check.
|
|
2086
|
+
* @throws {Error} Throws an error if the key already exists in the form group.
|
|
2087
|
+
*/
|
|
2088
|
+
checkIndexes({ key }) {
|
|
2089
|
+
if (this.forms.has(key)) {
|
|
2090
|
+
throw new Error(`duplicate index ${key} on form group`);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Prints the form group instance to the console.
|
|
2095
|
+
*/
|
|
2096
|
+
printFormGroupInstance() {
|
|
2097
|
+
console.log(this.forms);
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Prototype submit function to multiple forms
|
|
2101
|
+
* @param {string[]} indexes form indexes to be submitted
|
|
2102
|
+
* @returns
|
|
2103
|
+
*/
|
|
2104
|
+
submitMultipleFormsByIndex(indexes) {
|
|
2105
|
+
let isValid = true;
|
|
2106
|
+
let values = {};
|
|
2107
|
+
let erroredFields = [];
|
|
2108
|
+
indexes.forEach((index) => {
|
|
2109
|
+
const res = this.forms.get(index)?.getFormValues();
|
|
2110
|
+
isValid = isValid && (res?.isValid || false);
|
|
2111
|
+
values = { ...values, ...res?.values || {} };
|
|
2112
|
+
erroredFields = [...erroredFields, ...res?.erroredFields || []];
|
|
2113
|
+
});
|
|
2114
|
+
return {
|
|
2115
|
+
erroredFields,
|
|
2116
|
+
isValid,
|
|
2117
|
+
values
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
};
|
|
2121
|
+
export {
|
|
2122
|
+
FormCore,
|
|
2123
|
+
FormField,
|
|
2124
|
+
FormGroup,
|
|
2125
|
+
TMutationEnum
|
|
2126
|
+
};
|