n4s 6.1.11 → 6.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/dist/exports/date.cjs +1 -1
- package/dist/exports/date.mjs +1 -1
- package/dist/exports/email.cjs +1 -1
- package/dist/exports/email.mjs +1 -1
- package/dist/exports/isURL.cjs +1 -1
- package/dist/exports/isURL.mjs +1 -1
- package/dist/{n4s-CoDF5Fg6.cjs → n4s-BTHEz-bJ.cjs} +215 -5
- package/dist/n4s-BTHEz-bJ.cjs.map +1 -0
- package/dist/{n4s-KWquSyTb.mjs → n4s-BxrvnvKp.mjs} +218 -8
- package/dist/n4s-BxrvnvKp.mjs.map +1 -0
- package/dist/n4s.cjs +1 -1
- package/dist/n4s.mjs +1 -1
- package/package.json +7 -3
- package/src/eager/eagerTypes.ts +14 -0
- package/src/lazy.ts +24 -0
- package/src/n4s.ts +5 -0
- package/src/rules/schemaRules/__tests__/integrationSchemaRules.types.test.ts +92 -0
- package/src/rules/schemaRules/__tests__/isArrayOf.test.ts +37 -1
- package/src/rules/schemaRules/__tests__/lazy.test.ts +312 -0
- package/src/rules/schemaRules/__tests__/record.test.ts +205 -0
- package/src/rules/schemaRules/__tests__/schema.parse.integration.test.ts +79 -0
- package/src/rules/schemaRules/__tests__/tuple.test.ts +256 -0
- package/src/rules/schemaRules/lazy.ts +48 -0
- package/src/rules/schemaRules/record.ts +126 -0
- package/src/rules/schemaRules/schemaRules.ts +8 -1
- package/src/rules/schemaRules/schemaRulesLazyTypes.ts +21 -0
- package/src/rules/schemaRules/tuple.ts +157 -0
- package/types/exports/date.d.cts +1 -1
- package/types/exports/date.d.mts +1 -1
- package/types/n4s.d.cts +21 -2
- package/types/n4s.d.cts.map +1 -1
- package/types/n4s.d.mts +78 -69
- package/types/n4s.d.mts.map +1 -1
- package/types/n4s.d.ts +21 -2
- package/types/{n4sTypes-Bb1zNxyv.d.mts → n4sTypes-3THfSmAQ.d.mts} +79 -5
- package/types/n4sTypes-3THfSmAQ.d.mts.map +1 -0
- package/types/{n4sTypes-ChCugpFQ.d.cts → n4sTypes-BSTzXRsU.d.cts} +66 -2
- package/types/n4sTypes-BSTzXRsU.d.cts.map +1 -0
- package/dist/n4s-CoDF5Fg6.cjs.map +0 -1
- package/dist/n4s-KWquSyTb.mjs.map +0 -1
- package/types/n4sTypes-Bb1zNxyv.d.mts.map +0 -1
- package/types/n4sTypes-ChCugpFQ.d.cts.map +0 -1
package/dist/exports/date.cjs
CHANGED
package/dist/exports/date.mjs
CHANGED
package/dist/exports/email.cjs
CHANGED
package/dist/exports/email.mjs
CHANGED
package/dist/exports/isURL.cjs
CHANGED
package/dist/exports/isURL.mjs
CHANGED
|
@@ -204,7 +204,7 @@ function isArray(value) {
|
|
|
204
204
|
//#region src/rules/commonComparison.ts
|
|
205
205
|
var commonComparison_exports = /* @__PURE__ */ __export({
|
|
206
206
|
equals: () => equals,
|
|
207
|
-
greaterThan: () => greaterThan$
|
|
207
|
+
greaterThan: () => greaterThan$4,
|
|
208
208
|
greaterThanOrEquals: () => greaterThanOrEquals$1,
|
|
209
209
|
lessThan: () => lessThan$1,
|
|
210
210
|
lessThanOrEquals: () => lessThanOrEquals$1,
|
|
@@ -219,7 +219,7 @@ function equals(a, b) {
|
|
|
219
219
|
function notEquals(a, b) {
|
|
220
220
|
return a !== b;
|
|
221
221
|
}
|
|
222
|
-
function greaterThan$
|
|
222
|
+
function greaterThan$4(a, b) {
|
|
223
223
|
return a > b;
|
|
224
224
|
}
|
|
225
225
|
function greaterThanOrEquals$1(a, b) {
|
|
@@ -1575,16 +1575,177 @@ function shape(value, schema) {
|
|
|
1575
1575
|
return RuleRunReturn.Passing(baseRes.type);
|
|
1576
1576
|
}
|
|
1577
1577
|
|
|
1578
|
+
//#endregion
|
|
1579
|
+
//#region src/rules/schemaRules/record.ts
|
|
1580
|
+
/**
|
|
1581
|
+
* Validates that an object's dynamic keys and/or values match provided rules.
|
|
1582
|
+
* Like TypeScript's Record<K, V>, it checks elements against shape rules.
|
|
1583
|
+
*
|
|
1584
|
+
* @param value - The object to validate
|
|
1585
|
+
* @param arg1 - Either the key rule (if arg2 is present) or the value rule
|
|
1586
|
+
* @param arg2 - The value rule (if arg1 is the key rule)
|
|
1587
|
+
* @returns RuleRunReturn indicating success or failure
|
|
1588
|
+
*/
|
|
1589
|
+
function record(value, arg1, arg2) {
|
|
1590
|
+
if (!(0, vest_utils.isObject)(value) || Array.isArray(value)) return RuleRunReturn.Failing(value);
|
|
1591
|
+
const rules = parseRules(arg1, arg2);
|
|
1592
|
+
const dangerousKey = findDangerousOwnKey(value);
|
|
1593
|
+
if (dangerousKey) return createRecordFailure(value, dangerousKey, RuleRunReturn.Failing(value));
|
|
1594
|
+
const parsedValue = safeShallowCopy(value);
|
|
1595
|
+
return (0, vest_utils.mapFirst)(ownKeys(value), (key, breakout) => {
|
|
1596
|
+
const errorRes = evaluateRecordEntry(key, value, rules, parsedValue);
|
|
1597
|
+
if (errorRes) breakout(true, errorRes);
|
|
1598
|
+
}) || RuleRunReturn.Passing(parsedValue);
|
|
1599
|
+
}
|
|
1600
|
+
function parseRules(arg1, arg2) {
|
|
1601
|
+
if (arg2 !== void 0) return {
|
|
1602
|
+
keyRule: arg1,
|
|
1603
|
+
valueRule: arg2
|
|
1604
|
+
};
|
|
1605
|
+
return {
|
|
1606
|
+
keyRule: void 0,
|
|
1607
|
+
valueRule: arg1
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
function validateKey(key, keyRule) {
|
|
1611
|
+
return ctx.run({
|
|
1612
|
+
value: key,
|
|
1613
|
+
set: true
|
|
1614
|
+
}, () => keyRule.run(key));
|
|
1615
|
+
}
|
|
1616
|
+
function evaluateRecordEntry(key, value, rules, parsedValue) {
|
|
1617
|
+
if (rules.keyRule) {
|
|
1618
|
+
const keyRes = validateKey(key, rules.keyRule);
|
|
1619
|
+
if (!keyRes.pass) return createRecordFailure(value, key, keyRes);
|
|
1620
|
+
if (keyRes.type !== key) {
|
|
1621
|
+
delete parsedValue[key];
|
|
1622
|
+
key = keyRes.type;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
const valRes = ctx.run({
|
|
1626
|
+
value: value[key],
|
|
1627
|
+
set: true,
|
|
1628
|
+
meta: { key }
|
|
1629
|
+
}, () => rules.valueRule.run(value[key]));
|
|
1630
|
+
if (!valRes.pass) return createRecordFailure(value, key, valRes);
|
|
1631
|
+
parsedValue[key] = valRes.type;
|
|
1632
|
+
}
|
|
1633
|
+
function createRecordFailure(value, key, ruleRes) {
|
|
1634
|
+
const currentPath = ruleRes.path || [];
|
|
1635
|
+
const newRes = RuleRunReturn.Failing(value, ruleRes.message);
|
|
1636
|
+
newRes.path = [key, ...currentPath];
|
|
1637
|
+
return newRes;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
//#endregion
|
|
1641
|
+
//#region src/rules/schemaRules/tuple.ts
|
|
1642
|
+
/**
|
|
1643
|
+
* Validates that a value is a fixed-length array (tuple) where each position
|
|
1644
|
+
* matches the corresponding rule. Enforces exact length unless trailing
|
|
1645
|
+
* elements use enforce.optional().
|
|
1646
|
+
*
|
|
1647
|
+
* Parsed values are propagated: if a rule transforms its input (e.g. toNumber),
|
|
1648
|
+
* the parsed tuple returned via `.parse()` carries the transformed values.
|
|
1649
|
+
*
|
|
1650
|
+
* @param value - The array to validate
|
|
1651
|
+
* @param rules - One RuleInstance per tuple position
|
|
1652
|
+
* @returns RuleRunReturn indicating success or failure, with `.type` holding
|
|
1653
|
+
* the parsed tuple on success
|
|
1654
|
+
*
|
|
1655
|
+
* @example
|
|
1656
|
+
* ```typescript
|
|
1657
|
+
* // Eager API
|
|
1658
|
+
* enforce(['hello', 42]).tuple(enforce.isString(), enforce.isNumber());
|
|
1659
|
+
*
|
|
1660
|
+
* // Lazy API
|
|
1661
|
+
* const coordSchema = enforce.tuple(enforce.isNumber(), enforce.isNumber());
|
|
1662
|
+
* coordSchema.test([40.7, -74.0]); // true
|
|
1663
|
+
* coordSchema.test([40.7]); // false — too few
|
|
1664
|
+
* coordSchema.test([40.7, -74, 0]);// false — too many
|
|
1665
|
+
* ```
|
|
1666
|
+
*/
|
|
1667
|
+
function tuple(value, ...rules) {
|
|
1668
|
+
if (!Array.isArray(value)) return RuleRunReturn.Failing(value);
|
|
1669
|
+
if ((0, vest_utils.greaterThan)(countRequired(rules), value.length) || (0, vest_utils.longerThan)(value, rules.length)) return RuleRunReturn.Failing(value);
|
|
1670
|
+
return validateElements(value, rules);
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Counts the number of required (non-optional) leading positions by scanning
|
|
1674
|
+
* backwards from the end of the rules array. Stops at the first non-optional
|
|
1675
|
+
* rule, so only *trailing* optionals reduce the required count.
|
|
1676
|
+
*/
|
|
1677
|
+
function countRequired(rules) {
|
|
1678
|
+
let count = rules.length;
|
|
1679
|
+
for (let i = rules.length - 1; i >= 0; i--) if (isOptionalRule(rules[i])) count = i;
|
|
1680
|
+
else break;
|
|
1681
|
+
return count;
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Iterates over each rule position, validates the corresponding array element,
|
|
1685
|
+
* and collects parsed output values. Returns early on the first failing element
|
|
1686
|
+
* with an index-based error path.
|
|
1687
|
+
*/
|
|
1688
|
+
function validateElements(value, rules) {
|
|
1689
|
+
const parsedTuple = [];
|
|
1690
|
+
for (let i = 0; i < rules.length; i++) {
|
|
1691
|
+
if (isBeyondArrayEnd(value, i, rules[i])) continue;
|
|
1692
|
+
const res = runElementRule(value[i], rules[i], i);
|
|
1693
|
+
if (!res.pass) return elementFailure(value, res, i);
|
|
1694
|
+
parsedTuple.push(res.type ?? value[i]);
|
|
1695
|
+
}
|
|
1696
|
+
return RuleRunReturn.Passing(parsedTuple);
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Checks whether the given index is past the array's actual length
|
|
1700
|
+
* and the corresponding rule is optional, meaning it can be skipped.
|
|
1701
|
+
*/
|
|
1702
|
+
function isBeyondArrayEnd(value, index, rule) {
|
|
1703
|
+
return index >= value.length && isOptionalRule(rule);
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Runs a single element's rule within an enforce context that carries
|
|
1707
|
+
* the element value and its positional index as metadata.
|
|
1708
|
+
*/
|
|
1709
|
+
function runElementRule(item, rule, index) {
|
|
1710
|
+
return ctx.run({
|
|
1711
|
+
value: item,
|
|
1712
|
+
set: true,
|
|
1713
|
+
meta: { index }
|
|
1714
|
+
}, () => rule.run(item));
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Builds a failing RuleRunReturn with an error path that includes the
|
|
1718
|
+
* tuple index, prepended to any nested path from the inner rule failure.
|
|
1719
|
+
* For example, a shape failure at index 1 on key "id" yields path ["1", "id"].
|
|
1720
|
+
*/
|
|
1721
|
+
function elementFailure(value, res, index) {
|
|
1722
|
+
const failure = RuleRunReturn.Failing(value, res.message);
|
|
1723
|
+
failure.path = [index.toString(), ...res.path || []];
|
|
1724
|
+
return failure;
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Determines whether a rule is optional by testing if it passes with undefined.
|
|
1728
|
+
* This mirrors how shape/loose detect optional fields — a rule wrapping
|
|
1729
|
+
* enforce.optional() will pass for undefined, while required rules will not.
|
|
1730
|
+
*/
|
|
1731
|
+
function isOptionalRule(rule) {
|
|
1732
|
+
if (!rule || !(0, vest_utils.isFunction)(rule.test)) return false;
|
|
1733
|
+
return rule.test(void 0);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1578
1736
|
//#endregion
|
|
1579
1737
|
//#region src/rules/schemaRules/schemaRules.ts
|
|
1580
1738
|
var schemaRules_exports = /* @__PURE__ */ __export({
|
|
1581
1739
|
isArrayOf: () => isArrayOf,
|
|
1740
|
+
list: () => isArrayOf,
|
|
1582
1741
|
loose: () => loose,
|
|
1583
1742
|
omit: () => omit,
|
|
1584
1743
|
optional: () => optional,
|
|
1585
1744
|
partial: () => partial,
|
|
1586
1745
|
pick: () => pick,
|
|
1587
|
-
|
|
1746
|
+
record: () => record,
|
|
1747
|
+
shape: () => shape,
|
|
1748
|
+
tuple: () => tuple
|
|
1588
1749
|
});
|
|
1589
1750
|
|
|
1590
1751
|
//#endregion
|
|
@@ -2229,6 +2390,44 @@ const typeRules = {
|
|
|
2229
2390
|
isUndefined: () => addToChain({}, isUndefined)
|
|
2230
2391
|
};
|
|
2231
2392
|
|
|
2393
|
+
//#endregion
|
|
2394
|
+
//#region src/rules/schemaRules/lazy.ts
|
|
2395
|
+
/**
|
|
2396
|
+
* Creates a lazy schema wrapper for recursive/self-referencing schemas.
|
|
2397
|
+
* The factory function is called on first validation and cached.
|
|
2398
|
+
*
|
|
2399
|
+
* @param factory - A function that returns the RuleInstance to delegate to
|
|
2400
|
+
* @returns A RuleInstance that defers schema resolution to validation time
|
|
2401
|
+
*
|
|
2402
|
+
* @example
|
|
2403
|
+
* ```typescript
|
|
2404
|
+
* type Category = { name: string; children: Category[] };
|
|
2405
|
+
*
|
|
2406
|
+
* const categorySchema = enforce.shape({
|
|
2407
|
+
* name: enforce.isString(),
|
|
2408
|
+
* children: enforce.isArrayOf(enforce.lazy(() => categorySchema)),
|
|
2409
|
+
* });
|
|
2410
|
+
*
|
|
2411
|
+
* categorySchema.test({
|
|
2412
|
+
* name: 'Root',
|
|
2413
|
+
* children: [
|
|
2414
|
+
* { name: 'Child', children: [] },
|
|
2415
|
+
* ],
|
|
2416
|
+
* }); // true
|
|
2417
|
+
* ```
|
|
2418
|
+
*/
|
|
2419
|
+
function lazy(factory) {
|
|
2420
|
+
let cached = null;
|
|
2421
|
+
const resolve = () => {
|
|
2422
|
+
if (!cached) cached = factory();
|
|
2423
|
+
return cached;
|
|
2424
|
+
};
|
|
2425
|
+
return addToChain({}, (value) => {
|
|
2426
|
+
const result = ctx.run({ value }, () => resolve().run(value));
|
|
2427
|
+
return RuleRunReturn.create(result, value);
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2232
2431
|
//#endregion
|
|
2233
2432
|
//#region src/lazy.ts
|
|
2234
2433
|
const schemaModifiers = adaptDynamicRules({
|
|
@@ -2241,6 +2440,7 @@ const schemaEvaluators = adaptDynamicRules({
|
|
|
2241
2440
|
shape,
|
|
2242
2441
|
loose
|
|
2243
2442
|
});
|
|
2443
|
+
const recordEvaluators = adaptDynamicRules({ record });
|
|
2244
2444
|
/**
|
|
2245
2445
|
* Wraps a lazy schema evaluator so the resulting RuleInstance carries
|
|
2246
2446
|
* a `__schema` reference to the original schema definition.
|
|
@@ -2258,8 +2458,18 @@ const schemaRulesWithArrayChaining = {
|
|
|
2258
2458
|
const result = ctx.run({ value }, () => isArrayOf(value, ...rules));
|
|
2259
2459
|
return RuleRunReturn.create(result, value);
|
|
2260
2460
|
}),
|
|
2461
|
+
lazy,
|
|
2462
|
+
list: (...rules) => addToChain(arrayRules_exports, (value) => {
|
|
2463
|
+
const result = ctx.run({ value }, () => isArrayOf(value, ...rules));
|
|
2464
|
+
return RuleRunReturn.create(result, value);
|
|
2465
|
+
}),
|
|
2261
2466
|
loose: schemaAttacher(schemaEvaluators.loose),
|
|
2262
|
-
|
|
2467
|
+
record: recordEvaluators.record,
|
|
2468
|
+
shape: schemaAttacher(schemaEvaluators.shape),
|
|
2469
|
+
tuple: (...rules) => addToChain(arrayRules_exports, (value) => {
|
|
2470
|
+
const result = ctx.run({ value }, () => tuple(value, ...rules));
|
|
2471
|
+
return RuleRunReturn.create(result, value);
|
|
2472
|
+
})
|
|
2263
2473
|
};
|
|
2264
2474
|
const baseEnforceLazy = {
|
|
2265
2475
|
...adaptDynamicRules(compoundRules_exports),
|
|
@@ -2467,4 +2677,4 @@ Object.defineProperty(exports, 'enforce', {
|
|
|
2467
2677
|
return enforce;
|
|
2468
2678
|
}
|
|
2469
2679
|
});
|
|
2470
|
-
//# sourceMappingURL=n4s-
|
|
2680
|
+
//# sourceMappingURL=n4s-BTHEz-bJ.cjs.map
|