unischema 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -2
- package/dist/adapters/backend/index.d.mts +2 -2
- package/dist/adapters/backend/index.d.ts +2 -2
- package/dist/adapters/backend/index.js +11 -11
- package/dist/adapters/backend/index.mjs +8 -8
- package/dist/adapters/frontend/index.d.mts +2 -2
- package/dist/adapters/frontend/index.d.ts +2 -2
- package/dist/adapters/frontend/index.js +10 -10
- package/dist/adapters/frontend/index.mjs +8 -8
- package/dist/{chunk-XGTUU27F.mjs → chunk-5A4ITJVD.mjs} +1 -1
- package/dist/{chunk-ASKTY6EG.js → chunk-66RFUBVU.js} +20 -20
- package/dist/{chunk-KHHJD6QK.mjs → chunk-75YSYC4K.mjs} +1 -1
- package/dist/{chunk-BNIB23NQ.js → chunk-76BBWQDH.js} +13 -13
- package/dist/{chunk-ELL7U7IC.mjs → chunk-7XES4A3M.mjs} +1 -1
- package/dist/{chunk-FRBZHN4K.mjs → chunk-COMVAVFU.mjs} +1 -1
- package/dist/chunk-DT2TQZU7.js +796 -0
- package/dist/{chunk-2JYFKT3R.js → chunk-FPCCH55A.js} +14 -14
- package/dist/{chunk-3FANCMEF.js → chunk-IUXRLMET.js} +34 -34
- package/dist/{chunk-CQYXR2LZ.js → chunk-JEW6U6CB.js} +65 -65
- package/dist/{chunk-XC4DKEXP.mjs → chunk-KZCV5IW4.mjs} +1 -1
- package/dist/{chunk-FKDWSZIV.mjs → chunk-KZZ7NVU3.mjs} +4 -2
- package/dist/{chunk-3TS35CVJ.mjs → chunk-MFEBMQAU.mjs} +341 -40
- package/dist/{chunk-NUW55QTO.js → chunk-OIYG5D2I.js} +4 -2
- package/dist/{chunk-VWP24NYS.mjs → chunk-RW6HDA5H.mjs} +1 -1
- package/dist/{chunk-FZ7K2PC7.js → chunk-TXT36BCE.js} +35 -35
- package/dist/index-C17xs-fU.d.mts +140 -0
- package/dist/index-C17xs-fU.d.ts +140 -0
- package/dist/index.d.mts +26 -8
- package/dist/index.d.ts +26 -8
- package/dist/index.js +262 -25
- package/dist/index.mjs +228 -14
- package/dist/{schema-DYU1zGVm.d.mts → schema-DYE8Wz8X.d.mts} +84 -2
- package/dist/{schema-CpAjXgEF.d.ts → schema-Dtp-joeT.d.ts} +84 -2
- package/dist/validators/array.d.mts +1 -1
- package/dist/validators/array.d.ts +1 -1
- package/dist/validators/array.js +8 -8
- package/dist/validators/array.mjs +2 -2
- package/dist/validators/common.d.mts +1 -1
- package/dist/validators/common.d.ts +1 -1
- package/dist/validators/common.js +7 -7
- package/dist/validators/common.mjs +2 -2
- package/dist/validators/date.d.mts +1 -1
- package/dist/validators/date.d.ts +1 -1
- package/dist/validators/date.js +12 -12
- package/dist/validators/date.mjs +2 -2
- package/dist/validators/index.d.mts +2 -2
- package/dist/validators/index.d.ts +2 -2
- package/dist/validators/index.js +68 -68
- package/dist/validators/index.mjs +7 -7
- package/dist/validators/number.d.mts +1 -1
- package/dist/validators/number.d.ts +1 -1
- package/dist/validators/number.js +13 -13
- package/dist/validators/number.mjs +2 -2
- package/dist/validators/object.d.mts +1 -1
- package/dist/validators/object.d.ts +1 -1
- package/dist/validators/object.js +6 -6
- package/dist/validators/object.mjs +2 -2
- package/dist/validators/string.d.mts +1 -1
- package/dist/validators/string.d.ts +1 -1
- package/dist/validators/string.js +19 -19
- package/dist/validators/string.mjs +2 -2
- package/package.json +47 -5
- package/dist/chunk-BJLVOIAP.js +0 -491
- package/dist/index-BQR7OrY7.d.mts +0 -80
- package/dist/index-BQR7OrY7.d.ts +0 -80
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { strictValidator, omitValidator, pickValidator, keysValidator } from './chunk-
|
|
2
|
-
import { dependsOnValidator, whenValidator, lessThanValidator, greaterThanValidator, notMatchesValidator } from './chunk-
|
|
3
|
-
import { endsWithValidator, startsWithValidator, containsValidator, lengthValidator, jsonValidator, base64Validator, hexValidator, slugValidator, uppercaseValidator, lowercaseValidator, numericValidator, alphanumericValidator, alphaValidator, ipv6Validator, ipAddressValidator, urlValidator, emailValidator } from './chunk-
|
|
4
|
-
import { finiteValidator, safeValidator, oddValidator, evenValidator, multipleOfValidator, divisibleByValidator, betweenValidator as betweenValidator$1, percentageValidator, longitudeValidator, latitudeValidator, portValidator } from './chunk-
|
|
5
|
-
import { betweenValidator, ageValidator, weekendValidator, weekdayValidator, thisYearValidator, thisMonthValidator, thisWeekValidator, tomorrowValidator, yesterdayValidator, todayValidator } from './chunk-
|
|
6
|
-
import { compactValidator, sortedValidator, notEmptyValidator, emptyValidator, excludesValidator, includesValidator } from './chunk-
|
|
1
|
+
import { strictValidator, omitValidator, pickValidator, keysValidator } from './chunk-75YSYC4K.mjs';
|
|
2
|
+
import { dependsOnValidator, whenValidator, lessThanValidator, greaterThanValidator, notMatchesValidator } from './chunk-KZCV5IW4.mjs';
|
|
3
|
+
import { endsWithValidator, startsWithValidator, containsValidator, lengthValidator, jsonValidator, base64Validator, hexValidator, slugValidator, uppercaseValidator, lowercaseValidator, numericValidator, alphanumericValidator, alphaValidator, ipv6Validator, ipAddressValidator, urlValidator, emailValidator } from './chunk-COMVAVFU.mjs';
|
|
4
|
+
import { finiteValidator, safeValidator, oddValidator, evenValidator, multipleOfValidator, divisibleByValidator, betweenValidator as betweenValidator$1, percentageValidator, longitudeValidator, latitudeValidator, portValidator } from './chunk-RW6HDA5H.mjs';
|
|
5
|
+
import { betweenValidator, ageValidator, weekendValidator, weekdayValidator, thisYearValidator, thisMonthValidator, thisWeekValidator, tomorrowValidator, yesterdayValidator, todayValidator } from './chunk-7XES4A3M.mjs';
|
|
6
|
+
import { compactValidator, sortedValidator, notEmptyValidator, emptyValidator, excludesValidator, includesValidator } from './chunk-5A4ITJVD.mjs';
|
|
7
7
|
|
|
8
8
|
// src/core/validators.ts
|
|
9
|
-
function createError(context, code, message, soft = false) {
|
|
9
|
+
function createError(context, code, message, soft = false, received, expected) {
|
|
10
10
|
return {
|
|
11
11
|
field: context.path,
|
|
12
12
|
code,
|
|
13
13
|
message,
|
|
14
|
-
severity: soft ? "soft" : "hard"
|
|
14
|
+
severity: soft ? "soft" : "hard",
|
|
15
|
+
received,
|
|
16
|
+
expected
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
19
|
var typeValidators = {
|
|
@@ -87,7 +89,9 @@ var ruleValidators = {
|
|
|
87
89
|
context,
|
|
88
90
|
"MIN_VALUE",
|
|
89
91
|
message || `Value must be at least ${min}`,
|
|
90
|
-
soft
|
|
92
|
+
soft,
|
|
93
|
+
value,
|
|
94
|
+
{ min }
|
|
91
95
|
);
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -97,7 +101,9 @@ var ruleValidators = {
|
|
|
97
101
|
context,
|
|
98
102
|
"MIN_LENGTH",
|
|
99
103
|
message || `Must be at least ${min} characters`,
|
|
100
|
-
soft
|
|
104
|
+
soft,
|
|
105
|
+
value,
|
|
106
|
+
{ min }
|
|
101
107
|
);
|
|
102
108
|
}
|
|
103
109
|
}
|
|
@@ -107,7 +113,9 @@ var ruleValidators = {
|
|
|
107
113
|
context,
|
|
108
114
|
"MIN_ITEMS",
|
|
109
115
|
message || `Must have at least ${min} items`,
|
|
110
|
-
soft
|
|
116
|
+
soft,
|
|
117
|
+
value,
|
|
118
|
+
{ min }
|
|
111
119
|
);
|
|
112
120
|
}
|
|
113
121
|
}
|
|
@@ -124,7 +132,9 @@ var ruleValidators = {
|
|
|
124
132
|
context,
|
|
125
133
|
"MAX_VALUE",
|
|
126
134
|
message || `Value must be at most ${max}`,
|
|
127
|
-
soft
|
|
135
|
+
soft,
|
|
136
|
+
value,
|
|
137
|
+
{ max }
|
|
128
138
|
);
|
|
129
139
|
}
|
|
130
140
|
}
|
|
@@ -134,7 +144,9 @@ var ruleValidators = {
|
|
|
134
144
|
context,
|
|
135
145
|
"MAX_LENGTH",
|
|
136
146
|
message || `Must be at most ${max} characters`,
|
|
137
|
-
soft
|
|
147
|
+
soft,
|
|
148
|
+
value,
|
|
149
|
+
{ max }
|
|
138
150
|
);
|
|
139
151
|
}
|
|
140
152
|
}
|
|
@@ -144,7 +156,9 @@ var ruleValidators = {
|
|
|
144
156
|
context,
|
|
145
157
|
"MAX_ITEMS",
|
|
146
158
|
message || `Must have at most ${max} items`,
|
|
147
|
-
soft
|
|
159
|
+
soft,
|
|
160
|
+
value,
|
|
161
|
+
{ max }
|
|
148
162
|
);
|
|
149
163
|
}
|
|
150
164
|
}
|
|
@@ -346,21 +360,46 @@ function getTypeValidator(type) {
|
|
|
346
360
|
// src/core/engine.ts
|
|
347
361
|
function validateField(fieldDef, value, context) {
|
|
348
362
|
const errors = [];
|
|
363
|
+
let processedValue = value;
|
|
364
|
+
if (value === null || value === void 0) {
|
|
365
|
+
if (fieldDef.nullish || fieldDef.nullable && value === null) {
|
|
366
|
+
if (!fieldDef.required) {
|
|
367
|
+
return errors;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (fieldDef.preprocess) {
|
|
372
|
+
processedValue = fieldDef.preprocess(value);
|
|
373
|
+
}
|
|
374
|
+
if (fieldDef.transforms && fieldDef.transforms.length > 0) {
|
|
375
|
+
for (const transform of fieldDef.transforms) {
|
|
376
|
+
processedValue = transform(processedValue);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
349
379
|
const typeValidator = getTypeValidator(fieldDef.type);
|
|
350
380
|
if (typeValidator) {
|
|
351
|
-
const typeError = typeValidator(
|
|
381
|
+
const typeError = typeValidator(processedValue, void 0, context);
|
|
352
382
|
if (typeError) {
|
|
353
|
-
errors.push(
|
|
383
|
+
errors.push({
|
|
384
|
+
...typeError,
|
|
385
|
+
path: context.path.split(".").filter((p) => p !== "")
|
|
386
|
+
});
|
|
354
387
|
return errors;
|
|
355
388
|
}
|
|
356
389
|
}
|
|
357
390
|
if (fieldDef.required) {
|
|
358
|
-
const
|
|
359
|
-
if (
|
|
360
|
-
const
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
391
|
+
const isMissing = processedValue === void 0 && !fieldDef.nullish || processedValue === null && !fieldDef.nullable && !fieldDef.nullish || processedValue === "" && !fieldDef.nullable && !fieldDef.nullish || Array.isArray(processedValue) && processedValue.length === 0;
|
|
392
|
+
if (isMissing) {
|
|
393
|
+
const requiredValidator = getValidator("required");
|
|
394
|
+
if (requiredValidator) {
|
|
395
|
+
const error = requiredValidator(processedValue, void 0, context);
|
|
396
|
+
if (error) {
|
|
397
|
+
errors.push({
|
|
398
|
+
...error,
|
|
399
|
+
path: context.path.split(".").filter((p) => p !== "")
|
|
400
|
+
});
|
|
401
|
+
return errors;
|
|
402
|
+
}
|
|
364
403
|
}
|
|
365
404
|
}
|
|
366
405
|
} else if (value === void 0 || value === null || value === "") {
|
|
@@ -377,29 +416,32 @@ function validateField(fieldDef, value, context) {
|
|
|
377
416
|
soft: rule.soft,
|
|
378
417
|
message: rule.message
|
|
379
418
|
};
|
|
380
|
-
const error = validator(
|
|
419
|
+
const error = validator(processedValue, params, context);
|
|
381
420
|
if (error) {
|
|
382
|
-
errors.push(
|
|
421
|
+
errors.push({
|
|
422
|
+
...error,
|
|
423
|
+
path: context.path.split(".").filter((p) => p !== "")
|
|
424
|
+
});
|
|
383
425
|
}
|
|
384
426
|
}
|
|
385
|
-
if (fieldDef.type === "object" && fieldDef.schema &&
|
|
386
|
-
const nestedResult = validateSchema(fieldDef.schema,
|
|
427
|
+
if (fieldDef.type === "object" && fieldDef.schema && processedValue !== null && processedValue !== void 0) {
|
|
428
|
+
const nestedResult = validateSchema(fieldDef.schema, processedValue, context.path, context.root);
|
|
387
429
|
errors.push(...nestedResult.hardErrors, ...nestedResult.softErrors);
|
|
388
430
|
}
|
|
389
|
-
if (fieldDef.type === "array" && fieldDef.items && Array.isArray(
|
|
390
|
-
for (let i = 0; i <
|
|
431
|
+
if (fieldDef.type === "array" && fieldDef.items && Array.isArray(processedValue)) {
|
|
432
|
+
for (let i = 0; i < processedValue.length; i++) {
|
|
391
433
|
const itemContext = {
|
|
392
434
|
path: `${context.path}[${i}]`,
|
|
393
435
|
root: context.root,
|
|
394
|
-
parent:
|
|
436
|
+
parent: processedValue
|
|
395
437
|
};
|
|
396
|
-
const itemErrors = validateField(fieldDef.items,
|
|
438
|
+
const itemErrors = validateField(fieldDef.items, processedValue[i], itemContext);
|
|
397
439
|
errors.push(...itemErrors);
|
|
398
440
|
}
|
|
399
441
|
}
|
|
400
442
|
return errors;
|
|
401
443
|
}
|
|
402
|
-
function validateSchema(schema, data, basePath = "", root) {
|
|
444
|
+
function validateSchema(schema, data, basePath = "", root, options) {
|
|
403
445
|
const hardErrors = [];
|
|
404
446
|
const softErrors = [];
|
|
405
447
|
const rootData = root ?? data;
|
|
@@ -412,28 +454,54 @@ function validateSchema(schema, data, basePath = "", root) {
|
|
|
412
454
|
parent: data
|
|
413
455
|
};
|
|
414
456
|
const errors = validateField(fieldDef, value, context);
|
|
415
|
-
for (
|
|
457
|
+
for (let error of errors) {
|
|
458
|
+
if (options?.errorMap) {
|
|
459
|
+
const mapped = options.errorMap(error);
|
|
460
|
+
if ("message" in mapped && !("field" in mapped)) {
|
|
461
|
+
error = { ...error, message: mapped.message };
|
|
462
|
+
} else {
|
|
463
|
+
error = mapped;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
416
466
|
if (error.severity === "soft") {
|
|
417
467
|
softErrors.push(error);
|
|
418
468
|
} else {
|
|
419
469
|
hardErrors.push(error);
|
|
470
|
+
if (options?.abortEarly) {
|
|
471
|
+
return buildValidationResult(hardErrors, softErrors, options);
|
|
472
|
+
}
|
|
420
473
|
}
|
|
421
474
|
}
|
|
422
475
|
}
|
|
423
|
-
return
|
|
476
|
+
return buildValidationResult(hardErrors, softErrors, options);
|
|
477
|
+
}
|
|
478
|
+
function buildValidationResult(hardErrors, softErrors, options) {
|
|
479
|
+
const result = {
|
|
424
480
|
valid: hardErrors.length === 0,
|
|
425
481
|
hardErrors,
|
|
426
482
|
softErrors
|
|
427
483
|
};
|
|
484
|
+
if (options?.aggregateByField) {
|
|
485
|
+
const errorsByField = {};
|
|
486
|
+
for (const error of [...hardErrors, ...softErrors]) {
|
|
487
|
+
const field = error.field;
|
|
488
|
+
if (!errorsByField[field]) {
|
|
489
|
+
errorsByField[field] = [];
|
|
490
|
+
}
|
|
491
|
+
errorsByField[field].push(error);
|
|
492
|
+
}
|
|
493
|
+
result.errorsByField = errorsByField;
|
|
494
|
+
}
|
|
495
|
+
return result;
|
|
428
496
|
}
|
|
429
|
-
function validate(schema, data) {
|
|
430
|
-
return validateSchema(schema, data);
|
|
497
|
+
function validate(schema, data, options) {
|
|
498
|
+
return validateSchema(schema, data, "", void 0, options);
|
|
431
499
|
}
|
|
432
|
-
function isValid(schema, data) {
|
|
433
|
-
return validate(schema, data).valid;
|
|
500
|
+
function isValid(schema, data, options) {
|
|
501
|
+
return validate(schema, data, options).valid;
|
|
434
502
|
}
|
|
435
|
-
function assertValid(schema, data) {
|
|
436
|
-
const result = validate(schema, data);
|
|
503
|
+
function assertValid(schema, data, options) {
|
|
504
|
+
const result = validate(schema, data, options);
|
|
437
505
|
if (!result.valid) {
|
|
438
506
|
const error = new Error("Validation failed");
|
|
439
507
|
error.errors = result.hardErrors;
|
|
@@ -475,4 +543,237 @@ function errorResult(field, code, message, soft = false) {
|
|
|
475
543
|
};
|
|
476
544
|
}
|
|
477
545
|
|
|
478
|
-
|
|
546
|
+
// src/core/async-engine.ts
|
|
547
|
+
var debounceCache = /* @__PURE__ */ new Map();
|
|
548
|
+
function createDebouncedValidation(key, validate2, value, context, message, soft = false, timeout = 5e3, debounceMs = 300) {
|
|
549
|
+
const cache = debounceCache.get(key) || {};
|
|
550
|
+
if (cache.timeoutId !== void 0) {
|
|
551
|
+
clearTimeout(cache.timeoutId);
|
|
552
|
+
}
|
|
553
|
+
if (cache.reject) {
|
|
554
|
+
cache.reject(new Error("Validation cancelled - new input received"));
|
|
555
|
+
}
|
|
556
|
+
return new Promise((resolve, reject) => {
|
|
557
|
+
cache.resolve = resolve;
|
|
558
|
+
cache.reject = reject;
|
|
559
|
+
cache.timeoutId = setTimeout(async () => {
|
|
560
|
+
try {
|
|
561
|
+
const result = await executeAsyncValidator(validate2, value, context, message, soft, timeout);
|
|
562
|
+
resolve(result);
|
|
563
|
+
debounceCache.delete(key);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
reject(error);
|
|
566
|
+
debounceCache.delete(key);
|
|
567
|
+
}
|
|
568
|
+
}, debounceMs);
|
|
569
|
+
debounceCache.set(key, cache);
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
function withTimeout(promise, timeoutMs, errorMessage) {
|
|
573
|
+
return Promise.race([
|
|
574
|
+
promise,
|
|
575
|
+
new Promise(
|
|
576
|
+
(_, reject) => setTimeout(() => reject(new Error(errorMessage)), timeoutMs)
|
|
577
|
+
)
|
|
578
|
+
]);
|
|
579
|
+
}
|
|
580
|
+
async function executeAsyncValidator(validate2, value, context, message, soft = false, timeout = 5e3) {
|
|
581
|
+
try {
|
|
582
|
+
const result = await withTimeout(
|
|
583
|
+
validate2(value),
|
|
584
|
+
timeout,
|
|
585
|
+
`Async validation timed out after ${timeout}ms`
|
|
586
|
+
);
|
|
587
|
+
if (typeof result === "boolean") {
|
|
588
|
+
if (result) {
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
field: context.path,
|
|
593
|
+
path: context.path.split("."),
|
|
594
|
+
code: "ASYNC_VALIDATION_FAILED",
|
|
595
|
+
message: message || "Async validation failed",
|
|
596
|
+
severity: soft ? "soft" : "hard",
|
|
597
|
+
received: value
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
if (!result.valid) {
|
|
601
|
+
return {
|
|
602
|
+
field: context.path,
|
|
603
|
+
path: context.path.split("."),
|
|
604
|
+
code: "ASYNC_VALIDATION_FAILED",
|
|
605
|
+
message: result.message || message || "Async validation failed",
|
|
606
|
+
severity: soft ? "soft" : "hard",
|
|
607
|
+
received: value
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
return null;
|
|
611
|
+
} catch (error) {
|
|
612
|
+
return {
|
|
613
|
+
field: context.path,
|
|
614
|
+
path: context.path.split("."),
|
|
615
|
+
code: "ASYNC_VALIDATION_ERROR",
|
|
616
|
+
message: error instanceof Error ? error.message : "Async validation error",
|
|
617
|
+
severity: soft ? "soft" : "hard",
|
|
618
|
+
received: value
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
async function validateFieldAsync(fieldDef, value, context) {
|
|
623
|
+
const errors = [];
|
|
624
|
+
const asyncValidations = [];
|
|
625
|
+
const typeValidator = getTypeValidator(fieldDef.type);
|
|
626
|
+
if (typeValidator) {
|
|
627
|
+
const typeError = typeValidator(value, void 0, context);
|
|
628
|
+
if (typeError) {
|
|
629
|
+
errors.push({
|
|
630
|
+
...typeError,
|
|
631
|
+
path: context.path.split(".")
|
|
632
|
+
});
|
|
633
|
+
return errors;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (fieldDef.required) {
|
|
637
|
+
const requiredValidator = getValidator("required");
|
|
638
|
+
if (requiredValidator) {
|
|
639
|
+
const error = requiredValidator(value, void 0, context);
|
|
640
|
+
if (error) {
|
|
641
|
+
errors.push({
|
|
642
|
+
...error,
|
|
643
|
+
path: context.path.split(".")
|
|
644
|
+
});
|
|
645
|
+
return errors;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
} else if (value === void 0 || value === null || value === "") {
|
|
649
|
+
return errors;
|
|
650
|
+
}
|
|
651
|
+
for (const rule of fieldDef.rules) {
|
|
652
|
+
if (rule.async && rule.type === "refineAsync") {
|
|
653
|
+
const validate2 = rule.params?.validate;
|
|
654
|
+
if (!validate2) continue;
|
|
655
|
+
if (rule.debounce && rule.debounce > 0) {
|
|
656
|
+
const key = `${context.path}_${rule.type}`;
|
|
657
|
+
asyncValidations.push(
|
|
658
|
+
createDebouncedValidation(
|
|
659
|
+
key,
|
|
660
|
+
validate2,
|
|
661
|
+
value,
|
|
662
|
+
context,
|
|
663
|
+
rule.message,
|
|
664
|
+
rule.soft,
|
|
665
|
+
rule.timeout || 5e3,
|
|
666
|
+
rule.debounce
|
|
667
|
+
)
|
|
668
|
+
);
|
|
669
|
+
} else {
|
|
670
|
+
asyncValidations.push(
|
|
671
|
+
executeAsyncValidator(
|
|
672
|
+
validate2,
|
|
673
|
+
value,
|
|
674
|
+
context,
|
|
675
|
+
rule.message,
|
|
676
|
+
rule.soft,
|
|
677
|
+
rule.timeout || 5e3
|
|
678
|
+
)
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
} else {
|
|
682
|
+
const validator = getValidator(rule.type);
|
|
683
|
+
if (!validator) {
|
|
684
|
+
console.warn(`Unknown validator: ${rule.type}`);
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
const params = {
|
|
688
|
+
...rule.params,
|
|
689
|
+
soft: rule.soft,
|
|
690
|
+
message: rule.message
|
|
691
|
+
};
|
|
692
|
+
const error = validator(value, params, context);
|
|
693
|
+
if (error) {
|
|
694
|
+
errors.push({
|
|
695
|
+
...error,
|
|
696
|
+
path: context.path.split(".")
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const asyncErrors = await Promise.all(asyncValidations);
|
|
702
|
+
for (const error of asyncErrors) {
|
|
703
|
+
if (error) {
|
|
704
|
+
errors.push(error);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (fieldDef.type === "object" && fieldDef.schema && value !== null && value !== void 0) {
|
|
708
|
+
const nestedResult = await validateSchemaAsync(
|
|
709
|
+
fieldDef.schema,
|
|
710
|
+
value,
|
|
711
|
+
context.path,
|
|
712
|
+
context.root
|
|
713
|
+
);
|
|
714
|
+
errors.push(...nestedResult.hardErrors, ...nestedResult.softErrors);
|
|
715
|
+
}
|
|
716
|
+
if (fieldDef.type === "array" && fieldDef.items && Array.isArray(value)) {
|
|
717
|
+
const itemValidations = value.map(async (item, i) => {
|
|
718
|
+
const itemContext = {
|
|
719
|
+
path: `${context.path}[${i}]`,
|
|
720
|
+
root: context.root,
|
|
721
|
+
parent: value
|
|
722
|
+
};
|
|
723
|
+
return validateFieldAsync(fieldDef.items, item, itemContext);
|
|
724
|
+
});
|
|
725
|
+
const itemResults = await Promise.all(itemValidations);
|
|
726
|
+
for (const itemErrors of itemResults) {
|
|
727
|
+
errors.push(...itemErrors);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return errors;
|
|
731
|
+
}
|
|
732
|
+
async function validateSchemaAsync(schema, data, basePath = "", root) {
|
|
733
|
+
const hardErrors = [];
|
|
734
|
+
const softErrors = [];
|
|
735
|
+
const rootData = root ?? data;
|
|
736
|
+
const fieldValidations = Object.entries(schema.fields).map(async ([fieldName, fieldDef]) => {
|
|
737
|
+
const value = data[fieldName];
|
|
738
|
+
const path = basePath ? `${basePath}.${fieldName}` : fieldName;
|
|
739
|
+
const context = {
|
|
740
|
+
path,
|
|
741
|
+
root: rootData,
|
|
742
|
+
parent: data
|
|
743
|
+
};
|
|
744
|
+
return validateFieldAsync(fieldDef, value, context);
|
|
745
|
+
});
|
|
746
|
+
const results = await Promise.all(fieldValidations);
|
|
747
|
+
for (const errors of results) {
|
|
748
|
+
for (const error of errors) {
|
|
749
|
+
if (error.severity === "soft") {
|
|
750
|
+
softErrors.push(error);
|
|
751
|
+
} else {
|
|
752
|
+
hardErrors.push(error);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return {
|
|
757
|
+
valid: hardErrors.length === 0,
|
|
758
|
+
hardErrors,
|
|
759
|
+
softErrors
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
async function validateAsync(schema, data) {
|
|
763
|
+
return validateSchemaAsync(schema, data);
|
|
764
|
+
}
|
|
765
|
+
async function isValidAsync(schema, data) {
|
|
766
|
+
const result = await validateAsync(schema, data);
|
|
767
|
+
return result.valid;
|
|
768
|
+
}
|
|
769
|
+
async function assertValidAsync(schema, data) {
|
|
770
|
+
const result = await validateAsync(schema, data);
|
|
771
|
+
if (!result.valid) {
|
|
772
|
+
const error = new Error("Async validation failed");
|
|
773
|
+
error.errors = result.hardErrors;
|
|
774
|
+
throw error;
|
|
775
|
+
}
|
|
776
|
+
return data;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export { assertValid, assertValidAsync, errorResult, getTypeValidator, getValidator, isValid, isValidAsync, mergeResults, registerValidator, ruleValidators, typeValidators, validResult, validate, validateAsync, validateSchema, validateSchemaAsync };
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/validators/utils.ts
|
|
4
|
-
function createError(context, code, message, soft = false) {
|
|
4
|
+
function createError(context, code, message, soft = false, received, expected) {
|
|
5
5
|
return {
|
|
6
6
|
field: context.path,
|
|
7
7
|
code,
|
|
8
8
|
message,
|
|
9
|
-
severity: soft ? "soft" : "hard"
|
|
9
|
+
severity: soft ? "soft" : "hard",
|
|
10
|
+
received,
|
|
11
|
+
expected
|
|
10
12
|
};
|
|
11
13
|
}
|
|
12
14
|
function isEmpty(value) {
|