assertions/mixed.js

/**
 * @fileOverview Various checks.
 * @module Mixed
 */
const Helpers = require('../helpers');
const Types = require('./types');
const Interface = require('../interface');
let Mixed = {};

let regExp = {
    email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
    hex: /^(?:0x)?[a-f0-9]+$/,
    ipv4: /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
    ipv6: /^(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))$/,
    base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
    semVer: /^(\d*)\.(\d*)\.(\d*)(-(\d*|\d*[a-z-][0-9a-z-]*)(\.(\d*|\d*[a-z-][0-9a-z-]*))*)?(\+[0-9a-z-]+(\.[0-9a-z-]+)*)?$/i,
    fiscalCodeIT: /^[A-Za-z]{6}[0-9]{2}[A-Za-z]{1}[0-9]{2}[A-Za-z]{1}[0-9]{3}[A-Za-z]{1}$/,
    macAddress: /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/,
    uuid1: /^[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
    uuid3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
    uuid4: /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
    uuid5: /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
    uuid: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
    isrc: /^([A-Z]{2}-[0-9A-Z]{3}-\d{2}-\d{5}|[A-Z]{2}[0-9A-Z]{3}\d{2}\d{5})$/,
    iswc: /^T-(\d{9}|\d{3}.\d{3}.\d{3})-[A-Za-z0-9]$/
};

Mixed = Helpers.createRegExpMethods(Mixed, regExp);

/**
 * Check if is ISWC
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name iswc
 * @param value {string} ISWC code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.iswc('T-000000001-0') // true
 */

/**
 * Check if is ISRC
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name isrc
 * @param value {string} ISRC code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.isrc('JMK401400212') // true
 */

/**
 * Check if is UUID
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name uuid
 * @param value {string} UUID code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.uuid('9e3a0460-d72d-11e4-a631-c8e0eb141dab') // true
 */

/**
 * Check if is UUID ver 1
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name uuid1
 * @param value {string} UUID code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.uuid1('9e3a0460-d72d-11e4-a631-c8e0eb141dab') // true
 */

/**
 * Check if is UUID ver 3
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name uuid3
 * @param value {string} UUID code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.uuid3('2c1d43b8-e6d7-376e-af7f-d4bde997cc3f') // true
 */

/**
 * Check if is UUID ver 4
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name uuid4
 * @param value {string} UUID code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.uuid4('366a77ba-d506-4a03-a730-318b8e6be8c5') // true
 */

/**
 * Check if is UUID ver 5
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name uuid5
 * @param value {string} UUID code
 * @returns {boolean}
 * @since 1.7.0
 * @example
 * be.uuid5('39888f87-fb62-5988-a425-b2ea63f5b81e') // true
 */

/**
 * Check if is valid email
 * https://emailregex.com/
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name email
 * @param value {string} email
 * @returns {boolean}
 * @example
 * be.email('fabio@rica.li') // true
 * be.not.email('fabiorica.li') // true
 */

/**
 * Check if is a hexadecimal
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name hex
 * @param value {string} hex string
 * @returns {boolean}
 * @example
 * be.hex('fff') // true
 */

/**
 * Check if is a valid IPv4
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name ipv4
 * @param value {string} ip string
 * @returns {boolean}
 * @example
 * be.ipv4('127.0.0.1') // true
 */

/**
 * Check if is a valid IPv6
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name ipv6
 * @param value {string} ip string
 * @returns {boolean}
 * @example
 * be.ipv6('FF01:0:0:0:0:0:0:1') // true
 */

/**
 * Check if is base64 encoded string
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name base64
 * @param value {string} base64 string
 * @returns {boolean}
 * @example
 * be.base64('aGVsbG8=') // true
 */

/**
 * Check if is a valid semver string
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name semVer
 * @param value {string} version string
 * @returns {boolean}
 * @example
 * be.semVer('1.0.0') // true
 */

/**
 * Check if is an IT fiscal code
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name fiscalCodeIT
 * @param value {string} code string
 * @returns {boolean}
 * @example
 * be.fiscalCodeIT('OLEFBA97C64F158X') // true
 */

