@cleverbrush/schema 1.1.11 → 3.0.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 (98) hide show
  1. package/README.md +1721 -104
  2. package/dist/builders/AnySchemaBuilder.d.ts +54 -14
  3. package/dist/builders/AnySchemaBuilder.js +2 -112
  4. package/dist/builders/AnySchemaBuilder.js.map +1 -0
  5. package/dist/builders/ArraySchemaBuilder.d.ts +126 -23
  6. package/dist/builders/ArraySchemaBuilder.js +2 -284
  7. package/dist/builders/ArraySchemaBuilder.js.map +1 -0
  8. package/dist/builders/BooleanSchemaBuilder.d.ts +109 -19
  9. package/dist/builders/BooleanSchemaBuilder.js +2 -150
  10. package/dist/builders/BooleanSchemaBuilder.js.map +1 -0
  11. package/dist/builders/DateSchemaBuilder.d.ts +154 -34
  12. package/dist/builders/DateSchemaBuilder.js +2 -433
  13. package/dist/builders/DateSchemaBuilder.js.map +1 -0
  14. package/dist/builders/ExternSchemaBuilder.d.ts +202 -0
  15. package/dist/builders/ExternSchemaBuilder.js +2 -0
  16. package/dist/builders/ExternSchemaBuilder.js.map +1 -0
  17. package/dist/builders/FunctionSchemaBuilder.d.ts +205 -18
  18. package/dist/builders/FunctionSchemaBuilder.js +2 -113
  19. package/dist/builders/FunctionSchemaBuilder.js.map +1 -0
  20. package/dist/builders/GenericSchemaBuilder.d.ts +294 -0
  21. package/dist/builders/LazySchemaBuilder.d.ts +169 -0
  22. package/dist/builders/NullSchemaBuilder.d.ts +162 -0
  23. package/dist/builders/NumberSchemaBuilder.d.ts +159 -31
  24. package/dist/builders/NumberSchemaBuilder.js +2 -386
  25. package/dist/builders/NumberSchemaBuilder.js.map +1 -0
  26. package/dist/builders/ObjectSchemaBuilder.d.ts +486 -61
  27. package/dist/builders/ObjectSchemaBuilder.js +2 -589
  28. package/dist/builders/ObjectSchemaBuilder.js.map +1 -0
  29. package/dist/builders/ParseStringSchemaBuilder.d.ts +204 -0
  30. package/dist/builders/ParseStringSchemaBuilder.js +2 -0
  31. package/dist/builders/ParseStringSchemaBuilder.js.map +1 -0
  32. package/dist/builders/PromiseSchemaBuilder.d.ts +213 -0
  33. package/dist/builders/PromiseSchemaBuilder.js +2 -0
  34. package/dist/builders/PromiseSchemaBuilder.js.map +1 -0
  35. package/dist/builders/PropertyValidationResult.d.ts +68 -0
  36. package/dist/builders/RecordSchemaBuilder.d.ts +343 -0
  37. package/dist/builders/RecordSchemaBuilder.js +2 -0
  38. package/dist/builders/RecordSchemaBuilder.js.map +1 -0
  39. package/dist/builders/SchemaBuilder.d.ts +907 -30
  40. package/dist/builders/StringSchemaBuilder.d.ts +154 -37
  41. package/dist/builders/StringSchemaBuilder.js +2 -414
  42. package/dist/builders/StringSchemaBuilder.js.map +1 -0
  43. package/dist/builders/TupleSchemaBuilder.d.ts +250 -0
  44. package/dist/builders/TupleSchemaBuilder.js +2 -0
  45. package/dist/builders/TupleSchemaBuilder.js.map +1 -0
  46. package/dist/builders/UnionSchemaBuilder.d.ts +141 -39
  47. package/dist/builders/UnionSchemaBuilder.js +2 -216
  48. package/dist/builders/UnionSchemaBuilder.js.map +1 -0
  49. package/dist/chunk-3JMDGYDT.js +2 -0
  50. package/dist/chunk-3JMDGYDT.js.map +1 -0
  51. package/dist/chunk-BUEVZ3KA.js +2 -0
  52. package/dist/chunk-BUEVZ3KA.js.map +1 -0
  53. package/dist/chunk-CFIJQ4GP.js +2 -0
  54. package/dist/chunk-CFIJQ4GP.js.map +1 -0
  55. package/dist/chunk-DY7J6RNN.js +2 -0
  56. package/dist/chunk-DY7J6RNN.js.map +1 -0
  57. package/dist/chunk-EIVZX4ZO.js +2 -0
  58. package/dist/chunk-EIVZX4ZO.js.map +1 -0
  59. package/dist/chunk-GXPV6UQK.js +2 -0
  60. package/dist/chunk-GXPV6UQK.js.map +1 -0
  61. package/dist/chunk-HN774HD7.js +2 -0
  62. package/dist/chunk-HN774HD7.js.map +1 -0
  63. package/dist/chunk-K6Z47OQY.js +2 -0
  64. package/dist/chunk-K6Z47OQY.js.map +1 -0
  65. package/dist/chunk-NUW3VXZV.js +2 -0
  66. package/dist/chunk-NUW3VXZV.js.map +1 -0
  67. package/dist/chunk-PHE4LIAN.js +2 -0
  68. package/dist/chunk-PHE4LIAN.js.map +1 -0
  69. package/dist/chunk-QARCEYGO.js +2 -0
  70. package/dist/chunk-QARCEYGO.js.map +1 -0
  71. package/dist/chunk-WDMJBGBD.js +2 -0
  72. package/dist/chunk-WDMJBGBD.js.map +1 -0
  73. package/dist/chunk-WQDYWDOE.js +2 -0
  74. package/dist/chunk-WQDYWDOE.js.map +1 -0
  75. package/dist/chunk-YQZHDMRF.js +2 -0
  76. package/dist/chunk-YQZHDMRF.js.map +1 -0
  77. package/dist/chunk-ZC6YBKCP.js +2 -0
  78. package/dist/chunk-ZC6YBKCP.js.map +1 -0
  79. package/dist/chunk-ZFI27R3L.js +2 -0
  80. package/dist/chunk-ZFI27R3L.js.map +1 -0
  81. package/dist/core.d.ts +28 -0
  82. package/dist/core.js +2 -0
  83. package/dist/core.js.map +1 -0
  84. package/dist/extension.d.ts +421 -0
  85. package/dist/extensions/array.d.ts +112 -0
  86. package/dist/extensions/enum.d.ts +190 -0
  87. package/dist/extensions/index.d.ts +112 -0
  88. package/dist/extensions/nullable.d.ts +26 -0
  89. package/dist/extensions/number.d.ts +228 -0
  90. package/dist/extensions/string.d.ts +332 -0
  91. package/dist/extensions/util.d.ts +45 -0
  92. package/dist/index.d.ts +10 -20
  93. package/dist/index.js +2 -19
  94. package/dist/index.js.map +1 -0
  95. package/dist/utils/transaction.d.ts +27 -4
  96. package/package.json +83 -7
  97. package/dist/builders/SchemaBuilder.js +0 -275
  98. package/dist/utils/transaction.js +0 -178
