• is.js

  • ¶
    is.js - 1.0.2
    Minimalistic predicate library
    Pwn <hi@pwn.buzz>
    
    ( function ( root , factory ) {
    
    if ( typeof define === 'function' && define.amd ) {
  • ¶

    AMD. Register as an anonymous module.

        define( factory )
    
    } else if ( typeof module === 'object' && module.exports ) {
  • ¶

    Node. Does not work with strict CommonJS, but only CommonJS-like environments that support module.exports, like Node.

        module.exports = factory()
    
    } else {
  • ¶

    Browser globals

        root.is = factory()
    
    }
    
    } )( this , function factory() {
    
        var is = { not : {} }
        var util
    
        var hasOwnProperty = Object.prototype.hasOwnProperty
  • ¶

    getTag( value )

    Get the [[class]] attribute, or tag in is.js terminology, of any given value.

        var getTag = ( function () {
    
            var reSource = /(?:function|class)\s*(\w*)/
    
            var toString = Object.prototype.toString
            var toSource = Function.prototype.toString
    
            return function tagOf( value ) {
    
                var tagFromClass
                var tagFromSource
    
                if ( value === null ) {
                    return 'null'
                } else if ( value === void 0 ) {
                    return 'undefined'
                }
    
                tagFromClass = toString.call( value )
                tagFromClass = tagFromClass.substring( 8 , tagFromClass.length - 1 )
    
                if ( typeof value.constructor !== 'function' ) {
                    return tagFromClass.toLowerCase()
                } else {
                    tagFromSource = toSource.call( value.constructor ).match( reSource )[ 1 ]
                    return ( tagFromSource || tagFromClass ).toLowerCase()
                }
    
            }
    
        } )()
  • ¶

    ownKeys( value )

    Object.keys ponyfill.

        var ownKeys = Object.keys || ( function ( dontEnums ) {
    
            var dontEnumsLength = dontEnums.length
            var hasDontEnumBug = !{ toString : null }.propertyIsEnumerable( 'toString' )
    
            return function ownKeys( object ) {
    
                var key
                var keys = []
                var index
    
                if ( object === null || object === void 0 ) {
                    throw new TypeError( 'ownKeys called on non-object' )
                }
    
                for ( key in object ) {
                    if ( hasOwnProperty.call( object , key ) ) {
                        keys.push( key )
                    }
                }
  • ¶

    Fix IE < 9 JScript DontEnum Bug.

                if ( hasDontEnumBug ) {
                    for ( index = 0 ; index < dontEnumsLength ; index += 1 ) {
                        key = dontEnums[ index ]
                        if ( hasOwnProperty.call( object , key ) ) {
                            keys.push( key )
                        }
                    }
                }
    
                return keys
    
            }
    
        } )( [
  • ¶

    These properties are marked as DontEnum in IE < 9. They will never show up in for...in loops nor pass propertyIsEnumerable check.

            'toString' ,
            'toLocaleString' ,
            'valueOf' ,
            'isPrototypeOf' ,
            'hasOwnProperty' ,
            'propertyIsEnumerable' ,
            'constructor'
    
        ] )
    
    
        util = {
  • ¶

    util.addPredicate( name , predicate )

    Add new checks(or predicates in is.js terminology).

            addPredicate : function addPredicate( name , predicate ) {
    
                if ( /^(not|use)$/.test( name ) ) {
                    throw new Error( '"' + name + '" is a reserved name' )
                }
    
                if ( hasOwnProperty.call( is , name ) ) {
                    throw new Error( 'predicate "' + name + '" already defined' )
                }
    
                if ( typeof predicate !== 'function' ) {
                    throw new TypeError( 'predicate must be a function' )
                }
    
                is[ name ] = predicate
                is.not[ name ] = function delegate() {
                    return !predicate.apply( null , arguments )
                }
    
            }
    
        }
  • ¶

    is.use( bundle )

    Define new bundles(collection of related predicates).

        is.use = function use( bundle ) {
    
            if ( typeof bundle === 'function' ) {
  • ¶

    bundle takes two parameters(order matters):

    • util: The utility object.
    • is: The is export.

    The util and is export is passed in as free variables so that one can write standalone bundles without referencing is.js first.

       // standalone bundle, does not depend on `is.js`
       module.exports = function bundle( util , is ) {
           util.addPredicate( 'eq' , function ( value , other ) {
               if ( is.not.object( value ) || is.not.object( other ) ) {
                   return false
               }
               return value.uuid = other.uuid
           } )
       }
    

    To import the bundle:

       is.use( require( 'path/to/bundle' ) )
    
                bundle( util , is )
    
            }
    
        }
  • ¶

    CORE BUNDLES

    Predicates shipped with is.js, packaged in various bundles.

  • ¶

    bundle:nil

        is.use( function nilBundle( util ) {
  • ¶

    is.null( value )

    Checks whether given value is null.

            util.addPredicate( 'null' , function isNull( value ) {
                return value === null
            } )
  • ¶

    is.undefined( value )

    Checks whether given value is undefined.

            util.addPredicate( 'undefined' , function isUndefined( value ) {
                return value === void 0
            } )
  • ¶

    is.exist( value )

    Checks whether given value exists, i.e, not null nor undefined.

            util.addPredicate( 'exist' , function isExist( value ) {
                return value != null // eslint-disable-line no-eq-null
            } )
  • ¶

    is.nil( value )

    Checks whether given value is either null or undefined.

            util.addPredicate( 'nil' , function isNil( value ) {
                return value == null // eslint-disable-line no-eq-null
            } )
    
        } )
  • ¶

    bundle:number

        is.use( function numberBundle( util ) {
  • ¶

    is.number( value )

    Checks whether given value is a number.

            util.addPredicate( 'number' , function isNumber( value ) {
                return typeof value === 'number'
            } )
  • ¶

    is.numeral( value )

    Checks whether given value is a numeral, i.e:

    • a genuine finite number
    • or a string that represents a finite number
            util.addPredicate( 'numeral' , function isNumeral( value ) {
    
                var tag = getTag( value )
                if ( tag !== 'number' && tag !== 'string' ) {
                    return false
                }
    
                if ( is.emptyString( value ) ) {
                    return false
                }
    
                try {
                    value = Number( value )
                } catch ( error ) {
                    return false
                }
    
                return is.finite( value )
    
            } )
  • ¶

    is.nan( value )

    Checks whether given value is NaN.

            util.addPredicate( 'nan' , function isNaN( value ) {
                return value !== value // eslint-disable-line no-self-compare
            } )
  • ¶

    is.odd( number )

    Checks whether given value is an odd number.

            util.addPredicate( 'odd' , function isOdd( number ) {
                return is.integer( number ) && number % 2 === 1
            } )
  • ¶

    is.even( number )

    Checks whether given value is an even number.

            util.addPredicate( 'even' , function isEven( number ) {
                return is.integer( number ) && number % 2 === 0
            } )
  • ¶

    is.finite( number )

    Checks whether given value is a finite number.

            if ( Number.isFinite ) {
                util.addPredicate( 'finite' , Number.isFinite )
            } else {
                util.addPredicate( 'finite' , function isFiniteNumber( number ) {
                    return is.number( number ) && isFinite( number )
                } )
            }
  • ¶

    is.infinite( number )

    Checks whether given value is an infinite number, i.e: +∞ or -∞.

            util.addPredicate( 'infinite' , function isInfinite( number ) {
                return number === +1 / 0 || number === -1 / 0
            } )
  • ¶

    is.integer( number )

    Checks whether given value is an integer.

            if ( Number.isInteger ) {
                util.addPredicate( 'integer' , Number.isInteger )
            } else {
                util.addPredicate( 'integer' , function isInteger( number ) {
                    return is.finite( number ) && Math.floor( number ) === number
                } )
            }
  • ¶

    is.safeInteger( number )

    Checks whether given value is a safe integer.

            if ( Number.isSafeInteger ) {
                util.addPredicate( 'safeInteger' , Number.isSafeInteger )
            } else {
                ( function () {
    
                    var MAX = Number.MAX_SAFE_INTEGER || Math.pow( 2 , 53 ) - 1
                    var MIN = Number.MIN_SAFE_INTEGER || -MAX
    
                    util.addPredicate( 'safeInteger' , function isSafeInteger( number ) {
                        return is.integer( number ) && ( number >= MIN && number <= MAX )
                    } )
    
                } )()
            }
    
        } )
  • ¶

    bundle:string

        is.use( function stringBundle( util ) {
  • ¶

    is.string( value )

    Checks whether given value is a string.

            util.addPredicate( 'string' , function isString( value ) {
                return typeof value === 'string'
            } )
  • ¶

    is.emptyString( string )

    Checks whether given value is an empty string, i.e, a string with whitespace characters only.

            util.addPredicate( 'emptyString' , function isEmptyString( string ) {
                return is.string( string ) && /^\s*$/.test( string )
            } )
  • ¶

    is.substring( substring , string , [offset=0] )

    Checks whether one string may be found within another string.

            util.addPredicate( 'substring' , function isSubstring( substring , string , offset ) {
    
                var length
    
                if ( getTag( string ) !== 'string' ) {
                    return false
                }
    
                length = string.length
                offset = is.integer( offset ) ? offset : 0
  • ¶

    Allow negative offsets.

                if ( offset < 0 ) {
                    offset = length + offset
                }
    
                if ( offset < 0 || offset >= length ) {
                    return false
                }
    
                return string.indexOf( substring , offset ) !== -1
    
            } )
    
    
            if ( String.prototype.startsWith && String.prototype.endsWith ) {
  • ¶

    is.prefix( prefix , string )

    Checks whether string starts with prefix.

                util.addPredicate( 'prefix' , function isPrefix( prefix , string ) {
                    return getTag( string ) === 'string' && string.startsWith( prefix )
                } )
  • ¶

    is.suffix( suffix , string )

    Checks whether string ends with suffix.

                util.addPredicate( 'suffix' , function isSuffix( suffix , string ) {
                    return getTag( string ) === 'string' && string.endsWith( suffix )
                } )
    
            } else {
    
                ( function ( makePredicate ) {
    
                    util.addPredicate( 'prefix' , makePredicate() )
                    util.addPredicate( 'suffix' , makePredicate( true ) )
    
                } )( function makePredicate( suffix ) {
    
                    return function predicate( affix , string ) {
    
                        var index
                        var offset
                        var affixLength
                        var stringLength
    
                        if ( getTag( string ) !== 'string' ) {
                            return false
                        }
    
                        affix = String( affix )
    
                        affixLength = affix.length
                        stringLength = string.length
    
                        if ( affixLength > stringLength ) {
                            return false
                        }
    
                        offset = suffix ? stringLength - affixLength : 0
    
                        for ( index = 0 ; index < affixLength ; index += 1 ) {
                            if ( string.charCodeAt( offset + index ) !== affix.charCodeAt( index ) ) {
                                return false
                            }
                        }
    
                        return true
    
                    }
    
                } )
    
            }
    
        } )
  • ¶

    bundle:boolean

        is.use( function booleanBundle( util ) {
  • ¶

    is.boolean( value )

    Checks whether given value is a boolean.

            util.addPredicate( 'boolean' , function isBoolean( value ) {
                return value === true || value === false
            } )
    
        } )
  • ¶

    bundle:object

        is.use( function objectBundle( util ) {
  • ¶

    is.object( value )

    Checks whether given value is an object.

            util.addPredicate( 'object' , function isObject( value ) {
                return is.not.primitive( value )
            } )
  • ¶

    is.emptyObject( object )

    Checks whether given value is an empty object, i.e, an object without any own, enumerable, string keyed properties.

            util.addPredicate( 'emptyObject' , function isEmptyObject( object ) {
                return is.object( object ) && ownKeys( object ).length === 0
            } )
  • ¶

    is.propertyDefined( object , path )

    Checks whether path is a direct or inherited property of object.

            util.addPredicate( 'propertyDefined' , function isPropertyDefined( object , path ) {
    
                var key
                var keys
                var context
    
                context = object
                keys = String( path ).split( '.' )
    
                while ( key = keys.shift() ) { // eslint-disable-line no-cond-assign
                    if ( is.not.object( context ) || !( key in context ) ) {
                        return false
                    } else {
                        context = context[ key ]
                    }
                }
    
                return true
    
            } )
  • ¶

    is.conforms( object , schema , [strict=false] )

    Checks whether object conforms to schema.

    A schema is an object whose properties are functions that takes these parameters(in order):

    • value:any - The value of current iteration.
    • key:string - The corresponding key of current iteration.
    • context:object - The object in question.

    These functions, or validators, are called for each corresponding key in object to check whether object conforms to the schema. An object is said to be conforms to the schema if all validators passed.

    In strict mode(where strict=true), is.conforms also checks whether object and schema has the same set of own, enumerable, string-keyed properties, in addition to check whether all validators passed.

            util.addPredicate( 'conforms' , function isConforms( object , schema , strict ) {
    
                var key
                var keys
                var index
                var length
                var validator
    
                if ( is.not.object( object ) || is.not.object( schema ) ) {
                    return false
                }
    
                keys = ownKeys( schema )
                length = keys.length
    
                if ( strict && length !== ownKeys( object ).length ) {
                    return false
                }
    
                for ( index = 0 ; index < length ; index += 1 ) {
    
                    key = keys[ index ]
                    validator = schema[ key ]
    
                    if ( typeof validator !== 'function' ) {
                        continue
                    }
    
                    if ( !hasOwnProperty.call( object , key ) ||
                         !validator( object[ key ] , key , object ) ) {
                        return false
                    }
    
                }
    
                return true
    
            } )
    
        } )
  • ¶

    bundle:array

        is.use( function arrayBundle( util ) {
  • ¶

    is.array( value )

    Checks whether given value is an array.

            if ( Array.isArray ) {
                util.addPredicate( 'array' , Array.isArray )
            } else {
                util.addPredicate( 'array' , function isArray( value ) {
                    return getTag( value ) === 'array'
                } )
            }
  • ¶

    is.arrayLikeObject( value )

    Checks whether given value is an array-like object.

    An object is qualified as array-like if it has a property named length that is a positive safe integer. As a special case, functions are never qualified as array-like.

            util.addPredicate( 'arrayLikeObject' , function isArrayLikeObject( value ) {
    
                var length
    
                if ( is.primitive( value ) || is[ 'function' ]( value ) ) {
                    return false
                } else {
                    length = value.length
                    return is.integer( length ) && length >= 0 && length <= 0xFFFFFFFF // 32-bit unsigned int maximum
                }
    
            } )
  • ¶

    is.inArray( value , array , [offset=0] , [comparator=is.equal] )

    Checks whether given array or array-like object contains certain element.

    • value: The element to search.
    • array: The array or array-like object to search from.
    • offset: The index to search from, inclusive.
    • comparator: The comparator invoked per element against value.
            util.addPredicate( 'inArray' , function isInArray( value , array , offset , comparator ) {
    
                var index
                var length
  • ¶

    Only works with genuine arrays or array-like objects.

                if ( is.not.arrayLikeObject( array ) ) {
                    return false
                }
    
                if ( is[ 'function' ]( offset ) ) {
                    comparator = offset
                    offset = 0
                } else {
                    offset = is.integer( offset ) ? offset : 0
                    comparator = is[ 'function' ]( comparator ) ? comparator : is.equal
                }
    
                length = array.length
  • ¶

    Allow negative offsets.

                if ( offset < 0 ) {
                    offset = length + offset
                }
    
                if ( offset < 0 || offset >= length ) {
                    return false
                }
    
                for ( index = offset ; index < length ; index += 1 ) {
  • ¶

    Skip holes in sparse arrays.

                    if ( !hasOwnProperty.call( array , index ) ) {
                        continue
                    }
    
                    if ( comparator( value , array[ index ] ) ) {
                        return true
                    }
    
                }
    
                return false
    
            } )
    
        } )
  • ¶

    bundle:type

        is.use( function typeBundle( util ) {
  • ¶

    is.sameType( value , other )

    Checks whether given values are of the same type.

            util.addPredicate( 'sameType' , function isSameType( value , other ) {
                return typeof value === typeof other && getTag( value ) === getTag( other )
            } )
  • ¶

    is.primitive( value )

    Checks whether given value is a primitive.

            util.addPredicate( 'primitive' , function isPrimitive( value ) {
                return is.nil( value ) ||
                       is.number( value ) ||
                       is.string( value ) ||
                       is.boolean( value ) ||
                       is.symbol( value )
            } )
  • ¶

    Generate type check predicates for standard builtin classes.

            ; ( function ( makePredicate , tags ) { // eslint-disable-line semi-spacing
    
                var tag
                var index
                var length = tags.length
    
                for ( index = 0 ; index < length ; index += 1 ) {
                    tag = tags[ index ]
                    util.addPredicate( tag , makePredicate( tag.toLowerCase() ) )
                }
    
            } )( function makePredicate( tag ) {
    
                return function predicate( value ) {
                    return getTag( value ) === tag
                }
    
            } , [ 'date' , 'error' , 'function' , 'map' , 'regexp' , 'set' , 'symbol' ] )
    
        } )
  • ¶

    bundle:equality

        is.use( function equalityBundle( util ) {
  • ¶

    is.equal( value , other )

    Checks whether given values are equal, using SameValueZero algorithm.

            util.addPredicate( 'equal' , function isEqual( value , other ) {
                return value === other || ( value !== value && other !== other ) // eslint-disable-line no-self-compare
            } )
  • ¶

    is.deepEqual( value , other )

    Checks whether given values are deeply equal, i.e:

    • If Type( value ) !== Type( other ), returns false.
    • For primitives, checks whether they are equal using SameValueZero.
    • For arrays, checks whether they have same set of members, all of which are deeply equal.
    • Otherwise, checks whether they have same set of own, enumerable, string keyed properties, all of which are deeply equal.
            util.addPredicate( 'deepEqual' , function isDeepEqual( value , other ) {
    
                if ( is.not.sameType( value , other ) ) {
                    return false
                }
    
                if ( is.primitive( value ) ) {
                    return is.equal( value , other )
                }
    
                if ( is.array( value ) ) {
    
                    if ( value.length !== other.length ) {
                        return false
                    }
    
                    return ( function () {
    
                        var index
                        var length
    
                        for ( index = 0 , length = value.length ; index < length ; index += 1 ) {
                            if ( is.not.deepEqual( value[ index ] , other[ index ] ) ) {
                                return false
                            }
                        }
    
                        return true
    
                    } )()
    
                }
    
                return ( function () {
    
                    var key
                    var keys
                    var index
                    var length
    
                    keys = ownKeys( value )
                    length = keys.length
    
                    if ( length !== ownKeys( other ).length ) {
                        return false
                    }
    
                    for ( index = 0 ; index < length ; index += 1 ) {
                        key = keys[ index ]
                        if ( !hasOwnProperty.call( other , key ) ||
                             is.not.deepEqual( value[ key ] , other[ key ] ) ) {
                            return false
                        }
                    }
    
                    return true
    
                } )()
    
            } )
    
        } )
    
    
        return is
    
    } )