json-diff-ts 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/lib/jsonDiff.d.ts +8 -0
- package/lib/jsonDiff.js +28 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,6 +119,18 @@ Paths can be utilized to identify keys within nested arrays.
|
|
|
119
119
|
const diffs = diff(oldData, newData, { characters.subarray: 'id' });
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
Alternative Syntax
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const diffs = diff(oldData, newData, { 'characters.subarray': 'id' });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
You can also designate the root by using '.' instead of an empty string ('').
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
const diffs = diff(oldData, newData, { '.characters.subarray': 'id' });
|
|
132
|
+
```
|
|
133
|
+
|
|
122
134
|
You can use a function to dynamically resolve the key of the object.
|
|
123
135
|
The first parameter is the object and the second is to signal if the function should return the key name instead of the value. This is needed to flatten the changeset
|
|
124
136
|
|
|
@@ -238,6 +250,7 @@ Discover more about the company behind this project: [hololux](https://hololux.c
|
|
|
238
250
|
|
|
239
251
|
## Release Notes
|
|
240
252
|
|
|
253
|
+
- **v2.1.0:** Resolves a problem related to JSON Path filters by replacing the single equal sign (=) with a double equal sign (==). This update maintains compatibility with existing flat changes. Allows to use either '' or '.' as root in the path.
|
|
241
254
|
- **v2.0.0:** json-diff-ts has been upgraded to an ECMAScript module! This major update brings optimizations and enhanced documentation. Additionally, a previously existing issue where all paths were treated as regex has been fixed. In this new version, you'll need to use a Map instead of a Record for regex paths. Please note that this is a breaking change if you were using regex paths in the previous versions.
|
|
242
255
|
- **v1.2.6:** Enhanced JSON Path handling for period-inclusive segments.
|
|
243
256
|
- **v1.2.5:** Patched dependencies; added key name resolution support for key functions.
|
package/lib/jsonDiff.d.ts
CHANGED
|
@@ -23,6 +23,14 @@ export interface IFlatChange {
|
|
|
23
23
|
value?: any;
|
|
24
24
|
oldValue?: any;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Computes the difference between two objects.
|
|
28
|
+
*
|
|
29
|
+
* @param {any} oldObj - The original object.
|
|
30
|
+
* @param {any} newObj - The updated object.
|
|
31
|
+
* @param {EmbeddedObjKeysType | EmbeddedObjKeysMapType} embeddedObjKeys - An optional parameter specifying keys of embedded objects.
|
|
32
|
+
* @returns {IChange[]} - An array of changes that transform the old object into the new object.
|
|
33
|
+
*/
|
|
26
34
|
export declare function diff(oldObj: any, newObj: any, embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType): IChange[];
|
|
27
35
|
/**
|
|
28
36
|
* Applies all changes in the changeset to the object.
|
package/lib/jsonDiff.js
CHANGED
|
@@ -5,7 +5,26 @@ export var Operation;
|
|
|
5
5
|
Operation["ADD"] = "ADD";
|
|
6
6
|
Operation["UPDATE"] = "UPDATE";
|
|
7
7
|
})(Operation || (Operation = {}));
|
|
8
|
+
/**
|
|
9
|
+
* Computes the difference between two objects.
|
|
10
|
+
*
|
|
11
|
+
* @param {any} oldObj - The original object.
|
|
12
|
+
* @param {any} newObj - The updated object.
|
|
13
|
+
* @param {EmbeddedObjKeysType | EmbeddedObjKeysMapType} embeddedObjKeys - An optional parameter specifying keys of embedded objects.
|
|
14
|
+
* @returns {IChange[]} - An array of changes that transform the old object into the new object.
|
|
15
|
+
*/
|
|
8
16
|
export function diff(oldObj, newObj, embeddedObjKeys) {
|
|
17
|
+
// Trim leading '.' from keys in embeddedObjKeys
|
|
18
|
+
if (embeddedObjKeys instanceof Map) {
|
|
19
|
+
embeddedObjKeys = new Map(Array.from(embeddedObjKeys.entries()).map(([key, value]) => [
|
|
20
|
+
key instanceof RegExp ? key : key.replace(/^\./, ''),
|
|
21
|
+
value
|
|
22
|
+
]));
|
|
23
|
+
}
|
|
24
|
+
else if (embeddedObjKeys) {
|
|
25
|
+
embeddedObjKeys = Object.fromEntries(Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\./, ''), value]));
|
|
26
|
+
}
|
|
27
|
+
// Compare old and new objects to generate a list of changes
|
|
9
28
|
return compare(oldObj, newObj, [], embeddedObjKeys, []);
|
|
10
29
|
}
|
|
11
30
|
/**
|
|
@@ -115,14 +134,7 @@ export const unflattenChanges = (changes) => {
|
|
|
115
134
|
changes.forEach((change) => {
|
|
116
135
|
const obj = {};
|
|
117
136
|
let ptr = obj;
|
|
118
|
-
const segments = change.path.split(/([^@])
|
|
119
|
-
const x = Math.floor(i / 2);
|
|
120
|
-
if (!acc[x]) {
|
|
121
|
-
acc[x] = '';
|
|
122
|
-
}
|
|
123
|
-
acc[x] += curr;
|
|
124
|
-
return acc;
|
|
125
|
-
}, []);
|
|
137
|
+
const segments = change.path.split(/(?<=[^@])\.(?=[^@])/);
|
|
126
138
|
if (segments.length === 1) {
|
|
127
139
|
ptr.key = change.key;
|
|
128
140
|
ptr.type = change.type;
|
|
@@ -133,8 +145,8 @@ export const unflattenChanges = (changes) => {
|
|
|
133
145
|
else {
|
|
134
146
|
for (let i = 1; i < segments.length; i++) {
|
|
135
147
|
const segment = segments[i];
|
|
136
|
-
// Matches JSONPath segments: "items[?(@.id
|
|
137
|
-
const result = /^(.+)\[\?\(@\.(
|
|
148
|
+
// Matches JSONPath segments: "items[?(@.id=='123')]", items[?(@.id==123)], "items[2]"
|
|
149
|
+
const result = /^(.+)\[\?\(@\.([^=]+)={1,2}(?:'(.*)'|(\d+))\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
|
|
138
150
|
// array
|
|
139
151
|
if (result) {
|
|
140
152
|
let key;
|
|
@@ -146,9 +158,9 @@ export const unflattenChanges = (changes) => {
|
|
|
146
158
|
arrKey = result[3];
|
|
147
159
|
}
|
|
148
160
|
else {
|
|
149
|
-
key = result[
|
|
161
|
+
key = result[5];
|
|
150
162
|
embeddedKey = '$index';
|
|
151
|
-
arrKey = Number(result[
|
|
163
|
+
arrKey = Number(result[6]);
|
|
152
164
|
}
|
|
153
165
|
// leaf
|
|
154
166
|
if (i === segments.length - 1) {
|
|
@@ -454,7 +466,7 @@ const applyArrayChange = (arr, change) => (() => {
|
|
|
454
466
|
element = arr[subchange.key];
|
|
455
467
|
}
|
|
456
468
|
else {
|
|
457
|
-
element = find(arr, (el) => el[change.embeddedKey]
|
|
469
|
+
element = find(arr, (el) => el[change.embeddedKey]?.toString() === subchange.key.toString());
|
|
458
470
|
}
|
|
459
471
|
result.push(applyChangeset(element, subchange.changes));
|
|
460
472
|
}
|
|
@@ -513,7 +525,8 @@ function append(basePath, nextSegment) {
|
|
|
513
525
|
}
|
|
514
526
|
/** returns a JSON Path filter expression; e.g., `$.pet[(?name='spot')]` */
|
|
515
527
|
function filterExpression(basePath, filterKey, filterValue) {
|
|
528
|
+
const value = typeof filterValue === 'number' ? filterValue : `'${filterValue}'`;
|
|
516
529
|
return typeof filterKey === 'string' && filterKey.includes('.')
|
|
517
|
-
? `${basePath}[?(@[${filterKey}]
|
|
518
|
-
: `${basePath}[?(@.${filterKey}
|
|
530
|
+
? `${basePath}[?(@[${filterKey}]==${value})]`
|
|
531
|
+
: `${basePath}[?(@.${filterKey}==${value})]`;
|
|
519
532
|
}
|