json-diff-ts 4.10.2 → 4.10.3

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/dist/index.cjs CHANGED
@@ -145,12 +145,12 @@ var revertChangeset = (obj, changeset) => {
145
145
  }
146
146
  return obj;
147
147
  };
148
- var atomizeChangeset = (obj, path = "$", embeddedKey) => {
148
+ var atomizeChangeset = (obj, path = "$", embeddedKey, embeddedKeyIsPath) => {
149
149
  if (Array.isArray(obj)) {
150
- return handleArray(obj, path, embeddedKey);
150
+ return handleArray(obj, path, embeddedKey, embeddedKeyIsPath);
151
151
  } else if (obj.changes || embeddedKey) {
152
152
  if (embeddedKey) {
153
- const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path);
153
+ const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path, embeddedKeyIsPath);
154
154
  path = updatedPath;
155
155
  if (atomicChange) {
156
156
  return atomicChange;
@@ -158,7 +158,7 @@ var atomizeChangeset = (obj, path = "$", embeddedKey) => {
158
158
  } else {
159
159
  path = append(path, obj.key);
160
160
  }
161
- return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey);
161
+ return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey, obj.embeddedKeyIsPath);
162
162
  } else {
163
163
  const valueType = getTypeOfObj(obj.value);
164
164
  let finalPath = path;
@@ -185,7 +185,7 @@ var atomizeChangeset = (obj, path = "$", embeddedKey) => {
185
185
  ];
186
186
  }
187
187
  };
188
- function handleEmbeddedKey(embeddedKey, obj, path) {
188
+ function handleEmbeddedKey(embeddedKey, obj, path, isPath) {
189
189
  if (embeddedKey === "$index") {
190
190
  path = `${path}[${obj.key}]`;
191
191
  return [path];
@@ -203,12 +203,12 @@ function handleEmbeddedKey(embeddedKey, obj, path) {
203
203
  ]
204
204
  ];
205
205
  } else {
206
- path = filterExpression(path, embeddedKey, obj.key);
206
+ path = filterExpression(path, embeddedKey, obj.key, isPath);
207
207
  return [path];
208
208
  }
209
209
  }
210
- var handleArray = (obj, path, embeddedKey) => {
211
- return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey)], []);
210
+ var handleArray = (obj, path, embeddedKey, embeddedKeyIsPath) => {
211
+ return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey, embeddedKeyIsPath)], []);
212
212
  };
