lib/check.js

/**
 * @module lib/check
 */

/**
 *
 * @param value
 * @param name
 * @returns {boolean}
 */
export function checkDefined(value, name) {
    if (value !== undefined) {
        return true
    }
    throw new Error([name || 'Value', 'should be provided'].join(' '))
}

// TODO: Decide if checkType([], 'object') is a 'false' positive
// eslint-disable-next-line complexity
export function checkType(value, type, name) {
    checkDefined(value, name)
    checkDefined(type, 'Type')

    if (
        (typeof type === 'function' && value instanceof type) ||
        (typeof type === 'string' && typeof value === type)
    ) {
        return true
    }
    throw new Error(['Expected', name || value, 'to have type', type].join(' '))
}

// TODO: Log type error?
export function isType(value, type) {
    function noop() {}

    try {
        checkType(value, type)
        return true
    } catch (e) {
        noop()
    }

    return false
}

export function isString(value) {
    return isType(value, 'string')
}

export function isArray(value) {
    return Array.isArray(value)
}

export function isObject(value) {
    return isType(value, Object)
}

export function isDefined(value) {
    return value != null
}

export function isInteger(nVal) {
    return (
        typeof nVal === 'number' &&
        isFinite(nVal) &&
        nVal > -9007199254740992 &&
        nVal < 9007199254740992 &&
        Math.floor(nVal) === nVal
    )
}

// Polyfill for the isInteger function that will be added in ES6
// http://wiki.ecmascript.org/doku.php?id=harmony:number.isinteger
/* istanbul ignore if  */
if (!Number.isInteger) {
    Number.isInteger = isInteger
}

export function isNumeric(nVal) {
    return (
        typeof nVal === 'number' &&
        isFinite(nVal) &&
        nVal - parseFloat(nVal) + 1 >= 0
    )
}

export function contains(item, list) {
    const listToCheck = (isArray(list) && list) || []

    return listToCheck.indexOf(item) >= 0
}

export const isEmpty = list => list.length === 0

/**
 * @deprecated Use isValidUid from the `uid.js` file.
 */
export function isValidUid(value) {
    return value && value.length === 11
}

export const hasKeys = object => object && Object.keys(object).length > 0

export function areDefinedAndEqual(left, right) {
    return isDefined(left) && isDefined(right) && right === left
}

export const toBe = (left, right) => left === right
export const toBeAny = values => left => values.some(right => toBe(left, right))
export const isNullUndefinedOrEmptyString = toBeAny([undefined, null, ''])

export const isFunction = fun => typeof fun === 'function'

export const hasOwnProperty = (object, propertyName) =>
    Object.prototype.hasOwnProperty.call(object, propertyName)

// The logical mode to use when having multiple filters.
// Default is AND.
// See https://docs.dhis2.org/master/en/developer/html/webapi_metadata_object_filter.html

export const rootJunctions = ['OR', 'AND']
export const isValidRootJunction = toBeAny(rootJunctions)
export function checkValidRootJunction(rootJunction) {
    checkType(rootJunction, 'string', 'rootJunction')

    if (isValidRootJunction(rootJunction)) {
        return true
    }
    throw new Error(`Expected ${rootJunction} to be one of [${rootJunctions}]`)
}