import type { Tester } from './types' ; export function equals ( a , b , customTesters ? , strictCheck ? ) { customTesters = customTesters || [ ] ; return eq ( a , b , [ ] , [ ] , customTesters , strictCheck ? hasKey : hasDefinedKey ) ; } const functionToString = Function . prototype . toString ; function isAsymmetric ( obj ) { return ! ! obj && isA ( 'Function' , obj . asymmetricMatch ) ; } function asymmetricMatch ( a , b ) { var asymmetricA = isAsymmetric ( a ) , asymmetricB = isAsymmetric ( b ) ; if ( asymmetricA && asymmetricB ) { return undefined ; } if ( asymmetricA ) { return a . asymmetricMatch ( b ) ; } if ( asymmetricB ) { return b . asymmetricMatch ( a ) ; } } function eq ( a , b , aStack , bStack , customTesters , hasKey ) { var result = true ; var asymmetricResult = asymmetricMatch ( a , b ) ; if ( asymmetricResult !== undefined ) { return asymmetricResult ; } for ( var i = 0 ; i < customTesters . length ; i ++ ) { var customTesterResult = customTesters [ i ] ( a , b ) ; if ( customTesterResult !== undefined ) { return customTesterResult ; } } if ( a instanceof Error && b instanceof Error ) { return a . message == b . message ; } if ( Object . is ( a , b ) ) { return true ; } if ( a === null || b === null ) { return a === b ; } var className = Object . prototype . toString . call ( a ) ; if ( className != Object . prototype . toString . call ( b ) ) { return false ; } switch ( className ) { case '[object Boolean]' : case '[object String]' : case '[object Number]' : if ( typeof a !== typeof b ) { return false ; } else if ( typeof a !== 'object' && typeof b !== 'object' ) { return Object . is ( a , b ) ; } else { return Object . is ( a . valueOf ( ) , b . valueOf ( ) ) ; } case '[object Date]' : return + a == + b ; case '[object RegExp]' : return a . source === b . source && a . flags === b . flags ; } if ( typeof a !== 'object' || typeof b !== 'object' ) { return false ; } if ( isDomNode ( a ) && isDomNode ( b ) ) { return a . isEqualNode ( b ) ; } var length = aStack . length ; while ( length -- ) { if ( aStack [ length ] === a ) { return bStack [ length ] === b ; } else if ( bStack [ length ] === b ) { return false ; } } aStack . push ( a ) ; bStack . push ( b ) ; if ( className == '[object Array]' && a . length !== b . length ) { return false ; } var aKeys = keys ( a , hasKey ) , key ; var size = aKeys . length ; if ( keys ( b , hasKey ) . length !== size ) { return false ; } while ( size -- ) { key = aKeys [ size ] ; result = hasKey ( b , key ) && eq ( a [ key ] , b [ key ] , aStack , bStack , customTesters , hasKey ) ; if ( ! result ) { return false ; } } aStack . pop ( ) ; bStack . pop ( ) ; return result ; } function keys ( obj , hasKey ) { var keys = [ ] ; for ( var key in obj ) { if ( hasKey ( obj , key ) ) { keys . push ( key ) ; } } return keys . concat ( ( Object . getOwnPropertySymbols ( obj ) as Array < any > ) . filter ( ( symbol ) => ( Object . getOwnPropertyDescriptor ( obj , symbol ) as PropertyDescriptor ) . enumerable ) ) ; } function hasDefinedKey ( obj , key ) { return hasKey ( obj , key ) && obj [ key ] !== undefined ; } function hasKey ( obj , key ) { return Object . prototype . hasOwnProperty . call ( obj , key ) ; } export function isA ( typeName , value ) { return ( Object . prototype . toString . apply ( value ) === '[object ' + typeName + ']' ) ; } function isDomNode ( obj ) { return ( obj !== null && typeof obj === 'object' && typeof obj . nodeType === 'number' && typeof obj . nodeName === 'string' && typeof obj . isEqualNode === 'function' ) ; } export function fnNameFor ( func ) { if ( func . name ) { return func . name ; } const matches = functionToString . call ( func ) . match ( /^(?:async)?\s*function\s*\*?\s*([\w$]+)\s*\(/ ) ; return matches ? matches [ 1 ] : '<anonymous>' ; } export function isUndefined ( obj ) { return obj === void 0 ; } function getPrototype ( obj ) { if ( Object . getPrototypeOf ) { return Object . getPrototypeOf ( obj ) ; } if ( obj . constructor . prototype == obj ) { return null ; } return obj . constructor . prototype ; } export function hasProperty ( obj , property ) { if ( ! obj ) { return false ; } if ( Object . prototype . hasOwnProperty . call ( obj , property ) ) { return true ; } return hasProperty ( getPrototype ( obj ) , property ) ; } const IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@' ; const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@' ; const IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@' ; export function isImmutableUnorderedKeyed ( maybeKeyed ) { return ! ! ( maybeKeyed && maybeKeyed [ IS_KEYED_SENTINEL ] && ! maybeKeyed [ IS_ORDERED_SENTINEL ] ) ; } export function isImmutableUnorderedSet ( maybeSet ) { return ! ! ( maybeSet && maybeSet [ IS_SET_SENTINEL ] && ! maybeSet [ IS_ORDERED_SENTINEL ] ) ; }