| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 | 'use strict';const Types = require('./types');const internals = {    mismatched: null};module.exports = function (obj, ref, options) {    options = Object.assign({ prototype: true }, options);    return !!internals.isDeepEqual(obj, ref, options, []);};internals.isDeepEqual = function (obj, ref, options, seen) {    if (obj === ref) {                                                      // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql        return obj !== 0 || 1 / obj === 1 / ref;    }    const type = typeof obj;    if (type !== typeof ref) {        return false;    }    if (obj === null ||        ref === null) {        return false;    }    if (type === 'function') {        if (!options.deepFunction ||            obj.toString() !== ref.toString()) {            return false;        }        // Continue as object    }    else if (type !== 'object') {        return obj !== obj && ref !== ref;                                  // NaN    }    const instanceType = internals.getSharedType(obj, ref, !!options.prototype);    switch (instanceType) {        case Types.buffer:            return Buffer && Buffer.prototype.equals.call(obj, ref);        // $lab:coverage:ignore$        case Types.promise:            return obj === ref;        case Types.regex:            return obj.toString() === ref.toString();        case internals.mismatched:            return false;    }    for (let i = seen.length - 1; i >= 0; --i) {        if (seen[i].isSame(obj, ref)) {            return true;                                                    // If previous comparison failed, it would have stopped execution        }    }    seen.push(new internals.SeenEntry(obj, ref));    try {        return !!internals.isDeepEqualObj(instanceType, obj, ref, options, seen);    }    finally {        seen.pop();    }};internals.getSharedType = function (obj, ref, checkPrototype) {    if (checkPrototype) {        if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {            return internals.mismatched;        }        return Types.getInternalProto(obj);    }    const type = Types.getInternalProto(obj);    if (type !== Types.getInternalProto(ref)) {        return internals.mismatched;    }    return type;};internals.valueOf = function (obj) {    const objValueOf = obj.valueOf;    if (objValueOf === undefined) {        return obj;    }    try {        return objValueOf.call(obj);    }    catch (err) {        return err;    }};internals.hasOwnEnumerableProperty = function (obj, key) {    return Object.prototype.propertyIsEnumerable.call(obj, key);};internals.isSetSimpleEqual = function (obj, ref) {    for (const entry of obj) {        if (!ref.has(entry)) {            return false;        }    }    return true;};internals.isDeepEqualObj = function (instanceType, obj, ref, options, seen) {    const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals;    const { keys, getOwnPropertySymbols } = Object;    if (instanceType === Types.array) {        if (options.part) {            // Check if any index match any other index            for (const objValue of obj) {                for (const refValue of ref) {                    if (isDeepEqual(objValue, refValue, options, seen)) {                        return true;                    }                }            }        }        else {            if (obj.length !== ref.length) {                return false;            }            for (let i = 0; i < obj.length; ++i) {                if (!isDeepEqual(obj[i], ref[i], options, seen)) {                    return false;                }            }            return true;        }    }    else if (instanceType === Types.set) {        if (obj.size !== ref.size) {            return false;        }        if (!internals.isSetSimpleEqual(obj, ref)) {            // Check for deep equality            const ref2 = new Set(ref);            for (const objEntry of obj) {                if (ref2.delete(objEntry)) {                    continue;                }                let found = false;                for (const refEntry of ref2) {                    if (isDeepEqual(objEntry, refEntry, options, seen)) {                        ref2.delete(refEntry);                        found = true;                        break;                    }                }                if (!found) {                    return false;                }            }        }    }    else if (instanceType === Types.map) {        if (obj.size !== ref.size) {            return false;        }        for (const [key, value] of obj) {            if (value === undefined && !ref.has(key)) {                return false;            }            if (!isDeepEqual(value, ref.get(key), options, seen)) {                return false;            }        }    }    else if (instanceType === Types.error) {        // Always check name and message        if (obj.name !== ref.name ||            obj.message !== ref.message) {            return false;        }    }    // Check .valueOf()    const valueOfObj = valueOf(obj);    const valueOfRef = valueOf(ref);    if ((obj !== valueOfObj || ref !== valueOfRef) &&        !isDeepEqual(valueOfObj, valueOfRef, options, seen)) {        return false;    }    // Check properties    const objKeys = keys(obj);    if (!options.part &&        objKeys.length !== keys(ref).length &&        !options.skip) {        return false;    }    let skipped = 0;    for (const key of objKeys) {        if (options.skip &&            options.skip.includes(key)) {            if (ref[key] === undefined) {                ++skipped;            }            continue;        }        if (!hasOwnEnumerableProperty(ref, key)) {            return false;        }        if (!isDeepEqual(obj[key], ref[key], options, seen)) {            return false;        }    }    if (!options.part &&        objKeys.length - skipped !== keys(ref).length) {        return false;    }    // Check symbols    if (options.symbols !== false) {                                // Defaults to true        const objSymbols = getOwnPropertySymbols(obj);        const refSymbols = new Set(getOwnPropertySymbols(ref));        for (const key of objSymbols) {            if (!options.skip ||                !options.skip.includes(key)) {                if (hasOwnEnumerableProperty(obj, key)) {                    if (!hasOwnEnumerableProperty(ref, key)) {                        return false;                    }                    if (!isDeepEqual(obj[key], ref[key], options, seen)) {                        return false;                    }                }                else if (hasOwnEnumerableProperty(ref, key)) {                    return false;                }            }            refSymbols.delete(key);        }        for (const key of refSymbols) {            if (hasOwnEnumerableProperty(ref, key)) {                return false;            }        }    }    return true;};internals.SeenEntry = class {    constructor(obj, ref) {        this.obj = obj;        this.ref = ref;    }    isSame(obj, ref) {        return this.obj === obj && this.ref === ref;    }};
 |