n4s 6.1.12 → 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.
Files changed (42) hide show
  1. package/dist/exports/date.cjs +1 -1
  2. package/dist/exports/date.mjs +1 -1
  3. package/dist/exports/email.cjs +1 -1
  4. package/dist/exports/email.mjs +1 -1
  5. package/dist/exports/isURL.cjs +1 -1
  6. package/dist/exports/isURL.mjs +1 -1
  7. package/dist/{n4s-CoDF5Fg6.cjs → n4s-BTHEz-bJ.cjs} +215 -5
  8. package/dist/n4s-BTHEz-bJ.cjs.map +1 -0
  9. package/dist/{n4s-KWquSyTb.mjs → n4s-BxrvnvKp.mjs} +218 -8
  10. package/dist/n4s-BxrvnvKp.mjs.map +1 -0
  11. package/dist/n4s.cjs +1 -1
  12. package/dist/n4s.mjs +1 -1
  13. package/package.json +5 -1
  14. package/src/eager/eagerTypes.ts +14 -0
  15. package/src/lazy.ts +24 -0
  16. package/src/n4s.ts +5 -0
  17. package/src/rules/schemaRules/__tests__/integrationSchemaRules.types.test.ts +92 -0
  18. package/src/rules/schemaRules/__tests__/isArrayOf.test.ts +37 -1
  19. package/src/rules/schemaRules/__tests__/lazy.test.ts +312 -0
  20. package/src/rules/schemaRules/__tests__/record.test.ts +205 -0
  21. package/src/rules/schemaRules/__tests__/schema.parse.integration.test.ts +79 -0
  22. package/src/rules/schemaRules/__tests__/tuple.test.ts +256 -0
  23. package/src/rules/schemaRules/lazy.ts +48 -0
  24. package/src/rules/schemaRules/record.ts +126 -0
  25. package/src/rules/schemaRules/schemaRules.ts +8 -1
  26. package/src/rules/schemaRules/schemaRulesLazyTypes.ts +21 -0
  27. package/src/rules/schemaRules/tuple.ts +157 -0
  28. package/types/exports/date.d.cts +1 -1
  29. package/types/exports/date.d.mts +1 -1
  30. package/types/n4s.d.cts +21 -2
  31. package/types/n4s.d.cts.map +1 -1
  32. package/types/n4s.d.mts +78 -69
  33. package/types/n4s.d.mts.map +1 -1
  34. package/types/n4s.d.ts +21 -2
  35. package/types/{n4sTypes-Bb1zNxyv.d.mts → n4sTypes-3THfSmAQ.d.mts} +79 -5
  36. package/types/n4sTypes-3THfSmAQ.d.mts.map +1 -0
  37. package/types/{n4sTypes-ChCugpFQ.d.cts → n4sTypes-BSTzXRsU.d.cts} +66 -2
  38. package/types/n4sTypes-BSTzXRsU.d.cts.map +1 -0
  39. package/dist/n4s-CoDF5Fg6.cjs.map +0 -1
  40. package/dist/n4s-KWquSyTb.mjs.map +0 -1
  41. package/types/n4sTypes-Bb1zNxyv.d.mts.map +0 -1
  42. package/types/n4sTypes-ChCugpFQ.d.cts.map +0 -1
@@ -1,4 +1,4 @@
1
- const require_n4s = require('../n4s-CoDF5Fg6.cjs');
1
+ const require_n4s = require('../n4s-BTHEz-bJ.cjs');
2
2
  const require_merge = require('../merge-Co1t_slP.cjs');
3
3
 
4
4
  //#region ../../node_modules/validator/es/lib/toDate.js
@@ -1,4 +1,4 @@
1
- import { t as enforce } from "../n4s-KWquSyTb.mjs";
1
+ import { t as enforce } from "../n4s-BxrvnvKp.mjs";
2
2
  import { n as assertString, t as merge } from "../merge-WxNyiiA8.mjs";
3
3
 
4
4
  //#region ../../node_modules/validator/es/lib/toDate.js
@@ -1,4 +1,4 @@
1
- const require_n4s = require('../n4s-CoDF5Fg6.cjs');
1
+ const require_n4s = require('../n4s-BTHEz-bJ.cjs');
2
2
  const require_merge = require('../merge-Co1t_slP.cjs');
3
3
  const require_isIP = require('../isIP-BBSgBWBl.cjs');
4
4
 
@@ -1,4 +1,4 @@
1
- import { t as enforce } from "../n4s-KWquSyTb.mjs";
1
+ import { t as enforce } from "../n4s-BxrvnvKp.mjs";
2
2
  import { n as assertString, t as merge } from "../merge-WxNyiiA8.mjs";
3
3
  import { n as isFQDN, t as isIP } from "../isIP-CfWqYYV7.mjs";
4
4
 
@@ -1,4 +1,4 @@
1
- const require_n4s = require('../n4s-CoDF5Fg6.cjs');
1
+ const require_n4s = require('../n4s-BTHEz-bJ.cjs');
2
2
  const require_merge = require('../merge-Co1t_slP.cjs');
3
3
  const require_isIP = require('../isIP-BBSgBWBl.cjs');
4
4
 
@@ -1,4 +1,4 @@
1
- import { t as enforce } from "../n4s-KWquSyTb.mjs";
1
+ import { t as enforce } from "../n4s-BxrvnvKp.mjs";
2
2
  import { n as assertString, t as merge } from "../merge-WxNyiiA8.mjs";
3
3
  import { n as isFQDN, t as isIP } from "../isIP-CfWqYYV7.mjs";
4
4
 
@@ -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$3,
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$3(a, b) {
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
- shape: () => shape
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
- shape: schemaAttacher(schemaEvaluators.shape)
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-CoDF5Fg6.cjs.map
2680
+ //# sourceMappingURL=n4s-BTHEz-bJ.cjs.map