/**
 * Check if is a valid MAC address
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name macAddress
 * @param value {string} MAC string
 * @returns {boolean}
 * @example
 * be.macAddress('3D:F2:C9:A6:B3:4F') // true
 */

/**
 * Check if is a valid ip string
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name ip
 * @param value {string} ip string
 * @returns {boolean}
 * @example
 * be.ip('127.0.0.1') // true
 */
Mixed.ip = (value) => {
    return Mixed.ipv4(value) || Mixed.ipv6(value);
};

/**
 * Checks if equal
 *
 * **Interfaces**: `not`, `err`
 *
 * @function
 * @name equal
 * @param value {Number|String|Boolean|RegExp|Array|Object} first
 * @param other {Number|String|Boolean|RegExp|Array|Object} second
 * @returns {boolean}
 * @example
 * be.equal('hello', 'hello') // true
 * be.equal('hello', 'hellow') // false
 * be.equal(true, 'true') // false
 * be.equal([1,2,3], [1,1,1]) // false
 * be.equal({a:1}, {a:1}) // true
 */
Mixed.equal = (value, other) => {
    if (Types.all.regexp(value, other))
        return value.toString() === other.toString();
    else if (Types.all.object(value, other) || Types.all.array(value, other)) {
        if (Object.keys(value).length !== Object.keys(other).length)
            return false;
        for (let prop in value) {
            if (value.hasOwnProperty(prop) && other.hasOwnProperty(prop)) {
                if (!Mixed.equal(value[prop], other[prop]))
                    return false;
            } else
                return false;
        }
        return true;
    } else {
        return Object.is(value, other);
    }
};

Mixed.equal.multiple = false;

/**
 * Check if is a hexadecimal color
 *
 * **Interfaces**: `all`, `any`, `not`, `err`
 *
 * @function
 * @name hexColor
 * @param value {string} hex color string
 * @returns {boolean}
 * @example
 * be.hexColor('#ff0000') // true
 */
Mixed.hexColor = (value) => {
    try {
        value = value.replace('#', '');
        return Mixed.hex(value) &&
            (value.length === 3 || value.length === 6);
    } catch (e) {
        return false;
    }
};

/**
 * Compare two version number
 *
 * **Interfaces**: `not`, `err`
 *
 * @function
 * @name compareVersion
 * @param a {string} version a
 * @param operator {string} operator "==", "<", "<=", ">", ">="
 * @param b {string} version b
 * @param major {boolean} consider major only
 * @returns {boolean}
 * @since 1.6.0
 * @example
 * be.compareVersion('1.0.2', '==', '1.0.3') // false
 * //Consider major only
 * be.compareVersion('1.0.2', '==', '1.0.3', true) // true
 */
Mixed.compareVersion = (a, operator, b, major) => {
    if (major) {
        a = a.split('.')[0];
        b = b.split('.')[0];
    }
    return Helpers.comparators[operator](a, b);
};

/**
 * Checks if string length or if a number value is greater or equal than a given number
 *
 * **Interfaces**: `not`, `err`
 *
 * @function
 * @name max
 * @param value {string|number} value to check
 * @param num {number} number target
 * @returns {boolean}
 * @since 1.16.0
 * @example
 * be.max(10, 2) // false
 * be.max('hello', 5) // true
 */
Mixed.max = (value, num) => {
    if (Types.string(value))
        value = value.length;
    return Types.all.number(value, num) && value <= num;
};

Mixed.max.multiple = false;

/**
 * Checks if string length or if a number value is lesser or equal than a given number
 *
 * **Interfaces**: `not`, `err`
 *
 * @function
 * @name min
 * @param value {string|number} value to check
 * @param num {number} number target
 * @returns {boolean}
 * @since 1.16.0
 * @example
 * be.min(10, 2) // true
 * be.min('hello', 3) // true
 */
Mixed.min = (value, num) => {
    if (Types.string(value))
        value = value.length;
    return Types.all.number(value, num) && value >= num;
};

Mixed.min.multiple = false;

Mixed = Interface.create(Mixed);

module.exports = Mixed;