forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			131 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			131 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/. */
 | 
						|
 | 
						|
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) {
 | 
						|
        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
 | 
						|
  };
 | 
						|
})();
 |