ts-fortress 11.0.2 → 11.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 (105) hide show
  1. package/README.md +11 -8
  2. package/dist/brand/brand.mjs +1 -0
  3. package/dist/brand/brand.mjs.map +1 -1
  4. package/dist/compose/intersection.mjs +1 -0
  5. package/dist/compose/intersection.mjs.map +1 -1
  6. package/dist/compose/union.d.mts.map +1 -1
  7. package/dist/compose/union.mjs +94 -17
  8. package/dist/compose/union.mjs.map +1 -1
  9. package/dist/entry-point.mjs +3 -1
  10. package/dist/entry-point.mjs.map +1 -1
  11. package/dist/enum/index.d.mts +2 -0
  12. package/dist/enum/index.d.mts.map +1 -1
  13. package/dist/enum/index.mjs +2 -0
  14. package/dist/enum/index.mjs.map +1 -1
  15. package/dist/enum/int-range-inclusive.d.mts +13 -0
  16. package/dist/enum/int-range-inclusive.d.mts.map +1 -0
  17. package/dist/enum/int-range-inclusive.mjs +61 -0
  18. package/dist/enum/int-range-inclusive.mjs.map +1 -0
  19. package/dist/enum/int-range.d.mts +7 -8
  20. package/dist/enum/int-range.d.mts.map +1 -1
  21. package/dist/enum/int-range.mjs +17 -7
  22. package/dist/enum/int-range.mjs.map +1 -1
  23. package/dist/enum/uint-range-inclusive.d.mts +13 -0
  24. package/dist/enum/uint-range-inclusive.d.mts.map +1 -0
  25. package/dist/enum/uint-range-inclusive.mjs +61 -0
  26. package/dist/enum/uint-range-inclusive.mjs.map +1 -0
  27. package/dist/enum/uint-range.d.mts +6 -3
  28. package/dist/enum/uint-range.d.mts.map +1 -1
  29. package/dist/enum/uint-range.mjs +17 -7
  30. package/dist/enum/uint-range.mjs.map +1 -1
  31. package/dist/index.mjs +4 -2
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/other-types/literal.mjs +1 -0
  34. package/dist/other-types/literal.mjs.map +1 -1
  35. package/dist/other-types/recursion.mjs +1 -0
  36. package/dist/other-types/recursion.mjs.map +1 -1
  37. package/dist/other-types/unknown.mjs +1 -0
  38. package/dist/other-types/unknown.mjs.map +1 -1
  39. package/dist/predefined/int8.d.mts.map +1 -1
  40. package/dist/predefined/int8.mjs +1 -5
  41. package/dist/predefined/int8.mjs.map +1 -1
  42. package/dist/predefined/json.mjs +1 -1
  43. package/dist/predefined/nullable.mjs +1 -1
  44. package/dist/predefined/uint8.d.mts.map +1 -1
  45. package/dist/predefined/uint8.mjs +1 -5
  46. package/dist/predefined/uint8.mjs.map +1 -1
  47. package/dist/primitives/bigint.mjs +1 -1
  48. package/dist/primitives/boolean.mjs +1 -0
  49. package/dist/primitives/boolean.mjs.map +1 -1
  50. package/dist/primitives/null.mjs +1 -0
  51. package/dist/primitives/null.mjs.map +1 -1
  52. package/dist/primitives/number.mjs +1 -1
  53. package/dist/primitives/string.mjs +1 -1
  54. package/dist/primitives/symbol.mjs +1 -0
  55. package/dist/primitives/symbol.mjs.map +1 -1
  56. package/dist/primitives/undefined.mjs +1 -0
  57. package/dist/primitives/undefined.mjs.map +1 -1
  58. package/dist/record/at.mjs +1 -1
  59. package/dist/record/merge-records.mjs +1 -1
  60. package/dist/record/omit.mjs +1 -0
  61. package/dist/record/omit.mjs.map +1 -1
  62. package/dist/record/partial.mjs +1 -0
  63. package/dist/record/partial.mjs.map +1 -1
  64. package/dist/record/pick.mjs +1 -0
  65. package/dist/record/pick.mjs.map +1 -1
  66. package/dist/record/required.mjs +1 -0
  67. package/dist/record/required.mjs.map +1 -1
  68. package/dist/record/valueof.mjs +1 -1
  69. package/dist/type.d.mts +17 -0
  70. package/dist/type.d.mts.map +1 -1
  71. package/dist/type.mjs +3 -1
  72. package/dist/type.mjs.map +1 -1
  73. package/dist/utils/index.mjs +1 -1
  74. package/dist/utils/validation-error.d.mts +35 -0
  75. package/dist/utils/validation-error.d.mts.map +1 -1
  76. package/dist/utils/validation-error.mjs +80 -51
  77. package/dist/utils/validation-error.mjs.map +1 -1
  78. package/package.json +35 -92
  79. package/src/brand/branded-string.test.mts +1 -1
  80. package/src/compose/intersection.test.mts +2 -2
  81. package/src/compose/union-closest-member.test.mts +328 -0
  82. package/src/compose/union-error-message.test.mts +173 -0
  83. package/src/compose/union-mixed.test.mts +1 -1
  84. package/src/compose/union-nested-record.test.mts +7 -4
  85. package/src/compose/union-nested-union.test.mts +131 -0
  86. package/src/compose/union-primitive-literal.test.mts +1 -1
  87. package/src/compose/union-records.test.mts +7 -6
  88. package/src/compose/union.mts +192 -21
  89. package/src/enum/index.mts +2 -0
  90. package/src/enum/int-range-inclusive.mts +106 -0
  91. package/src/enum/int-range-inclusive.test.mts +112 -0
  92. package/src/enum/int-range.mts +48 -71
  93. package/src/enum/int-range.test.mts +1 -3
  94. package/src/enum/uint-range-inclusive.mts +106 -0
  95. package/src/enum/uint-range-inclusive.test.mts +159 -0
  96. package/src/enum/uint-range.mts +50 -15
  97. package/src/enum/uint-range.test.mts +1 -3
  98. package/src/other-types/set.test.mts +2 -2
  99. package/src/predefined/int8.mts +1 -5
  100. package/src/predefined/uint8.mts +1 -5
  101. package/src/primitives/undefined.test.mts +2 -2
  102. package/src/type.mts +24 -0
  103. package/src/utils/validation-error.formatting.test.mts +395 -85
  104. package/src/utils/validation-error.mts +223 -61
  105. package/src/utils/validation-error.test.mts +1 -1
package/README.md CHANGED
@@ -909,14 +909,15 @@ const ColorEnum = t.enumType(['red', 'green', 'blue']);
909
909
 
910
910
  type Color = t.TypeOf<typeof ColorEnum>; // 'red' | 'green' | 'blue'
911
911
 
912
- // Numeric ranges
913
- const DiceRoll = t.uintRange({
914
- start: 1,
915
- end: 7,
916
- defaultValue: 1,
917
- }); // integers from 1 to 6
912
+ // Numeric ranges (end is exclusive)
913
+ const DiceRoll = t.uintRange(1, 7, { defaultValue: 1 }); // integers from 1 to 6
918
914
 
919
915
  type DiceRoll = t.TypeOf<typeof DiceRoll>; // 1 | 2 | 3 | 4 | 5 | 6
