@modulify/validator 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/README.md +12 -2
- package/dist/assert.cjs +99 -63
- package/dist/assert.d.cts +37 -0
- package/dist/assert.d.mts +37 -0
- package/dist/assert.d.ts +24 -3
- package/dist/assert.mjs +94 -64
- package/dist/assertions.cjs +283 -178
- package/dist/assertions.d.cts +56 -0
- package/dist/assertions.d.mts +56 -0
- package/dist/assertions.d.ts +43 -45
- package/dist/assertions.mjs +274 -201
- package/dist/checkers.cjs +23 -0
- package/dist/checkers.d.cts +8 -0
- package/dist/checkers.d.mts +8 -0
- package/dist/checkers.d.ts +1 -1
- package/dist/checkers.mjs +16 -0
- package/dist/combinators.cjs +305 -304
- package/dist/combinators.d.cts +16 -0
- package/dist/combinators.d.mts +16 -0
- package/dist/combinators.d.ts +15 -16
- package/dist/combinators.mjs +305 -314
- package/dist/constraints.cjs +23 -0
- package/dist/constraints.d.cts +4 -0
- package/dist/constraints.d.mts +4 -0
- package/dist/constraints.d.ts +2 -2
- package/dist/constraints.mjs +21 -0
- package/dist/extractors.cjs +6 -0
- package/dist/extractors.d.cts +2 -0
- package/dist/extractors.d.mts +2 -0
- package/dist/extractors.mjs +5 -0
- package/dist/index.cjs +140 -219
- package/dist/index.d.cts +12 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.mjs +93 -222
- package/dist/json-schema.cjs +364 -489
- package/dist/json-schema.d.cts +14 -0
- package/dist/json-schema.d.mts +14 -0
- package/dist/json-schema.d.ts +3 -3
- package/dist/json-schema.mjs +365 -492
- package/dist/metadata.cjs +98 -7
- package/dist/metadata.d.cts +8 -0
- package/dist/metadata.d.mts +8 -0
- package/dist/metadata.d.ts +2 -2
- package/dist/metadata.mjs +93 -7
- package/dist/predicates.cjs +98 -41
- package/dist/predicates.d.cts +77 -0
- package/dist/predicates.d.mts +77 -0
- package/dist/predicates.d.ts +25 -4
- package/dist/predicates.mjs +92 -66
- package/dist/types/index.d.cts +984 -0
- package/dist/types/index.d.mts +984 -0
- package/dist/types/index.d.ts +984 -0
- package/dist/types/json-schema.d.cts +75 -0
- package/dist/types/json-schema.d.mts +75 -0
- package/dist/types/json-schema.d.ts +75 -0
- package/dist/violations.cjs +81 -0
- package/dist/violations.d.cts +29 -0
- package/dist/violations.d.mts +29 -0
- package/dist/violations.d.ts +1 -1
- package/dist/violations.mjs +80 -0
- package/docs/RELEASING.md +66 -0
- package/docs/en/00-index.md +2 -0
- package/docs/en/01-shape-api.md +35 -10
- package/docs/en/02-metadata-and-introspection.md +2 -1
- package/docs/en/03-violations.md +1 -1
- package/docs/en/04-json-schema-export.md +5 -0
- package/docs/en/05-public-api.md +35 -3
- package/docs/en/06-common-recipes.md +2 -1
- package/docs/en/07-ai-reference.md +5 -2
- package/docs/en/08-violation-code-types.md +28 -2
- package/docs/en/09-migration.md +75 -0
- package/docs/ru/00-index.md +2 -0
- package/docs/ru/01-shape-api.md +35 -10
- package/docs/ru/02-metadata-and-introspection.md +2 -1
- package/docs/ru/03-violations.md +1 -1
- package/docs/ru/04-json-schema-export.md +5 -0
- package/docs/ru/05-public-api.md +35 -3
- package/docs/ru/06-common-recipes.md +2 -1
- package/docs/ru/07-ai-reference.md +5 -2
- package/docs/ru/08-violation-code-types.md +28 -2
- package/docs/ru/09-migration.md +76 -0
- package/docs/ru/README.md +10 -2
- package/package.json +63 -37
- package/types/index.d.ts +275 -115
- package/dist/metadata.cjs.js +0 -130
- package/dist/metadata.es.js +0 -131
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
/** Internal utility that intersects all members of a tuple into a single type. */
|
|
2
|
+
export type Intersect<T extends readonly unknown[]> =
|
|
3
|
+
T extends readonly [infer First, ...infer Rest extends readonly unknown[]]
|
|
4
|
+
? First & Intersect<Rest>
|
|
5
|
+
: unknown;
|
|
6
|
+
|
|
7
|
+
/** Internal utility that converts a union like `A | B` into `A & B`. */
|
|
8
|
+
export type UnionToIntersection<T> =
|
|
9
|
+
(T extends unknown ? (value: T) => void : never) extends (value: infer I) => void
|
|
10
|
+
? I
|
|
11
|
+
: never;
|
|
12
|
+
|
|
13
|
+
/** Internal helper for nested validation results. */
|
|
14
|
+
export type Recursive<T> = T | Recursive<T>[]
|
|
15
|
+
|
|
16
|
+
/** Accepts either a single value or an array of values. */
|
|
17
|
+
export type MaybeMany<V> = V | readonly V[]
|
|
18
|
+
/** Accepts either a plain value or a promise of that value. */
|
|
19
|
+
export type MaybePromise<V> = V | Promise<V>
|
|
20
|
+
|
|
21
|
+
/** Runtime predicate that also acts as a TypeScript type guard. */
|
|
22
|
+
export type Predicate<T = unknown> = (value: unknown) => value is T
|
|
23
|
+
|
|
24
|
+
/** Checker used by assertion constraints after a value is extracted. */
|
|
25
|
+
export type Checker<T, A extends readonly unknown[] = readonly unknown[]> = (value: T, ...args: A) => boolean
|
|
26
|
+
|
|
27
|
+
/** Extracts a derived value from the original input before a checker runs. */
|
|
28
|
+
export type Extractor<T, V> = (value: T) => V
|
|
29
|
+
|
|
30
|
+
/** Public stage marker for assertion pipelines. */
|
|
31
|
+
export type AssertionStage = 'guard' | 'refinement'
|
|
32
|
+
|
|
33
|
+
/** Origin layer that produced a violation. */
|
|
34
|
+
export type ViolationKind = 'assertion' | 'validator' | 'runtime'
|
|
35
|
+
|
|
36
|
+
/** Contract stored in `ViolationCodeRegistry` for a known machine-readable code. */
|
|
37
|
+
export type ViolationCodeEntry<
|
|
38
|
+
K extends ViolationKind = ViolationKind,
|
|
39
|
+
N extends string = string,
|
|
40
|
+
A extends readonly unknown[] = readonly unknown[],
|
|
41
|
+
> = {
|
|
42
|
+
kind: K;
|
|
43
|
+
name: N;
|
|
44
|
+
args: A;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type ResolveViolationEntry<E> =
|
|
48
|
+
[E] extends [never]
|
|
49
|
+
? ViolationCodeEntry
|
|
50
|
+
: E extends ViolationCodeEntry
|
|
51
|
+
? E
|
|
52
|
+
: ViolationCodeEntry
|
|
53
|
+
|
|
54
|
+
type ResolveViolationSubjectCode<COrT extends string | readonly unknown[]> = COrT extends string ? COrT : string
|
|
55
|
+
type ResolveViolationSubjectArgs<COrT extends string | readonly unknown[], C extends string> = [COrT] extends [readonly unknown[]]
|
|
56
|
+
? COrT
|
|
57
|
+
: ViolationArgs<C>
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extensible registry of machine-readable violation codes.
|
|
61
|
+
*
|
|
62
|
+
* Consumers can augment this interface in their app code:
|
|
63
|
+
* `declare module '@modulify/validator' { interface ViolationCodeRegistry { 'app.user.conflict': ViolationCodeEntry<'validator', 'user', readonly []> } }`
|
|
64
|
+
*
|
|
65
|
+
* Legacy `never` markers remain supported as a fallback for gradual migration:
|
|
66
|
+
* `declare module '@modulify/validator' { interface ViolationCodeRegistry { 'legacy.code': never } }`
|
|
67
|
+
*/
|
|
68
|
+
export interface ViolationCodeRegistry {
|
|
69
|
+
'date.valid': ViolationCodeEntry<'assertion', 'isValidDate', readonly []>;
|
|
70
|
+
'length.exact': ViolationCodeEntry<'assertion', 'hasLength', readonly [exact: number]>;
|
|
71
|
+
'length.max': ViolationCodeEntry<'assertion', 'hasLength', readonly [max: number]>;
|
|
72
|
+
'length.min': ViolationCodeEntry<'assertion', 'hasLength', readonly [min: number]>;
|
|
73
|
+
'length.range': ViolationCodeEntry<'assertion', 'hasLength', readonly [range: readonly [number, number]]>;
|
|
74
|
+
'length.unsupported-type': ViolationCodeEntry<'assertion', 'hasLength', readonly []>;
|
|
75
|
+
'number.exact': ViolationCodeEntry<'assertion', 'hasValue', readonly [exact: number]>;
|
|
76
|
+
'number.finite': ViolationCodeEntry<'assertion', 'isFiniteNumber', readonly []>;
|
|
77
|
+
'number.integer': ViolationCodeEntry<'assertion', 'isInteger', readonly []>;
|
|
78
|
+
'number.max': ViolationCodeEntry<'assertion', 'hasValue', readonly [max: number]>;
|
|
79
|
+
'number.min': ViolationCodeEntry<'assertion', 'hasValue', readonly [min: number]>;
|
|
80
|
+
'number.multiple-of': ViolationCodeEntry<'assertion', 'multipleOf', readonly [step: number]>;
|
|
81
|
+
'number.nan': ViolationCodeEntry<'assertion', 'isNaN', readonly []>;
|
|
82
|
+
'number.range': ViolationCodeEntry<'assertion', 'hasValue', readonly [range: readonly [number, number]]>;
|
|
83
|
+
'number.safe-integer': ViolationCodeEntry<'assertion', 'isSafeInteger', readonly []>;
|
|
84
|
+
'number.unsupported-type': ViolationCodeEntry<'assertion', 'hasValue' | 'multipleOf', readonly []>;
|
|
85
|
+
'runtime.rejection': ViolationCodeEntry<'runtime', 'validate', readonly [reason: unknown]>;
|
|
86
|
+
'shape.fields.mismatch': ViolationCodeEntry<
|
|
87
|
+
'validator',
|
|
88
|
+
'shape',
|
|
89
|
+
readonly [selectors: readonly [ShapeFieldSelector, ShapeFieldSelector]]
|
|
90
|
+
>;
|
|
91
|
+
'shape.unknown-key': ViolationCodeEntry<'validator', 'shape', readonly []>;
|
|
92
|
+
'size.exact': ViolationCodeEntry<'assertion', 'hasSize', readonly [exact: number]>;
|
|
93
|
+
'size.max': ViolationCodeEntry<'assertion', 'hasSize', readonly [max: number]>;
|
|
94
|
+
'size.min': ViolationCodeEntry<'assertion', 'hasSize', readonly [min: number]>;
|
|
95
|
+
'size.range': ViolationCodeEntry<'assertion', 'hasSize', readonly [range: readonly [number, number]]>;
|
|
96
|
+
'size.unsupported-type': ViolationCodeEntry<'assertion', 'hasSize', readonly []>;
|
|
97
|
+
'string.email': ViolationCodeEntry<'assertion', 'isEmail', readonly []>;
|
|
98
|
+
'string.ends-with': ViolationCodeEntry<'assertion', 'endsWith', readonly [suffix: string]>;
|
|
99
|
+
'string.pattern': ViolationCodeEntry<'assertion', 'hasPattern', readonly [pattern: RegExp]>;
|
|
100
|
+
'string.starts-with': ViolationCodeEntry<'assertion', 'startsWith', readonly [prefix: string]>;
|
|
101
|
+
'string.unsupported-type': ViolationCodeEntry<
|
|
102
|
+
'assertion',
|
|
103
|
+
'hasPattern' | 'startsWith' | 'endsWith',
|
|
104
|
+
readonly []
|
|
105
|
+
>;
|
|
106
|
+
'tuple.length': ViolationCodeEntry<'validator', 'tuple', readonly [length: number]>;
|
|
107
|
+
'type.array': ViolationCodeEntry<'validator', 'each' | 'tuple', readonly []>;
|
|
108
|
+
'type.bigint': ViolationCodeEntry<'assertion', 'isBigInt', readonly []>;
|
|
109
|
+
'type.blob': ViolationCodeEntry<'assertion', 'isBlob', readonly []>;
|
|
110
|
+
'type.boolean': ViolationCodeEntry<'assertion', 'isBoolean', readonly []>;
|
|
111
|
+
'type.date': ViolationCodeEntry<'assertion', 'isDate', readonly []>;
|
|
112
|
+
'type.error': ViolationCodeEntry<'assertion', 'isError', readonly []>;
|
|
113
|
+
'type.file': ViolationCodeEntry<'assertion', 'isFile', readonly []>;
|
|
114
|
+
'type.function': ViolationCodeEntry<'assertion', 'isFunction', readonly []>;
|
|
115
|
+
'type.map': ViolationCodeEntry<'assertion', 'isMap', readonly []>;
|
|
116
|
+
'type.null': ViolationCodeEntry<'assertion', 'isNull', readonly []>;
|
|
117
|
+
'type.number': ViolationCodeEntry<'assertion', 'isNumber', readonly []>;
|
|
118
|
+
'type.promise-like': ViolationCodeEntry<'assertion', 'isPromiseLike', readonly []>;
|
|
119
|
+
'type.record': ViolationCodeEntry<'validator', 'shape' | 'discriminatedUnion' | 'record', readonly []>;
|
|
120
|
+
'type.regexp': ViolationCodeEntry<'assertion', 'isRegExp', readonly []>;
|
|
121
|
+
'type.set': ViolationCodeEntry<'assertion', 'isSet', readonly []>;
|
|
122
|
+
'type.string': ViolationCodeEntry<'assertion', 'isString', readonly []>;
|
|
123
|
+
'type.symbol': ViolationCodeEntry<'assertion', 'isSymbol', readonly []>;
|
|
124
|
+
'union.invalid-discriminator': ViolationCodeEntry<
|
|
125
|
+
'validator',
|
|
126
|
+
'discriminatedUnion',
|
|
127
|
+
readonly [variants: readonly PropertyKey[]]
|
|
128
|
+
>;
|
|
129
|
+
'union.no-match': ViolationCodeEntry<'validator', 'union', readonly [branches: number]>;
|
|
130
|
+
'value.defined': ViolationCodeEntry<'assertion', 'isDefined', readonly []>;
|
|
131
|
+
'value.exact': ViolationCodeEntry<'assertion', 'exact', readonly [expected: unknown]>;
|
|
132
|
+
'value.one-of': ViolationCodeEntry<'assertion', 'oneOf', readonly [values: readonly unknown[]]>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Union of all registered machine-readable violation codes. */
|
|
136
|
+
export type ViolationCode = Extract<keyof ViolationCodeRegistry, string>
|
|
137
|
+
|
|
138
|
+
/** Registered codes that provide a full contract entry instead of a legacy `never` marker. */
|
|
139
|
+
export type KnownViolationCode = Extract<{
|
|
140
|
+
[C in ViolationCode]:
|
|
141
|
+
[ViolationCodeRegistry[C]] extends [never]
|
|
142
|
+
? never
|
|
143
|
+
: ViolationCodeRegistry[C] extends ViolationCodeEntry
|
|
144
|
+
? C
|
|
145
|
+
: never
|
|
146
|
+
}[ViolationCode], string>
|
|
147
|
+
|
|
148
|
+
/** Contract entry derived from `ViolationCodeRegistry`, with a generic fallback for unknown or legacy codes. */
|
|
149
|
+
export type ViolationEntry<C extends string = string> = C extends ViolationCode
|
|
150
|
+
? ResolveViolationEntry<ViolationCodeRegistry[C]>
|
|
151
|
+
: ViolationCodeEntry
|
|
152
|
+
|
|
153
|
+
/** Tuple of machine-readable arguments associated with a violation code. */
|
|
154
|
+
export type ViolationArgs<C extends string = string> = ViolationEntry<C>['args']
|
|
155
|
+
|
|
156
|
+
/** Origin layer associated with a violation code. */
|
|
157
|
+
export type ViolationKindOf<C extends string = string> = ViolationEntry<C>['kind']
|
|
158
|
+
|
|
159
|
+
/** Constraint name associated with a violation code. */
|
|
160
|
+
export type ViolationNameOf<C extends string = string> = ViolationEntry<C>['name']
|
|
161
|
+
|
|
162
|
+
/** Strict code-driven violation subject for a fully registered violation code. */
|
|
163
|
+
export type KnownViolationSubject<C extends KnownViolationCode> = {
|
|
164
|
+
kind: ViolationKindOf<C>;
|
|
165
|
+
name: ViolationNameOf<C>;
|
|
166
|
+
code: C;
|
|
167
|
+
args: ViolationArgs<C>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Machine-readable description of a validation failure. */
|
|
171
|
+
export type ViolationSubject<
|
|
172
|
+
COrT extends string | readonly unknown[] = string,
|
|
173
|
+
K extends ViolationKind = COrT extends string ? ViolationKindOf<COrT> : ViolationKind,
|
|
174
|
+
C extends string = ResolveViolationSubjectCode<COrT>,
|
|
175
|
+
T extends readonly unknown[] = ResolveViolationSubjectArgs<COrT, C>,
|
|
176
|
+
> = [COrT] extends [readonly unknown[]]
|
|
177
|
+
? {
|
|
178
|
+
kind: K;
|
|
179
|
+
name: string;
|
|
180
|
+
code: C;
|
|
181
|
+
args: T;
|
|
182
|
+
}
|
|
183
|
+
: C extends KnownViolationCode
|
|
184
|
+
? {
|
|
185
|
+
kind: K & ViolationKindOf<C>;
|
|
186
|
+
name: ViolationNameOf<C>;
|
|
187
|
+
code: C;
|
|
188
|
+
args: T & ViolationArgs<C>;
|
|
189
|
+
}
|
|
190
|
+
: {
|
|
191
|
+
kind: K;
|
|
192
|
+
name: string;
|
|
193
|
+
code: C;
|
|
194
|
+
args: T;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Structured validation error returned by assertions and composed validators.
|
|
199
|
+
*
|
|
200
|
+
* `path` points to the nested property or array index that failed.
|
|
201
|
+
*
|
|
202
|
+
* Example:
|
|
203
|
+
* `violation.violates.code === 'length.min'`
|
|
204
|
+
*/
|
|
205
|
+
export type Violation<S extends ViolationSubject = ViolationSubject> = {
|
|
206
|
+
value: unknown;
|
|
207
|
+
path?: PropertyKey[];
|
|
208
|
+
violates: S;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Read-only utility wrapper for working with `Violation[]` results. */
|
|
212
|
+
export declare class ViolationCollection<V extends Violation = Violation> implements Iterable<V> {
|
|
213
|
+
constructor(violations: readonly V[]);
|
|
214
|
+
readonly size: number;
|
|
215
|
+
[Symbol.iterator](): Iterator<V>;
|
|
216
|
+
forEach(callback: (violation: V, index: number, collection: ViolationCollection<V>) => void): void;
|
|
217
|
+
map<T>(callback: (violation: V, index: number, collection: ViolationCollection<V>) => T): T[];
|
|
218
|
+
at(path: readonly PropertyKey[]): ViolationCollection<V>;
|
|
219
|
+
tree(): ViolationTreeNode<V>;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Tree node built from a `ViolationCollection` for nested path traversal. */
|
|
223
|
+
export type ViolationTreeNode<V extends Violation = Violation> = {
|
|
224
|
+
readonly path: readonly PropertyKey[];
|
|
225
|
+
readonly self: ViolationCollection<V>;
|
|
226
|
+
readonly subtree: ViolationCollection<V>;
|
|
227
|
+
readonly children: ReadonlyMap<PropertyKey, ViolationTreeNode<V>>;
|
|
228
|
+
at(path: readonly PropertyKey[]): ViolationTreeNode<V> | undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Standard entrypoint for wrapping `Violation[]` into a collection utility API. */
|
|
232
|
+
export declare const collection: <V extends Violation>(violations: readonly V[]) => ViolationCollection<V>
|
|
233
|
+
|
|
234
|
+
/** Read-only machine-readable metadata attached to a constraint. */
|
|
235
|
+
export type ConstraintMetadata = Readonly<Record<string, unknown>>
|
|
236
|
+
|
|
237
|
+
/** Public descriptor entry for additional assertion-level checks. */
|
|
238
|
+
export interface AssertionConstraintDescriptor<
|
|
239
|
+
C extends string = string,
|
|
240
|
+
A extends readonly unknown[] = readonly unknown[],
|
|
241
|
+
> {
|
|
242
|
+
readonly code: C;
|
|
243
|
+
readonly args: A
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Shared descriptor shape returned by `describe(...)`. */
|
|
247
|
+
export interface BaseConstraintDescriptor<K extends string = string> {
|
|
248
|
+
readonly kind: K;
|
|
249
|
+
readonly metadata?: ConstraintMetadata
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Descriptor for leaf assertions created with `assert(...)` or compatible custom assertions. */
|
|
253
|
+
export interface AssertionDescriptor<
|
|
254
|
+
C extends string = string,
|
|
255
|
+
A extends readonly unknown[] = readonly unknown[],
|
|
256
|
+
T extends readonly AssertionConstraintDescriptor[] = readonly AssertionConstraintDescriptor[],
|
|
257
|
+
> extends BaseConstraintDescriptor<'assertion'> {
|
|
258
|
+
readonly name: string;
|
|
259
|
+
readonly bail: boolean;
|
|
260
|
+
readonly code: C;
|
|
261
|
+
readonly args: A;
|
|
262
|
+
readonly constraints: T
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Generic fallback descriptor for custom validators without structural instrumentation. */
|
|
266
|
+
export type OpaqueValidatorDescriptor = BaseConstraintDescriptor<'validator'>
|
|
267
|
+
|
|
268
|
+
/** Public extension descriptor for custom validators that expose their own `describe()` contract. */
|
|
269
|
+
export interface CustomConstraintDescriptor<K extends string = string> extends BaseConstraintDescriptor<K> {
|
|
270
|
+
readonly [key: string]: unknown
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Descriptor for sequential arrays of constraints used in a single slot. */
|
|
274
|
+
export interface AllOfConstraintDescriptor<
|
|
275
|
+
T extends readonly unknown[] = readonly ConstraintDescriptor[],
|
|
276
|
+
> extends BaseConstraintDescriptor<'allOf'> {
|
|
277
|
+
readonly constraints: T
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Descriptor for wrapper combinators such as `optional(...)`. */
|
|
281
|
+
export interface WrapperConstraintDescriptor<
|
|
282
|
+
K extends 'optional' | 'nullable' | 'nullish' = 'optional' | 'nullable' | 'nullish',
|
|
283
|
+
C = ConstraintDescriptor,
|
|
284
|
+
> extends BaseConstraintDescriptor<K> {
|
|
285
|
+
readonly child: C
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** Descriptor for `each(...)`. */
|
|
289
|
+
export interface EachConstraintDescriptor<
|
|
290
|
+
C = ConstraintDescriptor,
|
|
291
|
+
> extends BaseConstraintDescriptor<'each'> {
|
|
292
|
+
readonly item: C
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Descriptor for `tuple(...)`. */
|
|
296
|
+
export interface TupleConstraintDescriptor<
|
|
297
|
+
T extends readonly unknown[] = readonly ConstraintDescriptor[],
|
|
298
|
+
> extends BaseConstraintDescriptor<'tuple'> {
|
|
299
|
+
readonly items: T
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Descriptor for `union(...)`. */
|
|
303
|
+
export interface UnionConstraintDescriptor<
|
|
304
|
+
T extends readonly unknown[] = readonly ConstraintDescriptor[],
|
|
305
|
+
> extends BaseConstraintDescriptor<'union'> {
|
|
306
|
+
readonly branches: T
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Descriptor for `record(...)`. */
|
|
310
|
+
export interface RecordConstraintDescriptor<
|
|
311
|
+
C = ConstraintDescriptor,
|
|
312
|
+
> extends BaseConstraintDescriptor<'record'> {
|
|
313
|
+
readonly values: C
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Descriptor for `discriminatedUnion(...)`. */
|
|
317
|
+
export interface DiscriminatedUnionConstraintDescriptor<
|
|
318
|
+
V = Readonly<Record<PropertyKey, ConstraintDescriptor>>,
|
|
319
|
+
> extends BaseConstraintDescriptor<'discriminatedUnion'> {
|
|
320
|
+
readonly key: PropertyKey;
|
|
321
|
+
readonly variants: V
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Machine-readable summary of object-level rules registered on a shape. */
|
|
325
|
+
export interface ObjectShapeRuleDescriptorBase<K extends string = string> {
|
|
326
|
+
readonly kind: K;
|
|
327
|
+
readonly metadata?: ConstraintMetadata
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Generic compact descriptor for sync-safe object-level rules. */
|
|
331
|
+
export type SyncObjectShapeRuleDescriptor<
|
|
332
|
+
K extends string = 'refine',
|
|
333
|
+
> = ObjectShapeRuleDescriptorBase<K>
|
|
334
|
+
|
|
335
|
+
/** Compact descriptor for object-level rules registered through the async-first `.refine(...)` API. */
|
|
336
|
+
export interface AsyncObjectShapeRuleDescriptor<
|
|
337
|
+
K extends string = 'refine',
|
|
338
|
+
> extends ObjectShapeRuleDescriptorBase<K> {
|
|
339
|
+
readonly async: true
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Descriptor for the built-in `.fieldsMatch(...)` helper. */
|
|
343
|
+
export interface FieldsMatchObjectShapeRuleDescriptor<
|
|
344
|
+
Left extends ShapeFieldSelector = ShapeFieldSelector,
|
|
345
|
+
Right extends ShapeFieldSelector = ShapeFieldSelector,
|
|
346
|
+
> extends ObjectShapeRuleDescriptorBase<'fieldsMatch'> {
|
|
347
|
+
readonly selectors: readonly [Left, Right]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Machine-readable summary of object-level rules registered on a shape. */
|
|
351
|
+
export type ObjectShapeRuleDescriptor =
|
|
352
|
+
| SyncObjectShapeRuleDescriptor<string>
|
|
353
|
+
| AsyncObjectShapeRuleDescriptor<string>
|
|
354
|
+
| FieldsMatchObjectShapeRuleDescriptor
|
|
355
|
+
|
|
356
|
+
/** Descriptor for `shape(...)`. */
|
|
357
|
+
export interface ShapeConstraintDescriptor<
|
|
358
|
+
F = Readonly<Record<PropertyKey, ConstraintDescriptor>>,
|
|
359
|
+
R extends readonly ObjectShapeRuleDescriptor[] = readonly ObjectShapeRuleDescriptor[],
|
|
360
|
+
> extends BaseConstraintDescriptor<'shape'> {
|
|
361
|
+
readonly unknownKeys: UnknownKeysMode;
|
|
362
|
+
readonly fields: F;
|
|
363
|
+
readonly rules: R
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Stable machine-readable description of a constraint tree. */
|
|
367
|
+
export type BuiltInConstraintDescriptor =
|
|
368
|
+
| AssertionDescriptor
|
|
369
|
+
| AllOfConstraintDescriptor
|
|
370
|
+
| OpaqueValidatorDescriptor
|
|
371
|
+
| WrapperConstraintDescriptor
|
|
372
|
+
| EachConstraintDescriptor
|
|
373
|
+
| TupleConstraintDescriptor
|
|
374
|
+
| UnionConstraintDescriptor
|
|
375
|
+
| RecordConstraintDescriptor
|
|
376
|
+
| DiscriminatedUnionConstraintDescriptor
|
|
377
|
+
| ShapeConstraintDescriptor
|
|
378
|
+
|
|
379
|
+
/** Stable machine-readable description of a constraint tree. */
|
|
380
|
+
export type ConstraintDescriptor = BuiltInConstraintDescriptor | CustomConstraintDescriptor
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Extra checker pipeline for an assertion.
|
|
384
|
+
*
|
|
385
|
+
* Example:
|
|
386
|
+
* `type LengthConstraint = AssertionConstraint<string, number, [min: number], 'length.min'>`
|
|
387
|
+
*/
|
|
388
|
+
export type AssertionConstraint<
|
|
389
|
+
// Defaults erase heterogeneous checker signatures; concrete tuples retain their types.
|
|
390
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
391
|
+
T = any,
|
|
392
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
393
|
+
V = any,
|
|
394
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
395
|
+
A extends readonly unknown[] = any[],
|
|
396
|
+
C extends string = string
|
|
397
|
+
> = readonly [
|
|
398
|
+
Extractor<T, V>,
|
|
399
|
+
Checker<V, A>,
|
|
400
|
+
C,
|
|
401
|
+
...A
|
|
402
|
+
]
|
|
403
|
+
|
|
404
|
+
/** Maps an assertion checker tuple into its public descriptor entry. */
|
|
405
|
+
export type DescribeAssertionConstraint<C extends AssertionConstraint> =
|
|
406
|
+
C extends readonly [unknown, unknown, infer Code extends string, ...infer A]
|
|
407
|
+
? AssertionConstraintDescriptor<Code, A>
|
|
408
|
+
: never
|
|
409
|
+
|
|
410
|
+
/** Maps an assertion checker tuple into the violation subject it can produce. */
|
|
411
|
+
export type AssertionConstraintSubject<C extends AssertionConstraint, N extends string = string> =
|
|
412
|
+
C extends readonly [unknown, unknown, infer Code extends string, ...infer A]
|
|
413
|
+
? {
|
|
414
|
+
kind: 'assertion';
|
|
415
|
+
name: N;
|
|
416
|
+
code: Code;
|
|
417
|
+
args: A;
|
|
418
|
+
}
|
|
419
|
+
: never
|
|
420
|
+
|
|
421
|
+
/** Maps assertion checker tuples into their public descriptor entries. */
|
|
422
|
+
export type DescribeAssertionConstraintTuple<T extends readonly AssertionConstraint[]> = {
|
|
423
|
+
readonly [K in keyof T]: T[K] extends AssertionConstraint
|
|
424
|
+
? DescribeAssertionConstraint<T[K]>
|
|
425
|
+
: never
|
|
426
|
+
} & ReadonlyArray<DescribeAssertionConstraint<T[number]>>
|
|
427
|
+
|
|
428
|
+
declare const assertionStageBrand: unique symbol
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Leaf-level validator that checks a single value and either succeeds with `null`
|
|
432
|
+
* or returns a structured violation.
|
|
433
|
+
*
|
|
434
|
+
* `check` is the synchronous type guard used for inference and sync narrowing.
|
|
435
|
+
*/
|
|
436
|
+
export type Assertion<
|
|
437
|
+
T = unknown,
|
|
438
|
+
C extends readonly AssertionConstraint[] = readonly AssertionConstraint[],
|
|
439
|
+
Code extends string = string,
|
|
440
|
+
A extends readonly unknown[] = readonly unknown[],
|
|
441
|
+
Name extends string = string,
|
|
442
|
+
Stage extends AssertionStage = AssertionStage,
|
|
443
|
+
> = ((value: unknown) => MaybePromise<Omit<Violation<
|
|
444
|
+
Stage extends 'refinement'
|
|
445
|
+
? AssertionConstraintSubject<C[number], Name>
|
|
446
|
+
: {
|
|
447
|
+
kind: 'assertion';
|
|
448
|
+
name: Name;
|
|
449
|
+
code: Code;
|
|
450
|
+
args: A;
|
|
451
|
+
} | AssertionConstraintSubject<C[number], Name>
|
|
452
|
+
>, 'path'> | null>) & {
|
|
453
|
+
readonly name: Name;
|
|
454
|
+
readonly bail: boolean;
|
|
455
|
+
readonly constraints: C;
|
|
456
|
+
readonly check: Predicate<T>;
|
|
457
|
+
readonly [assertionStageBrand]: Stage;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** Assertion stage that establishes the base domain for subsequent checks. */
|
|
461
|
+
export type Guard<
|
|
462
|
+
T = unknown,
|
|
463
|
+
C extends readonly AssertionConstraint[] = readonly AssertionConstraint[],
|
|
464
|
+
Code extends string = string,
|
|
465
|
+
A extends readonly unknown[] = readonly unknown[],
|
|
466
|
+
Name extends string = string,
|
|
467
|
+
> = Assertion<T, C, Code, A, Name, 'guard'>
|
|
468
|
+
|
|
469
|
+
/** Assertion stage that validates properties inside an already established domain. */
|
|
470
|
+
export type Refinement<
|
|
471
|
+
T = unknown,
|
|
472
|
+
C extends readonly AssertionConstraint[] = readonly AssertionConstraint[],
|
|
473
|
+
Code extends string = string,
|
|
474
|
+
A extends readonly unknown[] = readonly unknown[],
|
|
475
|
+
Name extends string = string,
|
|
476
|
+
> = Assertion<T, C, Code, A, Name, 'refinement'>
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Any reusable validation unit: either a leaf `Assertion` or a composed `Validator`.
|
|
480
|
+
*
|
|
481
|
+
* This is the main building block accepted by `validate(...)`, `matches.sync(...)`,
|
|
482
|
+
* `shape(...)`, and `each(...)`.
|
|
483
|
+
*/
|
|
484
|
+
export type Constraint<T = unknown> = Assertion<T> | Validator<T>
|
|
485
|
+
|
|
486
|
+
type ConstraintSequenceState<
|
|
487
|
+
Value,
|
|
488
|
+
Ready extends boolean,
|
|
489
|
+
> = {
|
|
490
|
+
value: Value;
|
|
491
|
+
ready: Ready;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
type ApplyConstraintStep<
|
|
495
|
+
State extends ConstraintSequenceState<unknown, boolean>,
|
|
496
|
+
Step extends Constraint,
|
|
497
|
+
> =
|
|
498
|
+
[Step] extends [Refinement<infer Input, readonly AssertionConstraint[], string, readonly unknown[], string>]
|
|
499
|
+
? State['ready'] extends true
|
|
500
|
+
? [State['value']] extends [Input]
|
|
501
|
+
? ConstraintSequenceState<State['value'], true>
|
|
502
|
+
: never
|
|
503
|
+
: never
|
|
504
|
+
: Step extends Validator<infer Output>
|
|
505
|
+
? ConstraintSequenceState<State['value'] & Output, false>
|
|
506
|
+
: Step extends Assertion<infer Output>
|
|
507
|
+
? ConstraintSequenceState<State['value'] & Output, true>
|
|
508
|
+
: never
|
|
509
|
+
|
|
510
|
+
type CompatibleConstraintTupleState<
|
|
511
|
+
T extends readonly Constraint[],
|
|
512
|
+
State extends ConstraintSequenceState<unknown, boolean> = ConstraintSequenceState<unknown, false>,
|
|
513
|
+
> =
|
|
514
|
+
T extends readonly [infer First extends Constraint, ...infer Rest extends readonly Constraint[]]
|
|
515
|
+
? ApplyConstraintStep<State, First> extends infer Next
|
|
516
|
+
? [Next] extends [never]
|
|
517
|
+
? never
|
|
518
|
+
: Next extends ConstraintSequenceState<unknown, boolean>
|
|
519
|
+
? CompatibleConstraintTupleState<Rest, Next>
|
|
520
|
+
: never
|
|
521
|
+
: never
|
|
522
|
+
: State
|
|
523
|
+
|
|
524
|
+
/** Tuple of sequential constraints with stage-aware assertion compatibility checks. */
|
|
525
|
+
export type CompatibleConstraintTuple<T extends readonly Constraint[] = readonly Constraint[]> =
|
|
526
|
+
number extends T['length']
|
|
527
|
+
? T
|
|
528
|
+
: T extends readonly [Constraint, ...Constraint[]]
|
|
529
|
+
? CompatibleConstraintTupleState<T> extends never
|
|
530
|
+
? never
|
|
531
|
+
: T
|
|
532
|
+
: T
|
|
533
|
+
|
|
534
|
+
/** One-or-many constraint input after applying staged assertion compatibility checks. */
|
|
535
|
+
export type CompatibleConstraints<C> =
|
|
536
|
+
C extends readonly Constraint[]
|
|
537
|
+
? CompatibleConstraintTuple<C>
|
|
538
|
+
: C extends Refinement<unknown, readonly AssertionConstraint[], string, readonly unknown[], string>
|
|
539
|
+
? never
|
|
540
|
+
: C extends Constraint
|
|
541
|
+
? C
|
|
542
|
+
: never
|
|
543
|
+
|
|
544
|
+
/** Extracts the validated TypeScript type from a single constraint. */
|
|
545
|
+
export type InferConstraint<C> =
|
|
546
|
+
C extends Assertion<infer T, readonly AssertionConstraint[], string, readonly unknown[], string, AssertionStage>
|
|
547
|
+
? T
|
|
548
|
+
: C extends Validator<infer T>
|
|
549
|
+
? T
|
|
550
|
+
: never
|
|
551
|
+
|
|
552
|
+
type InferConstraintIntersection<C> =
|
|
553
|
+
(C extends unknown ? (value: InferConstraint<C>) => void : never) extends (value: infer Output) => void
|
|
554
|
+
? Output
|
|
555
|
+
: never
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Extracts the validated TypeScript type from one or many constraints.
|
|
559
|
+
*
|
|
560
|
+
* When an array of constraints is provided, their inferred types are intersected.
|
|
561
|
+
*
|
|
562
|
+
* Example:
|
|
563
|
+
* `InferConstraints<[typeof isDefined, typeof isString]> // string`
|
|
564
|
+
*
|
|
565
|
+
* Example:
|
|
566
|
+
* `InferConstraints<typeof shape({ name: [isDefined, isString] })> // { name: string }`
|
|
567
|
+
*/
|
|
568
|
+
export type InferConstraints<C> =
|
|
569
|
+
C extends readonly []
|
|
570
|
+
? unknown
|
|
571
|
+
: C extends readonly unknown[]
|
|
572
|
+
? number extends C['length']
|
|
573
|
+
? InferConstraintIntersection<C[number]>
|
|
574
|
+
: Intersect<{ [K in keyof C]: InferConstraint<C[K]> }>
|
|
575
|
+
: InferConstraint<C>
|
|
576
|
+
|
|
577
|
+
/** Internal async runner signature used by composed validators. */
|
|
578
|
+
export type Validate = ((
|
|
579
|
+
value: unknown,
|
|
580
|
+
constraints: CompatibleConstraints<MaybeMany<Constraint>>,
|
|
581
|
+
path?: PropertyKey[]
|
|
582
|
+
) => Promise<Violation[]>) & {
|
|
583
|
+
readonly sync?: false
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** Internal sync runner signature used by composed validators. */
|
|
587
|
+
export type ValidateSync = ((
|
|
588
|
+
value: unknown,
|
|
589
|
+
constraints: CompatibleConstraints<MaybeMany<Constraint>>,
|
|
590
|
+
path?: PropertyKey[]
|
|
591
|
+
) => Violation[]) & {
|
|
592
|
+
readonly sync: true
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** Internal union of async and sync runner signatures. */
|
|
596
|
+
export type ValidateLike = Validate | ValidateSync
|
|
597
|
+
|
|
598
|
+
/** Internal helper that maps a runner kind to nested validation results. */
|
|
599
|
+
export type Validation<F extends ValidateLike> = F extends Validate
|
|
600
|
+
? MaybePromise<Violation[]>
|
|
601
|
+
: Violation[]
|
|
602
|
+
|
|
603
|
+
/** Controls how object shapes handle keys missing from the descriptor. */
|
|
604
|
+
export type UnknownKeysMode = 'passthrough' | 'strict'
|
|
605
|
+
|
|
606
|
+
/** Field selector accepted by shape helpers that can point to the current level or a nested path. */
|
|
607
|
+
export type ShapeFieldSelector = PropertyKey | readonly PropertyKey[]
|
|
608
|
+
|
|
609
|
+
type ResolveShapeRefinementViolationCode<COrA extends string | readonly unknown[]> = COrA extends string ? COrA : string
|
|
610
|
+
type ResolveShapeRefinementViolationArgs<COrA extends string | readonly unknown[], C extends string> = [COrA] extends [readonly unknown[]]
|
|
611
|
+
? COrA
|
|
612
|
+
: ViolationArgs<C>
|
|
613
|
+
|
|
614
|
+
/** Machine-readable violation input returned by an object-level shape refinement. */
|
|
615
|
+
export type ShapeRefinementViolationInput<
|
|
616
|
+
COrA extends string | readonly unknown[] = string,
|
|
617
|
+
C extends string = ResolveShapeRefinementViolationCode<COrA>,
|
|
618
|
+
A extends readonly unknown[] = ResolveShapeRefinementViolationArgs<COrA, C>,
|
|
619
|
+
> = {
|
|
620
|
+
path?: PropertyKey[];
|
|
621
|
+
code: C;
|
|
622
|
+
args?: [COrA] extends [readonly unknown[]]
|
|
623
|
+
? A
|
|
624
|
+
: C extends KnownViolationCode
|
|
625
|
+
? A & ViolationArgs<C>
|
|
626
|
+
: A;
|
|
627
|
+
value?: unknown;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/** Sync-safe object-level rule that runs after the base shape has validated successfully. */
|
|
631
|
+
export type SyncShapeRefinement<
|
|
632
|
+
T,
|
|
633
|
+
I extends ShapeRefinementViolationInput = ShapeRefinementViolationInput,
|
|
634
|
+
> = (
|
|
635
|
+
value: T
|
|
636
|
+
) => MaybeMany<I | null | undefined> | null | undefined
|
|
637
|
+
|
|
638
|
+
/** Async-first object-level rule that runs after the base shape has validated successfully. */
|
|
639
|
+
export type ShapeRefinement<
|
|
640
|
+
T,
|
|
641
|
+
I extends ShapeRefinementViolationInput = ShapeRefinementViolationInput,
|
|
642
|
+
> = (
|
|
643
|
+
value: T
|
|
644
|
+
) => MaybePromise<MaybeMany<I | null | undefined> | null | undefined>
|
|
645
|
+
|
|
646
|
+
type AsyncObjectShapeRuleDescriptorOf<RD extends SyncObjectShapeRuleDescriptor<string>> =
|
|
647
|
+
Omit<RD, 'async'> & AsyncObjectShapeRuleDescriptor<RD['kind']>
|
|
648
|
+
|
|
649
|
+
/** Explicitly sync-safe callable helper exposed as `shape(...).refine.sync(...)`. */
|
|
650
|
+
export interface ShapeRefineMethodSync<
|
|
651
|
+
D extends ShapeDescriptor = ShapeDescriptor,
|
|
652
|
+
M extends UnknownKeysMode = UnknownKeysMode,
|
|
653
|
+
R extends readonly ObjectShapeRuleDescriptor[] = readonly ObjectShapeRuleDescriptor[],
|
|
654
|
+
RI extends ShapeRefinementViolationInput = never,
|
|
655
|
+
> {
|
|
656
|
+
<const I extends ShapeRefinementViolationInput = ShapeRefinementViolationInput>(
|
|
657
|
+
refinement: SyncShapeRefinement<InferShape<D>, I>
|
|
658
|
+
): ObjectShape<D, M, [...R, SyncObjectShapeRuleDescriptor<'refine'>], RI | I>;
|
|
659
|
+
<
|
|
660
|
+
const I extends ShapeRefinementViolationInput = ShapeRefinementViolationInput,
|
|
661
|
+
const RD extends SyncObjectShapeRuleDescriptor<string> = SyncObjectShapeRuleDescriptor<'refine'>
|
|
662
|
+
>(
|
|
663
|
+
refinement: SyncShapeRefinement<InferShape<D>, I>,
|
|
664
|
+
descriptor: RD
|
|
665
|
+
): ObjectShape<D, M, [...R, RD], RI | I>;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** Async-first callable shape helper exposed as `shape(...).refine(...)`. */
|
|
669
|
+
export interface ShapeRefineMethod<
|
|
670
|
+
D extends ShapeDescriptor = ShapeDescriptor,
|
|
671
|
+
M extends UnknownKeysMode = UnknownKeysMode,
|
|
672
|
+
R extends readonly ObjectShapeRuleDescriptor[] = readonly ObjectShapeRuleDescriptor[],
|
|
673
|
+
RI extends ShapeRefinementViolationInput = never,
|
|
674
|
+
> {
|
|
675
|
+
<const I extends ShapeRefinementViolationInput = ShapeRefinementViolationInput>(
|
|
676
|
+
refinement: ShapeRefinement<InferShape<D>, I>
|
|
677
|
+
): ObjectShape<D, M, [...R, AsyncObjectShapeRuleDescriptor<'refine'>], RI | I>;
|
|
678
|
+
<
|
|
679
|
+
const I extends ShapeRefinementViolationInput = ShapeRefinementViolationInput,
|
|
680
|
+
const RD extends SyncObjectShapeRuleDescriptor<string> = SyncObjectShapeRuleDescriptor<'refine'>
|
|
681
|
+
>(
|
|
682
|
+
refinement: ShapeRefinement<InferShape<D>, I>,
|
|
683
|
+
descriptor: RD
|
|
684
|
+
): ObjectShape<D, M, [...R, AsyncObjectShapeRuleDescriptorOf<RD>], RI | I>;
|
|
685
|
+
sync: ShapeRefineMethodSync<D, M, R, RI>;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
type KnownCodeViolation<C extends KnownViolationCode> = Violation<KnownViolationSubject<C>>
|
|
689
|
+
|
|
690
|
+
type ShapeRefinementIssueSubject<I extends ShapeRefinementViolationInput> =
|
|
691
|
+
I extends ShapeRefinementViolationInput<string | readonly unknown[], infer C, infer A>
|
|
692
|
+
? C extends KnownViolationCode
|
|
693
|
+
? {
|
|
694
|
+
kind: 'validator';
|
|
695
|
+
name: 'shape' & ViolationNameOf<C>;
|
|
696
|
+
code: C;
|
|
697
|
+
args: A & ViolationArgs<C>;
|
|
698
|
+
}
|
|
699
|
+
: ViolationSubject<A, 'validator', C>
|
|
700
|
+
: never
|
|
701
|
+
|
|
702
|
+
type ShapeRefinementIssueViolation<I extends ShapeRefinementViolationInput> =
|
|
703
|
+
I extends ShapeRefinementViolationInput
|
|
704
|
+
? Violation<ShapeRefinementIssueSubject<I>>
|
|
705
|
+
: never
|
|
706
|
+
|
|
707
|
+
type InferShapeViolations<D extends ShapeDescriptor> = {
|
|
708
|
+
[K in keyof D]: InferViolations<D[K]>
|
|
709
|
+
}[keyof D]
|
|
710
|
+
|
|
711
|
+
/** Maps a single constraint into the union of violations it can produce. */
|
|
712
|
+
export type InferConstraintViolations<C extends Constraint> =
|
|
713
|
+
C extends Guard<unknown, infer AC, infer Code, infer Args, infer Name>
|
|
714
|
+
? Violation<{
|
|
715
|
+
kind: 'assertion';
|
|
716
|
+
name: Name;
|
|
717
|
+
code: Code;
|
|
718
|
+
args: Args;
|
|
719
|
+
} | AssertionConstraintSubject<AC[number], Name>>
|
|
720
|
+
: C extends Refinement<unknown, infer AC, string, readonly unknown[], infer Name>
|
|
721
|
+
? Violation<AssertionConstraintSubject<AC[number], Name>>
|
|
722
|
+
: C extends ObjectShape<infer D, infer M, readonly ObjectShapeRuleDescriptor[], infer RI>
|
|
723
|
+
? KnownCodeViolation<'type.record'>
|
|
724
|
+
| (M extends 'strict' ? KnownCodeViolation<'shape.unknown-key'> : never)
|
|
725
|
+
| InferShapeViolations<D>
|
|
726
|
+
| ShapeRefinementIssueViolation<RI>
|
|
727
|
+
: C extends OptionalValidator<infer Child>
|
|
728
|
+
? InferViolations<Child>
|
|
729
|
+
: C extends NullableValidator<infer Child>
|
|
730
|
+
? InferViolations<Child>
|
|
731
|
+
: C extends NullishValidator<infer Child>
|
|
732
|
+
? InferViolations<Child>
|
|
733
|
+
: C extends EachValidator<infer Child>
|
|
734
|
+
? KnownCodeViolation<'type.array'> | InferViolations<Child>
|
|
735
|
+
: C extends TupleValidator<infer Items>
|
|
736
|
+
? KnownCodeViolation<'type.array'>
|
|
737
|
+
| KnownCodeViolation<'tuple.length'>
|
|
738
|
+
| InferViolations<Items[number]>
|
|
739
|
+
: C extends UnionValidator<infer Branches>
|
|
740
|
+
? KnownCodeViolation<'union.no-match'> | InferViolations<Branches[number]>
|
|
741
|
+
: C extends DiscriminatedUnionValidator<PropertyKey, infer Variants>
|
|
742
|
+
? KnownCodeViolation<'type.record'>
|
|
743
|
+
| KnownCodeViolation<'union.invalid-discriminator'>
|
|
744
|
+
| InferViolations<Variants[keyof Variants]>
|
|
745
|
+
: C extends RecordValidator<infer Values>
|
|
746
|
+
? KnownCodeViolation<'type.record'> | InferViolations<Values>
|
|
747
|
+
: C extends Validator
|
|
748
|
+
? Violation
|
|
749
|
+
: never
|
|
750
|
+
|
|
751
|
+
/** Maps one-or-many constraints into the union of violations they can produce. */
|
|
752
|
+
export type InferViolations<C extends MaybeMany<Constraint>> =
|
|
753
|
+
C extends readonly []
|
|
754
|
+
? never
|
|
755
|
+
: C extends readonly Constraint[]
|
|
756
|
+
? InferConstraintViolations<C[number]>
|
|
757
|
+
: C extends Constraint
|
|
758
|
+
? InferConstraintViolations<C>
|
|
759
|
+
: never
|
|
760
|
+
|
|
761
|
+
/** Successful `validate(...)` tuple with typed `validated` value. */
|
|
762
|
+
export type ValidationSuccess<T> = [ok: true, validated: T, violations: []]
|
|
763
|
+
|
|
764
|
+
/** Failed `validate(...)` tuple with original value and collected violations. */
|
|
765
|
+
export type ValidationFailure<V extends Violation = Violation> = [ok: false, validated: unknown, violations: V[]]
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* The result returned by `validate(...)` and `validate.sync(...)`.
|
|
769
|
+
*
|
|
770
|
+
* Example:
|
|
771
|
+
* `const [ok, validated, violations] = await validate(value, schema)`
|
|
772
|
+
*
|
|
773
|
+
* Example:
|
|
774
|
+
* `if (ok) validated.name.toUpperCase()`
|
|
775
|
+
*/
|
|
776
|
+
export type ValidationResult<T, V extends Violation = Violation> = ValidationSuccess<T> | ValidationFailure<V>
|
|
777
|
+
|
|
778
|
+
/** Attaches read-only metadata to a constraint without changing validation semantics. */
|
|
779
|
+
export declare const meta: <const C extends Constraint, const M extends ConstraintMetadata>(constraint: C, metadata: M) => C
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Composed validator used by recursive helpers such as `shape(...)` and `each(...)`.
|
|
783
|
+
*
|
|
784
|
+
* Custom validators should keep `check` aligned with runtime behavior so that
|
|
785
|
+
* inference and sync narrowing stay trustworthy.
|
|
786
|
+
*
|
|
787
|
+
* Example:
|
|
788
|
+
* `const schema: Validator<{ name: string }>`
|
|
789
|
+
*/
|
|
790
|
+
export interface Validator<T = unknown> {
|
|
791
|
+
readonly check: Predicate<T>;
|
|
792
|
+
run <F extends ValidateLike> (
|
|
793
|
+
validate: F,
|
|
794
|
+
value: unknown,
|
|
795
|
+
path: PropertyKey[]
|
|
796
|
+
): Validation<F>[];
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/** Public validator extension contract for participating in `describe(...)` without private runtime knowledge. */
|
|
800
|
+
export interface DescribedValidator<
|
|
801
|
+
T = unknown,
|
|
802
|
+
D extends ConstraintDescriptor = ConstraintDescriptor,
|
|
803
|
+
> extends Validator<T> {
|
|
804
|
+
describe(): D;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/** Identity helper that preserves the exact shape of custom validators, including public descriptors. */
|
|
808
|
+
export declare const custom: <const V extends Validator>(validator: V) => V
|
|
809
|
+
|
|
810
|
+
/** Descriptor that maps object keys to one or many constraints. */
|
|
811
|
+
export type ShapeDescriptor = Record<PropertyKey, MaybeMany<Constraint>>
|
|
812
|
+
|
|
813
|
+
/** Shape descriptor with stage-aware compatibility checks applied to every field slot. */
|
|
814
|
+
export type CompatibleShapeDescriptor<D extends ShapeDescriptor> = {
|
|
815
|
+
[K in keyof D]: CompatibleConstraints<D[K]>
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/** Runtime type inferred from a shape descriptor. */
|
|
819
|
+
export type InferShape<D extends ShapeDescriptor> = {
|
|
820
|
+
[K in keyof D]: InferConstraints<D[K]>
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/** Descriptor produced by `.partial()` where every field accepts `undefined`. */
|
|
824
|
+
export type PartialShapeDescriptor<D extends ShapeDescriptor> = {
|
|
825
|
+
[K in keyof D]: Validator<InferConstraints<D[K]> | undefined>
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/** Utility type for overriding descriptor keys from left to right. */
|
|
829
|
+
export type MergeShapeDescriptors<
|
|
830
|
+
Left extends ShapeDescriptor,
|
|
831
|
+
Right extends ShapeDescriptor,
|
|
832
|
+
> = Omit<Left, keyof Right> & Right
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Object-aware validator with descriptor introspection and immutable shape helpers.
|
|
836
|
+
*
|
|
837
|
+
* Example:
|
|
838
|
+
* `const user = shape({ name: isString }).strict()`
|
|
839
|
+
*/
|
|
840
|
+
export interface ObjectShape<
|
|
841
|
+
D extends ShapeDescriptor = ShapeDescriptor,
|
|
842
|
+
M extends UnknownKeysMode = 'passthrough',
|
|
843
|
+
R extends readonly ObjectShapeRuleDescriptor[] = readonly ObjectShapeRuleDescriptor[],
|
|
844
|
+
RI extends ShapeRefinementViolationInput = never,
|
|
845
|
+
> extends Validator<InferShape<D>> {
|
|
846
|
+
readonly descriptor: D;
|
|
847
|
+
readonly unknownKeys: M;
|
|
848
|
+
readonly refine: ShapeRefineMethod<D, M, R, RI>;
|
|
849
|
+
fieldsMatch<const K extends readonly [ShapeFieldSelector, ShapeFieldSelector]>(
|
|
850
|
+
keys: K
|
|
851
|
+
): ObjectShape<D, M, [...R, FieldsMatchObjectShapeRuleDescriptor<K[0], K[1]>], RI | ShapeRefinementViolationInput<'shape.fields.mismatch'>>;
|
|
852
|
+
strict(): ObjectShape<D, 'strict', R, RI>;
|
|
853
|
+
passthrough(): ObjectShape<D, 'passthrough', R, RI>;
|
|
854
|
+
pick<const K extends readonly (keyof D)[]>(keys: K): ObjectShape<Pick<D, K[number]>, M, [], never>;
|
|
855
|
+
omit<const K extends readonly (keyof D)[]>(keys: K): ObjectShape<Omit<D, K[number]>, M, [], never>;
|
|
856
|
+
partial(): ObjectShape<PartialShapeDescriptor<D>, M, [], never>;
|
|
857
|
+
extend<const E extends ShapeDescriptor>(descriptor: E): ObjectShape<MergeShapeDescriptors<D, E>, M, [], never>;
|
|
858
|
+
merge<const E extends ShapeDescriptor, OM extends UnknownKeysMode, OR extends readonly ObjectShapeRuleDescriptor[]>(
|
|
859
|
+
shape: ObjectShape<E, OM, OR, ShapeRefinementViolationInput>
|
|
860
|
+
): ObjectShape<MergeShapeDescriptors<D, E>, M, [], never>;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/** Helper that maps a single constraint into its public `describe(...)` result. */
|
|
864
|
+
export type DescribeConstraint<C extends Constraint> =
|
|
865
|
+
C extends Assertion<unknown, infer AC, infer Code, infer Args, string, AssertionStage>
|
|
866
|
+
? AssertionDescriptor<Code, Args, DescribeAssertionConstraintTuple<AC>>
|
|
867
|
+
: C extends ObjectShape<infer D, infer M, infer R, ShapeRefinementViolationInput>
|
|
868
|
+
? ShapeConstraintDescriptor<DescribeShapeDescriptor<D>, R> & { readonly unknownKeys: M }
|
|
869
|
+
: C extends OptionalValidator<infer Child>
|
|
870
|
+
? WrapperConstraintDescriptor<'optional', DescribeConstraints<Child>>
|
|
871
|
+
: C extends NullableValidator<infer Child>
|
|
872
|
+
? WrapperConstraintDescriptor<'nullable', DescribeConstraints<Child>>
|
|
873
|
+
: C extends NullishValidator<infer Child>
|
|
874
|
+
? WrapperConstraintDescriptor<'nullish', DescribeConstraints<Child>>
|
|
875
|
+
: C extends EachValidator<infer Child>
|
|
876
|
+
? EachConstraintDescriptor<DescribeConstraints<Child>>
|
|
877
|
+
: C extends TupleValidator<infer Items>
|
|
878
|
+
? TupleConstraintDescriptor<DescribeConstraintTuple<Items>>
|
|
879
|
+
: C extends UnionValidator<infer Branches>
|
|
880
|
+
? UnionConstraintDescriptor<DescribeConstraintTuple<Branches>>
|
|
881
|
+
: C extends DiscriminatedUnionValidator<PropertyKey, infer Variants>
|
|
882
|
+
? DiscriminatedUnionConstraintDescriptor<DescribeShapeDescriptor<Variants>>
|
|
883
|
+
: C extends RecordValidator<infer Values>
|
|
884
|
+
? RecordConstraintDescriptor<DescribeConstraints<Values>>
|
|
885
|
+
: C extends DescribedValidator<unknown, infer D>
|
|
886
|
+
? D & { readonly metadata?: ConstraintMetadata }
|
|
887
|
+
: C extends Validator
|
|
888
|
+
? OpaqueValidatorDescriptor
|
|
889
|
+
: never
|
|
890
|
+
|
|
891
|
+
/** Helper that maps a one-or-many constraint slot into its public `describe(...)` result. */
|
|
892
|
+
export type DescribeConstraints<C extends MaybeMany<Constraint>> =
|
|
893
|
+
C extends readonly [infer Only]
|
|
894
|
+
? Only extends Constraint
|
|
895
|
+
? DescribeConstraint<Only>
|
|
896
|
+
: never
|
|
897
|
+
: C extends readonly [Constraint, Constraint, ...Constraint[]]
|
|
898
|
+
? AllOfConstraintDescriptor<DescribeConstraintTuple<C>>
|
|
899
|
+
: C extends readonly Constraint[]
|
|
900
|
+
? DescribeConstraint<C[number]> | AllOfConstraintDescriptor
|
|
901
|
+
: C extends Constraint
|
|
902
|
+
? DescribeConstraint<C>
|
|
903
|
+
: never
|
|
904
|
+
|
|
905
|
+
/** Helper that maps object descriptors into their `describe(...)` field tree. */
|
|
906
|
+
export type DescribeShapeDescriptor<D extends ShapeDescriptor> = {
|
|
907
|
+
[K in keyof D]: DescribeConstraints<D[K]>
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/** Helper that maps tuples of constraints into tuples of descriptors. */
|
|
911
|
+
export type DescribeConstraintTuple<T extends readonly MaybeMany<Constraint>[]> = {
|
|
912
|
+
readonly [K in keyof T]: DescribeConstraints<T[K]>
|
|
913
|
+
} & ReadonlyArray<DescribeConstraints<T[number]>>
|
|
914
|
+
|
|
915
|
+
declare const optionalValidatorBrand: unique symbol
|
|
916
|
+
declare const nullableValidatorBrand: unique symbol
|
|
917
|
+
declare const nullishValidatorBrand: unique symbol
|
|
918
|
+
declare const eachValidatorBrand: unique symbol
|
|
919
|
+
declare const tupleValidatorBrand: unique symbol
|
|
920
|
+
declare const unionValidatorBrand: unique symbol
|
|
921
|
+
declare const discriminatedUnionValidatorBrand: unique symbol
|
|
922
|
+
declare const recordValidatorBrand: unique symbol
|
|
923
|
+
|
|
924
|
+
/** Typed validator returned by `optional(...)`. */
|
|
925
|
+
export type OptionalValidator<C extends MaybeMany<Constraint> = MaybeMany<Constraint>> =
|
|
926
|
+
Validator<InferConstraints<C> | undefined> & {
|
|
927
|
+
readonly [optionalValidatorBrand]: C
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/** Typed validator returned by `nullable(...)`. */
|
|
931
|
+
export type NullableValidator<C extends MaybeMany<Constraint> = MaybeMany<Constraint>> =
|
|
932
|
+
Validator<InferConstraints<C> | null> & {
|
|
933
|
+
readonly [nullableValidatorBrand]: C
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/** Typed validator returned by `nullish(...)`. */
|
|
937
|
+
export type NullishValidator<C extends MaybeMany<Constraint> = MaybeMany<Constraint>> =
|
|
938
|
+
Validator<InferConstraints<C> | null | undefined> & {
|
|
939
|
+
readonly [nullishValidatorBrand]: C
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/** Typed validator returned by `each(...)`. */
|
|
943
|
+
export type EachValidator<C extends MaybeMany<Constraint> = MaybeMany<Constraint>> =
|
|
944
|
+
Validator<InferConstraints<C>[]> & {
|
|
945
|
+
readonly [eachValidatorBrand]: C
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/** Typed validator returned by `tuple(...)`. */
|
|
949
|
+
export type TupleValidator<T extends readonly MaybeMany<Constraint>[] = readonly MaybeMany<Constraint>[]> =
|
|
950
|
+
Validator<{
|
|
951
|
+
-readonly [K in keyof T]: InferConstraints<T[K]>
|
|
952
|
+
}> & {
|
|
953
|
+
readonly [tupleValidatorBrand]: T
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/** Typed validator returned by `union(...)`. */
|
|
957
|
+
export type UnionValidator<T extends readonly MaybeMany<Constraint>[] = readonly MaybeMany<Constraint>[]> =
|
|
958
|
+
Validator<{
|
|
959
|
+
[K in keyof T]: InferConstraints<T[K]>
|
|
960
|
+
}[number]> & {
|
|
961
|
+
readonly [unionValidatorBrand]: T
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/** Typed validator returned by `discriminatedUnion(...)`. */
|
|
965
|
+
export type DiscriminatedUnionValidator<
|
|
966
|
+
K extends PropertyKey = PropertyKey,
|
|
967
|
+
T extends Record<PropertyKey, MaybeMany<Constraint>> = Record<PropertyKey, MaybeMany<Constraint>>,
|
|
968
|
+
> = Validator<{
|
|
969
|
+
[P in keyof T]: InferConstraints<T[P]>
|
|
970
|
+
}[keyof T]> & {
|
|
971
|
+
readonly [discriminatedUnionValidatorBrand]: {
|
|
972
|
+
readonly key: K;
|
|
973
|
+
readonly variants: T;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/** Typed validator returned by `record(...)`. */
|
|
978
|
+
export type RecordValidator<C extends MaybeMany<Constraint> = MaybeMany<Constraint>> =
|
|
979
|
+
Validator<Record<string, InferConstraints<C>>> & {
|
|
980
|
+
readonly [recordValidatorBrand]: C
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/** Returns a stable machine-readable description of a constraint tree. */
|
|
984
|
+
export declare const describe: <const C extends Constraint>(constraint: C) => DescribeConstraint<C>
|