UNPKG

@fajarnugraha37/validator

Version:

A typed façade over [AJV](https://ajv.js.org/) that brings schema builders, caching, and loader pipelines to the `nope` workspace

2 lines (1 loc) 11 kB
var x=Object.defineProperty;var r=(a,e)=>x(a,"name",{value:e,configurable:!0});import w from"ajv";import b from"ajv-formats";import v from"ajv-errors";import O from"ajv-keywords";import{ValidationError as f}from"@fajarnugraha37/error";import{LruTtlCache as K}from"@fajarnugraha37/cache";var d=class a{static{r(this,"ValidatorBuilder")}options={};schemas={};loader;cacheOptions;static create(){return new a}withOptions(e){return this.options={...this.options,...e},this}withSchema(e,t){return this.schemas={...this.schemas,[e]:t},this}withSchemaBuilder(e,t){return this.withSchema(e,t.build())}withSchemas(e){return this.schemas={...this.schemas,...e},this}withSchemaBuilders(e){for(let[t,s]of Object.entries(e))s&&this.withSchemaBuilder(t,s);return this}fromJSON(e){let t=typeof e=="string"?JSON.parse(e):e;if(typeof t!="object"||t===null||Array.isArray(t))throw new Error("Schema JSON must be an object keyed by schema type");return this.withSchemas(t),this}withSchemaLoader(e){return this.loader=e,this}withCache(e={}){return this.cacheOptions=e,this}build(){let e=new m(this.options);return this.cacheOptions&&e.enableSchemaCache(this.cacheOptions),this.loader&&e.setSchemaLoader(this.loader),Object.keys(this.schemas).length>0&&e.registerSchemas(this.schemas),e}};var m=class{static{r(this,"Validator")}ajv;validators=new Map;schemas={};schemaLoader;schemaCache;schemaCacheTtl;constructor(e={}){let t={strict:!0,allErrors:!0,removeAdditional:!1,useDefaults:!0,coerceTypes:!1,verbose:!0,...e};this.ajv=new w.default({...t,strict:!1,validateSchema:!1,addUsedSchema:!1});try{b.default(this.ajv)}catch{}try{v.default(this.ajv)}catch{}try{O.default(this.ajv)}catch{}}static builder(){return new d}registerSchema(e,t){try{this.schemas[e]=t;let s=this.ajv.compile(t);return this.validators.set(e,s),this.cacheSchema(e,t),this}catch(s){throw new Error(`Failed to register schema for type '${String(e)}': ${s}`)}}registerSchemas(e){for(let[t,s]of Object.entries(e))this.registerSchema(t,s);return this}registerSchemaBuilder(e,t){return this.registerSchema(e,t.build())}registerSchemaBuilders(e){for(let[t,s]of Object.entries(e))s&&this.registerSchemaBuilder(t,s);return this}enableSchemaCache(e={}){this.schemaCache=new K({maxEntries:e.maxEntries,maxSize:e.maxSize,sizer:e.sizer,sweepIntervalMs:e.sweepIntervalMs}),this.schemaCacheTtl={ttlMs:e.ttlMs,slidingTtlMs:e.slidingTtlMs};for(let[t,s]of Object.entries(this.schemas))s&&this.cacheSchema(t,s);return this}setSchemaLoader(e){return this.schemaLoader=e,this}importSchemasFromJSON(e,t={}){let s=this.normalizeSchemaInput(e);return(t.register??!0)&&this.registerSchemas(s),s}exportSchemas(e){let t=e??Object.keys(this.schemas),s={};for(let i of t){let c=this.schemas[i];c&&(s[i]=c)}return s}exportSchemasToJSON(e,t=2){return JSON.stringify(this.exportSchemas(e),null,t)}validate(e,t){let s=this.validators.get(e);if(!s)throw new Error(`No schema registered for type '${String(e)}'`);try{return s(t)?{valid:!0,data:t}:{valid:!1,errors:this.formatErrors(s.errors||[])}}catch(i){return{valid:!1,errors:[{keyword:"exception",instancePath:"",schemaPath:"",params:{},message:`Validation exception: ${i}`,data:t}]}}}async validateAsync(e,t){return await this.ensureSchemaLoaded(e),this.validate(e,t)}validateStrict(e,t){let s=this.validate(e,t);if(!s.valid){let i=s.errors?.map(c=>c.message).join(", ")||"Unknown validation error";throw new f(`Validation failed for type '${String(e)}': ${i}`)}return s.data}async validateStrictAsync(e,t){let s=await this.validateAsync(e,t);if(!s.valid){let i=s.errors?.map(c=>c.message).join(", ")||"Unknown validation error";throw new f(`Validation failed for type '${String(e)}': ${i}`)}return s.data}hasSchema(e){return this.validators.has(e)}getSchema(e){return this.schemas[e]}getRegisteredTypes(){return Array.from(this.validators.keys())}validateMany(e,t){let s=t.map(n=>this.validate(e,n)),i=[],c=[];return s.forEach((n,o)=>{if(n.valid&&n.data)c.push(n.data);else if(n.errors){let k=n.errors.map(l=>({...l,instancePath:`[${o}]${l.instancePath}`,message:`Item ${o}: ${l.message}`}));i.push(...k)}}),{valid:i.length===0,data:i.length===0?c:void 0,errors:i.length>0?i:void 0}}async validateManyAsync(e,t){return await this.ensureSchemaLoaded(e),this.validateMany(e,t)}createTypeValidator(e){if(!this.hasSchema(e))throw new Error(`No schema registered for type '${String(e)}'`);return{validate:r(t=>this.validate(e,t),"validate"),validateAsync:r(t=>this.validateAsync(e,t),"validateAsync"),validateStrict:r(t=>this.validateStrict(e,t),"validateStrict"),validateStrictAsync:r(t=>this.validateStrictAsync(e,t),"validateStrictAsync"),validateMany:r(t=>this.validateMany(e,t),"validateMany"),validateManyAsync:r(t=>this.validateManyAsync(e,t),"validateManyAsync")}}addCustomValidation(e,t,s){return this.ajv.addKeyword({keyword:t,validate:r(function i(c,n){let o=s(n);return typeof o=="string"?(i.errors=[{message:o}],!1):o},"validate")}),this}async ensureSchemaLoaded(e){if(this.hasSchema(e))return;let t=this.schemaCache?.get(e);if(t){this.registerSchema(e,t);return}if(!this.schemaLoader)throw new Error(`No schema registered for type '${String(e)}' and no schema loader configured`);let s=await this.schemaLoader(e);if(!s)throw new Error(`Schema loader did not return a schema for type '${String(e)}'`);this.registerSchema(e,s)}cacheSchema(e,t){this.schemaCache&&this.schemaCache.set(e,t,{ttlMs:this.schemaCacheTtl?.ttlMs,slidingTtlMs:this.schemaCacheTtl?.slidingTtlMs})}normalizeSchemaInput(e){let t=typeof e=="string"?JSON.parse(e):e;if(typeof t!="object"||t===null||Array.isArray(t))throw new Error("Schema JSON must be an object keyed by schema type");return t}formatErrors(e){return e.map(t=>({keyword:t.keyword,instancePath:t.instancePath||"",schemaPath:t.schemaPath||"",params:t.params||{},message:t.message||"Validation error",data:t.data,parentSchema:t.parentSchema,schema:t.schema}))}};var y=r(a=>{let e=globalThis.structuredClone;return typeof e=="function"?e(a):JSON.parse(JSON.stringify(a))},"clone"),h=r(a=>a instanceof S?a.build():y(a),"normalizeInput"),u=r(a=>!a||typeof a!="object"||Array.isArray(a)?{}:a,"ensureObject"),p=r(a=>Array.from(new Set(a)),"unique"),S=class a{static{r(this,"SchemaBuilder")}schema;constructor(e={}){this.schema=y(e)}static create(e={}){return new a(e)}static object(){return new a({type:"object",properties:{},required:[]})}static array(){return new a({type:"array"})}static string(){return new a({type:"string"})}static number(){return new a({type:"number"})}static integer(){return new a({type:"integer"})}static boolean(){return new a({type:"boolean"})}static nil(){return new a({type:"null"})}clone(){return new a(this.build())}extend(e){return Object.assign(this.schema,h(e)),this}title(e){return this.schema.title=e,this}description(e){return this.schema.description=e,this}default(e){return this.schema.default=e,this}examples(...e){return this.schema.examples=e,this}example(e){let t=Array.isArray(this.schema.examples)?this.schema.examples:[];return t.push(e),this.schema.examples=t,this}const(e){return this.schema.const=e,this}enum(e){return this.schema.enum=e,this}format(e){return this.schema.format=e,this}$id(e){return this.schema.$id=e,this}$schema(e){return this.schema.$schema=e,this}ref(e){return this.schema.$ref=e,this}readOnly(e=!0){return this.schema.readOnly=e,this}writeOnly(e=!0){return this.schema.writeOnly=e,this}nullable(e=!0){let t=this.schema.type;return e?Array.isArray(t)?this.schema.type=p([...t,"null"]):t&&t!=="null"?this.schema.type=p([t,"null"]):this.schema.type="null":Array.isArray(t)?this.schema.type=t.filter(s=>s!=="null"):t==="null"&&delete this.schema.type,this}type(e){return this.schema.type=e,this}property(e,t,s={}){let i=u(this.schema.properties);return i[e]=h(t),this.schema.properties=i,s.required&&this.required(e),this}properties(e,t={}){for(let[s,i]of Object.entries(e))this.property(s,i);return t.required&&this.required(...t.required),this}required(...e){let t=Array.isArray(this.schema.required)?this.schema.required:[];return this.schema.required=p([...t,...e]),this}additionalProperties(e){return this.schema.additionalProperties=typeof e=="boolean"?e:h(e),this}patternProperty(e,t){let s=u(this.schema.patternProperties);return s[e]=h(t),this.schema.patternProperties=s,this}propertyNames(e){return this.schema.propertyNames=h(e),this}minProperties(e){return this.schema.minProperties=e,this}maxProperties(e){return this.schema.maxProperties=e,this}items(e){return this.schema.items=h(e),this}prefixItems(...e){return this.schema.prefixItems=e.map(h),this}contains(e){return this.schema.contains=h(e),this}minItems(e){return this.schema.minItems=e,this}maxItems(e){return this.schema.maxItems=e,this}uniqueItems(e=!0){return this.schema.uniqueItems=e,this}minLength(e){return this.schema.minLength=e,this}maxLength(e){return this.schema.maxLength=e,this}pattern(e){return this.schema.pattern=e,this}minimum(e){return this.schema.minimum=e,this}maximum(e){return this.schema.maximum=e,this}exclusiveMinimum(e){return this.schema.exclusiveMinimum=e,this}exclusiveMaximum(e){return this.schema.exclusiveMaximum=e,this}multipleOf(e){return this.schema.multipleOf=e,this}allOf(...e){return this.schema.allOf=e.map(h),this}anyOf(...e){return this.schema.anyOf=e.map(h),this}oneOf(...e){return this.schema.oneOf=e.map(h),this}not(e){return this.schema.not=h(e),this}ifSchema(e){return this.schema.if=h(e),this}thenSchema(e){return this.schema.then=h(e),this}elseSchema(e){return this.schema.else=h(e),this}definition(e,t){let s=u(this.schema.$defs);return s[e]=h(t),this.schema.$defs=s,this}definitions(e){for(let[t,s]of Object.entries(e))this.definition(t,s);return this}meta(e,t){return this.schema[e]=t,this}build(){return y(this.schema)}toJSON(){return this.build()}};var R=r(a=>a instanceof S,"isSchemaBuilder"),L=r(a=>R(a)?a.build():a,"toSchemaObject"),T=m.builder().withCache({maxEntries:100}).build(),Q=r(a=>a,"defineSchemas"),V=r(a=>{let e={};for(let[t,s]of Object.entries(a))s&&(e[t]=L(s));return e},"buildSchemaMap"),W=r(a=>T.validate("expression-schema",a),"validateExpression"),X=r(a=>T.validateStrict("expression-schema",a),"validateExpressionStrict"),Y=r((a,e)=>{let t=new m;return t.registerSchema(a,e),t.createTypeValidator(a)},"createValidator"),g=r((a,e={})=>{let t=m.builder();return e.options&&t.withOptions(e.options),e.cache&&t.withCache(e.cache),e.loader&&t.withSchemaLoader(e.loader),t.fromJSON(a),t.build()},"createValidatorFromJSON"),P=r((a,e={})=>g(V(a),e),"createValidatorFromBuilders"),Z=r(()=>m.builder(),"validatorBuilder"),_=r((a,e,t={})=>g(e,t).createTypeValidator(a),"createTypeValidatorFromJSON"),ee=r((a,e,t={})=>P(e,t).createTypeValidator(a),"createTypeValidatorFromBuilders");export{V as buildSchemaMap,ee as createTypeValidatorFromBuilders,_ as createTypeValidatorFromJSON,Y as createValidator,P as createValidatorFromBuilders,g as createValidatorFromJSON,T as defaultValidator,Q as defineSchemas,W as validateExpression,X as validateExpressionStrict,Z as validatorBuilder};