@cleverbrush/schema 4.0.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +21 -0
  2. package/dist/builders/AnySchemaBuilder.js +1 -1
  3. package/dist/builders/ArraySchemaBuilder.js +1 -1
  4. package/dist/builders/BooleanSchemaBuilder.js +1 -1
  5. package/dist/builders/DateSchemaBuilder.js +1 -1
  6. package/dist/builders/ExternSchemaBuilder.js +1 -1
  7. package/dist/builders/FunctionSchemaBuilder.js +1 -1
  8. package/dist/builders/IntersectionSchemaBuilder.d.ts +124 -0
  9. package/dist/builders/NumberSchemaBuilder.js +1 -1
  10. package/dist/builders/ObjectSchemaBuilder.js +1 -1
  11. package/dist/builders/ParseStringSchemaBuilder.js +1 -1
  12. package/dist/builders/PromiseSchemaBuilder.js +1 -1
  13. package/dist/builders/RecordSchemaBuilder.js +1 -1
  14. package/dist/builders/StringSchemaBuilder.js +1 -1
  15. package/dist/builders/TupleSchemaBuilder.js +1 -1
  16. package/dist/builders/UnionSchemaBuilder.js +1 -1
  17. package/dist/{chunk-ZC2HTRZF.js → chunk-54RHS4F4.js} +2 -2
  18. package/dist/{chunk-4RMOR7SV.js → chunk-6LSN7NXQ.js} +2 -2
  19. package/dist/{chunk-EBGC6ZBF.js → chunk-C6YQOKWB.js} +2 -2
  20. package/dist/{chunk-PUWIYD4T.js → chunk-ELPPAHNO.js} +2 -2
  21. package/dist/{chunk-VRRKXJ2H.js → chunk-G424M7GI.js} +2 -2
  22. package/dist/{chunk-FTA66XZT.js → chunk-JUFZ7PLO.js} +2 -2
  23. package/dist/{chunk-OJJHAZZ4.js → chunk-K4ZLXLE2.js} +2 -2
  24. package/dist/{chunk-3K7MOEPS.js → chunk-KC45JEFL.js} +2 -2
  25. package/dist/{chunk-YYE5HQCL.js → chunk-NF4CRFMN.js} +2 -2
  26. package/dist/{chunk-QG254RGI.js → chunk-ORV2G6ZL.js} +2 -2
  27. package/dist/{chunk-ETJPB3TR.js → chunk-PQINUGZW.js} +2 -2
  28. package/dist/chunk-REYZ7G7J.js +2 -0
  29. package/dist/chunk-REYZ7G7J.js.map +1 -0
  30. package/dist/chunk-VSU5GILY.js +2 -0
  31. package/dist/chunk-VSU5GILY.js.map +1 -0
  32. package/dist/{chunk-SY5EYKF2.js → chunk-XHSBY2QK.js} +2 -2
  33. package/dist/{chunk-57AZDIBB.js → chunk-XL723XFL.js} +2 -2
  34. package/dist/{chunk-ZHBJ46HB.js → chunk-XPLTW5DI.js} +2 -2
  35. package/dist/{chunk-QWYVMYJ2.js → chunk-YAOZEA2R.js} +2 -2
  36. package/dist/core.d.ts +2 -0
  37. package/dist/core.js +1 -1
  38. package/dist/extension.js +1 -1
  39. package/dist/index.js +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/package.json +2 -2
  42. package/dist/chunk-C4LSLV6T.js +0 -2
  43. package/dist/chunk-C4LSLV6T.js.map +0 -1
  44. package/dist/chunk-G6HTNXRO.js +0 -2
  45. package/dist/chunk-G6HTNXRO.js.map +0 -1
  46. /package/dist/{chunk-ZC2HTRZF.js.map → chunk-54RHS4F4.js.map} +0 -0
  47. /package/dist/{chunk-4RMOR7SV.js.map → chunk-6LSN7NXQ.js.map} +0 -0
  48. /package/dist/{chunk-EBGC6ZBF.js.map → chunk-C6YQOKWB.js.map} +0 -0
  49. /package/dist/{chunk-PUWIYD4T.js.map → chunk-ELPPAHNO.js.map} +0 -0
  50. /package/dist/{chunk-VRRKXJ2H.js.map → chunk-G424M7GI.js.map} +0 -0
  51. /package/dist/{chunk-FTA66XZT.js.map → chunk-JUFZ7PLO.js.map} +0 -0
  52. /package/dist/{chunk-OJJHAZZ4.js.map → chunk-K4ZLXLE2.js.map} +0 -0
  53. /package/dist/{chunk-3K7MOEPS.js.map → chunk-KC45JEFL.js.map} +0 -0
  54. /package/dist/{chunk-YYE5HQCL.js.map → chunk-NF4CRFMN.js.map} +0 -0
  55. /package/dist/{chunk-QG254RGI.js.map → chunk-ORV2G6ZL.js.map} +0 -0
  56. /package/dist/{chunk-ETJPB3TR.js.map → chunk-PQINUGZW.js.map} +0 -0
  57. /package/dist/{chunk-SY5EYKF2.js.map → chunk-XHSBY2QK.js.map} +0 -0
  58. /package/dist/{chunk-57AZDIBB.js.map → chunk-XL723XFL.js.map} +0 -0
  59. /package/dist/{chunk-ZHBJ46HB.js.map → chunk-XPLTW5DI.js.map} +0 -0
  60. /package/dist/{chunk-QWYVMYJ2.js.map → chunk-YAOZEA2R.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a as E,b as g,c as ee,d as re}from"./chunk-C4LSLV6T.js";import{a as B,b}from"./chunk-SY5EYKF2.js";import{a as Y,b as Z,c as se,d as oe,e as u,f as p}from"./chunk-ZC2HTRZF.js";import{a as ae}from"./chunk-EBGC6ZBF.js";import{a as X}from"./chunk-OJJHAZZ4.js";import{a as ne}from"./chunk-PUWIYD4T.js";import{a as te}from"./chunk-4RMOR7SV.js";import{a as T}from"./chunk-FTA66XZT.js";import{a as V}from"./chunk-57AZDIBB.js";import{a as ie}from"./chunk-QG254RGI.js";import{a as v}from"./chunk-VRRKXJ2H.js";import{a as C}from"./chunk-ZHBJ46HB.js";import{a as W}from"./chunk-3K7MOEPS.js";import{a as _}from"./chunk-ETJPB3TR.js";import{a as G}from"./chunk-YYE5HQCL.js";import{a as J,b as Q}from"./chunk-QWYVMYJ2.js";import{b as I,c as L,d as K,f as z}from"./chunk-G6HTNXRO.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,oe as EXTRA_TYPE_BRAND,J as ExternSchemaBuilder,X as FunctionSchemaBuilder,Y as GenericSchemaBuilder,E as LazySchemaBuilder,se as METHOD_LITERAL_BRAND,ee as NullSchemaBuilder,ne as NumberSchemaBuilder,te 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,ie as StringSchemaBuilder,v as TupleSchemaBuilder,ae 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,g as lazy,re 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};
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":"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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"]}
package/package.json CHANGED
@@ -106,9 +106,9 @@
106
106
  },