@@ -1,14 +1,112 @@
1
- import { Transaction } from '../utils/transaction.js';
2
- export type InferType<T> = T extends SchemaBuilder<infer TResult, infer TRequired> ? T extends {
3
- optimize: (...args: any[]) => SchemaBuilder<infer TOptimizedType, infer TOptimizedRequired>;
4
- } ? TOptimizedRequired extends true ? TOptimizedType : MakeOptional<TOptimizedType> : TRequired extends true ? TResult : MakeOptional<TResult> : T;
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
2
+ import { type Transaction } from '../utils/transaction.js';
3
+ import type { ArraySchemaBuilder } from './ArraySchemaBuilder.js';
4
+ import type { ExternSchemaBuilder } from './ExternSchemaBuilder.js';
5
+ import type { ObjectSchemaBuilder } from './ObjectSchemaBuilder.js';
6
+ /** @internal Symbol used as the key for the type brand on schema builders. */
7
+ declare const __type: unique symbol;
8
+ /** @internal */
9
+ export type SchemaTypeBrand = typeof __type;
10
+ /** @internal Symbol used as the key for the default-value brand on schema builders. */
11
+ declare const __hasDefault: unique symbol;
12
+ /** @internal */
13
+ export type HasDefaultBrand = typeof __hasDefault;
14
+ /** Symbol used as the key for branded/opaque types. */
15
+ declare const __brand: unique symbol;
16
+ /** Symbol used as the key for branded/opaque types. */
17
+ export type BRAND = typeof __brand;
18
+ /**
19
+ * Intersects a base type with a phantom brand tag.
20
+ * The brand exists only at the type level — zero runtime cost.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * type Email = Brand<string, 'Email'>;
25
+ * type UserId = Brand<number, 'UserId'>;
26
+ * ```
27
+ */
28
+ export type Brand<T, TBrand extends string | symbol> = T & {
29
+ readonly [K in BRAND]: TBrand;
30
+ };
31
+ /**
32
+ * Infers the TypeScript type that a `SchemaBuilder` instance validates.
33
+ * Takes into account type optimizations (via `optimize()`) and whether the schema is optional.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const userSchema = object({ name: string(), age: number().optional() });
38
+ * type User = InferType<typeof userSchema>;
39
+ * // { name: string; age?: number }
40
+ * ```
41
+ */
42
+ export type InferType<T> = T extends {
43
+ optimize: (...args: any[]) => {
44
+ readonly [K in SchemaTypeBrand]: infer TOptimized;
45
+ };
46
+ } ? TOptimized : T extends {
47
+ readonly [K in SchemaTypeBrand]: infer TType;
48
+ } ? TType : T;
49
+ /**
50
+ * Represents a single validation error with a human-readable error message.
51
+ *
52
+ * When returned from an object-level validator (via {@link SchemaBuilder.addValidator | addValidator}),
53
+ * the optional `property` selector can route the error to a specific property
54
+ * so that {@link ObjectSchemaValidationResult.getErrorsFor | getErrorsFor()} reports it
55
+ * on that property rather than only on the root object.
56
+ *
57
+ * ```ts
58
+ * .addValidator((v) => ({
59
+ * valid: false,
60
+ * errors: [{
61
+ * message: 'Passwords do not match',
62
+ * property: (t) => t.confirmPassword
63
+ * }]
64
+ * }))
65
+ * ```
66
+ */
5
67
  export type ValidationError = {
6
- path: string;
7
68
  message: string;
69
+ /**
70
+ * Optional property selector that targets this error to a specific
71
+ * property of the validated object. Uses the same selector signature
72
+ * as `getErrorsFor()` and react-form's `forProperty`.
73
+ */
74
+ property?: (tree: any) => any;
8
75
  };
76
+ /**
77
+ * Used to represent a validation result for nested
78
+ * objects/properties. Contains a list of errors and
79
+ * the value that caused them.
80
+ */
81
+ export type NestedValidationResult<TSchema, TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any>, TParentPropertyDescriptor> = {
82
+ /**
83
+ * Value that property had and which caused error or errors
84
+ */
85
+ seenValue?: InferType<TSchema>;
86
+ /**
87
+ * A list of errors, empty if object satisfies a schema
88
+ */
89
+ errors: ReadonlyArray<string>;
90
+ /**
91
+ * Whether validation passed for this property and all of its children.
92
+ */
93
+ isValid: boolean;
94
+ get descriptor(): PropertyDescriptorInner<TRootSchema, TSchema, TParentPropertyDescriptor>;
95
+ };
96
+ /**
97
+ * Utility type that makes a value `T` optional (i.e. `T | undefined`).
98
+ * Used internally by {@link InferType} to represent optional schema fields.
99
+ */
9
100
  export type MakeOptional<T> = {
10
101
  prop?: T;
11
102
  }['prop'];
