Write objectDiff(before, after). It compares two objects and returns { added, removed, changed }: three arrays of dotted paths, in any order.
A path is in added when after has it and before doesn't, in removed the other way round, and in changed when both have it with different values. A key counts as present when it's one of the object's own keys, even if its value is undefined.
When both sides hold the same kind of container at a path (two plain objects or two arrays), walk into them, using keys and indexes as the next parts of the path. Report an added or removed container once, at its own path, not each value inside it. If the kinds differ (an object becomes an array, a number, or null), that path is changed. Compare everything else with Object.is.
objectDiff(
{ name: "Ada", address: { city: "London", zip: "N1" }, tags: ["a", "b"] },
{ name: "Ada", address: { city: "Paris" }, tags: ["a", "c"], age: 36 },
);
// { added: ["age"], removed: ["address.zip"], changed: ["address.city", "tags.1"] }
expect(objectDiff({ a: 1, b: 2 }, { b: 3, c: 4 })).toEqual({ added: ["c"], removed: ["a"], changed: ["b"] });
expect(objectDiff({ a: { b: [1, { c: 2 }] } }, { a: { b: [1, { c: 2 }] } })).toEqual({ added: [], removed: [], changed: [] });
const diff = objectDiff(
{ user: { name: "Ada", address: { city: "London", zip: "N1" } } },
{ user: { name: "Ada", address: { city: "Paris" }, age: 36 } },
);
expect(diff).toEqual({ added: ["user.age"], removed: ["user.address.zip"], changed: ["user.address.city"] });
expect(objectDiff({ tags: ["a", "b"] }, { tags: ["a", "c", "d"] })).toEqual({ added: ["tags.2"], removed: [], changed: ["tags.1"] });
expect(objectDiff({ old: { x: 1, y: 2 } }, { fresh: { x: 1, list: [1] } })).toEqual({ added: ["fresh"], removed: ["old"], changed: [] });
const diff = objectDiff({ a: { x: 1 }, b: [1], c: null, d: 1 }, { a: 5, b: { 0: 1 }, c: { x: 1 }, d: { x: 1 } });
expect([...diff.changed].sort()).toEqual(["a", "b", "c", "d"]);
expect(diff.added).toEqual([]);
expect(diff.removed).toEqual([]);
expect(objectDiff({ a: undefined }, {})).toEqual({ added: [], removed: ["a"], changed: [] });
expect(objectDiff({}, { a: undefined })).toEqual({ added: ["a"], removed: [], changed: [] });
expect(objectDiff({ n: NaN, s: "1" }, { n: NaN, s: 1 })).toEqual({ added: [], removed: [], changed: ["s"] });
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with Object diff. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.