'use strict' module.exports = shallow shallow.strict = strict // TODO a future version of this that drops node 0.x support will // check for Symbol.iterator, and handle anything that can be passed // to Array.from() var hasSet = typeof Set === 'function' function isSet (object) { return hasSet && (object instanceof Set) } function isMap (object) { return hasSet && (object instanceof Map) } function setSame (a, b) { var ret = a.size === b.size if (a.size && ret) { a.forEach(function (entry) { if (ret) ret = b.has(entry) }) } return ret } function mapSame (a, b, ca, cb, fn) { var ret = a.size === b.size if (a.size && ret) { a.forEach(function (value, key) { if (ret) ret = b.has(key) if (ret) ret = fn(value, b.get(key), ca, cb) }) } return ret } function isArguments (object) { return Object.prototype.toString.call(object) === '[object Arguments]' } function arrayFrom (obj) { return Array.isArray(obj) ? obj : Array.from ? Array.from(obj) : Array.prototype.slice.call(obj) } function strict (a, b) { return deeper(a, b, [], []) } function deeper (a, b, ca, cb) { return a === b ? true : a !== a ? b !== b : typeof a !== 'object' || typeof b !== 'object' ? false : a === null || b === null ? false : Buffer.isBuffer(a) && Buffer.isBuffer(b) ? bufferSame(a, b) : a instanceof Date && b instanceof Date ? a.getTime() === b.getTime() : a instanceof RegExp && b instanceof RegExp ? regexpSame(a, b) : isArguments(a) ? isArguments(b) && deeper(arrayFrom(a), arrayFrom(b), ca, cb) : isArguments(b) ? false : a.constructor !== b.constructor ? false : isSet(a) && isSet(b) ? setSame(a, b) : isMap(a) && isMap(b) ? mapSame(a, b, ca, cb, deeper) : deeperObj(a, b, Object.keys(a), Object.keys(b), ca, cb) } function deeperObj (a, b, ka, kb, ca, cb) { // don't bother with stack acrobatics if there's nothing there return ka.length === 0 && kb.length === 0 ? true : ka.length !== kb.length ? false : deeperObj_(a, b, ka, kb, ca, cb) } function deeperObj_ (a, b, ka, kb, ca, cb) { var ret = true var cal = ca.length var go = true while (cal-- && go) { if (ca[cal] === a) { ret = cb[cal] === b go = false } } if (go) { ca.push(a) cb.push(b) ka.sort() kb.sort() for (var j = ka.length - 1; j >= 0 && ret; j--) { if (ka[j] !== kb[j]) ret = false } if (ret) { var key for (var k = ka.length - 1; k >= 0 && ret; k--) { key = ka[k] if (!deeper(a[key], b[key], ca, cb)) ret = false } } if (ret) { ca.pop() cb.pop() } } return ret } function shallow (a, b) { return shallower(a, b, [], []) } function regexpSame (a, b) { return a.source === b.source && a.global === b.global && a.multiline === b.multiline && a.lastIndex === b.lastIndex && a.ignoreCase === b.ignoreCase } function bufferSame (a, b) { var ret if (a.equals) { ret = a.equals(b) } else if (a.length !== b.length) { ret = false } else { ret = true for (var j = 0; j < a.length && ret; j++) { if (a[j] != b[j]) ret = false } } return ret } function shallower (a, b, ca, cb) { return typeof a !== 'object' && typeof b !== 'object' && a == b ? true : a === null || b === null ? a == b : a !== a ? b !== b : typeof a !== 'object' || typeof b !== 'object' ? false : Buffer.isBuffer(a) && Buffer.isBuffer(b) ? bufferSame(a, b) : a instanceof Date && b instanceof Date ? a.getTime() === b.getTime() : a instanceof RegExp && b instanceof RegExp ? regexpSame(a, b) : isArguments(a) || isArguments(b) ? shallower(arrayFrom(a), arrayFrom(b), ca, cb) : isSet(a) && isSet(b) ? setSame(a, b) : isMap(a) && isMap(b) ? mapSame(a, b, ca, cb, shallower) : shallowerObj(a, b, Object.keys(a), Object.keys(b), ca, cb) } function shallowerObj (a, b, ka, kb, ca, cb) { // don't bother with stack acrobatics if there's nothing there return ka.length === 0 && kb.length === 0 ? true : ka.length !== kb.length ? false : shallowerObj_(a, b, ka, kb, ca, cb) } function shallowerObj_ (a, b, ka, kb, ca, cb) { var ret var cal = ca.length var go = true while (cal-- && go) { if (ca[cal] === a) { ret = cb[cal] === b go = false } } if (go) { ca.push(a) cb.push(b) ka.sort() kb.sort() ret = true for (var k = ka.length - 1; k >= 0 && ret; k--) { if (ka[k] !== kb[k]) ret = false } if (ret) { var key for (var l = ka.length - 1; l >= 0 && ret; l--) { key = ka[l] if (!shallower(a[key], b[key], ca, cb)) ret = false } } if (ret) { ca.pop() cb.pop() } } return ret }