103
+ /**
104
+ * Type of the function that provides a validation error message for
105
+ * the given `seenValue` and `schema`. Can be a string or a function
106
+ * returning a string or a promise of a string.
107
+ * Should be used to provide a custom validation error message.
108
+ */
109
+ export type ValidationErrorMessageProvider<TSchema extends SchemaBuilder<any, any, any, any, any> = SchemaBuilder<any, any, any, any, any>> = string | ((seenValue: InferType<TSchema>, schema: TSchema) => string | Promise<string>);
12
110
  export type ValidationResult<T> = {
13
111
  /**
14
112
  * If `true` - object satisfies schema
@@ -21,33 +119,318 @@ export type ValidationResult<T> = {
21
119
  object?: T;
22
120
  errors?: ValidationError[];
23
121
  };
122
+ /**
123
+ * Error thrown by {@link SchemaBuilder.parse | parse()} and
124
+ * {@link SchemaBuilder.parseAsync | parseAsync()} when validation fails.
125
+ * Carries the full array of {@link ValidationError | validation errors}.
126
+ */
127
+ export declare class SchemaValidationError extends Error {
128
+ readonly errors: ValidationError[];
129
+ constructor(errors: ValidationError[]);
130
+ }
131
+ /**
132
+ * Internal result returned by the `preValidate` step of `SchemaBuilder`.
133
+ * Contains the validation context, any early errors, and the transaction
134
+ * wrapping the (possibly preprocessed) value.
135
+ */
24
136
  export type PreValidationResult<T, TTransactionType> = Omit<ValidationResult<T>, 'object'> & {
25
137
  context: ValidationContext;
26
138
  transaction?: Transaction<TTransactionType>;
139
+ rootPropertyDescriptor?: PropertyDescriptor<any, any, undefined>;
27
140
  };
28
141
  type ValidatorResult<T> = Omit<ValidationResult<T>, 'object' | 'errors'> & {
29
- errors?: Omit<ValidationError, 'path'>[];
142
+ errors?: ValidationError[];
30
143
  };
144
+ /**
145
+ * A function that transforms the value before validation.
146
+ * Preprocessors run in order before validators and can modify or replace the value.
147
+ *
148
+ * @param object - the current value to preprocess
149
+ * @returns the transformed value, or a Promise resolving to it
150
+ */
31
151
  export type Preprocessor<T> = (object: T) => Promise<T> | T;
152
+ /**
153
+ * A custom validation function that checks a value and returns a result
154
+ * indicating whether the value is valid, along with optional error messages.
155
+ *
156
+ * @param object - the value to validate
157
+ * @returns a result with `valid` boolean and optional `errors` array, or a Promise resolving to it
158
+ */
32
159
  export type Validator<T> = (object: T) => Promise<ValidatorResult<T>> | ValidatorResult<T>;
160
+ /**
161
+ * Internal wrapper that pairs a preprocessor function with metadata
162
+ * indicating whether it may mutate the value.
163
+ */
164
+ export type PreprocessorEntry<T> = {
165
+ fn: Preprocessor<T>;
166
+ mutates: boolean;
167
+ };
168
+ /**
169
+ * Internal wrapper that pairs a validator function with metadata
170
+ * indicating whether it may mutate the value.
171
+ */
172
+ export type ValidatorEntry<T> = {
173
+ fn: Validator<T>;
174
+ mutates: boolean;
175
+ };
176
+ /**
177
+ * Configuration properties used to construct a `SchemaBuilder` instance.
178
+ * Contains the schema type identifier, requirement flag, and lists of
179
+ * preprocessors and validators.
180
+ */
33
181
  export type SchemaBuilderProps<T> = {
34
182
  type: string;
35
183
  isRequired?: boolean;
36
- preprocessors: Preprocessor<T>[];
37
- validators: Validator<T>[];
184
+ isNullable?: boolean;
185
+ isReadonly?: boolean;
186
+ preprocessors: PreprocessorEntry<T>[];
187
+ validators: ValidatorEntry<T>[];
188
+ requiredValidationErrorMessageProvider?: ValidationErrorMessageProvider;
189
+ extensions?: Record<string, unknown>;
190
+ defaultValue?: T | (() => T);
191
+ catchValue?: T | (() => T);
192
+ hasCatch?: boolean;
193
+ description?: string;
194
+ schemaName?: string;
195
+ example?: unknown;
38
196
  };
39
- export type ValidationContext = {
40
- /**
41
- * Path of the field. **Optional**, used to display correct error path in the {@link ValidationError}
42
- */
43
- path?: string;
197
+ export type ValidationContext<TSchema extends SchemaBuilder<any, any, any, any> = SchemaBuilder<any, any, any, any>> = {
44
198
  /**
45
199
  * Optional. By default validation will stop after the first validation error, in case if
46
200
  * you want to receive all validation erors, please set this flag to `true`.
47
201
  * You might need it to display validation errors.
48
202
  */
49
203
  doNotStopOnFirstError?: boolean;
204
+ /**
205
+ * Optional. If you define a `rootPropertyDescriptor` while validating an object,
206
+ * it will report all validation errors with the path starting from the root property.
207
+ * Normally it's used internally by the library for validation of nested objects and
208
+ * should not be used directly (but who knows, maybe you will find a use case for it).
209
+ */
210
+ rootPropertyDescriptor?: TSchema extends ObjectSchemaBuilder<any, any, any, any> ? PropertyDescriptor<TSchema, TSchema, undefined> : never;
211
+ /**
212
+ * Optional. This is a property descriptor for the current object being validated.
213
+ * This descriptor is descendant of the `rootPropertyDescriptor` and is used to provide
214
+ * a path to the current object being validated in the root object.
215
+ * Normally it's used internally by the library for validation of nested objects and
216
+ * should not be used directly (but who knows, maybe you will find a use case for it).
217
+ */
218
+ currentPropertyDescriptor?: TSchema extends ObjectSchemaBuilder<any, any, any> ? PropertyDescriptor<TSchema, TSchema, unknown> : never;
219
+ /**
220
+ * Optional. Used along with `rootPropertyDescriptor` and `currentPropertyDescriptor` to provide
221
+ * a root validation object, this object will be used to retrieve the value of properties
222
+ * using the `rootPropertyDescriptor` because the `rootPropertyDescriptor` is a property descriptor
223
+ * for the root object, and it needs the root object along with the whole structure to get the
224
+ * value of the property.
225
+ *
226
+ * Normally it's used internally by the library for validation of nested objects and
227
+ * should not be used directly (but who knows, maybe you will find a use case for it).
228
+ */
229
+ rootValidationObject?: InferType<TSchema>;
230
+ };
231
+ /**
232
+ * A symbol to mark property descriptors in the schema.
233
+ * Normally, you should not use it directly unless you want
234
+ * to develop some advanced features or extend the library.
235
+ * In normal conditions it's used internally by the library.
236
+ */
237
+ export declare const SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR: unique symbol;
238
+ /**
239
+ * A symbol that marks a schema as having sub-properties that can
240
+ * participate in property descriptor trees. When a schema exposes
241
+ * `[SYMBOL_HAS_PROPERTIES] = true` **and** its `introspect()` returns
242
+ * a `properties` record, it will be recursed into by
243
+ * `ObjectSchemaBuilder.getPropertiesFor()` — the same way nested
244
+ * `ObjectSchemaBuilder` instances are.
245
+ *
246
+ * Currently implemented by `ObjectSchemaBuilder` (always) and
247
+ * `ExternSchemaBuilder` (when created with an explicit property map).
248
+ */
249
+ export declare const SYMBOL_HAS_PROPERTIES: unique symbol;
250
+ /**
251
+ * Describes a property in a schema. And gives you
252
+ * a possibility to access property value and set it.
253
+ * suppose you have a schema like this:
254
+ * ```ts
255
+ * const schema = object({
256
+ * name: string(),
257
+ * address: object({
258
+ * city: string(),
259
+ * country: string()
260
+ * }),
261
+ * id: number()
262
+ * });
263
+ * ```
264
+ * then you can get a property descriptor for the `address.city` property
265
+ * like this:
266
+ * ```ts
267
+ * const addressCityDescriptor = object.getPropertiesFor(schema).address.city;
268
+ * ```
269
+ *
270
+ * And then you can use it to get and set the value of this property having the object:
271
+ * ```ts
272
+ * const obj = {
273
+ * name: 'Leo',
274
+ * address: {
275
+ * city: 'Kozelsk',
276
+ * country: 'Russia'
277
+ * },
278
+ * id: 123
279
+ * };
280
+ *
281
+ * const success = addressCityDescriptor.setValue(obj, 'Venyov');
282
+ * // this returns you a boolean value indicating if the value was set successfully
283
+ * ```
284
+ */
285
+ export type PropertySetterOptions = {
286
+ /**
287
+ * If set to `true`, the method will create missing structure
288
+ * in the object to set the value. For example, if you have a schema
289
+ * and property descriptor like this:
290
+ * ```ts
291
+ * const schema = object({
292
+ * address: object({
293
+ * city: string(),
294
+ * country: string()
295
+ * }),
296
+ * });
297
+ * const addressCityDescriptor = object.getPropertiesFor(schema).address.city;
298
+ * ```
299
+ * And then you try to set a new value to the `address.city` property on the object
300
+ * which does not have `address` property:
301
+ * ```ts
302
+ * const obj = {
303
+ * name: 'Leo'
304
+ * };
305
+ * const success = addressCityDescriptor.setValue(obj, 'Venyov', { createMissingStructure: true });
306
+ * // success === true
307
+ * // obj === {
308
+ * // name: 'Leo',
309
+ * // address: {
310
+ * // city: 'Venyov'
311
+ * // }
312
+ * // }
313
+ */
314
+ createMissingStructure?: boolean;
315
+ };
316
+ /**
317
+ * Extracts the inner property descriptor type from a `PropertyDescriptor`.
318
+ * Returns `undefined` if `T` is not a valid `PropertyDescriptor`.
319
+ */
320
+ export type PropertyDescriptorInnerFromPropertyDescriptor<T> = T extends PropertyDescriptor<infer TSchema, infer TPropertySchema, infer TParentPropertyDescriptor> ? PropertyDescriptorInner<TSchema, TPropertySchema, TParentPropertyDescriptor> : undefined;
321
+ export type PropertyDescriptorInner<TSchema extends ObjectSchemaBuilder<any, any, any, any, any>, TPropertySchema, TParentPropertyDescriptor> = {
322
+ /**
323
+ * Sets a new value to the property. If the process was successful,
324
+ * the method returns `true`, otherwise `false`.
325
+ * It can return `false` if the property could not be set to the object
326
+ * which can happen if the `setValue` method is called with an object
327
+ * which does not comply with the schema.
328
+ * for example, if you have a schema and property descriptopr like this:
329
+ * ```ts
330
+ * const schema = object({
331
+ * name: string(),
332
+ * address: object({
333
+ * city: string(),
334
+ * country: string()
335
+ * }),
336
+ * id: number()
337
+ * });
338
+ *
339
+ * const addressCityDescriptor = object.getPropertiesFor(schema).address.city;
340
+ * ```
341
+ * And then you try to set a new value to the `address.city` property on the object
342
+ * which does not have `address` property:
343
+ * ```ts
344
+ * const obj = {
345
+ * name: 'Leo'
346
+ * };
347
+ *
348
+ * const success = addressCityDescriptor.setValue(obj, 'Venyov');
349
+ * // success === false
350
+ * ```
351
+ *
352
+ * @param obj Object to set the value to
353
+ * @param value a new value to set to the property
354
+ * @param options additional optional parameters to control the process
355
+ * @returns
356
+ */
357
+ setValue: (obj: InferType<TSchema>, value: InferType<TPropertySchema>, options?: PropertySetterOptions) => boolean;
358
+ /**
359
+ * Gets the value of the property from the object.
360
+ * @param obj object to get the value from
361
+ * @returns an object containing a `value` and `success` properties. `value` is the value of the property
362
+ * if it was found in the object, `success` is a boolean value indicating if the property was found in the object.
363
+ */
364
+ getValue: (obj: InferType<TSchema>) => {
365
+ value?: InferType<TPropertySchema>;
366
+ success: boolean;
367
+ };
368
+ /**
369
+ * Gets the schema for the property described by the property descriptor.
370
+ * @returns a schema for the property
371
+ */
372
+ getSchema: () => TPropertySchema;
373
+ parent: PropertyDescriptorInnerFromPropertyDescriptor<TParentPropertyDescriptor>;
374
+ /**
375
+ * The name of this property within its parent object, or `undefined`
376
+ * for the root descriptor.
377
+ */
378
+ propertyName: string | undefined;
379
+ /**
380
+ * Returns a JSON Pointer (RFC 6901) string representing this
381
+ * property's path from the root descriptor.
382
+ *
383
+ * Property names are escaped per RFC 6901 (`~` → `~0`, `/` → `~1`).
384
+ * The root descriptor returns an empty string (`''`).
385
+ */
386
+ toJsonPointer: () => string;
50
387
  };
388
+ /**
389
+ * A wrapper object keyed by {@link SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR} that
390
+ * holds a {@link PropertyDescriptorInner} for a particular property within
391
+ * an object schema. Used to get/set property values on validated objects.
392
+ */
393
+ export type PropertyDescriptor<TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any>, TPropertySchema, TParentPropertyDescriptor> = {
394
+ [SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR]: PropertyDescriptorInner<TRootSchema, TPropertySchema, TParentPropertyDescriptor>;
395
+ };
396
+ /**
397
+ * A tree of property descriptors for the schema.
398
+ * Has a possibility to filter properties by the type (`TAssignableTo` type parameter).
399
+ */
400
+ export type PropertyDescriptorTree<TSchema extends ObjectSchemaBuilder<any, any, any, any, any>, TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any> = TSchema, TAssignableTo = any, TParentPropertyDescriptor = undefined> = PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor> & (TSchema extends ObjectSchemaBuilder<infer TProperties, any, any> ? {
401
+ [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder<any, any, any> ? PropertyDescriptorTree<TProperties[K], TRootSchema, any, PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor>> : TProperties[K] extends ExternSchemaBuilder<any, any, any, any, any, any, infer TExternResult> ? PropertyDescriptor<TRootSchema, TProperties[K], PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor>> & ExternOutputPropertyDescriptors<TExternResult, TRootSchema, PropertyDescriptor<TRootSchema, TProperties[K], PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor>>> : TProperties[K] extends ArraySchemaBuilder<infer TArrayElement, any, any> ? TArrayElement extends ObjectSchemaBuilder<any, any, any, any, any> ? PropertyDescriptor<TRootSchema, TProperties[K], PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor>> : InferType<TProperties[K]> extends TAssignableTo ? PropertyDescriptor<TRootSchema, TProperties[K], PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor>> : never : InferType<TProperties[K]> extends TAssignableTo ? PropertyDescriptor<TRootSchema, TProperties[K], PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor>> : never;
402
+ } : never);
403
+ /**
404
+ * Recursively maps the keys of an extern schema's output type into
405
+ * property descriptors. When a value is a plain-object type its keys
406
+ * are expanded recursively; primitives, arrays, Dates, and functions
407
+ * are treated as leaves.
408
+ *
409
+ * @internal
410
+ */
411
+ type ExternOutputPropertyDescriptors<TOutput, TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any>, TParentPropertyDescriptor> = TOutput extends Date | Function | readonly any[] | string | number | boolean | symbol | bigint | null | undefined ? {} : TOutput extends Record<string, any> ? {
412
+ [K in keyof TOutput]: PropertyDescriptor<TRootSchema, SchemaBuilder<TOutput[K], true, false, false, {}>, TParentPropertyDescriptor> & ExternOutputPropertyDescriptors<TOutput[K], TRootSchema, PropertyDescriptor<TRootSchema, SchemaBuilder<TOutput[K], true, false, false, {}>, TParentPropertyDescriptor>>;
413
+ } : {};
414
+ /**
415
+ * Creates an array augmented with non-enumerable NestedValidationResult
416
+ * properties (`seenValue`, `errors`, `isValid`, `descriptor`).
417
+ * Used by UnionSchemaBuilder and ArraySchemaBuilder to return hybrid
418
+ * arrays from `getErrorsFor()`.
419
+ */
420
+ export declare function createHybridErrorArray<T extends any[]>(items: T, seenValue: () => any, errors: () => ReadonlyArray<string>, descriptor: () => any): T;
421
+ /**
422
+ * Resolves the full output type of a schema, accounting for `TRequired` and
423
+ * `TNullable` modifiers. Mirrors the branded `[__type]` computation so that
424
+ * the `~standard` Standard Schema property carries the correct inferred type.
425
+ *
426
+ * - When `TRequired = true` and `TNullable = false` the result is `TResult`.
427
+ * - When `TRequired = true` and `TNullable = true` the result is `TResult | null`.
428
+ * - When `TRequired = false` the result is wrapped by {@link MakeOptional},
429
+ * adding `| undefined` (and `| null` when also nullable).
430
+ *
431
+ * @internal
432
+ */
433
+ type ResolvedSchemaType<TResult, TRequired extends boolean, TNullable extends boolean> = TRequired extends true ? TNullable extends true ? TResult | null : TResult : MakeOptional<TNullable extends true ? TResult | null : TResult>;
51
434
  /**
52
435
  * Base class for all schema builders. Provides basic functionality for schema building.
53
436
  *
@@ -55,45 +438,195 @@ export type ValidationContext = {
55
438
  * @typeparam TResult Type of the object that will be returned by `validate()` method.
56
439
  * @typeparam TRequired If `true`, object will be required. If `false`, object will be optional.
57
440
  */
58
- export declare abstract class SchemaBuilder<TResult = any, TRequired extends boolean = true> {
441
+ export declare abstract class SchemaBuilder<TResult = any, TRequired extends boolean = true, TNullable extends boolean = false, THasDefault extends boolean = false, TExtensions = {}> {
59
442
  #private;
60
443
  /**
61
- * Set type of schema explicitly. `notUsed` param is needed only for cas when JS is used. E.g. when you
444
+ * Type-level brand encoding the inferred type of this schema.
445
+ * Not emitted at runtime — used only by {@link InferType}.
446
+ * @internal
447
+ */
448
+ readonly [__type]: TRequired extends true ? TNullable extends true ? TResult | null : TResult : MakeOptional<TNullable extends true ? TResult | null : TResult>;
449
+ /**
450
+ * Type-level brand encoding whether this schema has a default value.
451
+ * Not emitted at runtime — used by input type inference.
452
+ * @internal
453
+ */
454
+ readonly [__hasDefault]: THasDefault;
455
+ /**
456
+ * Standard Schema v1 interface.
457
+ *
458
+ * Exposes this schema as a [Standard Schema v1](https://standardschema.dev/)
459
+ * validator, enabling out-of-the-box interoperability with any library that
460
+ * consumes the spec — including tRPC, TanStack Form, React Hook Form, T3 Env,
461
+ * Hono, Elysia, next-safe-action, and 50+ other tools.
462
+ *
463
+ * Every `SchemaBuilder` subclass (all 13 builders) inherits this property
464
+ * automatically — no additional setup required.
465
+ *
466
+ * **Shape of the returned object:**
467
+ * - `version` — always `1` (Standard Schema spec version)
468
+ * - `vendor` — `'@cleverbrush/schema'`
469
+ * - `validate(value)` — synchronous; wraps this builder's own `.validate()`
470
+ * and converts its result to the Standard Schema `Result<Output>` format:
471
+ * - Success: `{ value: <validated output> }`
472
+ * - Failure: `{ issues: [{ message: string }, …] }`
473
+ *
474
+ * The returned object is **cached** after the first access so repeated reads
475
+ * return the same reference (required by the spec).
476
+ *
477
+ * @example
478
+ * ```ts
479
+ * import { object, string, number } from '@cleverbrush/schema';
480
+ *
481
+ * const UserSchema = object({
482
+ * name: string().minLength(2),
483
+ * email: string().email(),
484
+ * age: number().min(18).optional(),
485
+ * });
486
+ *
487
+ * // Grab the Standard Schema interface
488
+ * const std = UserSchema['~standard'];
489
+ * // std.version === 1
490
+ * // std.vendor === '@cleverbrush/schema'
491
+ *
492
+ * const ok = std.validate({ name: 'Alice', email: 'alice@example.com' });
493
+ * // { value: { name: 'Alice', email: 'alice@example.com', age: undefined } }
494
+ *
495
+ * const fail = std.validate({ name: 'A', email: 'not-an-email' });
496
+ * // { issues: [{ message: 'minLength' }, { message: 'email' }] }
497
+ *
498
+ * // Pass directly to TanStack Form, T3 Env, tRPC, etc.:
499
+ * // validators: { onChange: UserSchema, onBlur: UserSchema }
500
+ * ```
501
+ *
502
+ * @see https://standardschema.dev/
503
+ */
504
+ get ['~standard'](): StandardSchemaV1.Props<ResolvedSchemaType<TResult, TRequired, TNullable>>;
505
+ /**
506
+ * Set type of schema explicitly. `notUsed` param is needed only for case when JS is used. E.g. when you
62
507
  * can't call method like `schema.hasType<Date>()`, so instead you can call `schema.hasType(new Date())`
63
508
  * with the same result.
64
509
  */
65
510
  abstract hasType<T>(notUsed?: T): any;
66
511
  /**
67
512
  * Clears type set by call to `.hasType<T>()`, default schema type inference will be used
68
- * for schema retuned by this call.
513
+ * for schema returned by this call.
69
514
  */
70
515
  abstract clearHasType(): any;
71
516
  /**
72
- * Protected method used to create an new instance of the Builder
73
- * defined by the `props` object. Should be used to instanticate new
517
+ * Protected method used to create a new instance of the Builder
518
+ * defined by the `props` object. Should be used to instantiate new
74
519
  * builders to keep builder's immutability.
75
520
  * @param props arbitrary props object
76
521
  */
77
522
  protected abstract createFromProps(props: any): this;
523
+ /**
524
+ * The string identifier of the schema type (e.g. `'string'`, `'number'`, `'object'`).
525
+ */
78
526
  protected get type(): string;
527
+ /**
528
+ * Sets the schema type identifier. Must be a non-empty string.
529
+ */
79
530
  protected set type(value: string);
80
531
  /**
81
532
  * A list of preprocessors associated with
82
533
  * the Builder
83
534
  */
84
- protected get preprocessors(): Preprocessor<TResult>[];
535
+ protected get preprocessors(): PreprocessorEntry<TResult>[];
85
536
  /**
86
537
  * A list of validators associated with
87
538
  * the Builder
88
539
  */
89
- protected get validators(): Validator<TResult>[];
540
+ protected get validators(): ValidatorEntry<TResult>[];
541
+ /**
542
+ * Whether the schema requires a non-null/non-undefined value.
543
+ */
90
544
  protected get isRequired(): TRequired;
545
+ /**
546
+ * Whether `null` is an accepted value for this schema.
547
+ */
548
+ protected get isNullable(): boolean;
549
+ /**
550
+ * Sets the requirement flag. Must be a boolean.
551
+ */
91
552
  protected set isRequired(value: boolean);
92
- protected preValidate(
93
553
  /**
94
- * Object to validate
554
+ * The error message provider used for the "is required" error.
555
+ * Exposed for fast-path validation in subclasses.
556
+ */
557
+ protected get requiredErrorMessage(): ValidationErrorMessageProvider;
558
+ /**
559
+ * Whether this schema has a default value configured via `.default()`.
560
+ * Exposed for fast-path validation in subclasses.
561
+ */
562
+ protected get hasDefault(): boolean;
563
+ /**
564
+ * Whether this schema has a catch/fallback value configured via `.catch()`.
565
+ */
566
+ protected get hasCatch(): boolean;
567
+ /**
568
+ * Resolves the catch/fallback value. If the stored value is a factory function,
569
+ * it is called to produce the value (useful for mutable fallbacks like `() => []`).
570
+ */
571
+ protected resolveCatchValue(): TResult;
572
+ /**
573
+ * Whether this schema is marked as readonly.
574
+ * Type-level only — no runtime enforcement.
575
+ */
576
+ protected get isReadonly(): boolean;
577
+ /**
578
+ * Resolves the default value. If the stored default is a function,
579
+ * it is called to produce the value (useful for mutable defaults).
580
+ */
581
+ protected resolveDefaultValue(): TResult;
582
+ /**
583
+ * Whether `preValidateSync` can be skipped entirely.
584
+ * True when there are no preprocessors and no validators,
585
+ * so the only work would be the required check and wrapping
586
+ * in a noop transaction — which subclasses can do inline.
587
+ */
588
+ protected get canSkipPreValidation(): boolean;
589
+ /**
590
+ * Whether `null` should count as a required-constraint violation.
591
+ *
592
+ * By default `null` is treated the same as `undefined` for the purposes
593
+ * of the required check — i.e. a required schema rejects both.
594
+ * Subclasses that may legally receive `null` as a value (e.g.
595
+ * `UnionSchemaBuilder` when a `NullSchemaBuilder` option is present)
596
+ * can override this to `false` so that `null` bypasses the required
597
+ * check and is passed directly to their option-validation logic.
598
+ *
599
+ * @protected
600
+ */
601
+ protected get isNullRequiredViolation(): boolean;
602
+ /**
603
+ * Synchronous version of {@link preValidateAsync}.
604
+ * Throws at runtime if any preprocessor or validator returns a Promise.
605
+ *
606
+ * @param object - the value to pre-validate
607
+ * @param context - optional validation context settings
608
+ * @returns a `PreValidationResult` containing the preprocessed transaction, context, and any errors
609
+ * @throws Error if a preprocessor or validator returns a Promise (use {@link preValidateAsync} instead)
610
+ */
611
+ protected preValidateSync(object: any, context?: ValidationContext): PreValidationResult<any, {
612
+ validatedObject: any;
613
+ }>;
614
+ /**
615
+ * Async version of pre-validation. Runs preprocessors, validators, and the
616
+ * required/optional check on `object`. Supports async preprocessors,
617
+ * validators, and error message providers.
618
+ *
619
+ * @param object - the value to pre-validate
620
+ * @param context - optional validation context settings
621
+ * @returns a `PreValidationResult` containing the preprocessed transaction, context, and any errors
95
622
  */
96
- object: any, context?: ValidationContext): Promise<PreValidationResult<any, {
623
+ protected preValidateAsync(object: any, context?: ValidationContext): Promise<PreValidationResult<any, {
624
+ validatedObject: any;
625
+ }>>;
626
+ /**
627
+ * @deprecated Use {@link preValidateAsync} instead. This alias will be removed in a future version.
628
+ */
629
+ protected preValidate(object: any, context?: ValidationContext): Promise<PreValidationResult<any, {
97
630
  validatedObject: any;
98
631
  }>>;
99
632
  /**
@@ -109,27 +642,262 @@ export declare abstract class SchemaBuilder<TResult = any, TRequired extends boo
109
642
  * will be considered as valid).
110
643
  */
111
644
  isRequired: boolean;
645
+ /**
646
+ * If set to `true`, schema values of `null` are considered valid.
647
+ */
648
+ isNullable: boolean;
649
+ /**
650
+ * If set to `true`, the inferred type is marked as readonly.
651
+ * Type-level only — no runtime enforcement.
652
+ */
653
+ isReadonly: boolean;
112
654
  /**
113
655
  * Array of preprocessor functions
114
656
  */
115
- preprocessors: readonly Preprocessor<TResult>[];
657
+ preprocessors: readonly PreprocessorEntry<TResult>[];
116
658
  /**
117
659
  * Array of validator functions
118
660
  */
119
- validators: readonly Validator<TResult>[];
661
+ validators: readonly ValidatorEntry<TResult>[];
662
+ /**
663
+ * Custom error message provider for the 'is required' validation error.
664
+ */
665
+ requiredValidationErrorMessageProvider: ValidationErrorMessageProvider<SchemaBuilder<any, any, any, any, any>>;
666
+ /**
667
+ * Extension metadata. Stores custom state set by schema extensions.
668
+ */
669
+ extensions: {
670
+ [x: string]: unknown;
671
+ };
672
+ /**
673
+ * Whether a default value (or factory) has been set on this schema.
674
+ */
675
+ hasDefault: boolean;
676
+ /**
677
+ * The default value or factory function.
678
+ */
679
+ defaultValue: TResult | (() => TResult) | undefined;
680
+ /**
681
+ * The human-readable description attached to this schema via `.describe()`,
682
+ * or `undefined` if none was set.
683
+ */
684
+ description: string | undefined;
685
+ /**
686
+ * The logical name attached to this schema via `.schemaName()`,
687
+ * or `undefined` if none was set.
688
+ */
689
+ schemaName: string | undefined;
690
+ /**
691
+ * Whether a catch/fallback value has been set on this schema via `.catch()`.
692
+ */
693
+ hasCatch: boolean;
694
+ /**
695
+ * The catch/fallback value or factory function set via `.catch()`.
696
+ */
697
+ catchValue: TResult | (() => TResult) | undefined;
698
+ /**
699
+ * An example value attached to this schema via `.example()`,
700
+ * or `undefined` if none was set.
701
+ */
702
+ example: unknown;
120
703
  };
121
704
  /**
122
705
  * Makes schema optional (consider `null` and `undefined` as valid objects for this schema)
123
706
  */
124
707
  optional(): any;
708
+ /**
709
+ * Makes schema nullable — `null` is accepted as a valid value.
710
+ *
711
+ * Unlike `.optional()` which accepts `undefined`, `.nullable()` accepts
712
+ * `null`. The inferred type changes from `T` to `T | null`. Combine with
713
+ * `.optional()` to accept both `null` and `undefined`.
714
+ */
715
+ nullable(): any;
716
+ /**
717
+ * Removes the nullable mark — `null` is no longer accepted as a valid
718
+ * value. This is the counterpart of `.nullable()`.
719
+ */
720
+ notNullable(): any;
721
+ /**
722
+ * Sets a default value for this schema. When the input is `undefined`,
723
+ * the default value is used instead. The default is still validated
724
+ * against the schema's constraints.
725
+ *
726
+ * Accepts either a static value or a factory function (useful for
727
+ * mutable defaults like `() => new Date()` or `() => []`).
728
+ *
729
+ * @example
730
+ * ```ts
731
+ * const schema = string().default('hello');
732
+ * schema.validate(undefined); // { valid: true, object: 'hello' }
733
+ * schema.validate('world'); // { valid: true, object: 'world' }
734
+ * ```
735
+ *
736
+ * @example
737
+ * ```ts
738
+ * // Factory function for mutable defaults
739
+ * const schema = array(string()).default(() => []);
740
+ * ```
741
+ */
742
+ default(value: TResult | (() => TResult)): any;
743
+ /**
744
+ * Sets a fallback value for this schema. When validation **fails** for any reason,
745
+ * the fallback value is returned as a successful result instead of validation errors.
746
+ *
747
+ * This is useful for graceful degradation — for example, providing a safe default
748
+ * when parsing untrusted input that might not conform to the schema.
749
+ *
750
+ * Accepts either a static value or a factory function. Factory functions are called
751
+ * each time the fallback is needed (useful for mutable values like `() => []`).
752
+ *
753
+ * Unlike {@link default}, which only fires when the input is `undefined`, `.catch()`
754
+ * fires on **any** validation failure — type mismatch, constraint violation, etc.
755
+ *
756
+ * When `.catch()` is set, {@link parse} and {@link parseAsync} will **never throw**.
757
+ *
758
+ * @param value - the fallback value, or a factory function producing the fallback
759
+ *
760
+ * @example
761
+ * ```ts
762
+ * const schema = string().catch('unknown');
763
+ * schema.validate(42); // { valid: true, object: 'unknown' }
764
+ * schema.validate('hello'); // { valid: true, object: 'hello' }
765
+ * schema.parse(42); // 'unknown' (no throw)
766
+ * ```
767
+ *
768
+ * @example
769
+ * ```ts
770
+ * // Factory function for mutable fallbacks
771
+ * const schema = array(string()).catch(() => []);
772
+ * schema.validate(null); // { valid: true, object: [] }
773
+ * ```
774
+ *
775
+ * @example
776
+ * ```ts
777
+ * // Contrast with .default() — default fires only on undefined
778
+ * const d = string().default('anon');
779
+ * d.validate(undefined); // { valid: true, object: 'anon' } ← fires
780
+ * d.validate(42); // { valid: false, errors: [...] } ← does NOT fire
781
+ *
782
+ * const c = string().catch('anon');
783
+ * c.validate(undefined); // { valid: true, object: 'anon' } ← fires
784
+ * c.validate(42); // { valid: true, object: 'anon' } ← also fires
785
+ * ```
786
+ */
787
+ catch(value: TResult | (() => TResult)): this;
788
+ /**
789
+ * Removes the default value set by a previous call to `.default()`.
790
+ */
791
+ clearDefault(): any;
792
+ /**
793
+ * Attaches a human-readable description to this schema as runtime metadata.
794
+ *
795
+ * The description has no effect on validation — it is purely informational.
796
+ * It is accessible via `.introspect().description` and is emitted as the
797
+ * `description` field by `toJsonSchema()` from `@cleverbrush/schema-json`.
798
+ *
799
+ * Useful for documentation generation, form labels, and AI tool descriptions.
800
+ *
801
+ * @example
802
+ * ```ts
803
+ * const schema = object({
804
+ * name: string().describe('The user\'s full name'),
805
+ * age: number().optional().describe('Age in years'),
806
+ * }).describe('A user object');
807
+ *
808
+ * schema.introspect().description; // 'A user object'
809
+ * ```
810
+ */
811
+ describe(text: string): this;
812
+ /**
813
+ * Attaches an example value to this schema instance.
814
+ *
815
+ * The example is purely metadata — it has no effect on validation.
816
+ * It is accessible via `.introspect().example` and is emitted as the
817
+ * `example` keyword in JSON Schema output and OpenAPI spec generation.
818
+ *
819
+ * @example
820
+ * ```ts
821
+ * import { string } from '@cleverbrush/schema';
822
+ *
823
+ * const Email = string().example('user@example.com');
824
+ *
825
+ * Email.introspect().example; // 'user@example.com'
826
+ * ```
827
+ */
828
+ example(value: TResult): this;
829
+ /**
830
+ * Attaches a logical name to this schema instance.
831
+ *
832
+ * The name is purely metadata — it has no effect on validation. It is
833
+ * accessible via `.introspect().schemaName` and can be consumed by any
834
+ * tool that introspects schemas at runtime, such as OpenAPI spec
835
+ * generators, documentation tools, form libraries, or code generators.
836
+ *
837
+ * **Uniqueness** is the responsibility of the consuming tool. Passing the
838
+ * same constant (same object reference) to multiple consumers is always
839
+ * safe; how conflicts between different instances with the same name are
840
+ * handled depends on the tool.
841
+ *
842
+ * @example
843
+ * ```ts
844
+ * import { object, string, number } from '@cleverbrush/schema';
845
+ *
846
+ * export const UserSchema = object({
847
+ * id: number(),
848
+ * name: string(),
849
+ * }).schemaName('User');
850
+ *
851
+ * UserSchema.introspect().schemaName; // 'User'
852
+ * ```
853
+ */
854
+ schemaName(name: string): this;
855
+ /**
856
+ * Brands the schema with a phantom type tag, preventing structural mixing
857
+ * of semantically different values at the type level. Zero runtime cost.
858
+ *
859
+ * The optional `_name` parameter is only needed when using plain JavaScript
860
+ * (where generic type parameters are unavailable). In TypeScript, prefer
861
+ * the generic form: `schema.brand<'Email'>()`.
862
+ *
863
+ * @example
864
+ * ```ts
865
+ * const Email = string().brand<'Email'>();
866
+ * const Username = string().brand<'Username'>();
867
+ * type Email = InferType<typeof Email>; // string & { readonly [BRAND]: 'Email' }
868
+ * type Username = InferType<typeof Username>; // string & { readonly [BRAND]: 'Username' }
869
+ * ```
870
+ */
871
+ brand<TBrand extends string | symbol>(_name?: TBrand): any;
872
+ /**
873
+ * Marks the inferred type as readonly. For objects, produces `Readonly<T>`.
874
+ * For arrays, produces `ReadonlyArray<T>`. Primitives are unchanged.
875
+ * Type-level only — no runtime enforcement.
876
+ *
877
+ * @example
878
+ * ```ts
879
+ * const schema = object({ name: string(), age: number() }).readonly();
880
+ * type T = InferType<typeof schema>; // Readonly<{ name: string; age: number }>
881
+ * ```
882
+ *
883
+ * @example
884
+ * ```ts
885
+ * const schema = array(string()).readonly();
886
+ * type T = InferType<typeof schema>; // ReadonlyArray<string>
887
+ * ```
888
+ */
889
+ readonly(): any;
125
890
  /**
126
891
  * Makes schema required (consider `null` and `undefined` as invalid objects for this schema)
892
+ * @param errorMessage - optional custom error message or provider for the 'is required' validation error
127
893
  */
128
- required(): any;
894
+ required(errorMessage?: ValidationErrorMessageProvider): any;
129
895
  /**
130
896
  * Adds a `preprocessor` to a preprocessors list
131
897
  */
132
- addPreprocessor(preprocessor: Preprocessor<TResult>): this;
898
+ addPreprocessor(preprocessor: Preprocessor<TResult>, options?: {
899
+ mutates?: boolean;
900
+ }): this;
133
901
  /**
134
902
  * Remove all preprocessors for this schema.
135
903
  */
@@ -137,15 +905,53 @@ export declare abstract class SchemaBuilder<TResult = any, TRequired extends boo
137
905
  /**
138
906
  * Adds a `validator` to validators list.
139
907
  */
140
- addValidator(validator: Validator<TResult>): this;
908
+ addValidator(validator: Validator<TResult>, options?: {
909
+ mutates?: boolean;
910
+ }): this;
141
911
  /**
142
912
  * Remove all validators for this schema.
143
913
  */
144
914
  clearValidators(): this;
145
915
  /**
146
- * Perform schema validation on `object`.
916
+ * Perform synchronous schema validation on `object`.
917
+ * Throws at runtime if any preprocessor, validator, or error message
918
+ * provider returns a Promise — use {@link validateAsync} instead.
919
+ * @internal Override this in subclasses. External callers use {@link validate}.
920
+ */
921
+ protected abstract _validate(object: any, context?: ValidationContext): ValidationResult<any>;
922
+ /**
923
+ * Perform asynchronous schema validation on `object`.
924
+ * Supports async preprocessors, validators, and error message providers.
925
+ * @internal Override this in subclasses. External callers use {@link validateAsync}.
926
+ */
927
+ protected abstract _validateAsync(object: any, context?: ValidationContext): Promise<ValidationResult<any>>;
928
+ /**
929
+ * Perform synchronous schema validation on `object`.
930
+ * Throws at runtime if any preprocessor, validator, or error message
931
+ * provider returns a Promise — use {@link validateAsync} instead.
932
+ *
933
+ * If a fallback has been set via {@link catch}, a failed validation result
934
+ * is replaced by a successful result built from the fallback value, preserving
935
+ * the specialized result shape (e.g. `getErrorsFor` / `getNestedErrors` methods).
936
+ */
937
+ validate(
938
+ /**
939
+ * Object to validate
147
940
  */
148
- abstract validate(
941
+ object: any,
942
+ /**
943
+ * Optional `ValidationContext` settings
944
+ */
945
+ context?: ValidationContext): ValidationResult<any>;
946
+ /**
947
+ * Perform asynchronous schema validation on `object`.
948
+ * Supports async preprocessors, validators, and error message providers.
949
+ *
950
+ * If a fallback has been set via {@link catch}, a failed validation result
951
+ * is replaced by a successful result built from the fallback value, preserving
952
+ * the specialized result shape (e.g. `getErrorsFor` / `getNestedErrors` methods).
953
+ */
954
+ validateAsync(
149
955
  /**
150
956
  * Object to validate
151
957
  */
@@ -154,6 +960,77 @@ export declare abstract class SchemaBuilder<TResult = any, TRequired extends boo
154
960
  * Optional `ValidationContext` settings
155
961
  */
156
962
  context?: ValidationContext): Promise<ValidationResult<any>>;
963
+ /**
964
+ * Synchronously resolves a `ValidationErrorMessageProvider` to a string.
965
+ * Throws if the provider function returns a Promise.
966
+ *
967
+ * @param provider - the error message provider (string or sync function)
968
+ * @param seenValue - the value that caused the validation error
969
+ * @returns the resolved error message string
970
+ * @throws Error if the provider returns a Promise (use {@link getValidationErrorMessage} with {@link validateAsync})
971
+ */
972
+ protected getValidationErrorMessageSync(provider: ValidationErrorMessageProvider<any>, seenValue: TResult): string;
973
+ /**
974
+ * Resolves a `ValidationErrorMessageProvider` to a string error message.
975
+ * Handles both string providers and function providers (sync or async).
976
+ *
977
+ * @param provider - the error message provider (string or function)
978
+ * @param seenValue - the value that caused the validation error
979
+ * @returns the resolved error message string
980
+ */
981
+ protected getValidationErrorMessage(provider: ValidationErrorMessageProvider<any>, seenValue: TResult): Promise<string>;
982
+ /**
983
+ * Ensures a `ValidationErrorMessageProvider` is valid.
984
+ * If `provider` is `undefined`, falls back to `defaultValue`.
985
+ * Function providers are bound to `this` for access to schema state.
986
+ *
987
+ * @param provider - the provider to validate, or `undefined`
988
+ * @param defaultValue - fallback provider when `provider` is not supplied
989
+ * @returns a valid `ValidationErrorMessageProvider`
990
+ */
991
+ protected assureValidationErrorMessageProvider(provider: ValidationErrorMessageProvider<any> | undefined, defaultValue: ValidationErrorMessageProvider<any>): ValidationErrorMessageProvider<any>;
992
+ /**
993
+ * Sets extension metadata by key. Returns a new schema instance with the
994
+ * extension data stored. The data survives fluent chaining.
995
+ * @internal Used by extension authors inside `defineExtension()` callbacks.
996
+ */
997
+ withExtension(key: string, value: unknown): this;
998
+ /**
999
+ * Retrieves extension metadata by key.
1000
+ * @internal Used by extension authors inside `defineExtension()` callbacks.
1001
+ */
1002
+ getExtension(key: string): unknown;
1003
+ /**
1004
+ * Synchronously validates the value and returns it if valid.
1005
+ * Throws a {@link SchemaValidationError} if validation fails.
1006
+ *
1007
+ * @param object - the value to parse
1008
+ * @param context - optional validation context
1009
+ * @returns the validated value
1010
+ * @throws SchemaValidationError if validation fails
1011
+ * @throws Error if the schema contains async preprocessors, validators, or error message providers
1012
+ */
1013
+ parse(object: any, context?: ValidationContext): TResult;
1014
+ /**
1015
+ * Asynchronously validates the value and returns it if valid.
1016
+ * Throws a {@link SchemaValidationError} if validation fails.
1017
+ *
1018
+ * @param object - the value to parse
1019
+ * @param context - optional validation context
1020
+ * @returns the validated value
1021
+ * @throws SchemaValidationError if validation fails
1022
+ */
1023
+ parseAsync(object: any, context?: ValidationContext): Promise<TResult>;
1024
+ /**
1025
+ * Alias for {@link validate}. Synchronously validates and returns a result object.
1026
+ * Provided for familiarity with the zod API.
1027
+ */
1028
+ safeParse(object: any, context?: ValidationContext): ValidationResult<TResult>;
1029
+ /**
1030
+ * Alias for {@link validateAsync}. Asynchronously validates and returns a result object.
1031
+ * Provided for familiarity with the zod API.
1032
+ */
1033
+ safeParseAsync(object: any, context?: ValidationContext): Promise<ValidationResult<TResult>>;
157
1034
  protected constructor(props: SchemaBuilderProps<TResult>);
158
1035
  }
159
1036
  export {};