/**
* Provides type checking functions
*
* @module Utils
* @class Utils.Types
* @static
*/
const getClass = (v) => Object.prototype.toString.call(v).toLowerCase();
const equals = (a) => (b) => a === b;
const equalsType = (t) => (v) => typeof v === t;
const equalsSymbol = (s) => (v) => `[object ${s}]` === getClass(v);
const passes = (f) => (v) => !!f(v);
const interfaced = (c) => (v) => c.prototype.isPrototypeOf(v);
const either = (cs) => (v) => cs.some((c) => !!c(v));
/**
* Given a value, checks if the value is null
*
* @method isNull
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for null values
*/
export const isNull = equals(null);
/**
* Given a value, checks if the value is null
*
* @method isVoid
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for undefined values
*/
export const isVoid = equals(void 0);
/**
* Given a value, checks if the value is either null or undefined
*
* @method isNil
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for null and/or undefined values
*/
export const isNil = passes((v) => v == null);
/**
* Given a value, checks if the value is a boolean
*
* @method isBool
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for boolean values
*/
export const isBool = equalsType('boolean');
/**
* Given a value, checks if the value is a string
*
* @method isString
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for string values
*/
export const isString = equalsType('string');
/**
* Given a value, checks if the value is numeric (Int, Float, NaN, Infinity, ...)
*
* @method isNumeric
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for any numeric values
*/
export const isNumeric = equalsType('number');
/**
* Given a value, checks if the value is a number (Int/Float)
*
* @method isNumber
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for number values
*/
export const isNumber = passes((v) => typeof v === 'number' && !isNaN(v) && isFinite(v));
/**
* Given a value, checks if the value is an integer
*
* @method isInteger
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for integer values
*/
export const isInteger = passes((v) => isNumber(v) && v % 1 === 0);
/**
* Given a value, checks if the value is a floating point number
*
* @method isFloat
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for floating point numbers
*/
export const isFloat = passes((v) => isNumber(v) && v % 1 !== 0)
/**
* Given a value, checks if the value is a function
*
* @method isFunction
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for function values
*/
export const isFunction = equalsType('function');
/**
* Given a value, checks if the value is a symbol
*
* @method isSymbol
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for function values
*/
export const isSymbol = equalsType('symbol');
/**
* Given a value, checks if the value is a array
*
* @method isArray
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for array values
*/
export const isArray = (v) => Array.isArray(v);
/**
* Given a value, checks if the value is a real object
*
* @method isObject
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for object values
*/
export const isObject = equalsSymbol('object');
/**
* Given a value, checks if the value is a date object
*
* @method isDate
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for date values
*/
export const isDate = equalsSymbol('date');
/**
* Given a value, checks if the value is a regular expression
*
* @method isRegex
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for regular expressions
*/
export const isRegex = equalsSymbol('regexp');
/**
* Given a value, checks if the value is a Node
*
* @method isNode
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for Node values
*/
export const isNode = interfaced(Node);
/**
* Given a value, checks if the value is a HTMLElement
*
* @method isElement
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for HTMLElement values
*/
export const isElement = interfaced(HTMLElement);
/**
* Given a value, checks if the value is a NodeList or HTMLCollection
*
* @method isElementList
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for NodeList and HTMLCollection values
*/
export const isElementList = interfaced(NodeList);
/**
* Given a value, checks if the value is a DocumentFragment
*
* @method isFragment
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True for DocumentFragment values
*/
export const isFragment = interfaced(DocumentFragment);
/**
* Given a value, checks if the value is equal to the Window object
*
* @method isWindow
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True if x is the Window object
*/
export const isWindow = equals(window);
/**
* Given a value, checks if the value is equal to the Document object
*
* @method isDocument
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True if x is the Document object
*/
export const isDocument = equals(document);
/**
* Given a value, checks if the value is in any way sequencial. Sequencial
* values are Arrays, Strings, NodeLists and HTMLCollections
*
* @method isSeq
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True if x is sequencial
*/
export const isSeq = either([isArray, isString, isElementList]);
/**
* Given a value, checks if the value is enumerable. Enumerable values are
* Arrays, Strings, NodeLists, HTMLCollections and Objects
*
* @method isEnum
* @for Utils.Types
* @param {any} x The value to test
* @return {boolean} True if x is enumerable
*/
export const isEnum = either([isSeq, isObject]);
export default {
isNull, isNil, isVoid, isString, isNumber, isInteger, isFloat, isNumeric,
isArray, isFunction, isBool, isDocument, isDate, isElement, isEnum, isSeq,
isWindow, isObject, isNode, isElementList, isFragment, isRegex
};