import { printExpected } from 'jest-matcher-utils' ; import { isEqual , isMatchWith , isObjectLike , isUndefined , omitBy , } from 'lodash' ; import { printArg } from '../print' ; import { isMatcher , Matcher , MATCHER_SYMBOL , TypeMatcher } from './matcher' ; param cb param toJSON example const matches = < T > ( cb , { toJSON = ( ) => `matches(${ cb . toString ( ) })` } = { } ) : TypeMatcher < T > => { const matcher = { [ MATCHER_SYMBOL ] : true , matches : ( arg ) => cb ( arg ) , toJSON , } ; return matcher as any ; } ; const removeUndefined = ( object ) : any => { if ( Array . isArray ( object ) ) { return object . map ( ( x ) => removeUndefined ( x ) ) ; } if ( ! isObjectLike ( object ) ) { return object ; } return omitBy ( object , isUndefined ) ; } ; param expected param strict see It . is const deepEquals = < T > ( expected , { strict = true } = { } ) : TypeMatcher < T > => matches ( ( actual ) => { if ( strict ) { return isEqual ( actual , expected ) ; } return isEqual ( removeUndefined ( actual ) , removeUndefined ( expected ) ) ; } , { toJSON : ( ) => printArg ( expected ) } ) ; link see It . deepEquals const is = < T = unknown > ( expected ) : TypeMatcher < T > => matches ( ( actual ) => Object . is ( actual , expected ) , { toJSON : ( ) => `${ printExpected ( expected ) }` , } ) ; example const isAny = ( ) : TypeMatcher < any > => matches ( ( ) => true , { toJSON : ( ) => 'anything' } ) ; type DeepPartial < T > = T extends object ? { [ K in keyof T ] ? : DeepPartial < T [ K ] > ; } : T ; param partial example example const isObject = < T extends object , K extends DeepPartial < T > > ( partial ? ) : TypeMatcher < T > => matches ( ( actual ) => isMatchWith ( actual , partial || { } , ( argValue , partialValue ) => { if ( isMatcher ( partialValue ) ) { return partialValue . matches ( argValue ) ; } return undefined ; } ) , { toJSON : ( ) => ( partial ? `object(${ printExpected ( partial ) })` : 'object' ) } ) ; example const isNumber = ( ) : TypeMatcher < number > => matches ( ( actual ) => typeof actual === 'number' && ! Number . isNaN ( actual ) , { toJSON : ( ) => 'number' , } ) ; param matching param containing example const isString = ( { matching , containing , } = { } ) : TypeMatcher < string > => { if ( matching && containing ) { throw new Error ( 'You can only pass `matching` or `containing`, not both.' ) ; } return matches ( ( actual ) => { if ( typeof actual !== 'string' ) { return false ; } if ( containing ) { return actual . indexOf ( containing ) !== - 1 ; } return matching ?. test ( actual ) ?? true ; } , { toJSON : ( ) => containing || matching ? `string(${ printExpected ( containing || matching ) })` : 'string' , } ) ; } ; param containing example example const isArray = < T extends any [ ] > ( containing ? ) : TypeMatcher < T > => matches ( ( actual ) => { if ( ! Array . isArray ( actual ) ) { return false ; } if ( ! containing ) { return true ; } return containing . every ( ( x ) => actual . find ( ( y ) => { if ( isMatcher ( x ) ) { return x . matches ( y ) ; } return deepEquals ( x ) . matches ( y ) ; } ) !== undefined ) ; } , { toJSON : ( ) => containing ? `array(${ printExpected ( containing ) })` : 'array' , } ) ; param name example const willCapture = < T = unknown > ( name ? ) : TypeMatcher < T > & { value : T | undefined ; } => { let capturedValue ; const matcher = { [ MATCHER_SYMBOL ] : true , matches : ( actual ) => { capturedValue = actual ; return true ; } , toJSON : ( ) => name ?? 'captures' , get value ( ) : T | undefined { return capturedValue ; } , } ; return matcher as any ; } ; /**
 * Contains argument matchers that can be used to ignore arguments in an
 * expectation or to match complex arguments.
 */ export const It = { matches , deepEquals , is , isAny , isObject , isNumber , isString , isArray , willCapture , } ;