@winglet/json
Version:
TypeScript library for safe and efficient JSON data manipulation with RFC 6901 (JSON Pointer) and RFC 6902 (JSON Patch) compliance, featuring prototype pollution protection and immutable operations
114 lines (113 loc) • 4.07 kB
TypeScript
import type { JsonObject } from '../../../../type';
/**
* Generates an optimized JSON Merge Patch for transforming one object into another.
*
* This function implements a high-performance algorithm to create merge patches between two plain objects.
* It uses an intelligent two-phase approach to optimize the handling of array changes while minimizing
* redundant operations:
*
* **Phase 1 - Array Optimization**:
* - Detects paths that target array elements using `getArrayBasePath()`
* - For arrays with changes, replaces the entire array rather than individual element patches
* - Prevents redundant individual element operations when the whole array is being updated
* - Stores non-array patches for processing in phase 2
*
* **Phase 2 - Individual Patches**:
* - Processes remaining patches that don't affect arrays
* - Applies ADD, REPLACE, and REMOVE operations directly
* - Uses optimized JSON Pointer path manipulation
*
* The algorithm provides O(n) time complexity where n is the number of patches, with optimized
* space usage through single-pass processing and minimal intermediate allocations.
*
* @param source - The source object to transform from
* @param target - The target object to transform to
*
* @see https://datatracker.ietf.org/doc/html/rfc7396 - JSON Merge Patch specification
* @see https://datatracker.ietf.org/doc/html/rfc6901 - JSON Pointer specification
* @see https://datatracker.ietf.org/doc/html/rfc6902 - JSON Patch specification (used internally by compare())
*
* @returns A JSON Merge Patch object maintaining the original structure, or `undefined` if no changes are needed.
* The patch uses the following conventions:
* - Property additions/changes: nested object structure with new values
* - Property removals: nested object structure with `null` values
* - Array replacements: entire array as new value in structure
*
* @example
* ```typescript
* // Simple property changes
* const source = { name: "John", age: 30 };
* const target = { name: "John", age: 31, city: "NYC" };
*
* const patch = differenceObjectPatch(source, target);
* // Returns: { age: 31, city: "NYC" }
* ```
*
* @example
* ```typescript
* // Array optimization in action
* const source = { users: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }] };
* const target = { users: [{ id: 1, name: "Alice" }, { id: 2, name: "Bobby" }, { id: 3, name: "Charlie" }] };
*
* const patch = differenceObjectPatch(source, target);
* // Returns: { users: [{ id: 1, name: "Alice" }, { id: 2, name: "Bobby" }, { id: 3, name: "Charlie" }] }
* // Note: Entire array is replaced rather than individual element patches
* ```
*
* @example
* ```typescript
* // Mixed operations with nested structure
* const source = {
* user: { name: "Alice", age: 25 },
* settings: { theme: "dark", lang: "en" },
* deprecated: "old_feature"
* };
* const target = {
* user: { name: "Alice", age: 26 },
* settings: { theme: "light", lang: "en", notifications: true }
* };
*
* const patch = differenceObjectPatch(source, target);
* // Returns: {
* // user: { age: 26 },
* // settings: { theme: "light", notifications: true },
* // deprecated: null
* // }
* ```
*
* @example
* ```typescript
* // No changes scenario
* const source = { unchanged: "data" };
* const target = { unchanged: "data" };
*
* const patch = differenceObjectPatch(source, target);
* // Returns: undefined
* ```
*
* @example
* ```typescript
* // Nested array handling
* const source = {
* data: {
* items: [1, 2, 3],
* meta: { count: 3 }
* }
* };
* const target = {
* data: {
* items: [1, 2, 3, 4],
* meta: { count: 4, updated: true }
* }
* };
*
* const patch = differenceObjectPatch(source, target);
* // Returns: {
* // data: {
* // items: [1, 2, 3, 4],
* // meta: { count: 4, updated: true }
* // }
* // }
* ```
*/
export declare const differenceObjectPatch: (source: JsonObject, target: JsonObject) => JsonObject | undefined;