916
+
917
+ // Numeric ranges (end is inclusive)
918
+ const DiceRoll2 = t.uintRangeInclusive(1, 6, { defaultValue: 1 }); // integers from 1 to 6
919
+
920
+ type DiceRoll2 = t.TypeOf<typeof DiceRoll2>; // 1 | 2 | 3 | 4 | 5 | 6
920
921
  ```
921
922
 
922
923
  Tips: It is often better to use `uintRange` instead of `enumType` when possible, because `enumType` stores a Set of the sizes of its members as data, while `uintRange` only stores the range, resulting in smaller memory usage.
@@ -1077,8 +1078,10 @@ type ValidationError = Readonly<{
1077
1078
 
1078
1079
  - `t.TypeOf<T>` - Extract TypeScript type from validator
1079
1080
  - `t.enumType(values)` - Enum validation
1080
- - `t.uintRange({ start, end, defaultValue? })` - Non-negative integer range validation
1081
- - `t.intRange({ start, end, defaultValue? })` - Integer range validation
1081
+ - `t.uintRange(start, end, { defaultValue? })` - Non-negative integer range validation (`end` is exclusive)
1082
+ - `t.intRange(start, end, { defaultValue? })` - Integer range validation (`end` is exclusive)
1083
+ - `t.uintRangeInclusive(start, end, { defaultValue? })` - Non-negative integer range validation (`end` is inclusive)
1084
+ - `t.intRangeInclusive(start, end, { defaultValue? })` - Integer range validation (`end` is inclusive)
1082
1085
  - `t.unknown` - Unknown Type
1083
1086
  - `t.recursion(typeName, definition)` - Define recursive type
1084
1087
 
@@ -1,4 +1,5 @@
1
1
  import { pipe, Result } from 'ts-data-forge';
2
+ import '@sindresorhus/is';
2
3
  import { createType } from '../utils/create-type.mjs';
3
4
 
4
5
  const brand = ({
@@ -1 +1 @@
1
- {"version":3,"file":"brand.mjs","sources":["../../src/brand/brand.mts"],"sourcesContent":["import { pipe, Result } from 'ts-data-forge';\nimport { type Brand, type Primitive, type StrictExtract } from 'ts-type-forge';\nimport { type Type } from '../type.mjs';\nimport { createType, type ValidationError } from '../utils/index.mjs';\n\nexport type { Brand } from 'ts-type-forge';\n\ntype ArrayToUnion<A extends readonly unknown[]> = A extends readonly []\n ? never\n : A[number];\n\nexport const brand = <\n const A extends StrictExtract<Primitive, string | number | bigint | boolean>,\n const BrandTrueKeys extends readonly string[],\n const BrandFalseKeys extends readonly string[] = readonly [],\n>({\n baseType,\n brandFalseKeys,\n brandKeys,\n defaultValue: defaultValue_,\n is: is_,\n typeName,\n}: Readonly<{\n baseType: Type<A>;\n is?: (\n a: A,\n ) => a is Brand<A, ArrayToUnion<BrandTrueKeys>, ArrayToUnion<BrandFalseKeys>>;\n defaultValue?: A;\n typeName?: string;\n brandKeys: BrandTrueKeys;\n brandFalseKeys?: BrandFalseKeys;\n}>): Type<\n Brand<A, ArrayToUnion<BrandTrueKeys>, ArrayToUnion<BrandFalseKeys>>\n> => {\n type T = Brand<A, ArrayToUnion<BrandTrueKeys>, ArrayToUnion<BrandFalseKeys>>;\n\n const is: (a: A) => a is T = is_ ?? ((_a): _a is T => true);\n\n const defaultValue: A = defaultValue_ ?? baseType.defaultValue;\n\n if (!is(defaultValue)) {\n throw new Error(\n `defaultValue ${defaultValue} doesn't pass \\`is\\` function`,\n );\n }\n\n const brandKeysStr = [\n ...brandKeys.map((s) => `\"${s}\"`),\n ...(brandFalseKeys?.map((s) => `not(\"${s}\")`) ?? []),\n ].join(' & ');\n\n const typeNameFilled = typeName ?? brandKeysStr;\n\n const validate: Type<T>['validate'] = (a) =>\n pipe(a)\n .map(baseType.validate)\n .map((res): Result<T, readonly ValidationError[]> =>\n Result.isErr(res)\n ? res\n : is(res.value)\n ? Result.ok(res.value satisfies T)\n : Result.err([\n {\n path: [],\n actualValue: res.value,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details:\n // If typeName is specified, it will be used in the error message, so no further information is required.\n typeName === undefined\n ? {\n kind: 'brand' as const,\n description: brandKeysStr,\n }\n : undefined,\n } satisfies ValidationError,\n ]),\n ).value;\n\n return createType({\n typeName: typeNameFilled,\n defaultValue,\n validate,\n });\n};\n"],"names":[],"mappings":";;;AAWO,MAAM,QAAQ,CAInB;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,EAAc,aAAA;AAAA,EACd,EAAA,EAAI,GAAA;AAAA,EACJ;AACF,CAAA,KAWK;AAGH,EAAA,MAAM,EAAA,GAAuB,GAAA,KAAQ,CAAC,EAAA,KAAgB,IAAA,CAAA;AAEtD,EAAA,MAAM,YAAA,GAAkB,iBAAiB,QAAA,CAAS,YAAA;AAElD,EAAA,IAAI,CAAC,EAAA,CAAG,YAAY,CAAA,EAAG;AACrB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,gBAAgB,YAAY,CAAA,6BAAA;AAAA,KAC9B;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,GAAG,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,IAChC,GAAI,gBAAgB,GAAA,CAAI,CAAC,MAAM,CAAA,KAAA,EAAQ,CAAC,CAAA,EAAA,CAAI,CAAA,IAAK;AAAC,GACpD,CAAE,KAAK,KAAK,CAAA;AAEZ,EAAA,MAAM,iBAAiB,QAAA,IAAY,YAAA;AAEnC,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KACrC,IAAA,CAAK,CAAC,CAAA,CACH,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,CACrB,GAAA;AAAA,IAAI,CAAC,GAAA,KACJ,MAAA,CAAO,KAAA,CAAM,GAAG,IACZ,GAAA,GACA,EAAA,CAAG,GAAA,CAAI,KAAK,IACV,MAAA,CAAO,EAAA,CAAG,IAAI,KAAiB,CAAA,GAC/B,OAAO,GAAA,CAAI;AAAA,MACT;AAAA,QACE,MAAM,EAAC;AAAA,QACP,aAAa,GAAA,CAAI,KAAA;AAAA,QACjB,YAAA,EAAc,cAAA;AAAA,QACd,QAAA,EAAU,cAAA;AAAA,QACV,OAAA;AAAA;AAAA,UAEE,aAAa,MAAA,GACT;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf,GACA;AAAA;AAAA;AACR,KACD;AAAA,GACT,CAAE,KAAA;AAEN,EAAA,OAAO,UAAA,CAAW;AAAA,IAChB,QAAA,EAAU,cAAA;AAAA,IACV,YAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"brand.mjs","sources":["../../src/brand/brand.mts"],"sourcesContent":["import { pipe, Result } from 'ts-data-forge';\nimport { type Brand, type Primitive, type StrictExtract } from 'ts-type-forge';\nimport { type Type } from '../type.mjs';\nimport { createType, type ValidationError } from '../utils/index.mjs';\n\nexport type { Brand } from 'ts-type-forge';\n\ntype ArrayToUnion<A extends readonly unknown[]> = A extends readonly []\n ? never\n : A[number];\n\nexport const brand = <\n const A extends StrictExtract<Primitive, string | number | bigint | boolean>,\n const BrandTrueKeys extends readonly string[],\n const BrandFalseKeys extends readonly string[] = readonly [],\n>({\n baseType,\n brandFalseKeys,\n brandKeys,\n defaultValue: defaultValue_,\n is: is_,\n typeName,\n}: Readonly<{\n baseType: Type<A>;\n is?: (\n a: A,\n ) => a is Brand<A, ArrayToUnion<BrandTrueKeys>, ArrayToUnion<BrandFalseKeys>>;\n defaultValue?: A;\n typeName?: string;\n brandKeys: BrandTrueKeys;\n brandFalseKeys?: BrandFalseKeys;\n}>): Type<\n Brand<A, ArrayToUnion<BrandTrueKeys>, ArrayToUnion<BrandFalseKeys>>\n> => {\n type T = Brand<A, ArrayToUnion<BrandTrueKeys>, ArrayToUnion<BrandFalseKeys>>;\n\n const is: (a: A) => a is T = is_ ?? ((_a): _a is T => true);\n\n const defaultValue: A = defaultValue_ ?? baseType.defaultValue;\n\n if (!is(defaultValue)) {\n throw new Error(\n `defaultValue ${defaultValue} doesn't pass \\`is\\` function`,\n );\n }\n\n const brandKeysStr = [\n ...brandKeys.map((s) => `\"${s}\"`),\n ...(brandFalseKeys?.map((s) => `not(\"${s}\")`) ?? []),\n ].join(' & ');\n\n const typeNameFilled = typeName ?? brandKeysStr;\n\n const validate: Type<T>['validate'] = (a) =>\n pipe(a)\n .map(baseType.validate)\n .map((res): Result<T, readonly ValidationError[]> =>\n Result.isErr(res)\n ? res\n : is(res.value)\n ? Result.ok(res.value satisfies T)\n : Result.err([\n {\n path: [],\n actualValue: res.value,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details:\n // If typeName is specified, it will be used in the error message, so no further information is required.\n typeName === undefined\n ? {\n kind: 'brand' as const,\n description: brandKeysStr,\n }\n : undefined,\n } satisfies ValidationError,\n ]),\n ).value;\n\n return createType({\n typeName: typeNameFilled,\n defaultValue,\n validate,\n });\n};\n"],"names":[],"mappings":";;;;AAWO,MAAM,QAAQ,CAInB;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,EAAc,aAAA;AAAA,EACd,EAAA,EAAI,GAAA;AAAA,EACJ;AACF,CAAA,KAWK;AAGH,EAAA,MAAM,EAAA,GAAuB,GAAA,KAAQ,CAAC,EAAA,KAAgB,IAAA,CAAA;AAEtD,EAAA,MAAM,YAAA,GAAkB,iBAAiB,QAAA,CAAS,YAAA;AAElD,EAAA,IAAI,CAAC,EAAA,CAAG,YAAY,CAAA,EAAG;AACrB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,gBAAgB,YAAY,CAAA,6BAAA;AAAA,KAC9B;AAAA,EACF;AAEA,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,GAAG,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,IAChC,GAAI,gBAAgB,GAAA,CAAI,CAAC,MAAM,CAAA,KAAA,EAAQ,CAAC,CAAA,EAAA,CAAI,CAAA,IAAK;AAAC,GACpD,CAAE,KAAK,KAAK,CAAA;AAEZ,EAAA,MAAM,iBAAiB,QAAA,IAAY,YAAA;AAEnC,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KACrC,IAAA,CAAK,CAAC,CAAA,CACH,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,CACrB,GAAA;AAAA,IAAI,CAAC,GAAA,KACJ,MAAA,CAAO,KAAA,CAAM,GAAG,IACZ,GAAA,GACA,EAAA,CAAG,GAAA,CAAI,KAAK,IACV,MAAA,CAAO,EAAA,CAAG,IAAI,KAAiB,CAAA,GAC/B,OAAO,GAAA,CAAI;AAAA,MACT;AAAA,QACE,MAAM,EAAC;AAAA,QACP,aAAa,GAAA,CAAI,KAAA;AAAA,QACjB,YAAA,EAAc,cAAA;AAAA,QACd,QAAA,EAAU,cAAA;AAAA,QACV,OAAA;AAAA;AAAA,UAEE,aAAa,MAAA,GACT;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf,GACA;AAAA;AAAA;AACR,KACD;AAAA,GACT,CAAE,KAAA;AAEN,EAAA,OAAO,UAAA,CAAW;AAAA,IAChB,QAAA,EAAU,cAAA;AAAA,IACV,YAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
@@ -3,6 +3,7 @@ import { hasRecordInternals } from '../type.mjs';
3
3
  import { createAssertFn } from '../utils/create-assert-fn.mjs';
4
4
  import { createCastFn } from '../utils/create-cast-fn.mjs';
5
5
  import { createIsFn } from '../utils/create-is-fn.mjs';
6
+ import '@sindresorhus/is';
6
7
  import { toIntersectionString } from '../utils/to-union-string.mjs';
7
8
 