107
107
  "type": "module",
108
108
  "types": "./dist/index.d.ts",
109
- "version": "4.0.0",
109
+ "version": "4.2.0",
110
110
  "devDependencies": {
111
- "@cleverbrush/deep": "^4.0.0"
111
+ "@cleverbrush/deep": "^4.2.0"
112
112
  },
113
113
  "peerDependencies": {
114
114
  "@standard-schema/spec": "^1.1.0"
@@ -1,2 +0,0 @@
1
- import{f as r}from"./chunk-G6HTNXRO.js";var s=class a extends r{#e;#t=null;static create(e){return new a({type:"lazy",...e})}constructor(e){if(super(e),typeof e.getter!="function")throw new Error("LazySchemaBuilder: getter must be a function");this.#e=e.getter}resolve(){return this.#t===null&&(this.#t=this.#e()),this.#t}introspect(){return{...super.introspect(),getter:this.#e}}#a(e,t){let{valid:n,transaction:i,errors:o}=e;if(!n)return{valid:n,errors:o};let{object:{validatedObject:l}}=i;return l==null?{valid:!0,object:l}:this.resolve().validate(l,t)}validate(e,t){return super.validate(e,t)}async validateAsync(e,t){return super.validateAsync(e,t)}_validate(e,t){return this.#a(this.preValidateSync(e,t),t)}async _validateAsync(e,t){let n=await super.preValidateAsync(e,t),{valid:i,transaction:o,errors:l}=n;if(!i)return{valid:i,errors:l};let{object:{validatedObject:d}}=o;return d==null?{valid:!0,object:d}:this.resolve().validateAsync(d,t)}createFromProps(e){return a.create(e)}hasType(e){return this.createFromProps({...this.introspect()})}clearHasType(){return this.createFromProps({...this.introspect()})}required(e){return super.required(e)}optional(){return super.optional()}default(e){return super.default(e)}clearDefault(){return super.clearDefault()}brand(e){return super.brand(e)}readonly(){return super.readonly()}nullable(){return super.nullable()}notNullable(){return super.notNullable()}};function c(a){return s.create({type:"lazy",isRequired:!0,preprocessors:[],validators:[],getter:a})}var u=class a extends r{static create(e){return new a({type:"null",...e})}constructor(e){super(e)}hasType(e){return this.createFromProps({...this.introspect()})}clearHasType(){return this.createFromProps({...this.introspect()})}#e(e){return e===null?{valid:!0,object:null}:e===void 0&&this.hasDefault?this.resolveDefaultValue()===null?{valid:!0,object:null}:{valid:!1,errors:[{message:"must be null"}]}:e===void 0&&!this.isRequired?{valid:!0,object:void 0}:{valid:!1,errors:[{message:"must be null"}]}}validate(e,t){return super.validate(e,t)}async validateAsync(e,t){return super.validateAsync(e,t)}_validate(e,t){return this.#e(e)}async _validateAsync(e,t){return this.#e(e)}createFromProps(e){return a.create(e)}required(e){return super.required(e)}optional(){return super.optional()}default(e){return super.default(e)}clearDefault(){return super.clearDefault()}brand(e){return super.brand(e)}readonly(){return super.readonly()}nullable(){return super.nullable()}notNullable(){return super.notNullable()}},p=()=>u.create({isRequired:!0});export{s as a,c as b,u as c,p as d};
2
- //# sourceMappingURL=chunk-C4LSLV6T.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/builders/LazySchemaBuilder.ts","../src/builders/NullSchemaBuilder.ts"],"sourcesContent":["import {\n type BRAND,\n SchemaBuilder,\n type ValidationContext,\n type ValidationErrorMessageProvider,\n type ValidationResult\n} from './SchemaBuilder.js';\n\ntype LazySchemaBuilderCreateProps<R extends boolean = true> = Partial<\n ReturnType<LazySchemaBuilder<any, R>['introspect']>\n>;\n\n/**\n * Lazy schema builder class. Allows defining recursive/self-referential schemas\n * by wrapping a getter function that returns the target schema. The getter is\n * called once on first validation and the result is cached.\n *\n * This is the primary mechanism for building recursive data structures such as\n * tree nodes, nested menus, and threaded comments.\n *\n * **NOTE** TypeScript cannot infer recursive types automatically, so you must\n * provide an explicit type annotation on the variable holding the schema:\n *\n * @example\n * ```ts\n * type TreeNode = { value: number; children: TreeNode[] };\n *\n * const treeNode: SchemaBuilder<TreeNode, true> = object({\n * value: number(),\n * children: array(lazy(() => treeNode))\n * });\n *\n * treeNode.validate({ value: 1, children: [{ value: 2, children: [] }] });\n * // { valid: true, object: { value: 1, children: [{ value: 2, children: [] }] } }\n * ```\n *\n * @example\n * ```ts\n * type Comment = { text: string; replies: Comment[] };\n *\n * const commentSchema: SchemaBuilder<Comment, true> = object({\n * text: string(),\n * replies: array(lazy(() => commentSchema))\n * });\n * ```\n */\nexport class LazySchemaBuilder<\n TResult = any,\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n THasDefault extends boolean = false,\n TExtensions = {}\n> extends SchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n> {\n #getter: () => SchemaBuilder<TResult, any, any>;\n #resolvedSchema: SchemaBuilder<TResult, any, any> | null = null;\n\n /**\n * @hidden\n */\n public static create(props: LazySchemaBuilderCreateProps<any>) {\n return new LazySchemaBuilder({\n type: 'lazy',\n ...props\n });\n }\n\n protected constructor(props: LazySchemaBuilderCreateProps<TRequired>) {\n super(props as any);\n if (typeof (props as any).getter !== 'function') {\n throw new Error('LazySchemaBuilder: getter must be a function');\n }\n this.#getter = (props as any).getter;\n }\n\n /**\n * Resolves the lazy schema by calling the getter (once; result is cached).\n * After the first call subsequent calls return the cached schema instance.\n */\n public resolve(): SchemaBuilder<TResult, any, any> {\n if (this.#resolvedSchema === null) {\n this.#resolvedSchema = this.#getter();\n }\n return this.#resolvedSchema;\n }\n\n /**\n * @inheritdoc\n */\n public introspect() {\n return {\n ...super.introspect(),\n /**\n * The getter function that returns the lazily-resolved schema.\n * Call {@link LazySchemaBuilder.resolve} to obtain the schema instance.\n */\n getter: this.#getter\n };\n }\n\n #buildResult(\n superResult: ReturnType<LazySchemaBuilder['preValidateSync']>,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n const {\n valid,\n transaction: preValidationTransaction,\n errors\n } = superResult;\n\n if (!valid) {\n return { valid, errors };\n }\n\n const {\n object: { validatedObject: objToValidate }\n } = preValidationTransaction!;\n\n // Value is null/undefined and the schema is optional — skip delegation.\n if (objToValidate == null) {\n return { valid: true, object: objToValidate };\n }\n\n return this.resolve().validate(\n objToValidate,\n context\n ) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validate} */\n public validate(\n object: TResult,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return super.validate(object, context) as ValidationResult<TResult>;\n }\n\n /** {@inheritDoc SchemaBuilder.validateAsync} */\n public async validateAsync(\n object: TResult,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n return super.validateAsync(object, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n /**\n * Performs synchronous validation of the schema over `object`.\n * Throws if any preprocessor, validator, or error message provider returns a Promise.\n * @param context Optional `ValidationContext` settings.\n */\n protected _validate(\n object: TResult,\n context?: ValidationContext\n ): ValidationResult<TResult> {\n return this.#buildResult(\n this.preValidateSync(object, context),\n context\n );\n }\n\n /**\n * Performs async validation of the schema over `object`.\n * Supports async preprocessors, validators, and error message providers.\n * @param context Optional `ValidationContext` settings.\n */\n protected async _validateAsync(\n object: TResult,\n context?: ValidationContext\n ): Promise<ValidationResult<TResult>> {\n const superResult = await super.preValidateAsync(object, context);\n\n const {\n valid,\n transaction: preValidationTransaction,\n errors\n } = superResult;\n\n if (!valid) {\n return { valid, errors };\n }\n\n const {\n object: { validatedObject: objToValidate }\n } = preValidationTransaction!;\n\n if (objToValidate == null) {\n return { valid: true, object: objToValidate };\n }\n\n return this.resolve().validateAsync(objToValidate, context) as Promise<\n ValidationResult<TResult>\n >;\n }\n\n protected createFromProps<TReq extends boolean>(\n props: LazySchemaBuilderCreateProps<TReq>\n ): this {\n return LazySchemaBuilder.create(props as any) as any;\n }\n\n /**\n * @inheritdoc\n */\n public hasType<T>(\n _notUsed?: T\n ): LazySchemaBuilder<T, true, TNullable, THasDefault, TExtensions> &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @inheritdoc\n */\n public clearHasType(): LazySchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public required(\n errorMessage?: ValidationErrorMessageProvider\n ): LazySchemaBuilder<TResult, true, TNullable, THasDefault, TExtensions> &\n TExtensions {\n return super.required(errorMessage);\n }\n\n /**\n * @hidden\n */\n public optional(): LazySchemaBuilder<\n TResult,\n false,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.optional();\n }\n\n /**\n * @hidden\n */\n public default(\n value: TResult | (() => TResult)\n ): LazySchemaBuilder<TResult, true, TNullable, true, TExtensions> &\n TExtensions {\n return super.default(value) as any;\n }\n\n /**\n * @hidden\n */\n public clearDefault(): LazySchemaBuilder<\n TResult,\n TRequired,\n TNullable,\n false,\n TExtensions\n > &\n TExtensions {\n return super.clearDefault() as any;\n }\n\n /**\n * @hidden\n */\n public brand<TBrand extends string | symbol>(\n _name?: TBrand\n ): LazySchemaBuilder<\n TResult & { readonly [K in BRAND]: TBrand },\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.brand(_name);\n }\n\n /**\n * @hidden\n */\n public readonly(): LazySchemaBuilder<\n Readonly<TResult>,\n TRequired,\n TNullable,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.readonly();\n }\n\n /**\n * @hidden\n */\n public nullable(): LazySchemaBuilder<\n TResult,\n TRequired,\n true,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.nullable() as any;\n }\n\n /**\n * @hidden\n */\n public notNullable(): LazySchemaBuilder<\n TResult,\n TRequired,\n false,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.notNullable() as any;\n }\n}\n\n/**\n * Creates a lazy schema that defers the schema definition until first validation.\n * Use this to define recursive/self-referential schemas.\n *\n * The getter function is called **once** on first use and the result is cached.\n * You **must** provide an explicit TypeScript type annotation on the variable\n * holding the outer schema — TypeScript cannot infer recursive types automatically.\n *\n * @param getter - A function that returns the schema to use for validation.\n *\n * @example\n * ```ts\n * // Tree structure\n * type TreeNode = { value: number; children: TreeNode[] };\n *\n * const treeNode: SchemaBuilder<TreeNode, true> = object({\n * value: number(),\n * children: array(lazy(() => treeNode))\n * });\n * ```\n *\n * @example\n * ```ts\n * // Optional recursive field (submenu)\n * type MenuItem = { label: string; submenu?: MenuItem[] };\n *\n * const menuItem: SchemaBuilder<MenuItem, true> = object({\n * label: string(),\n * submenu: array(lazy(() => menuItem)).optional()\n * });\n * ```\n */\nexport function lazy<TResult>(\n getter: () => SchemaBuilder<TResult, any, any>\n): LazySchemaBuilder<TResult, true, false, false, {}> {\n return LazySchemaBuilder.create({\n type: 'lazy',\n isRequired: true,\n preprocessors: [],\n validators: [],\n getter\n } as any);\n}\n","import {\n type BRAND,\n SchemaBuilder,\n type ValidationContext,\n type ValidationErrorMessageProvider,\n type ValidationResult\n} from './SchemaBuilder.js';\n\ntype NullSchemaBuilderCreateProps<R extends boolean = true> = Partial<\n ReturnType<NullSchemaBuilder<R>['introspect']>\n>;\n\n/**\n * Schema builder for `null` values. Validates that the input is exactly `null`.\n *\n * When required (the default), only `null` is accepted. When optional (via\n * `.optional()`), both `null` and `undefined` are accepted; any other value\n * is rejected.\n *\n * This builder is useful when you need to represent an explicitly-null field\n * in a typed schema, for example in discriminated-union branches or when\n * modelling a JSON payload that may carry a JSON `null` value.\n *\n * **NOTE** this class is exported only to give opportunity to extend it\n * by inheriting. It is not recommended to create an instance of this class\n * directly. Use {@link nul | nul()} function instead.\n *\n * @example\n * ```ts\n * import { nul } from '@cleverbrush/schema';\n *\n * const schema = nul();\n *\n * schema.validate(null); // { valid: true, object: null }\n * schema.validate(undefined); // { valid: false }\n * schema.validate(0); // { valid: false }\n * schema.validate(''); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * // Optional — accepts null or undefined\n * const schema = nul().optional();\n *\n * schema.validate(null); // { valid: true, object: null }\n * schema.validate(undefined); // { valid: true, object: undefined }\n * schema.validate(false); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * // Use inside a union to model a nullable string field\n * import { union, string, nul, InferType } from '@cleverbrush/schema';\n *\n * const NullableString = union(string()).or(nul());\n * type NullableString = InferType<typeof NullableString>;\n * // string | null\n *\n * NullableString.validate('hello'); // valid\n * NullableString.validate(null); // valid\n * NullableString.validate(42); // invalid\n * ```\n *\n * @see {@link nul}\n */\nexport class NullSchemaBuilder<\n TRequired extends boolean = true,\n TNullable extends boolean = false,\n TExplicitType = undefined,\n THasDefault extends boolean = false,\n TExtensions = {}\n> extends SchemaBuilder<null, TRequired, TNullable, THasDefault, TExtensions> {\n /**\n * @hidden\n */\n public static create(props: NullSchemaBuilderCreateProps<any>) {\n return new NullSchemaBuilder({\n type: 'null',\n ...props\n });\n }\n\n protected constructor(props: NullSchemaBuilderCreateProps<TRequired>) {\n super(props as any);\n }\n\n /**\n * @hidden\n */\n public hasType<T>(\n _notUsed?: T\n ): NullSchemaBuilder<true, TNullable, T, THasDefault, TExtensions> &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n /**\n * @hidden\n */\n public clearHasType(): NullSchemaBuilder<\n TRequired,\n TNullable,\n undefined,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return this.createFromProps({\n ...this.introspect()\n } as any) as any;\n }\n\n // The SchemaBuilder base-class preValidateSync/preValidateAsync treats\n // null as an invalid value for required schemas, which would prevent null\n // from ever passing validation here. We therefore bypass preValidateSync\n // entirely and implement the full (and simple) validation inline.\n #buildResult(object: any): ValidationResult<null> {\n if (object === null) return { valid: true, object: null };\n\n if (object === undefined && this.hasDefault) {\n const defaultVal = this.resolveDefaultValue();\n if (defaultVal === null) return { valid: true, object: null };\n return { valid: false, errors: [{ message: 'must be null' }] };\n }\n\n if (object === undefined && !this.isRequired) {\n return { valid: true, object: undefined as any };\n }\n\n return {\n valid: false,\n errors: [{ message: 'must be null' }]\n };\n }\n\n /** {@inheritDoc SchemaBuilder.validate} */\n public validate(\n object: null,\n context?: ValidationContext\n ): ValidationResult<null> {\n return super.validate(object, context) as ValidationResult<null>;\n }\n\n /** {@inheritDoc SchemaBuilder.validateAsync} */\n public async validateAsync(\n object: null,\n context?: ValidationContext\n ): Promise<ValidationResult<null>> {\n return super.validateAsync(object, context) as Promise<\n ValidationResult<null>\n >;\n }\n\n /**\n * Performs synchronous validation of the schema over `object`.\n * @param context Optional `ValidationContext` settings.\n */\n protected _validate(\n object: null,\n _context?: ValidationContext\n ): ValidationResult<null> {\n return this.#buildResult(object);\n }\n\n /**\n * Performs async validation of the schema over `object`.\n * @param context Optional `ValidationContext` settings.\n */\n protected async _validateAsync(\n object: null,\n _context?: ValidationContext\n ): Promise<ValidationResult<null>> {\n return this.#buildResult(object);\n }\n\n protected createFromProps<TReq extends boolean>(\n props: NullSchemaBuilderCreateProps<TReq>\n ): this {\n return NullSchemaBuilder.create(props as any) as any;\n }\n\n /**\n * @hidden\n */\n public required(\n errorMessage?: ValidationErrorMessageProvider\n ): NullSchemaBuilder<\n true,\n TNullable,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.required(errorMessage);\n }\n\n /**\n * @hidden\n */\n public optional(): NullSchemaBuilder<\n false,\n TNullable,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.optional();\n }\n\n /**\n * @hidden\n */\n public default(\n value: null | (() => null)\n ): NullSchemaBuilder<true, TNullable, TExplicitType, true, TExtensions> &\n TExtensions {\n return super.default(value) as any;\n }\n\n /**\n * @hidden\n */\n public clearDefault(): NullSchemaBuilder<\n TRequired,\n TNullable,\n TExplicitType,\n false,\n TExtensions\n > &\n TExtensions {\n return super.clearDefault() as any;\n }\n\n /**\n * @hidden\n */\n public brand<TBrand extends string | symbol>(\n _name?: TBrand\n ): NullSchemaBuilder<\n TRequired,\n TNullable,\n null & { readonly [K in BRAND]: TBrand },\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.brand(_name);\n }\n\n /**\n * Marks the inferred type as `Readonly<null>`. Since `null` is already\n * immutable this is an identity operation, but it sets the `isReadonly`\n * introspection flag for tooling consistency.\n *\n * @see {@link SchemaBuilder.readonly}\n */\n public readonly(): NullSchemaBuilder<\n TRequired,\n TNullable,\n Readonly<null>,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.readonly();\n }\n\n /**\n * @hidden\n */\n public nullable(): NullSchemaBuilder<\n TRequired,\n true,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.nullable() as any;\n }\n\n /**\n * @hidden\n */\n public notNullable(): NullSchemaBuilder<\n TRequired,\n false,\n TExplicitType,\n THasDefault,\n TExtensions\n > &\n TExtensions {\n return super.notNullable() as any;\n }\n}\n\n/**\n * Creates a schema that validates the value is exactly `null`.\n *\n * By default the schema is **required** — only `null` is accepted.\n * Call `.optional()` to also allow `undefined`.\n *\n * @example\n * ```ts\n * import { nul } from '@cleverbrush/schema';\n *\n * nul().validate(null); // { valid: true, object: null }\n * nul().validate(undefined); // { valid: false }\n * nul().validate(0); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * nul().optional().validate(null); // { valid: true, object: null }\n * nul().optional().validate(undefined); // { valid: true, object: undefined }\n * nul().optional().validate(false); // { valid: false }\n * ```\n *\n * @example\n * ```ts\n * // Nullable field in an object schema\n * import { object, string, nul, union, InferType } from '@cleverbrush/schema';\n *\n * const Schema = object({\n * name: string(),\n * deleted: union(nul()).or(string()), // null | string\n * });\n *\n * type T = InferType<typeof Schema>;\n * // { name: string; deleted: null | string }\n * ```\n */\nexport const nul = () =>\n NullSchemaBuilder.create({\n isRequired: true\n }) as NullSchemaBuilder<true>;\n"],"mappings":"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","names":["LazySchemaBuilder","_LazySchemaBuilder","SchemaBuilder","#getter","#resolvedSchema","props","#buildResult","superResult","context","valid","preValidationTransaction","errors","objToValidate","object","_notUsed","errorMessage","value","_name","lazy","getter","NullSchemaBuilder","_NullSchemaBuilder","SchemaBuilder","props","_notUsed","#buildResult","object","context","_context","errorMessage","value","_name","nul"]}
@@ -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-G6HTNXRO.js.map