/**
 * Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.
 * Modifications copyright (c) Microsoft Corporation.
 *
 * This source code is licensed under the MIT license found here
 * https://github.com/jestjs/jest/blob/v30.2.0/LICENSE
 */
// Based on https://github.com/jestjs/jest/tree/v30.2.0/packages/expect
// - Files merged into one.
// - Reformatted to follow the coding style.
// - Removed spy matchers: toHaveBeenCalled, toHaveReturned, etc.
// - Removed expect.assertions() and expect.hasAssertions() support.
// - Removed global state, INTERNAL_MATCHER_FLAG, addCustomEqualityTesters.
// - MatcherContext has only stubs for customTesters, getState and dontThrow.
// - MatcherState has no expand, currentTestName, assertionCalls, etc.
// - Extracted explicit buildCustomAsymmetricMatcher, createExpectedPromiseMessage,
//   createExpectedToResolveMessage, createExpectedToRejectMessage from internals.
import { arrayBufferEquality, equals, getObjectKeys, getObjectSubset, getPath, isA, isError, iterableEquality, pathAsArray, sparseArrayEquality, subsetEquality, typeEquality, } from '@jest/expect-utils';
import * as matcherUtils from 'jest-matcher-utils';
import { DIM_COLOR, EXPECTED_COLOR, INVERTED_COLOR, RECEIVED_COLOR, SUGGEST_TO_CONTAIN_EQUAL, ensureExpectedIsNonNegativeInteger, ensureNoExpected, ensureNumbers, getLabelPrinter, matcherErrorMessage, matcherHint, printDiffOrStringify, printExpected, printReceived, printWithType, stringify, } from 'jest-matcher-utils';
import { formatExecError, formatStackTrace, separateMessageFromStack } from 'jest-message-util';
function getType(value) {
    if (value === undefined)
        return 'undefined';
    if (value === null)
        return 'null';
    if (Array.isArray(value))
        return 'array';
    if (typeof value === 'boolean')
        return 'boolean';
    if (typeof value === 'function')
        return 'function';
    if (typeof value === 'number')
        return 'number';
    if (typeof value === 'string')
        return 'string';
    if (typeof value === 'bigint')
        return 'bigint';
    if (typeof value === 'object') {
        if (value.constructor === RegExp)
            return 'regexp';
        if (value.constructor === Map)
            return 'map';
        if (value.constructor === Set)
            return 'set';
        if (value.constructor === Date)
            return 'date';
        return 'object';
    }
    if (typeof value === 'symbol')
        return 'symbol';
    throw new Error(`value of unknown type: ${value}`);
}
const isPrimitive = (value) => Object(value) !== value;
export function isPromise(candidate) {
    return candidate !== null && candidate !== undefined
        && (typeof candidate === 'object' || typeof candidate === 'function')
        && typeof candidate.then === 'function';
}
// -----------------------------------------------------------------------------
// Asymmetric matchers (asymmetricMatchers.ts)
// -----------------------------------------------------------------------------
const functionToString = Function.prototype.toString;
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 const utils = Object.freeze({
    ...matcherUtils,
    iterableEquality,
    subsetEquality,
});
function hasProperty(obj, property) {
    if (!obj)
        return false;
    if (Object.prototype.hasOwnProperty.call(obj, property))
        return true;
    return hasProperty(Object.getPrototypeOf(obj), property);
}
export class AsymmetricMatcher {
    sample;
    inverse;
    $$typeof = Symbol.for('jest.asymmetricMatcher');
    constructor(sample, inverse = false) {
        this.sample = sample;
        this.inverse = inverse;
    }
    getMatcherContext() {
        return {
            customTesters: [],
            equals,
            isNot: this.inverse,
            utils,
        };
    }
}
export function buildCustomAsymmetricMatcher(matcherName, matcher) {
    class CustomMatcher extends AsymmetricMatcher {
        constructor(inverse = false, ...sample) {
            super(sample, inverse);
        }
        asymmetricMatch(other) {
            const { pass } = matcher.call(this.getMatcherContext(), other, ...this.sample);
            return this.inverse ? !pass : pass;
        }
        toString() {
            return `${this.inverse ? 'not.' : ''}${matcherName}`;
        }
        getExpectedType() {
            return 'any';
        }
        toAsymmetricMatcher() {
            return `${this.toString()}<${this.sample.map(String).join(', ')}>`;
        }
    }
    const positive = (...sample) => new CustomMatcher(false, ...sample);
    const inverse = (...sample) => new CustomMatcher(true, ...sample);
    return { positive, inverse };
}
class Any extends AsymmetricMatcher {
    constructor(sample) {
        if (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';
        if (this.sample === Array)
            return Array.isArray(other);
        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';
        if (this.sample === Array)
            return 'array';
        return fnNameFor(this.sample);
    }
    toAsymmetricMatcher() {
        return `Any<${fnNameFor(this.sample)}>`;
    }
}
class Anything extends AsymmetricMatcher {
    asymmetricMatch(other) {
        return other !== null && other !== undefined;
    }
    toString() {
        return 'Anything';
    }
    toAsymmetricMatcher() {
        return 'Anything';
    }
}
class ArrayContaining extends AsymmetricMatcher {
    constructor(sample, inverse = false) {
        super(sample, inverse);
    }
    asymmetricMatch(other) {
        if (!Array.isArray(this.sample)) {
            throw new TypeError(`You must provide an array to ${this.toString()}, not '${typeof this
                .sample}'.`);
        }
        const matcherContext = this.getMatcherContext();
        const result = this.sample.length === 0 ||
            (Array.isArray(other) &&
                this.sample.every(item => other.some(another => equals(item, another, matcherContext.customTesters))));
        return this.inverse ? !result : result;
    }
    toString() {
        return `Array${this.inverse ? 'Not' : ''}Containing`;
    }
    getExpectedType() {
        return 'array';
    }
}
class ArrayOf extends AsymmetricMatcher {
    asymmetricMatch(other) {
        const matcherContext = this.getMatcherContext();
        const result = Array.isArray(other) &&
            other.every(item => equals(this.sample, item, matcherContext.customTesters));
        return this.inverse ? !result : result;
    }
    toString() {
        return `${this.inverse ? 'Not' : ''}ArrayOf`;
    }
    getExpectedType() {
        return 'array';
    }
}
class ObjectContaining extends AsymmetricMatcher {
    constructor(sample, inverse = false) {
        super(sample, inverse);
    }
    asymmetricMatch(other) {
        if (typeof this.sample !== 'object') {
            throw new TypeError(`You must provide an object to ${this.toString()}, not '${typeof this
                .sample}'.`);
        }
        if (typeof other !== 'object' || Array.isArray(other))
            return false;
        let result = true;
        const matcherContext = this.getMatcherContext();
        const objectKeys = getObjectKeys(this.sample);
        for (const key of objectKeys) {
            if (!hasProperty(other, key) ||
                !equals(this.sample[key], other[key], matcherContext.customTesters)) {
                result = false;
                break;
            }
        }
        return this.inverse ? !result : result;
    }
    toString() {
        return `Object${this.inverse ? 'Not' : ''}Containing`;
    }
    getExpectedType() {
        return 'object';
    }
}
class StringContaining extends AsymmetricMatcher {
    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 {
    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';
    }
}
class CloseTo extends AsymmetricMatcher {
    precision;
    constructor(sample, precision = 2, inverse = false) {
        if (!isA('Number', sample))
            throw new Error('Expected is not a Number');
        if (!isA('Number', precision))
            throw new Error('Precision is not a Number');
        super(sample);
        this.inverse = inverse;
        this.precision = precision;
    }
    asymmetricMatch(other) {
        if (!isA('Number', other))
            return false;
        let result = false;
        if (other === Number.POSITIVE_INFINITY && this.sample === Number.POSITIVE_INFINITY)
            result = true;
        else if (other === Number.NEGATIVE_INFINITY && this.sample === Number.NEGATIVE_INFINITY)
            result = true;
        else
            result = Math.abs(this.sample - other) < Math.pow(10, -this.precision) / 2;
        return this.inverse ? !result : result;
    }
    toString() {
        return `Number${this.inverse ? 'Not' : ''}CloseTo`;
    }
    getExpectedType() {
        return 'number';
    }
    toAsymmetricMatcher() {
        return [
            this.toString(),
            this.sample,
            `(${this.precision} ${this.precision === 1 ? 'digit' : 'digits'})`,
        ].join(' ');
    }
}
export const any = (expectedObject) => new Any(expectedObject);
export const anything = () => new Anything();
export const arrayContaining = (sample) => new ArrayContaining(sample);
export const arrayNotContaining = (sample) => new ArrayContaining(sample, true);
export const arrayOf = (sample) => new ArrayOf(sample);
export const notArrayOf = (sample) => new ArrayOf(sample, true);
export const objectContaining = (sample) => new ObjectContaining(sample);
export const objectNotContaining = (sample) => new ObjectContaining(sample, true);
export const stringContaining = (expected) => new StringContaining(expected);
export const stringNotContaining = (expected) => new StringContaining(expected, true);
export const stringMatching = (expected) => new StringMatching(expected);
export const stringNotMatching = (expected) => new StringMatching(expected, true);
export const closeTo = (expected, precision) => new CloseTo(expected, precision);
export const notCloseTo = (expected, precision) => new CloseTo(expected, precision, true);
// -----------------------------------------------------------------------------
// Print helpers (print.ts)
// -----------------------------------------------------------------------------
const printSubstring = (val) => val.replace(/"|\\/g, '\\$&');
const printReceivedStringContainExpectedSubstring = (received, start, length) => RECEIVED_COLOR(`"${printSubstring(received.slice(0, start))}${INVERTED_COLOR(printSubstring(received.slice(start, start + length)))}${printSubstring(received.slice(start + length))}"`);
const printReceivedStringContainExpectedResult = (received, result) => result === null
    ? printReceived(received)
    : printReceivedStringContainExpectedSubstring(received, result.index, result[0].length);
const printReceivedArrayContainExpectedItem = (received, index) => RECEIVED_COLOR(`[${received
    .map((item, i) => {
    const stringified = stringify(item);
    return i === index ? INVERTED_COLOR(stringified) : stringified;
})
    .join(', ')}]`);
const printCloseTo = (receivedDiff, expectedDiff, precision, isNot) => {
    const receivedDiffString = stringify(receivedDiff);
    const expectedDiffString = receivedDiffString.includes('e')
        ? expectedDiff.toExponential(0)
        : 0 <= precision && precision < 20
            ? expectedDiff.toFixed(precision + 1)
            : stringify(expectedDiff);
    return (`Expected precision:  ${isNot ? '    ' : ''}  ${stringify(precision)}\n` +
        `Expected difference: ${isNot ? 'not ' : ''}< ${EXPECTED_COLOR(expectedDiffString)}\n` +
        `Received difference: ${isNot ? '    ' : ''}  ${RECEIVED_COLOR(receivedDiffString)}`);
};
const printConstructorName = (label, constructor, isNot, isExpected) => typeof constructor.name === 'string'
    ? constructor.name.length === 0
        ? `${label} name is an empty string`
        : `${label}: ${isNot ? (isExpected ? 'not ' : '    ') : ''}${isExpected
            ? EXPECTED_COLOR(constructor.name)
            : RECEIVED_COLOR(constructor.name)}`
    : `${label} name is not a string`;
const printExpectedConstructorName = (label, expected) => `${printConstructorName(label, expected, false, true)}\n`;
const printExpectedConstructorNameNot = (label, expected) => `${printConstructorName(label, expected, true, true)}\n`;
const printReceivedConstructorName = (label, received) => `${printConstructorName(label, received, false, false)}\n`;
const printReceivedConstructorNameNot = (label, received, expected) => typeof expected.name === 'string' &&
    expected.name.length > 0 &&
    typeof received.name === 'string' &&
    received.name.length > 0
    ? `${printConstructorName(label, received, true, false)} ${Object.getPrototypeOf(received) === expected
        ? 'extends'
        : 'extends … extends'} ${EXPECTED_COLOR(expected.name)}\n`
    : `${printConstructorName(label, received, false, false)}\n`;
// -----------------------------------------------------------------------------
// Default matchers (matchers.ts)
// -----------------------------------------------------------------------------
const EXPECTED_LABEL = 'Expected';
const RECEIVED_LABEL = 'Received';
const EXPECTED_VALUE_LABEL = 'Expected value';
const RECEIVED_VALUE_LABEL = 'Received value';
const toStrictEqualTesters = [
    iterableEquality,
    typeEquality,
    sparseArrayEquality,
    arrayBufferEquality,
];
export const matchers = {
    toBe(received, expected) {
        const matcherName = 'toBe';
        const options = {
            comment: 'Object.is equality',
            isNot: this.isNot,
            promise: this.promise,
        };
        const pass = Object.is(received, expected);
        const message = pass
            ? () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `Expected: not ${printExpected(expected)}`
            : () => {
                const expectedType = getType(expected);
                let deepEqualityName = null;
                if (expectedType !== 'map' && expectedType !== 'set') {
                    if (equals(received, expected, [...this.customTesters, ...toStrictEqualTesters], true))
                        deepEqualityName = 'toStrictEqual';
                    else if (equals(received, expected, [...this.customTesters, iterableEquality]))
                        deepEqualityName = 'toEqual';
                }
                return (matcherHint(matcherName, undefined, undefined, options) +
                    '\n\n' +
                    (deepEqualityName === null
                        ? ''
                        : `${DIM_COLOR(`If it should pass with deep equality, replace "${matcherName}" with "${deepEqualityName}"`)}\n\n`) +
                    printDiffOrStringify(expected, received, EXPECTED_LABEL, RECEIVED_LABEL, false));
            };
        return { actual: received, expected, message, name: matcherName, pass };
    },
    toBeCloseTo(received, expected, precision = 2) {
        const matcherName = 'toBeCloseTo';
        const secondArgument = arguments.length === 3 ? 'precision' : undefined;
        const isNot = this.isNot;
        const options = {
            isNot,
            promise: this.promise,
            secondArgument,
            secondArgumentColor: (arg) => arg,
        };
        if (typeof expected !== 'number') {
            throw new TypeError(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${EXPECTED_COLOR('expected')} value must be a number`, printWithType('Expected', expected, printExpected)));
        }
        if (typeof received !== 'number') {
            throw new TypeError(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${RECEIVED_COLOR('received')} value must be a number`, printWithType('Received', received, printReceived)));
        }
        let pass = false;
        let expectedDiff = 0;
        let receivedDiff = 0;
        if (received === Number.POSITIVE_INFINITY && expected === Number.POSITIVE_INFINITY) {
            pass = true;
        }
        else if (received === Number.NEGATIVE_INFINITY && expected === Number.NEGATIVE_INFINITY) {
            pass = true;
        }
        else {
            expectedDiff = Math.pow(10, -precision) / 2;
            receivedDiff = Math.abs(expected - received);
            pass = receivedDiff < expectedDiff;
        }
        const message = pass
            ? () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `Expected: not ${printExpected(expected)}\n` +
                (receivedDiff === 0
                    ? ''
                    : `Received:     ${printReceived(received)}\n` +
                        `\n${printCloseTo(receivedDiff, expectedDiff, precision, isNot)}`)
            : () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `Expected: ${printExpected(expected)}\n` +
                `Received: ${printReceived(received)}\n` +
                '\n' +
                printCloseTo(receivedDiff, expectedDiff, precision, isNot);
        return { message, pass };
    },
    toBeDefined(received, expected) {
        const matcherName = 'toBeDefined';
        const options = { isNot: this.isNot, promise: this.promise };
        ensureNoExpected(expected, matcherName, options);
        const pass = received !== void 0;
        const message = () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            `Received: ${printReceived(received)}`;
        return { message, pass };
    },
    toBeFalsy(received, expected) {
        const matcherName = 'toBeFalsy';
        const options = { isNot: this.isNot, promise: this.promise };
        ensureNoExpected(expected, matcherName, options);
        const pass = !received;
        const message = () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            `Received: ${printReceived(received)}`;
        return { message, pass };
    },
    toBeGreaterThan(received, expected) {
        const matcherName = 'toBeGreaterThan';
        const isNot = this.isNot;
        const options = { isNot, promise: this.promise };
        ensureNumbers(received, expected, matcherName, options);
        const pass = received > expected;
        const message = () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            `Expected:${isNot ? ' not' : ''} > ${printExpected(expected)}\n` +
            `Received:${isNot ? '    ' : ''}   ${printReceived(received)}`;
        return { message, pass };
    },
    toBeGreaterThanOrEqual(received, expected) {
        const matcherName = 'toBeGreaterThanOrEqual';
        const isNot = this.isNot;
        const options = { isNot, promise: this.promise };
        ensureNumbers(received, expected, matcherName, options);
        const pass = received >= expected;
        const message = () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            `Expected:${isNot ? ' not' : ''} >= ${printExpected(expected)}\n` +
            `Received:${isNot ? '    ' : ''}    ${printReceived(received)}`;
        return { message, pass };
    },
    toBeInstanceOf(received, expected) {
        const matcherName = 'toBeInstanceOf';
        const options = { isNot: this.isNot, promise: this.promise };
        if (typeof expected !== 'function') {
            throw new TypeError(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${EXPECTED_COLOR('expected')} value must be a function`, printWithType('Expected', expected, printExpected)));
        }
        const pass = received instanceof expected;
        const message = pass
            ? () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                printExpectedConstructorNameNot('Expected constructor', expected) +
                (typeof received.constructor === 'function' && received.constructor !== expected
                    ? printReceivedConstructorNameNot('Received constructor', received.constructor, expected)
                    : '')
            : () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                printExpectedConstructorName('Expected constructor', expected) +
                (isPrimitive(received) || Object.getPrototypeOf(received) === null
                    ? `\nReceived value has no prototype\nReceived value: ${printReceived(received)}`
                    : typeof received.constructor === 'function'
                        ? printReceivedConstructorName('Received constructor', received.constructor)
                        : `\nReceived value: ${printReceived(received)}`);
        return { message, pass };
    },
    toBeLessThan(received, expected) {
        const matcherName = 'toBeLessThan';
        const isNot = this.isNot;
        const options = { isNot, promise: this.promise };
        ensureNumbers(received, expected, matcherName, options);
        const pass = received < expected;
        const message = () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            `Expected:${isNot ? ' not' : ''} < ${printExpected(expected)}\n` +
            `Received:${isNot ? '    ' : ''}   ${printReceived(received)}`;
        return { message, pass };
    },
    toBeLessThanOrEqual(received, expected) {
        const matcherName = 'toBeLessThanOrEqual';
        const isNot = this.isNot;
        const options = { isNot, promise: this.promise };
        ensureNumbers(received, expected, matcherName, options);
        const pass = received <= expected;
        const message = () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            `Expected:${isNot ? ' not' : ''} <= ${printExpected(expected)}\n` +
            `Received:${isNot ? '    ' : ''}    ${printReceived(received)}`;
        return { message, pass };
    },
    toBeNaN(received, expected) {
        const matcherName = 'toBeNaN';
        const options = { isNot: this.isNot, promise: this.promise };
        ensureNoExpected(expected, matcherName, options);
        const pass = Number.isNaN(received);
        const message = () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            `Received: ${printReceived(received)}`;
        return { message, pass };
    },
    toBeNull(received, expected) {
        const matcherName = 'toBeNull';
        const options = { isNot: this.isNot, promise: this.promise };
        ensureNoExpected(expected, matcherName, options);
        const pass = received === null;
        const message = () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            `Received: ${printReceived(received)}`;
        return { message, pass };
    },
    toBeTruthy(received, expected) {
        const matcherName = 'toBeTruthy';
        const options = { isNot: this.isNot, promise: this.promise };
        ensureNoExpected(expected, matcherName, options);
        const pass = !!received;
        const message = () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            `Received: ${printReceived(received)}`;
        return { message, pass };
    },
    toBeUndefined(received, expected) {
        const matcherName = 'toBeUndefined';
        const options = { isNot: this.isNot, promise: this.promise };
        ensureNoExpected(expected, matcherName, options);
        const pass = received === void 0;
        const message = () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            `Received: ${printReceived(received)}`;
        return { message, pass };
    },
    toContain(received, expected) {
        const matcherName = 'toContain';
        const isNot = this.isNot;
        const options = { comment: 'indexOf', isNot, promise: this.promise };
        if (received === null || received === undefined) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${RECEIVED_COLOR('received')} value must not be null nor undefined`, printWithType('Received', received, printReceived)));
        }
        if (typeof received === 'string') {
            const wrongTypeErrorMessage = `${EXPECTED_COLOR('expected')} value must be a string if ${RECEIVED_COLOR('received')} value is a string`;
            if (typeof expected !== 'string') {
                throw new TypeError(matcherErrorMessage(matcherHint(matcherName, received, String(expected), options), wrongTypeErrorMessage, printWithType('Expected', expected, printExpected) +
                    '\n' +
                    printWithType('Received', received, printReceived)));
            }
            const index = received.indexOf(String(expected));
            const pass = index !== -1;
            const message = () => {
                const labelExpected = `Expected ${typeof expected === 'string' ? 'substring' : 'value'}`;
                const labelReceived = 'Received string';
                const printLabel = getLabelPrinter(labelExpected, labelReceived);
                return (matcherHint(matcherName, undefined, undefined, options) +
                    '\n\n' +
                    `${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(expected)}\n` +
                    `${printLabel(labelReceived)}${isNot ? '    ' : ''}${isNot
                        ? printReceivedStringContainExpectedSubstring(received, index, String(expected).length)
                        : printReceived(received)}`);
            };
            return { message, pass };
        }
        const indexable = [...received];
        const index = indexable.indexOf(expected);
        const pass = index !== -1;
        const message = () => {
            const labelExpected = 'Expected value';
            const labelReceived = `Received ${getType(received)}`;
            const printLabel = getLabelPrinter(labelExpected, labelReceived);
            return (matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(expected)}\n` +
                `${printLabel(labelReceived)}${isNot ? '    ' : ''}${isNot && Array.isArray(received)
                    ? printReceivedArrayContainExpectedItem(received, index)
                    : printReceived(received)}` +
                (!isNot &&
                    indexable.some(item => equals(item, expected, [...this.customTesters, iterableEquality]))
                    ? `\n\n${SUGGEST_TO_CONTAIN_EQUAL}`
                    : ''));
        };
        return { message, pass };
    },
    toContainEqual(received, expected) {
        const matcherName = 'toContainEqual';
        const isNot = this.isNot;
        const options = { comment: 'deep equality', isNot, promise: this.promise };
        if (received === null || received === undefined) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${RECEIVED_COLOR('received')} value must not be null nor undefined`, printWithType('Received', received, printReceived)));
        }
        const index = [...received].findIndex(item => equals(item, expected, [...this.customTesters, iterableEquality]));
        const pass = index !== -1;
        const message = () => {
            const labelExpected = 'Expected value';
            const labelReceived = `Received ${getType(received)}`;
            const printLabel = getLabelPrinter(labelExpected, labelReceived);
            return (matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(expected)}\n` +
                `${printLabel(labelReceived)}${isNot ? '    ' : ''}${isNot && Array.isArray(received)
                    ? printReceivedArrayContainExpectedItem(received, index)
                    : printReceived(received)}`);
        };
        return { message, pass };
    },
    toEqual(received, expected) {
        const matcherName = 'toEqual';
        const options = { comment: 'deep equality', isNot: this.isNot, promise: this.promise };
        const pass = equals(received, expected, [...this.customTesters, iterableEquality]);
        const message = pass
            ? () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `Expected: not ${printExpected(expected)}\n` +
                (stringify(expected) === stringify(received)
                    ? ''
                    : `Received:     ${printReceived(received)}`)
            : () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                printDiffOrStringify(expected, received, EXPECTED_LABEL, RECEIVED_LABEL, false);
        return { actual: received, expected, message, name: matcherName, pass };
    },
    toHaveLength(received, expected) {
        const matcherName = 'toHaveLength';
        const isNot = this.isNot;
        const options = { isNot, promise: this.promise };
        if (typeof received?.length !== 'number') {
            throw new TypeError(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${RECEIVED_COLOR('received')} value must have a length property whose value must be a number`, printWithType('Received', received, printReceived)));
        }
        ensureExpectedIsNonNegativeInteger(expected, matcherName, options);
        const pass = received.length === expected;
        const message = () => {
            const labelExpected = 'Expected length';
            const labelReceivedLength = 'Received length';
            const labelReceivedValue = `Received ${getType(received)}`;
            const printLabel = getLabelPrinter(labelExpected, labelReceivedLength, labelReceivedValue);
            return (matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `${printLabel(labelExpected)}${isNot ? 'not ' : ''}${printExpected(expected)}\n` +
                (isNot ? '' : `${printLabel(labelReceivedLength)}${printReceived(received.length)}\n`) +
                `${printLabel(labelReceivedValue)}${isNot ? '    ' : ''}${printReceived(received)}`);
        };
        return { message, pass };
    },
    toHaveProperty(received, expectedPath, expectedValue) {
        const matcherName = 'toHaveProperty';
        const expectedArgument = 'path';
        const hasValue = arguments.length === 3;
        const options = {
            isNot: this.isNot,
            promise: this.promise,
            secondArgument: hasValue ? 'value' : '',
        };
        if (received === null || received === undefined) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${RECEIVED_COLOR('received')} value must not be null nor undefined`, printWithType('Received', received, printReceived)));
        }
        const expectedPathType = getType(expectedPath);
        if (expectedPathType !== 'string' && expectedPathType !== 'array') {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${EXPECTED_COLOR('expected')} path must be a string or array`, printWithType('Expected', expectedPath, printExpected)));
        }
        const expectedPathLength = typeof expectedPath === 'string' ? pathAsArray(expectedPath).length : expectedPath.length;
        if (expectedPathType === 'array' && expectedPathLength === 0) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, expectedArgument, options), `${EXPECTED_COLOR('expected')} path must not be an empty array`, printWithType('Expected', expectedPath, printExpected)));
        }
        const result = getPath(received, expectedPath);
        const { lastTraversedObject, endPropIsDefined, hasEndProp, value } = result;
        const receivedPath = result.traversedPath;
        const hasCompletePath = receivedPath.length === expectedPathLength;
        const receivedValue = hasCompletePath ? result.value : lastTraversedObject;
        const pass = hasValue && endPropIsDefined
            ? equals(value, expectedValue, [...this.customTesters, iterableEquality])
            : Boolean(hasEndProp);
        const message = pass
            ? () => matcherHint(matcherName, undefined, expectedArgument, options) +
                '\n\n' +
                (hasValue
                    ? `Expected path: ${printExpected(expectedPath)}\n\n` +
                        `Expected value: not ${printExpected(expectedValue)}${stringify(expectedValue) === stringify(receivedValue)
                            ? ''
                            : `\nReceived value:     ${printReceived(receivedValue)}`}`
                    : `Expected path: not ${printExpected(expectedPath)}\n\n` +
                        `Received value: ${printReceived(receivedValue)}`)
            : () => matcherHint(matcherName, undefined, expectedArgument, options) +
                '\n\n' +
                `Expected path: ${printExpected(expectedPath)}\n` +
                (hasCompletePath
                    ? `\n${printDiffOrStringify(expectedValue, receivedValue, EXPECTED_VALUE_LABEL, RECEIVED_VALUE_LABEL, false)}`
                    : `Received path: ${printReceived(expectedPathType === 'array' || receivedPath.length === 0
                        ? receivedPath
                        : receivedPath.join('.'))}\n\n${hasValue ? `Expected value: ${printExpected(expectedValue)}\n` : ''}Received value: ${printReceived(receivedValue)}`);
        return { message, pass };
    },
    toMatch(received, expected) {
        const matcherName = 'toMatch';
        const options = { isNot: this.isNot, promise: this.promise };
        if (typeof received !== 'string') {
            throw new TypeError(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${RECEIVED_COLOR('received')} value must be a string`, printWithType('Received', received, printReceived)));
        }
        if (!(typeof expected === 'string') && !(expected && typeof expected.test === 'function')) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${EXPECTED_COLOR('expected')} value must be a string or regular expression`, printWithType('Expected', expected, printExpected)));
        }
        const pass = typeof expected === 'string'
            ? received.includes(expected)
            : new RegExp(expected).test(received);
        const message = pass
            ? () => typeof expected === 'string'
                ? matcherHint(matcherName, undefined, undefined, options) +
                    '\n\n' +
                    `Expected substring: not ${printExpected(expected)}\n` +
                    `Received string:        ${printReceivedStringContainExpectedSubstring(received, received.indexOf(expected), expected.length)}`
                : matcherHint(matcherName, undefined, undefined, options) +
                    '\n\n' +
                    `Expected pattern: not ${printExpected(expected)}\n` +
                    `Received string:      ${printReceivedStringContainExpectedResult(received, typeof expected.exec === 'function' ? expected.exec(received) : null)}`
            : () => {
                const labelExpected = `Expected ${typeof expected === 'string' ? 'substring' : 'pattern'}`;
                const labelReceived = 'Received string';
                const printLabel = getLabelPrinter(labelExpected, labelReceived);
                return (matcherHint(matcherName, undefined, undefined, options) +
                    '\n\n' +
                    `${printLabel(labelExpected)}${printExpected(expected)}\n` +
                    `${printLabel(labelReceived)}${printReceived(received)}`);
            };
        return { message, pass };
    },
    toMatchObject(received, expected) {
        const matcherName = 'toMatchObject';
        const options = { isNot: this.isNot, promise: this.promise };
        if (typeof received !== 'object' || received === null) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${RECEIVED_COLOR('received')} value must be a non-null object`, printWithType('Received', received, printReceived)));
        }
        if (typeof expected !== 'object' || expected === null) {
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${EXPECTED_COLOR('expected')} value must be a non-null object`, printWithType('Expected', expected, printExpected)));
        }
        const pass = equals(received, expected, [...this.customTesters, iterableEquality, subsetEquality]);
        const message = pass
            ? () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `Expected: not ${printExpected(expected)}` +
                (stringify(expected) === stringify(received)
                    ? ''
                    : `\nReceived:     ${printReceived(received)}`)
            : () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                printDiffOrStringify(expected, getObjectSubset(received, expected, this.customTesters), EXPECTED_LABEL, RECEIVED_LABEL, false);
        return { message, pass };
    },
    toStrictEqual(received, expected) {
        const matcherName = 'toStrictEqual';
        const options = { comment: 'deep equality', isNot: this.isNot, promise: this.promise };
        const pass = equals(received, expected, [...this.customTesters, ...toStrictEqualTesters], true);
        const message = pass
            ? () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                `Expected: not ${printExpected(expected)}\n` +
                (stringify(expected) === stringify(received)
                    ? ''
                    : `Received:     ${printReceived(received)}`)
            : () => matcherHint(matcherName, undefined, undefined, options) +
                '\n\n' +
                printDiffOrStringify(expected, received, EXPECTED_LABEL, RECEIVED_LABEL, false);
        return { actual: received, expected, message, name: matcherName, pass };
    },
};
// -----------------------------------------------------------------------------
// toThrow matcher (toThrowMatchers.ts)
// -----------------------------------------------------------------------------
const DID_NOT_THROW = 'Received function did not throw';
const getThrown = (e) => {
    const hasMessage = e !== null && e !== undefined && typeof e.message === 'string';
    if (hasMessage && typeof e.name === 'string' && typeof e.stack === 'string')
        return { hasMessage, isError: true, message: e.message, value: e };
    return {
        hasMessage,
        isError: false,
        message: hasMessage ? e.message : String(e),
        value: e,
    };
};
export const createThrowMatcher = (matcherName, fromPromise) => function (received, expected) {
    const options = { isNot: this.isNot, promise: this.promise };
    let thrown = null;
    if (fromPromise && isError(received)) {
        thrown = getThrown(received);
    }
    else {
        if (typeof received === 'function') {
            try {
                received();
            }
            catch (error) {
                thrown = getThrown(error);
            }
        }
        else if (!fromPromise) {
            const placeholder = expected === undefined ? '' : 'expected';
            throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, placeholder, options), `${RECEIVED_COLOR('received')} value must be a function`, printWithType('Received', received, printReceived)));
        }
    }
    if (expected === undefined)
        return toThrow(matcherName, options, thrown);
    if (typeof expected === 'function')
        return toThrowExpectedClass(matcherName, options, thrown, expected);
    if (typeof expected === 'string')
        return toThrowExpectedString(matcherName, options, thrown, expected);
    if (expected !== null && typeof expected.test === 'function')
        return toThrowExpectedRegExp(matcherName, options, thrown, expected);
    if (expected !== null && typeof expected.asymmetricMatch === 'function')
        return toThrowExpectedAsymmetric(matcherName, options, thrown, expected);
    if (expected !== null && typeof expected === 'object')
        return toThrowExpectedObject(matcherName, options, thrown, expected);
    throw new Error(matcherErrorMessage(matcherHint(matcherName, undefined, undefined, options), `${EXPECTED_COLOR('expected')} value must be a string or regular expression or class or error`, printWithType('Expected', expected, printExpected)));
};
const toThrowExpectedRegExp = (matcherName, options, thrown, expected) => {
    const pass = thrown !== null && expected.test(thrown.message);
    const message = pass
        ? () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected('Expected pattern: not ', expected) +
            (thrown !== null && thrown.hasMessage
                ? formatReceived('Received message:     ', thrown, 'message', expected) + formatStack(thrown)
                : formatReceived('Received value:       ', thrown, 'value'))
        : () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected('Expected pattern: ', expected) +
            (thrown === null
                ? `\n${DID_NOT_THROW}`
                : thrown.hasMessage
                    ? formatReceived('Received message: ', thrown, 'message') + formatStack(thrown)
                    : formatReceived('Received value:   ', thrown, 'value'));
    return { message, pass };
};
const toThrowExpectedAsymmetric = (matcherName, options, thrown, expected) => {
    const pass = thrown !== null && expected.asymmetricMatch(thrown.value);
    const message = pass
        ? () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected('Expected asymmetric matcher: not ', expected) +
            '\n' +
            (thrown !== null && thrown.hasMessage
                ? formatReceived('Received name:    ', thrown, 'name') +
                    formatReceived('Received message: ', thrown, 'message') +
                    formatStack(thrown)
                : formatReceived('Thrown value: ', thrown, 'value'))
        : () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected('Expected asymmetric matcher: ', expected) +
            '\n' +
            (thrown === null
                ? DID_NOT_THROW
                : thrown.hasMessage
                    ? formatReceived('Received name:    ', thrown, 'name') +
                        formatReceived('Received message: ', thrown, 'message') +
                        formatStack(thrown)
                    : formatReceived('Thrown value: ', thrown, 'value'));
    return { message, pass };
};
const toThrowExpectedObject = (matcherName, options, thrown, expected) => {
    const expectedMessageAndCause = createMessageAndCause(expected);
    const thrownMessageAndCause = thrown === null ? null : createMessageAndCause(thrown.value);
    const isCompareErrorInstance = thrown?.isError && expected instanceof Error;
    const isExpectedCustomErrorInstance = expected.constructor.name !== Error.name;
    const pass = thrown !== null &&
        thrown.message === expected.message &&
        thrownMessageAndCause === expectedMessageAndCause &&
        (!isCompareErrorInstance || !isExpectedCustomErrorInstance || thrown.value instanceof expected.constructor);
    const message = pass
        ? () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected(`Expected ${messageAndCause(expected)}: not `, expectedMessageAndCause) +
            (thrown !== null && thrown.hasMessage
                ? formatStack(thrown)
                : formatReceived('Received value:       ', thrown, 'value'))
        : () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            (thrown === null
                ? formatExpected(`Expected ${messageAndCause(expected)}: `, expectedMessageAndCause) +
                    '\n' +
                    DID_NOT_THROW
                : thrown.hasMessage
                    ? printDiffOrStringify(expectedMessageAndCause, thrownMessageAndCause, `Expected ${messageAndCause(expected)}`, `Received ${messageAndCause(thrown.value)}`, true) +
                        '\n' +
                        formatStack(thrown)
                    : formatExpected(`Expected ${messageAndCause(expected)}: `, expectedMessageAndCause) +
                        formatReceived('Received value:   ', thrown, 'value'));
    return { message, pass };
};
const toThrowExpectedClass = (matcherName, options, thrown, expected) => {
    const pass = thrown !== null && thrown.value instanceof expected;
    const message = pass
        ? () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            printExpectedConstructorNameNot('Expected constructor', expected) +
            (thrown !== null &&
                thrown.value !== null && thrown.value !== undefined &&
                typeof thrown.value.constructor === 'function' &&
                thrown.value.constructor !== expected
                ? printReceivedConstructorNameNot('Received constructor', thrown.value.constructor, expected)
                : '') +
            '\n' +
            (thrown !== null && thrown.hasMessage
                ? formatReceived('Received message: ', thrown, 'message') + formatStack(thrown)
                : formatReceived('Received value: ', thrown, 'value'))
        : () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            printExpectedConstructorName('Expected constructor', expected) +
            (thrown === null
                ? `\n${DID_NOT_THROW}`
                : `${thrown.value !== null && thrown.value !== undefined && typeof thrown.value.constructor === 'function'
                    ? printReceivedConstructorName('Received constructor', thrown.value.constructor)
                    : ''}\n${thrown.hasMessage
                    ? formatReceived('Received message: ', thrown, 'message') + formatStack(thrown)
                    : formatReceived('Received value: ', thrown, 'value')}`);
    return { message, pass };
};
const toThrowExpectedString = (matcherName, options, thrown, expected) => {
    const pass = thrown !== null && thrown.message.includes(expected);
    const message = pass
        ? () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected('Expected substring: not ', expected) +
            (thrown !== null && thrown.hasMessage
                ? formatReceived('Received message:       ', thrown, 'message', expected) + formatStack(thrown)
                : formatReceived('Received value:         ', thrown, 'value'))
        : () => matcherHint(matcherName, undefined, undefined, options) +
            '\n\n' +
            formatExpected('Expected substring: ', expected) +
            (thrown === null
                ? `\n${DID_NOT_THROW}`
                : thrown.hasMessage
                    ? formatReceived('Received message:   ', thrown, 'message') + formatStack(thrown)
                    : formatReceived('Received value:     ', thrown, 'value'));
    return { message, pass };
};
const toThrow = (matcherName, options, thrown) => {
    const pass = thrown !== null;
    const message = pass
        ? () => matcherHint(matcherName, undefined, '', options) +
            '\n\n' +
            (thrown !== null && thrown.hasMessage
                ? formatReceived('Error name:    ', thrown, 'name') +
                    formatReceived('Error message: ', thrown, 'message') +
                    formatStack(thrown)
                : formatReceived('Thrown value: ', thrown, 'value'))
        : () => matcherHint(matcherName, undefined, '', options) + '\n\n' + DID_NOT_THROW;
    return { message, pass };
};
const formatExpected = (label, expected) => `${label + printExpected(expected)}\n`;
const formatReceived = (label, thrown, key, expected) => {
    if (thrown === null)
        return '';
    if (key === 'message') {
        const message = thrown.message;
        if (typeof expected === 'string') {
            const index = message.indexOf(expected);
            if (index !== -1) {
                return `${label + printReceivedStringContainExpectedSubstring(message, index, expected.length)}\n`;
            }
        }
        else if (expected instanceof RegExp) {
            return `${label +
                printReceivedStringContainExpectedResult(message, typeof expected.exec === 'function' ? expected.exec(message) : null)}\n`;
        }
        return `${label + printReceived(message)}\n`;
    }
    if (key === 'name')
        return thrown.isError ? `${label + printReceived(thrown.value.name)}\n` : '';
    if (key === 'value')
        return thrown.isError ? '' : `${label + printReceived(thrown.value)}\n`;
    return '';
};
const formatStack = (thrown) => {
    if (thrown === null || !thrown.isError)
        return '';
    const config = { rootDir: process.cwd(), testMatch: [] };
    const options = { noStackTrace: false };
    if (thrown.value instanceof AggregateError)
        return formatExecError(thrown.value, config, options);
    return formatStackTrace(separateMessageFromStack(thrown.value.stack).stack, config, options);
};
function createMessageAndCause(error) {
    if (error.cause) {
        const seen = new WeakSet();
        return JSON.stringify(buildSerializeError(error), (_, value) => {
            if (isObject(value)) {
                if (seen.has(value))
                    return;
                seen.add(value);
            }
            if (typeof value === 'bigint' || value === undefined)
                return String(value);
            return value;
        });
    }
    return error.message;
}
function buildSerializeError(error) {
    if (!isObject(error))
        return error;
    const result = {};
    for (const name of Object.getOwnPropertyNames(error).sort()) {
        if (['stack', 'fileName', 'lineNumber'].includes(name))
            continue;
        if (name === 'cause') {
            result[name] = buildSerializeError(error['cause']);
            continue;
        }
        result[name] = error[name];
    }
    return result;
}
function isObject(obj) {
    return obj !== null && obj !== undefined && typeof obj === 'object';
}
function messageAndCause(error) {
    return error.cause === undefined ? 'message' : 'message and cause';
}
export const getMessage = (message) => (message && message()) ||
    RECEIVED_COLOR('No message was specified for this matcher.');
