166 lines
3.9 KiB
JavaScript
166 lines
3.9 KiB
JavaScript
|
import _arrayFromIterator from "./_arrayFromIterator.js";
|
||
|
import _includesWith from "./_includesWith.js";
|
||
|
import _functionName from "./_functionName.js";
|
||
|
import _has from "./_has.js";
|
||
|
import _objectIs from "./_objectIs.js";
|
||
|
import keys from "../keys.js";
|
||
|
import type from "../type.js";
|
||
|
/**
|
||
|
* private _uniqContentEquals function.
|
||
|
* That function is checking equality of 2 iterator contents with 2 assumptions
|
||
|
* - iterators lengths are the same
|
||
|
* - iterators values are unique
|
||
|
*
|
||
|
* false-positive result will be returned for comparision of, e.g.
|
||
|
* - [1,2,3] and [1,2,3,4]
|
||
|
* - [1,1,1] and [1,2,3]
|
||
|
* */
|
||
|
|
||
|
function _uniqContentEquals(aIterator, bIterator, stackA, stackB) {
|
||
|
var a = _arrayFromIterator(aIterator);
|
||
|
|
||
|
var b = _arrayFromIterator(bIterator);
|
||
|
|
||
|
function eq(_a, _b) {
|
||
|
return _equals(_a, _b, stackA.slice(), stackB.slice());
|
||
|
} // if *a* array contains any element that is not included in *b*
|
||
|
|
||
|
|
||
|
return !_includesWith(function (b, aItem) {
|
||
|
return !_includesWith(eq, aItem, b);
|
||
|
}, b, a);
|
||
|
}
|
||
|
|
||
|
export default function _equals(a, b, stackA, stackB) {
|
||
|
if (_objectIs(a, b)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
var typeA = type(a);
|
||
|
|
||
|
if (typeA !== type(b)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (a == null || b == null) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') {
|
||
|
return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a);
|
||
|
}
|
||
|
|
||
|
if (typeof a.equals === 'function' || typeof b.equals === 'function') {
|
||
|
return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a);
|
||
|
}
|
||
|
|
||
|
switch (typeA) {
|
||
|
case 'Arguments':
|
||
|
case 'Array':
|
||
|
case 'Object':
|
||
|
if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') {
|
||
|
return a === b;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'Boolean':
|
||
|
case 'Number':
|
||
|
case 'String':
|
||
|
if (!(typeof a === typeof b && _objectIs(a.valueOf(), b.valueOf()))) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'Date':
|
||
|
if (!_objectIs(a.valueOf(), b.valueOf())) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'Error':
|
||
|
return a.name === b.name && a.message === b.message;
|
||
|
|
||
|
case 'RegExp':
|
||
|
if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
var idx = stackA.length - 1;
|
||
|
|
||
|
while (idx >= 0) {
|
||
|
if (stackA[idx] === a) {
|
||
|
return stackB[idx] === b;
|
||
|
}
|
||
|
|
||
|
idx -= 1;
|
||
|
}
|
||
|
|
||
|
switch (typeA) {
|
||
|
case 'Map':
|
||
|
if (a.size !== b.size) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b]));
|
||
|
|
||
|
case 'Set':
|
||
|
if (a.size !== b.size) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b]));
|
||
|
|
||
|
case 'Arguments':
|
||
|
case 'Array':
|
||
|
case 'Object':
|
||
|
case 'Boolean':
|
||
|
case 'Number':
|
||
|
case 'String':
|
||
|
case 'Date':
|
||
|
case 'Error':
|
||
|
case 'RegExp':
|
||
|
case 'Int8Array':
|
||
|
case 'Uint8Array':
|
||
|
case 'Uint8ClampedArray':
|
||
|
case 'Int16Array':
|
||
|
case 'Uint16Array':
|
||
|
case 'Int32Array':
|
||
|
case 'Uint32Array':
|
||
|
case 'Float32Array':
|
||
|
case 'Float64Array':
|
||
|
case 'ArrayBuffer':
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// Values of other types are only equal if identical.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
var keysA = keys(a);
|
||
|
|
||
|
if (keysA.length !== keys(b).length) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
var extendedStackA = stackA.concat([a]);
|
||
|
var extendedStackB = stackB.concat([b]);
|
||
|
idx = keysA.length - 1;
|
||
|
|
||
|
while (idx >= 0) {
|
||
|
var key = keysA[idx];
|
||
|
|
||
|
if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
idx -= 1;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|