diff --git a/dist/index.js b/dist/index.js index 8721c28..7d3479b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2,4 +2,4 @@ * @license MIT https://github.com/omgaz/diffler * Author: Gary Chisholm @omgaz */ -function diffler(f,o){var r,t,e={};for(r in f)if(f.hasOwnProperty(r)&&"function"!=typeof f[r]){if(typeof(n=f[r])!=typeof(i=o[r])){e[r]={from:n,to:i};break}r in o?"object"==typeof n?(t=diffler(n,i),0r&&"object"==typeof r&&!Array.isArray(r),isValidProperty=(r,e)=>Object.prototype.hasOwnProperty.call(r,e)&&"function"!=typeof r[e],compareValues=(e,t)=>{if(typeof e!=typeof t)return{from:e,to:t};if(Array.isArray(e)&&Array.isArray(t)){var o={},l=Math.max(e.length,t.length);for(let r=0;r=8" @@ -301,22 +302,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -401,10 +386,11 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -668,6 +654,23 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/espree": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", @@ -801,10 +804,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1073,6 +1077,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1193,16 +1198,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/merge2": { @@ -1215,12 +1225,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -1656,13 +1667,11 @@ ] }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -1774,6 +1783,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1792,6 +1802,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -1860,10 +1871,11 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1906,12 +1918,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -2148,12 +2154,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browser-stdout": { @@ -2174,16 +2180,6 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2250,9 +2246,9 @@ "dev": true }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -2368,6 +2364,18 @@ "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "eslint-config-prettier": { @@ -2542,9 +2550,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -2823,15 +2831,18 @@ "requires": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "merge2": { @@ -2841,12 +2852,12 @@ "dev": true }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, @@ -3128,13 +3139,10 @@ "dev": true }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true }, "serialize-javascript": { "version": "6.0.0", @@ -3278,9 +3286,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "workerpool": { @@ -3312,12 +3320,6 @@ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index 2238bf4..7807b62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diffler", - "version": "2.0.4", + "version": "2.1.0", "description": "A recursive JSON comparison script for humans", "main": "./dist/index.js", "devDependencies": { diff --git a/src/index.js b/src/index.js index 01430a6..b66f573 100644 --- a/src/index.js +++ b/src/index.js @@ -4,80 +4,89 @@ */ /** - * Read in two objects. Iterate over them and return the differences. + * @typedef {object} DiffResult + * @property {*} from Original value. + * @property {*} to New value. + */ + +/** + * @param {any} value Value to check. + * @returns {boolean} True if value is a plain object. + */ +const isPlainObject = (value) => value && typeof value === 'object' && !Array.isArray(value); + +/** + * @param {object} obj The object to check. + * @param {string} key The key to check in the object. + * @returns {boolean} True if value is a valid property. + */ +const isValidProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key) && typeof obj[key] !== 'function'; + +/** + * @param {any} val1 First value. + * @param {any} val2 Second value. + * @returns {DiffResult|null} Difference result or null if no change. + */ +const compareValues = (val1, val2) => { + // Different types + if (typeof val1 !== typeof val2) { + return { from: val1, to: val2 }; + } + + // Handle arrays + if (Array.isArray(val1) && Array.isArray(val2)) { + const arrayDiff = {}; + const maxLength = Math.max(val1.length, val2.length); + + for (let i = 0; i < maxLength; i++) { + const diff = compareValues(val1[i], val2[i]); + if (diff) arrayDiff[i] = diff; + } + + return Object.keys(arrayDiff).length ? arrayDiff : null; + } + + // Handle objects + if (isPlainObject(val1) && isPlainObject(val2)) { + const nestedDiff = diffler(val1, val2); + return Object.keys(nestedDiff).length ? nestedDiff : null; + } + + // Compare values + return val1 !== val2 ? { from: val1, to: val2 } : null; +}; + +/**. + * Compares two objects and returns their differences * - * @param {object} obj1 First object to compare from. - * @param {object} obj2 Second object to compare against obj1. - * @returns {object} Nested json object of changed properties containing a from and to key. + * @param {object} originalObj First object to compare + * @param {object} newObj Second object to compare against + * @returns {Object.} Object containing changes */ -function diffler(obj1, obj2) { - var diff = {}; - - // Iterate over obj1 looking for removals and differences in existing values - for (var key in obj1) { - if (obj1.hasOwnProperty(key) && typeof obj1[key] !== 'function') { - var obj1Val = obj1[key], - obj2Val = obj2[key]; - - if (typeof obj1Val !== typeof obj2Val) { - diff[key] = { - from: obj1Val, - to: obj2Val, - }; - break; - } - - // If property exists in obj1 and not in obj2 then it has been removed - if (!(key in obj2)) { - diff[key] = { - from: obj1Val, - to: null, // using null to specify that the value is empty in obj2 - }; - } - - // If property is an object then we need to recursively go down the rabbit hole - else if (typeof obj1Val === 'object') { - var tempDiff = diffler(obj1Val, obj2Val); - if (Object.keys(tempDiff).length > 0) { - if (tempDiff) { - diff[key] = tempDiff; - } - } - } - - // If property is in both obj1 and obj2 and is different - else if (obj1Val !== obj2Val) { - diff[key] = { - from: obj1Val, - to: obj2Val, - }; - } +function diffler(originalObj, newObj) { + const diff = {}; + + // Check for changes and removals + for (const key in originalObj) { + if (!isValidProperty(originalObj, key)) continue; + + if (!(key in newObj)) { + diff[key] = { from: originalObj[key], to: null }; + continue; + } + + const difference = compareValues(originalObj[key], newObj[key]); + if (difference) { + diff[key] = difference; } } - // Iterate over obj2 looking for any new additions - for (key in obj2) { - if (obj2.hasOwnProperty(key) && typeof obj2[key] !== 'function') { - if (obj1 === null) { - diff[key] = { - from: obj1, - to: obj2[key], - }; - break; - } - - var obj1Val = obj1[key], - obj2Val = obj2[key]; - - if (!(key in obj1)) { - if (!diff) { - diff = {}; - } - diff[key] = { - from: null, - to: obj2Val, - }; - } + // Check for additions + for (const key in newObj) { + if (!isValidProperty(newObj, key)) continue; + + if (!(key in originalObj)) { + diff[key] = { from: null, to: newObj[key] }; } } diff --git a/tests/benchmarker.js b/tests/benchmarker.js index f421fd9..d894112 100644 --- a/tests/benchmarker.js +++ b/tests/benchmarker.js @@ -1,3 +1,9 @@ +/** + * Runs the provided function as many times as possible. + * + * @param {Function} func - The function to benchmark. + * @returns {number} The number of operations performed. + */ function bench(func) { let ops = 0; const startMs = Date.now(); @@ -9,13 +15,20 @@ function bench(func) { return ops; } +/** + * Runs the provided function 10 times and averages the results. + * + * @param {Function} func - The function to benchmark. + * @returns {number} The average number of operations performed per second. + */ function bench10(func) { let ops = 0; for (let i = 0; i < 10; i++) { ops += exports.bench(func); } - return ops / 10; + return ops / 10; // Return the average ops/sec } +// Export the benchmarking functions exports.bench = bench; exports.bench10 = bench10; diff --git a/tests/index.js b/tests/index.js index e630bd2..0d1fdc7 100644 --- a/tests/index.js +++ b/tests/index.js @@ -11,7 +11,7 @@ describe('getDiff', () => { assert.deepEqual(difference, {}); }); - it('should detect a single property change', () => { + it('detect a single property change', () => { const testObjectA = { name: 'gary' }; const testObjectB = { name: 'cindy' }; const difference = diffler(testObjectA, testObjectB); @@ -23,7 +23,7 @@ describe('getDiff', () => { assert.equal(difference.name.to, 'cindy'); }); - it('should detect no changes', () => { + it('detect no changes', () => { const testObjectA = { name: 'gary' }; const testObjectB = { name: 'gary' }; const difference = diffler(testObjectA, testObjectB); @@ -31,7 +31,7 @@ describe('getDiff', () => { assert.equal(Object.keys(difference).length, 0); }); - it('should detect type changes', () => { + it('detect type changes', () => { const testObjectA = { name: '1' }; const testObjectB = { name: 1 }; const difference = diffler(testObjectA, testObjectB); @@ -45,7 +45,7 @@ describe('getDiff', () => { }); describe('multiple checks', () => { - it('should detect a nested property change', () => { + it('detect a nested property change', () => { const testObjectA = { name: 'gary', age: 33, @@ -65,7 +65,7 @@ describe('getDiff', () => { assert.equal(difference.weight.value.to, 79); }); - it('should detect multiple nested property change', () => { + it('detect multiple nested property change', () => { const testObjectA = { name: 'gary', age: 33, @@ -93,7 +93,7 @@ describe('getDiff', () => { }); describe('property removals', () => { - it('should detect a single property removal as null', () => { + it('detect a single property removal as null', () => { const testObjectA = { name: 'gary' }; const testObjectB = {}; const difference = diffler(testObjectA, testObjectB); @@ -105,7 +105,7 @@ describe('getDiff', () => { assert.equal(difference.name.to, null); }); - it('should detect a nested property removal as null', () => { + it('detect a nested property removal as null', () => { const testObjectA = { name: 'gary', age: 33, @@ -121,7 +121,7 @@ describe('getDiff', () => { assert.equal(difference.weight.to, null); }); - it('should detect comparisons with null', () => { + it('detect comparisons with null', () => { const differenceFrom = diffler({ a: null, b: 'things' }, { a: 'more', b: 'things' }); const differenceTo = diffler({ a: 'some', b: 'things' }, { a: null, b: 'things' }); const same = diffler({ a: null, b: 'things' }, { a: null, b: 'things' }); @@ -135,7 +135,7 @@ describe('getDiff', () => { }); // https://github.com/omgaz/diffler/issues/31 - it('should detect comparisons with defined undefined', () => { + it('detect comparisons with defined undefined', () => { const differenceFrom = diffler({ a: undefined, b: 'things' }, { a: 'more', b: 'things' }); const differenceTo = diffler({ a: 'some', b: 'things' }, { a: undefined, b: 'things' }); const same = diffler({ a: undefined, b: 'things' }, { a: undefined, b: 'things' }); @@ -149,7 +149,7 @@ describe('getDiff', () => { }); // https://github.com/omgaz/diffler/issues/31 - it('should detect comparisons with arrays of mixed types', () => { + it('detect comparisons with arrays of mixed types', () => { const difference = diffler({ a: [1], b: ['one'] }, { a: ['one'], b: [1] }); assert.equal(Object.keys(difference).length, 2); @@ -163,7 +163,7 @@ describe('getDiff', () => { }); // https://github.com/omgaz/diffler/issues/31 - it('should detect comparisons with arrays of mixed primitives and objects', () => { + it('detect comparisons with arrays of mixed primitives and objects', () => { const difference = diffler( { a: ['something'], b: [{ b: 'something' }] }, { a: [{ a: 'something' }], b: ['something'] }, @@ -180,5 +180,54 @@ describe('getDiff', () => { }); assert.equal(difference.b[0].to, 'something'); }); + + it('detect changes in arrays of objects', () => { + const testObjectA = { + items: [ + { id: 1, value: 'a' }, + { id: 2, value: 'b' }, + ], + }; + const testObjectB = { + items: [ + { id: 1, value: 'a' }, + { id: 2, value: 'c' }, + ], + }; + const difference = diffler(testObjectA, testObjectB); + + assert.equal(Object.keys(difference).length, 1); + assert.equal(Object.keys(difference.items[1]).length, 1); + assert.equal(difference.items[1].value.from, 'b'); + assert.equal(difference.items[1].value.to, 'c'); + }); + + it('detect additions in arrays of objects', () => { + const testObjectA = { items: [{ id: 1, value: 'a' }] }; + const testObjectB = { + items: [ + { id: 1, value: 'a' }, + { id: 2, value: 'b' }, + ], + }; + const difference = diffler(testObjectA, testObjectB); + + assert.equal(Object.keys(difference).length, 1); + assert.deepEqual(difference.items[1], { from: undefined, to: { id: 2, value: 'b' } }); + }); + + it('detect removals in arrays of objects', () => { + const testObjectA = { + items: [ + { id: 1, value: 'a' }, + { id: 2, value: 'b' }, + ], + }; + const testObjectB = { items: [{ id: 1, value: 'a' }] }; + const difference = diffler(testObjectA, testObjectB); + + assert.equal(Object.keys(difference).length, 1); + assert.deepEqual(difference.items[1], { from: { id: 2, value: 'b' }, to: undefined }); + }); }); }); diff --git a/tests/performance.js b/tests/performance.js index cf1df6f..5312ca2 100644 --- a/tests/performance.js +++ b/tests/performance.js @@ -3,17 +3,28 @@ const diffler = require('../src'); const metadatav3 = require('./data/json-metadata-v3'); const metadatav2 = require('./data/json-metadata-v2'); +/** + * Function to run the diffler comparison as a benchmark suite. + */ function suite() { diffler(metadatav2, metadatav3); } +// Run the benchmark suite and get operations per second const ops = benchmarker.bench10(suite); -const benchmark = 255538; // update value to set new benchmark + +// Set the benchmark value for comparison +const benchmark = 466763; // Update this value to set a new benchmark + +// Log the number of operations per second console.info(`Executed ${ops} ops/s`); + +// Calculate the difference between the benchmark and the current ops const opsDiff = benchmark / ops; const opsDiffAsPercentage = Math.round(opsDiff * 100); const opsDiffAsPercentageDifference = 100 - opsDiffAsPercentage; +// Check if the performance has changed if (opsDiffAsPercentageDifference === 0) { console.log("Bench complete: Code hasn't changed."); return; @@ -23,5 +34,9 @@ if (opsDiffAsPercentageDifference === 0) { ); return; } + +// Determine if the code ran faster or slower than the benchmark const message = opsDiffAsPercentageDifference > 0 ? 'faster' : 'slower'; + +// Log the performance difference console.info(`Bench complete: Code ran ${Math.abs(opsDiffAsPercentageDifference)}% ${message} than benchmark.`);