0
# Options and Configuration
1
2
Comprehensive configuration system for customizing diff behavior including array handling, text diffing, property filtering, and output formatting.
3
4
## Capabilities
5
6
### Options Interface
7
8
Complete configuration interface for controlling diff, patch, and clone behavior.
9
10
```javascript { .api }
11
interface Options {
12
/** Custom hash function for object matching in arrays */
13
objectHash?: (item: object, index?: number) => string | undefined;
14
15
/** Match array items by position instead of content */
16
matchByPosition?: boolean;
17
18
/** Array-specific diffing options */
19
arrays?: {
20
/** Detect and represent item moves within arrays */
21
detectMove?: boolean;
22
/** Include moved item value in delta (not just index) */
23
includeValueOnMove?: boolean;
24
};
25
26
/** Text diffing configuration */
27
textDiff?: {
28
/** diff-match-patch instance for text diffing */
29
diffMatchPatch: typeof diff_match_patch;
30
/** Minimum string length to trigger text diffing */
31
minLength?: number;
32
};
33
34
/** Filter function to exclude properties from diffing */
35
propertyFilter?: (name: string, context: DiffContext) => boolean;
36
37
/** Control value cloning during diff operations */
38
cloneDiffValues?: boolean | ((value: unknown) => unknown);
39
40
/** Omit old values from deletion deltas */
41
omitRemovedValues?: boolean;
42
}
43
```
44
45
## Configuration Options
46
47
### Object Hash Function
48
49
Controls how objects are matched within arrays for optimal diff results.
50
51
```javascript { .api }
52
/**
53
* Custom hash function for object matching in arrays
54
* @param item - Object to generate hash for
55
* @param index - Position in array (optional)
56
* @returns Unique identifier string or undefined for position-based matching
57
*/
58
objectHash?: (item: object, index?: number) => string | undefined;
59
```
60
61
**Usage Examples:**
62
63
```javascript
64
import { create } from "jsondiffpatch";
65
66
// Match by ID field
67
const patcher = create({
68
objectHash: (obj) => obj.id ? String(obj.id) : undefined
69
});
70
71
const delta = patcher.diff(
72
[{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }],
73
[{ id: 2, name: "Bob", role: "admin" }, { id: 1, name: "Alice" }]
74
);
75
// Detects move of Alice and modification of Bob
76
77
// Multi-field hash
78
const complexPatcher = create({
79
objectHash: (obj, index) => {
80
if (obj.type === 'user' && obj.email) {
81
return `user:${obj.email}`;
82
}
83
if (obj.type === 'product' && obj.sku) {
84
return `product:${obj.sku}`;
85
}
86
return undefined; // Fall back to position matching
87
}
88
});
89
90
// Conditional hash based on context
91
const contextPatcher = create({
92
objectHash: (obj, index) => {
93
// Only use ID for large arrays to improve performance
94
if (index !== undefined && index > 100 && obj.id) {
95
return String(obj.id);
96
}
97
return undefined;
98
}
99
});
100
```
101
102
### Array Configuration
103
104
Controls array diffing behavior including move detection and value inclusion.
105
106
```javascript { .api }
107
arrays?: {
108
/** Detect and represent item moves within arrays */
109
detectMove?: boolean;
110
/** Include moved item value in delta (not just index) */
111
includeValueOnMove?: boolean;
112
};
113
```
114
115
**Usage Examples:**
116
117
```javascript
118
import { create } from "jsondiffpatch";
119
120
// Disable move detection for performance
121
const noMovePatcher = create({
122
arrays: {
123
detectMove: false
124
}
125
});
126
127
const delta1 = noMovePatcher.diff([1, 2, 3], [2, 3, 1]);
128
// Treats as delete + add instead of move
129
130
// Include values in move operations
131
const valueMovePatcher = create({
132
arrays: {
133
detectMove: true,
134
includeValueOnMove: true
135
}
136
});
137
138
const delta2 = valueMovePatcher.diff(
139
[{ name: "Alice" }, { name: "Bob" }],
140
[{ name: "Bob" }, { name: "Alice" }]
141
);
142
// Move delta includes the moved object value
143
144
// Position-based matching for simple arrays
145
const positionPatcher = create({
146
matchByPosition: true,
147
arrays: {
148
detectMove: false
149
}
150
});
151
152
const delta3 = positionPatcher.diff(["a", "b", "c"], ["x", "b", "c"]);
153
// Result: { 0: ["a", "x"] } - replaces first item
154
```
155
156
### Text Diff Configuration
157
158
Enables automatic text diffing for long strings using diff-match-patch algorithm.
159
160
```javascript { .api }
161
textDiff?: {
162
/** diff-match-patch instance for text diffing */
163
diffMatchPatch: typeof diff_match_patch;
164
/** Minimum string length to trigger text diffing */
165
minLength?: number;
166
};
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
import { create } from "jsondiffpatch";
173
import DiffMatchPatch from "diff-match-patch";
174
175
// Manual text diff configuration
176
const textPatcher = create({
177
textDiff: {
178
diffMatchPatch: DiffMatchPatch,
179
minLength: 50 // Only diff strings over 50 characters
180
}
181
});
182
183
const longText1 = "The quick brown fox jumps over the lazy dog. This is a longer text that will trigger text diffing.";
184
const longText2 = "The quick brown fox jumped over the lazy cat. This is a longer text that will trigger text diffing.";
185
186
const textDelta = textPatcher.diff({ content: longText1 }, { content: longText2 });
187
// Result includes text diff format instead of full string replacement
188
189
// Use with-text-diffs module for automatic setup
190
import { create as createWithText } from "jsondiffpatch/with-text-diffs";
191
192
const autoTextPatcher = createWithText({
193
textDiff: {
194
minLength: 30 // Override default minimum length
195
}
196
});
197
```
198
199
### Property Filtering
200
201
Excludes specific properties from diff operations based on custom logic.
202
203
```javascript { .api }
204
/**
205
* Filter function to exclude properties from diffing
206
* @param name - Property name being considered
207
* @param context - Diff context with left/right values and metadata
208
* @returns true to include property, false to exclude
209
*/
210
propertyFilter?: (name: string, context: DiffContext) => boolean;
211
```
212
213
**Usage Examples:**
214
215
```javascript
216
import { create } from "jsondiffpatch";
217
218
// Exclude private properties
219
const privatePatcher = create({
220
propertyFilter: (name) => !name.startsWith('_')
221
});
222
223
const delta1 = privatePatcher.diff(
224
{ name: "Alice", _internal: "secret1" },
225
{ name: "Bob", _internal: "secret2" }
226
);
227
// Result: { name: ["Alice", "Bob"] } - _internal ignored
228
229
// Contextual filtering
230
const contextPatcher = create({
231
propertyFilter: (name, context) => {
232
// Skip metadata for temporary objects
233
if (name === 'metadata' && context.left?.type === 'temp') {
234
return false;
235
}
236
237
// Skip computed properties that depend on other changes
238
if (name === 'computed' && (context.left?.dirty || context.right?.dirty)) {
239
return false;
240
}
241
242
// Skip large arrays in certain contexts
243
if (name === 'items' && Array.isArray(context.left?.[name]) &&
244
context.left[name].length > 1000) {
245
return false;
246
}
247
248
return true;
249
}
250
});
251
252
// Performance-focused filtering
253
const perfPatcher = create({
254
propertyFilter: (name, context) => {
255
// Skip deep object diffing for performance
256
const leftValue = context.left?.[name];
257
const rightValue = context.right?.[name];
258
259
if (typeof leftValue === 'object' && typeof rightValue === 'object' &&
260
leftValue && rightValue && Object.keys(leftValue).length > 50) {
261
return false;
262
}
263
264
return true;
265
}
266
});
267
```
268
269
### Clone Configuration
270
271
Controls how values are cloned during diff and patch operations.
272
273
```javascript { .api }
274
/**
275
* Control value cloning during diff operations
276
* Can be boolean or custom clone function
277
*/
278
cloneDiffValues?: boolean | ((value: unknown) => unknown);
279
```
280
281
**Usage Examples:**
282
283
```javascript
284
import { create } from "jsondiffpatch";
285
286
// Disable cloning for performance (modifies original objects)
287
const noClonePatcher = create({
288
cloneDiffValues: false
289
});
290
291
// This will modify the original objects during patching
292
const original = { name: "Alice", tags: ["user"] };
293
const delta = { tags: { _t: "a", 1: ["admin"] } };
294
noClonePatcher.patch(original, delta);
295
console.log(original.tags); // ["user", "admin"] - original was modified
296
297
// Custom clone function
298
const customClonePatcher = create({
299
cloneDiffValues: (value) => {
300
// Custom cloning logic
301
if (value instanceof Date) {
302
return new Date(value.getTime());
303
}
304
if (Array.isArray(value)) {
305
return value.map(item => customClonePatcher.clone(item));
306
}
307
if (value && typeof value === 'object') {
308
const cloned = {};
309
for (const [key, val] of Object.entries(value)) {
310
if (key !== '_computed') { // Skip computed properties
311
cloned[key] = customClonePatcher.clone(val);
312
}
313
}
314
return cloned;
315
}
316
return value;
317
}
318
});
319
```
320
321
### Remove Value Configuration
322
323
Controls whether deleted values are included in deletion deltas.
324
325
```javascript { .api }
326
/**
327
* Omit old values from deletion deltas
328
* Reduces delta size at cost of losing delete value information
329
*/
330
omitRemovedValues?: boolean;
331
```
332
333
**Usage Examples:**
334
335
```javascript
336
import { create } from "jsondiffpatch";
337
338
// Standard behavior (includes removed values)
339
const standardPatcher = create();
340
const delta1 = standardPatcher.diff(
341
{ name: "Alice", age: 25, role: "user" },
342
{ name: "Alice", age: 26 }
343
);
344
// Result: { age: [25, 26], role: ["user", 0, 0] }
345
346
// Omit removed values for smaller deltas
347
const omitPatcher = create({
348
omitRemovedValues: true
349
});
350
const delta2 = omitPatcher.diff(
351
{ name: "Alice", age: 25, role: "user" },
352
{ name: "Alice", age: 26 }
353
);
354
// Result: { age: [25, 26], role: [0, 0] } - removed value not stored
355
356
// Useful for large objects where removed values are not needed
357
const largePatcher = create({
358
omitRemovedValues: true,
359
propertyFilter: (name) => !name.startsWith('temp_')
360
});
361
```
362
363
## Configuration Examples
364
365
### Performance-Optimized Configuration
366
367
```javascript
368
const perfPatcher = create({
369
arrays: {
370
detectMove: false // Disable expensive move detection
371
},
372
cloneDiffValues: false, // Disable cloning for speed
373
omitRemovedValues: true, // Reduce delta size
374
propertyFilter: (name) => {
375
// Skip expensive-to-diff properties
376
return !['computed', 'cache', 'metadata'].includes(name);
377
}
378
});
379
```
380
381
### Comprehensive Diff Configuration
382
383
```javascript
384
const comprehensivePatcher = create({
385
objectHash: (obj) => obj.id || obj.key || obj.name,
386
arrays: {
387
detectMove: true,
388
includeValueOnMove: true
389
},
390
textDiff: {
391
diffMatchPatch: DiffMatchPatch,
392
minLength: 40
393
},
394
cloneDiffValues: true,
395
propertyFilter: (name, context) => {
396
// Include all properties except truly private ones
397
return !name.startsWith('__');
398
}
399
});
400
```
401
402
### Minimal Delta Configuration
403
404
```javascript
405
const minimalPatcher = create({
406
omitRemovedValues: true,
407
arrays: {
408
detectMove: true,
409
includeValueOnMove: false // Omit values from moves
410
},
411
propertyFilter: (name, context) => {
412
// Only include changed properties that matter
413
const essential = ['id', 'name', 'status', 'value'];
414
return essential.includes(name) || !name.startsWith('meta');
415
}
416
});
417
```