@cleverbrush/schema 3.1.0 → 4.1.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 (66) hide show
  1. package/README.md +35 -2
  2. package/dist/builders/AnySchemaBuilder.js +1 -1
  3. package/dist/builders/ArraySchemaBuilder.js +1 -1
  4. package/dist/builders/BooleanSchemaBuilder.js +1 -1
  5. package/dist/builders/DateSchemaBuilder.js +1 -1
  6. package/dist/builders/ExternSchemaBuilder.js +1 -1
  7. package/dist/builders/FunctionSchemaBuilder.js +1 -1
  8. package/dist/builders/IntersectionSchemaBuilder.d.ts +124 -0
  9. package/dist/builders/NumberSchemaBuilder.js +1 -1
  10. package/dist/builders/ObjectSchemaBuilder.js +1 -1
  11. package/dist/builders/ParseStringSchemaBuilder.d.ts +9 -0
  12. package/dist/builders/ParseStringSchemaBuilder.js +1 -1
  13. package/dist/builders/PromiseSchemaBuilder.js +1 -1
  14. package/dist/builders/RecordSchemaBuilder.js +1 -1
  15. package/dist/builders/SchemaBuilder.d.ts +13 -7
  16. package/dist/builders/StringSchemaBuilder.js +1 -1
  17. package/dist/builders/TupleSchemaBuilder.js +1 -1
  18. package/dist/builders/UnionSchemaBuilder.js +1 -1
  19. package/dist/chunk-54RHS4F4.js +2 -0
  20. package/dist/chunk-54RHS4F4.js.map +1 -0
  21. package/dist/{chunk-K6Z47OQY.js → chunk-6LSN7NXQ.js} +2 -2
  22. package/dist/{chunk-WQDYWDOE.js → chunk-C6YQOKWB.js} +2 -2
  23. package/dist/{chunk-BUEVZ3KA.js → chunk-ELPPAHNO.js} +2 -2
  24. package/dist/{chunk-QARCEYGO.js → chunk-G424M7GI.js} +2 -2
  25. package/dist/{chunk-WDMJBGBD.js → chunk-JUFZ7PLO.js} +2 -2
  26. package/dist/{chunk-ZC6YBKCP.js → chunk-K4ZLXLE2.js} +2 -2
  27. package/dist/{chunk-NUW3VXZV.js → chunk-KC45JEFL.js} +2 -2
  28. package/dist/{chunk-EIVZX4ZO.js → chunk-NF4CRFMN.js} +2 -2
  29. package/dist/{chunk-YQZHDMRF.js → chunk-ORV2G6ZL.js} +2 -2
  30. package/dist/{chunk-CFIJQ4GP.js → chunk-PQINUGZW.js} +2 -2
  31. package/dist/chunk-REYZ7G7J.js +2 -0
  32. package/dist/chunk-REYZ7G7J.js.map +1 -0
  33. package/dist/chunk-VSU5GILY.js +2 -0
  34. package/dist/chunk-VSU5GILY.js.map +1 -0
  35. package/dist/chunk-XHSBY2QK.js +2 -0
  36. package/dist/chunk-XHSBY2QK.js.map +1 -0
  37. package/dist/{chunk-ZFI27R3L.js → chunk-XL723XFL.js} +2 -2
  38. package/dist/{chunk-HN774HD7.js → chunk-XPLTW5DI.js} +2 -2
  39. package/dist/{chunk-PHE4LIAN.js → chunk-YAOZEA2R.js} +2 -2
  40. package/dist/core.d.ts +4 -2
  41. package/dist/core.js +1 -1
  42. package/dist/extension.d.ts +76 -4
  43. package/dist/extension.js +2 -0
  44. package/dist/extension.js.map +1 -0
  45. package/dist/index.js +1 -1
  46. package/dist/index.js.map +1 -1
  47. package/package.json +6 -2
  48. package/dist/chunk-3JMDGYDT.js +0 -2
  49. package/dist/chunk-3JMDGYDT.js.map +0 -1
  50. package/dist/chunk-DY7J6RNN.js +0 -2
  51. package/dist/chunk-DY7J6RNN.js.map +0 -1
  52. package/dist/chunk-GXPV6UQK.js +0 -2
  53. package/dist/chunk-GXPV6UQK.js.map +0 -1
  54. /package/dist/{chunk-K6Z47OQY.js.map → chunk-6LSN7NXQ.js.map} +0 -0
  55. /package/dist/{chunk-WQDYWDOE.js.map → chunk-C6YQOKWB.js.map} +0 -0
  56. /package/dist/{chunk-BUEVZ3KA.js.map → chunk-ELPPAHNO.js.map} +0 -0
  57. /package/dist/{chunk-QARCEYGO.js.map → chunk-G424M7GI.js.map} +0 -0
  58. /package/dist/{chunk-WDMJBGBD.js.map → chunk-JUFZ7PLO.js.map} +0 -0
  59. /package/dist/{chunk-ZC6YBKCP.js.map → chunk-K4ZLXLE2.js.map} +0 -0
  60. /package/dist/{chunk-NUW3VXZV.js.map → chunk-KC45JEFL.js.map} +0 -0
  61. /package/dist/{chunk-EIVZX4ZO.js.map → chunk-NF4CRFMN.js.map} +0 -0
  62. /package/dist/{chunk-YQZHDMRF.js.map → chunk-ORV2G6ZL.js.map} +0 -0
  63. /package/dist/{chunk-CFIJQ4GP.js.map → chunk-PQINUGZW.js.map} +0 -0
  64. /package/dist/{chunk-ZFI27R3L.js.map → chunk-XL723XFL.js.map} +0 -0
  65. /package/dist/{chunk-HN774HD7.js.map → chunk-XPLTW5DI.js.map} +0 -0
  66. /package/dist/{chunk-PHE4LIAN.js.map → chunk-YAOZEA2R.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/transaction.ts","../src/builders/SchemaBuilder.ts"],"sourcesContent":["const TRANSACTION_SYMBOL = Symbol('transaction');\n\nconst defaultNonTransactionalTypes = [Error, RegExp, Date];\n\n/**\n * Options for customizing transaction behavior.\n */\nexport type TransactionOptions = {\n /**\n * An optional callback returning boolean. Called for every\n * nested object's property (recursively) which is not\n * null `Object`. Using this function you can define if `child`\n * should be wrapped with transaction. It is useful for\n * some cases like Error, Map, etc. when you want to preserve a link,\n * instead of creation of the new transaction.\n * By default it's filtering all instances inheriting from Error and RegExp\n * If `true` is returned from this function `child` will not be wrapped with\n * nested transaction object.\n */\n shouldNotWrapWithTransaction?: (child: any) => boolean;\n};\n\nconst defaultTransactionOptions: TransactionOptions = {\n shouldNotWrapWithTransaction: child =>\n !!defaultNonTransactionalTypes.find(t => child instanceof t)\n};\n\n/**\n * A transaction wrapper around an object. Provides copy-on-write semantics:\n * modifications to `object` are isolated from the original until `commit()` is called.\n * Use `rollback()` to discard changes, and `isDirty()` to check for pending modifications.\n */\nexport type Transaction<T> = {\n /**\n * Transaction object you can modify (equals to `initial` right after the call).\n * All changes to `object` will not be reflected to `initial` until `commit`\n * is called.\n */\n object: T;\n /**\n * Commits transaction, all changes to `object` will be reflected to `initial`\n * after the call of this function.\n */\n commit: () => T;\n /**\n * Rollbacks transaction moving it to the initial state (`object` will be equal to `initial`\n * after the call of this function).\n */\n rollback: () => T;\n /**\n * Returns `true` if there are any changes to `object` which make it different from `initial`.\n */\n isDirty: () => boolean;\n};\n\n/**\n * Starts a transaction over the `initial` object. The returned `object` is a\n * proxy (for plain objects) or a shallow copy (for arrays) that tracks mutations\n * without modifying `initial`. Call `commit()` to apply or `rollback()` to discard changes.\n *\n * @param initial - the object or array to wrap in a transaction\n * @param options - optional configuration to control which nested values are wrapped\n * @returns a {@link Transaction} with `object`, `commit`, `rollback`, and `isDirty` members\n */\nexport const transaction = <T extends {}>(\n initial: T,\n options?: TransactionOptions\n): Transaction<T> => {\n let newProperties: Record<string | symbol, any> = {};\n let deletedProperties = new Map<keyof T, true>();\n\n options = Object.assign({}, defaultTransactionOptions, options || {});\n\n const { shouldNotWrapWithTransaction } =\n options as Required<TransactionOptions>;\n\n const isDirty = () =>\n !!Object.keys(newProperties).find(key => {\n if (newProperties[key]?.[TRANSACTION_SYMBOL]) {\n return newProperties[key][TRANSACTION_SYMBOL].isDirty();\n }\n return true;\n }) || ((deletedProperties.size > 0) as any);\n\n const commit = () => {\n const result = {} as Record<string, any>;\n Object.keys(initial).forEach(key => {\n result[key] = (initial as any)[key];\n });\n\n Object.keys(newProperties).forEach(key => {\n const value = newProperties[key];\n if (value[TRANSACTION_SYMBOL]) {\n const { commit: childCommit } = value[TRANSACTION_SYMBOL];\n result[key] = childCommit();\n } else {\n result[key] = newProperties[key];\n }\n });\n\n for (const key of deletedProperties.keys()) {\n delete result[key as string];\n }\n\n newProperties = {};\n deletedProperties = new Map<keyof T, true>();\n\n return result as T;\n };\n\n const rollback = () => {\n for (const key in newProperties) {\n const value = newProperties[key];\n if (\n value &&\n typeof value === 'object' &&\n value[TRANSACTION_SYMBOL]\n ) {\n // this is nested transaction, let's rollback it as well\n value[TRANSACTION_SYMBOL].rollback();\n }\n }\n newProperties = {};\n deletedProperties = new Map<keyof T, true>();\n return initial;\n };\n\n if (Array.isArray(initial)) {\n const result = initial.map(el =>\n typeof el === 'object' && el && !shouldNotWrapWithTransaction(el)\n ? transaction(el).object\n : el\n );\n const commitArray = () =>\n result.map(el =>\n el && typeof el[TRANSACTION_SYMBOL] === 'object'\n ? el[TRANSACTION_SYMBOL].commit()\n : el\n );\n\n const isDirtyArray = () => {\n return !!result.find((val, index) => {\n if (val && typeof val[TRANSACTION_SYMBOL] === 'object') {\n return val[TRANSACTION_SYMBOL].isDirty();\n }\n return result[index] !== initial[index];\n });\n };\n Object.defineProperty(result, TRANSACTION_SYMBOL, {\n writable: false,\n configurable: false,\n value: {\n initial,\n object: result,\n commit: commitArray as any,\n rollback: () => initial,\n isDirty: isDirtyArray\n }\n });\n return {\n object: result as any,\n commit: commitArray as any,\n rollback: () => initial,\n isDirty: isDirtyArray\n };\n }\n\n const proxy = new Proxy<T>(initial, {\n set: (target, property, value) => {\n if (target && (target as any)[property] === value) {\n delete newProperties[property];\n return true;\n }\n newProperties[property] = value;\n deletedProperties.delete(property as any);\n return true;\n },\n ownKeys: target => {\n return [\n ...Object.keys(target).filter(\n (k: any) => !deletedProperties.has(k)\n ),\n ...Object.keys(newProperties).filter((k: any) => !(k in target))\n ];\n },\n getOwnPropertyDescriptor: (target, prop: any) => {\n if (deletedProperties.has(prop)) {\n return undefined;\n }\n\n if (prop in newProperties) {\n return Object.getOwnPropertyDescriptor(newProperties, prop);\n }\n\n return Object.getOwnPropertyDescriptor(target, prop);\n },\n has: (target, prop: any) => {\n if (deletedProperties.has(prop)) {\n return false;\n }\n\n if (prop in newProperties) {\n return true;\n }\n\n return prop in target;\n },\n get: (target, prop) => {\n if (typeof prop === 'symbol') {\n if (prop === TRANSACTION_SYMBOL) {\n return {\n initial,\n object: proxy,\n commit,\n rollback,\n isDirty\n };\n }\n return (target as any)[prop];\n }\n\n if (prop in newProperties) {\n return newProperties[prop];\n }\n\n if (deletedProperties.has(prop as any)) {\n return undefined;\n }\n\n if (\n !isTransaction((target as any)[prop]) &&\n typeof (target as any)[prop] === 'object' &&\n (target as any)[prop] &&\n !shouldNotWrapWithTransaction((target as any)[prop])\n ) {\n const { object } = transaction((target as any)[prop], options);\n newProperties[prop] = object;\n return object;\n }\n\n return (target as any)[prop];\n },\n deleteProperty: (target, p) => {\n if (p in newProperties) {\n if (\n newProperties[p] &&\n typeof newProperties[p][TRANSACTION_SYMBOL] === 'object'\n ) {\n newProperties[p][TRANSACTION_SYMBOL].rollback();\n }\n delete newProperties[p];\n }\n if (p in target) {\n deletedProperties.set(p as any, true);\n }\n return true;\n }\n });\n\n return {\n object: proxy,\n commit,\n rollback,\n isDirty\n };\n};\n\n/**\n * Creates a lightweight no-op transaction that wraps the `initial` value\n * without any Proxy or copy-on-write overhead. `commit()` and `rollback()`\n * simply return the original object, and `isDirty()` is always `false`.\n *\n * Use this when no preprocessors or validators are defined — there is no\n * risk of mutation, so the full transaction machinery can be skipped.\n */\nexport const noopTransaction = <T extends {}>(initial: T): Transaction<T> => ({\n object: initial,\n commit: () => initial,\n rollback: () => initial,\n isDirty: () => false\n});\n\n/**\n * Checks if `obj` is an instance of a transaction.\n * @param obj object to check if it's a transaction\n * @returns `true` if `obj` is a transaction, `false` otherwise\n */\nexport const isTransaction = (obj: any) =>\n obj && typeof obj === 'object' && Object.hasOwn(obj, TRANSACTION_SYMBOL);\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport {\n noopTransaction,\n type Transaction,\n transaction\n} from '../utils/transaction.js';\nimport type { ArraySchemaBuilder } from './ArraySchemaBuilder.js';\nimport type { ExternSchemaBuilder } from './ExternSchemaBuilder.js';\nimport type { ObjectSchemaBuilder } from './ObjectSchemaBuilder.js';\n\n/** @internal Symbol used as the key for the type brand on schema builders. */\ndeclare const __type: unique symbol;\n/** @internal */\nexport type SchemaTypeBrand = typeof __type;\n\n/** @internal Symbol used as the key for the default-value brand on schema builders. */\ndeclare const __hasDefault: unique symbol;\n/** @internal */\nexport type HasDefaultBrand = typeof __hasDefault;\n\n/** Symbol used as the key for branded/opaque types. */\ndeclare const __brand: unique symbol;\n/** Symbol used as the key for branded/opaque types. */\nexport type BRAND = typeof __brand;\n\n/**\n * Intersects a base type with a phantom brand tag.\n * The brand exists only at the type level — zero runtime cost.\n *\n * @example\n * ```ts\n * type Email = Brand<string, 'Email'>;\n * type UserId = Brand<number, 'UserId'>;\n * ```\n */\nexport type Brand<T, TBrand extends string | symbol> = T & {\n readonly [K in BRAND]: TBrand;\n};\n\n/**\n * Infers the TypeScript type that a `SchemaBuilder` instance validates.\n * Takes into account type optimizations (via `optimize()`) and whether the schema is optional.\n *\n * @example\n * ```ts\n * const userSchema = object({ name: string(), age: number().optional() });\n * type User = InferType<typeof userSchema>;\n * // { name: string; age?: number }\n * ```\n */\nexport type InferType<T> = T extends {\n optimize: (...args: any[]) => {\n readonly [K in SchemaTypeBrand]: infer TOptimized;\n };\n}\n ? TOptimized\n : T extends { readonly [K in SchemaTypeBrand]: infer TType }\n ? TType\n : T;\n\n/**\n * Represents a single validation error with a human-readable error message.\n *\n * When returned from an object-level validator (via {@link SchemaBuilder.addValidator | addValidator}),\n * the optional `property` selector can route the error to a specific property\n * so that {@link ObjectSchemaValidationResult.getErrorsFor | getErrorsFor()} reports it\n * on that property rather than only on the root object.\n *\n * ```ts\n * .addValidator((v) => ({\n * valid: false,\n * errors: [{\n * message: 'Passwords do not match',\n * property: (t) => t.confirmPassword\n * }]\n * }))\n * ```\n */\nexport type ValidationError = {\n message: string;\n /**\n * Optional property selector that targets this error to a specific\n * property of the validated object. Uses the same selector signature\n * as `getErrorsFor()` and react-form's `forProperty`.\n */\n property?: (tree: any) => any;\n};\n\n/**\n * Used to represent a validation result for nested\n * objects/properties. Contains a list of errors and\n * the value that caused them.\n */\nexport type NestedValidationResult<\n TSchema,\n TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any>,\n TParentPropertyDescriptor\n> = {\n /**\n * Value that property had and which caused error or errors\n */\n seenValue?: InferType<TSchema>;\n /**\n * A list of errors, empty if object satisfies a schema\n */\n errors: ReadonlyArray<string>;\n\n /**\n * Whether validation passed for this property and all of its children.\n */\n isValid: boolean;\n\n get descriptor(): PropertyDescriptorInner<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >;\n};\n\n/**\n * Utility type that makes a value `T` optional (i.e. `T | undefined`).\n * Used internally by {@link InferType} to represent optional schema fields.\n */\nexport type MakeOptional<T> = { prop?: T }['prop'];\n\n/**\n * Type of the function that provides a validation error message for\n * the given `seenValue` and `schema`. Can be a string or a function\n * returning a string or a promise of a string.\n * Should be used to provide a custom validation error message.\n */\nexport type ValidationErrorMessageProvider<\n TSchema extends SchemaBuilder<any, any, any, any, any> = SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n >\n> =\n | string\n | ((\n seenValue: InferType<TSchema>,\n schema: TSchema\n ) => string | Promise<string>);\n\nexport type ValidationResult<T> = {\n /**\n * If `true` - object satisfies schema\n */\n valid: boolean;\n /**\n * Contains validated object. Can be different (if there are any preprocessors in the schema) from object\n * passed to the `validate` method of the `SchemaBuilder` class.\n */\n object?: T;\n errors?: ValidationError[];\n};\n\n/**\n * Error thrown by {@link SchemaBuilder.parse | parse()} and\n * {@link SchemaBuilder.parseAsync | parseAsync()} when validation fails.\n * Carries the full array of {@link ValidationError | validation errors}.\n */\nexport class SchemaValidationError extends Error {\n public readonly errors: ValidationError[];\n\n constructor(errors: ValidationError[]) {\n const message =\n errors.length > 0\n ? errors.map(e => e.message).join('; ')\n : 'Validation failed';\n super(message);\n this.name = 'SchemaValidationError';\n this.errors = errors;\n }\n}\n\n/**\n * Internal result returned by the `preValidate` step of `SchemaBuilder`.\n * Contains the validation context, any early errors, and the transaction\n * wrapping the (possibly preprocessed) value.\n */\nexport type PreValidationResult<T, TTransactionType> = Omit<\n ValidationResult<T>,\n 'object'\n> & {\n context: ValidationContext;\n transaction?: Transaction<TTransactionType>;\n rootPropertyDescriptor?: PropertyDescriptor<any, any, undefined>;\n};\n\ntype ValidatorResult<T> = Omit<ValidationResult<T>, 'object' | 'errors'> & {\n errors?: ValidationError[];\n};\n\n/**\n * A function that transforms the value before validation.\n * Preprocessors run in order before validators and can modify or replace the value.\n *\n * @param object - the current value to preprocess\n * @returns the transformed value, or a Promise resolving to it\n */\nexport type Preprocessor<T> = (object: T) => Promise<T> | T;\n\n/**\n * A custom validation function that checks a value and returns a result\n * indicating whether the value is valid, along with optional error messages.\n *\n * @param object - the value to validate\n * @returns a result with `valid` boolean and optional `errors` array, or a Promise resolving to it\n */\nexport type Validator<T> = (\n object: T\n) => Promise<ValidatorResult<T>> | ValidatorResult<T>;\n\n/**\n * Internal wrapper that pairs a preprocessor function with metadata\n * indicating whether it may mutate the value.\n */\nexport type PreprocessorEntry<T> = { fn: Preprocessor<T>; mutates: boolean };\n\n/**\n * Internal wrapper that pairs a validator function with metadata\n * indicating whether it may mutate the value.\n */\nexport type ValidatorEntry<T> = { fn: Validator<T>; mutates: boolean };\n\n/**\n * Configuration properties used to construct a `SchemaBuilder` instance.\n * Contains the schema type identifier, requirement flag, and lists of\n * preprocessors and validators.\n */\nexport type SchemaBuilderProps<T> = {\n type: string;\n isRequired?: boolean;\n isNullable?: boolean;\n isReadonly?: boolean;\n preprocessors: PreprocessorEntry<T>[];\n validators: ValidatorEntry<T>[];\n requiredValidationErrorMessageProvider?: ValidationErrorMessageProvider;\n extensions?: Record<string, unknown>;\n defaultValue?: T | (() => T);\n catchValue?: T | (() => T);\n hasCatch?: boolean;\n description?: string;\n schemaName?: string;\n example?: unknown;\n};\n\nexport type ValidationContext<\n TSchema extends SchemaBuilder<any, any, any, any> = SchemaBuilder<\n any,\n any,\n any,\n any\n >\n> = {\n /**\n * Optional. By default validation will stop after the first validation error, in case if\n * you want to receive all validation erors, please set this flag to `true`.\n * You might need it to display validation errors.\n */\n doNotStopOnFirstError?: boolean;\n\n /**\n * Optional. If you define a `rootPropertyDescriptor` while validating an object,\n * it will report all validation errors with the path starting from the root property.\n * Normally it's used internally by the library for validation of nested objects and\n * should not be used directly (but who knows, maybe you will find a use case for it).\n */\n rootPropertyDescriptor?: TSchema extends ObjectSchemaBuilder<\n any,\n any,\n any,\n any\n >\n ? PropertyDescriptor<TSchema, TSchema, undefined>\n : never;\n\n /**\n * Optional. This is a property descriptor for the current object being validated.\n * This descriptor is descendant of the `rootPropertyDescriptor` and is used to provide\n * a path to the current object being validated in the root object.\n * Normally it's used internally by the library for validation of nested objects and\n * should not be used directly (but who knows, maybe you will find a use case for it).\n */\n currentPropertyDescriptor?: TSchema extends ObjectSchemaBuilder<\n any,\n any,\n any\n >\n ? PropertyDescriptor<TSchema, TSchema, unknown>\n : never;\n\n /**\n * Optional. Used along with `rootPropertyDescriptor` and `currentPropertyDescriptor` to provide\n * a root validation object, this object will be used to retrieve the value of properties\n * using the `rootPropertyDescriptor` because the `rootPropertyDescriptor` is a property descriptor\n * for the root object, and it needs the root object along with the whole structure to get the\n * value of the property.\n *\n * Normally it's used internally by the library for validation of nested objects and\n * should not be used directly (but who knows, maybe you will find a use case for it).\n */\n rootValidationObject?: InferType<TSchema>;\n};\n\n/**\n * A symbol to mark property descriptors in the schema.\n * Normally, you should not use it directly unless you want\n * to develop some advanced features or extend the library.\n * In normal conditions it's used internally by the library.\n */\nexport const SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR = Symbol();\n\n/**\n * A symbol that marks a schema as having sub-properties that can\n * participate in property descriptor trees. When a schema exposes\n * `[SYMBOL_HAS_PROPERTIES] = true` **and** its `introspect()` returns\n * a `properties` record, it will be recursed into by\n * `ObjectSchemaBuilder.getPropertiesFor()` — the same way nested\n * `ObjectSchemaBuilder` instances are.\n *\n * Currently implemented by `ObjectSchemaBuilder` (always) and\n * `ExternSchemaBuilder` (when created with an explicit property map).\n */\nexport const SYMBOL_HAS_PROPERTIES = Symbol();\n\n/**\n * Describes a property in a schema. And gives you\n * a possibility to access property value and set it.\n * suppose you have a schema like this:\n * ```ts\n * const schema = object({\n * name: string(),\n * address: object({\n * city: string(),\n * country: string()\n * }),\n * id: number()\n * });\n * ```\n * then you can get a property descriptor for the `address.city` property\n * like this:\n * ```ts\n * const addressCityDescriptor = object.getPropertiesFor(schema).address.city;\n * ```\n *\n * And then you can use it to get and set the value of this property having the object:\n * ```ts\n * const obj = {\n * name: 'Leo',\n * address: {\n * city: 'Kozelsk',\n * country: 'Russia'\n * },\n * id: 123\n * };\n *\n * const success = addressCityDescriptor.setValue(obj, 'Venyov');\n * // this returns you a boolean value indicating if the value was set successfully\n * ```\n */\n\nexport type PropertySetterOptions = {\n /**\n * If set to `true`, the method will create missing structure\n * in the object to set the value. For example, if you have a schema\n * and property descriptor like this:\n * ```ts\n * const schema = object({\n * address: object({\n * city: string(),\n * country: string()\n * }),\n * });\n * const addressCityDescriptor = object.getPropertiesFor(schema).address.city;\n * ```\n * And then you try to set a new value to the `address.city` property on the object\n * which does not have `address` property:\n * ```ts\n * const obj = {\n * name: 'Leo'\n * };\n * const success = addressCityDescriptor.setValue(obj, 'Venyov', { createMissingStructure: true });\n * // success === true\n * // obj === {\n * // name: 'Leo',\n * // address: {\n * // city: 'Venyov'\n * // }\n * // }\n */\n createMissingStructure?: boolean;\n};\n\n/**\n * Extracts the inner property descriptor type from a `PropertyDescriptor`.\n * Returns `undefined` if `T` is not a valid `PropertyDescriptor`.\n */\nexport type PropertyDescriptorInnerFromPropertyDescriptor<T> =\n T extends PropertyDescriptor<\n infer TSchema,\n infer TPropertySchema,\n infer TParentPropertyDescriptor\n >\n ? PropertyDescriptorInner<\n TSchema,\n TPropertySchema,\n TParentPropertyDescriptor\n >\n : undefined;\n\nexport type PropertyDescriptorInner<\n TSchema extends ObjectSchemaBuilder<any, any, any, any, any>,\n TPropertySchema,\n TParentPropertyDescriptor\n> = {\n /**\n * Sets a new value to the property. If the process was successful,\n * the method returns `true`, otherwise `false`.\n * It can return `false` if the property could not be set to the object\n * which can happen if the `setValue` method is called with an object\n * which does not comply with the schema.\n * for example, if you have a schema and property descriptopr like this:\n * ```ts\n * const schema = object({\n * name: string(),\n * address: object({\n * city: string(),\n * country: string()\n * }),\n * id: number()\n * });\n *\n * const addressCityDescriptor = object.getPropertiesFor(schema).address.city;\n * ```\n * And then you try to set a new value to the `address.city` property on the object\n * which does not have `address` property:\n * ```ts\n * const obj = {\n * name: 'Leo'\n * };\n *\n * const success = addressCityDescriptor.setValue(obj, 'Venyov');\n * // success === false\n * ```\n *\n * @param obj Object to set the value to\n * @param value a new value to set to the property\n * @param options additional optional parameters to control the process\n * @returns\n */\n setValue: (\n obj: InferType<TSchema>,\n value: InferType<TPropertySchema>,\n options?: PropertySetterOptions\n ) => boolean;\n /**\n * Gets the value of the property from the object.\n * @param obj object to get the value from\n * @returns an object containing a `value` and `success` properties. `value` is the value of the property\n * if it was found in the object, `success` is a boolean value indicating if the property was found in the object.\n */\n getValue: (obj: InferType<TSchema>) => {\n value?: InferType<TPropertySchema>;\n success: boolean;\n };\n\n /**\n * Gets the schema for the property described by the property descriptor.\n * @returns a schema for the property\n */\n getSchema: () => TPropertySchema;\n\n parent: PropertyDescriptorInnerFromPropertyDescriptor<TParentPropertyDescriptor>;\n // extends PropertyDescriptor<\n // any,\n // any,\n // any\n // >\n // ? TParentPropertyDescriptor\n // : never;\n\n /**\n * The name of this property within its parent object, or `undefined`\n * for the root descriptor.\n */\n propertyName: string | undefined;\n\n /**\n * Returns a JSON Pointer (RFC 6901) string representing this\n * property's path from the root descriptor.\n *\n * Property names are escaped per RFC 6901 (`~` → `~0`, `/` → `~1`).\n * The root descriptor returns an empty string (`''`).\n */\n toJsonPointer: () => string;\n};\n\n/**\n * A wrapper object keyed by {@link SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR} that\n * holds a {@link PropertyDescriptorInner} for a particular property within\n * an object schema. Used to get/set property values on validated objects.\n */\nexport type PropertyDescriptor<\n TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any>,\n TPropertySchema,\n TParentPropertyDescriptor\n> = {\n [SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR]: PropertyDescriptorInner<\n TRootSchema,\n TPropertySchema,\n TParentPropertyDescriptor\n >;\n};\n\n/**\n * A tree of property descriptors for the schema.\n * Has a possibility to filter properties by the type (`TAssignableTo` type parameter).\n */\nexport type PropertyDescriptorTree<\n TSchema extends ObjectSchemaBuilder<any, any, any, any, any>,\n TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any> = TSchema,\n TAssignableTo = any,\n TParentPropertyDescriptor = undefined\n> = PropertyDescriptor<TRootSchema, TSchema, TParentPropertyDescriptor> &\n (TSchema extends ObjectSchemaBuilder<infer TProperties, any, any>\n ? {\n [K in keyof TProperties]: TProperties[K] extends ObjectSchemaBuilder<\n any,\n any,\n any\n >\n ? PropertyDescriptorTree<\n TProperties[K],\n TRootSchema,\n any,\n PropertyDescriptor<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >\n >\n : TProperties[K] extends ExternSchemaBuilder<\n any,\n any,\n any,\n any,\n any,\n any,\n infer TExternResult\n >\n ? PropertyDescriptor<\n TRootSchema,\n TProperties[K],\n PropertyDescriptor<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >\n > &\n ExternOutputPropertyDescriptors<\n TExternResult,\n TRootSchema,\n PropertyDescriptor<\n TRootSchema,\n TProperties[K],\n PropertyDescriptor<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >\n >\n >\n : TProperties[K] extends ArraySchemaBuilder<\n infer TArrayElement,\n any,\n any\n >\n ? TArrayElement extends ObjectSchemaBuilder<\n any,\n any,\n any,\n any,\n any\n >\n ? PropertyDescriptor<\n TRootSchema,\n TProperties[K],\n PropertyDescriptor<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >\n >\n : InferType<TProperties[K]> extends TAssignableTo\n ? PropertyDescriptor<\n TRootSchema,\n TProperties[K],\n PropertyDescriptor<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >\n >\n : never\n : InferType<TProperties[K]> extends TAssignableTo\n ? PropertyDescriptor<\n TRootSchema,\n TProperties[K],\n PropertyDescriptor<\n TRootSchema,\n TSchema,\n TParentPropertyDescriptor\n >\n >\n : never;\n }\n : never);\n\n/**\n * Recursively maps the keys of an extern schema's output type into\n * property descriptors. When a value is a plain-object type its keys\n * are expanded recursively; primitives, arrays, Dates, and functions\n * are treated as leaves.\n *\n * @internal\n */\ntype ExternOutputPropertyDescriptors<\n TOutput,\n TRootSchema extends ObjectSchemaBuilder<any, any, any, any, any>,\n TParentPropertyDescriptor\n> = TOutput extends\n | Date\n | Function\n | readonly any[]\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined\n ? {}\n : TOutput extends Record<string, any>\n ? {\n [K in keyof TOutput]: PropertyDescriptor<\n TRootSchema,\n SchemaBuilder<TOutput[K], true, false, false, {}>,\n TParentPropertyDescriptor\n > &\n ExternOutputPropertyDescriptors<\n TOutput[K],\n TRootSchema,\n PropertyDescriptor<\n TRootSchema,\n SchemaBuilder<TOutput[K], true, false, false, {}>,\n TParentPropertyDescriptor\n >\n >;\n }\n : {};\n\n/**\n * Creates an array augmented with non-enumerable NestedValidationResult\n * properties (`seenValue`, `errors`, `isValid`, `descriptor`).\n * Used by UnionSchemaBuilder and ArraySchemaBuilder to return hybrid\n * arrays from `getErrorsFor()`.\n */\nexport function createHybridErrorArray<T extends any[]>(\n items: T,\n seenValue: () => any,\n errors: () => ReadonlyArray<string>,\n descriptor: () => any\n): T {\n Object.defineProperties(items, {\n seenValue: {\n get: seenValue,\n enumerable: false\n },\n errors: {\n get: errors,\n enumerable: false\n },\n isValid: {\n get: () => errors().length === 0,\n enumerable: false\n },\n descriptor: {\n get: descriptor,\n enumerable: false\n }\n });\n return items;\n}\n\n/**\n * Resolves the full output type of a schema, accounting for `TRequired` and\n * `TNullable` modifiers. Mirrors the branded `[__type]` computation so that\n * the `~standard` Standard Schema property carries the correct inferred type.\n *\n * - When `TRequired = true` and `TNullable = false` the result is `TResult`.\n * - When `TRequired = true` and `TNullable = true` the result is `TResult | null`.\n * - When `TRequired = false` the result is wrapped by {@link MakeOptional},\n * adding `| undefined` (and `| null` when also nullable).\n *\n * @internal\n */\ntype ResolvedSchemaType<\n TResult,\n TRequired extends boolean,\n TNullable extends boolean\n> = TRequired extends true\n ? TNullable extends true\n ? TResult | null\n : TResult\n : MakeOptional<TNullable extends true ? TResult | null : TResult>;\n\n/**\n * Base class for all schema builders. Provides basic functionality for schema building.\n *\n * **Note:** this class is not intended to be used directly, use one of the subclasses instead.\n * @typeparam TResult Type of the object that will be returned by `validate()` method.\n * @typeparam TRequired If `true`, object will be required. If `false`, object will be optional.\n */\nexport abstract class SchemaBuilder<\n TResult = any,\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n THasDefault extends boolean = false,\n // biome-ignore lint/correctness/noUnusedVariables: used in extensions\n TExtensions = {}\n> {\n #isRequired = true;\n #isNullable = false;\n #isReadonly = false;\n #description: string | undefined;\n #schemaName: string | undefined;\n #preprocessors: PreprocessorEntry<TResult>[] = [];\n #validators: ValidatorEntry<TResult>[] = [];\n #hasMutating = false;\n #canSkipPreValidation = true;\n #extensions: Record<string, unknown> = {};\n #type = 'base';\n #defaultRequiredErrorMessageProvider: ValidationErrorMessageProvider =\n 'is required';\n #requiredErrorMessageProvider: ValidationErrorMessageProvider =\n 'is required';\n #defaultValue: TResult | (() => TResult) | undefined = undefined;\n #catchValue: TResult | (() => TResult) | undefined = undefined;\n #hasCatch = false;\n #example: unknown | undefined = undefined;\n /**\n * Cached result of the first `['~standard']` access. Stored so that\n * repeated property reads return the exact same object reference, which\n * is required by the Standard Schema spec.\n */\n #standardProps:\n | StandardSchemaV1.Props<\n ResolvedSchemaType<TResult, TRequired, TNullable>\n >\n | undefined;\n\n /**\n * Type-level brand encoding the inferred type of this schema.\n * Not emitted at runtime — used only by {@link InferType}.\n * @internal\n */\n declare readonly [__type]: TRequired extends true\n ? TNullable extends true\n ? TResult | null\n : TResult\n : MakeOptional<TNullable extends true ? TResult | null : TResult>;\n\n /**\n * Type-level brand encoding whether this schema has a default value.\n * Not emitted at runtime — used by input type inference.\n * @internal\n */\n declare readonly [__hasDefault]: THasDefault;\n\n /**\n * Standard Schema v1 interface.\n *\n * Exposes this schema as a [Standard Schema v1](https://standardschema.dev/)\n * validator, enabling out-of-the-box interoperability with any library that\n * consumes the spec — including tRPC, TanStack Form, React Hook Form, T3 Env,\n * Hono, Elysia, next-safe-action, and 50+ other tools.\n *\n * Every `SchemaBuilder` subclass (all 13 builders) inherits this property\n * automatically — no additional setup required.\n *\n * **Shape of the returned object:**\n * - `version` — always `1` (Standard Schema spec version)\n * - `vendor` — `'@cleverbrush/schema'`\n * - `validate(value)` — synchronous; wraps this builder's own `.validate()`\n * and converts its result to the Standard Schema `Result<Output>` format:\n * - Success: `{ value: <validated output> }`\n * - Failure: `{ issues: [{ message: string }, …] }`\n *\n * The returned object is **cached** after the first access so repeated reads\n * return the same reference (required by the spec).\n *\n * @example\n * ```ts\n * import { object, string, number } from '@cleverbrush/schema';\n *\n * const UserSchema = object({\n * name: string().minLength(2),\n * email: string().email(),\n * age: number().min(18).optional(),\n * });\n *\n * // Grab the Standard Schema interface\n * const std = UserSchema['~standard'];\n * // std.version === 1\n * // std.vendor === '@cleverbrush/schema'\n *\n * const ok = std.validate({ name: 'Alice', email: 'alice@example.com' });\n * // { value: { name: 'Alice', email: 'alice@example.com', age: undefined } }\n *\n * const fail = std.validate({ name: 'A', email: 'not-an-email' });\n * // { issues: [{ message: 'minLength' }, { message: 'email' }] }\n *\n * // Pass directly to TanStack Form, T3 Env, tRPC, etc.:\n * // validators: { onChange: UserSchema, onBlur: UserSchema }\n * ```\n *\n * @see https://standardschema.dev/\n */\n get ['~standard'](): StandardSchemaV1.Props<\n ResolvedSchemaType<TResult, TRequired, TNullable>\n > {\n if (this.#standardProps) return this.#standardProps;\n // Capture `this` for the closure so the validate callback can call\n // the schema's own validate method.\n const self = this;\n this.#standardProps = {\n version: 1 as const,\n vendor: '@cleverbrush/schema',\n validate(\n value: unknown\n ): StandardSchemaV1.Result<\n ResolvedSchemaType<TResult, TRequired, TNullable>\n > {\n // Standard Schema validate accepts `unknown`, while the\n // schema's own validate() has a typed parameter. The cast\n // is safe because validate() performs full runtime\n // validation regardless of the compile-time input type.\n const result = self.validate(value as any);\n if (result.valid) {\n return {\n value: result.object as ResolvedSchemaType<\n TResult,\n TRequired,\n TNullable\n >\n };\n }\n return {\n issues: (result.errors ?? []).map(e => ({\n message: e.message\n }))\n };\n }\n };\n return this.#standardProps;\n }\n\n /**\n * Set type of schema explicitly. `notUsed` param is needed only for case when JS is used. E.g. when you\n * can't call method like `schema.hasType<Date>()`, so instead you can call `schema.hasType(new Date())`\n * with the same result.\n */\n public abstract hasType<T>(notUsed?: T): any;\n\n /**\n * Clears type set by call to `.hasType<T>()`, default schema type inference will be used\n * for schema returned by this call.\n */\n public abstract clearHasType(): any;\n\n /**\n * Protected method used to create a new instance of the Builder\n * defined by the `props` object. Should be used to instantiate new\n * builders to keep builder's immutability.\n * @param props arbitrary props object\n */\n protected abstract createFromProps(props: any): this;\n\n /**\n * The string identifier of the schema type (e.g. `'string'`, `'number'`, `'object'`).\n */\n protected get type() {\n return this.#type;\n }\n\n /**\n * Sets the schema type identifier. Must be a non-empty string.\n */\n protected set type(value: string) {\n if (typeof value !== 'string' || !value)\n throw new Error('value should be non empty string');\n this.#type = value;\n }\n\n /**\n * A list of preprocessors associated with\n * the Builder\n */\n protected get preprocessors() {\n return this.#preprocessors;\n }\n\n /**\n * A list of validators associated with\n * the Builder\n */\n protected get validators() {\n return this.#validators;\n }\n\n /**\n * Whether the schema requires a non-null/non-undefined value.\n */\n protected get isRequired(): TRequired {\n return this.#isRequired as TRequired;\n }\n\n /**\n * Whether `null` is an accepted value for this schema.\n */\n protected get isNullable(): boolean {\n return this.#isNullable;\n }\n\n /**\n * Sets the requirement flag. Must be a boolean.\n */\n protected set isRequired(value: boolean) {\n if (typeof value !== 'boolean')\n throw new Error('should be a boolean value');\n this.#isRequired = value as any;\n }\n\n /**\n * The error message provider used for the \"is required\" error.\n * Exposed for fast-path validation in subclasses.\n */\n protected get requiredErrorMessage(): ValidationErrorMessageProvider {\n return this.#requiredErrorMessageProvider;\n }\n\n /**\n * Whether this schema has a default value configured via `.default()`.\n * Exposed for fast-path validation in subclasses.\n */\n protected get hasDefault(): boolean {\n return this.#defaultValue !== undefined;\n }\n\n /**\n * Whether this schema has a catch/fallback value configured via `.catch()`.\n */\n protected get hasCatch(): boolean {\n return this.#hasCatch;\n }\n\n /**\n * Resolves the catch/fallback value. If the stored value is a factory function,\n * it is called to produce the value (useful for mutable fallbacks like `() => []`).\n */\n protected resolveCatchValue(): TResult {\n return typeof this.#catchValue === 'function'\n ? (this.#catchValue as () => TResult)()\n : (this.#catchValue as TResult);\n }\n\n /**\n * Whether this schema is marked as readonly.\n * Type-level only — no runtime enforcement.\n */\n protected get isReadonly(): boolean {\n return this.#isReadonly;\n }\n\n /**\n * Resolves the default value. If the stored default is a function,\n * it is called to produce the value (useful for mutable defaults).\n */\n protected resolveDefaultValue(): TResult {\n return typeof this.#defaultValue === 'function'\n ? (this.#defaultValue as () => TResult)()\n : (this.#defaultValue as TResult);\n }\n\n /**\n * Whether `preValidateSync` can be skipped entirely.\n * True when there are no preprocessors and no validators,\n * so the only work would be the required check and wrapping\n * in a noop transaction — which subclasses can do inline.\n */\n protected get canSkipPreValidation(): boolean {\n return this.#canSkipPreValidation;\n }\n\n /**\n * Whether `null` should count as a required-constraint violation.\n *\n * By default `null` is treated the same as `undefined` for the purposes\n * of the required check — i.e. a required schema rejects both.\n * Subclasses that may legally receive `null` as a value (e.g.\n * `UnionSchemaBuilder` when a `NullSchemaBuilder` option is present)\n * can override this to `false` so that `null` bypasses the required\n * check and is passed directly to their option-validation logic.\n *\n * @protected\n */\n protected get isNullRequiredViolation(): boolean {\n return true;\n }\n\n /**\n * Shared setup for both {@link preValidateSync} and {@link preValidateAsync}.\n * Builds the validation context, creates the initial transaction, and\n * returns mutable state for the caller to drive.\n */\n #initPreValidation(object: any, context?: ValidationContext) {\n const doNotStopOnFirstError = context?.doNotStopOnFirstError ?? false;\n\n const resultingContext: ValidationContext = {\n doNotStopOnFirstError,\n rootPropertyDescriptor: context?.rootPropertyDescriptor,\n currentPropertyDescriptor: context?.currentPropertyDescriptor\n };\n\n const needsTransaction = this.#hasMutating;\n\n return {\n doNotStopOnFirstError,\n resultingContext,\n transaction: needsTransaction\n ? transaction({ validatedObject: object })\n : noopTransaction({ validatedObject: object }),\n errors: [] as ValidationError[]\n };\n }\n\n /**\n * Builds the failed early-return result used when\n * `doNotStopOnFirstError` is false.\n */\n #earlyFailResult(\n errors: ValidationError[],\n resultingContext: ValidationContext\n ): PreValidationResult<any, { validatedObject: any }> {\n return {\n valid: false,\n errors: [errors[0]].filter(e => e),\n context: resultingContext\n };\n }\n\n /**\n * Builds the error entries for a validator that reported `valid: false`.\n */\n #validatorFailureErrors(\n index: number,\n name: string | undefined,\n validatorErrors: ValidationError[] | undefined\n ): ValidationError[] {\n if (Array.isArray(validatorErrors) && validatorErrors.length) {\n return validatorErrors;\n }\n return [\n {\n message: `Validator #${index}${\n name ? ` (${name})` : ''\n } didn't pass.`\n }\n ];\n }\n\n /**\n * Assembles the final {@link PreValidationResult} after all preprocessors,\n * validators, and the required check have run.\n */\n #buildPreValidationResult(\n errors: ValidationError[],\n doNotStopOnFirstError: boolean,\n resultingContext: ValidationContext,\n trans: Transaction<{ validatedObject: any }>\n ): PreValidationResult<any, { validatedObject: any }> {\n if (errors.length > 0) {\n return {\n valid: false,\n errors: errors\n .filter(e => e)\n .filter((_e, i) =>\n doNotStopOnFirstError ? true : i === 0\n ),\n context: resultingContext,\n transaction: trans\n };\n }\n\n return {\n valid: true,\n context: resultingContext,\n transaction: trans\n };\n }\n\n /**\n * Synchronous version of {@link preValidateAsync}.\n * Throws at runtime if any preprocessor or validator returns a Promise.\n *\n * @param object - the value to pre-validate\n * @param context - optional validation context settings\n * @returns a `PreValidationResult` containing the preprocessed transaction, context, and any errors\n * @throws Error if a preprocessor or validator returns a Promise (use {@link preValidateAsync} instead)\n */\n protected preValidateSync(\n object: any,\n context?: ValidationContext\n ): PreValidationResult<any, { validatedObject: any }> {\n const state = this.#initPreValidation(object, context);\n const { doNotStopOnFirstError, resultingContext, errors } = state;\n let preprocessingTransaction = state.transaction;\n let preprocessedObject =\n preprocessingTransaction.object.validatedObject;\n\n if (this.#preprocessors.length > 0) {\n let currentPrepropIndex = 0;\n for (const entry of this.#preprocessors) {\n try {\n const result = entry.fn(preprocessedObject);\n if (result instanceof Promise) {\n throw new Error(\n `Preprocessor #${currentPrepropIndex}${entry.fn.name ? ` (${entry.fn.name})` : ''} returned a Promise. Use validateAsync() for schemas with async preprocessors.`\n );\n }\n preprocessedObject = result;\n } catch (err) {\n if (\n (err as Error).message?.includes('Use validateAsync()')\n ) {\n throw err;\n }\n errors.push({\n message: `Preprocessor #${currentPrepropIndex}${\n entry.fn.name ? ` (${entry.fn.name})` : ''\n } thrown an error: ${(err as Error).message}`\n });\n if (!doNotStopOnFirstError) {\n return this.#earlyFailResult(errors, resultingContext);\n }\n } finally {\n currentPrepropIndex++;\n }\n }\n preprocessingTransaction = this.#hasMutating\n ? transaction({ validatedObject: preprocessedObject })\n : noopTransaction({ validatedObject: preprocessedObject });\n }\n\n if (typeof preprocessedObject === 'undefined' && this.hasDefault) {\n preprocessedObject = this.resolveDefaultValue();\n preprocessingTransaction = this.#hasMutating\n ? transaction({ validatedObject: preprocessedObject })\n : noopTransaction({ validatedObject: preprocessedObject });\n }\n\n if (\n this.#validators.length > 0 &&\n !(preprocessedObject == null && !this.isRequired) &&\n !(preprocessedObject === null && this.#isNullable)\n ) {\n let currentValidatorIndex = 0;\n for (const entry of this.#validators) {\n try {\n const validatorResult = entry.fn(preprocessedObject);\n if (validatorResult instanceof Promise) {\n throw new Error(\n `Validator #${currentValidatorIndex}${entry.fn.name ? ` (${entry.fn.name})` : ''} returned a Promise. Use validateAsync() for schemas with async validators.`\n );\n }\n const { valid, errors: validatorErrors } = validatorResult;\n if (!valid) {\n errors.push(\n ...this.#validatorFailureErrors(\n currentValidatorIndex,\n entry.fn.name,\n validatorErrors\n )\n );\n if (!doNotStopOnFirstError) {\n return this.#earlyFailResult(\n errors,\n resultingContext\n );\n }\n }\n } catch (err) {\n if (\n (err as Error).message?.includes('Use validateAsync()')\n ) {\n throw err;\n }\n errors.push({\n message: `Validator #${currentValidatorIndex}${\n entry.fn.name ? ` (${entry.fn.name})` : ''\n } thrown an error: ${(err as Error).message}`\n });\n if (!doNotStopOnFirstError) {\n return this.#earlyFailResult(errors, resultingContext);\n }\n } finally {\n currentValidatorIndex++;\n }\n }\n }\n\n if (\n this.isRequired &&\n (typeof preprocessedObject === 'undefined' ||\n (preprocessedObject === null &&\n this.isNullRequiredViolation &&\n !this.#isNullable))\n ) {\n errors.push({\n message: this.getValidationErrorMessageSync(\n this.#requiredErrorMessageProvider,\n preprocessedObject\n )\n });\n if (!doNotStopOnFirstError) {\n preprocessingTransaction.rollback();\n return this.#earlyFailResult(errors, resultingContext);\n }\n }\n\n return this.#buildPreValidationResult(\n errors,\n doNotStopOnFirstError,\n resultingContext,\n preprocessingTransaction\n );\n }\n\n /**\n * Async version of pre-validation. Runs preprocessors, validators, and the\n * required/optional check on `object`. Supports async preprocessors,\n * validators, and error message providers.\n *\n * @param object - the value to pre-validate\n * @param context - optional validation context settings\n * @returns a `PreValidationResult` containing the preprocessed transaction, context, and any errors\n */\n protected async preValidateAsync(\n object: any,\n context?: ValidationContext\n ): Promise<PreValidationResult<any, { validatedObject: any }>> {\n const state = this.#initPreValidation(object, context);\n const { doNotStopOnFirstError, resultingContext, errors } = state;\n let preprocessingTransaction = state.transaction;\n let preprocessedObject =\n preprocessingTransaction.object.validatedObject;\n\n if (this.#preprocessors.length > 0) {\n let currentPrepropIndex = 0;\n for (const entry of this.#preprocessors) {\n try {\n preprocessedObject = await Promise.resolve(\n entry.fn(preprocessedObject)\n );\n } catch (err) {\n errors.push({\n message: `Preprocessor #${currentPrepropIndex}${\n entry.fn.name ? ` (${entry.fn.name})` : ''\n } thrown an error: ${(err as Error).message}`\n });\n if (!doNotStopOnFirstError) {\n return this.#earlyFailResult(errors, resultingContext);\n }\n } finally {\n currentPrepropIndex++;\n }\n }\n preprocessingTransaction = this.#hasMutating\n ? transaction({ validatedObject: preprocessedObject })\n : noopTransaction({ validatedObject: preprocessedObject });\n }\n\n if (typeof preprocessedObject === 'undefined' && this.hasDefault) {\n preprocessedObject = this.resolveDefaultValue();\n preprocessingTransaction = this.#hasMutating\n ? transaction({ validatedObject: preprocessedObject })\n : noopTransaction({ validatedObject: preprocessedObject });\n }\n\n if (\n this.#validators.length > 0 &&\n !(preprocessedObject == null && !this.isRequired) &&\n !(preprocessedObject === null && this.#isNullable)\n ) {\n let currentValidatorIndex = 0;\n for (const entry of this.#validators) {\n try {\n const { valid, errors: validatorErrors } =\n await Promise.resolve(entry.fn(preprocessedObject));\n if (!valid) {\n errors.push(\n ...this.#validatorFailureErrors(\n currentValidatorIndex,\n entry.fn.name,\n validatorErrors\n )\n );\n if (!doNotStopOnFirstError) {\n return this.#earlyFailResult(\n errors,\n resultingContext\n );\n }\n }\n } catch (err) {\n errors.push({\n message: `Validator #${currentValidatorIndex}${\n entry.fn.name ? ` (${entry.fn.name})` : ''\n } thrown an error: ${(err as Error).message}`\n });\n if (!doNotStopOnFirstError) {\n return this.#earlyFailResult(errors, resultingContext);\n }\n } finally {\n currentValidatorIndex++;\n }\n }\n }\n\n if (\n this.isRequired &&\n (typeof preprocessedObject === 'undefined' ||\n (preprocessedObject === null &&\n this.isNullRequiredViolation &&\n !this.#isNullable))\n ) {\n errors.push({\n message: await this.getValidationErrorMessage(\n this.#requiredErrorMessageProvider,\n preprocessedObject\n )\n });\n if (!doNotStopOnFirstError) {\n preprocessingTransaction.rollback();\n return this.#earlyFailResult(errors, resultingContext);\n }\n }\n\n return this.#buildPreValidationResult(\n errors,\n doNotStopOnFirstError,\n resultingContext,\n preprocessingTransaction\n );\n }\n\n /**\n * @deprecated Use {@link preValidateAsync} instead. This alias will be removed in a future version.\n */\n protected preValidate(\n object: any,\n context?: ValidationContext\n ): Promise<PreValidationResult<any, { validatedObject: any }>> {\n return this.preValidateAsync(object, context);\n }\n\n /**\n * Generates a serializable object describing the defined schema\n */\n public introspect() {\n return {\n /**\n * String `id` of schema type, e.g. `string', `number` or `object`.\n */\n type: this.type,\n /**\n * If set to `false`, schema will be optional (`null` or `undefined` values\n * will be considered as valid).\n */\n isRequired: this.#isRequired,\n /**\n * If set to `true`, schema values of `null` are considered valid.\n */\n isNullable: this.#isNullable,\n /**\n * If set to `true`, the inferred type is marked as readonly.\n * Type-level only — no runtime enforcement.\n */\n isReadonly: this.#isReadonly,\n /**\n * Array of preprocessor functions\n */\n preprocessors: [\n ...this.preprocessors\n ] as readonly PreprocessorEntry<TResult>[],\n /**\n * Array of validator functions\n */\n validators: [\n ...this.validators\n ] as readonly ValidatorEntry<TResult>[],\n /**\n * Custom error message provider for the 'is required' validation error.\n */\n requiredValidationErrorMessageProvider:\n this.#requiredErrorMessageProvider,\n /**\n * Extension metadata. Stores custom state set by schema extensions.\n */\n extensions: { ...this.#extensions },\n /**\n * Whether a default value (or factory) has been set on this schema.\n */\n hasDefault: this.#defaultValue !== undefined,\n /**\n * The default value or factory function.\n */\n defaultValue: this.#defaultValue,\n /**\n * The human-readable description attached to this schema via `.describe()`,\n * or `undefined` if none was set.\n */\n description: this.#description,\n /**\n * The logical name attached to this schema via `.schemaName()`,\n * or `undefined` if none was set.\n */\n schemaName: this.#schemaName,\n /**\n * Whether a catch/fallback value has been set on this schema via `.catch()`.\n */\n\n hasCatch: this.#hasCatch,\n /**\n * The catch/fallback value or factory function set via `.catch()`.\n */\n catchValue: this.#catchValue,\n /**\n * An example value attached to this schema via `.example()`,\n * or `undefined` if none was set.\n */\n example: this.#example\n };\n }\n\n /**\n * Makes schema optional (consider `null` and `undefined` as valid objects for this schema)\n */\n public optional() {\n return this.createFromProps({\n ...this.introspect(),\n isRequired: false\n }) as any;\n }\n\n /**\n * Makes schema nullable — `null` is accepted as a valid value.\n *\n * Unlike `.optional()` which accepts `undefined`, `.nullable()` accepts\n * `null`. The inferred type changes from `T` to `T | null`. Combine with\n * `.optional()` to accept both `null` and `undefined`.\n */\n public nullable() {\n return this.createFromProps({\n ...this.introspect(),\n isNullable: true\n }) as any;\n }\n\n /**\n * Removes the nullable mark — `null` is no longer accepted as a valid\n * value. This is the counterpart of `.nullable()`.\n */\n public notNullable() {\n return this.createFromProps({\n ...this.introspect(),\n isNullable: false\n }) as any;\n }\n\n /**\n * Sets a default value for this schema. When the input is `undefined`,\n * the default value is used instead. The default is still validated\n * against the schema's constraints.\n *\n * Accepts either a static value or a factory function (useful for\n * mutable defaults like `() => new Date()` or `() => []`).\n *\n * @example\n * ```ts\n * const schema = string().default('hello');\n * schema.validate(undefined); // { valid: true, object: 'hello' }\n * schema.validate('world'); // { valid: true, object: 'world' }\n * ```\n *\n * @example\n * ```ts\n * // Factory function for mutable defaults\n * const schema = array(string()).default(() => []);\n * ```\n */\n public default(value: TResult | (() => TResult)) {\n return this.createFromProps({\n ...this.introspect(),\n defaultValue: value\n }) as any;\n }\n\n /**\n * Sets a fallback value for this schema. When validation **fails** for any reason,\n * the fallback value is returned as a successful result instead of validation errors.\n *\n * This is useful for graceful degradation — for example, providing a safe default\n * when parsing untrusted input that might not conform to the schema.\n *\n * Accepts either a static value or a factory function. Factory functions are called\n * each time the fallback is needed (useful for mutable values like `() => []`).\n *\n * Unlike {@link default}, which only fires when the input is `undefined`, `.catch()`\n * fires on **any** validation failure — type mismatch, constraint violation, etc.\n *\n * When `.catch()` is set, {@link parse} and {@link parseAsync} will **never throw**.\n *\n * @param value - the fallback value, or a factory function producing the fallback\n *\n * @example\n * ```ts\n * const schema = string().catch('unknown');\n * schema.validate(42); // { valid: true, object: 'unknown' }\n * schema.validate('hello'); // { valid: true, object: 'hello' }\n * schema.parse(42); // 'unknown' (no throw)\n * ```\n *\n * @example\n * ```ts\n * // Factory function for mutable fallbacks\n * const schema = array(string()).catch(() => []);\n * schema.validate(null); // { valid: true, object: [] }\n * ```\n *\n * @example\n * ```ts\n * // Contrast with .default() — default fires only on undefined\n * const d = string().default('anon');\n * d.validate(undefined); // { valid: true, object: 'anon' } ← fires\n * d.validate(42); // { valid: false, errors: [...] } ← does NOT fire\n *\n * const c = string().catch('anon');\n * c.validate(undefined); // { valid: true, object: 'anon' } ← fires\n * c.validate(42); // { valid: true, object: 'anon' } ← also fires\n * ```\n */\n public catch(value: TResult | (() => TResult)): this {\n return this.createFromProps({\n ...this.introspect(),\n catchValue: value,\n hasCatch: true\n }) as unknown as this;\n }\n\n /**\n * Removes the default value set by a previous call to `.default()`.\n */\n public clearDefault() {\n return this.createFromProps({\n ...this.introspect(),\n defaultValue: undefined\n }) as any;\n }\n\n /**\n * Attaches a human-readable description to this schema as runtime metadata.\n *\n * The description has no effect on validation — it is purely informational.\n * It is accessible via `.introspect().description` and is emitted as the\n * `description` field by `toJsonSchema()` from `@cleverbrush/schema-json`.\n *\n * Useful for documentation generation, form labels, and AI tool descriptions.\n *\n * @example\n * ```ts\n * const schema = object({\n * name: string().describe('The user\\'s full name'),\n * age: number().optional().describe('Age in years'),\n * }).describe('A user object');\n *\n * schema.introspect().description; // 'A user object'\n * ```\n */\n public describe(text: string): this {\n return this.createFromProps({\n ...this.introspect(),\n description: text\n }) as unknown as this;\n }\n\n /**\n * Attaches an example value to this schema instance.\n *\n * The example is purely metadata — it has no effect on validation.\n * It is accessible via `.introspect().example` and is emitted as the\n * `example` keyword in JSON Schema output and OpenAPI spec generation.\n *\n * @example\n * ```ts\n * import { string } from '@cleverbrush/schema';\n *\n * const Email = string().example('user@example.com');\n *\n * Email.introspect().example; // 'user@example.com'\n * ```\n */\n public example(value: TResult): this {\n return this.createFromProps({\n ...this.introspect(),\n example: value\n }) as unknown as this;\n }\n\n /**\n * Attaches a logical name to this schema instance.\n *\n * The name is purely metadata — it has no effect on validation. It is\n * accessible via `.introspect().schemaName` and can be consumed by any\n * tool that introspects schemas at runtime, such as OpenAPI spec\n * generators, documentation tools, form libraries, or code generators.\n *\n * **Uniqueness** is the responsibility of the consuming tool. Passing the\n * same constant (same object reference) to multiple consumers is always\n * safe; how conflicts between different instances with the same name are\n * handled depends on the tool.\n *\n * @example\n * ```ts\n * import { object, string, number } from '@cleverbrush/schema';\n *\n * export const UserSchema = object({\n * id: number(),\n * name: string(),\n * }).schemaName('User');\n *\n * UserSchema.introspect().schemaName; // 'User'\n * ```\n */\n public schemaName(name: string): this {\n return this.createFromProps({\n ...this.introspect(),\n schemaName: name\n }) as unknown as this;\n }\n\n /**\n * Brands the schema with a phantom type tag, preventing structural mixing\n * of semantically different values at the type level. Zero runtime cost.\n *\n * The optional `_name` parameter is only needed when using plain JavaScript\n * (where generic type parameters are unavailable). In TypeScript, prefer\n * the generic form: `schema.brand<'Email'>()`.\n *\n * @example\n * ```ts\n * const Email = string().brand<'Email'>();\n * const Username = string().brand<'Username'>();\n * type Email = InferType<typeof Email>; // string & { readonly [BRAND]: 'Email' }\n * type Username = InferType<typeof Username>; // string & { readonly [BRAND]: 'Username' }\n * ```\n */\n public brand<TBrand extends string | symbol>(_name?: TBrand) {\n return this.createFromProps({\n ...this.introspect()\n }) as any;\n }\n\n /**\n * Marks the inferred type as readonly. For objects, produces `Readonly<T>`.\n * For arrays, produces `ReadonlyArray<T>`. Primitives are unchanged.\n * Type-level only — no runtime enforcement.\n *\n * @example\n * ```ts\n * const schema = object({ name: string(), age: number() }).readonly();\n * type T = InferType<typeof schema>; // Readonly<{ name: string; age: number }>\n * ```\n *\n * @example\n * ```ts\n * const schema = array(string()).readonly();\n * type T = InferType<typeof schema>; // ReadonlyArray<string>\n * ```\n */\n public readonly() {\n return this.createFromProps({\n ...this.introspect(),\n isReadonly: true\n }) as any;\n }\n\n /**\n * Makes schema required (consider `null` and `undefined` as invalid objects for this schema)\n * @param errorMessage - optional custom error message or provider for the 'is required' validation error\n */\n public required(errorMessage?: ValidationErrorMessageProvider) {\n return this.createFromProps({\n ...this.introspect(),\n isRequired: true,\n ...(errorMessage !== undefined\n ? {\n requiredValidationErrorMessageProvider:\n this.assureValidationErrorMessageProvider(\n errorMessage,\n this.#defaultRequiredErrorMessageProvider\n )\n }\n : {})\n }) as any;\n }\n\n /**\n * Adds a `preprocessor` to a preprocessors list\n */\n public addPreprocessor(\n preprocessor: Preprocessor<TResult>,\n options?: { mutates?: boolean }\n ): this {\n if (typeof preprocessor !== 'function') {\n throw new Error('preprocessor must be a function');\n }\n return this.createFromProps({\n ...this.introspect(),\n preprocessors: [\n ...this.preprocessors,\n { fn: preprocessor, mutates: options?.mutates ?? true }\n ]\n });\n }\n\n /**\n * Remove all preprocessors for this schema.\n */\n public clearPreprocessors(): this {\n return this.createFromProps({\n ...this.introspect(),\n preprocessors: []\n });\n }\n\n /**\n * Adds a `validator` to validators list.\n */\n public addValidator(\n validator: Validator<TResult>,\n options?: { mutates?: boolean }\n ): this {\n if (typeof validator !== 'function') {\n throw new Error('validator must be a function');\n }\n return this.createFromProps({\n ...this.introspect(),\n validators: [\n ...this.validators,\n { fn: validator, mutates: options?.mutates ?? false }\n ]\n });\n }\n\n /**\n * Remove all validators for this schema.\n */\n public clearValidators(): this {\n return this.createFromProps({\n ...this.introspect(),\n validators: []\n });\n }\n\n /**\n * Perform synchronous schema validation on `object`.\n * Throws at runtime if any preprocessor, validator, or error message\n * provider returns a Promise — use {@link validateAsync} instead.\n * @internal Override this in subclasses. External callers use {@link validate}.\n */\n protected abstract _validate(\n object: any,\n context?: ValidationContext\n ): ValidationResult<any>;\n\n /**\n * Perform asynchronous schema validation on `object`.\n * Supports async preprocessors, validators, and error message providers.\n * @internal Override this in subclasses. External callers use {@link validateAsync}.\n */\n protected abstract _validateAsync(\n object: any,\n context?: ValidationContext\n ): Promise<ValidationResult<any>>;\n\n /**\n * Perform synchronous schema validation on `object`.\n * Throws at runtime if any preprocessor, validator, or error message\n * provider returns a Promise — use {@link validateAsync} instead.\n *\n * If a fallback has been set via {@link catch}, a failed validation result\n * is replaced by a successful result built from the fallback value, preserving\n * the specialized result shape (e.g. `getErrorsFor` / `getNestedErrors` methods).\n */\n public validate(\n /**\n * Object to validate\n */\n object: any,\n /**\n * Optional `ValidationContext` settings\n */\n context?: ValidationContext\n ): ValidationResult<any> {\n const result = this._validate(object, context);\n if (!result.valid && this.#hasCatch) {\n const catchValue = this.resolveCatchValue();\n // Re-validate the fallback value so the returned result has the same\n // specialized shape as a normal successful result (e.g. getErrorsFor /\n // getNestedErrors helper methods are present and reflect success semantics).\n const catchResult = this._validate(catchValue, context);\n if (catchResult.valid) {\n return catchResult;\n }\n // Fallback value did not pass validation (user error) – return a plain\n // valid result as best-effort so that .catch() still suppresses the error.\n // Note: in this case specialized result methods such as getErrorsFor() /\n // getNestedErrors() will NOT be present on the returned object. This is an\n // edge case caused by the caller supplying a catch value that itself fails\n // schema validation; the type system should prevent this under normal use.\n return { valid: true, object: catchValue };\n }\n return result;\n }\n\n /**\n * Perform asynchronous schema validation on `object`.\n * Supports async preprocessors, validators, and error message providers.\n *\n * If a fallback has been set via {@link catch}, a failed validation result\n * is replaced by a successful result built from the fallback value, preserving\n * the specialized result shape (e.g. `getErrorsFor` / `getNestedErrors` methods).\n */\n public async validateAsync(\n /**\n * Object to validate\n */\n object: any,\n /**\n * Optional `ValidationContext` settings\n */\n context?: ValidationContext\n ): Promise<ValidationResult<any>> {\n const result = await this._validateAsync(object, context);\n if (!result.valid && this.#hasCatch) {\n const catchValue = this.resolveCatchValue();\n // Re-validate the fallback value so the returned result has the same\n // specialized shape as a normal successful result (e.g. getErrorsFor /\n // getNestedErrors helper methods are present and reflect success semantics).\n const catchResult = await this._validateAsync(catchValue, context);\n if (catchResult.valid) {\n return catchResult;\n }\n // Fallback value did not pass validation (user error) – return a plain\n // valid result as best-effort so that .catch() still suppresses the error.\n // Note: in this case specialized result methods such as getErrorsFor() /\n // getNestedErrors() will NOT be present on the returned object. This is an\n // edge case caused by the caller supplying a catch value that itself fails\n // schema validation; the type system should prevent this under normal use.\n return { valid: true, object: catchValue };\n }\n return result;\n }\n\n /**\n * Synchronously resolves a `ValidationErrorMessageProvider` to a string.\n * Throws if the provider function returns a Promise.\n *\n * @param provider - the error message provider (string or sync function)\n * @param seenValue - the value that caused the validation error\n * @returns the resolved error message string\n * @throws Error if the provider returns a Promise (use {@link getValidationErrorMessage} with {@link validateAsync})\n */\n protected getValidationErrorMessageSync(\n provider: ValidationErrorMessageProvider<any>,\n seenValue: TResult\n ): string {\n if (typeof provider === 'string') {\n return provider;\n }\n\n if (typeof provider === 'function') {\n const result = provider(seenValue, this);\n if (result instanceof Promise) {\n throw new Error(\n 'Async error message providers require validateAsync(). Use a string or sync function instead.'\n );\n }\n return result;\n }\n\n throw new Error(\n 'Invalid error message provider must be a string or a function returning a string'\n );\n }\n\n /**\n * Resolves a `ValidationErrorMessageProvider` to a string error message.\n * Handles both string providers and function providers (sync or async).\n *\n * @param provider - the error message provider (string or function)\n * @param seenValue - the value that caused the validation error\n * @returns the resolved error message string\n */\n protected async getValidationErrorMessage(\n provider: ValidationErrorMessageProvider<any>,\n seenValue: TResult\n ): Promise<string> {\n if (typeof provider === 'string') {\n return provider;\n }\n\n if (typeof provider === 'function') {\n return provider(seenValue, this);\n }\n\n throw new Error(\n 'Invalid error message provider must be a string or a function returning a string or a promise of a string'\n );\n }\n\n /**\n * Ensures a `ValidationErrorMessageProvider` is valid.\n * If `provider` is `undefined`, falls back to `defaultValue`.\n * Function providers are bound to `this` for access to schema state.\n *\n * @param provider - the provider to validate, or `undefined`\n * @param defaultValue - fallback provider when `provider` is not supplied\n * @returns a valid `ValidationErrorMessageProvider`\n */\n protected assureValidationErrorMessageProvider(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultValue: ValidationErrorMessageProvider<any>\n ): ValidationErrorMessageProvider<any> {\n if (typeof provider === 'string') {\n return provider;\n }\n if (typeof provider === 'function') {\n return provider.bind(this);\n }\n\n if (typeof defaultValue === 'function') {\n return defaultValue.bind(this);\n }\n\n return defaultValue;\n }\n\n /**\n * Sets extension metadata by key. Returns a new schema instance with the\n * extension data stored. The data survives fluent chaining.\n * @internal Used by extension authors inside `defineExtension()` callbacks.\n */\n public withExtension(key: string, value: unknown): this {\n return this.createFromProps({\n ...this.introspect(),\n extensions: {\n ...this.#extensions,\n [key]: value\n }\n });\n }\n\n /**\n * Retrieves extension metadata by key.\n * @internal Used by extension authors inside `defineExtension()` callbacks.\n */\n public getExtension(key: string): unknown {\n return this.#extensions[key];\n }\n\n /**\n * Synchronously validates the value and returns it if valid.\n * Throws a {@link SchemaValidationError} if validation fails.\n *\n * @param object - the value to parse\n * @param context - optional validation context\n * @returns the validated value\n * @throws SchemaValidationError if validation fails\n * @throws Error if the schema contains async preprocessors, validators, or error message providers\n */\n public parse(object: any, context?: ValidationContext): TResult {\n const result = this.validate(object, context);\n if (!result.valid) {\n throw new SchemaValidationError(result.errors || []);\n }\n return result.object as TResult;\n }\n\n /**\n * Asynchronously validates the value and returns it if valid.\n * Throws a {@link SchemaValidationError} if validation fails.\n *\n * @param object - the value to parse\n * @param context - optional validation context\n * @returns the validated value\n * @throws SchemaValidationError if validation fails\n */\n public async parseAsync(\n object: any,\n context?: ValidationContext\n ): Promise<TResult> {\n const result = await this.validateAsync(object, context);\n if (!result.valid) {\n throw new SchemaValidationError(result.errors || []);\n }\n return result.object as TResult;\n }\n\n /**\n * Alias for {@link validate}. Synchronously validates and returns a result object.\n * Provided for familiarity with the zod API.\n */\n public safeParse(\n object: any,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return this.validate(object, context) as ValidationResult<TResult>;\n }\n\n /**\n * Alias for {@link validateAsync}. Asynchronously validates and returns a result object.\n * Provided for familiarity with the zod API.\n */\n public safeParseAsync(\n object: any,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n return this.validateAsync(object, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n protected constructor(props: SchemaBuilderProps<TResult>) {\n if (!(typeof props === 'object' && props))\n throw new Error('SchemaBuilder props must be an object');\n const { type, preprocessors, validators, isRequired } = props;\n this.type = type;\n if (typeof isRequired === 'boolean') this.isRequired = isRequired;\n if (typeof props.isNullable === 'boolean')\n this.#isNullable = props.isNullable;\n if (typeof props.isReadonly === 'boolean')\n this.#isReadonly = props.isReadonly;\n if (Array.isArray(preprocessors)) {\n this.#preprocessors = [...preprocessors];\n }\n\n if (Array.isArray(validators)) {\n this.#validators = [...validators];\n }\n\n this.#hasMutating =\n this.#preprocessors.some(p => p.mutates) ||\n this.#validators.some(v => v.mutates);\n\n this.#canSkipPreValidation =\n this.#preprocessors.length === 0 && this.#validators.length === 0;\n\n if (typeof props.extensions === 'object' && props.extensions) {\n this.#extensions = { ...props.extensions };\n }\n\n if (props.defaultValue !== undefined) {\n this.#defaultValue = props.defaultValue;\n }\n\n if (props.hasCatch) {\n this.#hasCatch = true;\n this.#catchValue = props.catchValue;\n }\n\n if (typeof props.description === 'string') {\n this.#description = props.description;\n }\n\n if (typeof props.schemaName === 'string') {\n this.#schemaName = props.schemaName;\n }\n\n if (props.example !== undefined) {\n this.#example = props.example;\n }\n\n this.#requiredErrorMessageProvider =\n this.assureValidationErrorMessageProvider(\n props.requiredValidationErrorMessageProvider,\n this.#defaultRequiredErrorMessageProvider\n );\n }\n}\n"],"mappings":"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","names":["TRANSACTION_SYMBOL","defaultNonTransactionalTypes","defaultTransactionOptions","child","t","transaction","initial","options","newProperties","deletedProperties","shouldNotWrapWithTransaction","isDirty","key","commit","result","value","childCommit","rollback","el","commitArray","isDirtyArray","val","index","proxy","target","property","k","prop","isTransaction","object","p","noopTransaction","obj","SchemaValidationError","errors","message","e","SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR","SYMBOL_HAS_PROPERTIES","createHybridErrorArray","items","seenValue","descriptor","SchemaBuilder","#isRequired","#isNullable","#isReadonly","#description","#schemaName","#preprocessors","#validators","#hasMutating","#canSkipPreValidation","#extensions","#type","#defaultRequiredErrorMessageProvider","#requiredErrorMessageProvider","#defaultValue","#catchValue","#hasCatch","#example","#standardProps","self","value","result","#initPreValidation","object","context","doNotStopOnFirstError","resultingContext","needsTransaction","transaction","noopTransaction","#earlyFailResult","#validatorFailureErrors","index","name","validatorErrors","#buildPreValidationResult","trans","_e","i","state","preprocessingTransaction","preprocessedObject","currentPrepropIndex","entry","err","currentValidatorIndex","validatorResult","valid","text","_name","errorMessage","preprocessor","options","validator","catchValue","catchResult","provider","defaultValue","key","props","type","preprocessors","validators","isRequired","p","v"]}
@@ -1,2 +0,0 @@
1
- import{a as m}from"./chunk-K6Z47OQY.js";import{c as g,f as S}from"./chunk-3JMDGYDT.js";function x(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function P(o,e){let r=o;for(let a of e.split(".")){if(r==null)return;r=r[a]}return r}function b(o){let e=[];function r(a){return new Proxy(a,{get(t,s){if(s===g)return t[g];if(typeof s!="string")return t[s];let l=t[s];return typeof l!="object"||l===null?l:(e.push(s),r(l))}})}return{proxy:r(o),getPath:()=>e}}var R=class o extends S{#r;#e;#t=null;static create(e){return new o({type:"parseString",...e})}constructor(e){super(e),this.#r=e.objectSchema,this.#e=e.templateDefinition}#s(){if(this.#t)return this.#t;let{literals:e,segments:r}=this.#e,a="^";for(let t=0;t<r.length;t++){a+=x(e[t]);let s=t===r.length-1,l=e[t+1]??"";a+=s&&l===""?"(.*)":"(.*?)"}return a+=x(e[r.length]??""),a+="$",this.#t=new RegExp(a),this.#t}#n(){let{literals:e,segments:r}=this.#e,a="";for(let t=0;t<r.length;t++)a+=e[t]+`{${r[t].path}}`;return a+=e[r.length]??"",a}introspect(){return{...super.introspect(),objectSchema:this.#r,templateDefinition:this.#e}}serialize(e){let{literals:r,segments:a}=this.#e,t="";for(let s=0;s<a.length;s++){t+=r[s];let l=a[s].path,d=P(e,l);if(d==null)throw new Error(`Missing required parameter "${l}" for template ${this.#n()}`);t+=String(d)}return t+=r[a.length]??"",t}validate(e,r){return super.validate(e,r)}async validateAsync(e,r){return super.validateAsync(e,r)}_validate(e,r){return typeof e>"u"||e===null?typeof e>"u"&&this.hasDefault?(e=this.resolveDefaultValue(),{valid:!0,object:e}):!this.isRequired||e===null&&this.isNullable?{valid:!0,object:e}:{valid:!1,errors:[{message:this.getValidationErrorMessageSync(this.requiredErrorMessage,e)}]}:this.#a(e,r,(a,t)=>a.validate(t))}async _validateAsync(e,r){return typeof e>"u"||e===null?typeof e>"u"&&this.hasDefault?(e=this.resolveDefaultValue(),{valid:!0,object:e}):!this.isRequired||e===null&&this.isNullable?{valid:!0,object:e}:{valid:!1,errors:[{message:await this.getValidationErrorMessage(this.requiredErrorMessage,e)}]}:this.#a(e,r,(a,t)=>a.validateAsync(t))}#a(e,r,a){if(typeof e!="string")return{valid:!1,errors:[{message:`expected a string to parse, but saw ${typeof e}`}]};let{segments:t}=this.#e;if(t.length===0){let n=this.#e.literals[0]??"";return e!==n?{valid:!1,errors:[{message:`expected "${n}" but saw "${e}"`}]}:{valid:!0,object:{}}}let l=this.#s().exec(e);if(!l)return{valid:!1,errors:[{message:`does not match the parse-string pattern ${this.#n()}`}]};let d=r?.doNotStopOnFirstError??!1,p=new Proxy([],{get:(n,u,c)=>{if(u==="length")return t.length;let i=typeof u=="string"?Number(u):Number.NaN;return Number.isInteger(i)&&i>=0&&i<t.length?(i in n||(n[i]=a(t[i].schema,l[i+1])),n[i]):Reflect.get(n,u,c)}});if(d)for(let n=0;n<t.length;n++)p[n];let f=p[0];if(f&&typeof f.then=="function")return(async()=>{let n=[],u={};for(let c=0;c<t.length;c++){let i=await p[c];if(!i.valid){let h=i.errors?.[0]?.message??"validation failed";if(n.push({message:`${t[c].path}: ${h}`}),!d)return{valid:!1,errors:n};continue}t[c].descriptor.setValue(u,i.object,{createMissingStructure:!0})}return n.length>0?{valid:!1,errors:n}:{valid:!0,object:u}})();let y=[],T={};for(let n=0;n<t.length;n++){let u=p[n];if(!u.valid){let c=u.errors?.[0]?.message??"validation failed";if(y.push({message:`${t[n].path}: ${c}`}),!d)return{valid:!1,errors:y};continue}t[n].descriptor.setValue(T,u.object,{createMissingStructure:!0})}return y.length>0?{valid:!1,errors:y}:{valid:!0,object:T}}hasType(e){return this.createFromProps({...this.introspect()})}clearHasType(){return this.createFromProps({...this.introspect()})}nullable(){return super.nullable()}notNullable(){return super.notNullable()}required(e){return super.required(e)}optional(){return super.optional()}default(e){return super.default(e)}clearDefault(){return super.clearDefault()}brand(e){return super.brand(e)}readonly(){return super.readonly()}createFromProps(e){return o.create(e)}};function v(o,e){if(!(o instanceof m))throw new Error("First argument must be an ObjectSchemaBuilder instance");let r=m.getPropertiesFor(o),t=e(((s,...l)=>{let d=new Set,p=[];for(let f of l){if(typeof f!="function")throw new Error("Template expressions must be property selector functions (e.g. t => t.id)");let{proxy:y,getPath:T}=b(r),n=f(y);if(!n||typeof n!="object"||!(g in n))throw new Error("Template expression must select a property from the schema (e.g. t => t.id)");let u=n[g],c=u.getSchema(),i=T();if(i.length===0)throw new Error("Template expression must select a specific property (e.g. t => t.id), not the root object");let h=i.join(".");if(d.has(h))throw new Error(`Duplicate template parameter: "${h}" is already used in this template`);d.add(h),p.push({schema:c,path:h,descriptor:u})}return{literals:[...s],segments:p}}));return R.create({isRequired:!0,objectSchema:o,templateDefinition:t})}export{R as a,v as b};
2
- //# sourceMappingURL=chunk-DY7J6RNN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/builders/ParseStringSchemaBuilder.ts"],"sourcesContent":["import { ObjectSchemaBuilder } from './ObjectSchemaBuilder.js';\nimport {\n type BRAND,\n type InferType,\n type PropertyDescriptor,\n type PropertyDescriptorInner,\n type PropertyDescriptorTree,\n SchemaBuilder,\n SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR,\n type ValidationContext,\n type ValidationErrorMessageProvider,\n type ValidationResult\n} from './SchemaBuilder.js';\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Descriptor for a single interpolation segment captured at creation time. */\ntype SegmentDef = {\n /** The property schema for this segment. */\n schema: SchemaBuilder<any, any, any, any, any>;\n /** Dot-separated property path (e.g. `'order.id'`) — used in error messages. */\n path: string;\n /** The property descriptor inner — used to set parsed values on the result object. */\n descriptor: PropertyDescriptorInner<any, any, any>;\n};\n\n/** Internal data captured by the `$template` tagged-template invocation. */\ntype ParseStringTemplateDefinition = {\n /** Literal string fragments from the tagged template. */\n literals: readonly string[];\n /** One segment per interpolation expression, in order. */\n segments: readonly SegmentDef[];\n};\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * The typed tagged-template function passed to the `parseString`\n * callback. Template expressions must be property-selector lambdas that\n * navigate the {@link PropertyDescriptorTree} of the object schema.\n *\n * Only properties whose inferred type extends `string | number | boolean | Date`\n * are selectable — nested `ObjectSchemaBuilder` children are navigable but\n * not themselves endpoints.\n */\nexport type ParseStringTemplateTag<\n TSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>\n> = (\n strings: TemplateStringsArray,\n ...selectors: Array<\n (\n tree: PropertyDescriptorTree<\n TSchema,\n TSchema,\n string | number | boolean | Date\n >\n ) => PropertyDescriptor<TSchema, any, any>\n >\n) => ParseStringTemplateDefinition;\n\ntype ParseStringSchemaBuilderCreateProps<\n T = any,\n R extends boolean = true\n> = Partial<ReturnType<ParseStringSchemaBuilder<T, R>['introspect']>>;\n\n// ---------------------------------------------------------------------------\n// Regex helper\n// ---------------------------------------------------------------------------\n\n/** Escapes characters that have special meaning in a regular expression. */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Resolves a dot-separated property path on a (possibly nested) object.\n *\n * For flat paths like `'id'` this is equivalent to `obj['id']`.\n * For nested paths like `'order.id'` it traverses `obj.order.id`.\n */\nfunction resolvePath(obj: any, path: string): unknown {\n let current: any = obj;\n for (const part of path.split('.')) {\n if (current == null) return undefined;\n current = current[part];\n }\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// Path-tracking Proxy (used at schema creation time)\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps a `PropertyDescriptorTree` in a Proxy that records the traversed\n * property path. When the result is accessed via\n * `SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR` we know we've reached a leaf, so we\n * return the real descriptor. All other property accesses are captured as\n * path segments and the proxy recurses.\n *\n * @returns A proxy that looks identical to the tree from TypeScript's\n * perspective but captures `[propName, propName, …]` as the user\n * navigates via `t => t.order.id`.\n */\nfunction createPathTrackingProxy(tree: any): {\n proxy: any;\n getPath: () => string[];\n} {\n // Shared mutable array — child proxy pushes propagate to parent's getPath\n const pathSegments: string[] = [];\n\n function wrapProxy(target: any): any {\n return new Proxy(target, {\n get(t, prop) {\n // Property descriptor access — return real descriptor\n if (prop === SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR) {\n return t[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR];\n }\n\n // Symbol / non-string — pass through\n if (typeof prop !== 'string') {\n return t[prop];\n }\n\n const child = t[prop];\n if (typeof child !== 'object' || child === null) {\n return child;\n }\n\n // Record this segment and recurse\n pathSegments.push(prop);\n return wrapProxy(child);\n }\n });\n }\n\n return {\n proxy: wrapProxy(tree),\n getPath: () => pathSegments\n };\n}\n\n// ---------------------------------------------------------------------------\n// Builder\n// ---------------------------------------------------------------------------\n\n/**\n * Validates a string against a template pattern and parses it\n * into a strongly-typed object.\n *\n * Created via the {@link parseString} factory:\n *\n * ```ts\n * const RouteSchema = parseString(\n * object({ userId: string().uuid(), id: number() }),\n * $t => $t`/orders/${t => t.id}/${t => t.userId}`\n * );\n *\n * const result = RouteSchema.validate('/orders/42/550e8400-...');\n * // result.object === { id: 42, userId: '550e8400-...' }\n * ```\n *\n * @see {@link parseString}\n */\nexport class ParseStringSchemaBuilder<\n TResult = any,\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n THasDefault extends boolean = false,\n TExtensions = {}\n> extends SchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n> {\n #objectSchema: ObjectSchemaBuilder<any, any, any, any, any, any, any>;\n #templateDef: ParseStringTemplateDefinition;\n #compiledRegex: RegExp | null = null;\n\n /**\n * @hidden\n */\n public static create(props: ParseStringSchemaBuilderCreateProps) {\n return new ParseStringSchemaBuilder({\n type: 'parseString',\n ...props\n });\n }\n\n protected constructor(props: ParseStringSchemaBuilderCreateProps) {\n super(props as any);\n\n this.#objectSchema = props.objectSchema!;\n this.#templateDef = props.templateDefinition!;\n }\n\n // -- Regex ---------------------------------------------------------------\n\n #buildRegex(): RegExp {\n if (this.#compiledRegex) return this.#compiledRegex;\n const { literals, segments } = this.#templateDef;\n let pattern = '^';\n for (let i = 0; i < segments.length; i++) {\n pattern += escapeRegex(literals[i]);\n // Use non-greedy unless this is the last capture AND the\n // trailing literal is empty (nothing to anchor to).\n const isLast = i === segments.length - 1;\n const trailingLiteral = literals[i + 1] ?? '';\n pattern += isLast && trailingLiteral === '' ? '(.*)' : '(.*?)';\n }\n // Append the trailing literal (after all segments)\n pattern += escapeRegex(literals[segments.length] ?? '');\n pattern += '$';\n this.#compiledRegex = new RegExp(pattern);\n return this.#compiledRegex;\n }\n\n /** Builds a human-readable pattern like `/orders/{id}/{userId}` for error messages. */\n #humanPattern(): string {\n const { literals, segments } = this.#templateDef;\n let result = '';\n for (let i = 0; i < segments.length; i++) {\n result += literals[i] + `{${segments[i].path}}`;\n }\n result += literals[segments.length] ?? '';\n return result;\n }\n\n // -- Introspect ----------------------------------------------------------\n\n /**\n * Return a snapshot of this builder's configuration.\n *\n * Includes all base-class fields plus:\n * - `objectSchema` — the object schema defining the result shape.\n * - `templateDefinition` — the parsed template (literals and selector segments).\n */\n public introspect() {\n return {\n ...super.introspect(),\n /** The object schema defining the result shape. */\n objectSchema: this.#objectSchema,\n /** The template definition (literals + segments). */\n templateDefinition: this.#templateDef\n };\n }\n\n // -- Serialize -----------------------------------------------------------\n\n /**\n * Builds a string from the template by substituting parameter values.\n *\n * This is the reverse of {@link validate}: where `validate` parses a\n * string into a typed object, `serialize` takes a params object and\n * produces the string.\n *\n * @param params - An object matching the template's parsed result type.\n * Nested properties are resolved via dot-paths (e.g. `order.id`).\n * Values are coerced to strings via `String()`.\n * @returns The reconstructed string with all segments replaced.\n * @throws {Error} If a required parameter is missing (`undefined`).\n *\n * @example\n * ```ts\n * const Route = parseString(\n * object({ id: number().coerce() }),\n * $t => $t`/todos/${t => t.id}`\n * );\n *\n * Route.serialize({ id: 42 }); // '/todos/42'\n * ```\n */\n public serialize(params: TResult): string {\n const { literals, segments } = this.#templateDef;\n let result = '';\n for (let i = 0; i < segments.length; i++) {\n result += literals[i];\n const key = segments[i].path;\n const value = resolvePath(params, key);\n if (value === undefined || value === null) {\n throw new Error(\n `Missing required parameter \"${key}\" for template ${this.#humanPattern()}`\n );\n }\n result += String(value);\n }\n result += literals[segments.length] ?? '';\n return result;\n }\n\n // -- Validate (sync) -----------------------------------------------------\n\n /** {@inheritDoc SchemaBuilder.validate} */\n public validate(\n object: string,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return super.validate(object, context) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validateAsync} */\n public async validateAsync(\n object: string,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n return super.validateAsync(object, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n protected _validate(\n object: any,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n // Handle optional / nullable / default at the top\n if (typeof object === 'undefined' || object === null) {\n if (typeof object === 'undefined' && this.hasDefault) {\n object = this.resolveDefaultValue();\n return { valid: true, object: object as TResult };\n }\n if (!this.isRequired || (object === null && this.isNullable)) {\n return { valid: true, object: object as any };\n }\n return {\n valid: false,\n errors: [\n {\n message: this.getValidationErrorMessageSync(\n this.requiredErrorMessage,\n object\n )\n }\n ]\n };\n }\n\n return this.#matchAndValidate(object, context, (schema, raw) =>\n schema.validate(raw)\n );\n }\n\n // -- Validate (async) ----------------------------------------------------\n\n protected async _validateAsync(\n object: any,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n // Handle optional / nullable / default\n if (typeof object === 'undefined' || object === null) {\n if (typeof object === 'undefined' && this.hasDefault) {\n object = this.resolveDefaultValue();\n return { valid: true, object: object as TResult };\n }\n if (!this.isRequired || (object === null && this.isNullable)) {\n return { valid: true, object: object as any };\n }\n return {\n valid: false,\n errors: [\n {\n message: await this.getValidationErrorMessage(\n this.requiredErrorMessage,\n object\n )\n }\n ]\n };\n }\n\n return this.#matchAndValidate(object, context, (schema, raw) =>\n schema.validateAsync(raw)\n );\n }\n\n /**\n * Shared regex-match + per-segment validation logic used by both\n * `_validate` (sync) and `_validateAsync` (async).\n *\n * The caller supplies `validateSegment` which is either the sync\n * `schema.validate` or async `schema.validateAsync`.\n */\n #matchAndValidate<\n R extends ValidationResult<unknown> | Promise<ValidationResult<unknown>>\n >(\n object: any,\n context: ValidationContext | undefined,\n validateSegment: (\n schema: SchemaBuilder<any, any, any, any, any>,\n raw: string\n ) => R\n ): R extends Promise<any>\n ? Promise<ValidationResult<TResult>>\n : ValidationResult<TResult> {\n if (typeof object !== 'string') {\n return {\n valid: false,\n errors: [\n {\n message: `expected a string to parse, but saw ${typeof object}`\n }\n ]\n } as any;\n }\n\n const { segments } = this.#templateDef;\n\n // Degenerate case: no segments — just compare literals\n if (segments.length === 0) {\n const expected = this.#templateDef.literals[0] ?? '';\n if (object !== expected) {\n return {\n valid: false,\n errors: [\n {\n message: `expected \"${expected}\" but saw \"${object}\"`\n }\n ]\n } as any;\n }\n return { valid: true, object: {} as TResult } as any;\n }\n\n const regex = this.#buildRegex();\n const match = regex.exec(object);\n\n if (!match) {\n return {\n valid: false,\n errors: [\n {\n message: `does not match the parse-string pattern ${this.#humanPattern()}`\n }\n ]\n } as any;\n }\n\n const doNotStop = context?.doNotStopOnFirstError ?? false;\n\n // Compute segment validation results lazily so fail-fast mode can\n // short-circuit without eagerly validating later segments. When\n // doNotStopOnFirstError is enabled, prestart all validations to\n // preserve the existing eager/parallel behavior.\n const segResults = new Proxy([] as R[], {\n get: (target, prop, receiver) => {\n if (prop === 'length') return segments.length;\n\n const index =\n typeof prop === 'string' ? Number(prop) : Number.NaN;\n if (\n Number.isInteger(index) &&\n index >= 0 &&\n index < segments.length\n ) {\n if (!(index in target)) {\n target[index] = validateSegment(\n segments[index].schema,\n match[index + 1]\n );\n }\n return target[index];\n }\n\n return Reflect.get(target, prop, receiver);\n }\n }) as R[];\n\n if (doNotStop) {\n for (let i = 0; i < segments.length; i++) {\n void segResults[i];\n }\n }\n\n // If first result is a promise, the whole pipeline is async\n const firstResult = segResults[0];\n if (firstResult && typeof (firstResult as any).then === 'function') {\n return (async () => {\n const errors: { message: string }[] = [];\n const resultObj = {} as any;\n for (let i = 0; i < segments.length; i++) {\n const segResult = (await segResults[\n i\n ]) as ValidationResult<unknown>;\n if (!segResult.valid) {\n const inner =\n segResult.errors?.[0]?.message ??\n 'validation failed';\n errors.push({\n message: `${segments[i].path}: ${inner}`\n });\n if (!doNotStop) return { valid: false, errors };\n continue;\n }\n segments[i].descriptor.setValue(\n resultObj,\n segResult.object,\n { createMissingStructure: true }\n );\n }\n if (errors.length > 0) return { valid: false, errors };\n return { valid: true, object: resultObj as TResult };\n })() as any;\n }\n\n // Sync path\n const errors: { message: string }[] = [];\n const resultObj = {} as any;\n for (let i = 0; i < segments.length; i++) {\n const segResult = segResults[i] as ValidationResult<unknown>;\n if (!segResult.valid) {\n const inner =\n segResult.errors?.[0]?.message ?? 'validation failed';\n errors.push({\n message: `${segments[i].path}: ${inner}`\n });\n if (!doNotStop) return { valid: false, errors } as any;\n continue;\n }\n segments[i].descriptor.setValue(resultObj, segResult.object, {\n createMissingStructure: true\n });\n }\n if (errors.length > 0) return { valid: false, errors } as any;\n return { valid: true, object: resultObj as TResult } as any;\n }\n\n // -- Fluent overrides (return type narrowing) ----------------------------\n\n /**\n * @inheritdoc\n */\n public hasType<T>(\n _notUsed?: T\n ): ParseStringSchemaBuilder<T, true, TNullable, THasDefault, TExtensions> &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @inheritdoc\n */\n public clearHasType(): ParseStringSchemaBuilder<\n any,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public nullable(): ParseStringSchemaBuilder<\n TResult,\n TRequired,\n true,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.nullable() as any;\n }\n\n /**\n * @hidden\n */\n public notNullable(): ParseStringSchemaBuilder<\n TResult,\n TRequired,\n false,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.notNullable() as any;\n }\n\n /**\n * @hidden\n */\n public required(\n errorMessage?: ValidationErrorMessageProvider\n ): ParseStringSchemaBuilder<\n TResult,\n true,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.required(errorMessage);\n }\n\n /**\n * @hidden\n */\n public optional(): ParseStringSchemaBuilder<\n TResult,\n false,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.optional();\n }\n\n /**\n * @hidden\n */\n public default(\n value: TResult | (() => TResult)\n ): ParseStringSchemaBuilder<TResult, true, TNullable, true, TExtensions> &\n TExtensions {\n return super.default(value) as any;\n }\n\n /**\n * @hidden\n */\n public clearDefault(): ParseStringSchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n false,\n TExtensions\n > &\n TExtensions {\n return super.clearDefault() as any;\n }\n\n /**\n * @hidden\n */\n public brand<TBrand extends string | symbol>(\n _name?: TBrand\n ): ParseStringSchemaBuilder<\n TResult & { readonly [K in BRAND]: TBrand },\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.brand(_name);\n }\n\n /**\n * @hidden\n */\n public readonly(): ParseStringSchemaBuilder<\n Readonly<TResult>,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.readonly();\n }\n\n protected createFromProps<T, TReq extends boolean>(\n props: ParseStringSchemaBuilderCreateProps<T, TReq>\n ): this {\n return ParseStringSchemaBuilder.create(props as any) as any;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a parse-string schema that validates a string against a\n * template pattern and parses it into a strongly-typed object.\n *\n * The first argument defines the result shape via `object(...)`, and the\n * second argument is a callback receiving a typed `$template` tagged-template\n * function whose template expressions are type-safe property selectors.\n *\n * @example\n * ```ts\n * const RouteSchema = parseString(\n * object({\n * userId: string().uuid(),\n * id: number()\n * }),\n * $t => $t`/orders/${t => t.id}/${t => t.userId}`\n * );\n *\n * const result = RouteSchema.validate('/orders/42/550e8400-e29b-41d4-a716-446655440000');\n * // result.valid === true\n * // result.object === { id: 42, userId: '550e8400-e29b-41d4-a716-446655440000' }\n *\n * type Route = InferType<typeof RouteSchema>;\n * // { id: number; userId: string }\n * ```\n *\n * @example Nested objects\n * ```ts\n * const schema = parseString(\n * object({\n * order: object({ id: number() }),\n * user: object({ name: string() })\n * }),\n * $t => $t`/orders/${t => t.order.id}/by/${t => t.user.name}`\n * );\n * ```\n *\n * @param objectSchema - An `ObjectSchemaBuilder` defining the result type and\n * per-property validation schemas.\n * @param templateBuilder - Callback receiving the typed `$template`\n * tagged-template function. Must return the result of invoking `$template`.\n * @returns A `ParseStringSchemaBuilder` whose `validate()` accepts a\n * string and whose `InferType` is the object schema's inferred type.\n */\nexport function parseString<\n TSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>\n>(\n objectSchema: TSchema,\n templateBuilder: (\n $template: ParseStringTemplateTag<TSchema>\n ) => ParseStringTemplateDefinition\n): ParseStringSchemaBuilder<InferType<TSchema>> {\n if (!(objectSchema instanceof ObjectSchemaBuilder)) {\n throw new Error(\n 'First argument must be an ObjectSchemaBuilder instance'\n );\n }\n\n // Get the PropertyDescriptorTree for the object schema\n const tree = ObjectSchemaBuilder.getPropertiesFor(objectSchema as any);\n\n // Build the $template tagged-template function\n const $template = ((\n strings: TemplateStringsArray,\n ...selectors: Array<(t: any) => any>\n ): ParseStringTemplateDefinition => {\n const seenPaths = new Set<string>();\n const segments: SegmentDef[] = [];\n\n for (const selector of selectors) {\n if (typeof selector !== 'function') {\n throw new Error(\n 'Template expressions must be property selector functions (e.g. t => t.id)'\n );\n }\n\n // Create a path-tracking proxy for this selector invocation\n const { proxy, getPath } = createPathTrackingProxy(tree);\n const descriptor = selector(proxy);\n\n if (\n !descriptor ||\n typeof descriptor !== 'object' ||\n !(SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR in descriptor)\n ) {\n throw new Error(\n 'Template expression must select a property from the schema (e.g. t => t.id)'\n );\n }\n\n const inner: PropertyDescriptorInner<any, any, any> =\n descriptor[SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR];\n const schema = inner.getSchema();\n const path = getPath();\n\n if (path.length === 0) {\n throw new Error(\n 'Template expression must select a specific property (e.g. t => t.id), not the root object'\n );\n }\n\n const pathStr = path.join('.');\n\n if (seenPaths.has(pathStr)) {\n throw new Error(\n `Duplicate template parameter: \"${pathStr}\" is already used in this template`\n );\n }\n seenPaths.add(pathStr);\n\n segments.push({\n schema,\n path: pathStr,\n descriptor: inner\n });\n }\n\n return {\n literals: [...strings],\n segments\n };\n }) as ParseStringTemplateTag<TSchema>;\n\n const templateDef = templateBuilder($template);\n\n return ParseStringSchemaBuilder.create({\n isRequired: true,\n objectSchema: objectSchema as any,\n templateDefinition: templateDef\n }) as any;\n}\n"],"mappings":"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","names":["escapeRegex","s","resolvePath","obj","path","current","part","createPathTrackingProxy","tree","pathSegments","wrapProxy","target","prop","SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR","child","ParseStringSchemaBuilder","_ParseStringSchemaBuilder","SchemaBuilder","#objectSchema","#templateDef","#compiledRegex","props","#buildRegex","literals","segments","pattern","i","isLast","trailingLiteral","#humanPattern","result","params","key","value","object","context","#matchAndValidate","schema","raw","validateSegment","expected","match","doNotStop","segResults","receiver","index","firstResult","errors","resultObj","segResult","inner","_notUsed","errorMessage","_name","parseString","objectSchema","templateBuilder","ObjectSchemaBuilder","templateDef","strings","selectors","seenPaths","selector","proxy","getPath","descriptor","pathStr"]}
@@ -1,2 +0,0 @@
1
- import{a as g,b as V}from"./chunk-BUEVZ3KA.js";import{a as F,b as N}from"./chunk-K6Z47OQY.js";import{a as P,b as v}from"./chunk-WDMJBGBD.js";import{a as D,b as M}from"./chunk-ZFI27R3L.js";import{a as C,b as q}from"./chunk-YQZHDMRF.js";import{a as j,b as A}from"./chunk-QARCEYGO.js";import{a as w,b as H}from"./chunk-WQDYWDOE.js";import{a as p,b as x}from"./chunk-HN774HD7.js";import{a as m,b as h}from"./chunk-NUW3VXZV.js";import{a as f,b as E}from"./chunk-CFIJQ4GP.js";import{a as b,b as S}from"./chunk-EIVZX4ZO.js";import{a as R,b as B}from"./chunk-ZC6YBKCP.js";import{f as o}from"./chunk-3JMDGYDT.js";var u=class s extends o{#e;#t;#a;static create(e){return new s({type:"generic",...e})}constructor(e){super(e),this.#e=e.templateFn,this.#t=e.defaults,this.apply=(...t)=>{if(!this.#e)throw new Error("GenericSchemaBuilder: no template function defined");return this.#e(...t)}}introspect(){return{...super.introspect(),templateFn:this.#e,defaults:this.#t}}#n(){if(!(!this.#e||!this.#t))return this.#a||(this.#a=this.#e(...this.#t)),this.#a}#r(e,t){let{valid:r,transaction:i,errors:l}=e;if(!r)return{valid:r,errors:l};let{object:{validatedObject:n}}=i;if(typeof n>"u"&&!this.isRequired||n===null&&(!this.isRequired||this.isNullable))return{valid:!0,object:n};let a=this.#n();return a?a.validate(n,t):{valid:!1,errors:[{message:"This is a generic schema template. Call .apply() with concrete schemas to get a validatable schema, or provide default arguments to generic()."}]}}async#i(e,t){let{valid:r,transaction:i,errors:l}=e;if(!r)return{valid:r,errors:l};let{object:{validatedObject:n}}=i;if(typeof n>"u"&&!this.isRequired||n===null&&(!this.isRequired||this.isNullable))return{valid:!0,object:n};let a=this.#n();return a?await a.validateAsync(n,t):{valid:!1,errors:[{message:"This is a generic schema template. Call .apply() with concrete schemas to get a validatable schema, or provide default arguments to generic()."}]}}validate(e,t){return super.validate(e,t)}async validateAsync(e,t){return super.validateAsync(e,t)}_validate(e,t){return this.#r(this.preValidateSync(e,t),t)}async _validateAsync(e,t){return this.#i(await super.preValidateAsync(e,t),t)}createFromProps(e){return s.create(e)}hasType(e){return this.createFromProps({...this.introspect()})}clearHasType(){return this.createFromProps({...this.introspect()})}required(e){return super.required(e)}optional(){return super.optional()}nullable(){return super.nullable()}notNullable(){return super.notNullable()}default(e){return super.default(e)}clearDefault(){return super.clearDefault()}brand(e){return super.brand(e)}readonly(){return super.readonly()}};function O(s,e){let t=e!==void 0?e:s,r=e!==void 0?s:void 0;return u.create({isRequired:!0,templateFn:t,defaults:r})}var c=class s extends o{#e;#t=null;static create(e){return new s({type:"lazy",...e})}constructor(e){if(super(e),typeof e.getter!="function")throw new Error("LazySchemaBuilder: getter must be a function");this.#e=e.getter}resolve(){return this.#t===null&&(this.#t=this.#e()),this.#t}introspect(){return{...super.introspect(),getter:this.#e}}#a(e,t){let{valid:r,transaction:i,errors:l}=e;if(!r)return{valid:r,errors:l};let{object:{validatedObject:n}}=i;return n==null?{valid:!0,object:n}:this.resolve().validate(n,t)}validate(e,t){return super.validate(e,t)}async validateAsync(e,t){return super.validateAsync(e,t)}_validate(e,t){return this.#a(this.preValidateSync(e,t),t)}async _validateAsync(e,t){let r=await super.preValidateAsync(e,t),{valid:i,transaction:l,errors:n}=r;if(!i)return{valid:i,errors:n};let{object:{validatedObject:a}}=l;return a==null?{valid:!0,object:a}:this.resolve().validateAsync(a,t)}createFromProps(e){return s.create(e)}hasType(e){return this.createFromProps({...this.introspect()})}clearHasType(){return this.createFromProps({...this.introspect()})}required(e){return super.required(e)}optional(){return super.optional()}default(e){return super.default(e)}clearDefault(){return super.clearDefault()}brand(e){return super.brand(e)}readonly(){return super.readonly()}nullable(){return super.nullable()}notNullable(){return super.notNullable()}};function z(s){return c.create({type:"lazy",isRequired:!0,preprocessors:[],validators:[],getter:s})}var y=class s extends o{static create(e){return new s({type:"null",...e})}constructor(e){super(e)}hasType(e){return this.createFromProps({...this.introspect()})}clearHasType(){return this.createFromProps({...this.introspect()})}#e(e){return e===null?{valid:!0,object:null}:e===void 0&&this.hasDefault?this.resolveDefaultValue()===null?{valid:!0,object:null}:{valid:!1,errors:[{message:"must be null"}]}:e===void 0&&!this.isRequired?{valid:!0,object:void 0}:{valid:!1,errors:[{message:"must be null"}]}}validate(e,t){return super.validate(e,t)}async validateAsync(e,t){return super.validateAsync(e,t)}_validate(e,t){return this.#e(e)}async _validateAsync(e,t){return this.#e(e)}createFromProps(e){return s.create(e)}required(e){return super.required(e)}optional(){return super.optional()}default(e){return super.default(e)}clearDefault(){return super.clearDefault()}brand(e){return super.brand(e)}readonly(){return super.readonly()}nullable(){return super.nullable()}notNullable(){return super.notNullable()}},L=()=>y.create({isRequired:!0});var T={string:C,number:g,boolean:f,date:b,object:F,array:m,tuple:j,record:D,union:w,func:R,any:p,promise:P,generic:u},G={string:q,number:V,boolean:E,date:S,object:N,array:h,tuple:A,record:M,union:H,func:B,any:x,promise:v,generic:O},_=new Set(["validate","validateAsync","parse","parseAsync","safeParse","safeParseAsync","introspect","optional","required","addPreprocessor","clearPreprocessors","addValidator","clearValidators","hasType","clearHasType","createFromProps","preValidate","preValidateSync","preValidateAsync","getValidationErrorMessage","getValidationErrorMessageSync","assureValidationErrorMessageProvider","withExtension","getExtension"]);function U(s){let e={};for(let t of Object.keys(s)){if(!(t in T))throw new Error(`Unknown builder type "${t}". Valid types: ${Object.keys(T).join(", ")}`);let r=s[t];if(!r||typeof r!="object")throw new Error(`Extension config for "${t}" must be an object of methods`);e[t]={};for(let i of Object.keys(r)){if(_.has(i))throw new Error(`Cannot override reserved method "${i}" on "${t}"`);let l=r[i];if(typeof l!="function")throw new Error(`Extension method "${t}.${i}" must be a function`);e[t][i]=function(...n){let a=l.apply(this,n);return a&&typeof a=="object"&&typeof a.withExtension=="function"&&(typeof a.getExtension!="function"||a.getExtension(i)===void 0)?a.withExtension(i,n.length===1?n[0]:n.length===0?!0:n):a}}}return{config:e}}function k(...s){let e=new Map;for(let r of s)for(let i of Object.keys(r.config)){e.has(i)||e.set(i,new Map);let l=e.get(i),n=r.config[i];for(let a of Object.keys(n)){if(l.has(a))throw new Error(`Extension method collision: "${a}" is defined by multiple extensions for "${i}"`);l.set(a,n[a])}}let t={};for(let r of Object.keys(T)){let i=e.get(r);if(!i||i.size===0){t[r]=G[r];continue}let l=T[r],n=class extends l{constructor(...a){super(...a)}static create(a){return new n({...a})}createFromProps(a){return n.create(a)}};for(let[a,d]of i)Object.defineProperty(n.prototype,a,{value:d,writable:!0,configurable:!0,enumerable:!1});t[r]=(...a)=>{let d=G[r](...a);return Object.setPrototypeOf(d,n.prototype),d}}return t}export{u as a,O as b,c,z as d,y as e,L as f,U as g,k as h};
2
- //# sourceMappingURL=chunk-GXPV6UQK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/builders/GenericSchemaBuilder.ts","../src/builders/LazySchemaBuilder.ts","../src/builders/NullSchemaBuilder.ts","../src/extension.ts"],"sourcesContent":["import {\n type BRAND,\n SchemaBuilder,\n type ValidationContext,\n type ValidationErrorMessageProvider,\n type ValidationResult\n} from './SchemaBuilder.js';\n\ntype GenericSchemaBuilderCreateProps<TRequired extends boolean = true> =\n Partial<ReturnType<GenericSchemaBuilder<any, TRequired>['introspect']>>;\n\n/**\n * Schema builder that wraps a generic template function, enabling reusable\n * parameterized schemas. Call {@link GenericSchemaBuilder.apply | `.apply()`}\n * with concrete schema arguments to obtain a fully typed concrete schema\n * builder whose TypeScript type is inferred from the template function's\n * generic signature.\n *\n * **NOTE** this class is exported only to give opportunity to extend it\n * by inheriting. It is not recommended to create an instance of this class\n * directly. Use {@link generic | generic()} function instead.\n *\n * @example Single type parameter\n * ```ts\n * import { generic, object, array, number, string, InferType } from '@cleverbrush/schema';\n *\n * const PaginatedList = generic(\n * <T extends SchemaBuilder<any, any, any, any, any>>(itemSchema: T) =>\n * object({\n * items: array(itemSchema),\n * total: number(),\n * page: number(),\n * })\n * );\n *\n * const userSchema = object({ name: string(), age: number() });\n * const PaginatedUsers = PaginatedList.apply(userSchema);\n *\n * type PaginatedUsersType = InferType<typeof PaginatedUsers>;\n * // → { items: { name: string; age: number }[]; total: number; page: number }\n * ```\n *\n * @example Multiple type parameters\n * ```ts\n * const Result = generic(\n * <T extends SchemaBuilder<any, any, any, any, any>,\n * E extends SchemaBuilder<any, any, any, any, any>>(\n * valueSchema: T,\n * errorSchema: E\n * ) =>\n * object({\n * ok: boolean(),\n * value: valueSchema.optional(),\n * error: errorSchema.optional(),\n * })\n * );\n *\n * const StringResult = Result.apply(string(), number());\n * // InferType → { ok: boolean; value?: string; error?: number }\n * ```\n *\n * @example With default arguments (enables direct `.validate()` on the template)\n * ```ts\n * const AnyList = generic(\n * [any()], // default args — one per template parameter\n * <T extends SchemaBuilder<any, any, any, any, any>>(itemSchema: T) =>\n * object({ items: array(itemSchema), total: number() })\n * );\n *\n * // Validate directly using defaults:\n * AnyList.validate({ items: [1, 'two', true], total: 3 }); // valid\n *\n * // Or apply concrete schemas first:\n * AnyList.apply(string()).validate({ items: ['a', 'b'], total: 2 }); // valid\n * ```\n *\n * @see {@link generic}\n *\n * @typeParam TFn - The generic template function type. Its return type\n * determines `TResult` (the validated value type) when no explicit type\n * override has been applied via `.hasType<T>()`.\n * @typeParam TRequired - `true` when the schema is required (default),\n * `false` after calling `.optional()`. Governs whether `undefined` is a\n * valid value.\n * @typeParam TNullable - `true` after calling `.nullable()`. Governs whether\n * `null` is a valid value.\n * @typeParam TExplicitType - Type override set via `.hasType<T>()`. When\n * `undefined` (the default), `TResult` is derived from `TFn`'s return type.\n * @typeParam THasDefault - `true` after calling `.default(value)`. Governs\n * whether `InferType` emits `T` instead of `T | undefined` for optional\n * schemas with a default.\n * @typeParam TExtensions - Object type carrying extension methods added via\n * `withExtensions()`. Defaults to `{}`.\n * @typeParam TResult - The inferred result type: `TExplicitType` when set,\n * otherwise the value type inferred from `ReturnType<TFn>`.\n */\nexport class GenericSchemaBuilder<\n TFn extends (...args: any[]) => SchemaBuilder<any, any, any, any, any>,\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n TExplicitType = undefined,\n THasDefault extends boolean = false,\n TExtensions = {},\n TResult = TExplicitType extends undefined\n ? ReturnType<TFn> extends SchemaBuilder<infer R, any, any, any, any>\n ? R\n : any\n : TExplicitType\n> extends SchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n> {\n #templateFn?: (...args: any[]) => SchemaBuilder<any, any, any, any, any>;\n #defaults?: readonly any[];\n #cachedDefaultSchema?: SchemaBuilder<any, any, any, any, any>;\n\n /**\n * Applies the template function with concrete schema arguments, returning\n * a fully typed concrete schema builder. TypeScript infers the result type\n * from the template function's own generic signature.\n *\n * The returned builder is independent of this `GenericSchemaBuilder` and\n * can be used like any other schema: `.validate()`, `.optional()`, etc.\n *\n * @example\n * ```ts\n * const Wrapper = generic(\n * <T extends SchemaBuilder<any, any, any, any, any>>(schema: T) =>\n * object({ data: schema })\n * );\n *\n * const s = Wrapper.apply(string());\n * // InferType<typeof s> → { data: string }\n * s.validate({ data: 'hello' }); // { valid: true }\n * ```\n */\n // Set to the actual function in the constructor; declared here for TypeScript.\n public declare readonly apply: TFn;\n\n /**\n * @hidden\n */\n public static create(props: GenericSchemaBuilderCreateProps<any>) {\n return new GenericSchemaBuilder({\n type: 'generic',\n ...props\n });\n }\n\n protected constructor(props: GenericSchemaBuilderCreateProps<TRequired>) {\n super(props as any);\n this.#templateFn = (props as any).templateFn;\n this.#defaults = (props as any).defaults;\n\n // Own property: typed as TFn so generic inference works at call sites.\n (this as any).apply = (...args: any[]) => {\n if (!this.#templateFn) {\n throw new Error(\n 'GenericSchemaBuilder: no template function defined'\n );\n }\n return this.#templateFn(...args);\n };\n }\n\n /**\n * Returns an object describing the current schema configuration.\n *\n * In addition to the base fields exposed by {@link SchemaBuilder.introspect},\n * the following fields are included:\n *\n * - `templateFn` — the template function passed to {@link generic}.\n * - `defaults` — the default argument list passed to the two-argument\n * form of {@link generic}, or `undefined` when no defaults were provided.\n *\n * @example\n * ```ts\n * const schema = generic([string()], <T>(s: T) => object({ data: s }));\n *\n * const info = schema.introspect();\n * // info.type → 'generic'\n * // info.templateFn → [Function]\n * // info.defaults → [StringSchemaBuilder]\n * ```\n */\n public introspect() {\n return {\n ...super.introspect(),\n /** Template function passed to {@link generic}. */\n templateFn: this.#templateFn,\n /** Default positional arguments for the template function, or `undefined`. */\n defaults: this.#defaults\n };\n }\n\n #getOrCreateDefaultSchema():\n | SchemaBuilder<any, any, any, any, any>\n | undefined {\n if (!this.#templateFn || !this.#defaults) {\n return undefined;\n }\n if (!this.#cachedDefaultSchema) {\n this.#cachedDefaultSchema = this.#templateFn(...this.#defaults);\n }\n return this.#cachedDefaultSchema;\n }\n\n #buildResult(\n superResult: ReturnType<\n GenericSchemaBuilder<TFn, TRequired>['preValidateSync']\n >,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n const {\n valid,\n transaction: preValidationTransaction,\n errors\n } = superResult;\n\n if (!valid) {\n return { valid, errors };\n }\n\n const {\n object: { validatedObject: objToValidate }\n } = preValidationTransaction!;\n\n if (\n (typeof objToValidate === 'undefined' && !this.isRequired) ||\n (objToValidate === null && (!this.isRequired || this.isNullable))\n ) {\n return { valid: true, object: objToValidate };\n }\n\n const defaultSchema = this.#getOrCreateDefaultSchema();\n if (!defaultSchema) {\n return {\n valid: false,\n errors: [\n {\n message:\n 'This is a generic schema template. Call .apply() with concrete schemas to get a validatable schema, or provide default arguments to generic().'\n }\n ]\n };\n }\n\n return defaultSchema.validate(\n objToValidate,\n context\n ) as ValidationResult<TResult>;\n }\n\n async #buildAsyncResult(\n superResult: Awaited<\n ReturnType<GenericSchemaBuilder<TFn, TRequired>['preValidateAsync']>\n >,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n const {\n valid,\n transaction: preValidationTransaction,\n errors\n } = superResult;\n\n if (!valid) {\n return { valid, errors };\n }\n\n const {\n object: { validatedObject: objToValidate }\n } = preValidationTransaction!;\n\n if (\n (typeof objToValidate === 'undefined' && !this.isRequired) ||\n (objToValidate === null && (!this.isRequired || this.isNullable))\n ) {\n return { valid: true, object: objToValidate };\n }\n\n const defaultSchema = this.#getOrCreateDefaultSchema();\n if (!defaultSchema) {\n return {\n valid: false,\n errors: [\n {\n message:\n 'This is a generic schema template. Call .apply() with concrete schemas to get a validatable schema, or provide default arguments to generic().'\n }\n ]\n };\n }\n\n return (await defaultSchema.validateAsync(\n objToValidate,\n context\n )) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validate} */\n public validate(\n object: TResult,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return super.validate(object, context) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validateAsync} */\n public async validateAsync(\n object: TResult,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n return super.validateAsync(object, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n /**\n * Performs synchronous validation of the schema over `object`.\n * Throws if any preprocessor, validator, or error message provider returns a Promise.\n * @param context Optional `ValidationContext` settings.\n */\n protected _validate(\n object: TResult,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return this.#buildResult(\n this.preValidateSync(object, context),\n context\n );\n }\n\n /**\n * Performs async validation of the schema over `object`.\n * Supports async preprocessors, validators, and error message providers.\n * @param context Optional `ValidationContext` settings.\n */\n protected async _validateAsync(\n object: TResult,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n return this.#buildAsyncResult(\n await super.preValidateAsync(object, context),\n context\n );\n }\n\n protected createFromProps<TReq extends boolean>(\n props: GenericSchemaBuilderCreateProps<TReq>\n ): this {\n return GenericSchemaBuilder.create(props as any) as any;\n }\n\n /**\n * @hidden\n */\n public hasType<T>(\n _notUsed?: T\n ): GenericSchemaBuilder<TFn, true, TNullable, T, THasDefault, TExtensions> &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public clearHasType(): GenericSchemaBuilder<\n TFn,\n TRequired,\n TNullable,\n undefined,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public required(\n errorMessage?: ValidationErrorMessageProvider\n ): GenericSchemaBuilder<\n TFn,\n true,\n TNullable,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.required(errorMessage);\n }\n\n /**\n * @hidden\n */\n public optional(): GenericSchemaBuilder<\n TFn,\n false,\n TNullable,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.optional();\n }\n\n /**\n * @hidden\n */\n public nullable(): GenericSchemaBuilder<\n TFn,\n TRequired,\n true,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.nullable() as any;\n }\n\n /**\n * @hidden\n */\n public notNullable(): GenericSchemaBuilder<\n TFn,\n TRequired,\n false,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.notNullable() as any;\n }\n\n /**\n * @hidden\n */\n public default(\n value: TResult | (() => TResult)\n ): GenericSchemaBuilder<\n TFn,\n true,\n TNullable,\n TExplicitType,\n true,\n TExtensions\n > &\n TExtensions {\n return super.default(value) as any;\n }\n\n /**\n * @hidden\n */\n public clearDefault(): GenericSchemaBuilder<\n TFn,\n TRequired,\n TNullable,\n TExplicitType,\n false,\n TExtensions\n > &\n TExtensions {\n return super.clearDefault() as any;\n }\n\n /**\n * @hidden\n */\n public brand<TBrand extends string | symbol>(\n _name?: TBrand\n ): GenericSchemaBuilder<\n TFn,\n TRequired,\n TNullable,\n TResult & { readonly [K in BRAND]: TBrand },\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.brand(_name);\n }\n\n /**\n * @hidden\n */\n public readonly(): GenericSchemaBuilder<\n TFn,\n TRequired,\n TNullable,\n Readonly<TResult>,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.readonly();\n }\n}\n\n/**\n * Creates a generic schema template — a reusable, parameterized schema factory\n * whose TypeScript type is inferred from the template function's generic\n * signature.\n *\n * Call {@link GenericSchemaBuilder.apply | `.apply()`} on the returned builder\n * to instantiate the template with concrete schema arguments and receive a\n * fully typed concrete schema.\n *\n * There are two overloads:\n *\n * 1. **`generic(templateFn)`** — Provide only the template function. The\n * template must be called via `.apply()` before validation.\n * 2. **`generic(defaults, templateFn)`** — Provide positional default arguments\n * followed by the template function. The template can be validated directly\n * using those defaults (without calling `.apply()` first).\n *\n * @param templateFn - A (generic) function that accepts schema arguments and\n * returns a concrete schema. TypeScript infers the result type from this\n * function's generic signature when `.apply()` is called.\n *\n * @returns A new {@link GenericSchemaBuilder} with `isRequired` set to `true`.\n *\n * @example Single type parameter\n * ```ts\n * import { generic, object, array, number, string, any, InferType } from '@cleverbrush/schema';\n *\n * const PaginatedList = generic(\n * <T extends SchemaBuilder<any, any, any, any, any>>(itemSchema: T) =>\n * object({ items: array(itemSchema), total: number(), page: number() })\n * );\n *\n * const UserList = PaginatedList.apply(object({ name: string() }));\n * type UserListType = InferType<typeof UserList>;\n * // → { items: { name: string }[]; total: number; page: number }\n *\n * UserList.validate({ items: [{ name: 'Alice' }], total: 1, page: 1 }); // valid\n * ```\n *\n * @example Multiple type parameters\n * ```ts\n * const Result = generic(\n * <T extends SchemaBuilder<any, any, any, any, any>,\n * E extends SchemaBuilder<any, any, any, any, any>>(\n * valueSchema: T,\n * errorSchema: E\n * ) =>\n * union(\n * object({ ok: boolean().equalsTo(true), value: valueSchema }),\n * object({ ok: boolean().equalsTo(false), error: errorSchema })\n * )\n * );\n *\n * const StringResult = Result.apply(string(), number());\n * ```\n *\n * @example With defaults (enables direct validation on the template)\n * ```ts\n * const AnyList = generic(\n * [any()], // default args — positional, one per template parameter\n * <T extends SchemaBuilder<any, any, any, any, any>>(itemSchema: T) =>\n * object({ items: array(itemSchema), total: number() })\n * );\n *\n * // Validate directly — uses the default any() schema:\n * AnyList.validate({ items: [1, 'two'], total: 2 }); // valid\n *\n * // Or apply concrete schemas first:\n * AnyList.apply(string()).validate({ items: ['x'], total: 1 }); // valid\n * ```\n *\n * @see {@link GenericSchemaBuilder}\n */\nexport function generic<\n TFn extends (...args: any[]) => SchemaBuilder<any, any, any, any, any>\n>(\n templateFn: TFn\n): GenericSchemaBuilder<TFn, true, false, undefined, false, {}>;\nexport function generic<\n TFn extends (...args: any[]) => SchemaBuilder<any, any, any, any, any>\n>(\n defaults: readonly any[],\n templateFn: TFn\n): GenericSchemaBuilder<TFn, true, false, undefined, false, {}>;\nexport function generic<\n TFn extends (...args: any[]) => SchemaBuilder<any, any, any, any, any>\n>(\n fnOrDefaults: TFn | readonly any[],\n templateFn?: TFn\n): GenericSchemaBuilder<TFn, true, false, undefined, false, {}> {\n const fn = templateFn !== undefined ? templateFn : (fnOrDefaults as TFn);\n const defaults =\n templateFn !== undefined ? (fnOrDefaults as readonly any[]) : undefined;\n return GenericSchemaBuilder.create({\n isRequired: true,\n templateFn: fn,\n defaults\n }) as any;\n}\n","import {\n type BRAND,\n SchemaBuilder,\n type ValidationContext,\n type ValidationErrorMessageProvider,\n type ValidationResult\n} from './SchemaBuilder.js';\n\ntype LazySchemaBuilderCreateProps<R extends boolean = true> = Partial<\n ReturnType<LazySchemaBuilder<any, R>['introspect']>\n>;\n\n/**\n * Lazy schema builder class. Allows defining recursive/self-referential schemas\n * by wrapping a getter function that returns the target schema. The getter is\n * called once on first validation and the result is cached.\n *\n * This is the primary mechanism for building recursive data structures such as\n * tree nodes, nested menus, and threaded comments.\n *\n * **NOTE** TypeScript cannot infer recursive types automatically, so you must\n * provide an explicit type annotation on the variable holding the schema:\n *\n * @example\n * ```ts\n * type TreeNode = { value: number; children: TreeNode[] };\n *\n * const treeNode: SchemaBuilder<TreeNode, true> = object({\n * value: number(),\n * children: array(lazy(() => treeNode))\n * });\n *\n * treeNode.validate({ value: 1, children: [{ value: 2, children: [] }] });\n * // { valid: true, object: { value: 1, children: [{ value: 2, children: [] }] } }\n * ```\n *\n * @example\n * ```ts\n * type Comment = { text: string; replies: Comment[] };\n *\n * const commentSchema: SchemaBuilder<Comment, true> = object({\n * text: string(),\n * replies: array(lazy(() => commentSchema))\n * });\n * ```\n */\nexport class LazySchemaBuilder<\n TResult = any,\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n THasDefault extends boolean = false,\n TExtensions = {}\n> extends SchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n> {\n #getter: () => SchemaBuilder<TResult, any, any>;\n #resolvedSchema: SchemaBuilder<TResult, any, any> | null = null;\n\n /**\n * @hidden\n */\n public static create(props: LazySchemaBuilderCreateProps<any>) {\n return new LazySchemaBuilder({\n type: 'lazy',\n ...props\n });\n }\n\n protected constructor(props: LazySchemaBuilderCreateProps<TRequired>) {\n super(props as any);\n if (typeof (props as any).getter !== 'function') {\n throw new Error('LazySchemaBuilder: getter must be a function');\n }\n this.#getter = (props as any).getter;\n }\n\n /**\n * Resolves the lazy schema by calling the getter (once; result is cached).\n * After the first call subsequent calls return the cached schema instance.\n */\n public resolve(): SchemaBuilder<TResult, any, any> {\n if (this.#resolvedSchema === null) {\n this.#resolvedSchema = this.#getter();\n }\n return this.#resolvedSchema;\n }\n\n /**\n * @inheritdoc\n */\n public introspect() {\n return {\n ...super.introspect(),\n /**\n * The getter function that returns the lazily-resolved schema.\n * Call {@link LazySchemaBuilder.resolve} to obtain the schema instance.\n */\n getter: this.#getter\n };\n }\n\n #buildResult(\n superResult: ReturnType<LazySchemaBuilder['preValidateSync']>,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n const {\n valid,\n transaction: preValidationTransaction,\n errors\n } = superResult;\n\n if (!valid) {\n return { valid, errors };\n }\n\n const {\n object: { validatedObject: objToValidate }\n } = preValidationTransaction!;\n\n // Value is null/undefined and the schema is optional — skip delegation.\n if (objToValidate == null) {\n return { valid: true, object: objToValidate };\n }\n\n return this.resolve().validate(\n objToValidate,\n context\n ) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validate} */\n public validate(\n object: TResult,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return super.validate(object, context) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validateAsync} */\n public async validateAsync(\n object: TResult,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n return super.validateAsync(object, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n /**\n * Performs synchronous validation of the schema over `object`.\n * Throws if any preprocessor, validator, or error message provider returns a Promise.\n * @param context Optional `ValidationContext` settings.\n */\n protected _validate(\n object: TResult,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return this.#buildResult(\n this.preValidateSync(object, context),\n context\n );\n }\n\n /**\n * Performs async validation of the schema over `object`.\n * Supports async preprocessors, validators, and error message providers.\n * @param context Optional `ValidationContext` settings.\n */\n protected async _validateAsync(\n object: TResult,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n const superResult = await super.preValidateAsync(object, context);\n\n const {\n valid,\n transaction: preValidationTransaction,\n errors\n } = superResult;\n\n if (!valid) {\n return { valid, errors };\n }\n\n const {\n object: { validatedObject: objToValidate }\n } = preValidationTransaction!;\n\n if (objToValidate == null) {\n return { valid: true, object: objToValidate };\n }\n\n return this.resolve().validateAsync(objToValidate, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n protected createFromProps<TReq extends boolean>(\n props: LazySchemaBuilderCreateProps<TReq>\n ): this {\n return LazySchemaBuilder.create(props as any) as any;\n }\n\n /**\n * @inheritdoc\n */\n public hasType<T>(\n _notUsed?: T\n ): LazySchemaBuilder<T, true, TNullable, THasDefault, TExtensions> &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @inheritdoc\n */\n public clearHasType(): LazySchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public required(\n errorMessage?: ValidationErrorMessageProvider\n ): LazySchemaBuilder<TResult, true, TNullable, THasDefault, TExtensions> &\n TExtensions {\n return super.required(errorMessage);\n }\n\n /**\n * @hidden\n */\n public optional(): LazySchemaBuilder<\n TResult,\n false,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.optional();\n }\n\n /**\n * @hidden\n */\n public default(\n value: TResult | (() => TResult)\n ): LazySchemaBuilder<TResult, true, TNullable, true, TExtensions> &\n TExtensions {\n return super.default(value) as any;\n }\n\n /**\n * @hidden\n */\n public clearDefault(): LazySchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n false,\n TExtensions\n > &\n TExtensions {\n return super.clearDefault() as any;\n }\n\n /**\n * @hidden\n */\n public brand<TBrand extends string | symbol>(\n _name?: TBrand\n ): LazySchemaBuilder<\n TResult & { readonly [K in BRAND]: TBrand },\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.brand(_name);\n }\n\n /**\n * @hidden\n */\n public readonly(): LazySchemaBuilder<\n Readonly<TResult>,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.readonly();\n }\n\n /**\n * @hidden\n */\n public nullable(): LazySchemaBuilder<\n TResult,\n TRequired,\n true,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.nullable() as any;\n }\n\n /**\n * @hidden\n */\n public notNullable(): LazySchemaBuilder<\n TResult,\n TRequired,\n false,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.notNullable() as any;\n }\n}\n\n/**\n * Creates a lazy schema that defers the schema definition until first validation.\n * Use this to define recursive/self-referential schemas.\n *\n * The getter function is called **once** on first use and the result is cached.\n * You **must** provide an explicit TypeScript type annotation on the variable\n * holding the outer schema — TypeScript cannot infer recursive types automatically.\n *\n * @param getter - A function that returns the schema to use for validation.\n *\n * @example\n * ```ts\n * // Tree structure\n * type TreeNode = { value: number; children: TreeNode[] };\n *\n * const treeNode: SchemaBuilder<TreeNode, true> = object({\n * value: number(),\n * children: array(lazy(() => treeNode))\n * });\n * ```\n *\n * @example\n * ```ts\n * // Optional recursive field (submenu)\n * type MenuItem = { label: string; submenu?: MenuItem[] };\n *\n * const menuItem: SchemaBuilder<MenuItem, true> = object({\n * label: string(),\n * submenu: array(lazy(() => menuItem)).optional()\n * });\n * ```\n */\nexport function lazy<TResult>(\n getter: () => SchemaBuilder<TResult, any, any>\n): LazySchemaBuilder<TResult, true, false, false, {}> {\n return LazySchemaBuilder.create({\n type: 'lazy',\n isRequired: true,\n preprocessors: [],\n validators: [],\n getter\n } as any);\n}\n","import {\n type BRAND,\n SchemaBuilder,\n type ValidationContext,\n type ValidationErrorMessageProvider,\n type ValidationResult\n} from './SchemaBuilder.js';\n\ntype NullSchemaBuilderCreateProps<R extends boolean = true> = Partial<\n ReturnType<NullSchemaBuilder<R>['introspect']>\n>;\n\n/**\n * Schema builder for `null` values. Validates that the input is exactly `null`.\n *\n * When required (the default), only `null` is accepted. When optional (via\n * `.optional()`), both `null` and `undefined` are accepted; any other value\n * is rejected.\n *\n * This builder is useful when you need to represent an explicitly-null field\n * in a typed schema, for example in discriminated-union branches or when\n * modelling a JSON payload that may carry a JSON `null` value.\n *\n * **NOTE** this class is exported only to give opportunity to extend it\n * by inheriting. It is not recommended to create an instance of this class\n * directly. Use {@link nul | nul()} function instead.\n *\n * @example\n * ```ts\n * import { nul } from '@cleverbrush/schema';\n *\n * const schema = nul();\n *\n * schema.validate(null); // { valid: true, object: null }\n * schema.validate(undefined); // { valid: false }\n * schema.validate(0); // { valid: false }\n * schema.validate(''); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * // Optional — accepts null or undefined\n * const schema = nul().optional();\n *\n * schema.validate(null); // { valid: true, object: null }\n * schema.validate(undefined); // { valid: true, object: undefined }\n * schema.validate(false); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * // Use inside a union to model a nullable string field\n * import { union, string, nul, InferType } from '@cleverbrush/schema';\n *\n * const NullableString = union(string()).or(nul());\n * type NullableString = InferType<typeof NullableString>;\n * // string | null\n *\n * NullableString.validate('hello'); // valid\n * NullableString.validate(null); // valid\n * NullableString.validate(42); // invalid\n * ```\n *\n * @see {@link nul}\n */\nexport class NullSchemaBuilder<\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n TExplicitType = undefined,\n THasDefault extends boolean = false,\n TExtensions = {}\n> extends SchemaBuilder<null, TRequired, TNullable, THasDefault, TExtensions> {\n /**\n * @hidden\n */\n public static create(props: NullSchemaBuilderCreateProps<any>) {\n return new NullSchemaBuilder({\n type: 'null',\n ...props\n });\n }\n\n protected constructor(props: NullSchemaBuilderCreateProps<TRequired>) {\n super(props as any);\n }\n\n /**\n * @hidden\n */\n public hasType<T>(\n _notUsed?: T\n ): NullSchemaBuilder<true, TNullable, T, THasDefault, TExtensions> &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public clearHasType(): NullSchemaBuilder<\n TRequired,\n TNullable,\n undefined,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n // The SchemaBuilder base-class preValidateSync/preValidateAsync treats\n // null as an invalid value for required schemas, which would prevent null\n // from ever passing validation here. We therefore bypass preValidateSync\n // entirely and implement the full (and simple) validation inline.\n #buildResult(object: any): ValidationResult<null> {\n if (object === null) return { valid: true, object: null };\n\n if (object === undefined && this.hasDefault) {\n const defaultVal = this.resolveDefaultValue();\n if (defaultVal === null) return { valid: true, object: null };\n return { valid: false, errors: [{ message: 'must be null' }] };\n }\n\n if (object === undefined && !this.isRequired) {\n return { valid: true, object: undefined as any };\n }\n\n return {\n valid: false,\n errors: [{ message: 'must be null' }]\n };\n }\n\n /** {@inheritDoc SchemaBuilder.validate} */\n public validate(\n object: null,\n context?: ValidationContext\n ): ValidationResult<null> {\n return super.validate(object, context) as ValidationResult<null>;\n }\n\n /** {@inheritDoc SchemaBuilder.validateAsync} */\n public async validateAsync(\n object: null,\n context?: ValidationContext\n ): Promise<ValidationResult<null>> {\n return super.validateAsync(object, context) as Promise<\n ValidationResult<null>\n >;\n }\n\n /**\n * Performs synchronous validation of the schema over `object`.\n * @param context Optional `ValidationContext` settings.\n */\n protected _validate(\n object: null,\n _context?: ValidationContext\n ): ValidationResult<null> {\n return this.#buildResult(object);\n }\n\n /**\n * Performs async validation of the schema over `object`.\n * @param context Optional `ValidationContext` settings.\n */\n protected async _validateAsync(\n object: null,\n _context?: ValidationContext\n ): Promise<ValidationResult<null>> {\n return this.#buildResult(object);\n }\n\n protected createFromProps<TReq extends boolean>(\n props: NullSchemaBuilderCreateProps<TReq>\n ): this {\n return NullSchemaBuilder.create(props as any) as any;\n }\n\n /**\n * @hidden\n */\n public required(\n errorMessage?: ValidationErrorMessageProvider\n ): NullSchemaBuilder<\n true,\n TNullable,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.required(errorMessage);\n }\n\n /**\n * @hidden\n */\n public optional(): NullSchemaBuilder<\n false,\n TNullable,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.optional();\n }\n\n /**\n * @hidden\n */\n public default(\n value: null | (() => null)\n ): NullSchemaBuilder<true, TNullable, TExplicitType, true, TExtensions> &\n TExtensions {\n return super.default(value) as any;\n }\n\n /**\n * @hidden\n */\n public clearDefault(): NullSchemaBuilder<\n TRequired,\n TNullable,\n TExplicitType,\n false,\n TExtensions\n > &\n TExtensions {\n return super.clearDefault() as any;\n }\n\n /**\n * @hidden\n */\n public brand<TBrand extends string | symbol>(\n _name?: TBrand\n ): NullSchemaBuilder<\n TRequired,\n TNullable,\n null & { readonly [K in BRAND]: TBrand },\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.brand(_name);\n }\n\n /**\n * Marks the inferred type as `Readonly<null>`. Since `null` is already\n * immutable this is an identity operation, but it sets the `isReadonly`\n * introspection flag for tooling consistency.\n *\n * @see {@link SchemaBuilder.readonly}\n */\n public readonly(): NullSchemaBuilder<\n TRequired,\n TNullable,\n Readonly<null>,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.readonly();\n }\n\n /**\n * @hidden\n */\n public nullable(): NullSchemaBuilder<\n TRequired,\n true,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.nullable() as any;\n }\n\n /**\n * @hidden\n */\n public notNullable(): NullSchemaBuilder<\n TRequired,\n false,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.notNullable() as any;\n }\n}\n\n/**\n * Creates a schema that validates the value is exactly `null`.\n *\n * By default the schema is **required** — only `null` is accepted.\n * Call `.optional()` to also allow `undefined`.\n *\n * @example\n * ```ts\n * import { nul } from '@cleverbrush/schema';\n *\n * nul().validate(null); // { valid: true, object: null }\n * nul().validate(undefined); // { valid: false }\n * nul().validate(0); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * nul().optional().validate(null); // { valid: true, object: null }\n * nul().optional().validate(undefined); // { valid: true, object: undefined }\n * nul().optional().validate(false); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * // Nullable field in an object schema\n * import { object, string, nul, union, InferType } from '@cleverbrush/schema';\n *\n * const Schema = object({\n * name: string(),\n * deleted: union(nul()).or(string()), // null | string\n * });\n *\n * type T = InferType<typeof Schema>;\n * // { name: string; deleted: null | string }\n * ```\n */\nexport const nul = () =>\n NullSchemaBuilder.create({\n isRequired: true\n }) as NullSchemaBuilder<true>;\n","/**\n * @module extension\n *\n * The **extension system** for `@cleverbrush/schema` allows third-party and\n * first-party code to add custom methods to any schema builder type\n * (`string`, `number`, `date`, `object`, …) without modifying the core\n * library.\n *\n * ## Overview\n *\n * Extensions follow a two-step workflow:\n *\n * 1. **Define** an extension with {@link defineExtension} — declare which\n * builder types it targets and what methods it adds.\n * 2. **Apply** one or more extensions with {@link withExtensions} — get back\n * augmented factory functions (`string()`, `number()`, …) whose return\n * types include the new methods.\n *\n * ## Ergonomic authoring\n *\n * Extension methods do **not** need to call `withExtension()` manually.\n * The system automatically attaches metadata using the method name as the\n * extension key and the method arguments as the value. This keeps extension\n * definitions concise:\n *\n * ```ts\n * const slugExt = defineExtension({\n * string: {\n * slug(this: StringSchemaBuilder) {\n * return this.addValidator((val) => {\n * const valid = /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(val);\n * return { valid, errors: valid ? [] : [{ message: 'must be a valid URL slug' }] };\n * });\n * }\n * }\n * });\n * ```\n *\n * If you need **custom metadata** (e.g. a different key or a transformed\n * value), call `this.withExtension(key, value)` explicitly — the auto-infer\n * logic will detect the existing key and skip the automatic attachment.\n *\n * ## Stacking and composition\n *\n * Multiple extensions can target the same builder type. Pass them all to\n * `withExtensions()` and the methods are merged. A runtime error is thrown\n * if two extensions define the same method name on the same builder type.\n *\n * ```ts\n * const s = withExtensions(emailExt, slugExt, rangeExt);\n * const schema = s.string().email().slug(); // both methods available\n * ```\n *\n * ## Introspection\n *\n * Extension metadata is accessible via `schema.introspect().extensions`.\n * Each key corresponds to an extension method name and its value is whatever\n * was passed (or auto-inferred) as the extension data.\n *\n * @see {@link defineExtension} — define an extension\n * @see {@link withExtensions} — apply extensions to builder factories\n * @see {@link ExtensionConfig} — shape of the configuration object\n * @see {@link ExtensionDescriptor} — branded descriptor returned by `defineExtension`\n */\nimport { AnySchemaBuilder, any } from './builders/AnySchemaBuilder.js';\nimport { ArraySchemaBuilder, array } from './builders/ArraySchemaBuilder.js';\nimport {\n BooleanSchemaBuilder,\n boolean\n} from './builders/BooleanSchemaBuilder.js';\nimport { DateSchemaBuilder, date } from './builders/DateSchemaBuilder.js';\nimport {\n FunctionSchemaBuilder,\n func\n} from './builders/FunctionSchemaBuilder.js';\nimport {\n GenericSchemaBuilder,\n generic\n} from './builders/GenericSchemaBuilder.js';\nimport { NumberSchemaBuilder, number } from './builders/NumberSchemaBuilder.js';\nimport { ObjectSchemaBuilder, object } from './builders/ObjectSchemaBuilder.js';\nimport {\n PromiseSchemaBuilder,\n promise\n} from './builders/PromiseSchemaBuilder.js';\nimport { RecordSchemaBuilder, record } from './builders/RecordSchemaBuilder.js';\nimport type { SchemaBuilder } from './builders/SchemaBuilder.js';\nimport { StringSchemaBuilder, string } from './builders/StringSchemaBuilder.js';\nimport { TupleSchemaBuilder, tuple } from './builders/TupleSchemaBuilder.js';\nimport { UnionSchemaBuilder, union } from './builders/UnionSchemaBuilder.js';\n\n// ---------------------------------------------------------------------------\n// Builder type name mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Maps each builder type name to the corresponding generic builder class.\n *\n * Used internally to type-check extension method `this` bindings — for\n * example, an extension targeting `\"string\"` receives `this: StringSchemaBuilder`.\n *\n * @internal Not exported — used only by the extension type machinery.\n */\ntype BuilderMap = {\n string: StringSchemaBuilder<any, any, any, any, any>;\n number: NumberSchemaBuilder<any, any, any, any, any>;\n boolean: BooleanSchemaBuilder<any, any, any, any, any, any, any>;\n date: DateSchemaBuilder<any, any, any, any, any>;\n object: ObjectSchemaBuilder<any, any, any, any, any, any, any>;\n array: ArraySchemaBuilder<any, any, any, any, any, any, any>;\n tuple: TupleSchemaBuilder<any, any, any, any, any, any, any>;\n record: RecordSchemaBuilder<any, any, any, any, any, any, any>;\n union: UnionSchemaBuilder<any, any, any, any, any, any>;\n func: FunctionSchemaBuilder<any, any, any, any, any>;\n any: AnySchemaBuilder<any, any, any, any, any, any>;\n promise: PromiseSchemaBuilder<any, any, any, any, any>;\n generic: GenericSchemaBuilder<any, any, any, any, any, any>;\n};\n\ntype BuilderTypeName = keyof BuilderMap;\n\n// Runtime mapping from type name to the actual class constructor\nconst builderClasses: Record<BuilderTypeName, typeof SchemaBuilder> = {\n string: StringSchemaBuilder as any,\n number: NumberSchemaBuilder as any,\n boolean: BooleanSchemaBuilder as any,\n date: DateSchemaBuilder as any,\n object: ObjectSchemaBuilder as any,\n array: ArraySchemaBuilder as any,\n tuple: TupleSchemaBuilder as any,\n record: RecordSchemaBuilder as any,\n union: UnionSchemaBuilder as any,\n func: FunctionSchemaBuilder as any,\n any: AnySchemaBuilder as any,\n promise: PromiseSchemaBuilder as any,\n generic: GenericSchemaBuilder as any\n};\n\n// Runtime mapping from type name to factory function\nconst builderFactories: Record<BuilderTypeName, (...args: any[]) => any> = {\n string,\n number,\n boolean,\n date,\n object,\n array,\n tuple,\n record,\n union,\n func,\n any,\n promise,\n generic\n};\n\n// ---------------------------------------------------------------------------\n// Extension configuration types\n// ---------------------------------------------------------------------------\n\n/**\n * Defines the shape of an extension configuration object passed to\n * {@link defineExtension}.\n *\n * Each key is a **builder type name** — one of `\"string\"`, `\"number\"`,\n * `\"boolean\"`, `\"date\"`, `\"object\"`, `\"array\"`, `\"union\"`, `\"func\"`, or\n * `\"any\"`. The value is a record of **method implementations** to add to\n * that builder type.\n *\n * Method implementations receive `this` bound to the target builder instance\n * (e.g. `StringSchemaBuilder` for the `\"string\"` key) and **must** return a\n * builder of the same type to support fluent chaining.\n *\n * @remarks\n * Extension methods that only add validators/preprocessors do not need to\n * call `this.withExtension()` — the system will auto-attach metadata using\n * the method name as the key and the arguments as the value. Call\n * `this.withExtension(key, value)` explicitly only when you need custom\n * metadata (e.g. a transformed value or a different key).\n *\n * @example\n * ```ts\n * // Minimal extension config — auto-inferred metadata\n * const config: ExtensionConfig = {\n * string: {\n * slug(this: StringSchemaBuilder) {\n * return this.addValidator((v) => ({ valid: /^[a-z0-9-]+$/.test(v), errors: [] }));\n * }\n * },\n * number: {\n * port(this: NumberSchemaBuilder) {\n * return this.isInteger().min(1).max(65535);\n * }\n * }\n * };\n * ```\n *\n * @see {@link defineExtension}\n */\nexport type ExtensionConfig = {\n [K in BuilderTypeName]?: Record<\n string,\n (this: BuilderMap[K], ...args: any[]) => any\n >;\n};\n\n/**\n * A branded descriptor returned by {@link defineExtension}.\n *\n * The descriptor captures the extension's method signatures at the **type\n * level** so that {@link withExtensions} can produce correctly-typed factory\n * functions. At runtime it holds the (possibly wrapped) configuration object.\n *\n * Extension descriptors are intentionally **opaque** — consumers should not\n * access `config` directly. Instead, pass descriptors to\n * {@link withExtensions} to obtain augmented builder factories.\n *\n * @typeParam T - The concrete {@link ExtensionConfig} shape. Inferred\n * automatically by `defineExtension`; you rarely need to specify it.\n *\n * @example\n * ```ts\n * // The type is inferred — no need to annotate\n * const myExt: ExtensionDescriptor<{ string: { slug: ... } }> = defineExtension({ ... });\n * ```\n *\n * @see {@link defineExtension}\n * @see {@link withExtensions}\n */\nexport type ExtensionDescriptor<T extends ExtensionConfig = ExtensionConfig> = {\n readonly __brand: unique symbol;\n readonly config: T;\n};\n\n// ---------------------------------------------------------------------------\n// Type-level extraction of extension methods per builder type\n// ---------------------------------------------------------------------------\n\n/** Extracts the method signatures an extension adds to a given builder type. */\ntype ExtractMethods<\n TExt extends ExtensionConfig,\n TType extends BuilderTypeName\n> =\n TExt[TType] extends Record<string, (...args: any[]) => any>\n ? TExt[TType]\n : {};\n\n/** Merges the methods from multiple extensions for a given builder type. */\ntype MergeExtensionMethods<\n TExts extends readonly ExtensionDescriptor<any>[],\n TType extends BuilderTypeName\n> = TExts extends readonly [\n ExtensionDescriptor<infer TFirst>,\n ...infer TRest extends readonly ExtensionDescriptor<any>[]\n]\n ? ExtractMethods<TFirst, TType> & MergeExtensionMethods<TRest, TType>\n : {};\n\n// ---------------------------------------------------------------------------\n// Return types for withExtensions()\n// ---------------------------------------------------------------------------\n\n/**\n * Intersected onto consumer-facing builder types to make `withExtension`\n * and `getExtension` uncallable (`never`). Using an intersection instead\n * of `Omit` preserves the class identity so extended builders remain\n * assignable to `SchemaBuilder<any, any, any, any, any>`.\n */\nexport type HiddenExtensionMethods = {\n /** @internal Extension-author only — use inside `defineExtension()`. */\n withExtension: never;\n /** @internal Extension-author only — use inside `defineExtension()`. */\n getExtension: never;\n};\n\n/**\n * Overrides extension method return types so they always return the full\n * extended builder type. This ensures extension methods preserve all other\n * extension methods through chaining (e.g. `s.string().email().slug()`).\n *\n * The self-reference (`FixedMethods` appears in its own mapped return\n * types) is resolved lazily by TypeScript because the recursion sits\n * inside a function-return position within a conditional mapped type.\n */\nexport type FixedMethods<TRawMethods, TBase> = {\n [K in keyof TRawMethods]: TRawMethods[K] extends (\n this: any,\n ...args: infer A\n ) => any\n ? (\n ...args: A\n ) => TBase & FixedMethods<TRawMethods, TBase> & HiddenExtensionMethods\n : TRawMethods[K];\n};\n\n/**\n * Produces the consumer-facing type for an extended builder: the base\n * builder intersected with its fixed extension methods, with\n * `withExtension` / `getExtension` overridden to `never` so they\n * don't appear as callable in consumer code.\n */\nexport type CleanExtended<TBuilder, TExt> = TBuilder &\n FixedMethods<TExt, TBuilder> &\n HiddenExtensionMethods;\n\n// -- Factory types that return builders with corrected extension methods ------\n\ntype ExtendedStringFactory<TExt> = {\n (): CleanExtended<\n StringSchemaBuilder<string, true, false, false, TExt>,\n TExt\n >;\n <T extends string>(\n equals: T\n ): CleanExtended<StringSchemaBuilder<T, true, false, false, TExt>, TExt>;\n};\n\ntype ExtendedNumberFactory<TExt> = {\n (): CleanExtended<\n NumberSchemaBuilder<number, true, false, false, TExt>,\n TExt\n >;\n <T extends number>(\n equals: T\n ): CleanExtended<NumberSchemaBuilder<T, true, false, false, TExt>, TExt>;\n};\n\ntype ExtendedBooleanFactory<TExt> = () => CleanExtended<\n BooleanSchemaBuilder<boolean, true, false, undefined, false, TExt>,\n TExt\n>;\n\ntype ExtendedDateFactory<TExt> = () => CleanExtended<\n DateSchemaBuilder<Date, true, false, false, TExt>,\n TExt\n>;\n\ntype ExtendedObjectFactory<TExt> = <\n P extends Record<string, SchemaBuilder<any, any, any, any, any>>\n>(\n properties?: P\n) => CleanExtended<\n ObjectSchemaBuilder<P, true, false, undefined, false, TExt, []>,\n TExt\n>;\n\ntype ExtendedArrayFactory<TExt> = <\n TElementSchema extends SchemaBuilder<any, any, any, any, any>\n>(\n elementSchema?: TElementSchema\n) => CleanExtended<\n ArraySchemaBuilder<TElementSchema, true, false, undefined, false, TExt>,\n TExt\n>;\n\ntype ExtendedUnionFactory<TExt> = <\n T extends SchemaBuilder<any, any, any, any, any>\n>(\n schema: T\n) => CleanExtended<\n UnionSchemaBuilder<[T], true, false, undefined, false, TExt>,\n TExt\n>;\n\ntype ExtendedFuncFactory<TExt> = () => CleanExtended<\n FunctionSchemaBuilder<true, false, undefined, false, TExt>,\n TExt\n>;\n\ntype ExtendedAnyFactory<TExt> = () => CleanExtended<\n AnySchemaBuilder<true, false, undefined, false, TExt>,\n TExt\n>;\n\ntype ExtendedTupleFactory<TExt> = <\n const TElements extends readonly SchemaBuilder<any, any, any, any, any>[]\n>(\n elements: [...TElements]\n) => CleanExtended<\n TupleSchemaBuilder<TElements, true, false, undefined, false, TExt>,\n TExt\n>;\n\ntype ExtendedRecordFactory<TExt> = <\n TKeySchema extends StringSchemaBuilder<any, any, any, any>,\n TValueSchema extends SchemaBuilder<any, any, any, any, any>\n>(\n keySchema: TKeySchema,\n valueSchema: TValueSchema\n) => CleanExtended<\n RecordSchemaBuilder<\n TKeySchema,\n TValueSchema,\n true,\n false,\n undefined,\n false,\n TExt\n >,\n TExt\n>;\n\ntype ExtendedPromiseFactory<TExt> = <\n TSchema extends SchemaBuilder<any, any, any, any, any>\n>(\n resolvedTypeSchema?: TSchema\n) => CleanExtended<\n PromiseSchemaBuilder<true, false, undefined, false, TExt, TSchema>,\n TExt\n>;\n\ntype ExtendedGenericFactory<TExt> = <\n TFn extends (...args: any[]) => SchemaBuilder<any, any, any, any, any>\n>(\n templateFn: TFn\n) => CleanExtended<\n GenericSchemaBuilder<TFn, true, false, undefined, false, TExt>,\n TExt\n>;\n\n/**\n * The return type of {@link withExtensions}.\n *\n * Contains a factory function for every builder type (`string`, `number`,\n * `boolean`, `date`, `object`, `array`, `union`, `func`, `any`). Each\n * factory returns a builder whose type includes the methods contributed\n * by all provided extension descriptors.\n *\n * @typeParam TExts - Tuple of extension descriptors passed to `withExtensions`.\n *\n * @see {@link withExtensions}\n */\ntype WithExtensionsResult<TExts extends readonly ExtensionDescriptor<any>[]> = {\n string: ExtendedStringFactory<MergeExtensionMethods<TExts, 'string'>>;\n number: ExtendedNumberFactory<MergeExtensionMethods<TExts, 'number'>>;\n boolean: ExtendedBooleanFactory<MergeExtensionMethods<TExts, 'boolean'>>;\n date: ExtendedDateFactory<MergeExtensionMethods<TExts, 'date'>>;\n object: ExtendedObjectFactory<MergeExtensionMethods<TExts, 'object'>>;\n array: ExtendedArrayFactory<MergeExtensionMethods<TExts, 'array'>>;\n tuple: ExtendedTupleFactory<MergeExtensionMethods<TExts, 'tuple'>>;\n record: ExtendedRecordFactory<MergeExtensionMethods<TExts, 'record'>>;\n union: ExtendedUnionFactory<MergeExtensionMethods<TExts, 'union'>>;\n func: ExtendedFuncFactory<MergeExtensionMethods<TExts, 'func'>>;\n any: ExtendedAnyFactory<MergeExtensionMethods<TExts, 'any'>>;\n promise: ExtendedPromiseFactory<MergeExtensionMethods<TExts, 'promise'>>;\n generic: ExtendedGenericFactory<MergeExtensionMethods<TExts, 'generic'>>;\n};\n\n// ---------------------------------------------------------------------------\n// Reserved method names — cannot be overridden by extensions\n// ---------------------------------------------------------------------------\n\n/**\n * Method names on `SchemaBuilder` that extensions are **not** allowed to\n * override. An error is thrown at definition time if an extension tries\n * to use any of these names.\n *\n * @internal\n */\nconst RESERVED_METHODS = new Set([\n 'validate',\n 'validateAsync',\n 'parse',\n 'parseAsync',\n 'safeParse',\n 'safeParseAsync',\n 'introspect',\n 'optional',\n 'required',\n 'addPreprocessor',\n 'clearPreprocessors',\n 'addValidator',\n 'clearValidators',\n 'hasType',\n 'clearHasType',\n 'createFromProps',\n 'preValidate',\n 'preValidateSync',\n 'preValidateAsync',\n 'getValidationErrorMessage',\n 'getValidationErrorMessageSync',\n 'assureValidationErrorMessageProvider',\n 'withExtension',\n 'getExtension'\n]);\n\n// ---------------------------------------------------------------------------\n// defineExtension()\n// ---------------------------------------------------------------------------\n\n/**\n * Defines an extension targeting one or more schema builder types.\n *\n * Each extension is a plain object keyed by builder type name (`\"string\"`,\n * `\"number\"`, `\"date\"`, …) whose values are method implementations.\n * Methods receive `this` bound to the builder instance and must return a\n * builder to support fluent chaining.\n *\n * ## Ergonomic metadata (auto-infer)\n *\n * Extension methods **do not** have to call `this.withExtension()`. The\n * system wraps each method and automatically attaches\n * `withExtension(methodName, args)` to the returned builder when the key\n * is not already present. This eliminates the most common source of\n * duplication in extension code.\n *\n * - **Zero-arg methods** → metadata value is `true`\n * - **Single-arg methods** → metadata value is the argument itself\n * - **Multi-arg methods** → metadata value is the arguments array\n *\n * If you need **custom metadata** (e.g. a different key, a transformed\n * value, or a structured object), call `this.withExtension(key, value)`\n * explicitly inside the method — the auto-infer logic detects the existing\n * key and skips automatic attachment.\n *\n * ## Validation\n *\n * `defineExtension` validates the configuration eagerly:\n * - Unknown builder type names throw immediately.\n * - {@link RESERVED_METHODS | Reserved method names} (e.g. `validate`,\n * `introspect`) cannot be overridden.\n * - Non-function values in the method record are rejected.\n *\n * @param config - An {@link ExtensionConfig} object mapping builder type\n * names to method records.\n * @returns A branded {@link ExtensionDescriptor} ready to pass to\n * {@link withExtensions}.\n *\n * @example Simple extension (auto-inferred metadata)\n * ```ts\n * const slugExt = defineExtension({\n * string: {\n * slug(this: StringSchemaBuilder) {\n * return this.addValidator((val) => {\n * const valid = /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(val);\n * return { valid, errors: valid ? [] : [{ message: 'invalid slug' }] };\n * });\n * }\n * }\n * });\n *\n * // Usage:\n * const s = withExtensions(slugExt);\n * const schema = s.string().slug();\n * schema.introspect().extensions.slug; // true\n * ```\n *\n * @example Extension with custom metadata\n * ```ts\n * const currencyExt = defineExtension({\n * number: {\n * currency(this: NumberSchemaBuilder, opts?: { maxDecimals?: number }) {\n * const maxDec = opts?.maxDecimals ?? 2;\n * return this.withExtension('currency', { maxDecimals: maxDec })\n * .min(0)\n * .addValidator((val) => {\n * const decimals = (String(val).split('.')[1] ?? '').length;\n * const valid = decimals <= maxDec;\n * return { valid, errors: valid ? [] : [{ message: `max ${maxDec} decimals` }] };\n * });\n * }\n * }\n * });\n * ```\n *\n * @example Multi-builder extension\n * ```ts\n * const myExt = defineExtension({\n * string: {\n * email(this: StringSchemaBuilder) { return this.addValidator(...); }\n * },\n * number: {\n * port(this: NumberSchemaBuilder) { return this.isInteger().min(1).max(65535); }\n * }\n * });\n * ```\n *\n * @throws {Error} If a builder type name is unknown.\n * @throws {Error} If a method name is reserved.\n * @throws {Error} If a method value is not a function.\n *\n * @see {@link withExtensions} — apply the defined extension\n * @see {@link ExtensionConfig} — configuration shape\n */\nexport function defineExtension<T extends ExtensionConfig>(\n config: T\n): ExtensionDescriptor<T> {\n // Validate at definition time and wrap methods for auto-infer extension key\n const wrappedConfig: any = {};\n for (const builderName of Object.keys(config) as BuilderTypeName[]) {\n if (!(builderName in builderClasses)) {\n throw new Error(\n `Unknown builder type \"${builderName}\". Valid types: ${Object.keys(builderClasses).join(', ')}`\n );\n }\n\n const methods = config[builderName];\n if (!methods || typeof methods !== 'object') {\n throw new Error(\n `Extension config for \"${builderName}\" must be an object of methods`\n );\n }\n\n wrappedConfig[builderName] = {};\n for (const methodName of Object.keys(methods)) {\n if (RESERVED_METHODS.has(methodName)) {\n throw new Error(\n `Cannot override reserved method \"${methodName}\" on \"${builderName}\"`\n );\n }\n const origMethod = methods[methodName];\n if (typeof origMethod !== 'function') {\n throw new Error(\n `Extension method \"${builderName}.${methodName}\" must be a function`\n );\n }\n // Wrap the method to auto-infer extension key if not already set\n wrappedConfig[builderName][methodName] = function (\n this: any,\n ...args: any[]\n ) {\n const result = (origMethod as any).apply(this, args);\n // If result is a builder and does not have the extension key, auto-apply withExtension\n if (\n result &&\n typeof result === 'object' &&\n typeof result.withExtension === 'function' &&\n // Only auto-apply if the extension key is not already present\n (typeof result.getExtension !== 'function' ||\n result.getExtension(methodName) === undefined)\n ) {\n // Only auto-apply if the original method did not call withExtension\n return result.withExtension(\n methodName,\n args.length === 1\n ? args[0]\n : args.length === 0\n ? true\n : args\n );\n }\n return result;\n };\n }\n }\n\n return { config: wrappedConfig } as ExtensionDescriptor<T>;\n}\n\n// ---------------------------------------------------------------------------\n// withExtensions()\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a set of schema factory functions with the provided extensions\n * applied.\n *\n * Each factory function (`string()`, `number()`, `date()`, …) returned by\n * `withExtensions` produces builder instances whose prototypes include the\n * extension methods. All built-in builder methods remain available and\n * fully chainable alongside the new ones.\n *\n * ## Stacking multiple extensions\n *\n * Pass any number of {@link ExtensionDescriptor}s — their methods are\n * merged per builder type. If two extensions define the **same** method\n * name on the same builder type, a runtime error is thrown to prevent\n * silent conflicts.\n *\n * ## Type safety\n *\n * The return type is fully inferred: TypeScript knows exactly which\n * extension methods are available on each builder factory. Extension\n * methods return the full extended builder type, so chaining like\n * `s.string().email().slug().minLength(3)` is fully typed.\n *\n * ## Builder types without extensions\n *\n * Builders that have no methods from any of the provided extensions\n * use the standard (unextended) factory, so there is zero overhead.\n *\n * @param extensions - One or more {@link ExtensionDescriptor}s created\n * by {@link defineExtension}.\n * @returns An object with factory functions for all builder types\n * (`string`, `number`, `boolean`, `date`, `object`, `array`, `union`,\n * `func`, `any`), each returning augmented builders.\n *\n * @example Basic usage\n * ```ts\n * const s = withExtensions(emailExt, rangeExt);\n *\n * // string() now has .email()\n * const emailSchema = s.string().email().minLength(5);\n *\n * // number() now has .range()\n * const rangeSchema = s.number().range(0, 100);\n *\n * // builders without targeted extensions work as normal\n * const dateSchema = s.date();\n * ```\n *\n * @example Stacking extensions on the same builder\n * ```ts\n * const s = withExtensions(emailExt, slugExt, trimmedExt);\n * const schema = s.string().email().slug().trimmed();\n * ```\n *\n * @example Using extensions in object schemas\n * ```ts\n * const s = withExtensions(emailExt, portExt);\n * const ServerConfig = s.object({\n * host: s.string().email(),\n * port: s.number().port()\n * });\n * ```\n *\n * @throws {Error} If two extensions define the same method name on the\n * same builder type.\n *\n * @see {@link defineExtension} — create extension descriptors\n * @see {@link ExtensionDescriptor}\n */\nexport function withExtensions<\n const TExts extends readonly ExtensionDescriptor<any>[]\n>(...extensions: TExts): WithExtensionsResult<TExts> {\n // Collect all methods per builder type and check for collisions\n const methodsByBuilder = new Map<BuilderTypeName, Map<string, Function>>();\n\n for (const ext of extensions) {\n for (const builderName of Object.keys(\n ext.config\n ) as BuilderTypeName[]) {\n if (!methodsByBuilder.has(builderName)) {\n methodsByBuilder.set(builderName, new Map());\n }\n const methods = methodsByBuilder.get(builderName)!;\n const extMethods = ext.config[builderName]!;\n\n for (const methodName of Object.keys(extMethods)) {\n if (methods.has(methodName)) {\n throw new Error(\n `Extension method collision: \"${methodName}\" is defined by multiple extensions for \"${builderName}\"`\n );\n }\n methods.set(methodName, extMethods[methodName]);\n }\n }\n }\n\n // For each builder type, create a dynamic subclass if there are extension methods\n const factories: Record<string, (...args: any[]) => any> = {};\n\n for (const builderName of Object.keys(\n builderClasses\n ) as BuilderTypeName[]) {\n const methods = methodsByBuilder.get(builderName);\n\n if (!methods || methods.size === 0) {\n // No extensions for this builder type — use the standard factory\n factories[builderName] = builderFactories[builderName];\n continue;\n }\n\n const BaseClass = builderClasses[builderName] as any;\n\n // Create a dynamic subclass\n const ExtendedClass = class extends BaseClass {\n // biome-ignore lint/complexity/noUselessConstructor: required\n constructor(...args: any[]) {\n super(...args);\n }\n\n static create(props: any) {\n return new ExtendedClass({\n ...props\n });\n }\n\n protected createFromProps(props: any): any {\n return ExtendedClass.create(props);\n }\n };\n\n // Add extension methods to the subclass prototype\n for (const [methodName, methodFn] of methods) {\n Object.defineProperty(ExtendedClass.prototype, methodName, {\n value: methodFn,\n writable: true,\n configurable: true,\n enumerable: false\n });\n }\n\n // Create a factory that uses the extended class\n factories[builderName] = (...args: any[]) => {\n // Delegate to the original factory to get an initialized instance,\n // then upgrade its prototype so it gains the extension methods.\n // Note: Object.setPrototypeOf can cause V8 hidden-class deoptimization\n // on the mutated object, but avoids the double allocation and\n // introspect() round-trip of the previous approach.\n const original = builderFactories[builderName](...args);\n Object.setPrototypeOf(original, ExtendedClass.prototype);\n return original;\n };\n }\n\n return factories as WithExtensionsResult<TExts>;\n}\n"],"mappings":"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","names":["GenericSchemaBuilder","_GenericSchemaBuilder","SchemaBuilder","#templateFn","#defaults","#cachedDefaultSchema","props","args","#getOrCreateDefaultSchema","#buildResult","superResult","context","valid","preValidationTransaction","errors","objToValidate","defaultSchema","#buildAsyncResult","object","_notUsed","errorMessage","value","_name","generic","fnOrDefaults","templateFn","fn","defaults","LazySchemaBuilder","_LazySchemaBuilder","SchemaBuilder","#getter","#resolvedSchema","props","#buildResult","superResult","context","valid","preValidationTransaction","errors","objToValidate","object","_notUsed","errorMessage","value","_name","lazy","getter","NullSchemaBuilder","_NullSchemaBuilder","SchemaBuilder","props","_notUsed","#buildResult","object","context","_context","errorMessage","value","_name","nul","builderClasses","StringSchemaBuilder","NumberSchemaBuilder","BooleanSchemaBuilder","DateSchemaBuilder","ObjectSchemaBuilder","ArraySchemaBuilder","TupleSchemaBuilder","RecordSchemaBuilder","UnionSchemaBuilder","FunctionSchemaBuilder","AnySchemaBuilder","PromiseSchemaBuilder","GenericSchemaBuilder","builderFactories","string","number","boolean","date","object","array","tuple","record","union","func","any","promise","generic","RESERVED_METHODS","defineExtension","config","wrappedConfig","builderName","methods","methodName","origMethod","args","result","withExtensions","extensions","methodsByBuilder","ext","extMethods","factories","BaseClass","ExtendedClass","props","methodFn","original"]}