UNPKG

ts-valid8

Version:

A next-generation TypeScript validation library with advanced features

3 lines (2 loc) 10.6 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Valid8={})}(this,(function(e){"use strict";class t{constructor(){this._validators=[],this._isOptional=!1,this._isNullable=!1}validate(e,t={path:[]}){if(void 0===e&&this._isOptional){if(void 0!==this._defaultValue){return{success:!0,value:"function"==typeof this._defaultValue?this._defaultValue():this._defaultValue}}return{success:!0,value:void 0}}if(null===e&&this._isNullable){if(null===e&&void 0!==this._defaultValue){return{success:!0,value:"function"==typeof this._defaultValue?this._defaultValue():this._defaultValue}}return{success:!0,value:null}}const s=this.validateType(e,t);if(!s.success)return s;const r=[];for(const s of this._validators){const n=s(e,t);n&&r.push(n)}return r.length>0?{success:!1,value:e,errors:r}:{success:!0,value:e}}optional(){const e=this.clone();return e._isOptional=!0,e}nullable(){const e=this.clone();return e._isNullable=!0,e}default(e){const t=this.clone();return t._defaultValue=e,t}required(e="This field is required"){const t=this.clone();return t._validators.push(((t,s={path:[]})=>void 0===t?this.createError("required",e,s):null)),t}refine(e,t){const s=this.clone();return s._validators.push(((s,r={path:[]})=>{if(!1===e(s,r)){const e="function"==typeof t?t(s):t;return{path:r.path,message:e,code:"custom"}}return null})),s}transform(e){const t=this.clone();return t._validators.push(((e,t)=>null)),t}createError(e,t,s,r){return{path:s.path,message:t,code:e,params:r}}use(e){return e(this)}}class s extends t{constructor(){super(...arguments),this._type="string",this._patterns=new Map,this._transformers=[]}validateType(e,t){return"string"!=typeof e?{success:!1,value:e,errors:[this.createError("type","Expected string, received "+typeof e,t)]}:{success:!0,value:e}}clone(){const e=new s;return e._validators=[...this._validators],e._isOptional=this._isOptional,e._isNullable=this._isNullable,e._defaultValue=this._defaultValue,e._patterns=new Map(this._patterns),e._transformers=[...this._transformers],e}min(e,t){const s=this.clone();return s._validators.push(((s,r={path:[]})=>"string"==typeof s&&s.length<e?this.createError("string.min",t||`String must be at least ${e} characters long`,r,{minLength:e,actualLength:s.length}):null)),s}max(e,t){const s=this.clone();return s._validators.push(((s,r={path:[]})=>"string"==typeof s&&s.length>e?this.createError("string.max",t||`String must be at most ${e} characters long`,r,{maxLength:e,actualLength:s.length}):null)),s}length(e,t){const s=this.clone();return s._validators.push(((s,r={path:[]})=>"string"==typeof s&&s.length!==e?this.createError("string.length",t||`String must be exactly ${e} characters long`,r,{expectedLength:e,actualLength:s.length}):null)),s}pattern(e,t){const s=this.clone(),r=t||`String must match pattern: ${e}`;return s._patterns.set(e,r),s._validators.push(((t,s={path:[]})=>"string"!=typeof t||e.test(t)?null:this.createError("string.pattern",r,s,{pattern:e.toString()}))),s}email(e){return this.pattern(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,e||"Must be a valid email address")}url(e){return this.pattern(/^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i,e||"Must be a valid URL")}uuid(e){return this.pattern(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,e||"Must be a valid UUID")}password(e){const t={minLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSpecialChars:!0,...e},s=this.clone();return s._validators.push(((e,s={path:[]})=>{if("string"!=typeof e)return null;const r=[];return t.minLength&&e.length<t.minLength&&r.push(`at least ${t.minLength} characters`),t.requireLowercase&&!/[a-z]/.test(e)&&r.push("lowercase letters"),t.requireUppercase&&!/[A-Z]/.test(e)&&r.push("uppercase letters"),t.requireNumbers&&!/[0-9]/.test(e)&&r.push("numbers"),t.requireSpecialChars&&!/[!@#$%^&*(),.?":{}|<>]/.test(e)&&r.push("special characters"),r.length>0?this.createError("string.password",t.customMessage||`Password must contain ${r.join(", ")}`,s,{requirements:t}):null})),s}toUpperCase(){const e=this.clone();return e._transformers=e._transformers||[],e._transformers.push((e=>e.toUpperCase())),e}toLowerCase(){const e=this.clone();return e._transformers=e._transformers||[],e._transformers.push((e=>e.toLowerCase())),e}trim(){const e=this.clone();return e._transformers=e._transformers||[],e._transformers.push((e=>e.trim())),e}transform(e){const t=this.clone();return t._transformers=t._transformers||[],t._transformers.push(e),t}oneOf(e,t){const s=this.clone(),r=Array.isArray(e)?e:[e];return s._validators.push(((e,s={path:[]})=>"string"!=typeof e||r.includes(e)?null:this.createError("string.oneOf",t||`String must be one of: ${r.join(", ")}`,s,{allowedValues:r,actual:e}))),s}}class r extends t{constructor(e){super(),this._type="object",this._crossFieldValidators=[],this._strict=!1,this.shape=e}validateType(e,t){if("object"!=typeof e||null===e||Array.isArray(e))return{success:!1,value:e,errors:[this.createError("type","Expected object, received "+(null===e?"null":Array.isArray(e)?"array":typeof e),t)]};const s=e,r={},n=[];for(const e in this.shape){const a=this.shape[e],i=s[e],o={...t,path:[...t.path,e],parent:s,siblings:s,root:t.root||s},l=a.validate(i,o);r[e]=l.value,!l.success&&l.errors&&n.push(...l.errors)}if(this._strict){const e=Object.keys(this.shape),r=Object.keys(s);for(const s of r)e.includes(s)||n.push(this.createError("object.unknown",`Unrecognized key: ${s}`,{...t,path:[...t.path,s]}))}for(const e of this._crossFieldValidators){const s=e(r,t);s&&n.push(s)}return n.length>0?{success:!1,value:r,errors:n}:{success:!0,value:r}}clone(){const e=new r(this.shape);return e._validators=[...this._validators],e._crossFieldValidators=[...this._crossFieldValidators],e._isOptional=this._isOptional,e._isNullable=this._isNullable,e._defaultValue=this._defaultValue,e._strict=this._strict,e}crossField(e,t,s){const r=this.clone();return r._crossFieldValidators.push(((r,n)=>{if(!1===e(r)){const e="function"==typeof t?t(r):t;return{path:(s?s.map((e=>[...n.path,e])):[n.path])[0],message:e,code:"object.crossField",params:{affectedFields:s}}}return null})),r}passwordsMatch(e,t,s="Passwords must match"){return this.crossField((s=>s[e]===s[t]),s,[t])}strict(e=!0){const t=this.clone();return t._strict=e,t}passthrough(){return this.strict(!1)}when(e,t,s){const n=this.clone();return n._validators.push(((n,a={path:[]})=>{if("object"!=typeof n||null===n)return null;const i=n[e];if(t(i)){const e=s(new r(this.shape)).validate(n,a);if(!e.success&&e.errors)return e.errors[0]}return null})),n}pick(e){const t={};for(const s of e)t[s]=this.shape[s];return new r(t)}omit(e){const t={...this.shape};for(const s of e)delete t[s];return new r(t)}partial(){const e={};for(const t in this.shape)this.shape.hasOwnProperty(t)&&(e[t]=this.shape[t].optional());const t=new r(e);return t._strict=this._strict,t}extend(e){const t={...this.shape};for(const s in e)e.hasOwnProperty(s)&&(t[s]=e[s]);const s=new r(t);return s._strict=this._strict,s}}class n extends t{constructor(){super(...arguments),this._type="boolean"}validateType(e,t){return"boolean"!=typeof e?{success:!1,value:e,errors:[this.createError("type","Expected boolean, received "+typeof e,t)]}:{success:!0,value:e}}clone(){const e=new n;return e._validators=[...this._validators],e._isOptional=this._isOptional,e._isNullable=this._isNullable,e._defaultValue=this._defaultValue,e}true(e="Value must be true"){const t=this.clone();return t._validators.push(((t,s={path:[]})=>!0!==t?this.createError("boolean.true",e,s):null)),t}false(e="Value must be false"){const t=this.clone();return t._validators.push(((t,s={path:[]})=>!1!==t?this.createError("boolean.false",e,s):null)),t}required(e="This field is required"){const t=this.clone();return t._validators.push(((t,s={path:[]})=>void 0===t?this.createError("boolean.required",e,s):null)),t}coerce(){const e=this.clone(),t=e.validateType;return e.validateType=(s,r)=>{if("string"==typeof s){const e=s.toLowerCase().trim();if(["true","1","yes","y","on"].includes(e))return{success:!0,value:!0};if(["false","0","no","n","off"].includes(e))return{success:!0,value:!1}}return 1===s||0===s?{success:!0,value:1===s}:t.call(e,s,r)},e}equals(e,t){const s=this.clone();return s._validators.push(((s,r={path:[]})=>"boolean"==typeof s&&s!==e?this.createError("boolean.equals",t||`Boolean must be ${e}`,r,{expected:e,actual:s}):null)),s}transform(e){const t=this.clone(),s=t.validateType.bind(t);return t.validateType=(t,r)=>{const n=s(t,r);if(n.success)try{n.value=e(n.value)}catch(e){return{success:!1,value:t,errors:[this.createError("boolean.transform","Error transforming boolean value",r,{error:e.message})]}}return n},t}}class a{constructor(){this.plugins=new Map,this.extensions=new Map,this.schemas=new Map,this.validators=new Map}use(e){if(this.plugins.has(e.name))return void console.warn(`Plugin "${e.name}" is already registered. Skipping.`);this.plugins.set(e.name,e);const t={extend:(e,t,s)=>{this.extensions.has(e)||this.extensions.set(e,new Map),this.extensions.get(e).set(t,s)},registerSchema:(e,t)=>{this.schemas.set(e,t)},registerValidator:(e,t)=>{this.validators.set(e,t)}};e.install(t)}getExtension(e,t){const s=this.extensions.get(e);if(s)return s.get(t)}getSchema(e){return this.schemas.get(e)}getValidator(e){return this.validators.get(e)}}const i=new a;const o={string:()=>new s,object:e=>new r(e),boolean:()=>new n,oneOf:e=>({_type:"union",_validators:[],validate(t,s={path:[]}){const r=[];for(const n of e){const e=n.validate(t,s);if(e.success)return e;e.errors&&r.push(...e.errors)}return{success:!1,value:t,errors:r}},optional(){throw new Error("Not implemented")},nullable(){throw new Error("Not implemented")},default(e){throw new Error("Not implemented")},refine(){throw new Error("Not implemented")},required(){throw new Error("Not implemented")},transform(){throw new Error("Not implemented")}}),context:e=>({withSchema:t=>({validate:s=>t.validate(s,{path:[],...e})})}),plugins:{use:i.use.bind(i),create:(e,t,s)=>({name:e,version:t,install:s})}};e.PluginManager=a,e.Valid8=o,e.applyPlugin=function(e,t){if(!e.use)throw new Error(`The schema of type '${e._type}' does not support plugins`);return e.use(t)},e.createPlugin=function(e,t,s){return{name:e,version:t,install:s}},e.default=o,e.pluginManager=i,Object.defineProperty(e,"__esModule",{value:!0})})); //# sourceMappingURL=valid8.umd.js.map