Comparing version 1.1.0 to 1.2.0
@@ -0,1 +1,20 @@ | ||
## 1.2.0 (Sep 21, 2015) | ||
- Fixes `deepEgal` to consider `Array.prototype` equivalent to an empty array. | ||
JavaScript is a prototypical language after all and the prototype of an array | ||
is an array. | ||
- Fixes `egal` to consider two objects inheriting from `null` without | ||
`constructor` properties, but `valueOf` functions, as plain objects and not | ||
as value objects. | ||
- Adds support for comparing value objects that return compound values from | ||
their `valueOf` function. That is, you no longer need to return a single | ||
primitive value from `valueOf`, but merely a _more_ primitive one than before: | ||
```javascript | ||
function Point(x, y) { this.x = x; this.y = y } | ||
Point.prototype.valueOf = function() { return [this.x, this.y] } | ||
egal(new Point(42, 69), new Point(42, 69)) // => true | ||
egal(new Point(42, 69), new Point(13, 42)) // => false | ||
``` | ||
## 1.1.0 (Jun 13, 2015) | ||
@@ -2,0 +21,0 @@ - Adds `deepEgal` for comparing plain objects and arrays recursively. |
49
index.js
@@ -9,19 +9,18 @@ var kindof = require("kindof") | ||
var type | ||
switch (type = kindof(a)) { | ||
switch (type = kindofPlain(a)) { | ||
case "date": | ||
if (type != kindof(b)) return false | ||
if (type !== kindof(b)) return false | ||
return a.valueOf() === b.valueOf() | ||
case "regexp": | ||
if (type != kindof(b)) return false | ||
if (type !== kindof(b)) return false | ||
return a.toString() === b.toString() | ||
case "object": | ||
if (type != kindof(b)) return false | ||
if (type !== kindofPlain(b)) return false | ||
var constructor = getConstructorOf(a) | ||
if (constructor === Object) return false | ||
if (constructor !== getConstructorOf(b)) return false | ||
if (hasValueOf(a) && hasValueOf(b)) return a.valueOf() === b.valueOf() | ||
return false | ||
if (!hasValueOf(a) || !hasValueOf(b)) return false | ||
return deepEgal(a.valueOf(), b.valueOf()) | ||
@@ -43,7 +42,7 @@ default: return false | ||
case "plain": | ||
if (type != kindofPlain(b)) return false | ||
if (type !== kindofPlain(b)) return false | ||
var aPos = aStack && aStack.indexOf(a) | ||
var bPos = bStack && bStack.indexOf(b) | ||
if (aPos != bPos) return false | ||
if (aPos !== bPos) return false | ||
if (aPos != null && aPos >= 0) return true | ||
@@ -59,3 +58,3 @@ | ||
case "array": | ||
if (a.length != b.length) return false | ||
if (a.length !== b.length) return false | ||
if (a.length === 0) return true | ||
@@ -87,5 +86,18 @@ | ||
function kindofPlain(obj) { | ||
var type = kindof(obj) | ||
if (type === "object" && isObjectPlain(obj)) return "plain" | ||
return type | ||
} | ||
function isObjectPlain(obj) { | ||
var prototype = Object.getPrototypeOf(obj) | ||
if (prototype === null) return true | ||
if (!("constructor" in prototype)) return true | ||
return prototype.constructor === Object | ||
} | ||
function getConstructorOf(obj) { | ||
var prototype = Object.getPrototypeOf(obj) | ||
return prototype == null ? null : prototype.constructor | ||
return prototype === null ? undefined : prototype.constructor | ||
} | ||
@@ -98,17 +110,2 @@ | ||
function kindofPlain(obj) { | ||
if (isPlainObject(obj)) return "plain" | ||
return kindof(obj) | ||
} | ||
function isPlainObject(obj) { | ||
if (obj == null) return false | ||
if (typeof obj !== "object") return false | ||
var prototype = Object.getPrototypeOf(obj) | ||
if (prototype === null) return true | ||
if (!("constructor" in prototype)) return true | ||
return prototype.constructor === Object | ||
} | ||
function keys(obj) { | ||
@@ -115,0 +112,0 @@ var all = [] |
{ | ||
"name": "egal", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Strict equality test (like ===) that handles both built-in and custom value objects (those with a valueOf function).", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -27,2 +27,3 @@ Egal.js | ||
#### Primitives | ||
A **primivitive** and its **boxed object** equivalent are considered different. | ||
@@ -34,2 +35,3 @@ Allowing unexpected boxed objects (e.g. `new Boolean(false)`) through is risky | ||
#### Objects | ||
**Non-value objects**, like `Array` or `Object`, are compared by `egal` as `===` | ||
@@ -39,2 +41,3 @@ does it — based on object identity. For recursive or deep comparison, see | ||
#### NaN | ||
**NaN**s (not-a-number) are **not equal** (matching how `===` behaves). This is | ||
@@ -45,2 +48,3 @@ because when you compare results of two mathematical operations that may both | ||
#### Zeros | ||
**Negative and positive** zeros are **equal** (also matching how `===` behaves). | ||
@@ -52,2 +56,14 @@ You might end up with unexpected negative zeros via various calculations and | ||
#### Value Objects | ||
**Value objects** can also return **compound values**. That is, you need not | ||
return a single primitive value from `valueOf`, but merely a _more_ primitive | ||
one. Those values are compared with [`deepEgal`](#deep-comparison). | ||
```javascript | ||
function Point(x, y) { this.x = x; this.y = y } | ||
Point.prototype.valueOf = function() { return [this.x, this.y] } | ||
egal(new Point(42, 69), new Point(42, 69)) // => true | ||
egal(new Point(42, 69), new Point(13, 42)) // => false | ||
``` | ||
[npm-badge]: https://img.shields.io/npm/v/egal.svg | ||
@@ -54,0 +70,0 @@ [travis-badge]: https://travis-ci.org/moll/js-egal.png?branch=master |
module.exports = function(egal) { | ||
// Allow using Boolean as constructor: | ||
/* jshint -W053 */ | ||
/* eslint no-new-wrappers: 0 */ | ||
describe("given Boolean", function() { | ||
it("must return true given equivalent primitives", function() { | ||
it("must return true given identical primitives", function() { | ||
egal(true, true).must.be.true() | ||
@@ -8,0 +9,0 @@ }) |
@@ -11,3 +11,3 @@ module.exports = function(egal) { | ||
it("must return false given date and number", function() { | ||
it("must return false given Date and number primitive", function() { | ||
egal(new Date(1337), 1337).must.be.false() | ||
@@ -14,0 +14,0 @@ }) |
module.exports = function(egal) { | ||
// Allow using Number as constructor: | ||
/* jshint -W053 */ | ||
/* eslint no-new-wrappers: 0 */ | ||
describe("given Number", function() { | ||
it("must return true given equivalent primitives", function() { | ||
it("must return true given identical primitives", function() { | ||
egal(42, 42).must.be.true() | ||
@@ -14,6 +15,10 @@ }) | ||
it("must return false given string", function() { | ||
it("must return false given string primitive", function() { | ||
egal(42, "69").must.be.false() | ||
}) | ||
it("must return false given string primitive", function() { | ||
egal(42, new String("69")).must.be.false() | ||
}) | ||
it("must return true given equivalent objects", function() { | ||
@@ -32,9 +37,13 @@ egal(new Number(42), new Number(42)).must.be.true() | ||
describe("given -0", function() { | ||
it("must return true given equivalent primitives", function() { | ||
it("must return true given primitives", function() { | ||
egal(-0, +0).must.be.true() | ||
}) | ||
it("must return true given equivalent objects", function() { | ||
it("must return true given objects", function() { | ||
egal(new Number(-0), new Number(+0)).must.be.true() | ||
}) | ||
it("must return false given primitive and object", function() { | ||
egal(-0, new Number(+0)).must.be.false() | ||
}) | ||
}) | ||
@@ -50,6 +59,10 @@ | ||
}) | ||
it("must return false given number and NaN", function() { | ||
egal(42, NaN).must.be.false() | ||
}) | ||
}) | ||
describe("given Infinity", function() { | ||
it("must return true given equivalent primitivies", function() { | ||
it("must return true given identical primitivies", function() { | ||
egal(Infinity, Infinity).must.be.true() | ||
@@ -59,3 +72,3 @@ egal(-Infinity, -Infinity).must.be.true() | ||
it("must return false unequivalent primitives", function() { | ||
it("must return false given unequivalent primitives", function() { | ||
egal(Infinity, -Infinity).must.be.false() | ||
@@ -77,4 +90,9 @@ }) | ||
}) | ||
it("must return false given number and infinity", function() { | ||
egal(42, Infinity).must.be.false() | ||
egal(42, -Infinity).must.be.false() | ||
}) | ||
}) | ||
}) | ||
} |
@@ -15,3 +15,3 @@ module.exports = function(egal) { | ||
it("must return false given RegExp and string", function() { | ||
it("must return false given RegExp and string primitive", function() { | ||
egal(/a/, "/a/").must.be.false() | ||
@@ -18,0 +18,0 @@ }) |
module.exports = function(egal) { | ||
// Allow using String as constructor: | ||
/* jshint -W053 */ | ||
/* eslint no-new-wrappers: 0 */ | ||
describe("given String", function() { | ||
it("must return true given equivalent primitives", function() { | ||
it("must return true given identical primitives", function() { | ||
egal("ok", "ok").must.be.true() | ||
@@ -26,6 +27,10 @@ }) | ||
it("must return false given number", function() { | ||
it("must return false given number primitive", function() { | ||
egal("42", 42).must.be.false() | ||
}) | ||
it("must return false given number object", function() { | ||
egal("42", new Number(42)).must.be.false() | ||
}) | ||
}) | ||
} |
@@ -18,2 +18,26 @@ module.exports = function(egal) { | ||
it("must return true given equivalent array values", function() { | ||
function Value(value) { this.value = value } | ||
Value.prototype.valueOf = function() { return [42, this.value] } | ||
var a = new Value(42) | ||
var b = new Value(42) | ||
egal(a, b).must.be.true() | ||
}) | ||
it("must return false given unequivalent array values", function() { | ||
function Value(value) { this.value = value } | ||
Value.prototype.valueOf = function() { return [42, this.value] } | ||
var a = new Value(42) | ||
var b = new Value(69) | ||
egal(a, b).must.be.false() | ||
}) | ||
xit("must return false given valueOfs returning self", function() { | ||
function Value(value) { this.value = value } | ||
Value.prototype.valueOf = function() { return this } | ||
var a = new Value(42) | ||
var b = new Value(42) | ||
egal(a, b).must.be.false() | ||
}) | ||
it("must return false given plain object", function() { | ||
@@ -25,2 +49,22 @@ var a = {valueOf: function() { return 1 }} | ||
it("must return true given null inherited value objects", function() { | ||
function Value(value) { this.value = value } | ||
Value.prototype = Object.create(null, { | ||
constructor: {value: Value, configurable: true, writeable: true} | ||
}) | ||
Value.prototype.valueOf = function() { return this.value } | ||
var a = new Value(42) | ||
var b = new Value(42) | ||
egal(a, b).must.be.true() | ||
}) | ||
it("must return false given null inherited plain objects", function() { | ||
var a = Object.create(null); a.valueOf = function() { return 42 } | ||
var b = Object.create(null); b.valueOf = function() { return 42 } | ||
egal(a, b).must.be.false() | ||
}) | ||
it("must return false given instance and plain object", function() { | ||
@@ -52,3 +96,3 @@ function Value(value) { this.value = value } | ||
MoreValue.prototype = Object.create(Value.prototype, { | ||
constructor: {value: MoreValue, configurable: 1, writable: 1} | ||
constructor: {value: MoreValue, configurable: true, writable: true} | ||
}) | ||
@@ -55,0 +99,0 @@ |
@@ -87,9 +87,14 @@ var wrap = require("lodash.wrap") | ||
require("./_function_test")(deepEgal) | ||
require("./_constructed_object_test")(deepEgal) | ||
require("./_value_object_test")(deepEgal) | ||
describe("given Array", function() { | ||
it("must return true empty equivalent arrays", function() { | ||
it("must return true given equivalent empty arrays", function() { | ||
deepEgal([], []).must.be.true() | ||
}) | ||
it("must return true given empty array and Array.prototype", function() { | ||
deepEgal([], Array.prototype).must.be.true() | ||
}) | ||
it("must return true given equivalent arrays", function() { | ||
@@ -138,7 +143,3 @@ deepEgal([1], [1]).must.be.true() | ||
a.push(5) | ||
var b = [1, 2, 3] | ||
b.push([1, 2, 3, 5]) | ||
b.push(5) | ||
var b = [1, 2, 3, [1, 2, 3, 5], 5] | ||
deepEgal(a, b).must.be.false() | ||
@@ -171,2 +172,3 @@ }) | ||
require("./_function_test")(nestedDeepEgal) | ||
require("./_constructed_object_test")(nestedDeepEgal) | ||
require("./_value_object_test")(nestedDeepEgal) | ||
@@ -283,3 +285,4 @@ }) | ||
it("must return true given empty objects inherited from null", function() { | ||
it("must return true given empty objects inherited from null", | ||
function() { | ||
var a = Object.create(null) | ||
@@ -373,2 +376,3 @@ var b = Object.create(null) | ||
require("./_function_test")(nestedDeepEgal) | ||
require("./_constructed_object_test")(nestedDeepEgal) | ||
require("./_value_object_test")(nestedDeepEgal) | ||
@@ -375,0 +379,0 @@ }) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
39249
19
736
180
0