Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: inspect-js/is-equal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.4.2
Choose a base ref
...
head repository: inspect-js/is-equal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.5.0
Choose a head ref
  • 11 commits
  • 11 files changed
  • 1 contributor

Commits on Dec 17, 2015

  1. [Dev Deps] update es6-shim

    ljharb committed Dec 17, 2015

    Verified

    This commit was signed with the committer’s verified signature.
    rm3l Armel Soro
    Copy the full SHA
    e6f5e76 View commit details

Commits on Dec 24, 2015

  1. Copy the full SHA
    e246264 View commit details

Commits on Feb 14, 2016

  1. [Tests] up to node v5.6, v4.3

    ljharb committed Feb 14, 2016
    Copy the full SHA
    087c8e6 View commit details
  2. [Deps] update is-callable

    ljharb committed Feb 14, 2016
    Copy the full SHA
    2766a04 View commit details
  3. [Dev Deps] update tape, jscs, eslint, @ljharb/eslint-config, …

    …`core-js`, `es6-shim`
    ljharb committed Feb 14, 2016
    Copy the full SHA
    f0fc78c View commit details

Commits on Feb 16, 2016

  1. [Tests] add some more tests.

    ljharb committed Feb 16, 2016
    Copy the full SHA
    06f434f View commit details
  2. Copy the full SHA
    637fa7c View commit details
  3. Copy the full SHA
    8f47efa View commit details
  4. Copy the full SHA
    fd7a11d View commit details
  5. Copy the full SHA
    692f0a5 View commit details
  6. v1.5.0

    ljharb committed Feb 16, 2016
    Copy the full SHA
    9d9d0e8 View commit details
Showing with 1,026 additions and 251 deletions.
  1. +12 −2 .jscs.json
  2. +13 −1 .travis.yml
  3. +10 −0 CHANGELOG.md
  4. +13 −0 README.md
  5. +2 −223 index.js
  6. +15 −14 package.json
  7. +2 −0 test/corejs.js
  8. +19 −11 test/native.js
  9. +2 −0 test/shimmed.js
  10. +632 −0 test/why.js
  11. +306 −0 why.js
14 changes: 12 additions & 2 deletions .jscs.json
Original file line number Diff line number Diff line change
@@ -122,7 +122,7 @@

"disallowArrowFunctions": true,

"disallowMultiLineTernary": true,
"disallowMultiLineTernary": false,

"validateOrderInObjectKeys": "asc-insensitive",

@@ -147,6 +147,16 @@

"requireEnhancedObjectLiterals": false,

"requireObjectDestructuring": false
"requireObjectDestructuring": false,

"requireEarlyReturn": false,

"requireCapitalizedConstructorsNew": {
"allExcept": ["Function", "String", "Object", "Symbol", "Number", "Date", "RegExp", "Error", "Boolean", "Array"]
},

"requireImportAlphabetized": false,

"disallowSpacesInsideTemplateStringPlaceholders": true
}

14 changes: 13 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
language: node_js
node_js:
- "5.6"
- "5.5"
- "5.4"
- "5.3"
- "5.2"
- "5.1"
- "5.0"
- "4.3"
- "4.2"
- "4.1"
- "4.0"
@@ -35,12 +41,18 @@ before_install:
- 'if [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi'
- 'if [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then npm install -g npm; fi'
script:
- 'if [ "${TRAVIS_NODE_VERSION}" != "4.2" ]; then npm run tests-only ; else npm test ; fi'
- 'if [ "${TRAVIS_NODE_VERSION}" != "4.3" ]; then npm run tests-only ; else npm test ; fi'
sudo: false
matrix:
fast_finish: true
allow_failures:
- node_js: "5.5"
- node_js: "5.4"
- node_js: "5.3"
- node_js: "5.2"
- node_js: "5.1"
- node_js: "5.0"
- node_js: "4.2"
- node_js: "4.1"
- node_js: "4.0"
- node_js: "iojs-v3.2"
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
1.5.0 / 2016-02-15
=================
* [New] add “whyNotEqual” at `require(‘is-equal/why’)` to provide an inequality reason
* [Refactor] use `whyNotEqual` internally in `isEqual`
* [Deps] update `is-callable`
* [Dev Deps] update `es6-shim`, `tape`, `nsp`, `core-js`, `jscs`, `eslint`, `@ljharb/eslint-config`
* [Tests] add some more tests
* [Tests] use `getSymbolIterator` internal module
* [Tests] up to `node` `v5.6`, `v4.3`

