json-diff-ts 1.2.6 → 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/README.md CHANGED
@@ -281,7 +281,7 @@ Blog: https://blog.leitwolf.io
281
281
  Twitter: [@cglessner](https://twitter.com/cglessner)
282
282
 
283
283
  ## Changelog
284
- - v1.2.6 Improve handling of JSON Path segments that include periods (PR by [EdVinyard](https://github.com/EdVinyard))
284
+
285
285
  - v1.2.5 Patch all dependencies; add support for resolving a key name if a function is used to get the key value
286
286
  - v1.2.4 Fix readme (npm install); update TypeScript and Lodash
287
287
  - v1.2.3 Update outdated dependencies; update TypeScript version to 4.5.2
package/lib/index.js CHANGED
@@ -1,18 +1,2 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
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';
@@ -1,64 +1,58 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compare = exports.applyChangelist = exports.enrich = exports.createContainer = exports.createValue = exports.CompareOperation = void 0;
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 = exports.CompareOperation || (exports.CompareOperation = {}));
11
- const createValue = (value) => ({ type: CompareOperation.UNCHANGED, value });
12
- exports.createValue = createValue;
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
- exports.createContainer = createContainer;
18
- const enrich = (object) => {
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 (0, lodash_1.keys)(object)
23
- .map((key) => ({ key, value: (0, exports.enrich)(object[key]) }))
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
- }, (0, exports.createContainer)({}));
22
+ }, createContainer({}));
28
23
  case 'Array':
29
- return (0, lodash_1.chain)(object)
30
- .map(value => (0, exports.enrich)(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
- }, (0, exports.createContainer)([]))
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 (0, exports.createValue)(object);
36
+ return createValue(object);
42
37
  }
43
38
  };
44
- exports.enrich = enrich;
45
- const applyChangelist = (object, changelist) => {
46
- (0, lodash_1.chain)(changelist)
47
- .map(entry => (Object.assign(Object.assign({}, entry), { path: (0, lodash_1.replace)(entry.path, '$.', '.') })))
48
- .map(entry => (Object.assign(Object.assign({}, entry), { path: (0, lodash_1.replace)(entry.path, /(\[(?<array>\d)\]\.)/g, 'ARRVAL_START$<array>ARRVAL_END') })))
49
- .map(entry => (Object.assign(Object.assign({}, entry), { path: (0, lodash_1.replace)(entry.path, /(?<dot>\.)/g, '.value$<dot>') })))
50
- .map(entry => (Object.assign(Object.assign({}, entry), { path: (0, lodash_1.replace)(entry.path, /\./, '') })))
51
- .map(entry => (Object.assign(Object.assign({}, entry), { path: (0, lodash_1.replace)(entry.path, /ARRVAL_START/g, '.value[') })))
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 jsonDiff_1.Operation.ADD:
57
- case jsonDiff_1.Operation.UPDATE:
58
- (0, lodash_1.set)(object, entry.path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });
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 jsonDiff_1.Operation.REMOVE:
61
- (0, lodash_1.set)(object, entry.path, { type: entry.type, value: undefined, oldValue: entry.value });
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
- exports.applyChangelist = applyChangelist;
70
- const compare = (oldObject, newObject) => {
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
- import { Dictionary } from 'lodash';
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?: Dictionary<string | FunctionKey>) => IChange[];
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 declare type Changeset = IChange[];
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
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
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 = (0, exports.getTypeOfObj)(oldObj);
22
- const typeOfNewObj = (0, exports.getTypeOfObj)(newObj);
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 = (0, lodash_1.intersection)(oldObjKeys, newObjKeys);
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 = (0, lodash_1.difference)(newObjKeys, oldObjKeys);
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 = (0, lodash_1.difference)(oldObjKeys, newObjKeys);
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 !== '$index') {
138
- obj = (0, lodash_1.keyBy)(arr, uniqKey);
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 = (0, lodash_1.find)(arr, (el) => el[change.embeddedKey].toString() === subchange.key.toString());
232
+ element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key.toString());
223
233
  }
224
- result.push((0, exports.applyChangeset)(element, subchange.changes));
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 (0, exports.applyChangeset)(obj, change.changes);
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 = (0, lodash_1.find)(arr, (el) => el[change.embeddedKey].toString() === subchange.key);
270
+ element = find(arr, (el) => el[change.embeddedKey].toString() === subchange.key);
261
271
  }
262
- result.push((0, exports.revertChangeset)(element, subchange.changes));
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 (0, exports.revertChangeset)(obj, change.changes);
282
+ return revertChangeset(obj, change.changes);
273
283
  }