export const validateMatcherResult = (result) => {
    if (typeof result !== 'object' ||
        typeof result.pass !== 'boolean' ||
        (result.message &&
            typeof result.message !== 'string' &&
            typeof result.message !== 'function')) {
        throw new Error('Unexpected return from a matcher function.\n' +
            'Matcher functions should ' +
            'return an object in the following format:\n' +
            '  {message?: string | function, pass: boolean}\n' +
            `'${stringify(result)}' was returned`);
    }
};
export function createExpectedPromiseMessage(matcherName, isNot, promise, actual) {
    return () => matcherErrorMessage(matcherHint(matcherName, undefined, '', { isNot, promise }), `${RECEIVED_COLOR('received')} value must be a promise or a function returning a promise`, printWithType('Received', actual, printReceived));
}
export function createExpectedToResolveMessage(matcherName, isNot, promise, actual) {
    return () => `${matcherHint(matcherName, undefined, '', { isNot, promise })}\n\n` +
        'Received promise rejected instead of resolved\n' +
        `Rejected to value: ${printReceived(actual)}`;
}
export function createExpectedToRejectMessage(matcherName, isNot, promise, actual) {
    return () => `${matcherHint(matcherName, undefined, '', { isNot, promise })}\n\n` +
        'Received promise resolved instead of rejected\n' +
        `Resolved to value: ${printReceived(actual)}`;
}
//# sourceMappingURL=expectLibrary.js.map