JSON structural diff with colorized output and fuzzy array matching
npx @tessl/cli install tessl/npm-json-diff@1.0.00
# JSON Diff
1
2
JSON Diff provides structural comparison of JSON objects and files with colorized, diff-like output. It features fuzzy matching of modified array elements, extensive configuration options, and both programmatic and command-line interfaces.
3
4
## Package Information
5
6
- **Package Name**: json-diff
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install json-diff`
10
- **Global Installation**: `npm install -g json-diff`
11
12
## Core Imports
13
14
```javascript
15
const { diff, diffString, colorize, colorizeToCallback } = require('json-diff');
16
```
17
18
ES6 module import:
19
20
```javascript
21
import { diff, diffString, colorize, colorizeToCallback } from 'json-diff';
22
```
23
24
Additional exports (from colorize module):
25
26
```javascript
27
const { colorizeToArray, colorizeToCallback } = require('json-diff/lib/colorize');
28
// or
29
import { colorizeToArray, colorizeToCallback } from 'json-diff/lib/colorize';
30
```
31
32
**Note**: `colorize` and `colorizeToCallback` are available from both the main module and the colorize module, but `colorizeToArray` is only available from the colorize module.
33
34
## Basic Usage
35
36
```javascript
37
const { diff, diffString } = require('json-diff');
38
39
// Basic comparison
40
const obj1 = { foo: 'bar', num: 1 };
41
const obj2 = { foo: 'baz', num: 1 };
42
43
// Get raw diff result
44
const diffResult = diff(obj1, obj2);
45
console.log(diffResult);
46
// Output: { foo: { __old: 'bar', __new: 'baz' } }
47
48
// Get colorized string output
49
const diffOutput = diffString(obj1, obj2);
50
console.log(diffOutput);
51
// Output:
52
// {
53
// - foo: "bar"
54
// + foo: "baz"
55
// }
56
57
// Array comparison with fuzzy matching
58
const arr1 = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
59
const arr2 = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Robert' }];
60
61
console.log(diffString(arr1, arr2));
62
```
63
64
## Command Line Usage
65
66
```bash
67
# Compare two JSON files
68
json-diff file1.json file2.json
69
70
# With options
71
json-diff --full --color file1.json file2.json
72
json-diff --raw-json --keys-only file1.json file2.json
73
```
74
75
## Capabilities
76
77
### Core Comparison
78
79
#### diff
80
81
Compares two JSON objects and returns the structural differences.
82
83
```javascript { .api }
84
/**
85
* Compare two JSON objects and return structural differences
86
* @param {any} obj1 - First object to compare
87
* @param {any} obj2 - Second object to compare
88
* @param {DiffOptions} options - Configuration options
89
* @returns {any|undefined} Difference object or undefined if objects are equal
90
*/
91
function diff(obj1, obj2, options = {});
92
93
interface DiffOptions {
94
/** Array of keys to always include in output even if unchanged */
95
outputKeys?: string[];
96
/** Array of keys to exclude from comparison */
97
excludeKeys?: string[];
98
/** Include equal sections of the document, not just deltas */
99
full?: boolean;
100
/** Compare only the keys, ignore the differences in values */
101
keysOnly?: boolean;
102
/** Include unchanged values in output instead of omitting them */
103
keepUnchangedValues?: boolean;
104
/** Output only the updated and new key/value pairs */
105
outputNewOnly?: boolean;
106
/** Sort primitive values in arrays before comparing */
107
sort?: boolean;
108
/** Round floating point numbers to specified decimal places before comparison */
109
precision?: number;
110
}
111
```
112
113
**Examples:**
114
115
```javascript
116
// Basic comparison
117
diff({ a: 1, b: 2 }, { a: 1, b: 3 });
118
// Returns: { b: { __old: 2, __new: 3 } }
119
120
// Full mode - includes unchanged values
121
diff({ a: 1, b: 2 }, { a: 1, b: 3 }, { full: true });
122
// Returns: { a: 1, b: { __old: 2, __new: 3 } }
123
124
// Keys only mode
125
diff({ a: 1, b: 2 }, { a: 1, b: 3 }, { keysOnly: true });
126
// Returns: undefined (same keys)
127
128
// Exclude specific keys
129
diff({ a: 1, b: 2, c: 3 }, { a: 1, b: 3, c: 4 }, { excludeKeys: ['c'] });
130
// Returns: { b: { __old: 2, __new: 3 } }
131
132
// Always output certain keys
133
diff({ a: 1, b: 2 }, { a: 1, b: 2 }, { outputKeys: ['a'] });
134
// Returns: { a: 1 }
135
136
// Precision rounding
137
diff({ pi: 3.14159 }, { pi: 3.14158 }, { precision: 3 });
138
// Returns: undefined (rounded values are equal)
139
```
140
141
#### diffString
142
143
Compares two JSON objects and returns a colorized string representation of the differences.
144
145
```javascript { .api }
146
/**
147
* Compare two JSON objects and return colorized string output
148
* @param {any} obj1 - First object to compare
149
* @param {any} obj2 - Second object to compare
150
* @param {DiffStringOptions} options - Display and comparison options
151
* @returns {string} Formatted, colorized string representation of differences
152
*/
153
function diffString(obj1, obj2, options = {});
154
155
interface DiffStringOptions extends DiffOptions {
156
/** Enable/disable colored output (default: true) */
157
color?: boolean;
158
/** Custom color theme object */
159
theme?: ColorTheme;
160
/** Maximum number of elisions to show before collapsing them */
161
maxElisions?: number;
162
}
163
164
interface ColorTheme {
165
' '?: (text: string) => string; // Unchanged content (default: identity function)
166
'+'?: (text: string) => string; // Added content (default: green)
167
'-'?: (text: string) => string; // Removed content (default: red)
168
}
169
```
170
171
**Examples:**
172
173
```javascript
174
// Colorized output (default)
175
diffString({ foo: 'bar' }, { foo: 'baz' });
176
177
// No colors
178
diffString({ foo: 'bar' }, { foo: 'baz' }, { color: false });
179
180
// Custom max elisions (default: Infinity)
181
diffString(largeArray1, largeArray2, { maxElisions: 3 });
182
// If more than 3 consecutive unchanged items, shows "... (N entries)" instead of individual "..."
183
184
// Full mode with no elisions limit
185
diffString(obj1, obj2, { full: true, maxElisions: Infinity });
186
```
187
188
### Output Formatting
189
190
#### colorize
191
192
Converts a diff result object into a formatted, colorized string.
193
194
```javascript { .api }
195
/**
196
* Convert diff result to colorized string output
197
* @param {any} diff - Diff result object from diff() function
198
* @param {ColorizeOptions} options - Display options
199
* @returns {string} Formatted, colorized string
200
*/
201
function colorize(diff, options = {});
202
203
interface ColorizeOptions {
204
/** Enable/disable colored output (default: true) */
205
color?: boolean;
206
/** Custom color theme object */
207
theme?: ColorTheme;
208
/** Maximum number of elisions to show before collapsing them */
209
maxElisions?: number;
210
}
211
```
212
213
**Example:**
214
215
```javascript
216
const diffResult = diff({ foo: 'bar' }, { foo: 'baz' });
217
const colorized = colorize(diffResult, { color: true });
218
console.log(colorized);
219
```
220
221
#### colorizeToCallback
222
223
Converts a diff result object to colorized output using a callback function for each line.
224
225
```javascript { .api }
226
/**
227
* Convert diff result to colorized output using callback
228
* @param {any} diff - Diff result object
229
* @param {ColorizeOptions} options - Display options
230
* @param {ColorizeCallback} output - Callback function to handle output lines
231
* @returns {void}
232
*/
233
function colorizeToCallback(diff, options, output);
234
235
type ColorizeCallback = (color: string, line: string) => void;
236
```
237
238
**Example:**
239
240
```javascript
241
const lines = [];
242
const diffResult = diff({ foo: 'bar' }, { foo: 'baz' });
243
244
colorizeToCallback(diffResult, { color: false }, (color, line) => {
245
lines.push(`${color}${line}`);
246
});
247
248
console.log(lines.join('\n'));
249
```
250
251
#### colorizeToArray
252
253
Converts a diff result object to an array of colorized strings (available directly from colorize module).
254
255
```javascript { .api }
256
/**
257
* Convert diff result to array of colorized lines
258
* @param {any} diff - Diff result object from diff() function
259
* @param {ColorizeOptions} options - Display options (optional)
260
* @returns {string[]} Array of formatted, colorized strings
261
*/
262
function colorizeToArray(diff, options = {});
263
```
264
265
**Note**: This function is exported from `json-diff/lib/colorize` but not from the main module.
266
267
**Example:**
268
269
```javascript
270
const { colorizeToArray } = require('json-diff/lib/colorize');
271
const diffResult = diff({ foo: 'bar' }, { foo: 'baz' });
272
const lines = colorizeToArray(diffResult, { color: false });
273
console.log(lines);
274
// Output: [' {', '- foo: "bar"', '+ foo: "baz"', ' }']
275
```
276
277
## CLI Interface
278
279
The `json-diff` command provides a command-line interface for comparing JSON files.
280
281
```bash { .api }
282
# Usage
283
json-diff [options] <first.json> <second.json>
284
285
# Arguments:
286
# <first.json> Old file (required)
287
# <second.json> New file (required)
288
289
# General Options:
290
# -v, --verbose Output progress info
291
# -C, --[no-]color Colored output (auto-detected from TTY)
292
# -j, --raw-json Display raw JSON encoding of the diff
293
# -f, --full Include equal sections of document, not just deltas
294
# --max-elisions COUNT Max number of ...s to show in a row in "deltas" mode (before collapsing them)
295
296
# Filtering Options:
297
# -o, --output-keys KEYS Always print comma-separated keys with their value, if they are part of an object with any diff
298
# -x, --exclude-keys KEYS Exclude comma-separated keys from comparison on both files
299
# -n, --output-new-only Output only updated and new key/value pairs (without marking them as such)
300
301
# Comparison Options:
302
# -s, --sort Sort primitive values in arrays before comparing
303
# -k, --keys-only Compare only the keys, ignore differences in values
304
# -K, --keep-unchanged-values Instead of omitting values that are equal, output them as they are
305
# -p, --precision DECIMALS Round all floating point numbers to this number of decimal places prior to comparison
306
307
# Exit Codes:
308
# 0 No differences found
309
# 1 Differences found
310
```
311
312
**Examples:**
313
314
```bash
315
# Basic comparison (colors auto-detected based on TTY)
316
json-diff a.json b.json
317
318
# Full output with explicit colors
319
json-diff --full --color a.json b.json
320
321
# Force no colors
322
json-diff --no-color a.json b.json
323
324
# Raw JSON output only
325
json-diff --raw-json a.json b.json
326
327
# Compare only structure, not values
328
json-diff --keys-only a.json b.json
329
330
# Exclude timestamps from comparison
331
json-diff --exclude-keys timestamp,updatedAt a.json b.json
332
333
# Always show id field even if unchanged (requires --full or changes in object)
334
json-diff --output-keys id a.json b.json
335
```
336
337
## Output Format
338
339
### Raw JSON Mode
340
341
When using the `diff()` function or `--raw-json` CLI flag:
342
343
#### Object Changes
344
- **Scalar value changes**: `{ "key": { "__old": oldValue, "__new": newValue } }`
345
- **Deleted keys**: `{ "key__deleted": deletedValue }`
346
- **Added keys**: `{ "key__added": newValue }`
347
348
#### Array Changes
349
- **Array elements**: Transformed into 2-tuples `[operation, value]`
350
- **Operations**: `" "` (unchanged), `"+"` (added), `"-"` (deleted), `"~"` (modified)
351
- **Unchanged elements in delta mode**: `[" "]` (value omitted)
352
- **Unchanged elements in full mode**: `[" ", value]`
353
354
**Examples:**
355
356
```javascript
357
// Object with changed value
358
diff({ name: "John" }, { name: "Jane" });
359
// Result: { name: { __old: "John", __new: "Jane" } }
360
361
// Object with added key
362
diff({ a: 1 }, { a: 1, b: 2 });
363
// Result: { b__added: 2 }
364
365
// Array with changes
366
diff([1, 2, 3], [1, 4, 3]);
367
// Result: [[" "], ["-", 2], ["+", 4], [" "]]
368
```
369
370
### Colorized String Mode
371
372
When using `diffString()` or CLI without `--raw-json`:
373
374
- **Green (+)**: Added elements
375
- **Red (-)**: Deleted elements
376
- **White**: Unchanged elements (in full mode)
377
- **Elisions**: Consecutive unchanged elements shown as `...`
378
379
## Advanced Features
380
381
### Fuzzy Array Matching
382
383
JSON Diff uses intelligent fuzzy matching for arrays containing objects. When array elements are modified, it attempts to match similar objects rather than treating them as separate additions and deletions.
384
385
```javascript
386
const before = [
387
{ id: 1, name: "Alice", role: "admin" },
388
{ id: 2, name: "Bob", role: "user" }
389
];
390
391
const after = [
392
{ id: 1, name: "Alice", role: "admin" },
393
{ id: 2, name: "Robert", role: "user" } // name changed
394
];
395
396
// Shows modification rather than delete + add
397
diffString(before, after);
398
// Output shows Bob -> Robert change, not full object replacement
399
```
400
401
### Precision Handling
402
403
For floating-point comparisons, use the `precision` option to avoid issues with floating-point representation:
404
405
```javascript
406
diff(
407
{ measurement: 3.14159265359 },
408
{ measurement: 3.14159265358 },
409
{ precision: 5 }
410
);
411
// Returns: undefined (equal when rounded to 5 decimal places)
412
```
413
414
### Error Handling
415
416
The library throws errors for:
417
- Invalid JSON input (when reading files in CLI)
418
- Internal consistency errors during array processing
419
- Invalid CLI arguments
420
421
All functions handle `null`, `undefined`, and various JavaScript types gracefully.
422
423
## Types Reference
424
425
```javascript { .api }
426
// Core diff result types
427
type DiffResult = any | undefined;
428
429
// Array diff tuple format
430
type ArrayDiffTuple = [' ' | '+' | '-' | '~', any] | [' '];
431
432
// Object change format for scalar values
433
interface ScalarChange {
434
__old: any;
435
__new: any;
436
}
437
438
// Object key change formats
439
interface ObjectKeyChange {
440
[key: `${string}__added`]: any; // Added keys
441
[key: `${string}__deleted`]: any; // Deleted keys
442
}
443
444
// Color operations used in diff output
445
type ColorOperation = ' ' | '+' | '-' | '~';
446
447
// CLI exit codes
448
const CLI_EXIT_CODES = {
449
NO_DIFFERENCES: 0, // Files are identical
450
DIFFERENCES_FOUND: 1 // Files have differences
451
};
452
453
// Extended types recognized by json-diff
454
type ExtendedType = 'null' | 'array' | 'date' | 'object' | 'string' | 'number' | 'boolean' | 'undefined';
455
```