Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added files for production.

  • Loading branch information...
commit 443699e49ccb763befc0268b0b8b17f130900950 1 parent f49f1dd
iclanzan authored
Showing with 304 additions and 0 deletions.
  1. +303 −0 jassi.js
  2. +1 −0  jassi.min.js
View
303 jassi.js
@@ -0,0 +1,303 @@
+/*
+ * Jassi v0.1.0
+ * https://github.com/iclanzan/jassi
+ *
+ * Copyright (c) 2012 Sorin Iclanzan <sorin@iclanzan.com>
+ * License: https://github.com/iclanzan/jassi
+ */
+
+(function(root, undefined) {
+ 'use strict';
+
+function isArray(value) {
+ return Array.isArray(value);
+}
+
+function inArray(value, array) {
+ return array.indexOf(value) != -1;
+}
+
+function getKeys(obj) {
+ return Object.keys(obj);
+}
+
+/**
+ * Check if a given value is an instance of a JSON object.
+ * This means that arrays and the null object are not considered objects.
+ *
+ * @param {any} value Any value to be checked
+ * @return {Boolean} Returns true if the value is an instance of a JSON object, false otherwise.
+ */
+function isObject(value) {
+ return null !== value && typeof value == 'object' && !isArray(value);
+}
+
+/**
+ * Get the type of a value.
+ *
+ * JSON primitive types:
+ * Array, Boolean, Number, null, Object, String
+ *
+ * @param {any} value Any value
+ * @return {String} One of the JSON primitive types.
+ */
+function getType(value) {
+ return isObject(value) && 'object' ||
+ isArray(value) && 'array' ||
+ null === value && 'null' ||
+ typeof value;
+}
+
+/**
+ * Check if two items are equal as per the JSON Schema spec.
+ *
+ * @param {any} item1 The first item
+ * @param {any} item2 The second item
+ * @return {Boolean} Returns true if the items are equal.
+ */
+function areEqual(item1, item2) {
+ var i, l, keys1, keys2, key;
+
+ if (typeof item1 !== typeof item2) return false;
+
+ if (isArray(item1)) {
+ if (item1.length !== item2.length) return false;
+
+ for (i = 0, l = item1.length; i < l; i ++)
+ if (!areEqual(item1[i], item2[i])) return false;
+
+ return true;
+ }
+
+ if (isObject(item1)) {
+ // edge case when one of the items is null
+ if (!isObject(item2)) return false;
+
+ keys1 = getKeys(item1);
+ keys2 = getKeys(item2);
+
+ if (keys1.length !== keys2.length) return false;
+
+ for (i = 0, l = keys1.length; i < l; i ++) {
+ key = keys1[i];
+ if (!item2.hasOwnProperty(key) || !areEqual(item1[key], item2[key])) return false;
+ }
+
+ return true;
+ }
+
+ return item1 === item2;
+}
+
+function or(item1, item2) {
+ return undefined !== item1 ? item1 : item2;
+}
+
+/**
+ * Validate a JSON instance against a schema.
+ *
+ * The function returns an empty array if validation is successful.
+ *
+ * @param {any} instance An instance of a JSON data that needs to be validated
+ * @param {Object} schema The schema to validate the instance against
+ * @param {String} path Optional. The path to the property that is being validated.
+ * @return {Array} An array of objects describing validation errors.
+ */
+var validate = function(instance, schema, path) {
+ var errors = [], type, l, i, j, items, itemsIsArray, additional, additionalIsObject, found, properties, pattern, pp;
+
+ function addError(message) {
+ errors.push({property:path, message: message});
+ return errors;
+ }
+
+ if (undefined === path) path = '';
+
+ if (!isObject(schema)) return addError('Invalid schema.');
+
+ type = getType(instance);
+ if (schema.type && schema.type != type && (schema.type != 'integer' || type == 'number' && instance % 1 != 0 ))
+ addError('Invalid type. Was expecting ' + schema.type + ' but found ' + type + '.');
+
+ if (null === instance) return errors;
+
+ if ('array' == type) {
+ l = instance.length;
+
+ if (schema.items || schema.additionalItems) {
+ items = schema.items || {};
+ itemsIsArray = isArray(schema.items);
+
+ additional = schema.additionalItems;
+ additionalIsObject = isObject(schema.additionalItems);
+
+ if (itemsIsArray && false === additional && l > (j = items.length))
+ addError('The instance can only have up to ' + j + ' items.');
+
+ else for (i = 0; i < l; i ++)
+ errors = errors.concat(validate(
+ instance[i],
+ itemsIsArray ? items[i] || additionalIsObject && additional || {} : items,
+ path + '[' + i + ']'
+ ));
+ }
+
+ if (schema.maxItems && l > schema.maxItems)
+ addError('There must be a maximum of ' + schema.maxItems + ' item(s) in the array.');
+
+ if (schema.minItems && l < schema.minItems)
+ addError('There must be a minimum of ' + schema.minItems + ' item(s) in the array.');
+
+ if (schema.uniqueItems) {
+ dance: for (i = 0; i < l; i ++) {
+ for (j = i + 1; j < l; j ++) {
+ if (areEqual(instance[i], instance[j])) {
+ addError("The items in the array must be unique.");
+ break dance;
+ }
+ }
+ }
+ }
+ }
+
+ if ('object' == type) {
+ if (schema.maxProperties && getKeys(instance).length > schema.maxProperties)
+ addError('The instance must have at most ' + schema.maxProperties + ' members.');
+
+ if (schema.minProperties && getKeys(instance).length < schema.minProperties)
+ addError('The instance must have at least ' + schema.maxProperties + ' members.');
+
+ if (schema.required)
+ schema.required.forEach(function(requiredProperty) {
+ if (!instance.hasOwnProperty(requiredProperty))
+ addError('Required property "' + requiredProperty + '" is missing.');
+ });
+
+ if (schema.properties || schema.additionalProperties || schema.patternProperties) {
+ properties = or(schema.properties, {});
+ pattern = or(schema.patternProperties, {});
+ additional = or(schema.additionalProperties, {});
+ pp = getKeys(pattern);
+ }
+
+ getKeys(instance).forEach(function(key) {
+ var schemas, match;
+
+ if (schema.dependencies && schema.dependencies[key])
+ errors = errors.concat(validate(instance, schema.dependencies[key], path));
+
+ if (
+ properties &&
+ false === additional &&
+ !properties.hasOwnProperty(key) &&
+ !(pp && pp.some(function(regex) { return key.match(regex); }))
+ )
+ addError('The key "' + key + '" is not allowed to be set.');
+
+ else {
+ schemas = [];
+ if (properties && properties.hasOwnProperty(key))
+ schemas.push(properties[key]);
+ if (pp && pp.some(function(regex) { return key.match(regex) && (match = pp[regex]); }))
+ schemas.push(match);
+ if (!schema.length && additional)
+ schemas.push(additional);
+
+ schemas.forEach(function(schema) {
+ errors = errors.concat(validate(instance[key], schema, path ? path + '.' + key : key));
+ });
+ }
+ });
+ }
+
+ if ('string' == type) {
+ if (schema.maxLength && instance.length > schema.maxLength)
+ addError('The instance must not be more than ' + schema.maxLength + ' character(s) long.');
+
+ if (schema.minLength && instance.length < schema.minLength)
+ addError('The instance must be at least ' + schema.minLength + ' character(s) long.');
+
+ if (schema.pattern && !instance.match(schema.pattern))
+ addError('Regex pattern /' + schema.pattern + '/ is a mismatch.');
+ }
+
+ if ('number' == type) {
+ if (schema.multipleOf !== undefined && instance / schema.multipleOf % 1 != 0)
+ addError('The instance is required to be a multiple of ' + schema.multipleOf + '.');
+
+ if (schema.maximum !== undefined) {
+ if (!schema.exclusiveMaximum && schema.maximum < instance)
+ addError('The instance must have a maximum value of ' + schema.maximum + '.');
+
+ if (schema.exclusiveMaximum && schema.maximum <= instance)
+ addError('The instance must be lower than ' + schema.maximum + '.');
+ }
+
+ if (schema.minimum !== undefined) {
+ if (!schema.exclusiveMinimum && schema.minimum > instance)
+ addError('The instance must have a minimum value of ' + schema.minimum + '.');
+
+ if (schema.exclusiveMinimum && schema.minimum >= instance)
+ addError('The instance must be greater than ' + schema.minimum + '.');
+ }
+ }
+
+ if (schema['enum']) {
+ items = schema['enum'];
+ l = items.length;
+ for (i = 0, found = 0; i < l && !found; i++)
+ if (areEqual(items[i], instance))
+ found = 1;
+
+ if (!found) addError('The instance must have one of the following values: ' + items.join(', ') + '.');
+ }
+
+ if (schema.allOf) {
+ schema.allOf.forEach(function(schema) {
+ errors = errors.concat(validate(instance, schema, path));
+ });
+ }
+
+ if (schema.anyOf) {
+ items = schema.anyOf;
+ l = items.length;
+ for(i = 0, found = 0; i < l && !found; i++)
+ if (!validate(instance, items[i], path).length)
+ found = 1;
+
+ if (!found) addError('The instance must validate against at least one schema defined by the "anyOf" keyword.');
+ }
+
+ if (schema.oneOf) {
+ items = schema.oneOf;
+ l = items.length;
+ for (i = 0, found = 0; i < l; i++)
+ if (!validate(instance, items[i], path).length) {
+ if (found) {
+ addError('The instance must validate against exactly one schema defined by the "oneOf" keyword.');
+ break;
+ }
+ found = 1;
+ }
+ }
+
+ if (schema.not && !validate(instance, schema.not, path).length)
+ addError('The instance must not validate against the schema defined by the "not" keyword.');
+
+ return errors;
+};
+
+// Expose Jassi as a CommonJS module for Node
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = validate;
+}
+
+// Expose Jassi as an AMD module
+else if (typeof define === 'function' && define.amd) {
+ define(function () { return validate; });
+}
+
+// Attach to the root object, usually window.
+else root.jassi = validate;
+
+})(this);
View
1  jassi.min.js
@@ -0,0 +1 @@
+/*! Jassi v0.1.0 */(function(e,t){"use strict";function n(e){return Array.isArray(e)}function i(e){return Object.keys(e)}function r(e){return null!==e&&"object"==typeof e&&!n(e)}function a(e){return r(e)&&"object"||n(e)&&"array"||null===e&&"null"||typeof e}function m(e,t){var a,s,u,o,h;if(typeof e!=typeof t)return!1;if(n(e)){if(e.length!==t.length)return!1;for(a=0,s=e.length;s>a;a++)if(!m(e[a],t[a]))return!1;return!0}if(r(e)){if(!r(t))return!1;if(u=i(e),o=i(t),u.length!==o.length)return!1;for(a=0,s=u.length;s>a;a++)if(h=u[a],!t.hasOwnProperty(h)||!m(e[h],t[h]))return!1;return!0}return e===t}function s(e,n){return t!==e?e:n}var u=function(e,o,h){function f(e){return I.push({property:h,message:e}),I}var l,c,p,d,g,y,x,b,v,T,O,P,I=[];if(t===h&&(h=""),!r(o))return f("Invalid schema.");if(l=a(e),o.type&&o.type!=l&&("integer"!=o.type||"number"==l&&0!=e%1)&&f("Invalid type. Was expecting "+o.type+" but found "+l+"."),null===e)return I;if("array"==l){if(c=e.length,o.items||o.additionalItems)if(g=o.items||{},y=n(o.items),x=o.additionalItems,b=r(o.additionalItems),y&&!1===x&&c>(d=g.length))f("The instance can only have up to "+d+" items.");else for(p=0;c>p;p++)I=I.concat(u(e[p],y?g[p]||b&&x||{}:g,h+"["+p+"]"));if(o.maxItems&&c>o.maxItems&&f("There must be a maximum of "+o.maxItems+" item(s) in the array."),o.minItems&&o.minItems>c&&f("There must be a minimum of "+o.minItems+" item(s) in the array."),o.uniqueItems)e:for(p=0;c>p;p++)for(d=p+1;c>d;d++)if(m(e[p],e[d])){f("The items in the array must be unique.");break e}}if("object"==l&&(o.maxProperties&&i(e).length>o.maxProperties&&f("The instance must have at most "+o.maxProperties+" members."),o.minProperties&&i(e).length<o.minProperties&&f("The instance must have at least "+o.maxProperties+" members."),o.required&&o.required.forEach(function(t){e.hasOwnProperty(t)||f('Required property "'+t+'" is missing.')}),(o.properties||o.additionalProperties||o.patternProperties)&&(T=s(o.properties,{}),O=s(o.patternProperties,{}),x=s(o.additionalProperties,{}),P=i(O)),i(e).forEach(function(t){var n,i;o.dependencies&&o.dependencies[t]&&(I=I.concat(u(e,o.dependencies[t],h))),!T||!1!==x||T.hasOwnProperty(t)||P&&P.some(function(e){return t.match(e)})?(n=[],T&&T.hasOwnProperty(t)&&n.push(T[t]),P&&P.some(function(e){return t.match(e)&&(i=P[e])})&&n.push(i),!o.length&&x&&n.push(x),n.forEach(function(n){I=I.concat(u(e[t],n,h?h+"."+t:t))})):f('The key "'+t+'" is not allowed to be set.')})),"string"==l&&(o.maxLength&&e.length>o.maxLength&&f("The instance must not be more than "+o.maxLength+" character(s) long."),o.minLength&&e.length<o.minLength&&f("The instance must be at least "+o.minLength+" character(s) long."),o.pattern&&!e.match(o.pattern)&&f("Regex pattern /"+o.pattern+"/ is a mismatch.")),"number"==l&&(o.multipleOf!==t&&0!=e/o.multipleOf%1&&f("The instance is required to be a multiple of "+o.multipleOf+"."),o.maximum!==t&&(!o.exclusiveMaximum&&e>o.maximum&&f("The instance must have a maximum value of "+o.maximum+"."),o.exclusiveMaximum&&e>=o.maximum&&f("The instance must be lower than "+o.maximum+".")),o.minimum!==t&&(!o.exclusiveMinimum&&o.minimum>e&&f("The instance must have a minimum value of "+o.minimum+"."),o.exclusiveMinimum&&o.minimum>=e&&f("The instance must be greater than "+o.minimum+"."))),o["enum"]){for(g=o["enum"],c=g.length,p=0,v=0;c>p&&!v;p++)m(g[p],e)&&(v=1);v||f("The instance must have one of the following values: "+g.join(", ")+".")}if(o.allOf&&o.allOf.forEach(function(t){I=I.concat(u(e,t,h))}),o.anyOf){for(g=o.anyOf,c=g.length,p=0,v=0;c>p&&!v;p++)u(e,g[p],h).length||(v=1);v||f('The instance must validate against at least one schema defined by the "anyOf" keyword.')}if(o.oneOf)for(g=o.oneOf,c=g.length,p=0,v=0;c>p;p++)if(!u(e,g[p],h).length){if(v){f('The instance must validate against exactly one schema defined by the "oneOf" keyword.');break}v=1}return o.not&&!u(e,o.not,h).length&&f('The instance must not validate against the schema defined by the "not" keyword.'),I};"undefined"!=typeof module&&module.exports?module.exports=u:"function"==typeof define&&define.amd?define(function(){return u}):e.jassi=u})(this);
Please sign in to comment.
Something went wrong with that request. Please try again.