json-diff-ts 3.0.0 → 4.0.0-beta.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 +22 -12
- package/dist/index.cjs +105 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -14
- package/dist/index.d.ts +19 -14
- package/dist/index.js +103 -53
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ In CommonJS, you can import the diff function like this:
|
|
|
28
28
|
|
|
29
29
|
```javascript
|
|
30
30
|
const { diff } = require('json-diff-ts');
|
|
31
|
-
```
|
|
31
|
+
```
|
|
32
32
|
|
|
33
33
|
## Capabilities
|
|
34
34
|
|
|
@@ -132,13 +132,19 @@ const expectedDiffs = [
|
|
|
132
132
|
Paths can be utilized to identify keys within nested arrays.
|
|
133
133
|
|
|
134
134
|
```javascript
|
|
135
|
-
const diffs = diff(oldData, newData, { 'characters.subarray': 'id' });
|
|
135
|
+
const diffs = diff(oldData, newData, { embeddedObjKeys { 'characters.subarray': 'id' }});
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
You can also designate the root by using '.' instead of an empty string ('').
|
|
139
139
|
|
|
140
140
|
```javascript
|
|
141
|
-
const diffs = diff(oldData, newData, { '.characters.subarray': 'id' });
|
|
141
|
+
const diffs = diff(oldData, newData, { embeddedObjKeys: { '.characters.subarray': 'id' } });
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Determine if type changes are treated as a replace (remove, add) or as an update; default is replace.
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
const diffs = diff(oldData, newData, { treatTypeChangeAsReplace: false });
|
|
142
148
|
```
|
|
143
149
|
|
|
144
150
|
You can use a function to dynamically resolve the key of the object.
|
|
@@ -146,7 +152,9 @@ The first parameter is the object and the second is to signal if the function sh
|
|
|
146
152
|
|
|
147
153
|
```javascript
|
|
148
154
|
const diffs = diff(oldData, newData, {
|
|
149
|
-
|
|
155
|
+
embeddedObjKeys: {
|
|
156
|
+
characters: (obj, shouldReturnKeyName) => (shouldReturnKeyName ? 'id' : obj.id)
|
|
157
|
+
}
|
|
150
158
|
});
|
|
151
159
|
```
|
|
152
160
|
|
|
@@ -157,30 +165,30 @@ const embeddedObjKeys: EmbeddedObjKeysMapType = new Map();
|
|
|
157
165
|
|
|
158
166
|
embeddedObjKeys.set(/^char\w+$/, 'id'); // instead of 'id' you can specify a function
|
|
159
167
|
|
|
160
|
-
const diffs = diff(oldObj, newObj, embeddedObjKeys);
|
|
168
|
+
const diffs = diff(oldObj, newObj, { embeddedObjKeys });
|
|
161
169
|
```
|
|
162
170
|
|
|
163
171
|
Compare string arrays by value instead of index
|
|
164
172
|
|
|
165
173
|
```javascript
|
|
166
|
-
const diffs = diff(oldObj, newObj, { stringArr: '$value' });
|
|
174
|
+
const diffs = diff(oldObj, newObj, { embeddedObjKeys: { stringArr: '$value' } });
|
|
167
175
|
```
|
|
168
176
|
|
|
169
|
-
### `
|
|
177
|
+
### `atomizeChangeset`
|
|
170
178
|
|
|
171
|
-
Transforms a complex changeset into a
|
|
179
|
+
Transforms a complex changeset into a list of atomic changes, each describable by a JSONPath.
|
|
172
180
|
|
|
173
181
|
#### Examples:
|
|
174
182
|
|
|
175
183
|
```javascript
|
|
176
|
-
const
|
|
177
|
-
// Restore the changeset from a selection of
|
|
178
|
-
const changeset =
|
|
184
|
+
const atomicChanges = atomizeChangeset(diffs);
|
|
185
|
+
// Restore the changeset from a selection of atomic changes
|
|
186
|
+
const changeset = unatomizeChangeset(flatChanges.slice(0, 3));
|
|
179
187
|
// Alternatively, apply the changes using a JSONPath-capable library
|
|
180
188
|
// ...
|
|
181
189
|
```
|
|
182
190
|
|
|
183
|
-
|
|
191
|
+
**Atomic Changes** will have the following structure:
|
|
184
192
|
|
|
185
193
|
```javascript
|
|
186
194
|
[
|
|
@@ -265,6 +273,8 @@ Reach out to the maintainer via LinkedIn or Twitter:
|
|
|
265
273
|
Discover more about the company behind this project: [hololux](https://hololux.com)
|
|
266
274
|
|
|
267
275
|
## Release Notes
|
|
276
|
+
- **v4.0.0:** Change naming of flattenChangest and unflattenChanges to atomizeChangeset and unatomizeChangeset; option to set treatTypeChangeAsReplace
|
|
277
|
+
- **v3.0.1:** Fix issue with unflattenChanges when a key has periods
|
|
268
278
|
- **v3.0.0:** Supports CommonJS and ECMAScript Modules. Dependency to lodash-es was replaced with lodash to support both ECMAScript and CommonJS.
|
|
269
279
|
- **v2.2.0:** Fix lodash-es decependency, exclude keys, compare string arrays by value
|
|
270
280
|
- **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.
|
package/dist/index.cjs
CHANGED
|
@@ -24,27 +24,58 @@ __export(src_exports, {
|
|
|
24
24
|
Operation: () => Operation,
|
|
25
25
|
applyChangelist: () => applyChangelist,
|
|
26
26
|
applyChangeset: () => applyChangeset,
|
|
27
|
+
atomizeChangeset: () => atomizeChangeset,
|
|
27
28
|
compare: () => compare2,
|
|
28
29
|
createContainer: () => createContainer,
|
|
29
30
|
createValue: () => createValue,
|
|
30
31
|
diff: () => diff,
|
|
31
32
|
enrich: () => enrich,
|
|
32
|
-
flattenChangeset: () => flattenChangeset,
|
|
33
33
|
getTypeOfObj: () => getTypeOfObj,
|
|
34
34
|
revertChangeset: () => revertChangeset,
|
|
35
|
-
|
|
35
|
+
unatomizeChangeset: () => unatomizeChangeset
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(src_exports);
|
|
38
38
|
|
|
39
39
|
// src/jsonDiff.ts
|
|
40
40
|
var import_lodash = require("lodash");
|
|
41
|
+
|
|
42
|
+
// src/helpers.ts
|
|
43
|
+
function splitJSONPath(path) {
|
|
44
|
+
let parts = [];
|
|
45
|
+
let currentPart = "";
|
|
46
|
+
let inSingleQuotes = false;
|
|
47
|
+
let inBrackets = 0;
|
|
48
|
+
for (let i = 0; i < path.length; i++) {
|
|
49
|
+
const char = path[i];
|
|
50
|
+
if (char === "'" && path[i - 1] !== "\\") {
|
|
51
|
+
inSingleQuotes = !inSingleQuotes;
|
|
52
|
+
} else if (char === "[" && !inSingleQuotes) {
|
|
53
|
+
inBrackets++;
|
|
54
|
+
} else if (char === "]" && !inSingleQuotes) {
|
|
55
|
+
inBrackets--;
|
|
56
|
+
}
|
|
57
|
+
if (char === "." && !inSingleQuotes && inBrackets === 0) {
|
|
58
|
+
parts.push(currentPart);
|
|
59
|
+
currentPart = "";
|
|
60
|
+
} else {
|
|
61
|
+
currentPart += char;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (currentPart !== "") {
|
|
65
|
+
parts.push(currentPart);
|
|
66
|
+
}
|
|
67
|
+
return parts;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/jsonDiff.ts
|
|
41
71
|
var Operation = /* @__PURE__ */ ((Operation2) => {
|
|
42
72
|
Operation2["REMOVE"] = "REMOVE";
|
|
43
73
|
Operation2["ADD"] = "ADD";
|
|
44
74
|
Operation2["UPDATE"] = "UPDATE";
|
|
45
75
|
return Operation2;
|
|
46
76
|
})(Operation || {});
|
|
47
|
-
function diff(oldObj, newObj,
|
|
77
|
+
function diff(oldObj, newObj, options = {}) {
|
|
78
|
+
let { embeddedObjKeys, keysToSkip, treatTypeChangeAsReplace } = options;
|
|
48
79
|
if (embeddedObjKeys instanceof Map) {
|
|
49
80
|
embeddedObjKeys = new Map(
|
|
50
81
|
Array.from(embeddedObjKeys.entries()).map(([key, value]) => [
|
|
@@ -57,7 +88,11 @@ function diff(oldObj, newObj, embeddedObjKeys, keysToSkip) {
|
|
|
57
88
|
Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\./, ""), value])
|
|
58
89
|
);
|
|
59
90
|
}
|
|
60
|
-
return compare(oldObj, newObj, [],
|
|
91
|
+
return compare(oldObj, newObj, [], [], {
|
|
92
|
+
embeddedObjKeys,
|
|
93
|
+
keysToSkip: keysToSkip ?? [],
|
|
94
|
+
treatTypeChangeAsReplace: treatTypeChangeAsReplace ?? true
|
|
95
|
+
});
|
|
61
96
|
}
|
|
62
97
|
var applyChangeset = (obj, changeset) => {
|
|
63
98
|
if (changeset) {
|
|
@@ -80,45 +115,55 @@ var revertChangeset = (obj, changeset) => {
|
|
|
80
115
|
}
|
|
81
116
|
return obj;
|
|
82
117
|
};
|
|
83
|
-
var
|
|
118
|
+
var atomizeChangeset = (obj, path = "$", embeddedKey) => {
|
|
84
119
|
if (Array.isArray(obj)) {
|
|
85
|
-
return obj
|
|
86
|
-
} else {
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
path = `${path}[?(@='${obj.key}')]`;
|
|
93
|
-
const valueType = getTypeOfObj(obj.value);
|
|
94
|
-
return [
|
|
95
|
-
{
|
|
96
|
-
...obj,
|
|
97
|
-
path,
|
|
98
|
-
valueType
|
|
99
|
-
}
|
|
100
|
-
];
|
|
101
|
-
} else if (obj.type === "ADD" /* ADD */) {
|
|
102
|
-
} else {
|
|
103
|
-
path = filterExpression(path, embeddedKey, obj.key);
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
path = append(path, obj.key);
|
|
120
|
+
return handleArray(obj, path, embeddedKey);
|
|
121
|
+
} else if (obj.changes || embeddedKey) {
|
|
122
|
+
if (embeddedKey) {
|
|
123
|
+
const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path);
|
|
124
|
+
path = updatedPath;
|
|
125
|
+
if (atomicChange) {
|
|
126
|
+
return atomicChange;
|
|
107
127
|
}
|
|
108
|
-
return flattenChangeset(obj.changes || obj, path, obj.embeddedKey);
|
|
109
128
|
} else {
|
|
110
|
-
|
|
111
|
-
return [
|
|
112
|
-
{
|
|
113
|
-
...obj,
|
|
114
|
-
path: valueType === "Object" || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),
|
|
115
|
-
valueType
|
|
116
|
-
}
|
|
117
|
-
];
|
|
129
|
+
path = append(path, obj.key);
|
|
118
130
|
}
|
|
131
|
+
return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey);
|
|
132
|
+
} else {
|
|
133
|
+
const valueType = getTypeOfObj(obj.value);
|
|
134
|
+
return [{
|
|
135
|
+
...obj,
|
|
136
|
+
path: valueType === "Object" || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),
|
|
137
|
+
valueType
|
|
138
|
+
}];
|
|
119
139
|
}
|
|
120
140
|
};
|
|
121
|
-
|
|
141
|
+
function handleEmbeddedKey(embeddedKey, obj, path) {
|
|
142
|
+
if (embeddedKey === "$index") {
|
|
143
|
+
path = `${path}[${obj.key}]`;
|
|
144
|
+
return [path];
|
|
145
|
+
} else if (embeddedKey === "$value") {
|
|
146
|
+
path = `${path}[?(@=='${obj.key}')]`;
|
|
147
|
+
const valueType = getTypeOfObj(obj.value);
|
|
148
|
+
return [
|
|
149
|
+
path,
|
|
150
|
+
[{
|
|
151
|
+
...obj,
|
|
152
|
+
path,
|
|
153
|
+
valueType
|
|
154
|
+
}]
|
|
155
|
+
];
|
|
156
|
+
} else if (obj.type === "ADD" /* ADD */) {
|
|
157
|
+
return [path];
|
|
158
|
+
} else {
|
|
159
|
+
path = filterExpression(path, embeddedKey, obj.key);
|
|
160
|
+
return [path];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
var handleArray = (obj, path, embeddedKey) => {
|
|
164
|
+
return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey)], []);
|
|
165
|
+
};
|
|
166
|
+
var unatomizeChangeset = (changes) => {
|
|
122
167
|
if (!Array.isArray(changes)) {
|
|
123
168
|
changes = [changes];
|
|
124
169
|
}
|
|
@@ -126,7 +171,7 @@ var unflattenChanges = (changes) => {
|
|
|
126
171
|
changes.forEach((change) => {
|
|
127
172
|
const obj = {};
|
|
128
173
|
let ptr = obj;
|
|
129
|
-
const segments = change.path
|
|
174
|
+
const segments = splitJSONPath(change.path);
|
|
130
175
|
if (segments.length === 1) {
|
|
131
176
|
ptr.key = change.key;
|
|
132
177
|
ptr.type = change.type;
|
|
@@ -136,7 +181,7 @@ var unflattenChanges = (changes) => {
|
|
|
136
181
|
} else {
|
|
137
182
|
for (let i = 1; i < segments.length; i++) {
|
|
138
183
|
const segment = segments[i];
|
|
139
|
-
const result = /^(
|
|
184
|
+
const result = /^([^[\]]+)\[\?\(@\.?([^=]*)=+'([^']+)'\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
|
|
140
185
|
if (result) {
|
|
141
186
|
let key;
|
|
142
187
|
let embeddedKey;
|
|
@@ -148,7 +193,7 @@ var unflattenChanges = (changes) => {
|
|
|
148
193
|
} else {
|
|
149
194
|
key = result[4];
|
|
150
195
|
embeddedKey = "$index";
|
|
151
|
-
arrKey = Number(result[
|
|
196
|
+
arrKey = Number(result[5]);
|
|
152
197
|
}
|
|
153
198
|
if (i === segments.length - 1) {
|
|
154
199
|
ptr.key = key;
|
|
@@ -221,15 +266,19 @@ var getKey = (path) => {
|
|
|
221
266
|
const left = path[path.length - 1];
|
|
222
267
|
return left != null ? left : "$root";
|
|
223
268
|
};
|
|
224
|
-
var compare = (oldObj, newObj, path,
|
|
269
|
+
var compare = (oldObj, newObj, path, keyPath, options) => {
|
|
225
270
|
let changes = [];
|
|
226
271
|
const typeOfOldObj = getTypeOfObj(oldObj);
|
|
227
272
|
const typeOfNewObj = getTypeOfObj(newObj);
|
|
228
|
-
if (typeOfOldObj !== typeOfNewObj) {
|
|
273
|
+
if (options.treatTypeChangeAsReplace && typeOfOldObj !== typeOfNewObj) {
|
|
229
274
|
changes.push({ type: "REMOVE" /* REMOVE */, key: getKey(path), value: oldObj });
|
|
230
275
|
changes.push({ type: "ADD" /* ADD */, key: getKey(path), value: newObj });
|
|
231
276
|
return changes;
|
|
232
277
|
}
|
|
278
|
+
if (typeOfNewObj === "Object" && typeOfOldObj === "Array") {
|
|
279
|
+
changes.push({ type: "UPDATE" /* UPDATE */, key: getKey(path), value: newObj, oldValue: oldObj });
|
|
280
|
+
return changes;
|
|
281
|
+
}
|
|
233
282
|
switch (typeOfOldObj) {
|
|
234
283
|
case "Date":
|
|
235
284
|
changes = changes.concat(
|
|
@@ -240,8 +289,8 @@ var compare = (oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip) => {
|
|
|
240
289
|
}))
|
|
241
290
|
);
|
|
242
291
|
break;
|
|
243
|
-
case "Object":
|
|
244
|
-
const diffs = compareObject(oldObj, newObj, path,
|
|
292
|
+
case "Object": {
|
|
293
|
+
const diffs = compareObject(oldObj, newObj, path, keyPath, false, options);
|
|
245
294
|
if (diffs.length) {
|
|
246
295
|
if (path.length) {
|
|
247
296
|
changes.push({
|
|
@@ -254,8 +303,9 @@ var compare = (oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip) => {
|
|
|
254
303
|
}
|
|
255
304
|
}
|
|
256
305
|
break;
|
|
306
|
+
}
|
|
257
307
|
case "Array":
|
|
258
|
-
changes = changes.concat(compareArray(oldObj, newObj, path,
|
|
308
|
+
changes = changes.concat(compareArray(oldObj, newObj, path, keyPath, options));
|
|
259
309
|
break;
|
|
260
310
|
case "Function":
|
|
261
311
|
break;
|
|
@@ -264,7 +314,7 @@ var compare = (oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip) => {
|
|
|
264
314
|
}
|
|
265
315
|
return changes;
|
|
266
316
|
};
|
|
267
|
-
var compareObject = (oldObj, newObj, path,
|
|
317
|
+
var compareObject = (oldObj, newObj, path, keyPath, skipPath = false, options = {}) => {
|
|
268
318
|
let k;
|
|
269
319
|
let newKeyPath;
|
|
270
320
|
let newPath;
|
|
@@ -272,13 +322,13 @@ var compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath =
|
|
|
272
322
|
skipPath = false;
|
|
273
323
|
}
|
|
274
324
|
let changes = [];
|
|
275
|
-
const oldObjKeys = Object.keys(oldObj).filter((key) => keysToSkip.indexOf(key) === -1);
|
|
276
|
-
const newObjKeys = Object.keys(newObj).filter((key) => keysToSkip.indexOf(key) === -1);
|
|
325
|
+
const oldObjKeys = Object.keys(oldObj).filter((key) => options.keysToSkip.indexOf(key) === -1);
|
|
326
|
+
const newObjKeys = Object.keys(newObj).filter((key) => options.keysToSkip.indexOf(key) === -1);
|
|
277
327
|
const intersectionKeys = (0, import_lodash.intersection)(oldObjKeys, newObjKeys);
|
|
278
328
|
for (k of intersectionKeys) {
|
|
279
329
|
newPath = path.concat([k]);
|
|
280
330
|
newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
|
|
281
|
-
const diffs = compare(oldObj[k], newObj[k], newPath,
|
|
331
|
+
const diffs = compare(oldObj[k], newObj[k], newPath, newKeyPath, options);
|
|
282
332
|
if (diffs.length) {
|
|
283
333
|
changes = changes.concat(diffs);
|
|
284
334
|
}
|
|
@@ -305,12 +355,12 @@ var compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath =
|
|
|
305
355
|
}
|
|
306
356
|
return changes;
|
|
307
357
|
};
|
|
308
|
-
var compareArray = (oldObj, newObj, path,
|
|
309
|
-
const left = getObjectKey(embeddedObjKeys, keyPath);
|
|
358
|
+
var compareArray = (oldObj, newObj, path, keyPath, options) => {
|
|
359
|
+
const left = getObjectKey(options.embeddedObjKeys, keyPath);
|
|
310
360
|
const uniqKey = left != null ? left : "$index";
|
|
311
361
|
const indexedOldObj = convertArrayToObj(oldObj, uniqKey);
|
|
312
362
|
const indexedNewObj = convertArrayToObj(newObj, uniqKey);
|
|
313
|
-
const diffs = compareObject(indexedOldObj, indexedNewObj, path,
|
|
363
|
+
const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);
|
|
314
364
|
if (diffs.length) {
|
|
315
365
|
return [
|
|
316
366
|
{
|
|
@@ -546,7 +596,7 @@ var applyChangelist = (object, changelist) => {
|
|
|
546
596
|
return object;
|
|
547
597
|
};
|
|
548
598
|
var compare2 = (oldObject, newObject) => {
|
|
549
|
-
return applyChangelist(enrich(oldObject),
|
|
599
|
+
return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));
|
|
550
600
|
};
|
|
551
601
|
// Annotate the CommonJS export names for ESM import in node:
|
|
552
602
|
0 && (module.exports = {
|
|
@@ -554,14 +604,14 @@ var compare2 = (oldObject, newObject) => {
|
|
|
554
604
|
Operation,
|
|
555
605
|
applyChangelist,
|
|
556
606
|
applyChangeset,
|
|
607
|
+
atomizeChangeset,
|
|
557
608
|
compare,
|
|
558
609
|
createContainer,
|
|
559
610
|
createValue,
|
|
560
611
|
diff,
|
|
561
612
|
enrich,
|
|
562
|
-
flattenChangeset,
|
|
563
613
|
getTypeOfObj,
|
|
564
614
|
revertChangeset,
|
|
565
|
-
|
|
615
|
+
unatomizeChangeset
|
|
566
616
|
});
|
|
567
617
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/jsonDiff.ts","../src/jsonCompare.ts"],"sourcesContent":["export * from './jsonDiff.js';\nexport * from './jsonCompare.js';\n","import { difference, find, intersection, keyBy } from 'lodash';\n\ntype FunctionKey = (obj: any, shouldReturnKeyName?: boolean) => any;\nexport type EmbeddedObjKeysType = Record<string, string | FunctionKey>;\nexport type EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nexport enum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\nexport interface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n value?: any | any[];\n oldValue?: any;\n changes?: IChange[];\n}\nexport type Changeset = IChange[];\n\nexport interface IFlatChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\n/**\n * Computes the difference between two objects.\n *\n * @param {any} oldObj - The original object.\n * @param {any} newObj - The updated object.\n * @param {EmbeddedObjKeysType | EmbeddedObjKeysMapType} embeddedObjKeys - An optional parameter specifying keys of embedded objects.\n * @returns {IChange[]} - An array of changes that transform the old object into the new object.\n */\nexport function diff(\n oldObj: any,\n newObj: any,\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType,\n keysToSkip?: string[]\n): IChange[] {\n // Trim leading '.' from keys in embeddedObjKeys\n if (embeddedObjKeys instanceof Map) {\n embeddedObjKeys = new Map(\n Array.from(embeddedObjKeys.entries()).map(([key, value]) => [\n key instanceof RegExp ? key : key.replace(/^\\./, ''),\n value\n ])\n );\n } else if (embeddedObjKeys) {\n embeddedObjKeys = Object.fromEntries(\n Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\\./, ''), value])\n );\n }\n\n // Compare old and new objects to generate a list of changes\n return compare(oldObj, newObj, [], embeddedObjKeys, [], keysToSkip);\n}\n\n/**\n * Applies all changes in the changeset to the object.\n *\n * @param {any} obj - The object to apply changes to.\n * @param {Changeset} changeset - The changeset to apply.\n * @returns {any} - The object after the changes from the changeset have been applied.\n *\n * The function first checks if a changeset is provided. If so, it iterates over each change in the changeset.\n * If the change value is not null or undefined, or if the change type is REMOVE, it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nexport const applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n if ((value !== null && value !== undefined) || type === Operation.REMOVE) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n applyBranchChange(obj[key], change);\n }\n });\n }\n return obj;\n};\n\n/**\n * Reverts the changes made to an object based on a given changeset.\n *\n * @param {any} obj - The object on which to revert changes.\n * @param {Changeset} changeset - The changeset to revert.\n * @returns {any} - The object after the changes from the changeset have been reverted.\n *\n * The function first checks if a changeset is provided. If so, it reverses the changeset to start reverting from the last change.\n * It then iterates over each change in the changeset. If the change does not have any nested changes, it reverts the change on the object directly.\n * If the change does have nested changes, it reverts the changes on the corresponding branch of the object.\n */\nexport const revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any =>\n !change.changes ? revertLeafChange(obj, change) : revertBranchChange(obj[change.key], change)\n );\n }\n\n return obj;\n};\n\n/**\n * Flattens a changeset into an array of flat changes.\n *\n * @param {Changeset | IChange} obj - The changeset or change to flatten.\n * @param {string} [path='$'] - The current path in the changeset.\n * @param {string | FunctionKey} [embeddedKey] - The key to use for embedded objects.\n * @returns {IFlatChange[]} - An array of flat changes.\n *\n * The function first checks if the input is an array. If so, it recursively flattens each change in the array.\n * If the input is not an array, it checks if the change has nested changes or an embedded key.\n * If so, it updates the path and recursively flattens the nested changes or the embedded object.\n * If the change does not have nested changes or an embedded key, it creates a flat change and returns it in an array.\n */\nexport const flattenChangeset = (\n obj: Changeset | IChange,\n path = '$',\n embeddedKey?: string | FunctionKey\n): IFlatChange[] => {\n if (Array.isArray(obj)) {\n return obj.reduce((memo, change) => [...memo, ...flattenChangeset(change, path, embeddedKey)], [] as IFlatChange[]);\n } else {\n if (obj.changes || embeddedKey) {\n if (embeddedKey) {\n if (embeddedKey === '$index') {\n path = `${path}[${obj.key}]`;\n } else if (embeddedKey === '$value') {\n path = `${path}[?(@='${obj.key}')]`;\n const valueType = getTypeOfObj(obj.value);\n return [\n {\n ...obj,\n path,\n valueType\n }\n ];\n } else if (obj.type === Operation.ADD) {\n // do nothing\n } else {\n path = filterExpression(path, embeddedKey, obj.key);\n }\n } else {\n path = append(path, obj.key);\n }\n\n return flattenChangeset(obj.changes || obj, path, obj.embeddedKey);\n } else {\n const valueType = getTypeOfObj(obj.value);\n return [\n {\n ...obj,\n path: valueType === 'Object' || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),\n valueType\n }\n ];\n }\n }\n};\n\n/**\n * Transforms a flat changeset into a nested changeset.\n *\n * @param {IFlatChange | IFlatChange[]} changes - The flat changeset to unflatten.\n * @returns {IChange[]} - The unflattened changeset.\n *\n * The function first checks if the input is a single change or an array of changes.\n * It then iterates over each change and splits its path into segments.\n * For each segment, it checks if it represents an array or a leaf node.\n * If it represents an array, it creates a new change object and updates the pointer to this new object.\n * If it represents a leaf node, it sets the key, type, value, and oldValue of the current change object.\n * Finally, it pushes the unflattened change object into the changes array.\n */\nexport const unflattenChanges = (changes: IFlatChange | IFlatChange[]) => {\n if (!Array.isArray(changes)) {\n changes = [changes];\n }\n\n const changesArr: IChange[] = [];\n\n changes.forEach((change) => {\n const obj = {} as IChange;\n let ptr = obj;\n\n const segments = change.path.split(/(?<=[^@])\\.(?=[^@])/);\n\n if (segments.length === 1) {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n changesArr.push(ptr);\n } else {\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i];\n // Matches JSONPath segments: \"items[?(@.id=='123')]\", \"items[?(@.id==123)]\", \"items[2]\", \"items[?(@='123')]\"\n const result = /^(.+?)\\[\\?\\(@.?(?:([^=]*))?={1,2}'(.*)'\\)\\]$|^(.+?)\\[(\\d+)\\]$/.exec(segment); //NOSONAR\n // array\n if (result) {\n let key: string;\n let embeddedKey: string;\n let arrKey: string | number;\n if (result[1]) {\n key = result[1];\n embeddedKey = result[2] || '$value';\n arrKey = result[3];\n } else {\n key = result[4];\n embeddedKey = '$index';\n arrKey = Number(result[4]);\n }\n // leaf\n if (i === segments.length - 1) {\n ptr.key = key!;\n ptr.embeddedKey = embeddedKey!;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n type: change.type,\n key: arrKey!,\n value: change.value,\n oldValue: change.oldValue\n } as IChange\n ];\n } else {\n // object\n ptr.key = key;\n ptr.embeddedKey = embeddedKey;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [\n {\n type: Operation.UPDATE,\n key: arrKey,\n changes: [newPtr]\n } as IChange\n ];\n ptr = newPtr;\n }\n } else {\n // leaf\n if (i === segments.length - 1) {\n // check if value is a primitive or object\n if (change.value !== null && change.valueType === 'Object') {\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n key: change.key,\n type: change.type,\n value: change.value\n } as IChange\n ];\n } else {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n }\n } else {\n // branch\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [newPtr];\n ptr = newPtr;\n }\n }\n }\n changesArr.push(obj);\n }\n });\n return changesArr;\n};\n\n/**\n * Determines the type of a given object.\n *\n * @param {any} obj - The object whose type is to be determined.\n * @returns {string | null} - The type of the object, or null if the object is null.\n *\n * This function first checks if the object is undefined or null, and returns 'undefined' or null respectively.\n * If the object is neither undefined nor null, it uses Object.prototype.toString to get the object's type.\n * The type is extracted from the string returned by Object.prototype.toString using a regular expression.\n */\nexport const getTypeOfObj = (obj: any) => {\n if (typeof obj === 'undefined') {\n return 'undefined';\n }\n\n if (obj === null) {\n return null;\n }\n\n // Extracts the \"Type\" from \"[object Type]\" string.\n return Object.prototype.toString.call(obj).match(/^\\[object\\s(.*)\\]$/)[1];\n};\n\nconst getKey = (path: string) => {\n const left = path[path.length - 1];\n return left != null ? left : '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, embeddedObjKeys: any, keyPath: any, keysToSkip: string[]) => {\n let changes: any[] = [];\n\n const typeOfOldObj = getTypeOfObj(oldObj);\n const typeOfNewObj = getTypeOfObj(newObj);\n\n // if type of object changes, consider it as old obj has been deleted and a new object has been added\n if (typeOfOldObj !== typeOfNewObj) {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n changes = changes.concat(\n comparePrimitives(oldObj.getTime(), newObj.getTime(), path).map((x) => ({\n ...x,\n value: new Date(x.value),\n oldValue: new Date(x.oldValue)\n }))\n );\n break;\n case 'Object':\n const diffs = compareObject(oldObj, newObj, path, embeddedObjKeys, keyPath, false, keysToSkip);\n if (diffs.length) {\n if (path.length) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n changes: diffs\n });\n } else {\n changes = changes.concat(diffs);\n }\n }\n break;\n case 'Array':\n changes = changes.concat(compareArray(oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip));\n break;\n case 'Function':\n break;\n // do nothing\n default:\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n\n return changes;\n};\n\nconst compareObject = (\n oldObj: any,\n newObj: any,\n path: any,\n embeddedObjKeys: any,\n keyPath: any,\n skipPath = false,\n keysToSkip: string[] = []\n) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n const oldObjKeys = Object.keys(oldObj).filter((key) => keysToSkip.indexOf(key) === -1);\n const newObjKeys = Object.keys(newObj).filter((key) => keysToSkip.indexOf(key) === -1);\n\n const intersectionKeys = intersection(oldObjKeys, newObjKeys);\n for (k of intersectionKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n const diffs = compare(oldObj[k], newObj[k], newPath, embeddedObjKeys, newKeyPath, keysToSkip);\n if (diffs.length) {\n changes = changes.concat(diffs);\n }\n }\n\n const addedKeys = difference(newObjKeys, oldObjKeys);\n for (k of addedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.ADD,\n key: getKey(newPath),\n value: newObj[k]\n });\n }\n\n const deletedKeys = difference(oldObjKeys, newObjKeys);\n for (k of deletedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (\n oldObj: any,\n newObj: any,\n path: any,\n embeddedObjKeys: any,\n keyPath: any,\n keysToSkip: string[]\n) => {\n const left = getObjectKey(embeddedObjKeys, keyPath);\n const uniqKey = left != null ? left : '$index';\n const indexedOldObj = convertArrayToObj(oldObj, uniqKey);\n const indexedNewObj = convertArrayToObj(newObj, uniqKey);\n const diffs = compareObject(indexedOldObj, indexedNewObj, path, embeddedObjKeys, keyPath, true, keysToSkip);\n if (diffs.length) {\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: typeof uniqKey === 'function' && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,\n changes: diffs\n }\n ];\n } else {\n return [];\n }\n};\n\nconst getObjectKey = (embeddedObjKeys: any, keyPath: any) => {\n if (embeddedObjKeys != null) {\n const path = keyPath.join('.');\n\n if (embeddedObjKeys instanceof Map) {\n for (const [key, value] of embeddedObjKeys.entries()) {\n if (key instanceof RegExp) {\n if (path.match(key)) {\n return value;\n }\n } else if (path === key) {\n return value;\n }\n }\n }\n\n const key = embeddedObjKeys[path];\n if (key != null) {\n return key;\n }\n }\n return undefined;\n};\n\nconst convertArrayToObj = (arr: any[], uniqKey: any) => {\n let obj: any = {};\n if (uniqKey === '$value') {\n arr.forEach((value) => {\n obj[value] = value;\n });\n } else if (uniqKey !== '$index') {\n obj = keyBy(arr, uniqKey);\n } else {\n for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n }\n return obj;\n};\n\nconst comparePrimitives = (oldObj: any, newObj: any, path: any) => {\n const changes = [];\n if (oldObj !== newObj) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n value: newObj,\n oldValue: oldObj\n });\n }\n return changes;\n};\n\nconst removeKey = (obj: any, key: any, embeddedKey: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(key);\n return;\n }\n const index = indexOfItemInArray(obj, embeddedKey, key);\n if (index === -1) {\n // tslint:disable-next-line:no-console\n console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array'`);\n return;\n }\n return obj.splice(index != null ? index : key, 1);\n } else {\n obj[key] = undefined;\n delete obj[key];\n return;\n }\n};\n\nconst indexOfItemInArray = (arr: any[], key: any, value: any) => {\n if (key === '$value') {\n return arr.indexOf(value);\n }\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i];\n if (item && item[key] ? item[key].toString() === value.toString() : undefined) {\n return i;\n }\n }\n return -1;\n};\n\nconst modifyKeyValue = (obj: any, key: any, value: any) => (obj[key] = value);\n\nconst addKeyValue = (obj: any, key: any, value: any) => {\n if (Array.isArray(obj)) {\n return obj.push(value);\n } else {\n return obj ? (obj[key] = value) : null;\n }\n};\n\nconst applyLeafChange = (obj: any, change: any, embeddedKey: any) => {\n const { type, key, value } = change;\n switch (type) {\n case Operation.ADD:\n return addKeyValue(obj, key, value);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey);\n }\n};\n\nconst applyArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(applyLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[subchange.key];\n } else if (change.embeddedKey === '$value') {\n const index = arr.indexOf(subchange.key);\n if (index !== -1) {\n element = arr[index];\n }\n } else {\n element = find(arr, (el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n result.push(applyChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst applyBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return applyArrayChange(obj, change);\n } else {\n return applyChangeset(obj, change.changes);\n }\n};\n\nconst revertLeafChange = (obj: any, change: any, embeddedKey = '$index') => {\n const { type, key, value, oldValue } = change;\n switch (type) {\n case Operation.ADD:\n return removeKey(obj, key, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, oldValue);\n case Operation.REMOVE:\n return addKeyValue(obj, key, value);\n }\n};\n\nconst revertArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(revertLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[+subchange.key];\n } else {\n element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key);\n }\n result.push(revertChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst revertBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return revertArrayChange(obj, change);\n } else {\n return revertChangeset(obj, change.changes);\n }\n};\n\n/** combine a base JSON Path with a subsequent segment */\nfunction append(basePath: string, nextSegment: string): string {\n return nextSegment.includes('.') ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;\n}\n\n/** returns a JSON Path filter expression; e.g., `$.pet[(?name='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string | FunctionKey, filterValue: string | number) {\n const value = typeof filterValue === 'number' ? filterValue : `'${filterValue}'`;\n return typeof filterKey === 'string' && filterKey.includes('.')\n ? `${basePath}[?(@[${filterKey}]==${value})]`\n : `${basePath}[?(@.${filterKey}==${value})]`;\n}\n","import { chain, keys, replace, set } from 'lodash';\nimport { diff, flattenChangeset, getTypeOfObj, IFlatChange, Operation } from './jsonDiff.js';\n\nexport enum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\nexport interface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nexport const createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nexport const createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nexport const enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return keys(object)\n .map((key: string) => ({ key, value: enrich(object[key]) }))\n .reduce((accumulator, entry) => {\n accumulator.value[entry.key] = entry.value;\n return accumulator;\n }, createContainer({}));\n case 'Array':\n return chain(object)\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]))\n .value();\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\nexport const applyChangelist = (\n object: IComparisonEnrichedNode,\n changelist: IFlatChange[]\n): IComparisonEnrichedNode => {\n chain(changelist)\n .map((entry) => ({ ...entry, path: replace(entry.path, '$.', '.') }))\n .map((entry) => ({\n ...entry,\n path: replace(entry.path, /(\\[(?<array>\\d)\\]\\.)/g, 'ARRVAL_START$<array>ARRVAL_END')\n }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /(?<dot>\\.)/g, '.value$<dot>') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /\\./, '') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_START/g, '.value[') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_END/g, '].value.') }))\n .value()\n .forEach((entry) => {\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n set(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n set(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nexport const compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n return applyChangelist(enrich(oldObject), flattenChangeset(diff(oldObject, newObject)));\n};\n"],"mappings":"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","names":["compare","Operation","key","import_lodash","CompareOperation","compare"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/jsonDiff.ts","../src/helpers.ts","../src/jsonCompare.ts"],"sourcesContent":["export * from './jsonDiff.js';\nexport * from './jsonCompare.js';\n","import { difference, find, intersection, keyBy } from 'lodash';\nimport { splitJSONPath } from './helpers';\n\ntype FunctionKey = (obj: any, shouldReturnKeyName?: boolean) => any;\nexport type EmbeddedObjKeysType = Record<string, string | FunctionKey>;\nexport type EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nexport enum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\nexport interface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n value?: any;\n oldValue?: any;\n changes?: IChange[];\n}\nexport type Changeset = IChange[];\n\nexport interface IAtomicChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\nexport interface Options {\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;\n keysToSkip?: string[];\n treatTypeChangeAsReplace?: boolean;\n}\n\n/**\n * Computes the difference between two objects.\n *\n * @param {any} oldObj - The original object.\n * @param {any} newObj - The updated object.\n * @param {Options} options - An optional parameter specifying keys of embedded objects and keys to skip.\n * @returns {IChange[]} - An array of changes that transform the old object into the new object.\n */\nexport function diff(\n oldObj: any,\n newObj: any,\n options: Options = {}\n): IChange[] {\n let { embeddedObjKeys, keysToSkip, treatTypeChangeAsReplace } = options;\n\n // Trim leading '.' from keys in embeddedObjKeys\n if (embeddedObjKeys instanceof Map) {\n embeddedObjKeys = new Map(\n Array.from(embeddedObjKeys.entries()).map(([key, value]) => [\n key instanceof RegExp ? key : key.replace(/^\\./, ''),\n value\n ])\n );\n } else if (embeddedObjKeys) {\n embeddedObjKeys = Object.fromEntries(\n Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\\./, ''), value])\n );\n }\n\n // Compare old and new objects to generate a list of changes\n return compare(oldObj, newObj, [], [], {\n embeddedObjKeys,\n keysToSkip: keysToSkip ?? [],\n treatTypeChangeAsReplace: treatTypeChangeAsReplace ?? true\n });\n}\n\n/**\n * Applies all changes in the changeset to the object.\n *\n * @param {any} obj - The object to apply changes to.\n * @param {Changeset} changeset - The changeset to apply.\n * @returns {any} - The object after the changes from the changeset have been applied.\n *\n * The function first checks if a changeset is provided. If so, it iterates over each change in the changeset.\n * If the change value is not null or undefined, or if the change type is REMOVE, it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nexport const applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n if ((value !== null && value !== undefined) || type === Operation.REMOVE) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n applyBranchChange(obj[key], change);\n }\n });\n }\n return obj;\n};\n\n/**\n * Reverts the changes made to an object based on a given changeset.\n *\n * @param {any} obj - The object on which to revert changes.\n * @param {Changeset} changeset - The changeset to revert.\n * @returns {any} - The object after the changes from the changeset have been reverted.\n *\n * The function first checks if a changeset is provided. If so, it reverses the changeset to start reverting from the last change.\n * It then iterates over each change in the changeset. If the change does not have any nested changes, it reverts the change on the object directly.\n * If the change does have nested changes, it reverts the changes on the corresponding branch of the object.\n */\nexport const revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any =>\n !change.changes ? revertLeafChange(obj, change) : revertBranchChange(obj[change.key], change)\n );\n }\n\n return obj;\n};\n\n/**\n * Atomize a changeset into an array of single changes.\n *\n * @param {Changeset | IChange} obj - The changeset or change to flatten.\n * @param {string} [path='$'] - The current path in the changeset.\n * @param {string | FunctionKey} [embeddedKey] - The key to use for embedded objects.\n * @returns {IAtomicChange[]} - An array of atomic changes.\n *\n * The function first checks if the input is an array. If so, it recursively atomize each change in the array.\n * If the input is not an array, it checks if the change has nested changes or an embedded key.\n * If so, it updates the path and recursively flattens the nested changes or the embedded object.\n * If the change does not have nested changes or an embedded key, it creates a atomic change and returns it in an array.\n */\nexport const atomizeChangeset = (\n obj: Changeset | IChange,\n path = '$',\n embeddedKey?: string | FunctionKey\n): IAtomicChange[] => {\n if (Array.isArray(obj)) {\n return handleArray(obj, path, embeddedKey);\n } else if (obj.changes || embeddedKey) {\n if (embeddedKey) {\n const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path);\n path = updatedPath;\n if (atomicChange) {\n return atomicChange;\n }\n } else {\n path = append(path, obj.key);\n }\n return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey);\n } else {\n const valueType = getTypeOfObj(obj.value);\n return [{\n ...obj,\n path: valueType === 'Object' || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),\n valueType\n }];\n }\n};\n\n// Function to handle embeddedKey logic and update the path\nfunction handleEmbeddedKey(embeddedKey: string | FunctionKey, obj: IChange, path: string): [string, IAtomicChange[]?] {\n if (embeddedKey === '$index') {\n path = `${path}[${obj.key}]`;\n return [path]\n } else if (embeddedKey === '$value') {\n path = `${path}[?(@=='${obj.key}')]`;\n const valueType = getTypeOfObj(obj.value);\n return [\n path,\n [{\n ...obj,\n path,\n valueType\n }]\n ];\n } else if (obj.type === Operation.ADD) {\n // do nothing\n return [path];\n } else {\n path = filterExpression(path, embeddedKey, obj.key);\n return [path];\n }\n}\n\n\nconst handleArray = (obj: Changeset | IChange[], path: string, embeddedKey?: string | FunctionKey): IAtomicChange[] => {\n return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey)], [] as IAtomicChange[]);\n}\n\n\n\n/**\n * Transforms an atomized changeset into a nested changeset.\n *\n * @param {IAtomicChange | IAtomicChange[]} changes - The atomic changeset to unflatten.\n * @returns {IChange[]} - The unflattened changeset.\n *\n * The function first checks if the input is a single change or an array of changes.\n * It then iterates over each change and splits its path into segments.\n * For each segment, it checks if it represents an array or a leaf node.\n * If it represents an array, it creates a new change object and updates the pointer to this new object.\n * If it represents a leaf node, it sets the key, type, value, and oldValue of the current change object.\n * Finally, it pushes the unflattened change object into the changes array.\n */\nexport const unatomizeChangeset = (changes: IAtomicChange | IAtomicChange[]) => {\n if (!Array.isArray(changes)) {\n changes = [changes];\n }\n\n const changesArr: IChange[] = [];\n\n\n changes.forEach((change) => {\n const obj = {} as IChange;\n let ptr = obj;\n\n const segments = splitJSONPath(change.path);\n\n if (segments.length === 1) {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n changesArr.push(ptr);\n } else {\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i];\n // Matches JSONPath segments: \"items[?(@.id=='123')]\", \"items[?(@.id==123)]\", \"items[2]\", \"items[?(@='123')]\"\n const result = /^([^[\\]]+)\\[\\?\\(@\\.?([^=]*)=+'([^']+)'\\)\\]$|^(.+)\\[(\\d+)\\]$/.exec(segment);\n // array\n if (result) {\n let key: string;\n let embeddedKey: string;\n let arrKey: string | number;\n if (result[1]) {\n key = result[1];\n embeddedKey = result[2] || '$value';\n arrKey = result[3];\n } else {\n key = result[4];\n embeddedKey = '$index';\n arrKey = Number(result[5]);\n }\n // leaf\n if (i === segments.length - 1) {\n ptr.key = key!;\n ptr.embeddedKey = embeddedKey!;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n type: change.type,\n key: arrKey!,\n value: change.value,\n oldValue: change.oldValue\n } as IChange\n ];\n } else {\n // object\n ptr.key = key;\n ptr.embeddedKey = embeddedKey;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [\n {\n type: Operation.UPDATE,\n key: arrKey,\n changes: [newPtr]\n } as IChange\n ];\n ptr = newPtr;\n }\n } else {\n // leaf\n if (i === segments.length - 1) {\n // check if value is a primitive or object\n if (change.value !== null && change.valueType === 'Object') {\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n key: change.key,\n type: change.type,\n value: change.value\n } as IChange\n ];\n } else {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n }\n } else {\n // branch\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [newPtr];\n ptr = newPtr;\n }\n }\n }\n changesArr.push(obj);\n }\n });\n return changesArr;\n};\n\n/**\n * Determines the type of a given object.\n *\n * @param {any} obj - The object whose type is to be determined.\n * @returns {string | null} - The type of the object, or null if the object is null.\n *\n * This function first checks if the object is undefined or null, and returns 'undefined' or null respectively.\n * If the object is neither undefined nor null, it uses Object.prototype.toString to get the object's type.\n * The type is extracted from the string returned by Object.prototype.toString using a regular expression.\n */\nexport const getTypeOfObj = (obj: any) => {\n if (typeof obj === 'undefined') {\n return 'undefined';\n }\n\n if (obj === null) {\n return null;\n }\n\n // Extracts the \"Type\" from \"[object Type]\" string.\n return Object.prototype.toString.call(obj).match(/^\\[object\\s(.*)\\]$/)[1];\n};\n\nconst getKey = (path: string) => {\n const left = path[path.length - 1];\n return left != null ? left : '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n let changes: any[] = [];\n\n const typeOfOldObj = getTypeOfObj(oldObj);\n const typeOfNewObj = getTypeOfObj(newObj);\n\n // `treatTypeChangeAsReplace` is a flag used to determine if a change in type should be treated as a replacement.\n if (options.treatTypeChangeAsReplace && typeOfOldObj !== typeOfNewObj) {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n return changes;\n }\n\n if (typeOfNewObj === 'Object' && typeOfOldObj === 'Array') {\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n changes = changes.concat(\n comparePrimitives(oldObj.getTime(), newObj.getTime(), path).map((x) => ({\n ...x,\n value: new Date(x.value),\n oldValue: new Date(x.oldValue)\n }))\n );\n break;\n case 'Object':\n {\n const diffs = compareObject(oldObj, newObj, path, keyPath, false, options);\n if (diffs.length) {\n if (path.length) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n changes: diffs\n });\n } else {\n changes = changes.concat(diffs);\n }\n }\n break;\n }\n case 'Array':\n changes = changes.concat(compareArray(oldObj, newObj, path, keyPath, options));\n break;\n case 'Function':\n break;\n // do nothing\n default:\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n\n return changes;\n};\n\nconst compareObject = (\n oldObj: any,\n newObj: any,\n path: any,\n keyPath: any,\n skipPath = false,\n options: Options = {},\n) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n const oldObjKeys = Object.keys(oldObj).filter((key) => options.keysToSkip.indexOf(key) === -1);\n const newObjKeys = Object.keys(newObj).filter((key) => options.keysToSkip.indexOf(key) === -1);\n\n const intersectionKeys = intersection(oldObjKeys, newObjKeys);\n for (k of intersectionKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n const diffs = compare(oldObj[k], newObj[k], newPath, newKeyPath, options);\n if (diffs.length) {\n changes = changes.concat(diffs);\n }\n }\n\n const addedKeys = difference(newObjKeys, oldObjKeys);\n for (k of addedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.ADD,\n key: getKey(newPath),\n value: newObj[k]\n });\n }\n\n const deletedKeys = difference(oldObjKeys, newObjKeys);\n for (k of deletedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (\n oldObj: any,\n newObj: any,\n path: any,\n keyPath: any,\n options: Options\n) => {\n const left = getObjectKey(options.embeddedObjKeys, keyPath);\n const uniqKey = left != null ? left : '$index';\n const indexedOldObj = convertArrayToObj(oldObj, uniqKey);\n const indexedNewObj = convertArrayToObj(newObj, uniqKey);\n const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);\n if (diffs.length) {\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: typeof uniqKey === 'function' && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,\n changes: diffs\n }\n ];\n } else {\n return [];\n }\n};\n\nconst getObjectKey = (embeddedObjKeys: any, keyPath: any) => {\n if (embeddedObjKeys != null) {\n const path = keyPath.join('.');\n\n if (embeddedObjKeys instanceof Map) {\n for (const [key, value] of embeddedObjKeys.entries()) {\n if (key instanceof RegExp) {\n if (path.match(key)) {\n return value;\n }\n } else if (path === key) {\n return value;\n }\n }\n }\n\n const key = embeddedObjKeys[path];\n if (key != null) {\n return key;\n }\n }\n return undefined;\n};\n\nconst convertArrayToObj = (arr: any[], uniqKey: any) => {\n let obj: any = {};\n if (uniqKey === '$value') {\n arr.forEach((value) => {\n obj[value] = value;\n });\n } else if (uniqKey !== '$index') {\n obj = keyBy(arr, uniqKey);\n } else {\n for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n }\n return obj;\n};\n\nconst comparePrimitives = (oldObj: any, newObj: any, path: any) => {\n const changes = [];\n if (oldObj !== newObj) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n value: newObj,\n oldValue: oldObj\n });\n }\n return changes;\n};\n\nconst removeKey = (obj: any, key: any, embeddedKey: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(key);\n return;\n }\n const index = indexOfItemInArray(obj, embeddedKey, key);\n if (index === -1) {\n // tslint:disable-next-line:no-console\n console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array'`);\n return;\n }\n return obj.splice(index != null ? index : key, 1);\n } else {\n obj[key] = undefined;\n delete obj[key];\n return;\n }\n};\n\nconst indexOfItemInArray = (arr: any[], key: any, value: any) => {\n if (key === '$value') {\n return arr.indexOf(value);\n }\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i];\n if (item && item[key] ? item[key].toString() === value.toString() : undefined) {\n return i;\n }\n }\n return -1;\n};\n\nconst modifyKeyValue = (obj: any, key: any, value: any) => (obj[key] = value);\n\nconst addKeyValue = (obj: any, key: any, value: any) => {\n if (Array.isArray(obj)) {\n return obj.push(value);\n } else {\n return obj ? (obj[key] = value) : null;\n }\n};\n\nconst applyLeafChange = (obj: any, change: any, embeddedKey: any) => {\n const { type, key, value } = change;\n switch (type) {\n case Operation.ADD:\n return addKeyValue(obj, key, value);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey);\n }\n};\n\nconst applyArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(applyLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[subchange.key];\n } else if (change.embeddedKey === '$value') {\n const index = arr.indexOf(subchange.key);\n if (index !== -1) {\n element = arr[index];\n }\n } else {\n element = find(arr, (el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n result.push(applyChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst applyBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return applyArrayChange(obj, change);\n } else {\n return applyChangeset(obj, change.changes);\n }\n};\n\nconst revertLeafChange = (obj: any, change: any, embeddedKey = '$index') => {\n const { type, key, value, oldValue } = change;\n switch (type) {\n case Operation.ADD:\n return removeKey(obj, key, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, oldValue);\n case Operation.REMOVE:\n return addKeyValue(obj, key, value);\n }\n};\n\nconst revertArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(revertLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[+subchange.key];\n } else {\n element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key);\n }\n result.push(revertChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst revertBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return revertArrayChange(obj, change);\n } else {\n return revertChangeset(obj, change.changes);\n }\n};\n\n/** combine a base JSON Path with a subsequent segment */\nfunction append(basePath: string, nextSegment: string): string {\n return nextSegment.includes('.') ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;\n}\n\n/** returns a JSON Path filter expression; e.g., `$.pet[(?name='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string | FunctionKey, filterValue: string | number) {\n const value = typeof filterValue === 'number' ? filterValue : `'${filterValue}'`;\n return typeof filterKey === 'string' && filterKey.includes('.')\n ? `${basePath}[?(@[${filterKey}]==${value})]`\n : `${basePath}[?(@.${filterKey}==${value})]`;\n}\n\n","export function splitJSONPath(path: string): string[] {\n let parts: string[] = [];\n let currentPart = '';\n let inSingleQuotes = false;\n let inBrackets = 0;\n\n for (let i = 0; i < path.length; i++) {\n const char = path[i];\n\n if (char === \"'\" && path[i - 1] !== '\\\\') {\n // Toggle single quote flag if not escaped\n inSingleQuotes = !inSingleQuotes;\n } else if (char === '[' && !inSingleQuotes) {\n // Increase bracket nesting level\n inBrackets++;\n } else if (char === ']' && !inSingleQuotes) {\n // Decrease bracket nesting level\n inBrackets--;\n }\n\n if (char === '.' && !inSingleQuotes && inBrackets === 0) {\n // Split at period if not in quotes or brackets\n parts.push(currentPart);\n currentPart = '';\n } else {\n // Otherwise, keep adding to the current part\n currentPart += char;\n }\n }\n\n // Add the last part if there's any\n if (currentPart !== '') {\n parts.push(currentPart);\n }\n\n return parts;\n}\n","import { chain, keys, replace, set } from 'lodash';\nimport { diff, atomizeChangeset, getTypeOfObj, IAtomicChange, Operation } from './jsonDiff.js';\n\nexport enum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\nexport interface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nexport const createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nexport const createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nexport const enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return keys(object)\n .map((key: string) => ({ key, value: enrich(object[key]) }))\n .reduce((accumulator, entry) => {\n accumulator.value[entry.key] = entry.value;\n return accumulator;\n }, createContainer({}));\n case 'Array':\n return chain(object)\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]))\n .value();\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\nexport const applyChangelist = (\n object: IComparisonEnrichedNode,\n changelist: IAtomicChange[]\n): IComparisonEnrichedNode => {\n chain(changelist)\n .map((entry) => ({ ...entry, path: replace(entry.path, '$.', '.') }))\n .map((entry) => ({\n ...entry,\n path: replace(entry.path, /(\\[(?<array>\\d)\\]\\.)/g, 'ARRVAL_START$<array>ARRVAL_END')\n }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /(?<dot>\\.)/g, '.value$<dot>') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /\\./, '') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_START/g, '.value[') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_END/g, '].value.') }))\n .value()\n .forEach((entry) => {\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n set(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n set(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nexport const compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));\n};\n"],"mappings":"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","names":["compare","Operation","key","import_lodash","CompareOperation","compare"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -10,12 +10,12 @@ interface IChange {
|
|
|
10
10
|
type: Operation;
|
|
11
11
|
key: string;
|
|
12
12
|
embeddedKey?: string | FunctionKey;
|
|
13
|
-
value?: any
|
|
13
|
+
value?: any;
|
|
14
14
|
oldValue?: any;
|
|
15
15
|
changes?: IChange[];
|
|
16
16
|
}
|
|
17
17
|
type Changeset = IChange[];
|
|
18
|
-
interface
|
|
18
|
+
interface IAtomicChange {
|
|
19
19
|
type: Operation;
|
|
20
20
|
key: string;
|
|
21
21
|
path: string;
|
|
@@ -23,15 +23,20 @@ interface IFlatChange {
|
|
|
23
23
|
value?: any;
|
|
24
24
|
oldValue?: any;
|
|
25
25
|
}
|
|
26
|
+
interface Options {
|
|
27
|
+
embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;
|
|
28
|
+
keysToSkip?: string[];
|
|
29
|
+
treatTypeChangeAsReplace?: boolean;
|
|
30
|
+
}
|
|
26
31
|
/**
|
|
27
32
|
* Computes the difference between two objects.
|
|
28
33
|
*
|
|
29
34
|
* @param {any} oldObj - The original object.
|
|
30
35
|
* @param {any} newObj - The updated object.
|
|
31
|
-
* @param {
|
|
36
|
+
* @param {Options} options - An optional parameter specifying keys of embedded objects and keys to skip.
|
|
32
37
|
* @returns {IChange[]} - An array of changes that transform the old object into the new object.
|
|
33
38
|
*/
|
|
34
|
-
declare function diff(oldObj: any, newObj: any,
|
|
39
|
+
declare function diff(oldObj: any, newObj: any, options?: Options): IChange[];
|
|
35
40
|
/**
|
|
36
41
|
* Applies all changes in the changeset to the object.
|
|
37
42
|
*
|
|
@@ -57,23 +62,23 @@ declare const applyChangeset: (obj: any, changeset: Changeset) => any;
|
|
|
57
62
|
*/
|
|
58
63
|
declare const revertChangeset: (obj: any, changeset: Changeset) => any;
|
|
59
64
|
/**
|
|
60
|
-
*
|
|
65
|
+
* Atomize a changeset into an array of single changes.
|
|
61
66
|
*
|
|
62
67
|
* @param {Changeset | IChange} obj - The changeset or change to flatten.
|
|
63
68
|
* @param {string} [path='$'] - The current path in the changeset.
|
|
64
69
|
* @param {string | FunctionKey} [embeddedKey] - The key to use for embedded objects.
|
|
65
|
-
* @returns {
|
|
70
|
+
* @returns {IAtomicChange[]} - An array of atomic changes.
|
|
66
71
|
*
|
|
67
|
-
* The function first checks if the input is an array. If so, it recursively
|
|
72
|
+
* The function first checks if the input is an array. If so, it recursively atomize each change in the array.
|
|
68
73
|
* If the input is not an array, it checks if the change has nested changes or an embedded key.
|
|
69
74
|
* If so, it updates the path and recursively flattens the nested changes or the embedded object.
|
|
70
|
-
* If the change does not have nested changes or an embedded key, it creates a
|
|
75
|
+
* If the change does not have nested changes or an embedded key, it creates a atomic change and returns it in an array.
|
|
71
76
|
*/
|
|
72
|
-
declare const
|
|
77
|
+
declare const atomizeChangeset: (obj: Changeset | IChange, path?: string, embeddedKey?: string | FunctionKey) => IAtomicChange[];
|
|
73
78
|
/**
|
|
74
|
-
* Transforms
|
|
79
|
+
* Transforms an atomized changeset into a nested changeset.
|
|
75
80
|
*
|
|
76
|
-
* @param {
|
|
81
|
+
* @param {IAtomicChange | IAtomicChange[]} changes - The atomic changeset to unflatten.
|
|
77
82
|
* @returns {IChange[]} - The unflattened changeset.
|
|
78
83
|
*
|
|
79
84
|
* The function first checks if the input is a single change or an array of changes.
|
|
@@ -83,7 +88,7 @@ declare const flattenChangeset: (obj: Changeset | IChange, path?: string, embedd
|
|
|
83
88
|
* If it represents a leaf node, it sets the key, type, value, and oldValue of the current change object.
|
|
84
89
|
* Finally, it pushes the unflattened change object into the changes array.
|
|
85
90
|
*/
|
|
86
|
-
declare const
|
|
91
|
+
declare const unatomizeChangeset: (changes: IAtomicChange | IAtomicChange[]) => IChange[];
|
|
87
92
|
/**
|
|
88
93
|
* Determines the type of a given object.
|
|
89
94
|
*
|
|
@@ -109,7 +114,7 @@ declare const createValue: (value: any) => IComparisonEnrichedNode;
|
|
|
109
114
|
declare const createContainer: (value: object | [
|
|
110
115
|
]) => IComparisonEnrichedNode;
|
|
111
116
|
declare const enrich: (object: any) => IComparisonEnrichedNode;
|
|
112
|
-
declare const applyChangelist: (object: IComparisonEnrichedNode, changelist:
|
|
117
|
+
declare const applyChangelist: (object: IComparisonEnrichedNode, changelist: IAtomicChange[]) => IComparisonEnrichedNode;
|
|
113
118
|
declare const compare: (oldObject: any, newObject: any) => IComparisonEnrichedNode;
|
|
114
119
|
|
|
115
|
-
export { type Changeset, CompareOperation, type EmbeddedObjKeysMapType, type EmbeddedObjKeysType, type
|
|
120
|
+
export { type Changeset, CompareOperation, type EmbeddedObjKeysMapType, type EmbeddedObjKeysType, type IAtomicChange, type IChange, type IComparisonEnrichedNode, Operation, type Options, applyChangelist, applyChangeset, atomizeChangeset, compare, createContainer, createValue, diff, enrich, getTypeOfObj, revertChangeset, unatomizeChangeset };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,12 +10,12 @@ interface IChange {
|
|
|
10
10
|
type: Operation;
|
|
11
11
|
key: string;
|
|
12
12
|
embeddedKey?: string | FunctionKey;
|
|
13
|
-
value?: any
|
|
13
|
+
value?: any;
|
|
14
14
|
oldValue?: any;
|
|
15
15
|
changes?: IChange[];
|
|
16
16
|
}
|
|
17
17
|
type Changeset = IChange[];
|
|
18
|
-
interface
|
|
18
|
+
interface IAtomicChange {
|
|
19
19
|
type: Operation;
|
|
20
20
|
key: string;
|
|
21
21
|
path: string;
|
|
@@ -23,15 +23,20 @@ interface IFlatChange {
|
|
|
23
23
|
value?: any;
|
|
24
24
|
oldValue?: any;
|
|
25
25
|
}
|
|
26
|
+
interface Options {
|
|
27
|
+
embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;
|
|
28
|
+
keysToSkip?: string[];
|
|
29
|
+
treatTypeChangeAsReplace?: boolean;
|
|
30
|
+
}
|
|
26
31
|
/**
|
|
27
32
|
* Computes the difference between two objects.
|
|
28
33
|
*
|
|
29
34
|
* @param {any} oldObj - The original object.
|
|
30
35
|
* @param {any} newObj - The updated object.
|
|
31
|
-
* @param {
|
|
36
|
+
* @param {Options} options - An optional parameter specifying keys of embedded objects and keys to skip.
|
|
32
37
|
* @returns {IChange[]} - An array of changes that transform the old object into the new object.
|
|
33
38
|
*/
|
|
34
|
-
declare function diff(oldObj: any, newObj: any,
|
|
39
|
+
declare function diff(oldObj: any, newObj: any, options?: Options): IChange[];
|
|
35
40
|
/**
|
|
36
41
|
* Applies all changes in the changeset to the object.
|
|
37
42
|
*
|
|
@@ -57,23 +62,23 @@ declare const applyChangeset: (obj: any, changeset: Changeset) => any;
|
|
|
57
62
|
*/
|
|
58
63
|
declare const revertChangeset: (obj: any, changeset: Changeset) => any;
|
|
59
64
|
/**
|
|
60
|
-
*
|
|
65
|
+
* Atomize a changeset into an array of single changes.
|
|
61
66
|
*
|
|
62
67
|
* @param {Changeset | IChange} obj - The changeset or change to flatten.
|
|
63
68
|
* @param {string} [path='$'] - The current path in the changeset.
|
|
64
69
|
* @param {string | FunctionKey} [embeddedKey] - The key to use for embedded objects.
|
|
65
|
-
* @returns {
|
|
70
|
+
* @returns {IAtomicChange[]} - An array of atomic changes.
|
|
66
71
|
*
|
|
67
|
-
* The function first checks if the input is an array. If so, it recursively
|
|
72
|
+
* The function first checks if the input is an array. If so, it recursively atomize each change in the array.
|
|
68
73
|
* If the input is not an array, it checks if the change has nested changes or an embedded key.
|
|
69
74
|
* If so, it updates the path and recursively flattens the nested changes or the embedded object.
|
|
70
|
-
* If the change does not have nested changes or an embedded key, it creates a
|
|
75
|
+
* If the change does not have nested changes or an embedded key, it creates a atomic change and returns it in an array.
|
|
71
76
|
*/
|
|
72
|
-
declare const
|
|
77
|
+
declare const atomizeChangeset: (obj: Changeset | IChange, path?: string, embeddedKey?: string | FunctionKey) => IAtomicChange[];
|
|
73
78
|
/**
|
|
74
|
-
* Transforms
|
|
79
|
+
* Transforms an atomized changeset into a nested changeset.
|
|
75
80
|
*
|
|
76
|
-
* @param {
|
|
81
|
+
* @param {IAtomicChange | IAtomicChange[]} changes - The atomic changeset to unflatten.
|
|
77
82
|
* @returns {IChange[]} - The unflattened changeset.
|
|
78
83
|
*
|
|
79
84
|
* The function first checks if the input is a single change or an array of changes.
|
|
@@ -83,7 +88,7 @@ declare const flattenChangeset: (obj: Changeset | IChange, path?: string, embedd
|
|
|
83
88
|
* If it represents a leaf node, it sets the key, type, value, and oldValue of the current change object.
|
|
84
89
|
* Finally, it pushes the unflattened change object into the changes array.
|
|
85
90
|
*/
|
|
86
|
-
declare const
|
|
91
|
+
declare const unatomizeChangeset: (changes: IAtomicChange | IAtomicChange[]) => IChange[];
|
|
87
92
|
/**
|
|
88
93
|
* Determines the type of a given object.
|
|
89
94
|
*
|
|
@@ -109,7 +114,7 @@ declare const createValue: (value: any) => IComparisonEnrichedNode;
|
|
|
109
114
|
declare const createContainer: (value: object | [
|
|
110
115
|
]) => IComparisonEnrichedNode;
|
|
111
116
|
declare const enrich: (object: any) => IComparisonEnrichedNode;
|
|
112
|
-
declare const applyChangelist: (object: IComparisonEnrichedNode, changelist:
|
|
117
|
+
declare const applyChangelist: (object: IComparisonEnrichedNode, changelist: IAtomicChange[]) => IComparisonEnrichedNode;
|
|
113
118
|
declare const compare: (oldObject: any, newObject: any) => IComparisonEnrichedNode;
|
|
114
119
|
|
|
115
|
-
export { type Changeset, CompareOperation, type EmbeddedObjKeysMapType, type EmbeddedObjKeysType, type
|
|
120
|
+
export { type Changeset, CompareOperation, type EmbeddedObjKeysMapType, type EmbeddedObjKeysType, type IAtomicChange, type IChange, type IComparisonEnrichedNode, Operation, type Options, applyChangelist, applyChangeset, atomizeChangeset, compare, createContainer, createValue, diff, enrich, getTypeOfObj, revertChangeset, unatomizeChangeset };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
// src/jsonDiff.ts
|
|
2
2
|
import { difference, find, intersection, keyBy } from "lodash";
|
|
3
|
+
|
|
4
|
+
// src/helpers.ts
|
|
5
|
+
function splitJSONPath(path) {
|
|
6
|
+
let parts = [];
|
|
7
|
+
let currentPart = "";
|
|
8
|
+
let inSingleQuotes = false;
|
|
9
|
+
let inBrackets = 0;
|
|
10
|
+
for (let i = 0; i < path.length; i++) {
|
|
11
|
+
const char = path[i];
|
|
12
|
+
if (char === "'" && path[i - 1] !== "\\") {
|
|
13
|
+
inSingleQuotes = !inSingleQuotes;
|
|
14
|
+
} else if (char === "[" && !inSingleQuotes) {
|
|
15
|
+
inBrackets++;
|
|
16
|
+
} else if (char === "]" && !inSingleQuotes) {
|
|
17
|
+
inBrackets--;
|
|
18
|
+
}
|
|
19
|
+
if (char === "." && !inSingleQuotes && inBrackets === 0) {
|
|
20
|
+
parts.push(currentPart);
|
|
21
|
+
currentPart = "";
|
|
22
|
+
} else {
|
|
23
|
+
currentPart += char;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (currentPart !== "") {
|
|
27
|
+
parts.push(currentPart);
|
|
28
|
+
}
|
|
29
|
+
return parts;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/jsonDiff.ts
|
|
3
33
|
var Operation = /* @__PURE__ */ ((Operation2) => {
|
|
4
34
|
Operation2["REMOVE"] = "REMOVE";
|
|
5
35
|
Operation2["ADD"] = "ADD";
|
|
6
36
|
Operation2["UPDATE"] = "UPDATE";
|
|
7
37
|
return Operation2;
|
|
8
38
|
})(Operation || {});
|
|
9
|
-
function diff(oldObj, newObj,
|
|
39
|
+
function diff(oldObj, newObj, options = {}) {
|
|
40
|
+
let { embeddedObjKeys, keysToSkip, treatTypeChangeAsReplace } = options;
|
|
10
41
|
if (embeddedObjKeys instanceof Map) {
|
|
11
42
|
embeddedObjKeys = new Map(
|
|
12
43
|
Array.from(embeddedObjKeys.entries()).map(([key, value]) => [
|
|
@@ -19,7 +50,11 @@ function diff(oldObj, newObj, embeddedObjKeys, keysToSkip) {
|
|
|
19
50
|
Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\./, ""), value])
|
|
20
51
|
);
|
|
21
52
|
}
|
|
22
|
-
return compare(oldObj, newObj, [],
|
|
53
|
+
return compare(oldObj, newObj, [], [], {
|
|
54
|
+
embeddedObjKeys,
|
|
55
|
+
keysToSkip: keysToSkip ?? [],
|
|
56
|
+
treatTypeChangeAsReplace: treatTypeChangeAsReplace ?? true
|
|
57
|
+
});
|
|
23
58
|
}
|
|
24
59
|
var applyChangeset = (obj, changeset) => {
|
|
25
60
|
if (changeset) {
|
|
@@ -42,45 +77,55 @@ var revertChangeset = (obj, changeset) => {
|
|
|
42
77
|
}
|
|
43
78
|
return obj;
|
|
44
79
|
};
|
|
45
|
-
var
|
|
80
|
+
var atomizeChangeset = (obj, path = "$", embeddedKey) => {
|
|
46
81
|
if (Array.isArray(obj)) {
|
|
47
|
-
return obj
|
|
48
|
-
} else {
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
path = `${path}[?(@='${obj.key}')]`;
|
|
55
|
-
const valueType = getTypeOfObj(obj.value);
|
|
56
|
-
return [
|
|
57
|
-
{
|
|
58
|
-
...obj,
|
|
59
|
-
path,
|
|
60
|
-
valueType
|
|
61
|
-
}
|
|
62
|
-
];
|
|
63
|
-
} else if (obj.type === "ADD" /* ADD */) {
|
|
64
|
-
} else {
|
|
65
|
-
path = filterExpression(path, embeddedKey, obj.key);
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
path = append(path, obj.key);
|
|
82
|
+
return handleArray(obj, path, embeddedKey);
|
|
83
|
+
} else if (obj.changes || embeddedKey) {
|
|
84
|
+
if (embeddedKey) {
|
|
85
|
+
const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path);
|
|
86
|
+
path = updatedPath;
|
|
87
|
+
if (atomicChange) {
|
|
88
|
+
return atomicChange;
|
|
69
89
|
}
|
|
70
|
-
return flattenChangeset(obj.changes || obj, path, obj.embeddedKey);
|
|
71
90
|
} else {
|
|
72
|
-
|
|
73
|
-
return [
|
|
74
|
-
{
|
|
75
|
-
...obj,
|
|
76
|
-
path: valueType === "Object" || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),
|
|
77
|
-
valueType
|
|
78
|
-
}
|
|
79
|
-
];
|
|
91
|
+
path = append(path, obj.key);
|
|
80
92
|
}
|
|
93
|
+
return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey);
|
|
94
|
+
} else {
|
|
95
|
+
const valueType = getTypeOfObj(obj.value);
|
|
96
|
+
return [{
|
|
97
|
+
...obj,
|
|
98
|
+
path: valueType === "Object" || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),
|
|
99
|
+
valueType
|
|
100
|
+
}];
|
|
81
101
|
}
|
|
82
102
|
};
|
|
83
|
-
|
|
103
|
+
function handleEmbeddedKey(embeddedKey, obj, path) {
|
|
104
|
+
if (embeddedKey === "$index") {
|
|
105
|
+
path = `${path}[${obj.key}]`;
|
|
106
|
+
return [path];
|
|
107
|
+
} else if (embeddedKey === "$value") {
|
|
108
|
+
path = `${path}[?(@=='${obj.key}')]`;
|
|
109
|
+
const valueType = getTypeOfObj(obj.value);
|
|
110
|
+
return [
|
|
111
|
+
path,
|
|
112
|
+
[{
|
|
113
|
+
...obj,
|
|
114
|
+
path,
|
|
115
|
+
valueType
|
|
116
|
+
}]
|
|
117
|
+
];
|
|
118
|
+
} else if (obj.type === "ADD" /* ADD */) {
|
|
119
|
+
return [path];
|
|
120
|
+
} else {
|
|
121
|
+
path = filterExpression(path, embeddedKey, obj.key);
|
|
122
|
+
return [path];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
var handleArray = (obj, path, embeddedKey) => {
|
|
126
|
+
return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey)], []);
|
|
127
|
+
};
|
|
128
|
+
var unatomizeChangeset = (changes) => {
|
|
84
129
|
if (!Array.isArray(changes)) {
|
|
85
130
|
changes = [changes];
|
|
86
131
|
}
|
|
@@ -88,7 +133,7 @@ var unflattenChanges = (changes) => {
|
|
|
88
133
|
changes.forEach((change) => {
|
|
89
134
|
const obj = {};
|
|
90
135
|
let ptr = obj;
|
|
91
|
-
const segments = change.path
|
|
136
|
+
const segments = splitJSONPath(change.path);
|
|
92
137
|
if (segments.length === 1) {
|
|
93
138
|
ptr.key = change.key;
|
|
94
139
|
ptr.type = change.type;
|
|
@@ -98,7 +143,7 @@ var unflattenChanges = (changes) => {
|
|
|
98
143
|
} else {
|
|
99
144
|
for (let i = 1; i < segments.length; i++) {
|
|
100
145
|
const segment = segments[i];
|
|
101
|
-
const result = /^(
|
|
146
|
+
const result = /^([^[\]]+)\[\?\(@\.?([^=]*)=+'([^']+)'\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
|
|
102
147
|
if (result) {
|
|
103
148
|
let key;
|
|
104
149
|
let embeddedKey;
|
|
@@ -110,7 +155,7 @@ var unflattenChanges = (changes) => {
|
|
|
110
155
|
} else {
|
|
111
156
|
key = result[4];
|
|
112
157
|
embeddedKey = "$index";
|
|
113
|
-
arrKey = Number(result[
|
|
158
|
+
arrKey = Number(result[5]);
|
|
114
159
|
}
|
|
115
160
|
if (i === segments.length - 1) {
|
|
116
161
|
ptr.key = key;
|
|
@@ -183,15 +228,19 @@ var getKey = (path) => {
|
|
|
183
228
|
const left = path[path.length - 1];
|
|
184
229
|
return left != null ? left : "$root";
|
|
185
230
|
};
|
|
186
|
-
var compare = (oldObj, newObj, path,
|
|
231
|
+
var compare = (oldObj, newObj, path, keyPath, options) => {
|
|
187
232
|
let changes = [];
|
|
188
233
|
const typeOfOldObj = getTypeOfObj(oldObj);
|
|
189
234
|
const typeOfNewObj = getTypeOfObj(newObj);
|
|
190
|
-
if (typeOfOldObj !== typeOfNewObj) {
|
|
235
|
+
if (options.treatTypeChangeAsReplace && typeOfOldObj !== typeOfNewObj) {
|
|
191
236
|
changes.push({ type: "REMOVE" /* REMOVE */, key: getKey(path), value: oldObj });
|
|
192
237
|
changes.push({ type: "ADD" /* ADD */, key: getKey(path), value: newObj });
|
|
193
238
|
return changes;
|
|
194
239
|
}
|
|
240
|
+
if (typeOfNewObj === "Object" && typeOfOldObj === "Array") {
|
|
241
|
+
changes.push({ type: "UPDATE" /* UPDATE */, key: getKey(path), value: newObj, oldValue: oldObj });
|
|
242
|
+
return changes;
|
|
243
|
+
}
|
|
195
244
|
switch (typeOfOldObj) {
|
|
196
245
|
case "Date":
|
|
197
246
|
changes = changes.concat(
|
|
@@ -202,8 +251,8 @@ var compare = (oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip) => {
|
|
|
202
251
|
}))
|
|
203
252
|
);
|
|
204
253
|
break;
|
|
205
|
-
case "Object":
|
|
206
|
-
const diffs = compareObject(oldObj, newObj, path,
|
|
254
|
+
case "Object": {
|
|
255
|
+
const diffs = compareObject(oldObj, newObj, path, keyPath, false, options);
|
|
207
256
|
if (diffs.length) {
|
|
208
257
|
if (path.length) {
|
|
209
258
|
changes.push({
|
|
@@ -216,8 +265,9 @@ var compare = (oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip) => {
|
|
|
216
265
|
}
|
|
217
266
|
}
|
|
218
267
|
break;
|
|
268
|
+
}
|
|
219
269
|
case "Array":
|
|
220
|
-
changes = changes.concat(compareArray(oldObj, newObj, path,
|
|
270
|
+
changes = changes.concat(compareArray(oldObj, newObj, path, keyPath, options));
|
|
221
271
|
break;
|
|
222
272
|
case "Function":
|
|
223
273
|
break;
|
|
@@ -226,7 +276,7 @@ var compare = (oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip) => {
|
|
|
226
276
|
}
|
|
227
277
|
return changes;
|
|
228
278
|
};
|
|
229
|
-
var compareObject = (oldObj, newObj, path,
|
|
279
|
+
var compareObject = (oldObj, newObj, path, keyPath, skipPath = false, options = {}) => {
|
|
230
280
|
let k;
|
|
231
281
|
let newKeyPath;
|
|
232
282
|
let newPath;
|
|
@@ -234,13 +284,13 @@ var compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath =
|
|
|
234
284
|
skipPath = false;
|
|
235
285
|
}
|
|
236
286
|
let changes = [];
|
|
237
|
-
const oldObjKeys = Object.keys(oldObj).filter((key) => keysToSkip.indexOf(key) === -1);
|
|
238
|
-
const newObjKeys = Object.keys(newObj).filter((key) => keysToSkip.indexOf(key) === -1);
|
|
287
|
+
const oldObjKeys = Object.keys(oldObj).filter((key) => options.keysToSkip.indexOf(key) === -1);
|
|
288
|
+
const newObjKeys = Object.keys(newObj).filter((key) => options.keysToSkip.indexOf(key) === -1);
|
|
239
289
|
const intersectionKeys = intersection(oldObjKeys, newObjKeys);
|
|
240
290
|
for (k of intersectionKeys) {
|
|
241
291
|
newPath = path.concat([k]);
|
|
242
292
|
newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
|
|
243
|
-
const diffs = compare(oldObj[k], newObj[k], newPath,
|
|
293
|
+
const diffs = compare(oldObj[k], newObj[k], newPath, newKeyPath, options);
|
|
244
294
|
if (diffs.length) {
|
|
245
295
|
changes = changes.concat(diffs);
|
|
246
296
|
}
|
|
@@ -267,12 +317,12 @@ var compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath =
|
|
|
267
317
|
}
|
|
268
318
|
return changes;
|
|
269
319
|
};
|
|
270
|
-
var compareArray = (oldObj, newObj, path,
|
|
271
|
-
const left = getObjectKey(embeddedObjKeys, keyPath);
|
|
320
|
+
var compareArray = (oldObj, newObj, path, keyPath, options) => {
|
|
321
|
+
const left = getObjectKey(options.embeddedObjKeys, keyPath);
|
|
272
322
|
const uniqKey = left != null ? left : "$index";
|
|
273
323
|
const indexedOldObj = convertArrayToObj(oldObj, uniqKey);
|
|
274
324
|
const indexedNewObj = convertArrayToObj(newObj, uniqKey);
|
|
275
|
-
const diffs = compareObject(indexedOldObj, indexedNewObj, path,
|
|
325
|
+
const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);
|
|
276
326
|
if (diffs.length) {
|
|
277
327
|
return [
|
|
278
328
|
{
|
|
@@ -508,21 +558,21 @@ var applyChangelist = (object, changelist) => {
|
|
|
508
558
|
return object;
|
|
509
559
|
};
|
|
510
560
|
var compare2 = (oldObject, newObject) => {
|
|
511
|
-
return applyChangelist(enrich(oldObject),
|
|
561
|
+
return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));
|
|
512
562
|
};
|
|
513
563
|
export {
|
|
514
564
|
CompareOperation,
|
|
515
565
|
Operation,
|
|
516
566
|
applyChangelist,
|
|
517
567
|
applyChangeset,
|
|
568
|
+
atomizeChangeset,
|
|
518
569
|
compare2 as compare,
|
|
519
570
|
createContainer,
|
|
520
571
|
createValue,
|
|
521
572
|
diff,
|
|
522
573
|
enrich,
|
|
523
|
-
flattenChangeset,
|
|
524
574
|
getTypeOfObj,
|
|
525
575
|
revertChangeset,
|
|
526
|
-
|
|
576
|
+
unatomizeChangeset
|
|
527
577
|
};
|
|
528
578
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/jsonDiff.ts","../src/jsonCompare.ts"],"sourcesContent":["import { difference, find, intersection, keyBy } from 'lodash';\n\ntype FunctionKey = (obj: any, shouldReturnKeyName?: boolean) => any;\nexport type EmbeddedObjKeysType = Record<string, string | FunctionKey>;\nexport type EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nexport enum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\nexport interface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n value?: any | any[];\n oldValue?: any;\n changes?: IChange[];\n}\nexport type Changeset = IChange[];\n\nexport interface IFlatChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\n/**\n * Computes the difference between two objects.\n *\n * @param {any} oldObj - The original object.\n * @param {any} newObj - The updated object.\n * @param {EmbeddedObjKeysType | EmbeddedObjKeysMapType} embeddedObjKeys - An optional parameter specifying keys of embedded objects.\n * @returns {IChange[]} - An array of changes that transform the old object into the new object.\n */\nexport function diff(\n oldObj: any,\n newObj: any,\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType,\n keysToSkip?: string[]\n): IChange[] {\n // Trim leading '.' from keys in embeddedObjKeys\n if (embeddedObjKeys instanceof Map) {\n embeddedObjKeys = new Map(\n Array.from(embeddedObjKeys.entries()).map(([key, value]) => [\n key instanceof RegExp ? key : key.replace(/^\\./, ''),\n value\n ])\n );\n } else if (embeddedObjKeys) {\n embeddedObjKeys = Object.fromEntries(\n Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\\./, ''), value])\n );\n }\n\n // Compare old and new objects to generate a list of changes\n return compare(oldObj, newObj, [], embeddedObjKeys, [], keysToSkip);\n}\n\n/**\n * Applies all changes in the changeset to the object.\n *\n * @param {any} obj - The object to apply changes to.\n * @param {Changeset} changeset - The changeset to apply.\n * @returns {any} - The object after the changes from the changeset have been applied.\n *\n * The function first checks if a changeset is provided. If so, it iterates over each change in the changeset.\n * If the change value is not null or undefined, or if the change type is REMOVE, it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nexport const applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n if ((value !== null && value !== undefined) || type === Operation.REMOVE) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n applyBranchChange(obj[key], change);\n }\n });\n }\n return obj;\n};\n\n/**\n * Reverts the changes made to an object based on a given changeset.\n *\n * @param {any} obj - The object on which to revert changes.\n * @param {Changeset} changeset - The changeset to revert.\n * @returns {any} - The object after the changes from the changeset have been reverted.\n *\n * The function first checks if a changeset is provided. If so, it reverses the changeset to start reverting from the last change.\n * It then iterates over each change in the changeset. If the change does not have any nested changes, it reverts the change on the object directly.\n * If the change does have nested changes, it reverts the changes on the corresponding branch of the object.\n */\nexport const revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any =>\n !change.changes ? revertLeafChange(obj, change) : revertBranchChange(obj[change.key], change)\n );\n }\n\n return obj;\n};\n\n/**\n * Flattens a changeset into an array of flat changes.\n *\n * @param {Changeset | IChange} obj - The changeset or change to flatten.\n * @param {string} [path='$'] - The current path in the changeset.\n * @param {string | FunctionKey} [embeddedKey] - The key to use for embedded objects.\n * @returns {IFlatChange[]} - An array of flat changes.\n *\n * The function first checks if the input is an array. If so, it recursively flattens each change in the array.\n * If the input is not an array, it checks if the change has nested changes or an embedded key.\n * If so, it updates the path and recursively flattens the nested changes or the embedded object.\n * If the change does not have nested changes or an embedded key, it creates a flat change and returns it in an array.\n */\nexport const flattenChangeset = (\n obj: Changeset | IChange,\n path = '$',\n embeddedKey?: string | FunctionKey\n): IFlatChange[] => {\n if (Array.isArray(obj)) {\n return obj.reduce((memo, change) => [...memo, ...flattenChangeset(change, path, embeddedKey)], [] as IFlatChange[]);\n } else {\n if (obj.changes || embeddedKey) {\n if (embeddedKey) {\n if (embeddedKey === '$index') {\n path = `${path}[${obj.key}]`;\n } else if (embeddedKey === '$value') {\n path = `${path}[?(@='${obj.key}')]`;\n const valueType = getTypeOfObj(obj.value);\n return [\n {\n ...obj,\n path,\n valueType\n }\n ];\n } else if (obj.type === Operation.ADD) {\n // do nothing\n } else {\n path = filterExpression(path, embeddedKey, obj.key);\n }\n } else {\n path = append(path, obj.key);\n }\n\n return flattenChangeset(obj.changes || obj, path, obj.embeddedKey);\n } else {\n const valueType = getTypeOfObj(obj.value);\n return [\n {\n ...obj,\n path: valueType === 'Object' || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),\n valueType\n }\n ];\n }\n }\n};\n\n/**\n * Transforms a flat changeset into a nested changeset.\n *\n * @param {IFlatChange | IFlatChange[]} changes - The flat changeset to unflatten.\n * @returns {IChange[]} - The unflattened changeset.\n *\n * The function first checks if the input is a single change or an array of changes.\n * It then iterates over each change and splits its path into segments.\n * For each segment, it checks if it represents an array or a leaf node.\n * If it represents an array, it creates a new change object and updates the pointer to this new object.\n * If it represents a leaf node, it sets the key, type, value, and oldValue of the current change object.\n * Finally, it pushes the unflattened change object into the changes array.\n */\nexport const unflattenChanges = (changes: IFlatChange | IFlatChange[]) => {\n if (!Array.isArray(changes)) {\n changes = [changes];\n }\n\n const changesArr: IChange[] = [];\n\n changes.forEach((change) => {\n const obj = {} as IChange;\n let ptr = obj;\n\n const segments = change.path.split(/(?<=[^@])\\.(?=[^@])/);\n\n if (segments.length === 1) {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n changesArr.push(ptr);\n } else {\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i];\n // Matches JSONPath segments: \"items[?(@.id=='123')]\", \"items[?(@.id==123)]\", \"items[2]\", \"items[?(@='123')]\"\n const result = /^(.+?)\\[\\?\\(@.?(?:([^=]*))?={1,2}'(.*)'\\)\\]$|^(.+?)\\[(\\d+)\\]$/.exec(segment); //NOSONAR\n // array\n if (result) {\n let key: string;\n let embeddedKey: string;\n let arrKey: string | number;\n if (result[1]) {\n key = result[1];\n embeddedKey = result[2] || '$value';\n arrKey = result[3];\n } else {\n key = result[4];\n embeddedKey = '$index';\n arrKey = Number(result[4]);\n }\n // leaf\n if (i === segments.length - 1) {\n ptr.key = key!;\n ptr.embeddedKey = embeddedKey!;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n type: change.type,\n key: arrKey!,\n value: change.value,\n oldValue: change.oldValue\n } as IChange\n ];\n } else {\n // object\n ptr.key = key;\n ptr.embeddedKey = embeddedKey;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [\n {\n type: Operation.UPDATE,\n key: arrKey,\n changes: [newPtr]\n } as IChange\n ];\n ptr = newPtr;\n }\n } else {\n // leaf\n if (i === segments.length - 1) {\n // check if value is a primitive or object\n if (change.value !== null && change.valueType === 'Object') {\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n key: change.key,\n type: change.type,\n value: change.value\n } as IChange\n ];\n } else {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n }\n } else {\n // branch\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [newPtr];\n ptr = newPtr;\n }\n }\n }\n changesArr.push(obj);\n }\n });\n return changesArr;\n};\n\n/**\n * Determines the type of a given object.\n *\n * @param {any} obj - The object whose type is to be determined.\n * @returns {string | null} - The type of the object, or null if the object is null.\n *\n * This function first checks if the object is undefined or null, and returns 'undefined' or null respectively.\n * If the object is neither undefined nor null, it uses Object.prototype.toString to get the object's type.\n * The type is extracted from the string returned by Object.prototype.toString using a regular expression.\n */\nexport const getTypeOfObj = (obj: any) => {\n if (typeof obj === 'undefined') {\n return 'undefined';\n }\n\n if (obj === null) {\n return null;\n }\n\n // Extracts the \"Type\" from \"[object Type]\" string.\n return Object.prototype.toString.call(obj).match(/^\\[object\\s(.*)\\]$/)[1];\n};\n\nconst getKey = (path: string) => {\n const left = path[path.length - 1];\n return left != null ? left : '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, embeddedObjKeys: any, keyPath: any, keysToSkip: string[]) => {\n let changes: any[] = [];\n\n const typeOfOldObj = getTypeOfObj(oldObj);\n const typeOfNewObj = getTypeOfObj(newObj);\n\n // if type of object changes, consider it as old obj has been deleted and a new object has been added\n if (typeOfOldObj !== typeOfNewObj) {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n changes = changes.concat(\n comparePrimitives(oldObj.getTime(), newObj.getTime(), path).map((x) => ({\n ...x,\n value: new Date(x.value),\n oldValue: new Date(x.oldValue)\n }))\n );\n break;\n case 'Object':\n const diffs = compareObject(oldObj, newObj, path, embeddedObjKeys, keyPath, false, keysToSkip);\n if (diffs.length) {\n if (path.length) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n changes: diffs\n });\n } else {\n changes = changes.concat(diffs);\n }\n }\n break;\n case 'Array':\n changes = changes.concat(compareArray(oldObj, newObj, path, embeddedObjKeys, keyPath, keysToSkip));\n break;\n case 'Function':\n break;\n // do nothing\n default:\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n\n return changes;\n};\n\nconst compareObject = (\n oldObj: any,\n newObj: any,\n path: any,\n embeddedObjKeys: any,\n keyPath: any,\n skipPath = false,\n keysToSkip: string[] = []\n) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n const oldObjKeys = Object.keys(oldObj).filter((key) => keysToSkip.indexOf(key) === -1);\n const newObjKeys = Object.keys(newObj).filter((key) => keysToSkip.indexOf(key) === -1);\n\n const intersectionKeys = intersection(oldObjKeys, newObjKeys);\n for (k of intersectionKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n const diffs = compare(oldObj[k], newObj[k], newPath, embeddedObjKeys, newKeyPath, keysToSkip);\n if (diffs.length) {\n changes = changes.concat(diffs);\n }\n }\n\n const addedKeys = difference(newObjKeys, oldObjKeys);\n for (k of addedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.ADD,\n key: getKey(newPath),\n value: newObj[k]\n });\n }\n\n const deletedKeys = difference(oldObjKeys, newObjKeys);\n for (k of deletedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (\n oldObj: any,\n newObj: any,\n path: any,\n embeddedObjKeys: any,\n keyPath: any,\n keysToSkip: string[]\n) => {\n const left = getObjectKey(embeddedObjKeys, keyPath);\n const uniqKey = left != null ? left : '$index';\n const indexedOldObj = convertArrayToObj(oldObj, uniqKey);\n const indexedNewObj = convertArrayToObj(newObj, uniqKey);\n const diffs = compareObject(indexedOldObj, indexedNewObj, path, embeddedObjKeys, keyPath, true, keysToSkip);\n if (diffs.length) {\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: typeof uniqKey === 'function' && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,\n changes: diffs\n }\n ];\n } else {\n return [];\n }\n};\n\nconst getObjectKey = (embeddedObjKeys: any, keyPath: any) => {\n if (embeddedObjKeys != null) {\n const path = keyPath.join('.');\n\n if (embeddedObjKeys instanceof Map) {\n for (const [key, value] of embeddedObjKeys.entries()) {\n if (key instanceof RegExp) {\n if (path.match(key)) {\n return value;\n }\n } else if (path === key) {\n return value;\n }\n }\n }\n\n const key = embeddedObjKeys[path];\n if (key != null) {\n return key;\n }\n }\n return undefined;\n};\n\nconst convertArrayToObj = (arr: any[], uniqKey: any) => {\n let obj: any = {};\n if (uniqKey === '$value') {\n arr.forEach((value) => {\n obj[value] = value;\n });\n } else if (uniqKey !== '$index') {\n obj = keyBy(arr, uniqKey);\n } else {\n for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n }\n return obj;\n};\n\nconst comparePrimitives = (oldObj: any, newObj: any, path: any) => {\n const changes = [];\n if (oldObj !== newObj) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n value: newObj,\n oldValue: oldObj\n });\n }\n return changes;\n};\n\nconst removeKey = (obj: any, key: any, embeddedKey: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(key);\n return;\n }\n const index = indexOfItemInArray(obj, embeddedKey, key);\n if (index === -1) {\n // tslint:disable-next-line:no-console\n console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array'`);\n return;\n }\n return obj.splice(index != null ? index : key, 1);\n } else {\n obj[key] = undefined;\n delete obj[key];\n return;\n }\n};\n\nconst indexOfItemInArray = (arr: any[], key: any, value: any) => {\n if (key === '$value') {\n return arr.indexOf(value);\n }\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i];\n if (item && item[key] ? item[key].toString() === value.toString() : undefined) {\n return i;\n }\n }\n return -1;\n};\n\nconst modifyKeyValue = (obj: any, key: any, value: any) => (obj[key] = value);\n\nconst addKeyValue = (obj: any, key: any, value: any) => {\n if (Array.isArray(obj)) {\n return obj.push(value);\n } else {\n return obj ? (obj[key] = value) : null;\n }\n};\n\nconst applyLeafChange = (obj: any, change: any, embeddedKey: any) => {\n const { type, key, value } = change;\n switch (type) {\n case Operation.ADD:\n return addKeyValue(obj, key, value);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey);\n }\n};\n\nconst applyArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(applyLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[subchange.key];\n } else if (change.embeddedKey === '$value') {\n const index = arr.indexOf(subchange.key);\n if (index !== -1) {\n element = arr[index];\n }\n } else {\n element = find(arr, (el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n result.push(applyChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst applyBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return applyArrayChange(obj, change);\n } else {\n return applyChangeset(obj, change.changes);\n }\n};\n\nconst revertLeafChange = (obj: any, change: any, embeddedKey = '$index') => {\n const { type, key, value, oldValue } = change;\n switch (type) {\n case Operation.ADD:\n return removeKey(obj, key, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, oldValue);\n case Operation.REMOVE:\n return addKeyValue(obj, key, value);\n }\n};\n\nconst revertArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(revertLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[+subchange.key];\n } else {\n element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key);\n }\n result.push(revertChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst revertBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return revertArrayChange(obj, change);\n } else {\n return revertChangeset(obj, change.changes);\n }\n};\n\n/** combine a base JSON Path with a subsequent segment */\nfunction append(basePath: string, nextSegment: string): string {\n return nextSegment.includes('.') ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;\n}\n\n/** returns a JSON Path filter expression; e.g., `$.pet[(?name='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string | FunctionKey, filterValue: string | number) {\n const value = typeof filterValue === 'number' ? filterValue : `'${filterValue}'`;\n return typeof filterKey === 'string' && filterKey.includes('.')\n ? `${basePath}[?(@[${filterKey}]==${value})]`\n : `${basePath}[?(@.${filterKey}==${value})]`;\n}\n","import { chain, keys, replace, set } from 'lodash';\nimport { diff, flattenChangeset, getTypeOfObj, IFlatChange, Operation } from './jsonDiff.js';\n\nexport enum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\nexport interface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nexport const createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nexport const createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nexport const enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return keys(object)\n .map((key: string) => ({ key, value: enrich(object[key]) }))\n .reduce((accumulator, entry) => {\n accumulator.value[entry.key] = entry.value;\n return accumulator;\n }, createContainer({}));\n case 'Array':\n return chain(object)\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]))\n .value();\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\nexport const applyChangelist = (\n object: IComparisonEnrichedNode,\n changelist: IFlatChange[]\n): IComparisonEnrichedNode => {\n chain(changelist)\n .map((entry) => ({ ...entry, path: replace(entry.path, '$.', '.') }))\n .map((entry) => ({\n ...entry,\n path: replace(entry.path, /(\\[(?<array>\\d)\\]\\.)/g, 'ARRVAL_START$<array>ARRVAL_END')\n }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /(?<dot>\\.)/g, '.value$<dot>') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /\\./, '') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_START/g, '.value[') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_END/g, '].value.') }))\n .value()\n .forEach((entry) => {\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n set(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n set(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nexport const compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n return applyChangelist(enrich(oldObject), flattenChangeset(diff(oldObject, newObject)));\n};\n"],"mappings":"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","names":["Operation","key","CompareOperation","compare"]}
|
|
1
|
+
{"version":3,"sources":["../src/jsonDiff.ts","../src/helpers.ts","../src/jsonCompare.ts"],"sourcesContent":["import { difference, find, intersection, keyBy } from 'lodash';\nimport { splitJSONPath } from './helpers';\n\ntype FunctionKey = (obj: any, shouldReturnKeyName?: boolean) => any;\nexport type EmbeddedObjKeysType = Record<string, string | FunctionKey>;\nexport type EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nexport enum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\nexport interface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n value?: any;\n oldValue?: any;\n changes?: IChange[];\n}\nexport type Changeset = IChange[];\n\nexport interface IAtomicChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\nexport interface Options {\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;\n keysToSkip?: string[];\n treatTypeChangeAsReplace?: boolean;\n}\n\n/**\n * Computes the difference between two objects.\n *\n * @param {any} oldObj - The original object.\n * @param {any} newObj - The updated object.\n * @param {Options} options - An optional parameter specifying keys of embedded objects and keys to skip.\n * @returns {IChange[]} - An array of changes that transform the old object into the new object.\n */\nexport function diff(\n oldObj: any,\n newObj: any,\n options: Options = {}\n): IChange[] {\n let { embeddedObjKeys, keysToSkip, treatTypeChangeAsReplace } = options;\n\n // Trim leading '.' from keys in embeddedObjKeys\n if (embeddedObjKeys instanceof Map) {\n embeddedObjKeys = new Map(\n Array.from(embeddedObjKeys.entries()).map(([key, value]) => [\n key instanceof RegExp ? key : key.replace(/^\\./, ''),\n value\n ])\n );\n } else if (embeddedObjKeys) {\n embeddedObjKeys = Object.fromEntries(\n Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\\./, ''), value])\n );\n }\n\n // Compare old and new objects to generate a list of changes\n return compare(oldObj, newObj, [], [], {\n embeddedObjKeys,\n keysToSkip: keysToSkip ?? [],\n treatTypeChangeAsReplace: treatTypeChangeAsReplace ?? true\n });\n}\n\n/**\n * Applies all changes in the changeset to the object.\n *\n * @param {any} obj - The object to apply changes to.\n * @param {Changeset} changeset - The changeset to apply.\n * @returns {any} - The object after the changes from the changeset have been applied.\n *\n * The function first checks if a changeset is provided. If so, it iterates over each change in the changeset.\n * If the change value is not null or undefined, or if the change type is REMOVE, it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nexport const applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n if ((value !== null && value !== undefined) || type === Operation.REMOVE) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n applyBranchChange(obj[key], change);\n }\n });\n }\n return obj;\n};\n\n/**\n * Reverts the changes made to an object based on a given changeset.\n *\n * @param {any} obj - The object on which to revert changes.\n * @param {Changeset} changeset - The changeset to revert.\n * @returns {any} - The object after the changes from the changeset have been reverted.\n *\n * The function first checks if a changeset is provided. If so, it reverses the changeset to start reverting from the last change.\n * It then iterates over each change in the changeset. If the change does not have any nested changes, it reverts the change on the object directly.\n * If the change does have nested changes, it reverts the changes on the corresponding branch of the object.\n */\nexport const revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any =>\n !change.changes ? revertLeafChange(obj, change) : revertBranchChange(obj[change.key], change)\n );\n }\n\n return obj;\n};\n\n/**\n * Atomize a changeset into an array of single changes.\n *\n * @param {Changeset | IChange} obj - The changeset or change to flatten.\n * @param {string} [path='$'] - The current path in the changeset.\n * @param {string | FunctionKey} [embeddedKey] - The key to use for embedded objects.\n * @returns {IAtomicChange[]} - An array of atomic changes.\n *\n * The function first checks if the input is an array. If so, it recursively atomize each change in the array.\n * If the input is not an array, it checks if the change has nested changes or an embedded key.\n * If so, it updates the path and recursively flattens the nested changes or the embedded object.\n * If the change does not have nested changes or an embedded key, it creates a atomic change and returns it in an array.\n */\nexport const atomizeChangeset = (\n obj: Changeset | IChange,\n path = '$',\n embeddedKey?: string | FunctionKey\n): IAtomicChange[] => {\n if (Array.isArray(obj)) {\n return handleArray(obj, path, embeddedKey);\n } else if (obj.changes || embeddedKey) {\n if (embeddedKey) {\n const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path);\n path = updatedPath;\n if (atomicChange) {\n return atomicChange;\n }\n } else {\n path = append(path, obj.key);\n }\n return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey);\n } else {\n const valueType = getTypeOfObj(obj.value);\n return [{\n ...obj,\n path: valueType === 'Object' || path.endsWith(`[${obj.key}]`) ? path : append(path, obj.key),\n valueType\n }];\n }\n};\n\n// Function to handle embeddedKey logic and update the path\nfunction handleEmbeddedKey(embeddedKey: string | FunctionKey, obj: IChange, path: string): [string, IAtomicChange[]?] {\n if (embeddedKey === '$index') {\n path = `${path}[${obj.key}]`;\n return [path]\n } else if (embeddedKey === '$value') {\n path = `${path}[?(@=='${obj.key}')]`;\n const valueType = getTypeOfObj(obj.value);\n return [\n path,\n [{\n ...obj,\n path,\n valueType\n }]\n ];\n } else if (obj.type === Operation.ADD) {\n // do nothing\n return [path];\n } else {\n path = filterExpression(path, embeddedKey, obj.key);\n return [path];\n }\n}\n\n\nconst handleArray = (obj: Changeset | IChange[], path: string, embeddedKey?: string | FunctionKey): IAtomicChange[] => {\n return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey)], [] as IAtomicChange[]);\n}\n\n\n\n/**\n * Transforms an atomized changeset into a nested changeset.\n *\n * @param {IAtomicChange | IAtomicChange[]} changes - The atomic changeset to unflatten.\n * @returns {IChange[]} - The unflattened changeset.\n *\n * The function first checks if the input is a single change or an array of changes.\n * It then iterates over each change and splits its path into segments.\n * For each segment, it checks if it represents an array or a leaf node.\n * If it represents an array, it creates a new change object and updates the pointer to this new object.\n * If it represents a leaf node, it sets the key, type, value, and oldValue of the current change object.\n * Finally, it pushes the unflattened change object into the changes array.\n */\nexport const unatomizeChangeset = (changes: IAtomicChange | IAtomicChange[]) => {\n if (!Array.isArray(changes)) {\n changes = [changes];\n }\n\n const changesArr: IChange[] = [];\n\n\n changes.forEach((change) => {\n const obj = {} as IChange;\n let ptr = obj;\n\n const segments = splitJSONPath(change.path);\n\n if (segments.length === 1) {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n changesArr.push(ptr);\n } else {\n for (let i = 1; i < segments.length; i++) {\n const segment = segments[i];\n // Matches JSONPath segments: \"items[?(@.id=='123')]\", \"items[?(@.id==123)]\", \"items[2]\", \"items[?(@='123')]\"\n const result = /^([^[\\]]+)\\[\\?\\(@\\.?([^=]*)=+'([^']+)'\\)\\]$|^(.+)\\[(\\d+)\\]$/.exec(segment);\n // array\n if (result) {\n let key: string;\n let embeddedKey: string;\n let arrKey: string | number;\n if (result[1]) {\n key = result[1];\n embeddedKey = result[2] || '$value';\n arrKey = result[3];\n } else {\n key = result[4];\n embeddedKey = '$index';\n arrKey = Number(result[5]);\n }\n // leaf\n if (i === segments.length - 1) {\n ptr.key = key!;\n ptr.embeddedKey = embeddedKey!;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n type: change.type,\n key: arrKey!,\n value: change.value,\n oldValue: change.oldValue\n } as IChange\n ];\n } else {\n // object\n ptr.key = key;\n ptr.embeddedKey = embeddedKey;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [\n {\n type: Operation.UPDATE,\n key: arrKey,\n changes: [newPtr]\n } as IChange\n ];\n ptr = newPtr;\n }\n } else {\n // leaf\n if (i === segments.length - 1) {\n // check if value is a primitive or object\n if (change.value !== null && change.valueType === 'Object') {\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n ptr.changes = [\n {\n key: change.key,\n type: change.type,\n value: change.value\n } as IChange\n ];\n } else {\n ptr.key = change.key;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\n }\n } else {\n // branch\n ptr.key = segment;\n ptr.type = Operation.UPDATE;\n const newPtr = {} as IChange;\n ptr.changes = [newPtr];\n ptr = newPtr;\n }\n }\n }\n changesArr.push(obj);\n }\n });\n return changesArr;\n};\n\n/**\n * Determines the type of a given object.\n *\n * @param {any} obj - The object whose type is to be determined.\n * @returns {string | null} - The type of the object, or null if the object is null.\n *\n * This function first checks if the object is undefined or null, and returns 'undefined' or null respectively.\n * If the object is neither undefined nor null, it uses Object.prototype.toString to get the object's type.\n * The type is extracted from the string returned by Object.prototype.toString using a regular expression.\n */\nexport const getTypeOfObj = (obj: any) => {\n if (typeof obj === 'undefined') {\n return 'undefined';\n }\n\n if (obj === null) {\n return null;\n }\n\n // Extracts the \"Type\" from \"[object Type]\" string.\n return Object.prototype.toString.call(obj).match(/^\\[object\\s(.*)\\]$/)[1];\n};\n\nconst getKey = (path: string) => {\n const left = path[path.length - 1];\n return left != null ? left : '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n let changes: any[] = [];\n\n const typeOfOldObj = getTypeOfObj(oldObj);\n const typeOfNewObj = getTypeOfObj(newObj);\n\n // `treatTypeChangeAsReplace` is a flag used to determine if a change in type should be treated as a replacement.\n if (options.treatTypeChangeAsReplace && typeOfOldObj !== typeOfNewObj) {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n return changes;\n }\n\n if (typeOfNewObj === 'Object' && typeOfOldObj === 'Array') {\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n changes = changes.concat(\n comparePrimitives(oldObj.getTime(), newObj.getTime(), path).map((x) => ({\n ...x,\n value: new Date(x.value),\n oldValue: new Date(x.oldValue)\n }))\n );\n break;\n case 'Object':\n {\n const diffs = compareObject(oldObj, newObj, path, keyPath, false, options);\n if (diffs.length) {\n if (path.length) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n changes: diffs\n });\n } else {\n changes = changes.concat(diffs);\n }\n }\n break;\n }\n case 'Array':\n changes = changes.concat(compareArray(oldObj, newObj, path, keyPath, options));\n break;\n case 'Function':\n break;\n // do nothing\n default:\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n\n return changes;\n};\n\nconst compareObject = (\n oldObj: any,\n newObj: any,\n path: any,\n keyPath: any,\n skipPath = false,\n options: Options = {},\n) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n const oldObjKeys = Object.keys(oldObj).filter((key) => options.keysToSkip.indexOf(key) === -1);\n const newObjKeys = Object.keys(newObj).filter((key) => options.keysToSkip.indexOf(key) === -1);\n\n const intersectionKeys = intersection(oldObjKeys, newObjKeys);\n for (k of intersectionKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n const diffs = compare(oldObj[k], newObj[k], newPath, newKeyPath, options);\n if (diffs.length) {\n changes = changes.concat(diffs);\n }\n }\n\n const addedKeys = difference(newObjKeys, oldObjKeys);\n for (k of addedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.ADD,\n key: getKey(newPath),\n value: newObj[k]\n });\n }\n\n const deletedKeys = difference(oldObjKeys, newObjKeys);\n for (k of deletedKeys) {\n newPath = path.concat([k]);\n newKeyPath = skipPath ? keyPath : keyPath.concat([k]);\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (\n oldObj: any,\n newObj: any,\n path: any,\n keyPath: any,\n options: Options\n) => {\n const left = getObjectKey(options.embeddedObjKeys, keyPath);\n const uniqKey = left != null ? left : '$index';\n const indexedOldObj = convertArrayToObj(oldObj, uniqKey);\n const indexedNewObj = convertArrayToObj(newObj, uniqKey);\n const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);\n if (diffs.length) {\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: typeof uniqKey === 'function' && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,\n changes: diffs\n }\n ];\n } else {\n return [];\n }\n};\n\nconst getObjectKey = (embeddedObjKeys: any, keyPath: any) => {\n if (embeddedObjKeys != null) {\n const path = keyPath.join('.');\n\n if (embeddedObjKeys instanceof Map) {\n for (const [key, value] of embeddedObjKeys.entries()) {\n if (key instanceof RegExp) {\n if (path.match(key)) {\n return value;\n }\n } else if (path === key) {\n return value;\n }\n }\n }\n\n const key = embeddedObjKeys[path];\n if (key != null) {\n return key;\n }\n }\n return undefined;\n};\n\nconst convertArrayToObj = (arr: any[], uniqKey: any) => {\n let obj: any = {};\n if (uniqKey === '$value') {\n arr.forEach((value) => {\n obj[value] = value;\n });\n } else if (uniqKey !== '$index') {\n obj = keyBy(arr, uniqKey);\n } else {\n for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n }\n return obj;\n};\n\nconst comparePrimitives = (oldObj: any, newObj: any, path: any) => {\n const changes = [];\n if (oldObj !== newObj) {\n changes.push({\n type: Operation.UPDATE,\n key: getKey(path),\n value: newObj,\n oldValue: oldObj\n });\n }\n return changes;\n};\n\nconst removeKey = (obj: any, key: any, embeddedKey: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(key);\n return;\n }\n const index = indexOfItemInArray(obj, embeddedKey, key);\n if (index === -1) {\n // tslint:disable-next-line:no-console\n console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array'`);\n return;\n }\n return obj.splice(index != null ? index : key, 1);\n } else {\n obj[key] = undefined;\n delete obj[key];\n return;\n }\n};\n\nconst indexOfItemInArray = (arr: any[], key: any, value: any) => {\n if (key === '$value') {\n return arr.indexOf(value);\n }\n for (let i = 0; i < arr.length; i++) {\n const item = arr[i];\n if (item && item[key] ? item[key].toString() === value.toString() : undefined) {\n return i;\n }\n }\n return -1;\n};\n\nconst modifyKeyValue = (obj: any, key: any, value: any) => (obj[key] = value);\n\nconst addKeyValue = (obj: any, key: any, value: any) => {\n if (Array.isArray(obj)) {\n return obj.push(value);\n } else {\n return obj ? (obj[key] = value) : null;\n }\n};\n\nconst applyLeafChange = (obj: any, change: any, embeddedKey: any) => {\n const { type, key, value } = change;\n switch (type) {\n case Operation.ADD:\n return addKeyValue(obj, key, value);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey);\n }\n};\n\nconst applyArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(applyLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[subchange.key];\n } else if (change.embeddedKey === '$value') {\n const index = arr.indexOf(subchange.key);\n if (index !== -1) {\n element = arr[index];\n }\n } else {\n element = find(arr, (el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n result.push(applyChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst applyBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return applyArrayChange(obj, change);\n } else {\n return applyChangeset(obj, change.changes);\n }\n};\n\nconst revertLeafChange = (obj: any, change: any, embeddedKey = '$index') => {\n const { type, key, value, oldValue } = change;\n switch (type) {\n case Operation.ADD:\n return removeKey(obj, key, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, oldValue);\n case Operation.REMOVE:\n return addKeyValue(obj, key, value);\n }\n};\n\nconst revertArrayChange = (arr: any, change: any) =>\n (() => {\n const result = [];\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n result.push(revertLeafChange(arr, subchange, change.embeddedKey));\n } else {\n let element;\n if (change.embeddedKey === '$index') {\n element = arr[+subchange.key];\n } else {\n element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key);\n }\n result.push(revertChangeset(element, subchange.changes));\n }\n }\n return result;\n })();\n\nconst revertBranchChange = (obj: any, change: any) => {\n if (Array.isArray(obj)) {\n return revertArrayChange(obj, change);\n } else {\n return revertChangeset(obj, change.changes);\n }\n};\n\n/** combine a base JSON Path with a subsequent segment */\nfunction append(basePath: string, nextSegment: string): string {\n return nextSegment.includes('.') ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;\n}\n\n/** returns a JSON Path filter expression; e.g., `$.pet[(?name='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string | FunctionKey, filterValue: string | number) {\n const value = typeof filterValue === 'number' ? filterValue : `'${filterValue}'`;\n return typeof filterKey === 'string' && filterKey.includes('.')\n ? `${basePath}[?(@[${filterKey}]==${value})]`\n : `${basePath}[?(@.${filterKey}==${value})]`;\n}\n\n","export function splitJSONPath(path: string): string[] {\n let parts: string[] = [];\n let currentPart = '';\n let inSingleQuotes = false;\n let inBrackets = 0;\n\n for (let i = 0; i < path.length; i++) {\n const char = path[i];\n\n if (char === \"'\" && path[i - 1] !== '\\\\') {\n // Toggle single quote flag if not escaped\n inSingleQuotes = !inSingleQuotes;\n } else if (char === '[' && !inSingleQuotes) {\n // Increase bracket nesting level\n inBrackets++;\n } else if (char === ']' && !inSingleQuotes) {\n // Decrease bracket nesting level\n inBrackets--;\n }\n\n if (char === '.' && !inSingleQuotes && inBrackets === 0) {\n // Split at period if not in quotes or brackets\n parts.push(currentPart);\n currentPart = '';\n } else {\n // Otherwise, keep adding to the current part\n currentPart += char;\n }\n }\n\n // Add the last part if there's any\n if (currentPart !== '') {\n parts.push(currentPart);\n }\n\n return parts;\n}\n","import { chain, keys, replace, set } from 'lodash';\nimport { diff, atomizeChangeset, getTypeOfObj, IAtomicChange, Operation } from './jsonDiff.js';\n\nexport enum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\nexport interface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nexport const createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nexport const createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nexport const enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return keys(object)\n .map((key: string) => ({ key, value: enrich(object[key]) }))\n .reduce((accumulator, entry) => {\n accumulator.value[entry.key] = entry.value;\n return accumulator;\n }, createContainer({}));\n case 'Array':\n return chain(object)\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]))\n .value();\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\nexport const applyChangelist = (\n object: IComparisonEnrichedNode,\n changelist: IAtomicChange[]\n): IComparisonEnrichedNode => {\n chain(changelist)\n .map((entry) => ({ ...entry, path: replace(entry.path, '$.', '.') }))\n .map((entry) => ({\n ...entry,\n path: replace(entry.path, /(\\[(?<array>\\d)\\]\\.)/g, 'ARRVAL_START$<array>ARRVAL_END')\n }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /(?<dot>\\.)/g, '.value$<dot>') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /\\./, '') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_START/g, '.value[') }))\n .map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_END/g, '].value.') }))\n .value()\n .forEach((entry) => {\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n set(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n set(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nexport const compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));\n};\n"],"mappings":"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","names":["Operation","key","CompareOperation","compare"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-diff-ts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-beta.0",
|
|
4
4
|
"description": "A JSON diff tool for JavaScript written in TypeScript.",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"build": "tsup --format cjs,esm",
|
|
11
11
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
12
12
|
"lint": "eslint 'src/**/*.ts'",
|
|
13
|
-
"test": "
|
|
14
|
-
"test:watch": "
|
|
13
|
+
"test": "jest --config jest.config.mjs",
|
|
14
|
+
"test:watch": "jest --watch --config jest.config.mjs",
|
|
15
15
|
"prepare": "npm run build",
|
|
16
16
|
"prepublishOnly": "npm test && npm run lint",
|
|
17
17
|
"preversion": "npm run lint",
|