pwnn / is.js
- суббота, 11 июня 2016 г. в 03:12:58
JavaScript
Minimalistic predicate library.
Minimalistic predicate library.
Node:
$ npm install --save @pwn/is
Browser:
<script src="path/to/is.min.js"></script>
A code sample is worth a thousand words:
const is = require( '@pwn/is' )
is.array( [] ) // true
is.not.integer( 0 ) // false
is.propertyDefined( { foo : { bar : 0 } } , 'foo.bar' ) // true
is.equal( [ 1 , [ 2 , 3 ] ] , [ 1 , [ 2 , 3 ] ] ) // false
is.deepEqual( [ 1 , [ 2 , 3 ] ] , [ 1 , [ 2 , 3 ] ] ) // true
// use a third-party bundle
is.use( require( 'path/to/some/math/bundle' ) )
is.prime( 7 ) // true
All checks, or predicates in is.js
terminology, takes two general forms:
is.predicate( ...args )
- Checks whether certain condition met.is.not.predicate( ...args )
- The inverse of its corresponding positive check.That's it! What's next?
is.js
.TL;DR
A bundle is simply a way of organizing related predicates.
bundle:nil
bundle:number
bundle:string
bundle:boolean
bundle:object
bundle:array
bundle:type
bundle:equality
Checks whether given value is null
.
is.null( null ) // true
is.null( undefined ) // false
Checks whether given value is undefined
.
is.undefined( null ) // false
is.undefined( undefined ) // true
Checks whether given value exists, i.e, not null
nor undefined
.
is.exist( null ) // false
is.exist( undefined ) // false
Checks whether given value is either null
or undefined
.
is.nil( null ) // true
is.nil( undefined ) // true
Checks whether given value is a number.
is.number( 0 ) // true
is.number( Number.NaN ) // true
is.number( Number.POSITIVE_INFINITY ) // true
is.number( Number.NEGATIVE_INFINITY ) // true
is.number( '0' ) // false
is.number( new Number( 0 ) ) // false
Checks whether given value is a numeral, i.e:
is.numeral( null ) // false
is.numeral( undefined ) // false
is.numeral( true ) // false
is.numeral( false ) // false
is.numeral( Symbol( 0 ) ) // false
is.numeral( Symbol.for( 0 ) ) // false
is.numeral( { valueOf() { return 0 } } ) // false
is.numeral( [ 0 ] ) // false
is.numeral( () => 0 ) // false
is.numeral( '' ) // false
is.numeral( 'one' ) // false
is.numeral( '1px' ) // false
is.numeral( ' 0xFF ' ) // true
is.numeral( '1e1' ) // true
is.numeral( '1.1E-1' ) // true
is.numeral( '-1' ) // true
is.numeral( '1.1' ) // true
is.numeral( new Number( 1 ) ) // true
is.numeral( new String( '-1.1' ) ) // true
is.numeral( Number.NaN ) // false
is.numeral( Number.POSITIVE_INFINITY ) // false
is.numeral( Number.NEGATIVE_INFINITY ) // false
Checks whether given value is NaN
.
is.nan( 0 ) // false
is.nan( Number.NaN ) // true
is.nan( new Number( Number.NaN ) ) // false
is.nan( Number.POSITIVE_INFINITY ) // false
is.nan( Number.NEGATIVE_INFINITY ) // false
is.nan( 'one' ) // false
Checks whether given value is an odd number.
is.odd( 1 ) // true
is.odd( 2 ) // false
is.odd( '1' ) // false
is.odd( '2' ) // false
is.odd( new Number( 1 ) ) // false
is.odd( new Number( 2 ) ) // false
is.odd( Number.NaN ) // false
is.odd( Number.POSITIVE_INFINITY ) // false
is.odd( Number.NEGATIVE_INFINITY ) // false
Checks whether given value is an even number.
is.even( 1 ) // false
is.even( 2 ) // true
is.even( '1' ) // false
is.even( '2' ) // false
is.even( new Number( 1 ) ) // false
is.even( new Number( 2 ) ) // false
is.even( Number.NaN ) // false
is.even( Number.POSITIVE_INFINITY ) // false
is.even( Number.NEGATIVE_INFINITY ) // false
Checks whether given value is a finite number.
is.finite( 0 ) // true
is.finite( '0' ) // false
is.finite( Number.NaN ) // false
is.finite( Number.POSITIVE_INFINITY ) // false
is.finite( Number.NEGATIVE_INFINITY ) // false
Checks whether given value is an infinite number, i.e,
Number.POSITIVE_INFINITY
or Number.NEGATIVE_INFINITY
.
is.infinite( 0 ) // false
is.infinite( '0' ) // false
is.infinite( Number.NaN ) // false
is.infinite( Number.POSITIVE_INFINITY ) // true
is.infinite( Number.NEGATIVE_INFINITY ) // true
Checks whether given value is an integer.
is.integer( 0 ) // true
is.integer( '0' ) // false
is.integer( new Number( 0 ) ) // false
is.integer( 0.1 ) // false
is.integer( Number.NaN ) // false
is.integer( Number.POSITIVE_INFINITY ) // false
is.integer( Number.NEGATIVE_INFINITY ) // false
is.integer( Number.MAX_SAFE_INTEGER ) // true
is.integer( Number.MIN_SAFE_INTEGER ) // true
is.integer( Number.MAX_SAFE_INTEGER + 1 ) // true
is.integer( Number.MIN_SAFE_INTEGER - 1 ) // true
Checks whether given value is a safe integer.
is.safeInteger( 0 ) // true
is.safeInteger( '0' ) // false
is.safeInteger( new Number( 0 ) ) // false
is.safeInteger( 0.1 ) // false
is.safeInteger( Number.NaN ) // false
is.safeInteger( Number.POSITIVE_INFINITY ) // false
is.safeInteger( Number.NEGATIVE_INFINITY ) // false
is.safeInteger( Number.MAX_SAFE_INTEGER ) // true
is.safeInteger( Number.MIN_SAFE_INTEGER ) // true
is.safeInteger( Number.MAX_SAFE_INTEGER + 1 ) // false
is.safeInteger( Number.MIN_SAFE_INTEGER - 1 ) // false
Checks whether given value is a string.
is.string( 'lipsum' ) // true
is.string( new String( 'lipsum' ) ) // false
Checks whether given value is an empty string, i.e, a string with whitespace characters only.
is.emptyString( '' ) // true
is.emptyString( ' ' ) // true
is.emptyString( '\f\n\r\t' ) // true
is.emptyString( '\u0009\u000A\u000B\u000C\u000D\u0020' ) // true
is.emptyString( 'lipsum' ) // false
Checks whether one string may be found within another string.
is.substring( 'ps' , 'lipsum' ) // true
is.substring( 'sp' , 'lipsum' ) // false
is.substring( [ 'ps' ] , 'lipsum' ) // true; `substring` will be converted to a string as needed
is.substring( 'ps' , [ 'lipsum' ] ) // false; `string` must be a string
is.substring( 'ps' , 'lipsum' , 2 ) // true
is.substring( 'ps' , 'lipsum' , 3 ) // false
is.substring( 'ps' , 'lipsum' , 3.14 ) // true; non-integer offset will be omitted and defaults to 0
is.substring( 'ps' , 'lipsum' , -4 ) // true; supports negative offset
is.substring( 'ps' , 'lipsum' , 6 ) // false; offset out of range
is.substring( 'ps' , 'lipsum' , -7 ) // false; offset out of range
Checks whether string
starts with prefix
.
is.prefix( 'lip' , 'lipsum' ) // true
is.prefix( 'sum' , 'lipsum' ) // false
is.prefix( 'lip' , [ 'lipsum' ] ) // false; `string` must be a string
is.prefix( [ 'lip' ] , 'lipsum' ) // true - `prefix` will be converted to a string as needed
Checks whether string
ends with suffix
.
is.suffix( 'sum' , 'lipsum' ) // true
is.suffix( 'lip' , 'lipsum' ) // false
is.suffix( 'sum' , [ 'lipsum' ] ) // false; `string` must be a string
is.suffix( [ 'sum' ] , 'lipsum' ) // true - `suffix` will be converted to a string as needed
Checks whether given value is a boolean.
is.boolean( 1 ) // false
is.boolean( 0 ) // false
is.boolean( true ) // true
is.boolean( false ) // true
is.boolean( new Boolean( true ) ) // false
is.boolean( new Boolean( false ) ) // false
Checks whether given value is an object.
is.object( null ) // false
is.object( undefined ) // false
is.object( 0 ) // false
is.object( new Number( 0 ) ) // true
is.object( '' ) // false
is.object( new String( '' ) ) // true
is.object( true ) // false
is.object( new Boolean( true ) ) // true
is.object( Symbol() ) // false
is.object( Symbol.for( 'is' ) ) // false
is.object( {} ) // true
is.object( [] ) // true
is.object( function () {} ) // true
Checks whether given value is an empty object, i.e, an object without any own, enumerable, string keyed properties.
is.emptyObject( {} ) // true
is.emptyObject( { foo : 'bar' } ) // false
is.emptyObject( Object.create( { foo : 'bar' } ) ) // true; ignore inherited properties
is.emptyObject( Object.defineProperty( {} , 'foo' , { value : 'bar' } ) ) // true; ignore non-enumerable properties
is.emptyObject( { [ Symbol() ] : 0 } ) // true; ignore non-string-keyed properties
Checks whether path
is a direct or inherited property of object
.
is.propertyDefined( Object.create( { foo : 'bar' } ) , 'foo' ) // true
is.propertyDefined( { foo : { bar : { baz : 0 } } } , 'foo' ) // true
is.propertyDefined( { foo : { bar : { baz : 0 } } } , 'foo.bar' ) // true
is.propertyDefined( { foo : { bar : { baz : 0 } } } , 'foo.bar.baz' ) // true
is.propertyDefined( { foo : { bar : { baz : 0 } } } , 'foo.qux.baz' ) // false
is.propertyDefined( { foo : { bar : { baz : 0 } } } , 'foo.bar.baz.qux' ) // false
Checks whether object
conforms to schema
.
A schema
is an object whose properties are functions that takes
these parameters(in order):
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.
is.conforms(
{ name : '@pwn/is' , access : 'public' } ,
{ name : is.exist }
) // true
is.conforms(
{ name : '@pwn/is' , access : 'public' } ,
{ description : is.string }
) // false; key `description` does not exist on `object`
is.conforms(
{ name : '@pwn/is' , access : 'public' } ,
{
name( value , key , context ) {
return is.exist( value ) && context.access === 'public'
}
}
) // true
//
// strict mode
//
is.conforms(
{
name : '@pwn/is' ,
access : 'public'
} ,
{
name( value , key , context ) {
return is.string( value ) && value.length >= 3
}
} ,
true // enable strict mode
) // false; `object` has extraneous properties
Checks whether given value is an array.
is.array( [] ) // true
is.array( '' ) // false
is.array( document.scripts ) // false
is.array( function() {} ) // false
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.
is.arrayLikeObject( [] ) // true
is.arrayLikeObject( '' ) // false
is.arrayLikeObject( document.scripts ) // true
is.arrayLikeObject( function() {} ) // false
Checks whether given array or array-like object contains certain element.
value
.is.inArray( 2 , [ 1 , 2 , 3 ] ) // true
is.inArray( 4 , [ 1 , 2 , 3 ] ) // false
is.inArray( 2 , [ 1 , 2 , 3 ] , 1 ) // true
is.inArray( 2 , [ 1 , 2 , 3 ] , 2 ) // false
is.inArray( 2 , [ 1 , 2 , 3 ] , -2 ) // true; supports negative offset
is.inArray( 2 , [ 1 , 2 , 3 ] , 3 ) // false; offset out of range
is.inArray( 2 , [ 1 , 2 , 3 ] , -4 ) // false; offset out of range
is.inArray( [ 2 ] , [ 1 , [ 2 ] , 3 ] ) // false; default comparator is `is.equal`
is.inArray( [ 2 ] , [ 1 , [ 2 ] , 3 ] , 0 , is.deepEqual ) // true
is.inArray( [ 2 ] , [ 1 , [ 2 ] , 3 ] , is.deepEqual ) // true; `offset` can be omitted when passing a custom comparator only
is.inArray( 2 , [ 1 , 2 , 3 ] , ( val , arrMember ) => val === arrMember ) // true; `comparator` takes two parameters, the element to search and the array element of current iteration
Checks whether given values are of the same type.
is.sameType( 0 , 0 ) // true
is.sameType( 0 , '0' ) // false
is.sameType( 0 , new Number( 0 ) ) // false
is.sameType( 0 , Number.NaN ) // true
is.sameType( [] , {} ) // false
Checks whether given value is a primitive.
is.primitive( null ) // true
is.primitive( undefined ) // true
is.primitive( 0 ) // true
is.primitive( new Number( 0 ) ) // false
is.primitive( '' ) // true
is.primitive( new String( '' ) ) // false
is.primitive( true ) // true
is.primitive( new Boolean( true ) ) // false
is.primitive( Symbol() ) // true
is.primitive( Symbol.for( 'is' ) ) // true
is.primitive( {} ) // false
is.primitive( [] ) // false
is.primitive( function() {} ) // false
Checks whether given value is a Date
object.
is.date( new Date() ) // true
Checks whether given value is an Error
object.
is.error( new Error() ) // true
is.error( new TypeError() ) // true
Checks whether given value is a function.
is.function( function () {} ) // true
is.function( () => null ) // true
is.function( new Function() ) // true
Checks whether given value is a Map
object.
is.map( new Map() ) // true
Checks whether given value is a RegExp
object.
is.regexp( /^/ ) // true
is.regexp( new RegExp() ) // true
Checks whether given value is a Set
object.
is.set( new Set() ) // true
Checks whether given value is a symbol.
is.symbol( Symbol() ) // true
is.symbol( Symbol.for( 'is' ) ) // true
Checks whether given values are equal, using SameValueZero algorithm.
is.equal( null , undefined ) // false
is.equal( 0 , 0 ) // true
is.equal( 0 , '0' ) // false
is.equal( +0 , -0 ) // true; SameValueZero
is.equal( Number.NaN , Number.NaN ) // true; SameValueZero
is.equal( [] , [] ) // false
Checks whether given values are deeply equal, i.e:
Type( value ) !== Type( other )
, returns false
.is.deepEqual( null , undefined ) // false
is.deepEqual( 0 , 0 ) // true
is.deepEqual( 0 , '0' ) // false
is.deepEqual( +0 , -0 ) // true; SameValueZero
is.deepEqual( Number.NaN , Number.NaN ) // true; SameValueZero
is.deepEqual( [ 1 , { foo : [ 2 , [ 3 , 4 ] ] , bar : { baz : 5 } } ] , [ 1 , { foo : [ 2 , [ 3 , 4 ] ] , bar : { baz : 5 } } ] ) // true
is.deepEqual( Object.create( { foo : 1 } ) , Object.create( { foo : 2 } ) ) // true; only own, enumerable, string-keyed properties are checked
Predicates are essentially functions that checks whether certain condition met based on passed in arguments. They are packaged in various bundles. Conceptually, a bundle is simply a way of organizing related predicates. Implementation-wise, a bundle is a just a function that takes two parameters:
util:object
- The utility object.is:object
- The is
export.The util
object defines a method called addPredicate
that allows you to define new predicates:
util.addPredicate( name:string , predicate:function )
- name - The name of the predicate.
- predicate - The predicate function.
Once defined, the predicate will be available on both is
and is.not
— util.addPredicate
wraps the predicate in a delegate function and automatically handles positive/negative cases for you.
Still confused? Take a look at this sample bundle:
// my_bundle.js
// `util` and `is` are passed in as free variables, so you don't
// need to call `require( '@pwn/is' )`
module.exports = function bundle( util , is ) {
util.addPredicate( 'positive' , function isPositive( value ) {
return is.number( value ) && value > 0
} )
util.addPredicate( 'negative' , function isNegative( value ) {
return is.number( value ) && value < 0
} )
}
To use a bundle, simple call is.use
:
is.use( bundle:function )
const is = require( '@pwn/is' )
// import all predicates from my_bundle.js
is.use( require( 'path/to/my_bundle' ) )
is.positive( +1 ) // true
is.not.positive( -1 ) // true
is.negative( -1 ) // true
is.not.negative( +1 ) // true