Source: lib/util/Validator.js

'use strict';

const valLib = require('validator');
const deprecated = require('./deprecated');

/**
 * @alias util.Validator
 */
class Validator {
  /**
   * Compiles the given validation code for the managedType
   * @param {metamodel.ManagedType} managedType The managedType of the code
   * @param {string} validationCode The validation code
   * @return {void}
   */
  static compile(managedType, validationCode) {
    const keys = [];
    const iter = managedType.attributes();
    for (let el = iter.next(); !el.done; el = iter.next()) {
      const attr = el.value;
      keys.push(attr.name);
    }

    // eslint-disable-next-line no-new-func
    const fn = new Function(keys, validationCode);
    return function onValidate(argObj) {
      const args = keys.map(name => argObj[name]);

      return fn.apply({}, args);
    };
  }

  /**
   * Gets the value of the attribute
   * @return {*} Value
   */
  get value() {
    return this.entity[this.key];
  }

  /**
   * Checks if the attribute is valid
   * @return {boolean}
   */
  get isValid() {
    return this.errors.length === 0;
  }

  /**
   * Executes the given validation function to validate the value.
   *
   * The value will be passed as the first parameter to the validation function and
   * the library {@link https://github.com/chriso/validator.js} as the second one.
   * If the function returns true the value is valid, otherwise it's invalid.
   *
   * @name is
   * @memberOf util.Validator.prototype
   * @function
   * @param {Function} fn will be used to validate the value
   * @return {util.Validator}
   */

  /**
   * Executes the given validation function to validate the value.
   *
   * The value will be passed as the first parameter to the validation function and
   * the library {@link https://github.com/chriso/validator.js} as the second one.
   * If the function returns true the value is valid, otherwise it's invalid.
   *
   * @param {string} error The error message which will be used if the value is invalid
   * @param {Function} fn will be used to validate the value
   * @return {util.Validator}
   */
  is(error, fn) {
    if (error instanceof Function) {
      return this.is('is', error);
    }

    if (fn(this.value, valLib) === false) {
      this.errors.push(error);
    }

    return this;
  }

  constructor(key, entity) {
    /**
     * Name of the attribute
     * @type string
     */
    this.key = key;

    /**
     * Entity to get the value of the attribute
     * @type {binding.Entity}
     * @private
     */
    this.entity = entity;

    /**
     * Entity to get the value of the attribute
     * @type {binding.Entity}
     * @private
     */
    this.errors = [];
  }

  callMethod(method, error, argumentList) {
    const args = argumentList || [];
    args.unshift(this.value);
    if (valLib[method].apply(this, args) === false) {
      this.errors.push(error);
    }
    return this;
  }

  toString() {
    return this.value;
  }

  toJSON() {
    return {
      isValid: this.isValid,
      errors: this.errors,
    };
  }
}

Object.keys(valLib).forEach((name) => {
  if (typeof valLib[name] === 'function' && name !== 'toString' &&
    name !== 'toDate' && name !== 'extend' && name !== 'init') {
    /**
     * @ignore
     */
    Validator.prototype[name] = function validate(error) { // use function here to keep the correct this context
      return this.callMethod(name, error || name, Array.prototype.slice.call(arguments, error ? 1 : 0));
    };
  }
});

deprecated(Validator.prototype, '_callMethod', 'callMethod');
deprecated(Validator.prototype, '_entity', 'entity');

module.exports = Validator;