8
9
  const intersection = (types, defaultType, options) => {
@@ -1 +1 @@
1
- {"version":3,"file":"intersection.mjs","sources":["../../src/compose/intersection.mts"],"sourcesContent":["import { Arr, expectType, hasKey, isRecord, Result, tp } from 'ts-data-forge';\nimport { type Intersection, type NonEmptyTuple } from 'ts-type-forge';\nimport {\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n toIntersectionString,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const intersection = <const Types extends NonEmptyTuple<AnyType>>(\n types: Types,\n defaultType: IntersectionType<Types>,\n options?: Partial<\n Readonly<{\n typeName: string;\n }>\n >,\n): IntersectionType<Types> => {\n type T = IntersectionTypeValue<Types>;\n\n const typeNameFilled: string =\n options?.typeName ??\n `(${toIntersectionString(types.map((a) => a.typeName))})`;\n\n const validate: Type<T>['validate'] = (a) => {\n const errors: readonly ValidationError[] = Arr.generate(function* () {\n for (const type of types) {\n const res = type.validate(a);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'intersection',\n typeNames: types.map((t) => t.typeName),\n },\n } satisfies ValidationError;\n\n yield* res.value;\n }\n }\n });\n\n if (Arr.isNonEmpty(errors)) {\n return Result.err(errors);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : defaultType.fill(a));\n\n const baseType: Type<T> = {\n typeName: typeNameFilled,\n defaultValue: defaultType.defaultValue,\n fill,\n // Non-record intersections (e.g. branded primitives) have no excess paths\n // to remove. Record intersections override this below.\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n } as const;\n\n // If all types are records, add RecordTypeInternals\n if (types.every(hasRecordInternals)) {\n const shapeStructures = Arr.map(types, (t) => t.shapeStructure);\n\n const excessProperty: ExcessPropertyOption = Arr.some(\n types,\n (t) => t.excessProperty === 'reject',\n )\n ? 'reject'\n : 'allow';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n ...baseType,\n // A value path is represented by a record intersection if it is\n // represented by any member, so the pruned members are merged (deeply;\n // see `mergePruned`). All members are record types here\n // (`hasRecordInternals`), so each pruned result is a record.\n prune: (a: T): T =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion, @typescript-eslint/no-unsafe-return\n types.map((t) => t.prune(a)).reduce(mergePruned, {}) as T,\n shapeStructure: Arr.isFixedLengthTuple(shapeStructures, 1)\n ? shapeStructures[0]\n : ({ kind: 'intersection', parts: shapeStructures } as const),\n excessProperty,\n } as IntersectionType<Types>;\n }\n\n return baseType;\n};\n\n/**\n * Deep-merges the pruned results of intersection members. Each pruned result\n * contains only the value paths represented by its own member type, so the\n * results have to be merged recursively to keep the union of all represented\n * paths — a shallow spread would drop nested paths kept by an earlier member\n * whenever a later member shares the same key (e.g. two members both having a\n * `pos` sub-record with different fields).\n */\nconst mergePruned = (x: unknown, y: unknown): unknown => {\n if (isRecord(x) && isRecord(y)) {\n const xMergedWithY = Object.fromEntries(\n Object.entries(x).map(([k, xv]) =>\n tp(k, hasKey(y, k) ? mergePruned(xv, y[k]) : xv),\n ),\n );\n\n const yOnly = Object.fromEntries(\n Object.entries(y).filter(([k]) => !hasKey(x, k)),\n );\n\n return { ...xMergedWithY, ...yOnly };\n }\n\n // Both members pruned the same input array, so the lengths always match;\n // merge element-wise to keep every represented element path.\n if (Arr.isArray(x) && Arr.isArray(y) && x.length === y.length) {\n return x.map((xi, i) => mergePruned(xi, y[i]));\n }\n\n // Not structurally mergeable — the later member wins.\n return y;\n};\n\ntype IntersectionType<Types extends NonEmptyTuple<AnyType>> = Type<\n IntersectionTypeValue<Types>\n>;\n\ntype IntersectionTypeValue<Types extends NonEmptyTuple<AnyType>> =\n TsFortressInternal.IntersectionTypeValueImpl<Types>;\n\nnamespace TsFortressInternal {\n export type IntersectionTypeValueImpl<Types extends NonEmptyTuple<AnyType>> =\n Intersection<Cast0<UnwrapTypeList<Types>>>;\n\n type Cast0<T> = readonly [T] extends readonly [NonEmptyTuple<unknown>]\n ? T\n : never;\n}\n\nexpectType<\n IntersectionType<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n Type<\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n >\n>('=');\n\ntype UnwrapTypeList<Types extends readonly AnyType[]> =\n TsFortressInternal.UnwrapTypeImpl<Types>;\n\nnamespace TsFortressInternal {\n export type UnwrapTypeImpl<Types extends readonly unknown[]> =\n Types extends readonly []\n ? readonly []\n : Types extends readonly [infer Head, ...infer Tail]\n ? readonly [TypeOf<Cast1<Head>>, ...UnwrapTypeImpl<Tail>]\n : never;\n\n type Cast1<T> = [T] extends [AnyType] ? T : never;\n}\n\nexpectType<\n TypeOf<\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >\n >,\n Readonly<{\n a: 0;\n b: 0;\n }>\n>('=');\n\nexpectType<\n UnwrapTypeList<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n Readonly<{\n c: 0;\n d: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n d: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 1;\n c: 0;\n }>,\n ]\n >,\n never\n>('=');\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"intersection.mjs","sources":["../../src/compose/intersection.mts"],"sourcesContent":["import { Arr, expectType, hasKey, isRecord, Result, tp } from 'ts-data-forge';\nimport { type Intersection, type NonEmptyTuple } from 'ts-type-forge';\nimport {\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n toIntersectionString,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const intersection = <const Types extends NonEmptyTuple<AnyType>>(\n types: Types,\n defaultType: IntersectionType<Types>,\n options?: Partial<\n Readonly<{\n typeName: string;\n }>\n >,\n): IntersectionType<Types> => {\n type T = IntersectionTypeValue<Types>;\n\n const typeNameFilled: string =\n options?.typeName ??\n `(${toIntersectionString(types.map((a) => a.typeName))})`;\n\n const validate: Type<T>['validate'] = (a) => {\n const errors: readonly ValidationError[] = Arr.generate(function* () {\n for (const type of types) {\n const res = type.validate(a);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'intersection',\n typeNames: types.map((t) => t.typeName),\n },\n } satisfies ValidationError;\n\n yield* res.value;\n }\n }\n });\n\n if (Arr.isNonEmpty(errors)) {\n return Result.err(errors);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : defaultType.fill(a));\n\n const baseType: Type<T> = {\n typeName: typeNameFilled,\n defaultValue: defaultType.defaultValue,\n fill,\n // Non-record intersections (e.g. branded primitives) have no excess paths\n // to remove. Record intersections override this below.\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n } as const;\n\n // If all types are records, add RecordTypeInternals\n if (types.every(hasRecordInternals)) {\n const shapeStructures = Arr.map(types, (t) => t.shapeStructure);\n\n const excessProperty: ExcessPropertyOption = Arr.some(\n types,\n (t) => t.excessProperty === 'reject',\n )\n ? 'reject'\n : 'allow';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n ...baseType,\n // A value path is represented by a record intersection if it is\n // represented by any member, so the pruned members are merged (deeply;\n // see `mergePruned`). All members are record types here\n // (`hasRecordInternals`), so each pruned result is a record.\n prune: (a: T): T =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion, @typescript-eslint/no-unsafe-return\n types.map((t) => t.prune(a)).reduce(mergePruned, {}) as T,\n shapeStructure: Arr.isFixedLengthTuple(shapeStructures, 1)\n ? shapeStructures[0]\n : ({ kind: 'intersection', parts: shapeStructures } as const),\n excessProperty,\n } as IntersectionType<Types>;\n }\n\n return baseType;\n};\n\n/**\n * Deep-merges the pruned results of intersection members. Each pruned result\n * contains only the value paths represented by its own member type, so the\n * results have to be merged recursively to keep the union of all represented\n * paths — a shallow spread would drop nested paths kept by an earlier member\n * whenever a later member shares the same key (e.g. two members both having a\n * `pos` sub-record with different fields).\n */\nconst mergePruned = (x: unknown, y: unknown): unknown => {\n if (isRecord(x) && isRecord(y)) {\n const xMergedWithY = Object.fromEntries(\n Object.entries(x).map(([k, xv]) =>\n tp(k, hasKey(y, k) ? mergePruned(xv, y[k]) : xv),\n ),\n );\n\n const yOnly = Object.fromEntries(\n Object.entries(y).filter(([k]) => !hasKey(x, k)),\n );\n\n return { ...xMergedWithY, ...yOnly };\n }\n\n // Both members pruned the same input array, so the lengths always match;\n // merge element-wise to keep every represented element path.\n if (Arr.isArray(x) && Arr.isArray(y) && x.length === y.length) {\n return x.map((xi, i) => mergePruned(xi, y[i]));\n }\n\n // Not structurally mergeable — the later member wins.\n return y;\n};\n\ntype IntersectionType<Types extends NonEmptyTuple<AnyType>> = Type<\n IntersectionTypeValue<Types>\n>;\n\ntype IntersectionTypeValue<Types extends NonEmptyTuple<AnyType>> =\n TsFortressInternal.IntersectionTypeValueImpl<Types>;\n\nnamespace TsFortressInternal {\n export type IntersectionTypeValueImpl<Types extends NonEmptyTuple<AnyType>> =\n Intersection<Cast0<UnwrapTypeList<Types>>>;\n\n type Cast0<T> = readonly [T] extends readonly [NonEmptyTuple<unknown>]\n ? T\n : never;\n}\n\nexpectType<\n IntersectionType<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n Type<\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n >\n>('=');\n\ntype UnwrapTypeList<Types extends readonly AnyType[]> =\n TsFortressInternal.UnwrapTypeImpl<Types>;\n\nnamespace TsFortressInternal {\n export type UnwrapTypeImpl<Types extends readonly unknown[]> =\n Types extends readonly []\n ? readonly []\n : Types extends readonly [infer Head, ...infer Tail]\n ? readonly [TypeOf<Cast1<Head>>, ...UnwrapTypeImpl<Tail>]\n : never;\n\n type Cast1<T> = [T] extends [AnyType] ? T : never;\n}\n\nexpectType<\n TypeOf<\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >\n >,\n Readonly<{\n a: 0;\n b: 0;\n }>\n>('=');\n\nexpectType<\n UnwrapTypeList<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n Readonly<{\n c: 0;\n d: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n d: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 1;\n c: 0;\n }>,\n ]\n >,\n never\n>('=');\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"union.d.mts","sourceRoot":"","sources":["../../src/compose/union.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAEL,KAAK,OAAO,EAEZ,KAAK,IAAI,EACT,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AASrB,eAAO,MAAM,KAAK,GAAI,KAAK,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,SACvD,KAAK,YACF,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;CAC/B,CAAC,CACH,KACA,SAAS,CAAC,KAAK,CA6EjB,CAAC;AAEF,KAAK,SAAS,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI,CACzD,cAAc,CAAC,KAAK,CAAC,CACtB,CAAC;AAEF,KAAK,cAAc,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IACtD,kBAAkB,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;AAE/C,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IACjE,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnC,KAAK,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;;CACvE"}
1
+ {"version":3,"file":"union.d.mts","sourceRoot":"","sources":["../../src/compose/union.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAKL,KAAK,OAAO,EAEZ,KAAK,IAAI,EACT,KAAK,MAAM,EAEZ,MAAM,aAAa,CAAC;AAWrB,eAAO,MAAM,KAAK,GAAI,KAAK,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,SACvD,KAAK,YACF,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;CAC/B,CAAC,CACH,KACA,SAAS,CAAC,KAAK,CA0KjB,CAAC;AA0EF,KAAK,SAAS,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI,CACzD,cAAc,CAAC,KAAK,CAAC,CACtB,CAAC;AAEF,KAAK,cAAc,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IACtD,kBAAkB,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;AAE/C,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IACjE,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnC,KAAK,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;;CACvE"}
@@ -1,8 +1,9 @@
1
1
  import { memoizeFunction, Arr, Result } from 'ts-data-forge';
2
- import { hasRecordInternals } from '../type.mjs';
2
+ import { hasUnionInternals, hasRecordInternals, flattenShapeStructure, hasTupleInternals } from '../type.mjs';
3
3
  import { createAssertFn } from '../utils/create-assert-fn.mjs';
4
4
  import { createCastFn } from '../utils/create-cast-fn.mjs';
5
5
  import { createIsFn } from '../utils/create-is-fn.mjs';
6
+ import { UNION_MEMBER_LISTING_MAX_LENGTH, runtimeTypeNameOf } from '../utils/validation-error.mjs';
6
7
  import { toUnionString } from '../utils/to-union-string.mjs';
7
8
 
8
9
  const union = (types, options) => {
@@ -10,25 +11,74 @@ const union = (types, options) => {
10
11
  () => options?.defaultType ?? types[0]
11
12
  );
12
13
  const typeNameFilled = options?.typeName ?? `(${toUnionString(types.map((a) => a.typeName))})`;
13
- const validate = (a) => types.some((t) => t.is(a)) ? (
14
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
15
- Result.ok(a)
16
- ) : Result.err([
17
- {
18
- path: [],
19
- actualValue: a,
20
- expectedType: typeNameFilled,
21
- typeName: typeNameFilled,
22
- details: {
23
- kind: "union",
24
- typeNames: types.map((t) => t.typeName)
25
- }
14
+ const memberTypes = types.flatMap(
15
+ (t) => hasUnionInternals(t) ? t.memberTypes : [t]
16
+ );
17
+ const validate = (a) => {
18
+ if (memberTypes.some((t) => t.is(a))) {
19
+ return Result.ok(a);
20
+ }
21
+ const memberTypeNames = types.map((t) => t.typeName);
22
+ if (toUnionString(memberTypeNames).length <= UNION_MEMBER_LISTING_MAX_LENGTH) {
23
+ return Result.err([
24
+ {
25
+ path: [],
26
+ actualValue: a,
27
+ expectedType: typeNameFilled,
28
+ typeName: typeNameFilled,
29
+ details: {
30
+ kind: "union",
31
+ typeNames: memberTypeNames
32
+ }
33
+ }
34
+ ]);
35
+ }
36
+ const actualCategory = runtimeTypeNameOf(a);
37
+ const candidates = memberTypes.filter((t) => runtimeTypeNameOf(t.defaultValue) === actualCategory).map((t) => evaluateMember(t, a));
38
+ if (!Arr.isNonEmpty(candidates)) {
39
+ return Result.err([
40
+ {
41
+ path: [],
42
+ actualValue: a,
43
+ expectedType: typeNameFilled,
44
+ typeName: typeNameFilled,
45
+ details: {
46
+ kind: "union-category-mismatch",
47
+ memberCount: memberTypes.length,
48
+ memberCategories: Arr.uniq(
49
+ memberTypes.map((t) => runtimeTypeNameOf(t.defaultValue))
50
+ )
51
+ }
52
+ }
53
+ ]);
26
54
  }
27
- ]);
55
+ const closest = Arr.minBy(
56
+ candidates,
57
+ (candidate) => candidate,
58
+ compareByCloseness
59
+ ).value;
60
+ const equallyClose = candidates.filter(
61
+ (c) => c !== closest && compareByCloseness(c, closest) === 0
62
+ );
63
+ return Result.err(
64
+ Arr.toUnshifted({
65
+ path: [],
66
+ actualValue: a,
67
+ expectedType: typeNameFilled,
68
+ typeName: typeNameFilled,
69
+ details: {
70
+ kind: "union-closest-member",
71
+ memberCount: memberTypes.length,
72
+ closestMemberTypeName: closest.typeName,
73
+ equallyCloseMemberTypeNames: equallyClose.map((c) => c.typeName)
74
+ }
75
+ })(closest.errors)
76
+ );
77
+ };
28
78
  const is = createIsFn(validate);
29
79
  const fill = (a) => is(a) ? a : getDefaultType().fill(a);
30
80
  const prune = (a) => {
31
- const matched = types.find((t) => t.is(a));
81
+ const matched = memberTypes.find((t) => t.is(a));
32
82
  return matched === void 0 ? a : (
33
83
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
34
84
  matched.prune(a)
@@ -44,7 +94,9 @@ const union = (types, options) => {
44
94
  validate,
45
95
  is,
46
96
  assertIs: createAssertFn(validate),
47
- cast: createCastFn(validate)
97
+ cast: createCastFn(validate),
98
+ // Lets a union that takes this one as a member flatten it in.
99
+ memberTypes
48
100
  };
49
101
  if (types.every(hasRecordInternals)) {
50
102
  const shapeStructures = Arr.map(types, (t) => t.shapeStructure);
@@ -60,6 +112,31 @@ const union = (types, options) => {
60
112
  }
61
113
  return baseType;
62
114
  };
115
+ const evaluateMember = (memberType, a) => {
116
+ const errors = validationErrorsOf(memberType.validate(a));
117
+ const satisfiedCheckCount = Math.max(
118
+ 0,
119
+ checkCountOf(memberType) - errors.length
120
+ );
121
+ return {
122
+ typeName: memberType.typeName,
123
+ errors,
124
+ satisfiedCheckCount,
125
+ score: errors.length - satisfiedCheckCount
126
+ };
127
+ };
128
+ const compareByCloseness = (x, y) => x.score !== y.score ? x.score - y.score : y.satisfiedCheckCount - x.satisfiedCheckCount;
129
+ const checkCountOf = (memberType) => {
130
+ if (hasRecordInternals(memberType)) {
131
+ const shape = flattenShapeStructure(memberType.shapeStructure);
132
+ return shape === void 0 ? 1 : Object.keys(shape).length;
133
+ }
134
+ if (hasTupleInternals(memberType)) {
135
+ return memberType.elementTypes.length;
136
+ }
137
+ return 1;
138
+ };
139
+ const validationErrorsOf = (result) => Result.isErr(result) ? result.value : [];
63
140
 
64
141
  export { union };
65
142
  //# sourceMappingURL=union.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"union.mjs","sources":["../../src/compose/union.mts"],"sourcesContent":["import { Arr, Result, expectType, memoizeFunction } from 'ts-data-forge';\nimport { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';\nimport {\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n toUnionString,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const union = <const Types extends NonEmptyTuple<AnyType>>(\n types: Types,\n options?: Partial<\n Readonly<{\n typeName: string;\n defaultType: UnionType<Types>;\n }>\n >,\n): UnionType<Types> => {\n type T = UnionTypeValue<Types>;\n\n const getDefaultType = memoizeFunction(\n (): UnionType<Types> =>\n options?.defaultType ?? (types[0] as UnionType<Types>),\n );\n\n const typeNameFilled: string =\n options?.typeName ?? `(${toUnionString(types.map((a) => a.typeName))})`;\n\n const validate: Type<T>['validate'] = (a) =>\n types.some((t) => t.is(a))\n ? // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Result.ok(a as T)\n : Result.err([\n {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'union',\n typeNames: types.map((t) => t.typeName),\n },\n } satisfies ValidationError,\n ]);\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : getDefaultType().fill(a));\n\n // Prunes with the first member type that matches the value.\n const prune = (a: T): T => {\n const matched = types.find((t) => t.is(a));\n\n return matched === undefined\n ? a\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (matched.prune(a) as T);\n };\n\n const baseType: Type<T> = {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultType().defaultValue;\n },\n fill,\n prune,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n } as const;\n\n // If all types are records, add RecordTypeInternals with union structure\n if (types.every(hasRecordInternals)) {\n const shapeStructures = Arr.map(types, (t) => t.shapeStructure);\n\n const excessProperty: ExcessPropertyOption = Arr.some(\n types,\n (t) => t.excessProperty === 'reject',\n )\n ? 'reject'\n : 'allow';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n ...baseType,\n shapeStructure: Arr.isFixedLengthTuple(shapeStructures, 1)\n ? shapeStructures[0]\n : ({ kind: 'union', variants: shapeStructures } as const),\n excessProperty,\n } as UnionType<Types>;\n }\n\n return baseType;\n};\n\ntype UnionType<Types extends NonEmptyTuple<AnyType>> = Type<\n UnionTypeValue<Types>\n>;\n\ntype UnionTypeValue<Types extends NonEmptyTuple<AnyType>> =\n TsFortressInternal.UnionTypeValueImpl<Types>;\n\nnamespace TsFortressInternal {\n export type UnionTypeValueImpl<Types extends NonEmptyTuple<AnyType>> =\n UnwrapUnion<ArrayElement<Types>>;\n\n type UnwrapUnion<T extends AnyType> = T extends T ? TypeOf<T> : never;\n}\n\nexpectType<\n UnionType<\n readonly [Type<Readonly<{ a: 0; b: 0 }>>, Type<Readonly<{ b: 0; c: 0 }>>]\n >,\n Type<Readonly<{ a: 0; b: 0 } | { b: 0; c: 0 }>>\n>('=');\n\nexpectType<\n UnionType<\n readonly [\n Type<Readonly<{ a: 0; b: 0 }>>,\n Type<Readonly<{ b: 0; c: 0 }>>,\n Type<Readonly<{ e: 0; f: 0 }>>,\n ]\n >,\n Type<Readonly<{ a: 0; b: 0 } | { b: 0; c: 0 } | { e: 0; f: 0 }>>\n>('=');\n"],"names":[],"mappings":";;;;;;;MAiBa,KAAA,GAAQ,CACnB,KAAA,EACA,OAAA,KAMqB;AAGrB,EAAA,MAAM,cAAA,GAAiB,eAAA;AAAA,IACrB,MACE,OAAA,EAAS,WAAA,IAAgB,KAAA,CAAM,CAAC;AAAA,GACpC;AAEA,EAAA,MAAM,cAAA,GACJ,OAAA,EAAS,QAAA,IAAY,CAAA,CAAA,EAAI,aAAA,CAAc,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AAEtE,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KACrC,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,CAAG,CAAC,CAAC,CAAA;AAAA;AAAA,IAErB,MAAA,CAAO,GAAG,CAAM;AAAA,MAChB,OAAO,GAAA,CAAI;AAAA,IACT;AAAA,MACE,MAAM,EAAC;AAAA,MACP,WAAA,EAAa,CAAA;AAAA,MACb,YAAA,EAAc,cAAA;AAAA,MACd,QAAA,EAAU,cAAA;AAAA,MACV,OAAA,EAAS;AAAA,QACP,IAAA,EAAM,OAAA;AAAA,QACN,WAAW,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,QAAQ;AAAA;AACxC;AACF,GACD,CAAA;AAEP,EAAA,MAAM,EAAA,GAAK,WAAc,QAAQ,CAAA;AAEjC,EAAA,MAAM,IAAA,GAAwB,CAAC,CAAA,KAAO,EAAA,CAAG,CAAC,IAAI,CAAA,GAAI,cAAA,EAAe,CAAE,IAAA,CAAK,CAAC,CAAA;AAGzE,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAY;AACzB,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,CAAG,CAAC,CAAC,CAAA;AAEzC,IAAA,OAAO,YAAY,MAAA,GACf,CAAA;AAAA;AAAA,MAEC,OAAA,CAAQ,MAAM,CAAC;AAAA,KAAA;AAAA,EAAA,CACtB;AAEA,EAAA,MAAM,QAAA,GAAoB;AAAA,IACxB,QAAA,EAAU,cAAA;AAAA,IACV,IAAI,YAAA,GAAe;AACjB,MAAA,OAAO,gBAAe,CAAE,YAAA;AAAA,IAAA,CAC1B;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,EAAA;AAAA,IACA,QAAA,EAAU,eAAe,QAAQ,CAAA;AAAA,IACjC,IAAA,EAAM,aAAa,QAAQ;AAAA,GAC7B;AAGA,EAAA,IAAI,KAAA,CAAM,KAAA,CAAM,kBAAkB,CAAA,EAAG;AACnC,IAAA,MAAM,kBAAkB,GAAA,CAAI,GAAA,CAAI,OAAO,CAAC,CAAA,KAAM,EAAE,cAAc,CAAA;AAE9D,IAAA,MAAM,iBAAuC,GAAA,CAAI,IAAA;AAAA,MAC/C,KAAA;AAAA,MACA,CAAC,CAAA,KAAM,CAAA,CAAE,cAAA,KAAmB;AAAA,QAE1B,QAAA,GACA,OAAA;AAGJ,IAAA,OAAO;AAAA,MACL,GAAG,QAAA;AAAA,MACH,cAAA,EAAgB,GAAA,CAAI,kBAAA,CAAmB,eAAA,EAAiB,CAAC,CAAA,GACrD,eAAA,CAAgB,CAAC,CAAA,GAChB,EAAE,IAAA,EAAM,OAAA,EAAS,UAAU,eAAA,EAAgB;AAAA,MAChD;AAAA,KACF;AAAA,EAAA;AAGF,EAAA,OAAO,QAAA;AACT;;;;"}
1
+ {"version":3,"file":"union.mjs","sources":["../../src/compose/union.mts"],"sourcesContent":["import { Arr, expectType, memoizeFunction, Result } from 'ts-data-forge';\nimport { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';\nimport {\n flattenShapeStructure,\n hasRecordInternals,\n hasTupleInternals,\n hasUnionInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n type UnionTypeInternals,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n runtimeTypeNameOf,\n toUnionString,\n UNION_MEMBER_LISTING_MAX_LENGTH,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const union = <const Types extends NonEmptyTuple<AnyType>>(\n types: Types,\n options?: Partial<\n Readonly<{\n typeName: string;\n defaultType: UnionType<Types>;\n }>\n >,\n): UnionType<Types> => {\n type T = UnionTypeValue<Types>;\n\n const getDefaultType = memoizeFunction(\n (): UnionType<Types> =>\n options?.defaultType ?? (types[0] as UnionType<Types>),\n );\n\n const typeNameFilled: string =\n options?.typeName ?? `(${toUnionString(types.map((a) => a.typeName))})`;\n\n /**\n * A union nested directly inside this one contributes its own members\n * instead of itself. `A | (B | C)` and `A | B | C` describe the same set of\n * values, so this changes nothing about what the union accepts.\n *\n * It was introduced for the error path. Reporting the member closest to a\n * rejected value starts by filing each member under a single runtime type\n * category, taken from its default value — and a nested union has only one\n * default value. Unflattened, `union([union([literal('alpha'), literal(42)]),\n * ...])` is filed under `string`, so validating `41` finds no candidate at\n * all and the union falls back to listing the categories it accepts.\n * Flattened, the `42` member competes on its own and is reported.\n *\n * Two things deliberately stay unflattened: `typeName` and the member\n * listing use the members as they were written, so a nested union that\n * carries a name of its own keeps it; and a `recursion` member answers\n * {@link hasUnionInternals} without running its definition, so a type\n * defined in terms of itself stays a single opaque member.\n *\n * See `documents/union-closest-member-heuristic.md`.\n */\n const memberTypes: readonly AnyType[] = types.flatMap((t) =>\n hasUnionInternals(t) ? t.memberTypes : [t],\n );\n\n const validate: Type<T>['validate'] = (a) => {\n if (memberTypes.some((t) => t.is(a))) {\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n }\n\n const memberTypeNames = types.map((t) => t.typeName);\n\n if (\n toUnionString(memberTypeNames).length <= UNION_MEMBER_LISTING_MAX_LENGTH\n ) {\n return Result.err([\n {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'union',\n typeNames: memberTypeNames,\n },\n } satisfies ValidationError,\n ]);\n }\n\n // The member listing is too long to be a readable error message, so\n // narrow the report down to the members whose runtime type category\n // (derived from each member's default value) matches the value.\n const actualCategory = runtimeTypeNameOf(a);\n\n const candidates = memberTypes\n .filter((t) => runtimeTypeNameOf(t.defaultValue) === actualCategory)\n .map((t) => evaluateMember(t, a));\n\n if (!Arr.isNonEmpty(candidates)) {\n return Result.err([\n {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'union-category-mismatch',\n memberCount: memberTypes.length,\n memberCategories: Arr.uniq(\n memberTypes.map((t) => runtimeTypeNameOf(t.defaultValue)),\n ),\n },\n } satisfies ValidationError,\n ]);\n }\n\n // The closest member is the one with the lowest similarity score (see\n // `evaluateMember`); its errors explain the mismatch far better than the\n // full member listing would. Members that tie with it are named alongside\n // it, and the first of them (in declaration order, as in `prune` and\n // `fill`) is the one whose errors are reported.\n const closest = Arr.minBy(\n candidates,\n (candidate) => candidate,\n compareByCloseness,\n ).value;\n\n const equallyClose = candidates.filter(\n (c) => c !== closest && compareByCloseness(c, closest) === 0,\n );\n\n return Result.err(\n Arr.toUnshifted({\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'union-closest-member',\n memberCount: memberTypes.length,\n closestMemberTypeName: closest.typeName,\n equallyCloseMemberTypeNames: equallyClose.map((c) => c.typeName),\n },\n } satisfies ValidationError)(closest.errors),\n );\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : getDefaultType().fill(a));\n\n // Prunes with the first member type that matches the value.\n const prune = (a: T): T => {\n const matched = memberTypes.find((t) => t.is(a));\n\n return matched === undefined\n ? a\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (matched.prune(a) as T);\n };\n\n const baseType = {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultType().defaultValue;\n },\n fill,\n prune,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n // Lets a union that takes this one as a member flatten it in.\n memberTypes,\n } as const satisfies Type<T> & UnionTypeInternals;\n\n // If all types are records, add RecordTypeInternals with union structure\n if (types.every(hasRecordInternals)) {\n const shapeStructures = Arr.map(types, (t) => t.shapeStructure);\n\n const excessProperty: ExcessPropertyOption = Arr.some(\n types,\n (t) => t.excessProperty === 'reject',\n )\n ? 'reject'\n : 'allow';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n ...baseType,\n shapeStructure: Arr.isFixedLengthTuple(shapeStructures, 1)\n ? shapeStructures[0]\n : ({ kind: 'union', variants: shapeStructures } as const),\n excessProperty,\n } as UnionType<Types>;\n }\n\n return baseType as UnionType<Types>;\n};\n\n/**\n * How close a member is to a value it rejected.\n *\n * `score` is the number of checks the member failed minus the number it\n * passed, so a member is credited for what the value does satisfy. Plain error\n * counting would let a small unrelated member (one missing key) outrank a large\n * member the value nearly satisfies (two wrong fields out of ten), while a\n * ratio would do the opposite and let a large member win with a long list of\n * errors just because it also has many keys. Subtracting keeps both the failed\n * and the passed checks in absolute terms.\n *\n * Members with the same score are ordered by how much they satisfied, so the\n * one that recognized more of the value comes first.\n *\n * See `documents/union-closest-member-heuristic.md` for the scenarios these\n * rules were chosen against.\n */\ntype MemberCloseness = Readonly<{\n typeName: string;\n errors: readonly ValidationError[];\n satisfiedCheckCount: number;\n score: number;\n}>;\n\nconst evaluateMember = (memberType: AnyType, a: unknown): MemberCloseness => {\n const errors = validationErrorsOf(memberType.validate(a));\n\n // A member cannot pass fewer than zero checks: a record that rejects excess\n // properties can report more errors than it has keys.\n const satisfiedCheckCount = Math.max(\n 0,\n checkCountOf(memberType) - errors.length,\n );\n\n return {\n typeName: memberType.typeName,\n errors,\n satisfiedCheckCount,\n score: errors.length - satisfiedCheckCount,\n };\n};\n\nconst compareByCloseness = (x: MemberCloseness, y: MemberCloseness): number =>\n x.score !== y.score\n ? x.score - y.score\n : y.satisfiedCheckCount - x.satisfiedCheckCount;\n\n/**\n * How many checks a member performs on a value: one per key for a record, one\n * per element for a tuple, and a single check for everything else, which either\n * matches or does not. A record whose shape cannot be flattened to a single set\n * of keys (a union of shapes) also counts as one check.\n */\nconst checkCountOf = (memberType: AnyType): number => {\n if (hasRecordInternals(memberType)) {\n const shape = flattenShapeStructure(memberType.shapeStructure);\n\n return shape === undefined ? 1 : Object.keys(shape).length;\n }\n\n if (hasTupleInternals(memberType)) {\n return memberType.elementTypes.length;\n }\n\n return 1;\n};\n\nconst validationErrorsOf = (\n result: Result<unknown, readonly ValidationError[]>,\n): readonly ValidationError[] =>\n Result.isErr(result) ? result.value : ([] as const);\n\ntype UnionType<Types extends NonEmptyTuple<AnyType>> = Type<\n UnionTypeValue<Types>\n>;\n\ntype UnionTypeValue<Types extends NonEmptyTuple<AnyType>> =\n TsFortressInternal.UnionTypeValueImpl<Types>;\n\nnamespace TsFortressInternal {\n export type UnionTypeValueImpl<Types extends NonEmptyTuple<AnyType>> =\n UnwrapUnion<ArrayElement<Types>>;\n\n type UnwrapUnion<T extends AnyType> = T extends T ? TypeOf<T> : never;\n}\n\nexpectType<\n UnionType<\n readonly [Type<Readonly<{ a: 0; b: 0 }>>, Type<Readonly<{ b: 0; c: 0 }>>]\n >,\n Type<Readonly<{ a: 0; b: 0 } | { b: 0; c: 0 }>>\n>('=');\n\nexpectType<\n UnionType<\n readonly [\n Type<Readonly<{ a: 0; b: 0 }>>,\n Type<Readonly<{ b: 0; c: 0 }>>,\n Type<Readonly<{ e: 0; f: 0 }>>,\n ]\n >,\n Type<Readonly<{ a: 0; b: 0 } | { b: 0; c: 0 } | { e: 0; f: 0 }>>\n>('=');\n"],"names":[],"mappings":"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"}
@@ -16,7 +16,9 @@ export { brandedString, simpleBrandedString } from './brand/branded-string.mjs';
16
16
  export { intersection } from './compose/intersection.mjs';
17
17
  export { union } from './compose/union.mjs';
18
18
  export { enumType } from './enum/enum.mjs';
19
+ export { intRangeInclusive } from './enum/int-range-inclusive.mjs';
19
20
  export { intRange } from './enum/int-range.mjs';
21
+ export { uintRangeInclusive } from './enum/uint-range-inclusive.mjs';
20
22
  export { uintRange } from './enum/uint-range.mjs';
21
23
  export { literal } from './other-types/literal.mjs';
22
24
  export { MapType } from './other-types/map.mjs';
@@ -81,5 +83,5 @@ export { createIsFn } from './utils/create-is-fn.mjs';
81
83
  export { createPrimitiveType } from './utils/create-primitive-type.mjs';
82
84
  export { createType } from './utils/create-type.mjs';
83
85
  export { toIntersectionString, toUnionKeyString, toUnionString } from './utils/to-union-string.mjs';
84
- export { createPrimitiveValidationError, prependIndexToValidationErrors, prependPathToValidationErrors, validationErrorToMessage, validationErrorsToMessages } from './utils/validation-error.mjs';
86
+ export { UNION_MEMBER_LISTING_MAX_LENGTH, createPrimitiveValidationError, prependIndexToValidationErrors, prependPathToValidationErrors, runtimeTypeNameOf, validationErrorToMessage, validationErrorsToMessages } from './utils/validation-error.mjs';
85
87
  //# sourceMappingURL=entry-point.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"entry-point.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"entry-point.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,4 +1,6 @@
1
1
  export * from './enum.mjs';
2
+ export * from './int-range-inclusive.mjs';
2
3
  export * from './int-range.mjs';
4
+ export * from './uint-range-inclusive.mjs';
3
5
  export * from './uint-range.mjs';
4
6
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/enum/index.mts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/enum/index.mts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export { enumType } from './enum.mjs';
2
+ export { intRangeInclusive } from './int-range-inclusive.mjs';
2
3
  export { intRange } from './int-range.mjs';
4
+ export { uintRangeInclusive } from './uint-range-inclusive.mjs';
3
5
  export { uintRange } from './uint-range.mjs';
4
6
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,13 @@
1
+ import { type Int11, type IntRangeInclusive } from 'ts-type-forge';
2
+ import { type Type } from '../type.mjs';
3
+ export type { IntRangeInclusive } from 'ts-type-forge';
4
+ export declare const intRangeInclusive: <Start extends Int11, End extends Int11>(...args: readonly [start: Start, end: End, options?: Readonly<{
5
+ typeName?: string;
6
+ defaultValue?: IntRangeInclusive<Start, End>;
7
+ }>] | readonly [options: Readonly<{
8
+ start: Start;
9
+ end: End;
10
+ typeName?: string;
11
+ defaultValue?: IntRangeInclusive<Start, End>;
12
+ }>]) => Type<IntRangeInclusive<Start, End>>;
13
+ //# sourceMappingURL=int-range-inclusive.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"int-range-inclusive.d.mts","sourceRoot":"","sources":["../../src/enum/int-range-inclusive.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAQxC,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,eAAO,MAAM,iBAAiB,GAAI,KAAK,SAAS,KAAK,EAAE,GAAG,SAAS,KAAK,WAElE,SAAS,CACP,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CAC9C,CAAC,CACH,GACD,SAAS,CACP,OAAO,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CAC9C,CAAC,CACH,KACJ,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAcpC,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { memoizeFunction, isNumber, Num, Result } from 'ts-data-forge';
2
+ import { createAssertFn } from '../utils/create-assert-fn.mjs';
3
+ import { createCastFn } from '../utils/create-cast-fn.mjs';
4
+ import { createIsFn } from '../utils/create-is-fn.mjs';
5
+ import '@sindresorhus/is';
6
+
7
+ const intRangeInclusive = (...args) => {
8
+ switch (args.length) {
9
+ case 1:
10
+ return intRangeInclusiveImpl(args[0].start, args[0].end, {
11
+ defaultValue: args[0].defaultValue,
12
+ typeName: args[0].typeName
13
+ });
14
+ case 2:
15
+ return intRangeInclusiveImpl(args[0], args[1]);
16
+ case 3:
17
+ return intRangeInclusiveImpl(args[0], args[1], args[2]);
18
+ }
19
+ };
20
+ const intRangeInclusiveImpl = (start, end, options) => {
21
+ const typeNameFilled = options?.typeName ?? `intRangeInclusive(${start}, ${end})`;
22
+ const getDefaultValue = memoizeFunction(
23
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
24
+ () => options?.defaultValue ?? start
25
+ );
26
+ const validate = (a) => {
27
+ if (!(isNumber(a) && Number.isSafeInteger(a) && Num.isInRangeInclusive(start, end)(a))) {
28
+ return Result.err([
29
+ {
30
+ path: [],
31
+ actualValue: a,
32
+ expectedType: typeNameFilled,
33
+ typeName: typeNameFilled,
34
+ details: {
35
+ kind: "integer-range-inclusive",
36
+ start,
37
+ endInclusive: end
38
+ }
39
+ }
40
+ ]);
41
+ }
42
+ return Result.ok(a);
43
+ };
44
+ const is = createIsFn(validate);
45
+ const fill = (a) => is(a) ? a : getDefaultValue();
46
+ return {
47
+ typeName: typeNameFilled,
48
+ get defaultValue() {
49
+ return getDefaultValue();
50
+ },
51
+ fill,
52
+ prune: (a) => a,
53
+ validate,
54
+ is,
55
+ assertIs: createAssertFn(validate),
56
+ cast: createCastFn(validate)
57
+ };
58
+ };
59
+
60
+ export { intRangeInclusive };
61
+ //# sourceMappingURL=int-range-inclusive.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"int-range-inclusive.mjs","sources":["../../src/enum/int-range-inclusive.mts"],"sourcesContent":["import { isNumber, memoizeFunction, Num, Result } from 'ts-data-forge';\nimport { type Int11, type IntRangeInclusive } from 'ts-type-forge';\nimport { type Type } from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport type { IntRangeInclusive } from 'ts-type-forge';\n\nexport const intRangeInclusive = <Start extends Int11, End extends Int11>(\n ...args:\n | readonly [\n start: Start,\n end: End,\n options?: Readonly<{\n typeName?: string;\n defaultValue?: IntRangeInclusive<Start, End>;\n }>,\n ]\n | readonly [\n options: Readonly<{\n start: Start;\n end: End;\n typeName?: string;\n defaultValue?: IntRangeInclusive<Start, End>;\n }>,\n ]\n): Type<IntRangeInclusive<Start, End>> => {\n switch (args.length) {\n case 1:\n return intRangeInclusiveImpl(args[0].start, args[0].end, {\n defaultValue: args[0].defaultValue,\n typeName: args[0].typeName,\n });\n\n case 2:\n return intRangeInclusiveImpl(args[0], args[1]);\n\n case 3:\n return intRangeInclusiveImpl(args[0], args[1], args[2]);\n }\n};\n\nconst intRangeInclusiveImpl = <Start extends Int11, End extends Int11>(\n start: Start,\n end: End,\n options?: Readonly<{\n typeName?: string;\n defaultValue?: IntRangeInclusive<Start, End>;\n }>,\n): Type<IntRangeInclusive<Start, End>> => {\n type T = IntRangeInclusive<Start, End>;\n\n const typeNameFilled =\n options?.typeName ?? `intRangeInclusive(${start}, ${end})`;\n\n const getDefaultValue = memoizeFunction(\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (): T => options?.defaultValue ?? (start as T),\n );\n\n const validate: Type<T>['validate'] = (a) => {\n if (!(\n isNumber(a) &&\n Number.isSafeInteger(a) &&\n Num.isInRangeInclusive(start, end)(a)\n )) {\n return Result.err([\n {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'integer-range-inclusive',\n start,\n endInclusive: end,\n },\n } satisfies ValidationError,\n ]);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : getDefaultValue());\n\n return {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultValue();\n },\n fill,\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n };\n};\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,iBAAA,GAAoB,IAC5B,IAAA,KAiBqC;AACxC,EAAA,QAAQ,KAAK,MAAA;AAAQ,IACnB,KAAK,CAAA;AACH,MAAA,OAAO,qBAAA,CAAsB,KAAK,CAAC,CAAA,CAAE,OAAO,IAAA,CAAK,CAAC,EAAE,GAAA,EAAK;AAAA,QACvD,YAAA,EAAc,IAAA,CAAK,CAAC,CAAA,CAAE,YAAA;AAAA,QACtB,QAAA,EAAU,IAAA,CAAK,CAAC,CAAA,CAAE;AAAA,OACnB,CAAA;AAAA,IAEH,KAAK,CAAA;AACH,MAAA,OAAO,sBAAsB,IAAA,CAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,IAE/C,KAAK,CAAA;AACH,MAAA,OAAO,qBAAA,CAAsB,KAAK,CAAC,CAAA,EAAG,KAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA;AAE5D;AAEA,MAAM,qBAAA,GAAwB,CAC5B,KAAA,EACA,GAAA,EACA,OAAA,KAIwC;AAGxC,EAAA,MAAM,iBACJ,OAAA,EAAS,QAAA,IAAY,CAAA,kBAAA,EAAqB,KAAK,KAAK,GAAG,CAAA,CAAA,CAAA;AAEzD,EAAA,MAAM,eAAA,GAAkB,eAAA;AAAA;AAAA,IAEtB,MAAS,SAAS,YAAA,IAAiB;AAAA,GACrC;AAEA,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KAAM;AAC3C,IAAA,IAAI,EACF,QAAA,CAAS,CAAC,CAAA,IACV,OAAO,aAAA,CAAc,CAAC,CAAA,IACtB,GAAA,CAAI,kBAAA,CAAmB,KAAA,EAAO,GAAG,CAAA,CAAE,CAAC,CAAA,CAAA,EACnC;AACD,MAAA,OAAO,OAAO,GAAA,CAAI;AAAA,QAChB;AAAA,UACE,MAAM,EAAC;AAAA,UACP,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,cAAA;AAAA,UACd,QAAA,EAAU,cAAA;AAAA,UACV,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,yBAAA;AAAA,YACN,KAAA;AAAA,YACA,YAAA,EAAc;AAAA;AAChB;AACF,OACD,CAAA;AAAA,IACH;AAGA,IAAA,OAAO,MAAA,CAAO,GAAG,CAAM,CAAA;AAAA,EACzB,CAAA;AAEA,EAAA,MAAM,EAAA,GAAK,WAAc,QAAQ,CAAA;AAEjC,EAAA,MAAM,OAAwB,CAAC,CAAA,KAAO,GAAG,CAAC,CAAA,GAAI,IAAI,eAAA,EAAgB;AAElE,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,cAAA;AAAA,IACV,IAAI,YAAA,GAAe;AACjB,MAAA,OAAO,eAAA,EAAgB;AAAA,IACzB,CAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA,EAAO,CAAC,CAAA,KAAM,CAAA;AAAA,IACd,QAAA;AAAA,IACA,EAAA;AAAA,IACA,QAAA,EAAU,eAAe,QAAQ,CAAA;AAAA,IACjC,IAAA,EAAM,aAAa,QAAQ;AAAA,GAC7B;AACF,CAAA;;;;"}
@@ -1,14 +1,13 @@
1
- import { type BoolAnd, type Index, type IndexInclusive, type Int8, type NegativeIndex, type TypeExtends, type UintRange } from 'ts-type-forge';
1
+ import { type Int11, type IntRange } from 'ts-type-forge';
2
2
  import { type Type } from '../type.mjs';
3
- export declare const intRange: <Start extends Int8, End extends Int8 | 128>({ end, start, ...options }: Readonly<{
3
+ export type { IntRange } from 'ts-type-forge';
4
+ export declare const intRange: <Start extends Int11, End extends Int11 | 1024>(...args: readonly [start: Start, end: End, options?: Readonly<{
5
+ typeName?: string;
6
+ defaultValue?: IntRange<Start, End>;
7
+ }>] | readonly [options: Readonly<{
4
8
  start: Start;
5
9
  end: End;
6
10
  typeName?: string;
7
11
  defaultValue?: IntRange<Start, End>;
8
- }>) => Type<IntRange<Start, End>>;
9
- type NegativeRange = NegativeIndex<128>;
10
- type PositiveRange = IndexInclusive<128>;
11
- export type IntRange<Start extends Int8, End extends Int8 | 128> = BoolAnd<TypeExtends<Start, PositiveRange>, TypeExtends<End, PositiveRange>> extends true ? UintRange<Start, End> : BoolAnd<TypeExtends<Start, NegativeRange>, TypeExtends<End, PositiveRange>> extends true ? NegativeIndex<NegativeToPositive<Start>> | Index<End> : BoolAnd<TypeExtends<Start, PositiveRange>, TypeExtends<End, NegativeRange>> extends true ? never : BoolAnd<TypeExtends<Start, NegativeRange>, TypeExtends<End, NegativeRange>> extends true ? Exclude<NegativeIndex<NegativeToPositive<Start>>, NegativeIndex<NegativeToPositive<End>>> : never;
12
- type NegativeToPositive<N extends number> = `${N}` extends `-${infer D extends number}` ? D : never;
13
- export {};
12
+ }>]) => Type<IntRange<Start, End>>;
14
13
  //# sourceMappingURL=int-range.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"int-range.d.mts","sourceRoot":"","sources":["../../src/enum/int-range.mts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,KAAK,EACV,KAAK,cAAc,EACnB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAQxC,eAAO,MAAM,QAAQ,GAAI,KAAK,SAAS,IAAI,EAAE,GAAG,SAAS,IAAI,GAAG,GAAG,8BAIhE,QAAQ,CAAC;IACV,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CACrC,CAAC,KAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAmD7B,CAAC;AAEF,KAAK,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;AAExC,KAAK,aAAa,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;AAEzC,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,IAAI,EAAE,GAAG,SAAS,IAAI,GAAG,GAAG,IAC7D,OAAO,CACL,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,EACjC,WAAW,CAAC,GAAG,EAAE,aAAa,CAAC,CAChC,SAAS,IAAI,GACV,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,GACrB,OAAO,CACH,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,EACjC,WAAW,CAAC,GAAG,EAAE,aAAa,CAAC,CAChC,SAAS,IAAI,GACd,aAAa,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GACrD,OAAO,CACH,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,EACjC,WAAW,CAAC,GAAG,EAAE,aAAa,CAAC,CAChC,SAAS,IAAI,GACd,KAAK,GACL,OAAO,CACH,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,EACjC,WAAW,CAAC,GAAG,EAAE,aAAa,CAAC,CAChC,SAAS,IAAI,GACd,OAAO,CACL,aAAa,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EACxC,aAAa,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CACvC,GACD,KAAK,CAAC;AAElB,KAAK,kBAAkB,CAAC,CAAC,SAAS,MAAM,IACtC,GAAG,CAAC,EAAE,SAAS,IAAI,MAAM,CAAC,SAAS,MAAM,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC"}
1
+ {"version":3,"file":"int-range.d.mts","sourceRoot":"","sources":["../../src/enum/int-range.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAQxC,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,eAAO,MAAM,QAAQ,GAAI,KAAK,SAAS,KAAK,EAAE,GAAG,SAAS,KAAK,GAAG,IAAI,WAEhE,SAAS,CACP,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CACrC,CAAC,CACH,GACD,SAAS,CACP,OAAO,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CACrC,CAAC,CACH,KACJ,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAc3B,CAAC"}
@@ -2,16 +2,26 @@ import { memoizeFunction, isNumber, Num, Result } from 'ts-data-forge';
2
2
  import { createAssertFn } from '../utils/create-assert-fn.mjs';
3
3
  import { createCastFn } from '../utils/create-cast-fn.mjs';
4
4
  import { createIsFn } from '../utils/create-is-fn.mjs';
5
+ import '@sindresorhus/is';
5
6
 
6
- const intRange = ({
7
- end,
8
- start,
9
- ...options
10
- }) => {
11
- const typeNameFilled = options.typeName ?? `intRange(${start}, ${end})`;
7
+ const intRange = (...args) => {
8
+ switch (args.length) {
9
+ case 1:
10
+ return intRangeImpl(args[0].start, args[0].end, {
11
+ defaultValue: args[0].defaultValue,
12
+ typeName: args[0].typeName
13
+ });
14
+ case 2:
15
+ return intRangeImpl(args[0], args[1]);
16
+ case 3:
17
+ return intRangeImpl(args[0], args[1], args[2]);
18
+ }
19
+ };
20
+ const intRangeImpl = (start, end, options) => {
21
+ const typeNameFilled = options?.typeName ?? `intRange(${start}, ${end})`;
12
22
  const getDefaultValue = memoizeFunction(
13
23
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
14
- () => options.defaultValue ?? start
24
+ () => options?.defaultValue ?? start
15
25
  );
16
26
  const validate = (a) => {
17
27
  if (!(isNumber(a) && Number.isSafeInteger(a) && Num.isInRange(start, end)(a))) {
@@ -1 +1 @@
1
- {"version":3,"file":"int-range.mjs","sources":["../../src/enum/int-range.mts"],"sourcesContent":["import {\n expectType,\n isNumber,\n memoizeFunction,\n Num,\n Result,\n} from 'ts-data-forge';\nimport {\n type BoolAnd,\n type Index,\n type IndexInclusive,\n type Int8,\n type NegativeIndex,\n type TypeExtends,\n type UintRange,\n} from 'ts-type-forge';\nimport { type Type } from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const intRange = <Start extends Int8, End extends Int8 | 128>({\n end,\n start,\n ...options\n}: Readonly<{\n start: Start;\n end: End;\n typeName?: string;\n defaultValue?: IntRange<Start, End>;\n}>): Type<IntRange<Start, End>> => {\n type T = IntRange<Start, End>;\n\n const typeNameFilled = options.typeName ?? `intRange(${start}, ${end})`;\n\n const getDefaultValue = memoizeFunction(\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (): T => options.defaultValue ?? (start as T),\n );\n\n const validate: Type<T>['validate'] = (a) => {\n if (!(\n isNumber(a) &&\n Number.isSafeInteger(a) &&\n Num.isInRange(start, end)(a)\n )) {\n return Result.err([\n {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'integer-range',\n start,\n endExclusive: end,\n },\n } satisfies ValidationError,\n ]);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : getDefaultValue());\n\n return {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultValue();\n },\n fill,\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n };\n};\n\ntype NegativeRange = NegativeIndex<128>;\n\ntype PositiveRange = IndexInclusive<128>;\n\nexport type IntRange<Start extends Int8, End extends Int8 | 128> =\n BoolAnd<\n TypeExtends<Start, PositiveRange>,\n TypeExtends<End, PositiveRange>\n > extends true\n ? UintRange<Start, End>\n : BoolAnd<\n TypeExtends<Start, NegativeRange>,\n TypeExtends<End, PositiveRange>\n > extends true\n ? NegativeIndex<NegativeToPositive<Start>> | Index<End>\n : BoolAnd<\n TypeExtends<Start, PositiveRange>,\n TypeExtends<End, NegativeRange>\n > extends true\n ? never\n : BoolAnd<\n TypeExtends<Start, NegativeRange>,\n TypeExtends<End, NegativeRange>\n > extends true\n ? Exclude<\n NegativeIndex<NegativeToPositive<Start>>,\n NegativeIndex<NegativeToPositive<End>>\n >\n : never;\n\ntype NegativeToPositive<N extends number> =\n `${N}` extends `-${infer D extends number}` ? D : never;\n\nexpectType<NegativeToPositive<-3>, 3>('=');\n\nexpectType<IntRange<1, 5>, 1 | 2 | 3 | 4>('=');\n\nexpectType<IntRange<-3, 3>, -3 | -2 | -1 | 0 | 1 | 2>('=');\n\nexpectType<IntRange<3, -3>, never>('=');\n\nexpectType<IntRange<-5, -1>, -5 | -4 | -3 | -2>('=');\n"],"names":[],"mappings":";;;;;AAwBO,MAAM,WAAW,CAA6C;AAAA,EACnE,GAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAG;AACL,CAAA,KAKmC;AAGjC,EAAA,MAAM,iBAAiB,OAAA,CAAQ,QAAA,IAAY,CAAA,SAAA,EAAY,KAAK,KAAK,GAAG,CAAA,CAAA,CAAA;AAEpE,EAAA,MAAM,eAAA,GAAkB,eAAA;AAAA;AAAA,IAEtB,MAAS,QAAQ,YAAA,IAAiB;AAAA,GACpC;AAEA,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KAAM;AAC3C,IAAA,IAAI,EACF,QAAA,CAAS,CAAC,CAAA,IACV,OAAO,aAAA,CAAc,CAAC,CAAA,IACtB,GAAA,CAAI,SAAA,CAAU,KAAA,EAAO,GAAG,CAAA,CAAE,CAAC,CAAA,CAAA,EAC1B;AACD,MAAA,OAAO,OAAO,GAAA,CAAI;AAAA,QAChB;AAAA,UACE,MAAM,EAAC;AAAA,UACP,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,cAAA;AAAA,UACd,QAAA,EAAU,cAAA;AAAA,UACV,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,eAAA;AAAA,YACN,KAAA;AAAA,YACA,YAAA,EAAc;AAAA;AAChB;AACF,OACD,CAAA;AAAA,IAAA;AAIH,IAAA,OAAO,MAAA,CAAO,GAAG,CAAM,CAAA;AAAA,EAAA,CACzB;AAEA,EAAA,MAAM,EAAA,GAAK,WAAc,QAAQ,CAAA;AAEjC,EAAA,MAAM,OAAwB,CAAC,CAAA,KAAO,GAAG,CAAC,CAAA,GAAI,IAAI,eAAA,EAAgB;AAElE,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,cAAA;AAAA,IACV,IAAI,YAAA,GAAe;AACjB,MAAA,OAAO,eAAA,EAAgB;AAAA,IAAA,CACzB;AAAA,IACA,IAAA;AAAA,IACA,KAAA,EAAO,CAAC,CAAA,KAAM,CAAA;AAAA,IACd,QAAA;AAAA,IACA,EAAA;AAAA,IACA,QAAA,EAAU,eAAe,QAAQ,CAAA;AAAA,IACjC,IAAA,EAAM,aAAa,QAAQ;AAAA,GAC7B;AACF;;;;"}
1
+ {"version":3,"file":"int-range.mjs","sources":["../../src/enum/int-range.mts"],"sourcesContent":["import { isNumber, memoizeFunction, Num, Result } from 'ts-data-forge';\nimport { type Int11, type IntRange } from 'ts-type-forge';\nimport { type Type } from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport type { IntRange } from 'ts-type-forge';\n\nexport const intRange = <Start extends Int11, End extends Int11 | 1024>(\n ...args:\n | readonly [\n start: Start,\n end: End,\n options?: Readonly<{\n typeName?: string;\n defaultValue?: IntRange<Start, End>;\n }>,\n ]\n | readonly [\n options: Readonly<{\n start: Start;\n end: End;\n typeName?: string;\n defaultValue?: IntRange<Start, End>;\n }>,\n ]\n): Type<IntRange<Start, End>> => {\n switch (args.length) {\n case 1:\n return intRangeImpl(args[0].start, args[0].end, {\n defaultValue: args[0].defaultValue,\n typeName: args[0].typeName,\n });\n\n case 2:\n return intRangeImpl(args[0], args[1]);\n\n case 3:\n return intRangeImpl(args[0], args[1], args[2]);\n }\n};\n\nconst intRangeImpl = <Start extends Int11, End extends Int11 | 1024>(\n start: Start,\n end: End,\n options?: Readonly<{\n typeName?: string;\n defaultValue?: IntRange<Start, End>;\n }>,\n): Type<IntRange<Start, End>> => {\n type T = IntRange<Start, End>;\n\n const typeNameFilled = options?.typeName ?? `intRange(${start}, ${end})`;\n\n const getDefaultValue = memoizeFunction(\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (): T => options?.defaultValue ?? (start as T),\n );\n\n const validate: Type<T>['validate'] = (a) => {\n if (!(\n isNumber(a) &&\n Number.isSafeInteger(a) &&\n Num.isInRange(start, end)(a)\n )) {\n return Result.err([\n {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'integer-range',\n start,\n endExclusive: end,\n },\n } satisfies ValidationError,\n ]);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : getDefaultValue());\n\n return {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultValue();\n },\n fill,\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n };\n};\n"],"names":[],"mappings":";;;;;;AAYO,MAAM,QAAA,GAAW,IACnB,IAAA,KAiB4B;AAC/B,EAAA,QAAQ,KAAK,MAAA;AAAQ,IACnB,KAAK,CAAA;AACH,MAAA,OAAO,YAAA,CAAa,KAAK,CAAC,CAAA,CAAE,OAAO,IAAA,CAAK,CAAC,EAAE,GAAA,EAAK;AAAA,QAC9C,YAAA,EAAc,IAAA,CAAK,CAAC,CAAA,CAAE,YAAA;AAAA,QACtB,QAAA,EAAU,IAAA,CAAK,CAAC,CAAA,CAAE;AAAA,OACnB,CAAA;AAAA,IAEH,KAAK,CAAA;AACH,MAAA,OAAO,aAAa,IAAA,CAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,IAEtC,KAAK,CAAA;AACH,MAAA,OAAO,YAAA,CAAa,KAAK,CAAC,CAAA,EAAG,KAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA;AAEnD;AAEA,MAAM,YAAA,GAAe,CACnB,KAAA,EACA,GAAA,EACA,OAAA,KAI+B;AAG/B,EAAA,MAAM,iBAAiB,OAAA,EAAS,QAAA,IAAY,CAAA,SAAA,EAAY,KAAK,KAAK,GAAG,CAAA,CAAA,CAAA;AAErE,EAAA,MAAM,eAAA,GAAkB,eAAA;AAAA;AAAA,IAEtB,MAAS,SAAS,YAAA,IAAiB;AAAA,GACrC;AAEA,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KAAM;AAC3C,IAAA,IAAI,EACF,QAAA,CAAS,CAAC,CAAA,IACV,OAAO,aAAA,CAAc,CAAC,CAAA,IACtB,GAAA,CAAI,SAAA,CAAU,KAAA,EAAO,GAAG,CAAA,CAAE,CAAC,CAAA,CAAA,EAC1B;AACD,MAAA,OAAO,OAAO,GAAA,CAAI;AAAA,QAChB;AAAA,UACE,MAAM,EAAC;AAAA,UACP,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,cAAA;AAAA,UACd,QAAA,EAAU,cAAA;AAAA,UACV,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,eAAA;AAAA,YACN,KAAA;AAAA,YACA,YAAA,EAAc;AAAA;AAChB;AACF,OACD,CAAA;AAAA,IACH;AAGA,IAAA,OAAO,MAAA,CAAO,GAAG,CAAM,CAAA;AAAA,EACzB,CAAA;AAEA,EAAA,MAAM,EAAA,GAAK,WAAc,QAAQ,CAAA;AAEjC,EAAA,MAAM,OAAwB,CAAC,CAAA,KAAO,GAAG,CAAC,CAAA,GAAI,IAAI,eAAA,EAAgB;AAElE,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,cAAA;AAAA,IACV,IAAI,YAAA,GAAe;AACjB,MAAA,OAAO,eAAA,EAAgB;AAAA,IACzB,CAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA,EAAO,CAAC,CAAA,KAAM,CAAA;AAAA,IACd,QAAA;AAAA,IACA,EAAA;AAAA,IACA,QAAA,EAAU,eAAe,QAAQ,CAAA;AAAA,IACjC,IAAA,EAAM,aAAa,QAAQ;AAAA,GAC7B;AACF,CAAA;;;;"}
@@ -0,0 +1,13 @@
1
+ import { type Uint11, type UintRangeInclusive } from 'ts-type-forge';
2
+ import { type Type } from '../type.mjs';
3
+ export type { UintRangeInclusive } from 'ts-type-forge';
4
+ export declare const uintRangeInclusive: <Start extends Uint11, End extends Uint11>(...args: readonly [start: Start, end: End, options?: Readonly<{
5
+ typeName?: string;
6
+ defaultValue?: UintRangeInclusive<Start, End>;
7
+ }>] | readonly [options: Readonly<{
8
+ start: Start;
9
+ end: End;
10
+ typeName?: string;
11
+ defaultValue?: UintRangeInclusive<Start, End>;
12
+ }>]) => Type<UintRangeInclusive<Start, End>>;
13
+ //# sourceMappingURL=uint-range-inclusive.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uint-range-inclusive.d.mts","sourceRoot":"","sources":["../../src/enum/uint-range-inclusive.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAQxC,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,WAErE,SAAS,CACP,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CAC/C,CAAC,CACH,GACD,SAAS,CACP,OAAO,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;CAC/C,CAAC,CACH,KACJ,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAcrC,CAAC"}