Skip to content

Instantly share code, notes, and snippets.

@justinvdm
Last active April 17, 2020 07:07
Show Gist options
  • Save justinvdm/bc6c705a2469458c2c752abfc06dfc47 to your computer and use it in GitHub Desktop.
Save justinvdm/bc6c705a2469458c2c752abfc06dfc47 to your computer and use it in GitHub Desktop.
const diff = (() => {
const toString = Function.prototype.toString;
const objectString = toString.call(Object);
return function diff(a, b, opts) {
opts = {
printShallow: false,
...opts,
};
return diffValues(a, b, '$', opts);
}
function diffValues(a, b, path, opts) {
if (a === b) {
return [];
}
let childResults;
if (Array.isArray(a) && Array.isArray(b)) {
childResults = diffArrays(a, b, path, opts);
} else if (isPlainObject(a) && isPlainObject(b)) {
childResults = diffObjects(a, b, path, opts);
}
const results = [];
if (!childResults || opts.printShallow) {
results.push({
path,
a,
b
});
}
if (childResults) {
results.push(...childResults);
}
return results;
}
function diffObjects(a, b, path, opts) {
const results = [];
const keys = [...new Set([...Object.keys(a), ...Object.keys(b)])];
const n = keys.length;
let i = -1;
while (++i < n) {
const k = keys[i];
results.push(...diffValues(a[k], b[k], addToPath(path, k), opts));
}
return results;
}
function diffArrays(a, b, path, opts) {
const aLen = a.length;
const bLen = b.length;
let n = aLen
if (aLen < bLen) {
[a, b] = [b, a];
n = bLen
}
let i = -1;
const results = [];
while (++i < n) {
results.push(...diffValues(a[i], b[i], addToPath(path, i), opts));
}
return results;
}
function addToPath(path, key) {
return path + '.' + key;
}
function isPlainObject(v) {
if (!v || Array.isArray(v) || typeof v !== 'object') {
return false;
}
const proto = Object.getPrototypeOf(v);
return !proto || toString.call(proto.constructor) === objectString;
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment