/**
 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */ import * as matcherUtils from './matcher-utils' ; import { equals , fnNameFor , hasProperty , isA , isUndefined , } from './jasmineUtils' ; import { getState } from './jestMatchersObject' ; import type { AsymmetricMatcher as AsymmetricMatcherInterface , MatcherState , } from './types' ; import { iterableEquality , subsetEquality } from './utils' ; const utils = Object . freeze ( { ... matcherUtils , iterableEquality , subsetEquality , } ) ; export abstract class AsymmetricMatcher < T , State extends MatcherState = MatcherState > implements AsymmetricMatcherInterface { $$typeof = Symbol . for ( 'jest.asymmetricMatcher' ) ; constructor ( protected sample , protected inverse = false ) { } protected getMatcherContext ( ) { return { ... getState ( ) , equals , isNot : this . inverse , utils , } as State ; } abstract asymmetricMatch ( other ) ; abstract toString ( ) ; getExpectedType ? ( ) ; toAsymmetricMatcher ? ( ) ; } class Any extends AsymmetricMatcher < any > { constructor ( sample ) { if ( typeof sample === 'undefined' ) { throw new TypeError ( 'any() expects to be passed a constructor function. ' + 'Please pass one or use anything() to match any object.' ) ; } super ( sample ) ; } asymmetricMatch ( other ) { if ( this . sample == String ) { return typeof other == 'string' || other instanceof String ; } if ( this . sample == Number ) { return typeof other == 'number' || other instanceof Number ; } if ( this . sample == Function ) { return typeof other == 'function' || other instanceof Function ; } if ( this . sample == Boolean ) { return typeof other == 'boolean' || other instanceof Boolean ; } if ( this . sample == BigInt ) { return typeof other == 'bigint' || other instanceof BigInt ; } if ( this . sample == Symbol ) { return typeof other == 'symbol' || other instanceof Symbol ; } if ( this . sample == Object ) { return typeof other == 'object' ; } return other instanceof this . sample ; } toString ( ) { return 'Any' ; } getExpectedType ( ) { if ( this . sample == String ) { return 'string' ; } if ( this . sample == Number ) { return 'number' ; } if ( this . sample == Function ) { return 'function' ; } if ( this . sample == Object ) { return 'object' ; } if ( this . sample == Boolean ) { return 'boolean' ; } return fnNameFor ( this . sample ) ; } toAsymmetricMatcher ( ) { return 'Any<' + fnNameFor ( this . sample ) + '>' ; } } class Anything extends AsymmetricMatcher < void > { asymmetricMatch ( other ) { return ! isUndefined ( other ) && other !== null ; } toString ( ) { return 'Anything' ; } toAsymmetricMatcher ( ) { return 'Anything' ; } } class ArrayContaining extends AsymmetricMatcher < Array < unknown > > { constructor ( sample , inverse = false ) { super ( sample , inverse ) ; } asymmetricMatch ( other ) { if ( ! Array . isArray ( this . sample ) ) { throw new Error ( `You must provide an array to ${ this . toString ( ) }, not '` + typeof this . sample + "'." ) ; } const result = this . sample . length === 0 || ( Array . isArray ( other ) && this . sample . every ( ( item ) => other . some ( ( another ) => equals ( item , another ) ) ) ) ; return this . inverse ? ! result : result ; } toString ( ) { return `Array${ this . inverse ? 'Not' : '' }Containing` ; } getExpectedType ( ) { return 'array' ; } } class ObjectContaining extends AsymmetricMatcher < Record < string , unknown > > { constructor ( sample , inverse = false ) { super ( sample , inverse ) ; } asymmetricMatch ( other ? ) { if ( typeof this . sample !== 'object' ) { throw new Error ( `You must provide an object to ${ this . toString ( ) }, not '` + typeof this . sample + "'." ) ; } let result = true ; for ( const property in this . sample ) { if ( ! hasProperty ( other , property ) || ! equals ( this . sample [ property ] , other [ property ] ) ) { result = false ; break ; } } return this . inverse ? ! result : result ; } toString ( ) { return `Object${ this . inverse ? 'Not' : '' }Containing` ; } getExpectedType ( ) { return 'object' ; } } class StringContaining extends AsymmetricMatcher < string > { constructor ( sample , inverse = false ) { if ( ! isA ( 'String' , sample ) ) { throw new Error ( 'Expected is not a string' ) ; } super ( sample , inverse ) ; } asymmetricMatch ( other ) { const result = isA ( 'String' , other ) && other . includes ( this . sample ) ; return this . inverse ? ! result : result ; } toString ( ) { return `String${ this . inverse ? 'Not' : '' }Containing` ; } getExpectedType ( ) { return 'string' ; } } class StringMatching extends AsymmetricMatcher < RegExp > { constructor ( sample , inverse = false ) { if ( ! isA ( 'String' , sample ) && ! isA ( 'RegExp' , sample ) ) { throw new Error ( 'Expected is not a String or a RegExp' ) ; } super ( new RegExp ( sample ) , inverse ) ; } asymmetricMatch ( other ) { const result = isA ( 'String' , other ) && this . sample . test ( other ) ; return this . inverse ? ! result : result ; } toString ( ) { return `String${ this . inverse ? 'Not' : '' }Matching` ; } getExpectedType ( ) { return 'string' ; } } export const any = ( expectedObject ) : Any => new Any ( expectedObject ) ; export const anything = ( ) : Anything => new Anything ( ) ; export const arrayContaining = ( sample ) : ArrayContaining => new ArrayContaining ( sample ) ; export const arrayNotContaining = ( sample ) : ArrayContaining => new ArrayContaining ( sample , true ) ; export const objectContaining = ( sample ) : ObjectContaining => new ObjectContaining ( sample ) ; export const objectNotContaining = ( sample ) : ObjectContaining => new ObjectContaining ( sample , true ) ; export const stringContaining = ( expected ) : StringContaining => new StringContaining ( expected ) ; export const stringNotContaining = ( expected ) : StringContaining => new StringContaining ( expected , true ) ; export const stringMatching = ( expected ) : StringMatching => new StringMatching ( expected ) ; export const stringNotMatching = ( expected ) : StringMatching => new StringMatching ( expected , true ) ;