### Install Microdiff using npm Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Install the microdiff package using npm. This is the first step to using the library in your project. ```bash npm i microdiff ``` -------------------------------- ### Array Diff with microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Compares two arrays to detect elements that have been removed. This example shows a top-level array comparison. ```typescript import diff from "microdiff"; // ── Array diff (top-level) ───────────────────────────────────────────────── console.log(diff(["a", "b", "c"], ["a", "b"])); // [ { type: "REMOVE", path: [2], oldValue: "c" } ] ``` -------------------------------- ### Mixed Nesting Diff (Object to Array) with microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Compares data structures containing both objects and arrays at various nesting levels. This example demonstrates a change within an array element. ```typescript import diff from "microdiff"; // ── Mixed nesting: object → array → object ───────────────────────────────── const s1 = { items: [{ id: 1, active: true }, { id: 2, active: true }] }; const s2 = { items: [{ id: 1, active: true }, { id: 2, active: false }] }; console.log(diff(s1, s2)); // [ { type: "CHANGE", path: ["items", 1, "active"], value: false, oldValue: true } ] ``` -------------------------------- ### Run Microdiff Benchmarks Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Execute the benchmarking script to compare Microdiff's performance against other diffing libraries. This command builds the project first and then runs the benchmarks. ```bash npm run bench ``` -------------------------------- ### Run Microdiff Tests Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Execute the entire test suite for Microdiff. This command builds the project and then runs all tests to ensure correctness. It's recommended to add a test when fixing a bug. ```bash npm run test ``` -------------------------------- ### Microdiff Benchmark Results Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Comparison of Microdiff's performance against other diffing libraries. Lower percentages indicate better performance relative to Microdiff. ```text Geometric mean of time per operation relative to Microdiff (no cycles) (100%==equal time, lower is better) microdiff (no cycles): 100% microdiff: 149% deep-diff: 197% deep-object-diff: 288% jsDiff: 1565% ``` -------------------------------- ### Applying Diffs Manually with microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Demonstrates how to programmatically apply the differences generated by `microdiff` to a target object. Requires importing the `Difference` type. ```typescript import type { Difference } from "microdiff"; function applyDiff(target: Record, differences: Difference[]) { for (const d of differences) { let cursor: any = target; for (let i = 0; i < d.path.length - 1; i++) cursor = cursor[d.path[i]]; const last = d.path[d.path.length - 1]; if (d.type === "REMOVE") delete cursor[last]; else cursor[last] = d.value; } } const obj = { x: 1, y: 2 }; applyDiff(obj, diff(obj, { x: 1, y: 99, z: 3 })); console.log(obj); // { x: 1, y: 99, z: 3 } ``` -------------------------------- ### Build Microdiff Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Compile the Microdiff project to generate CommonJS and ESM modules in the `/dist` directory. This command is typically used during development or before contributing. ```bash npm run build ``` -------------------------------- ### Import and Use Microdiff in JavaScript Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Import the diff function from microdiff and use it to compare two objects. The output shows the changes detected between the objects. ```js import diff from "microdiff"; const obj1 = { originalProperty: true, }; const obj2 = { originalProperty: true, newProperty: "new", }; console.log(diff(obj1, obj2)); // [{type: "CREATE", path: ["newProperty"], value: "new"}] ``` -------------------------------- ### Basic Object Diff with microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Compares two simple objects to identify changes in properties. Requires importing the `diff` function. ```typescript import diff from "microdiff"; // ── Basic object diff ────────────────────────────────────────────────────── const before = { name: "Alice", age: 30, role: "user" }; const after = { name: "Alice", age: 31, role: "admin", verified: true }; console.log(diff(before, after)); // [ // { type: "CHANGE", path: ["age"], value: 31, oldValue: 30 }, // { type: "CHANGE", path: ["role"], value: "admin", oldValue: "user" }, // { type: "CREATE", path: ["verified"], value: true } // ] ``` -------------------------------- ### diff(obj, newObj, options?) Source: https://context7.com/asyncbanana/microdiff/llms.txt Recursively compares two objects or arrays and returns an array of Difference objects detailing changes, creations, and removals. ```APIDOC ## diff(obj, newObj, options?) ### Description Recursively walks `obj` and `newObj`, producing a `Difference[]` array. Each element is one of three shapes: `DifferenceCreate` (a key/index that exists only in `newObj`), `DifferenceRemove` (a key/index that exists only in `obj`), or `DifferenceChange` (a key/index present in both but with a different value). The `path` array on every difference gives the full key/index trail from the root to the changed value, using strings for object keys and numbers for array indices. ### Parameters #### Path Parameters - **obj** (object | array) - Required - The original object or array to compare. - **newObj** (object | array) - Required - The new object or array to compare against. - **options** (object) - Optional - Configuration options for the diffing process. ### Request Example ```javascript import diff from "microdiff"; const before = { name: "Alice", age: 30, role: "user" }; const after = { name: "Alice", age: 31, role: "admin", verified: true }; console.log(diff(before, after)); // Expected output: // [ // { type: "CHANGE", path: ["age"], value: 31, oldValue: 30 }, // { type: "CHANGE", path: ["role"], value: "admin", oldValue: "user" }, // { type: "CREATE", path: ["verified"], value: true } // ] ``` ### Response #### Success Response (200) - **Difference[]** - An array of difference objects. Each object has a `type` (CREATE, REMOVE, CHANGE), a `path` (array of keys/indices), and potentially `value` and `oldValue`. #### Response Example ```json [ { "type": "CHANGE", "path": ["age"], "value": 31, "oldValue": 30 }, { "type": "CHANGE", "path": ["role"], "value": "admin", "oldValue": "user" }, { "type": "CREATE", "path": ["verified"], "value": true } ] ``` ``` -------------------------------- ### Import Microdiff in CommonJS Source: https://github.com/asyncbanana/microdiff/blob/master/README.md Import the default export of microdiff when using CommonJS module system. ```js const diff = require("microdiff").default; ``` -------------------------------- ### Handle Added Properties with `DifferenceCreate` Source: https://context7.com/asyncbanana/microdiff/llms.txt Use `DifferenceCreate` to identify properties or elements that exist in the new object but not the original. The `path` indicates the location and `value` holds the new content. ```typescript import diff from "microdiff"; import type { DifferenceCreate } from "microdiff"; const before = { settings: { theme: "dark" } }; const after = { settings: { theme: "dark", language: "en", notifications: { email: true } } }; const changes = diff(before, after); // Filter for creations only const creations = changes.filter((d): d is DifferenceCreate => d.type === "CREATE"); console.log(creations); // [ // { type: "CREATE", path: ["settings", "language"], value: "en" }, // { type: "CREATE", path: ["settings", "notifications", "email"], value: true } // ] // Practical use — build an audit log of new fields function describeCreations(diffs: DifferenceCreate[]): string[] { return diffs.map(d => `Added "${d.path.join(".")}" = ${JSON.stringify(d.value)}`); } console.log(describeCreations(creations)); // [ 'Added "settings.language" = "en"', // 'Added "settings.notifications.email" = true' ] ``` -------------------------------- ### Compare Temporal API Types with Microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Microdiff compares Temporal API types using their toString() representation when the Temporal global is available. This ensures semantically equal instants are treated as equal. ```typescript import diff from "microdiff"; // Requires: node --harmony-temporal (or a runtime with native Temporal) // ── PlainDate ────────────────────────────────────────────────────────────── diff( { date: Temporal.PlainDate.from("2024-01-01") }, { date: Temporal.PlainDate.from("2024-01-01") } ); // [] diff( { date: Temporal.PlainDate.from("2024-01-01") }, { date: Temporal.PlainDate.from("2024-12-31") } ); // [ { type: "CHANGE", path: ["date"], value: PlainDate("2024-12-31"), oldValue: PlainDate("2024-01-01") } ] // ── Instant ──────────────────────────────────────────────────────────────── diff( { ts: Temporal.Instant.from("2024-01-01T00:00:00Z") }, { ts: Temporal.Instant.from("2024-01-01T00:00:01Z") } ); // [ { type: "CHANGE", path: ["ts"], value: ..., oldValue: ... } ] // ── Duration ─────────────────────────────────────────────────────────────── diff( { ttl: Temporal.Duration.from({ hours: 1 }) }, { ttl: Temporal.Duration.from({ hours: 2 }) } ); // [ { type: "CHANGE", path: ["ttl"], value: Duration("PT2H"), oldValue: Duration("PT1H") } ] // ── ZonedDateTime ────────────────────────────────────────────────────────── const zdt1 = Temporal.ZonedDateTime.from("2024-06-01T12:00:00+01:00[Europe/London]"); const zdt2 = Temporal.ZonedDateTime.from("2024-06-01T12:00:00+01:00[Europe/London]"); diff({ event: zdt1 }, { event: zdt2 }); // [] // ── Temporal value replaced with non-Temporal ────────────────────────────── diff( { start: Temporal.PlainDate.from("2024-01-01") }, { start: "2024-01-01" } ); // [ { type: "CHANGE", path: ["start"], value: "2024-01-01", oldValue: PlainDate("2024-01-01") } ] ``` -------------------------------- ### Compare Dates, RegExps, Boxed Primitives, and NaN with Microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Microdiff compares Date objects by timestamp, RegExp by string representation, and boxed primitives by coercion. NaN values are considered equal to themselves. ```typescript import diff from "microdiff"; // ── Date comparison ──────────────────────────────────────────────────────── diff({ ts: new Date("2024-01-01") }, { ts: new Date("2024-01-01") }); // [] — same timestamp, no diff diff({ ts: new Date("2024-01-01") }, { ts: new Date("2024-06-01") }); // [ { type: "CHANGE", path: ["ts"], value: Date("2024-06-01"), oldValue: Date("2024-01-01") } ] // ── RegExp comparison ────────────────────────────────────────────────────── diff({ pattern: /^\d+$/ }, { pattern: /^\d+$/ }); // [] diff({ pattern: /^\d+$/ }, { pattern: /^\w+$/i }); // [ { type: "CHANGE", ... } ] // ── NaN comparison (uses Object.is — NaN equals NaN) ────────────────────── diff({ val: NaN }, { val: NaN }); // [] diff({ val: NaN }, { val: 0 }); // [ { type: "CHANGE", path: ["val"], value: 0, oldValue: NaN } ] // ── Boxed primitives ─────────────────────────────────────────────────────── diff({ n: new Number(42) }, { n: new Number(42) }); // [] diff({ n: new Number(1) }, { n: new Number(2) }); // [ { type: "CHANGE", path: ["n"], value: Number(2), oldValue: Number(1) } ] // ── Type mismatch: Date vs string ────────────────────────────────────────── diff({ d: new Date(0) }, { d: "not a date" }); // [ { type: "CHANGE", path: ["d"], value: "not a date", oldValue: Date(0) } ] ``` -------------------------------- ### Nested Object Diff with microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Compares objects with nested structures to pinpoint changes deep within the data. The `path` property in the output reflects the nested keys. ```typescript import diff from "microdiff"; // ── Nested object diff ───────────────────────────────────────────────────── const v1 = { user: { address: { city: "NYC", zip: "10001" } } }; const v2 = { user: { address: { city: "LA", zip: "90001" } } }; console.log(diff(v1, v2)); // [ // { type: "CHANGE", path: ["user", "address", "city"], value: "LA", oldValue: "NYC" }, // { type: "CHANGE", path: ["user", "address", "zip"], value: "90001", oldValue: "10001" } // ] ``` -------------------------------- ### Disable Cycle Detection with `cyclesFix: false` Source: https://context7.com/asyncbanana/microdiff/llms.txt Set `cyclesFix: false` to disable cycle detection for performance gains when your data is known to be free of circular references, such as plain JSON. ```typescript import diff from "microdiff"; // ── Disable cycle detection for plain JSON payloads (faster) ─────────────── const apiResponse1 = { data: { count: 5, items: ["a", "b", "c", "d", "e"] } }; const apiResponse2 = { data: { count: 3, items: ["a", "b", "c"] } }; console.log(diff(apiResponse1, apiResponse2, { cyclesFix: false })); // [ // { type: "CHANGE", path: ["data", "count"], value: 3, oldValue: 5 }, // { type: "REMOVE", path: ["data", "items", 3], oldValue: "d" }, // { type: "REMOVE", path: ["data", "items", 4], oldValue: "e" } // ] // ── Cycle detection in action (cyclesFix: true, the default) ────────────── const node: any = { id: 1, children: [] }; node.self = node; // circular reference node.children.push(node); // circular reference in array // With cyclesFix: true the circular parts are simply skipped — no infinite loop console.log(diff(node, node)); // [] // With cyclesFix: false on a cyclic object → infinite loop / stack overflow // ⚠ DO NOT do this: // diff(node, node, { cyclesFix: false }); // UNSAFE — will crash ``` -------------------------------- ### Disable Cycle Support in Microdiff Source: https://github.com/asyncbanana/microdiff/blob/master/README.md When comparing objects that are known not to have cyclical references, you can disable cycle detection for potential performance improvements using the `cyclesFix` option. ```js diff(obj1, obj2, { cyclesFix: false }); ``` -------------------------------- ### TypeScript Type Narrowing with microdiff Source: https://context7.com/asyncbanana/microdiff/llms.txt Use the Difference union type with a switch statement to narrow down to specific change types (CREATE, REMOVE, CHANGE). This ensures type-safe access to properties like .value and .oldValue. ```typescript import diff from "microdiff"; import type { Difference, DifferenceCreate, DifferenceRemove, DifferenceChange } from "microdiff"; interface Config { version: number; features: string[]; meta: { author: string; tags: string[] }; } const oldCfg: Config = { version: 1, features: ["a", "b"], meta: { author: "Alice", tags: ["x"] } }; const newCfg: Config = { version: 2, features: ["a", "b", "c"], meta: { author: "Alice", tags: [] } }; const changes: Difference[] = diff( oldCfg as Record, newCfg as Record, { cyclesFix: false } ); for (const d of changes) { switch (d.type) { case "CREATE": // d is DifferenceCreate — has .value, no .oldValue console.log(`[+] ${d.path.join(".")} = ${JSON.stringify(d.value)}`); break; case "REMOVE": // d is DifferenceRemove — has .oldValue, no .value console.log(`[-] ${d.path.join(".")} was ${JSON.stringify(d.oldValue)}`); break; case "CHANGE": // d is DifferenceChange — has both .value and .oldValue console.log(`[~] ${d.path.join(".")}: ${JSON.stringify(d.oldValue)} → ${JSON.stringify(d.value)}`); break; } } // [~] version: 1 → 2 // [+] features.2 = "c" // [-] meta.tags.0 was "x" ``` -------------------------------- ### Handle Removed Properties with `DifferenceRemove` Source: https://context7.com/asyncbanana/microdiff/llms.txt Identify deleted properties or elements using `DifferenceRemove`, which signifies a key or index present in the original object but absent in the new one. The `path` points to the removed item, and `oldValue` contains its previous value. ```typescript import diff from "microdiff"; import type { DifferenceRemove } from "microdiff"; const v1Config = { db: { host: "localhost", port: 5432, legacy: true }, debug: true }; const v2Config = { db: { host: "localhost", port: 5432 } }; const changes = diff(v1Config, v2Config); const removals = changes.filter((d): d is DifferenceRemove => d.type === "REMOVE"); console.log(removals); // [ // { type: "REMOVE", path: ["db", "legacy"], oldValue: true }, // { type: "REMOVE", path: ["debug"], oldValue: true } // ] // Check whether a critical field was removed const criticalFields = ["debug", "auth"]; const removedCritical = removals.filter(d => criticalFields.includes(d.path[0] as string)); if (removedCritical.length) { console.warn("Critical fields removed:", removedCritical.map(d => d.path.join("."))); // Critical fields removed: [ 'debug' ] } ``` -------------------------------- ### Handle Mutated Values with `DifferenceChange` Source: https://context7.com/asyncbanana/microdiff/llms.txt Use `DifferenceChange` to detect when a property or element exists in both objects but has a different value. Both the new `value` and the `oldValue` are provided for before-and-after comparisons. ```typescript import diff from "microdiff"; import type { DifferenceChange } from "microdiff"; const oldUser = { id: 42, name: "Bob", score: 100, status: "active" }; const newUser = { id: 42, name: "Robert", score: 150, status: "active" }; const changes = diff(oldUser, newUser); const mutations = changes.filter((d): d is DifferenceChange => d.type === "CHANGE"); console.log(mutations); // [ // { type: "CHANGE", path: ["name"], value: "Robert", oldValue: "Bob" }, // { type: "CHANGE", path: ["score"], value: 150, oldValue: 100 } // ] // Generate a human-readable changelog function changelog(diffs: DifferenceChange[]): string { return diffs .map(d => `${d.path.join(".")}: ${JSON.stringify(d.oldValue)} → ${JSON.stringify(d.value)}`) .join("\n"); } console.log(changelog(mutations)); // name: "Bob" → "Robert" // score: 100 → 150 ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.