UNPKG

@astech/deepdiff

Version:

A fast, lightweight TypeScript library for comparing deeply nested objects and detecting changes with detailed diff information.

262 lines (198 loc) 6.12 kB
# Deep Object Diff A fast, lightweight TypeScript library for comparing deeply nested objects and detecting changes with detailed diff information. ## Features - 🔍 **Deep Object Comparison** - Compare objects of any depth and complexity - 🚀 **High Performance** - Optimized with circular reference detection - 🎯 **Detailed Output** - Get precise information about what changed, where, and how - ⚙️ **Configurable** - Customize comparison behavior with options - 🛠️ **Utility Functions** - Built-in helpers for filtering and analyzing diffs - 📦 **Zero Dependencies** - Lightweight and tree-shakeable - 🎨 **TypeScript Support** - Full type safety and IntelliSense ## Installation ```bash npm install @astech/deepdiff ``` ## Basic Usage ```typescript import { compare } from "deepdiff"; const objA = { user: { name: "Alice", age: 30, hobbies: ["reading", "gaming"], }, }; const objB = { user: { name: "Alice Smith", age: 31, hobbies: ["reading", "hiking"], }, }; const diffs = compare(objA, objB); console.log(diffs); // Output: // [ // { // path: "user.name", // type: "changed", // before: "Alice", // after: "Alice Smith", // summary: 'Changed user.name from "Alice" to "Alice Smith"', // description: 'Field "user" → "name" changed from "Alice" to "Alice Smith".' // }, // { // path: "user.age", // type: "changed", // before: 30, // after: 31, // summary: "Changed user.age from 30 to 31", // description: 'Field "user" → "age" changed from 30 to 31.' // }, // { // path: "user.hobbies.[1]", // type: "changed", // before: "gaming", // after: "hiking", // summary: 'Changed user.hobbies.[1] from "gaming" to "hiking"', // description: 'Field "user" → "hobbies" → index 1 changed from "gaming" to "hiking".' // } // ] ``` ## Advanced Configuration ### Compare Options ```typescript import { compare, CompareOptions } from "deepdiff"; const options: CompareOptions = { // Include null/undefined values in the diff includeNulls: true, // Custom equality function customEqual: (a, b) => Math.abs(a - b) <= 1, // Maximum depth to traverse (prevents stack overflow) maxDepth: 10, // Keys to ignore during comparison ignoreKeys: ["timestamp", "id"], // Whether to ignore case for string comparisons ignoreCase: true, }; const diffs = compare(objA, objB, options); ``` ### Example Use Cases ```typescript // Ignore specific fields const diffs = compare(userA, userB, { ignoreKeys: ["lastModified", "version"], }); // Case-insensitive comparison const diffs = compare(configA, configB, { ignoreCase: true, }); // Custom tolerance for numbers const diffs = compare(dataA, dataB, { customEqual: (a, b) => { if (typeof a === "number" && typeof b === "number") { return Math.abs(a - b) < 0.01; // 1% tolerance } return a === b; }, }); ``` ## Utility Functions ### Filtering Diffs ```typescript import { compare, filterByType, groupByType } from "deepdiff"; const diffs = compare(objA, objB); // Filter by change type const added = filterByType(diffs, "added"); const removed = filterByType(diffs, "removed"); const changed = filterByType(diffs, "changed"); // Group all diffs by type const groups = groupByType(diffs); console.log(groups); // { // added: [...], // removed: [...], // changed: [...] // } ``` ### Summary Statistics ```typescript import { compare, getSummary } from "deepdiff"; const diffs = compare(objA, objB); const summary = getSummary(diffs); console.log(summary); // { // total: 5, // added: 2, // removed: 1, // changed: 2 // } ``` ### Quick Checks ```typescript import { compare, isDeepEqual, getChangedPaths } from "deepdiff"; // Check if objects are deeply equal const areEqual = isDeepEqual(objA, objB); // Get just the paths that changed const changedPaths = getChangedPaths(diffs); // ['user.name', 'user.age', 'user.hobbies.[1]'] ``` ## Error Handling The library provides clear error messages for invalid inputs: ```typescript // Missing objects compare(undefined, objB); // Error: "Both objects must be provided for comparison" // Non-objects compare("string", objB); // Error: "Both parameters must be objects for comparison" // Null values compare(null, objB); // Error: "Both objects must be provided for comparison" ``` ## Performance Features - **Circular Reference Detection**: Prevents infinite loops - **Depth Limiting**: Configurable maximum depth to prevent stack overflow - **Efficient Traversal**: Uses generators for memory efficiency - **Early Termination**: Stops comparison when objects are identical ## API Reference ### `compare(a, b, options?)` Main comparison function. **Parameters:** - `a` (object): First object to compare - `b` (object): Second object to compare - `options` (CompareOptions, optional): Configuration options **Returns:** `DiffResult[]` ### `CompareOptions` ```typescript interface CompareOptions { includeNulls?: boolean; // Include null/undefined values customEqual?: (a: any, b: any) => boolean; // Custom equality function maxDepth?: number; // Maximum traversal depth ignoreKeys?: string[]; // Keys to ignore ignoreCase?: boolean; // Case-insensitive string comparison } ``` ### `DiffResult` ```typescript interface DiffResult { path: string; // Dot-notation path to the change type: "added" | "removed" | "changed"; before?: any; // Previous value after?: any; // New value summary: string; // Human-readable summary description: string; // Detailed description } ``` ### Utility Functions - `filterByType(diffs, type)` - Filter diffs by change type - `groupByType(diffs)` - Group diffs by type - `getSummary(diffs)` - Get summary statistics - `isDeepEqual(a, b, options?)` - Check if objects are equal - `getChangedPaths(diffs)` - Get array of changed paths ## CLI Usage ```bash # Compare two JSON files npx deepdiff file1.json file2.json # Compare with options npx deepdiff file1.json file2.json --ignore-keys timestamp,id --max-depth 5 ``` ## License MIT