json-diff-ts 1.2.5 → 1.2.7
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/lib/index.js +2 -18
- package/lib/jsonCompare.js +31 -39
- package/lib/jsonDiff.d.ts +3 -4
- package/lib/jsonDiff.js +60 -43
- package/package.json +8 -8
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';
|
|
2
|
+
export * from './jsonCompare';
|
package/lib/jsonCompare.js
CHANGED
|
@@ -1,64 +1,58 @@
|
|
|
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';
|
|
2
|
+
import { diff, flattenChangeset, getTypeOfObj, Operation } from './jsonDiff';
|
|
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 => (Object.assign(Object.assign({}, entry), { path:
|
|
48
|
-
.map(entry => (Object.assign(Object.assign({}, entry), { path:
|
|
49
|
-
.map(entry => (Object.assign(Object.assign({}, entry), { path:
|
|
50
|
-
.map(entry => (Object.assign(Object.assign({}, entry), { path:
|
|
51
|
-
.map(entry => (Object.assign(Object.assign({}, entry), { path:
|
|
52
|
-
.map(entry => (Object.assign(Object.assign({}, entry), { path: (0, lodash_1.replace)(entry.path, /ARRVAL_END/g, '].value.') })))
|
|
39
|
+
export const applyChangelist = (object, changelist) => {
|
|
40
|
+
chain(changelist)
|
|
41
|
+
.map((entry) => (Object.assign(Object.assign({}, entry), { path: replace(entry.path, '$.', '.') })))
|
|
42
|
+
.map((entry) => (Object.assign(Object.assign({}, entry), { path: replace(entry.path, /(\[(?<array>\d)\]\.)/g, 'ARRVAL_START$<array>ARRVAL_END') })))
|
|
43
|
+
.map((entry) => (Object.assign(Object.assign({}, entry), { path: replace(entry.path, /(?<dot>\.)/g, '.value$<dot>') })))
|
|
44
|
+
.map((entry) => (Object.assign(Object.assign({}, entry), { path: replace(entry.path, /\./, '') })))
|
|
45
|
+
.map((entry) => (Object.assign(Object.assign({}, entry), { path: replace(entry.path, /ARRVAL_START/g, '.value[') })))
|
|
46
|
+
.map((entry) => (Object.assign(Object.assign({}, entry), { path: replace(entry.path, /ARRVAL_END/g, '].value.') })))
|
|
53
47
|
.value()
|
|
54
|
-
.forEach(entry => {
|
|
48
|
+
.forEach((entry) => {
|
|
55
49
|
switch (entry.type) {
|
|
56
|
-
case
|
|
57
|
-
case
|
|
58
|
-
|
|
50
|
+
case Operation.ADD:
|
|
51
|
+
case Operation.UPDATE:
|
|
52
|
+
set(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });
|
|
59
53
|
break;
|
|
60
|
-
case
|
|
61
|
-
|
|
54
|
+
case Operation.REMOVE:
|
|
55
|
+
set(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });
|
|
62
56
|
break;
|
|
63
57
|
default:
|
|
64
58
|
throw new Error();
|
|
@@ -66,8 +60,6 @@ const applyChangelist = (object, changelist) => {
|
|
|
66
60
|
});
|
|
67
61
|
return object;
|
|
68
62
|
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return (0, exports.applyChangelist)((0, exports.enrich)(oldObject), (0, jsonDiff_1.flattenChangeset)((0, jsonDiff_1.diff)(oldObject, newObject)));
|
|
63
|
+
export const compare = (oldObject, newObject) => {
|
|
64
|
+
return applyChangelist(enrich(oldObject), flattenChangeset(diff(oldObject, newObject)));
|
|
72
65
|
};
|
|
73
|
-
exports.compare = compare;
|
package/lib/jsonDiff.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
declare type FunctionKey = (obj: any, getKeyName?: boolean) => any;
|
|
1
|
+
type FunctionKey = (obj: any, getKeyName?: boolean) => any;
|
|
3
2
|
export declare const getTypeOfObj: (obj: any) => string;
|
|
4
|
-
export declare const diff: (oldObj: any, newObj: any, embeddedObjKeys?:
|
|
3
|
+
export declare const diff: (oldObj: any, newObj: any, embeddedObjKeys?: Record<string, string | FunctionKey>) => IChange[];
|
|
5
4
|
export declare const applyChangeset: (obj: any, changeset: Changeset) => any;
|
|
6
5
|
export declare const revertChangeset: (obj: any, changeset: Changeset) => any;
|
|
7
6
|
export declare enum Operation {
|
|
@@ -17,7 +16,7 @@ export interface IChange {
|
|
|
17
16
|
oldValue?: any;
|
|
18
17
|
changes?: IChange[];
|
|
19
18
|
}
|
|
20
|
-
export
|
|
19
|
+
export type Changeset = IChange[];
|
|
21
20
|
export interface IFlatChange {
|
|
22
21
|
type: Operation;
|
|
23
22
|
key: string;
|
package/lib/jsonDiff.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.unflattenChanges = exports.flattenChangeset = exports.Operation = exports.revertChangeset = exports.applyChangeset = exports.diff = exports.getTypeOfObj = void 0;
|
|
4
|
-
const lodash_1 = require("lodash");
|
|
5
|
-
const getTypeOfObj = (obj) => {
|
|
1
|
+
import { difference, find, intersection, keyBy } from 'lodash';
|
|
2
|
+
export const getTypeOfObj = (obj) => {
|
|
6
3
|
if (typeof obj === 'undefined') {
|
|
7
4
|
return 'undefined';
|
|
8
5
|
}
|
|
@@ -11,15 +8,14 @@ const getTypeOfObj = (obj) => {
|
|
|
11
8
|
}
|
|
12
9
|
return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
|
|
13
10
|
};
|
|
14
|
-
exports.getTypeOfObj = getTypeOfObj;
|
|
15
11
|
const getKey = (path) => {
|
|
16
12
|
const left = path[path.length - 1];
|
|
17
13
|
return left != null ? left : '$root';
|
|
18
14
|
};
|
|
19
15
|
const compare = (oldObj, newObj, path, embeddedObjKeys, keyPath) => {
|
|
20
16
|
let changes = [];
|
|
21
|
-
const typeOfOldObj =
|
|
22
|
-
const typeOfNewObj =
|
|
17
|
+
const typeOfOldObj = getTypeOfObj(oldObj);
|
|
18
|
+
const typeOfNewObj = getTypeOfObj(newObj);
|
|
23
19
|
// if type of object changes, consider it as old obj has been deleted and a new object has been added
|
|
24
20
|
if (typeOfOldObj !== typeOfNewObj) {
|
|
25
21
|
changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });
|
|
@@ -66,7 +62,7 @@ const compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath
|
|
|
66
62
|
let changes = [];
|
|
67
63
|
const oldObjKeys = Object.keys(oldObj);
|
|
68
64
|
const newObjKeys = Object.keys(newObj);
|
|
69
|
-
const intersectionKeys =
|
|
65
|
+
const intersectionKeys = intersection(oldObjKeys, newObjKeys);
|
|
70
66
|
for (k of intersectionKeys) {
|
|
71
67
|
newPath = path.concat([k]);
|
|
72
68
|
newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
|
|
@@ -75,7 +71,7 @@ const compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath
|
|
|
75
71
|
changes = changes.concat(diffs);
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
|
-
const addedKeys =
|
|
74
|
+
const addedKeys = difference(newObjKeys, oldObjKeys);
|
|
79
75
|
for (k of addedKeys) {
|
|
80
76
|
newPath = path.concat([k]);
|
|
81
77
|
newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
|
|
@@ -85,7 +81,7 @@ const compareObject = (oldObj, newObj, path, embeddedObjKeys, keyPath, skipPath
|
|
|
85
81
|
value: newObj[k]
|
|
86
82
|
});
|
|
87
83
|
}
|
|
88
|
-
const deletedKeys =
|
|
84
|
+
const deletedKeys = difference(oldObjKeys, newObjKeys);
|
|
89
85
|
for (k of deletedKeys) {
|
|
90
86
|
newPath = path.concat([k]);
|
|
91
87
|
newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
|
|
@@ -134,8 +130,13 @@ const getObjectKey = (embeddedObjKeys, keyPath) => {
|
|
|
134
130
|
};
|
|
135
131
|
const convertArrayToObj = (arr, uniqKey) => {
|
|
136
132
|
let obj = {};
|
|
137
|
-
if (uniqKey
|
|
138
|
-
|
|
133
|
+
if (uniqKey === '$value') {
|
|
134
|
+
arr.forEach((value) => {
|
|
135
|
+
obj[value] = value;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else if (uniqKey !== '$index') {
|
|
139
|
+
obj = keyBy(arr, uniqKey);
|
|
139
140
|
}
|
|
140
141
|
else {
|
|
141
142
|
for (let i = 0; i < arr.length; i++) {
|
|
@@ -179,6 +180,9 @@ const removeKey = (obj, key, embeddedKey) => {
|
|
|
179
180
|
}
|
|
180
181
|
};
|
|
181
182
|
const indexOfItemInArray = (arr, key, value) => {
|
|
183
|
+
if (key === '$value') {
|
|
184
|
+
return arr.indexOf(value);
|
|
185
|
+
}
|
|
182
186
|
for (let i = 0; i < arr.length; i++) {
|
|
183
187
|
const item = arr[i];
|
|
184
188
|
if (item && item[key] ? item[key].toString() === value.toString() : undefined) {
|
|
@@ -218,10 +222,16 @@ const applyArrayChange = (arr, change) => (() => {
|
|
|
218
222
|
if (change.embeddedKey === '$index') {
|
|
219
223
|
element = arr[subchange.key];
|
|
220
224
|
}
|
|
225
|
+
else if (change.embeddedKey === '$value') {
|
|
226
|
+
const index = arr.indexOf(subchange.key);
|
|
227
|
+
if (index !== -1) {
|
|
228
|
+
element = arr[index];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
221
231
|
else {
|
|
222
|
-
element =
|
|
232
|
+
element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key.toString());
|
|
223
233
|
}
|
|
224
|
-
result.push(
|
|
234
|
+
result.push(applyChangeset(element, subchange.changes));
|
|
225
235
|
}
|
|
226
236
|
}
|
|
227
237
|
return result;
|
|
@@ -231,7 +241,7 @@ const applyBranchChange = (obj, change) => {
|
|
|
231
241
|
return applyArrayChange(obj, change);
|
|
232
242
|
}
|
|
233
243
|
else {
|
|
234
|
-
return
|
|
244
|
+
return applyChangeset(obj, change.changes);
|
|
235
245
|
}
|
|
236
246
|
};
|
|
237
247
|
const revertLeafChange = (obj, change, embeddedKey = '$index') => {
|
|
@@ -257,9 +267,9 @@ const revertArrayChange = (arr, change) => (() => {
|
|
|
257
267
|
element = arr[+subchange.key];
|
|
258
268
|
}
|
|
259
269
|
else {
|
|
260
|
-
element =
|
|
270
|
+
element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key);
|
|
261
271
|
}
|
|
262
|
-
result.push(
|
|
272
|
+
result.push(revertChangeset(element, subchange.changes));
|
|
263
273
|
}
|
|
264
274
|
}
|
|
265
275
|
return result;
|
|
@@ -269,12 +279,11 @@ const revertBranchChange = (obj, change) => {
|
|
|
269
279
|
return revertArrayChange(obj, change);
|
|
270
280
|
}
|
|
271
281
|
else {
|
|
272
|
-
return
|
|
282
|
+
return revertChangeset(obj, change.changes);
|
|
273
283
|
}
|
|
274
284
|
};
|
|
275
|
-
const diff = (oldObj, newObj, embeddedObjKeys) => compare(oldObj, newObj, [], embeddedObjKeys, []);
|
|
276
|
-
|
|
277
|
-
const applyChangeset = (obj, changeset) => {
|
|
285
|
+
export const diff = (oldObj, newObj, embeddedObjKeys) => compare(oldObj, newObj, [], embeddedObjKeys, []);
|
|
286
|
+
export const applyChangeset = (obj, changeset) => {
|
|
278
287
|
if (changeset) {
|
|
279
288
|
changeset.forEach((change) => (change.value !== null && change.value !== undefined) || change.type === Operation.REMOVE
|
|
280
289
|
? applyLeafChange(obj, change, change.embeddedKey)
|
|
@@ -282,8 +291,7 @@ const applyChangeset = (obj, changeset) => {
|
|
|
282
291
|
}
|
|
283
292
|
return obj;
|
|
284
293
|
};
|
|
285
|
-
|
|
286
|
-
const revertChangeset = (obj, changeset) => {
|
|
294
|
+
export const revertChangeset = (obj, changeset) => {
|
|
287
295
|
if (changeset) {
|
|
288
296
|
changeset
|
|
289
297
|
.reverse()
|
|
@@ -291,38 +299,48 @@ const revertChangeset = (obj, changeset) => {
|
|
|
291
299
|
}
|
|
292
300
|
return obj;
|
|
293
301
|
};
|
|
294
|
-
|
|
295
|
-
var Operation;
|
|
302
|
+
export var Operation;
|
|
296
303
|
(function (Operation) {
|
|
297
304
|
Operation["REMOVE"] = "REMOVE";
|
|
298
305
|
Operation["ADD"] = "ADD";
|
|
299
306
|
Operation["UPDATE"] = "UPDATE";
|
|
300
|
-
})(Operation
|
|
301
|
-
const flattenChangeset = (obj, path = '$', embeddedKey) => {
|
|
307
|
+
})(Operation || (Operation = {}));
|
|
308
|
+
export const flattenChangeset = (obj, path = '$', embeddedKey) => {
|
|
302
309
|
if (Array.isArray(obj)) {
|
|
303
|
-
return obj.reduce((memo, change) => [...memo, ...
|
|
310
|
+
return obj.reduce((memo, change) => [...memo, ...flattenChangeset(change, path, embeddedKey)], []);
|
|
304
311
|
}
|
|
305
312
|
else {
|
|
306
313
|
if (obj.changes || embeddedKey) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
314
|
+
if (embeddedKey) {
|
|
315
|
+
if (embeddedKey === '$index') {
|
|
316
|
+
path = `${path}[${obj.key}]`;
|
|
317
|
+
}
|
|
318
|
+
else if (embeddedKey === '$value') {
|
|
319
|
+
path = `${path}[?(@='${obj.key}')]`;
|
|
320
|
+
const valueType = getTypeOfObj(obj.value);
|
|
321
|
+
return [
|
|
322
|
+
Object.assign(Object.assign({}, obj), { path,
|
|
323
|
+
valueType })
|
|
324
|
+
];
|
|
325
|
+
}
|
|
326
|
+
else if (obj.type !== Operation.ADD) {
|
|
327
|
+
path = `${path}[?(@.${embeddedKey}='${obj.key}')]`;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
path = `${path}.${obj.key}`;
|
|
332
|
+
}
|
|
333
|
+
return flattenChangeset(obj.changes || obj, path, obj.embeddedKey);
|
|
315
334
|
}
|
|
316
335
|
else {
|
|
317
|
-
const valueType =
|
|
336
|
+
const valueType = getTypeOfObj(obj.value);
|
|
318
337
|
return [
|
|
319
338
|
Object.assign(Object.assign({}, obj), { path: valueType === 'Object' || path.endsWith(`[${obj.key}]`) ? path : `${path}.${obj.key}`, valueType })
|
|
320
339
|
];
|
|
321
340
|
}
|
|
322
341
|
}
|
|
323
342
|
};
|
|
324
|
-
|
|
325
|
-
const unflattenChanges = (changes) => {
|
|
343
|
+
export const unflattenChanges = (changes) => {
|
|
326
344
|
if (!Array.isArray(changes)) {
|
|
327
345
|
changes = [changes];
|
|
328
346
|
}
|
|
@@ -354,7 +372,7 @@ const unflattenChanges = (changes) => {
|
|
|
354
372
|
for (let i = 1; i < segments.length; i++) {
|
|
355
373
|
const segment = segments[i];
|
|
356
374
|
// check for array
|
|
357
|
-
const result = /^(.+)\[\?\(
|
|
375
|
+
const result = /^(.+)\[\?\(@\.?(.{0,})='(.+)'\)]$|^(.+)\[(\d+)\]/.exec(segment);
|
|
358
376
|
// array
|
|
359
377
|
if (result) {
|
|
360
378
|
let key;
|
|
@@ -362,7 +380,7 @@ const unflattenChanges = (changes) => {
|
|
|
362
380
|
let arrKey;
|
|
363
381
|
if (result[1]) {
|
|
364
382
|
key = result[1];
|
|
365
|
-
embeddedKey = result[2];
|
|
383
|
+
embeddedKey = result[2] || '$value';
|
|
366
384
|
arrKey = result[3];
|
|
367
385
|
}
|
|
368
386
|
else {
|
|
@@ -437,4 +455,3 @@ const unflattenChanges = (changes) => {
|
|
|
437
455
|
});
|
|
438
456
|
return changesArr;
|
|
439
457
|
};
|
|
440
|
-
exports.unflattenChanges = unflattenChanges;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-diff-ts",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "A diff tool for JavaScript based on https://www.npmjs.com/package/diff-json written in TypeScript.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
|
-
"format": "prettier --write \"src/**/*.ts\"
|
|
9
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
10
10
|
"lint": "tslint -p tsconfig.json",
|
|
11
11
|
"test": "jest --config jest.config.json",
|
|
12
12
|
"test:watch": "jest --watch --config jest.config.json",
|
|
@@ -38,15 +38,15 @@
|
|
|
38
38
|
"homepage": "https://github.com/ltwlf/json-diff-ts#readme",
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/jest": "^29.1.1",
|
|
41
|
-
"@types/lodash": "^4.14.149",
|
|
42
|
-
"jest": "^
|
|
41
|
+
"@types/lodash-es": "^4.14.149",
|
|
42
|
+
"jest": "^29.5.0",
|
|
43
43
|
"prettier": "^2.5.1",
|
|
44
|
-
"ts-jest": "^
|
|
44
|
+
"ts-jest": "^29.0.5",
|
|
45
45
|
"tslint": "^6.1.3",
|
|
46
46
|
"tslint-config-prettier": "^1.18.0",
|
|
47
47
|
"typescript": "^4.5.2"
|
|
48
48
|
},
|
|
49
|
-
"
|
|
50
|
-
"lodash": "^4.
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"lodash": "^4.17.21"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|