Comparing version 0.3.0 to 0.3.1
{ | ||
"name": "typology", | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"description": "A data validation library for Node.js and the browser.", | ||
@@ -5,0 +5,0 @@ "main": "typology.js", |
305
typology.js
/** | ||
* typology.js - A data validation library for Node.js and the browser, | ||
* | ||
* Version: 0.3.0 | ||
* Version: 0.3.1 | ||
* Sources: http://github.com/jacomyal/typology | ||
@@ -33,35 +33,114 @@ * Doc: http://github.com/jacomyal/typology#readme | ||
var k, | ||
className, | ||
classes = [ | ||
'Arguments', | ||
'Boolean', | ||
'Number', | ||
'String', | ||
'Function', | ||
'Array', | ||
'Date', | ||
'RegExp', | ||
'Object' | ||
], | ||
class2type = {}, | ||
nativeTypes = ['*']; | ||
/** | ||
* Code conventions: | ||
* ***************** | ||
* - 80 characters max per line | ||
* - Write "__myVar" for any global private variable | ||
* - Write "_myVar" for any instance private variable | ||
* - Write "myVar" any local variable | ||
*/ | ||
// Fill types | ||
for (k in classes) { | ||
className = classes[k]; | ||
nativeTypes.push(className.toLowerCase()); | ||
class2type['[object ' + className + ']'] = className.toLowerCase(); | ||
} | ||
/** | ||
* Main object | ||
* PRIVATE GLOBALS: | ||
* **************** | ||
*/ | ||
/** | ||
* This object is a dictionnary that maps "[object Something]" strings to the | ||
* typology form "something": | ||
*/ | ||
var __class2type = {}; | ||
/** | ||
* This array is the list of every types considered native by typology: | ||
*/ | ||
var __nativeTypes = ['*']; | ||
(function() { | ||
var k, | ||
className, | ||
classes = [ | ||
'Arguments', | ||
'Boolean', | ||
'Number', | ||
'String', | ||
'Function', | ||
'Array', | ||
'Date', | ||
'RegExp', | ||
'Object' | ||
]; | ||
// Fill types | ||
for (k in classes) { | ||
className = classes[k]; | ||
__nativeTypes.push(className.toLowerCase()); | ||
__class2type['[object ' + className + ']'] = className.toLowerCase(); | ||
} | ||
})(); | ||
/** | ||
* CONSTRUCTOR: | ||
* ************ | ||
*/ | ||
function Typology(defs) { | ||
// Privates | ||
var _self = this, | ||
_customTypes = {}; | ||
/** | ||
* INSTANCE PRIVATES: | ||
* ****************** | ||
*/ | ||
// Validate the given data against the given type, but returns a more | ||
// specific object | ||
var _self = this; | ||
/** | ||
* This objects will contain every instance-specific custom types: | ||
*/ | ||
var _customTypes = {}; | ||
/** | ||
* This function will recursively scan an object to check wether or not it | ||
* matches a given type. It will return null if it matches, and an Error | ||
* object else. | ||
* | ||
* Examples: | ||
* ********* | ||
* 1. When the type matches: | ||
* > _scan('abc', 'string'); | ||
* will return null. | ||
* | ||
* 2. When a top-level type does not match: | ||
* > _scan('abc', 'number'); | ||
* will return an Error object with the following information: | ||
* - message: Expected a "number" but found a "string". | ||
* | ||
* 3. When a sub-object type does not its type: | ||
* > _scan({ a: 'abc' }, { a: 'number' }); | ||
* will return an Error object with the following information: | ||
* - message: Expected a "number" but found a "string". | ||
* - path: [ 'a' ] | ||
* | ||
* 4. When a deep sub-object type does not its type: | ||
* > _scan({ a: [ 123, 'abc' ] }, { a: ['number'] }); | ||
* will return an Error object with the following information: | ||
* - message: Expected a "number" but found a "string". | ||
* - path: [ 'a', 1 ] | ||
* | ||
* 5. When a required key is missing: | ||
* > _scan({}, { a: 'number' }); | ||
* will return an Error object with the following information: | ||
* - message: Expected a "number" but found a "undefined". | ||
* - path: [ 'a' ] | ||
* | ||
* 6. When an unexpected key is present: | ||
* > _scan({ a: 123, b: 456 }, { a: 'number' }); | ||
* will return an Error object with the following information: | ||
* - message: Unexpected key "b". | ||
* | ||
* @param {*} obj The value to validate. | ||
* @param {type} type The type. | ||
* @return {?Error} Returns null or an Error object. | ||
*/ | ||
function _scan(obj, type) { | ||
@@ -84,3 +163,3 @@ var a, | ||
for (i = 0; i < l; i++) | ||
if (nativeTypes.indexOf(a[i]) < 0 && !(a[i] in _customTypes)) | ||
if (__nativeTypes.indexOf(a[i]) < 0 && !(a[i] in _customTypes)) | ||
throw new Error('Invalid type.'); | ||
@@ -211,7 +290,61 @@ | ||
/** | ||
* Methods | ||
* INSTANCE METHODS: | ||
* ***************** | ||
*/ | ||
// Adding a custom type | ||
/** | ||
* This method registers a custom type into the Typology instance. A type | ||
* is registered under a unique name, and is described by an object (like | ||
* classical C structures) or a function. | ||
* | ||
* Variant 1: | ||
* ********** | ||
* > types.add('user', { id: 'string', name: '?string' }); | ||
* | ||
* @param {string} id The unique id of the type. | ||
* @param {object} type The corresponding structure. | ||
* @return {Typology} Returns this. | ||
* | ||
* Variant 2: | ||
* ********** | ||
* > types.add('integer', function(value) { | ||
* > return typeof value === 'number' && value === value | 0; | ||
* > }); | ||
* | ||
* @param {string} id The unique id of the type. | ||
* @param {function} type The function validating the type. | ||
* @return {Typology} Returns this. | ||
* | ||
* Variant 3: | ||
* ********** | ||
* > types.add({ | ||
* > id: 'user', | ||
* > type: { id: 'string', name: '?string' } | ||
* > }); | ||
* | ||
* > types.add({ | ||
* > id: 'integer', | ||
* > type: function(value) { | ||
* > return typeof value === 'number' && value === value | 0; | ||
* > } | ||
* > }); | ||
* | ||
* @param {object} specs An object describing fully the type. | ||
* @return {Typology} Returns this. | ||
* | ||
* Recognized parameters: | ||
* ********************** | ||
* Here is the exhaustive list of every accepted parameters in the specs | ||
* object: | ||
* | ||
* {string} id The unique id of the type. | ||
* {function|object} type The function or the structure object | ||
* validating the type. | ||
* {?[string]} proto Eventually an array of ids of types that are | ||
* referenced in the structure but do not exist | ||
* yet. | ||
*/ | ||
this.add = function(a1, a2) { | ||
@@ -252,3 +385,3 @@ var o, | ||
if (~nativeTypes.indexOf(id)) | ||
if (~__nativeTypes.indexOf(id)) | ||
throw new Error('"' + id + '" is a reserved type name.'); | ||
@@ -293,3 +426,9 @@ | ||
// Check whether this typology has the given type | ||
/** | ||
* This method returns true if a custom type is already registered in this | ||
* instance under the given key. | ||
* | ||
* @param {string} key A type name. | ||
* @return {boolean} Returns true if the key is registered. | ||
*/ | ||
this.has = function(key) { | ||
@@ -299,10 +438,48 @@ return !!_customTypes[key]; | ||
// Get the native type of the given variable | ||
/** | ||
* This method returns the native type of a given value. | ||
* | ||
* Examples: | ||
* ********* | ||
* > types.get({ a: 1 }); // returns "object" | ||
* > types.get('abcde'); // returns "string" | ||
* > types.get(1234567); // returns "number" | ||
* > types.get([1, 2]); // returns "array" | ||
* | ||
* @param {*} value Anything. | ||
* @return {string} Returns the native type of the value. | ||
*/ | ||
this.get = function(obj) { | ||
return (obj === null || obj === undefined) ? | ||
String(obj) : | ||
class2type[Object.prototype.toString.call(obj)] || 'object'; | ||
__class2type[Object.prototype.toString.call(obj)] || 'object'; | ||
}; | ||
// Validate the given data against the given type | ||
/** | ||
* This method validates some value against a given type. If the flag throws | ||
* has a truthy value, then the method will throw an error instead of | ||
* returning false. | ||
* | ||
* To know more about the error thrown, you can read the documentation of | ||
* the private method _scan. | ||
* | ||
* Examples: | ||
* ********* | ||
* > types.check({ a: 1 }, 'object'); // returns true | ||
* > types.check({ a: 1 }, { a: 'string' }); // returns true | ||
* > types.check({ a: 1 }, { a: 'string', b: '?number' }); // returns true | ||
* | ||
* > types.check({ a: 1 }, { a: 'string', b: 'number' }); // returns false | ||
* > types.check({ a: 1 }, { a: 'number' }); // returns false | ||
* > types.check({ a: 1 }, 'array'); // returns false | ||
* | ||
* > types.check({ a: 1 }, 'array', true); // throws an Error | ||
* | ||
* @param {*} value Anything. | ||
* @param {type} type A valid type. | ||
* @param {?boolean} throws If true, this method will throw an error | ||
* instead of returning false. | ||
* @return {boolean} Returns true if the value matches the type, and | ||
* not else. | ||
*/ | ||
this.check = function(obj, type, throws) { | ||
@@ -316,3 +493,30 @@ var result = _scan(obj, type); | ||
// Is the given type valid? | ||
/** | ||
* This method validates a type. If the type is not referenced or is not | ||
* valid, it will return false. | ||
* | ||
* To know more about that function, don't hesitate to read the related | ||
* unit tests. | ||
* | ||
* Examples: | ||
* ********* | ||
* > types.isValid('string'); // returns true | ||
* > types.isValid('?string'); // returns true | ||
* > types.isValid('!string'); // returns true | ||
* > types.isValid('string|number'); // returns true | ||
* > types.isValid({ a: 'string' }); // returns true | ||
* > types.isValid(['string']); // returns true | ||
* | ||
* > types.isValid('!?string'); // returns false | ||
* > types.isValid('myNotDefinedType'); // returns false | ||
* > types.isValid(['myNotDefinedType']); // returns false | ||
* > types.isValid({ a: 'myNotDefinedType' }); // returns false | ||
* | ||
* > types.isValid('user'); // returns false | ||
* > types.add('user', { id: 'string' }); // makes the type become valid | ||
* > types.isValid('user'); // returns true | ||
* | ||
* @param {*} type The type to get checked. | ||
* @return {boolean} Returns true if the type is valid, and false else. | ||
*/ | ||
this.isValid = function(type) { | ||
@@ -326,3 +530,3 @@ var a, | ||
for (i in a) | ||
if (nativeTypes.indexOf(a[i]) < 0 && !(a[i] in _customTypes)) | ||
if (__nativeTypes.indexOf(a[i]) < 0 && !(a[i] in _customTypes)) | ||
return false; | ||
@@ -345,7 +549,10 @@ return true; | ||
/** | ||
* Instantiation routine | ||
* INSTANTIATION ROUTINE: | ||
* ********************** | ||
*/ | ||
// Add a type "type" to shortcut the isValid method: | ||
// Add a type "type" to shortcut the #isValid method: | ||
this.add('type', (function(v) { | ||
@@ -360,3 +567,3 @@ return this.isValid(v); | ||
// Adding custom types at instantiation | ||
// Adding custom types at instantiation: | ||
defs = defs || {}; | ||
@@ -370,17 +577,23 @@ if (this.get(defs) !== 'object') | ||
/** | ||
* Public interface | ||
* GLOBAL PUBLIC API: | ||
* ****************** | ||
*/ | ||
// Creating a "main" typology instance to export | ||
// Creating a "main" typology instance to export: | ||
var types = Typology; | ||
Typology.call(types); | ||
// Version | ||
// Version: | ||
Object.defineProperty(types, 'version', { | ||
value: '0.3.0' | ||
value: '0.3.1' | ||
}); | ||
/** | ||
* Export | ||
* EXPORT: | ||
* ******* | ||
*/ | ||
@@ -387,0 +600,0 @@ if (typeof exports !== 'undefined') { |
/** | ||
* typology - A data validation library for Node.js and the browser. | ||
* @version v0.3.0 | ||
* @version v0.3.1 | ||
* @link https://github.com/jacomyal/typology | ||
* @license MIT | ||
*/ | ||
!function(){"use strict";function e(e){function t(e,i){var a,s,f,u,d,p,h,l,c=!1,g=!1,y=r.get(e);if("string"===r.get(i)){for(a=i.replace(/^[\?\!]/,"").split(/\|/),f=a.length,s=0;f>s;s++)if(o.indexOf(a[s])<0&&!(a[s]in n))throw new Error("Invalid type.");if(i.match(/^\?/)&&(c=!0),i.replace(/^\?/,"").match(/^\!/)&&(g=!0),g&&c)throw new Error("Invalid type.");for(s in a)if(n[a[s]]&&("function"==typeof n[a[s]].type?n[a[s]].type.call(r,e)===!0:!t(e,n[a[s]].type)))return g?(d=new Error,d.message='Expected a "'+i+'" but found a "'+a[s]+'".',d.expected=i,d.type=a[s],d.value=e,d):null;return null===e||void 0===e?g||c?null:(d=new Error,d.message='Expected a "'+i+'" but found a "'+y+'".',d.expected=i,d.type=y,d.value=e,d):(h=~a.indexOf("*"),l=~a.indexOf(y),g&&(h||l)?(d=new Error,d.message='Expected a "'+i+'" but found a "'+(l?y:"*")+'".',d.type=l?y:"*",d.expected=i,d.value=e,d):g||h||l?null:(d=new Error,d.message='Expected a "'+i+'" but found a "'+y+'".',d.expected=i,d.type=y,d.value=e,d))}if("object"===r.get(i)){if("object"!==y)return d=new Error,d.message='Expected an object but found a "'+y+'".',d.expected=i,d.type=y,d.value=e,d;for(u in i)if(p=t(e[u],i[u]))return d=p,d.path=d.path?[u].concat(d.path):[u],d;for(u in e)if(void 0===i[u])return d=new Error,d.message='Unexpected key "'+u+'".',d.type=y,d.value=e,d;return null}if("array"===r.get(i)){if(1!==i.length)throw new Error("Invalid type.");if("array"!==y)return d=new Error,d.message='Expected an array but found a "'+y+'".',d.expected=i,d.type=y,d.value=e,d;for(f=e.length,s=0;f>s;s++)if(p=t(e[s],i[0]))return d=p,d.path=d.path?[s].concat(d.path):[s],d;return null}throw new Error("Invalid type.")}var r=this,n={};if(this.add=function(e,t){var r,i,a,s,f,u;if(1===arguments.length){if("object"!==this.get(e))throw new Error("If types.add is called with one argument, this one has to be an object.");r=e,s=r.id,u=r.type}else{if(2!==arguments.length)throw new Error("types.add has to be called with one or two arguments.");if("string"!=typeof e||!e)throw new Error("If types.add is called with more than one argument, the first one must be the string id.");s=e,u=t}if("string"!==this.get(s)||0===s.length)throw new Error("A type requires an string id.");if(void 0!==n[s]&&"proto"!==n[s])throw new Error('The type "'+s+'" already exists.');if(~o.indexOf(s))throw new Error('"'+s+'" is a reserved type name.');n[s]=1,a=(r||{}).proto||[],a=Array.isArray(a)?a:[a],f={};for(i in a)void 0===n[a[i]]&&(n[a[i]]=1,f[a[i]]=1);if("function"!==this.get(u)&&!this.isValid(u))throw new Error("A type requires a valid definition. This one can be a preexistant type or else a function testing given objects.");if(n[s]=void 0===r?{id:s,type:u}:{},void 0!==r)for(i in r)n[s][i]=r[i];for(i in f)i!==s&&delete n[i];return this},this.has=function(e){return!!n[e]},this.get=function(e){return null===e||void 0===e?String(e):i[Object.prototype.toString.call(e)]||"object"},this.check=function(e,r,n){var i=t(e,r);if(n&&i)throw i;return!i},this.isValid=function(e){var t,r,i;if("string"===this.get(e)){t=e.replace(/^[\?\!]/,"").split(/\|/);for(i in t)if(o.indexOf(t[i])<0&&!(t[i]in n))return!1;return!0}if("object"===this.get(e)){for(r in e)if(!this.isValid(e[r]))return!1;return!0}return"array"===this.get(e)&&1===e.length?this.isValid(e[0]):!1},this.add("type",function(e){return this.isValid(e)}.bind(this)),this.add("primitive",function(e){return!e||!(e instanceof Object||"object"==typeof e)}),e=e||{},"object"!==this.get(e))throw Error("Invalid argument.");for(var a in e)this.add(a,e[a])}var t,r,n=["Arguments","Boolean","Number","String","Function","Array","Date","RegExp","Object"],i={},o=["*"];for(t in n)r=n[t],o.push(r.toLowerCase()),i["[object "+r+"]"]=r.toLowerCase();var a=e;e.call(a),Object.defineProperty(a,"version",{value:"0.3.0"}),"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=a),exports.types=a):"function"==typeof define&&define.amd?define("typology",[],function(){return a}):this.types=a}(this); | ||
!function(){"use strict";function e(e){function n(e,t){var a,s,f,u,d,p,h,l,c=!1,g=!1,y=i.get(e);if("string"===i.get(t)){for(a=t.replace(/^[\?\!]/,"").split(/\|/),f=a.length,s=0;f>s;s++)if(r.indexOf(a[s])<0&&!(a[s]in o))throw new Error("Invalid type.");if(t.match(/^\?/)&&(c=!0),t.replace(/^\?/,"").match(/^\!/)&&(g=!0),g&&c)throw new Error("Invalid type.");for(s in a)if(o[a[s]]&&("function"==typeof o[a[s]].type?o[a[s]].type.call(i,e)===!0:!n(e,o[a[s]].type)))return g?(d=new Error,d.message='Expected a "'+t+'" but found a "'+a[s]+'".',d.expected=t,d.type=a[s],d.value=e,d):null;return null===e||void 0===e?g||c?null:(d=new Error,d.message='Expected a "'+t+'" but found a "'+y+'".',d.expected=t,d.type=y,d.value=e,d):(h=~a.indexOf("*"),l=~a.indexOf(y),g&&(h||l)?(d=new Error,d.message='Expected a "'+t+'" but found a "'+(l?y:"*")+'".',d.type=l?y:"*",d.expected=t,d.value=e,d):g||h||l?null:(d=new Error,d.message='Expected a "'+t+'" but found a "'+y+'".',d.expected=t,d.type=y,d.value=e,d))}if("object"===i.get(t)){if("object"!==y)return d=new Error,d.message='Expected an object but found a "'+y+'".',d.expected=t,d.type=y,d.value=e,d;for(u in t)if(p=n(e[u],t[u]))return d=p,d.path=d.path?[u].concat(d.path):[u],d;for(u in e)if(void 0===t[u])return d=new Error,d.message='Unexpected key "'+u+'".',d.type=y,d.value=e,d;return null}if("array"===i.get(t)){if(1!==t.length)throw new Error("Invalid type.");if("array"!==y)return d=new Error,d.message='Expected an array but found a "'+y+'".',d.expected=t,d.type=y,d.value=e,d;for(f=e.length,s=0;f>s;s++)if(p=n(e[s],t[0]))return d=p,d.path=d.path?[s].concat(d.path):[s],d;return null}throw new Error("Invalid type.")}var i=this,o={};if(this.add=function(e,t){var n,i,a,s,f,u;if(1===arguments.length){if("object"!==this.get(e))throw new Error("If types.add is called with one argument, this one has to be an object.");n=e,s=n.id,u=n.type}else{if(2!==arguments.length)throw new Error("types.add has to be called with one or two arguments.");if("string"!=typeof e||!e)throw new Error("If types.add is called with more than one argument, the first one must be the string id.");s=e,u=t}if("string"!==this.get(s)||0===s.length)throw new Error("A type requires an string id.");if(void 0!==o[s]&&"proto"!==o[s])throw new Error('The type "'+s+'" already exists.');if(~r.indexOf(s))throw new Error('"'+s+'" is a reserved type name.');o[s]=1,a=(n||{}).proto||[],a=Array.isArray(a)?a:[a],f={};for(i in a)void 0===o[a[i]]&&(o[a[i]]=1,f[a[i]]=1);if("function"!==this.get(u)&&!this.isValid(u))throw new Error("A type requires a valid definition. This one can be a preexistant type or else a function testing given objects.");if(o[s]=void 0===n?{id:s,type:u}:{},void 0!==n)for(i in n)o[s][i]=n[i];for(i in f)i!==s&&delete o[i];return this},this.has=function(e){return!!o[e]},this.get=function(e){return null===e||void 0===e?String(e):t[Object.prototype.toString.call(e)]||"object"},this.check=function(e,t,r){var i=n(e,t);if(r&&i)throw i;return!i},this.isValid=function(e){var t,n,i;if("string"===this.get(e)){t=e.replace(/^[\?\!]/,"").split(/\|/);for(i in t)if(r.indexOf(t[i])<0&&!(t[i]in o))return!1;return!0}if("object"===this.get(e)){for(n in e)if(!this.isValid(e[n]))return!1;return!0}return"array"===this.get(e)&&1===e.length?this.isValid(e[0]):!1},this.add("type",function(e){return this.isValid(e)}.bind(this)),this.add("primitive",function(e){return!e||!(e instanceof Object||"object"==typeof e)}),e=e||{},"object"!==this.get(e))throw Error("Invalid argument.");for(var a in e)this.add(a,e[a])}var t={},r=["*"];!function(){var e,n,i=["Arguments","Boolean","Number","String","Function","Array","Date","RegExp","Object"];for(e in i)n=i[e],r.push(n.toLowerCase()),t["[object "+n+"]"]=n.toLowerCase()}();var n=e;e.call(n),Object.defineProperty(n,"version",{value:"0.3.1"}),"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=n),exports.types=n):"function"==typeof define&&define.amd?define("typology",[],function(){return n}):this.types=n}(this); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30373
586