@bolttech/form-engine-core 1.1.0-beta.0 → 1.1.1
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/CHANGELOG.md +36 -0
- package/credit-card.d.ts +743 -0
- package/credit-card.esm.js +1 -0
- package/currency.d.ts +131 -0
- package/currency.esm.js +1 -0
- package/date.d.ts +582 -0
- package/date.esm.js +1 -0
- package/document.d.ts +527 -0
- package/document.esm.js +1 -0
- package/index.d.ts +2393 -0
- package/index.esm.js +1 -4435
- package/lite.d.ts +2393 -0
- package/lite.esm.js +1 -0
- package/package.json +50 -10
- package/src/constants/constants.d.ts +2 -1
- package/src/helpers/SafeSubject.d.ts +12 -2
- package/src/helpers/helpers.d.ts +6 -6
- package/src/helpers/lodash-replacements.d.ts +41 -0
- package/src/helpers/validation.d.ts +2 -1
- package/src/index.d.ts +5 -0
- package/src/interfaces/schema.d.ts +28 -1
- package/src/lite.d.ts +30 -0
- package/src/managers/field.d.ts +20 -3
- package/src/managers/form.d.ts +8 -2
- package/src/masks/currency.d.ts +29 -0
- package/src/masks/handler.d.ts +1 -1
- package/src/masks/string.d.ts +0 -62
- package/src/plugins/credit-card.d.ts +4 -0
- package/src/plugins/currency.d.ts +2 -0
- package/src/plugins/date.d.ts +2 -0
- package/src/plugins/document.d.ts +2 -0
- package/src/registry.d.ts +20 -0
- package/src/types/schema.d.ts +42 -23
- package/src/types/utility.d.ts +7 -4
- package/src/validations/custom.d.ts +3 -1
- package/index.esm.d.ts +0 -1
package/index.esm.js
CHANGED
|
@@ -1,4435 +1 @@
|
|
|
1
|
-
import { Subject, Subscription, groupBy, mergeMap, debounceTime, filter, combineLatest, startWith, map, distinctUntilKeyChanged } from 'rxjs';
|
|
2
|
-
import creditCardType from 'credit-card-type';
|
|
3
|
-
import { isNumber as isNumber$1, isFunction, cloneDeep, isEqual, get, isNil, set } from 'lodash';
|
|
4
|
-
import { getCurrencySymbol } from '@gaignoux/currency';
|
|
5
|
-
|
|
6
|
-
var TMutationEnum;
|
|
7
|
-
(function (TMutationEnum) {
|
|
8
|
-
TMutationEnum["ON_VALUE"] = "value";
|
|
9
|
-
TMutationEnum["ON_PROPS"] = "props";
|
|
10
|
-
// ON_VALIDATION = 'valid',
|
|
11
|
-
TMutationEnum["ON_VISIBILITY"] = "visibility";
|
|
12
|
-
TMutationEnum["ON_API"] = "api";
|
|
13
|
-
TMutationEnum["ON_IVARS"] = "iVars";
|
|
14
|
-
TMutationEnum["ON_FIELDS"] = "fields";
|
|
15
|
-
})(TMutationEnum || (TMutationEnum = {}));
|
|
16
|
-
|
|
17
|
-
/******************************************************************************
|
|
18
|
-
Copyright (c) Microsoft Corporation.
|
|
19
|
-
|
|
20
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
21
|
-
purpose with or without fee is hereby granted.
|
|
22
|
-
|
|
23
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
24
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
25
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
26
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
27
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
28
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
29
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
30
|
-
***************************************************************************** */
|
|
31
|
-
|
|
32
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
33
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
34
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
35
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
36
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
37
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
38
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
43
|
-
var e = new Error(message);
|
|
44
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const DEFAULT_API_DEBOUNCE_TIME = 1000;
|
|
48
|
-
const DEFAULT_STATE_REFRESH_TIME = 100;
|
|
49
|
-
const TEMPLATE_REGEX_STRING_CONCATENATION_DETECTOR = /^\$\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}$/;
|
|
50
|
-
const TEMPLATE_REGEX_DELIMITATOR = /\$\{((?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*)\}/g;
|
|
51
|
-
const TEMPLATE_REGEX_OPERATOR_SPLITTER = /\s*(\|\||&&|!+)\s*/g;
|
|
52
|
-
const TEMPLATE_REGEX_OPERATOR_MATCHER = /^\|\||&&|!+$/;
|
|
53
|
-
const TEMPLATE_AVALIABLE_SCOPES = ['fields', 'iVars', 'form'];
|
|
54
|
-
const ALLOWED_RESET_PROPS_MUTATIONS = ['api', 'apiSchema', 'props', 'validations', 'visibilityConditions', 'resetValues'];
|
|
55
|
-
const DEFAULT_LOG_VERBOSE = false;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Makes an HTTP request using XMLHttpRequest.
|
|
59
|
-
*
|
|
60
|
-
* @param {string} method - The HTTP method (GET, POST, PUT, DELETE, etc.).
|
|
61
|
-
* @param {string} url - The URL to which the request is sent.
|
|
62
|
-
* @param {OutgoingHttpHeaders} [headers] - Optional request headers.
|
|
63
|
-
* @param {Record<string,unknown>} [body] - Optional object body.
|
|
64
|
-
* @returns {Promise<string>} A promise that resolves with the response text if the request is successful, otherwise rejects with an error message.
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```typescript
|
|
68
|
-
* const response = await makeRequest('GET', 'https://api.example.com/data');
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
function makeRequest(method, url, headers, body, queryParams) {
|
|
72
|
-
return new Promise(function (resolve, reject) {
|
|
73
|
-
const xhr = new XMLHttpRequest();
|
|
74
|
-
if (queryParams) {
|
|
75
|
-
const [baseUrl, existingParamsString] = url.split('?');
|
|
76
|
-
const searchParams = new URLSearchParams(existingParamsString);
|
|
77
|
-
Object.keys(queryParams).forEach(param => {
|
|
78
|
-
searchParams.append(param, queryParams[param]);
|
|
79
|
-
});
|
|
80
|
-
url = `${baseUrl}?${searchParams.toString()}`;
|
|
81
|
-
}
|
|
82
|
-
xhr.open(method, url, true);
|
|
83
|
-
if (headers) {
|
|
84
|
-
Object.keys(headers).forEach(header => {
|
|
85
|
-
xhr.setRequestHeader(header, headers[header]);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
xhr.onload = function () {
|
|
89
|
-
resolve({
|
|
90
|
-
status: xhr.status,
|
|
91
|
-
response: xhr.responseText
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
xhr.onerror = function () {
|
|
95
|
-
reject(xhr.statusText);
|
|
96
|
-
};
|
|
97
|
-
xhr.send(JSON.stringify(body) || null);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Extracts keys enclosed in `${}` from a given expression.
|
|
102
|
-
*
|
|
103
|
-
* @param {string} expression - The expression to extract keys from.
|
|
104
|
-
* @returns {
|
|
105
|
-
* originFieldKeys: string[];
|
|
106
|
-
* originPropertyKeys: string[];
|
|
107
|
-
* } An object containing the field names and properties from the template expression.
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```typescript
|
|
111
|
-
* const keys = extractFieldKeys('Hello ${name.value}, your age is ${age.props.label}.');
|
|
112
|
-
* // keys will be {originFieldKeys:['name', 'age'],originPropertyKeys:[value,props]}
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
function extractFieldKeys(expression) {
|
|
116
|
-
const regex = TEMPLATE_REGEX_DELIMITATOR;
|
|
117
|
-
const extractedValues = [];
|
|
118
|
-
let match;
|
|
119
|
-
while ((match = regex.exec(expression)) !== null) {
|
|
120
|
-
extractedValues.push(match[1]);
|
|
121
|
-
}
|
|
122
|
-
const operatorRegex = TEMPLATE_REGEX_OPERATOR_SPLITTER;
|
|
123
|
-
const splittedString = extractedValues.map(el => el.split(operatorRegex).filter(item => !operatorRegex.test(item))).flat().filter(el => el.split('.').length > 1);
|
|
124
|
-
return {
|
|
125
|
-
originScopeKeys: Array.from(new Set(splittedString.map(el => el.split('.')[0]))),
|
|
126
|
-
originFieldKeys: Array.from(new Set(splittedString.map(el => el.split('.')[1]))),
|
|
127
|
-
originPropertyKeys: Array.from(new Set(splittedString.map(el => el.split('.')[2])))
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Traverses an object and extracts expressions containing keys.
|
|
132
|
-
*
|
|
133
|
-
* @param {any} obj - The object to traverse.
|
|
134
|
-
* @param {string} [path] - Optional path within the object (used internally during recursion).
|
|
135
|
-
* @returns {TSubscribedTemplates[]} An array of extracted expressions along with their keys and paths.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```typescript
|
|
139
|
-
* const data = {
|
|
140
|
-
* user: {
|
|
141
|
-
* name: 'John',
|
|
142
|
-
* age: 30,
|
|
143
|
-
* address: {
|
|
144
|
-
* street: '123 Main St',
|
|
145
|
-
* city: 'Example City'
|
|
146
|
-
* }
|
|
147
|
-
* },
|
|
148
|
-
* message: 'Hello ${user.name}, your age is ${user.age}.'
|
|
149
|
-
* };
|
|
150
|
-
*
|
|
151
|
-
* const expressions = traverseObject(data);
|
|
152
|
-
* // expressions will contain an array of objects with origin expressions, field keys, and destination paths.
|
|
153
|
-
* ```
|
|
154
|
-
*/
|
|
155
|
-
function traverseObject(element, path) {
|
|
156
|
-
const result = [];
|
|
157
|
-
if (Array.isArray(element)) {
|
|
158
|
-
element.forEach((item, index) => {
|
|
159
|
-
result.push(...traverseObject(item, `${path ? `${path}.` : ``}${index}`));
|
|
160
|
-
});
|
|
161
|
-
} else if (typeof element === 'object') {
|
|
162
|
-
for (const key in element) {
|
|
163
|
-
if (Object.prototype.hasOwnProperty.call(element, key)) {
|
|
164
|
-
const value = element[key];
|
|
165
|
-
result.push(...traverseObject(value, `${path ? `${path}.` : ``}${key}`));
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
} else if (typeof element === 'string') {
|
|
169
|
-
if (element.includes('${')) {
|
|
170
|
-
// const extractedPath = value.replace(/\$|{|}/g, '').split('.');
|
|
171
|
-
const destinationPath = (path ? path : '').split('.');
|
|
172
|
-
// if(destinationPath[0])
|
|
173
|
-
const originfieldKeys = extractFieldKeys(element);
|
|
174
|
-
if (!originfieldKeys.originScopeKeys.every(scopeKey => TEMPLATE_AVALIABLE_SCOPES.includes(scopeKey))) {
|
|
175
|
-
console.warn(`scope malformed on this expression: ${element}, ignoring..`);
|
|
176
|
-
} else {
|
|
177
|
-
result.push(Object.assign(Object.assign({
|
|
178
|
-
originExpression: element
|
|
179
|
-
}, extractFieldKeys(element)), {
|
|
180
|
-
destinationKey: destinationPath[0],
|
|
181
|
-
destinationProperty: destinationPath[1],
|
|
182
|
-
destinationPath: destinationPath.slice(2)
|
|
183
|
-
}));
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return result;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Splits a string by inserting specified values at given positions.
|
|
192
|
-
*
|
|
193
|
-
* @param value - The value to be processed.
|
|
194
|
-
* @param formatters - An object containing formatting options.
|
|
195
|
-
* @returns The processed value with splitters applied.
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```typescript
|
|
199
|
-
* import { splitter } from './path/to/formatterFunctions';
|
|
200
|
-
*
|
|
201
|
-
* const processedValue = splitter('HelloWorld', { splitter: [{ position: 5, value: '_' }] });
|
|
202
|
-
* console.log(processedValue); // Output: 'Hello_World'
|
|
203
|
-
* ```
|
|
204
|
-
*/
|
|
205
|
-
const splitter = (value, formatters) => {
|
|
206
|
-
if (!value || !formatters.splitter || typeof value !== 'string') return value;
|
|
207
|
-
formatters.splitter.sort((a, b) => a.position - b.position);
|
|
208
|
-
let result = value;
|
|
209
|
-
let offset = 0;
|
|
210
|
-
for (const splitter of formatters.splitter) {
|
|
211
|
-
const {
|
|
212
|
-
position,
|
|
213
|
-
value
|
|
214
|
-
} = splitter;
|
|
215
|
-
const adjustedPosition = position + offset;
|
|
216
|
-
if (adjustedPosition >= 0 && adjustedPosition <= result.length) {
|
|
217
|
-
result = result.slice(0, adjustedPosition) + value + result.slice(adjustedPosition);
|
|
218
|
-
offset += value.length;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return result;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Capitalizes the first letter of a string.
|
|
226
|
-
*
|
|
227
|
-
* @param value - The value to be capitalized.
|
|
228
|
-
* @returns The value with the first letter capitalized.
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* ```typescript
|
|
232
|
-
* import { capitalize } from './path/to/formatterFunctions';
|
|
233
|
-
*
|
|
234
|
-
* const capitalizedValue = capitalize('hello world');
|
|
235
|
-
* console.log(capitalizedValue); // Output: 'Hello world'
|
|
236
|
-
* ```
|
|
237
|
-
*/
|
|
238
|
-
const capitalize = value => String(value).charAt(0).toUpperCase() + String(value).slice(1);
|
|
239
|
-
/**
|
|
240
|
-
* Converts a string to uppercase.
|
|
241
|
-
*
|
|
242
|
-
* @param value - The value to be converted.
|
|
243
|
-
* @returns The value in uppercase.
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* ```typescript
|
|
247
|
-
* import { uppercase } from './path/to/formatterFunctions';
|
|
248
|
-
*
|
|
249
|
-
* const uppercasedValue = uppercase('hello world');
|
|
250
|
-
* console.log(uppercasedValue); // Output: 'HELLO WORLD'
|
|
251
|
-
* ```
|
|
252
|
-
*/
|
|
253
|
-
const uppercase = value => String(value).toUpperCase();
|
|
254
|
-
/**
|
|
255
|
-
* Formats a string as a float number with a specific precision and decimal separator.
|
|
256
|
-
*
|
|
257
|
-
* @param value - The value to be formatted.
|
|
258
|
-
* @param formatters - An object containing formatting options.
|
|
259
|
-
* @returns The formatted float number.
|
|
260
|
-
*
|
|
261
|
-
* @example
|
|
262
|
-
* ```typescript
|
|
263
|
-
* import { onlyFloatNumber } from './path/to/formatterFunctions';
|
|
264
|
-
*
|
|
265
|
-
* const formattedNumber = onlyFloatNumber('1234567.89', { onlyFloatNumber: { precision: 2, decimal: '.' } });
|
|
266
|
-
* console.log(formattedNumber); // Output: '1234567.89'
|
|
267
|
-
* ```
|
|
268
|
-
*/
|
|
269
|
-
const onlyFloatNumber = (value, formatters) => {
|
|
270
|
-
const {
|
|
271
|
-
onlyFloatNumber
|
|
272
|
-
} = formatters;
|
|
273
|
-
if (!onlyFloatNumber || typeof value !== 'string' || !value) return value;
|
|
274
|
-
const {
|
|
275
|
-
precision = 2,
|
|
276
|
-
decimal = '.'
|
|
277
|
-
} = onlyFloatNumber;
|
|
278
|
-
if (!value.includes(decimal)) {
|
|
279
|
-
return value;
|
|
280
|
-
}
|
|
281
|
-
const replacedValue = value.replace(/[^0-9]/g, '');
|
|
282
|
-
const partOf = replacedValue.slice(0, replacedValue.length - precision);
|
|
283
|
-
const sliceOf = replacedValue.slice(replacedValue.length - precision);
|
|
284
|
-
return parseFloat(`${partOf}.${sliceOf}`).toFixed(precision);
|
|
285
|
-
};
|
|
286
|
-
/**
|
|
287
|
-
* Trims whitespace from the beginning and end of a string.
|
|
288
|
-
*
|
|
289
|
-
* @param value - The value to be trimmed.
|
|
290
|
-
* @param formatters - An object containing formatting options.
|
|
291
|
-
* @returns The trimmed value.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```typescript
|
|
295
|
-
* import { trim } from './path/to/formatterFunctions';
|
|
296
|
-
*
|
|
297
|
-
* const trimmedValue = trim(' hello world ');
|
|
298
|
-
* console.log(trimmedValue); // Output: 'hello world'
|
|
299
|
-
* ```
|
|
300
|
-
*/
|
|
301
|
-
const trim = (value, formatters) => {
|
|
302
|
-
if (!value || (formatters === null || formatters === void 0 ? void 0 : formatters.trim)) return value;
|
|
303
|
-
return String(value).trim();
|
|
304
|
-
};
|
|
305
|
-
/**
|
|
306
|
-
* Truncates the input value to a specified maximum length if necessary.
|
|
307
|
-
*
|
|
308
|
-
* @param {string | number} value - The input value to be formatted.
|
|
309
|
-
* @param {TFormatters} formatters - An object containing formatting options.
|
|
310
|
-
* @param {number} formatters.maxLength - The maximum allowed length for the input value.
|
|
311
|
-
* @returns {string | number} - The formatted value truncated to the maximum length, if applicable.
|
|
312
|
-
*
|
|
313
|
-
* @example
|
|
314
|
-
* ```typescript
|
|
315
|
-
* const result = maxLength('Hello, World!', { maxLength: 5 });
|
|
316
|
-
* console.log(result); // "Hello"
|
|
317
|
-
* ```
|
|
318
|
-
* @example
|
|
319
|
-
* ```typescript
|
|
320
|
-
* const result = maxLength(123456789, { maxLength: 4 });
|
|
321
|
-
* console.log(result); // "1234"
|
|
322
|
-
* ```
|
|
323
|
-
* @example
|
|
324
|
-
* ```typescript
|
|
325
|
-
* const result = maxLength('Short', { maxLength: 10 });
|
|
326
|
-
* console.log(result); // "Short" (no truncation since input is shorter than maxLength)
|
|
327
|
-
* ```
|
|
328
|
-
*/
|
|
329
|
-
const maxLength = (value, formatters) => {
|
|
330
|
-
if (!value || !formatters.maxLength) return value;
|
|
331
|
-
const input = String(value);
|
|
332
|
-
if (input.length > formatters.maxLength) {
|
|
333
|
-
return input.substring(0, formatters.maxLength);
|
|
334
|
-
}
|
|
335
|
-
return value;
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Removes all non-numeric characters from a string.
|
|
340
|
-
*
|
|
341
|
-
* @param value - The value to be processed.
|
|
342
|
-
* @returns The processed value with only numbers.
|
|
343
|
-
*
|
|
344
|
-
* @example
|
|
345
|
-
* ```typescript
|
|
346
|
-
* import { onlyNumbers } from './path/to/formatterFunctions';
|
|
347
|
-
*
|
|
348
|
-
* const processedValue = onlyNumbers('abc123def456');
|
|
349
|
-
* console.log(processedValue); // Output: '123456'
|
|
350
|
-
* ```
|
|
351
|
-
*/
|
|
352
|
-
const onlyNumbers = value => String(value).replace(/(\D)+/gim, '');
|
|
353
|
-
/**
|
|
354
|
-
* Removes all non-letter characters from a string.
|
|
355
|
-
*
|
|
356
|
-
* @param value - The value to be processed.
|
|
357
|
-
* @returns The processed value with only letters.
|
|
358
|
-
*
|
|
359
|
-
* @example
|
|
360
|
-
* ```typescript
|
|
361
|
-
* import { onlyLetters } from './path/to/formatterFunctions';
|
|
362
|
-
*
|
|
363
|
-
* const processedValue = onlyLetters('abc123def456');
|
|
364
|
-
* console.log(processedValue); // Output: 'abcdef'
|
|
365
|
-
* ```
|
|
366
|
-
*/
|
|
367
|
-
const onlyLetters$1 = value => String(value).replace(/[^\p{L}\s]/gu, '');
|
|
368
|
-
/**
|
|
369
|
-
* Applies a regular expression pattern to remove matching substrings from a string.
|
|
370
|
-
*
|
|
371
|
-
* @param value - The value to be processed.
|
|
372
|
-
* @param formatters - An object containing formatting options.
|
|
373
|
-
* @returns The processed value with matched substrings removed.
|
|
374
|
-
*
|
|
375
|
-
* @example
|
|
376
|
-
* ```typescript
|
|
377
|
-
* import { regex } from './path/to/formatterFunctions';
|
|
378
|
-
*
|
|
379
|
-
* const processedValue = regex('abc123def456', { regex: '\\d+' });
|
|
380
|
-
* console.log(processedValue); // Output: 'abcdef'
|
|
381
|
-
* ```
|
|
382
|
-
*/
|
|
383
|
-
const regex$1 = (value, formatters) => {
|
|
384
|
-
if (!formatters.regex) return value;
|
|
385
|
-
return String(value).replace(new RegExp(formatters.regex, 'g'), '');
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Retrieves the type of the credit card and the raw value without spaces.
|
|
390
|
-
*
|
|
391
|
-
* @param value - The credit card number as a string.
|
|
392
|
-
* @param availableOptions - An optional array of credit card types to consider.
|
|
393
|
-
* @returns An array containing the detected credit card type and the raw value without spaces.
|
|
394
|
-
*
|
|
395
|
-
* @example
|
|
396
|
-
* ```typescript
|
|
397
|
-
* import { getTypeCard } from './path/to/helperFunctions';
|
|
398
|
-
*
|
|
399
|
-
* const [creditCardType, rawValue] = getTypeCard('4111 1111 1111 1111');
|
|
400
|
-
* console.log(creditCardType); // Output: { niceType: 'Visa', type: 'visa', ... }
|
|
401
|
-
* console.log(rawValue); // Output: '4111111111111111'
|
|
402
|
-
* ```
|
|
403
|
-
*/
|
|
404
|
-
const getTypeCard = (value, availableOptions) => {
|
|
405
|
-
const rawValue = removeGaps(value === null || value === void 0 ? void 0 : value.toString());
|
|
406
|
-
const types = creditCardType(rawValue);
|
|
407
|
-
const selected = typeof availableOptions === 'object' && availableOptions.length ? types === null || types === void 0 ? void 0 : types.filter(({
|
|
408
|
-
type: id1
|
|
409
|
-
}) => availableOptions.some(id2 => id2 === id1))[0] : types[0];
|
|
410
|
-
return [selected, rawValue];
|
|
411
|
-
};
|
|
412
|
-
/**
|
|
413
|
-
* Removes all spaces from a string.
|
|
414
|
-
*
|
|
415
|
-
* @param value - The string to remove spaces from.
|
|
416
|
-
* @returns The string without spaces.
|
|
417
|
-
*/
|
|
418
|
-
const removeGaps = value => value === null || value === void 0 ? void 0 : value.replace(/ /g, '');
|
|
419
|
-
/**
|
|
420
|
-
* Adds specified gaps to a string based on given offsets.
|
|
421
|
-
*
|
|
422
|
-
* @param value - The string to add gaps to.
|
|
423
|
-
* @param gaps - An array containing gap positions.
|
|
424
|
-
* @returns The string with added gaps.
|
|
425
|
-
*/
|
|
426
|
-
const addGaps = (value, gaps = []) => {
|
|
427
|
-
const [regexString, replaceString] = gaps.reduce(([regexString, replaceString], offset, i) => {
|
|
428
|
-
const lastOffset = gaps[i - 1] || 0;
|
|
429
|
-
const digitNumber = offset - lastOffset;
|
|
430
|
-
return [`${regexString}([0-9]{0,${digitNumber}})`, `${replaceString}$${i + 1} `];
|
|
431
|
-
}, ['', '']);
|
|
432
|
-
return value.replace(new RegExp(regexString), replaceString).trim();
|
|
433
|
-
};
|
|
434
|
-
/**
|
|
435
|
-
* Formats a credit card number according to its type's gaps and lengths.
|
|
436
|
-
*
|
|
437
|
-
* @param value - The credit card number as a string.
|
|
438
|
-
* @param type - The type of the credit card.
|
|
439
|
-
* @returns The formatted credit card number.
|
|
440
|
-
*/
|
|
441
|
-
const formatValue = (value, type) => {
|
|
442
|
-
const DEFAULT_LENGTH = 19;
|
|
443
|
-
return type ? addGaps(value.slice(0, type === null || type === void 0 ? void 0 : type.lengths[0]), type.gaps) : value === null || value === void 0 ? void 0 : value.slice(0, DEFAULT_LENGTH);
|
|
444
|
-
};
|
|
445
|
-
/**
|
|
446
|
-
* Formats a date string by adding a prefix and/or trimming the string based on its length.
|
|
447
|
-
*
|
|
448
|
-
* @param value - The date string to be formatted.
|
|
449
|
-
* @param end - The ending index to slice the string to.
|
|
450
|
-
* @param prefix - The prefix to add between date components.
|
|
451
|
-
* @returns The formatted date string.
|
|
452
|
-
*
|
|
453
|
-
* @example
|
|
454
|
-
* ```typescript
|
|
455
|
-
* import { formatDateCard } from './path/to/helperFunctions';
|
|
456
|
-
*
|
|
457
|
-
* const formattedDate = formatDateCard('1223', 4, '/');
|
|
458
|
-
* console.log(formattedDate); // Output: '12/23'
|
|
459
|
-
* ```
|
|
460
|
-
*/
|
|
461
|
-
const formatDateCard = (value, end = 4, prefix = '/') => {
|
|
462
|
-
const fixedValue = value.replace(/\D/g, '');
|
|
463
|
-
const valZeroTwo = fixedValue.slice(0, 2);
|
|
464
|
-
return fixedValue.length >= 5 ? `${valZeroTwo}${prefix}${fixedValue.slice(2, end)}` : fixedValue.length >= 3 ? `${valZeroTwo}${prefix}${fixedValue.slice(2)}` : fixedValue;
|
|
465
|
-
};
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Formats a credit card number by adding gaps based on the card type.
|
|
469
|
-
*
|
|
470
|
-
* @param {unknown} value - The input value to be formatted, expected to be a string representing a credit card number.
|
|
471
|
-
* @param {TFormatters} formatters - An object containing formatting options.
|
|
472
|
-
* @param {boolean} formatters.gapsCreditCard - A flag indicating whether to apply credit card gap formatting.
|
|
473
|
-
* @returns {unknown} - The formatted credit card number with appropriate gaps, or the original value if formatting is not applied.
|
|
474
|
-
*
|
|
475
|
-
* @example
|
|
476
|
-
* ```typescript
|
|
477
|
-
* const formatters = { gapsCreditCard: true };
|
|
478
|
-
* const result = gapsCreditCard('4111111111111111', formatters);
|
|
479
|
-
* console.log(result); // "4111 1111 1111 1111" (formatted based on card type, e.g., Visa)
|
|
480
|
-
* ```
|
|
481
|
-
* @example
|
|
482
|
-
* ```typescript
|
|
483
|
-
* const formatters = { gapsCreditCard: false };
|
|
484
|
-
* const result = gapsCreditCard('4111111111111111', formatters);
|
|
485
|
-
* console.log(result); // "4111111111111111" (no formatting applied)
|
|
486
|
-
* ```
|
|
487
|
-
*/
|
|
488
|
-
const gapsCreditCard = (value, formatters) => {
|
|
489
|
-
if (!formatters.gapsCreditCard) return value;
|
|
490
|
-
const [type, rawValue] = getTypeCard(value, formatters === null || formatters === void 0 ? void 0 : formatters.gapsCreditCard);
|
|
491
|
-
return formatValue(rawValue, type);
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Applies a custom callback function to format a value.
|
|
496
|
-
*
|
|
497
|
-
* @param {unknown} value - The input value to be formatted.
|
|
498
|
-
* @param {TFormatters} formatters - An object containing formatting options.
|
|
499
|
-
* @param {(value: unknown) => unknown} formatters.callback - A custom callback function to apply to the value.
|
|
500
|
-
* @returns {unknown} - The value after applying the custom callback function, or the original value if no callback is provided.
|
|
501
|
-
*
|
|
502
|
-
* @example
|
|
503
|
-
* ```typescript
|
|
504
|
-
* const formatters = { callback: (val) => `Formatted: ${val}` };
|
|
505
|
-
* const result = callback('example', formatters);
|
|
506
|
-
* console.log(result); // "Formatted: example"
|
|
507
|
-
* ```
|
|
508
|
-
* @example
|
|
509
|
-
* ```typescript
|
|
510
|
-
* const formatters = { callback: (val) => val.toString().toUpperCase() };
|
|
511
|
-
* const result = callback('example', formatters);
|
|
512
|
-
* console.log(result); // "EXAMPLE"
|
|
513
|
-
* ```
|
|
514
|
-
* @example
|
|
515
|
-
* ```typescript
|
|
516
|
-
* const formatters = { callback: null };
|
|
517
|
-
* const result = callback('example', formatters);
|
|
518
|
-
* console.log(result); // "example" (no formatting applied)
|
|
519
|
-
* ```
|
|
520
|
-
*/
|
|
521
|
-
const callback$1 = (value, formatters) => {
|
|
522
|
-
if (!(formatters === null || formatters === void 0 ? void 0 : formatters.callback)) return value;
|
|
523
|
-
return formatters.callback(value);
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
const formatters = {
|
|
527
|
-
capitalize,
|
|
528
|
-
uppercase,
|
|
529
|
-
onlyNumbers,
|
|
530
|
-
onlyLetters: onlyLetters$1,
|
|
531
|
-
regex: regex$1,
|
|
532
|
-
splitter,
|
|
533
|
-
maxLength,
|
|
534
|
-
onlyFloatNumber,
|
|
535
|
-
trim,
|
|
536
|
-
gapsCreditCard,
|
|
537
|
-
callback: callback$1,
|
|
538
|
-
// todo: to be removed
|
|
539
|
-
dotEvery3chars: value => {
|
|
540
|
-
const result = String(value).replace(/\./g, '').replace(/(.{3})/g, '$1.');
|
|
541
|
-
return result.endsWith('.') ? result.slice(0, -1) : result;
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Applies multiple generic masks to a string based on the provided mask configuration.
|
|
547
|
-
*
|
|
548
|
-
* @param value - The value to be masked.
|
|
549
|
-
* @param masks - An object containing the mask configuration.
|
|
550
|
-
* @returns The masked value.
|
|
551
|
-
*
|
|
552
|
-
* @example
|
|
553
|
-
* ```typescript
|
|
554
|
-
* import maskValue from './path/to/maskFunctions';
|
|
555
|
-
*
|
|
556
|
-
* const masks = {
|
|
557
|
-
* generic: [
|
|
558
|
-
* { from: 2, to: 4, mask: '*' },
|
|
559
|
-
* { from: 7, to: 9, mask: '#' }
|
|
560
|
-
* ]
|
|
561
|
-
* };
|
|
562
|
-
*
|
|
563
|
-
* const maskedValue = maskValue('123456789', masks);
|
|
564
|
-
* console.log(maskedValue); // Output: '1**45###9'
|
|
565
|
-
*
|
|
566
|
-
* // Using from a JSON config
|
|
567
|
-
* const config = {
|
|
568
|
-
* value: 'abcdefghij',
|
|
569
|
-
* masks: {
|
|
570
|
-
* generic: [
|
|
571
|
-
* { from: 3, to: 6, mask: '*' },
|
|
572
|
-
* { from: 8, to: 10, mask: '#' }
|
|
573
|
-
* ]
|
|
574
|
-
* }
|
|
575
|
-
* };
|
|
576
|
-
*
|
|
577
|
-
* const maskedValue = maskValue(config.value, config.masks);
|
|
578
|
-
* console.log(maskedValue); // Output: 'ab***gh###'
|
|
579
|
-
* ```
|
|
580
|
-
*/
|
|
581
|
-
var generic = (value, masks) => {
|
|
582
|
-
if (!(masks === null || masks === void 0 ? void 0 : masks.generic)) return value;
|
|
583
|
-
let masked = value;
|
|
584
|
-
masks.generic.forEach(item => {
|
|
585
|
-
const {
|
|
586
|
-
to = masked.length,
|
|
587
|
-
mask
|
|
588
|
-
} = item;
|
|
589
|
-
let {
|
|
590
|
-
from
|
|
591
|
-
} = item;
|
|
592
|
-
if (to > value.length - 1) return;
|
|
593
|
-
if (from === 0) {
|
|
594
|
-
from = 1;
|
|
595
|
-
}
|
|
596
|
-
const maskedPortion = new Array(to - from + 2).join(mask);
|
|
597
|
-
masked = masked.slice(0, from - 1) + maskedPortion + masked.slice(to);
|
|
598
|
-
});
|
|
599
|
-
return masked;
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Replaces all characters in a string with a specified replacement string or character.
|
|
604
|
-
*
|
|
605
|
-
* @param value - The value to be masked.
|
|
606
|
-
* @param masks - An object containing the mask configuration.
|
|
607
|
-
* @returns The masked value.
|
|
608
|
-
*
|
|
609
|
-
* @example
|
|
610
|
-
* ```typescript
|
|
611
|
-
* import { replaceAll } from './path/to/maskFunctions';
|
|
612
|
-
*
|
|
613
|
-
* const masks = { replaceAll: '*' };
|
|
614
|
-
*
|
|
615
|
-
* const maskedValue = replaceAll('12345', masks);
|
|
616
|
-
* console.log(maskedValue); // Output: '*****'
|
|
617
|
-
*
|
|
618
|
-
* // Using from a JSON config
|
|
619
|
-
* const config = {
|
|
620
|
-
* value: 'hello',
|
|
621
|
-
* masks: { replaceAll: '*' }
|
|
622
|
-
* };
|
|
623
|
-
*
|
|
624
|
-
* const maskedValue = replaceAll(config.value, config.masks);
|
|
625
|
-
* console.log(maskedValue); // Output: '*****'
|
|
626
|
-
* ```
|
|
627
|
-
*/
|
|
628
|
-
const replaceAll = (value, masks) => {
|
|
629
|
-
let targetReplaceMask = masks.replaceAll;
|
|
630
|
-
if (!targetReplaceMask) return value;
|
|
631
|
-
if (typeof targetReplaceMask === 'number') {
|
|
632
|
-
targetReplaceMask = targetReplaceMask === null || targetReplaceMask === void 0 ? void 0 : targetReplaceMask.toString();
|
|
633
|
-
}
|
|
634
|
-
return new Array(String(value).length + 1).join(targetReplaceMask);
|
|
635
|
-
};
|
|
636
|
-
/**
|
|
637
|
-
* Formats a numeric value as a currency string based on the provided mask configuration.
|
|
638
|
-
*
|
|
639
|
-
* @param value - The numeric value to be formatted.
|
|
640
|
-
* @param masks - An object containing the mask configuration.
|
|
641
|
-
* @returns The formatted currency string.
|
|
642
|
-
*
|
|
643
|
-
* @example
|
|
644
|
-
* ```typescript
|
|
645
|
-
* import { currency } from './path/to/maskFunctions';
|
|
646
|
-
*
|
|
647
|
-
* const masks = {
|
|
648
|
-
* currency: {
|
|
649
|
-
* align: 'right',
|
|
650
|
-
* decimal: ',',
|
|
651
|
-
* precision: 2,
|
|
652
|
-
* prefix: 'USD',
|
|
653
|
-
* thousands: '.'
|
|
654
|
-
* }
|
|
655
|
-
* };
|
|
656
|
-
*
|
|
657
|
-
* const formattedValue = currency(12345.67, masks);
|
|
658
|
-
* console.log(formattedValue); // Output: '12.345,67 $'
|
|
659
|
-
*
|
|
660
|
-
* // Using from a JSON config
|
|
661
|
-
* const config = {
|
|
662
|
-
* value: 9876.54,
|
|
663
|
-
* masks: {
|
|
664
|
-
* currency: {
|
|
665
|
-
* align: 'right',
|
|
666
|
-
* decimal: ',',
|
|
667
|
-
* precision: 2,
|
|
668
|
-
* prefix: 'EUR',
|
|
669
|
-
* thousands: '.'
|
|
670
|
-
* }
|
|
671
|
-
* }
|
|
672
|
-
* };
|
|
673
|
-
*
|
|
674
|
-
* const formattedValue = currency(config.value, config.masks);
|
|
675
|
-
* console.log(formattedValue); // Output: '9.876,54 €'
|
|
676
|
-
*
|
|
677
|
-
* PS: To unCurrency this value, usage onlyFloatNumber formatter
|
|
678
|
-
* ```
|
|
679
|
-
*/
|
|
680
|
-
const currency = (value, masks) => {
|
|
681
|
-
if (!(masks === null || masks === void 0 ? void 0 : masks.currency)) return value;
|
|
682
|
-
const {
|
|
683
|
-
align = '',
|
|
684
|
-
decimal = '.',
|
|
685
|
-
precision = 2,
|
|
686
|
-
prefix = 'BBD',
|
|
687
|
-
thousands = ','
|
|
688
|
-
} = masks.currency;
|
|
689
|
-
const rawValue = isNumber$1(value) ? Number(value).toFixed(precision) : value;
|
|
690
|
-
let convertedValue = rawValue.replace(/[^0-9]/g, '');
|
|
691
|
-
if (!convertedValue) {
|
|
692
|
-
return '';
|
|
693
|
-
}
|
|
694
|
-
let integerPart = convertedValue.slice(0, convertedValue.length - precision).replace(/^0*/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, thousands);
|
|
695
|
-
if (integerPart === '') {
|
|
696
|
-
integerPart = '0';
|
|
697
|
-
}
|
|
698
|
-
if (align === 'right' && String(value).endsWith(' ')) {
|
|
699
|
-
convertedValue = convertedValue.slice(0, -1);
|
|
700
|
-
}
|
|
701
|
-
let newRawValue = integerPart;
|
|
702
|
-
let decimalPart = convertedValue.slice(convertedValue.length - precision);
|
|
703
|
-
if (precision > 0) {
|
|
704
|
-
decimalPart = '0'.repeat(precision - decimalPart.length) + decimalPart;
|
|
705
|
-
newRawValue += decimal + decimalPart;
|
|
706
|
-
}
|
|
707
|
-
if (!align) {
|
|
708
|
-
return newRawValue;
|
|
709
|
-
}
|
|
710
|
-
const symbol = getCurrencySymbol(prefix);
|
|
711
|
-
return align === 'left' ? `${symbol} ${newRawValue}` : `${newRawValue} ${symbol}`;
|
|
712
|
-
};
|
|
713
|
-
/**
|
|
714
|
-
* Applies a custom mask to a string based on the provided mask configuration.
|
|
715
|
-
*
|
|
716
|
-
* @param value - The value to be masked.
|
|
717
|
-
* @param masks - An object containing the mask configuration.
|
|
718
|
-
* @returns The masked value.
|
|
719
|
-
*
|
|
720
|
-
* @example
|
|
721
|
-
* ```typescript
|
|
722
|
-
* import { custom } from './path/to/maskFunctions';
|
|
723
|
-
*
|
|
724
|
-
* const masks = { custom: '##-##' };
|
|
725
|
-
*
|
|
726
|
-
* const maskedValue = custom('123456', masks);
|
|
727
|
-
* console.log(maskedValue); // Output: '12-34'
|
|
728
|
-
*
|
|
729
|
-
* // Using from a JSON config
|
|
730
|
-
* const config = {
|
|
731
|
-
* masks: { custom: '###-###' }
|
|
732
|
-
* };
|
|
733
|
-
*
|
|
734
|
-
* const maskedValue = custom(config.value, config.masks);
|
|
735
|
-
* console.log(maskedValue); // Output: '987-654'
|
|
736
|
-
* ```
|
|
737
|
-
*/
|
|
738
|
-
const custom = (value, masks) => {
|
|
739
|
-
if (!masks.custom || !value) return value;
|
|
740
|
-
let mask = '';
|
|
741
|
-
let index = 0;
|
|
742
|
-
const convertedValue = value.replace(/[^\w\s]/gi, '');
|
|
743
|
-
for (const char of masks.custom) {
|
|
744
|
-
if (char === '#') {
|
|
745
|
-
if (index < convertedValue.length) {
|
|
746
|
-
mask += convertedValue[index];
|
|
747
|
-
index++;
|
|
748
|
-
} else {
|
|
749
|
-
break;
|
|
750
|
-
}
|
|
751
|
-
} else if (index <= convertedValue.length) {
|
|
752
|
-
mask += char;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
if (value.length < mask.length) {
|
|
756
|
-
mask = mask.replace(/[^\w]+$/, '');
|
|
757
|
-
}
|
|
758
|
-
return mask;
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
/**
|
|
762
|
-
* Applies a secure mask to a credit card number, hiding most of its digits.
|
|
763
|
-
*
|
|
764
|
-
* @param value - The credit card number to be masked.
|
|
765
|
-
* @returns The masked credit card number.
|
|
766
|
-
*
|
|
767
|
-
* @example
|
|
768
|
-
* ```typescript
|
|
769
|
-
* import { secureCreditCard } from './path/to/creditCardFunctions';
|
|
770
|
-
*
|
|
771
|
-
* const maskedCardNumber = secureCreditCard('1234567890123456');
|
|
772
|
-
* console.log(maskedCardNumber); // Output: '1xxxxxxxxxxxx456'
|
|
773
|
-
* ```
|
|
774
|
-
*/
|
|
775
|
-
const secureCreditCard = value => {
|
|
776
|
-
const maskValue = [{
|
|
777
|
-
from: 1,
|
|
778
|
-
to: 4,
|
|
779
|
-
mask: 'x'
|
|
780
|
-
}, {
|
|
781
|
-
from: 6,
|
|
782
|
-
to: 9,
|
|
783
|
-
mask: 'x'
|
|
784
|
-
}, {
|
|
785
|
-
from: 11,
|
|
786
|
-
to: 14,
|
|
787
|
-
mask: 'x'
|
|
788
|
-
}, {
|
|
789
|
-
from: 16,
|
|
790
|
-
to: 19,
|
|
791
|
-
mask: 'x'
|
|
792
|
-
}];
|
|
793
|
-
return generic(value, {
|
|
794
|
-
generic: maskValue
|
|
795
|
-
});
|
|
796
|
-
};
|
|
797
|
-
/**
|
|
798
|
-
* Formats a credit card number by inserting spaces every four characters.
|
|
799
|
-
*
|
|
800
|
-
* @param value - The credit card number to be formatted.
|
|
801
|
-
* @returns The formatted credit card number.
|
|
802
|
-
*
|
|
803
|
-
* @example
|
|
804
|
-
* ```typescript
|
|
805
|
-
* import { card } from './path/to/creditCardFunctions';
|
|
806
|
-
*
|
|
807
|
-
* const formattedCardNumber = card('1234567890123456');
|
|
808
|
-
* console.log(formattedCardNumber); // Output: '1234 5678 9012 3456'
|
|
809
|
-
* ```
|
|
810
|
-
*/
|
|
811
|
-
const card = value => {
|
|
812
|
-
return value.replace(/[^\dA-Z]/g, '').replace(/(.{4})/g, '$1 ').trim();
|
|
813
|
-
};
|
|
814
|
-
/**
|
|
815
|
-
* Formats a credit card expiration date (MM/YY).
|
|
816
|
-
*
|
|
817
|
-
* @param value - The expiration date to be formatted (in MMYY or MM/YY format).
|
|
818
|
-
* @returns The formatted expiration date.
|
|
819
|
-
*
|
|
820
|
-
* @example
|
|
821
|
-
* ```typescript
|
|
822
|
-
* import { cardDate } from './path/to/creditCardFunctions';
|
|
823
|
-
*
|
|
824
|
-
* const formattedCardDate = cardDate('1223');
|
|
825
|
-
* console.log(formattedCardDate); // Output: '12/23'
|
|
826
|
-
* ```
|
|
827
|
-
*/
|
|
828
|
-
const cardDate = value => formatDateCard(value);
|
|
829
|
-
/**
|
|
830
|
-
* Formats a credit card FEIN (Federal Employer Identification Number) in a specific format.
|
|
831
|
-
*
|
|
832
|
-
* @param value - The FEIN to be formatted.
|
|
833
|
-
* @returns The formatted FEIN.
|
|
834
|
-
*
|
|
835
|
-
* @example
|
|
836
|
-
* ```typescript
|
|
837
|
-
* import { fein } from './path/to/creditCardFunctions';
|
|
838
|
-
*
|
|
839
|
-
* const formattedFEIN = fein('123456789');
|
|
840
|
-
* console.log(formattedFEIN); // Output: '12-3456789'
|
|
841
|
-
* ```
|
|
842
|
-
*/
|
|
843
|
-
const fein = value => formatDateCard(value, 9, '-');
|
|
844
|
-
|
|
845
|
-
const masks = {
|
|
846
|
-
currency,
|
|
847
|
-
custom,
|
|
848
|
-
callback: (value, masks) => (masks === null || masks === void 0 ? void 0 : masks.callback) && masks.callback(value),
|
|
849
|
-
generic,
|
|
850
|
-
secureCreditCard,
|
|
851
|
-
card,
|
|
852
|
-
cardDate,
|
|
853
|
-
fein,
|
|
854
|
-
replaceAll
|
|
855
|
-
};
|
|
856
|
-
|
|
857
|
-
/**
|
|
858
|
-
* Validates the length of a value based on the provided validation rules.
|
|
859
|
-
*
|
|
860
|
-
* @param value - The value to be validated. Can be of any type but will be converted to a string for length validation.
|
|
861
|
-
* @param validations - An object containing the length validation rules.
|
|
862
|
-
* @returns `true` if the value meets the length validation rule, otherwise `false`.
|
|
863
|
-
*
|
|
864
|
-
* @example
|
|
865
|
-
* ```typescript
|
|
866
|
-
* import validateLength from './path/to/validationFunctions';
|
|
867
|
-
*
|
|
868
|
-
* const validations = {
|
|
869
|
-
* length: {
|
|
870
|
-
* target: 5,
|
|
871
|
-
* rule: 'equal'
|
|
872
|
-
* }
|
|
873
|
-
* };
|
|
874
|
-
*
|
|
875
|
-
* const isValid = validateLength('hello', validations);
|
|
876
|
-
* console.log(isValid); // Output: true
|
|
877
|
-
*
|
|
878
|
-
* // Using from a JSON config
|
|
879
|
-
* const config = {
|
|
880
|
-
* inputValue: 'test',
|
|
881
|
-
* validations: {
|
|
882
|
-
* length: {
|
|
883
|
-
* target: 4,
|
|
884
|
-
* rule: 'equal'
|
|
885
|
-
* }
|
|
886
|
-
* }
|
|
887
|
-
* };
|
|
888
|
-
*
|
|
889
|
-
* const isValid = validateLength(config.inputValue, config.validations);
|
|
890
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
891
|
-
* ```
|
|
892
|
-
*/
|
|
893
|
-
var length = (value, validations) => {
|
|
894
|
-
if (!validations.length || !value) return false;
|
|
895
|
-
let targetValue = value;
|
|
896
|
-
// We want length even if it is a numeric
|
|
897
|
-
if (typeof targetValue !== 'string') {
|
|
898
|
-
targetValue = (value === null || value === void 0 ? void 0 : value.toString()) || targetValue;
|
|
899
|
-
}
|
|
900
|
-
const condition = {
|
|
901
|
-
equal: targetValue.length !== validations.length.target,
|
|
902
|
-
notEqual: targetValue.length === validations.length.target,
|
|
903
|
-
less: targetValue.length >= validations.length.target,
|
|
904
|
-
lessOrEqual: targetValue.length > validations.length.target,
|
|
905
|
-
greater: targetValue.length <= validations.length.target,
|
|
906
|
-
greaterOrEqual: targetValue.length < validations.length.target
|
|
907
|
-
};
|
|
908
|
-
return condition[validations.length.rule];
|
|
909
|
-
};
|
|
910
|
-
|
|
911
|
-
/**
|
|
912
|
-
* Validates a Spanish NIF (Número de Identificación Fiscal).
|
|
913
|
-
*
|
|
914
|
-
* @param value - The NIF value to validate.
|
|
915
|
-
* @returns `true` if the NIF is invalid, otherwise `false`.
|
|
916
|
-
*/
|
|
917
|
-
const NIF_ES = value => {
|
|
918
|
-
if (value.length !== 9) return true;
|
|
919
|
-
if (!/^\d{8}$/.test(value.slice(0, 8))) {
|
|
920
|
-
return true;
|
|
921
|
-
}
|
|
922
|
-
const validLetters = 'TRWAGMYFPDXBNJZSQVHLCKE';
|
|
923
|
-
const numberPart = parseInt(value.slice(0, 8), 10);
|
|
924
|
-
const expectedLetter = validLetters[numberPart % 23];
|
|
925
|
-
return !(value[8].toUpperCase() === expectedLetter);
|
|
926
|
-
};
|
|
927
|
-
/**
|
|
928
|
-
* Validates a Portuguese NIF (Número de Identificação Fiscal).
|
|
929
|
-
*
|
|
930
|
-
* @param value - The NIF value to validate.
|
|
931
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
932
|
-
*/
|
|
933
|
-
const NIF_PT = value => {
|
|
934
|
-
const regex = /^\d{9}$/;
|
|
935
|
-
if (!regex.test(value)) return false;
|
|
936
|
-
const checkDigit = parseInt(value[8], 10);
|
|
937
|
-
const sum = Array.from(value.substring(0, 8)).reduce((acc, digit, index) => acc + parseInt(digit, 10) * (9 - index), 0);
|
|
938
|
-
const calculatedCheckDigit = 11 - sum % 11;
|
|
939
|
-
return calculatedCheckDigit === 10 || calculatedCheckDigit === 11 ? 0 === checkDigit : calculatedCheckDigit === checkDigit;
|
|
940
|
-
};
|
|
941
|
-
/**
|
|
942
|
-
* Validates an Italian NIF (Codice Fiscale).
|
|
943
|
-
*
|
|
944
|
-
* @param value - The NIF value to validate.
|
|
945
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
946
|
-
*/
|
|
947
|
-
const NIF_IT = value => {
|
|
948
|
-
const regex = /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/;
|
|
949
|
-
return regex.test(value);
|
|
950
|
-
};
|
|
951
|
-
/**
|
|
952
|
-
* Validates a German NIF (Steuerliche Identifikationsnummer).
|
|
953
|
-
*
|
|
954
|
-
* @param nif - The NIF value to validate.
|
|
955
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
956
|
-
*/
|
|
957
|
-
const NIF_DE = nif => {
|
|
958
|
-
const regex = /^\d{11}$/;
|
|
959
|
-
return regex.test(nif);
|
|
960
|
-
};
|
|
961
|
-
/**
|
|
962
|
-
* Validates a French NIF (Numéro d'Immatriculation Fiscale).
|
|
963
|
-
*
|
|
964
|
-
* @param nif - The NIF value to validate.
|
|
965
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
966
|
-
*/
|
|
967
|
-
const NIF_FR = nif => {
|
|
968
|
-
const regex = /^\d{2} \d{3} \d{3} \d{3} \d{3}$/;
|
|
969
|
-
return regex.test(nif);
|
|
970
|
-
};
|
|
971
|
-
/**
|
|
972
|
-
* Validates a UK NIF (National Insurance Number).
|
|
973
|
-
*
|
|
974
|
-
* @param value - The NIF value to validate.
|
|
975
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
976
|
-
*/
|
|
977
|
-
const NIF_UK = value => {
|
|
978
|
-
const regex = /^GB\d{9}|\d{12}|\d{3}[A-Z]{5}$/;
|
|
979
|
-
return regex.test(value);
|
|
980
|
-
};
|
|
981
|
-
/**
|
|
982
|
-
* Validates a Belgian NIF (Numéro d'Identification Fiscale).
|
|
983
|
-
*
|
|
984
|
-
* @param value - The NIF value to validate.
|
|
985
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
986
|
-
*/
|
|
987
|
-
const NIF_BE = value => {
|
|
988
|
-
const regex = /^\d{11}$/;
|
|
989
|
-
if (!regex.test(value)) return false;
|
|
990
|
-
const number = parseInt(value.substring(0, 9), 10);
|
|
991
|
-
const checkDigits = parseInt(value.substring(9), 10);
|
|
992
|
-
const mod = 97 - number % 97;
|
|
993
|
-
return mod === checkDigits;
|
|
994
|
-
};
|
|
995
|
-
/**
|
|
996
|
-
* Validates a Dutch NIF (Burgerservicenummer).
|
|
997
|
-
*
|
|
998
|
-
* @param value - The NIF value to validate.
|
|
999
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
1000
|
-
*/
|
|
1001
|
-
const NIF_NL = value => {
|
|
1002
|
-
const regex = /^\d{9}$/;
|
|
1003
|
-
if (!regex.test(value)) return false;
|
|
1004
|
-
const total = value.split('').map((digit, index) => parseInt(digit, 10) * (9 - index)).reduce((sum, val) => sum + val, 0);
|
|
1005
|
-
return total % 11 === 0;
|
|
1006
|
-
};
|
|
1007
|
-
/**
|
|
1008
|
-
* Validates a Swedish NIF (Personnummer).
|
|
1009
|
-
*
|
|
1010
|
-
* @param value - The NIF value to validate.
|
|
1011
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
1012
|
-
*/
|
|
1013
|
-
const NIF_SE = value => {
|
|
1014
|
-
const regex = /^\d{10,12}$/;
|
|
1015
|
-
if (!regex.test(value)) return false;
|
|
1016
|
-
const normalizedNIF = value.length === 12 ? value.substring(2) : value;
|
|
1017
|
-
const total = normalizedNIF.split('').map((digit, index) => {
|
|
1018
|
-
let num = parseInt(digit, 10) * (index % 2 === 0 ? 2 : 1);
|
|
1019
|
-
if (num > 9) num -= 9;
|
|
1020
|
-
return num;
|
|
1021
|
-
}).reduce((sum, val) => sum + val, 0);
|
|
1022
|
-
return total % 10 === 0;
|
|
1023
|
-
};
|
|
1024
|
-
/**
|
|
1025
|
-
* Validates a NIF based on the locale.
|
|
1026
|
-
*
|
|
1027
|
-
* @param nif - The NIF value to validate.
|
|
1028
|
-
* @param locale - The locale code to determine the type of NIF.
|
|
1029
|
-
* @returns `true` if the NIF is valid, otherwise `false`.
|
|
1030
|
-
*
|
|
1031
|
-
* @example
|
|
1032
|
-
* ```typescript
|
|
1033
|
-
* import { NIF } from './path/to/validationFunctions';
|
|
1034
|
-
*
|
|
1035
|
-
* const isValid = NIF('123456789', 'pt-PT');
|
|
1036
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
1037
|
-
* ```
|
|
1038
|
-
*/
|
|
1039
|
-
const NIF = (nif, locale) => {
|
|
1040
|
-
switch (locale) {
|
|
1041
|
-
case 'pt-PT':
|
|
1042
|
-
return NIF_PT(nif);
|
|
1043
|
-
case 'es-ES':
|
|
1044
|
-
return NIF_ES(nif);
|
|
1045
|
-
case 'it-IT':
|
|
1046
|
-
return NIF_IT(nif);
|
|
1047
|
-
case 'de-DE':
|
|
1048
|
-
return NIF_DE(nif);
|
|
1049
|
-
case 'fr-FR':
|
|
1050
|
-
return NIF_FR(nif);
|
|
1051
|
-
case 'en-GB':
|
|
1052
|
-
return NIF_UK(nif);
|
|
1053
|
-
case 'nl-BE':
|
|
1054
|
-
case 'fr-BE':
|
|
1055
|
-
return NIF_BE(nif);
|
|
1056
|
-
case 'nl-NL':
|
|
1057
|
-
return NIF_NL(nif);
|
|
1058
|
-
case 'sv-SE':
|
|
1059
|
-
// Suécia
|
|
1060
|
-
return NIF_SE(nif);
|
|
1061
|
-
default:
|
|
1062
|
-
throw new Error(`NIF validation not supported for locale: ${locale}`);
|
|
1063
|
-
}
|
|
1064
|
-
};
|
|
1065
|
-
/**
|
|
1066
|
-
* Validates a Spanish NIE (Número de Identificación de Extranjeros).
|
|
1067
|
-
*
|
|
1068
|
-
* @param value - The NIE value to validate.
|
|
1069
|
-
* @returns `true` if the NIE is invalid, otherwise `false`.
|
|
1070
|
-
*/
|
|
1071
|
-
const NIE = value => {
|
|
1072
|
-
if (value.length !== 9) return true;
|
|
1073
|
-
const nieRegex = /^[XYZ]\d{7}[TRWAGMYFPDXBNJZSQVHLCKE]$/;
|
|
1074
|
-
if (!nieRegex.test(value)) {
|
|
1075
|
-
return true;
|
|
1076
|
-
}
|
|
1077
|
-
let fixedDocNumber = value.toUpperCase().padStart(9, '0');
|
|
1078
|
-
fixedDocNumber = fixedDocNumber[0].replace(/[XYZ]/g, char => {
|
|
1079
|
-
return {
|
|
1080
|
-
X: '0',
|
|
1081
|
-
Y: '1',
|
|
1082
|
-
Z: '2'
|
|
1083
|
-
}[char] || char;
|
|
1084
|
-
}) + fixedDocNumber.slice(1);
|
|
1085
|
-
return NIF_ES(fixedDocNumber);
|
|
1086
|
-
};
|
|
1087
|
-
const mod9710 = validationString => {
|
|
1088
|
-
while (validationString.length > 2) {
|
|
1089
|
-
const part = validationString.slice(0, 6);
|
|
1090
|
-
const partInt = parseInt(part, 10);
|
|
1091
|
-
if (isNaN(partInt)) {
|
|
1092
|
-
return NaN;
|
|
1093
|
-
}
|
|
1094
|
-
validationString = partInt % 97 + validationString.slice(part.length);
|
|
1095
|
-
}
|
|
1096
|
-
return parseInt(validationString, 10) % 97;
|
|
1097
|
-
};
|
|
1098
|
-
/**
|
|
1099
|
-
* Validates an IBAN (International Bank Account Number).
|
|
1100
|
-
*
|
|
1101
|
-
* @param value - The IBAN value to validate.
|
|
1102
|
-
* @returns `true` if the IBAN is invalid, otherwise `false`.
|
|
1103
|
-
*/
|
|
1104
|
-
const IBAN = value => {
|
|
1105
|
-
const iban = value.replace(/\s/g, '');
|
|
1106
|
-
if (iban.length !== 24) return true;
|
|
1107
|
-
const ibanRegex = /^(ES)[0-9]{22}$/;
|
|
1108
|
-
if (!ibanRegex.test(iban)) {
|
|
1109
|
-
return true;
|
|
1110
|
-
}
|
|
1111
|
-
const ES_ALPHABET_NUMBER = 1428;
|
|
1112
|
-
const transformedIban = iban.substring(4) + ES_ALPHABET_NUMBER + iban.substring(2, 4);
|
|
1113
|
-
return mod9710(transformedIban) !== 1;
|
|
1114
|
-
};
|
|
1115
|
-
/**
|
|
1116
|
-
* Validates a Spanish CIF (Código de Identificación Fiscal).
|
|
1117
|
-
*
|
|
1118
|
-
* @param value - The CIF value to validate.
|
|
1119
|
-
* @returns `true` if the CIF is invalid, otherwise `false`.
|
|
1120
|
-
*/
|
|
1121
|
-
const CIF = value => {
|
|
1122
|
-
const cifRegex = /^[A-Z][0-9]{7}[A-J0-9]$/;
|
|
1123
|
-
return !cifRegex.test(value);
|
|
1124
|
-
};
|
|
1125
|
-
/**
|
|
1126
|
-
* General validation function for various document types based on the provided validation methods.
|
|
1127
|
-
*
|
|
1128
|
-
* @param value - The document value to validate.
|
|
1129
|
-
* @param validations - An object containing validation methods.
|
|
1130
|
-
* @returns `true` if the document is valid, otherwise `false`.
|
|
1131
|
-
*
|
|
1132
|
-
* @example
|
|
1133
|
-
* ```typescript
|
|
1134
|
-
* import validateDocument from './path/to/validationFunctions';
|
|
1135
|
-
*
|
|
1136
|
-
* const validations = {
|
|
1137
|
-
* document: {
|
|
1138
|
-
* type: 'NIF',
|
|
1139
|
-
* locale: 'pt-PT'
|
|
1140
|
-
* }
|
|
1141
|
-
* };
|
|
1142
|
-
*
|
|
1143
|
-
* const isValid = validateDocument('123456789', validations);
|
|
1144
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
1145
|
-
* ```
|
|
1146
|
-
*/
|
|
1147
|
-
var document = (value, validations) => {
|
|
1148
|
-
if (!value || !validations.document) return true;
|
|
1149
|
-
const validation = {
|
|
1150
|
-
NIF: (value, locale) => NIF(value, locale),
|
|
1151
|
-
NIE: value => NIE(value),
|
|
1152
|
-
CIF: value => CIF(value),
|
|
1153
|
-
IBAN: value => IBAN(value)
|
|
1154
|
-
};
|
|
1155
|
-
return validation[validations.document.type](value, validations.document.locale);
|
|
1156
|
-
};
|
|
1157
|
-
|
|
1158
|
-
/**
|
|
1159
|
-
* Validates if a value exceeds the maximum allowed value.
|
|
1160
|
-
*
|
|
1161
|
-
* @param value - The value to be checked.
|
|
1162
|
-
* @param validations - An object containing the maximum value for validation.
|
|
1163
|
-
* @returns `true` if the value exceeds the maximum, otherwise `false`.
|
|
1164
|
-
*
|
|
1165
|
-
* @example
|
|
1166
|
-
* ```typescript
|
|
1167
|
-
* import { max } from './path/to/validationFunctions';
|
|
1168
|
-
*
|
|
1169
|
-
* const validations = { max: 10 };
|
|
1170
|
-
*
|
|
1171
|
-
* const isValid = max(15, validations);
|
|
1172
|
-
* console.log(isValid); // Output: true
|
|
1173
|
-
*
|
|
1174
|
-
* // Using from a JSON config
|
|
1175
|
-
* const config = {
|
|
1176
|
-
* inputValue: '8',
|
|
1177
|
-
* validations: { max: 10 }
|
|
1178
|
-
* };
|
|
1179
|
-
*
|
|
1180
|
-
* const isValid = max(config.inputValue, config.validations);
|
|
1181
|
-
* console.log(isValid); // Output: false
|
|
1182
|
-
* ```
|
|
1183
|
-
*/
|
|
1184
|
-
const max = (value, validations) => {
|
|
1185
|
-
const number = Number(value);
|
|
1186
|
-
if (!validations.max || Number.isNaN(number)) return false;
|
|
1187
|
-
return number > Number(validations.max);
|
|
1188
|
-
};
|
|
1189
|
-
/**
|
|
1190
|
-
* Validates if a value is less than the minimum allowed value.
|
|
1191
|
-
*
|
|
1192
|
-
* @param value - The value to be checked.
|
|
1193
|
-
* @param validations - An object containing the minimum value for validation.
|
|
1194
|
-
* @returns `true` if the value is less than the minimum, otherwise `false`.
|
|
1195
|
-
*
|
|
1196
|
-
* @example
|
|
1197
|
-
* ```typescript
|
|
1198
|
-
* import { min } from './path/to/validationFunctions';
|
|
1199
|
-
*
|
|
1200
|
-
* const validations = { min: 5 };
|
|
1201
|
-
*
|
|
1202
|
-
* const isValid = min(3, validations);
|
|
1203
|
-
* console.log(isValid); // Output: true
|
|
1204
|
-
*
|
|
1205
|
-
* // Using from a JSON config
|
|
1206
|
-
* const config = {
|
|
1207
|
-
* inputValue: '8',
|
|
1208
|
-
* validations: { min: 10 }
|
|
1209
|
-
* };
|
|
1210
|
-
*
|
|
1211
|
-
* const isValid = min(config.inputValue, config.validations);
|
|
1212
|
-
* console.log(isValid); // Output: true
|
|
1213
|
-
* ```
|
|
1214
|
-
*/
|
|
1215
|
-
const min = (value, validations) => {
|
|
1216
|
-
const number = Number(value);
|
|
1217
|
-
if (!validations.min || Number.isNaN(number)) return false;
|
|
1218
|
-
return number < Number(validations.min);
|
|
1219
|
-
};
|
|
1220
|
-
/**
|
|
1221
|
-
* Validates if a value falls within a specified range.
|
|
1222
|
-
*
|
|
1223
|
-
* @param value - The value to be checked.
|
|
1224
|
-
* @param validations - An object containing the range (start and end) for validation.
|
|
1225
|
-
* @returns `true` if the value falls within the range, otherwise `false`.
|
|
1226
|
-
*
|
|
1227
|
-
* @example
|
|
1228
|
-
* ```typescript
|
|
1229
|
-
* import { between } from './path/to/validationFunctions';
|
|
1230
|
-
*
|
|
1231
|
-
* const validations = { between: { start: 5, end: 10 } };
|
|
1232
|
-
*
|
|
1233
|
-
* const isValid = between(7, validations);
|
|
1234
|
-
* console.log(isValid); // Output: true
|
|
1235
|
-
*
|
|
1236
|
-
* // Using from a JSON config
|
|
1237
|
-
* const config = {
|
|
1238
|
-
* inputValue: '4',
|
|
1239
|
-
* validations: { between: { start: 5, end: 10 } }
|
|
1240
|
-
* };
|
|
1241
|
-
*
|
|
1242
|
-
* const isValid = between(config.inputValue, config.validations);
|
|
1243
|
-
* console.log(isValid); // Output: false
|
|
1244
|
-
* ```
|
|
1245
|
-
*/
|
|
1246
|
-
const between = (value, validations) => {
|
|
1247
|
-
if (!validations.between || !value) return false;
|
|
1248
|
-
const num = Number(value);
|
|
1249
|
-
return !Number.isNaN(num) && !(+num >= validations.between.start && +num <= validations.between.end);
|
|
1250
|
-
};
|
|
1251
|
-
/**
|
|
1252
|
-
* Checks if a given value is less than a specified threshold.
|
|
1253
|
-
*
|
|
1254
|
-
* @param value - The value to be checked. This value will be converted to a number.
|
|
1255
|
-
* @param validations - An object containing validation methods, specifically the `lessThan` property which holds the threshold value.
|
|
1256
|
-
* @returns Returns `false` if the `lessThan` threshold is not provided or if the value is not a valid number. Otherwise, returns `true` if the value is greater than or equal to the `lessThan` threshold.
|
|
1257
|
-
*
|
|
1258
|
-
* @example
|
|
1259
|
-
* ```typescript
|
|
1260
|
-
* const validations = { lessThan: 10 };
|
|
1261
|
-
* console.log(lessThan(5, validations)); // true
|
|
1262
|
-
* console.log(lessThan(15, validations)); // false
|
|
1263
|
-
* ```
|
|
1264
|
-
*/
|
|
1265
|
-
const lessThan = (value, validations) => {
|
|
1266
|
-
const number = Number(value);
|
|
1267
|
-
if (!validations.lessThan || Number.isNaN(number)) return false;
|
|
1268
|
-
return number >= validations.lessThan;
|
|
1269
|
-
};
|
|
1270
|
-
/**
|
|
1271
|
-
* Checks if a given value is greater than a specified threshold.
|
|
1272
|
-
*
|
|
1273
|
-
* @param value - The value to be checked. This value will be converted to a number.
|
|
1274
|
-
* @param validations - An object containing validation methods, specifically the `greaterThan` property which holds the threshold value.
|
|
1275
|
-
* @returns Returns `false` if the `greaterThan` threshold is not provided or if the value is not a valid number. Otherwise, returns `true` if the value is less than or equal to the `greaterThan` threshold.
|
|
1276
|
-
*
|
|
1277
|
-
* @example
|
|
1278
|
-
* ```typescript
|
|
1279
|
-
* const validations = { greaterThan: 10 };
|
|
1280
|
-
* console.log(greaterThan(15, validations)); // true
|
|
1281
|
-
* console.log(greaterThan(5, validations)); // false
|
|
1282
|
-
* ```
|
|
1283
|
-
*/
|
|
1284
|
-
const greaterThan = (value, validations) => {
|
|
1285
|
-
const number = Number(value);
|
|
1286
|
-
if (!validations.greaterThan || Number.isNaN(number)) return false;
|
|
1287
|
-
return number <= validations.greaterThan;
|
|
1288
|
-
};
|
|
1289
|
-
/**
|
|
1290
|
-
* Validates if a value contains sequential numbers.
|
|
1291
|
-
*
|
|
1292
|
-
* @param value - The value to be checked.
|
|
1293
|
-
* @param validations - An object containing the validation methods.
|
|
1294
|
-
* @returns `true` if the value contains sequential numbers, otherwise `false`.
|
|
1295
|
-
*
|
|
1296
|
-
* @example
|
|
1297
|
-
* ```typescript
|
|
1298
|
-
* import { sequential } from './path/to/validationFunctions';
|
|
1299
|
-
*
|
|
1300
|
-
* const validations = { sequential: true };
|
|
1301
|
-
*
|
|
1302
|
-
* const isValid = sequential('12345', validations);
|
|
1303
|
-
* console.log(isValid); // Output: true
|
|
1304
|
-
*
|
|
1305
|
-
* // Using in a React component
|
|
1306
|
-
* const MyComponent = ({ inputValue }) => {
|
|
1307
|
-
* const isValid = sequential(inputValue, validations);
|
|
1308
|
-
* return <div>{isValid ? 'Valid' : 'Invalid'}</div>;
|
|
1309
|
-
* };
|
|
1310
|
-
*
|
|
1311
|
-
* // Using from a JSON config
|
|
1312
|
-
* const config = {
|
|
1313
|
-
* inputValue: '98765',
|
|
1314
|
-
* validations: { sequential: true }
|
|
1315
|
-
* };
|
|
1316
|
-
*
|
|
1317
|
-
* const isValid = sequential(config.inputValue, config.validations);
|
|
1318
|
-
* console.log(isValid); // Output: true
|
|
1319
|
-
* ```
|
|
1320
|
-
*/
|
|
1321
|
-
const sequential = (value, validations) => {
|
|
1322
|
-
if (!validations.sequential) return false;
|
|
1323
|
-
const numbers = '0123456789';
|
|
1324
|
-
const numbersRev = '9876543210';
|
|
1325
|
-
const replacedValue = String(value).replace(/[^0-9]/g, '');
|
|
1326
|
-
return !(numbers.indexOf(replacedValue) === -1 && numbersRev.indexOf(replacedValue) === -1);
|
|
1327
|
-
};
|
|
1328
|
-
|
|
1329
|
-
/**
|
|
1330
|
-
* Validates if a value matches a given regular expression.
|
|
1331
|
-
*
|
|
1332
|
-
* @param value - The value to be checked.
|
|
1333
|
-
* @param validations - An object containing the regex pattern for validation.
|
|
1334
|
-
* @returns `true` if the value does not match the regex, otherwise `false`.
|
|
1335
|
-
*
|
|
1336
|
-
* @example
|
|
1337
|
-
* ```typescript
|
|
1338
|
-
* import { regex } from './path/to/validationFunctions';
|
|
1339
|
-
*
|
|
1340
|
-
* const validations = { regex: '^[a-zA-Z0-9]*$' };
|
|
1341
|
-
*
|
|
1342
|
-
* const isValid = regex('abc123', validations);
|
|
1343
|
-
* console.log(isValid); // Output: false
|
|
1344
|
-
*
|
|
1345
|
-
* // Using from a JSON config
|
|
1346
|
-
* const config = {
|
|
1347
|
-
* inputValue: 'abc123',
|
|
1348
|
-
* validations: { regex: '^[a-zA-Z0-9]*$' }
|
|
1349
|
-
* };
|
|
1350
|
-
*
|
|
1351
|
-
* const isValid = regex(config.inputValue, config.validations);
|
|
1352
|
-
* console.log(isValid); // Output: false
|
|
1353
|
-
* ```
|
|
1354
|
-
*/
|
|
1355
|
-
const regex = (value, validations) => {
|
|
1356
|
-
if (!validations.regex || !value) return false;
|
|
1357
|
-
const regex = new RegExp(validations.regex);
|
|
1358
|
-
return !regex.test(value);
|
|
1359
|
-
};
|
|
1360
|
-
/**
|
|
1361
|
-
* Validates if a value is a valid email address.
|
|
1362
|
-
*
|
|
1363
|
-
* @param value - The value to be checked.
|
|
1364
|
-
* @param validations - An object containing the email validation flag.
|
|
1365
|
-
* @returns `true` if the value is not a valid email, otherwise `false`.
|
|
1366
|
-
*
|
|
1367
|
-
* @example
|
|
1368
|
-
* ```typescript
|
|
1369
|
-
* import { email } from './path/to/validationFunctions';
|
|
1370
|
-
*
|
|
1371
|
-
* const validations = { email: true };
|
|
1372
|
-
*
|
|
1373
|
-
* const isValid = email('test@example.com', validations);
|
|
1374
|
-
* console.log(isValid); // Output: false
|
|
1375
|
-
*
|
|
1376
|
-
* // Using from a JSON config
|
|
1377
|
-
* const config = {
|
|
1378
|
-
* inputValue: 'invalid-email',
|
|
1379
|
-
* validations: { email: true }
|
|
1380
|
-
* };
|
|
1381
|
-
*
|
|
1382
|
-
* const isValid = email(config.inputValue, config.validations);
|
|
1383
|
-
* console.log(isValid); // Output: true
|
|
1384
|
-
* ```
|
|
1385
|
-
*/
|
|
1386
|
-
const email = (value, validations) => {
|
|
1387
|
-
if (!validations.email || !value) return false;
|
|
1388
|
-
const regex = /^(([^<>()[\]\\.,;:\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,}))$/;
|
|
1389
|
-
return !regex.test(value);
|
|
1390
|
-
};
|
|
1391
|
-
/**
|
|
1392
|
-
* Validates if a value is a valid URL.
|
|
1393
|
-
*
|
|
1394
|
-
* @param value - The value to be checked.
|
|
1395
|
-
* @param validations - An object containing the URL validation flag.
|
|
1396
|
-
* @returns `true` if the value is not a valid URL, otherwise `false`.
|
|
1397
|
-
*
|
|
1398
|
-
* @example
|
|
1399
|
-
* ```typescript
|
|
1400
|
-
* import { url } from './path/to/validationFunctions';
|
|
1401
|
-
*
|
|
1402
|
-
* const validations = { url: true };
|
|
1403
|
-
*
|
|
1404
|
-
* const isValid = url('https://example.com', validations);
|
|
1405
|
-
* console.log(isValid); // Output: false
|
|
1406
|
-
*
|
|
1407
|
-
* // Using from a JSON config
|
|
1408
|
-
* const config = {
|
|
1409
|
-
* inputValue: 'invalid-url',
|
|
1410
|
-
* validations: { url: true }
|
|
1411
|
-
* };
|
|
1412
|
-
*
|
|
1413
|
-
* const isValid = url(config.inputValue, config.validations);
|
|
1414
|
-
* console.log(isValid); // Output: true
|
|
1415
|
-
* ```
|
|
1416
|
-
*/
|
|
1417
|
-
const url = (value, validations) => {
|
|
1418
|
-
if (!validations.url || !value) return false;
|
|
1419
|
-
const regex = /[(http(s)?)://(www.)?a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi;
|
|
1420
|
-
return !regex.test(value);
|
|
1421
|
-
};
|
|
1422
|
-
/**
|
|
1423
|
-
* Validates if a value contains only letters.
|
|
1424
|
-
*
|
|
1425
|
-
* @param value - The value to be checked.
|
|
1426
|
-
* @param validations - An object containing the onlyLetters validation flag.
|
|
1427
|
-
* @returns `true` if the value contains non-letter characters, otherwise `false`.
|
|
1428
|
-
*
|
|
1429
|
-
* @example
|
|
1430
|
-
* ```typescript
|
|
1431
|
-
* import { onlyLetters } from './path/to/validationFunctions';
|
|
1432
|
-
*
|
|
1433
|
-
* const validations = { onlyLetters: true };
|
|
1434
|
-
*
|
|
1435
|
-
* const isValid = onlyLetters('abc', validations);
|
|
1436
|
-
* console.log(isValid); // Output: false
|
|
1437
|
-
*
|
|
1438
|
-
* // Using from a JSON config
|
|
1439
|
-
* const config = {
|
|
1440
|
-
* inputValue: '123',
|
|
1441
|
-
* validations: { onlyLetters: true }
|
|
1442
|
-
* };
|
|
1443
|
-
*
|
|
1444
|
-
* const isValid = onlyLetters(config.inputValue, config.validations);
|
|
1445
|
-
* console.log(isValid); // Output: true
|
|
1446
|
-
* ```
|
|
1447
|
-
*/
|
|
1448
|
-
const onlyLetters = (value, validations) => {
|
|
1449
|
-
if (!validations.onlyLetters) return false;
|
|
1450
|
-
return !/^[\p{L}\s]*$/u.test(value);
|
|
1451
|
-
};
|
|
1452
|
-
/**
|
|
1453
|
-
* Validates if a value does not contain spaces.
|
|
1454
|
-
*
|
|
1455
|
-
* @param value - The value to be checked.
|
|
1456
|
-
* @param validations - An object containing the notAllowSpaces validation flag.
|
|
1457
|
-
* @returns `true` if the value contains spaces, otherwise `false`.
|
|
1458
|
-
*
|
|
1459
|
-
* @example
|
|
1460
|
-
* ```typescript
|
|
1461
|
-
* import { notAllowSpaces } from './path/to/validationFunctions';
|
|
1462
|
-
*
|
|
1463
|
-
* const validations = { notAllowSpaces: true };
|
|
1464
|
-
*
|
|
1465
|
-
* const isValid = notAllowSpaces('no spaces', validations);
|
|
1466
|
-
* console.log(isValid); // Output: true
|
|
1467
|
-
*
|
|
1468
|
-
* // Using from a JSON config
|
|
1469
|
-
* const config = {
|
|
1470
|
-
* inputValue: 'nospaces',
|
|
1471
|
-
* validations: { notAllowSpaces: true }
|
|
1472
|
-
* };
|
|
1473
|
-
*
|
|
1474
|
-
* const isValid = notAllowSpaces(config.inputValue, config.validations);
|
|
1475
|
-
* console.log(isValid); // Output: false
|
|
1476
|
-
* ```
|
|
1477
|
-
*/
|
|
1478
|
-
const notAllowSpaces = (value, validations) => {
|
|
1479
|
-
if (!validations.notAllowSpaces) return false;
|
|
1480
|
-
return /\s/.test(value);
|
|
1481
|
-
};
|
|
1482
|
-
/**
|
|
1483
|
-
* Validates if a value is a number.
|
|
1484
|
-
*
|
|
1485
|
-
* @param value - The value to be checked.
|
|
1486
|
-
* @param validations - An object containing the isNumber validation flag.
|
|
1487
|
-
* @returns `true` if the value is not a number, otherwise `false`.
|
|
1488
|
-
*
|
|
1489
|
-
* @example
|
|
1490
|
-
* ```typescript
|
|
1491
|
-
* import { isNumber } from './path/to/validationFunctions';
|
|
1492
|
-
*
|
|
1493
|
-
* const validations = { isNumber: true };
|
|
1494
|
-
*
|
|
1495
|
-
* const isValid = isNumber('123', validations);
|
|
1496
|
-
* console.log(isValid); // Output: false
|
|
1497
|
-
*
|
|
1498
|
-
* // Using from a JSON config
|
|
1499
|
-
* const config = {
|
|
1500
|
-
* inputValue: 'abc',
|
|
1501
|
-
* validations: { isNumber: true }
|
|
1502
|
-
* };
|
|
1503
|
-
*
|
|
1504
|
-
* const isValid = isNumber(config.inputValue, config.validations);
|
|
1505
|
-
* console.log(isValid); // Output: true
|
|
1506
|
-
* ```
|
|
1507
|
-
*/
|
|
1508
|
-
const isNumber = (value, validations) => {
|
|
1509
|
-
if (!validations.isNumber) return false;
|
|
1510
|
-
return !!value && !/^[0-9\s]*$/.test(value);
|
|
1511
|
-
};
|
|
1512
|
-
/**
|
|
1513
|
-
* Validates if a value has no trailing or leading spaces.
|
|
1514
|
-
*
|
|
1515
|
-
* @param value - The value to be checked.
|
|
1516
|
-
* @param validations - An object containing the hasNoExtraSpaces validation flag.
|
|
1517
|
-
* @returns `true` if the value has trailing or leading spaces, otherwise `false`.
|
|
1518
|
-
*
|
|
1519
|
-
* @example
|
|
1520
|
-
* ```typescript
|
|
1521
|
-
* import { hasNoExtraSpaces } from './path/to/validationFunctions';
|
|
1522
|
-
*
|
|
1523
|
-
* const validations = { hasNoExtraSpaces: true };
|
|
1524
|
-
*
|
|
1525
|
-
* const isValid = hasNoExtraSpaces('Hello', validations);
|
|
1526
|
-
* console.log(isValid); // Output: true
|
|
1527
|
-
*
|
|
1528
|
-
* // Using from a JSON config
|
|
1529
|
-
* const config = {
|
|
1530
|
-
* inputValue: ' Hello ',
|
|
1531
|
-
* validations: { hasNoExtraSpaces: true }
|
|
1532
|
-
* };
|
|
1533
|
-
*
|
|
1534
|
-
* const isValid = hasNoExtraSpaces(config.inputValue, config.validations);
|
|
1535
|
-
* console.log(isValid); // Output: false
|
|
1536
|
-
* ```
|
|
1537
|
-
*/
|
|
1538
|
-
const hasNoExtraSpaces = (value, validations) => {
|
|
1539
|
-
if (!validations.hasNoExtraSpaces || !value) return false;
|
|
1540
|
-
return regex(value, {
|
|
1541
|
-
regex: '^[A-Za-zÀ-ÖØ-öø-ÿäöüÄÖÜß0-9]+$'
|
|
1542
|
-
});
|
|
1543
|
-
};
|
|
1544
|
-
/**
|
|
1545
|
-
* Validates if a value contains repeated digits.
|
|
1546
|
-
*
|
|
1547
|
-
* @param value - The value to be checked.
|
|
1548
|
-
* @param validations - An object containing the repeated validation flag.
|
|
1549
|
-
* @returns `true` if the value contains repeated digits, otherwise `false`.
|
|
1550
|
-
*
|
|
1551
|
-
* @example
|
|
1552
|
-
* ```typescript
|
|
1553
|
-
* import { repeated } from './path/to/validationFunctions';
|
|
1554
|
-
*
|
|
1555
|
-
* const validations = { repeated: true };
|
|
1556
|
-
*
|
|
1557
|
-
* const isValid = repeated('1231', validations);
|
|
1558
|
-
* console.log(isValid); // Output: true
|
|
1559
|
-
*
|
|
1560
|
-
* // Using from a JSON config
|
|
1561
|
-
* const config = {
|
|
1562
|
-
* inputValue: '1234',
|
|
1563
|
-
* validations: { repeated: true }
|
|
1564
|
-
* };
|
|
1565
|
-
*
|
|
1566
|
-
* const isValid = repeated(config.inputValue, config.validations);
|
|
1567
|
-
* console.log(isValid); // Output: false
|
|
1568
|
-
* ```
|
|
1569
|
-
*/
|
|
1570
|
-
const repeated = (value, validations) => {
|
|
1571
|
-
if (!validations.repeated) return false;
|
|
1572
|
-
const numCount = {};
|
|
1573
|
-
for (const char of String(value)) {
|
|
1574
|
-
if (/\d/.test(char)) {
|
|
1575
|
-
if (numCount[char]) {
|
|
1576
|
-
return true;
|
|
1577
|
-
}
|
|
1578
|
-
numCount[char] = 1;
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
return false;
|
|
1582
|
-
};
|
|
1583
|
-
|
|
1584
|
-
/**
|
|
1585
|
-
* Executes a custom callback validation function if provided.
|
|
1586
|
-
*
|
|
1587
|
-
* @param value - The value to be validated.
|
|
1588
|
-
* @param validations - An object containing validation methods, including a custom callback function.
|
|
1589
|
-
* @returns `true` if the custom callback validation function returns `true`, otherwise `false`.
|
|
1590
|
-
*
|
|
1591
|
-
* @example
|
|
1592
|
-
* ```typescript
|
|
1593
|
-
* import { callback } from './path/to/validationFunctions';
|
|
1594
|
-
*
|
|
1595
|
-
* const validations = {
|
|
1596
|
-
* callback: (value) => typeof value === 'string' && value.length > 5
|
|
1597
|
-
* };
|
|
1598
|
-
*
|
|
1599
|
-
* // Or from a JSON config
|
|
1600
|
-
* const schema = {
|
|
1601
|
-
* validations: {
|
|
1602
|
-
* callback: (value) => typeof value === 'string' && value.length > 5
|
|
1603
|
-
* }
|
|
1604
|
-
* };
|
|
1605
|
-
* ```
|
|
1606
|
-
*/
|
|
1607
|
-
const callback = (value, validations) => {
|
|
1608
|
-
if (!validations.callback || !((validations === null || validations === void 0 ? void 0 : validations.callback) instanceof Function)) return false;
|
|
1609
|
-
return validations.callback(value);
|
|
1610
|
-
};
|
|
1611
|
-
|
|
1612
|
-
/**
|
|
1613
|
-
* Checks if a value is included in the specified array within the validation rules.
|
|
1614
|
-
*
|
|
1615
|
-
* @param value - The value to be checked.
|
|
1616
|
-
* @param validations - An object containing validation methods, including an array of allowed values.
|
|
1617
|
-
* @returns `true` if the value is included in the array, otherwise `false`.
|
|
1618
|
-
*
|
|
1619
|
-
* @example
|
|
1620
|
-
* ```typescript
|
|
1621
|
-
* import { includes } from './path/to/validationFunctions';
|
|
1622
|
-
*
|
|
1623
|
-
* const validations = {
|
|
1624
|
-
* includes: ['apple', 'banana', 'cherry']
|
|
1625
|
-
* };
|
|
1626
|
-
*
|
|
1627
|
-
* const isValid = includes('banana', validations);
|
|
1628
|
-
* console.log(isValid); // Output: true
|
|
1629
|
-
*
|
|
1630
|
-
* // Using from a JSON config
|
|
1631
|
-
* const config = {
|
|
1632
|
-
* inputValue: 'apple',
|
|
1633
|
-
* validations: {
|
|
1634
|
-
* includes: ['apple', 'banana', 'cherry']
|
|
1635
|
-
* }
|
|
1636
|
-
* };
|
|
1637
|
-
*
|
|
1638
|
-
* const isValid = includes(config.inputValue, config.validations);
|
|
1639
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
1640
|
-
* ```
|
|
1641
|
-
*/
|
|
1642
|
-
const includes = (value, validations) => {
|
|
1643
|
-
if (!value || !Array.isArray(validations === null || validations === void 0 ? void 0 : validations.includes)) return false;
|
|
1644
|
-
return !(validations === null || validations === void 0 ? void 0 : validations.includes.some(code => code === value || JSON.stringify(code) === value));
|
|
1645
|
-
};
|
|
1646
|
-
|
|
1647
|
-
/**
|
|
1648
|
-
* Validates if a given value is a valid credit card number based on predefined validation methods.
|
|
1649
|
-
*
|
|
1650
|
-
* @param value - The value to be validated as a credit card number.
|
|
1651
|
-
* @param validations - An object containing validation methods.
|
|
1652
|
-
* @returns `true` if the value is either falsy or does not match a valid credit card type, otherwise `false`.
|
|
1653
|
-
*
|
|
1654
|
-
* @example
|
|
1655
|
-
* ```typescript
|
|
1656
|
-
* import { isCreditCard } from './path/to/validationFunctions';
|
|
1657
|
-
* import { validationMethods } from './path/to/validationConfig';
|
|
1658
|
-
*
|
|
1659
|
-
* const isValid = isCreditCard('4111111111111111', validationMethods);
|
|
1660
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
1661
|
-
* ```
|
|
1662
|
-
*/
|
|
1663
|
-
const isCreditCard = (value, validations) => {
|
|
1664
|
-
if (!value) return true;
|
|
1665
|
-
const [type] = getTypeCard(String(value), validations.isCreditCard);
|
|
1666
|
-
return !type;
|
|
1667
|
-
};
|
|
1668
|
-
/**
|
|
1669
|
-
* Validates if a given security code matches the expected length for a specified credit card type.
|
|
1670
|
-
*
|
|
1671
|
-
* @param value - The security code to be validated.
|
|
1672
|
-
* @param validations - An object containing validation methods, specifically with `isCreditCodeMatch` details.
|
|
1673
|
-
* @returns `true` if the value is either falsy or if the validation methods are not provided. Otherwise, it checks if the security code length matches the expected length for the card type.
|
|
1674
|
-
*
|
|
1675
|
-
* @example
|
|
1676
|
-
* ```typescript
|
|
1677
|
-
* import { isCreditCodeMatch } from './path/to/validationFunctions';
|
|
1678
|
-
* import { validationMethods } from './path/to/validationConfig';
|
|
1679
|
-
*
|
|
1680
|
-
* const isValid = isCreditCodeMatch('123', validationMethods);
|
|
1681
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
1682
|
-
* ```
|
|
1683
|
-
*/
|
|
1684
|
-
const isCreditCodeMatch = (value, validations) => {
|
|
1685
|
-
var _a;
|
|
1686
|
-
if (!value || !validations.isCreditCodeMatch) return false;
|
|
1687
|
-
const [type] = getTypeCard(validations.isCreditCodeMatch.numberCard, validations.isCreditCodeMatch.availableOptions);
|
|
1688
|
-
return ((_a = type === null || type === void 0 ? void 0 : type.code) === null || _a === void 0 ? void 0 : _a.size) !== value.length;
|
|
1689
|
-
};
|
|
1690
|
-
/**
|
|
1691
|
-
* Validates if a given value is a valid credit card number and checks if its length matches the expected lengths for the card type.
|
|
1692
|
-
*
|
|
1693
|
-
* @param value - The credit card number to be validated.
|
|
1694
|
-
* @param validations - An object containing validation methods, specifically with `isCreditCardAndLength` details.
|
|
1695
|
-
* @returns `true` if the value is either falsy or if the card number does not match any valid lengths for the card type, otherwise `false`.
|
|
1696
|
-
*
|
|
1697
|
-
* @example
|
|
1698
|
-
* ```typescript
|
|
1699
|
-
* import { isCreditCardAndLength } from './path/to/validationFunctions';
|
|
1700
|
-
* import { validationMethods } from './path/to/validationConfig';
|
|
1701
|
-
*
|
|
1702
|
-
* const isValid = isCreditCardAndLength('4111111111111111', validationMethods);
|
|
1703
|
-
* console.log(isValid); // Output: true or false based on validation
|
|
1704
|
-
* ```
|
|
1705
|
-
*/
|
|
1706
|
-
const isCreditCardAndLength = (value, validations) => {
|
|
1707
|
-
if (!value || !validations.isCreditCardAndLength) return false;
|
|
1708
|
-
const [type, rawValue] = getTypeCard(value, validations.isCreditCardAndLength);
|
|
1709
|
-
return type && !type.lengths.includes(rawValue.length);
|
|
1710
|
-
};
|
|
1711
|
-
|
|
1712
|
-
/**
|
|
1713
|
-
* Validates that a string value is not empty.
|
|
1714
|
-
*
|
|
1715
|
-
* @param {string} value - The value to be validated.
|
|
1716
|
-
* @param {TValidationMethods} validations - The validation methods object containing the notEmpty validation rule.
|
|
1717
|
-
* @returns {boolean} - Returns `true` if the value is empty and the notEmpty validation rule is set, otherwise `false`.
|
|
1718
|
-
*
|
|
1719
|
-
* @example
|
|
1720
|
-
* ```typescript
|
|
1721
|
-
* // Assume validations is an object with a notEmpty property
|
|
1722
|
-
* const validations = { notEmpty: true };
|
|
1723
|
-
*
|
|
1724
|
-
* // Returns true because the string is empty
|
|
1725
|
-
* const result1 = notEmpty('', validations);
|
|
1726
|
-
* console.log(result1); // true
|
|
1727
|
-
*
|
|
1728
|
-
* // Returns false because the string is not empty
|
|
1729
|
-
* const result2 = notEmpty('hello', validations);
|
|
1730
|
-
* console.log(result2); // false
|
|
1731
|
-
*
|
|
1732
|
-
* // Returns false because the notEmpty validation rule is not set
|
|
1733
|
-
* const result3 = notEmpty('', { notEmpty: false });
|
|
1734
|
-
* console.log(result3); // false
|
|
1735
|
-
* ```
|
|
1736
|
-
*/
|
|
1737
|
-
const notEmpty = (value, validations) => {
|
|
1738
|
-
var _a;
|
|
1739
|
-
if (!(validations === null || validations === void 0 ? void 0 : validations.notEmpty) || typeof value === 'undefined') return false;
|
|
1740
|
-
return value === null || value === '' || value === 0 || !((_a = String(value)) === null || _a === void 0 ? void 0 : _a.trim().length);
|
|
1741
|
-
};
|
|
1742
|
-
/**
|
|
1743
|
-
* Validates that a value matches a specified value.
|
|
1744
|
-
*
|
|
1745
|
-
* @param {unknown} value - The value to be validated.
|
|
1746
|
-
* @param {TValidationMethods} validations - The validation methods object containing the value validation rule.
|
|
1747
|
-
* @returns {boolean} - Returns `true` if the value does not match the specified validation value, otherwise `false`.
|
|
1748
|
-
*
|
|
1749
|
-
* @example
|
|
1750
|
-
* ```typescript
|
|
1751
|
-
* // Assume validations is an object with a value property
|
|
1752
|
-
* const validations = { value: 42 };
|
|
1753
|
-
*
|
|
1754
|
-
* // Returns true because the value does not match the validation value
|
|
1755
|
-
* const result1 = value(10, validations);
|
|
1756
|
-
* console.log(result1); // true
|
|
1757
|
-
*
|
|
1758
|
-
* // Returns false because the value matches the validation value
|
|
1759
|
-
* const result2 = value(42, validations);
|
|
1760
|
-
* console.log(result2); // false
|
|
1761
|
-
*
|
|
1762
|
-
* // Returns false because the value validation rule is not set
|
|
1763
|
-
* const result3 = value(10, { value: undefined });
|
|
1764
|
-
* console.log(result3); // false
|
|
1765
|
-
* ```
|
|
1766
|
-
*/
|
|
1767
|
-
const value = (value, validations) => {
|
|
1768
|
-
if (typeof (validations === null || validations === void 0 ? void 0 : validations.value) === 'undefined' || (validations === null || validations === void 0 ? void 0 : validations.value) === null || typeof value === 'undefined' || value === null) return false;
|
|
1769
|
-
return value != validations.value;
|
|
1770
|
-
};
|
|
1771
|
-
|
|
1772
|
-
/**
|
|
1773
|
-
* Validates that a value is required.
|
|
1774
|
-
*
|
|
1775
|
-
* @param {unknown} value - The value to be validated.
|
|
1776
|
-
* @param {TValidationMethods} validations - The validation methods object containing the required validation rule.
|
|
1777
|
-
* @returns {boolean} - Returns `true` if the value is required and is empty or not provided, otherwise `false`.
|
|
1778
|
-
*
|
|
1779
|
-
* @example
|
|
1780
|
-
* ```typescript
|
|
1781
|
-
* // Assume validations is an object with a required property
|
|
1782
|
-
* const validations = { required: true };
|
|
1783
|
-
*
|
|
1784
|
-
* // Returns true because the value is required and is empty
|
|
1785
|
-
* const result1 = required('', validations);
|
|
1786
|
-
* console.log(result1); // true
|
|
1787
|
-
*
|
|
1788
|
-
* // Returns false because the value is required and is provided
|
|
1789
|
-
* const result2 = required('text', validations);
|
|
1790
|
-
* console.log(result2); // false
|
|
1791
|
-
*
|
|
1792
|
-
* // Returns false because the required validation rule is not set
|
|
1793
|
-
* const result3 = required('', { required: false });
|
|
1794
|
-
* console.log(result3); // false
|
|
1795
|
-
* ```
|
|
1796
|
-
*/
|
|
1797
|
-
const required = (value, validations) => !!(validations.required && (!value || typeof value === 'string' && value.trim().length === 0));
|
|
1798
|
-
/**
|
|
1799
|
-
* Validates that a value matches a boolean rule. Useful with iVars property.
|
|
1800
|
-
*
|
|
1801
|
-
* @param _
|
|
1802
|
-
* @param {TValidationMethods} validations - The validation methods object containing the boolean validation rule.
|
|
1803
|
-
* @returns {boolean} - Returns `true` if the boolean validation rule is set and fails, otherwise `false`.
|
|
1804
|
-
*
|
|
1805
|
-
* @example
|
|
1806
|
-
* ```typescript
|
|
1807
|
-
* // Assume validations is an object with a bool property
|
|
1808
|
-
* const validations = { bool: true };
|
|
1809
|
-
*
|
|
1810
|
-
* // Returns true because the boolean validation rule is set to fail
|
|
1811
|
-
* const result1 = bool(null, validations);
|
|
1812
|
-
* console.log(result1); // true
|
|
1813
|
-
*
|
|
1814
|
-
* // Returns false because the boolean validation rule is not set
|
|
1815
|
-
* const result2 = bool(null, { bool: false });
|
|
1816
|
-
* console.log(result2); // false
|
|
1817
|
-
* ```
|
|
1818
|
-
*/
|
|
1819
|
-
const bool = (_, validations) => {
|
|
1820
|
-
if (!(validations === null || validations === void 0 ? void 0 : validations.bool)) return false;
|
|
1821
|
-
let fail = false;
|
|
1822
|
-
if (typeof validations.bool === 'boolean') {
|
|
1823
|
-
fail = validations.bool;
|
|
1824
|
-
}
|
|
1825
|
-
return fail;
|
|
1826
|
-
};
|
|
1827
|
-
/**
|
|
1828
|
-
* Validates that a value exists. Useful with iVars property.
|
|
1829
|
-
*
|
|
1830
|
-
* @param {unknown} value - The value to be validated.
|
|
1831
|
-
* @param {TValidationMethods} validations - The validation methods object containing the exists validation rule.
|
|
1832
|
-
* @returns {boolean} - Returns `true` if the value does not exist when the exists rule is set, otherwise `false`.
|
|
1833
|
-
*
|
|
1834
|
-
* @example
|
|
1835
|
-
* ```typescript
|
|
1836
|
-
* // Assume validations is an object with an exists property
|
|
1837
|
-
* const validations = { exists: true };
|
|
1838
|
-
*
|
|
1839
|
-
* // Returns true because the value does not exist
|
|
1840
|
-
* const result1 = exists(null, validations);
|
|
1841
|
-
* console.log(result1); // true
|
|
1842
|
-
*
|
|
1843
|
-
* // Returns false because the value exists
|
|
1844
|
-
* const result2 = exists('text', validations);
|
|
1845
|
-
* console.log(result2); // false
|
|
1846
|
-
*
|
|
1847
|
-
* // Returns false because the exists validation rule is not set
|
|
1848
|
-
* const result3 = exists(null, { exists: false });
|
|
1849
|
-
* console.log(result3); // false
|
|
1850
|
-
* ```
|
|
1851
|
-
*/
|
|
1852
|
-
const exists = (value, validations) => {
|
|
1853
|
-
if (!validations.exists) return false;
|
|
1854
|
-
let fail = !validations.exists;
|
|
1855
|
-
if (!fail) {
|
|
1856
|
-
fail = !value;
|
|
1857
|
-
}
|
|
1858
|
-
return fail;
|
|
1859
|
-
};
|
|
1860
|
-
|
|
1861
|
-
/**
|
|
1862
|
-
* @internal
|
|
1863
|
-
* Evaluates a condition based on the provided rule and value.
|
|
1864
|
-
*
|
|
1865
|
-
* @param {number | string | boolean} value - The value to be used in the condition evaluation.
|
|
1866
|
-
* @param {TConditionsValidationSet} rule - The rule defining the condition to be evaluated.
|
|
1867
|
-
* @returns {boolean} - The result of the condition evaluation.
|
|
1868
|
-
*
|
|
1869
|
-
* @example
|
|
1870
|
-
* const rule = {
|
|
1871
|
-
* condition: '===',
|
|
1872
|
-
* origin: 5,
|
|
1873
|
-
* target: 5,
|
|
1874
|
-
* };
|
|
1875
|
-
* const result = conditionResult(5, rule);
|
|
1876
|
-
* console.log(result); // true (5 === 5)
|
|
1877
|
-
*
|
|
1878
|
-
* @example
|
|
1879
|
-
* const rule = {
|
|
1880
|
-
* condition: '!==',
|
|
1881
|
-
* origin: 5,
|
|
1882
|
-
* target: 10,
|
|
1883
|
-
* };
|
|
1884
|
-
* const result = conditionResult(5, rule);
|
|
1885
|
-
* console.log(result); // true (5 !== 10)
|
|
1886
|
-
*
|
|
1887
|
-
* @example
|
|
1888
|
-
* const rule = {
|
|
1889
|
-
* condition: '<',
|
|
1890
|
-
* origin: 5,
|
|
1891
|
-
* target: 10,
|
|
1892
|
-
* };
|
|
1893
|
-
* const result = conditionResult(5, rule);
|
|
1894
|
-
* console.log(result); // true (5 < 10)
|
|
1895
|
-
*/
|
|
1896
|
-
const conditionResult = (value, rule) => {
|
|
1897
|
-
if (rule.forceDefinedOrigin && rule.origin === undefined || rule.forceDefinedTarget && rule.target === undefined) {
|
|
1898
|
-
return false;
|
|
1899
|
-
}
|
|
1900
|
-
const origin = rule.origin === undefined ? value : rule.origin;
|
|
1901
|
-
const target = rule.target === undefined ? value : rule.target;
|
|
1902
|
-
const conditionMapper = {
|
|
1903
|
-
'!==': (origin || value) !== (target || value),
|
|
1904
|
-
'===': (origin || value) === (target || value),
|
|
1905
|
-
'<': (origin || value) < (target || value),
|
|
1906
|
-
'>': (origin || value) > (target || value),
|
|
1907
|
-
'<=': (origin || value) <= (target || value),
|
|
1908
|
-
'>=': (origin || value) >= (target || value),
|
|
1909
|
-
'!!origin': !!String(origin || value).trim().length
|
|
1910
|
-
};
|
|
1911
|
-
return conditionMapper[rule.condition];
|
|
1912
|
-
};
|
|
1913
|
-
/**
|
|
1914
|
-
* Validates that a value meets specified conditions.
|
|
1915
|
-
*
|
|
1916
|
-
* @param {number | string | boolean} value - The value to be validated.
|
|
1917
|
-
* @param {TValidationMethods} validations - The validation methods object containing the conditions validation rule.
|
|
1918
|
-
* @returns {boolean} - Returns `true` if the value meets the specified conditions, otherwise `false`.
|
|
1919
|
-
*
|
|
1920
|
-
* @example
|
|
1921
|
-
* ```typescript
|
|
1922
|
-
* // Assume validations is an object with a conditions property
|
|
1923
|
-
* const validations = {
|
|
1924
|
-
* conditions: {
|
|
1925
|
-
* rule: 'and',
|
|
1926
|
-
* set: [
|
|
1927
|
-
* { condition: '===', origin: 10, target: 10 },
|
|
1928
|
-
* { condition: '!==', origin: 5, target: 3 }
|
|
1929
|
-
* ]
|
|
1930
|
-
* }
|
|
1931
|
-
* };
|
|
1932
|
-
*
|
|
1933
|
-
* // Returns true because both conditions are met
|
|
1934
|
-
* const result1 = conditions(10, validations);
|
|
1935
|
-
* console.log(result1); // true
|
|
1936
|
-
*
|
|
1937
|
-
* // Returns false because the second condition is not met
|
|
1938
|
-
* const result2 = conditions(5, validations);
|
|
1939
|
-
* console.log(result2); // false
|
|
1940
|
-
*
|
|
1941
|
-
* // Returns true because at least one condition is met with 'or' rule
|
|
1942
|
-
* const orValidations = {
|
|
1943
|
-
* conditions: {
|
|
1944
|
-
* rule: 'or',
|
|
1945
|
-
* set: [
|
|
1946
|
-
* { condition: '===', origin: 10, target: 5 },
|
|
1947
|
-
* { condition: '!==', origin: 5, target: 3 }
|
|
1948
|
-
* ]
|
|
1949
|
-
* }
|
|
1950
|
-
* };
|
|
1951
|
-
* const result3 = conditions(10, orValidations);
|
|
1952
|
-
* console.log(result3); // true
|
|
1953
|
-
* ```
|
|
1954
|
-
*/
|
|
1955
|
-
const conditions = (value, validations) => {
|
|
1956
|
-
if (!validations.conditions) return false;
|
|
1957
|
-
const rulesMapper = {
|
|
1958
|
-
and: () => {
|
|
1959
|
-
var _a;
|
|
1960
|
-
return !!((_a = validations.conditions) === null || _a === void 0 ? void 0 : _a.set.every(validate => conditionResult(value, validate)));
|
|
1961
|
-
},
|
|
1962
|
-
or: () => {
|
|
1963
|
-
var _a;
|
|
1964
|
-
return !!((_a = validations.conditions) === null || _a === void 0 ? void 0 : _a.set.some(validate => conditionResult(value, validate)));
|
|
1965
|
-
}
|
|
1966
|
-
};
|
|
1967
|
-
let result = rulesMapper[validations.conditions.rule]();
|
|
1968
|
-
if (validations.conditions.conditions) {
|
|
1969
|
-
if (validations.conditions.rule === 'and') {
|
|
1970
|
-
result = result && conditions(value, {
|
|
1971
|
-
conditions: validations.conditions.conditions
|
|
1972
|
-
});
|
|
1973
|
-
} else {
|
|
1974
|
-
result = result || conditions(value, {
|
|
1975
|
-
conditions: validations.conditions.conditions
|
|
1976
|
-
});
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1979
|
-
return !result;
|
|
1980
|
-
};
|
|
1981
|
-
|
|
1982
|
-
/**
|
|
1983
|
-
* @internal
|
|
1984
|
-
* Validates if a date string matches a specific date format.
|
|
1985
|
-
* The function accepts strings with '/' or '-' separators and removes them before validating the format.
|
|
1986
|
-
*
|
|
1987
|
-
* @param {string} value - The date string to be validated. It can contain '/' or '-' separators.
|
|
1988
|
-
* @param {string} format - The expected date format. It can be one of the following:
|
|
1989
|
-
* 'DDMMYYYY', 'YYYYMMDD', 'YYYYDDMM', 'MMDDYYYY',
|
|
1990
|
-
* 'DMYYYY', 'YYYYMD', 'YYYYDM', 'MDYYYY'.
|
|
1991
|
-
* @returns {boolean} - Returns `false` if the date string matches the specified format, otherwise `true`.
|
|
1992
|
-
*
|
|
1993
|
-
* @example
|
|
1994
|
-
* // Returns false
|
|
1995
|
-
* invalidStringDate("25/07/1997", "DDMMYYYY");
|
|
1996
|
-
*
|
|
1997
|
-
* @example
|
|
1998
|
-
* // Returns false
|
|
1999
|
-
* invalidStringDate("1997-07-25", "YYYYMMDD");
|
|
2000
|
-
*
|
|
2001
|
-
* @example
|
|
2002
|
-
* // Returns true, as the format does not match
|
|
2003
|
-
* invalidStringDate("1997/25/07", "MMDDYYYY");
|
|
2004
|
-
*/
|
|
2005
|
-
const invalidStringDate = (value, format) => {
|
|
2006
|
-
if (!value.includes('/') && !value.includes('-') || !format) {
|
|
2007
|
-
return true;
|
|
2008
|
-
}
|
|
2009
|
-
const valueParts = value.replace(/[-/]/g, '');
|
|
2010
|
-
const dateMapper = {
|
|
2011
|
-
DDMMYYYY: /^(\d{2})(\d{2})(\d{4})$/,
|
|
2012
|
-
YYYYMMDD: /^(\d{4})(\d{2})(\d{2})$/,
|
|
2013
|
-
YYYYDDMM: /^(\d{4})(\d{2})(\d{2})$/,
|
|
2014
|
-
MMDDYYYY: /^(\d{2})(\d{2})(\d{4})$/,
|
|
2015
|
-
DMYYYY: /^(\d{1,2})(\d{1,2})(\d{4})$/,
|
|
2016
|
-
YYYYMD: /^(\d{4})(\d{1,2})(\d{1,2})$/,
|
|
2017
|
-
YYYYDM: /^(\d{4})(\d{1,2})(\d{1,2})$/,
|
|
2018
|
-
MDYYYY: /^(\d{1,2})(\d{1,2})(\d{4})$/
|
|
2019
|
-
};
|
|
2020
|
-
return !dateMapper[format].test(valueParts);
|
|
2021
|
-
};
|
|
2022
|
-
/**
|
|
2023
|
-
* @internal
|
|
2024
|
-
* Adjusts a date by adding intervals of years, months, or days.
|
|
2025
|
-
*
|
|
2026
|
-
* @param {Date} date - The initial date.
|
|
2027
|
-
* @param {TDateInterval} intervals - An object specifying the intervals to add.
|
|
2028
|
-
* @returns {Date} - The adjusted date.
|
|
2029
|
-
*
|
|
2030
|
-
* @example
|
|
2031
|
-
* const initialDate = new Date('2023-01-01');
|
|
2032
|
-
* const intervals = { years: 1, months: 6, days: 15 };
|
|
2033
|
-
* const newDate = getIntervalsDate(initialDate, intervals);
|
|
2034
|
-
* console.log(newDate); // Expected date: '2024-07-16'
|
|
2035
|
-
*/
|
|
2036
|
-
const getIntervalsDate = (date, intervals) => {
|
|
2037
|
-
const intervalsMapper = {
|
|
2038
|
-
years: (date, value) => new Date(date.setUTCFullYear(date.getUTCFullYear() + value)),
|
|
2039
|
-
months: (date, value) => new Date(date.setUTCMonth(date.getUTCMonth() + value)),
|
|
2040
|
-
days: (date, value) => new Date(date.setDate(date.getUTCDate() + value))
|
|
2041
|
-
};
|
|
2042
|
-
return Object.keys(intervals).reduce((acc, interval) => intervalsMapper[interval](acc, intervals[interval]), new Date(date));
|
|
2043
|
-
};
|
|
2044
|
-
/**
|
|
2045
|
-
* @internal
|
|
2046
|
-
* A mapper object for rearranging date strings into different formats.
|
|
2047
|
-
*
|
|
2048
|
-
* @type {Record<TDateFormatsValidation, (value: string) => string>}
|
|
2049
|
-
*
|
|
2050
|
-
* @example
|
|
2051
|
-
* const formattedDate1 = dateRearrangeMapper['DDMMYYYY']('01-12-2023');
|
|
2052
|
-
* console.log(formattedDate1); // '12/01/2023'
|
|
2053
|
-
*
|
|
2054
|
-
* const formattedDate2 = dateRearrangeMapper['YYYYMMDD']('2023-12-01');
|
|
2055
|
-
* console.log(formattedDate2); // '12/01/2023'
|
|
2056
|
-
*/
|
|
2057
|
-
const dateRearrangeMapper = {
|
|
2058
|
-
DDMMYYYY: value => {
|
|
2059
|
-
const dateParts = value.split(value.includes('/') ? '/' : '-');
|
|
2060
|
-
return `${dateParts[1]}/${dateParts[0]}/${dateParts[2]}`;
|
|
2061
|
-
},
|
|
2062
|
-
YYYYMMDD: value => {
|
|
2063
|
-
const dateParts = value.split(value.includes('/') ? '/' : '-');
|
|
2064
|
-
return `${dateParts[1]}/${dateParts[2]}/${dateParts[0]}`;
|
|
2065
|
-
},
|
|
2066
|
-
YYYYDDMM: value => {
|
|
2067
|
-
const dateParts = value.split(value.includes('/') ? '/' : '-');
|
|
2068
|
-
return `${dateParts[2]}/${dateParts[1]}/${dateParts[0]}`;
|
|
2069
|
-
},
|
|
2070
|
-
MMDDYYYY: value => value,
|
|
2071
|
-
timestamp: value => new Date(value).toString()
|
|
2072
|
-
};
|
|
2073
|
-
/**
|
|
2074
|
-
* @function betweenDates
|
|
2075
|
-
* Validates if a date value falls between two specified dates.
|
|
2076
|
-
*
|
|
2077
|
-
* @param {string} value - The date value to be validated in string format.
|
|
2078
|
-
* @param {TValidationMethods} validations - The validation methods object containing the betweenDates validation rules.
|
|
2079
|
-
* @returns {boolean} - Returns `true` if the date value fails the betweenDates validation, otherwise `false`.
|
|
2080
|
-
*
|
|
2081
|
-
* @example
|
|
2082
|
-
* ```typescript
|
|
2083
|
-
* const validations = {
|
|
2084
|
-
* betweenDates: [
|
|
2085
|
-
* { origin: { value: '2023-01-01', format: 'yyyy-MM-dd' }, operator: '>=' },
|
|
2086
|
-
* { origin: { value: '2023-12-31', format: 'yyyy-MM-dd' }, operator: '<=' }
|
|
2087
|
-
* ]
|
|
2088
|
-
* };
|
|
2089
|
-
*
|
|
2090
|
-
* const result1 = betweenDates('2023-06-01', validations);
|
|
2091
|
-
* console.log(result1); // false (date is within the range)
|
|
2092
|
-
*
|
|
2093
|
-
* const result2 = betweenDates('2024-01-01', validations);
|
|
2094
|
-
* console.log(result2); // true (date is outside the range)
|
|
2095
|
-
* ```
|
|
2096
|
-
*/
|
|
2097
|
-
const betweenDates = (value, validations) => {
|
|
2098
|
-
var _a;
|
|
2099
|
-
let fail = false;
|
|
2100
|
-
if (((_a = validations.betweenDates) === null || _a === void 0 ? void 0 : _a.length) != 2) return false;
|
|
2101
|
-
for (const validation of validations.betweenDates) {
|
|
2102
|
-
if (date(value, {
|
|
2103
|
-
date: validation
|
|
2104
|
-
})) {
|
|
2105
|
-
fail = true;
|
|
2106
|
-
break;
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
return fail;
|
|
2110
|
-
};
|
|
2111
|
-
/**
|
|
2112
|
-
* @function date
|
|
2113
|
-
* Validates a date value based on various date conditions and intervals.
|
|
2114
|
-
*
|
|
2115
|
-
* @param {string} value - The date value to be validated in string format.
|
|
2116
|
-
* @param {TValidationMethods} validations - The validation methods object containing the date validation rules.
|
|
2117
|
-
* @returns {boolean} - Returns `true` if the date validation fails, otherwise `false`.
|
|
2118
|
-
*
|
|
2119
|
-
* @example
|
|
2120
|
-
* ```typescript
|
|
2121
|
-
* const validations = {
|
|
2122
|
-
* date: {
|
|
2123
|
-
* origin: {
|
|
2124
|
-
* value: '2023-01-01',
|
|
2125
|
-
* format: 'YYYY-MM-DD'
|
|
2126
|
-
* },
|
|
2127
|
-
* target: {
|
|
2128
|
-
* value: '2023-12-31',
|
|
2129
|
-
* format: 'YYYY-MM-DD'
|
|
2130
|
-
* },
|
|
2131
|
-
* operator: '<=',
|
|
2132
|
-
* onlyValidDate: true
|
|
2133
|
-
* }
|
|
2134
|
-
* };
|
|
2135
|
-
*
|
|
2136
|
-
* const result1 = date('2023-06-01', validations);
|
|
2137
|
-
* console.log(result1); // false (date is within the range)
|
|
2138
|
-
*
|
|
2139
|
-
* const result2 = date('2024-01-01', validations);
|
|
2140
|
-
* console.log(result2); // true (date is outside the range)
|
|
2141
|
-
* ```
|
|
2142
|
-
*/
|
|
2143
|
-
const date = (value, validations) => {
|
|
2144
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
2145
|
-
if (!((_b = (_a = validations.date) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.value) && !((_d = (_c = validations.date) === null || _c === void 0 ? void 0 : _c.origin) === null || _d === void 0 ? void 0 : _d.intervals)) {
|
|
2146
|
-
return false;
|
|
2147
|
-
}
|
|
2148
|
-
const originValue = validations.date.origin.value || value;
|
|
2149
|
-
const mappedValue = dateRearrangeMapper[(_e = validations.date) === null || _e === void 0 ? void 0 : _e.origin.format](originValue).toString();
|
|
2150
|
-
let originDate = new Date(mappedValue);
|
|
2151
|
-
let targetDate = new Date();
|
|
2152
|
-
let target = new Date();
|
|
2153
|
-
if ((_g = (_f = validations.date) === null || _f === void 0 ? void 0 : _f.target) === null || _g === void 0 ? void 0 : _g.format) {
|
|
2154
|
-
target = new Date(dateRearrangeMapper[(_j = (_h = validations.date) === null || _h === void 0 ? void 0 : _h.target) === null || _j === void 0 ? void 0 : _j.format](validations.date.target.value).toString());
|
|
2155
|
-
targetDate = target;
|
|
2156
|
-
}
|
|
2157
|
-
if (validations.date.origin.intervals) {
|
|
2158
|
-
targetDate = getIntervalsDate(originDate, validations.date.origin.intervals);
|
|
2159
|
-
const date = new Date();
|
|
2160
|
-
if (((_k = validations.date.target) === null || _k === void 0 ? void 0 : _k.value) && target) {
|
|
2161
|
-
date.setDate(target.getDate());
|
|
2162
|
-
date.setMonth(target.getMonth());
|
|
2163
|
-
}
|
|
2164
|
-
originDate = new Date(`${date.getUTCMonth() + 1}/${date.getUTCDate()}/${date.getUTCFullYear()}`);
|
|
2165
|
-
}
|
|
2166
|
-
if (validations.date.onlyValidDate && (!(targetDate instanceof Date && isFinite(targetDate)) || !(targetDate instanceof Date && isFinite(originDate)) || originValue.length < 8)) {
|
|
2167
|
-
return true;
|
|
2168
|
-
}
|
|
2169
|
-
if (invalidStringDate(mappedValue, (_l = validations.date) === null || _l === void 0 ? void 0 : _l.origin.format)) {
|
|
2170
|
-
return false;
|
|
2171
|
-
}
|
|
2172
|
-
const originTimestamp = originDate.getTime();
|
|
2173
|
-
const targetTimestamp = targetDate.getTime();
|
|
2174
|
-
const operationsMapper = {
|
|
2175
|
-
'>': originTimestamp > targetTimestamp,
|
|
2176
|
-
'>=': originTimestamp >= targetTimestamp,
|
|
2177
|
-
'<': originTimestamp < targetTimestamp,
|
|
2178
|
-
'<=': originTimestamp <= targetTimestamp,
|
|
2179
|
-
'===': originTimestamp === targetTimestamp,
|
|
2180
|
-
'!==': originTimestamp !== targetTimestamp
|
|
2181
|
-
};
|
|
2182
|
-
return operationsMapper[(_m = validations.date) === null || _m === void 0 ? void 0 : _m.operator];
|
|
2183
|
-
};
|
|
2184
|
-
/**
|
|
2185
|
-
* @function validDate
|
|
2186
|
-
* Validates that a date string is a valid date according to the given format.
|
|
2187
|
-
*
|
|
2188
|
-
* @param {string} value - The date value to be validated in string format.
|
|
2189
|
-
* @param {TValidationMethods} validations - The validation methods object containing the validDate rule.
|
|
2190
|
-
* @returns {boolean} - Returns `true` if the date is not valid, otherwise `false`.
|
|
2191
|
-
*
|
|
2192
|
-
* @example
|
|
2193
|
-
* ```typescript
|
|
2194
|
-
* const validations = { validDate: 'MM-dd-yyyy' };
|
|
2195
|
-
*
|
|
2196
|
-
* const result1 = validDate('12-31-2023', validations);
|
|
2197
|
-
* console.log(result1); // false (date is valid)
|
|
2198
|
-
*
|
|
2199
|
-
* const result2 = validDate('02-30-2023', validations);
|
|
2200
|
-
* console.log(result2); // true (date is invalid)
|
|
2201
|
-
* ```
|
|
2202
|
-
*/
|
|
2203
|
-
const validDate = (value, validations) => {
|
|
2204
|
-
if (!validations.validDate || !value) return false;
|
|
2205
|
-
if (/[^a-zA-Z0-9\s-]/.test(value)) return true;
|
|
2206
|
-
const dateParts = dateRearrangeMapper[validations.validDate](value).toString().split(/[/-]/);
|
|
2207
|
-
const year = parseInt(dateParts[2], 10);
|
|
2208
|
-
const month = parseInt(dateParts[0], 10) - 1; // Month is zero-based
|
|
2209
|
-
const day = parseInt(dateParts[1], 10);
|
|
2210
|
-
const date = new Date(year, month, day);
|
|
2211
|
-
/*
|
|
2212
|
-
* Motivation: due to the scenario in which a date field may be 'typeable',
|
|
2213
|
-
* we need to ensure that dates less than a thousand and such years are valid.
|
|
2214
|
-
* E.g.: user types 13-07-199 (without this condition, it becomes a valid date, as 199 is a valid year)
|
|
2215
|
-
*
|
|
2216
|
-
* Ps: 150 is a valid value for now, as we still cannot live more than that, from the
|
|
2217
|
-
* the moment we start to live longer, we can rethink this.
|
|
2218
|
-
*/
|
|
2219
|
-
const today = new Date();
|
|
2220
|
-
today.setFullYear(today.getFullYear() - 150);
|
|
2221
|
-
if (date.getFullYear() < today.getFullYear()) {
|
|
2222
|
-
return true;
|
|
2223
|
-
}
|
|
2224
|
-
// Check if the date is valid
|
|
2225
|
-
const isValidDate = date.getFullYear() === year && date.getMonth() === month && date.getDate() === day;
|
|
2226
|
-
return !isValidDate;
|
|
2227
|
-
};
|
|
2228
|
-
|
|
2229
|
-
/**
|
|
2230
|
-
* @internal
|
|
2231
|
-
* Runs a set of validation handlers against a given value.
|
|
2232
|
-
*
|
|
2233
|
-
* @param {unknown} value - The value to be validated.
|
|
2234
|
-
* @param {TValidationMethods} handlers - An object containing validation methods to be applied.
|
|
2235
|
-
* @param {TValidationHandler} validations - An object containing every validation methods to be executed.
|
|
2236
|
-
* @returns {boolean[]} - An array of boolean results for each validation method.
|
|
2237
|
-
*
|
|
2238
|
-
* @example
|
|
2239
|
-
* const handlers = {
|
|
2240
|
-
* max: { max: 10 },
|
|
2241
|
-
* required: true,
|
|
2242
|
-
* email: true
|
|
2243
|
-
* };
|
|
2244
|
-
* const results = run('test@example.com', handlers);
|
|
2245
|
-
* console.log(results); // [false, false, true] (value fails 'max', passes 'required', passes 'email')
|
|
2246
|
-
*/
|
|
2247
|
-
function run$1(value, handlers, validations) {
|
|
2248
|
-
const runner = [];
|
|
2249
|
-
Object.keys(handlers).forEach(rule => {
|
|
2250
|
-
runner.push(validations[rule](value, {
|
|
2251
|
-
[rule]: handlers[rule]
|
|
2252
|
-
}));
|
|
2253
|
-
});
|
|
2254
|
-
return runner;
|
|
2255
|
-
}
|
|
2256
|
-
/**
|
|
2257
|
-
* Validates a given value based on specified validation methods inside a custom named validation.
|
|
2258
|
-
*
|
|
2259
|
-
* @param {unknown} value - The value to be validated.
|
|
2260
|
-
* @param {TValidationMethods} methods - The validation methods to be applied.
|
|
2261
|
-
* @param {TValidationHandler} validations - An object containing every validation methods to be executed.
|
|
2262
|
-
* @returns {boolean} - Returns true if any of the validation methods pass, otherwise false.
|
|
2263
|
-
*
|
|
2264
|
-
* @example
|
|
2265
|
-
* const value = 'example@example.com';
|
|
2266
|
-
* const methods = {
|
|
2267
|
-
* required: true,
|
|
2268
|
-
* email: true
|
|
2269
|
-
* };
|
|
2270
|
-
*
|
|
2271
|
-
* const isValid = validateValue(value, methods);
|
|
2272
|
-
* console.log(isValid); // Output: true
|
|
2273
|
-
*/
|
|
2274
|
-
var namedRule = (value, methods, validations) => {
|
|
2275
|
-
if (!methods) return false;
|
|
2276
|
-
return run$1(value, methods, validations).some(validation => validation);
|
|
2277
|
-
};
|
|
2278
|
-
|
|
2279
|
-
/**
|
|
2280
|
-
* @internal
|
|
2281
|
-
* An object mapping validation keys to their respective validation functions.
|
|
2282
|
-
*
|
|
2283
|
-
* @type {Record<keyof TAvailableValidations, (value: unknown, validations: TAvailableValidations) => boolean>}
|
|
2284
|
-
*
|
|
2285
|
-
* @example
|
|
2286
|
-
* const isValid = validations.max(5, { max: 10 });
|
|
2287
|
-
* console.log(isValid); // false (5 is not greater than 10)
|
|
2288
|
-
*/
|
|
2289
|
-
const validations$1 = {
|
|
2290
|
-
max,
|
|
2291
|
-
min,
|
|
2292
|
-
lessThan,
|
|
2293
|
-
greaterThan,
|
|
2294
|
-
length,
|
|
2295
|
-
regex,
|
|
2296
|
-
url,
|
|
2297
|
-
email,
|
|
2298
|
-
onlyLetters,
|
|
2299
|
-
notAllowSpaces,
|
|
2300
|
-
callback,
|
|
2301
|
-
hasNoExtraSpaces,
|
|
2302
|
-
between,
|
|
2303
|
-
sequential,
|
|
2304
|
-
includes,
|
|
2305
|
-
repeated,
|
|
2306
|
-
document,
|
|
2307
|
-
isCreditCard,
|
|
2308
|
-
isCreditCodeMatch,
|
|
2309
|
-
isCreditCardAndLength,
|
|
2310
|
-
required,
|
|
2311
|
-
value,
|
|
2312
|
-
notEmpty,
|
|
2313
|
-
bool,
|
|
2314
|
-
exists,
|
|
2315
|
-
isNumber,
|
|
2316
|
-
conditions,
|
|
2317
|
-
validDate,
|
|
2318
|
-
date,
|
|
2319
|
-
betweenDates
|
|
2320
|
-
};
|
|
2321
|
-
/**
|
|
2322
|
-
* @internal
|
|
2323
|
-
* Runs a set of validation handlers against a given value.
|
|
2324
|
-
*
|
|
2325
|
-
* @param {unknown} value - The value to be validated.
|
|
2326
|
-
* @param {TValidationMethods} handlers - An object containing validation methods to be applied.
|
|
2327
|
-
* @returns {boolean[]} - An array of boolean results for each validation method.
|
|
2328
|
-
*
|
|
2329
|
-
* @example
|
|
2330
|
-
* const handlers = {
|
|
2331
|
-
* max: { max: 10 },
|
|
2332
|
-
* required: true,
|
|
2333
|
-
* email: true
|
|
2334
|
-
* };
|
|
2335
|
-
* const results = run('test@example.com', handlers);
|
|
2336
|
-
* console.log(results); // [false, false, true] (value fails 'max', passes 'required', passes 'email')
|
|
2337
|
-
*/
|
|
2338
|
-
function run(value, handlers) {
|
|
2339
|
-
const runner = [];
|
|
2340
|
-
Object.keys(handlers).forEach(rule => {
|
|
2341
|
-
let handler;
|
|
2342
|
-
if (isFunction(validations$1[rule])) {
|
|
2343
|
-
handler = validations$1[rule](value, {
|
|
2344
|
-
[rule]: handlers[rule]
|
|
2345
|
-
});
|
|
2346
|
-
} else {
|
|
2347
|
-
handler = namedRule(value, handlers[rule], validations$1);
|
|
2348
|
-
}
|
|
2349
|
-
runner.push(handler);
|
|
2350
|
-
});
|
|
2351
|
-
return runner;
|
|
2352
|
-
}
|
|
2353
|
-
/**
|
|
2354
|
-
* Validates that a value meets multiple validation rules.
|
|
2355
|
-
*
|
|
2356
|
-
* @param {number | string | boolean} value - The value to be validated.
|
|
2357
|
-
* @param {TValidationMethods} methods - The validation methods object containing the multipleValidations rule set.
|
|
2358
|
-
* @returns {boolean} - Returns `true` if the value meets the specified multiple validation rules, otherwise `false`.
|
|
2359
|
-
*
|
|
2360
|
-
* @example
|
|
2361
|
-
* ```typescript
|
|
2362
|
-
* // Assume validations is an object with a multipleValidations property
|
|
2363
|
-
* const validations = {
|
|
2364
|
-
* multipleValidations: {
|
|
2365
|
-
* rule: 'AND',
|
|
2366
|
-
* validations: {
|
|
2367
|
-
* required: true,
|
|
2368
|
-
* isNumber: true
|
|
2369
|
-
* }
|
|
2370
|
-
* }
|
|
2371
|
-
* };
|
|
2372
|
-
*
|
|
2373
|
-
* // Returns true because both required and isNumber validations pass
|
|
2374
|
-
* const result1 = multipleValidations(123, validations);
|
|
2375
|
-
* console.log(result1); // true
|
|
2376
|
-
*
|
|
2377
|
-
* // Returns false because the value is not a number
|
|
2378
|
-
* const result2 = multipleValidations('abc', validations);
|
|
2379
|
-
* console.log(result2); // false
|
|
2380
|
-
* ```
|
|
2381
|
-
*/
|
|
2382
|
-
const multipleValidations = (value, methods) => {
|
|
2383
|
-
if (!methods.multipleValidations) return false;
|
|
2384
|
-
const runner = run(value, methods.multipleValidations.validations);
|
|
2385
|
-
const rulesMapper = {
|
|
2386
|
-
AND: () => runner.every(validation => validation),
|
|
2387
|
-
OR: () => runner.some(validation => validation),
|
|
2388
|
-
NOT: () => !runner.every(validation => validation)
|
|
2389
|
-
};
|
|
2390
|
-
return rulesMapper[methods.multipleValidations.rule]();
|
|
2391
|
-
};
|
|
2392
|
-
|
|
2393
|
-
const validations = {
|
|
2394
|
-
max,
|
|
2395
|
-
min,
|
|
2396
|
-
lessThan,
|
|
2397
|
-
greaterThan,
|
|
2398
|
-
length,
|
|
2399
|
-
regex,
|
|
2400
|
-
url,
|
|
2401
|
-
email,
|
|
2402
|
-
onlyLetters,
|
|
2403
|
-
notAllowSpaces,
|
|
2404
|
-
callback,
|
|
2405
|
-
hasNoExtraSpaces,
|
|
2406
|
-
between,
|
|
2407
|
-
sequential,
|
|
2408
|
-
includes,
|
|
2409
|
-
repeated,
|
|
2410
|
-
document,
|
|
2411
|
-
isCreditCard,
|
|
2412
|
-
isCreditCodeMatch,
|
|
2413
|
-
isCreditCardAndLength,
|
|
2414
|
-
required,
|
|
2415
|
-
value,
|
|
2416
|
-
notEmpty,
|
|
2417
|
-
bool,
|
|
2418
|
-
exists,
|
|
2419
|
-
isNumber,
|
|
2420
|
-
conditions,
|
|
2421
|
-
multipleValidations,
|
|
2422
|
-
date,
|
|
2423
|
-
betweenDates,
|
|
2424
|
-
validDate
|
|
2425
|
-
};
|
|
2426
|
-
|
|
2427
|
-
/**
|
|
2428
|
-
* Custom RXJS Subject to gracefully handle errors on unsubscribed Subjects
|
|
2429
|
-
* that were unmounted due to adapter external handling such as visibility
|
|
2430
|
-
*/
|
|
2431
|
-
class SafeSubject extends Subject {
|
|
2432
|
-
constructor(isMounted) {
|
|
2433
|
-
super();
|
|
2434
|
-
this.isMounted = isMounted;
|
|
2435
|
-
}
|
|
2436
|
-
next(value) {
|
|
2437
|
-
if (this.isMounted()) {
|
|
2438
|
-
super.next(value);
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
|
|
2443
|
-
/**
|
|
2444
|
-
* @internal
|
|
2445
|
-
* Handles the validation of a given value based on specified validation methods and rules.
|
|
2446
|
-
*
|
|
2447
|
-
* @param {string | number | boolean | unknown} value - The value to be validated.
|
|
2448
|
-
* @param {TSchemaValidation} validations - The schema validations to be applied.
|
|
2449
|
-
* @param {TValidationHandler} methods - The validation handler methods.
|
|
2450
|
-
* @param {keyof TValidationMethods} key - The specific key of the validation method to be used.
|
|
2451
|
-
* @returns {boolean} - Returns true if the value passes the validation, otherwise false.
|
|
2452
|
-
*
|
|
2453
|
-
* @example
|
|
2454
|
-
* const value = 'example@example.com';
|
|
2455
|
-
* const validations = {
|
|
2456
|
-
* required: true,
|
|
2457
|
-
* customName: { email: true }
|
|
2458
|
-
* };
|
|
2459
|
-
* const methods = {
|
|
2460
|
-
* email: (value) => /\S+@\S+\.\S+/.test(value)
|
|
2461
|
-
* };
|
|
2462
|
-
* const key = 'required';
|
|
2463
|
-
*
|
|
2464
|
-
* const isValid = handleValidation(value, validations, methods, key);
|
|
2465
|
-
* console.log(isValid); // Output: true
|
|
2466
|
-
*/
|
|
2467
|
-
function handleValidation(value, validations, methods, key) {
|
|
2468
|
-
if (isFunction(methods[key])) {
|
|
2469
|
-
return methods[key](value, validations);
|
|
2470
|
-
}
|
|
2471
|
-
return namedRule(value, validations[key], methods);
|
|
2472
|
-
}
|
|
2473
|
-
|
|
2474
|
-
/**
|
|
2475
|
-
* Represents a form field with observables for managing form state, validations, and API requests.
|
|
2476
|
-
*/
|
|
2477
|
-
class FormField {
|
|
2478
|
-
/**
|
|
2479
|
-
* Creates an instance of FormField.
|
|
2480
|
-
*
|
|
2481
|
-
* @param {object} options - Configuration options for the form field.
|
|
2482
|
-
* @param {IComponentSchema} options.schemaComponent - The schema definition for the form field.
|
|
2483
|
-
* @param {TSchemaFormConfig} options.config - The schema default configuration for debounced actions.
|
|
2484
|
-
* @param {string} [options.path] - The path within the form field (used internally during recursion).
|
|
2485
|
-
* @param {string[]} options.children - An array of children fields names.
|
|
2486
|
-
* @param {Function} options.validateVisibility - A function to validate the visibility of the field.
|
|
2487
|
-
* @param {Function} options.resetValue - A function to reset the field value.
|
|
2488
|
-
* @param {Function} options.resetProperty - A function to reset a field property.
|
|
2489
|
-
* @param {Subject<{ key: string }>} options.templateSubject$ - A subject for template updates.
|
|
2490
|
-
* @param {Subject<TFieldEvent>} options.fieldEventSubject$, - Subject for basic event mapped field emissions, except onData to form instance
|
|
2491
|
-
* @param {Subject<{ key: string; event: TEvents }>} options.dataSubject$, - Subject to emit onData events to form instance
|
|
2492
|
-
* @param {Subject<{ key: string }>} options.formValidNotification$, - Subject to emit field valid change to form instance
|
|
2493
|
-
* @param {TMapper<unknown>} options.mapper, - component generic mapper containing render parameters for adapters
|
|
2494
|
-
* @param {() => TFormValues<unknown>} options.getFormValues, - form instance function that builds onData parameter payload from fields
|
|
2495
|
-
*/
|
|
2496
|
-
constructor({
|
|
2497
|
-
formIndex,
|
|
2498
|
-
schemaComponent,
|
|
2499
|
-
config,
|
|
2500
|
-
path,
|
|
2501
|
-
children,
|
|
2502
|
-
validateVisibility,
|
|
2503
|
-
resetValue,
|
|
2504
|
-
resetProperty,
|
|
2505
|
-
templateSubject$,
|
|
2506
|
-
fieldEventSubject$,
|
|
2507
|
-
dataSubject$,
|
|
2508
|
-
fieldValidNotification$,
|
|
2509
|
-
mountSubject$,
|
|
2510
|
-
mapper,
|
|
2511
|
-
getFormValues,
|
|
2512
|
-
submitEvent,
|
|
2513
|
-
visibility,
|
|
2514
|
-
persistValue
|
|
2515
|
-
}) {
|
|
2516
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2517
|
-
this.valueSubscription$ = new Subscription();
|
|
2518
|
-
this.fieldStateSubscription$ = new Subscription();
|
|
2519
|
-
this.formIndex = formIndex;
|
|
2520
|
-
this.originalSchema = cloneDeep(schemaComponent);
|
|
2521
|
-
this.config = {
|
|
2522
|
-
defaultAPIdebounceTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultAPIdebounceTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultAPIdebounceTimeMS) : DEFAULT_API_DEBOUNCE_TIME,
|
|
2523
|
-
defaultStateRefreshTimeMS: Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) ? Number(config === null || config === void 0 ? void 0 : config.defaultStateRefreshTimeMS) : DEFAULT_STATE_REFRESH_TIME,
|
|
2524
|
-
defaultLogVerbose: (config === null || config === void 0 ? void 0 : config.defaultLogVerbose) ? config.defaultLogVerbose : DEFAULT_LOG_VERBOSE
|
|
2525
|
-
};
|
|
2526
|
-
this.name = schemaComponent.name;
|
|
2527
|
-
this.nameToSubmit = schemaComponent.nameToSubmit;
|
|
2528
|
-
this.component = schemaComponent.component;
|
|
2529
|
-
this.children = children;
|
|
2530
|
-
this.validations = cloneDeep(schemaComponent.validations);
|
|
2531
|
-
this.visibilityConditions = cloneDeep(schemaComponent.visibilityConditions);
|
|
2532
|
-
this.resetValues = cloneDeep(schemaComponent.resetValues);
|
|
2533
|
-
this.resetPropertyValues = cloneDeep(schemaComponent.resetPropertyValues);
|
|
2534
|
-
this.apiSchema = cloneDeep(schemaComponent.api);
|
|
2535
|
-
this.formatters = cloneDeep(schemaComponent.formatters);
|
|
2536
|
-
this.masks = cloneDeep(schemaComponent.masks);
|
|
2537
|
-
if (mapper.valueChangeEvent) this.valueChangeEvent = mapper.valueChangeEvent;
|
|
2538
|
-
if ((_a = mapper.events) === null || _a === void 0 ? void 0 : _a.setValue) this.valuePropName = mapper.events.setValue;
|
|
2539
|
-
this.mapper = mapper;
|
|
2540
|
-
this.validateVisibility = validateVisibility;
|
|
2541
|
-
this.resetValue = resetValue;
|
|
2542
|
-
this.resetProperty = resetProperty;
|
|
2543
|
-
this.getFormValues = getFormValues;
|
|
2544
|
-
this.submitEvent = submitEvent;
|
|
2545
|
-
this.templateSubject$ = templateSubject$;
|
|
2546
|
-
this.fieldEventSubject$ = fieldEventSubject$;
|
|
2547
|
-
this.dataSubject$ = dataSubject$;
|
|
2548
|
-
this.fieldValidNotification$ = fieldValidNotification$;
|
|
2549
|
-
this.mountSubject$ = mountSubject$;
|
|
2550
|
-
this._props = FormField.filterProps(cloneDeep(schemaComponent.props || {}));
|
|
2551
|
-
this._metadata = '';
|
|
2552
|
-
this.errorsString = '';
|
|
2553
|
-
this.errorsList = [];
|
|
2554
|
-
this._visibility = typeof visibility === 'boolean' ? visibility : true;
|
|
2555
|
-
this._api = {
|
|
2556
|
-
default: {
|
|
2557
|
-
response: ((_d = (_c = (_b = this.apiSchema) === null || _b === void 0 ? void 0 : _b.defaultConfig) === null || _c === void 0 ? void 0 : _c.config) === null || _d === void 0 ? void 0 : _d.fallbackValue) || '',
|
|
2558
|
-
status: null
|
|
2559
|
-
},
|
|
2560
|
-
named: ((_e = this.apiSchema) === null || _e === void 0 ? void 0 : _e.configs) && Object.keys((_f = this.apiSchema) === null || _f === void 0 ? void 0 : _f.configs).reduce((acc, curr) => {
|
|
2561
|
-
var _a, _b;
|
|
2562
|
-
acc[curr] = {
|
|
2563
|
-
response: ((_b = (_a = this.apiSchema) === null || _a === void 0 ? void 0 : _a.configs) === null || _b === void 0 ? void 0 : _b[curr].config.fallbackValue) || '',
|
|
2564
|
-
status: null
|
|
2565
|
-
};
|
|
2566
|
-
return acc;
|
|
2567
|
-
}, {}),
|
|
2568
|
-
apiState: {
|
|
2569
|
-
loading: false
|
|
2570
|
-
}
|
|
2571
|
-
};
|
|
2572
|
-
this._errors = {};
|
|
2573
|
-
this._mounted = false;
|
|
2574
|
-
this.valid = true;
|
|
2575
|
-
this.persistValue = persistValue;
|
|
2576
|
-
this.initializeObservers();
|
|
2577
|
-
}
|
|
2578
|
-
/**
|
|
2579
|
-
* method to initialize all recycled Subjects and initialize Observers on field instance creation or rerender
|
|
2580
|
-
* due to some visibility conditions unmounts the field from the adapter if they are children of it and avoid
|
|
2581
|
-
* emissions to unsubscribed fields
|
|
2582
|
-
*/
|
|
2583
|
-
initializeObservers() {
|
|
2584
|
-
if (!this.valueSubject$ || this.valueSubject$.closed) {
|
|
2585
|
-
this.valueSubject$ = new SafeSubject(() => this.mounted);
|
|
2586
|
-
}
|
|
2587
|
-
if (!this.errorSubject$ || this.errorSubject$.closed) {
|
|
2588
|
-
this.errorSubject$ = new SafeSubject(() => this.mounted);
|
|
2589
|
-
}
|
|
2590
|
-
if (!this.visibilitySubject$ || this.visibilitySubject$.closed) {
|
|
2591
|
-
this.visibilitySubject$ = new SafeSubject(() => this.mounted);
|
|
2592
|
-
}
|
|
2593
|
-
if (!this.propsSubject$ || this.propsSubject$.closed) {
|
|
2594
|
-
this.propsSubject$ = new SafeSubject(() => this.mounted);
|
|
2595
|
-
}
|
|
2596
|
-
if (!this.fieldStateSubscription$ || this.fieldStateSubscription$.closed) {
|
|
2597
|
-
this.fieldStateSubscription$ = new Subscription();
|
|
2598
|
-
}
|
|
2599
|
-
if (!this.apiEventQueueSubject$ || this.apiEventQueueSubject$.closed) {
|
|
2600
|
-
this.apiEventQueueSubject$ = new SafeSubject(() => this.mounted);
|
|
2601
|
-
}
|
|
2602
|
-
!this.apiEventQueueSubject$.observed && this.apiEventQueueSubject$.pipe(groupBy(({
|
|
2603
|
-
event
|
|
2604
|
-
}) => event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultAPIdebounceTimeMS))), filter(() => this.apiEventQueueSubject$ && !this.apiEventQueueSubject$.closed)).subscribe(payload => {
|
|
2605
|
-
this.apiRequest(payload);
|
|
2606
|
-
});
|
|
2607
|
-
}
|
|
2608
|
-
/**
|
|
2609
|
-
* Retrieves the properties associated with the form field.
|
|
2610
|
-
*
|
|
2611
|
-
* @returns {Record<string, unknown>} - The properties of the form field.
|
|
2612
|
-
*/
|
|
2613
|
-
get props() {
|
|
2614
|
-
return this._props;
|
|
2615
|
-
}
|
|
2616
|
-
/**
|
|
2617
|
-
* Sets the properties of the form field and notifies subscribers about the change.
|
|
2618
|
-
*
|
|
2619
|
-
* @param {Record<string, unknown>} props - The new properties to be set.
|
|
2620
|
-
*/
|
|
2621
|
-
set props(props) {
|
|
2622
|
-
if (typeof props === 'undefined' || isEqual(props, this.props)) return;
|
|
2623
|
-
this._props = props;
|
|
2624
|
-
this.propsSubject$.next(this.props);
|
|
2625
|
-
this.templateSubject$.next({
|
|
2626
|
-
scope: 'fields',
|
|
2627
|
-
key: this.name,
|
|
2628
|
-
event: 'ON_PROPS'
|
|
2629
|
-
});
|
|
2630
|
-
}
|
|
2631
|
-
/**
|
|
2632
|
-
* Static function to remove templates form the component props that will be shown when
|
|
2633
|
-
* the field mounts and the template routine executes, to be used on the adapter
|
|
2634
|
-
*
|
|
2635
|
-
* @param {unknown} props - the properties from the adapter components.
|
|
2636
|
-
*/
|
|
2637
|
-
static filterProps(props) {
|
|
2638
|
-
if (Array.isArray(props)) {
|
|
2639
|
-
return props.filter(el => typeof el === 'string' && el.includes('${') ? false : true).map(el => FormField.filterProps(el));
|
|
2640
|
-
}
|
|
2641
|
-
if (typeof props === 'object' && props !== null) {
|
|
2642
|
-
if (props instanceof Date) return props;
|
|
2643
|
-
return Object.keys(props).reduce((acc, curr) => {
|
|
2644
|
-
const propValue = props[curr];
|
|
2645
|
-
if (typeof propValue === 'string' && propValue.includes('${')) {
|
|
2646
|
-
return acc;
|
|
2647
|
-
}
|
|
2648
|
-
acc[curr] = FormField.filterProps(props[curr]);
|
|
2649
|
-
return acc;
|
|
2650
|
-
}, {});
|
|
2651
|
-
}
|
|
2652
|
-
return props;
|
|
2653
|
-
}
|
|
2654
|
-
/**
|
|
2655
|
-
* Retrieves the current state value of the form field.
|
|
2656
|
-
*
|
|
2657
|
-
* @returns {Record<string,unknown>} - The current state value of the form field.
|
|
2658
|
-
*/
|
|
2659
|
-
get stateValue() {
|
|
2660
|
-
return this._stateValue;
|
|
2661
|
-
}
|
|
2662
|
-
get metadata() {
|
|
2663
|
-
return this._metadata;
|
|
2664
|
-
}
|
|
2665
|
-
/**
|
|
2666
|
-
* Retrieves the current value of the form field.
|
|
2667
|
-
*
|
|
2668
|
-
* @returns {unknown} - The current value of the form field.
|
|
2669
|
-
*/
|
|
2670
|
-
get value() {
|
|
2671
|
-
return this._value;
|
|
2672
|
-
}
|
|
2673
|
-
/**
|
|
2674
|
-
* Sets the value of the form field and notifies subscribers about the change.
|
|
2675
|
-
*
|
|
2676
|
-
* @param {unknown} value - The new value to be set.
|
|
2677
|
-
*/
|
|
2678
|
-
set value(value) {
|
|
2679
|
-
var _a, _b, _c;
|
|
2680
|
-
/*
|
|
2681
|
-
too much unstable, if the valueChangeEvent parses the template event
|
|
2682
|
-
value, might occur unexpected results
|
|
2683
|
-
*/
|
|
2684
|
-
let val;
|
|
2685
|
-
if (this.valueChangeEvent) {
|
|
2686
|
-
try {
|
|
2687
|
-
val = this.valueChangeEvent(value, {
|
|
2688
|
-
props: this.props
|
|
2689
|
-
});
|
|
2690
|
-
} catch (e) {
|
|
2691
|
-
val = value;
|
|
2692
|
-
}
|
|
2693
|
-
} else {
|
|
2694
|
-
val = value;
|
|
2695
|
-
}
|
|
2696
|
-
if (typeof val === 'undefined' || val === null) return;
|
|
2697
|
-
if (typeof val === 'object' && '_value' in val && '_metadata' in val) {
|
|
2698
|
-
this._value = this.formatValue(val['_value']);
|
|
2699
|
-
this._stateValue = ((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setValue) ? {
|
|
2700
|
-
[this.mapper.events.setValue]: this.maskValue(this.formatValue(val['_value']))
|
|
2701
|
-
} : {};
|
|
2702
|
-
this._metadata = val._metadata;
|
|
2703
|
-
} else {
|
|
2704
|
-
this._value = this.formatValue(val);
|
|
2705
|
-
this._stateValue = ((_b = this.mapper.events) === null || _b === void 0 ? void 0 : _b.setValue) ? {
|
|
2706
|
-
[(_c = this.mapper.events) === null || _c === void 0 ? void 0 : _c.setValue]: this.maskValue(this.formatValue(val))
|
|
2707
|
-
} : {};
|
|
2708
|
-
this.maskValue(this.formatValue(val));
|
|
2709
|
-
this._metadata = val;
|
|
2710
|
-
}
|
|
2711
|
-
this.stateValue && this.valueSubject$.next(this.stateValue);
|
|
2712
|
-
this.templateSubject$.next({
|
|
2713
|
-
scope: 'fields',
|
|
2714
|
-
key: this.name,
|
|
2715
|
-
event: 'ON_VALUE'
|
|
2716
|
-
});
|
|
2717
|
-
}
|
|
2718
|
-
/**
|
|
2719
|
-
* Retrieves the visibility status of the form field.
|
|
2720
|
-
*
|
|
2721
|
-
* @returns {boolean} - The visibility status of the form field.
|
|
2722
|
-
*/
|
|
2723
|
-
get visibility() {
|
|
2724
|
-
return this._visibility;
|
|
2725
|
-
}
|
|
2726
|
-
/**
|
|
2727
|
-
* Sets the visibility status of the form field and notifies subscribers about the change.
|
|
2728
|
-
*
|
|
2729
|
-
* @param {boolean} visible - The new visibility status to be set.
|
|
2730
|
-
*/
|
|
2731
|
-
set visibility(visible) {
|
|
2732
|
-
if (typeof visible === 'undefined' || visible === this.visibility) return;
|
|
2733
|
-
this._visibility = visible;
|
|
2734
|
-
this.visibilitySubject$.next(this.visibility);
|
|
2735
|
-
this.templateSubject$.next({
|
|
2736
|
-
scope: 'fields',
|
|
2737
|
-
key: this.name,
|
|
2738
|
-
event: 'ON_VISIBILITY'
|
|
2739
|
-
});
|
|
2740
|
-
}
|
|
2741
|
-
/**
|
|
2742
|
-
* sets valid field state and notifies form instance via formValidNotification$
|
|
2743
|
-
*/
|
|
2744
|
-
set valid(valid) {
|
|
2745
|
-
if (typeof valid !== 'boolean' && this.valid === valid) return;
|
|
2746
|
-
this._valid = valid;
|
|
2747
|
-
this.triggerFieldValidNotification();
|
|
2748
|
-
}
|
|
2749
|
-
/**
|
|
2750
|
-
* Retrieves the validity status of the form field.
|
|
2751
|
-
*
|
|
2752
|
-
* @returns {boolean} - The validity status of the form field.
|
|
2753
|
-
*/
|
|
2754
|
-
get valid() {
|
|
2755
|
-
return this._valid;
|
|
2756
|
-
}
|
|
2757
|
-
/**
|
|
2758
|
-
* triggers field valid notification to handle the form instance valid notification
|
|
2759
|
-
*
|
|
2760
|
-
* Note: since form unmount can occur before field unmount, this subject might already be closed by form instance
|
|
2761
|
-
* quick workaround is to check if the subject is already closed before emitting
|
|
2762
|
-
* if form instance onValid or template form.valid doesn't work properly, might be due to this workaround
|
|
2763
|
-
*/
|
|
2764
|
-
triggerFieldValidNotification() {
|
|
2765
|
-
!this.fieldValidNotification$.closed && this.fieldValidNotification$.next({
|
|
2766
|
-
fieldTrigger: this.name
|
|
2767
|
-
});
|
|
2768
|
-
}
|
|
2769
|
-
/**
|
|
2770
|
-
* Retrieves the error messages associated with the form field.
|
|
2771
|
-
*
|
|
2772
|
-
* @returns {TErrorMessages} - The error messages associated with the form field.
|
|
2773
|
-
*/
|
|
2774
|
-
get errors() {
|
|
2775
|
-
return this._errors;
|
|
2776
|
-
}
|
|
2777
|
-
/**
|
|
2778
|
-
* Sets the error messages associated with the form field and notifies subscribers about the change.
|
|
2779
|
-
*
|
|
2780
|
-
* @param {TErrorMessages} errors - The new error messages to be set.
|
|
2781
|
-
*/
|
|
2782
|
-
set errors(errors) {
|
|
2783
|
-
var _a;
|
|
2784
|
-
if (typeof errors === 'undefined' || isEqual(errors, this.errors)) return;
|
|
2785
|
-
this._errors = errors;
|
|
2786
|
-
this.errorsList = Object.values(this.errors).filter(el => el !== undefined && el !== null);
|
|
2787
|
-
this.errorsString = this.errorsList.join(', ');
|
|
2788
|
-
/**
|
|
2789
|
-
* if any error receives a list of errors, set a prop for it, currently only supporting a single string
|
|
2790
|
-
*/
|
|
2791
|
-
((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setErrorMessage) && this.errorSubject$.next({
|
|
2792
|
-
[this.mapper.events.setErrorMessage]: this.errorsString
|
|
2793
|
-
});
|
|
2794
|
-
this.templateSubject$.next({
|
|
2795
|
-
scope: 'fields',
|
|
2796
|
-
key: this.name,
|
|
2797
|
-
event: 'ON_PROPS'
|
|
2798
|
-
});
|
|
2799
|
-
}
|
|
2800
|
-
/**
|
|
2801
|
-
* Retrieves the API response data associated with the form field.
|
|
2802
|
-
*
|
|
2803
|
-
* @returns {TApiResponse} - The API response data associated with the form field.
|
|
2804
|
-
*/
|
|
2805
|
-
get api() {
|
|
2806
|
-
return this._api;
|
|
2807
|
-
}
|
|
2808
|
-
/**
|
|
2809
|
-
* Sets the API response data associated with the form field and notifies subscribers about the change.
|
|
2810
|
-
*
|
|
2811
|
-
* @param {TApiResponse} response - The new API response data to be set.
|
|
2812
|
-
*/
|
|
2813
|
-
set api(response) {
|
|
2814
|
-
if (typeof response === 'undefined') return;
|
|
2815
|
-
this._api = response;
|
|
2816
|
-
this.templateSubject$.next({
|
|
2817
|
-
scope: 'fields',
|
|
2818
|
-
key: this.name,
|
|
2819
|
-
event: 'ON_API_RESPONSE'
|
|
2820
|
-
});
|
|
2821
|
-
// this.apiResponseSubject$.next({ key: this.name });
|
|
2822
|
-
this.emitEvents({
|
|
2823
|
-
event: 'ON_API_FIELD_RESPONSE'
|
|
2824
|
-
});
|
|
2825
|
-
}
|
|
2826
|
-
/**
|
|
2827
|
-
* notifies templates and event binded field configurations that a request starts it's processing
|
|
2828
|
-
*/
|
|
2829
|
-
notifyApiRequest() {
|
|
2830
|
-
this._api.apiState.loading = true;
|
|
2831
|
-
this.templateSubject$.next({
|
|
2832
|
-
scope: 'fields',
|
|
2833
|
-
key: this.name,
|
|
2834
|
-
event: 'ON_API_REQUEST'
|
|
2835
|
-
});
|
|
2836
|
-
this.emitEvents({
|
|
2837
|
-
event: 'ON_API_FIELD_REQUEST'
|
|
2838
|
-
});
|
|
2839
|
-
}
|
|
2840
|
-
/** Retrieves the mounted status of the field.
|
|
2841
|
-
*
|
|
2842
|
-
* @returns {boolean} - the mounted status of the field.
|
|
2843
|
-
*/
|
|
2844
|
-
get mounted() {
|
|
2845
|
-
return this._mounted;
|
|
2846
|
-
}
|
|
2847
|
-
/**
|
|
2848
|
-
* sets the mountedStatus and notifies the form that the field was mounted on the adapter
|
|
2849
|
-
* and it's ready to be handled by the form instance
|
|
2850
|
-
*
|
|
2851
|
-
* @param {boolean} mountedStatus - the mounted status to be set from the mountField function.
|
|
2852
|
-
*/
|
|
2853
|
-
set mounted(mountedStatus) {
|
|
2854
|
-
if (typeof mountedStatus === 'undefined' || mountedStatus === this.mounted) return;
|
|
2855
|
-
this._mounted = mountedStatus;
|
|
2856
|
-
this.initializeObservers();
|
|
2857
|
-
this.mountSubject$.next({
|
|
2858
|
-
key: this.name,
|
|
2859
|
-
status: this.mounted
|
|
2860
|
-
});
|
|
2861
|
-
}
|
|
2862
|
-
/**
|
|
2863
|
-
* Mounts the form field by initializing necessary subjects and combining their streams.
|
|
2864
|
-
*
|
|
2865
|
-
* @param {object} mountOpts - Adapter mount options.
|
|
2866
|
-
* @param {(value: unknown) => unknown} prop.valueSubscription - Adapter value change function
|
|
2867
|
-
* @param {(payload: Partial<IState>) => unknown} prop.propsSubscription - Adapter prop change function
|
|
2868
|
-
* @returns {void}
|
|
2869
|
-
*/
|
|
2870
|
-
mountField({
|
|
2871
|
-
valueSubscription,
|
|
2872
|
-
propsSubscription
|
|
2873
|
-
}) {
|
|
2874
|
-
this.mounted = true;
|
|
2875
|
-
this.subscribeValue(valueSubscription);
|
|
2876
|
-
this.subscribeState(propsSubscription);
|
|
2877
|
-
this.valueSubject$.next(this.stateValue);
|
|
2878
|
-
this.propsSubject$.next(this.props);
|
|
2879
|
-
this.visibilitySubject$.next(this.visibility);
|
|
2880
|
-
this.setFieldValidity({
|
|
2881
|
-
event: 'ON_FIELD_MOUNT'
|
|
2882
|
-
});
|
|
2883
|
-
}
|
|
2884
|
-
/**
|
|
2885
|
-
* Sets the value of the form field and emits associated events.
|
|
2886
|
-
*
|
|
2887
|
-
* @param {unknown} prop.value - The new value to be set.
|
|
2888
|
-
* @param {TEvents} prop.event - The event associated with setting the value.
|
|
2889
|
-
* @returns {void}
|
|
2890
|
-
*/
|
|
2891
|
-
emitValue(prop) {
|
|
2892
|
-
if (!this.visibility || !this.mounted) return;
|
|
2893
|
-
this.value = prop.value;
|
|
2894
|
-
this.dataSubject$.next({
|
|
2895
|
-
event: prop.event,
|
|
2896
|
-
fieldIndex: this.name,
|
|
2897
|
-
formIndex: this.formIndex
|
|
2898
|
-
});
|
|
2899
|
-
this.emitEvents({
|
|
2900
|
-
event: prop.event
|
|
2901
|
-
});
|
|
2902
|
-
}
|
|
2903
|
-
/**
|
|
2904
|
-
* Emits events to trigger field-related actions such as validation, visibility checks, value resets, and API requests.
|
|
2905
|
-
*
|
|
2906
|
-
* @param {TEvents} event - The event type that triggers the field actions.
|
|
2907
|
-
* @returns {void}
|
|
2908
|
-
*/
|
|
2909
|
-
emitEvents({
|
|
2910
|
-
event
|
|
2911
|
-
}) {
|
|
2912
|
-
if (event === 'ON_FORM_SUBMIT') {
|
|
2913
|
-
return this.submitEvent();
|
|
2914
|
-
}
|
|
2915
|
-
this.validateVisibility({
|
|
2916
|
-
event,
|
|
2917
|
-
key: this.name
|
|
2918
|
-
});
|
|
2919
|
-
this.setFieldValidity({
|
|
2920
|
-
event
|
|
2921
|
-
});
|
|
2922
|
-
this.resetValue({
|
|
2923
|
-
event,
|
|
2924
|
-
key: this.name
|
|
2925
|
-
});
|
|
2926
|
-
this.resetProperty({
|
|
2927
|
-
event,
|
|
2928
|
-
key: this.name
|
|
2929
|
-
});
|
|
2930
|
-
this.apiEventQueueSubject$.next({
|
|
2931
|
-
event
|
|
2932
|
-
});
|
|
2933
|
-
this.fieldEventSubject$.next({
|
|
2934
|
-
event,
|
|
2935
|
-
fieldName: this.name,
|
|
2936
|
-
fieldInstance: this
|
|
2937
|
-
});
|
|
2938
|
-
}
|
|
2939
|
-
/**
|
|
2940
|
-
* Sets the validity state of the field based on the provided validation rules and triggers error message updates.
|
|
2941
|
-
*
|
|
2942
|
-
* @param {TEvents} event - The event type associated with the field action.
|
|
2943
|
-
* @returns {void}
|
|
2944
|
-
*/
|
|
2945
|
-
setFieldValidity({
|
|
2946
|
-
event
|
|
2947
|
-
}) {
|
|
2948
|
-
var _a, _b, _c, _d;
|
|
2949
|
-
if (!this.validations || !this.visibility) {
|
|
2950
|
-
this.errors = {};
|
|
2951
|
-
this.valid = true;
|
|
2952
|
-
return;
|
|
2953
|
-
}
|
|
2954
|
-
let valid = true;
|
|
2955
|
-
const errors = {};
|
|
2956
|
-
const schemaValidations = (_a = this.validations) === null || _a === void 0 ? void 0 : _a.methods;
|
|
2957
|
-
schemaValidations && Object.keys(schemaValidations).forEach(validationKey => {
|
|
2958
|
-
var _a;
|
|
2959
|
-
const error = handleValidation(this.value, schemaValidations, validations, validationKey);
|
|
2960
|
-
// setting valid flag
|
|
2961
|
-
valid = !error && valid;
|
|
2962
|
-
// setting error messages
|
|
2963
|
-
if (error && ((_a = this.validations) === null || _a === void 0 ? void 0 : _a.messages)) {
|
|
2964
|
-
if (validationKey in this.validations.messages) {
|
|
2965
|
-
const messages = this.validations.messages;
|
|
2966
|
-
errors[validationKey] = messages[validationKey];
|
|
2967
|
-
} else if ('default' in this.validations.messages) {
|
|
2968
|
-
errors[validationKey] = this.validations.messages.default;
|
|
2969
|
-
}
|
|
2970
|
-
} else {
|
|
2971
|
-
delete errors[validationKey];
|
|
2972
|
-
}
|
|
2973
|
-
});
|
|
2974
|
-
this.valid = valid;
|
|
2975
|
-
if ((_c = (_b = this.validations) === null || _b === void 0 ? void 0 : _b.eventMessages) === null || _c === void 0 ? void 0 : _c[event]) {
|
|
2976
|
-
const eventMessages = {};
|
|
2977
|
-
(_d = this.validations.eventMessages[event]) === null || _d === void 0 ? void 0 : _d.forEach(method => {
|
|
2978
|
-
if (method in errors) {
|
|
2979
|
-
eventMessages[method] = errors[method];
|
|
2980
|
-
}
|
|
2981
|
-
});
|
|
2982
|
-
this.errors = eventMessages;
|
|
2983
|
-
} else if (event === 'ON_FIELD_VALIDATION') {
|
|
2984
|
-
this.errors = errors;
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
2987
|
-
/**
|
|
2988
|
-
* Formats the field value using the specified formatters, if available.
|
|
2989
|
-
*
|
|
2990
|
-
* @param {unknown} value - The value to be formatted.
|
|
2991
|
-
* @returns {unknown} - The formatted value.
|
|
2992
|
-
*/
|
|
2993
|
-
formatValue(value) {
|
|
2994
|
-
if (this.formatters) {
|
|
2995
|
-
return Object.keys(this.formatters).reduce((acc, curr) => {
|
|
2996
|
-
return formatters[curr](acc, this.formatters);
|
|
2997
|
-
}, value);
|
|
2998
|
-
}
|
|
2999
|
-
return value;
|
|
3000
|
-
}
|
|
3001
|
-
/**
|
|
3002
|
-
* Masks the field value using the specified masks, if available.
|
|
3003
|
-
*
|
|
3004
|
-
* @param {unknown} value - The value to be masked.
|
|
3005
|
-
* @returns {unknown} - The masked value.
|
|
3006
|
-
*/
|
|
3007
|
-
maskValue(value) {
|
|
3008
|
-
if (this.masks) {
|
|
3009
|
-
return Object.keys(this.masks).reduce((acc, curr) => {
|
|
3010
|
-
return masks[curr](acc, this.masks);
|
|
3011
|
-
}, value);
|
|
3012
|
-
}
|
|
3013
|
-
return value;
|
|
3014
|
-
}
|
|
3015
|
-
checkApiRequestValidations(config) {
|
|
3016
|
-
let valid = true;
|
|
3017
|
-
const preConditions = config.preConditions;
|
|
3018
|
-
preConditions && Object.keys(preConditions).forEach(validationKey => {
|
|
3019
|
-
const error = handleValidation(this.value, preConditions, validations, validationKey);
|
|
3020
|
-
valid = valid && !error;
|
|
3021
|
-
});
|
|
3022
|
-
if (config.blockRequestWhenInvalid) {
|
|
3023
|
-
valid = valid && this.valid;
|
|
3024
|
-
}
|
|
3025
|
-
return valid;
|
|
3026
|
-
}
|
|
3027
|
-
/**
|
|
3028
|
-
* Makes an API request based on the field's API configuration and event type, updating the field's API response data.
|
|
3029
|
-
*
|
|
3030
|
-
* @param {TEvents} event - The event type associated with the API request.
|
|
3031
|
-
* @returns {Promise<void>}
|
|
3032
|
-
*/
|
|
3033
|
-
apiRequest({
|
|
3034
|
-
event
|
|
3035
|
-
}) {
|
|
3036
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
3037
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
3038
|
-
let requestMadeOnce = false;
|
|
3039
|
-
const configRequest = config => __awaiter(this, void 0, void 0, function* () {
|
|
3040
|
-
var _k;
|
|
3041
|
-
try {
|
|
3042
|
-
const {
|
|
3043
|
-
status,
|
|
3044
|
-
response
|
|
3045
|
-
} = yield makeRequest(config.method, config.url, config.headers, config.body, config.queryParams);
|
|
3046
|
-
const callbackTransform = (_k = config.transform) === null || _k === void 0 ? void 0 : _k.callback;
|
|
3047
|
-
const apiResponseData = callbackTransform ? callbackTransform({
|
|
3048
|
-
payload: JSON.parse(String(response)),
|
|
3049
|
-
formValues: this.getFormValues()
|
|
3050
|
-
}) : JSON.parse(String(response));
|
|
3051
|
-
const responseReturn = config.resultPath ? get(apiResponseData, config.resultPath) : apiResponseData;
|
|
3052
|
-
// this.apiResponseData = { response };
|
|
3053
|
-
return {
|
|
3054
|
-
response: responseReturn,
|
|
3055
|
-
status
|
|
3056
|
-
};
|
|
3057
|
-
} catch (e) {
|
|
3058
|
-
return {
|
|
3059
|
-
response: !isNil(config === null || config === void 0 ? void 0 : config.fallbackValue) ? config.fallbackValue : 'error',
|
|
3060
|
-
status: 500
|
|
3061
|
-
};
|
|
3062
|
-
}
|
|
3063
|
-
});
|
|
3064
|
-
if (this.api.apiState.lastEvent === 'ON_API_FIELD_RESPONSE' && event === 'ON_API_FIELD_RESPONSE' || !((_b = (_a = this.apiSchema) === null || _a === void 0 ? void 0 : _a.defaultConfig) === null || _b === void 0 ? void 0 : _b.events.includes(event)) && !(((_c = this.apiSchema) === null || _c === void 0 ? void 0 : _c.configs) && Object.keys((_d = this.apiSchema) === null || _d === void 0 ? void 0 : _d.configs).some(key => {
|
|
3065
|
-
var _a, _b;
|
|
3066
|
-
return (_b = (_a = this.apiSchema) === null || _a === void 0 ? void 0 : _a.configs) === null || _b === void 0 ? void 0 : _b[key].events.includes(event);
|
|
3067
|
-
}))) return;
|
|
3068
|
-
const responses = {
|
|
3069
|
-
default: Object.assign({}, this.api.default),
|
|
3070
|
-
named: Object.assign({}, this.api.named),
|
|
3071
|
-
apiState: Object.assign({}, this.api.apiState)
|
|
3072
|
-
};
|
|
3073
|
-
const config = (_e = this.apiSchema.defaultConfig) === null || _e === void 0 ? void 0 : _e.config;
|
|
3074
|
-
if (config && ((_g = (_f = this.apiSchema) === null || _f === void 0 ? void 0 : _f.defaultConfig) === null || _g === void 0 ? void 0 : _g.events.includes(event)) && this.checkApiRequestValidations(config)) {
|
|
3075
|
-
!requestMadeOnce && this.notifyApiRequest();
|
|
3076
|
-
const {
|
|
3077
|
-
response,
|
|
3078
|
-
status
|
|
3079
|
-
} = yield configRequest(config);
|
|
3080
|
-
requestMadeOnce = true;
|
|
3081
|
-
responses.default = {
|
|
3082
|
-
response,
|
|
3083
|
-
status
|
|
3084
|
-
};
|
|
3085
|
-
}
|
|
3086
|
-
if (((_h = this.apiSchema) === null || _h === void 0 ? void 0 : _h.configs) && Object.keys((_j = this.apiSchema) === null || _j === void 0 ? void 0 : _j.configs).some(key => {
|
|
3087
|
-
var _a, _b;
|
|
3088
|
-
return (_b = (_a = this.apiSchema) === null || _a === void 0 ? void 0 : _a.configs) === null || _b === void 0 ? void 0 : _b[key].events.includes(event);
|
|
3089
|
-
})) {
|
|
3090
|
-
if (this.apiSchema.configs) {
|
|
3091
|
-
/*
|
|
3092
|
-
@TODO handle promises with error
|
|
3093
|
-
*/
|
|
3094
|
-
const result = yield Promise.all(Object.keys(this.apiSchema.configs).map(configKey => __awaiter(this, void 0, void 0, function* () {
|
|
3095
|
-
var _l, _m, _o, _p;
|
|
3096
|
-
const config = (_m = (_l = this.apiSchema) === null || _l === void 0 ? void 0 : _l.configs) === null || _m === void 0 ? void 0 : _m[configKey].config;
|
|
3097
|
-
if (config && ((_p = (_o = this.apiSchema) === null || _o === void 0 ? void 0 : _o.configs) === null || _p === void 0 ? void 0 : _p[configKey].events.includes(event)) && this.checkApiRequestValidations(config)) {
|
|
3098
|
-
!requestMadeOnce && this.notifyApiRequest();
|
|
3099
|
-
const {
|
|
3100
|
-
response,
|
|
3101
|
-
status
|
|
3102
|
-
} = yield configRequest(config);
|
|
3103
|
-
requestMadeOnce = true;
|
|
3104
|
-
return {
|
|
3105
|
-
name: configKey,
|
|
3106
|
-
result: {
|
|
3107
|
-
response,
|
|
3108
|
-
status
|
|
3109
|
-
}
|
|
3110
|
-
};
|
|
3111
|
-
}
|
|
3112
|
-
return null;
|
|
3113
|
-
})));
|
|
3114
|
-
result.forEach(payload => {
|
|
3115
|
-
if (payload && responses.named) responses.named[payload.name] = payload.result;
|
|
3116
|
-
});
|
|
3117
|
-
}
|
|
3118
|
-
}
|
|
3119
|
-
if (requestMadeOnce) {
|
|
3120
|
-
responses.apiState.lastEvent = event;
|
|
3121
|
-
responses.apiState.loading = false;
|
|
3122
|
-
this.api = responses;
|
|
3123
|
-
}
|
|
3124
|
-
});
|
|
3125
|
-
}
|
|
3126
|
-
/**
|
|
3127
|
-
* Unsubscribes from all subject subscriptions associated with the field, cleaning up resources.
|
|
3128
|
-
*
|
|
3129
|
-
* @returns {void}
|
|
3130
|
-
*/
|
|
3131
|
-
destroyField() {
|
|
3132
|
-
this.mounted = false;
|
|
3133
|
-
this.valueSubscription$.unsubscribe();
|
|
3134
|
-
this.visibilitySubject$.unsubscribe();
|
|
3135
|
-
this.fieldStateSubscription$.unsubscribe();
|
|
3136
|
-
this.propsSubject$.unsubscribe();
|
|
3137
|
-
this.errorSubject$.unsubscribe();
|
|
3138
|
-
this.apiEventQueueSubject$.unsubscribe();
|
|
3139
|
-
!this.dataSubject$.closed && this.dataSubject$.next({
|
|
3140
|
-
event: 'ON_FIELD_UNMOUNT',
|
|
3141
|
-
fieldIndex: this.name,
|
|
3142
|
-
formIndex: this.formIndex
|
|
3143
|
-
});
|
|
3144
|
-
!this.fieldEventSubject$.closed && this.fieldEventSubject$.next({
|
|
3145
|
-
event: 'ON_FIELD_UNMOUNT',
|
|
3146
|
-
fieldName: this.name,
|
|
3147
|
-
fieldInstance: this
|
|
3148
|
-
});
|
|
3149
|
-
}
|
|
3150
|
-
/**
|
|
3151
|
-
* Subscribes to changes in the field state and executes the provided callback function.
|
|
3152
|
-
*
|
|
3153
|
-
* @param {Function} callback - The callback function to be executed when the field state changes.
|
|
3154
|
-
* @returns {void}
|
|
3155
|
-
*/
|
|
3156
|
-
subscribeState(callback) {
|
|
3157
|
-
var _a;
|
|
3158
|
-
this.fieldStateSubscription$ = combineLatest({
|
|
3159
|
-
visibility: this.visibilitySubject$.pipe(startWith(this.visibility)),
|
|
3160
|
-
props: this.propsSubject$.pipe(startWith(this.props)),
|
|
3161
|
-
errors: this.errorSubject$.pipe(startWith(Object.assign({}, ((_a = this.mapper.events) === null || _a === void 0 ? void 0 : _a.setErrorMessage) && {
|
|
3162
|
-
[this.mapper.events.setErrorMessage]: this.errorsString
|
|
3163
|
-
})))
|
|
3164
|
-
}).pipe(debounceTime(this.config.defaultStateRefreshTimeMS)).subscribe({
|
|
3165
|
-
next: callback
|
|
3166
|
-
});
|
|
3167
|
-
}
|
|
3168
|
-
/**
|
|
3169
|
-
* Subscribes to changes in the field value and executes the provided callback function.
|
|
3170
|
-
*
|
|
3171
|
-
* @param {Function} callback - The callback function to be executed when the field value changes.
|
|
3172
|
-
* @returns {void}
|
|
3173
|
-
*/
|
|
3174
|
-
subscribeValue(callback) {
|
|
3175
|
-
this.valueSubscription$ = this.valueSubject$.subscribe({
|
|
3176
|
-
next: callback
|
|
3177
|
-
});
|
|
3178
|
-
}
|
|
3179
|
-
}
|
|
3180
|
-
|
|
3181
|
-
/**
|
|
3182
|
-
* Represents the core logic for managing a form, including field management, validation, and submission.
|
|
3183
|
-
*/
|
|
3184
|
-
class FormCore {
|
|
3185
|
-
/**
|
|
3186
|
-
* Creates an instance of FormCore.
|
|
3187
|
-
*
|
|
3188
|
-
* @param {TFormEntry & Omit<IFormSchema, 'components'>} entry - Configuration options for the form.
|
|
3189
|
-
* @param {IFormSchema} entry.schema - The schema definition for the form.
|
|
3190
|
-
* @param {Record<string, unknown> | IFormSchema.initialValues} [entry.initialValues] - Initial values for the form fields.
|
|
3191
|
-
* @param {string} [entry.action] - The action attribute of the form.
|
|
3192
|
-
* @param {string} [entry.method] - The method attribute of the form.
|
|
3193
|
-
* @param {IFormSchema.iVars} [entry.iVars] - The internal variables of the form.
|
|
3194
|
-
* @param {((payload: {field: string;data: TFormValues;}) => void) | undefined} [entry.onData] - A callback function to handle data emission.
|
|
3195
|
-
*/
|
|
3196
|
-
constructor(entry) {
|
|
3197
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
3198
|
-
this.templateSubscription$ = new Subscription();
|
|
3199
|
-
this.mappers = new Map();
|
|
3200
|
-
this.queuedFieldVisibilityEvents = new Map();
|
|
3201
|
-
this.queuedFieldResetValuesEvents = new Map();
|
|
3202
|
-
this.queuedFieldResetPropertyEvents = new Map();
|
|
3203
|
-
this.queuedInitialValues = new Map();
|
|
3204
|
-
this._valid = false;
|
|
3205
|
-
this.stopEventsOnSubmit = false;
|
|
3206
|
-
this.submitted = false;
|
|
3207
|
-
this.index = entry.index;
|
|
3208
|
-
this.schema = entry.schema;
|
|
3209
|
-
this.fields = new Map();
|
|
3210
|
-
this.action = entry.action || ((_a = entry.schema) === null || _a === void 0 ? void 0 : _a.action);
|
|
3211
|
-
this.method = entry.method || ((_b = entry.schema) === null || _b === void 0 ? void 0 : _b.method);
|
|
3212
|
-
this.config = {
|
|
3213
|
-
defaultAPIdebounceTimeMS: Number((_c = entry.config) === null || _c === void 0 ? void 0 : _c.defaultAPIdebounceTimeMS) ? Number((_d = entry.config) === null || _d === void 0 ? void 0 : _d.defaultAPIdebounceTimeMS) : DEFAULT_API_DEBOUNCE_TIME,
|
|
3214
|
-
defaultStateRefreshTimeMS: Number((_e = entry.config) === null || _e === void 0 ? void 0 : _e.defaultStateRefreshTimeMS) ? Number((_f = entry.config) === null || _f === void 0 ? void 0 : _f.defaultStateRefreshTimeMS) : DEFAULT_STATE_REFRESH_TIME,
|
|
3215
|
-
defaultLogVerbose: ((_g = entry.config) === null || _g === void 0 ? void 0 : _g.defaultLogVerbose) ? entry.config.defaultLogVerbose : DEFAULT_LOG_VERBOSE
|
|
3216
|
-
};
|
|
3217
|
-
(_h = entry.mappers) === null || _h === void 0 ? void 0 : _h.map(mapper => {
|
|
3218
|
-
this.mappers.set(mapper.componentName, mapper);
|
|
3219
|
-
});
|
|
3220
|
-
if ((!entry.submitSubject$ || !entry.dataSubject$ || !entry.formValidSubject$) && this.config.defaultLogVerbose) console.warn(`some formGroup events are not properly instanciated, any onData, onValid, onSubmit events managed by formGroup won't trigger on form: ${this.index}`);
|
|
3221
|
-
this.schema && FormCore.checkIndexes(this.schema.components);
|
|
3222
|
-
this.templateSubject$ = new Subject();
|
|
3223
|
-
this.fieldEventSubject$ = new Subject();
|
|
3224
|
-
this.mountSubject$ = new Subject();
|
|
3225
|
-
this.fieldValidNotification$ = new Subject();
|
|
3226
|
-
this.submitSubject$ = entry.submitSubject$ ? entry.submitSubject$ : new Subject();
|
|
3227
|
-
this.dataSubject$ = entry.dataSubject$ ? entry.dataSubject$ : new Subject();
|
|
3228
|
-
this.formValidSubject$ = entry.formValidSubject$ ? entry.formValidSubject$ : new Subject();
|
|
3229
|
-
this.subscribedTemplates = [];
|
|
3230
|
-
this.templateSubscription$ = this.templateSubject$.subscribe(this.refreshTemplates.bind(this));
|
|
3231
|
-
this.fieldValidNotification$.subscribe(() => {
|
|
3232
|
-
this.validateForm();
|
|
3233
|
-
});
|
|
3234
|
-
this.mountSubject$.subscribe(this.mountActions.bind(this));
|
|
3235
|
-
this.initialValues = entry.initialValues || ((_j = entry.schema) === null || _j === void 0 ? void 0 : _j.initialValues);
|
|
3236
|
-
this.iVars = entry.iVars || ((_k = entry.schema) === null || _k === void 0 ? void 0 : _k.iVars) || {};
|
|
3237
|
-
this.stopEventsOnSubmit = (entry === null || entry === void 0 ? void 0 : entry.stopEventsOnSubmit) || false;
|
|
3238
|
-
this.submitted = false;
|
|
3239
|
-
}
|
|
3240
|
-
/**
|
|
3241
|
-
* mock function to simulate form mount onto the adapter
|
|
3242
|
-
*/
|
|
3243
|
-
generateFields() {
|
|
3244
|
-
this.schema && this.serializeStructure(this.schema.components);
|
|
3245
|
-
this.fields.forEach(field => {
|
|
3246
|
-
field.mountField({
|
|
3247
|
-
valueSubscription: () => null,
|
|
3248
|
-
propsSubscription: () => null
|
|
3249
|
-
});
|
|
3250
|
-
});
|
|
3251
|
-
}
|
|
3252
|
-
/**
|
|
3253
|
-
*flag utility to prevent Subjects from emitting after form submission and stopEventsOnSubmit
|
|
3254
|
-
* @returns {boolean} - result of the flag utility.
|
|
3255
|
-
*/
|
|
3256
|
-
submitChecker() {
|
|
3257
|
-
return !(this.stopEventsOnSubmit && this.submitted);
|
|
3258
|
-
}
|
|
3259
|
-
/**
|
|
3260
|
-
* callback function passed to field instance to notify field adapter mount status
|
|
3261
|
-
* once the field has all field instance properties set, this function will handle all
|
|
3262
|
-
* field routines
|
|
3263
|
-
*
|
|
3264
|
-
* @param { string } entry.key field unique identifier
|
|
3265
|
-
* @param { boolean } entry.status mount status notified from field
|
|
3266
|
-
*/
|
|
3267
|
-
mountActions({
|
|
3268
|
-
key,
|
|
3269
|
-
status
|
|
3270
|
-
}) {
|
|
3271
|
-
if (status) {
|
|
3272
|
-
const field = this.fields.get(key);
|
|
3273
|
-
if (!field) {
|
|
3274
|
-
/*
|
|
3275
|
-
@TODO check a better way to handle nested fields unmounted by visiblity conditions from a parent
|
|
3276
|
-
since they are dependent on adapter field recycling runtimes
|
|
3277
|
-
*/
|
|
3278
|
-
this.config.defaultLogVerbose && console.warn(`field ${key} was mounted but since it's parent has some visibility condition the field was already removed`);
|
|
3279
|
-
return;
|
|
3280
|
-
}
|
|
3281
|
-
this.subscribeTemplates();
|
|
3282
|
-
this.refreshTemplates({
|
|
3283
|
-
scope: 'fields',
|
|
3284
|
-
event: 'ON_FIELDS'
|
|
3285
|
-
});
|
|
3286
|
-
this.templateSubject$.next({
|
|
3287
|
-
scope: 'iVars',
|
|
3288
|
-
event: 'ON_IVARS'
|
|
3289
|
-
});
|
|
3290
|
-
if (!this.queuedInitialValues.has(key)) field.valuePropName && !field.value ? field.emitValue({
|
|
3291
|
-
event: 'ON_FIELD_MOUNT',
|
|
3292
|
-
value: ''
|
|
3293
|
-
}) : field.emitEvents({
|
|
3294
|
-
event: 'ON_FIELD_MOUNT'
|
|
3295
|
-
});
|
|
3296
|
-
this.checkFieldEventQueues(key);
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
/**
|
|
3300
|
-
* initialValues setter to handle field values set externally from the adapter
|
|
3301
|
-
*
|
|
3302
|
-
* @param { Record<string, unknown> | undefined } payload initialValues to set onto fields
|
|
3303
|
-
*/
|
|
3304
|
-
set initialValues(payload) {
|
|
3305
|
-
if (payload) {
|
|
3306
|
-
Object.keys(payload).forEach(key => {
|
|
3307
|
-
const field = this.fields.get(key);
|
|
3308
|
-
if (!field || !(field === null || field === void 0 ? void 0 : field.visibility) || !(field === null || field === void 0 ? void 0 : field.mounted)) {
|
|
3309
|
-
this.queuedInitialValues.set(key, payload === null || payload === void 0 ? void 0 : payload[key]);
|
|
3310
|
-
} else {
|
|
3311
|
-
field.emitValue({
|
|
3312
|
-
value: payload === null || payload === void 0 ? void 0 : payload[key],
|
|
3313
|
-
event: 'ON_FIELD_MOUNT'
|
|
3314
|
-
});
|
|
3315
|
-
}
|
|
3316
|
-
});
|
|
3317
|
-
}
|
|
3318
|
-
}
|
|
3319
|
-
/**
|
|
3320
|
-
* Retrieves the internal variables (iVars) of the form.
|
|
3321
|
-
*
|
|
3322
|
-
* @returns {Record<string, unknown>} - The internal variables of the form.
|
|
3323
|
-
*/
|
|
3324
|
-
get iVars() {
|
|
3325
|
-
return this._iVars;
|
|
3326
|
-
}
|
|
3327
|
-
/**
|
|
3328
|
-
* Sets the internal variables (iVars) of the form and notifies subscribers about the change.
|
|
3329
|
-
*
|
|
3330
|
-
* @param {Record<string, unknown>} payload - The new internal variables to be set.
|
|
3331
|
-
*/
|
|
3332
|
-
set iVars(payload) {
|
|
3333
|
-
this._iVars = payload;
|
|
3334
|
-
this.templateSubject$.next({
|
|
3335
|
-
scope: 'iVars',
|
|
3336
|
-
event: 'ON_IVARS'
|
|
3337
|
-
});
|
|
3338
|
-
}
|
|
3339
|
-
/**
|
|
3340
|
-
* Validates all form fields and sets the form valid flag
|
|
3341
|
-
*
|
|
3342
|
-
*/
|
|
3343
|
-
validateForm() {
|
|
3344
|
-
if (this.fields.size === 0) return this.valid = false;
|
|
3345
|
-
for (const [, field] of this.fields) {
|
|
3346
|
-
if (!field.valid) return this.valid = false;
|
|
3347
|
-
}
|
|
3348
|
-
return this.valid = true;
|
|
3349
|
-
}
|
|
3350
|
-
get valid() {
|
|
3351
|
-
return this._valid;
|
|
3352
|
-
}
|
|
3353
|
-
set valid(valid) {
|
|
3354
|
-
if (this._valid === valid) return;
|
|
3355
|
-
this._valid = valid;
|
|
3356
|
-
this.templateSubject$.next({
|
|
3357
|
-
event: 'ON_FORM',
|
|
3358
|
-
scope: 'form'
|
|
3359
|
-
});
|
|
3360
|
-
this.formValidSubject$.next({
|
|
3361
|
-
formIndex: this.index,
|
|
3362
|
-
valid: this.valid
|
|
3363
|
-
});
|
|
3364
|
-
}
|
|
3365
|
-
/**
|
|
3366
|
-
* Subscribes to templates for dynamic updates.
|
|
3367
|
-
*/
|
|
3368
|
-
subscribeTemplates() {
|
|
3369
|
-
this.subscribedTemplates = [];
|
|
3370
|
-
this.fields.forEach(({
|
|
3371
|
-
originalSchema: {
|
|
3372
|
-
component,
|
|
3373
|
-
props,
|
|
3374
|
-
name,
|
|
3375
|
-
validations,
|
|
3376
|
-
visibilityConditions,
|
|
3377
|
-
resetValues,
|
|
3378
|
-
resetPropertyValues,
|
|
3379
|
-
api
|
|
3380
|
-
}
|
|
3381
|
-
}, key) => {
|
|
3382
|
-
const template = {
|
|
3383
|
-
component,
|
|
3384
|
-
props,
|
|
3385
|
-
name,
|
|
3386
|
-
validations,
|
|
3387
|
-
visibilityConditions,
|
|
3388
|
-
resetValues,
|
|
3389
|
-
resetPropertyValues,
|
|
3390
|
-
apiSchema: api
|
|
3391
|
-
};
|
|
3392
|
-
traverseObject(template, key).forEach(element => this.subscribedTemplates.push(element));
|
|
3393
|
-
});
|
|
3394
|
-
}
|
|
3395
|
-
/**
|
|
3396
|
-
* Gets the value of a property from a field.
|
|
3397
|
-
*
|
|
3398
|
-
* @param {object} options - Options for getting the value.
|
|
3399
|
-
* @param {string} options.key - The key of the field.
|
|
3400
|
-
* @param {string} options.property - The property to retrieve.
|
|
3401
|
-
* @param {string[]} options.path - The path to the property if it's nested.
|
|
3402
|
-
* @returns {unknown | undefined} The value of the property, or undefined if the field doesn't exist.
|
|
3403
|
-
*/
|
|
3404
|
-
getValue({
|
|
3405
|
-
scope,
|
|
3406
|
-
key,
|
|
3407
|
-
property,
|
|
3408
|
-
path
|
|
3409
|
-
}) {
|
|
3410
|
-
switch (scope) {
|
|
3411
|
-
case 'iVars':
|
|
3412
|
-
{
|
|
3413
|
-
const value = get(this.iVars, [key, ...(property ? [property] : []), ...path]);
|
|
3414
|
-
return value;
|
|
3415
|
-
}
|
|
3416
|
-
case 'form':
|
|
3417
|
-
{
|
|
3418
|
-
const value = get(this, [key, ...(property ? [property] : []), ...path]);
|
|
3419
|
-
return value;
|
|
3420
|
-
}
|
|
3421
|
-
case 'fields':
|
|
3422
|
-
{
|
|
3423
|
-
const field = this.fields.get(key);
|
|
3424
|
-
if (!field) return this.config.defaultLogVerbose && console.warn(`failed to get value from ${key}`);
|
|
3425
|
-
if (property === 'props' && path[0] === field.valuePropName) {
|
|
3426
|
-
return field.value;
|
|
3427
|
-
}
|
|
3428
|
-
return path.length > 0 ? get(field[property], path) : field[property];
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
}
|
|
3432
|
-
/**
|
|
3433
|
-
* Sets the value of a property in a field.
|
|
3434
|
-
*
|
|
3435
|
-
* @param {object} options - Options for setting the value.
|
|
3436
|
-
* @param {string} options.key - The key of the field.
|
|
3437
|
-
* @param {string} options.property - The property to set.
|
|
3438
|
-
* @param {string[]} options.path - The path to the property if it's nested.
|
|
3439
|
-
* @param {unknown} options.originKey - field that called templating
|
|
3440
|
-
* @param {unknown} options.value - The value to set.
|
|
3441
|
-
* @param {TMutationEvents} options.event - Internal Event for template Handling.
|
|
3442
|
-
*/
|
|
3443
|
-
setValue({
|
|
3444
|
-
key,
|
|
3445
|
-
property,
|
|
3446
|
-
path,
|
|
3447
|
-
originKey,
|
|
3448
|
-
value
|
|
3449
|
-
}) {
|
|
3450
|
-
const field = this.fields.get(key);
|
|
3451
|
-
if (!field) {
|
|
3452
|
-
this.config.defaultLogVerbose && console.warn(`failed to update field ${key}`);
|
|
3453
|
-
return;
|
|
3454
|
-
}
|
|
3455
|
-
if (path.length > 0) {
|
|
3456
|
-
/*
|
|
3457
|
-
property value is only allowed to be templated if the value isn't
|
|
3458
|
-
changed by itself, else a black hole opens
|
|
3459
|
-
previously using event !== 'ON_VALUE' on the condition
|
|
3460
|
-
now using key !== originKey, check if any recursion error occurs
|
|
3461
|
-
**/
|
|
3462
|
-
if (property === 'props' && path[0] === field.valuePropName && key !== originKey) {
|
|
3463
|
-
field.emitValue({
|
|
3464
|
-
event: 'ON_FIELD_CHANGE',
|
|
3465
|
-
value
|
|
3466
|
-
});
|
|
3467
|
-
return;
|
|
3468
|
-
}
|
|
3469
|
-
const fieldProp = field[property];
|
|
3470
|
-
let propState;
|
|
3471
|
-
if (Array.isArray(fieldProp) || typeof fieldProp === 'object' && !isNil(fieldProp)) {
|
|
3472
|
-
propState = cloneDeep(fieldProp);
|
|
3473
|
-
} else {
|
|
3474
|
-
this.config.defaultLogVerbose && console.warn(`invalid template property, skipping evaluation of ${field.name} with ${fieldProp}`);
|
|
3475
|
-
return;
|
|
3476
|
-
}
|
|
3477
|
-
set(propState, path, value);
|
|
3478
|
-
field[property] = propState;
|
|
3479
|
-
return;
|
|
3480
|
-
}
|
|
3481
|
-
field[property] = value;
|
|
3482
|
-
return;
|
|
3483
|
-
}
|
|
3484
|
-
/**
|
|
3485
|
-
* Extracts parameters from an expression.
|
|
3486
|
-
*
|
|
3487
|
-
* @param {string} expression - The expression containing parameters.
|
|
3488
|
-
* @returns {string[]} An array of extracted parameters.
|
|
3489
|
-
*/
|
|
3490
|
-
extractParams(expression) {
|
|
3491
|
-
const getTemplateValue = function getTemplvalue(pathOrValue) {
|
|
3492
|
-
const element = pathOrValue.split('.');
|
|
3493
|
-
return element.length > 1 ? this.getValue({
|
|
3494
|
-
scope: element[0],
|
|
3495
|
-
key: element[1],
|
|
3496
|
-
property: element[2],
|
|
3497
|
-
path: element.slice(3)
|
|
3498
|
-
}) : element[0];
|
|
3499
|
-
}.bind(this);
|
|
3500
|
-
const extractedValues = [];
|
|
3501
|
-
let match;
|
|
3502
|
-
while (!isNil(match = TEMPLATE_REGEX_DELIMITATOR.exec(expression))) {
|
|
3503
|
-
extractedValues.push(match[1]);
|
|
3504
|
-
}
|
|
3505
|
-
const splittedString = extractedValues.map(el => el.split(TEMPLATE_REGEX_OPERATOR_SPLITTER));
|
|
3506
|
-
const result = splittedString.map(splittedStringVal => {
|
|
3507
|
-
// skip operator logic parsing and pass element directly
|
|
3508
|
-
if (splittedStringVal.length <= 1) {
|
|
3509
|
-
return {
|
|
3510
|
-
parse: false,
|
|
3511
|
-
value: getTemplateValue(splittedStringVal[0])
|
|
3512
|
-
};
|
|
3513
|
-
}
|
|
3514
|
-
const value = splittedStringVal.filter(Boolean).reduce((acc, curr) => {
|
|
3515
|
-
if (curr.match(TEMPLATE_REGEX_OPERATOR_MATCHER)) {
|
|
3516
|
-
return `${acc}${curr}`;
|
|
3517
|
-
}
|
|
3518
|
-
let value;
|
|
3519
|
-
const currElementContent = getTemplateValue(curr);
|
|
3520
|
-
let currValue;
|
|
3521
|
-
// if any parsable content was passed to the conditions, parse them
|
|
3522
|
-
// required to be able to apply conditions
|
|
3523
|
-
try {
|
|
3524
|
-
currValue = JSON.parse(currElementContent);
|
|
3525
|
-
} catch (e) {
|
|
3526
|
-
currValue = currElementContent;
|
|
3527
|
-
}
|
|
3528
|
-
switch (typeof currValue) {
|
|
3529
|
-
case 'string':
|
|
3530
|
-
value = `\`${currValue}\``;
|
|
3531
|
-
break;
|
|
3532
|
-
case 'boolean':
|
|
3533
|
-
case 'undefined':
|
|
3534
|
-
case 'number':
|
|
3535
|
-
value = currValue;
|
|
3536
|
-
break;
|
|
3537
|
-
case 'object':
|
|
3538
|
-
if (currValue === null) {
|
|
3539
|
-
value = null;
|
|
3540
|
-
break;
|
|
3541
|
-
}
|
|
3542
|
-
if (currValue instanceof Date) {
|
|
3543
|
-
value = `new Date(\`${currValue}\`)`;
|
|
3544
|
-
break;
|
|
3545
|
-
}
|
|
3546
|
-
value = JSON.stringify(currValue);
|
|
3547
|
-
break;
|
|
3548
|
-
default:
|
|
3549
|
-
value = currValue;
|
|
3550
|
-
}
|
|
3551
|
-
return `${acc}${value}`;
|
|
3552
|
-
}, '');
|
|
3553
|
-
return {
|
|
3554
|
-
parse: true,
|
|
3555
|
-
value
|
|
3556
|
-
};
|
|
3557
|
-
});
|
|
3558
|
-
return result.map(({
|
|
3559
|
-
parse,
|
|
3560
|
-
value
|
|
3561
|
-
}) => {
|
|
3562
|
-
try {
|
|
3563
|
-
return parse ? new Function(`return ${value}`)() : value;
|
|
3564
|
-
} catch (_a) {
|
|
3565
|
-
this.config.defaultLogVerbose && console.warn(`unhandled parsing on ${expression} returning`);
|
|
3566
|
-
this.config.defaultLogVerbose && console.warn(value);
|
|
3567
|
-
return value;
|
|
3568
|
-
}
|
|
3569
|
-
});
|
|
3570
|
-
}
|
|
3571
|
-
/**
|
|
3572
|
-
* Replaces expressions marked by ${...} in the expression string with the provided values.
|
|
3573
|
-
*
|
|
3574
|
-
* @param {string} expression - The expression string containing the marked expressions.
|
|
3575
|
-
* @param {string[]} values - The values to be inserted into the marked expressions.
|
|
3576
|
-
* @returns {string} The expression string with the replacements made.
|
|
3577
|
-
*/
|
|
3578
|
-
replaceExpression(expression, values) {
|
|
3579
|
-
const regex = TEMPLATE_REGEX_DELIMITATOR;
|
|
3580
|
-
return expression.replace(regex, () => String(values.shift()) || '');
|
|
3581
|
-
}
|
|
3582
|
-
/**
|
|
3583
|
-
* Checks if an expression string contains string concatenation within a marked expression.
|
|
3584
|
-
*
|
|
3585
|
-
* @param {string} expression - The expression string to be checked.
|
|
3586
|
-
* @returns {boolean} True if the expression contains string concatenation, otherwise false.
|
|
3587
|
-
*/
|
|
3588
|
-
hasStringConcatenation(expression) {
|
|
3589
|
-
return !TEMPLATE_REGEX_STRING_CONCATENATION_DETECTOR.test(expression);
|
|
3590
|
-
}
|
|
3591
|
-
/**
|
|
3592
|
-
* Refreshes templates with updated values.
|
|
3593
|
-
*
|
|
3594
|
-
* @param {object} options - Options for refreshing templates.
|
|
3595
|
-
* @param {string} options.key - The key of the field triggering the update.
|
|
3596
|
-
* @param {TMutationEvents} options.event - Internal event descriptor to handle templating.
|
|
3597
|
-
*/
|
|
3598
|
-
refreshTemplates({
|
|
3599
|
-
key,
|
|
3600
|
-
event
|
|
3601
|
-
}) {
|
|
3602
|
-
this.subscribedTemplates.forEach(({
|
|
3603
|
-
destinationKey,
|
|
3604
|
-
destinationPath,
|
|
3605
|
-
destinationProperty,
|
|
3606
|
-
originExpression,
|
|
3607
|
-
originFieldKeys
|
|
3608
|
-
}) => {
|
|
3609
|
-
if (!key || originFieldKeys.includes(key)) {
|
|
3610
|
-
const originExpressions = this.extractParams(originExpression);
|
|
3611
|
-
let originValue;
|
|
3612
|
-
if (this.hasStringConcatenation(originExpression)) {
|
|
3613
|
-
originValue = this.replaceExpression(originExpression, [...originExpressions]);
|
|
3614
|
-
} else {
|
|
3615
|
-
originValue = originExpressions === null || originExpressions === void 0 ? void 0 : originExpressions[0];
|
|
3616
|
-
}
|
|
3617
|
-
const destinationValue = this.getValue({
|
|
3618
|
-
scope: 'fields',
|
|
3619
|
-
key: destinationKey,
|
|
3620
|
-
property: destinationProperty,
|
|
3621
|
-
path: destinationPath
|
|
3622
|
-
});
|
|
3623
|
-
if (!isEqual(destinationValue, originValue)) {
|
|
3624
|
-
this.setValue({
|
|
3625
|
-
key: destinationKey,
|
|
3626
|
-
property: destinationProperty,
|
|
3627
|
-
path: destinationPath,
|
|
3628
|
-
originKey: key,
|
|
3629
|
-
value: originValue,
|
|
3630
|
-
event
|
|
3631
|
-
});
|
|
3632
|
-
}
|
|
3633
|
-
}
|
|
3634
|
-
});
|
|
3635
|
-
}
|
|
3636
|
-
/**
|
|
3637
|
-
* executes events that were stored due to field unavaliability
|
|
3638
|
-
*
|
|
3639
|
-
* @param {string} field field to check
|
|
3640
|
-
*/
|
|
3641
|
-
checkFieldEventQueues(field) {
|
|
3642
|
-
var _a;
|
|
3643
|
-
if (!((_a = this.fields.get(field)) === null || _a === void 0 ? void 0 : _a.mounted)) return;
|
|
3644
|
-
if (this.queuedFieldVisibilityEvents.has(field)) {
|
|
3645
|
-
this.setFieldVisibility(Object.assign({
|
|
3646
|
-
field: field
|
|
3647
|
-
}, this.queuedFieldVisibilityEvents.get(field)));
|
|
3648
|
-
this.queuedFieldVisibilityEvents.delete(field);
|
|
3649
|
-
}
|
|
3650
|
-
if (this.queuedInitialValues.has(field)) {
|
|
3651
|
-
const value = this.queuedInitialValues.get(field);
|
|
3652
|
-
this.queuedInitialValues.delete(field);
|
|
3653
|
-
this.initialValues = {
|
|
3654
|
-
[field]: value
|
|
3655
|
-
};
|
|
3656
|
-
}
|
|
3657
|
-
if (this.queuedFieldResetValuesEvents.has(field)) {
|
|
3658
|
-
this.setResetFieldValue(Object.assign({
|
|
3659
|
-
key: field
|
|
3660
|
-
}, this.queuedFieldResetValuesEvents.get(field)));
|
|
3661
|
-
this.queuedFieldResetValuesEvents.delete(field);
|
|
3662
|
-
}
|
|
3663
|
-
if (this.queuedFieldResetPropertyEvents.has(field)) {
|
|
3664
|
-
this.setResetPathValue(Object.assign({
|
|
3665
|
-
key: field
|
|
3666
|
-
}, this.queuedFieldResetPropertyEvents.get(field)));
|
|
3667
|
-
this.queuedFieldResetPropertyEvents.delete(field);
|
|
3668
|
-
}
|
|
3669
|
-
}
|
|
3670
|
-
/**
|
|
3671
|
-
* @internal
|
|
3672
|
-
* Update field visibility accordingly.
|
|
3673
|
-
*
|
|
3674
|
-
* @param {object} options - options to set field visibility
|
|
3675
|
-
* @param {string} options.field - Field name to be updated.
|
|
3676
|
-
* @param {boolean} options.hasError - Condition to be used as visibility.
|
|
3677
|
-
* @param {boolean|undefined} options.showOnlyIfTrue - Flag to be considered when update field visibility. If it's true, then considered error, if it's false, always considered the opposite.
|
|
3678
|
-
*/
|
|
3679
|
-
setFieldVisibility({
|
|
3680
|
-
field,
|
|
3681
|
-
hasError,
|
|
3682
|
-
showOnlyIfTrue
|
|
3683
|
-
}) {
|
|
3684
|
-
const fieldInstance = this.fields.get(field);
|
|
3685
|
-
if (!fieldInstance || !fieldInstance.mounted) {
|
|
3686
|
-
this.queuedFieldVisibilityEvents.set(field, {
|
|
3687
|
-
hasError,
|
|
3688
|
-
showOnlyIfTrue
|
|
3689
|
-
});
|
|
3690
|
-
} else {
|
|
3691
|
-
const currentVisibility = fieldInstance.visibility;
|
|
3692
|
-
const visibility = showOnlyIfTrue ? hasError : !hasError;
|
|
3693
|
-
fieldInstance.visibility = visibility;
|
|
3694
|
-
if (currentVisibility === visibility) return;
|
|
3695
|
-
/**
|
|
3696
|
-
* I was sure I would not require to gambiarra, but..
|
|
3697
|
-
* in order to ignore an hidden value on a form submit
|
|
3698
|
-
* or revalidate it when it comes back to visibility
|
|
3699
|
-
* I needed to...
|
|
3700
|
-
* I don't recommend setting private properties like this
|
|
3701
|
-
* this will force the field to be valid when it's hidden
|
|
3702
|
-
* and trigger the validation when it's visible
|
|
3703
|
-
*/
|
|
3704
|
-
if (fieldInstance.visibility) {
|
|
3705
|
-
if (this.queuedInitialValues.has(field)) {
|
|
3706
|
-
fieldInstance === null || fieldInstance === void 0 ? void 0 : fieldInstance.emitValue({
|
|
3707
|
-
value: this.queuedInitialValues.get(field) || '',
|
|
3708
|
-
event: 'ON_FIELD_MOUNT'
|
|
3709
|
-
});
|
|
3710
|
-
this.queuedInitialValues.delete(field);
|
|
3711
|
-
} else {
|
|
3712
|
-
fieldInstance.emitEvents({
|
|
3713
|
-
event: 'ON_FIELD_MOUNT'
|
|
3714
|
-
});
|
|
3715
|
-
}
|
|
3716
|
-
} else {
|
|
3717
|
-
fieldInstance.emitEvents({
|
|
3718
|
-
event: 'ON_FIELD_UNMOUNT'
|
|
3719
|
-
});
|
|
3720
|
-
if (fieldInstance.persistValue) {
|
|
3721
|
-
this.queuedInitialValues.set(fieldInstance.name, fieldInstance.value);
|
|
3722
|
-
}
|
|
3723
|
-
fieldInstance.value = '';
|
|
3724
|
-
fieldInstance.valid = true;
|
|
3725
|
-
}
|
|
3726
|
-
}
|
|
3727
|
-
}
|
|
3728
|
-
/**
|
|
3729
|
-
* Validates visibility conditions for a given event and updates field visibility accordingly.
|
|
3730
|
-
*
|
|
3731
|
-
* @param {object} options - Options for validating visibility.
|
|
3732
|
-
* @param {TEvents} options.event - The event triggering visibility validation.
|
|
3733
|
-
* @param {string} options.key - The key of the field.
|
|
3734
|
-
*/
|
|
3735
|
-
validateVisibility({
|
|
3736
|
-
event,
|
|
3737
|
-
key
|
|
3738
|
-
}) {
|
|
3739
|
-
const field = this.fields.get(key);
|
|
3740
|
-
const structVisibility = field === null || field === void 0 ? void 0 : field.visibilityConditions;
|
|
3741
|
-
if (!structVisibility || !(structVisibility === null || structVisibility === void 0 ? void 0 : structVisibility.some(config => config.events.includes(event)))) {
|
|
3742
|
-
return;
|
|
3743
|
-
}
|
|
3744
|
-
structVisibility.forEach(structElement => {
|
|
3745
|
-
if (!structElement.events.includes(event)) return;
|
|
3746
|
-
Object.keys(structElement.validations).forEach(validationKey => {
|
|
3747
|
-
const error = handleValidation(field.value, structElement.validations, validations, validationKey);
|
|
3748
|
-
if (Array.isArray(structElement.fields)) {
|
|
3749
|
-
structElement.fields.forEach(fieldKey => {
|
|
3750
|
-
this.setFieldVisibility({
|
|
3751
|
-
field: fieldKey,
|
|
3752
|
-
hasError: error,
|
|
3753
|
-
showOnlyIfTrue: !!(field.value && structElement.showOnlyIfTrue)
|
|
3754
|
-
});
|
|
3755
|
-
});
|
|
3756
|
-
} else if (structElement.fields) {
|
|
3757
|
-
this.setFieldVisibility({
|
|
3758
|
-
field: structElement.fields,
|
|
3759
|
-
hasError: error,
|
|
3760
|
-
showOnlyIfTrue: !!(field.value && structElement.showOnlyIfTrue)
|
|
3761
|
-
});
|
|
3762
|
-
}
|
|
3763
|
-
});
|
|
3764
|
-
});
|
|
3765
|
-
}
|
|
3766
|
-
/**
|
|
3767
|
-
* @internal
|
|
3768
|
-
* Update field value and emit change and cleared event.
|
|
3769
|
-
*
|
|
3770
|
-
* @param {options} options to reset the field value
|
|
3771
|
-
* @param {string} options.key - Field name to be updated.
|
|
3772
|
-
* @param {unknown} options.value - Value to be inserted into field.
|
|
3773
|
-
*/
|
|
3774
|
-
setResetFieldValue({
|
|
3775
|
-
key,
|
|
3776
|
-
value
|
|
3777
|
-
}) {
|
|
3778
|
-
const field = this.fields.get(key);
|
|
3779
|
-
if (!field || !(field === null || field === void 0 ? void 0 : field.mounted)) {
|
|
3780
|
-
this.queuedFieldResetValuesEvents.set(key, {
|
|
3781
|
-
value
|
|
3782
|
-
});
|
|
3783
|
-
} else {
|
|
3784
|
-
field.emitValue({
|
|
3785
|
-
value: value,
|
|
3786
|
-
event: 'ON_FIELD_CLEARED'
|
|
3787
|
-
});
|
|
3788
|
-
}
|
|
3789
|
-
}
|
|
3790
|
-
/**
|
|
3791
|
-
* Resets field values based on reset conditions defined in the schema.
|
|
3792
|
-
*
|
|
3793
|
-
* @param {object} options - Options for resetting field values.
|
|
3794
|
-
* @param {TEvents} options.event - The event triggering the reset.
|
|
3795
|
-
* @param {string} options.key - The key of the field.
|
|
3796
|
-
*/
|
|
3797
|
-
resetValue({
|
|
3798
|
-
event,
|
|
3799
|
-
key
|
|
3800
|
-
}) {
|
|
3801
|
-
const field = this.fields.get(key);
|
|
3802
|
-
const structResetValue = field === null || field === void 0 ? void 0 : field.resetValues;
|
|
3803
|
-
if (!structResetValue || !(structResetValue === null || structResetValue === void 0 ? void 0 : structResetValue.some(config => config.events.includes(event)))) return;
|
|
3804
|
-
structResetValue.forEach(structElement => {
|
|
3805
|
-
if (!structElement.events.includes(event)) return;
|
|
3806
|
-
const handleFieldRestoration = () => {
|
|
3807
|
-
if (Array.isArray(structElement.fields)) {
|
|
3808
|
-
structElement.fields.forEach((fieldKey, index) => {
|
|
3809
|
-
const resettledValue = Array.isArray(structElement.resettledValue) ? structElement.resettledValue[index] : structElement.resettledValue;
|
|
3810
|
-
this.setResetFieldValue({
|
|
3811
|
-
key: fieldKey,
|
|
3812
|
-
value: resettledValue
|
|
3813
|
-
});
|
|
3814
|
-
});
|
|
3815
|
-
} else if (structElement.fields) {
|
|
3816
|
-
this.setResetFieldValue({
|
|
3817
|
-
key: structElement.fields,
|
|
3818
|
-
value: structElement.resettledValue
|
|
3819
|
-
});
|
|
3820
|
-
}
|
|
3821
|
-
};
|
|
3822
|
-
if (!structElement.validations) {
|
|
3823
|
-
return handleFieldRestoration();
|
|
3824
|
-
}
|
|
3825
|
-
Object.keys(structElement.validations).forEach(validationKey => {
|
|
3826
|
-
const error = handleValidation(field.value, structElement.validations, validations, validationKey);
|
|
3827
|
-
if (!error) {
|
|
3828
|
-
handleFieldRestoration();
|
|
3829
|
-
}
|
|
3830
|
-
});
|
|
3831
|
-
});
|
|
3832
|
-
}
|
|
3833
|
-
/**
|
|
3834
|
-
* @internal
|
|
3835
|
-
* Update field property and emit template change.
|
|
3836
|
-
*
|
|
3837
|
-
* @param {object} options - Options for resetting field property
|
|
3838
|
-
* @param {string} options.key - Field name to be updated.
|
|
3839
|
-
* @param {string} options.property - field property to change.
|
|
3840
|
-
* @param {string} options.path - field property path to change.
|
|
3841
|
-
* @param {unknown} options.value - Value to be inserted into field.
|
|
3842
|
-
*/
|
|
3843
|
-
setResetPathValue({
|
|
3844
|
-
key,
|
|
3845
|
-
property,
|
|
3846
|
-
path,
|
|
3847
|
-
value
|
|
3848
|
-
}) {
|
|
3849
|
-
const field = this.fields.get(key);
|
|
3850
|
-
if (!field) {
|
|
3851
|
-
this.queuedFieldResetPropertyEvents.set(key, {
|
|
3852
|
-
property,
|
|
3853
|
-
path,
|
|
3854
|
-
value
|
|
3855
|
-
});
|
|
3856
|
-
} else {
|
|
3857
|
-
this.setValue({
|
|
3858
|
-
key,
|
|
3859
|
-
property,
|
|
3860
|
-
path: path.split('.'),
|
|
3861
|
-
value: value,
|
|
3862
|
-
event: 'ON_RESET'
|
|
3863
|
-
});
|
|
3864
|
-
}
|
|
3865
|
-
}
|
|
3866
|
-
/**
|
|
3867
|
-
* Resets field properties based on reset conditions defined in the schema.
|
|
3868
|
-
*
|
|
3869
|
-
* @param {object} options - Options for resetting field property.
|
|
3870
|
-
* @param {TEvents} options.event - The event triggering the reset.
|
|
3871
|
-
* @param {string} options.key - The key of the field.
|
|
3872
|
-
*/
|
|
3873
|
-
resetProperty({
|
|
3874
|
-
event,
|
|
3875
|
-
key
|
|
3876
|
-
}) {
|
|
3877
|
-
const field = this.fields.get(key);
|
|
3878
|
-
const structResetPath = field === null || field === void 0 ? void 0 : field.resetPropertyValues;
|
|
3879
|
-
if (!structResetPath || !(structResetPath === null || structResetPath === void 0 ? void 0 : structResetPath.some(config => config.events.includes(event)))) return;
|
|
3880
|
-
structResetPath.forEach(structElement => {
|
|
3881
|
-
if (!structElement.events.includes(event)) return;
|
|
3882
|
-
if (!ALLOWED_RESET_PROPS_MUTATIONS.includes(structElement.property)) return;
|
|
3883
|
-
if (!structElement.validations) {
|
|
3884
|
-
return this.setResetPathValue({
|
|
3885
|
-
key: structElement.field,
|
|
3886
|
-
path: structElement.path,
|
|
3887
|
-
property: structElement.property,
|
|
3888
|
-
value: structElement.resettledValue
|
|
3889
|
-
});
|
|
3890
|
-
}
|
|
3891
|
-
Object.keys(structElement.validations).forEach(validationKey => {
|
|
3892
|
-
const error = handleValidation(field.value, structElement.validations, validations, validationKey);
|
|
3893
|
-
if (!error) {
|
|
3894
|
-
this.setResetPathValue({
|
|
3895
|
-
key: structElement.field,
|
|
3896
|
-
path: structElement.path,
|
|
3897
|
-
property: structElement.property,
|
|
3898
|
-
value: structElement.resettledValue
|
|
3899
|
-
});
|
|
3900
|
-
}
|
|
3901
|
-
});
|
|
3902
|
-
});
|
|
3903
|
-
}
|
|
3904
|
-
/**
|
|
3905
|
-
* Adds a field onto the form instance regardless there is a schema or not
|
|
3906
|
-
*
|
|
3907
|
-
* @param fieldSchema
|
|
3908
|
-
* @param mapperElement
|
|
3909
|
-
*/
|
|
3910
|
-
addField({
|
|
3911
|
-
fieldSchema,
|
|
3912
|
-
mapperElement,
|
|
3913
|
-
path
|
|
3914
|
-
}) {
|
|
3915
|
-
var _a, _b, _c, _d;
|
|
3916
|
-
if (this.fields.has(fieldSchema.name)) {
|
|
3917
|
-
throw new Error(`field name ${fieldSchema.name} already defined`);
|
|
3918
|
-
}
|
|
3919
|
-
const mapper = mapperElement || ((_a = this.mappers) === null || _a === void 0 ? void 0 : _a.get(fieldSchema.component));
|
|
3920
|
-
if (!mapper) throw new Error(`mapper not found for ${fieldSchema.component}, add it to the mappers configuration`);
|
|
3921
|
-
if ((_b = mapper.events) === null || _b === void 0 ? void 0 : _b.setValue) {
|
|
3922
|
-
const initialValue = (_c = fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema.props) === null || _c === void 0 ? void 0 : _c[(_d = mapper === null || mapper === void 0 ? void 0 : mapper.events) === null || _d === void 0 ? void 0 : _d.setValue];
|
|
3923
|
-
if (!(typeof initialValue === 'undefined') && !this.queuedInitialValues.has(fieldSchema.name) && !(typeof initialValue === 'string' && initialValue.includes('${'))) {
|
|
3924
|
-
this.queuedInitialValues.set(fieldSchema.name, cloneDeep(initialValue));
|
|
3925
|
-
}
|
|
3926
|
-
}
|
|
3927
|
-
this.fields.set(fieldSchema.name, new FormField({
|
|
3928
|
-
formIndex: this.index,
|
|
3929
|
-
schemaComponent: fieldSchema,
|
|
3930
|
-
mapper,
|
|
3931
|
-
children: fieldSchema.children ? fieldSchema.children.map(el => el.name) : [],
|
|
3932
|
-
validateVisibility: this.validateVisibility.bind(this),
|
|
3933
|
-
resetValue: this.resetValue.bind(this),
|
|
3934
|
-
resetProperty: this.resetProperty.bind(this),
|
|
3935
|
-
getFormValues: this.getFormValues.bind(this),
|
|
3936
|
-
templateSubject$: this.templateSubject$,
|
|
3937
|
-
fieldEventSubject$: this.fieldEventSubject$,
|
|
3938
|
-
dataSubject$: this.dataSubject$,
|
|
3939
|
-
fieldValidNotification$: this.fieldValidNotification$,
|
|
3940
|
-
mountSubject$: this.mountSubject$,
|
|
3941
|
-
config: this.config,
|
|
3942
|
-
submitEvent: this.submit.bind(this),
|
|
3943
|
-
visibility: fieldSchema.visibility,
|
|
3944
|
-
persistValue: fieldSchema.persistValue,
|
|
3945
|
-
path
|
|
3946
|
-
}));
|
|
3947
|
-
}
|
|
3948
|
-
/**
|
|
3949
|
-
* function to be called from the adapter to remove a field when a field is removed from it
|
|
3950
|
-
*
|
|
3951
|
-
* @param {{ key: string }} entry.key
|
|
3952
|
-
*/
|
|
3953
|
-
removeField({
|
|
3954
|
-
key
|
|
3955
|
-
}) {
|
|
3956
|
-
var _a;
|
|
3957
|
-
(_a = this.fields.get(key)) === null || _a === void 0 ? void 0 : _a.destroyField();
|
|
3958
|
-
this.fields.delete(key);
|
|
3959
|
-
this.subscribeTemplates();
|
|
3960
|
-
this.templateSubject$.next({
|
|
3961
|
-
scope: 'fields',
|
|
3962
|
-
key,
|
|
3963
|
-
event: 'ON_FIELDS'
|
|
3964
|
-
});
|
|
3965
|
-
this.validateForm();
|
|
3966
|
-
}
|
|
3967
|
-
/**
|
|
3968
|
-
* Serializes the schema structure to create form fields.
|
|
3969
|
-
*
|
|
3970
|
-
* @param {IComponentSchema[]} [struct] - The schema structure to serialize.
|
|
3971
|
-
* @param {string} [path] - The path of the parent component.
|
|
3972
|
-
*/
|
|
3973
|
-
serializeStructure(struct, path) {
|
|
3974
|
-
if (!struct) return;
|
|
3975
|
-
struct.forEach(structElement => {
|
|
3976
|
-
var _a;
|
|
3977
|
-
const currField = this.fields.get(structElement.name);
|
|
3978
|
-
if (!currField) {
|
|
3979
|
-
this.addField({
|
|
3980
|
-
fieldSchema: structElement,
|
|
3981
|
-
mapperElement: structElement.mapper,
|
|
3982
|
-
path
|
|
3983
|
-
});
|
|
3984
|
-
} else {
|
|
3985
|
-
currField.children = ((_a = structElement === null || structElement === void 0 ? void 0 : structElement.children) === null || _a === void 0 ? void 0 : _a.map(el => el.name)) || (currField === null || currField === void 0 ? void 0 : currField.children) || [];
|
|
3986
|
-
currField.originalSchema = structElement;
|
|
3987
|
-
currField.templateSubject$ = this.templateSubject$;
|
|
3988
|
-
}
|
|
3989
|
-
if (structElement.children) {
|
|
3990
|
-
this.serializeStructure(structElement.children, `${path ? `${path}.` : ``}${structElement.name}`);
|
|
3991
|
-
}
|
|
3992
|
-
});
|
|
3993
|
-
}
|
|
3994
|
-
/**
|
|
3995
|
-
* Refreshes form fields based on changes in the schema structure.
|
|
3996
|
-
*
|
|
3997
|
-
* @param {IComponentSchema[]} struct - The updated schema structure.
|
|
3998
|
-
*/
|
|
3999
|
-
refreshFields(struct) {
|
|
4000
|
-
const prevKeys = Array.from(this.fields.keys());
|
|
4001
|
-
this.serializeStructure(struct);
|
|
4002
|
-
const keys = FormCore.checkIndexes(struct);
|
|
4003
|
-
this.fields.forEach((_, key) => {
|
|
4004
|
-
var _a;
|
|
4005
|
-
if (!keys.includes(key)) {
|
|
4006
|
-
(_a = this.fields.get(key)) === null || _a === void 0 ? void 0 : _a.destroyField();
|
|
4007
|
-
this.fields.delete(key);
|
|
4008
|
-
}
|
|
4009
|
-
});
|
|
4010
|
-
this.subscribeTemplates();
|
|
4011
|
-
this.fields.forEach((_, key) => {
|
|
4012
|
-
var _a;
|
|
4013
|
-
if (!prevKeys.includes(key)) {
|
|
4014
|
-
(_a = this.fields.get(key)) === null || _a === void 0 ? void 0 : _a.emitEvents({
|
|
4015
|
-
event: 'ON_FIELD_MOUNT'
|
|
4016
|
-
});
|
|
4017
|
-
this.checkFieldEventQueues(key);
|
|
4018
|
-
}
|
|
4019
|
-
});
|
|
4020
|
-
this.subscribedTemplates.forEach(el => {
|
|
4021
|
-
el.originFieldKeys.forEach(field => {
|
|
4022
|
-
this.templateSubject$.next({
|
|
4023
|
-
scope: 'fields',
|
|
4024
|
-
key: field,
|
|
4025
|
-
event: 'ON_FIELDS'
|
|
4026
|
-
});
|
|
4027
|
-
});
|
|
4028
|
-
});
|
|
4029
|
-
}
|
|
4030
|
-
/**
|
|
4031
|
-
* Gets a form field by its key.
|
|
4032
|
-
*
|
|
4033
|
-
* @param {object} options - Options for getting the form field.
|
|
4034
|
-
* @param {string} options.key - The key of the form field.
|
|
4035
|
-
* @returns {IFormField | undefined} The form field, or undefined if not found.
|
|
4036
|
-
*/
|
|
4037
|
-
getField({
|
|
4038
|
-
key
|
|
4039
|
-
}) {
|
|
4040
|
-
return this.fields.get(key);
|
|
4041
|
-
}
|
|
4042
|
-
/**
|
|
4043
|
-
* Prints the current values of all form fields.
|
|
4044
|
-
*/
|
|
4045
|
-
printValues() {
|
|
4046
|
-
console.table(this.getFormValues().values);
|
|
4047
|
-
}
|
|
4048
|
-
/**
|
|
4049
|
-
* Gets the current values of all form fields.
|
|
4050
|
-
*
|
|
4051
|
-
* @returns {TFormValues} The current form values.
|
|
4052
|
-
*/
|
|
4053
|
-
getFormValues() {
|
|
4054
|
-
const values = {};
|
|
4055
|
-
const metadata = {};
|
|
4056
|
-
const erroredFields = [];
|
|
4057
|
-
this.fields.forEach((val, key) => {
|
|
4058
|
-
if (!(typeof val.value === 'string' && val.value.length === 0) && typeof val.value !== 'undefined' && val.value !== null) {
|
|
4059
|
-
set(values, val.nameToSubmit || key, val.value);
|
|
4060
|
-
metadata[key] = val.metadata;
|
|
4061
|
-
}
|
|
4062
|
-
if (!val.valid) {
|
|
4063
|
-
erroredFields.push(key);
|
|
4064
|
-
}
|
|
4065
|
-
});
|
|
4066
|
-
return {
|
|
4067
|
-
values,
|
|
4068
|
-
metadata,
|
|
4069
|
-
erroredFields,
|
|
4070
|
-
isValid: this.valid
|
|
4071
|
-
};
|
|
4072
|
-
}
|
|
4073
|
-
/**
|
|
4074
|
-
* function to be called to events sent from the adapter
|
|
4075
|
-
*
|
|
4076
|
-
* @param {{callback: (payload: TFieldEvent) => void}} entry.callback callback function from the adapter
|
|
4077
|
-
* @returns
|
|
4078
|
-
*/
|
|
4079
|
-
subscribeFieldEvent({
|
|
4080
|
-
callback
|
|
4081
|
-
}) {
|
|
4082
|
-
const sub = this.fieldEventSubject$.pipe(filter(() => this.submitChecker()), groupBy(payload => `${payload.event}|${payload.fieldName}`), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS)))).subscribe({
|
|
4083
|
-
next: callback
|
|
4084
|
-
});
|
|
4085
|
-
return sub;
|
|
4086
|
-
}
|
|
4087
|
-
/**
|
|
4088
|
-
* to be called from the adapter when the form mounts
|
|
4089
|
-
*
|
|
4090
|
-
* @param {(payload: TFormValues<T>) => void} callback
|
|
4091
|
-
* @returns Subscription
|
|
4092
|
-
*/
|
|
4093
|
-
subscribeOnMount(callback) {
|
|
4094
|
-
const sub = this.mountSubject$.pipe(map(() => this.getFormValues())).subscribe({
|
|
4095
|
-
next: callback
|
|
4096
|
-
});
|
|
4097
|
-
return sub;
|
|
4098
|
-
}
|
|
4099
|
-
/**
|
|
4100
|
-
*
|
|
4101
|
-
* @param {(payload: { field: string; data: TFormValues }) => void} callback callback function to call onData
|
|
4102
|
-
*/
|
|
4103
|
-
subscribeData(callback) {
|
|
4104
|
-
const sub = this.dataSubject$.pipe(filter(({
|
|
4105
|
-
formIndex
|
|
4106
|
-
}) => this.index === formIndex && this.submitChecker()), groupBy(payload => payload.event), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS))), map(({
|
|
4107
|
-
fieldIndex
|
|
4108
|
-
}) => ({
|
|
4109
|
-
field: fieldIndex,
|
|
4110
|
-
data: this.getFormValues()
|
|
4111
|
-
}))).subscribe({
|
|
4112
|
-
next: callback
|
|
4113
|
-
});
|
|
4114
|
-
return sub;
|
|
4115
|
-
}
|
|
4116
|
-
/**
|
|
4117
|
-
* method to register a callback function to be called when the form is valid
|
|
4118
|
-
*
|
|
4119
|
-
* @param {(payload: TFormValues<T>) => void} callback callback function to call when the submit action occurs
|
|
4120
|
-
*/
|
|
4121
|
-
subscribeOnSubmit(callback) {
|
|
4122
|
-
const sub = this.submitSubject$.pipe(filter(({
|
|
4123
|
-
formIndex
|
|
4124
|
-
}) => formIndex === this.index && this.submitChecker()), map(({
|
|
4125
|
-
values
|
|
4126
|
-
}) => values)).subscribe({
|
|
4127
|
-
next: callback
|
|
4128
|
-
});
|
|
4129
|
-
return sub;
|
|
4130
|
-
}
|
|
4131
|
-
/**
|
|
4132
|
-
* method to check whenever the validity status of the form changes, only emits on status change
|
|
4133
|
-
*
|
|
4134
|
-
* @param {(payload: TFormValidationPayload) => void} callback callback function to call onValid
|
|
4135
|
-
*/
|
|
4136
|
-
subscribeFormValidation(callback) {
|
|
4137
|
-
const sub = this.formValidSubject$.pipe(filter(({
|
|
4138
|
-
formIndex
|
|
4139
|
-
}) => this.index === formIndex), map(() => ({
|
|
4140
|
-
formIndex: this.index,
|
|
4141
|
-
valid: this.valid
|
|
4142
|
-
})), distinctUntilKeyChanged('valid'), startWith({
|
|
4143
|
-
formIndex: this.index,
|
|
4144
|
-
valid: this.valid
|
|
4145
|
-
})).subscribe({
|
|
4146
|
-
next: callback
|
|
4147
|
-
});
|
|
4148
|
-
return sub;
|
|
4149
|
-
}
|
|
4150
|
-
/**
|
|
4151
|
-
* Submits the form by triggering form field events and invoking the onSubmit callback.
|
|
4152
|
-
*/
|
|
4153
|
-
submit() {
|
|
4154
|
-
this.fields.forEach(field => {
|
|
4155
|
-
field.emitEvents({
|
|
4156
|
-
event: 'ON_FIELD_VALIDATION'
|
|
4157
|
-
});
|
|
4158
|
-
});
|
|
4159
|
-
if (!this.valid) return;
|
|
4160
|
-
const values = this.getFormValues();
|
|
4161
|
-
this.submitSubject$.next({
|
|
4162
|
-
formIndex: this.index,
|
|
4163
|
-
values
|
|
4164
|
-
});
|
|
4165
|
-
this.submitted = true;
|
|
4166
|
-
}
|
|
4167
|
-
/**
|
|
4168
|
-
* recycles all the Suscriptions, to be called from the adapter when the form leaves the page
|
|
4169
|
-
*/
|
|
4170
|
-
destroy() {
|
|
4171
|
-
this.templateSubscription$.unsubscribe();
|
|
4172
|
-
this.fieldEventSubject$.unsubscribe();
|
|
4173
|
-
this.fieldValidNotification$.unsubscribe();
|
|
4174
|
-
this.fields.forEach(field => field.destroyField());
|
|
4175
|
-
}
|
|
4176
|
-
}
|
|
4177
|
-
/**
|
|
4178
|
-
* Validates and collects the names of form fields in the provided schema structure.
|
|
4179
|
-
*
|
|
4180
|
-
* @param {IComponentSchema[]} [struct] - The schema structure of the form components.
|
|
4181
|
-
* @param {string[]} [indexes=[]] - An array to collect the names of the form fields.
|
|
4182
|
-
* @returns {string[]} - An array of form field names.
|
|
4183
|
-
* @throws {Error} - Throws an error if a field name matches the reserved name defined by `IVARPROPNAME`.
|
|
4184
|
-
* @private
|
|
4185
|
-
*/
|
|
4186
|
-
FormCore.checkIndexes = (struct, indexes = []) => {
|
|
4187
|
-
if (!struct) return indexes;
|
|
4188
|
-
const helper = (struct, indexes) => {
|
|
4189
|
-
for (let i = 0; i < struct.length; i++) {
|
|
4190
|
-
const structElement = struct[i];
|
|
4191
|
-
indexes.push(structElement.name);
|
|
4192
|
-
if (structElement.children) {
|
|
4193
|
-
helper(structElement.children, indexes);
|
|
4194
|
-
}
|
|
4195
|
-
}
|
|
4196
|
-
};
|
|
4197
|
-
helper(struct, indexes);
|
|
4198
|
-
const duppedIndexes = indexes.filter((item, index) => indexes.indexOf(item) !== index);
|
|
4199
|
-
if (duppedIndexes.length > 0) {
|
|
4200
|
-
throw new Error(`duplicated indexes found on schema: ${JSON.stringify(duppedIndexes)}`);
|
|
4201
|
-
}
|
|
4202
|
-
return indexes;
|
|
4203
|
-
};
|
|
4204
|
-
|
|
4205
|
-
/**
|
|
4206
|
-
* Represents a group that manages multiple forms.
|
|
4207
|
-
*/
|
|
4208
|
-
class FormGroup {
|
|
4209
|
-
/**
|
|
4210
|
-
* Creates an instance of FormGroup.
|
|
4211
|
-
*/
|
|
4212
|
-
constructor(entry) {
|
|
4213
|
-
var _a, _b, _c, _d, _e;
|
|
4214
|
-
this.destroy = () => {
|
|
4215
|
-
this.forms.forEach(form => form.destroy());
|
|
4216
|
-
this.dataSubject$.unsubscribe();
|
|
4217
|
-
this.formValidSubject$.unsubscribe();
|
|
4218
|
-
this.submitSubject$.unsubscribe();
|
|
4219
|
-
};
|
|
4220
|
-
this.forms = new Map();
|
|
4221
|
-
this.config = {
|
|
4222
|
-
defaultAPIdebounceTimeMS: Number((_a = entry === null || entry === void 0 ? void 0 : entry.config) === null || _a === void 0 ? void 0 : _a.defaultAPIdebounceTimeMS) ? Number((_b = entry === null || entry === void 0 ? void 0 : entry.config) === null || _b === void 0 ? void 0 : _b.defaultAPIdebounceTimeMS) : DEFAULT_API_DEBOUNCE_TIME,
|
|
4223
|
-
defaultStateRefreshTimeMS: Number((_c = entry === null || entry === void 0 ? void 0 : entry.config) === null || _c === void 0 ? void 0 : _c.defaultStateRefreshTimeMS) ? Number((_d = entry === null || entry === void 0 ? void 0 : entry.config) === null || _d === void 0 ? void 0 : _d.defaultStateRefreshTimeMS) : DEFAULT_STATE_REFRESH_TIME,
|
|
4224
|
-
defaultLogVerbose: ((_e = entry === null || entry === void 0 ? void 0 : entry.config) === null || _e === void 0 ? void 0 : _e.defaultLogVerbose) ? entry.config.defaultLogVerbose : DEFAULT_LOG_VERBOSE
|
|
4225
|
-
};
|
|
4226
|
-
this.dataSubject$ = new Subject();
|
|
4227
|
-
this.formValidSubject$ = new Subject();
|
|
4228
|
-
this.submitSubject$ = new Subject();
|
|
4229
|
-
this.mappers = entry === null || entry === void 0 ? void 0 : entry.mappers;
|
|
4230
|
-
}
|
|
4231
|
-
/**
|
|
4232
|
-
* Creates an empty form with given index
|
|
4233
|
-
*
|
|
4234
|
-
* @param {string} options.index
|
|
4235
|
-
* @param {TMapper<unknown>} options.mappers
|
|
4236
|
-
*/
|
|
4237
|
-
createFormWithIndex({
|
|
4238
|
-
index,
|
|
4239
|
-
mappers
|
|
4240
|
-
}) {
|
|
4241
|
-
this.addForm({
|
|
4242
|
-
key: index,
|
|
4243
|
-
params: {
|
|
4244
|
-
index,
|
|
4245
|
-
mappers,
|
|
4246
|
-
config: this.config
|
|
4247
|
-
}
|
|
4248
|
-
});
|
|
4249
|
-
}
|
|
4250
|
-
/**
|
|
4251
|
-
* Adds a form instance to the form group.
|
|
4252
|
-
*
|
|
4253
|
-
* @param {object} options - Options for adding a form.
|
|
4254
|
-
* @param {string} options.key - The key associated with the form instance.
|
|
4255
|
-
* @param {TFormCore} options.formInstance - The instance of the form to add.
|
|
4256
|
-
*/
|
|
4257
|
-
addForm({
|
|
4258
|
-
key,
|
|
4259
|
-
params
|
|
4260
|
-
}) {
|
|
4261
|
-
this.checkIndexes({
|
|
4262
|
-
key: key
|
|
4263
|
-
});
|
|
4264
|
-
const formInstance = new FormCore(Object.assign(Object.assign({}, params), {
|
|
4265
|
-
dataSubject$: this.dataSubject$,
|
|
4266
|
-
formValidSubject$: this.formValidSubject$,
|
|
4267
|
-
submitSubject$: this.submitSubject$
|
|
4268
|
-
}));
|
|
4269
|
-
if (!formInstance.config) {
|
|
4270
|
-
formInstance.config = this.config;
|
|
4271
|
-
}
|
|
4272
|
-
this.forms.set(key, formInstance);
|
|
4273
|
-
}
|
|
4274
|
-
/**
|
|
4275
|
-
* Retrieves a form instance from the form group.
|
|
4276
|
-
*
|
|
4277
|
-
* @param {object} options - Options for retrieving a form.
|
|
4278
|
-
* @param {string} options.key - The key associated with the form instance.
|
|
4279
|
-
* @returns {TFormCore | undefined} The instance of the form, if found; otherwise, undefined.
|
|
4280
|
-
*/
|
|
4281
|
-
getForm({
|
|
4282
|
-
key
|
|
4283
|
-
}) {
|
|
4284
|
-
return this.forms.get(key);
|
|
4285
|
-
}
|
|
4286
|
-
/**
|
|
4287
|
-
* Removes a form instance from the form group.
|
|
4288
|
-
*
|
|
4289
|
-
* @param {object} options - Options for removing a form.
|
|
4290
|
-
* @param {string} options.key - The key associated with the form instance to remove.
|
|
4291
|
-
*/
|
|
4292
|
-
removeForm({
|
|
4293
|
-
key
|
|
4294
|
-
}) {
|
|
4295
|
-
var _a;
|
|
4296
|
-
//@TODO logic to unsubscribe all form related
|
|
4297
|
-
(_a = this.forms.get(key)) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
4298
|
-
this.forms.delete(key);
|
|
4299
|
-
}
|
|
4300
|
-
/**
|
|
4301
|
-
* removes a field given a form and field index
|
|
4302
|
-
*
|
|
4303
|
-
* @param {string} options.formIndex
|
|
4304
|
-
* @param {string} options.fieldIndex
|
|
4305
|
-
*/
|
|
4306
|
-
removeField({
|
|
4307
|
-
formIndex,
|
|
4308
|
-
fieldIndex
|
|
4309
|
-
}) {
|
|
4310
|
-
const form = this.forms.get(formIndex);
|
|
4311
|
-
form === null || form === void 0 ? void 0 : form.removeField({
|
|
4312
|
-
key: fieldIndex
|
|
4313
|
-
});
|
|
4314
|
-
if ((form === null || form === void 0 ? void 0 : form.fields.size) === 0) {
|
|
4315
|
-
this.removeForm({
|
|
4316
|
-
key: formIndex
|
|
4317
|
-
});
|
|
4318
|
-
}
|
|
4319
|
-
}
|
|
4320
|
-
/**
|
|
4321
|
-
* Checks if the specified key already exists in the form group.
|
|
4322
|
-
*
|
|
4323
|
-
* @param {object} options - Options for checking the key.
|
|
4324
|
-
* @param {string} options.key - The key to check.
|
|
4325
|
-
* @throws {Error} Throws an error if the key already exists in the form group.
|
|
4326
|
-
*/
|
|
4327
|
-
checkIndexes({
|
|
4328
|
-
key
|
|
4329
|
-
}) {
|
|
4330
|
-
if (this.forms.has(key)) {
|
|
4331
|
-
throw new Error(`duplicate index ${key} on form group`);
|
|
4332
|
-
}
|
|
4333
|
-
}
|
|
4334
|
-
/**
|
|
4335
|
-
* Prints the form group instance to the console.
|
|
4336
|
-
*/
|
|
4337
|
-
printFormGroupInstance() {
|
|
4338
|
-
console.table(this.forms);
|
|
4339
|
-
}
|
|
4340
|
-
/**
|
|
4341
|
-
* Prototype submit function to multiple forms
|
|
4342
|
-
* @param {string[]} indexes form indexes to be submitted
|
|
4343
|
-
* @param callback
|
|
4344
|
-
* @returns
|
|
4345
|
-
*/
|
|
4346
|
-
submitMultipleFormsByIndex(indexes, callback) {
|
|
4347
|
-
let isValid = true;
|
|
4348
|
-
let values = {};
|
|
4349
|
-
let metadata = {};
|
|
4350
|
-
let erroredFields = [];
|
|
4351
|
-
indexes.forEach(index => {
|
|
4352
|
-
var _a, _b;
|
|
4353
|
-
(_a = this.forms.get(index)) === null || _a === void 0 ? void 0 : _a.submit();
|
|
4354
|
-
const res = (_b = this.forms.get(index)) === null || _b === void 0 ? void 0 : _b.getFormValues();
|
|
4355
|
-
const formMetadata = typeof (res === null || res === void 0 ? void 0 : res.metadata) === 'object' && res.metadata !== null ? res.metadata : {};
|
|
4356
|
-
isValid = isValid && ((res === null || res === void 0 ? void 0 : res.isValid) || false);
|
|
4357
|
-
values = Object.assign(Object.assign({}, values), (res === null || res === void 0 ? void 0 : res.values) || {});
|
|
4358
|
-
metadata = Object.assign(Object.assign({}, metadata), formMetadata);
|
|
4359
|
-
erroredFields = [...erroredFields, ...((res === null || res === void 0 ? void 0 : res.erroredFields) || [])];
|
|
4360
|
-
});
|
|
4361
|
-
isValid && callback && callback({
|
|
4362
|
-
erroredFields,
|
|
4363
|
-
isValid,
|
|
4364
|
-
values,
|
|
4365
|
-
metadata
|
|
4366
|
-
});
|
|
4367
|
-
}
|
|
4368
|
-
onDataSubscription({
|
|
4369
|
-
ids,
|
|
4370
|
-
callback
|
|
4371
|
-
}) {
|
|
4372
|
-
const sub = this.dataSubject$.pipe(filter(({
|
|
4373
|
-
formIndex
|
|
4374
|
-
}) => ids.includes(formIndex)), groupBy(({
|
|
4375
|
-
event,
|
|
4376
|
-
formIndex
|
|
4377
|
-
}) => `${event}.${formIndex}`), mergeMap(group$ => group$.pipe(debounceTime(this.config.defaultStateRefreshTimeMS))), map(({
|
|
4378
|
-
fieldIndex,
|
|
4379
|
-
formIndex
|
|
4380
|
-
}) => ids.reduce((acc, curr) => {
|
|
4381
|
-
const formInstance = this.forms.get(curr);
|
|
4382
|
-
if (formInstance) {
|
|
4383
|
-
acc[curr] = {
|
|
4384
|
-
formId: formIndex,
|
|
4385
|
-
formField: fieldIndex,
|
|
4386
|
-
values: formInstance.getFormValues()
|
|
4387
|
-
};
|
|
4388
|
-
}
|
|
4389
|
-
return acc;
|
|
4390
|
-
}, {}))).subscribe(callback);
|
|
4391
|
-
return sub;
|
|
4392
|
-
}
|
|
4393
|
-
onValidSubscription({
|
|
4394
|
-
ids,
|
|
4395
|
-
callback
|
|
4396
|
-
}) {
|
|
4397
|
-
const sub = this.formValidSubject$.pipe(filter(({
|
|
4398
|
-
formIndex
|
|
4399
|
-
}) => ids.includes(formIndex)), groupBy(({
|
|
4400
|
-
formIndex
|
|
4401
|
-
}) => formIndex), mergeMap(group$ => group$.pipe(debounceTime(0))), startWith({
|
|
4402
|
-
fieldTrigger: null
|
|
4403
|
-
}), map(() => ({
|
|
4404
|
-
groupValid: ids.every(id => {
|
|
4405
|
-
var _a;
|
|
4406
|
-
return !this.forms.get(id) || ((_a = this.forms.get(id)) === null || _a === void 0 ? void 0 : _a.valid);
|
|
4407
|
-
}),
|
|
4408
|
-
forms: ids.reduce((acc, curr) => {
|
|
4409
|
-
const formInstance = this.forms.get(curr);
|
|
4410
|
-
if (formInstance) {
|
|
4411
|
-
acc[curr] = formInstance.valid;
|
|
4412
|
-
}
|
|
4413
|
-
return acc;
|
|
4414
|
-
}, {})
|
|
4415
|
-
}))).subscribe(callback);
|
|
4416
|
-
return sub;
|
|
4417
|
-
}
|
|
4418
|
-
onSubmitSubscription({
|
|
4419
|
-
ids,
|
|
4420
|
-
callback
|
|
4421
|
-
}) {
|
|
4422
|
-
const sub = this.submitSubject$.pipe(filter(({
|
|
4423
|
-
formIndex
|
|
4424
|
-
}) => ids.includes(formIndex)), map(() => ids.reduce((acc, curr) => {
|
|
4425
|
-
const formInstance = this.forms.get(curr);
|
|
4426
|
-
if (formInstance) {
|
|
4427
|
-
acc[curr] = formInstance.getFormValues();
|
|
4428
|
-
}
|
|
4429
|
-
return acc;
|
|
4430
|
-
}, {}))).subscribe(callback);
|
|
4431
|
-
return sub;
|
|
4432
|
-
}
|
|
4433
|
-
}
|
|
4434
|
-
|
|
4435
|
-
export { FormCore, FormField, FormGroup, TMutationEnum };
|
|
1
|
+
import e from"credit-card-type";import{getCurrencySymbol as t}from"@gaignoux/currency";import{BehaviorSubject as i,Subject as s,Subscription as n,groupBy as r,mergeMap as a,debounceTime as l,filter as o,combineLatest as u,startWith as d,map as c,distinctUntilKeyChanged as h}from"rxjs";var v=(e,t)=>{if(!t.length||!e)return!1;let i=e;return"string"!=typeof i&&(i=(null==e?void 0:e.toString())||i),{equal:i.length!==t.length.target,notEqual:i.length===t.length.target,less:i.length>=t.length.target,lessOrEqual:i.length>t.length.target,greater:i.length<=t.length.target,greaterOrEqual:i.length<t.length.target}[t.length.rule]};const f=e=>{if(9!==e.length)return!0;if(!/^\d{8}$/.test(e.slice(0,8)))return!0;const t="TRWAGMYFPDXBNJZSQVHLCKE"[parseInt(e.slice(0,8),10)%23];return!(e[8].toUpperCase()===t)};var p=(e,t)=>{if(!e||!t.document)return!0;const i={NIF:(e,t)=>((e,t)=>{switch(t){case"pt-PT":return(e=>{if(!/^\d{9}$/.test(e))return!1;const t=parseInt(e[8],10),i=11-Array.from(e.substring(0,8)).reduce((e,t,i)=>e+parseInt(t,10)*(9-i),0)%11;return 10===i||11===i?0===t:i===t})(e);case"es-ES":return f(e);case"it-IT":return(e=>/^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/.test(e))(e);case"de-DE":return(e=>/^\d{11}$/.test(e))(e);case"fr-FR":return(e=>/^\d{2} \d{3} \d{3} \d{3} \d{3}$/.test(e))(e);case"en-GB":return(e=>/^GB\d{9}|\d{12}|\d{3}[A-Z]{5}$/.test(e))(e);case"nl-BE":case"fr-BE":return(e=>!!/^\d{11}$/.test(e)&&97-parseInt(e.substring(0,9),10)%97===parseInt(e.substring(9),10))(e);case"nl-NL":return(e=>!!/^\d{9}$/.test(e)&&e.split("").map((e,t)=>parseInt(e,10)*(9-t)).reduce((e,t)=>e+t,0)%11==0)(e);case"sv-SE":return(e=>!!/^\d{10,12}$/.test(e)&&(12===e.length?e.substring(2):e).split("").map((e,t)=>{let i=parseInt(e,10)*(t%2==0?2:1);return i>9&&(i-=9),i}).reduce((e,t)=>e+t,0)%10==0)(e);default:throw new Error(`NIF validation not supported for locale: ${t}`)}})(e,t),NIE:e=>(e=>{if(9!==e.length)return!0;if(!/^[XYZ]\d{7}[TRWAGMYFPDXBNJZSQVHLCKE]$/.test(e))return!0;let t=e.toUpperCase().padStart(9,"0");return t=t[0].replace(/[XYZ]/g,e=>({X:"0",Y:"1",Z:"2"}[e]||e))+t.slice(1),f(t)})(e),CIF:e=>(e=>!/^[A-Z][0-9]{7}[A-J0-9]$/.test(e))(e),IBAN:e=>(e=>{const t=e.replace(/\s/g,"");return 24!==t.length||!/^(ES)[0-9]{22}$/.test(t)||1!==(e=>{for(;e.length>2;){const t=e.slice(0,6),i=parseInt(t,10);if(isNaN(i))return NaN;e=i%97+e.slice(t.length)}return parseInt(e,10)%97})(t.substring(4)+1428+t.substring(2,4))})(e)};return i[t.document.type](e,t.document.locale)};const m=(e,t)=>{const i=Number(e);return!(!t.max||Number.isNaN(i))&&i>Number(t.max)},b=(e,t)=>{const i=Number(e);return!(!t.min||Number.isNaN(i))&&i<Number(t.min)},g=(e,t)=>{if(!t.between||!e)return!1;const i=Number(e);return!(Number.isNaN(i)||+i>=t.between.start&&+i<=t.between.end)},S=(e,t)=>{const i=Number(e);return!(!t.lessThan||Number.isNaN(i))&&i>=t.lessThan},y=(e,t)=>{const i=Number(e);return!(!t.greaterThan||Number.isNaN(i))&&i<=t.greaterThan},$=(e,t)=>{if(!t.sequential)return!1;const i=String(e).replace(/[^0-9]/g,"");return!(-1==="0123456789".indexOf(i)&&-1==="9876543210".indexOf(i))},V=(e,t)=>!(!t.regex||!e)&&!new RegExp(t.regex).test(e),j=(e,t)=>!(!t.email||!e)&&!/^(([^<>()[\]\\.,;:\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,}))$/.test(e),E=(e,t)=>!(!t.url||!e)&&!/[(http(s)?)://(www.)?a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi.test(e),N=(e,t)=>!!t.onlyLetters&&!/^[\p{L}\s]*$/u.test(e),x=(e,t)=>!!t.notAllowSpaces&&/\s/.test(e),O=(e,t)=>!!t.isNumber&&!!e&&!/^[0-9\s]*$/.test(e),I=(e,t)=>!(!t.hasNoExtraSpaces||!e)&&V(e,{regex:"^[A-Za-zÀ-ÖØ-öø-ÿäöüÄÖÜß0-9]+$"}),F=(e,t)=>{if(!t.repeated)return!1;const i={};for(const t of String(e))if(/\d/.test(t)){if(i[t])return!0;i[t]=1}return!1},k=(e,t,{values:i=[],metadata:s=[]}={values:[],metadata:[],erroredFields:[],isValid:!0})=>!!(t.callback&&(null==t?void 0:t.callback)instanceof Function)&&t.callback(e,{values:i,metadata:s}),w=(e,t)=>!(!e||!Array.isArray(null==t?void 0:t.includes)||(null==t?void 0:t.includes.some(t=>t===e||JSON.stringify(t)===e))),_=(t,i)=>{const s=D(null==t?void 0:t.toString()),n=e(s);return["object"==typeof i&&i.length?null==n?void 0:n.filter(({type:e})=>i.some(t=>t===e))[0]:n[0],s]},D=e=>null==e?void 0:e.replace(/ /g,""),A=(e,t=4,i="/")=>{const s=e.replace(/\D/g,""),n=s.slice(0,2);return s.length>=5?`${n}${i}${s.slice(2,t)}`:s.length>=3?`${n}${i}${s.slice(2)}`:s},T=(e,t)=>{if(!e)return!0;const[i]=_(String(e),t.isCreditCard);return!i},M=(e,t)=>{var i;if(!e||!t.isCreditCodeMatch)return!1;const[s]=_(t.isCreditCodeMatch.numberCard,t.isCreditCodeMatch.availableOptions);return(null===(i=null==s?void 0:s.code)||void 0===i?void 0:i.size)!==e.length},P=(e,t)=>{if(!e||!t.isCreditCardAndLength)return!1;const[i,s]=_(e,t.isCreditCardAndLength);return i&&!i.lengths.includes(s.length)},C=(e,t)=>{var i;return!(!(null==t?void 0:t.notEmpty)||void 0===e||null!==e&&""!==e&&0!==e&&(null===(i=String(e))||void 0===i?void 0:i.trim().length))},R=(e,t)=>null!=(null==t?void 0:t.value)&&null!=e&&e!=t.value,L=(e,t)=>!(!t.required||e&&("string"!=typeof e||0!==e.trim().length)),Y=(e,t)=>{if(!(null==t?void 0:t.bool))return!1;let i=!1;return"boolean"==typeof t.bool&&(i=t.bool),i},q=(e,t)=>{if(!t.exists)return!1;let i=!t.exists;return i||(i=!e),i},U=(e,t)=>{if(t.forceDefinedOrigin&&void 0===t.origin||t.forceDefinedTarget&&void 0===t.target)return!1;const i=void 0===t.origin?e:t.origin,s=void 0===t.target?e:t.target;return{"!==":(i||e)!==(s||e),"===":(i||e)===(s||e),"<":(i||e)<(s||e),">":(i||e)>(s||e),"<=":(i||e)<=(s||e),">=":(i||e)>=(s||e),"!!origin":!!String(i||e).trim().length}[t.condition]},z=(e,t)=>{if(!t.conditions)return!1;let i={and:()=>{var i;return!!(null===(i=t.conditions)||void 0===i?void 0:i.set.every(t=>U(e,t)))},or:()=>{var i;return!!(null===(i=t.conditions)||void 0===i?void 0:i.set.some(t=>U(e,t)))}}[t.conditions.rule]();return t.conditions.conditions&&(i="and"===t.conditions.rule?i&&z(e,{conditions:t.conditions.conditions}):i||z(e,{conditions:t.conditions.conditions})),!i},Z={DDMMYYYY:e=>{if(!e)return"";const t=e.split(e.includes("/")?"/":"-");return`${t[1]}/${t[0]}/${t[2]}`},YYYYMMDD:e=>{if(!e)return"";const t=e.split(e.includes("/")?"/":"-");return`${t[1]}/${t[2]}/${t[0]}`},YYYYDDMM:e=>{if(!e)return"";const t=e.split(e.includes("/")?"/":"-");return`${t[2]}/${t[1]}/${t[0]}`},MMDDYYYY:e=>e,timestamp:e=>new Date(e).toString()},Q=(e,t)=>{var i;let s=!1;if(2!=(null===(i=t.betweenDates)||void 0===i?void 0:i.length))return!1;for(const i of t.betweenDates)if(B(e,{date:i})){s=!0;break}return s},B=(e,t)=>{var i,s,n,r,a,l,o,u,d,c,h,v;if(!(null===(s=null===(i=t.date)||void 0===i?void 0:i.target)||void 0===s?void 0:s.value)&&!(null===(r=null===(n=t.date)||void 0===n?void 0:n.origin)||void 0===r?void 0:r.intervals))return!1;const f=t.date.origin.value||e,p=Z[null===(a=t.date)||void 0===a?void 0:a.origin.format](f).toString();let m=new Date(p),b=new Date,g=new Date;if((null===(o=null===(l=t.date)||void 0===l?void 0:l.target)||void 0===o?void 0:o.format)&&(g=new Date(Z[null===(d=null===(u=t.date)||void 0===u?void 0:u.target)||void 0===d?void 0:d.format](t.date.target.value).toString()),b=g),t.date.origin.intervals){b=((e,t)=>{const i={years:(e,t)=>new Date(e.setUTCFullYear(e.getUTCFullYear()+t)),months:(e,t)=>new Date(e.setUTCMonth(e.getUTCMonth()+t)),days:(e,t)=>new Date(e.setDate(e.getUTCDate()+t))};return Object.keys(t).reduce((e,s)=>i[s](e,t[s]),new Date(e))})(m,t.date.origin.intervals);const e=new Date;(null===(c=t.date.target)||void 0===c?void 0:c.value)&&g&&(e.setDate(g.getDate()),e.setMonth(g.getMonth())),m=new Date(`${e.getUTCMonth()+1}/${e.getUTCDate()}/${e.getUTCFullYear()}`)}if(t.date.onlyValidDate&&(!(b instanceof Date&&isFinite(b))||!(b instanceof Date&&isFinite(m))||f.length<8))return!0;if(((e,t)=>{if(!e.includes("/")&&!e.includes("-")||!t)return!0;const i=e.replace(/[-/]/g,"");return!{DDMMYYYY:/^(\d{2})(\d{2})(\d{4})$/,YYYYMMDD:/^(\d{4})(\d{2})(\d{2})$/,YYYYDDMM:/^(\d{4})(\d{2})(\d{2})$/,MMDDYYYY:/^(\d{2})(\d{2})(\d{4})$/,DMYYYY:/^(\d{1,2})(\d{1,2})(\d{4})$/,YYYYMD:/^(\d{4})(\d{1,2})(\d{1,2})$/,YYYYDM:/^(\d{4})(\d{1,2})(\d{1,2})$/,MDYYYY:/^(\d{1,2})(\d{1,2})(\d{4})$/}[t].test(i)})(p,null===(h=t.date)||void 0===h?void 0:h.origin.format))return!1;const S=m.getTime(),y=b.getTime();return{">":S>y,">=":S>=y,"<":S<y,"<=":S<=y,"===":S===y,"!==":S!==y}[null===(v=t.date)||void 0===v?void 0:v.operator]},J=(e,t)=>{if(!t.validDate||!e)return!1;if(/[^a-zA-Z0-9\s-]/.test(e))return!0;const i=Z[t.validDate](e).toString().split(/[/-]/),s=parseInt(i[2],10),n=parseInt(i[0],10)-1,r=parseInt(i[1],10),a=new Date(s,n,r),l=new Date;return l.setFullYear(l.getFullYear()-150),a.getFullYear()<l.getFullYear()||!(a.getFullYear()===s&&a.getMonth()===n&&a.getDate()===r)};function K(e){if(null===e||"object"!=typeof e)return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(e=>K(e));const t={};for(const i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=K(e[i]));return t}function G(e,t,i){if(null==e)return i;const s=Array.isArray(t)?t:t.split(".");let n=e;for(let e=0;e<s.length;e++){if(null==n)return i;n=n[s[e]]}return void 0===n?i:n}function W(e,t,i){if(null==e||"object"!=typeof e)return e;const s=Array.isArray(t)?t:t.split(".");let n=e;for(let e=0;e<s.length-1;e++){const t=s[e],i=s[e+1];null!=n[t]&&"object"==typeof n[t]||(n[t]="number"==typeof i||/^\d+$/.test(String(i))?[]:{}),n=n[t]}return n[s[s.length-1]]=i,e}function X(e,t){if(e===t)return!0;if(null==e||null==t)return e===t;if(typeof e!=typeof t)return!1;if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if("object"!=typeof e)return!1;const i=Array.isArray(e);if(i!==Array.isArray(t))return!1;if(i){if(e.length!==t.length)return!1;for(let i=0;i<e.length;i++)if(!X(e[i],t[i]))return!1;return!0}const s=Object.keys(e),n=Object.keys(t);if(s.length!==n.length)return!1;for(const i of s){if(!Object.prototype.hasOwnProperty.call(t,i))return!1;if(!X(e[i],t[i]))return!1}return!0}function H(e){return null==e}function ee(e){return"function"==typeof e}var te=(e,t,i)=>!!t&&function(e,t,i){const s=[];return Object.keys(t).forEach(n=>{s.push(i[n](e,{[n]:t[n]}))}),s}(e,t,i).some(e=>e);const ie={max:m,min:b,lessThan:S,greaterThan:y,length:v,regex:V,url:E,email:j,onlyLetters:N,notAllowSpaces:x,callback:k,hasNoExtraSpaces:I,between:g,sequential:$,includes:w,repeated:F,document:p,isCreditCard:T,isCreditCodeMatch:M,isCreditCardAndLength:P,required:L,value:R,notEmpty:C,bool:Y,exists:q,isNumber:O,conditions:z,validDate:J,date:B,betweenDates:Q},se={},ne={},re={};function ae(e){Object.assign(se,e)}function le(e){Object.assign(ne,e)}function oe(e){Object.assign(re,e)}const ue={max:m,min:b,lessThan:S,greaterThan:y,length:v,regex:V,url:E,email:j,onlyLetters:N,notAllowSpaces:x,callback:k,hasNoExtraSpaces:I,between:g,sequential:$,includes:w,repeated:F,document:p,isCreditCard:T,isCreditCodeMatch:M,isCreditCardAndLength:P,required:L,value:R,notEmpty:C,bool:Y,exists:q,isNumber:O,conditions:z,multipleValidations:(e,t)=>{if(!t.multipleValidations)return!1;const i=function(e,t){const i=[];return Object.keys(t).forEach(s=>{let n;n=ee(ie[s])?ie[s](e,{[s]:t[s]}):te(e,t[s],ie),i.push(n)}),i}(e,t.multipleValidations.validations);return{AND:()=>i.every(e=>e),OR:()=>i.some(e=>e),NOT:()=>!i.every(e=>e)}[t.multipleValidations.rule]()},date:B,betweenDates:Q,validDate:J};ae(ue);const de={capitalize:e=>String(e).charAt(0).toUpperCase()+String(e).slice(1),uppercase:e=>String(e).toUpperCase(),onlyNumbers:e=>String(e).replace(/(\D)+/gim,""),onlyLetters:e=>String(e).replace(/[^\p{L}\s]/gu,""),regex:(e,t)=>t.regex?String(e).replace(new RegExp(t.regex,"g"),""):e,splitter:(e,t)=>{if(!e||!t.splitter||"string"!=typeof e)return e;t.splitter.sort((e,t)=>e.position-t.position);let i=e,s=0;for(const e of t.splitter){const{position:t,value:n}=e,r=t+s;r>=0&&r<=i.length&&(i=i.slice(0,r)+n+i.slice(r),s+=n.length)}return i},maxLength:(e,t)=>{if(!e||!t.maxLength)return e;const i=String(e);return i.length>t.maxLength?i.substring(0,t.maxLength):e},onlyFloatNumber:(e,t)=>{const{onlyFloatNumber:i}=t;if(!i||"string"!=typeof e||!e)return e;const{precision:s=2,decimal:n="."}=i;if(!e.includes(n))return e;const r=e.replace(/[^0-9]/g,""),a=r.slice(0,r.length-s),l=r.slice(r.length-s);return parseFloat(`${a}.${l}`).toFixed(s)},trim:(e,t)=>!e||(null==t?void 0:t.trim)?e:String(e).trim(),gapsCreditCard:(e,t)=>{if(!t.gapsCreditCard)return e;const[i,s]=_(e,null==t?void 0:t.gapsCreditCard);return((e,t)=>t?((e,t=[])=>{const[i,s]=t.reduce(([e,i],s,n)=>[`${e}([0-9]{0,${s-(t[n-1]||0)}})`,`${i}$${n+1} `],["",""]);return e.replace(new RegExp(i),s).trim()})(e.slice(0,null==t?void 0:t.lengths[0]),t.gaps):null==e?void 0:e.slice(0,19))(s,i)},callback:(e,t)=>(null==t?void 0:t.callback)?t.callback(e):e,dotEvery3chars:e=>{const t=String(e).replace(/\./g,"").replace(/(.{3})/g,"$1.");return t.endsWith(".")?t.slice(0,-1):t}};le(de);var ce=(e,t)=>{if(!(null==t?void 0:t.generic))return e;let i=e;return t.generic.forEach(t=>{const{to:s=i.length,mask:n}=t;let{from:r}=t;if(s>e.length-1)return;0===r&&(r=1);const a=new Array(s-r+2).join(n);i=i.slice(0,r-1)+a+i.slice(s)}),i};const he={currency:(e,i)=>{if(!(null==i?void 0:i.currency))return e;const{align:s="",decimal:n=".",precision:r=2,prefix:a="BBD",thousands:l=","}=i.currency;let o=(function(e){return"number"==typeof e||"object"==typeof e&&null!==e&&"[object Number]"===Object.prototype.toString.call(e)}(e)?Number(e).toFixed(r):e).replace(/[^0-9]/g,"");if(!o)return"";let u=o.slice(0,o.length-r).replace(/^0*/g,"").replace(/\B(?=(\d{3})+(?!\d))/g,l);""===u&&(u="0"),"right"===s&&String(e).endsWith(" ")&&(o=o.slice(0,-1));let d=u,c=o.slice(o.length-r);if(r>0&&(c="0".repeat(r-c.length)+c,d+=n+c),!s)return d;const h=t(a);return"left"===s?`${h} ${d}`:`${d} ${h}`},custom:(e,t)=>{if(!t.custom||!e)return e;let i="",s=0;const n=e.replace(/[^\w\s]/gi,"");for(const e of t.custom)if("#"===e){if(!(s<n.length))break;i+=n[s],s++}else s<=n.length&&(i+=e);return e.length<i.length&&(i=i.replace(/[^\w]+$/,"")),i},callback:(e,t)=>(null==t?void 0:t.callback)&&t.callback(e),generic:ce,secureCreditCard:e=>ce(e,{generic:[{from:1,to:4,mask:"x"},{from:6,to:9,mask:"x"},{from:11,to:14,mask:"x"},{from:16,to:19,mask:"x"}]}),card:e=>e.replace(/[^\dA-Z]/g,"").replace(/(.{4})/g,"$1 ").trim(),cardDate:e=>A(e),fein:e=>A(e,9,"-"),replaceAll:(e,t)=>{let i=t.replaceAll;return i?("number"==typeof i&&(i=null==i?void 0:i.toString()),new Array(String(e).length+1).join(i)):e}};var ve;function fe(e,t,i,s){return new(i||(i=Promise))(function(n,r){function a(e){try{o(s.next(e))}catch(e){r(e)}}function l(e){try{o(s.throw(e))}catch(e){r(e)}}function o(e){e.done?n(e.value):function(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(a,l)}o((s=s.apply(e,t||[])).next())})}oe(he),function(e){e.ON_VALUE="value",e.ON_PROPS="props",e.ON_VISIBILITY="visibility",e.ON_API="api",e.ON_IVARS="iVars",e.ON_FIELDS="fields"}(ve||(ve={})),"function"==typeof SuppressedError&&SuppressedError;const pe=1e3,me=/^\$\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}$/,be=/\$\{((?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*)\}/g,ge=/\s*(\|\||&&|!+)\s*/g,Se=/^\|\||&&|!+$/,ye=["fields","iVars","form"],$e=["api","apiSchema","props","validations","visibilityConditions","resetValues"],Ve=!1;function je(e){const t=be,i=[];let s;for(;null!==(s=t.exec(e));)i.push(s[1]);const n=ge,r=i.map(e=>e.split(n).filter(e=>!n.test(e))).flat().filter(e=>e.split(".").length>1);return{originScopeKeys:Array.from(new Set(r.map(e=>e.split(".")[0]))),originFieldKeys:Array.from(new Set(r.map(e=>e.split(".")[1]))),originPropertyKeys:Array.from(new Set(r.map(e=>e.split(".")[2])))}}function Ee(e,t){const i=[];if(Array.isArray(e))e.forEach((e,s)=>{i.push(...Ee(e,`${t?`${t}.`:""}${s}`))});else if("object"==typeof e)for(const s in e)Object.prototype.hasOwnProperty.call(e,s)&&i.push(...Ee(e[s],`${t?`${t}.`:""}${s}`));else if("string"==typeof e&&e.includes("${")){const s=(t||"").split(".");je(e).originScopeKeys.every(e=>ye.includes(e))?i.push(Object.assign(Object.assign({originExpression:e},je(e)),{destinationKey:s[0],destinationProperty:s[1],destinationPath:s.slice(2)})):console.warn(`scope malformed on this expression: ${e}, ignoring..`)}return i}class Ne extends s{constructor(e){super(),this.isMounted=e}next(e){this.isMounted()&&super.next(e)}}class xe extends i{constructor(e){super(e),this.defaultValue=e}next(e){this.closed||super.next(e)}get value(){return this.closed?this.defaultValue:super.value}}function Oe(e,t,i,s,n){return ee(i[s])?i[s](e,t,n):te(e,t[s],i)}class Ie{constructor({formIndex:e,schemaComponent:t,config:i,children:s,validateVisibility:r,resetValue:a,resetProperty:l,templateSubject$:o,fieldEventSubject$:u,dataSubject$:d,fieldValidNotification$:c,mountSubject$:h,mapper:v,formValuesStateSubject$:f,submitEvent:p,visibility:m,persistValue:b}){var g,S,y,$,V,j;this.valueSubscription$=new n,this.fieldStateSubscription$=new n,this.formIndex=e,this.originalSchema=K(t),this.config={defaultAPIdebounceTimeMS:Number(null==i?void 0:i.defaultAPIdebounceTimeMS)?Number(null==i?void 0:i.defaultAPIdebounceTimeMS):pe,defaultStateRefreshTimeMS:Number(null==i?void 0:i.defaultStateRefreshTimeMS)?Number(null==i?void 0:i.defaultStateRefreshTimeMS):100,defaultLogVerbose:(null==i?void 0:i.defaultLogVerbose)?i.defaultLogVerbose:Ve},this.name=t.name,this.nameToSubmit=t.nameToSubmit,this.component=t.component,this.children=s,this.validations=K(t.validations),this.visibilityConditions=K(t.visibilityConditions),this.resetValues=K(t.resetValues),this.resetPropertyValues=K(t.resetPropertyValues),this.apiSchema=K(t.api),this.formatters=K(t.formatters),this.masks=K(t.masks),v.valueChangeEvent&&(this.valueChangeEvent=v.valueChangeEvent),(null===(g=v.events)||void 0===g?void 0:g.setValue)&&(this.valuePropName=v.events.setValue),this.mapper=v,this.validateVisibility=r,this.resetValue=a,this.resetProperty=l,this.submitEvent=p,this.templateSubject$=o,this.fieldEventSubject$=u,this.dataSubject$=d,this.fieldValidNotification$=c,this.mountSubject$=h,this.formValuesStateSubject$=f,this.getFormValues=()=>this.formValuesStateSubject$.value,this._props=Ie.filterProps(K(t.props||{})),this._adapterProps=JSON.stringify(t.props||{}),this._metadata="",this.errorsString="",this.errorsList=[],this._visibility="boolean"!=typeof m||m,this._api={default:{response:(null===($=null===(y=null===(S=this.apiSchema)||void 0===S?void 0:S.defaultConfig)||void 0===y?void 0:y.config)||void 0===$?void 0:$.fallbackValue)||"",status:null},named:(null===(V=this.apiSchema)||void 0===V?void 0:V.configs)&&Object.keys(null===(j=this.apiSchema)||void 0===j?void 0:j.configs).reduce((e,t)=>{var i,s;return e[t]={response:(null===(s=null===(i=this.apiSchema)||void 0===i?void 0:i.configs)||void 0===s?void 0:s[t].config.fallbackValue)||"",status:null},e},{}),apiState:{loading:!1}},this._errors={},this._mounted=!1,this.valid=!0,this.persistValue=b,this.initializeObservers()}initializeObservers(){this.valueSubject$&&!this.valueSubject$.closed||(this.valueSubject$=new Ne(()=>this.mounted)),this.errorSubject$&&!this.errorSubject$.closed||(this.errorSubject$=new Ne(()=>this.mounted)),this.visibilitySubject$&&!this.visibilitySubject$.closed||(this.visibilitySubject$=new Ne(()=>this.mounted)),this.propsSubject$&&!this.propsSubject$.closed||(this.propsSubject$=new Ne(()=>this.mounted)),this.fieldStateSubscription$&&!this.fieldStateSubscription$.closed||(this.fieldStateSubscription$=new n),this.apiEventQueueSubject$&&!this.apiEventQueueSubject$.closed||(this.apiEventQueueSubject$=new Ne(()=>this.mounted)),this.apiEventQueueSubject$.observed||this.apiEventQueueSubject$.pipe(r(({event:e})=>e),a(e=>e.pipe(l(this.config.defaultAPIdebounceTimeMS))),o(()=>this.apiEventQueueSubject$&&!this.apiEventQueueSubject$.closed)).subscribe(e=>{this.apiRequest(e)})}get adapterProps(){return this._adapterProps}set adapterProps(e){const t=JSON.stringify(e||{});t!==this.adapterProps&&(this.props=Ie.filterProps(e),this._adapterProps=t)}get props(){return this._props}set props(e){void 0===e||X(e,this.props)||(this._props=e,this.propsSubject$.next(this.props),this.templateSubject$.next({scope:"fields",key:this.name,event:"ON_PROPS"}))}static filterProps(e){return Array.isArray(e)?e.filter(e=>"string"!=typeof e||!e.includes("${")).map(e=>Ie.filterProps(e)):"object"==typeof e&&null!==e?e instanceof Date?e:Object.keys(e).reduce((t,i)=>{const s=e[i];return"string"==typeof s&&s.includes("${")||(t[i]=Ie.filterProps(e[i])),t},{}):e}get stateValue(){return this._stateValue}get metadata(){return this._metadata}get value(){return this._value}set value(e){var t,i,s;let n;if(this.valueChangeEvent)try{n=this.valueChangeEvent(e,{props:this.props})}catch(t){n=e}else n=e;null!=n&&("object"==typeof n&&"_value"in n&&"_metadata"in n?(this._value=this.formatValue(n._value),this._stateValue=(null===(t=this.mapper.events)||void 0===t?void 0:t.setValue)?{[this.mapper.events.setValue]:this.maskValue(this.formatValue(n._value))}:{},this._metadata=n._metadata):(this._value=this.formatValue(n),this._stateValue=(null===(i=this.mapper.events)||void 0===i?void 0:i.setValue)?{[null===(s=this.mapper.events)||void 0===s?void 0:s.setValue]:this.maskValue(this.formatValue(n))}:{},this.maskValue(this.formatValue(n)),this._metadata=n),this.stateValue&&this.valueSubject$.next(this.stateValue),this.templateSubject$.next({scope:"fields",key:this.name,event:"ON_VALUE"}))}get visibility(){return this._visibility}set visibility(e){void 0!==e&&e!==this.visibility&&(this._visibility=e,this.visibilitySubject$.next(this.visibility),this.templateSubject$.next({scope:"fields",key:this.name,event:"ON_VISIBILITY"}))}set valid(e){"boolean"!=typeof e&&this.valid===e||(this._valid=e,this.triggerFieldValidNotification())}get valid(){return this._valid}triggerFieldValidNotification(){this.fieldValidNotification$.closed||this.fieldValidNotification$.next({fieldTrigger:this.name})}get errors(){return this._errors}set errors(e){var t;void 0===e||X(e,this.errors)||(this._errors=e,this.errorsList=Object.values(this.errors).filter(e=>null!=e),this.errorsString=this.errorsList.join(", "),(null===(t=this.mapper.events)||void 0===t?void 0:t.setErrorMessage)&&this.errorSubject$.next({[this.mapper.events.setErrorMessage]:this.errorsString}),this.templateSubject$.next({scope:"fields",key:this.name,event:"ON_PROPS"}))}get api(){return this._api}set api(e){void 0!==e&&(this._api=e,this.templateSubject$.next({scope:"fields",key:this.name,event:"ON_API_RESPONSE"}),this.emitEvents({event:"ON_API_FIELD_RESPONSE"}))}notifyApiRequest(){this._api.apiState.loading=!0,this.templateSubject$.next({scope:"fields",key:this.name,event:"ON_API_REQUEST"}),this.emitEvents({event:"ON_API_FIELD_REQUEST"})}get mounted(){return this._mounted}set mounted(e){void 0!==e&&e!==this.mounted&&(this._mounted=e,this.initializeObservers(),this.mountSubject$.closed||this.mountSubject$.next({key:this.name,status:this.mounted}))}mountField({valueSubscription:e,propsSubscription:t}){this.mounted=!0,this.subscribeValue(e),this.subscribeState(t),this.valueSubject$.next(this.stateValue),this.propsSubject$.next(this.props),this.visibilitySubject$.next(this.visibility),this.fieldEventSubject$.next({event:"ON_FIELD_MOUNT",fieldName:this.name,fieldInstance:this})}emitValue(e){this.visibility&&this.mounted&&(this.value=e.value,this.dataSubject$.next({event:e.event,fieldIndex:this.name,formIndex:this.formIndex}),this.emitEvents({event:e.event}))}emitEvents({event:e}){if("ON_FORM_SUBMIT"===e)return this.submitEvent();this.validateVisibility({event:e,key:this.name}),this.setFieldValidity({event:e}),this.resetValue({event:e,key:this.name}),this.resetProperty({event:e,key:this.name}),this.apiEventQueueSubject$.next({event:e}),this.fieldEventSubject$.next({event:e,fieldName:this.name,fieldInstance:this})}setFieldValidity({event:e}){var t,i,s,n;if(!this.validations||!this.visibility)return this.errors={},void(this.valid=!0);let r=!0;const a={},l=null===(t=this.validations)||void 0===t?void 0:t.methods;if(l&&Object.keys(l).forEach(e=>{var t,i;const s=Oe(this.value,l,se,e,null===(t=this.formValuesStateSubject$)||void 0===t?void 0:t.value);r=!s&&r,s&&(null===(i=this.validations)||void 0===i?void 0:i.messages)?e in this.validations.messages?a[e]=this.validations.messages[e]:"default"in this.validations.messages&&(a[e]=this.validations.messages.default):delete a[e]}),this.valid=r,null===(s=null===(i=this.validations)||void 0===i?void 0:i.eventMessages)||void 0===s?void 0:s[e]){const t={};null===(n=this.validations.eventMessages[e])||void 0===n||n.forEach(e=>{e in a&&(t[e]=a[e])}),this.errors=t}else"ON_FIELD_VALIDATION"===e&&(this.errors=a)}formatValue(e){return this.formatters?Object.keys(this.formatters).reduce((e,t)=>{const i=ne[t];return i?i(e,this.formatters):e},e):e}maskValue(e){return this.masks?Object.keys(this.masks).reduce((e,t)=>{const i=re[t];return i?i(e,this.masks):e},e):e}checkApiRequestValidations(e){let t=!0;const i=e.preConditions;return i&&Object.keys(i).forEach(e=>{var s;const n=Oe(this.value,i,se,e,null===(s=this.formValuesStateSubject$)||void 0===s?void 0:s.value);t=t&&!n}),e.blockRequestWhenInvalid&&(t=t&&this.valid),t}apiRequest(e){return fe(this,arguments,void 0,function*({event:e}){var t,i,s,n,r,a,l,o,u;let d=!1;const c=e=>fe(this,void 0,void 0,function*(){var t,i;try{const{status:s,response:n}=yield function(e,t,i,s,n){return fe(this,void 0,void 0,function*(){if(n){const[e,i]=t.split("?"),s=new URLSearchParams(i);Object.keys(n).forEach(e=>{s.append(e,n[e])}),t=`${e}?${s.toString()}`}const r=yield fetch(t,{method:e,headers:i,body:s?JSON.stringify(s):void 0}),a=yield r.text();return{status:r.status,response:a}})}(e.method,e.url,e.headers,e.body,e.queryParams),r=null===(t=e.transform)||void 0===t?void 0:t.callback,a=r?r({payload:JSON.parse(String(n)),formValues:null===(i=this.formValuesStateSubject$)||void 0===i?void 0:i.value}):JSON.parse(String(n));return{response:e.resultPath?G(a,e.resultPath):a,status:s}}catch(t){return{response:H(null==e?void 0:e.fallbackValue)?"error":e.fallbackValue,status:500}}});if("ON_API_FIELD_RESPONSE"===this.api.apiState.lastEvent&&"ON_API_FIELD_RESPONSE"===e||!(null===(i=null===(t=this.apiSchema)||void 0===t?void 0:t.defaultConfig)||void 0===i?void 0:i.events.includes(e))&&(!(null===(s=this.apiSchema)||void 0===s?void 0:s.configs)||!Object.keys(null===(n=this.apiSchema)||void 0===n?void 0:n.configs).some(t=>{var i,s;return null===(s=null===(i=this.apiSchema)||void 0===i?void 0:i.configs)||void 0===s?void 0:s[t].events.includes(e)})))return;const h={default:Object.assign({},this.api.default),named:Object.assign({},this.api.named),apiState:Object.assign({},this.api.apiState)},v=null===(r=this.apiSchema.defaultConfig)||void 0===r?void 0:r.config;if(v&&(null===(l=null===(a=this.apiSchema)||void 0===a?void 0:a.defaultConfig)||void 0===l?void 0:l.events.includes(e))&&this.checkApiRequestValidations(v)){d||this.notifyApiRequest();const{response:e,status:t}=yield c(v);d=!0,h.default={response:e,status:t}}if((null===(o=this.apiSchema)||void 0===o?void 0:o.configs)&&Object.keys(null===(u=this.apiSchema)||void 0===u?void 0:u.configs).some(t=>{var i,s;return null===(s=null===(i=this.apiSchema)||void 0===i?void 0:i.configs)||void 0===s?void 0:s[t].events.includes(e)})&&this.apiSchema.configs){const t=yield Promise.all(Object.keys(this.apiSchema.configs).map(t=>fe(this,void 0,void 0,function*(){var i,s,n,r;const a=null===(s=null===(i=this.apiSchema)||void 0===i?void 0:i.configs)||void 0===s?void 0:s[t].config;if(a&&(null===(r=null===(n=this.apiSchema)||void 0===n?void 0:n.configs)||void 0===r?void 0:r[t].events.includes(e))&&this.checkApiRequestValidations(a)){d||this.notifyApiRequest();const{response:e,status:i}=yield c(a);return d=!0,{name:t,result:{response:e,status:i}}}return null})));t.forEach(e=>{e&&h.named&&(h.named[e.name]=e.result)})}d&&(h.apiState.lastEvent=e,h.apiState.loading=!1,this.api=h)})}destroyField(){this.mounted=!1,this.valueSubscription$.unsubscribe(),this.visibilitySubject$.unsubscribe(),this.fieldStateSubscription$.unsubscribe(),this.propsSubject$.unsubscribe(),this.errorSubject$.unsubscribe(),this.apiEventQueueSubject$.unsubscribe(),this.dataSubject$.closed||this.dataSubject$.next({event:"ON_FIELD_UNMOUNT",fieldIndex:this.name,formIndex:this.formIndex}),this.fieldEventSubject$.closed||this.fieldEventSubject$.next({event:"ON_FIELD_UNMOUNT",fieldName:this.name,fieldInstance:this})}subscribeState(e){var t;this.fieldStateSubscription$=u({visibility:this.visibilitySubject$.pipe(d(this.visibility)),props:this.propsSubject$.pipe(d(this.props)),errors:this.errorSubject$.pipe(d(Object.assign({},(null===(t=this.mapper.events)||void 0===t?void 0:t.setErrorMessage)&&{[this.mapper.events.setErrorMessage]:this.errorsString})))}).pipe(l(this.config.defaultStateRefreshTimeMS)).subscribe({next:e})}subscribeValue(e){this.valueSubscription$=this.valueSubject$.subscribe({next:e})}}class Fe{constructor(e){var t,i,r,a,l,o,u,d,c,h,v;this.templateSubscription$=new n,this.mappers=new Map,this.queuedFieldVisibilityEvents=new Map,this.queuedFieldResetValuesEvents=new Map,this.queuedFieldResetPropertyEvents=new Map,this.queuedInitialValues=new Map,this._valid=!1,this.stopEventsOnSubmit=!1,this.submitted=!1,this.isolatedFormInstance=!1,this.index=e.index,this.schema=e.schema,this.fields=new Map,this.action=e.action||(null===(t=e.schema)||void 0===t?void 0:t.action),this.method=e.method||(null===(i=e.schema)||void 0===i?void 0:i.method),this.config={defaultAPIdebounceTimeMS:Number(null===(r=e.config)||void 0===r?void 0:r.defaultAPIdebounceTimeMS)?Number(null===(a=e.config)||void 0===a?void 0:a.defaultAPIdebounceTimeMS):pe,defaultStateRefreshTimeMS:Number(null===(l=e.config)||void 0===l?void 0:l.defaultStateRefreshTimeMS)?Number(null===(o=e.config)||void 0===o?void 0:o.defaultStateRefreshTimeMS):100,defaultLogVerbose:(null===(u=e.config)||void 0===u?void 0:u.defaultLogVerbose)?e.config.defaultLogVerbose:Ve},null===(d=e.mappers)||void 0===d||d.map(e=>{this.mappers.set(e.componentName,e)}),e.submitSubject$&&e.dataSubject$&&e.formValidSubject$||(this.isolatedFormInstance=!0,this.config.defaultLogVerbose&&console.warn(`some formGroup events are not properly instanciated, any onData, onValid, onSubmit events managed by formGroup won't trigger on form: ${this.index}`)),this.schema&&Fe.checkIndexes(this.schema.components),this.templateSubject$=new s,this.fieldEventSubject$=new s,this.mountSubject$=new s,this.fieldValidNotification$=new s,this.submitSubject$=e.submitSubject$?e.submitSubject$:new s,this.dataSubject$=e.dataSubject$?e.dataSubject$:new s,this.formValidSubject$=e.formValidSubject$?e.formValidSubject$:new s,this.formValuesStateSubject$=new xe({erroredFields:[],isValid:!0,metadata:[],values:[]}),this.getFormValues=()=>this.formValuesStateSubject$.value,this.subscribedTemplates=[],this.templateSubscription$=this.templateSubject$.subscribe(this.refreshTemplates.bind(this)),this.fieldValidNotification$.subscribe(()=>{this.validateForm()}),this.fieldEventSubject$.subscribe(()=>{this.formValuesStateSubject$.next(this.getFormState())}),this.dataSubject$.subscribe(()=>{this.formValuesStateSubject$.next(this.getFormState())}),this.mountSubject$.subscribe(this.mountActions.bind(this)),this.prefetchedData=null===(c=e.schema)||void 0===c?void 0:c.prefetchedData,this.initialValues=e.initialValues||(null===(h=e.schema)||void 0===h?void 0:h.initialValues),this.iVars=e.iVars||(null===(v=e.schema)||void 0===v?void 0:v.iVars)||{},this.stopEventsOnSubmit=(null==e?void 0:e.stopEventsOnSubmit)||!1,this.submitted=!1}generateFields(){this.schema&&this.serializeStructure(this.schema.components),this.fields.forEach(e=>{e.mountField({valueSubscription:()=>null,propsSubscription:()=>null})})}submitChecker(){return!(this.stopEventsOnSubmit&&this.submitted)}mountActions({key:e,status:t}){if(t){const t=this.fields.get(e);if(!t)return void(this.config.defaultLogVerbose&&console.warn(`field ${e} was mounted but since it's parent has some visibility condition the field was already removed`));this.subscribeTemplates(),this.refreshTemplates({scope:"fields",event:"ON_FIELDS"}),this.templateSubject$.next({scope:"iVars",event:"ON_IVARS"}),this.queuedInitialValues.has(e)||(t.valuePropName&&!t.value?t.emitValue({event:"ON_FIELD_MOUNT",value:""}):t.emitEvents({event:"ON_FIELD_MOUNT"})),this.checkFieldEventQueues(e)}}set initialValues(e){e&&Object.keys(e).forEach(t=>{const i=this.fields.get(t);i&&(null==i?void 0:i.visibility)&&(null==i?void 0:i.mounted)?i.emitValue({value:null==e?void 0:e[t],event:"ON_FIELD_MOUNT"}):this.queuedInitialValues.set(t,null==e?void 0:e[t])})}get iVars(){return this._iVars}set iVars(e){this._iVars=e,this.templateSubject$.next({scope:"iVars",event:"ON_IVARS"})}validateForm(){if(0===this.fields.size)return this.valid=!1;for(const[,e]of this.fields)if(!e.valid)return this.valid=!1;return this.valid=!0}get valid(){return this._valid}set valid(e){this._valid!==e&&(this._valid=e,this.templateSubject$.next({event:"ON_FORM",scope:"form"}),this.formValidSubject$.next({formIndex:this.index,valid:this.valid}))}subscribeTemplates(){this.subscribedTemplates=[],this.fields.forEach(({originalSchema:{component:e,props:t,name:i,validations:s,visibilityConditions:n,resetValues:r,resetPropertyValues:a,api:l}},o)=>{Ee({component:e,props:t,name:i,validations:s,visibilityConditions:n,resetValues:r,resetPropertyValues:a,apiSchema:l},o).forEach(e=>this.subscribedTemplates.push(e))})}getValue({scope:e,key:t,property:i,path:s}){switch(e){case"iVars":return G(this.iVars,[t,...i?[i]:[],...s]);case"form":return G(this,[t,...i?[i]:[],...s]);case"fields":{const e=this.fields.get(t);return e?"props"===i&&s[0]===e.valuePropName?e.value:s.length>0?G(e[i],s):e[i]:this.config.defaultLogVerbose&&console.warn(`failed to get value from ${t}`)}}}setValue({key:e,property:t,path:i,originKey:s,value:n}){const r=this.fields.get(e);if(r){if(i.length>0){if("props"===t&&i[0]===r.valuePropName&&e!==s)return void r.emitValue({event:"ON_FIELD_CHANGE",value:n});const a=r[t];let l;return Array.isArray(a)||"object"==typeof a&&!H(a)?(l=K(a),W(l,i,n),void(r[t]=l)):void(this.config.defaultLogVerbose&&console.warn(`invalid template property, skipping evaluation of ${r.name} with ${a}`))}r[t]=n}else this.config.defaultLogVerbose&&console.warn(`failed to update field ${e}`)}extractParams(e){const t=function(e){const t=e.split(".");return t.length>1?this.getValue({scope:t[0],key:t[1],property:t[2],path:t.slice(3)}):t[0]}.bind(this),i=[];let s;for(;!H(s=be.exec(e));)i.push(s[1]);const n=i.map(e=>e.split(ge)).map(e=>e.length<=1?{parse:!1,value:t(e[0])}:{parse:!0,value:e.filter(Boolean).reduce((e,i)=>{if(i.match(Se))return`${e}${i}`;let s;const n=t(i);let r;try{r=JSON.parse(n)}catch(e){r=n}switch(typeof r){case"string":s=`\`${r}\``;break;case"boolean":case"undefined":case"number":default:s=r;break;case"object":if(null===r){s=null;break}if(r instanceof Date){s=`new Date(\`${r}\`)`;break}s=JSON.stringify(r)}return`${e}${s}`},"")});return n.map(({parse:t,value:i})=>{try{return t?new Function(`return ${i}`)():i}catch(t){return this.config.defaultLogVerbose&&(console.warn(`unhandled parsing on ${e} returning`),console.warn(i)),i}})}replaceExpression(e,t){return e.replace(be,()=>String(t.shift())||"")}hasStringConcatenation(e){return!me.test(e)}refreshTemplates({key:e,event:t}){this.subscribedTemplates.forEach(({destinationKey:i,destinationPath:s,destinationProperty:n,originExpression:r,originFieldKeys:a})=>{if(!e||a.includes(e)){const a=this.extractParams(r);let l;l=this.hasStringConcatenation(r)?this.replaceExpression(r,[...a]):null==a?void 0:a[0],X(this.getValue({scope:"fields",key:i,property:n,path:s}),l)||this.setValue({key:i,property:n,path:s,originKey:e,value:l,event:t})}})}checkFieldEventQueues(e){var t;if(null===(t=this.fields.get(e))||void 0===t?void 0:t.mounted){if(this.queuedFieldVisibilityEvents.has(e)&&(this.setFieldVisibility(Object.assign({field:e},this.queuedFieldVisibilityEvents.get(e))),this.queuedFieldVisibilityEvents.delete(e)),this.queuedInitialValues.has(e)){const t=this.queuedInitialValues.get(e);this.queuedInitialValues.delete(e),this.initialValues={[e]:t}}this.queuedFieldResetValuesEvents.has(e)&&(this.setResetFieldValue(Object.assign({key:e},this.queuedFieldResetValuesEvents.get(e))),this.queuedFieldResetValuesEvents.delete(e)),this.queuedFieldResetPropertyEvents.has(e)&&(this.setResetPathValue(Object.assign({key:e},this.queuedFieldResetPropertyEvents.get(e))),this.queuedFieldResetPropertyEvents.delete(e))}}setFieldVisibility({field:e,hasError:t,showOnlyIfTrue:i}){const s=this.fields.get(e);if(s&&s.mounted){const n=s.visibility,r=i?t:!t;if(s.visibility=r,n===r)return;s.visibility?this.queuedInitialValues.has(e)?(null==s||s.emitValue({value:this.queuedInitialValues.get(e)||"",event:"ON_FIELD_MOUNT"}),this.queuedInitialValues.delete(e)):s.emitEvents({event:"ON_FIELD_MOUNT"}):(s.emitEvents({event:"ON_FIELD_UNMOUNT"}),s.persistValue&&this.queuedInitialValues.set(s.name,s.value),s.value="",s.valid=!0)}else this.queuedFieldVisibilityEvents.set(e,{hasError:t,showOnlyIfTrue:i})}validateVisibility({event:e,key:t}){const i=this.fields.get(t),s=null==i?void 0:i.visibilityConditions;s&&(null==s?void 0:s.some(t=>t.events.includes(e)))&&s.forEach(t=>{t.events.includes(e)&&Object.keys(t.validations).forEach(e=>{const s=Oe(i.value,t.validations,se,e,this.formValuesStateSubject$.value);Array.isArray(t.fields)?t.fields.forEach(e=>{this.setFieldVisibility({field:e,hasError:s,showOnlyIfTrue:!(!i.value||!t.showOnlyIfTrue)})}):t.fields&&this.setFieldVisibility({field:t.fields,hasError:s,showOnlyIfTrue:!(!i.value||!t.showOnlyIfTrue)})})})}setResetFieldValue({key:e,value:t}){const i=this.fields.get(e);i&&(null==i?void 0:i.mounted)?i.emitValue({value:t,event:"ON_FIELD_CLEARED"}):this.queuedFieldResetValuesEvents.set(e,{value:t})}resetValue({event:e,key:t}){const i=this.fields.get(t),s=null==i?void 0:i.resetValues;s&&(null==s?void 0:s.some(t=>t.events.includes(e)))&&s.forEach(t=>{if(!t.events.includes(e))return;const s=()=>{Array.isArray(t.fields)?t.fields.forEach((e,i)=>{const s=Array.isArray(t.resettledValue)?t.resettledValue[i]:t.resettledValue;this.setResetFieldValue({key:e,value:s})}):t.fields&&this.setResetFieldValue({key:t.fields,value:t.resettledValue})};if(!t.validations)return s();Object.keys(t.validations).forEach(e=>{Oe(i.value,t.validations,se,e,this.formValuesStateSubject$.value)||s()})})}setResetPathValue({key:e,property:t,path:i,value:s}){this.fields.get(e)?this.setValue({key:e,property:t,path:i.split("."),value:s,event:"ON_RESET"}):this.queuedFieldResetPropertyEvents.set(e,{property:t,path:i,value:s})}resetProperty({event:e,key:t}){const i=this.fields.get(t),s=null==i?void 0:i.resetPropertyValues;s&&(null==s?void 0:s.some(t=>t.events.includes(e)))&&s.forEach(t=>{if(t.events.includes(e)&&$e.includes(t.property))return t.validations?void Object.keys(t.validations).forEach(e=>{Oe(i.value,t.validations,se,e,this.formValuesStateSubject$.value)||this.setResetPathValue({key:t.field,path:t.path,property:t.property,value:t.resettledValue})}):this.setResetPathValue({key:t.field,path:t.path,property:t.property,value:t.resettledValue})})}addField({fieldSchema:e,mapperElement:t,path:i}){var s,n,r,a,l;if(this.fields.has(e.name))throw new Error(`field name ${e.name} already defined`);const o=t||(null===(s=this.mappers)||void 0===s?void 0:s.get(e.component));if(!o)throw new Error(`mapper not found for ${e.component}, add it to the mappers configuration`);if(null===(n=o.events)||void 0===n?void 0:n.setValue){const t=null===(r=null==e?void 0:e.props)||void 0===r?void 0:r[null===(a=null==o?void 0:o.events)||void 0===a?void 0:a.setValue];void 0===t||this.queuedInitialValues.has(e.name)||"string"==typeof t&&t.includes("${")||this.queuedInitialValues.set(e.name,K(t))}if(this.fields.set(e.name,new Ie({formIndex:this.index,schemaComponent:e,mapper:o,children:e.children?e.children.map(e=>e.name):[],validateVisibility:this.validateVisibility.bind(this),resetValue:this.resetValue.bind(this),resetProperty:this.resetProperty.bind(this),formValuesStateSubject$:this.formValuesStateSubject$,templateSubject$:this.templateSubject$,fieldEventSubject$:this.fieldEventSubject$,dataSubject$:this.dataSubject$,fieldValidNotification$:this.fieldValidNotification$,mountSubject$:this.mountSubject$,config:this.config,submitEvent:this.submit.bind(this),visibility:e.visibility,persistValue:e.persistValue,path:i})),null===(l=this.prefetchedData)||void 0===l?void 0:l[e.name]){const t=this.fields.get(e.name);if(t){const i=this.prefetchedData[e.name],s=Object.assign({},t.api);void 0!==i.defaultResponse&&(s.default={response:i.defaultResponse,status:200}),i.namedResponses&&(s.named=s.named||{},Object.keys(i.namedResponses).forEach(e=>{s.named[e]={response:i.namedResponses[e],status:200}})),t._api=s}}}removeField({key:e}){var t;null===(t=this.fields.get(e))||void 0===t||t.destroyField(),this.fields.delete(e),this.subscribeTemplates(),this.templateSubject$.next({scope:"fields",key:e,event:"ON_FIELDS"}),this.validateForm()}serializeStructure(e,t){e&&e.forEach(e=>{var i;const s=this.fields.get(e.name);s?(s.children=(null===(i=null==e?void 0:e.children)||void 0===i?void 0:i.map(e=>e.name))||(null==s?void 0:s.children)||[],s.originalSchema=e,s.templateSubject$=this.templateSubject$):this.addField({fieldSchema:e,mapperElement:e.mapper,path:t}),e.children&&this.serializeStructure(e.children,`${t?`${t}.`:""}${e.name}`)})}refreshFields(e){const t=Array.from(this.fields.keys());this.serializeStructure(e);const i=Fe.checkIndexes(e);this.fields.forEach((e,t)=>{var s;i.includes(t)||(null===(s=this.fields.get(t))||void 0===s||s.destroyField(),this.fields.delete(t))}),this.subscribeTemplates(),this.fields.forEach((e,i)=>{var s;t.includes(i)||(null===(s=this.fields.get(i))||void 0===s||s.emitEvents({event:"ON_FIELD_MOUNT"}),this.checkFieldEventQueues(i))}),this.subscribedTemplates.forEach(e=>{e.originFieldKeys.forEach(e=>{this.templateSubject$.next({scope:"fields",key:e,event:"ON_FIELDS"})})})}getField({key:e}){return this.fields.get(e)}printValues(){console.table(this.formValuesStateSubject$.value.values)}getFormState(){const e={},t={},i=[];return this.fields.forEach((s,n)=>{"string"==typeof s.value&&0===s.value.length||null==s.value||(W(e,s.nameToSubmit||n,s.value),t[n]=s.metadata),s.valid||i.push(n)}),{values:e,metadata:t,erroredFields:i,isValid:this.valid}}subscribeFieldEvent({callback:e}){return this.fieldEventSubject$.pipe(o(()=>this.submitChecker()),r(e=>`${e.event}|${e.fieldName}`),a(e=>e.pipe(l(this.config.defaultStateRefreshTimeMS)))).subscribe({next:e})}subscribeOnMount(e){return this.mountSubject$.pipe(c(()=>this.formValuesStateSubject$.value)).subscribe({next:e})}subscribeData(e){return this.dataSubject$.pipe(o(({formIndex:e})=>this.index===e&&this.submitChecker()),r(e=>e.event),a(e=>e.pipe(l(this.config.defaultStateRefreshTimeMS))),c(({fieldIndex:e})=>({field:e,data:this.formValuesStateSubject$.value}))).subscribe({next:e})}subscribeOnSubmit(e){return this.submitSubject$.pipe(o(({formIndex:e})=>e===this.index&&this.submitChecker()),c(({values:e})=>e)).subscribe({next:e})}subscribeFormValidation(e){return this.formValidSubject$.pipe(o(({formIndex:e})=>this.index===e),c(()=>({formIndex:this.index,valid:this.valid})),h("valid"),d({formIndex:this.index,valid:this.valid})).subscribe({next:e})}submit(){this.fields.forEach(e=>{e.emitEvents({event:"ON_FIELD_VALIDATION"})}),this.valid&&(this.submitSubject$.next({formIndex:this.index,values:this.formValuesStateSubject$.value}),this.submitted=!0)}destroy(){this.templateSubject$.unsubscribe(),this.templateSubscription$.unsubscribe(),this.mountSubject$.unsubscribe(),this.fieldEventSubject$.unsubscribe(),this.fieldValidNotification$.unsubscribe(),this.formValuesStateSubject$.unsubscribe(),this.isolatedFormInstance&&(this.submitSubject$.unsubscribe(),this.dataSubject$.unsubscribe(),this.formValidSubject$.unsubscribe()),this.fields.forEach(e=>e.destroyField())}}Fe.checkIndexes=(e,t=[])=>{if(!e)return t;const i=(e,t)=>{for(let s=0;s<e.length;s++){const n=e[s];t.push(n.name),n.children&&i(n.children,t)}};i(e,t);const s=t.filter((e,i)=>t.indexOf(e)!==i);if(s.length>0)throw new Error(`duplicated indexes found on schema: ${JSON.stringify(s)}`);return t};class ke{constructor(e){var t,i,n,r,a;this.destroy=()=>{this.forms.forEach(e=>e.destroy()),this.dataSubject$.unsubscribe(),this.formValidSubject$.unsubscribe(),this.submitSubject$.unsubscribe()},this.forms=new Map,this.config={defaultAPIdebounceTimeMS:Number(null===(t=null==e?void 0:e.config)||void 0===t?void 0:t.defaultAPIdebounceTimeMS)?Number(null===(i=null==e?void 0:e.config)||void 0===i?void 0:i.defaultAPIdebounceTimeMS):pe,defaultStateRefreshTimeMS:Number(null===(n=null==e?void 0:e.config)||void 0===n?void 0:n.defaultStateRefreshTimeMS)?Number(null===(r=null==e?void 0:e.config)||void 0===r?void 0:r.defaultStateRefreshTimeMS):100,defaultLogVerbose:(null===(a=null==e?void 0:e.config)||void 0===a?void 0:a.defaultLogVerbose)?e.config.defaultLogVerbose:Ve},this.dataSubject$=new s,this.formValidSubject$=new s,this.submitSubject$=new s,this.mappers=null==e?void 0:e.mappers}createFormWithIndex({index:e,mappers:t}){this.addForm({key:e,params:{index:e,mappers:t,config:this.config}})}addForm({key:e,params:t}){this.checkIndexes({key:e});const i=new Fe(Object.assign(Object.assign({},t),{dataSubject$:this.dataSubject$,formValidSubject$:this.formValidSubject$,submitSubject$:this.submitSubject$}));i.config||(i.config=this.config),this.forms.set(e,i)}getForm({key:e}){return this.forms.get(e)}removeForm({key:e}){var t;null===(t=this.forms.get(e))||void 0===t||t.destroy(),this.forms.delete(e)}removeField({formIndex:e,fieldIndex:t}){const i=this.forms.get(e);null==i||i.removeField({key:t}),0===(null==i?void 0:i.fields.size)&&this.removeForm({key:e})}checkIndexes({key:e}){if(this.forms.has(e))throw new Error(`duplicate index ${e} on form group`)}printFormGroupInstance(){console.table(this.forms)}submitMultipleFormsByIndex(e,t){let i=!0,s={},n={},r=[];e.forEach(e=>{var t,a;null===(t=this.forms.get(e))||void 0===t||t.submit();const l=null===(a=this.forms.get(e))||void 0===a?void 0:a.formValuesStateSubject$.value,o="object"==typeof(null==l?void 0:l.metadata)&&null!==l.metadata?l.metadata:{};i=i&&((null==l?void 0:l.isValid)||!1),s=Object.assign(Object.assign({},s),(null==l?void 0:l.values)||{}),n=Object.assign(Object.assign({},n),o),r=[...r,...(null==l?void 0:l.erroredFields)||[]]}),i&&t&&t({erroredFields:r,isValid:i,values:s,metadata:n})}onDataSubscription({ids:e,callback:t}){return this.dataSubject$.pipe(o(({formIndex:t})=>e.includes(t)),r(({event:e,formIndex:t})=>`${e}.${t}`),a(e=>e.pipe(l(this.config.defaultStateRefreshTimeMS))),c(({fieldIndex:t,formIndex:i})=>e.reduce((e,s)=>{const n=this.forms.get(s);return n&&(e[s]={formId:i,formField:t,values:n.formValuesStateSubject$.value}),e},{}))).subscribe(t)}onValidSubscription({ids:e,callback:t}){return this.formValidSubject$.pipe(o(({formIndex:t})=>e.includes(t)),r(({formIndex:e})=>e),a(e=>e.pipe(l(0))),d({fieldTrigger:null}),c(()=>({groupValid:e.every(e=>{var t;return!this.forms.get(e)||(null===(t=this.forms.get(e))||void 0===t?void 0:t.valid)}),forms:e.reduce((e,t)=>{const i=this.forms.get(t);return i&&(e[t]=i.valid),e},{})}))).subscribe(t)}onSubmitSubscription({ids:e,callback:t}){return this.submitSubject$.pipe(o(({formIndex:t})=>e.includes(t)),c(()=>e.reduce((e,t)=>{const i=this.forms.get(t);return i&&(e[t]=i.formValuesStateSubject$.value),e},{}))).subscribe(t)}}export{Fe as FormCore,Ie as FormField,ke as FormGroup,ve as TMutationEnum,ne as formatterRegistry,re as maskRegistry,le as registerFormatters,oe as registerMasks,ae as registerValidations,se as validationRegistry};
|