UNPKG

@pwn/is

Version:

Minimalistic predicate library

942 lines (678 loc) 21 kB
// // 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. // // ```js // // 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: // // ```js // 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 } )