superstruct
Advanced tools
Comparing version
@@ -334,3 +334,3 @@ /** | ||
/** | ||
* Enums. | ||
* Enum. | ||
* | ||
@@ -394,2 +394,77 @@ * @param {Array} schema | ||
/** | ||
* Instance. | ||
* | ||
* @param {Array} schema | ||
* @param {Any} defaults | ||
* @param {Object} options | ||
*/ | ||
function instance(schema, defaults, options) { | ||
const name = 'instance'; | ||
const type = `instance<${schema.name}>`; | ||
const validate = (value = defaults) => { | ||
return value instanceof schema ? [undefined, value] : [{ data: value, path: [], value, type }]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* Interface. | ||
* | ||
* @param {Object} schema | ||
* @param {Object} defaults | ||
* @param {Object} options | ||
*/ | ||
function inter(schema, defaults, options) { | ||
if (kindOf(schema) !== 'object') { | ||
if (process.env.NODE_ENV !== 'production') { | ||
throw new Error(`Interface structs must be defined as an object, but you passed: ${schema}`); | ||
} else { | ||
throw new Error(`Invalid schema: ${schema}`); | ||
} | ||
} | ||
const ks = []; | ||
const properties = {}; | ||
for (const key in schema) { | ||
ks.push(key); | ||
const s = schema[key]; | ||
const kind = any(s, undefined, options); | ||
properties[key] = kind; | ||
} | ||
const name = 'interface'; | ||
const type = `{${ks.join()}}`; | ||
const validate = (value = defaults) => { | ||
const errors = []; | ||
for (const key in properties) { | ||
const v = value[key]; | ||
const kind = properties[key]; | ||
const [e] = kind.validate(v); | ||
if (e) { | ||
e.path = [key].concat(e.path); | ||
e.data = value; | ||
errors.push(e); | ||
continue; | ||
} | ||
} | ||
if (errors.length) { | ||
const first = errors[0]; | ||
first.errors = errors; | ||
return [first]; | ||
} | ||
return [undefined, value]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* List. | ||
@@ -454,2 +529,20 @@ * | ||
/** | ||
* Literal. | ||
* | ||
* @param {Array} schema | ||
* @param {Any} defaults | ||
* @param {Object} options | ||
*/ | ||
function literal(schema, defaults, options) { | ||
const name = 'literal'; | ||
const type = `literal: ${JSON.stringify(schema)}`; | ||
const validate = (value = defaults) => { | ||
return value === schema ? [undefined, value] : [{ data: value, path: [], value, type }]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* Object. | ||
@@ -747,3 +840,6 @@ * | ||
function: func, | ||
instance, | ||
interface: inter, | ||
list, | ||
literal, | ||
object, | ||
@@ -750,0 +846,0 @@ optional, |
@@ -338,3 +338,3 @@ 'use strict'; | ||
/** | ||
* Enums. | ||
* Enum. | ||
* | ||
@@ -398,2 +398,77 @@ * @param {Array} schema | ||
/** | ||
* Instance. | ||
* | ||
* @param {Array} schema | ||
* @param {Any} defaults | ||
* @param {Object} options | ||
*/ | ||
function instance(schema, defaults, options) { | ||
const name = 'instance'; | ||
const type = `instance<${schema.name}>`; | ||
const validate = (value = defaults) => { | ||
return value instanceof schema ? [undefined, value] : [{ data: value, path: [], value, type }]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* Interface. | ||
* | ||
* @param {Object} schema | ||
* @param {Object} defaults | ||
* @param {Object} options | ||
*/ | ||
function inter(schema, defaults, options) { | ||
if (kindOf(schema) !== 'object') { | ||
if (process.env.NODE_ENV !== 'production') { | ||
throw new Error(`Interface structs must be defined as an object, but you passed: ${schema}`); | ||
} else { | ||
throw new Error(`Invalid schema: ${schema}`); | ||
} | ||
} | ||
const ks = []; | ||
const properties = {}; | ||
for (const key in schema) { | ||
ks.push(key); | ||
const s = schema[key]; | ||
const kind = any(s, undefined, options); | ||
properties[key] = kind; | ||
} | ||
const name = 'interface'; | ||
const type = `{${ks.join()}}`; | ||
const validate = (value = defaults) => { | ||
const errors = []; | ||
for (const key in properties) { | ||
const v = value[key]; | ||
const kind = properties[key]; | ||
const [e] = kind.validate(v); | ||
if (e) { | ||
e.path = [key].concat(e.path); | ||
e.data = value; | ||
errors.push(e); | ||
continue; | ||
} | ||
} | ||
if (errors.length) { | ||
const first = errors[0]; | ||
first.errors = errors; | ||
return [first]; | ||
} | ||
return [undefined, value]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* List. | ||
@@ -458,2 +533,20 @@ * | ||
/** | ||
* Literal. | ||
* | ||
* @param {Array} schema | ||
* @param {Any} defaults | ||
* @param {Object} options | ||
*/ | ||
function literal(schema, defaults, options) { | ||
const name = 'literal'; | ||
const type = `literal: ${JSON.stringify(schema)}`; | ||
const validate = (value = defaults) => { | ||
return value === schema ? [undefined, value] : [{ data: value, path: [], value, type }]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* Object. | ||
@@ -751,3 +844,6 @@ * | ||
function: func, | ||
instance, | ||
interface: inter, | ||
list, | ||
literal, | ||
object, | ||
@@ -754,0 +850,0 @@ optional, |
{ | ||
"name": "superstruct", | ||
"description": "A simple, expressive way to validate data in JavaScript.", | ||
"version": "0.4.3", | ||
"version": "0.4.4", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "repository": "git://github.com/ianstormtaylor/superstruct.git", |
@@ -17,2 +17,3 @@ | ||
<a href="#principles">Principles</a> • | ||
<a href="#demo">Demo</a> • | ||
<a href="#examples">Examples</a> • | ||
@@ -114,8 +115,6 @@ <a href="#documentation">Documentation</a> | ||
There are lots of existing validation libraries. Some of them, like [`joi`](), [`express-validator`](https://github.com/ctavan/express-validator), [`validator.js`](https://github.com/chriso/validator.js), [`yup`](https://github.com/jquense/yup) or [`ajv`](https://github.com/epoberezkin/ajv) are decently popular. But all of them exhibit many issues that lead to hard to maintain codebases... | ||
There are lots of existing validation libraries—[`joi`](https://github.com/hapijs/joi), [`express-validator`](https://github.com/ctavan/express-validator), [`validator.js`](https://github.com/chriso/validator.js), [`yup`](https://github.com/jquense/yup), [`ajv`](https://github.com/epoberezkin/ajv), [`is-my-json-valid`](https://github.com/mafintosh/is-my-json-valid)... But they exhibit many issues that lead to your codebase becoming hard to maintain... | ||
- **They can't throw errors.** Many validators simply return `true/false` or string errors. Although helpful in the days of callbacks, not using `throw` in modern JavaScript makes code much more complex. | ||
- **They don't expose detailed errors.** Many validators simply return string-only errors or booleans without any details as to why, making it difficult to customize the errors to be helpful for end-users. | ||
- **They don't expose detailed errors.** For those that do `throw`, they often throw string-only errors without any details as to why, making it difficult to customize the errors to be helpful for end-users. | ||
- **They make custom types hard.** Many validators ship with built-in types like emails, URLs, UUIDs, etc. with no way to know what they check for, and complicated APIs for defining new types. | ||
@@ -125,2 +124,4 @@ | ||
- **They don't throw errors.** Many don't actually throw the errors, forcing you to wrap everywhere. Although helpful in the days of callbacks, not using `throw` in modern JavaScript makes code much more complex. | ||
- **They don't pre-compile schemas.** Many validators define schemas as plain JavaScript objects, which means they delegate the parsing of the schema logic to validation time, making them much slower. | ||
@@ -130,2 +131,4 @@ | ||
- **They use JSON Schema.** Don't get me wrong, JSON Schema _can_ be useful. But it's kind of like HATEOS—it's usually way more complexity than you need and you aren't using any of its benefits. (Sorry, I said it.) | ||
Of course, not every validation library suffers from all of these issues, but most of them exhibit at least one. If you've run into this problem before, you might like Superstruct. | ||
@@ -157,2 +160,11 @@ | ||
### Demo | ||
Try out the [live demo on JSFiddle](https://jsfiddle.net/yjugaeg8/2/) to get an idea for how the API works, or to quickly verify your use case: | ||
[](https://jsfiddle.net/yjugaeg8/2/) | ||
<br/> | ||
### Examples | ||
@@ -159,0 +171,0 @@ |
@@ -340,3 +340,3 @@ (function (global, factory) { | ||
/** | ||
* Enums. | ||
* Enum. | ||
* | ||
@@ -400,2 +400,77 @@ * @param {Array} schema | ||
/** | ||
* Instance. | ||
* | ||
* @param {Array} schema | ||
* @param {Any} defaults | ||
* @param {Object} options | ||
*/ | ||
function instance(schema, defaults, options) { | ||
const name = 'instance'; | ||
const type = `instance<${schema.name}>`; | ||
const validate = (value = defaults) => { | ||
return value instanceof schema ? [undefined, value] : [{ data: value, path: [], value, type }]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* Interface. | ||
* | ||
* @param {Object} schema | ||
* @param {Object} defaults | ||
* @param {Object} options | ||
*/ | ||
function inter(schema, defaults, options) { | ||
if (kindOf(schema) !== 'object') { | ||
if (process.env.NODE_ENV !== 'production') { | ||
throw new Error(`Interface structs must be defined as an object, but you passed: ${schema}`); | ||
} else { | ||
throw new Error(`Invalid schema: ${schema}`); | ||
} | ||
} | ||
const ks = []; | ||
const properties = {}; | ||
for (const key in schema) { | ||
ks.push(key); | ||
const s = schema[key]; | ||
const kind = any(s, undefined, options); | ||
properties[key] = kind; | ||
} | ||
const name = 'interface'; | ||
const type = `{${ks.join()}}`; | ||
const validate = (value = defaults) => { | ||
const errors = []; | ||
for (const key in properties) { | ||
const v = value[key]; | ||
const kind = properties[key]; | ||
const [e] = kind.validate(v); | ||
if (e) { | ||
e.path = [key].concat(e.path); | ||
e.data = value; | ||
errors.push(e); | ||
continue; | ||
} | ||
} | ||
if (errors.length) { | ||
const first = errors[0]; | ||
first.errors = errors; | ||
return [first]; | ||
} | ||
return [undefined, value]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* List. | ||
@@ -460,2 +535,20 @@ * | ||
/** | ||
* Literal. | ||
* | ||
* @param {Array} schema | ||
* @param {Any} defaults | ||
* @param {Object} options | ||
*/ | ||
function literal(schema, defaults, options) { | ||
const name = 'literal'; | ||
const type = `literal: ${JSON.stringify(schema)}`; | ||
const validate = (value = defaults) => { | ||
return value === schema ? [undefined, value] : [{ data: value, path: [], value, type }]; | ||
}; | ||
return new Kind(name, type, validate); | ||
} | ||
/** | ||
* Object. | ||
@@ -753,3 +846,6 @@ * | ||
function: func, | ||
instance, | ||
interface: inter, | ||
list, | ||
literal, | ||
object, | ||
@@ -756,0 +852,0 @@ optional, |
@@ -1,1 +0,1 @@ | ||
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?factory(exports):typeof define==="function"&&define.amd?define(["exports"],factory):factory(global.Superstruct={})})(this,function(exports){"use strict";class StructError extends TypeError{constructor(attrs){const{data:data,value:value,type:type,path:path,errors:errors=[]}=attrs;const message=`Expected a value of type \`${type}\`${path.length?` for \`${path.join(".")}\``:""} but received \`${value}\`.`;super(message);this.data=data;this.path=path;this.value=value;this.type=type;this.errors=errors;if(!errors.length)errors.push(this);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}else{this.stack=(new Error).stack}}}var toString=Object.prototype.toString;var kindOf=function kindOf(val){if(val===void 0)return"undefined";if(val===null)return"null";var type=typeof val;if(type==="boolean")return"boolean";if(type==="string")return"string";if(type==="number")return"number";if(type==="symbol")return"symbol";if(type==="function"){return isGeneratorFn(val)?"generatorfunction":"function"}if(isArray(val))return"array";if(isBuffer(val))return"buffer";if(isArguments(val))return"arguments";if(isDate(val))return"date";if(isError(val))return"error";if(isRegexp(val))return"regexp";switch(ctorName(val)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(isGeneratorObj(val)){return"generator"}type=toString.call(val);switch(type){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return type.slice(8,-1).toLowerCase().replace(/\s/g,"")};function ctorName(val){return val.constructor?val.constructor.name:null}function isArray(val){if(Array.isArray)return Array.isArray(val);return val instanceof Array}function isError(val){return val instanceof Error||typeof val.message==="string"&&val.constructor&&typeof val.constructor.stackTraceLimit==="number"}function isDate(val){if(val instanceof Date)return true;return typeof val.toDateString==="function"&&typeof val.getDate==="function"&&typeof val.setDate==="function"}function isRegexp(val){if(val instanceof RegExp)return true;return typeof val.flags==="string"&&typeof val.ignoreCase==="boolean"&&typeof val.multiline==="boolean"&&typeof val.global==="boolean"}function isGeneratorFn(name,val){return ctorName(name)==="GeneratorFunction"}function isGeneratorObj(val){return typeof val.throw==="function"&&typeof val.return==="function"&&typeof val.next==="function"}function isArguments(val){try{if(typeof val.length==="number"&&typeof val.callee==="function"){return true}}catch(err){if(err.message.indexOf("callee")!==-1){return true}}return false}function isBuffer(val){if(val.constructor&&typeof val.constructor.isBuffer==="function"){return val.constructor.isBuffer(val)}return false}const IS_STRUCT="@@__STRUCT__@@";const KIND="@@__KIND__@@";function isStruct(value){return!!(value&&value[IS_STRUCT])}class Kind{constructor(name,type,validate){this.name=name;this.type=type;this.validate=validate}}function any(schema,defaults,options){if(isStruct(schema))return schema[KIND];if(schema instanceof Kind)return schema;switch(kindOf(schema)){case"array":{return schema.length>1?tuple(schema,defaults,options):list(schema,defaults,options)}case"function":{return func(schema,defaults,options)}case"object":{return object(schema,defaults,options)}case"string":{let required=true;let type;if(schema.endsWith("?")){required=false;schema=schema.slice(0,-1)}if(schema.includes("|")){const scalars=schema.split(/\s*\|\s*/g);type=union(scalars,defaults,options)}else if(schema.includes("&")){const scalars=schema.split(/\s*&\s*/g);type=intersection(scalars,defaults,options)}else{type=scalar(schema,defaults,options)}if(!required){type=optional(type,undefined,options)}return type}}{throw new Error(`Invalid schema: ${schema}`)}}function dict(schema,defaults,options){if(kindOf(schema)!=="array"||schema.length!==2){{throw new Error(`Invalid schema: ${schema}`)}}const obj=scalar("object",undefined,options);const keys=any(schema[0],undefined,options);const values=any(schema[1],undefined,options);const name="dict";const type=`dict<${keys.type},${values.type}>`;const validate=(value=defaults)=>{const[error]=obj.validate(value);if(error){error.type=type;return[error]}const ret={};const errors=[];for(let k in value){const v=value[k];const[e,r]=keys.validate(k);if(e){e.path=[k].concat(e.path);e.data=value;errors.push(e);continue}k=r;const[e2,r2]=values.validate(v);if(e2){e2.path=[k].concat(e2.path);e2.data=value;errors.push(e2);continue}ret[k]=r2}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function enums(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const name="enum";const type=schema.map(s=>{try{return JSON.stringify(s)}catch(e){return String(s)}}).join(" | ");const validate=(value=defaults)=>{return schema.includes(value)?[undefined,value]:[{data:value,path:[],value:value,type:type}]};return new Kind(name,type,validate)}function func(schema,defaults,options){if(kindOf(schema)!=="function"){{throw new Error(`Invalid schema: ${schema}`)}}const name="function";const type="<function>";const validate=(value=defaults)=>{return schema(value)?[undefined,value]:[{type:type,value:value,data:value,path:[]}]};return new Kind(name,type,validate)}function list(schema,defaults,options){if(kindOf(schema)!=="array"||schema.length!==1){{throw new Error(`Invalid schema: ${schema}`)}}const array=scalar("array",undefined,options);const element=any(schema[0],undefined,options);const name="list";const type=`[${element.type}]`;const validate=(value=defaults)=>{const[error,result]=array.validate(value);if(error){error.type=type;return[error]}value=result;const errors=[];const ret=[];for(let i=0;i<value.length;i++){const v=value[i];const[e,r]=element.validate(v);if(e){e.path=[i].concat(e.path);e.data=value;errors.push(e);continue}ret[i]=r}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function object(schema,defaults,options){if(kindOf(schema)!=="object"){{throw new Error(`Invalid schema: ${schema}`)}}const obj=scalar("object",undefined,options);const ks=[];const properties={};for(const key in schema){ks.push(key);const s=schema[key];const d=defaults&&defaults[key];const kind=any(s,d,options);properties[key]=kind}const name="object";const type=`{${ks.join()}}`;const validate=(value=defaults)=>{const[error,result]=obj.validate(value);if(error){error.type=type;return[error]}value=result;const errors=[];const ret={};const valueKeys=Object.keys(value);const schemaKeys=Object.keys(properties);const keys=new Set(valueKeys.concat(schemaKeys));keys.forEach(key=>{const v=value[key];const kind=properties[key];if(!kind){const e={data:value,path:[key],value:v};errors.push(e);return}const[e,r]=kind.validate(v);if(e){e.path=[key].concat(e.path);e.data=value;errors.push(e);return}if(key in value){ret[key]=r}});if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function optional(schema,defaults,options){return union([schema,"undefined"],defaults,options)}function scalar(schema,defaults,options){if(kindOf(schema)!=="string"){{throw new Error(`Invalid schema: ${schema}`)}}const{types:types}=options;const fn=types[schema];if(kindOf(fn)!=="function"){{throw new Error(`Invalid type: ${schema}`)}}const kind=func(fn,defaults,options);const name="scalar";const type=schema;const validate=value=>{const[error,result]=kind.validate(value);if(error){error.type=type;return[error]}return[undefined,result]};return new Kind(name,type,validate)}function tuple(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const kinds=schema.map(s=>any(s,undefined,options));const array=scalar("array",undefined,options);const name="tuple";const type=`[${kinds.map(k=>k.type).join()}]`;const validate=(value=defaults)=>{const[error]=array.validate(value);if(error){error.type=type;return[error]}const ret=[];const errors=[];const length=Math.max(value.length,kinds.length);for(let i=0;i<length;i++){const kind=kinds[i];const v=value[i];if(!kind){const e={data:value,path:[i],value:v};errors.push(e);continue}const[e,r]=kind.validate(v);if(e){e.path=[i].concat(e.path);e.data=value;errors.push(e);continue}ret[i]=r}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function union(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const kinds=schema.map(s=>any(s,undefined,options));const name="union";const type=kinds.map(k=>k.type).join(" | ");const validate=(value=defaults)=>{let error;for(const k of kinds){const[e,r]=k.validate(value);if(!e)return[undefined,r];error=e}error.type=type;return[error]};return new Kind(name,type,validate)}function intersection(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const types=schema.map(s=>any(s,undefined,options));const name="intersection";const type=types.map(t=>t.type).join(" & ");const validate=(value=defaults)=>{let v=value;for(const t of types){const[e,r]=t.validate(v);if(e){e.type=type;return[e]}v=r}return[undefined,v]};return new Kind(name,type,validate)}const Kinds={any:any,dict:dict,enum:enums,function:func,list:list,object:object,optional:optional,scalar:scalar,tuple:tuple,union:union,intersection:intersection};const TYPES=["arguments","array","boolean","buffer","date","error","float32array","float64array","function","generatorfunction","int16array","int32array","int8array","map","null","number","object","regexp","set","string","symbol","uint16array","uint32array","uint8array","uint8clampedarray","undefined","weakmap","weakset"];const Types={any:value=>value!==undefined};TYPES.forEach(type=>{Types[type]=(value=>kindOf(value)===type)});var _extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key]}}}return target};function superstruct(config={}){const types=_extends({},Types,config.types||{});function struct(schema,defaults$$1,options={}){if(isStruct(schema))schema=schema.schema;const kind=Kinds.any(schema,defaults$$1,_extends({},options,{types:types}));function Struct(data){if(this instanceof Struct){{throw new Error("Invalid `new` keyword!")}}return Struct.assert(data)}Object.defineProperty(Struct,IS_STRUCT,{value:true});Object.defineProperty(Struct,KIND,{value:kind});Struct.kind=kind.name;Struct.type=kind.type;Struct.schema=schema;Struct.defaults=defaults$$1;Struct.options=options;Struct.assert=(value=>{const[error,result]=kind.validate(value);if(error)throw new StructError(error);return result});Struct.test=(value=>{const[error]=kind.validate(value);return!error});Struct.validate=(value=>{const[error,result]=kind.validate(value);if(error)return[new StructError(error)];return[undefined,result]});return Struct}Object.keys(Kinds).forEach(name=>{const kind=Kinds[name];struct[name]=((schema,defaults$$1,options)=>{const type=kind(schema,defaults$$1,_extends({},options,{types:types}));const s=struct(type,defaults$$1,options);return s})});return struct}const struct=superstruct();exports.struct=struct;exports.superstruct=superstruct;exports.StructError=StructError;Object.defineProperty(exports,"__esModule",{value:true})}); | ||
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?factory(exports):typeof define==="function"&&define.amd?define(["exports"],factory):factory(global.Superstruct={})})(this,function(exports){"use strict";class StructError extends TypeError{constructor(attrs){const{data:data,value:value,type:type,path:path,errors:errors=[]}=attrs;const message=`Expected a value of type \`${type}\`${path.length?` for \`${path.join(".")}\``:""} but received \`${value}\`.`;super(message);this.data=data;this.path=path;this.value=value;this.type=type;this.errors=errors;if(!errors.length)errors.push(this);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}else{this.stack=(new Error).stack}}}var toString=Object.prototype.toString;var kindOf=function kindOf(val){if(val===void 0)return"undefined";if(val===null)return"null";var type=typeof val;if(type==="boolean")return"boolean";if(type==="string")return"string";if(type==="number")return"number";if(type==="symbol")return"symbol";if(type==="function"){return isGeneratorFn(val)?"generatorfunction":"function"}if(isArray(val))return"array";if(isBuffer(val))return"buffer";if(isArguments(val))return"arguments";if(isDate(val))return"date";if(isError(val))return"error";if(isRegexp(val))return"regexp";switch(ctorName(val)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(isGeneratorObj(val)){return"generator"}type=toString.call(val);switch(type){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return type.slice(8,-1).toLowerCase().replace(/\s/g,"")};function ctorName(val){return val.constructor?val.constructor.name:null}function isArray(val){if(Array.isArray)return Array.isArray(val);return val instanceof Array}function isError(val){return val instanceof Error||typeof val.message==="string"&&val.constructor&&typeof val.constructor.stackTraceLimit==="number"}function isDate(val){if(val instanceof Date)return true;return typeof val.toDateString==="function"&&typeof val.getDate==="function"&&typeof val.setDate==="function"}function isRegexp(val){if(val instanceof RegExp)return true;return typeof val.flags==="string"&&typeof val.ignoreCase==="boolean"&&typeof val.multiline==="boolean"&&typeof val.global==="boolean"}function isGeneratorFn(name,val){return ctorName(name)==="GeneratorFunction"}function isGeneratorObj(val){return typeof val.throw==="function"&&typeof val.return==="function"&&typeof val.next==="function"}function isArguments(val){try{if(typeof val.length==="number"&&typeof val.callee==="function"){return true}}catch(err){if(err.message.indexOf("callee")!==-1){return true}}return false}function isBuffer(val){if(val.constructor&&typeof val.constructor.isBuffer==="function"){return val.constructor.isBuffer(val)}return false}const IS_STRUCT="@@__STRUCT__@@";const KIND="@@__KIND__@@";function isStruct(value){return!!(value&&value[IS_STRUCT])}class Kind{constructor(name,type,validate){this.name=name;this.type=type;this.validate=validate}}function any(schema,defaults,options){if(isStruct(schema))return schema[KIND];if(schema instanceof Kind)return schema;switch(kindOf(schema)){case"array":{return schema.length>1?tuple(schema,defaults,options):list(schema,defaults,options)}case"function":{return func(schema,defaults,options)}case"object":{return object(schema,defaults,options)}case"string":{let required=true;let type;if(schema.endsWith("?")){required=false;schema=schema.slice(0,-1)}if(schema.includes("|")){const scalars=schema.split(/\s*\|\s*/g);type=union(scalars,defaults,options)}else if(schema.includes("&")){const scalars=schema.split(/\s*&\s*/g);type=intersection(scalars,defaults,options)}else{type=scalar(schema,defaults,options)}if(!required){type=optional(type,undefined,options)}return type}}{throw new Error(`Invalid schema: ${schema}`)}}function dict(schema,defaults,options){if(kindOf(schema)!=="array"||schema.length!==2){{throw new Error(`Invalid schema: ${schema}`)}}const obj=scalar("object",undefined,options);const keys=any(schema[0],undefined,options);const values=any(schema[1],undefined,options);const name="dict";const type=`dict<${keys.type},${values.type}>`;const validate=(value=defaults)=>{const[error]=obj.validate(value);if(error){error.type=type;return[error]}const ret={};const errors=[];for(let k in value){const v=value[k];const[e,r]=keys.validate(k);if(e){e.path=[k].concat(e.path);e.data=value;errors.push(e);continue}k=r;const[e2,r2]=values.validate(v);if(e2){e2.path=[k].concat(e2.path);e2.data=value;errors.push(e2);continue}ret[k]=r2}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function enums(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const name="enum";const type=schema.map(s=>{try{return JSON.stringify(s)}catch(e){return String(s)}}).join(" | ");const validate=(value=defaults)=>{return schema.includes(value)?[undefined,value]:[{data:value,path:[],value:value,type:type}]};return new Kind(name,type,validate)}function func(schema,defaults,options){if(kindOf(schema)!=="function"){{throw new Error(`Invalid schema: ${schema}`)}}const name="function";const type="<function>";const validate=(value=defaults)=>{return schema(value)?[undefined,value]:[{type:type,value:value,data:value,path:[]}]};return new Kind(name,type,validate)}function instance(schema,defaults,options){const name="instance";const type=`instance<${schema.name}>`;const validate=(value=defaults)=>{return value instanceof schema?[undefined,value]:[{data:value,path:[],value:value,type:type}]};return new Kind(name,type,validate)}function inter(schema,defaults,options){if(kindOf(schema)!=="object"){{throw new Error(`Invalid schema: ${schema}`)}}const ks=[];const properties={};for(const key in schema){ks.push(key);const s=schema[key];const kind=any(s,undefined,options);properties[key]=kind}const name="interface";const type=`{${ks.join()}}`;const validate=(value=defaults)=>{const errors=[];for(const key in properties){const v=value[key];const kind=properties[key];const[e]=kind.validate(v);if(e){e.path=[key].concat(e.path);e.data=value;errors.push(e);continue}}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,value]};return new Kind(name,type,validate)}function list(schema,defaults,options){if(kindOf(schema)!=="array"||schema.length!==1){{throw new Error(`Invalid schema: ${schema}`)}}const array=scalar("array",undefined,options);const element=any(schema[0],undefined,options);const name="list";const type=`[${element.type}]`;const validate=(value=defaults)=>{const[error,result]=array.validate(value);if(error){error.type=type;return[error]}value=result;const errors=[];const ret=[];for(let i=0;i<value.length;i++){const v=value[i];const[e,r]=element.validate(v);if(e){e.path=[i].concat(e.path);e.data=value;errors.push(e);continue}ret[i]=r}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function literal(schema,defaults,options){const name="literal";const type=`literal: ${JSON.stringify(schema)}`;const validate=(value=defaults)=>{return value===schema?[undefined,value]:[{data:value,path:[],value:value,type:type}]};return new Kind(name,type,validate)}function object(schema,defaults,options){if(kindOf(schema)!=="object"){{throw new Error(`Invalid schema: ${schema}`)}}const obj=scalar("object",undefined,options);const ks=[];const properties={};for(const key in schema){ks.push(key);const s=schema[key];const d=defaults&&defaults[key];const kind=any(s,d,options);properties[key]=kind}const name="object";const type=`{${ks.join()}}`;const validate=(value=defaults)=>{const[error,result]=obj.validate(value);if(error){error.type=type;return[error]}value=result;const errors=[];const ret={};const valueKeys=Object.keys(value);const schemaKeys=Object.keys(properties);const keys=new Set(valueKeys.concat(schemaKeys));keys.forEach(key=>{const v=value[key];const kind=properties[key];if(!kind){const e={data:value,path:[key],value:v};errors.push(e);return}const[e,r]=kind.validate(v);if(e){e.path=[key].concat(e.path);e.data=value;errors.push(e);return}if(key in value){ret[key]=r}});if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function optional(schema,defaults,options){return union([schema,"undefined"],defaults,options)}function scalar(schema,defaults,options){if(kindOf(schema)!=="string"){{throw new Error(`Invalid schema: ${schema}`)}}const{types:types}=options;const fn=types[schema];if(kindOf(fn)!=="function"){{throw new Error(`Invalid type: ${schema}`)}}const kind=func(fn,defaults,options);const name="scalar";const type=schema;const validate=value=>{const[error,result]=kind.validate(value);if(error){error.type=type;return[error]}return[undefined,result]};return new Kind(name,type,validate)}function tuple(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const kinds=schema.map(s=>any(s,undefined,options));const array=scalar("array",undefined,options);const name="tuple";const type=`[${kinds.map(k=>k.type).join()}]`;const validate=(value=defaults)=>{const[error]=array.validate(value);if(error){error.type=type;return[error]}const ret=[];const errors=[];const length=Math.max(value.length,kinds.length);for(let i=0;i<length;i++){const kind=kinds[i];const v=value[i];if(!kind){const e={data:value,path:[i],value:v};errors.push(e);continue}const[e,r]=kind.validate(v);if(e){e.path=[i].concat(e.path);e.data=value;errors.push(e);continue}ret[i]=r}if(errors.length){const first=errors[0];first.errors=errors;return[first]}return[undefined,ret]};return new Kind(name,type,validate)}function union(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const kinds=schema.map(s=>any(s,undefined,options));const name="union";const type=kinds.map(k=>k.type).join(" | ");const validate=(value=defaults)=>{let error;for(const k of kinds){const[e,r]=k.validate(value);if(!e)return[undefined,r];error=e}error.type=type;return[error]};return new Kind(name,type,validate)}function intersection(schema,defaults,options){if(kindOf(schema)!=="array"){{throw new Error(`Invalid schema: ${schema}`)}}const types=schema.map(s=>any(s,undefined,options));const name="intersection";const type=types.map(t=>t.type).join(" & ");const validate=(value=defaults)=>{let v=value;for(const t of types){const[e,r]=t.validate(v);if(e){e.type=type;return[e]}v=r}return[undefined,v]};return new Kind(name,type,validate)}const Kinds={any:any,dict:dict,enum:enums,function:func,instance:instance,interface:inter,list:list,literal:literal,object:object,optional:optional,scalar:scalar,tuple:tuple,union:union,intersection:intersection};const TYPES=["arguments","array","boolean","buffer","date","error","float32array","float64array","function","generatorfunction","int16array","int32array","int8array","map","null","number","object","regexp","set","string","symbol","uint16array","uint32array","uint8array","uint8clampedarray","undefined","weakmap","weakset"];const Types={any:value=>value!==undefined};TYPES.forEach(type=>{Types[type]=(value=>kindOf(value)===type)});var _extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key]}}}return target};function superstruct(config={}){const types=_extends({},Types,config.types||{});function struct(schema,defaults$$1,options={}){if(isStruct(schema))schema=schema.schema;const kind=Kinds.any(schema,defaults$$1,_extends({},options,{types:types}));function Struct(data){if(this instanceof Struct){{throw new Error("Invalid `new` keyword!")}}return Struct.assert(data)}Object.defineProperty(Struct,IS_STRUCT,{value:true});Object.defineProperty(Struct,KIND,{value:kind});Struct.kind=kind.name;Struct.type=kind.type;Struct.schema=schema;Struct.defaults=defaults$$1;Struct.options=options;Struct.assert=(value=>{const[error,result]=kind.validate(value);if(error)throw new StructError(error);return result});Struct.test=(value=>{const[error]=kind.validate(value);return!error});Struct.validate=(value=>{const[error,result]=kind.validate(value);if(error)return[new StructError(error)];return[undefined,result]});return Struct}Object.keys(Kinds).forEach(name=>{const kind=Kinds[name];struct[name]=((schema,defaults$$1,options)=>{const type=kind(schema,defaults$$1,_extends({},options,{types:types}));const s=struct(type,defaults$$1,options);return s})});return struct}const struct=superstruct();exports.struct=struct;exports.superstruct=superstruct;exports.StructError=StructError;Object.defineProperty(exports,"__esModule",{value:true})}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
182566
9.65%2488
10.92%203
6.28%