UNPKG

@type-r/mixture

Version:

React-style mixins, Backbone-style events, logging router.

290 lines (234 loc) 7.72 kB
/** Similar to underscore `_.defaults` */ export function defaults< T >( dest : T, ...sources : Object[] ) : T export function defaults< T >( dest : T, source : Object ) : T { for( var name in source ) { if( source.hasOwnProperty( name ) && !dest.hasOwnProperty( name ) ) { dest[ name ] = source[ name ]; } } if( arguments.length > 2 ){ for( let i = 2; i < arguments.length; i++ ){ const other = arguments[ i ]; other && defaults( dest, other ); } } return dest; } /** Check if value is raw JSON */ export function isValidJSON( value : any ) : boolean { if( value === null ){ return true; } switch( typeof value ){ case 'number' : case 'string' : case 'boolean' : return true; case 'object': var proto = Object.getPrototypeOf( value ); if( proto === Object.prototype || proto === Array.prototype ){ return every( value, isValidJSON ); } } return false; } /** Get the base class constructor function. * @param Class Subclass constructor function. * @returns Base class constructor function. */ export function getBaseClass( Class : Function ) { return Object.getPrototypeOf( Class.prototype ).constructor } export function assignToClassProto<T, K extends keyof T>( Class, definition : T, ...names : K[] ) : void { for( let name of names ){ const value = definition[ name ]; value === void 0 || ( Class.prototype[ name ] = value ); } } /** Checks whenever given object is an empty hash `{}` */ export function isEmpty( obj : {} ) : boolean { if( obj ){ for( let key in obj ){ if( obj.hasOwnProperty( key ) ){ return false; } } } return true; } export type Iteratee = ( value : any, key? : string | number ) => any; function someArray( arr : any[], fun : Iteratee ) : any { let result; for( let i = 0; i < arr.length; i++ ){ if( result = fun( arr[ i ], i ) ){ return result; } } } function someObject( obj : {}, fun : Iteratee ) : any { let result; for( let key in obj ){ if( obj.hasOwnProperty( key ) ){ if( result = fun( obj[ key ], key ) ){ return result; } } } } /** Similar to underscore `_.some` */ export function some( obj, fun : Iteratee ) : any { if( Object.getPrototypeOf( obj ) === ArrayProto ){ return someArray( obj, fun ); } else{ return someObject( obj, fun ); } } /** Similar to underscore `_.every` */ export function every( obj : { }, predicate : Iteratee ) : boolean { return !some( obj, x => !predicate( x ) ); } /** Similar to `getOwnPropertyDescriptor`, but traverse the whole prototype chain. */ export function getPropertyDescriptor( obj : {}, prop : string ) : PropertyDescriptor { let desc : PropertyDescriptor; for( let proto = obj; !desc && proto; proto = Object.getPrototypeOf( proto ) ) { desc = Object.getOwnPropertyDescriptor( proto, prop ); } return desc; } /** Similar to underscore `_.omit` */ export function omit( source : {}, ...rest : string[] ) : {} export function omit( source ) : {} { const dest = {}, discard = {}; for( let i = 1; i < arguments.length; i ++ ){ discard[ arguments[ i ] ] = true; } for( var name in source ) { if( !discard.hasOwnProperty( name ) && source.hasOwnProperty( name ) ) { dest[ name ] = source[ name ]; } } return dest; } /** map `source` object properties with a given function, and assign the result to the `dest` object. * When `fun` returns `undefined`, skip this value. */ export function transform< A, B >( dest : { [ key : string ] : A }, source : { [ key : string ] : B }, fun : ( value : B, key : string ) => A | void ) : { [ key : string ] : A } { for( var name in source ) { if( source.hasOwnProperty( name ) ) { var value = fun( source[ name ], name ); value === void 0 || ( dest[ name ] = < A >value ); } } return dest; } export function fastAssign< A >( dest : A, source : {} ) : A { for( var name in source ) { dest[ name ] = source[ name ]; } return dest; } export function fastDefaults< A >( dest : A, source : {} ) : A { for( var name in source ) { if( dest[ name ] === void 0 ){ dest[ name ] = source[ name ]; } } return dest; } /** Similar to underscore `_.extend` and `Object.assign` */ export function assign< T >( dest : T, ...sources : Object[] ) : T export function assign< T >( dest : T, source : Object ) : T { for( var name in source ) { if( source.hasOwnProperty( name ) ) { dest[ name ] = source[ name ]; } } if( arguments.length > 2 ){ for( let i = 2; i < arguments.length; i++ ){ const other = arguments[ i ]; other && assign( dest, other ); } } return dest; } /** Similar to underscore `_.keys` */ export function keys( o : any ) : string[]{ return o ? Object.keys( o ) : []; } /** Similar to underscore `_.once` */ export function once( func : Function ) : Function { var memo, first = true; return function() { if ( first ) { first = false; memo = func.apply(this, arguments); func = null; } return memo; }; } const ArrayProto = Array.prototype, DateProto = Date.prototype, ObjectProto = Object.prototype; /** * Determine whenever two values are not equal, deeply traversing * arrays and plain JS objects (hashes). Dates are compared by enclosed timestamps, all other * values are compared with strict comparison. */ export function notEqual( a : any, b : any) : boolean { if( a === b ) return false; if( a && b && typeof a == 'object' && typeof b == 'object' ) { const protoA = Object.getPrototypeOf( a ); if( protoA !== Object.getPrototypeOf( b ) ) return true; switch( protoA ){ case DateProto : return +a !== +b; case ArrayProto : return arraysNotEqual( a, b ); case ObjectProto : case null: return objectsNotEqual( a, b ); } } return true; } function objectsNotEqual( a, b ) { const keysA = Object.keys( a ); if( keysA.length !== Object.keys( b ).length ) return true; for( let i = 0; i < keysA.length; i++ ) { const key = keysA[ i ]; if( !b.hasOwnProperty( key ) || notEqual( a[ key ], b[ key ] ) ) { return true; } } return false; } function arraysNotEqual( a, b ) { if( a.length !== b.length ) return true; for( let i = 0; i < a.length; i++ ) { if( notEqual( a[ i ], b[ i ] ) ) return true; } return false; } /** * Create an object without Object prototype members except hasOwnProperty. * @param obj - optional parameter to populate the hash map from. */ const HashProto = Object.create( null ); HashProto.hasOwnProperty = ObjectProto.hasOwnProperty; export function hashMap( obj? ){ const hash = Object.create( HashProto ); return obj ? assign( hash, obj ) : hash; } export function compare( a : any, b : any ) : -1 | 0 | 1 { // Handle strictly equal values. if( a == b ) return 0; // Handle nulls. if( a == null ) return -1; if( b == null ) return 1; // No nulls. Convert values to primitives. const av = a.valueOf(), bv = b.valueOf(); return av < bv ? -1 : av > bv ? 1 : 0; }