@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.
- package/README.md +35 -2
- package/dist/builders/AnySchemaBuilder.js +1 -1
- package/dist/builders/ArraySchemaBuilder.js +1 -1
- package/dist/builders/BooleanSchemaBuilder.js +1 -1
- package/dist/builders/DateSchemaBuilder.js +1 -1
- package/dist/builders/ExternSchemaBuilder.js +1 -1
- package/dist/builders/FunctionSchemaBuilder.js +1 -1
- package/dist/builders/IntersectionSchemaBuilder.d.ts +124 -0
- package/dist/builders/NumberSchemaBuilder.js +1 -1
- package/dist/builders/ObjectSchemaBuilder.js +1 -1
- package/dist/builders/ParseStringSchemaBuilder.d.ts +9 -0
- package/dist/builders/ParseStringSchemaBuilder.js +1 -1
- package/dist/builders/PromiseSchemaBuilder.js +1 -1
- package/dist/builders/RecordSchemaBuilder.js +1 -1
- package/dist/builders/SchemaBuilder.d.ts +13 -7
- package/dist/builders/StringSchemaBuilder.js +1 -1
- package/dist/builders/TupleSchemaBuilder.js +1 -1
- package/dist/builders/UnionSchemaBuilder.js +1 -1
- package/dist/chunk-54RHS4F4.js +2 -0
- package/dist/chunk-54RHS4F4.js.map +1 -0
- package/dist/{chunk-K6Z47OQY.js → chunk-6LSN7NXQ.js} +2 -2
- package/dist/{chunk-WQDYWDOE.js → chunk-C6YQOKWB.js} +2 -2
- package/dist/{chunk-BUEVZ3KA.js → chunk-ELPPAHNO.js} +2 -2
- package/dist/{chunk-QARCEYGO.js → chunk-G424M7GI.js} +2 -2
- package/dist/{chunk-WDMJBGBD.js → chunk-JUFZ7PLO.js} +2 -2
- package/dist/{chunk-ZC6YBKCP.js → chunk-K4ZLXLE2.js} +2 -2
- package/dist/{chunk-NUW3VXZV.js → chunk-KC45JEFL.js} +2 -2
- package/dist/{chunk-EIVZX4ZO.js → chunk-NF4CRFMN.js} +2 -2
- package/dist/{chunk-YQZHDMRF.js → chunk-ORV2G6ZL.js} +2 -2
- package/dist/{chunk-CFIJQ4GP.js → chunk-PQINUGZW.js} +2 -2
- package/dist/chunk-REYZ7G7J.js +2 -0
- package/dist/chunk-REYZ7G7J.js.map +1 -0
- package/dist/chunk-VSU5GILY.js +2 -0
- package/dist/chunk-VSU5GILY.js.map +1 -0
- package/dist/chunk-XHSBY2QK.js +2 -0
- package/dist/chunk-XHSBY2QK.js.map +1 -0
- package/dist/{chunk-ZFI27R3L.js → chunk-XL723XFL.js} +2 -2
- package/dist/{chunk-HN774HD7.js → chunk-XPLTW5DI.js} +2 -2
- package/dist/{chunk-PHE4LIAN.js → chunk-YAOZEA2R.js} +2 -2
- package/dist/core.d.ts +4 -2
- package/dist/core.js +1 -1
- package/dist/extension.d.ts +76 -4
- package/dist/extension.js +2 -0
- package/dist/extension.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/dist/chunk-3JMDGYDT.js +0 -2
- package/dist/chunk-3JMDGYDT.js.map +0 -1
- package/dist/chunk-DY7J6RNN.js +0 -2
- package/dist/chunk-DY7J6RNN.js.map +0 -1
- package/dist/chunk-GXPV6UQK.js +0 -2
- package/dist/chunk-GXPV6UQK.js.map +0 -1
- /package/dist/{chunk-K6Z47OQY.js.map → chunk-6LSN7NXQ.js.map} +0 -0
- /package/dist/{chunk-WQDYWDOE.js.map → chunk-C6YQOKWB.js.map} +0 -0
- /package/dist/{chunk-BUEVZ3KA.js.map → chunk-ELPPAHNO.js.map} +0 -0
- /package/dist/{chunk-QARCEYGO.js.map → chunk-G424M7GI.js.map} +0 -0
- /package/dist/{chunk-WDMJBGBD.js.map → chunk-JUFZ7PLO.js.map} +0 -0
- /package/dist/{chunk-ZC6YBKCP.js.map → chunk-K4ZLXLE2.js.map} +0 -0
- /package/dist/{chunk-NUW3VXZV.js.map → chunk-KC45JEFL.js.map} +0 -0
- /package/dist/{chunk-EIVZX4ZO.js.map → chunk-NF4CRFMN.js.map} +0 -0
- /package/dist/{chunk-YQZHDMRF.js.map → chunk-ORV2G6ZL.js.map} +0 -0
- /package/dist/{chunk-CFIJQ4GP.js.map → chunk-PQINUGZW.js.map} +0 -0
- /package/dist/{chunk-ZFI27R3L.js.map → chunk-XL723XFL.js.map} +0 -0
- /package/dist/{chunk-HN774HD7.js.map → chunk-XPLTW5DI.js.map} +0 -0
- /package/dist/{chunk-PHE4LIAN.js.map → chunk-YAOZEA2R.js.map} +0 -0
package/dist/extension.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ import { NumberSchemaBuilder } from './builders/NumberSchemaBuilder.js';
|
|
|
72
72
|
import { ObjectSchemaBuilder } from './builders/ObjectSchemaBuilder.js';
|
|
73
73
|
import { PromiseSchemaBuilder } from './builders/PromiseSchemaBuilder.js';
|
|
74
74
|
import { RecordSchemaBuilder } from './builders/RecordSchemaBuilder.js';
|
|
75
|
-
import type { SchemaBuilder } from './builders/SchemaBuilder.js';
|
|
75
|
+
import type { PropertyDescriptorTree, SchemaBuilder } from './builders/SchemaBuilder.js';
|
|
76
76
|
import { StringSchemaBuilder } from './builders/StringSchemaBuilder.js';
|
|
77
77
|
import { TupleSchemaBuilder } from './builders/TupleSchemaBuilder.js';
|
|
78
78
|
import { UnionSchemaBuilder } from './builders/UnionSchemaBuilder.js';
|
|
@@ -176,6 +176,46 @@ type MergeExtensionMethods<TExts extends readonly ExtensionDescriptor<any>[], TT
|
|
|
176
176
|
ExtensionDescriptor<infer TFirst>,
|
|
177
177
|
...infer TRest extends readonly ExtensionDescriptor<any>[]
|
|
178
178
|
] ? ExtractMethods<TFirst, TType> & MergeExtensionMethods<TRest, TType> : {};
|
|
179
|
+
/**
|
|
180
|
+
* Unique string-literal brand key used by {@link FixedMethods} to detect
|
|
181
|
+
* extension methods whose first-argument literal should be accumulated in the
|
|
182
|
+
* return type.
|
|
183
|
+
*
|
|
184
|
+
* Declare the return type of any extension method as
|
|
185
|
+
* `this & { readonly [METHOD_LITERAL_BRAND]?: N }` (where `N extends string`)
|
|
186
|
+
* and `FixedMethods` will automatically make it generic so the literal name
|
|
187
|
+
* flows through the type system and accumulates across multiple calls.
|
|
188
|
+
*
|
|
189
|
+
* This powers scope-name autocomplete in `SchemaQueryBuilder.scoped()`.
|
|
190
|
+
*/
|
|
191
|
+
declare const METHOD_LITERAL_BRAND: "__cleverbrush_method_literal_brand__";
|
|
192
|
+
export { METHOD_LITERAL_BRAND };
|
|
193
|
+
export type MethodLiteralBrandSymbol = typeof METHOD_LITERAL_BRAND;
|
|
194
|
+
/**
|
|
195
|
+
* Generic accumulator brand for extension methods that want to thread
|
|
196
|
+
* a `Record<name, readonly string[]>` map through the builder chain.
|
|
197
|
+
*
|
|
198
|
+
* Extension authors can declare a method's return type as
|
|
199
|
+
* `this & { readonly [EXTRA_TYPE_BRAND]?: { [name]: TKeys } }`
|
|
200
|
+
* and {@link FixedMethods} will automatically:
|
|
201
|
+
* - Make the first argument const-generic (to capture the literal name).
|
|
202
|
+
* - Make the second argument const-generic when it is a `readonly string[]`
|
|
203
|
+
* tuple (to capture the literal key list).
|
|
204
|
+
* - Accumulate both into the 4th `TExtraTypes` parameter of `FixedMethods`
|
|
205
|
+
* so the information survives subsequent method calls on the same builder.
|
|
206
|
+
*
|
|
207
|
+
* This is deliberately projection-agnostic — any extension that follows the
|
|
208
|
+
* `(name: string, data: readonly string[] | function)` signature convention
|
|
209
|
+
* can use it. Projection-specific semantics (e.g. `PROJECTION_BRAND`) live
|
|
210
|
+
* in the consuming library, not here.
|
|
211
|
+
*
|
|
212
|
+
* @see {@link FixedMethods} for how the accumulation works.
|
|
213
|
+
*/
|
|
214
|
+
declare const EXTRA_TYPE_BRAND: "__cleverbrush_extra_type_brand__";
|
|
215
|
+
export { EXTRA_TYPE_BRAND };
|
|
216
|
+
export type ExtraTypeBrandSymbol = typeof EXTRA_TYPE_BRAND;
|
|
217
|
+
/** @internal Drops the first element of a tuple type. */
|
|
218
|
+
type TailArgs<T> = T extends readonly [unknown, ...infer R] ? R : [];
|
|
179
219
|
/**
|
|
180
220
|
* Intersected onto consumer-facing builder types to make `withExtension`
|
|
181
221
|
* and `getExtension` uncallable (`never`). Using an intersection instead
|
|
@@ -196,9 +236,42 @@ export type HiddenExtensionMethods = {
|
|
|
196
236
|
* The self-reference (`FixedMethods` appears in its own mapped return
|
|
197
237
|
* types) is resolved lazily by TypeScript because the recursion sits
|
|
198
238
|
* inside a function-return position within a conditional mapped type.
|
|
239
|
+
*
|
|
240
|
+
* The optional third parameter `TAccum` accumulates literal string names
|
|
241
|
+
* registered by methods whose raw return type includes
|
|
242
|
+
* `{ readonly [METHOD_LITERAL_BRAND]?: any }`. Those methods are rewritten
|
|
243
|
+
* as `const`-generic so the literal flows through; all other methods thread
|
|
244
|
+
* the accumulator unchanged.
|
|
245
|
+
*
|
|
246
|
+
* The optional fourth parameter `TExtraTypes` accumulates a
|
|
247
|
+
* `Record<name, readonly string[]>` map contributed by methods whose raw
|
|
248
|
+
* return type includes `{ readonly [EXTRA_TYPE_BRAND]?: any }`. Those
|
|
249
|
+
* methods are rewritten as const-generic for both the name and the keys
|
|
250
|
+
* tuple so the mapping flows through; all other methods thread it unchanged.
|
|
251
|
+
*
|
|
252
|
+
* For object-schema methods the accessor-form callback parameter is
|
|
253
|
+
* automatically typed as `PropertyDescriptorTree<TBase, TBase>` when
|
|
254
|
+
* `TBase` is an `ObjectSchemaBuilder`, giving callers IDE autocomplete over
|
|
255
|
+
* the schema's own properties.
|
|
199
256
|
*/
|
|
200
|
-
export type FixedMethods<TRawMethods, TBase> = {
|
|
201
|
-
[K in keyof TRawMethods]: TRawMethods[K] extends (this: any, ...args: infer A) =>
|
|
257
|
+
export type FixedMethods<TRawMethods, TBase, TAccum extends string = never, TExtraTypes extends Record<string, readonly string[]> = Record<never, never>> = {
|
|
258
|
+
[K in keyof TRawMethods]: TRawMethods[K] extends (this: any, ...args: infer A) => infer R ? R extends {
|
|
259
|
+
readonly [EXTRA_TYPE_BRAND]?: any;
|
|
260
|
+
} ? <const TName extends string & A[0], const TKey extends string>(name: TName, ...columns: ReadonlyArray<TKey | (TBase extends ObjectSchemaBuilder<any, any, any, any, any> ? (t: PropertyDescriptorTree<TBase, TBase>) => any : (t: any) => any)>) => TBase & FixedMethods<TRawMethods, TBase, TAccum, TExtraTypes & Record<TName, readonly TKey[]>> & HiddenExtensionMethods & {
|
|
261
|
+
readonly [EXTRA_TYPE_BRAND]?: TExtraTypes & Record<TName, readonly TKey[]>;
|
|
262
|
+
} & ([TAccum] extends [never] ? {} : {
|
|
263
|
+
readonly [METHOD_LITERAL_BRAND]?: TAccum;
|
|
264
|
+
}) : R extends {
|
|
265
|
+
readonly [METHOD_LITERAL_BRAND]?: any;
|
|
266
|
+
} ? <const TName extends string & A[0]>(name: TName, ...rest: TailArgs<A>) => TBase & FixedMethods<TRawMethods, TBase, TAccum | TName, TExtraTypes> & HiddenExtensionMethods & {
|
|
267
|
+
readonly [METHOD_LITERAL_BRAND]?: TAccum | TName;
|
|
268
|
+
} & ([keyof TExtraTypes] extends [never] ? {} : {
|
|
269
|
+
readonly [EXTRA_TYPE_BRAND]?: TExtraTypes;
|
|
270
|
+
}) : (...args: A) => TBase & FixedMethods<TRawMethods, TBase, TAccum, TExtraTypes> & HiddenExtensionMethods & ([TAccum] extends [never] ? {} : {
|
|
271
|
+
readonly [METHOD_LITERAL_BRAND]?: TAccum;
|
|
272
|
+
}) & ([keyof TExtraTypes] extends [never] ? {} : {
|
|
273
|
+
readonly [EXTRA_TYPE_BRAND]?: TExtraTypes;
|
|
274
|
+
}) : TRawMethods[K];
|
|
202
275
|
};
|
|
203
276
|
/**
|
|
204
277
|
* Produces the consumer-facing type for an extended builder: the base
|
|
@@ -418,4 +491,3 @@ export declare function defineExtension<T extends ExtensionConfig>(config: T): E
|
|
|
418
491
|
* @see {@link ExtensionDescriptor}
|
|
419
492
|
*/
|
|
420
493
|
export declare function withExtensions<const TExts extends readonly ExtensionDescriptor<any>[]>(...extensions: TExts): WithExtensionsResult<TExts>;
|
|
421
|
-
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{c as a,d as b,e as c,f as d}from"./chunk-54RHS4F4.js";import"./chunk-C6YQOKWB.js";import"./chunk-K4ZLXLE2.js";import"./chunk-ELPPAHNO.js";import"./chunk-6LSN7NXQ.js";import"./chunk-JUFZ7PLO.js";import"./chunk-XL723XFL.js";import"./chunk-ORV2G6ZL.js";import"./chunk-G424M7GI.js";import"./chunk-XPLTW5DI.js";import"./chunk-KC45JEFL.js";import"./chunk-PQINUGZW.js";import"./chunk-NF4CRFMN.js";import"./chunk-REYZ7G7J.js";export{b as EXTRA_TYPE_BRAND,a as METHOD_LITERAL_BRAND,c as defineExtension,d as withExtensions};
|
|
2
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as ee,b as re,c as E,d as g,e as ne,f as te}from"./chunk-VSU5GILY.js";import{a as B,b}from"./chunk-XHSBY2QK.js";import{a as Y,b as Z,c as de,d as ue,e as u,f as p}from"./chunk-54RHS4F4.js";import{a as oe}from"./chunk-C6YQOKWB.js";import{a as X}from"./chunk-K4ZLXLE2.js";import{a as ie}from"./chunk-ELPPAHNO.js";import{a as ae}from"./chunk-6LSN7NXQ.js";import{a as T}from"./chunk-JUFZ7PLO.js";import{a as V}from"./chunk-XL723XFL.js";import{a as se}from"./chunk-ORV2G6ZL.js";import{a as v}from"./chunk-G424M7GI.js";import{a as C}from"./chunk-XPLTW5DI.js";import{a as W}from"./chunk-KC45JEFL.js";import{a as _}from"./chunk-PQINUGZW.js";import{a as G}from"./chunk-NF4CRFMN.js";import{a as J,b as Q}from"./chunk-YAOZEA2R.js";import{b as I,c as L,d as K,f as z}from"./chunk-REYZ7G7J.js";function i(e,r,n,a){return{valid:!1,errors:[{message:M(e,r,n,a)}]}}function M(e,r,n,a){if(e===void 0)return r;if(typeof e=="string")return e;let t=e(n,a);if(t instanceof Promise)throw new Error("Async error message providers require validateAsync(). Use a string or sync function instead.");return t}var l=u({array:{nonempty(e){return this.withExtension("nonempty",!0).addValidator(r=>Array.isArray(r)?r.length>0?{valid:!0,errors:[]}:i(e,"must not be empty",r,this):i(e,"must not be empty",r,this))},unique(e,r){let n=e??!0;return this.withExtension("unique",n).addValidator(a=>{if(!Array.isArray(a))return i(r,"must contain unique elements",a,this);let t=new Set;for(let s of a){let d=e?e(s):s;if(t.has(d))return i(r,"must contain unique elements",a,this);t.add(d)}return{valid:!0,errors:[]}})}}});var m=u({number:{positive(e){return this.withExtension("positive",!0).addValidator(r=>typeof r!="number"?i(e,"must be a positive number",r,this):r>0?{valid:!0,errors:[]}:i(e,"must be a positive number",r,this))},negative(e){return this.withExtension("negative",!0).addValidator(r=>typeof r!="number"?i(e,"must be a negative number",r,this):r<0?{valid:!0,errors:[]}:i(e,"must be a negative number",r,this))},finite(e){return this.withExtension("finite",!0).addValidator(r=>typeof r!="number"?i(e,"must be a finite number",r,this):Number.isFinite(r)?{valid:!0,errors:[]}:i(e,"must be a finite number",r,this))},multipleOf(e,r){if(e===0||!Number.isFinite(e))throw new Error("multipleOf: n must be a finite, non-zero number");return this.withExtension("multipleOf",e).addValidator(n=>{if(typeof n!="number")return i(r,`must be a multiple of ${e}`,n,this);let a=Math.abs(n%e),t=Math.abs(e)*1e-10;return a<t||Math.abs(a-Math.abs(e))<t?{valid:!0,errors:[]}:i(r,`must be a multiple of ${e}`,n,this)})},oneOf(...e){let r,n;if(e.length===0)throw new Error("oneOf requires at least one value");if(Array.isArray(e[0]))r=e[0],n=e[1];else{let t=e[e.length-1];typeof t=="string"||typeof t=="function"?(r=e.slice(0,-1),n=t):(r=e,n=void 0)}if(r.length===0)throw new Error("oneOf requires at least one value");let a=new Set(r);return this.withExtension("oneOf",r).addValidator(t=>typeof t=="number"&&a.has(t)?{valid:!0,errors:[]}:i(n,`must be one of: ${r.join(", ")}`,t,this))}}});var P=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,f=/^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/,S=/^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$|^::(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4}$|^(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}$|^(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}$|^(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}$|^(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}$|^(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}$|^[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}$|^::$/i,y=u({string:{email(e){return this.withExtension("email",!0).addValidator(r=>typeof r!="string"?i(e,"must be a valid email",r,this):/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r)?{valid:!0,errors:[]}:i(e,"must be a valid email",r,this))},url(e,r){let n;if(typeof e=="string"||typeof e=="function"?(r=e,n=void 0):n=e,n?.protocols!==void 0&&(n.protocols.length===0||n.protocols.some(s=>!s||s.trim()==="")))throw new Error("url: opts.protocols must be a non-empty array of non-empty strings");let a=n?.protocols??["http","https"],t=n?.protocols?{protocols:n.protocols}:!0;return this.withExtension("url",t).addValidator(s=>{if(typeof s!="string")return i(r,"must be a valid URL",s,this);let d=!1,h="must be a valid URL";try{let x=new URL(s).protocol.replace(":","");d=a.includes(x),d||(h=`protocol must be one of: ${a.join(", ")}`)}catch{}return d?{valid:!0,errors:[]}:i(r,h,s,this)})},uuid(e){return this.withExtension("uuid",!0).addValidator(r=>typeof r!="string"?i(e,"must be a valid UUID",r,this):P.test(r)?{valid:!0,errors:[]}:i(e,"must be a valid UUID",r,this))},ip(e,r){let n=e?.version,a=n?{version:n}:!0;return this.withExtension("ip",a).addValidator(t=>{let s=n?`must be a valid ${n} IP address`:"must be a valid IP address";if(typeof t!="string")return i(r,s,t,this);let d;return n==="v4"?d=f.test(t):n==="v6"?d=S.test(t):d=f.test(t)||S.test(t),d?{valid:!0,errors:[]}:i(r,s,t,this)})},trim(){return this.addPreprocessor(e=>typeof e=="string"?e.trim():e)},toLowerCase(){return this.addPreprocessor(e=>typeof e=="string"?e.toLowerCase():e)},nonempty(e){return this.withExtension("nonempty",!0).addValidator(r=>typeof r!="string"?i(e,"must not be empty",r,this):r.length>0?{valid:!0,errors:[]}:i(e,"must not be empty",r,this))},oneOf(...e){let r,n;if(e.length===0)throw new Error("oneOf requires at least one value");if(Array.isArray(e[0]))r=e[0],n=e[1];else{let t=e[e.length-1];typeof t=="function"?(r=e.slice(0,-1),n=t):(r=e,n=void 0)}if(r.length===0)throw new Error("oneOf requires at least one value");let a=new Set(r);return this.withExtension("oneOf",r).addValidator(t=>typeof t=="string"&&a.has(t)?{valid:!0,errors:[]}:i(n,`must be one of: ${r.join(", ")}`,t,this))}}});var o=p(y,m,l),c=o.string,w=o.number,N=o.array,O=o.boolean,A=o.date,R=o.object,j=o.union,H=o.func,$=o.any,U=o.tuple,k=o.record,F=o.promise;function q(...e){return Array.isArray(e[0])?c().oneOf(e[0],e[1]):c().oneOf(...e)}export{C as AnySchemaBuilder,W as ArraySchemaBuilder,_ as BooleanSchemaBuilder,G as DateSchemaBuilder,ue as EXTRA_TYPE_BRAND,J as ExternSchemaBuilder,X as FunctionSchemaBuilder,Y as GenericSchemaBuilder,ee as IntersectionSchemaBuilder,E as LazySchemaBuilder,de as METHOD_LITERAL_BRAND,ne as NullSchemaBuilder,ie as NumberSchemaBuilder,ae as ObjectSchemaBuilder,B as ParseStringSchemaBuilder,T as PromiseSchemaBuilder,V as RecordSchemaBuilder,K as SYMBOL_HAS_PROPERTIES,L as SYMBOL_SCHEMA_PROPERTY_DESCRIPTOR,z as SchemaBuilder,I as SchemaValidationError,se as StringSchemaBuilder,v as TupleSchemaBuilder,oe as UnionSchemaBuilder,$ as any,N as array,l as arrayExtensions,O as boolean,A as date,u as defineExtension,q as enumOf,Q as extern,H as func,Z as generic,re as intersection,g as lazy,te as nul,w as number,m as numberExtensions,R as object,b as parseString,F as promise,k as record,c as string,y as stringExtensions,U as tuple,j as union,p as withExtensions};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/extensions/util.ts","../src/extensions/array.ts","../src/extensions/number.ts","../src/extensions/string.ts","../src/extensions/index.ts"],"sourcesContent":["import type { ValidationErrorMessageProvider } from '../builders/SchemaBuilder.js';\n\n/** Validation result returned by validators on failure. */\ninterface ValidationFailure {\n valid: false;\n errors: { message: string }[];\n}\n\n/**\n * Builds a synchronous validation-failure result, resolving the user-supplied\n * error-message provider (or falling back to `defaultMsg`).\n *\n * @param provider - custom error message provider (string, sync function, or `undefined`)\n * @param defaultMsg - fallback message used when `provider` is `undefined`\n * @param value - the value that failed validation\n * @param schema - the schema builder instance\n * @returns a `{ valid: false, errors: [{ message }] }` object\n */\nexport function validationFail(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultMsg: string,\n value: unknown,\n schema: unknown\n): ValidationFailure {\n const msg = resolveErrorMessage(provider, defaultMsg, value, schema);\n return { valid: false, errors: [{ message: msg }] };\n}\n\n/**\n * Synchronously resolves a {@link ValidationErrorMessageProvider} to a concrete error message string.\n * Returns the default message when no custom provider is supplied.\n * Throws if the provider function returns a Promise.\n *\n * @param provider - custom error message provider (string, sync function, or `undefined`)\n * @param defaultMsg - fallback message used when `provider` is `undefined`\n * @param value - the value that failed validation (passed to function providers)\n * @param schema - the schema builder instance (passed to function providers)\n * @returns the resolved error message string\n * @throws Error if the provider returns a Promise\n */\nexport function resolveErrorMessage(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultMsg: string,\n value: unknown,\n schema: unknown\n): string {\n if (provider === undefined) return defaultMsg;\n if (typeof provider === 'string') return provider;\n const result = provider(value, schema);\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/**\n * Asynchronously resolves a {@link ValidationErrorMessageProvider} to a concrete error message string.\n * Returns the default message when no custom provider is supplied.\n * Supports async provider functions.\n *\n * @param provider - custom error message provider (string, function, or `undefined`)\n * @param defaultMsg - fallback message used when `provider` is `undefined`\n * @param value - the value that failed validation (passed to function providers)\n * @param schema - the schema builder instance (passed to function providers)\n * @returns the resolved error message string\n */\nexport async function resolveErrorMessageAsync(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultMsg: string,\n value: unknown,\n schema: unknown\n): Promise<string> {\n if (provider === undefined) return defaultMsg;\n if (typeof provider === 'string') return provider;\n return provider(value, schema);\n}\n","/**\n * Built-in array extensions for `@cleverbrush/schema`.\n *\n * Provides common array validators: {@link arrayExtensions | nonempty}\n * and {@link arrayExtensions | unique}.\n *\n * These are pre-applied in the default `@cleverbrush/schema` import.\n * Import from `@cleverbrush/schema/core` to get bare builders without these extensions.\n *\n * @module\n */\nimport type { ArraySchemaBuilder } from '../builders/ArraySchemaBuilder.js';\nimport type {\n SchemaBuilder,\n ValidationErrorMessageProvider\n} from '../builders/SchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { defineExtension } from '../extension.js';\nimport { validationFail } from './util.js';\n\n// ---------------------------------------------------------------------------\n// Public interface — carries JSDoc into .d.ts for consumers\n// ---------------------------------------------------------------------------\n\n/** Return type shared by every method on {@link ArrayBuiltinExtensions}. */\ntype ArrayExtReturn<\n TElementSchema extends SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n > = SchemaBuilder<any, any, any>\n> = ArraySchemaBuilder<\n TElementSchema,\n true,\n false,\n undefined,\n false,\n ArrayBuiltinExtensions<TElementSchema>\n> &\n ArrayBuiltinExtensions<TElementSchema> &\n HiddenExtensionMethods;\n\n/**\n * Methods added to `ArraySchemaBuilder` by the built-in array extension pack.\n *\n * **WORKAROUND:** This interface duplicates the method signatures from\n * `arrayExtensions` so that JSDoc survives into the published `.d.ts`\n * files. TypeScript strips JSDoc when method signatures are reconstructed\n * through the `FixedMethods` mapped type (conditional `infer` loses\n * comments). Remove this interface once TypeScript preserves JSDoc\n * through mapped types / conditional type inference.\n *\n * @see https://github.com/microsoft/TypeScript/issues/50715\n */\nexport interface ArrayBuiltinExtensions<\n TElementSchema extends SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n > = SchemaBuilder<any, any, any>\n> {\n /**\n * Validates that the array contains at least one element.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * array().nonempty();\n * array().nonempty('At least one item required');\n * ```\n */\n nonempty(\n errorMessage?: ValidationErrorMessageProvider<ArraySchemaBuilder<any>>\n ): ArrayExtReturn<TElementSchema>;\n\n /**\n * Validates that all elements in the array are unique.\n *\n * For primitive elements, uses strict equality. For objects, pass a `keyFn`\n * that extracts a comparison key from each element.\n *\n * @param keyFn - optional function to extract a comparison key from each element\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the unique validator applied\n *\n * @example\n * ```ts\n * array().unique();\n * array().unique((item) => item.id);\n * array().unique(undefined, 'No duplicates allowed');\n * ```\n */\n unique(\n keyFn?: (item: any) => unknown,\n errorMessage?: ValidationErrorMessageProvider<ArraySchemaBuilder<any>>\n ): ArrayExtReturn<TElementSchema>;\n}\n\n/**\n * Extension descriptor that adds common array validators\n * to `ArraySchemaBuilder`.\n *\n * Included methods: `nonempty`, `unique`.\n *\n * @example\n * ```ts\n * import { withExtensions } from '@cleverbrush/schema/core';\n * import { arrayExtensions } from '@cleverbrush/schema';\n *\n * const s = withExtensions(arrayExtensions);\n * const schema = s.array().nonempty().unique();\n * ```\n */\nexport const arrayExtensions = defineExtension({\n array: {\n /**\n * Validates that the array contains at least one element.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * array().nonempty();\n * array().nonempty('At least one item required');\n * ```\n */\n nonempty(\n this: ArraySchemaBuilder<any>,\n errorMessage?: ValidationErrorMessageProvider<\n ArraySchemaBuilder<any>\n >\n ) {\n return this.withExtension('nonempty', true).addValidator(\n (val: unknown[]) => {\n if (!Array.isArray(val))\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n const valid = val.length > 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n }\n );\n },\n\n /**\n * Validates that all elements in the array are unique.\n *\n * For primitive elements, uses strict equality. For objects, pass a `keyFn`\n * that extracts a comparison key from each element.\n *\n * @param keyFn - optional function to extract a comparison key from each element\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the unique validator applied\n *\n * @example\n * ```ts\n * array().unique();\n * array().unique((item) => item.id);\n * array().unique(undefined, 'No duplicates allowed');\n * ```\n */\n unique(\n this: ArraySchemaBuilder<any>,\n keyFn?: (item: any) => unknown,\n errorMessage?: ValidationErrorMessageProvider<\n ArraySchemaBuilder<any>\n >\n ) {\n const meta = keyFn ?? true;\n\n return this.withExtension('unique', meta).addValidator(\n (val: unknown[]) => {\n if (!Array.isArray(val))\n return validationFail(\n errorMessage,\n 'must contain unique elements',\n val,\n this\n );\n const seen = new Set();\n for (const item of val) {\n const key = keyFn ? keyFn(item) : item;\n if (seen.has(key)) {\n return validationFail(\n errorMessage,\n 'must contain unique elements',\n val,\n this\n );\n }\n seen.add(key);\n }\n return { valid: true, errors: [] };\n }\n );\n }\n }\n});\n","/**\n * Built-in number extensions for `@cleverbrush/schema`.\n *\n * Provides common number validators: {@link numberExtensions | positive},\n * {@link numberExtensions | negative}, {@link numberExtensions | finite},\n * {@link numberExtensions | multipleOf}, and {@link numberExtensions | oneOf}.\n *\n * These are pre-applied in the default `@cleverbrush/schema` import.\n * Import from `@cleverbrush/schema/core` to get bare builders without these extensions.\n *\n * @module\n */\nimport type { NumberSchemaBuilder } from '../builders/NumberSchemaBuilder.js';\nimport type { ValidationErrorMessageProvider } from '../builders/SchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { defineExtension } from '../extension.js';\nimport { validationFail } from './util.js';\n\n// ---------------------------------------------------------------------------\n// Public interface — carries JSDoc into .d.ts for consumers\n// ---------------------------------------------------------------------------\n\n/** Return type shared by every method on {@link NumberBuiltinExtensions}. */\ntype NumberExtReturn<T extends number = number> = NumberSchemaBuilder<\n T,\n true,\n false,\n false,\n NumberBuiltinExtensions<T>\n> &\n NumberBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/**\n * Methods added to `NumberSchemaBuilder` by the built-in number extension pack.\n *\n * **WORKAROUND:** This interface duplicates the method signatures from\n * `numberExtensions` so that JSDoc survives into the published `.d.ts`\n * files. TypeScript strips JSDoc when method signatures are reconstructed\n * through the `FixedMethods` mapped type (conditional `infer` loses\n * comments). Remove this interface once TypeScript preserves JSDoc\n * through mapped types / conditional type inference.\n *\n * @see https://github.com/microsoft/TypeScript/issues/50715\n */\nexport interface NumberBuiltinExtensions<T extends number = number> {\n /**\n * Validates that the number is strictly greater than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the positive validator applied\n *\n * @example\n * ```ts\n * number().positive();\n * number().positive('Must be greater than zero');\n * ```\n */\n positive(\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Validates that the number is strictly less than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the negative validator applied\n *\n * @example\n * ```ts\n * number().negative();\n * number().negative('Must be below zero');\n * ```\n */\n negative(\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Validates that the number is finite (rejects `Infinity` and `-Infinity`).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the finite validator applied\n *\n * @example\n * ```ts\n * number().finite();\n * number().finite('No infinities allowed');\n * ```\n */\n finite(\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Validates that the number is an exact multiple of `n`.\n *\n * Uses a relative tolerance of `1e-10` for float-safe comparison.\n *\n * @param n - the divisor to check against\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the multipleOf validator applied\n *\n * @example\n * ```ts\n * number().multipleOf(5);\n * number().multipleOf(0.1, 'Must be a multiple of 0.1');\n * ```\n */\n multipleOf(\n n: number,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Constrains the number to one of the specified literal values.\n *\n * Narrows the inferred type from `number` to the union of the\n * provided literals.\n *\n * @param values - the allowed number literals\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * import { number, InferType } from '@cleverbrush/schema';\n *\n * const priority = number().oneOf(1, 2, 3);\n * type Priority = InferType<typeof priority>; // 1 | 2 | 3\n *\n * priority.validate(1); // valid\n * priority.validate(4); // invalid — \"must be one of: 1, 2, 3\"\n * ```\n */\n oneOf<V extends number>(...values: [V, ...V[]]): NumberExtReturn<V>;\n\n /**\n * Constrains the number to one of the specified literal values,\n * with a custom error message or factory as the last argument.\n *\n * @example\n * ```ts\n * const priority = number().oneOf(1, 2, 3, 'Priority must be 1, 2, or 3');\n * const priority2 = number().oneOf(1, 2, 3, (val) => `${val} is not a valid priority`);\n * ```\n */\n oneOf<V extends number>(\n ...args: [\n ...[V, ...V[]],\n ValidationErrorMessageProvider<NumberSchemaBuilder>\n ]\n ): NumberExtReturn<V>;\n\n /**\n * Constrains the number to one of the specified literal values,\n * with an optional custom error message or factory.\n *\n * @param values - the allowed number literals as an array\n * @param errorMessage - optional custom error message or factory function\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * const priority = number().oneOf([1, 2, 3], 'Must be 1, 2, or 3');\n * ```\n */\n oneOf<V extends number>(\n values: readonly [V, ...V[]],\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<V>;\n}\n\n/**\n * Subset of {@link NumberBuiltinExtensions} containing only the `.oneOf()` overloads.\n * Exported for backward compatibility.\n */\nexport type NumberOneOfExtension = Pick<NumberBuiltinExtensions, 'oneOf'>;\n\n/**\n * Extension descriptor that adds common number validators\n * to `NumberSchemaBuilder`.\n *\n * Included methods: `positive`, `negative`, `finite`, `multipleOf`, `oneOf`.\n *\n * @example\n * ```ts\n * import { withExtensions } from '@cleverbrush/schema/core';\n * import { numberExtensions } from '@cleverbrush/schema';\n *\n * const s = withExtensions(numberExtensions);\n * const schema = s.number().positive().multipleOf(5);\n * ```\n */\nexport const numberExtensions = defineExtension({\n number: {\n /**\n * Validates that the number is strictly greater than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the positive validator applied\n *\n * @example\n * ```ts\n * number().positive();\n * number().positive('Must be greater than zero');\n * ```\n */\n positive(\n this: NumberSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n return this.withExtension('positive', true).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n 'must be a positive number',\n val,\n this\n );\n const valid = val > 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a positive number',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the number is strictly less than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the negative validator applied\n *\n * @example\n * ```ts\n * number().negative();\n * number().negative('Must be below zero');\n * ```\n */\n negative(\n this: NumberSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n return this.withExtension('negative', true).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n 'must be a negative number',\n val,\n this\n );\n const valid = val < 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a negative number',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the number is finite (rejects `Infinity` and `-Infinity`).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the finite validator applied\n *\n * @example\n * ```ts\n * number().finite();\n * number().finite('No infinities allowed');\n * ```\n */\n finite(\n this: NumberSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n return this.withExtension('finite', true).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n 'must be a finite number',\n val,\n this\n );\n const valid = Number.isFinite(val);\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a finite number',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the number is an exact multiple of `n`.\n *\n * Uses a relative tolerance of `1e-10` for float-safe comparison.\n *\n * @param n - the divisor to check against\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the multipleOf validator applied\n *\n * @example\n * ```ts\n * number().multipleOf(5);\n * number().multipleOf(0.1, 'Must be a multiple of 0.1');\n * ```\n */\n multipleOf(\n this: NumberSchemaBuilder,\n n: number,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n if (n === 0 || !Number.isFinite(n)) {\n throw new Error(\n 'multipleOf: n must be a finite, non-zero number'\n );\n }\n return this.withExtension('multipleOf', n).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n `must be a multiple of ${n}`,\n val,\n this\n );\n const remainder = Math.abs(val % n);\n const tolerance = Math.abs(n) * 1e-10;\n const valid =\n remainder < tolerance ||\n Math.abs(remainder - Math.abs(n)) < tolerance;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n `must be a multiple of ${n}`,\n val,\n this\n );\n });\n },\n\n /**\n * Constrains the number to one of the specified literal values.\n *\n * @param args - the allowed number literals, optionally followed by an error message\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * number().oneOf(1, 2, 3);\n * number().oneOf([1, 2, 3], 'Must be 1, 2, or 3');\n * ```\n */\n oneOf(this: NumberSchemaBuilder, ...args: any[]) {\n let values: number[];\n let errorMessage:\n | ValidationErrorMessageProvider<NumberSchemaBuilder>\n | undefined;\n\n if (args.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n if (Array.isArray(args[0])) {\n // Array form: oneOf([1, 2, 3], errorMessage?)\n values = args[0] as number[];\n errorMessage = args[1] as\n | ValidationErrorMessageProvider<NumberSchemaBuilder>\n | undefined;\n } else {\n // Rest params form: oneOf(1, 2, 3) or oneOf(1, 2, 3, 'error') or oneOf(1, 2, 3, errorFn)\n // Last arg is a string or function → error message (unambiguous since values are numbers)\n const lastArg = args[args.length - 1];\n if (\n typeof lastArg === 'string' ||\n typeof lastArg === 'function'\n ) {\n values = args.slice(0, -1) as number[];\n errorMessage =\n lastArg as ValidationErrorMessageProvider<NumberSchemaBuilder>;\n } else {\n values = args as number[];\n errorMessage = undefined;\n }\n }\n\n if (values.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n const allowed = new Set(values);\n return this.withExtension('oneOf', values).addValidator(val => {\n if (typeof val === 'number' && allowed.has(val)) {\n return { valid: true, errors: [] };\n }\n return validationFail(\n errorMessage,\n `must be one of: ${values.join(', ')}`,\n val,\n this\n );\n });\n }\n }\n});\n","/**\n * Built-in string extensions for `@cleverbrush/schema`.\n *\n * Provides common string validators and preprocessors: {@link stringExtensions | email},\n * {@link stringExtensions | url}, {@link stringExtensions | uuid},\n * {@link stringExtensions | ip}, {@link stringExtensions | trim},\n * {@link stringExtensions | toLowerCase}, {@link stringExtensions | nonempty},\n * and {@link stringExtensions | oneOf}.\n *\n * These are pre-applied in the default `@cleverbrush/schema` import.\n * Import from `@cleverbrush/schema/core` to get bare builders without these extensions.\n *\n * @module\n */\nimport type { ValidationErrorMessageProvider } from '../builders/SchemaBuilder.js';\nimport type { StringSchemaBuilder } from '../builders/StringSchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { defineExtension } from '../extension.js';\nimport { validationFail } from './util.js';\n\n// ---------------------------------------------------------------------------\n// Public interface — carries JSDoc into .d.ts for consumers\n// ---------------------------------------------------------------------------\n\n/** Return type shared by every method on {@link StringBuiltinExtensions}. */\ntype StringExtReturn<T extends string = string> = StringSchemaBuilder<\n T,\n true,\n false,\n false,\n StringBuiltinExtensions<T>\n> &\n StringBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/**\n * Methods added to `StringSchemaBuilder` by the built-in string extension pack.\n *\n * **WORKAROUND:** This interface duplicates the method signatures from\n * `stringExtensions` so that JSDoc survives into the published `.d.ts`\n * files. TypeScript strips JSDoc when method signatures are reconstructed\n * through the `FixedMethods` mapped type (conditional `infer` loses\n * comments). Remove this interface once TypeScript preserves JSDoc\n * through mapped types / conditional type inference.\n *\n * @see https://github.com/microsoft/TypeScript/issues/50715\n */\nexport interface StringBuiltinExtensions<T extends string = string> {\n /**\n * Validates that the string is a well-formed email address.\n *\n * Uses the pattern `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$` for validation.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the email validator applied\n *\n * @example\n * ```ts\n * string().email();\n * string().email('Please enter a valid email');\n * string().email((val) => `\"${val}\" is not a valid email`);\n * ```\n */\n email(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Validates that the string is a well-formed URL.\n *\n * By default only `http` and `https` protocols are accepted.\n * Pass `opts.protocols` to restrict or expand the allowed set.\n *\n * @param opts - optional configuration\n * @param opts.protocols - allowed URL protocols (default: `['http', 'https']`)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the URL validator applied\n *\n * @example\n * ```ts\n * string().url();\n * string().url({ protocols: ['https'] });\n * string().url('Must be a valid URL');\n * string().url({ protocols: ['https'] }, 'Must be a valid URL');\n * ```\n */\n url(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n url(\n opts?: { protocols?: string[] },\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Validates that the string is a valid UUID (versions 1–5).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the UUID validator applied\n *\n * @example\n * ```ts\n * string().uuid();\n * string().uuid('Invalid identifier');\n * ```\n */\n uuid(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Validates that the string is a valid IP address (IPv4 or IPv6).\n *\n * Pass `opts.version` to restrict validation to a specific IP version.\n *\n * @param opts - optional configuration\n * @param opts.version - restrict to `'v4'` or `'v6'` (default: accept both)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the IP validator applied\n *\n * @example\n * ```ts\n * string().ip();\n * string().ip({ version: 'v4' });\n * string().ip(undefined, 'Bad IP address');\n * ```\n */\n ip(\n opts?: { version?: 'v4' | 'v6' },\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Preprocessor that trims leading and trailing whitespace before validation.\n *\n * @returns a new schema builder with the trim preprocessor applied\n *\n * @example\n * ```ts\n * string().trim().minLength(1); // ' hi ' → 'hi'\n * ```\n */\n trim(): StringExtReturn<T>;\n\n /**\n * Preprocessor that converts the string to lowercase before validation.\n *\n * @returns a new schema builder with the toLowerCase preprocessor applied\n *\n * @example\n * ```ts\n * string().toLowerCase(); // 'HELLO' → 'hello'\n * ```\n */\n toLowerCase(): StringExtReturn<T>;\n\n /**\n * Validates that the string is not empty (length > 0).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * string().nonempty();\n * string().nonempty('Name is required');\n * ```\n */\n nonempty(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Constrains the string to one of the specified literal values.\n *\n * Narrows the inferred type from `string` to the union of the\n * provided literals.\n *\n * @param values - the allowed string literals\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * import { string, InferType } from '@cleverbrush/schema';\n *\n * const role = string().oneOf('admin', 'user', 'guest');\n * type Role = InferType<typeof role>; // 'admin' | 'user' | 'guest'\n *\n * role.validate('admin'); // valid\n * role.validate('other'); // invalid — \"must be one of: admin, user, guest\"\n * ```\n */\n oneOf<V extends string>(...values: [V, ...V[]]): StringExtReturn<V>;\n\n /**\n * Constrains the string to one of the specified literal values,\n * with a custom error message or factory as the last argument.\n *\n * @example\n * ```ts\n * const role = string().oneOf('admin', 'user', (val) => `\"${val}\" is not allowed`);\n * ```\n */\n oneOf<V extends string>(\n ...args: [\n ...[V, ...V[]],\n ValidationErrorMessageProvider<StringSchemaBuilder>\n ]\n ): StringExtReturn<V>;\n\n /**\n * Constrains the string to one of the specified literal values,\n * with an optional custom error message or factory.\n *\n * @param values - the allowed string literals as an array\n * @param errorMessage - optional custom error message or factory function\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * const role = string().oneOf(['admin', 'user', 'guest'], 'Invalid role');\n * ```\n */\n oneOf<V extends string>(\n values: readonly [V, ...V[]],\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<V>;\n}\n\n/**\n * Subset of {@link StringBuiltinExtensions} containing only the `.oneOf()` overloads.\n * Exported for backward compatibility.\n */\nexport type StringOneOfExtension = Pick<StringBuiltinExtensions, 'oneOf'>;\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nconst IPV4_RE =\n /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\n\nconst IPV6_RE =\n /^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$|^::(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4}$|^(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}$|^(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}$|^(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}$|^(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}$|^(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}$|^[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}$|^::$/i;\n\n/**\n * Extension descriptor that adds common string validators and preprocessors\n * to `StringSchemaBuilder`.\n *\n * Included methods: `email`, `url`, `uuid`, `ip`, `trim`, `toLowerCase`, `nonempty`, `oneOf`.\n *\n * @example\n * ```ts\n * import { withExtensions } from '@cleverbrush/schema/core';\n * import { stringExtensions } from '@cleverbrush/schema';\n *\n * const s = withExtensions(stringExtensions);\n * const schema = s.string().email().trim();\n * ```\n */\nexport const stringExtensions = defineExtension({\n string: {\n /**\n * Validates that the string is a well-formed email address.\n *\n * Uses the pattern `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$` for validation.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the email validator applied\n *\n * @example\n * ```ts\n * string().email();\n * string().email('Please enter a valid email');\n * string().email((val) => `\"${val}\" is not a valid email`);\n * ```\n */\n email(\n this: StringSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n return this.withExtension('email', true).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must be a valid email',\n val,\n this\n );\n const valid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(val);\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a valid email',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the string is a well-formed URL.\n *\n * By default only `http` and `https` protocols are accepted.\n * Pass `opts.protocols` to restrict or expand the allowed set.\n *\n * @param opts - optional configuration\n * @param opts.protocols - allowed URL protocols (default: `['http', 'https']`)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the URL validator applied\n *\n * @example\n * ```ts\n * string().url();\n * string().url({ protocols: ['https'] });\n * string().url('Must be a valid URL');\n * string().url({ protocols: ['https'] }, 'Must be a valid URL');\n * ```\n */\n url(\n this: StringSchemaBuilder,\n optsOrError?:\n | { protocols?: string[] }\n | ValidationErrorMessageProvider<StringSchemaBuilder>,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n let opts: { protocols?: string[] } | undefined;\n if (\n typeof optsOrError === 'string' ||\n typeof optsOrError === 'function'\n ) {\n errorMessage = optsOrError;\n opts = undefined;\n } else {\n opts = optsOrError;\n }\n if (\n opts?.protocols !== undefined &&\n (opts.protocols.length === 0 ||\n opts.protocols.some(p => !p || p.trim() === ''))\n ) {\n throw new Error(\n 'url: opts.protocols must be a non-empty array of non-empty strings'\n );\n }\n const protocols = opts?.protocols ?? ['http', 'https'];\n const meta = opts?.protocols ? { protocols: opts.protocols } : true;\n\n return this.withExtension('url', meta).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must be a valid URL',\n val,\n this\n );\n let valid = false;\n let defaultMsg = 'must be a valid URL';\n try {\n const parsed = new URL(val);\n const proto = parsed.protocol.replace(':', '');\n valid = protocols.includes(proto);\n if (!valid)\n defaultMsg = `protocol must be one of: ${protocols.join(', ')}`;\n } catch {\n /* invalid URL */\n }\n if (valid) return { valid: true, errors: [] };\n return validationFail(errorMessage, defaultMsg, val, this);\n });\n },\n\n /**\n * Validates that the string is a valid UUID (versions 1–5).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the UUID validator applied\n *\n * @example\n * ```ts\n * string().uuid();\n * string().uuid('Invalid identifier');\n * ```\n */\n uuid(\n this: StringSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n return this.withExtension('uuid', true).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must be a valid UUID',\n val,\n this\n );\n const valid = UUID_RE.test(val);\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a valid UUID',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the string is a valid IP address (IPv4 or IPv6).\n *\n * Pass `opts.version` to restrict validation to a specific IP version.\n *\n * @param opts - optional configuration\n * @param opts.version - restrict to `'v4'` or `'v6'` (default: accept both)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the IP validator applied\n *\n * @example\n * ```ts\n * string().ip();\n * string().ip({ version: 'v4' });\n * string().ip(undefined, 'Bad IP address');\n * ```\n */\n ip(\n this: StringSchemaBuilder,\n opts?: { version?: 'v4' | 'v6' },\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n const version = opts?.version;\n const meta = version ? { version } : true;\n\n return this.withExtension('ip', meta).addValidator(val => {\n const defaultMsg = version\n ? `must be a valid ${version} IP address`\n : 'must be a valid IP address';\n if (typeof val !== 'string')\n return validationFail(errorMessage, defaultMsg, val, this);\n let valid: boolean;\n if (version === 'v4') {\n valid = IPV4_RE.test(val);\n } else if (version === 'v6') {\n valid = IPV6_RE.test(val);\n } else {\n valid = IPV4_RE.test(val) || IPV6_RE.test(val);\n }\n if (valid) return { valid: true, errors: [] };\n return validationFail(errorMessage, defaultMsg, val, this);\n });\n },\n\n /**\n * Preprocessor that trims leading and trailing whitespace before validation.\n *\n * @returns a new schema builder with the trim preprocessor applied\n *\n * @example\n * ```ts\n * string().trim().minLength(1); // ' hi ' → 'hi'\n * ```\n */\n trim(this: StringSchemaBuilder) {\n return this.addPreprocessor(val =>\n typeof val === 'string' ? val.trim() : val\n );\n },\n\n /**\n * Preprocessor that converts the string to lowercase before validation.\n *\n * @returns a new schema builder with the toLowerCase preprocessor applied\n *\n * @example\n * ```ts\n * string().toLowerCase(); // 'HELLO' → 'hello'\n * ```\n */\n toLowerCase(this: StringSchemaBuilder) {\n return this.addPreprocessor(val =>\n typeof val === 'string' ? val.toLowerCase() : val\n );\n },\n\n /**\n * Validates that the string is not empty (length > 0).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * string().nonempty();\n * string().nonempty('Name is required');\n * ```\n */\n nonempty(\n this: StringSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n return this.withExtension('nonempty', true).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n const valid = val.length > 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n });\n },\n\n /**\n * Constrains the string to one of the specified literal values.\n *\n * @param args - the allowed string literals, optionally followed by an error message\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * string().oneOf('admin', 'user', 'guest');\n * string().oneOf(['admin', 'user'], 'Invalid role');\n * ```\n */\n oneOf(this: StringSchemaBuilder, ...args: any[]) {\n let values: string[];\n let errorMessage:\n | ValidationErrorMessageProvider<StringSchemaBuilder>\n | undefined;\n\n if (args.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n if (Array.isArray(args[0])) {\n // Array form: oneOf(['a', 'b', 'c'], errorMessage?)\n values = args[0] as string[];\n errorMessage = args[1] as\n | ValidationErrorMessageProvider<StringSchemaBuilder>\n | undefined;\n } else {\n // Rest params form: oneOf('a', 'b', 'c') or oneOf('a', 'b', errorFn)\n // Last arg is a function → error message factory (unambiguous)\n const lastArg = args[args.length - 1];\n if (typeof lastArg === 'function') {\n values = args.slice(0, -1) as string[];\n errorMessage =\n lastArg as ValidationErrorMessageProvider<StringSchemaBuilder>;\n } else {\n values = args as string[];\n errorMessage = undefined;\n }\n }\n\n if (values.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n const allowed = new Set(values);\n return this.withExtension('oneOf', values).addValidator(val => {\n if (typeof val === 'string' && allowed.has(val)) {\n return { valid: true, errors: [] };\n }\n return validationFail(\n errorMessage,\n `must be one of: ${values.join(', ')}`,\n val,\n this\n );\n });\n }\n }\n});\n","/**\n * Pre‑wired extension pack for `@cleverbrush/schema`.\n *\n * Combines {@link stringExtensions}, {@link numberExtensions},\n * and {@link arrayExtensions} via\n * `withExtensions()` and re‑exports the augmented factory functions.\n *\n * The default `@cleverbrush/schema` entry point re‑exports these\n * augmented factories so that `email()`, `positive()`, `nonempty()`,\n * `.nullable()`, etc. are available without any setup.\n *\n * @module\n */\nimport type { AnySchemaBuilder } from '../builders/AnySchemaBuilder.js';\nimport type { ArraySchemaBuilder } from '../builders/ArraySchemaBuilder.js';\nimport type { BooleanSchemaBuilder } from '../builders/BooleanSchemaBuilder.js';\nimport type { DateSchemaBuilder } from '../builders/DateSchemaBuilder.js';\nimport type { FunctionSchemaBuilder } from '../builders/FunctionSchemaBuilder.js';\nimport type { NumberSchemaBuilder } from '../builders/NumberSchemaBuilder.js';\nimport type { ObjectSchemaBuilder } from '../builders/ObjectSchemaBuilder.js';\nimport type { PromiseSchemaBuilder } from '../builders/PromiseSchemaBuilder.js';\nimport type { RecordSchemaBuilder } from '../builders/RecordSchemaBuilder.js';\nimport type {\n SchemaBuilder,\n ValidationErrorMessageProvider\n} from '../builders/SchemaBuilder.js';\nimport type { StringSchemaBuilder } from '../builders/StringSchemaBuilder.js';\nimport type { TupleSchemaBuilder } from '../builders/TupleSchemaBuilder.js';\nimport type { UnionSchemaBuilder } from '../builders/UnionSchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { withExtensions } from '../extension.js';\nimport type { ArrayBuiltinExtensions } from './array.js';\nimport { arrayExtensions } from './array.js';\nimport type { NumberBuiltinExtensions } from './number.js';\nimport { numberExtensions } from './number.js';\nimport type { StringBuiltinExtensions } from './string.js';\nimport { stringExtensions } from './string.js';\n\nexport { type ArrayBuiltinExtensions, arrayExtensions } from './array.js';\nexport {\n type NumberBuiltinExtensions,\n type NumberOneOfExtension,\n numberExtensions\n} from './number.js';\nexport {\n type StringBuiltinExtensions,\n type StringOneOfExtension,\n stringExtensions\n} from './string.js';\n\n// ---------------------------------------------------------------------------\n// Explicitly-typed factories — preserves JSDoc in .d.ts output.\n// WORKAROUND: TypeScript strips JSDoc when signatures pass through the\n// FixedMethods mapped type (conditional `infer` loses comments). These\n// explicit type aliases + factory annotations bypass FixedMethods so that\n// JSDoc from the *BuiltinExtensions interfaces reaches consumers.\n// Remove once TypeScript preserves JSDoc through mapped types.\n// See: https://github.com/microsoft/TypeScript/issues/50715\n// ---------------------------------------------------------------------------\n\n/** A `StringSchemaBuilder` with built-in extension methods. */\nexport type ExtendedString<T extends string = string> = StringSchemaBuilder<\n T,\n true,\n false,\n false,\n StringBuiltinExtensions<T>\n> &\n StringBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/** A `NumberSchemaBuilder` with built-in extension methods. */\nexport type ExtendedNumber<T extends number = number> = NumberSchemaBuilder<\n T,\n true,\n false,\n false,\n NumberBuiltinExtensions<T>\n> &\n NumberBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/** An `ArraySchemaBuilder` with built-in extension methods. */\nexport type ExtendedArray<\n TElementSchema extends SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n > = SchemaBuilder<any, any, any>\n> = ArraySchemaBuilder<\n TElementSchema,\n true,\n false,\n undefined,\n false,\n ArrayBuiltinExtensions<TElementSchema>\n> &\n ArrayBuiltinExtensions<TElementSchema> &\n HiddenExtensionMethods;\n\n/** A `BooleanSchemaBuilder` with built-in extension methods. */\nexport type ExtendedBoolean = BooleanSchemaBuilder<\n boolean,\n true,\n false,\n undefined,\n false,\n {}\n> &\n HiddenExtensionMethods;\n\n/** A `DateSchemaBuilder` with built-in extension methods. */\nexport type ExtendedDate = DateSchemaBuilder<Date, true, false, false, {}> &\n HiddenExtensionMethods;\n\n/** An `ObjectSchemaBuilder` with built-in extension methods. */\nexport type ExtendedObject<\n TProps extends Record<string, SchemaBuilder<any, any, any, any, any>> = {}\n> = ObjectSchemaBuilder<TProps, true, false, undefined, false, {}, []> &\n HiddenExtensionMethods;\n\n/** A `UnionSchemaBuilder` with built-in extension methods. */\nexport type ExtendedUnion<\n TOptions extends readonly SchemaBuilder<any, any, any, any, any>[]\n> = UnionSchemaBuilder<TOptions, true, false, undefined, false, {}> &\n HiddenExtensionMethods;\n\n/** A `FunctionSchemaBuilder` with built-in extension methods. */\nexport type ExtendedFunc = FunctionSchemaBuilder<\n true,\n false,\n undefined,\n false,\n {}\n> &\n HiddenExtensionMethods;\n\n/** A `PromiseSchemaBuilder` with built-in extension methods. */\nexport type ExtendedPromise<\n TResolvedTypeSchema extends\n | SchemaBuilder<any, any, any, any, any>\n | undefined = undefined\n> = PromiseSchemaBuilder<\n true,\n false,\n undefined,\n false,\n {},\n TResolvedTypeSchema\n> &\n HiddenExtensionMethods;\n\n/** An `AnySchemaBuilder` with built-in extension methods. */\nexport type ExtendedAny = AnySchemaBuilder<true, false, undefined, false, {}> &\n HiddenExtensionMethods;\n\n/** A `TupleSchemaBuilder` with built-in extension methods. */\nexport type ExtendedTuple<\n TElements extends readonly SchemaBuilder<\n any,\n any,\n any\n >[] = readonly SchemaBuilder<any, any, any, any, any>[]\n> = TupleSchemaBuilder<TElements, true, false, undefined, false, {}> &\n HiddenExtensionMethods;\n\n/** A `RecordSchemaBuilder` with built-in extension methods. */\nexport type ExtendedRecord<\n TKeySchema extends StringSchemaBuilder<\n any,\n any,\n any,\n any\n > = StringSchemaBuilder<any, any, any, any>,\n TValueSchema extends SchemaBuilder<any, any, any, any, any> = SchemaBuilder<\n any,\n any,\n any\n >\n> = RecordSchemaBuilder<\n TKeySchema,\n TValueSchema,\n true,\n false,\n undefined,\n false,\n {}\n> &\n HiddenExtensionMethods;\n\n// -- Runtime factories with explicit type annotations -------------------------\n\nconst s = withExtensions(stringExtensions, numberExtensions, arrayExtensions);\n\nexport const string: {\n (): ExtendedString;\n <T extends string>(equals: T): ExtendedString<T>;\n} = s.string as any;\n\nexport const number: {\n (): ExtendedNumber;\n <T extends number>(equals: T): ExtendedNumber<T>;\n} = s.number as any;\n\nexport const array: <\n TElementSchema extends SchemaBuilder<any, any, any, any, any>\n>(\n elementSchema?: TElementSchema\n) => ExtendedArray<TElementSchema> = s.array as any;\n\nexport const boolean: () => ExtendedBoolean = s.boolean as any;\nexport const date: () => ExtendedDate = s.date as any;\nexport const object: {\n (): ExtendedObject<{}>;\n <TProps extends Record<string, SchemaBuilder<any, any, any, any, any>>>(\n props: TProps\n ): ExtendedObject<TProps>;\n <TProps extends Record<string, SchemaBuilder<any, any, any, any, any>>>(\n props?: TProps\n ): ExtendedObject<TProps>;\n} = s.object as any;\nexport const union: <TOptions extends SchemaBuilder<any, any, any, any, any>>(\n schema: TOptions\n) => ExtendedUnion<[TOptions]> = s.union as any;\nexport const func: () => ExtendedFunc = s.func as any;\nexport const any: () => ExtendedAny = s.any as any;\nexport const tuple: <\n const TElements extends readonly SchemaBuilder<any, any, any, any, any>[]\n>(\n elements: [...TElements]\n) => ExtendedTuple<TElements> = s.tuple as any;\n\nexport const record: <\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) => ExtendedRecord<TKeySchema, TValueSchema> = s.record as any;\n\nexport const promise: <TWrapped extends SchemaBuilder<any, any, any, any, any>>(\n wrapped: TWrapped\n) => ExtendedPromise<TWrapped> = s.promise as any;\n\n/**\n * Creates a string schema constrained to the given literal values.\n *\n * Convenience factory equivalent to `string().oneOf(...values)`.\n * Mirrors Zod's `z.enum(['admin', 'user', 'guest'])` API.\n *\n * **Rest-params form** (no custom error message):\n * ```ts\n * const Role = enumOf('admin', 'user', 'guest');\n * ```\n *\n * **Array form** (with optional custom error message):\n * ```ts\n * const Role = enumOf(['admin', 'user', 'guest'], 'Invalid role');\n * const Role2 = enumOf(['admin', 'user'], (val) => `\"${val}\" is not a valid role`);\n * ```\n *\n * @param values - the allowed string literals (at least one required)\n * @returns a typed `StringSchemaBuilder` that only accepts the given values\n *\n * @example\n * ```ts\n * import { enumOf, InferType } from '@cleverbrush/schema';\n *\n * const Role = enumOf('admin', 'user', 'guest');\n * type Role = InferType<typeof Role>; // 'admin' | 'user' | 'guest'\n *\n * Role.validate('admin'); // valid\n * Role.validate('other'); // invalid\n * ```\n */\nexport function enumOf<const T extends string>(\n ...values: [T, ...T[]]\n): ExtendedString<T>;\nexport function enumOf<const T extends string>(\n values: readonly [T, ...T[]],\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n): ExtendedString<T>;\nexport function enumOf<const T extends string>(\n ...args:\n | [T, ...T[]]\n | [\n readonly [T, ...T[]],\n ValidationErrorMessageProvider<StringSchemaBuilder>?\n ]\n): ExtendedString<T> {\n if (Array.isArray(args[0])) {\n return string().oneOf(\n args[0] as readonly [T, ...T[]],\n args[1] as\n | ValidationErrorMessageProvider<StringSchemaBuilder>\n | undefined\n ) as unknown as ExtendedString<T>;\n }\n return string().oneOf(\n ...(args as [T, ...T[]])\n ) as unknown as ExtendedString<T>;\n}\n"],"mappings":"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","names":["validationFail","provider","defaultMsg","value","schema","resolveErrorMessage","result","arrayExtensions","defineExtension","errorMessage","val","validationFail","keyFn","meta","seen","item","key","numberExtensions","defineExtension","errorMessage","val","validationFail","n","remainder","tolerance","args","values","lastArg","allowed","UUID_RE","IPV4_RE","IPV6_RE","stringExtensions","defineExtension","errorMessage","val","validationFail","optsOrError","opts","p","protocols","meta","valid","defaultMsg","proto","version","args","values","lastArg","allowed","s","withExtensions","stringExtensions","numberExtensions","arrayExtensions","string","number","array","boolean","date","object","union","func","any","tuple","record","promise","enumOf","args"]}
|
|
1
|
+
{"version":3,"sources":["../src/extensions/util.ts","../src/extensions/array.ts","../src/extensions/number.ts","../src/extensions/string.ts","../src/extensions/index.ts"],"sourcesContent":["import type { ValidationErrorMessageProvider } from '../builders/SchemaBuilder.js';\n\n/** Validation result returned by validators on failure. */\ninterface ValidationFailure {\n valid: false;\n errors: { message: string }[];\n}\n\n/**\n * Builds a synchronous validation-failure result, resolving the user-supplied\n * error-message provider (or falling back to `defaultMsg`).\n *\n * @param provider - custom error message provider (string, sync function, or `undefined`)\n * @param defaultMsg - fallback message used when `provider` is `undefined`\n * @param value - the value that failed validation\n * @param schema - the schema builder instance\n * @returns a `{ valid: false, errors: [{ message }] }` object\n */\nexport function validationFail(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultMsg: string,\n value: unknown,\n schema: unknown\n): ValidationFailure {\n const msg = resolveErrorMessage(provider, defaultMsg, value, schema);\n return { valid: false, errors: [{ message: msg }] };\n}\n\n/**\n * Synchronously resolves a {@link ValidationErrorMessageProvider} to a concrete error message string.\n * Returns the default message when no custom provider is supplied.\n * Throws if the provider function returns a Promise.\n *\n * @param provider - custom error message provider (string, sync function, or `undefined`)\n * @param defaultMsg - fallback message used when `provider` is `undefined`\n * @param value - the value that failed validation (passed to function providers)\n * @param schema - the schema builder instance (passed to function providers)\n * @returns the resolved error message string\n * @throws Error if the provider returns a Promise\n */\nexport function resolveErrorMessage(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultMsg: string,\n value: unknown,\n schema: unknown\n): string {\n if (provider === undefined) return defaultMsg;\n if (typeof provider === 'string') return provider;\n const result = provider(value, schema);\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/**\n * Asynchronously resolves a {@link ValidationErrorMessageProvider} to a concrete error message string.\n * Returns the default message when no custom provider is supplied.\n * Supports async provider functions.\n *\n * @param provider - custom error message provider (string, function, or `undefined`)\n * @param defaultMsg - fallback message used when `provider` is `undefined`\n * @param value - the value that failed validation (passed to function providers)\n * @param schema - the schema builder instance (passed to function providers)\n * @returns the resolved error message string\n */\nexport async function resolveErrorMessageAsync(\n provider: ValidationErrorMessageProvider<any> | undefined,\n defaultMsg: string,\n value: unknown,\n schema: unknown\n): Promise<string> {\n if (provider === undefined) return defaultMsg;\n if (typeof provider === 'string') return provider;\n return provider(value, schema);\n}\n","/**\n * Built-in array extensions for `@cleverbrush/schema`.\n *\n * Provides common array validators: {@link arrayExtensions | nonempty}\n * and {@link arrayExtensions | unique}.\n *\n * These are pre-applied in the default `@cleverbrush/schema` import.\n * Import from `@cleverbrush/schema/core` to get bare builders without these extensions.\n *\n * @module\n */\nimport type { ArraySchemaBuilder } from '../builders/ArraySchemaBuilder.js';\nimport type {\n SchemaBuilder,\n ValidationErrorMessageProvider\n} from '../builders/SchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { defineExtension } from '../extension.js';\nimport { validationFail } from './util.js';\n\n// ---------------------------------------------------------------------------\n// Public interface — carries JSDoc into .d.ts for consumers\n// ---------------------------------------------------------------------------\n\n/** Return type shared by every method on {@link ArrayBuiltinExtensions}. */\ntype ArrayExtReturn<\n TElementSchema extends SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n > = SchemaBuilder<any, any, any>\n> = ArraySchemaBuilder<\n TElementSchema,\n true,\n false,\n undefined,\n false,\n ArrayBuiltinExtensions<TElementSchema>\n> &\n ArrayBuiltinExtensions<TElementSchema> &\n HiddenExtensionMethods;\n\n/**\n * Methods added to `ArraySchemaBuilder` by the built-in array extension pack.\n *\n * **WORKAROUND:** This interface duplicates the method signatures from\n * `arrayExtensions` so that JSDoc survives into the published `.d.ts`\n * files. TypeScript strips JSDoc when method signatures are reconstructed\n * through the `FixedMethods` mapped type (conditional `infer` loses\n * comments). Remove this interface once TypeScript preserves JSDoc\n * through mapped types / conditional type inference.\n *\n * @see https://github.com/microsoft/TypeScript/issues/50715\n */\nexport interface ArrayBuiltinExtensions<\n TElementSchema extends SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n > = SchemaBuilder<any, any, any>\n> {\n /**\n * Validates that the array contains at least one element.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * array().nonempty();\n * array().nonempty('At least one item required');\n * ```\n */\n nonempty(\n errorMessage?: ValidationErrorMessageProvider<ArraySchemaBuilder<any>>\n ): ArrayExtReturn<TElementSchema>;\n\n /**\n * Validates that all elements in the array are unique.\n *\n * For primitive elements, uses strict equality. For objects, pass a `keyFn`\n * that extracts a comparison key from each element.\n *\n * @param keyFn - optional function to extract a comparison key from each element\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the unique validator applied\n *\n * @example\n * ```ts\n * array().unique();\n * array().unique((item) => item.id);\n * array().unique(undefined, 'No duplicates allowed');\n * ```\n */\n unique(\n keyFn?: (item: any) => unknown,\n errorMessage?: ValidationErrorMessageProvider<ArraySchemaBuilder<any>>\n ): ArrayExtReturn<TElementSchema>;\n}\n\n/**\n * Extension descriptor that adds common array validators\n * to `ArraySchemaBuilder`.\n *\n * Included methods: `nonempty`, `unique`.\n *\n * @example\n * ```ts\n * import { withExtensions } from '@cleverbrush/schema/core';\n * import { arrayExtensions } from '@cleverbrush/schema';\n *\n * const s = withExtensions(arrayExtensions);\n * const schema = s.array().nonempty().unique();\n * ```\n */\nexport const arrayExtensions = defineExtension({\n array: {\n /**\n * Validates that the array contains at least one element.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * array().nonempty();\n * array().nonempty('At least one item required');\n * ```\n */\n nonempty(\n this: ArraySchemaBuilder<any>,\n errorMessage?: ValidationErrorMessageProvider<\n ArraySchemaBuilder<any>\n >\n ) {\n return this.withExtension('nonempty', true).addValidator(\n (val: unknown[]) => {\n if (!Array.isArray(val))\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n const valid = val.length > 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n }\n );\n },\n\n /**\n * Validates that all elements in the array are unique.\n *\n * For primitive elements, uses strict equality. For objects, pass a `keyFn`\n * that extracts a comparison key from each element.\n *\n * @param keyFn - optional function to extract a comparison key from each element\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the unique validator applied\n *\n * @example\n * ```ts\n * array().unique();\n * array().unique((item) => item.id);\n * array().unique(undefined, 'No duplicates allowed');\n * ```\n */\n unique(\n this: ArraySchemaBuilder<any>,\n keyFn?: (item: any) => unknown,\n errorMessage?: ValidationErrorMessageProvider<\n ArraySchemaBuilder<any>\n >\n ) {\n const meta = keyFn ?? true;\n\n return this.withExtension('unique', meta).addValidator(\n (val: unknown[]) => {\n if (!Array.isArray(val))\n return validationFail(\n errorMessage,\n 'must contain unique elements',\n val,\n this\n );\n const seen = new Set();\n for (const item of val) {\n const key = keyFn ? keyFn(item) : item;\n if (seen.has(key)) {\n return validationFail(\n errorMessage,\n 'must contain unique elements',\n val,\n this\n );\n }\n seen.add(key);\n }\n return { valid: true, errors: [] };\n }\n );\n }\n }\n});\n","/**\n * Built-in number extensions for `@cleverbrush/schema`.\n *\n * Provides common number validators: {@link numberExtensions | positive},\n * {@link numberExtensions | negative}, {@link numberExtensions | finite},\n * {@link numberExtensions | multipleOf}, and {@link numberExtensions | oneOf}.\n *\n * These are pre-applied in the default `@cleverbrush/schema` import.\n * Import from `@cleverbrush/schema/core` to get bare builders without these extensions.\n *\n * @module\n */\nimport type { NumberSchemaBuilder } from '../builders/NumberSchemaBuilder.js';\nimport type { ValidationErrorMessageProvider } from '../builders/SchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { defineExtension } from '../extension.js';\nimport { validationFail } from './util.js';\n\n// ---------------------------------------------------------------------------\n// Public interface — carries JSDoc into .d.ts for consumers\n// ---------------------------------------------------------------------------\n\n/** Return type shared by every method on {@link NumberBuiltinExtensions}. */\ntype NumberExtReturn<T extends number = number> = NumberSchemaBuilder<\n T,\n true,\n false,\n false,\n NumberBuiltinExtensions<T>\n> &\n NumberBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/**\n * Methods added to `NumberSchemaBuilder` by the built-in number extension pack.\n *\n * **WORKAROUND:** This interface duplicates the method signatures from\n * `numberExtensions` so that JSDoc survives into the published `.d.ts`\n * files. TypeScript strips JSDoc when method signatures are reconstructed\n * through the `FixedMethods` mapped type (conditional `infer` loses\n * comments). Remove this interface once TypeScript preserves JSDoc\n * through mapped types / conditional type inference.\n *\n * @see https://github.com/microsoft/TypeScript/issues/50715\n */\nexport interface NumberBuiltinExtensions<T extends number = number> {\n /**\n * Validates that the number is strictly greater than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the positive validator applied\n *\n * @example\n * ```ts\n * number().positive();\n * number().positive('Must be greater than zero');\n * ```\n */\n positive(\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Validates that the number is strictly less than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the negative validator applied\n *\n * @example\n * ```ts\n * number().negative();\n * number().negative('Must be below zero');\n * ```\n */\n negative(\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Validates that the number is finite (rejects `Infinity` and `-Infinity`).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the finite validator applied\n *\n * @example\n * ```ts\n * number().finite();\n * number().finite('No infinities allowed');\n * ```\n */\n finite(\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Validates that the number is an exact multiple of `n`.\n *\n * Uses a relative tolerance of `1e-10` for float-safe comparison.\n *\n * @param n - the divisor to check against\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the multipleOf validator applied\n *\n * @example\n * ```ts\n * number().multipleOf(5);\n * number().multipleOf(0.1, 'Must be a multiple of 0.1');\n * ```\n */\n multipleOf(\n n: number,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<T>;\n\n /**\n * Constrains the number to one of the specified literal values.\n *\n * Narrows the inferred type from `number` to the union of the\n * provided literals.\n *\n * @param values - the allowed number literals\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * import { number, InferType } from '@cleverbrush/schema';\n *\n * const priority = number().oneOf(1, 2, 3);\n * type Priority = InferType<typeof priority>; // 1 | 2 | 3\n *\n * priority.validate(1); // valid\n * priority.validate(4); // invalid — \"must be one of: 1, 2, 3\"\n * ```\n */\n oneOf<V extends number>(...values: [V, ...V[]]): NumberExtReturn<V>;\n\n /**\n * Constrains the number to one of the specified literal values,\n * with a custom error message or factory as the last argument.\n *\n * @example\n * ```ts\n * const priority = number().oneOf(1, 2, 3, 'Priority must be 1, 2, or 3');\n * const priority2 = number().oneOf(1, 2, 3, (val) => `${val} is not a valid priority`);\n * ```\n */\n oneOf<V extends number>(\n ...args: [\n ...[V, ...V[]],\n ValidationErrorMessageProvider<NumberSchemaBuilder>\n ]\n ): NumberExtReturn<V>;\n\n /**\n * Constrains the number to one of the specified literal values,\n * with an optional custom error message or factory.\n *\n * @param values - the allowed number literals as an array\n * @param errorMessage - optional custom error message or factory function\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * const priority = number().oneOf([1, 2, 3], 'Must be 1, 2, or 3');\n * ```\n */\n oneOf<V extends number>(\n values: readonly [V, ...V[]],\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ): NumberExtReturn<V>;\n}\n\n/**\n * Subset of {@link NumberBuiltinExtensions} containing only the `.oneOf()` overloads.\n * Exported for backward compatibility.\n */\nexport type NumberOneOfExtension = Pick<NumberBuiltinExtensions, 'oneOf'>;\n\n/**\n * Extension descriptor that adds common number validators\n * to `NumberSchemaBuilder`.\n *\n * Included methods: `positive`, `negative`, `finite`, `multipleOf`, `oneOf`.\n *\n * @example\n * ```ts\n * import { withExtensions } from '@cleverbrush/schema/core';\n * import { numberExtensions } from '@cleverbrush/schema';\n *\n * const s = withExtensions(numberExtensions);\n * const schema = s.number().positive().multipleOf(5);\n * ```\n */\nexport const numberExtensions = defineExtension({\n number: {\n /**\n * Validates that the number is strictly greater than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the positive validator applied\n *\n * @example\n * ```ts\n * number().positive();\n * number().positive('Must be greater than zero');\n * ```\n */\n positive(\n this: NumberSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n return this.withExtension('positive', true).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n 'must be a positive number',\n val,\n this\n );\n const valid = val > 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a positive number',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the number is strictly less than zero.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the negative validator applied\n *\n * @example\n * ```ts\n * number().negative();\n * number().negative('Must be below zero');\n * ```\n */\n negative(\n this: NumberSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n return this.withExtension('negative', true).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n 'must be a negative number',\n val,\n this\n );\n const valid = val < 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a negative number',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the number is finite (rejects `Infinity` and `-Infinity`).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the finite validator applied\n *\n * @example\n * ```ts\n * number().finite();\n * number().finite('No infinities allowed');\n * ```\n */\n finite(\n this: NumberSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n return this.withExtension('finite', true).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n 'must be a finite number',\n val,\n this\n );\n const valid = Number.isFinite(val);\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a finite number',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the number is an exact multiple of `n`.\n *\n * Uses a relative tolerance of `1e-10` for float-safe comparison.\n *\n * @param n - the divisor to check against\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the multipleOf validator applied\n *\n * @example\n * ```ts\n * number().multipleOf(5);\n * number().multipleOf(0.1, 'Must be a multiple of 0.1');\n * ```\n */\n multipleOf(\n this: NumberSchemaBuilder,\n n: number,\n errorMessage?: ValidationErrorMessageProvider<NumberSchemaBuilder>\n ) {\n if (n === 0 || !Number.isFinite(n)) {\n throw new Error(\n 'multipleOf: n must be a finite, non-zero number'\n );\n }\n return this.withExtension('multipleOf', n).addValidator(val => {\n if (typeof val !== 'number')\n return validationFail(\n errorMessage,\n `must be a multiple of ${n}`,\n val,\n this\n );\n const remainder = Math.abs(val % n);\n const tolerance = Math.abs(n) * 1e-10;\n const valid =\n remainder < tolerance ||\n Math.abs(remainder - Math.abs(n)) < tolerance;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n `must be a multiple of ${n}`,\n val,\n this\n );\n });\n },\n\n /**\n * Constrains the number to one of the specified literal values.\n *\n * @param args - the allowed number literals, optionally followed by an error message\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * number().oneOf(1, 2, 3);\n * number().oneOf([1, 2, 3], 'Must be 1, 2, or 3');\n * ```\n */\n oneOf(this: NumberSchemaBuilder, ...args: any[]) {\n let values: number[];\n let errorMessage:\n | ValidationErrorMessageProvider<NumberSchemaBuilder>\n | undefined;\n\n if (args.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n if (Array.isArray(args[0])) {\n // Array form: oneOf([1, 2, 3], errorMessage?)\n values = args[0] as number[];\n errorMessage = args[1] as\n | ValidationErrorMessageProvider<NumberSchemaBuilder>\n | undefined;\n } else {\n // Rest params form: oneOf(1, 2, 3) or oneOf(1, 2, 3, 'error') or oneOf(1, 2, 3, errorFn)\n // Last arg is a string or function → error message (unambiguous since values are numbers)\n const lastArg = args[args.length - 1];\n if (\n typeof lastArg === 'string' ||\n typeof lastArg === 'function'\n ) {\n values = args.slice(0, -1) as number[];\n errorMessage =\n lastArg as ValidationErrorMessageProvider<NumberSchemaBuilder>;\n } else {\n values = args as number[];\n errorMessage = undefined;\n }\n }\n\n if (values.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n const allowed = new Set(values);\n return this.withExtension('oneOf', values).addValidator(val => {\n if (typeof val === 'number' && allowed.has(val)) {\n return { valid: true, errors: [] };\n }\n return validationFail(\n errorMessage,\n `must be one of: ${values.join(', ')}`,\n val,\n this\n );\n });\n }\n }\n});\n","/**\n * Built-in string extensions for `@cleverbrush/schema`.\n *\n * Provides common string validators and preprocessors: {@link stringExtensions | email},\n * {@link stringExtensions | url}, {@link stringExtensions | uuid},\n * {@link stringExtensions | ip}, {@link stringExtensions | trim},\n * {@link stringExtensions | toLowerCase}, {@link stringExtensions | nonempty},\n * and {@link stringExtensions | oneOf}.\n *\n * These are pre-applied in the default `@cleverbrush/schema` import.\n * Import from `@cleverbrush/schema/core` to get bare builders without these extensions.\n *\n * @module\n */\nimport type { ValidationErrorMessageProvider } from '../builders/SchemaBuilder.js';\nimport type { StringSchemaBuilder } from '../builders/StringSchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { defineExtension } from '../extension.js';\nimport { validationFail } from './util.js';\n\n// ---------------------------------------------------------------------------\n// Public interface — carries JSDoc into .d.ts for consumers\n// ---------------------------------------------------------------------------\n\n/** Return type shared by every method on {@link StringBuiltinExtensions}. */\ntype StringExtReturn<T extends string = string> = StringSchemaBuilder<\n T,\n true,\n false,\n false,\n StringBuiltinExtensions<T>\n> &\n StringBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/**\n * Methods added to `StringSchemaBuilder` by the built-in string extension pack.\n *\n * **WORKAROUND:** This interface duplicates the method signatures from\n * `stringExtensions` so that JSDoc survives into the published `.d.ts`\n * files. TypeScript strips JSDoc when method signatures are reconstructed\n * through the `FixedMethods` mapped type (conditional `infer` loses\n * comments). Remove this interface once TypeScript preserves JSDoc\n * through mapped types / conditional type inference.\n *\n * @see https://github.com/microsoft/TypeScript/issues/50715\n */\nexport interface StringBuiltinExtensions<T extends string = string> {\n /**\n * Validates that the string is a well-formed email address.\n *\n * Uses the pattern `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$` for validation.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the email validator applied\n *\n * @example\n * ```ts\n * string().email();\n * string().email('Please enter a valid email');\n * string().email((val) => `\"${val}\" is not a valid email`);\n * ```\n */\n email(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Validates that the string is a well-formed URL.\n *\n * By default only `http` and `https` protocols are accepted.\n * Pass `opts.protocols` to restrict or expand the allowed set.\n *\n * @param opts - optional configuration\n * @param opts.protocols - allowed URL protocols (default: `['http', 'https']`)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the URL validator applied\n *\n * @example\n * ```ts\n * string().url();\n * string().url({ protocols: ['https'] });\n * string().url('Must be a valid URL');\n * string().url({ protocols: ['https'] }, 'Must be a valid URL');\n * ```\n */\n url(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n url(\n opts?: { protocols?: string[] },\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Validates that the string is a valid UUID (versions 1–5).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the UUID validator applied\n *\n * @example\n * ```ts\n * string().uuid();\n * string().uuid('Invalid identifier');\n * ```\n */\n uuid(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Validates that the string is a valid IP address (IPv4 or IPv6).\n *\n * Pass `opts.version` to restrict validation to a specific IP version.\n *\n * @param opts - optional configuration\n * @param opts.version - restrict to `'v4'` or `'v6'` (default: accept both)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the IP validator applied\n *\n * @example\n * ```ts\n * string().ip();\n * string().ip({ version: 'v4' });\n * string().ip(undefined, 'Bad IP address');\n * ```\n */\n ip(\n opts?: { version?: 'v4' | 'v6' },\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Preprocessor that trims leading and trailing whitespace before validation.\n *\n * @returns a new schema builder with the trim preprocessor applied\n *\n * @example\n * ```ts\n * string().trim().minLength(1); // ' hi ' → 'hi'\n * ```\n */\n trim(): StringExtReturn<T>;\n\n /**\n * Preprocessor that converts the string to lowercase before validation.\n *\n * @returns a new schema builder with the toLowerCase preprocessor applied\n *\n * @example\n * ```ts\n * string().toLowerCase(); // 'HELLO' → 'hello'\n * ```\n */\n toLowerCase(): StringExtReturn<T>;\n\n /**\n * Validates that the string is not empty (length > 0).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * string().nonempty();\n * string().nonempty('Name is required');\n * ```\n */\n nonempty(\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<T>;\n\n /**\n * Constrains the string to one of the specified literal values.\n *\n * Narrows the inferred type from `string` to the union of the\n * provided literals.\n *\n * @param values - the allowed string literals\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * import { string, InferType } from '@cleverbrush/schema';\n *\n * const role = string().oneOf('admin', 'user', 'guest');\n * type Role = InferType<typeof role>; // 'admin' | 'user' | 'guest'\n *\n * role.validate('admin'); // valid\n * role.validate('other'); // invalid — \"must be one of: admin, user, guest\"\n * ```\n */\n oneOf<V extends string>(...values: [V, ...V[]]): StringExtReturn<V>;\n\n /**\n * Constrains the string to one of the specified literal values,\n * with a custom error message or factory as the last argument.\n *\n * @example\n * ```ts\n * const role = string().oneOf('admin', 'user', (val) => `\"${val}\" is not allowed`);\n * ```\n */\n oneOf<V extends string>(\n ...args: [\n ...[V, ...V[]],\n ValidationErrorMessageProvider<StringSchemaBuilder>\n ]\n ): StringExtReturn<V>;\n\n /**\n * Constrains the string to one of the specified literal values,\n * with an optional custom error message or factory.\n *\n * @param values - the allowed string literals as an array\n * @param errorMessage - optional custom error message or factory function\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * const role = string().oneOf(['admin', 'user', 'guest'], 'Invalid role');\n * ```\n */\n oneOf<V extends string>(\n values: readonly [V, ...V[]],\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ): StringExtReturn<V>;\n}\n\n/**\n * Subset of {@link StringBuiltinExtensions} containing only the `.oneOf()` overloads.\n * Exported for backward compatibility.\n */\nexport type StringOneOfExtension = Pick<StringBuiltinExtensions, 'oneOf'>;\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nconst IPV4_RE =\n /^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/;\n\nconst IPV6_RE =\n /^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$|^::(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4}$|^(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}$|^(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}$|^(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}$|^(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}$|^(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}$|^[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}$|^::$/i;\n\n/**\n * Extension descriptor that adds common string validators and preprocessors\n * to `StringSchemaBuilder`.\n *\n * Included methods: `email`, `url`, `uuid`, `ip`, `trim`, `toLowerCase`, `nonempty`, `oneOf`.\n *\n * @example\n * ```ts\n * import { withExtensions } from '@cleverbrush/schema/core';\n * import { stringExtensions } from '@cleverbrush/schema';\n *\n * const s = withExtensions(stringExtensions);\n * const schema = s.string().email().trim();\n * ```\n */\nexport const stringExtensions = defineExtension({\n string: {\n /**\n * Validates that the string is a well-formed email address.\n *\n * Uses the pattern `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$` for validation.\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the email validator applied\n *\n * @example\n * ```ts\n * string().email();\n * string().email('Please enter a valid email');\n * string().email((val) => `\"${val}\" is not a valid email`);\n * ```\n */\n email(\n this: StringSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n return this.withExtension('email', true).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must be a valid email',\n val,\n this\n );\n const valid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(val);\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a valid email',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the string is a well-formed URL.\n *\n * By default only `http` and `https` protocols are accepted.\n * Pass `opts.protocols` to restrict or expand the allowed set.\n *\n * @param opts - optional configuration\n * @param opts.protocols - allowed URL protocols (default: `['http', 'https']`)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the URL validator applied\n *\n * @example\n * ```ts\n * string().url();\n * string().url({ protocols: ['https'] });\n * string().url('Must be a valid URL');\n * string().url({ protocols: ['https'] }, 'Must be a valid URL');\n * ```\n */\n url(\n this: StringSchemaBuilder,\n optsOrError?:\n | { protocols?: string[] }\n | ValidationErrorMessageProvider<StringSchemaBuilder>,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n let opts: { protocols?: string[] } | undefined;\n if (\n typeof optsOrError === 'string' ||\n typeof optsOrError === 'function'\n ) {\n errorMessage = optsOrError;\n opts = undefined;\n } else {\n opts = optsOrError;\n }\n if (\n opts?.protocols !== undefined &&\n (opts.protocols.length === 0 ||\n opts.protocols.some(p => !p || p.trim() === ''))\n ) {\n throw new Error(\n 'url: opts.protocols must be a non-empty array of non-empty strings'\n );\n }\n const protocols = opts?.protocols ?? ['http', 'https'];\n const meta = opts?.protocols ? { protocols: opts.protocols } : true;\n\n return this.withExtension('url', meta).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must be a valid URL',\n val,\n this\n );\n let valid = false;\n let defaultMsg = 'must be a valid URL';\n try {\n const parsed = new URL(val);\n const proto = parsed.protocol.replace(':', '');\n valid = protocols.includes(proto);\n if (!valid)\n defaultMsg = `protocol must be one of: ${protocols.join(', ')}`;\n } catch {\n /* invalid URL */\n }\n if (valid) return { valid: true, errors: [] };\n return validationFail(errorMessage, defaultMsg, val, this);\n });\n },\n\n /**\n * Validates that the string is a valid UUID (versions 1–5).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the UUID validator applied\n *\n * @example\n * ```ts\n * string().uuid();\n * string().uuid('Invalid identifier');\n * ```\n */\n uuid(\n this: StringSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n return this.withExtension('uuid', true).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must be a valid UUID',\n val,\n this\n );\n const valid = UUID_RE.test(val);\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must be a valid UUID',\n val,\n this\n );\n });\n },\n\n /**\n * Validates that the string is a valid IP address (IPv4 or IPv6).\n *\n * Pass `opts.version` to restrict validation to a specific IP version.\n *\n * @param opts - optional configuration\n * @param opts.version - restrict to `'v4'` or `'v6'` (default: accept both)\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the IP validator applied\n *\n * @example\n * ```ts\n * string().ip();\n * string().ip({ version: 'v4' });\n * string().ip(undefined, 'Bad IP address');\n * ```\n */\n ip(\n this: StringSchemaBuilder,\n opts?: { version?: 'v4' | 'v6' },\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n const version = opts?.version;\n const meta = version ? { version } : true;\n\n return this.withExtension('ip', meta).addValidator(val => {\n const defaultMsg = version\n ? `must be a valid ${version} IP address`\n : 'must be a valid IP address';\n if (typeof val !== 'string')\n return validationFail(errorMessage, defaultMsg, val, this);\n let valid: boolean;\n if (version === 'v4') {\n valid = IPV4_RE.test(val);\n } else if (version === 'v6') {\n valid = IPV6_RE.test(val);\n } else {\n valid = IPV4_RE.test(val) || IPV6_RE.test(val);\n }\n if (valid) return { valid: true, errors: [] };\n return validationFail(errorMessage, defaultMsg, val, this);\n });\n },\n\n /**\n * Preprocessor that trims leading and trailing whitespace before validation.\n *\n * @returns a new schema builder with the trim preprocessor applied\n *\n * @example\n * ```ts\n * string().trim().minLength(1); // ' hi ' → 'hi'\n * ```\n */\n trim(this: StringSchemaBuilder) {\n return this.addPreprocessor(val =>\n typeof val === 'string' ? val.trim() : val\n );\n },\n\n /**\n * Preprocessor that converts the string to lowercase before validation.\n *\n * @returns a new schema builder with the toLowerCase preprocessor applied\n *\n * @example\n * ```ts\n * string().toLowerCase(); // 'HELLO' → 'hello'\n * ```\n */\n toLowerCase(this: StringSchemaBuilder) {\n return this.addPreprocessor(val =>\n typeof val === 'string' ? val.toLowerCase() : val\n );\n },\n\n /**\n * Validates that the string is not empty (length > 0).\n *\n * @param errorMessage - custom error message or function to generate one\n * @returns a new schema builder with the nonempty validator applied\n *\n * @example\n * ```ts\n * string().nonempty();\n * string().nonempty('Name is required');\n * ```\n */\n nonempty(\n this: StringSchemaBuilder,\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n ) {\n return this.withExtension('nonempty', true).addValidator(val => {\n if (typeof val !== 'string')\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n const valid = val.length > 0;\n if (valid) return { valid: true, errors: [] };\n return validationFail(\n errorMessage,\n 'must not be empty',\n val,\n this\n );\n });\n },\n\n /**\n * Constrains the string to one of the specified literal values.\n *\n * @param args - the allowed string literals, optionally followed by an error message\n * @returns a new schema builder restricted to the given values\n *\n * @example\n * ```ts\n * string().oneOf('admin', 'user', 'guest');\n * string().oneOf(['admin', 'user'], 'Invalid role');\n * ```\n */\n oneOf(this: StringSchemaBuilder, ...args: any[]) {\n let values: string[];\n let errorMessage:\n | ValidationErrorMessageProvider<StringSchemaBuilder>\n | undefined;\n\n if (args.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n if (Array.isArray(args[0])) {\n // Array form: oneOf(['a', 'b', 'c'], errorMessage?)\n values = args[0] as string[];\n errorMessage = args[1] as\n | ValidationErrorMessageProvider<StringSchemaBuilder>\n | undefined;\n } else {\n // Rest params form: oneOf('a', 'b', 'c') or oneOf('a', 'b', errorFn)\n // Last arg is a function → error message factory (unambiguous)\n const lastArg = args[args.length - 1];\n if (typeof lastArg === 'function') {\n values = args.slice(0, -1) as string[];\n errorMessage =\n lastArg as ValidationErrorMessageProvider<StringSchemaBuilder>;\n } else {\n values = args as string[];\n errorMessage = undefined;\n }\n }\n\n if (values.length === 0) {\n throw new Error('oneOf requires at least one value');\n }\n\n const allowed = new Set(values);\n return this.withExtension('oneOf', values).addValidator(val => {\n if (typeof val === 'string' && allowed.has(val)) {\n return { valid: true, errors: [] };\n }\n return validationFail(\n errorMessage,\n `must be one of: ${values.join(', ')}`,\n val,\n this\n );\n });\n }\n }\n});\n","/**\n * Pre‑wired extension pack for `@cleverbrush/schema`.\n *\n * Combines {@link stringExtensions}, {@link numberExtensions},\n * and {@link arrayExtensions} via\n * `withExtensions()` and re‑exports the augmented factory functions.\n *\n * The default `@cleverbrush/schema` entry point re‑exports these\n * augmented factories so that `email()`, `positive()`, `nonempty()`,\n * `.nullable()`, etc. are available without any setup.\n *\n * @module\n */\nimport type { AnySchemaBuilder } from '../builders/AnySchemaBuilder.js';\nimport type { ArraySchemaBuilder } from '../builders/ArraySchemaBuilder.js';\nimport type { BooleanSchemaBuilder } from '../builders/BooleanSchemaBuilder.js';\nimport type { DateSchemaBuilder } from '../builders/DateSchemaBuilder.js';\nimport type { FunctionSchemaBuilder } from '../builders/FunctionSchemaBuilder.js';\nimport type { NumberSchemaBuilder } from '../builders/NumberSchemaBuilder.js';\nimport type { ObjectSchemaBuilder } from '../builders/ObjectSchemaBuilder.js';\nimport type { PromiseSchemaBuilder } from '../builders/PromiseSchemaBuilder.js';\nimport type { RecordSchemaBuilder } from '../builders/RecordSchemaBuilder.js';\nimport type {\n SchemaBuilder,\n ValidationErrorMessageProvider\n} from '../builders/SchemaBuilder.js';\nimport type { StringSchemaBuilder } from '../builders/StringSchemaBuilder.js';\nimport type { TupleSchemaBuilder } from '../builders/TupleSchemaBuilder.js';\nimport type { UnionSchemaBuilder } from '../builders/UnionSchemaBuilder.js';\nimport type { HiddenExtensionMethods } from '../extension.js';\nimport { withExtensions } from '../extension.js';\nimport type { ArrayBuiltinExtensions } from './array.js';\nimport { arrayExtensions } from './array.js';\nimport type { NumberBuiltinExtensions } from './number.js';\nimport { numberExtensions } from './number.js';\nimport type { StringBuiltinExtensions } from './string.js';\nimport { stringExtensions } from './string.js';\n\nexport { type ArrayBuiltinExtensions, arrayExtensions } from './array.js';\nexport {\n type NumberBuiltinExtensions,\n type NumberOneOfExtension,\n numberExtensions\n} from './number.js';\nexport {\n type StringBuiltinExtensions,\n type StringOneOfExtension,\n stringExtensions\n} from './string.js';\n\n// ---------------------------------------------------------------------------\n// Explicitly-typed factories — preserves JSDoc in .d.ts output.\n// WORKAROUND: TypeScript strips JSDoc when signatures pass through the\n// FixedMethods mapped type (conditional `infer` loses comments). These\n// explicit type aliases + factory annotations bypass FixedMethods so that\n// JSDoc from the *BuiltinExtensions interfaces reaches consumers.\n// Remove once TypeScript preserves JSDoc through mapped types.\n// See: https://github.com/microsoft/TypeScript/issues/50715\n// ---------------------------------------------------------------------------\n\n/** A `StringSchemaBuilder` with built-in extension methods. */\nexport type ExtendedString<T extends string = string> = StringSchemaBuilder<\n T,\n true,\n false,\n false,\n StringBuiltinExtensions<T>\n> &\n StringBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/** A `NumberSchemaBuilder` with built-in extension methods. */\nexport type ExtendedNumber<T extends number = number> = NumberSchemaBuilder<\n T,\n true,\n false,\n false,\n NumberBuiltinExtensions<T>\n> &\n NumberBuiltinExtensions<T> &\n HiddenExtensionMethods;\n\n/** An `ArraySchemaBuilder` with built-in extension methods. */\nexport type ExtendedArray<\n TElementSchema extends SchemaBuilder<\n any,\n any,\n any,\n any,\n any\n > = SchemaBuilder<any, any, any>\n> = ArraySchemaBuilder<\n TElementSchema,\n true,\n false,\n undefined,\n false,\n ArrayBuiltinExtensions<TElementSchema>\n> &\n ArrayBuiltinExtensions<TElementSchema> &\n HiddenExtensionMethods;\n\n/** A `BooleanSchemaBuilder` with built-in extension methods. */\nexport type ExtendedBoolean = BooleanSchemaBuilder<\n boolean,\n true,\n false,\n undefined,\n false,\n {}\n> &\n HiddenExtensionMethods;\n\n/** A `DateSchemaBuilder` with built-in extension methods. */\nexport type ExtendedDate = DateSchemaBuilder<Date, true, false, false, {}> &\n HiddenExtensionMethods;\n\n/** An `ObjectSchemaBuilder` with built-in extension methods. */\nexport type ExtendedObject<\n TProps extends Record<string, SchemaBuilder<any, any, any, any, any>> = {}\n> = ObjectSchemaBuilder<TProps, true, false, undefined, false, {}, []> &\n HiddenExtensionMethods;\n\n/** A `UnionSchemaBuilder` with built-in extension methods. */\nexport type ExtendedUnion<\n TOptions extends readonly SchemaBuilder<any, any, any, any, any>[]\n> = UnionSchemaBuilder<TOptions, true, false, undefined, false, {}> &\n HiddenExtensionMethods;\n\n/** A `FunctionSchemaBuilder` with built-in extension methods. */\nexport type ExtendedFunc = FunctionSchemaBuilder<\n true,\n false,\n undefined,\n false,\n {}\n> &\n HiddenExtensionMethods;\n\n/** A `PromiseSchemaBuilder` with built-in extension methods. */\nexport type ExtendedPromise<\n TResolvedTypeSchema extends\n | SchemaBuilder<any, any, any, any, any>\n | undefined = undefined\n> = PromiseSchemaBuilder<\n true,\n false,\n undefined,\n false,\n {},\n TResolvedTypeSchema\n> &\n HiddenExtensionMethods;\n\n/** An `AnySchemaBuilder` with built-in extension methods. */\nexport type ExtendedAny = AnySchemaBuilder<true, false, undefined, false, {}> &\n HiddenExtensionMethods;\n\n/** A `TupleSchemaBuilder` with built-in extension methods. */\nexport type ExtendedTuple<\n TElements extends readonly SchemaBuilder<\n any,\n any,\n any\n >[] = readonly SchemaBuilder<any, any, any, any, any>[]\n> = TupleSchemaBuilder<TElements, true, false, undefined, false, {}> &\n HiddenExtensionMethods;\n\n/** A `RecordSchemaBuilder` with built-in extension methods. */\nexport type ExtendedRecord<\n TKeySchema extends StringSchemaBuilder<\n any,\n any,\n any,\n any\n > = StringSchemaBuilder<any, any, any, any>,\n TValueSchema extends SchemaBuilder<any, any, any, any, any> = SchemaBuilder<\n any,\n any,\n any\n >\n> = RecordSchemaBuilder<\n TKeySchema,\n TValueSchema,\n true,\n false,\n undefined,\n false,\n {}\n> &\n HiddenExtensionMethods;\n\n// -- Runtime factories with explicit type annotations -------------------------\n\nconst s = withExtensions(stringExtensions, numberExtensions, arrayExtensions);\n\nexport const string: {\n (): ExtendedString;\n <T extends string>(equals: T): ExtendedString<T>;\n} = s.string as any;\n\nexport const number: {\n (): ExtendedNumber;\n <T extends number>(equals: T): ExtendedNumber<T>;\n} = s.number as any;\n\nexport const array: <\n TElementSchema extends SchemaBuilder<any, any, any, any, any>\n>(\n elementSchema?: TElementSchema\n) => ExtendedArray<TElementSchema> = s.array as any;\n\nexport const boolean: () => ExtendedBoolean = s.boolean as any;\nexport const date: () => ExtendedDate = s.date as any;\nexport const object: {\n (): ExtendedObject<{}>;\n <TProps extends Record<string, SchemaBuilder<any, any, any, any, any>>>(\n props: TProps\n ): ExtendedObject<TProps>;\n <TProps extends Record<string, SchemaBuilder<any, any, any, any, any>>>(\n props?: TProps\n ): ExtendedObject<TProps>;\n} = s.object as any;\nexport const union: <TOptions extends SchemaBuilder<any, any, any, any, any>>(\n schema: TOptions\n) => ExtendedUnion<[TOptions]> = s.union as any;\nexport const func: () => ExtendedFunc = s.func as any;\nexport const any: () => ExtendedAny = s.any as any;\nexport const tuple: <\n const TElements extends readonly SchemaBuilder<any, any, any, any, any>[]\n>(\n elements: [...TElements]\n) => ExtendedTuple<TElements> = s.tuple as any;\n\nexport const record: <\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) => ExtendedRecord<TKeySchema, TValueSchema> = s.record as any;\n\nexport const promise: <TWrapped extends SchemaBuilder<any, any, any, any, any>>(\n wrapped: TWrapped\n) => ExtendedPromise<TWrapped> = s.promise as any;\n\n/**\n * Creates a string schema constrained to the given literal values.\n *\n * Convenience factory equivalent to `string().oneOf(...values)`.\n * Mirrors Zod's `z.enum(['admin', 'user', 'guest'])` API.\n *\n * **Rest-params form** (no custom error message):\n * ```ts\n * const Role = enumOf('admin', 'user', 'guest');\n * ```\n *\n * **Array form** (with optional custom error message):\n * ```ts\n * const Role = enumOf(['admin', 'user', 'guest'], 'Invalid role');\n * const Role2 = enumOf(['admin', 'user'], (val) => `\"${val}\" is not a valid role`);\n * ```\n *\n * @param values - the allowed string literals (at least one required)\n * @returns a typed `StringSchemaBuilder` that only accepts the given values\n *\n * @example\n * ```ts\n * import { enumOf, InferType } from '@cleverbrush/schema';\n *\n * const Role = enumOf('admin', 'user', 'guest');\n * type Role = InferType<typeof Role>; // 'admin' | 'user' | 'guest'\n *\n * Role.validate('admin'); // valid\n * Role.validate('other'); // invalid\n * ```\n */\nexport function enumOf<const T extends string>(\n ...values: [T, ...T[]]\n): ExtendedString<T>;\nexport function enumOf<const T extends string>(\n values: readonly [T, ...T[]],\n errorMessage?: ValidationErrorMessageProvider<StringSchemaBuilder>\n): ExtendedString<T>;\nexport function enumOf<const T extends string>(\n ...args:\n | [T, ...T[]]\n | [\n readonly [T, ...T[]],\n ValidationErrorMessageProvider<StringSchemaBuilder>?\n ]\n): ExtendedString<T> {\n if (Array.isArray(args[0])) {\n return string().oneOf(\n args[0] as readonly [T, ...T[]],\n args[1] as\n | ValidationErrorMessageProvider<StringSchemaBuilder>\n | undefined\n ) as unknown as ExtendedString<T>;\n }\n return string().oneOf(\n ...(args as [T, ...T[]])\n ) as unknown as ExtendedString<T>;\n}\n"],"mappings":"sxBAkBO,SAASA,EACZC,EACAC,EACAC,EACAC,EACiB,CAEjB,MAAO,CAAE,MAAO,GAAO,OAAQ,CAAC,CAAE,QADtBC,EAAoBJ,EAAUC,EAAYC,EAAOC,CAAM,CACpB,CAAC,CAAE,CACtD,CAcO,SAASC,EACZJ,EACAC,EACAC,EACAC,EACM,CACN,GAAIH,IAAa,OAAW,OAAOC,EACnC,GAAI,OAAOD,GAAa,SAAU,OAAOA,EACzC,IAAMK,EAASL,EAASE,EAAOC,CAAM,EACrC,GAAIE,aAAkB,QAClB,MAAM,IAAI,MACN,+FACJ,EAEJ,OAAOA,CACX,CCgEO,IAAMC,EAAkBC,EAAgB,CAC3C,MAAO,CAaH,SAEIC,EAGF,CACE,OAAO,KAAK,cAAc,WAAY,EAAI,EAAE,aACvCC,GACQ,MAAM,QAAQA,CAAG,EAORA,EAAI,OAAS,EACT,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,oBACAC,EACA,IACJ,EAbWC,EACHF,EACA,oBACAC,EACA,IACJ,CAUZ,CACJ,EAmBA,OAEIE,EACAH,EAGF,CACE,IAAMI,EAAOD,GAAS,GAEtB,OAAO,KAAK,cAAc,SAAUC,CAAI,EAAE,aACrCH,GAAmB,CAChB,GAAI,CAAC,MAAM,QAAQA,CAAG,EAClB,OAAOC,EACHF,EACA,+BACAC,EACA,IACJ,EACJ,IAAMI,EAAO,IAAI,IACjB,QAAWC,KAAQL,EAAK,CACpB,IAAMM,EAAMJ,EAAQA,EAAMG,CAAI,EAAIA,EAClC,GAAID,EAAK,IAAIE,CAAG,EACZ,OAAOL,EACHF,EACA,+BACAC,EACA,IACJ,EAEJI,EAAK,IAAIE,CAAG,CAChB,CACA,MAAO,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,CACrC,CACJ,CACJ,CACJ,CACJ,CAAC,ECpBM,IAAMC,EAAmBC,EAAgB,CAC5C,OAAQ,CAaJ,SAEIC,EACF,CACE,OAAO,KAAK,cAAc,WAAY,EAAI,EAAE,aAAaC,GACjD,OAAOA,GAAQ,SACRC,EACHF,EACA,4BACAC,EACA,IACJ,EACUA,EAAM,EACF,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,4BACAC,EACA,IACJ,CACH,CACL,EAcA,SAEID,EACF,CACE,OAAO,KAAK,cAAc,WAAY,EAAI,EAAE,aAAaC,GACjD,OAAOA,GAAQ,SACRC,EACHF,EACA,4BACAC,EACA,IACJ,EACUA,EAAM,EACF,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,4BACAC,EACA,IACJ,CACH,CACL,EAcA,OAEID,EACF,CACE,OAAO,KAAK,cAAc,SAAU,EAAI,EAAE,aAAaC,GAC/C,OAAOA,GAAQ,SACRC,EACHF,EACA,0BACAC,EACA,IACJ,EACU,OAAO,SAASA,CAAG,EACf,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,0BACAC,EACA,IACJ,CACH,CACL,EAiBA,WAEIE,EACAH,EACF,CACE,GAAIG,IAAM,GAAK,CAAC,OAAO,SAASA,CAAC,EAC7B,MAAM,IAAI,MACN,iDACJ,EAEJ,OAAO,KAAK,cAAc,aAAcA,CAAC,EAAE,aAAaF,GAAO,CAC3D,GAAI,OAAOA,GAAQ,SACf,OAAOC,EACHF,EACA,yBAAyBG,CAAC,GAC1BF,EACA,IACJ,EACJ,IAAMG,EAAY,KAAK,IAAIH,EAAME,CAAC,EAC5BE,EAAY,KAAK,IAAIF,CAAC,EAAI,MAIhC,OAFIC,EAAYC,GACZ,KAAK,IAAID,EAAY,KAAK,IAAID,CAAC,CAAC,EAAIE,EACtB,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCH,EACHF,EACA,yBAAyBG,CAAC,GAC1BF,EACA,IACJ,CACJ,CAAC,CACL,EAcA,SAAoCK,EAAa,CAC7C,IAAIC,EACAP,EAIJ,GAAIM,EAAK,SAAW,EAChB,MAAM,IAAI,MAAM,mCAAmC,EAGvD,GAAI,MAAM,QAAQA,EAAK,CAAC,CAAC,EAErBC,EAASD,EAAK,CAAC,EACfN,EAAeM,EAAK,CAAC,MAGlB,CAGH,IAAME,EAAUF,EAAKA,EAAK,OAAS,CAAC,EAEhC,OAAOE,GAAY,UACnB,OAAOA,GAAY,YAEnBD,EAASD,EAAK,MAAM,EAAG,EAAE,EACzBN,EACIQ,IAEJD,EAASD,EACTN,EAAe,OAEvB,CAEA,GAAIO,EAAO,SAAW,EAClB,MAAM,IAAI,MAAM,mCAAmC,EAGvD,IAAME,EAAU,IAAI,IAAIF,CAAM,EAC9B,OAAO,KAAK,cAAc,QAASA,CAAM,EAAE,aAAaN,GAChD,OAAOA,GAAQ,UAAYQ,EAAQ,IAAIR,CAAG,EACnC,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EAE9BC,EACHF,EACA,mBAAmBO,EAAO,KAAK,IAAI,CAAC,GACpCN,EACA,IACJ,CACH,CACL,CACJ,CACJ,CAAC,EChLD,IAAMS,EACF,6EAEEC,EACF,oFAEEC,EACF,0WAiBSC,EAAmBC,EAAgB,CAC5C,OAAQ,CAgBJ,MAEIC,EACF,CACE,OAAO,KAAK,cAAc,QAAS,EAAI,EAAE,aAAaC,GAC9C,OAAOA,GAAQ,SACRC,EACHF,EACA,wBACAC,EACA,IACJ,EACU,6BAA6B,KAAKA,CAAG,EACjC,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,wBACAC,EACA,IACJ,CACH,CACL,EAqBA,IAEIE,EAGAH,EACF,CACE,IAAII,EAUJ,GARI,OAAOD,GAAgB,UACvB,OAAOA,GAAgB,YAEvBH,EAAeG,EACfC,EAAO,QAEPA,EAAOD,EAGPC,GAAM,YAAc,SACnBA,EAAK,UAAU,SAAW,GACvBA,EAAK,UAAU,KAAKC,GAAK,CAACA,GAAKA,EAAE,KAAK,IAAM,EAAE,GAElD,MAAM,IAAI,MACN,oEACJ,EAEJ,IAAMC,EAAYF,GAAM,WAAa,CAAC,OAAQ,OAAO,EAC/CG,EAAOH,GAAM,UAAY,CAAE,UAAWA,EAAK,SAAU,EAAI,GAE/D,OAAO,KAAK,cAAc,MAAOG,CAAI,EAAE,aAAaN,GAAO,CACvD,GAAI,OAAOA,GAAQ,SACf,OAAOC,EACHF,EACA,sBACAC,EACA,IACJ,EACJ,IAAIO,EAAQ,GACRC,EAAa,sBACjB,GAAI,CAEA,IAAMC,EADS,IAAI,IAAIT,CAAG,EACL,SAAS,QAAQ,IAAK,EAAE,EAC7CO,EAAQF,EAAU,SAASI,CAAK,EAC3BF,IACDC,EAAa,4BAA4BH,EAAU,KAAK,IAAI,CAAC,GACrE,MAAQ,CAER,CACA,OAAIE,EAAc,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCN,EAAeF,EAAcS,EAAYR,EAAK,IAAI,CAC7D,CAAC,CACL,EAcA,KAEID,EACF,CACE,OAAO,KAAK,cAAc,OAAQ,EAAI,EAAE,aAAaC,GAC7C,OAAOA,GAAQ,SACRC,EACHF,EACA,uBACAC,EACA,IACJ,EACUN,EAAQ,KAAKM,CAAG,EACZ,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,uBACAC,EACA,IACJ,CACH,CACL,EAmBA,GAEIG,EACAJ,EACF,CACE,IAAMW,EAAUP,GAAM,QAChBG,EAAOI,EAAU,CAAE,QAAAA,CAAQ,EAAI,GAErC,OAAO,KAAK,cAAc,KAAMJ,CAAI,EAAE,aAAaN,GAAO,CACtD,IAAMQ,EAAaE,EACb,mBAAmBA,CAAO,cAC1B,6BACN,GAAI,OAAOV,GAAQ,SACf,OAAOC,EAAeF,EAAcS,EAAYR,EAAK,IAAI,EAC7D,IAAIO,EAQJ,OAPIG,IAAY,KACZH,EAAQZ,EAAQ,KAAKK,CAAG,EACjBU,IAAY,KACnBH,EAAQX,EAAQ,KAAKI,CAAG,EAExBO,EAAQZ,EAAQ,KAAKK,CAAG,GAAKJ,EAAQ,KAAKI,CAAG,EAE7CO,EAAc,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCN,EAAeF,EAAcS,EAAYR,EAAK,IAAI,CAC7D,CAAC,CACL,EAYA,MAAgC,CAC5B,OAAO,KAAK,gBAAgBA,GACxB,OAAOA,GAAQ,SAAWA,EAAI,KAAK,EAAIA,CAC3C,CACJ,EAYA,aAAuC,CACnC,OAAO,KAAK,gBAAgBA,GACxB,OAAOA,GAAQ,SAAWA,EAAI,YAAY,EAAIA,CAClD,CACJ,EAcA,SAEID,EACF,CACE,OAAO,KAAK,cAAc,WAAY,EAAI,EAAE,aAAaC,GACjD,OAAOA,GAAQ,SACRC,EACHF,EACA,oBACAC,EACA,IACJ,EACUA,EAAI,OAAS,EACT,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EACrCC,EACHF,EACA,oBACAC,EACA,IACJ,CACH,CACL,EAcA,SAAoCW,EAAa,CAC7C,IAAIC,EACAb,EAIJ,GAAIY,EAAK,SAAW,EAChB,MAAM,IAAI,MAAM,mCAAmC,EAGvD,GAAI,MAAM,QAAQA,EAAK,CAAC,CAAC,EAErBC,EAASD,EAAK,CAAC,EACfZ,EAAeY,EAAK,CAAC,MAGlB,CAGH,IAAME,EAAUF,EAAKA,EAAK,OAAS,CAAC,EAChC,OAAOE,GAAY,YACnBD,EAASD,EAAK,MAAM,EAAG,EAAE,EACzBZ,EACIc,IAEJD,EAASD,EACTZ,EAAe,OAEvB,CAEA,GAAIa,EAAO,SAAW,EAClB,MAAM,IAAI,MAAM,mCAAmC,EAGvD,IAAME,EAAU,IAAI,IAAIF,CAAM,EAC9B,OAAO,KAAK,cAAc,QAASA,CAAM,EAAE,aAAaZ,GAChD,OAAOA,GAAQ,UAAYc,EAAQ,IAAId,CAAG,EACnC,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EAE9BC,EACHF,EACA,mBAAmBa,EAAO,KAAK,IAAI,CAAC,GACpCZ,EACA,IACJ,CACH,CACL,CACJ,CACJ,CAAC,EC/XD,IAAMe,EAAIC,EAAeC,EAAkBC,EAAkBC,CAAe,EAE/DC,EAGTL,EAAE,OAEOM,EAGTN,EAAE,OAEOO,EAIwBP,EAAE,MAE1BQ,EAAiCR,EAAE,QACnCS,EAA2BT,EAAE,KAC7BU,EAQTV,EAAE,OACOW,EAEoBX,EAAE,MACtBY,EAA2BZ,EAAE,KAC7Ba,EAAyBb,EAAE,IAC3Bc,EAImBd,EAAE,MAErBe,EAMmCf,EAAE,OAErCgB,EAEoBhB,EAAE,QAwC5B,SAASiB,KACTC,EAMc,CACjB,OAAI,MAAM,QAAQA,EAAK,CAAC,CAAC,EACdb,EAAO,EAAE,MACZa,EAAK,CAAC,EACNA,EAAK,CAAC,CAGV,EAEGb,EAAO,EAAE,MACZ,GAAIa,CACR,CACJ","names":["validationFail","provider","defaultMsg","value","schema","resolveErrorMessage","result","arrayExtensions","defineExtension","errorMessage","val","validationFail","keyFn","meta","seen","item","key","numberExtensions","defineExtension","errorMessage","val","validationFail","n","remainder","tolerance","args","values","lastArg","allowed","UUID_RE","IPV4_RE","IPV6_RE","stringExtensions","defineExtension","errorMessage","val","validationFail","optsOrError","opts","p","protocols","meta","valid","defaultMsg","proto","version","args","values","lastArg","allowed","s","withExtensions","stringExtensions","numberExtensions","arrayExtensions","string","number","array","boolean","date","object","union","func","any","tuple","record","promise","enumOf","args"]}
|
package/package.json
CHANGED
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"types": "./dist/core.d.ts",
|
|
32
32
|
"import": "./dist/core.js"
|
|
33
33
|
},
|
|
34
|
+
"./extension": {
|
|
35
|
+
"types": "./dist/extension.d.ts",
|
|
36
|
+
"import": "./dist/extension.js"
|
|
37
|
+
},
|
|
34
38
|
"./string": {
|
|
35
39
|
"types": "./dist/builders/StringSchemaBuilder.d.ts",
|
|
36
40
|
"import": "./dist/builders/StringSchemaBuilder.js"
|
|
@@ -102,9 +106,9 @@
|
|
|
102
106
|
},
|
|
103
107
|
"type": "module",
|
|
104
108
|
"types": "./dist/index.d.ts",
|
|
105
|
-
"version": "
|
|
109
|
+
"version": "4.1.0",
|
|
106
110
|
"devDependencies": {
|
|
107
|
-
"@cleverbrush/deep": "^
|
|
111
|
+
"@cleverbrush/deep": "^4.1.0"
|
|
108
112
|
},
|
|
109
113
|
"peerDependencies": {
|
|
110
114
|
"@standard-schema/spec": "^1.1.0"
|
package/dist/chunk-3JMDGYDT.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var y=Symbol("transaction"),P=[Error,RegExp,Date],R={shouldNotWrapWithTransaction:u=>!!P.find(e=>u instanceof e)},h=(u,e)=>{let r={},a=new Map;e=Object.assign({},R,e||{});let{shouldNotWrapWithTransaction:i}=e,l=()=>!!Object.keys(r).find(s=>r[s]?.[y]?r[s][y].isDirty():!0)||a.size>0,c=()=>{let s={};Object.keys(u).forEach(t=>{s[t]=u[t]}),Object.keys(r).forEach(t=>{let o=r[t];if(o[y]){let{commit:d}=o[y];s[t]=d()}else s[t]=r[t]});for(let t of a.keys())delete s[t];return r={},a=new Map,s},p=()=>{for(let s in r){let t=r[s];t&&typeof t=="object"&&t[y]&&t[y].rollback()}return r={},a=new Map,u};if(Array.isArray(u)){let s=u.map(d=>typeof d=="object"&&d&&!i(d)?h(d).object:d),t=()=>s.map(d=>d&&typeof d[y]=="object"?d[y].commit():d),o=()=>!!s.find((d,f)=>d&&typeof d[y]=="object"?d[y].isDirty():s[f]!==u[f]);return Object.defineProperty(s,y,{writable:!1,configurable:!1,value:{initial:u,object:s,commit:t,rollback:()=>u,isDirty:o}}),{object:s,commit:t,rollback:()=>u,isDirty:o}}let n=new Proxy(u,{set:(s,t,o)=>s&&s[t]===o?(delete r[t],!0):(r[t]=o,a.delete(t),!0),ownKeys:s=>[...Object.keys(s).filter(t=>!a.has(t)),...Object.keys(r).filter(t=>!(t in s))],getOwnPropertyDescriptor:(s,t)=>{if(!a.has(t))return t in r?Object.getOwnPropertyDescriptor(r,t):Object.getOwnPropertyDescriptor(s,t)},has:(s,t)=>a.has(t)?!1:t in r?!0:t in s,get:(s,t)=>{if(typeof t=="symbol")return t===y?{initial:u,object:n,commit:c,rollback:p,isDirty:l}:s[t];if(t in r)return r[t];if(!a.has(t)){if(!g(s[t])&&typeof s[t]=="object"&&s[t]&&!i(s[t])){let{object:o}=h(s[t],e);return r[t]=o,o}return s[t]}},deleteProperty:(s,t)=>(t in r&&(r[t]&&typeof r[t][y]=="object"&&r[t][y].rollback(),delete r[t]),t in s&&a.set(t,!0),!0)});return{object:n,commit:c,rollback:p,isDirty:l}},T=u=>({object:u,commit:()=>u,rollback:()=>u,isDirty:()=>!1}),g=u=>u&&typeof u=="object"&&Object.hasOwn(u,y);var m=class extends Error{errors;constructor(e){let r=e.length>0?e.map(a=>a.message).join("; "):"Validation failed";super(r),this.name="SchemaValidationError",this.errors=e}},x=Symbol(),v=Symbol();function E(u,e,r,a){return Object.defineProperties(u,{seenValue:{get:e,enumerable:!1},errors:{get:r,enumerable:!1},isValid:{get:()=>r().length===0,enumerable:!1},descriptor:{get:a,enumerable:!1}}),u}var b=class{#d=!0;#a=!1;#y=!1;#p;#h;#e=[];#t=[];#n=!1;#T=!0;#c={};#f="base";#m="is required";#o="is required";#s=void 0;#i=void 0;#l=!1;#b=void 0;#u;get"~standard"(){if(this.#u)return this.#u;let e=this;return this.#u={version:1,vendor:"@cleverbrush/schema",validate(r){let a=e.validate(r);return a.valid?{value:a.object}:{issues:(a.errors??[]).map(i=>({message:i.message}))}}},this.#u}get type(){return this.#f}set type(e){if(typeof e!="string"||!e)throw new Error("value should be non empty string");this.#f=e}get preprocessors(){return this.#e}get validators(){return this.#t}get isRequired(){return this.#d}get isNullable(){return this.#a}set isRequired(e){if(typeof e!="boolean")throw new Error("should be a boolean value");this.#d=e}get requiredErrorMessage(){return this.#o}get hasDefault(){return this.#s!==void 0}get hasCatch(){return this.#l}resolveCatchValue(){return typeof this.#i=="function"?this.#i():this.#i}get isReadonly(){return this.#y}resolveDefaultValue(){return typeof this.#s=="function"?this.#s():this.#s}get canSkipPreValidation(){return this.#T}get isNullRequiredViolation(){return!0}#P(e,r){let a=r?.doNotStopOnFirstError??!1,i={doNotStopOnFirstError:a,rootPropertyDescriptor:r?.rootPropertyDescriptor,currentPropertyDescriptor:r?.currentPropertyDescriptor},l=this.#n;return{doNotStopOnFirstError:a,resultingContext:i,transaction:l?h({validatedObject:e}):T({validatedObject:e}),errors:[]}}#r(e,r){return{valid:!1,errors:[e[0]].filter(a=>a),context:r}}#R(e,r,a){return Array.isArray(a)&&a.length?a:[{message:`Validator #${e}${r?` (${r})`:""} didn't pass.`}]}#g(e,r,a,i){return e.length>0?{valid:!1,errors:e.filter(l=>l).filter((l,c)=>r?!0:c===0),context:a,transaction:i}:{valid:!0,context:a,transaction:i}}preValidateSync(e,r){let a=this.#P(e,r),{doNotStopOnFirstError:i,resultingContext:l,errors:c}=a,p=a.transaction,n=p.object.validatedObject;if(this.#e.length>0){let s=0;for(let t of this.#e)try{let o=t.fn(n);if(o instanceof Promise)throw new Error(`Preprocessor #${s}${t.fn.name?` (${t.fn.name})`:""} returned a Promise. Use validateAsync() for schemas with async preprocessors.`);n=o}catch(o){if(o.message?.includes("Use validateAsync()"))throw o;if(c.push({message:`Preprocessor #${s}${t.fn.name?` (${t.fn.name})`:""} thrown an error: ${o.message}`}),!i)return this.#r(c,l)}finally{s++}p=this.#n?h({validatedObject:n}):T({validatedObject:n})}if(typeof n>"u"&&this.hasDefault&&(n=this.resolveDefaultValue(),p=this.#n?h({validatedObject:n}):T({validatedObject:n})),this.#t.length>0&&!(n==null&&!this.isRequired)&&!(n===null&&this.#a)){let s=0;for(let t of this.#t)try{let o=t.fn(n);if(o instanceof Promise)throw new Error(`Validator #${s}${t.fn.name?` (${t.fn.name})`:""} returned a Promise. Use validateAsync() for schemas with async validators.`);let{valid:d,errors:f}=o;if(!d&&(c.push(...this.#R(s,t.fn.name,f)),!i))return this.#r(c,l)}catch(o){if(o.message?.includes("Use validateAsync()"))throw o;if(c.push({message:`Validator #${s}${t.fn.name?` (${t.fn.name})`:""} thrown an error: ${o.message}`}),!i)return this.#r(c,l)}finally{s++}}return this.isRequired&&(typeof n>"u"||n===null&&this.isNullRequiredViolation&&!this.#a)&&(c.push({message:this.getValidationErrorMessageSync(this.#o,n)}),!i)?(p.rollback(),this.#r(c,l)):this.#g(c,i,l,p)}async preValidateAsync(e,r){let a=this.#P(e,r),{doNotStopOnFirstError:i,resultingContext:l,errors:c}=a,p=a.transaction,n=p.object.validatedObject;if(this.#e.length>0){let s=0;for(let t of this.#e)try{n=await Promise.resolve(t.fn(n))}catch(o){if(c.push({message:`Preprocessor #${s}${t.fn.name?` (${t.fn.name})`:""} thrown an error: ${o.message}`}),!i)return this.#r(c,l)}finally{s++}p=this.#n?h({validatedObject:n}):T({validatedObject:n})}if(typeof n>"u"&&this.hasDefault&&(n=this.resolveDefaultValue(),p=this.#n?h({validatedObject:n}):T({validatedObject:n})),this.#t.length>0&&!(n==null&&!this.isRequired)&&!(n===null&&this.#a)){let s=0;for(let t of this.#t)try{let{valid:o,errors:d}=await Promise.resolve(t.fn(n));if(!o&&(c.push(...this.#R(s,t.fn.name,d)),!i))return this.#r(c,l)}catch(o){if(c.push({message:`Validator #${s}${t.fn.name?` (${t.fn.name})`:""} thrown an error: ${o.message}`}),!i)return this.#r(c,l)}finally{s++}}return this.isRequired&&(typeof n>"u"||n===null&&this.isNullRequiredViolation&&!this.#a)&&(c.push({message:await this.getValidationErrorMessage(this.#o,n)}),!i)?(p.rollback(),this.#r(c,l)):this.#g(c,i,l,p)}preValidate(e,r){return this.preValidateAsync(e,r)}introspect(){return{type:this.type,isRequired:this.#d,isNullable:this.#a,isReadonly:this.#y,preprocessors:[...this.preprocessors],validators:[...this.validators],requiredValidationErrorMessageProvider:this.#o,extensions:{...this.#c},hasDefault:this.#s!==void 0,defaultValue:this.#s,description:this.#p,schemaName:this.#h,hasCatch:this.#l,catchValue:this.#i,example:this.#b}}optional(){return this.createFromProps({...this.introspect(),isRequired:!1})}nullable(){return this.createFromProps({...this.introspect(),isNullable:!0})}notNullable(){return this.createFromProps({...this.introspect(),isNullable:!1})}default(e){return this.createFromProps({...this.introspect(),defaultValue:e})}catch(e){return this.createFromProps({...this.introspect(),catchValue:e,hasCatch:!0})}clearDefault(){return this.createFromProps({...this.introspect(),defaultValue:void 0})}describe(e){return this.createFromProps({...this.introspect(),description:e})}example(e){return this.createFromProps({...this.introspect(),example:e})}schemaName(e){return this.createFromProps({...this.introspect(),schemaName:e})}brand(e){return this.createFromProps({...this.introspect()})}readonly(){return this.createFromProps({...this.introspect(),isReadonly:!0})}required(e){return this.createFromProps({...this.introspect(),isRequired:!0,...e!==void 0?{requiredValidationErrorMessageProvider:this.assureValidationErrorMessageProvider(e,this.#m)}:{}})}addPreprocessor(e,r){if(typeof e!="function")throw new Error("preprocessor must be a function");return this.createFromProps({...this.introspect(),preprocessors:[...this.preprocessors,{fn:e,mutates:r?.mutates??!0}]})}clearPreprocessors(){return this.createFromProps({...this.introspect(),preprocessors:[]})}addValidator(e,r){if(typeof e!="function")throw new Error("validator must be a function");return this.createFromProps({...this.introspect(),validators:[...this.validators,{fn:e,mutates:r?.mutates??!1}]})}clearValidators(){return this.createFromProps({...this.introspect(),validators:[]})}validate(e,r){let a=this._validate(e,r);if(!a.valid&&this.#l){let i=this.resolveCatchValue(),l=this._validate(i,r);return l.valid?l:{valid:!0,object:i}}return a}async validateAsync(e,r){let a=await this._validateAsync(e,r);if(!a.valid&&this.#l){let i=this.resolveCatchValue(),l=await this._validateAsync(i,r);return l.valid?l:{valid:!0,object:i}}return a}getValidationErrorMessageSync(e,r){if(typeof e=="string")return e;if(typeof e=="function"){let a=e(r,this);if(a instanceof Promise)throw new Error("Async error message providers require validateAsync(). Use a string or sync function instead.");return a}throw new Error("Invalid error message provider must be a string or a function returning a string")}async getValidationErrorMessage(e,r){if(typeof e=="string")return e;if(typeof e=="function")return e(r,this);throw new Error("Invalid error message provider must be a string or a function returning a string or a promise of a string")}assureValidationErrorMessageProvider(e,r){return typeof e=="string"?e:typeof e=="function"?e.bind(this):typeof r=="function"?r.bind(this):r}withExtension(e,r){return this.createFromProps({...this.introspect(),extensions:{...this.#c,[e]:r}})}getExtension(e){return this.#c[e]}parse(e,r){let a=this.validate(e,r);if(!a.valid)throw new m(a.errors||[]);return a.object}async parseAsync(e,r){let a=await this.validateAsync(e,r);if(!a.valid)throw new m(a.errors||[]);return a.object}safeParse(e,r){return this.validate(e,r)}safeParseAsync(e,r){return this.validateAsync(e,r)}constructor(e){if(!(typeof e=="object"&&e))throw new Error("SchemaBuilder props must be an object");let{type:r,preprocessors:a,validators:i,isRequired:l}=e;this.type=r,typeof l=="boolean"&&(this.isRequired=l),typeof e.isNullable=="boolean"&&(this.#a=e.isNullable),typeof e.isReadonly=="boolean"&&(this.#y=e.isReadonly),Array.isArray(a)&&(this.#e=[...a]),Array.isArray(i)&&(this.#t=[...i]),this.#n=this.#e.some(c=>c.mutates)||this.#t.some(c=>c.mutates),this.#T=this.#e.length===0&&this.#t.length===0,typeof e.extensions=="object"&&e.extensions&&(this.#c={...e.extensions}),e.defaultValue!==void 0&&(this.#s=e.defaultValue),e.hasCatch&&(this.#l=!0,this.#i=e.catchValue),typeof e.description=="string"&&(this.#p=e.description),typeof e.schemaName=="string"&&(this.#h=e.schemaName),e.example!==void 0&&(this.#b=e.example),this.#o=this.assureValidationErrorMessageProvider(e.requiredValidationErrorMessageProvider,this.#m)}};export{h as a,m as b,x as c,v as d,E as e,b as f};
|
|
2
|
-
//# sourceMappingURL=chunk-3JMDGYDT.js.map
|