You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
3.2 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

'use strict'
var bufferEquals = require('buffer-equals')
function isArguments (object) {
return Object.prototype.toString.call(object) === '[object Arguments]'
}
module.exports = shallower
function shallower (a, b) {
return shallower_(a, b, [], [])
}
/**
* Based on `only-shallow` by @othiym23. The comments are mostly his, edited
* to reflect the usage of strict equality.
*
* This is a structural equality test, modeled on bits and pieces of loads of
* other implementations of this algorithm, most notably the much stricter
* `deeper`, from which this comment was copied.
*
* Everybody who writes one of these functions puts the documentation
* inline, which makes it incredibly hard to follow. Here's what this version
* of the algorithm does, in order:
*
* 1. Use strict equality (`===`).
* 2. `null` *is* an object a singleton value object, in fact so if
* either is `null`, return a === b.
* 3. Since the only way to make it this far is for `a` or `b` to be an object, if
* `a` or `b` is *not* an object, they're clearly not the same.
* 4. It's much faster to compare dates by numeric value than by lexical value.
* 5. Same goes for Regexps.
* 6. The parts of an arguments list most people care about are the arguments
* themselves, not the callee, which you shouldn't be looking at anyway.
* 7. Objects are more complex:
* a. Return `true` if `a` and `b` both have no properties.
* b. Ensure that `a` and `b` have the same number of own properties with the
* same names (which is what `Object.keys()` returns).
* c. Ensure that cyclical references don't blow up the stack.
* d. Ensure that all the key names match (faster).
* e. Ensure that all of the associated values match, recursively (slower).
*/
function shallower_ (a, b, ca, cb) {
if (typeof a !== 'object' && typeof b !== 'object' && a === b) {
return true
} else if (a === null || b === null) {
return a === b
} else if (typeof a !== 'object' || typeof b !== 'object') {
return false
} else if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
return bufferEquals(a, b)
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
} else if (a instanceof RegExp && b instanceof RegExp) {
return a.source === b.source &&
a.global === b.global &&
a.multiline === b.multiline &&
a.lastIndex === b.lastIndex &&
a.ignoreCase === b.ignoreCase
} else if (isArguments(a) || isArguments(b)) {
var slice = Array.prototype.slice
return shallower_(slice.call(a), slice.call(b), ca, cb)
} else {
if (Array.isArray(a) !== Array.isArray(b)) return false
var ka = Object.keys(a)
var kb = Object.keys(b)
// don't bother with stack acrobatics if there's nothing there
if (ka.length === 0 && kb.length === 0) return true
if (ka.length !== kb.length) return false
var cal = ca.length
while (cal--) if (ca[cal] === a) return cb[cal] === b
ca.push(a); cb.push(b)
ka.sort(); kb.sort()
for (var k = ka.length - 1; k >= 0; k--) if (ka[k] !== kb[k]) return false
var key
for (var l = ka.length - 1; l >= 0; l--) {
key = ka[l]
if (!shallower_(a[key], b[key], ca, cb)) return false
}
ca.pop(); cb.pop()
return true
}
}