Home Reference Source Test

source/validator.js

import { typeOf, isClass } from './utility/index';

import Model from './Model';

import { trigger } from './hook/index';


const base_type = [Number, String, Boolean, Date, RegExp, Object, Array];

function check(value, condition, key, data) {

    const type = typeOf( data );

    if (base_type.includes( condition )  ||  isClass( condition )) {

        if (Object(value) instanceof String)  try {

            value = JSON.parse( value );

        } catch (error) {/**/}

        value = Object( value );

        if (
            (condition === Object)  ?
                (value.constructor !== Object)  :  !(value instanceof condition)
        )
            throw TypeError(`"${key}" of ${type} should be ${condition.name}`);

    } else if (condition instanceof Function) {
        /**
         * Throw an Error is recommended when something is wrong
         *
         * @typedef {function(value: *, key: String, data: Model): void} ModelValueHandler
         */
        condition(value, key, data);

    } else if (condition instanceof RegExp) {

        if (! condition.test(value + ''))
            throw TypeError(`"${key}" of ${type} should match /${condition.source}/`);

    } else if (condition instanceof Array)
        if (! condition.includes( value ))
            throw TypeError(`"${key}" of ${type} should be in ${condition.join(', ')}`);
}

/**
 * Field Decorator to validate the value of Setter
 *
 * @param {Function|RegExp|Array|ModelValueHandler} condition
 * @param {*}                                       [defaultValue]
 *
 * @return {function(meta: DecoratorDescriptor): void}
 */
export function is(condition, defaultValue) {

    return  meta => {

        const { kind, placement, key, descriptor } = meta;

        const origin = descriptor.set;

        descriptor.set = function (value) {

            value = (value != null) ? value : defaultValue;

            if (!(value != null))  return this.delete( key );

            if (condition.prototype instanceof Model)
                value = new condition( value );
            else
                check(value, condition, key, this);

            origin.call(this, value);
        };

        meta.finisher = Class => {

            trigger('is',  {Class, kind, placement, key, descriptor});
        };
    };
}