mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-04-05 14:12:46 +00:00
128 lines
3.9 KiB
JavaScript
128 lines
3.9 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* jshint unused:false */
|
|
|
|
var loop = loop || {};
|
|
loop.validate = (function() {
|
|
"use strict";
|
|
|
|
/**
|
|
* Computes the difference between two arrays.
|
|
*
|
|
* @param {Array} arr1 First array
|
|
* @param {Array} arr2 Second array
|
|
* @return {Array} Array difference
|
|
*/
|
|
function difference(arr1, arr2) {
|
|
return arr1.filter(function(item) {
|
|
return arr2.indexOf(item) === -1;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Retrieves the type name of an object or constructor. Fallback to "unknown"
|
|
* when it fails.
|
|
*
|
|
* @param {Object} obj
|
|
* @return {String}
|
|
*/
|
|
function typeName(obj) {
|
|
if (obj === null)
|
|
return "null";
|
|
if (typeof obj === "function")
|
|
return obj.name || obj.toString().match(/^function\s?([^\s(]*)/)[1];
|
|
if (typeof obj.constructor === "function")
|
|
return typeName(obj.constructor);
|
|
return "unknown";
|
|
}
|
|
|
|
/**
|
|
* Simple typed values validator.
|
|
*
|
|
* @constructor
|
|
* @param {Object} schema Validation schema
|
|
*/
|
|
function Validator(schema) {
|
|
this.schema = schema || {};
|
|
}
|
|
|
|
Validator.prototype = {
|
|
/**
|
|
* Validates all passed values against declared dependencies.
|
|
*
|
|
* @param {Object} values The values object
|
|
* @return {Object} The validated values object
|
|
* @throws {TypeError} If validation fails
|
|
*/
|
|
validate: function(values) {
|
|
this._checkRequiredProperties(values);
|
|
this._checkRequiredTypes(values);
|
|
return values;
|
|
},
|
|
|
|
/**
|
|
* Checks if any of Object values matches any of current dependency type
|
|
* requirements.
|
|
*
|
|
* @param {Object} values The values object
|
|
* @throws {TypeError}
|
|
*/
|
|
_checkRequiredTypes: function(values) {
|
|
Object.keys(this.schema).forEach(function(name) {
|
|
var types = this.schema[name];
|
|
types = Array.isArray(types) ? types : [types];
|
|
if (!this._dependencyMatchTypes(values[name], types)) {
|
|
throw new TypeError("invalid dependency: " + name +
|
|
"; expected " + types.map(typeName).join(", ") +
|
|
", got " + typeName(values[name]));
|
|
}
|
|
}, this);
|
|
},
|
|
|
|
/**
|
|
* Checks if a values object owns the required keys defined in dependencies.
|
|
* Values attached to these properties shouldn't be null nor undefined.
|
|
*
|
|
* @param {Object} values The values object
|
|
* @throws {TypeError} If any dependency is missing.
|
|
*/
|
|
_checkRequiredProperties: function(values) {
|
|
var definedProperties = Object.keys(values).filter(function(name) {
|
|
return typeof values[name] !== "undefined";
|
|
});
|
|
var diff = difference(Object.keys(this.schema), definedProperties);
|
|
if (diff.length > 0)
|
|
throw new TypeError("missing required " + diff.join(", "));
|
|
},
|
|
|
|
/**
|
|
* Checks if a given value matches any of the provided type requirements.
|
|
*
|
|
* @param {Object} value The value to check
|
|
* @param {Array} types The list of types to check the value against
|
|
* @return {Boolean}
|
|
* @throws {TypeError} If the value doesn't match any types.
|
|
*/
|
|
_dependencyMatchTypes: function(value, types) {
|
|
return types.some(function(Type) {
|
|
/*jshint eqeqeq:false*/
|
|
try {
|
|
return typeof Type === "undefined" || // skip checking
|
|
Type === null && value === null || // null type
|
|
value.constructor == Type || // native type
|
|
Type.prototype.isPrototypeOf(value) || // custom type
|
|
typeName(value) === typeName(Type); // type string eq.
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
return {
|
|
Validator: Validator
|
|
};
|
|
})();
|