json-diff-ts 1.2.6 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -228
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -18
- package/lib/jsonCompare.d.ts +1 -1
- package/lib/jsonCompare.js +34 -39
- package/lib/jsonDiff.d.ts +74 -7
- package/lib/jsonDiff.js +276 -198
- package/package.json +17 -18
package/README.md
CHANGED
|
@@ -4,315 +4,266 @@
|
|
|
4
4
|
[](https://snyk.io/test/github/ltwlf/json-diff-ts?targetFile=package.json)
|
|
5
5
|
[](https://sonarcloud.io/dashboard?id=ltwlf_json-diff-ts)
|
|
6
6
|
|
|
7
|
-
TypeScript
|
|
7
|
+
`json-diff-ts` is a TypeScript library that calculates and applies differences between JSON objects. A standout feature is its ability to identify elements in arrays using keys instead of indices, which offers a more intuitive way to handle arrays. It also supports JSONPath, a query language for JSON, which enables you to target specific parts of a JSON document with precision.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Another significant feature of this library is its ability to transform changesets into atomic changes. This means that each change in the data can be isolated and applied independently, providing a granular level of control over the data manipulation process.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
This library is particularly valuable for applications where tracking changes in JSON data is crucial. It simplifies the process of comparing JSON objects and applying changes. The support for key-based array identification can be especially useful in complex JSON structures where tracking by index is not efficient or intuitive. JSONPath support further enhances its capabilities by allowing precise targeting of specific parts in a JSON document, making it a versatile tool for handling JSON data.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Installation
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
```sh
|
|
16
|
+
npm install json-diff-ts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Capabilities
|
|
20
|
+
|
|
21
|
+
### `diff`
|
|
22
|
+
|
|
23
|
+
Generates a difference set for JSON objects. When comparing arrays, if a specific key is provided, differences are determined by matching elements via this key rather than array indices.
|
|
24
|
+
|
|
25
|
+
#### Examples using Star Wars data:
|
|
16
26
|
|
|
17
27
|
```javascript
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{ name: 'kid1', age: 1 },
|
|
27
|
-
{ name: 'kid2', age: 2 }
|
|
28
|
+
import { diff } from 'json-diff-ts';
|
|
29
|
+
|
|
30
|
+
const oldData = {
|
|
31
|
+
planet: 'Tatooine',
|
|
32
|
+
faction: 'Jedi',
|
|
33
|
+
characters: [
|
|
34
|
+
{ id: 'LUK', name: 'Luke Skywalker', force: true },
|
|
35
|
+
{ id: 'LEI', name: 'Leia Organa', force: true }
|
|
28
36
|
]
|
|
29
37
|
};
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{ name: '
|
|
36
|
-
{ name: '
|
|
37
|
-
{ name: 'kid2', age: 2 }
|
|
39
|
+
const newData = {
|
|
40
|
+
planet: 'Alderaan',
|
|
41
|
+
faction: 'Rebel Alliance',
|
|
42
|
+
characters: [
|
|
43
|
+
{ id: 'LUK', name: 'Luke Skywalker', force: true, rank: 'Commander' },
|
|
44
|
+
{ id: 'HAN', name: 'Han Solo', force: false }
|
|
38
45
|
]
|
|
39
46
|
};
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
// keys can also be hierarchical e.g. {children: 'name', 'children.grandChildren', 'age'}
|
|
43
|
-
// or use functions that return the key of an object e.g. {children: function(obj) { return obj.key; }}
|
|
44
|
-
// when you use a function flatten can not generate the correct path.
|
|
45
|
-
// to fix this, you can add an additional parameter e.g. (obj, getKeyNameFlag) => {...}. getKeyNameFlag will be true when the diff library try to resolve the key name instead of the key value. You can return a static string or use obj to check which key name you should return. obj will be the first object of the array!
|
|
46
|
-
diffs = changesets.diff(oldObj, newObj, { children: 'name' });
|
|
48
|
+
const diffs = diff(oldData, newData, { characters: 'id' });
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
const expectedDiffs = [
|
|
49
51
|
{
|
|
50
|
-
type: '
|
|
51
|
-
key: '
|
|
52
|
-
value: '
|
|
53
|
-
oldValue: '
|
|
52
|
+
type: 'UPDATE',
|
|
53
|
+
key: 'planet',
|
|
54
|
+
value: 'Alderaan',
|
|
55
|
+
oldValue: 'Tatooine'
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
|
-
type: '
|
|
57
|
-
key: '
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
type: 'UPDATE',
|
|
59
|
+
key: 'faction',
|
|
60
|
+
value: 'Rebel Alliance',
|
|
61
|
+
oldValue: 'Jedi'
|
|
60
62
|
},
|
|
61
63
|
{
|
|
62
|
-
type: '
|
|
63
|
-
key: '
|
|
64
|
-
|
|
64
|
+
type: 'UPDATE',
|
|
65
|
+
key: 'characters',
|
|
66
|
+
embeddedKey: 'id',
|
|
65
67
|
changes: [
|
|
66
68
|
{
|
|
67
|
-
type: '
|
|
68
|
-
key: '
|
|
69
|
-
changes: [
|
|
69
|
+
type: 'UPDATE',
|
|
70
|
+
key: 'LUK',
|
|
71
|
+
changes: [
|
|
72
|
+
{
|
|
73
|
+
type: 'ADD',
|
|
74
|
+
key: 'rank',
|
|
75
|
+
value: 'Commander'
|
|
76
|
+
}
|
|
77
|
+
]
|
|
70
78
|
},
|
|
71
79
|
{
|
|
72
|
-
type: '
|
|
73
|
-
key: '
|
|
74
|
-
value: {
|
|
80
|
+
type: 'ADD',
|
|
81
|
+
key: 'HAN',
|
|
82
|
+
value: {
|
|
83
|
+
id: 'HAN',
|
|
84
|
+
name: 'Han Solo',
|
|
85
|
+
force: false
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: 'REMOVE',
|
|
90
|
+
key: 'LEI',
|
|
91
|
+
value: {
|
|
92
|
+
id: 'LEI',
|
|
93
|
+
name: 'Leia Organa',
|
|
94
|
+
force: true
|
|
95
|
+
}
|
|
75
96
|
}
|
|
76
97
|
]
|
|
77
98
|
},
|
|
78
99
|
{
|
|
79
|
-
type: '
|
|
80
|
-
key: '
|
|
81
|
-
|
|
100
|
+
type: 'UPDATE',
|
|
101
|
+
key: 'weapons',
|
|
102
|
+
embeddedKey: '$index',
|
|
103
|
+
changes: [
|
|
104
|
+
{
|
|
105
|
+
type: 'ADD',
|
|
106
|
+
key: '2',
|
|
107
|
+
value: 'Bowcaster'
|
|
108
|
+
}
|
|
109
|
+
]
|
|
82
110
|
}
|
|
83
|
-
]
|
|
111
|
+
];
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### Advanced
|
|
115
|
+
|
|
116
|
+
Paths can be utilized to identify keys within nested arrays.
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
const diffs = diff(oldData, newData, { characters.subarray: 'id' });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Alternative Syntax
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
const diffs = diff(oldData, newData, { 'characters.subarray': 'id' });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
You can also designate the root by using '.' instead of an empty string ('').
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
const diffs = diff(oldData, newData, { '.characters.subarray': 'id' });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
You can use a function to dynamically resolve the key of the object.
|
|
135
|
+
The first parameter is the object and the second is to signal if the function should return the key name instead of the value. This is needed to flatten the changeset
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
const diffs = diff(oldData, newData, {
|
|
139
|
+
characters: (obj, shouldReturnKeyName) => (shouldReturnKeyName ? 'id' : obj.id)
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
If you're using the Map type, you can employ regular expressions for path identification.
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const embeddedObjKeys: EmbeddedObjKeysMapType = new Map();
|
|
147
|
+
|
|
148
|
+
embeddedObjKeys.set(/^char\w+$/, 'id'); // instead of 'id' you can specify a function
|
|
149
|
+
|
|
150
|
+
const diffs = diff(oldObj, newObj, embeddedObjKeys);
|
|
84
151
|
```
|
|
85
152
|
|
|
86
|
-
### flattenChangeset
|
|
153
|
+
### `flattenChangeset`
|
|
87
154
|
|
|
88
|
-
|
|
155
|
+
Transforms a complex changeset into a flat list of atomic changes, each describable by a JSONPath.
|
|
89
156
|
|
|
90
157
|
#### Examples:
|
|
91
158
|
|
|
92
159
|
```javascript
|
|
93
160
|
const flatChanges = flattenChangeset(diffs);
|
|
94
|
-
//
|
|
95
|
-
const changeset = unflattenChanges(flatChanges.slice(
|
|
96
|
-
//
|
|
161
|
+
// Restore the changeset from a selection of flat changes
|
|
162
|
+
const changeset = unflattenChanges(flatChanges.slice(0, 3));
|
|
163
|
+
// Alternatively, apply the changes using a JSONPath-capable library
|
|
97
164
|
// ...
|
|
98
165
|
```
|
|
99
166
|
|
|
100
|
-
|
|
167
|
+
A **flatChange** will have the following structure:
|
|
101
168
|
|
|
102
169
|
```javascript
|
|
103
170
|
[
|
|
104
|
-
{ type: 'UPDATE', key: '
|
|
105
|
-
|
|
106
|
-
{ type: '
|
|
107
|
-
{
|
|
108
|
-
type: 'UPDATE',
|
|
109
|
-
key: 'date',
|
|
110
|
-
value: '2014-10-12T09:13:00.000Z',
|
|
111
|
-
oldValue: '2014-10-13T09:13:00.000Z',
|
|
112
|
-
path: '$.date',
|
|
113
|
-
valueType: 'Date'
|
|
114
|
-
},
|
|
115
|
-
{ type: 'ADD', key: '2', value: 1, path: '$.coins[2]', valueType: 'Number' },
|
|
116
|
-
{ type: 'REMOVE', key: '0', value: 'car', path: '$.toys[0]', valueType: 'String' },
|
|
117
|
-
{ type: 'REMOVE', key: '1', value: 'doll', path: '$.toys[1]', valueType: 'String' },
|
|
118
|
-
{ type: 'REMOVE', key: '0', path: '$.pets[0]', valueType: 'undefined' },
|
|
119
|
-
{ type: 'REMOVE', key: '1', value: null, path: '$.pets[1]', valueType: null },
|
|
120
|
-
{ type: 'UPDATE', key: 'age', value: 0, oldValue: 1, path: "$.children[?(@.name='kid1')].age", valueType: 'Number' },
|
|
121
|
-
{
|
|
122
|
-
type: 'UPDATE',
|
|
123
|
-
key: 'value',
|
|
124
|
-
value: 'heihei',
|
|
125
|
-
oldValue: 'haha',
|
|
126
|
-
path: "$.children[?(@.name='kid1')].subset[?(@.id='1')].value",
|
|
127
|
-
valueType: 'String'
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
type: 'REMOVE',
|
|
131
|
-
key: '2',
|
|
132
|
-
value: { id: 2, value: 'hehe' },
|
|
133
|
-
path: "$.children[?(@.name='kid1')].subset[?(@.id='2')]",
|
|
134
|
-
valueType: 'Object'
|
|
135
|
-
},
|
|
136
|
-
{ type: 'ADD', key: 'kid3', value: { name: 'kid3', age: 3 }, path: '$.children', valueType: 'Object' }
|
|
171
|
+
{ type: 'UPDATE', key: 'planet', value: 'Alderaan', oldValue: 'Tatooine', path: '$.planet', valueType: 'String' },
|
|
172
|
+
// ... Additional flat changes here
|
|
173
|
+
{ type: 'ADD', key: 'rank', value: 'Commander', path: "$.characters[?(@.id=='LUK')].rank", valueType: 'String' }
|
|
137
174
|
];
|
|
138
175
|
```
|
|
139
176
|
|
|
140
|
-
### applyChange
|
|
177
|
+
### `applyChange`
|
|
141
178
|
|
|
142
179
|
#### Examples:
|
|
143
180
|
|
|
144
181
|
```javascript
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
name: 'joe',
|
|
148
|
-
age: 55,
|
|
149
|
-
coins: [2, 5],
|
|
150
|
-
children: [
|
|
151
|
-
{ name: 'kid1', age: 1 },
|
|
152
|
-
{ name: 'kid2', age: 2 }
|
|
153
|
-
]
|
|
182
|
+
const oldData = {
|
|
183
|
+
// ... Initial data here
|
|
154
184
|
};
|
|
155
185
|
|
|
156
|
-
//
|
|
157
|
-
diffs = [
|
|
158
|
-
|
|
159
|
-
type: 'update',
|
|
160
|
-
key: 'name',
|
|
161
|
-
value: 'smith',
|
|
162
|
-
oldValue: 'joe'
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: 'update',
|
|
166
|
-
key: 'coins',
|
|
167
|
-
embededKey: '$index',
|
|
168
|
-
changes: [{ type: 'add', key: '2', value: 1 }]
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
type: 'update',
|
|
172
|
-
key: 'children',
|
|
173
|
-
embededKey: 'name', // The key property name of the elements in an array
|
|
174
|
-
changes: [
|
|
175
|
-
{
|
|
176
|
-
type: 'update',
|
|
177
|
-
key: 'kid1',
|
|
178
|
-
changes: [{ type: 'update', key: 'age', value: 0, oldValue: 1 }]
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
type: 'add',
|
|
182
|
-
key: 'kid3',
|
|
183
|
-
value: { name: 'kid3', age: 3 }
|
|
184
|
-
}
|
|
185
|
-
]
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
type: 'remove',
|
|
189
|
-
key: 'age',
|
|
190
|
-
value: 55
|
|
191
|
-
}
|
|
186
|
+
// Sample diffs array, similar to the one generated in the diff example
|
|
187
|
+
const diffs = [
|
|
188
|
+
// ... Diff objects here
|
|
192
189
|
];
|
|
193
190
|
|
|
194
|
-
changesets.applyChanges(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
children: [
|
|
199
|
-
{ name: 'kid3', age: 3 },
|
|
200
|
-
{ name: 'kid1', age: 0 },
|
|
201
|
-
{ name: 'kid2', age: 2 }
|
|
202
|
-
]
|
|
191
|
+
changesets.applyChanges(oldData, diffs);
|
|
192
|
+
|
|
193
|
+
expect(oldData).to.eql({
|
|
194
|
+
// ... Updated data here
|
|
203
195
|
});
|
|
204
196
|
```
|
|
205
197
|
|
|
206
|
-
### revertChange
|
|
198
|
+
### `revertChange`
|
|
207
199
|
|
|
208
200
|
#### Examples:
|
|
209
201
|
|
|
210
202
|
```javascript
|
|
203
|
+
const newData = {
|
|
204
|
+
// ... Updated data here
|
|
205
|
+
};
|
|
211
206
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
coins: [2, 5, 1],
|
|
217
|
-
children: [
|
|
218
|
-
{name: 'kid3', age: 3},
|
|
219
|
-
{name: 'kid1', age: 0},
|
|
220
|
-
{name: 'kid2', age: 2}
|
|
221
|
-
]};
|
|
222
|
-
|
|
223
|
-
// Assume children is an array of child object and the child object has 'name' as its primary key
|
|
224
|
-
diffs = [
|
|
225
|
-
{
|
|
226
|
-
type: 'update', key: 'name', value: 'smith', oldValue: 'joe'
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
type: 'update', key: 'coins', embededKey: '$index', changes: [
|
|
230
|
-
{type: 'add', key: '2', value: 1 }
|
|
231
|
-
]
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
type: 'update',
|
|
235
|
-
key: 'children',
|
|
236
|
-
embededKey: 'name', // The key property name of the elements in an array
|
|
237
|
-
changes: [
|
|
238
|
-
{
|
|
239
|
-
type: 'update', key: 'kid1', changes: [
|
|
240
|
-
{type: 'update', key: 'age', value: 0, oldValue: 1 }
|
|
241
|
-
]
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
type: 'add', key: 'kid3', value: {name: 'kid3', age: 3 }
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
type: 'remove', key: 'age', value: 55
|
|
250
|
-
}
|
|
251
|
-
]
|
|
252
|
-
|
|
253
|
-
changesets.revertChanges(newObj, diffs)
|
|
254
|
-
expect(newObj).to.eql {
|
|
255
|
-
name: 'joe',
|
|
256
|
-
age: 55,
|
|
257
|
-
coins: [2, 5],
|
|
258
|
-
children: [
|
|
259
|
-
{name: 'kid1', age: 1},
|
|
260
|
-
{name: 'kid2', age: 2}
|
|
261
|
-
]};
|
|
262
|
-
|
|
263
|
-
```
|
|
207
|
+
// Sample diffs array
|
|
208
|
+
const diffs = [
|
|
209
|
+
// ... Diff objects here
|
|
210
|
+
];
|
|
264
211
|
|
|
265
|
-
|
|
212
|
+
changesets.revertChanges(newData, diffs);
|
|
266
213
|
|
|
267
|
-
|
|
268
|
-
|
|
214
|
+
expect(newData).to.eql({
|
|
215
|
+
// ... Original data restored here
|
|
216
|
+
});
|
|
269
217
|
```
|
|
270
218
|
|
|
271
|
-
|
|
219
|
+
### `jsonPath`
|
|
272
220
|
|
|
273
|
-
|
|
274
|
-
npm run test
|
|
275
|
-
```
|
|
221
|
+
The `json-diff-ts` library uses JSONPath to address specific parts of a JSON document in both the changeset and the application/reversion of changes.
|
|
276
222
|
|
|
277
|
-
|
|
223
|
+
#### Examples:
|
|
278
224
|
|
|
279
|
-
|
|
225
|
+
```javascript
|
|
280
226
|
|
|
281
|
-
|
|
227
|
+
const jsonPath = changesets.jsonPath;
|
|
282
228
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
- v1.2.4 Fix readme (npm install); update TypeScript and Lodash
|
|
287
|
-
- v1.2.3 Update outdated dependencies; update TypeScript version to 4.5.2
|
|
288
|
-
- v1.2.2 Add support for functions to resove object keys (PR by [Abraxxa](https://github.com/abraxxa))
|
|
229
|
+
cost data = {
|
|
230
|
+
// ... Some JSON data
|
|
231
|
+
};
|
|
289
232
|
|
|
290
|
-
|
|
233
|
+
const value = jsonPath.query(data, '$.characters[?(@.id=="LUK")].name');
|
|
291
234
|
|
|
292
|
-
|
|
235
|
+
expect(value).to.eql(['Luke Skywalker']);
|
|
236
|
+
```
|
|
293
237
|
|
|
294
|
-
##
|
|
238
|
+
## Contributing
|
|
295
239
|
|
|
296
|
-
|
|
240
|
+
Contributions are welcome! Please follow the provided issue templates and code of conduct.
|
|
297
241
|
|
|
298
|
-
|
|
242
|
+
## Contact
|
|
299
243
|
|
|
300
|
-
|
|
244
|
+
Reach out to the maintainer via LinkedIn or Twitter:
|
|
301
245
|
|
|
302
|
-
|
|
246
|
+
- LinkedIn: [Christian Glessner](https://www.linkedin.com/in/christian-glessner/)
|
|
247
|
+
- Twitter: [@leitwolf_io](https://twitter.com/leitwolf_io)
|
|
303
248
|
|
|
304
|
-
|
|
249
|
+
Discover more about the company behind this project: [hololux](https://hololux.com)
|
|
305
250
|
|
|
306
|
-
|
|
251
|
+
## Release Notes
|
|
307
252
|
|
|
308
|
-
**
|
|
253
|
+
- **v2.1.0:** Resolves a problem related to JSON Path filters by replacing the single equal sign (=) with a double equal sign (==). This update maintains compatibility with existing flat changes. Allows to use either '' or '.' as root in the path.
|
|
254
|
+
- **v2.0.0:** json-diff-ts has been upgraded to an ECMAScript module! This major update brings optimizations and enhanced documentation. Additionally, a previously existing issue where all paths were treated as regex has been fixed. In this new version, you'll need to use a Map instead of a Record for regex paths. Please note that this is a breaking change if you were using regex paths in the previous versions.
|
|
255
|
+
- **v1.2.6:** Enhanced JSON Path handling for period-inclusive segments.
|
|
256
|
+
- **v1.2.5:** Patched dependencies; added key name resolution support for key functions.
|
|
257
|
+
- **v1.2.4:** Documentation updates; upgraded TypeScript and Lodash.
|
|
258
|
+
- **v1.2.3:** Dependency updates; switched to TypeScript 4.5.2.
|
|
259
|
+
- **v1.2.2:** Implemented object key resolution functions support.
|
|
309
260
|
|
|
310
|
-
|
|
261
|
+
## Acknowledgments
|
|
311
262
|
|
|
312
|
-
|
|
263
|
+
This project takes inspiration and code from [diff-json](https://www.npmjs.com/package/diff-json) by viruschidai@gmail.com.
|
|
313
264
|
|
|
314
|
-
|
|
265
|
+
## License
|
|
315
266
|
|
|
316
|
-
|
|
267
|
+
json-diff-ts is open-sourced software licensed under the [MIT license](LICENSE).
|
|
317
268
|
|
|
318
|
-
|
|
269
|
+
The original diff-json project is also under the MIT License. For more information, refer to its [license details](https://www.npmjs.com/package/diff-json#license).
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './jsonDiff';
|
|
2
|
-
export * from './jsonCompare';
|
|
1
|
+
export * from './jsonDiff.js';
|
|
2
|
+
export * from './jsonCompare.js';
|
package/lib/index.js
CHANGED
|
@@ -1,18 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./jsonDiff"), exports);
|
|
18
|
-
__exportStar(require("./jsonCompare"), exports);
|
|
1
|
+
export * from './jsonDiff.js';
|
|
2
|
+
export * from './jsonCompare.js';
|
package/lib/jsonCompare.d.ts
CHANGED
package/lib/jsonCompare.js
CHANGED
|
@@ -1,64 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const lodash_1 = require("lodash");
|
|
5
|
-
const jsonDiff_1 = require("./jsonDiff");
|
|
6
|
-
var CompareOperation;
|
|
1
|
+
import { chain, keys, replace, set } from 'lodash-es';
|
|
2
|
+
import { diff, flattenChangeset, getTypeOfObj, Operation } from './jsonDiff.js';
|
|
3
|
+
export var CompareOperation;
|
|
7
4
|
(function (CompareOperation) {
|
|
8
5
|
CompareOperation["CONTAINER"] = "CONTAINER";
|
|
9
6
|
CompareOperation["UNCHANGED"] = "UNCHANGED";
|
|
10
|
-
})(CompareOperation
|
|
11
|
-
const createValue = (value) => ({ type: CompareOperation.UNCHANGED, value });
|
|
12
|
-
|
|
13
|
-
const createContainer = (value) => ({
|
|
7
|
+
})(CompareOperation || (CompareOperation = {}));
|
|
8
|
+
export const createValue = (value) => ({ type: CompareOperation.UNCHANGED, value });
|
|
9
|
+
export const createContainer = (value) => ({
|
|
14
10
|
type: CompareOperation.CONTAINER,
|
|
15
11
|
value
|
|
16
12
|
});
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const objectType = (0, jsonDiff_1.getTypeOfObj)(object);
|
|
13
|
+
export const enrich = (object) => {
|
|
14
|
+
const objectType = getTypeOfObj(object);
|
|
20
15
|
switch (objectType) {
|
|
21
16
|
case 'Object':
|
|
22
|
-
return
|
|
23
|
-
.map((key) => ({ key, value:
|
|
17
|
+
return keys(object)
|
|
18
|
+
.map((key) => ({ key, value: enrich(object[key]) }))
|
|
24
19
|
.reduce((accumulator, entry) => {
|
|
25
20
|
accumulator.value[entry.key] = entry.value;
|
|
26
21
|
return accumulator;
|
|
27
|
-
},
|
|
22
|
+
}, createContainer({}));
|
|
28
23
|
case 'Array':
|
|
29
|
-
return
|
|
30
|
-
.map(value =>
|
|
24
|
+
return chain(object)
|
|
25
|
+
.map((value) => enrich(value))
|
|
31
26
|
.reduce((accumulator, value) => {
|
|
32
27
|
accumulator.value.push(value);
|
|
33
28
|
return accumulator;
|
|
34
|
-
},
|
|
29
|
+
}, createContainer([]))
|
|
35
30
|
.value();
|
|
36
31
|
case 'Function':
|
|
37
32
|
return undefined;
|
|
38
33
|
case 'Date':
|
|
39
34
|
default:
|
|
40
35
|
// Primitive value
|
|
41
|
-
return
|
|
36
|
+
return createValue(object);
|
|
42
37
|
}
|
|
43
38
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.map(entry => (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.map(entry => (
|
|
52
|
-
.map(entry => (
|
|
39
|
+
export const applyChangelist = (object, changelist) => {
|
|
40
|
+
chain(changelist)
|
|
41
|
+
.map((entry) => ({ ...entry, path: replace(entry.path, '$.', '.') }))
|
|
42
|
+
.map((entry) => ({
|
|
43
|
+
...entry,
|
|
44
|
+
path: replace(entry.path, /(\[(?<array>\d)\]\.)/g, 'ARRVAL_START$<array>ARRVAL_END')
|
|
45
|
+
}))
|
|
46
|
+
.map((entry) => ({ ...entry, path: replace(entry.path, /(?<dot>\.)/g, '.value$<dot>') }))
|
|
47
|
+
.map((entry) => ({ ...entry, path: replace(entry.path, /\./, '') }))
|
|
48
|
+
.map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_START/g, '.value[') }))
|
|
49
|
+
.map((entry) => ({ ...entry, path: replace(entry.path, /ARRVAL_END/g, '].value.') }))
|
|
53
50
|
.value()
|
|
54
|
-
.forEach(entry => {
|
|
51
|
+
.forEach((entry) => {
|
|
55
52
|
switch (entry.type) {
|
|
56
|
-
case
|
|
57
|
-
case
|
|
58
|
-
|
|
53
|
+
case Operation.ADD:
|
|
54
|
+
case Operation.UPDATE:
|
|
55
|
+
set(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });
|
|
59
56
|
break;
|
|
60
|
-
case
|
|
61
|
-
|
|
57
|
+
case Operation.REMOVE:
|
|
58
|
+
set(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });
|
|
62
59
|
break;
|
|
63
60
|
default:
|
|
64
61
|
throw new Error();
|
|
@@ -66,8 +63,6 @@ const applyChangelist = (object, changelist) => {
|
|
|
66
63
|
});
|
|
67
64
|
return object;
|
|
68
65
|
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return (0, exports.applyChangelist)((0, exports.enrich)(oldObject), (0, jsonDiff_1.flattenChangeset)((0, jsonDiff_1.diff)(oldObject, newObject)));
|
|
66
|
+
export const compare = (oldObject, newObject) => {
|
|
67
|
+
return applyChangelist(enrich(oldObject), flattenChangeset(diff(oldObject, newObject)));
|
|
72
68
|
};
|
|
73
|
-
exports.compare = compare;
|