213
213
  var unatomizeChangeset = (changes) => {
214
214
  if (!Array.isArray(changes)) {
@@ -228,15 +228,17 @@ var unatomizeChangeset = (changes) => {
228
228
  } else {
229
229
  for (let i = 1; i < segments.length; i++) {
230
230
  const segment = segments[i];
231
- const result = /^([^[\]]+)\[\?\(@(?:\.?([^=[]*)|(?:\['([^']*)'\]))=+'([^']+)'\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
231
+ const result = /^([^[\]]+)\[\?\(@(?:\.?([^=[]*)|(?:\['([^']*(?:''[^']*)*)'\]))=+'([^']*(?:''[^']*)*)'\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
232
232
  if (result) {
233
233
  let key;
234
234
  let embeddedKey;
235
235
  let arrKey;
236
+ let isPath;
236
237
  if (result[1]) {
237
238
  key = result[1];
238
- embeddedKey = result[3] || result[2] || "$value";
239
- arrKey = result[4];
239
+ embeddedKey = result[3]?.replace(/''/g, "'") || result[2] || "$value";
240
+ isPath = !result[3] && !!result[2] && result[2].includes(".") && NESTED_PATH_RE.test(result[2]) ? true : void 0;
241
+ arrKey = result[4]?.replace(/''/g, "'");
240
242
  } else {
241
243
  key = result[5];
242
244
  embeddedKey = "$index";
@@ -245,6 +247,7 @@ var unatomizeChangeset = (changes) => {
245
247
  if (i === segments.length - 1) {
246
248
  ptr.key = key;
247
249
  ptr.embeddedKey = embeddedKey;
250
+ if (isPath) ptr.embeddedKeyIsPath = true;
248
251
  ptr.type = "UPDATE" /* UPDATE */;
249
252
  ptr.changes = [
250
253
  {
@@ -257,6 +260,7 @@ var unatomizeChangeset = (changes) => {
257
260
  } else {
258
261
  ptr.key = key;
259
262
  ptr.embeddedKey = embeddedKey;
263
+ if (isPath) ptr.embeddedKeyIsPath = true;
260
264
  ptr.type = "UPDATE" /* UPDATE */;
261
265
  const newPtr = {};
262
266
  ptr.changes = [
@@ -458,12 +462,15 @@ var compareArray = (oldObj, newObj, path, keyPath, options) => {
458
462
  const indexedOldObj = convertArrayToObj(oldObj, uniqKey);
459
463
  const indexedNewObj = convertArrayToObj(newObj, uniqKey);
460
464
  const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);
465
+ const isFunctionKey = typeof uniqKey === "function" && uniqKey.length === 2;
461
466
  if (diffs.length) {
467
+ const resolvedKey = isFunctionKey ? uniqKey(newObj[0] ?? oldObj[0], true) : uniqKey;
462
468
  return [
463
469
  {
464
470
  type: "UPDATE" /* UPDATE */,
465
471
  key: getKey(path),
466
- embeddedKey: typeof uniqKey === "function" && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,
472
+ embeddedKey: resolvedKey,
473
+ ...isFunctionKey && typeof resolvedKey === "string" && NESTED_PATH_RE.test(resolvedKey) && resolvedKey.includes(".") ? { embeddedKeyIsPath: true } : {},
467
474
  changes: diffs
468
475
  }
469
476
  ];
@@ -521,13 +528,13 @@ var comparePrimitives = (oldObj, newObj, path) => {
521
528
  }
522
529
  return changes;
523
530
  };
524
- var removeKey = (obj, key, embeddedKey) => {
531
+ var removeKey = (obj, key, embeddedKey, isPath) => {
525
532
  if (Array.isArray(obj)) {
526
533
  if (embeddedKey === "$index") {
527
534
  obj.splice(Number(key), 1);
528
535
  return;
529
536
  }
530
- const index = indexOfItemInArray(obj, embeddedKey, key);
537
+ const index = indexOfItemInArray(obj, embeddedKey, key, isPath);
531
538
  if (index === -1) {
532
539
  console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array!`);
533
540
  return;
@@ -538,13 +545,20 @@ var removeKey = (obj, key, embeddedKey) => {
538
545
  return;
539
546
  }
540
547
  };
541
- var indexOfItemInArray = (arr, key, value) => {
548
+ var resolveProperty = (obj, key, isPath) => {
549
+ if (obj == null) return void 0;
550
+ if (typeof key !== "string" || !isPath || !key.includes(".")) return obj[key];
551
+ return key.split(".").reduce((cur, seg) => cur?.[seg], obj);
552
+ };
553
+ var indexOfItemInArray = (arr, key, value, isPath) => {
542
554
  if (key === "$value") {
543
555
  return arr.indexOf(value);
544
556
  }
545
557
  for (let i = 0; i < arr.length; i++) {
546
558
  const item = arr[i];
547
- if (item && item[key] ? item[key].toString() === value.toString() : void 0) {
559
+ if (item == null) continue;
560
+ const resolved = resolveProperty(item, key, isPath);
561
+ if (resolved != null && String(resolved) === String(value)) {
548
562
  return i;
549
563
  }
550
564
  }
@@ -562,7 +576,7 @@ var addKeyValue = (obj, key, value, embeddedKey) => {
562
576
  return obj ? obj[key] = value : null;
563
577
  }
564
578
  };
565
- var applyLeafChange = (obj, change, embeddedKey) => {
579
+ var applyLeafChange = (obj, change, embeddedKey, isPath) => {
566
580
  const { type, key, value } = change;
567
581
  switch (type) {
568
582
  case "ADD" /* ADD */:
@@ -570,7 +584,7 @@ var applyLeafChange = (obj, change, embeddedKey) => {
570
584
  case "UPDATE" /* UPDATE */:
571
585
  return modifyKeyValue(obj, key, value);
572
586
  case "REMOVE" /* REMOVE */:
573
- return removeKey(obj, key, embeddedKey);
587
+ return removeKey(obj, key, embeddedKey, isPath);
574
588
  }
575
589
  };
576
590
  var applyArrayChange = (arr, change) => {
@@ -587,7 +601,7 @@ var applyArrayChange = (arr, change) => {
587
601
  }
588
602
  for (const subchange of changes) {
589
603
  if (subchange.value !== null && subchange.value !== void 0 || subchange.type === "REMOVE" /* REMOVE */ || subchange.value === null && subchange.type === "ADD" /* ADD */ || subchange.value === void 0 && subchange.type === "ADD" /* ADD */) {
590
- applyLeafChange(arr, subchange, change.embeddedKey);
604
+ applyLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
591
605
  } else {
592
606
  let element;
593
607
  if (change.embeddedKey === "$index") {
@@ -598,7 +612,10 @@ var applyArrayChange = (arr, change) => {
598
612
  element = arr[index];
599
613
  }
600
614
  } else {
601
- element = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());
615
+ element = arr.find((el) => {
616
+ const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
617
+ return resolved != null && String(resolved) === String(subchange.key);
618
+ });
602
619
  }
603
620
  if (element) {
604
621
  applyChangeset(element, subchange.changes);
@@ -614,7 +631,7 @@ var applyBranchChange = (obj, change) => {
614
631
  return applyChangeset(obj, change.changes);
615
632
  }
616
633
  };
617
- var revertLeafChange = (obj, change, embeddedKey = "$index") => {
634
+ var revertLeafChange = (obj, change, embeddedKey = "$index", isPath) => {
618
635
  const { type, key, value, oldValue } = change;
619
636
  if (key === "$root") {
620
637
  switch (type) {
@@ -644,7 +661,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
644
661
  }
645
662
  switch (type) {
646
663
  case "ADD" /* ADD */:
647
- return removeKey(obj, key, embeddedKey);
664
+ return removeKey(obj, key, embeddedKey, isPath);
648
665
  case "UPDATE" /* UPDATE */:
649
666
  return modifyKeyValue(obj, key, oldValue);
650
667
  case "REMOVE" /* REMOVE */:
@@ -654,7 +671,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
654
671
  var revertArrayChange = (arr, change) => {
655
672
  for (const subchange of change.changes) {
656
673
  if (subchange.value != null || subchange.type === "REMOVE" /* REMOVE */) {
657
- revertLeafChange(arr, subchange, change.embeddedKey);
674
+ revertLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
658
675
  } else {
659
676
  let element;
660
677
  if (change.embeddedKey === "$index") {
@@ -665,7 +682,10 @@ var revertArrayChange = (arr, change) => {
665
682
  element = arr[index];
666
683
  }
667
684
  } else {
668
- element = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());
685
+ element = arr.find((el) => {
686
+ const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
687
+ return resolved != null && String(resolved) === String(subchange.key);
688
+ });
669
689
  }
670
690
  if (element) {
671
691
  revertChangeset(element, subchange.changes);
@@ -685,9 +705,17 @@ function append(basePath, nextSegment) {
685
705
  return nextSegment.includes(".") ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;
686
706
  }
687
707
  var IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
688
- function filterExpression(basePath, filterKey, filterValue) {
708
+ var NESTED_PATH_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*$/;
709
+ function filterExpression(basePath, filterKey, filterValue, isPath) {
689
710
  const escapedValue = `'${filterValue.replace(/'/g, "''")}'`;
690
- const memberAccess = IDENT_RE.test(filterKey) ? `.${filterKey}` : `['${filterKey.replace(/'/g, "''")}']`;
711
+ let memberAccess;
712
+ if (isPath && NESTED_PATH_RE.test(filterKey)) {
713
+ memberAccess = "." + filterKey;
714
+ } else if (IDENT_RE.test(filterKey)) {
715
+ memberAccess = `.${filterKey}`;
716
+ } else {
717
+ memberAccess = `['${filterKey.replace(/'/g, "''")}']`;
718
+ }
691
719
  return `${basePath}[?(@${memberAccess}==${escapedValue})]`;
692
720
  }
693
721
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/helpers.ts","../src/jsonDiff.ts","../src/jsonCompare.ts"],"sourcesContent":["export * from './jsonDiff.js';\nexport * from './jsonCompare.js';\n","export type FunctionKey<T = any> = (obj: T, shouldReturnKeyName?: boolean, index?: number) => any;\n\nexport function splitJSONPath(path: string): string[] {\n const 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\nexport function arrayDifference<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => !secondSet.has(item));\n}\n\nexport function arrayIntersection<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => secondSet.has(item));\n}\n\nexport function keyBy<T>(arr: T[], getKey: FunctionKey<T>): Record<string, T> {\n const result: Record<string, T> = {};\n for (const [index, item] of Object.entries(arr)) {\n result[String(getKey(item, false, Number(index)))] = item;\n }\n return result;\n}\n\nexport function setByPath(obj: any, path: string, value: any): void {\n const parts = path.replaceAll(/\\[(\\d+)\\]/g, '.$1').split('.').filter(Boolean);\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!(part in current)) {\n current[part] = /^\\d+$/.test(parts[i + 1]) ? [] : {};\n }\n current = current[part];\n }\n current[parts.at(-1)] = value;\n}\n","import { arrayDifference as difference, arrayIntersection as intersection, keyBy, splitJSONPath, FunctionKey } from './helpers.js';\n\ntype EmbeddedObjKeysType = Record<string, string | FunctionKey>;\ntype EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nenum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\ninterface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n value?: any;\n oldValue?: any;\n changes?: IChange[];\n}\ntype Changeset = IChange[];\n\ninterface IAtomicChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\ninterface Options {\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;\n keysToSkip?: readonly 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 */\nfunction diff(oldObj: any, newObj: any, options: Options = {}): IChange[] {\n let { embeddedObjKeys } = options;\n const { 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, or if the value is null and the type is ADD,\n * it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nconst applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n // Handle null values as leaf changes when the operation is ADD\n // Also handle undefined values for ADD operations in array contexts\n if ((value !== null && value !== undefined) || \n type === Operation.REMOVE || \n (value === null && type === Operation.ADD) ||\n (value === undefined && type === Operation.ADD)) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n // When key is '$root', apply to obj itself (root-level arrays)\n applyBranchChange(key === '$root' ? obj : 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, or if the value is null and\n * the type is REMOVE (which would be reverting an ADD operation), 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 */\nconst revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any => {\n const { value, type } = change;\n // Handle null values as leaf changes when the operation is REMOVE (since we're reversing ADD)\n if (!change.changes || (value === null && type === Operation.REMOVE)) {\n revertLeafChange(obj, change);\n } else {\n // When key is '$root', revert on obj itself (root-level arrays)\n revertBranchChange(change.key === '$root' ? obj : obj[change.key], change);\n }\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 */\nconst 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 let finalPath = path;\n if (!finalPath.endsWith(`[${obj.key}]`)) {\n // Avoid duplicate filter values at the end of the JSONPath\n let endsWithFilterValue = false;\n const filterEndIdx = path.lastIndexOf(')]');\n if (filterEndIdx !== -1) {\n const filterStartIdx = path.lastIndexOf('==', filterEndIdx);\n if (filterStartIdx !== -1) {\n const filterValue = path\n .slice(filterStartIdx + 2, filterEndIdx)\n // Remove single quotes at the start or end of the filter value\n .replaceAll(/(^'|'$)/g, '');\n endsWithFilterValue = filterValue === String(obj.key);\n }\n }\n if (!endsWithFilterValue) {\n finalPath = append(path, obj.key);\n }\n }\n \n return [\n {\n ...obj,\n path: finalPath,\n valueType\n }\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 {\n ...obj,\n path,\n valueType\n }\n ]\n ];\n } else {\n path = filterExpression(path, embeddedKey as string, obj.key);\n return [path];\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 * 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 */\nconst unatomizeChangeset = (changes: IAtomicChange | IAtomicChange[]) => {\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 = 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 filter segments and array index segments:\n // \"items[?(@.id=='123')]\" — dot-notation key filter\n // \"items[?(@['c.d']=='20')]\" — bracket-notation key filter\n // \"items[?(@=='123')]\" — value filter\n // \"items[2]\" — array index\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[3] || result[2] || '$value';\n arrKey = result[4];\n } else {\n key = result[5];\n embeddedKey = '$index';\n arrKey = Number(result[6]);\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 // Handle all leaf values the same way, regardless of type\n ptr.key = segment;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\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 */\nconst getTypeOfObj = (obj: any) => {\n if (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.at(-1);\n return left ?? '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n let changes: any[] = [];\n\n // Check if the current path should be skipped \n const currentPath = keyPath.join('.');\n if (options.keysToSkip?.some(skipPath => {\n // Exact match\n if (currentPath === skipPath) {\n return true;\n }\n \n // The current path is a parent of the skip path\n if (skipPath.includes('.') && skipPath.startsWith(currentPath + '.')) {\n return false; // Don't skip, we need to process the parent\n }\n \n // The current path is a child or deeper descendant of the skip path\n if (skipPath.includes('.')) {\n // Check if skipPath is a parent of currentPath\n const skipParts = skipPath.split('.');\n const currentParts = currentPath.split('.');\n \n if (currentParts.length >= skipParts.length) {\n // Check if all parts of skipPath match the corresponding parts in currentPath\n for (let i = 0; i < skipParts.length; i++) {\n if (skipParts[i] !== currentParts[i]) {\n return false;\n }\n }\n return true; // All parts match, so this is a child or equal path\n }\n }\n \n return false;\n })) {\n return changes; // Skip comparison for this path and its children\n }\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 // Only add a REMOVE operation if oldObj is not undefined\n if (typeOfOldObj !== 'undefined') {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\n\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n // As undefined is not serialized into JSON, it should not count as an added value.\n // However, for array elements, we want to preserve undefined as a value\n if (typeOfNewObj !== 'undefined' || isArrayElement) {\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n }\n\n return changes;\n }\n\n if (typeOfNewObj === 'undefined' && typeOfOldObj !== 'undefined') {\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n if (isArrayElement) {\n // In array contexts, treat transition to undefined as an update\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n } else {\n // In object contexts, treat transition to undefined as removal (original behavior)\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\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 if (typeOfNewObj === null) {\n if (typeOfOldObj !== null) {\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n }\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n if (typeOfNewObj === '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 } else {\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n break;\n case 'Object': {\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 = (oldObj: any, newObj: any, path: any, keyPath: any, skipPath = false, options: Options = {}) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n // Filter keys directly rather than filtering by keysToSkip at this level\n // The full path check is now done in the compare function\n const oldObjKeys = Object.keys(oldObj);\n const newObjKeys = Object.keys(newObj);\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip adding this key\n }\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip removing this key\n }\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n if (getTypeOfObj(newObj) !== 'Array') {\n return [{ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj }];\n }\n\n const left = getObjectKey(options.embeddedObjKeys, keyPath);\n const uniqKey = 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 for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n } else {\n // Convert string keys to functions for compatibility with es-toolkit keyBy\n const keyFunction = typeof uniqKey === 'string' ? (item: any) => item[uniqKey] : uniqKey;\n obj = keyBy(arr, keyFunction);\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(Number(key), 1);\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 ?? key, 1);\n } else {\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);\nconst addKeyValue = (obj: any, key: any, value: any, embeddedKey?: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(Number(key), 0, value);\n return obj.length;\n }\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, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey);\n }\n};\n\n/**\n * Applies changes to an array.\n * \n * @param {any[]} arr - The array to apply changes to.\n * @param {any} change - The change to apply, containing nested changes.\n * @returns {any[]} - The array after changes have been applied.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst applyArrayChange = (arr: any[], change: any) => {\n let changes = change.changes;\n if (change.embeddedKey === '$index') {\n changes = [...changes].sort((a, b) => {\n if (a.type === Operation.REMOVE && b.type === Operation.REMOVE) {\n return Number(b.key) - Number(a.key);\n }\n if (a.type === Operation.REMOVE) return -1;\n if (b.type === Operation.REMOVE) return 1;\n return Number(a.key) - Number(b.key);\n });\n }\n\n for (const subchange of changes) {\n if (\n (subchange.value !== null && subchange.value !== undefined) ||\n subchange.type === Operation.REMOVE ||\n (subchange.value === null && subchange.type === Operation.ADD) ||\n (subchange.value === undefined && subchange.type === Operation.ADD)\n ) {\n 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 = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n if (element) {\n applyChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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 \n // Special handling for $root key\n if (key === '$root') {\n switch (type) {\n case Operation.ADD:\n // When reverting an ADD of the entire object, clear all properties\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n return obj;\n case Operation.UPDATE:\n // Replace the entire object with the old value\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n if (oldValue && typeof oldValue === 'object') {\n Object.assign(obj, oldValue);\n }\n return obj;\n case Operation.REMOVE:\n // Restore the removed object\n if (value && typeof value === 'object') {\n Object.assign(obj, value);\n }\n return obj;\n }\n }\n \n // Regular property handling\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\n/**\n * Reverts changes in an array.\n * \n * @param {any[]} arr - The array to revert changes in.\n * @param {any} change - The change to revert, containing nested changes.\n * @returns {any[]} - The array after changes have been reverted.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst revertArrayChange = (arr: any[], change: any) => {\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n revertLeafChange(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 = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n if (element) {\n revertChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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\nconst IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/** returns a JSON Path filter expression; e.g., `$.pet[?(@.name=='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string, filterValue: string) {\n const escapedValue = `'${filterValue.replace(/'/g, \"''\")}'`;\n const memberAccess = IDENT_RE.test(filterKey)\n ? `.${filterKey}`\n : `['${filterKey.replace(/'/g, \"''\")}']`;\n return `${basePath}[?(@${memberAccess}==${escapedValue})]`;\n}\n\nexport {\n Changeset,\n EmbeddedObjKeysMapType,\n EmbeddedObjKeysType,\n IAtomicChange,\n IChange,\n Operation,\n Options,\n applyChangeset,\n atomizeChangeset,\n diff,\n getTypeOfObj,\n revertChangeset,\n unatomizeChangeset\n};\n","import { setByPath, splitJSONPath } from './helpers.js';\nimport { diff, atomizeChangeset, getTypeOfObj, IAtomicChange, Operation } from './jsonDiff.js';\n\nenum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\ninterface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nconst createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nconst createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nconst enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return Object.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 (object as any[])\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]));\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\n/**\n * Converts an atomized JSONPath (e.g. `$.items[0].name`) into a navigation\n * path through the enriched tree (e.g. `value.items.value[0].value.name`).\n *\n * The enriched tree wraps every level in `{ type, value }` nodes, so between\n * each logical key/index we must step through `.value` to unwrap the container.\n */\nconst buildEnrichedPath = (atomicPath: string): string => {\n const segments = splitJSONPath(atomicPath);\n // segments[0] is always '$' (the JSONPath root)\n\n let result = 'value'; // enter the root container's value\n\n for (let i = 1; i < segments.length; i++) {\n const seg = segments[i];\n const isLast = i === segments.length - 1;\n\n // Match segments like \"items[0]\" or \"variants[12]\"\n const arrayMatch = /^(.+?)\\[(\\d+)\\]$/.exec(seg);\n\n if (arrayMatch) {\n const [, key, index] = arrayMatch;\n // key.value → unwrap the array container, then [index] into the array\n result += `.${key}.value[${index}]`;\n } else {\n result += `.${seg}`;\n }\n\n // For non-leaf segments, unwrap the next container\n if (!isLast) {\n result += '.value';\n }\n }\n\n return result;\n};\n\nconst applyChangelist = (object: IComparisonEnrichedNode, changelist: IAtomicChange[]): IComparisonEnrichedNode => {\n changelist.forEach((entry) => {\n const path = buildEnrichedPath(entry.path);\n\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n setByPath(object, path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n setByPath(object, path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nconst ARRAY_WRAPPER_KEY = '_$arr';\n\nconst compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n // Root-level arrays produce $root paths that don't map to real properties.\n // Wrap them in an object so diff/atomize generates standard property paths.\n if (Array.isArray(oldObject) || Array.isArray(newObject)) {\n const wrappedOld = { [ARRAY_WRAPPER_KEY]: oldObject };\n const wrappedNew = { [ARRAY_WRAPPER_KEY]: newObject };\n const enriched = enrich(wrappedOld);\n const changes = atomizeChangeset(diff(wrappedOld, wrappedNew));\n const result = applyChangelist(enriched, changes);\n return (result.value as any)[ARRAY_WRAPPER_KEY];\n }\n\n return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));\n};\n\nexport { CompareOperation, IComparisonEnrichedNode, createValue, createContainer, enrich, applyChangelist, compare };\n"],"mappings":"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","names":["compare","getKey","Operation","skipPath","key","CompareOperation","compare"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/helpers.ts","../src/jsonDiff.ts","../src/jsonCompare.ts"],"sourcesContent":["export * from './jsonDiff.js';\nexport * from './jsonCompare.js';\n","export type FunctionKey<T = any> = (obj: T, shouldReturnKeyName?: boolean, index?: number) => any;\n\nexport function splitJSONPath(path: string): string[] {\n const 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\nexport function arrayDifference<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => !secondSet.has(item));\n}\n\nexport function arrayIntersection<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => secondSet.has(item));\n}\n\nexport function keyBy<T>(arr: T[], getKey: FunctionKey<T>): Record<string, T> {\n const result: Record<string, T> = {};\n for (const [index, item] of Object.entries(arr)) {\n result[String(getKey(item, false, Number(index)))] = item;\n }\n return result;\n}\n\nexport function setByPath(obj: any, path: string, value: any): void {\n const parts = path.replaceAll(/\\[(\\d+)\\]/g, '.$1').split('.').filter(Boolean);\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!(part in current)) {\n current[part] = /^\\d+$/.test(parts[i + 1]) ? [] : {};\n }\n current = current[part];\n }\n current[parts.at(-1)] = value;\n}\n","import { arrayDifference as difference, arrayIntersection as intersection, keyBy, splitJSONPath, FunctionKey } from './helpers.js';\n\ntype EmbeddedObjKeysType = Record<string, string | FunctionKey>;\ntype EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nenum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\ninterface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n /** When true, embeddedKey is a dot-separated nested path (e.g. \"a.b\" → @.a.b). */\n embeddedKeyIsPath?: boolean;\n value?: any;\n oldValue?: any;\n changes?: IChange[];\n}\ntype Changeset = IChange[];\n\ninterface IAtomicChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\ninterface Options {\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;\n keysToSkip?: readonly 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 */\nfunction diff(oldObj: any, newObj: any, options: Options = {}): IChange[] {\n let { embeddedObjKeys } = options;\n const { 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, or if the value is null and the type is ADD,\n * it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nconst applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n // Handle null values as leaf changes when the operation is ADD\n // Also handle undefined values for ADD operations in array contexts\n if ((value !== null && value !== undefined) || \n type === Operation.REMOVE || \n (value === null && type === Operation.ADD) ||\n (value === undefined && type === Operation.ADD)) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n // When key is '$root', apply to obj itself (root-level arrays)\n applyBranchChange(key === '$root' ? obj : 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, or if the value is null and\n * the type is REMOVE (which would be reverting an ADD operation), 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 */\nconst revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any => {\n const { value, type } = change;\n // Handle null values as leaf changes when the operation is REMOVE (since we're reversing ADD)\n if (!change.changes || (value === null && type === Operation.REMOVE)) {\n revertLeafChange(obj, change);\n } else {\n // When key is '$root', revert on obj itself (root-level arrays)\n revertBranchChange(change.key === '$root' ? obj : obj[change.key], change);\n }\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 */\nconst atomizeChangeset = (\n obj: Changeset | IChange,\n path = '$',\n embeddedKey?: string | FunctionKey,\n embeddedKeyIsPath?: boolean\n): IAtomicChange[] => {\n if (Array.isArray(obj)) {\n return handleArray(obj, path, embeddedKey, embeddedKeyIsPath);\n } else if (obj.changes || embeddedKey) {\n if (embeddedKey) {\n const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path, embeddedKeyIsPath);\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, obj.embeddedKeyIsPath);\n } else {\n const valueType = getTypeOfObj(obj.value);\n let finalPath = path;\n if (!finalPath.endsWith(`[${obj.key}]`)) {\n // Avoid duplicate filter values at the end of the JSONPath\n let endsWithFilterValue = false;\n const filterEndIdx = path.lastIndexOf(')]');\n if (filterEndIdx !== -1) {\n const filterStartIdx = path.lastIndexOf('==', filterEndIdx);\n if (filterStartIdx !== -1) {\n const filterValue = path\n .slice(filterStartIdx + 2, filterEndIdx)\n // Remove single quotes at the start or end of the filter value\n .replaceAll(/(^'|'$)/g, '');\n endsWithFilterValue = filterValue === String(obj.key);\n }\n }\n if (!endsWithFilterValue) {\n finalPath = append(path, obj.key);\n }\n }\n \n return [\n {\n ...obj,\n path: finalPath,\n valueType\n }\n ];\n }\n};\n\n// Function to handle embeddedKey logic and update the path\nfunction handleEmbeddedKey(embeddedKey: string | FunctionKey, obj: IChange, path: string, isPath?: boolean): [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 {\n ...obj,\n path,\n valueType\n }\n ]\n ];\n } else {\n path = filterExpression(path, embeddedKey as string, obj.key, isPath);\n return [path];\n }\n}\n\nconst handleArray = (obj: Changeset | IChange[], path: string, embeddedKey?: string | FunctionKey, embeddedKeyIsPath?: boolean): IAtomicChange[] => {\n return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey, embeddedKeyIsPath)], [] as IAtomicChange[]);\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 */\nconst unatomizeChangeset = (changes: IAtomicChange | IAtomicChange[]) => {\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 = 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 filter segments and array index segments.\n // Supports doubled-quote escaping in bracket keys and filter values (e.g. O''Brien).\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 let isPath: boolean | undefined;\n if (result[1]) {\n key = result[1];\n // Unescape doubled quotes in bracket keys and filter values\n embeddedKey = (result[3]?.replace(/''/g, \"'\") || result[2] || '$value');\n isPath = (!result[3] && !!result[2] && result[2].includes('.') && NESTED_PATH_RE.test(result[2])) ? true : undefined;\n arrKey = result[4]?.replace(/''/g, \"'\");\n } else {\n key = result[5];\n embeddedKey = '$index';\n arrKey = Number(result[6]);\n }\n // leaf\n if (i === segments.length - 1) {\n ptr.key = key!;\n ptr.embeddedKey = embeddedKey!;\n if (isPath) ptr.embeddedKeyIsPath = true;\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 if (isPath) ptr.embeddedKeyIsPath = true;\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 // Handle all leaf values the same way, regardless of type\n ptr.key = segment;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\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 */\nconst getTypeOfObj = (obj: any) => {\n if (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.at(-1);\n return left ?? '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n let changes: any[] = [];\n\n // Check if the current path should be skipped \n const currentPath = keyPath.join('.');\n if (options.keysToSkip?.some(skipPath => {\n // Exact match\n if (currentPath === skipPath) {\n return true;\n }\n \n // The current path is a parent of the skip path\n if (skipPath.includes('.') && skipPath.startsWith(currentPath + '.')) {\n return false; // Don't skip, we need to process the parent\n }\n \n // The current path is a child or deeper descendant of the skip path\n if (skipPath.includes('.')) {\n // Check if skipPath is a parent of currentPath\n const skipParts = skipPath.split('.');\n const currentParts = currentPath.split('.');\n \n if (currentParts.length >= skipParts.length) {\n // Check if all parts of skipPath match the corresponding parts in currentPath\n for (let i = 0; i < skipParts.length; i++) {\n if (skipParts[i] !== currentParts[i]) {\n return false;\n }\n }\n return true; // All parts match, so this is a child or equal path\n }\n }\n \n return false;\n })) {\n return changes; // Skip comparison for this path and its children\n }\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 // Only add a REMOVE operation if oldObj is not undefined\n if (typeOfOldObj !== 'undefined') {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\n\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n // As undefined is not serialized into JSON, it should not count as an added value.\n // However, for array elements, we want to preserve undefined as a value\n if (typeOfNewObj !== 'undefined' || isArrayElement) {\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n }\n\n return changes;\n }\n\n if (typeOfNewObj === 'undefined' && typeOfOldObj !== 'undefined') {\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n if (isArrayElement) {\n // In array contexts, treat transition to undefined as an update\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n } else {\n // In object contexts, treat transition to undefined as removal (original behavior)\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\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 if (typeOfNewObj === null) {\n if (typeOfOldObj !== null) {\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n }\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n if (typeOfNewObj === '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 } else {\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n break;\n case 'Object': {\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 = (oldObj: any, newObj: any, path: any, keyPath: any, skipPath = false, options: Options = {}) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n // Filter keys directly rather than filtering by keysToSkip at this level\n // The full path check is now done in the compare function\n const oldObjKeys = Object.keys(oldObj);\n const newObjKeys = Object.keys(newObj);\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip adding this key\n }\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip removing this key\n }\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n if (getTypeOfObj(newObj) !== 'Array') {\n return [{ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj }];\n }\n\n const left = getObjectKey(options.embeddedObjKeys, keyPath);\n const uniqKey = 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 const isFunctionKey = typeof uniqKey === 'function' && uniqKey.length === 2;\n if (diffs.length) {\n const resolvedKey = isFunctionKey ? uniqKey(newObj[0] ?? oldObj[0], true) : uniqKey;\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: resolvedKey,\n ...(isFunctionKey && typeof resolvedKey === 'string' && NESTED_PATH_RE.test(resolvedKey) && resolvedKey.includes('.') ? { embeddedKeyIsPath: true } : {}),\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 for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n } else {\n // Convert string keys to functions for compatibility with es-toolkit keyBy\n const keyFunction = typeof uniqKey === 'string' ? (item: any) => item[uniqKey] : uniqKey;\n obj = keyBy(arr, keyFunction);\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, isPath?: boolean) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(Number(key), 1);\n return;\n }\n const index = indexOfItemInArray(obj, embeddedKey, key, isPath);\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 ?? key, 1);\n } else {\n delete obj[key];\n return;\n }\n};\n\n/** Resolve a property on an object. When isPath is true, traverses nested dot-separated segments. */\nconst resolveProperty = (obj: any, key: any, isPath?: boolean): any => {\n if (obj == null) return undefined;\n if (typeof key !== 'string' || !isPath || !key.includes('.')) return obj[key];\n return key.split('.').reduce((cur, seg) => cur?.[seg], obj);\n};\n\nconst indexOfItemInArray = (arr: any[], key: any, value: any, isPath?: boolean) => {\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 == null) continue;\n const resolved = resolveProperty(item, key, isPath);\n if (resolved != null && String(resolved) === String(value)) {\n return i;\n }\n }\n return -1;\n};\n\nconst modifyKeyValue = (obj: any, key: any, value: any) => (obj[key] = value);\nconst addKeyValue = (obj: any, key: any, value: any, embeddedKey?: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(Number(key), 0, value);\n return obj.length;\n }\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, isPath?: boolean) => {\n const { type, key, value } = change;\n switch (type) {\n case Operation.ADD:\n return addKeyValue(obj, key, value, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey, isPath);\n }\n};\n\n/**\n * Applies changes to an array.\n * \n * @param {any[]} arr - The array to apply changes to.\n * @param {any} change - The change to apply, containing nested changes.\n * @returns {any[]} - The array after changes have been applied.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst applyArrayChange = (arr: any[], change: any) => {\n let changes = change.changes;\n if (change.embeddedKey === '$index') {\n changes = [...changes].sort((a, b) => {\n if (a.type === Operation.REMOVE && b.type === Operation.REMOVE) {\n return Number(b.key) - Number(a.key);\n }\n if (a.type === Operation.REMOVE) return -1;\n if (b.type === Operation.REMOVE) return 1;\n return Number(a.key) - Number(b.key);\n });\n }\n\n for (const subchange of changes) {\n if (\n (subchange.value !== null && subchange.value !== undefined) ||\n subchange.type === Operation.REMOVE ||\n (subchange.value === null && subchange.type === Operation.ADD) ||\n (subchange.value === undefined && subchange.type === Operation.ADD)\n ) {\n applyLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);\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 = arr.find((el) => {\n const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);\n return resolved != null && String(resolved) === String(subchange.key);\n });\n }\n if (element) {\n applyChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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', isPath?: boolean) => {\n const { type, key, value, oldValue } = change;\n \n // Special handling for $root key\n if (key === '$root') {\n switch (type) {\n case Operation.ADD:\n // When reverting an ADD of the entire object, clear all properties\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n return obj;\n case Operation.UPDATE:\n // Replace the entire object with the old value\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n if (oldValue && typeof oldValue === 'object') {\n Object.assign(obj, oldValue);\n }\n return obj;\n case Operation.REMOVE:\n // Restore the removed object\n if (value && typeof value === 'object') {\n Object.assign(obj, value);\n }\n return obj;\n }\n }\n \n // Regular property handling\n switch (type) {\n case Operation.ADD:\n return removeKey(obj, key, embeddedKey, isPath);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, oldValue);\n case Operation.REMOVE:\n return addKeyValue(obj, key, value);\n }\n};\n\n/**\n * Reverts changes in an array.\n * \n * @param {any[]} arr - The array to revert changes in.\n * @param {any} change - The change to revert, containing nested changes.\n * @returns {any[]} - The array after changes have been reverted.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst revertArrayChange = (arr: any[], change: any) => {\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n revertLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);\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 = arr.find((el) => {\n const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);\n return resolved != null && String(resolved) === String(subchange.key);\n });\n }\n if (element) {\n revertChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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\nconst IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\nconst NESTED_PATH_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*$/;\n\n/** returns a JSON Path filter expression; e.g., `$.pet[?(@.name=='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string, filterValue: string, isPath?: boolean) {\n const escapedValue = `'${filterValue.replace(/'/g, \"''\")}'`;\n let memberAccess: string;\n if (isPath && NESTED_PATH_RE.test(filterKey)) {\n memberAccess = '.' + filterKey;\n } else if (IDENT_RE.test(filterKey)) {\n memberAccess = `.${filterKey}`;\n } else {\n memberAccess = `['${filterKey.replace(/'/g, \"''\")}']`;\n }\n return `${basePath}[?(@${memberAccess}==${escapedValue})]`;\n}\n\nexport {\n Changeset,\n EmbeddedObjKeysMapType,\n EmbeddedObjKeysType,\n IAtomicChange,\n IChange,\n Operation,\n Options,\n applyChangeset,\n atomizeChangeset,\n diff,\n getTypeOfObj,\n revertChangeset,\n unatomizeChangeset\n};\n","import { setByPath, splitJSONPath } from './helpers.js';\nimport { diff, atomizeChangeset, getTypeOfObj, IAtomicChange, Operation } from './jsonDiff.js';\n\nenum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\ninterface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nconst createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nconst createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nconst enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return Object.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 (object as any[])\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]));\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\n/**\n * Converts an atomized JSONPath (e.g. `$.items[0].name`) into a navigation\n * path through the enriched tree (e.g. `value.items.value[0].value.name`).\n *\n * The enriched tree wraps every level in `{ type, value }` nodes, so between\n * each logical key/index we must step through `.value` to unwrap the container.\n */\nconst buildEnrichedPath = (atomicPath: string): string => {\n const segments = splitJSONPath(atomicPath);\n // segments[0] is always '$' (the JSONPath root)\n\n let result = 'value'; // enter the root container's value\n\n for (let i = 1; i < segments.length; i++) {\n const seg = segments[i];\n const isLast = i === segments.length - 1;\n\n // Match segments like \"items[0]\" or \"variants[12]\"\n const arrayMatch = /^(.+?)\\[(\\d+)\\]$/.exec(seg);\n\n if (arrayMatch) {\n const [, key, index] = arrayMatch;\n // key.value → unwrap the array container, then [index] into the array\n result += `.${key}.value[${index}]`;\n } else {\n result += `.${seg}`;\n }\n\n // For non-leaf segments, unwrap the next container\n if (!isLast) {\n result += '.value';\n }\n }\n\n return result;\n};\n\nconst applyChangelist = (object: IComparisonEnrichedNode, changelist: IAtomicChange[]): IComparisonEnrichedNode => {\n changelist.forEach((entry) => {\n const path = buildEnrichedPath(entry.path);\n\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n setByPath(object, path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n setByPath(object, path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nconst ARRAY_WRAPPER_KEY = '_$arr';\n\nconst compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n // Root-level arrays produce $root paths that don't map to real properties.\n // Wrap them in an object so diff/atomize generates standard property paths.\n if (Array.isArray(oldObject) || Array.isArray(newObject)) {\n const wrappedOld = { [ARRAY_WRAPPER_KEY]: oldObject };\n const wrappedNew = { [ARRAY_WRAPPER_KEY]: newObject };\n const enriched = enrich(wrappedOld);\n const changes = atomizeChangeset(diff(wrappedOld, wrappedNew));\n const result = applyChangelist(enriched, changes);\n return (result.value as any)[ARRAY_WRAPPER_KEY];\n }\n\n return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));\n};\n\nexport { CompareOperation, IComparisonEnrichedNode, createValue, createContainer, enrich, applyChangelist, compare };\n"],"mappings":"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","names":["compare","getKey","Operation","skipPath","key","CompareOperation","compare"]}
package/dist/index.d.cts CHANGED
@@ -11,6 +11,8 @@ interface IChange {
11
11
  type: Operation;
12
12
  key: string;
13
13
  embeddedKey?: string | FunctionKey;
14
+ /** When true, embeddedKey is a dot-separated nested path (e.g. "a.b" → @.a.b). */
15
+ embeddedKeyIsPath?: boolean;
14
16
  value?: any;
15
17
  oldValue?: any;
16
18
  changes?: IChange[];
@@ -77,7 +79,7 @@ declare const revertChangeset: (obj: any, changeset: Changeset) => any;
77
79
  * If so, it updates the path and recursively flattens the nested changes or the embedded object.
78
80
  * If the change does not have nested changes or an embedded key, it creates a atomic change and returns it in an array.
79
81
  */
80
- declare const atomizeChangeset: (obj: Changeset | IChange, path?: string, embeddedKey?: string | FunctionKey) => IAtomicChange[];
82
+ declare const atomizeChangeset: (obj: Changeset | IChange, path?: string, embeddedKey?: string | FunctionKey, embeddedKeyIsPath?: boolean) => IAtomicChange[];
81
83
  /**
82
84
  * Transforms an atomized changeset into a nested changeset.
83
85
  *
package/dist/index.d.ts CHANGED
@@ -11,6 +11,8 @@ interface IChange {
11
11
  type: Operation;
12
12
  key: string;
13
13
  embeddedKey?: string | FunctionKey;
14
+ /** When true, embeddedKey is a dot-separated nested path (e.g. "a.b" → @.a.b). */
15
+ embeddedKeyIsPath?: boolean;
14
16
  value?: any;
15
17
  oldValue?: any;
16
18
  changes?: IChange[];
@@ -77,7 +79,7 @@ declare const revertChangeset: (obj: any, changeset: Changeset) => any;
77
79
  * If so, it updates the path and recursively flattens the nested changes or the embedded object.
78
80
  * If the change does not have nested changes or an embedded key, it creates a atomic change and returns it in an array.
79
81
  */
80
- declare const atomizeChangeset: (obj: Changeset | IChange, path?: string, embeddedKey?: string | FunctionKey) => IAtomicChange[];
82
+ declare const atomizeChangeset: (obj: Changeset | IChange, path?: string, embeddedKey?: string | FunctionKey, embeddedKeyIsPath?: boolean) => IAtomicChange[];
81
83
  /**
82
84
  * Transforms an atomized changeset into a nested changeset.
83
85
  *
package/dist/index.js CHANGED
@@ -107,12 +107,12 @@ var revertChangeset = (obj, changeset) => {
107
107
  }
108
108
  return obj;
109
109
  };
110
- var atomizeChangeset = (obj, path = "$", embeddedKey) => {
110
+ var atomizeChangeset = (obj, path = "$", embeddedKey, embeddedKeyIsPath) => {
111
111
  if (Array.isArray(obj)) {
112
- return handleArray(obj, path, embeddedKey);
112
+ return handleArray(obj, path, embeddedKey, embeddedKeyIsPath);
113
113
  } else if (obj.changes || embeddedKey) {
114
114
  if (embeddedKey) {
115
- const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path);
115
+ const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path, embeddedKeyIsPath);
116
116
  path = updatedPath;
117
117
  if (atomicChange) {
118
118
  return atomicChange;
@@ -120,7 +120,7 @@ var atomizeChangeset = (obj, path = "$", embeddedKey) => {
120
120
  } else {
121
121
  path = append(path, obj.key);
122
122
  }
123
- return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey);
123
+ return atomizeChangeset(obj.changes || obj, path, obj.embeddedKey, obj.embeddedKeyIsPath);
124
124
  } else {
125
125
  const valueType = getTypeOfObj(obj.value);
126
126
  let finalPath = path;
@@ -147,7 +147,7 @@ var atomizeChangeset = (obj, path = "$", embeddedKey) => {
147
147
  ];
148
148
  }
149
149
  };
150
- function handleEmbeddedKey(embeddedKey, obj, path) {
150
+ function handleEmbeddedKey(embeddedKey, obj, path, isPath) {
151
151
  if (embeddedKey === "$index") {
152
152
  path = `${path}[${obj.key}]`;
153
153
  return [path];
@@ -165,12 +165,12 @@ function handleEmbeddedKey(embeddedKey, obj, path) {
165
165
  ]
166
166
  ];
167
167
  } else {
168
- path = filterExpression(path, embeddedKey, obj.key);
168
+ path = filterExpression(path, embeddedKey, obj.key, isPath);
169
169
  return [path];
170
170
  }
171
171
  }
172
- var handleArray = (obj, path, embeddedKey) => {
173
- return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey)], []);
172
+ var handleArray = (obj, path, embeddedKey, embeddedKeyIsPath) => {
173
+ return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey, embeddedKeyIsPath)], []);
174
174
  };
175
175
  var unatomizeChangeset = (changes) => {
176
176
  if (!Array.isArray(changes)) {
@@ -190,15 +190,17 @@ var unatomizeChangeset = (changes) => {
190
190
  } else {
191
191
  for (let i = 1; i < segments.length; i++) {
192
192
  const segment = segments[i];
193
- const result = /^([^[\]]+)\[\?\(@(?:\.?([^=[]*)|(?:\['([^']*)'\]))=+'([^']+)'\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
193
+ const result = /^([^[\]]+)\[\?\(@(?:\.?([^=[]*)|(?:\['([^']*(?:''[^']*)*)'\]))=+'([^']*(?:''[^']*)*)'\)\]$|^(.+)\[(\d+)\]$/.exec(segment);
194
194
  if (result) {
195
195
  let key;
196
196
  let embeddedKey;
197
197
  let arrKey;
198
+ let isPath;
198
199
  if (result[1]) {
199
200
  key = result[1];
200
- embeddedKey = result[3] || result[2] || "$value";
201
- arrKey = result[4];
201
+ embeddedKey = result[3]?.replace(/''/g, "'") || result[2] || "$value";
202
+ isPath = !result[3] && !!result[2] && result[2].includes(".") && NESTED_PATH_RE.test(result[2]) ? true : void 0;
203
+ arrKey = result[4]?.replace(/''/g, "'");
202
204
  } else {
203
205
  key = result[5];
204
206
  embeddedKey = "$index";
@@ -207,6 +209,7 @@ var unatomizeChangeset = (changes) => {
207
209
  if (i === segments.length - 1) {
208
210
  ptr.key = key;
209
211
  ptr.embeddedKey = embeddedKey;
212
+ if (isPath) ptr.embeddedKeyIsPath = true;
210
213
  ptr.type = "UPDATE" /* UPDATE */;
211
214
  ptr.changes = [
212
215
  {
@@ -219,6 +222,7 @@ var unatomizeChangeset = (changes) => {
219
222
  } else {
220
223
  ptr.key = key;
221
224
  ptr.embeddedKey = embeddedKey;
225
+ if (isPath) ptr.embeddedKeyIsPath = true;
222
226
  ptr.type = "UPDATE" /* UPDATE */;
223
227
  const newPtr = {};
224
228
  ptr.changes = [
@@ -420,12 +424,15 @@ var compareArray = (oldObj, newObj, path, keyPath, options) => {
420
424
  const indexedOldObj = convertArrayToObj(oldObj, uniqKey);
421
425
  const indexedNewObj = convertArrayToObj(newObj, uniqKey);
422
426
  const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);
427
+ const isFunctionKey = typeof uniqKey === "function" && uniqKey.length === 2;
423
428
  if (diffs.length) {
429
+ const resolvedKey = isFunctionKey ? uniqKey(newObj[0] ?? oldObj[0], true) : uniqKey;
424
430
  return [
425
431
  {
426
432
  type: "UPDATE" /* UPDATE */,
427
433
  key: getKey(path),
428
- embeddedKey: typeof uniqKey === "function" && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,
434
+ embeddedKey: resolvedKey,
435
+ ...isFunctionKey && typeof resolvedKey === "string" && NESTED_PATH_RE.test(resolvedKey) && resolvedKey.includes(".") ? { embeddedKeyIsPath: true } : {},
429
436
  changes: diffs
430
437
  }
431
438
  ];
@@ -483,13 +490,13 @@ var comparePrimitives = (oldObj, newObj, path) => {
483
490
  }
484
491
  return changes;
485
492
  };
486
- var removeKey = (obj, key, embeddedKey) => {
493
+ var removeKey = (obj, key, embeddedKey, isPath) => {
487
494
  if (Array.isArray(obj)) {
488
495
  if (embeddedKey === "$index") {
489
496
  obj.splice(Number(key), 1);
490
497
  return;
491
498
  }
492
- const index = indexOfItemInArray(obj, embeddedKey, key);
499
+ const index = indexOfItemInArray(obj, embeddedKey, key, isPath);
493
500
  if (index === -1) {
494
501
  console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array!`);
495
502
  return;
@@ -500,13 +507,20 @@ var removeKey = (obj, key, embeddedKey) => {
500
507
  return;
501
508
  }
502
509
  };
503
- var indexOfItemInArray = (arr, key, value) => {
510
+ var resolveProperty = (obj, key, isPath) => {
511
+ if (obj == null) return void 0;
512
+ if (typeof key !== "string" || !isPath || !key.includes(".")) return obj[key];
513
+ return key.split(".").reduce((cur, seg) => cur?.[seg], obj);
514
+ };
515
+ var indexOfItemInArray = (arr, key, value, isPath) => {
504
516
  if (key === "$value") {
505
517
  return arr.indexOf(value);
506
518
  }
507
519
  for (let i = 0; i < arr.length; i++) {
508
520
  const item = arr[i];
509
- if (item && item[key] ? item[key].toString() === value.toString() : void 0) {
521
+ if (item == null) continue;
522
+ const resolved = resolveProperty(item, key, isPath);
523
+ if (resolved != null && String(resolved) === String(value)) {
510
524
  return i;
511
525
  }
512
526
  }
@@ -524,7 +538,7 @@ var addKeyValue = (obj, key, value, embeddedKey) => {
524
538
  return obj ? obj[key] = value : null;
525
539
  }
526
540
  };
527
- var applyLeafChange = (obj, change, embeddedKey) => {
541
+ var applyLeafChange = (obj, change, embeddedKey, isPath) => {
528
542
  const { type, key, value } = change;
529
543
  switch (type) {
530
544
  case "ADD" /* ADD */:
@@ -532,7 +546,7 @@ var applyLeafChange = (obj, change, embeddedKey) => {
532
546
  case "UPDATE" /* UPDATE */:
533
547
  return modifyKeyValue(obj, key, value);
534
548
  case "REMOVE" /* REMOVE */:
535
- return removeKey(obj, key, embeddedKey);
549
+ return removeKey(obj, key, embeddedKey, isPath);
536
550
  }
537
551
  };
538
552
  var applyArrayChange = (arr, change) => {
@@ -549,7 +563,7 @@ var applyArrayChange = (arr, change) => {
549
563
  }
550
564
  for (const subchange of changes) {
551
565
  if (subchange.value !== null && subchange.value !== void 0 || subchange.type === "REMOVE" /* REMOVE */ || subchange.value === null && subchange.type === "ADD" /* ADD */ || subchange.value === void 0 && subchange.type === "ADD" /* ADD */) {
552
- applyLeafChange(arr, subchange, change.embeddedKey);
566
+ applyLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
553
567
  } else {
554
568
  let element;
555
569
  if (change.embeddedKey === "$index") {
@@ -560,7 +574,10 @@ var applyArrayChange = (arr, change) => {
560
574
  element = arr[index];
561
575
  }
562
576
  } else {
563
- element = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());
577
+ element = arr.find((el) => {
578
+ const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
579
+ return resolved != null && String(resolved) === String(subchange.key);
580
+ });
564
581
  }
565
582
  if (element) {
566
583
  applyChangeset(element, subchange.changes);
@@ -576,7 +593,7 @@ var applyBranchChange = (obj, change) => {
576
593
  return applyChangeset(obj, change.changes);
577
594
  }
578
595
  };
579
- var revertLeafChange = (obj, change, embeddedKey = "$index") => {
596
+ var revertLeafChange = (obj, change, embeddedKey = "$index", isPath) => {
580
597
  const { type, key, value, oldValue } = change;
581
598
  if (key === "$root") {
582
599
  switch (type) {
@@ -606,7 +623,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
606
623
  }
607
624
  switch (type) {
608
625
  case "ADD" /* ADD */:
609
- return removeKey(obj, key, embeddedKey);
626
+ return removeKey(obj, key, embeddedKey, isPath);
610
627
  case "UPDATE" /* UPDATE */:
611
628
  return modifyKeyValue(obj, key, oldValue);
612
629
  case "REMOVE" /* REMOVE */:
@@ -616,7 +633,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
616
633
  var revertArrayChange = (arr, change) => {
617
634
  for (const subchange of change.changes) {
618
635
  if (subchange.value != null || subchange.type === "REMOVE" /* REMOVE */) {
619
- revertLeafChange(arr, subchange, change.embeddedKey);
636
+ revertLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
620
637
  } else {
621
638
  let element;
622
639
  if (change.embeddedKey === "$index") {
@@ -627,7 +644,10 @@ var revertArrayChange = (arr, change) => {
627
644
  element = arr[index];
628
645
  }
629
646
  } else {
630
- element = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());
647
+ element = arr.find((el) => {
648
+ const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
649
+ return resolved != null && String(resolved) === String(subchange.key);
650
+ });
631
651
  }
632
652
  if (element) {
633
653
  revertChangeset(element, subchange.changes);
@@ -647,9 +667,17 @@ function append(basePath, nextSegment) {
647
667
  return nextSegment.includes(".") ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;
648
668
  }
649
669
  var IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
650
- function filterExpression(basePath, filterKey, filterValue) {
670
+ var NESTED_PATH_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*$/;
671
+ function filterExpression(basePath, filterKey, filterValue, isPath) {
651
672
  const escapedValue = `'${filterValue.replace(/'/g, "''")}'`;
652
- const memberAccess = IDENT_RE.test(filterKey) ? `.${filterKey}` : `['${filterKey.replace(/'/g, "''")}']`;
673
+ let memberAccess;
674
+ if (isPath && NESTED_PATH_RE.test(filterKey)) {
675
+ memberAccess = "." + filterKey;
676
+ } else if (IDENT_RE.test(filterKey)) {
677
+ memberAccess = `.${filterKey}`;
678
+ } else {
679
+ memberAccess = `['${filterKey.replace(/'/g, "''")}']`;
680
+ }
653
681
  return `${basePath}[?(@${memberAccess}==${escapedValue})]`;
654
682
  }
655
683
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/helpers.ts","../src/jsonDiff.ts","../src/jsonCompare.ts"],"sourcesContent":["export type FunctionKey<T = any> = (obj: T, shouldReturnKeyName?: boolean, index?: number) => any;\n\nexport function splitJSONPath(path: string): string[] {\n const 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\nexport function arrayDifference<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => !secondSet.has(item));\n}\n\nexport function arrayIntersection<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => secondSet.has(item));\n}\n\nexport function keyBy<T>(arr: T[], getKey: FunctionKey<T>): Record<string, T> {\n const result: Record<string, T> = {};\n for (const [index, item] of Object.entries(arr)) {\n result[String(getKey(item, false, Number(index)))] = item;\n }\n return result;\n}\n\nexport function setByPath(obj: any, path: string, value: any): void {\n const parts = path.replaceAll(/\\[(\\d+)\\]/g, '.$1').split('.').filter(Boolean);\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!(part in current)) {\n current[part] = /^\\d+$/.test(parts[i + 1]) ? [] : {};\n }\n current = current[part];\n }\n current[parts.at(-1)] = value;\n}\n","import { arrayDifference as difference, arrayIntersection as intersection, keyBy, splitJSONPath, FunctionKey } from './helpers.js';\n\ntype EmbeddedObjKeysType = Record<string, string | FunctionKey>;\ntype EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nenum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\ninterface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n value?: any;\n oldValue?: any;\n changes?: IChange[];\n}\ntype Changeset = IChange[];\n\ninterface IAtomicChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\ninterface Options {\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;\n keysToSkip?: readonly 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 */\nfunction diff(oldObj: any, newObj: any, options: Options = {}): IChange[] {\n let { embeddedObjKeys } = options;\n const { 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, or if the value is null and the type is ADD,\n * it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nconst applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n // Handle null values as leaf changes when the operation is ADD\n // Also handle undefined values for ADD operations in array contexts\n if ((value !== null && value !== undefined) || \n type === Operation.REMOVE || \n (value === null && type === Operation.ADD) ||\n (value === undefined && type === Operation.ADD)) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n // When key is '$root', apply to obj itself (root-level arrays)\n applyBranchChange(key === '$root' ? obj : 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, or if the value is null and\n * the type is REMOVE (which would be reverting an ADD operation), 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 */\nconst revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any => {\n const { value, type } = change;\n // Handle null values as leaf changes when the operation is REMOVE (since we're reversing ADD)\n if (!change.changes || (value === null && type === Operation.REMOVE)) {\n revertLeafChange(obj, change);\n } else {\n // When key is '$root', revert on obj itself (root-level arrays)\n revertBranchChange(change.key === '$root' ? obj : obj[change.key], change);\n }\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 */\nconst 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 let finalPath = path;\n if (!finalPath.endsWith(`[${obj.key}]`)) {\n // Avoid duplicate filter values at the end of the JSONPath\n let endsWithFilterValue = false;\n const filterEndIdx = path.lastIndexOf(')]');\n if (filterEndIdx !== -1) {\n const filterStartIdx = path.lastIndexOf('==', filterEndIdx);\n if (filterStartIdx !== -1) {\n const filterValue = path\n .slice(filterStartIdx + 2, filterEndIdx)\n // Remove single quotes at the start or end of the filter value\n .replaceAll(/(^'|'$)/g, '');\n endsWithFilterValue = filterValue === String(obj.key);\n }\n }\n if (!endsWithFilterValue) {\n finalPath = append(path, obj.key);\n }\n }\n \n return [\n {\n ...obj,\n path: finalPath,\n valueType\n }\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 {\n ...obj,\n path,\n valueType\n }\n ]\n ];\n } else {\n path = filterExpression(path, embeddedKey as string, obj.key);\n return [path];\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 * 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 */\nconst unatomizeChangeset = (changes: IAtomicChange | IAtomicChange[]) => {\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 = 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 filter segments and array index segments:\n // \"items[?(@.id=='123')]\" — dot-notation key filter\n // \"items[?(@['c.d']=='20')]\" — bracket-notation key filter\n // \"items[?(@=='123')]\" — value filter\n // \"items[2]\" — array index\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[3] || result[2] || '$value';\n arrKey = result[4];\n } else {\n key = result[5];\n embeddedKey = '$index';\n arrKey = Number(result[6]);\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 // Handle all leaf values the same way, regardless of type\n ptr.key = segment;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\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 */\nconst getTypeOfObj = (obj: any) => {\n if (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.at(-1);\n return left ?? '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n let changes: any[] = [];\n\n // Check if the current path should be skipped \n const currentPath = keyPath.join('.');\n if (options.keysToSkip?.some(skipPath => {\n // Exact match\n if (currentPath === skipPath) {\n return true;\n }\n \n // The current path is a parent of the skip path\n if (skipPath.includes('.') && skipPath.startsWith(currentPath + '.')) {\n return false; // Don't skip, we need to process the parent\n }\n \n // The current path is a child or deeper descendant of the skip path\n if (skipPath.includes('.')) {\n // Check if skipPath is a parent of currentPath\n const skipParts = skipPath.split('.');\n const currentParts = currentPath.split('.');\n \n if (currentParts.length >= skipParts.length) {\n // Check if all parts of skipPath match the corresponding parts in currentPath\n for (let i = 0; i < skipParts.length; i++) {\n if (skipParts[i] !== currentParts[i]) {\n return false;\n }\n }\n return true; // All parts match, so this is a child or equal path\n }\n }\n \n return false;\n })) {\n return changes; // Skip comparison for this path and its children\n }\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 // Only add a REMOVE operation if oldObj is not undefined\n if (typeOfOldObj !== 'undefined') {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\n\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n // As undefined is not serialized into JSON, it should not count as an added value.\n // However, for array elements, we want to preserve undefined as a value\n if (typeOfNewObj !== 'undefined' || isArrayElement) {\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n }\n\n return changes;\n }\n\n if (typeOfNewObj === 'undefined' && typeOfOldObj !== 'undefined') {\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n if (isArrayElement) {\n // In array contexts, treat transition to undefined as an update\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n } else {\n // In object contexts, treat transition to undefined as removal (original behavior)\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\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 if (typeOfNewObj === null) {\n if (typeOfOldObj !== null) {\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n }\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n if (typeOfNewObj === '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 } else {\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n break;\n case 'Object': {\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 = (oldObj: any, newObj: any, path: any, keyPath: any, skipPath = false, options: Options = {}) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n // Filter keys directly rather than filtering by keysToSkip at this level\n // The full path check is now done in the compare function\n const oldObjKeys = Object.keys(oldObj);\n const newObjKeys = Object.keys(newObj);\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip adding this key\n }\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip removing this key\n }\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n if (getTypeOfObj(newObj) !== 'Array') {\n return [{ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj }];\n }\n\n const left = getObjectKey(options.embeddedObjKeys, keyPath);\n const uniqKey = 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 for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n } else {\n // Convert string keys to functions for compatibility with es-toolkit keyBy\n const keyFunction = typeof uniqKey === 'string' ? (item: any) => item[uniqKey] : uniqKey;\n obj = keyBy(arr, keyFunction);\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(Number(key), 1);\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 ?? key, 1);\n } else {\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);\nconst addKeyValue = (obj: any, key: any, value: any, embeddedKey?: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(Number(key), 0, value);\n return obj.length;\n }\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, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey);\n }\n};\n\n/**\n * Applies changes to an array.\n * \n * @param {any[]} arr - The array to apply changes to.\n * @param {any} change - The change to apply, containing nested changes.\n * @returns {any[]} - The array after changes have been applied.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst applyArrayChange = (arr: any[], change: any) => {\n let changes = change.changes;\n if (change.embeddedKey === '$index') {\n changes = [...changes].sort((a, b) => {\n if (a.type === Operation.REMOVE && b.type === Operation.REMOVE) {\n return Number(b.key) - Number(a.key);\n }\n if (a.type === Operation.REMOVE) return -1;\n if (b.type === Operation.REMOVE) return 1;\n return Number(a.key) - Number(b.key);\n });\n }\n\n for (const subchange of changes) {\n if (\n (subchange.value !== null && subchange.value !== undefined) ||\n subchange.type === Operation.REMOVE ||\n (subchange.value === null && subchange.type === Operation.ADD) ||\n (subchange.value === undefined && subchange.type === Operation.ADD)\n ) {\n 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 = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n if (element) {\n applyChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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 \n // Special handling for $root key\n if (key === '$root') {\n switch (type) {\n case Operation.ADD:\n // When reverting an ADD of the entire object, clear all properties\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n return obj;\n case Operation.UPDATE:\n // Replace the entire object with the old value\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n if (oldValue && typeof oldValue === 'object') {\n Object.assign(obj, oldValue);\n }\n return obj;\n case Operation.REMOVE:\n // Restore the removed object\n if (value && typeof value === 'object') {\n Object.assign(obj, value);\n }\n return obj;\n }\n }\n \n // Regular property handling\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\n/**\n * Reverts changes in an array.\n * \n * @param {any[]} arr - The array to revert changes in.\n * @param {any} change - The change to revert, containing nested changes.\n * @returns {any[]} - The array after changes have been reverted.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst revertArrayChange = (arr: any[], change: any) => {\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n revertLeafChange(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 = arr.find((el) => el[change.embeddedKey]?.toString() === subchange.key.toString());\n }\n if (element) {\n revertChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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\nconst IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/** returns a JSON Path filter expression; e.g., `$.pet[?(@.name=='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string, filterValue: string) {\n const escapedValue = `'${filterValue.replace(/'/g, \"''\")}'`;\n const memberAccess = IDENT_RE.test(filterKey)\n ? `.${filterKey}`\n : `['${filterKey.replace(/'/g, \"''\")}']`;\n return `${basePath}[?(@${memberAccess}==${escapedValue})]`;\n}\n\nexport {\n Changeset,\n EmbeddedObjKeysMapType,\n EmbeddedObjKeysType,\n IAtomicChange,\n IChange,\n Operation,\n Options,\n applyChangeset,\n atomizeChangeset,\n diff,\n getTypeOfObj,\n revertChangeset,\n unatomizeChangeset\n};\n","import { setByPath, splitJSONPath } from './helpers.js';\nimport { diff, atomizeChangeset, getTypeOfObj, IAtomicChange, Operation } from './jsonDiff.js';\n\nenum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\ninterface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nconst createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nconst createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nconst enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return Object.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 (object as any[])\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]));\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\n/**\n * Converts an atomized JSONPath (e.g. `$.items[0].name`) into a navigation\n * path through the enriched tree (e.g. `value.items.value[0].value.name`).\n *\n * The enriched tree wraps every level in `{ type, value }` nodes, so between\n * each logical key/index we must step through `.value` to unwrap the container.\n */\nconst buildEnrichedPath = (atomicPath: string): string => {\n const segments = splitJSONPath(atomicPath);\n // segments[0] is always '$' (the JSONPath root)\n\n let result = 'value'; // enter the root container's value\n\n for (let i = 1; i < segments.length; i++) {\n const seg = segments[i];\n const isLast = i === segments.length - 1;\n\n // Match segments like \"items[0]\" or \"variants[12]\"\n const arrayMatch = /^(.+?)\\[(\\d+)\\]$/.exec(seg);\n\n if (arrayMatch) {\n const [, key, index] = arrayMatch;\n // key.value → unwrap the array container, then [index] into the array\n result += `.${key}.value[${index}]`;\n } else {\n result += `.${seg}`;\n }\n\n // For non-leaf segments, unwrap the next container\n if (!isLast) {\n result += '.value';\n }\n }\n\n return result;\n};\n\nconst applyChangelist = (object: IComparisonEnrichedNode, changelist: IAtomicChange[]): IComparisonEnrichedNode => {\n changelist.forEach((entry) => {\n const path = buildEnrichedPath(entry.path);\n\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n setByPath(object, path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n setByPath(object, path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nconst ARRAY_WRAPPER_KEY = '_$arr';\n\nconst compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n // Root-level arrays produce $root paths that don't map to real properties.\n // Wrap them in an object so diff/atomize generates standard property paths.\n if (Array.isArray(oldObject) || Array.isArray(newObject)) {\n const wrappedOld = { [ARRAY_WRAPPER_KEY]: oldObject };\n const wrappedNew = { [ARRAY_WRAPPER_KEY]: newObject };\n const enriched = enrich(wrappedOld);\n const changes = atomizeChangeset(diff(wrappedOld, wrappedNew));\n const result = applyChangelist(enriched, changes);\n return (result.value as any)[ARRAY_WRAPPER_KEY];\n }\n\n return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));\n};\n\nexport { CompareOperation, IComparisonEnrichedNode, createValue, createContainer, enrich, applyChangelist, compare };\n"],"mappings":"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","names":["getKey","Operation","skipPath","key","CompareOperation","compare"]}
1
+ {"version":3,"sources":["../src/helpers.ts","../src/jsonDiff.ts","../src/jsonCompare.ts"],"sourcesContent":["export type FunctionKey<T = any> = (obj: T, shouldReturnKeyName?: boolean, index?: number) => any;\n\nexport function splitJSONPath(path: string): string[] {\n const 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\nexport function arrayDifference<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => !secondSet.has(item));\n}\n\nexport function arrayIntersection<T>(first: T[], second: T[]): T[] {\n const secondSet = new Set(second);\n return first.filter(item => secondSet.has(item));\n}\n\nexport function keyBy<T>(arr: T[], getKey: FunctionKey<T>): Record<string, T> {\n const result: Record<string, T> = {};\n for (const [index, item] of Object.entries(arr)) {\n result[String(getKey(item, false, Number(index)))] = item;\n }\n return result;\n}\n\nexport function setByPath(obj: any, path: string, value: any): void {\n const parts = path.replaceAll(/\\[(\\d+)\\]/g, '.$1').split('.').filter(Boolean);\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!(part in current)) {\n current[part] = /^\\d+$/.test(parts[i + 1]) ? [] : {};\n }\n current = current[part];\n }\n current[parts.at(-1)] = value;\n}\n","import { arrayDifference as difference, arrayIntersection as intersection, keyBy, splitJSONPath, FunctionKey } from './helpers.js';\n\ntype EmbeddedObjKeysType = Record<string, string | FunctionKey>;\ntype EmbeddedObjKeysMapType = Map<string | RegExp, string | FunctionKey>;\nenum Operation {\n REMOVE = 'REMOVE',\n ADD = 'ADD',\n UPDATE = 'UPDATE'\n}\n\ninterface IChange {\n type: Operation;\n key: string;\n embeddedKey?: string | FunctionKey;\n /** When true, embeddedKey is a dot-separated nested path (e.g. \"a.b\" → @.a.b). */\n embeddedKeyIsPath?: boolean;\n value?: any;\n oldValue?: any;\n changes?: IChange[];\n}\ntype Changeset = IChange[];\n\ninterface IAtomicChange {\n type: Operation;\n key: string;\n path: string;\n valueType: string | null;\n value?: any;\n oldValue?: any;\n}\n\ninterface Options {\n embeddedObjKeys?: EmbeddedObjKeysType | EmbeddedObjKeysMapType;\n keysToSkip?: readonly 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 */\nfunction diff(oldObj: any, newObj: any, options: Options = {}): IChange[] {\n let { embeddedObjKeys } = options;\n const { 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, or if the value is null and the type is ADD,\n * it applies the change to the object directly.\n * Otherwise, it applies the change to the corresponding branch of the object.\n */\nconst applyChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset.forEach((change) => {\n const { type, key, value, embeddedKey } = change;\n\n // Handle null values as leaf changes when the operation is ADD\n // Also handle undefined values for ADD operations in array contexts\n if ((value !== null && value !== undefined) || \n type === Operation.REMOVE || \n (value === null && type === Operation.ADD) ||\n (value === undefined && type === Operation.ADD)) {\n // Apply the change to the object\n applyLeafChange(obj, change, embeddedKey);\n } else {\n // Apply the change to the branch\n // When key is '$root', apply to obj itself (root-level arrays)\n applyBranchChange(key === '$root' ? obj : 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, or if the value is null and\n * the type is REMOVE (which would be reverting an ADD operation), 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 */\nconst revertChangeset = (obj: any, changeset: Changeset) => {\n if (changeset) {\n changeset\n .reverse()\n .forEach((change: IChange): any => {\n const { value, type } = change;\n // Handle null values as leaf changes when the operation is REMOVE (since we're reversing ADD)\n if (!change.changes || (value === null && type === Operation.REMOVE)) {\n revertLeafChange(obj, change);\n } else {\n // When key is '$root', revert on obj itself (root-level arrays)\n revertBranchChange(change.key === '$root' ? obj : obj[change.key], change);\n }\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 */\nconst atomizeChangeset = (\n obj: Changeset | IChange,\n path = '$',\n embeddedKey?: string | FunctionKey,\n embeddedKeyIsPath?: boolean\n): IAtomicChange[] => {\n if (Array.isArray(obj)) {\n return handleArray(obj, path, embeddedKey, embeddedKeyIsPath);\n } else if (obj.changes || embeddedKey) {\n if (embeddedKey) {\n const [updatedPath, atomicChange] = handleEmbeddedKey(embeddedKey, obj, path, embeddedKeyIsPath);\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, obj.embeddedKeyIsPath);\n } else {\n const valueType = getTypeOfObj(obj.value);\n let finalPath = path;\n if (!finalPath.endsWith(`[${obj.key}]`)) {\n // Avoid duplicate filter values at the end of the JSONPath\n let endsWithFilterValue = false;\n const filterEndIdx = path.lastIndexOf(')]');\n if (filterEndIdx !== -1) {\n const filterStartIdx = path.lastIndexOf('==', filterEndIdx);\n if (filterStartIdx !== -1) {\n const filterValue = path\n .slice(filterStartIdx + 2, filterEndIdx)\n // Remove single quotes at the start or end of the filter value\n .replaceAll(/(^'|'$)/g, '');\n endsWithFilterValue = filterValue === String(obj.key);\n }\n }\n if (!endsWithFilterValue) {\n finalPath = append(path, obj.key);\n }\n }\n \n return [\n {\n ...obj,\n path: finalPath,\n valueType\n }\n ];\n }\n};\n\n// Function to handle embeddedKey logic and update the path\nfunction handleEmbeddedKey(embeddedKey: string | FunctionKey, obj: IChange, path: string, isPath?: boolean): [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 {\n ...obj,\n path,\n valueType\n }\n ]\n ];\n } else {\n path = filterExpression(path, embeddedKey as string, obj.key, isPath);\n return [path];\n }\n}\n\nconst handleArray = (obj: Changeset | IChange[], path: string, embeddedKey?: string | FunctionKey, embeddedKeyIsPath?: boolean): IAtomicChange[] => {\n return obj.reduce((memo, change) => [...memo, ...atomizeChangeset(change, path, embeddedKey, embeddedKeyIsPath)], [] as IAtomicChange[]);\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 */\nconst unatomizeChangeset = (changes: IAtomicChange | IAtomicChange[]) => {\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 = 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 filter segments and array index segments.\n // Supports doubled-quote escaping in bracket keys and filter values (e.g. O''Brien).\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 let isPath: boolean | undefined;\n if (result[1]) {\n key = result[1];\n // Unescape doubled quotes in bracket keys and filter values\n embeddedKey = (result[3]?.replace(/''/g, \"'\") || result[2] || '$value');\n isPath = (!result[3] && !!result[2] && result[2].includes('.') && NESTED_PATH_RE.test(result[2])) ? true : undefined;\n arrKey = result[4]?.replace(/''/g, \"'\");\n } else {\n key = result[5];\n embeddedKey = '$index';\n arrKey = Number(result[6]);\n }\n // leaf\n if (i === segments.length - 1) {\n ptr.key = key!;\n ptr.embeddedKey = embeddedKey!;\n if (isPath) ptr.embeddedKeyIsPath = true;\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 if (isPath) ptr.embeddedKeyIsPath = true;\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 // Handle all leaf values the same way, regardless of type\n ptr.key = segment;\n ptr.type = change.type;\n ptr.value = change.value;\n ptr.oldValue = change.oldValue;\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 */\nconst getTypeOfObj = (obj: any) => {\n if (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.at(-1);\n return left ?? '$root';\n};\n\nconst compare = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n let changes: any[] = [];\n\n // Check if the current path should be skipped \n const currentPath = keyPath.join('.');\n if (options.keysToSkip?.some(skipPath => {\n // Exact match\n if (currentPath === skipPath) {\n return true;\n }\n \n // The current path is a parent of the skip path\n if (skipPath.includes('.') && skipPath.startsWith(currentPath + '.')) {\n return false; // Don't skip, we need to process the parent\n }\n \n // The current path is a child or deeper descendant of the skip path\n if (skipPath.includes('.')) {\n // Check if skipPath is a parent of currentPath\n const skipParts = skipPath.split('.');\n const currentParts = currentPath.split('.');\n \n if (currentParts.length >= skipParts.length) {\n // Check if all parts of skipPath match the corresponding parts in currentPath\n for (let i = 0; i < skipParts.length; i++) {\n if (skipParts[i] !== currentParts[i]) {\n return false;\n }\n }\n return true; // All parts match, so this is a child or equal path\n }\n }\n \n return false;\n })) {\n return changes; // Skip comparison for this path and its children\n }\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 // Only add a REMOVE operation if oldObj is not undefined\n if (typeOfOldObj !== 'undefined') {\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\n\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n // As undefined is not serialized into JSON, it should not count as an added value.\n // However, for array elements, we want to preserve undefined as a value\n if (typeOfNewObj !== 'undefined' || isArrayElement) {\n changes.push({ type: Operation.ADD, key: getKey(path), value: newObj });\n }\n\n return changes;\n }\n\n if (typeOfNewObj === 'undefined' && typeOfOldObj !== 'undefined') {\n // Special case: In array contexts, undefined should be treated as a value, not as absence of value\n // Check if we're in an array element context by examining the path\n const lastPathSegment = path[path.length - 1];\n const isArrayElement = path.length > 0 && \n (typeof lastPathSegment === 'number' || \n (typeof lastPathSegment === 'string' && /^\\d+$/.test(lastPathSegment)));\n \n if (isArrayElement) {\n // In array contexts, treat transition to undefined as an update\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n } else {\n // In object contexts, treat transition to undefined as removal (original behavior)\n changes.push({ type: Operation.REMOVE, key: getKey(path), value: oldObj });\n }\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 if (typeOfNewObj === null) {\n if (typeOfOldObj !== null) {\n changes.push({ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj });\n }\n return changes;\n }\n\n switch (typeOfOldObj) {\n case 'Date':\n if (typeOfNewObj === '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 } else {\n changes = changes.concat(comparePrimitives(oldObj, newObj, path));\n }\n break;\n case 'Object': {\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 = (oldObj: any, newObj: any, path: any, keyPath: any, skipPath = false, options: Options = {}) => {\n let k;\n let newKeyPath;\n let newPath;\n\n if (skipPath == null) {\n skipPath = false;\n }\n let changes: any[] = [];\n\n // Filter keys directly rather than filtering by keysToSkip at this level\n // The full path check is now done in the compare function\n const oldObjKeys = Object.keys(oldObj);\n const newObjKeys = Object.keys(newObj);\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip adding this key\n }\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 // Check if the path should be skipped\n const currentPath = newKeyPath.join('.');\n if (options.keysToSkip?.some(skipPath => currentPath === skipPath || currentPath.startsWith(skipPath + '.'))) {\n continue; // Skip removing this key\n }\n changes.push({\n type: Operation.REMOVE,\n key: getKey(newPath),\n value: oldObj[k]\n });\n }\n return changes;\n};\n\nconst compareArray = (oldObj: any, newObj: any, path: any, keyPath: any, options: Options) => {\n if (getTypeOfObj(newObj) !== 'Array') {\n return [{ type: Operation.UPDATE, key: getKey(path), value: newObj, oldValue: oldObj }];\n }\n\n const left = getObjectKey(options.embeddedObjKeys, keyPath);\n const uniqKey = 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 const isFunctionKey = typeof uniqKey === 'function' && uniqKey.length === 2;\n if (diffs.length) {\n const resolvedKey = isFunctionKey ? uniqKey(newObj[0] ?? oldObj[0], true) : uniqKey;\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: resolvedKey,\n ...(isFunctionKey && typeof resolvedKey === 'string' && NESTED_PATH_RE.test(resolvedKey) && resolvedKey.includes('.') ? { embeddedKeyIsPath: true } : {}),\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 for (let i = 0; i < arr.length; i++) {\n const value = arr[i];\n obj[i] = value;\n }\n } else {\n // Convert string keys to functions for compatibility with es-toolkit keyBy\n const keyFunction = typeof uniqKey === 'string' ? (item: any) => item[uniqKey] : uniqKey;\n obj = keyBy(arr, keyFunction);\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, isPath?: boolean) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(Number(key), 1);\n return;\n }\n const index = indexOfItemInArray(obj, embeddedKey, key, isPath);\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 ?? key, 1);\n } else {\n delete obj[key];\n return;\n }\n};\n\n/** Resolve a property on an object. When isPath is true, traverses nested dot-separated segments. */\nconst resolveProperty = (obj: any, key: any, isPath?: boolean): any => {\n if (obj == null) return undefined;\n if (typeof key !== 'string' || !isPath || !key.includes('.')) return obj[key];\n return key.split('.').reduce((cur, seg) => cur?.[seg], obj);\n};\n\nconst indexOfItemInArray = (arr: any[], key: any, value: any, isPath?: boolean) => {\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 == null) continue;\n const resolved = resolveProperty(item, key, isPath);\n if (resolved != null && String(resolved) === String(value)) {\n return i;\n }\n }\n return -1;\n};\n\nconst modifyKeyValue = (obj: any, key: any, value: any) => (obj[key] = value);\nconst addKeyValue = (obj: any, key: any, value: any, embeddedKey?: any) => {\n if (Array.isArray(obj)) {\n if (embeddedKey === '$index') {\n obj.splice(Number(key), 0, value);\n return obj.length;\n }\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, isPath?: boolean) => {\n const { type, key, value } = change;\n switch (type) {\n case Operation.ADD:\n return addKeyValue(obj, key, value, embeddedKey);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, value);\n case Operation.REMOVE:\n return removeKey(obj, key, embeddedKey, isPath);\n }\n};\n\n/**\n * Applies changes to an array.\n * \n * @param {any[]} arr - The array to apply changes to.\n * @param {any} change - The change to apply, containing nested changes.\n * @returns {any[]} - The array after changes have been applied.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst applyArrayChange = (arr: any[], change: any) => {\n let changes = change.changes;\n if (change.embeddedKey === '$index') {\n changes = [...changes].sort((a, b) => {\n if (a.type === Operation.REMOVE && b.type === Operation.REMOVE) {\n return Number(b.key) - Number(a.key);\n }\n if (a.type === Operation.REMOVE) return -1;\n if (b.type === Operation.REMOVE) return 1;\n return Number(a.key) - Number(b.key);\n });\n }\n\n for (const subchange of changes) {\n if (\n (subchange.value !== null && subchange.value !== undefined) ||\n subchange.type === Operation.REMOVE ||\n (subchange.value === null && subchange.type === Operation.ADD) ||\n (subchange.value === undefined && subchange.type === Operation.ADD)\n ) {\n applyLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);\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 = arr.find((el) => {\n const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);\n return resolved != null && String(resolved) === String(subchange.key);\n });\n }\n if (element) {\n applyChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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', isPath?: boolean) => {\n const { type, key, value, oldValue } = change;\n \n // Special handling for $root key\n if (key === '$root') {\n switch (type) {\n case Operation.ADD:\n // When reverting an ADD of the entire object, clear all properties\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n return obj;\n case Operation.UPDATE:\n // Replace the entire object with the old value\n for (const prop in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n delete obj[prop];\n }\n }\n if (oldValue && typeof oldValue === 'object') {\n Object.assign(obj, oldValue);\n }\n return obj;\n case Operation.REMOVE:\n // Restore the removed object\n if (value && typeof value === 'object') {\n Object.assign(obj, value);\n }\n return obj;\n }\n }\n \n // Regular property handling\n switch (type) {\n case Operation.ADD:\n return removeKey(obj, key, embeddedKey, isPath);\n case Operation.UPDATE:\n return modifyKeyValue(obj, key, oldValue);\n case Operation.REMOVE:\n return addKeyValue(obj, key, value);\n }\n};\n\n/**\n * Reverts changes in an array.\n * \n * @param {any[]} arr - The array to revert changes in.\n * @param {any} change - The change to revert, containing nested changes.\n * @returns {any[]} - The array after changes have been reverted.\n *\n * Note: This function modifies the array in-place but also returns it for\n * consistency with other functions.\n */\nconst revertArrayChange = (arr: any[], change: any) => {\n for (const subchange of change.changes) {\n if (subchange.value != null || subchange.type === Operation.REMOVE) {\n revertLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);\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 = arr.find((el) => {\n const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);\n return resolved != null && String(resolved) === String(subchange.key);\n });\n }\n if (element) {\n revertChangeset(element, subchange.changes);\n }\n }\n }\n return arr;\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\nconst IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\nconst NESTED_PATH_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*$/;\n\n/** returns a JSON Path filter expression; e.g., `$.pet[?(@.name=='spot')]` */\nfunction filterExpression(basePath: string, filterKey: string, filterValue: string, isPath?: boolean) {\n const escapedValue = `'${filterValue.replace(/'/g, \"''\")}'`;\n let memberAccess: string;\n if (isPath && NESTED_PATH_RE.test(filterKey)) {\n memberAccess = '.' + filterKey;\n } else if (IDENT_RE.test(filterKey)) {\n memberAccess = `.${filterKey}`;\n } else {\n memberAccess = `['${filterKey.replace(/'/g, \"''\")}']`;\n }\n return `${basePath}[?(@${memberAccess}==${escapedValue})]`;\n}\n\nexport {\n Changeset,\n EmbeddedObjKeysMapType,\n EmbeddedObjKeysType,\n IAtomicChange,\n IChange,\n Operation,\n Options,\n applyChangeset,\n atomizeChangeset,\n diff,\n getTypeOfObj,\n revertChangeset,\n unatomizeChangeset\n};\n","import { setByPath, splitJSONPath } from './helpers.js';\nimport { diff, atomizeChangeset, getTypeOfObj, IAtomicChange, Operation } from './jsonDiff.js';\n\nenum CompareOperation {\n CONTAINER = 'CONTAINER',\n UNCHANGED = 'UNCHANGED'\n}\n\ninterface IComparisonEnrichedNode {\n type: Operation | CompareOperation;\n value: IComparisonEnrichedNode | IComparisonEnrichedNode[] | any | any[];\n oldValue?: any;\n}\n\nconst createValue = (value: any): IComparisonEnrichedNode => ({ type: CompareOperation.UNCHANGED, value });\nconst createContainer = (value: object | []): IComparisonEnrichedNode => ({\n type: CompareOperation.CONTAINER,\n value\n});\n\nconst enrich = (object: any): IComparisonEnrichedNode => {\n const objectType = getTypeOfObj(object);\n\n switch (objectType) {\n case 'Object':\n return Object.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 (object as any[])\n .map((value) => enrich(value))\n .reduce((accumulator, value) => {\n accumulator.value.push(value);\n return accumulator;\n }, createContainer([]));\n case 'Function':\n return undefined;\n case 'Date':\n default:\n // Primitive value\n return createValue(object);\n }\n};\n\n/**\n * Converts an atomized JSONPath (e.g. `$.items[0].name`) into a navigation\n * path through the enriched tree (e.g. `value.items.value[0].value.name`).\n *\n * The enriched tree wraps every level in `{ type, value }` nodes, so between\n * each logical key/index we must step through `.value` to unwrap the container.\n */\nconst buildEnrichedPath = (atomicPath: string): string => {\n const segments = splitJSONPath(atomicPath);\n // segments[0] is always '$' (the JSONPath root)\n\n let result = 'value'; // enter the root container's value\n\n for (let i = 1; i < segments.length; i++) {\n const seg = segments[i];\n const isLast = i === segments.length - 1;\n\n // Match segments like \"items[0]\" or \"variants[12]\"\n const arrayMatch = /^(.+?)\\[(\\d+)\\]$/.exec(seg);\n\n if (arrayMatch) {\n const [, key, index] = arrayMatch;\n // key.value → unwrap the array container, then [index] into the array\n result += `.${key}.value[${index}]`;\n } else {\n result += `.${seg}`;\n }\n\n // For non-leaf segments, unwrap the next container\n if (!isLast) {\n result += '.value';\n }\n }\n\n return result;\n};\n\nconst applyChangelist = (object: IComparisonEnrichedNode, changelist: IAtomicChange[]): IComparisonEnrichedNode => {\n changelist.forEach((entry) => {\n const path = buildEnrichedPath(entry.path);\n\n switch (entry.type) {\n case Operation.ADD:\n case Operation.UPDATE:\n setByPath(object, path, { type: entry.type, value: entry.value, oldValue: entry.oldValue });\n break;\n case Operation.REMOVE:\n setByPath(object, path, { type: entry.type, value: undefined, oldValue: entry.value });\n break;\n default:\n throw new Error();\n }\n });\n return object;\n};\n\nconst ARRAY_WRAPPER_KEY = '_$arr';\n\nconst compare = (oldObject: any, newObject: any): IComparisonEnrichedNode => {\n // Root-level arrays produce $root paths that don't map to real properties.\n // Wrap them in an object so diff/atomize generates standard property paths.\n if (Array.isArray(oldObject) || Array.isArray(newObject)) {\n const wrappedOld = { [ARRAY_WRAPPER_KEY]: oldObject };\n const wrappedNew = { [ARRAY_WRAPPER_KEY]: newObject };\n const enriched = enrich(wrappedOld);\n const changes = atomizeChangeset(diff(wrappedOld, wrappedNew));\n const result = applyChangelist(enriched, changes);\n return (result.value as any)[ARRAY_WRAPPER_KEY];\n }\n\n return applyChangelist(enrich(oldObject), atomizeChangeset(diff(oldObject, newObject)));\n};\n\nexport { CompareOperation, IComparisonEnrichedNode, createValue, createContainer, enrich, applyChangelist, compare };\n"],"mappings":"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","names":["getKey","Operation","skipPath","key","CompareOperation","compare"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-diff-ts",
3
- "version": "4.10.2",
3
+ "version": "4.10.3",
4
4
  "description": "Modern TypeScript JSON diff library - Zero dependencies, high performance, ESM + CommonJS support. Calculate and apply differences between JSON objects with advanced features like key-based array diffing, JSONPath support, and atomic changesets.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",