1.4.2 / 2015-12-16
=================
* [Fix] avoid false positives when the first items in two arrays are not equal (#5)
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -30,6 +30,19 @@ var timestamp = Date.now();
assert.equal(isEqual(new Date(timestamp), new Date(timestamp)), true);
```

## Want to know *why* two values are not equal?
Will return an empty string if `isEqual` would return `true` - otherwise will return a non-empty string that hopefully explains the reasoning.

```
var whyNotEqual = require('is-equal/why');
assert.equal(isEqual(1, 1), '');
assert.equal(
isEqual({ a: 1 }, { a: 2 }),
'value at key "a" differs: numbers are different: 1 !== 2'
);
```

## Tests
Simply clone the repo, `npm install`, and run `npm test`

225 changes: 2 additions & 223 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,228 +1,7 @@
'use strict';

var ObjectPrototype = Object.prototype;
var toStr = ObjectPrototype.toString;
var booleanValue = Boolean.prototype.valueOf;
var has = require('has');
var isArrowFunction = require('is-arrow-function');
var isBoolean = require('is-boolean-object');
var isDate = require('is-date-object');
var isGenerator = require('is-generator-function');
var isNumber = require('is-number-object');
var isRegex = require('is-regex');
var isString = require('is-string');
var isSymbol = require('is-symbol');
var isCallable = require('is-callable');

var isProto = Object.prototype.isPrototypeOf;

var foo = function foo() {};
var functionsHaveNames = foo.name === 'foo';

var symbolValue = typeof Symbol === 'function' ? Symbol.prototype.valueOf : null;
var symbolIterator = require('./getSymbolIterator')();

var collectionsForEach = require('./getCollectionsForEach')();

var getPrototypeOf = Object.getPrototypeOf;
if (!getPrototypeOf) {
/* eslint-disable no-proto */
if (typeof 'test'.__proto__ === 'object') {
getPrototypeOf = function (obj) {
return obj.__proto__;
};
} else {
getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (has(obj, 'constructor')) {
oldConstructor = constructor;
if (!(delete obj.constructor)) { // reset constructor
return null; // can't delete obj.constructor, return null
}
constructor = obj.constructor; // get real constructor
obj.constructor = oldConstructor; // restore constructor
}
return constructor ? constructor.prototype : ObjectPrototype; // needed for IE
};
}
/* eslint-enable no-proto */
}

var isArray = Array.isArray || function (value) {
return toStr.call(value) === '[object Array]';
};

var normalizeFnWhitespace = function normalizeFnWhitespace(fnStr) {
// this is needed in IE 9, at least, which has inconsistencies here.
return fnStr.replace(/^function ?\(/, 'function (').replace('){', ') {');
};

var tryMapSetEntries = function tryMapSetEntries(collection) {
var foundEntries = [];
try {
collectionsForEach.Map.call(collection, function (key, value) {
foundEntries.push([key, value]);
});
} catch (notMap) {
try {
collectionsForEach.Set.call(collection, function (value) {
foundEntries.push([value]);
});
} catch (notSet) {
return false;
}
}
return foundEntries;
};
var whyNotEqual = require('./why');

module.exports = function isEqual(value, other) {
if (value === other) { return true; }
if (value == null || other == null) { return value === other; }

if (toStr.call(value) !== toStr.call(other)) { return false; }

var valIsBool = isBoolean(value);
var otherIsBool = isBoolean(other);
if (valIsBool || otherIsBool) {
return valIsBool && otherIsBool && booleanValue.call(value) === booleanValue.call(other);
}

var valIsNumber = isNumber(value);
var otherIsNumber = isNumber(value);
if (valIsNumber || otherIsNumber) {
return valIsNumber && otherIsNumber && (Number(value) === Number(other) || (isNaN(value) && isNaN(other)));
}

var valIsString = isString(value);
var otherIsString = isString(other);
if (valIsString || otherIsString) {
return valIsString && otherIsString && String(value) === String(other);
}

var valIsDate = isDate(value);
var otherIsDate = isDate(other);
if (valIsDate || otherIsDate) {
return valIsDate && otherIsDate && +value === +other;
}

var valIsRegex = isRegex(value);
var otherIsRegex = isRegex(other);
if (valIsRegex || otherIsRegex) {
return valIsRegex && otherIsRegex && String(value) === String(other);
}

var valIsArray = isArray(value);
var otherIsArray = isArray(other);
if (valIsArray || otherIsArray) {
if (!valIsArray || !otherIsArray) { return false; }
if (value.length !== other.length) { return false; }
if (String(value) !== String(other)) { return false; }

var index = value.length - 1;
var equal = true;
while (equal && index >= 0) {
equal = has(value, index) && has(other, index) && isEqual(value[index], other[index]);
index -= 1;
}
return equal;
}

var valueIsSym = isSymbol(value);
var otherIsSym = isSymbol(other);
if (valueIsSym !== otherIsSym) { return false; }
if (valueIsSym && otherIsSym) {
return symbolValue.call(value) === symbolValue.call(other);
}

var valueIsGen = isGenerator(value);
var otherIsGen = isGenerator(other);
if (valueIsGen !== otherIsGen) { return false; }

var valueIsArrow = isArrowFunction(value);
var otherIsArrow = isArrowFunction(other);
if (valueIsArrow !== otherIsArrow) { return false; }

if (isCallable(value) || isCallable(other)) {
if (functionsHaveNames && !isEqual(value.name, other.name)) { return false; }
if (!isEqual(value.length, other.length)) { return false; }

var valueStr = normalizeFnWhitespace(String(value));
var otherStr = normalizeFnWhitespace(String(other));
if (isEqual(valueStr, otherStr)) { return true; }

if (!valueIsGen && !valueIsArrow) {
return isEqual(valueStr.replace(/\)\s*\{/, '){'), otherStr.replace(/\)\s*\{/, '){'));
}
return isEqual(valueStr, otherStr);
}

if (typeof value === 'object' || typeof other === 'object') {
if (typeof value !== typeof other) { return false; }
if (isProto.call(value, other) || isProto.call(other, value)) { return false; }
if (getPrototypeOf(value) !== getPrototypeOf(other)) { return false; }

if (symbolIterator) {
var valueIteratorFn = value[symbolIterator];
var valueIsIterable = isCallable(valueIteratorFn);
var otherIteratorFn = other[symbolIterator];
var otherIsIterable = isCallable(otherIteratorFn);
if (valueIsIterable !== otherIsIterable) {
return false;
}
if (valueIsIterable && otherIsIterable) {
var valueIterator = valueIteratorFn.call(value);
var otherIterator = otherIteratorFn.call(other);
var valueNext, otherNext;
do {
valueNext = valueIterator.next();
otherNext = otherIterator.next();
if (!valueNext.done && !otherNext.done && !isEqual(valueNext, otherNext)) {
return false;
}
} while (!valueNext.done && !otherNext.done);
return valueNext.done === otherNext.done;
}
} else if (collectionsForEach.Map || collectionsForEach.Set) {
var valueEntries = tryMapSetEntries(value);
var otherEntries = tryMapSetEntries(other);
if (isArray(valueEntries) !== isArray(otherEntries)) {
return false; // either: neither is a Map/Set, or one is and the other isn't.
}
if (valueEntries && otherEntries) {
return isEqual(valueEntries, otherEntries);
}
}

var key, valueKeyIsRecursive, otherKeyIsRecursive;
for (key in value) {
if (has(value, key)) {
if (!has(other, key)) { return false; }
valueKeyIsRecursive = value[key] && value[key][key] === value;
otherKeyIsRecursive = other[key] && other[key][key] === other;
if (valueKeyIsRecursive !== otherKeyIsRecursive) {
return false;
}
if (!valueKeyIsRecursive && !otherKeyIsRecursive && !isEqual(value[key], other[key])) {
return false;
}
}
}
for (key in other) {
if (has(other, key)) {
if (!has(value, key)) { return false; }
valueKeyIsRecursive = value[key] && value[key][key] === value;
otherKeyIsRecursive = other[key] && other[key][key] === other;
if (valueKeyIsRecursive !== otherKeyIsRecursive) {
return false;
}
if (!valueKeyIsRecursive && !otherKeyIsRecursive && !isEqual(other[key], value[key])) {
return false;
}
}
}
return true;
}

return false;
return whyNotEqual(value, other) === '';
};
29 changes: 15 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"name": "is-equal",
"version": "1.4.2",
"version": "1.5.0",
"description": "Are these two values conceptually equal?",
"author": "Jordan Harband",
"license": "MIT",
"main": "index.js",
"scripts": {
"test": "npm run lint && npm run tests-only && npm run security",
"tests-only": "npm run test:native && npm run test:shimmed && npm run test:corejs",
"test:native": "node test/native.js",
"test:shimmed": "node test/shimmed.js",
"test:corejs": "node test/corejs.js",
"coverage": "covert test/native.js",
"tests-only": "npm run test:native && npm run test:why && npm run test:shimmed && npm run test:corejs",
"test:native": "node test/native",
"test:why": "node test/why",
"test:shimmed": "node test/shimmed",
"test:corejs": "node test/corejs",
"coverage": "covert test/native test/why",
"coverage-quiet": "covert test/native.js --quiet",
"lint": "npm run jscs && npm run eslint",
"jscs": "jscs *.js test/*.js",
@@ -37,7 +38,7 @@
"has": "^1.0.1",
"is-arrow-function": "^2.0.3",
"is-boolean-object": "^1.0.0",
"is-callable": "^1.1.1",
"is-callable": "^1.1.2",
"is-date-object": "^1.0.1",
"is-generator-function": "^1.0.3",
"is-number-object": "^1.0.3",
@@ -47,20 +48,20 @@
"object.entries": "^1.0.3"
},
"devDependencies": {
"tape": "^4.2.2",
"tape": "^4.4.0",
"covert": "^1.1.0",
"jscs": "^2.7.0",
"jscs": "^2.10.1",
"foreach": "^2.0.5",
"object.entries": "^1.0.3",
"make-arrow-function": "^1.1.0",
"make-generator-function": "^1.1.0",
"semver": "^5.1.0",
"eslint": "^1.10.3",
"@ljharb/eslint-config": "^1.6.0",
"nsp": "^2.1.0",
"eslint": "^2.1.0",
"@ljharb/eslint-config": "^2.1.1",
"nsp": "^2.2.0",
"replace": "^0.3.0",
"es6-shim": "^0.33.13",
"core-js": "^1.2.6"
"es6-shim": "^0.34.4",
"core-js": "^2.1.0"
},
"testling": {
"files": "test/native.js",
2 changes: 2 additions & 0 deletions test/corejs.js
Original file line number Diff line number Diff line change
@@ -2,4 +2,6 @@

require('core-js');

require('./why');

require('./native');
Loading