274
284
  };
275
- const diff = (oldObj, newObj, embeddedObjKeys) => compare(oldObj, newObj, [], embeddedObjKeys, []);
276
- exports.diff = diff;
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
- exports.applyChangeset = applyChangeset;
286
- const revertChangeset = (obj, changeset) => {
294
+ export const revertChangeset = (obj, changeset) => {
287
295
  if (changeset) {
288
296
  changeset
289
297
  .reverse()
@@ -291,40 +299,48 @@ const revertChangeset = (obj, changeset) => {
291
299
  }
292
300
  return obj;
293
301
  };
294
- exports.revertChangeset = revertChangeset;
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 = exports.Operation || (exports.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, ...(0, exports.flattenChangeset)(change, path, embeddedKey)], []);
310
+ return obj.reduce((memo, change) => [...memo, ...flattenChangeset(change, path, embeddedKey)], []);
304
311
  }
305
312
  else {
306
313
  if (obj.changes || embeddedKey) {
307
- path = embeddedKey
308
- ? embeddedKey === '$index'
309
- ? `${path}[${obj.key}]`
310
- : obj.type === Operation.ADD
311
- ? path
312
- : filterExpression(path, embeddedKey, obj.key)
313
- : (path = append(path, obj.key));
314
- return (0, exports.flattenChangeset)(obj.changes || obj, path, obj.embeddedKey);
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 = (0, exports.getTypeOfObj)(obj.value);
336
+ const valueType = getTypeOfObj(obj.value);
318
337
  return [
319
- Object.assign(Object.assign({}, obj), { path: valueType === 'Object' || path.endsWith(`[${obj.key}]`)
320
- ? path
321
- : append(path, obj.key), valueType })
338
+ Object.assign(Object.assign({}, obj), { path: valueType === 'Object' || path.endsWith(`[${obj.key}]`) ? path : `${path}.${obj.key}`, valueType })
322
339
  ];
323
340
  }
324
341
  }
325
342
  };
326
- exports.flattenChangeset = flattenChangeset;
327
- const unflattenChanges = (changes) => {
343
+ export const unflattenChanges = (changes) => {
328
344
  if (!Array.isArray(changes)) {
329
345
  changes = [changes];
330
346
  }
@@ -356,7 +372,7 @@ const unflattenChanges = (changes) => {
356
372
  for (let i = 1; i < segments.length; i++) {
357
373
  const segment = segments[i];
358
374
  // check for array
359
- const result = /^(.+)\[\?\(@\.(.+)='(.+)'\)]$|^(.+)\[(\d+)\]/.exec(segment);
375
+ const result = /^(.+)\[\?\(@\.?(.{0,})='(.+)'\)]$|^(.+)\[(\d+)\]/.exec(segment);
360
376
  // array
361
377
  if (result) {
362
378
  let key;
@@ -364,7 +380,7 @@ const unflattenChanges = (changes) => {
364
380
  let arrKey;
365
381
  if (result[1]) {
366
382
  key = result[1];
367
- embeddedKey = result[2];
383
+ embeddedKey = result[2] || '$value';
368
384
  arrKey = result[3];
369
385
  }
370
386
  else {
@@ -439,16 +455,3 @@ const unflattenChanges = (changes) => {
439
455
  });
440
456
  return changesArr;
441
457
  };
442
- exports.unflattenChanges = unflattenChanges;
443
- /** combine a base JSON Path with a subsequent segment */
444
- function append(basePath, nextSegment) {
445
- return nextSegment.includes('.')
446
- ? `${basePath}[${nextSegment}]`
447
- : `${basePath}.${nextSegment}`;
448
- }
449
- /** returns a JSON Path filter expression; e.g., `$.pet[(?name='spot')]` */
450
- function filterExpression(basePath, filterKey, filterValue) {
451
- return typeof filterKey === 'string' && filterKey.includes('.')
452
- ? `${basePath}[?(@[${filterKey}]='${filterValue}')]`
453
- : `${basePath}[?(@.${filterKey}='${filterValue}')]`;
454
- }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "json-diff-ts",
3
- "version": "1.2.6",
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\" \"src/**/*.js\"",
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": "^24.9.0",
41
+ "@types/lodash-es": "^4.14.149",
42
+ "jest": "^29.5.0",
43
43
  "prettier": "^2.5.1",
44
- "ts-jest": "^24.2.0",
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
- "peerDependencies": {
50
- "lodash": "^4.x"
49
+ "dependencies": {
50
+ "lodash": "^4.17.21"
51
51
  }
52
- }
52
+ }