API Reference
Everything is a named export from the package root:
import { diff, patch, diffWith, // functions DELETED, ADDED, CHANGED, INSERTED, REMOVED, // op-type constants } from "@opentf/obj-diff";
| Export | Kind | Summary |
|---|---|---|
diff | function | Deep-compare two values into a list of operations. |
patch | function | Apply a diff to reconstruct the target. |
diffWith | function | diff with a custom equality function. |
DiffResult | type | The shape of a single operation. |
| Op constants | const | DELETED, ADDED, CHANGED, INSERTED, REMOVED. |
diff
function diff(a: unknown, b: unknown): DiffResult[]
Performs a deep comparison and returns the list of operations that transform a into b. An empty array means the two values are deeply equal.
Parameters
| Name | Type | Description |
|---|---|---|
a | unknown | The source (original) value. |
b | unknown | The target value to compare against. |
Returns — DiffResult[], in application order.
diff({ a: 1 }, { a: 2 }); //=> [{ type: 2, path: ["a"], value: 2 }]
Compact array diffs
diff trims the common prefix and suffix of arrays and resolves the remaining middle with a bounded shortest-edit-script (Myers LCS) pass. Inserting one element at the front of a 10,000-element array produces 1 op, not 10,001:
diff([1, 2, 3], [0, 1, 2, 3]); //=> [{ type: 3, path: [0], value: 0 }] diff([1, 2, 3, 4], [1, 4]); //=> [{ type: 4, path: [1] }, { type: 4, path: [1] }]
INSERTED / REMOVED indexes are application-time (RFC 6902 style): apply the ops in order and each index is valid at the moment it is applied. When two arrays are too different (an internal edit-distance cap is exceeded), diff falls back to index-by-index comparison to bound worst-case time and memory.
patch
function patch(obj: unknown, patches: DiffResult[]): unknown
Applies a diff to obj and returns the reconstructed value. The round-trip always holds: patch(a, diff(a, b)) is deep-equal to b.
Parameters
| Name | Type | Description |
|---|---|---|
obj | unknown | The source value to apply the diff to. |
patches | DiffResult[] | A diff produced by diff or diffWith. |
Returns — the patched value.
const a = { a: 1 }; const b = { a: 2 }; patch(a, diff(a, b)); //=> { a: 2 }
Added and changed values are placed into the result by reference, not cloned. See Caveats for aliasing details.
diffWith
function diffWith( a: unknown, b: unknown, isChanged: (a: object, b: object) => boolean | undefined, ): DiffResult[]
Like diff, but you supply a comparator to override equality for specific object types (e.g. MongoDB ObjectId, custom classes).
Parameters
| Name | Type | Description |
|---|---|---|
a | unknown | The source value. |
b | unknown | The target value. |
isChanged | (a, b) => boolean | undefined | Return true/false to force the result, or undefined to fall back to the built-in comparison. Invoked only when both values are objects. |
Returns — DiffResult[].
import { diffWith } from "@opentf/obj-diff"; import { ObjectId } from "bson"; diffWith(recordA, recordB, (a, b) => { if (a instanceof ObjectId && b instanceof ObjectId) { return a.toString() !== b.toString(); } });
DiffResult type
type DiffResult = { type: 0 | 1 | 2 | 3 | 4; // see the op-type table below path: Array<unknown>; // path to the property; Map entries use the Map key itself value?: unknown; // the new value (present for ADDED, CHANGED, INSERTED) };
Op-type constants
| Value | Constant | Meaning | Applies to |
|---|---|---|---|
0 | DELETED | Key no longer exists (delete obj.k / map.delete(k); on an array index it leaves a hole). | objects, Maps, arrays (sparse) |
1 | ADDED | New key/value (on arrays: assign at index). | objects, Maps, Sets, arrays |
2 | CHANGED | Value replaced at the path. | all |
3 | INSERTED | Insert value at the index, shifting later elements right (splice(i, 0, v)). | arrays only |
4 | REMOVED | Remove the element at the index, shifting later elements left (splice(i, 1)). | arrays only |
import { DELETED, ADDED, CHANGED, INSERTED, REMOVED } from "@opentf/obj-diff"; diff(a, b).filter((op) => op.type === REMOVED);
An empty path ([]) denotes the root — the entire source was replaced by the target (e.g. comparing an object to null).