Path: blob/master/node_modules/@hapi/hoek/lib/deepEqual.js
1126 views
'use strict';12const Types = require('./types');345const internals = {6mismatched: null7};8910module.exports = function (obj, ref, options) {1112options = Object.assign({ prototype: true }, options);1314return !!internals.isDeepEqual(obj, ref, options, []);15};161718internals.isDeepEqual = function (obj, ref, options, seen) {1920if (obj === ref) { // Copied from Deep-eql, copyright(c) 2013 Jake Luer, [email protected], MIT Licensed, https://github.com/chaijs/deep-eql21return obj !== 0 || 1 / obj === 1 / ref;22}2324const type = typeof obj;2526if (type !== typeof ref) {27return false;28}2930if (obj === null ||31ref === null) {3233return false;34}3536if (type === 'function') {37if (!options.deepFunction ||38obj.toString() !== ref.toString()) {3940return false;41}4243// Continue as object44}45else if (type !== 'object') {46return obj !== obj && ref !== ref; // NaN47}4849const instanceType = internals.getSharedType(obj, ref, !!options.prototype);50switch (instanceType) {51case Types.buffer:52return Buffer && Buffer.prototype.equals.call(obj, ref); // $lab:coverage:ignore$53case Types.promise:54return obj === ref;55case Types.regex:56return obj.toString() === ref.toString();57case internals.mismatched:58return false;59}6061for (let i = seen.length - 1; i >= 0; --i) {62if (seen[i].isSame(obj, ref)) {63return true; // If previous comparison failed, it would have stopped execution64}65}6667seen.push(new internals.SeenEntry(obj, ref));6869try {70return !!internals.isDeepEqualObj(instanceType, obj, ref, options, seen);71}72finally {73seen.pop();74}75};767778internals.getSharedType = function (obj, ref, checkPrototype) {7980if (checkPrototype) {81if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {82return internals.mismatched;83}8485return Types.getInternalProto(obj);86}8788const type = Types.getInternalProto(obj);89if (type !== Types.getInternalProto(ref)) {90return internals.mismatched;91}9293return type;94};959697internals.valueOf = function (obj) {9899const objValueOf = obj.valueOf;100if (objValueOf === undefined) {101return obj;102}103104try {105return objValueOf.call(obj);106}107catch (err) {108return err;109}110};111112113internals.hasOwnEnumerableProperty = function (obj, key) {114115return Object.prototype.propertyIsEnumerable.call(obj, key);116};117118119internals.isSetSimpleEqual = function (obj, ref) {120121for (const entry of Set.prototype.values.call(obj)) {122if (!Set.prototype.has.call(ref, entry)) {123return false;124}125}126127return true;128};129130131internals.isDeepEqualObj = function (instanceType, obj, ref, options, seen) {132133const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals;134const { keys, getOwnPropertySymbols } = Object;135136if (instanceType === Types.array) {137if (options.part) {138139// Check if any index match any other index140141for (const objValue of obj) {142for (const refValue of ref) {143if (isDeepEqual(objValue, refValue, options, seen)) {144return true;145}146}147}148}149else {150if (obj.length !== ref.length) {151return false;152}153154for (let i = 0; i < obj.length; ++i) {155if (!isDeepEqual(obj[i], ref[i], options, seen)) {156return false;157}158}159160return true;161}162}163else if (instanceType === Types.set) {164if (obj.size !== ref.size) {165return false;166}167168if (!internals.isSetSimpleEqual(obj, ref)) {169170// Check for deep equality171172const ref2 = new Set(Set.prototype.values.call(ref));173for (const objEntry of Set.prototype.values.call(obj)) {174if (ref2.delete(objEntry)) {175continue;176}177178let found = false;179for (const refEntry of ref2) {180if (isDeepEqual(objEntry, refEntry, options, seen)) {181ref2.delete(refEntry);182found = true;183break;184}185}186187if (!found) {188return false;189}190}191}192}193else if (instanceType === Types.map) {194if (obj.size !== ref.size) {195return false;196}197198for (const [key, value] of Map.prototype.entries.call(obj)) {199if (value === undefined && !Map.prototype.has.call(ref, key)) {200return false;201}202203if (!isDeepEqual(value, Map.prototype.get.call(ref, key), options, seen)) {204return false;205}206}207}208else if (instanceType === Types.error) {209210// Always check name and message211212if (obj.name !== ref.name ||213obj.message !== ref.message) {214215return false;216}217}218219// Check .valueOf()220221const valueOfObj = valueOf(obj);222const valueOfRef = valueOf(ref);223if ((obj !== valueOfObj || ref !== valueOfRef) &&224!isDeepEqual(valueOfObj, valueOfRef, options, seen)) {225226return false;227}228229// Check properties230231const objKeys = keys(obj);232if (!options.part &&233objKeys.length !== keys(ref).length &&234!options.skip) {235236return false;237}238239let skipped = 0;240for (const key of objKeys) {241if (options.skip &&242options.skip.includes(key)) {243244if (ref[key] === undefined) {245++skipped;246}247248continue;249}250251if (!hasOwnEnumerableProperty(ref, key)) {252return false;253}254255if (!isDeepEqual(obj[key], ref[key], options, seen)) {256return false;257}258}259260if (!options.part &&261objKeys.length - skipped !== keys(ref).length) {262263return false;264}265266// Check symbols267268if (options.symbols !== false) { // Defaults to true269const objSymbols = getOwnPropertySymbols(obj);270const refSymbols = new Set(getOwnPropertySymbols(ref));271272for (const key of objSymbols) {273if (!options.skip ||274!options.skip.includes(key)) {275276if (hasOwnEnumerableProperty(obj, key)) {277if (!hasOwnEnumerableProperty(ref, key)) {278return false;279}280281if (!isDeepEqual(obj[key], ref[key], options, seen)) {282return false;283}284}285else if (hasOwnEnumerableProperty(ref, key)) {286return false;287}288}289290refSymbols.delete(key);291}292293for (const key of refSymbols) {294if (hasOwnEnumerableProperty(ref, key)) {295return false;296}297}298}299300return true;301};302303304internals.SeenEntry = class {305306constructor(obj, ref) {307308this.obj = obj;309this.ref = ref;310}311312isSame(obj, ref) {313314return this.obj === obj && this.ref === ref;315}316};317318319