Skip to content

Commit

Permalink
[Fix] properly pass strict option through internals
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Mar 9, 2020
1 parent c21e14d commit 4e2919d
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 21 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
{
"files": "test/**",
"rules": {
"max-lines-per-function": 0,
"max-params": 0,
"no-magic-numbers": 0,
"no-magic-numbers": 0,
"operator-linebreak": [2, "before"],
},
},
Expand Down
37 changes: 20 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var whichCollection = require('which-collection');
var getIterator = require('es-get-iterator');
var getSideChannel = require('side-channel');
var whichTypedArray = require('which-typed-array');
var assign = require('object.assign');

var $getTime = callBound('Date.prototype.getTime');
var gPO = Object.getPrototypeOf;
Expand All @@ -29,11 +30,11 @@ var $setHas = callBound('Set.prototype.has', true);
var $setSize = callBound('Set.prototype.size', true);

// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L401-L414
function setHasEqualElement(set, val1, strict, channel) {
function setHasEqualElement(set, val1, opts, channel) {
var i = getIterator(set);
var result;
while ((result = i.next()) && !result.done) {
if (internalDeepEqual(val1, result.value, strict, channel)) { // eslint-disable-line no-use-before-define
if (internalDeepEqual(val1, result.value, opts, channel)) { // eslint-disable-line no-use-before-define
// Remove the matching element to make sure we do not check that again.
$setDelete(set, result.value);
return true;
Expand Down Expand Up @@ -62,18 +63,22 @@ function findLooseMatchingPrimitives(prim) {
}

// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L449-L460
function mapMightHaveLoosePrim(a, b, prim, item, channel) {
function mapMightHaveLoosePrim(a, b, prim, item, opts, channel) {
var altValue = findLooseMatchingPrimitives(prim);
if (altValue != null) {
return altValue;
}
var curB = $mapGet(b, altValue);
// eslint-disable-next-line no-use-before-define
if ((typeof curB === 'undefined' && !$mapHas(b, altValue)) || !internalDeepEqual(item, curB, false, channel)) {
var looseOpts = assign({}, opts, { strict: false });
if (
(typeof curB === 'undefined' && !$mapHas(b, altValue))
// eslint-disable-next-line no-use-before-define
|| !internalDeepEqual(item, curB, looseOpts, channel)
) {
return false;
}
// eslint-disable-next-line no-use-before-define
return !$mapHas(a, altValue) && internalDeepEqual(item, curB, false, channel);
return !$mapHas(a, altValue) && internalDeepEqual(item, curB, looseOpts, channel);
}

// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L441-L447
Expand All @@ -87,17 +92,17 @@ function setMightHaveLoosePrim(a, b, prim) {
}

// taken from https://github.com/browserify/commonjs-assert/blob/bba838e9ba9e28edf3127ce6974624208502f6bc/internal/util/comparisons.js#L518-L533
function mapHasEqualEntry(set, map, key1, item1, strict, channel) {
function mapHasEqualEntry(set, map, key1, item1, opts, channel) {
var i = getIterator(set);
var result;
var key2;
while ((result = i.next()) && !result.done) {
key2 = result.value;
if (
// eslint-disable-next-line no-use-before-define
internalDeepEqual(key1, key2, strict, channel)
internalDeepEqual(key1, key2, opts, channel)
// eslint-disable-next-line no-use-before-define
&& internalDeepEqual(item1, $mapGet(map, key2), strict, channel)
&& internalDeepEqual(item1, $mapGet(map, key2), opts, channel)
) {
$setDelete(set, key2);
return true;
Expand All @@ -123,7 +128,6 @@ function internalDeepEqual(actual, expected, options, channel) {

// 7.3. Other pairs that do not both pass typeof value == 'object', equivalence is determined by ==.
if (!actual || !expected || (typeof actual !== 'object' && typeof expected !== 'object')) {
if ((actual === false && expected) || (actual && expected === false)) { return false; }
return opts.strict ? is(actual, expected) : actual == expected; // eslint-disable-line eqeqeq
}

Expand Down Expand Up @@ -230,12 +234,11 @@ function mapEquiv(a, b, opts, channel) {
$setAdd(set, key);
} else {
item2 = $mapGet(b, key);
// if (typeof curB === 'undefined' && !$mapHas(b, altValue) || !internalDeepEqual(item, curB, false, channel)) {
if ((typeof item2 === 'undefined' && !$mapHas(b, key)) || !internalDeepEqual(item1, item2, opts.strict, channel)) {
if ((typeof item2 === 'undefined' && !$mapHas(b, key)) || !internalDeepEqual(item1, item2, opts, channel)) {
if (opts.strict) {
return false;
}
if (!mapMightHaveLoosePrim(a, b, key, item1, channel)) {
if (!mapMightHaveLoosePrim(a, b, key, item1, opts, channel)) {
return false;
}
if (!set) { set = new $Set(); }
Expand All @@ -247,15 +250,15 @@ function mapEquiv(a, b, opts, channel) {
if (set) {
while ((resultB = iB.next()) && !resultB.done) {
key = resultB.value[0];
item1 = resultB.value[1];
item2 = resultB.value[1];
if (key && typeof key === 'object') {
if (!mapHasEqualEntry(set, a, key, item1, opts.strict, channel)) {
if (!mapHasEqualEntry(set, a, key, item2, opts, channel)) {
return false;
}
} else if (
!opts.strict
&& (!a.has(key) || !internalDeepEqual($mapGet(a, key), item1, false, channel))
&& !mapHasEqualEntry(set, a, key, item1, false, channel)
&& (!a.has(key) || !internalDeepEqual($mapGet(a, key), item2, opts, channel))
&& !mapHasEqualEntry(set, a, key, item2, assign({}, opts, { strict: false }), channel)
) {
return false;
}
Expand Down
158 changes: 155 additions & 3 deletions test/cmp.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ test('equal', function (t) {
false
);

t.deepEqualTest(
{ a: 2, b: '4' },
{ a: 2, b: 4 },
'two loosely equal, strictly inequal objects',
true,
false
);

t.deepEqualTest(
{ a: 2, b: 4 },
{ a: 2, B: 4 },
'two inequal objects',
false,
false
);

t.deepEqualTest(
'-000',
false,
'`false` and `"-000"`',
true,
false
);

t.end();
});

Expand Down Expand Up @@ -63,13 +87,86 @@ test('Maps', { skip: typeof Map !== 'function' }, function (t) {
);

t.deepEqualTest(
new Map([[{}, 1], [{}, 2], [{}, 1]]),
new Map([[{}, 1], [{}, 2], [{}, 1]]),
'two equal Maps in different orders',
new Map([[{}, 3], [{}, 2], [{}, 1]]),
new Map([[{}, 1], [{}, 2], [{}, 3]]),
'two equal Maps in different orders with object keys',
true,
true
);

t.deepEqualTest(
new Map([[undefined, undefined]]),
new Map([[undefined, null]]),
'undefined keys, nullish values, loosely equal, strictly inequal',
true,
false,
true
);

t.deepEqualTest(
new Map([[null, undefined]]),
new Map([[null, null]]),
'null keys, nullish values, loosely equal, strictly inequal',
true,
false
);

t.deepEqualTest(
new Map([[undefined, 3]]),
new Map([[null, 3]]),
'nullish keys, loosely equal, strictly inequal',
true,
false
);

t.deepEqualTest(
new Map([[{}, null], [true, 2], [{}, 1], [undefined, {}]]),
new Map([[{}, 1], [true, 2], [{}, null], [undefined, {}]]),
'two equal Maps in different orders with primitive keys',
true,
true
);

t.deepEqualTest(
new Map([[false, 3], [{}, 2], [{}, 1]]),
new Map([[{}, 1], [{}, 2], [false, 3]]),
'two equal Maps in different orders with a mix of keys',
true,
true
);

t.deepEqualTest(
new Map(),
new Map([[{}, 1]]),
'two inequal Maps',
false,
false
);

t.deepEqualTest(
new Map([[{}, null], [false, 3]]),
new Map([[{}, null], [true, 2]]),
'two inequal maps, same size, primitive key, start with object key',
false,
false
);

t.deepEqualTest(
new Map([[false, 3], [{}, null]]),
new Map([[true, 2], [{}, null]]),
'two inequal maps, same size, primitive key, start with primitive key',
false,
false
);

t.deepEqualTest(
new Map([[undefined, null], ['+000', 2]]),
new Map([[null, undefined], [false, '2']]),
'primitive comparisons',
true,
false
);

t.end();
});

Expand Down Expand Up @@ -126,6 +223,61 @@ test('Sets', { skip: typeof Set !== 'function' }, function (t) {
true
);

t.deepEqualTest(
new Set(),
new Set([1]),
'two inequally sized Sets',
false,
false
);

t.deepEqualTest(
new Set([{ a: 1 }, 2]),
new Set(['2', { a: '1' }]),
'two loosely equal, strictly inequal Sets',
true,
false
);

t.deepEqualTest(
new Set([{ a: 1 }, 2]),
new Set(['2', { a: 2 }]),
'two inequal Sets',
false,
false
);

t.deepEqualTest(
new Set([null, '', 1, 5, 2, false]),
new Set([undefined, 0, '5', true, '2', '-000']),
'more primitive comparisons',
true,
false
);

t.end();
});

test('Set and Map', { skip: !Object.defineProperty || typeof Set !== 'function' || typeof Map !== 'function' }, function (t) {
t.deepEqualTest(
new Set(),
new Map(),
'Map and Set',
false,
false
);

var maplikeSet = new Set();
Object.defineProperty(maplikeSet, 'constructor', { enumerable: false, value: Map });
maplikeSet.__proto__ = Map.prototype; // eslint-disable-line no-proto
t.deepEqualTest(
maplikeSet,
new Map(),
'Map-like Set, and Map',
false,
false
);

t.end();
});

Expand Down

0 comments on commit 4e2919d

Please sign in to comment.