JSON diff & patch library with support for objects, arrays, text diffs, and multiple output formats
npx @tessl/cli install tessl/npm-jsondiffpatch@0.7.00
# jsondiffpatch
1
2
jsondiffpatch is a comprehensive JSON diff & patch library that detects differences between JavaScript objects and arrays, generates change deltas, and applies patches to transform objects from one state to another. It supports intelligent array diffing using LCS algorithm, multiple output formats, text diffing for strings, and extensive customization options.
3
4
## Package Information
5
6
- **Package Name**: jsondiffpatch
7
- **Package Type**: npm
8
- **Language**: TypeScript/JavaScript
9
- **Installation**: `npm install jsondiffpatch`
10
11
## Core Imports
12
13
```javascript
14
import { create, diff, patch, unpatch, reverse, clone, DiffPatcher } from "jsondiffpatch";
15
```
16
17
For text diff support:
18
19
```javascript
20
import { create, diff, patch, unpatch, reverse, clone, DiffPatcher } from "jsondiffpatch/with-text-diffs";
21
```
22
23
CommonJS:
24
25
```javascript
26
const { create, diff, patch, unpatch, reverse, clone, DiffPatcher } = require("jsondiffpatch");
27
```
28
29
## Basic Usage
30
31
```javascript
32
import { diff, patch, reverse } from "jsondiffpatch";
33
34
// Generate diff between two objects
35
const left = { name: "Alice", age: 25, active: true };
36
const right = { name: "Alice", age: 26, active: false, role: "admin" };
37
38
const delta = diff(left, right);
39
console.log(delta);
40
// { age: [25, 26], active: [true, false], role: ["admin"] }
41
42
// Apply patch to get target object
43
const result = patch(left, delta);
44
console.log(result);
45
// { name: "Alice", age: 26, active: false, role: "admin" }
46
47
// Reverse a patch
48
const reverseDelta = reverse(delta);
49
const original = patch(result, reverseDelta);
50
console.log(original);
51
// { name: "Alice", age: 25, active: true }
52
```
53
54
## Architecture
55
56
jsondiffpatch is built around several key components:
57
58
- **DiffPatcher Class**: Main class providing diff, patch, reverse, and utility operations
59
- **Processing Pipeline**: Filter-based architecture using pipes for extensible diff/patch operations
60
- **Context System**: Specialized contexts (DiffContext, PatchContext, ReverseContext) for each operation type
61
- **Delta Types**: Structured representation of changes (added, modified, deleted, moved, text diffs)
62
- **Formatters**: Multiple output formats including console, HTML, JSON Patch, and annotated formats
63
- **Filter System**: Modular filters for handling arrays, objects, text, dates, and trivial cases
64
65
## Capabilities
66
67
### Core Operations
68
69
Primary diff and patch operations for generating and applying changes between JavaScript values.
70
71
```javascript { .api }
72
function diff(left: unknown, right: unknown): Delta;
73
function patch(left: unknown, delta: Delta): unknown;
74
function unpatch(right: unknown, delta: Delta): unknown;
75
function reverse(delta: Delta): Delta;
76
function clone(value: unknown): unknown;
77
function create(options?: Options): DiffPatcher;
78
```
79
80
[Core Operations](./core-operations.md)
81
82
### DiffPatcher Class
83
84
Object-oriented interface providing full control over diff and patch operations with customizable options.
85
86
```javascript { .api }
87
class DiffPatcher {
88
constructor(options?: Options);
89
diff(left: unknown, right: unknown): Delta;
90
patch(left: unknown, delta: Delta): unknown;
91
unpatch(right: unknown, delta: Delta): unknown;
92
reverse(delta: Delta): Delta;
93
clone(value: unknown): unknown;
94
options(options?: Options): Options;
95
}
96
```
97
98
[DiffPatcher Class](./diffpatcher-class.md)
99
100
### Formatters
101
102
Multiple output formats for visualizing and processing diffs including console output, HTML visualization, JSON Patch compatibility, and annotated formatting.
103
104
```javascript { .api }
105
// Console formatter
106
import * as console from "jsondiffpatch/formatters/console";
107
function format(delta: Delta, left?: unknown): string;
108
function log(delta: Delta, left?: unknown): void;
109
110
// HTML formatter
111
import * as html from "jsondiffpatch/formatters/html";
112
function format(delta: Delta, left?: unknown): string;
113
function showUnchanged(show?: boolean, node?: Element, delay?: number): void;
114
function hideUnchanged(node?: Element, delay?: number): void;
115
116
// JSON Patch formatter
117
import * as jsonpatch from "jsondiffpatch/formatters/jsonpatch";
118
function format(delta: Delta): Op[];
119
function patch(target: unknown, operations: Op[]): void;
120
121
// Annotated formatter
122
import * as annotated from "jsondiffpatch/formatters/annotated";
123
function format(delta: Delta, left?: unknown): string;
124
```
125
126
[Formatters](./formatters.md)
127
128
### Options and Configuration
129
130
Comprehensive configuration system for customizing diff behavior including array handling, text diffing, property filtering, and output formatting.
131
132
```javascript { .api }
133
interface Options {
134
objectHash?: (item: object, index?: number) => string | undefined;
135
matchByPosition?: boolean;
136
arrays?: {
137
detectMove?: boolean;
138
includeValueOnMove?: boolean;
139
};
140
textDiff?: {
141
diffMatchPatch: typeof diff_match_patch;
142
minLength?: number;
143
};
144
propertyFilter?: (name: string, context: DiffContext) => boolean;
145
cloneDiffValues?: boolean | ((value: unknown) => unknown);
146
omitRemovedValues?: boolean;
147
}
148
```
149
150
[Options and Configuration](./options-configuration.md)
151
152
## Delta Types
153
154
jsondiffpatch uses structured delta objects to represent different types of changes:
155
156
```javascript { .api }
157
type Delta = AddedDelta | ModifiedDelta | DeletedDelta | ObjectDelta | ArrayDelta | MovedDelta | TextDiffDelta | undefined;
158
159
// Basic change types
160
type AddedDelta = [unknown]; // [newValue]
161
type ModifiedDelta = [unknown, unknown]; // [oldValue, newValue]
162
type DeletedDelta = [unknown, 0, 0]; // [oldValue, 0, 0]
163
164
// Complex change types
165
type MovedDelta = [unknown, number, 3]; // [value, newIndex, 3]
166
type TextDiffDelta = [string, 0, 2]; // [diffString, 0, 2]
167
interface ObjectDelta { [property: string]: Delta; }
168
interface ArrayDelta { _t: "a"; [index: number | `${number}`]: Delta; }
169
```
170
171
### Type Guards
172
173
```javascript { .api }
174
function isAddedDelta(delta: Delta): delta is AddedDelta;
175
function isModifiedDelta(delta: Delta): delta is ModifiedDelta;
176
function isDeletedDelta(delta: Delta): delta is DeletedDelta;
177
function isObjectDelta(delta: Delta): delta is ObjectDelta;
178
function isArrayDelta(delta: Delta): delta is ArrayDelta;
179
function isMovedDelta(delta: Delta): delta is MovedDelta;
180
function isTextDiffDelta(delta: Delta): delta is TextDiffDelta;
181
```
182
183
## Context Types
184
185
Context objects provide state and configuration for diff, patch, and reverse operations. These are primarily used when creating custom filters or advanced pipeline customization.
186
187
```javascript { .api }
188
// Base context class
189
abstract class Context<TResult> {
190
abstract pipe: string;
191
result?: TResult;
192
hasResult?: boolean;
193
exiting?: boolean;
194
parent?: Context<TResult>;
195
childName?: string | number;
196
root?: Context<TResult>;
197
options?: Options;
198
children?: Context<TResult>[];
199
nextAfterChildren?: Context<TResult> | null;
200
next?: Context<TResult> | null;
201
202
setResult(result: TResult): this;
203
exit(): this;
204
push(child: Context<TResult>, name?: string | number): this;
205
}
206
207
// Diff operation context
208
class DiffContext extends Context<Delta> {
209
pipe: "diff";
210
left: unknown;
211
right: unknown;
212
leftType?: string;
213
rightType?: string;
214
leftIsArray?: boolean;
215
rightIsArray?: boolean;
216
217
constructor(left: unknown, right: unknown);
218
prepareDeltaResult<T extends Delta>(result: T): T;
219
setResult(result: Delta): this;
220
}
221
222
// Patch operation context
223
class PatchContext extends Context<unknown> {
224
pipe: "patch";
225
left: unknown;
226
delta: Delta;
227
228
constructor(left: unknown, delta: Delta);
229
}
230
231
// Reverse operation context
232
class ReverseContext extends Context<Delta> {
233
pipe: "reverse";
234
delta: Delta;
235
236
constructor(delta: Delta);
237
}
238
```
239
240
**Usage in Custom Filters:**
241
242
```javascript
243
import { DiffContext, PatchContext, ReverseContext } from "jsondiffpatch";
244
245
// Example custom filter
246
const customFilter = (context) => {
247
if (context.pipe === "diff") {
248
const diffCtx = context; // DiffContext
249
console.log(`Diffing: ${typeof diffCtx.left} -> ${typeof diffCtx.right}`);
250
251
// Access parent context for nested operations
252
if (diffCtx.parent) {
253
console.log(`Parent operation: ${diffCtx.parent.pipe}`);
254
}
255
256
// Set custom result
257
if (diffCtx.left === diffCtx.right) {
258
diffCtx.setResult(undefined); // No difference
259
diffCtx.exit(); // Skip further processing
260
}
261
}
262
};
263
264
// Context hierarchy for nested objects
265
const result = diff({ user: { name: "Alice" } }, { user: { name: "Bob" } });
266
// Creates nested DiffContext instances:
267
// - Root context for entire object
268
// - Child context for 'user' property
269
// - Child context for 'name' property
270
```
271
272
## Utilities
273
274
```javascript { .api }
275
/**
276
* JSON.parse reviver function for converting ISO date strings back to Date objects
277
* Handles ISO 8601 format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ss±HH:mm
278
* @param key - Property key (unused)
279
* @param value - Property value to potentially revive
280
* @returns Date object if value matches ISO date pattern, otherwise original value
281
*/
282
function dateReviver(key: string, value: unknown): unknown;
283
284
/**
285
* Create deep clone of any value using the default DiffPatcher instance
286
* @param value - Value to clone
287
* @returns Deep cloned copy
288
*/
289
function clone(value: unknown): unknown;
290
```
291
292
**Date Reviver Usage:**
293
294
```javascript
295
import { dateReviver } from "jsondiffpatch";
296
297
// Parse JSON with automatic date revival
298
const jsonString = '{"created": "2023-12-25T10:30:00.000Z", "name": "example"}';
299
const parsed = JSON.parse(jsonString, dateReviver);
300
301
console.log(parsed.created instanceof Date); // true
302
console.log(parsed.created.getFullYear()); // 2023
303
console.log(parsed.name); // "example" (unchanged)
304
305
// Handles various ISO 8601 formats
306
const formats = [
307
"2023-12-25T10:30:00Z", // UTC
308
"2023-12-25T10:30:00.123Z", // UTC with milliseconds
309
"2023-12-25T10:30:00+05:30", // Timezone offset
310
"2023-12-25T10:30:00-08:00" // Negative timezone
311
];
312
313
formats.forEach(dateStr => {
314
const result = dateReviver("", dateStr);
315
console.log(result instanceof Date); // true for all
316
});
317
```
318
319
## CLI Tool
320
321
jsondiffpatch includes a command-line interface for diffing JSON files with support for HTTP URLs and multiple output formats:
322
323
```bash
324
jsondiffpatch left.json right.json [options]
325
```
326
327
**Options:**
328
329
- `--format=console|json|json-compact|jsonpatch` - Output format (default: console)
330
- `--omit-removed-values` - Exclude removed values from output (makes diffs irreversible)
331
- `--no-moves` - Disable array move detection (improves performance on large arrays)
332
- `--no-text-diff` - Disable text diffing for long strings
333
- `--object-keys=prop1,prop2` - Object matching keys for arrays (default: id,key)
334
- `--help` - Show usage information with example output
335
336
**Exit Codes:**
337
338
- `0` - No differences found between files
339
- `1` - Differences found (standard for diff tools)
340
- `2` - Error occurred (invalid arguments, file not found, etc.)
341
342
**Input Sources:**
343
344
- Local JSON files: `file1.json file2.json`
345
- HTTP/HTTPS URLs: Automatically fetches and parses JSON from URLs
346
- Mixed sources: `local.json https://api.example.com/data`
347
348
**Usage Examples:**
349
350
```bash
351
# Basic diff with colorized console output
352
jsondiffpatch file1.json file2.json
353
354
# Raw JSON delta output
355
jsondiffpatch file1.json file2.json --format=json
356
357
# Compact JSON (single line)
358
jsondiffpatch file1.json file2.json --format=json-compact
359
360
# RFC 6902 JSON Patch format
361
jsondiffpatch file1.json file2.json --format=jsonpatch
362
363
# Disable move detection for performance
364
jsondiffpatch large1.json large2.json --no-moves
365
366
# Compare remote APIs
367
jsondiffpatch https://api.example.com/v1 https://api.example.com/v2
368
369
# Object matching by specific keys (for array elements)
370
jsondiffpatch users1.json users2.json --object-keys=id,email
371
372
# Omit old values (smaller output, cannot reverse)
373
jsondiffpatch old.json new.json --omit-removed-values
374
375
# Help with live demo
376
jsondiffpatch --help
377
```
378
379
**Default Behavior:**
380
381
- Uses text diffing by default (via `jsondiffpatch/with-text-diffs`)
382
- Array objects matched by `id` or `key` properties first, then by position
383
- Move detection enabled for arrays
384
- Console output with ANSI colors for terminal display