json-diff-ts 4.10.2 → 4.10.4
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 +58 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +58 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 = /^([^[\]]+)\[\?\(@(?:\.?([^=[]*)|(?:\['([^']*)'\]))=+'([^']
|
|
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
|
-
|
|
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,17 @@ 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;
|
|
468
|
+
const sampleEl = [...newObj, ...oldObj].find((el) => el != null && typeof el === "object");
|
|
469
|
+
const isNestedPath = typeof resolvedKey === "string" && resolvedKey.includes(".") && NESTED_PATH_RE.test(resolvedKey) && (isFunctionKey || !(sampleEl != null && resolvedKey in sampleEl));
|
|
462
470
|
return [
|
|
463
471
|
{
|
|
464
472
|
type: "UPDATE" /* UPDATE */,
|
|
465
473
|
key: getKey(path),
|
|
466
|
-
embeddedKey:
|
|
474
|
+
embeddedKey: resolvedKey,
|
|
475
|
+
...isNestedPath ? { embeddedKeyIsPath: true } : {},
|
|
467
476
|
changes: diffs
|
|
468
477
|
}
|
|
469
478
|
];
|
|
@@ -504,7 +513,8 @@ var convertArrayToObj = (arr, uniqKey) => {
|
|
|
504
513
|
obj[i] = value;
|
|
505
514
|
}
|
|
506
515
|
} else {
|
|
507
|
-
const
|
|
516
|
+
const maybeNestedPath = typeof uniqKey === "string" && uniqKey.includes(".") && NESTED_PATH_RE.test(uniqKey);
|
|
517
|
+
const keyFunction = typeof uniqKey === "string" ? maybeNestedPath ? (item) => item != null && typeof item === "object" && uniqKey in item ? item[uniqKey] : resolveProperty(item, uniqKey, true) : (item) => item != null ? item[uniqKey] : void 0 : uniqKey;
|
|
508
518
|
obj = keyBy(arr, keyFunction);
|
|
509
519
|
}
|
|
510
520
|
return obj;
|
|
@@ -521,13 +531,13 @@ var comparePrimitives = (oldObj, newObj, path) => {
|
|
|
521
531
|
}
|
|
522
532
|
return changes;
|
|
523
533
|
};
|
|
524
|
-
var removeKey = (obj, key, embeddedKey) => {
|
|
534
|
+
var removeKey = (obj, key, embeddedKey, isPath) => {
|
|
525
535
|
if (Array.isArray(obj)) {
|
|
526
536
|
if (embeddedKey === "$index") {
|
|
527
537
|
obj.splice(Number(key), 1);
|
|
528
538
|
return;
|
|
529
539
|
}
|
|
530
|
-
const index = indexOfItemInArray(obj, embeddedKey, key);
|
|
540
|
+
const index = indexOfItemInArray(obj, embeddedKey, key, isPath);
|
|
531
541
|
if (index === -1) {
|
|
532
542
|
console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array!`);
|
|
533
543
|
return;
|
|
@@ -538,13 +548,20 @@ var removeKey = (obj, key, embeddedKey) => {
|
|
|
538
548
|
return;
|
|
539
549
|
}
|
|
540
550
|
};
|
|
541
|
-
var
|
|
551
|
+
var resolveProperty = (obj, key, isPath) => {
|
|
552
|
+
if (obj == null) return void 0;
|
|
553
|
+
if (typeof key !== "string" || !isPath || !key.includes(".")) return obj[key];
|
|
554
|
+
return key.split(".").reduce((cur, seg) => cur?.[seg], obj);
|
|
555
|
+
};
|
|
556
|
+
var indexOfItemInArray = (arr, key, value, isPath) => {
|
|
542
557
|
if (key === "$value") {
|
|
543
558
|
return arr.indexOf(value);
|
|
544
559
|
}
|
|
545
560
|
for (let i = 0; i < arr.length; i++) {
|
|
546
561
|
const item = arr[i];
|
|
547
|
-
if (item
|
|
562
|
+
if (item == null) continue;
|
|
563
|
+
const resolved = resolveProperty(item, key, isPath);
|
|
564
|
+
if (resolved !== void 0 && String(resolved) === String(value)) {
|
|
548
565
|
return i;
|
|
549
566
|
}
|
|
550
567
|
}
|
|
@@ -562,7 +579,7 @@ var addKeyValue = (obj, key, value, embeddedKey) => {
|
|
|
562
579
|
return obj ? obj[key] = value : null;
|
|
563
580
|
}
|
|
564
581
|
};
|
|
565
|
-
var applyLeafChange = (obj, change, embeddedKey) => {
|
|
582
|
+
var applyLeafChange = (obj, change, embeddedKey, isPath) => {
|
|
566
583
|
const { type, key, value } = change;
|
|
567
584
|
switch (type) {
|
|
568
585
|
case "ADD" /* ADD */:
|
|
@@ -570,7 +587,7 @@ var applyLeafChange = (obj, change, embeddedKey) => {
|
|
|
570
587
|
case "UPDATE" /* UPDATE */:
|
|
571
588
|
return modifyKeyValue(obj, key, value);
|
|
572
589
|
case "REMOVE" /* REMOVE */:
|
|
573
|
-
return removeKey(obj, key, embeddedKey);
|
|
590
|
+
return removeKey(obj, key, embeddedKey, isPath);
|
|
574
591
|
}
|
|
575
592
|
};
|
|
576
593
|
var applyArrayChange = (arr, change) => {
|
|
@@ -587,7 +604,7 @@ var applyArrayChange = (arr, change) => {
|
|
|
587
604
|
}
|
|
588
605
|
for (const subchange of changes) {
|
|
589
606
|
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);
|
|
607
|
+
applyLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
|
|
591
608
|
} else {
|
|
592
609
|
let element;
|
|
593
610
|
if (change.embeddedKey === "$index") {
|
|
@@ -598,7 +615,10 @@ var applyArrayChange = (arr, change) => {
|
|
|
598
615
|
element = arr[index];
|
|
599
616
|
}
|
|
600
617
|
} else {
|
|
601
|
-
element = arr.find((el) =>
|
|
618
|
+
element = arr.find((el) => {
|
|
619
|
+
const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
|
|
620
|
+
return resolved !== void 0 && String(resolved) === String(subchange.key);
|
|
621
|
+
});
|
|
602
622
|
}
|
|
603
623
|
if (element) {
|
|
604
624
|
applyChangeset(element, subchange.changes);
|
|
@@ -614,7 +634,7 @@ var applyBranchChange = (obj, change) => {
|
|
|
614
634
|
return applyChangeset(obj, change.changes);
|
|
615
635
|
}
|
|
616
636
|
};
|
|
617
|
-
var revertLeafChange = (obj, change, embeddedKey = "$index") => {
|
|
637
|
+
var revertLeafChange = (obj, change, embeddedKey = "$index", isPath) => {
|
|
618
638
|
const { type, key, value, oldValue } = change;
|
|
619
639
|
if (key === "$root") {
|
|
620
640
|
switch (type) {
|
|
@@ -644,7 +664,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
|
|
|
644
664
|
}
|
|
645
665
|
switch (type) {
|
|
646
666
|
case "ADD" /* ADD */:
|
|
647
|
-
return removeKey(obj, key, embeddedKey);
|
|
667
|
+
return removeKey(obj, key, embeddedKey, isPath);
|
|
648
668
|
case "UPDATE" /* UPDATE */:
|
|
649
669
|
return modifyKeyValue(obj, key, oldValue);
|
|
650
670
|
case "REMOVE" /* REMOVE */:
|
|
@@ -654,7 +674,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
|
|
|
654
674
|
var revertArrayChange = (arr, change) => {
|
|
655
675
|
for (const subchange of change.changes) {
|
|
656
676
|
if (subchange.value != null || subchange.type === "REMOVE" /* REMOVE */) {
|
|
657
|
-
revertLeafChange(arr, subchange, change.embeddedKey);
|
|
677
|
+
revertLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
|
|
658
678
|
} else {
|
|
659
679
|
let element;
|
|
660
680
|
if (change.embeddedKey === "$index") {
|
|
@@ -665,7 +685,10 @@ var revertArrayChange = (arr, change) => {
|
|
|
665
685
|
element = arr[index];
|
|
666
686
|
}
|
|
667
687
|
} else {
|
|
668
|
-
element = arr.find((el) =>
|
|
688
|
+
element = arr.find((el) => {
|
|
689
|
+
const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
|
|
690
|
+
return resolved !== void 0 && String(resolved) === String(subchange.key);
|
|
691
|
+
});
|
|
669
692
|
}
|
|
670
693
|
if (element) {
|
|
671
694
|
revertChangeset(element, subchange.changes);
|
|
@@ -685,9 +708,17 @@ function append(basePath, nextSegment) {
|
|
|
685
708
|
return nextSegment.includes(".") ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;
|
|
686
709
|
}
|
|
687
710
|
var IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
688
|
-
|
|
711
|
+
var NESTED_PATH_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*$/;
|
|
712
|
+
function filterExpression(basePath, filterKey, filterValue, isPath) {
|
|
689
713
|
const escapedValue = `'${filterValue.replace(/'/g, "''")}'`;
|
|
690
|
-
|
|
714
|
+
let memberAccess;
|
|
715
|
+
if (isPath && NESTED_PATH_RE.test(filterKey)) {
|
|
716
|
+
memberAccess = "." + filterKey;
|
|
717
|
+
} else if (IDENT_RE.test(filterKey)) {
|
|
718
|
+
memberAccess = `.${filterKey}`;
|
|
719
|
+
} else {
|
|
720
|
+
memberAccess = `['${filterKey.replace(/'/g, "''")}']`;
|
|
721
|
+
}
|
|
691
722
|
return `${basePath}[?(@${memberAccess}==${escapedValue})]`;
|
|
692
723
|
}
|
|
693
724
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -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 // Nested path when resolvedKey contains '.' and matches NESTED_PATH_RE.\n // Function keys qualify directly; string keys qualify only if the sample\n // element does not expose resolvedKey as a literal property.\n const sampleEl = [...newObj, ...oldObj].find((el) => el != null && typeof el === 'object');\n const isNestedPath = typeof resolvedKey === 'string' && resolvedKey.includes('.') && NESTED_PATH_RE.test(resolvedKey)\n && (isFunctionKey || !(sampleEl != null && resolvedKey in sampleEl));\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: resolvedKey,\n ...(isNestedPath ? { 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 const maybeNestedPath = typeof uniqKey === 'string' && uniqKey.includes('.') && NESTED_PATH_RE.test(uniqKey);\n const keyFunction = typeof uniqKey === 'string'\n ? (maybeNestedPath\n ? (item: any) => (item != null && typeof item === 'object' && uniqKey in item) ? item[uniqKey] : resolveProperty(item, uniqKey, true)\n : (item: any) => item != null ? item[uniqKey] : undefined)\n : 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 !== undefined && 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 !== undefined && 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 !== undefined && 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 = /^([^[\]]+)\[\?\(@(?:\.?([^=[]*)|(?:\['([^']*)'\]))=+'([^']
|
|
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
|
-
|
|
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,17 @@ 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;
|
|
430
|
+
const sampleEl = [...newObj, ...oldObj].find((el) => el != null && typeof el === "object");
|
|
431
|
+
const isNestedPath = typeof resolvedKey === "string" && resolvedKey.includes(".") && NESTED_PATH_RE.test(resolvedKey) && (isFunctionKey || !(sampleEl != null && resolvedKey in sampleEl));
|
|
424
432
|
return [
|
|
425
433
|
{
|
|
426
434
|
type: "UPDATE" /* UPDATE */,
|
|
427
435
|
key: getKey(path),
|
|
428
|
-
embeddedKey:
|
|
436
|
+
embeddedKey: resolvedKey,
|
|
437
|
+
...isNestedPath ? { embeddedKeyIsPath: true } : {},
|
|
429
438
|
changes: diffs
|
|
430
439
|
}
|
|
431
440
|
];
|
|
@@ -466,7 +475,8 @@ var convertArrayToObj = (arr, uniqKey) => {
|
|
|
466
475
|
obj[i] = value;
|
|
467
476
|
}
|
|
468
477
|
} else {
|
|
469
|
-
const
|
|
478
|
+
const maybeNestedPath = typeof uniqKey === "string" && uniqKey.includes(".") && NESTED_PATH_RE.test(uniqKey);
|
|
479
|
+
const keyFunction = typeof uniqKey === "string" ? maybeNestedPath ? (item) => item != null && typeof item === "object" && uniqKey in item ? item[uniqKey] : resolveProperty(item, uniqKey, true) : (item) => item != null ? item[uniqKey] : void 0 : uniqKey;
|
|
470
480
|
obj = keyBy(arr, keyFunction);
|
|
471
481
|
}
|
|
472
482
|
return obj;
|
|
@@ -483,13 +493,13 @@ var comparePrimitives = (oldObj, newObj, path) => {
|
|
|
483
493
|
}
|
|
484
494
|
return changes;
|
|
485
495
|
};
|
|
486
|
-
var removeKey = (obj, key, embeddedKey) => {
|
|
496
|
+
var removeKey = (obj, key, embeddedKey, isPath) => {
|
|
487
497
|
if (Array.isArray(obj)) {
|
|
488
498
|
if (embeddedKey === "$index") {
|
|
489
499
|
obj.splice(Number(key), 1);
|
|
490
500
|
return;
|
|
491
501
|
}
|
|
492
|
-
const index = indexOfItemInArray(obj, embeddedKey, key);
|
|
502
|
+
const index = indexOfItemInArray(obj, embeddedKey, key, isPath);
|
|
493
503
|
if (index === -1) {
|
|
494
504
|
console.warn(`Element with the key '${embeddedKey}' and value '${key}' could not be found in the array!`);
|
|
495
505
|
return;
|
|
@@ -500,13 +510,20 @@ var removeKey = (obj, key, embeddedKey) => {
|
|
|
500
510
|
return;
|
|
501
511
|
}
|
|
502
512
|
};
|
|
503
|
-
var
|
|
513
|
+
var resolveProperty = (obj, key, isPath) => {
|
|
514
|
+
if (obj == null) return void 0;
|
|
515
|
+
if (typeof key !== "string" || !isPath || !key.includes(".")) return obj[key];
|
|
516
|
+
return key.split(".").reduce((cur, seg) => cur?.[seg], obj);
|
|
517
|
+
};
|
|
518
|
+
var indexOfItemInArray = (arr, key, value, isPath) => {
|
|
504
519
|
if (key === "$value") {
|
|
505
520
|
return arr.indexOf(value);
|
|
506
521
|
}
|
|
507
522
|
for (let i = 0; i < arr.length; i++) {
|
|
508
523
|
const item = arr[i];
|
|
509
|
-
if (item
|
|
524
|
+
if (item == null) continue;
|
|
525
|
+
const resolved = resolveProperty(item, key, isPath);
|
|
526
|
+
if (resolved !== void 0 && String(resolved) === String(value)) {
|
|
510
527
|
return i;
|
|
511
528
|
}
|
|
512
529
|
}
|
|
@@ -524,7 +541,7 @@ var addKeyValue = (obj, key, value, embeddedKey) => {
|
|
|
524
541
|
return obj ? obj[key] = value : null;
|
|
525
542
|
}
|
|
526
543
|
};
|
|
527
|
-
var applyLeafChange = (obj, change, embeddedKey) => {
|
|
544
|
+
var applyLeafChange = (obj, change, embeddedKey, isPath) => {
|
|
528
545
|
const { type, key, value } = change;
|
|
529
546
|
switch (type) {
|
|
530
547
|
case "ADD" /* ADD */:
|
|
@@ -532,7 +549,7 @@ var applyLeafChange = (obj, change, embeddedKey) => {
|
|
|
532
549
|
case "UPDATE" /* UPDATE */:
|
|
533
550
|
return modifyKeyValue(obj, key, value);
|
|
534
551
|
case "REMOVE" /* REMOVE */:
|
|
535
|
-
return removeKey(obj, key, embeddedKey);
|
|
552
|
+
return removeKey(obj, key, embeddedKey, isPath);
|
|
536
553
|
}
|
|
537
554
|
};
|
|
538
555
|
var applyArrayChange = (arr, change) => {
|
|
@@ -549,7 +566,7 @@ var applyArrayChange = (arr, change) => {
|
|
|
549
566
|
}
|
|
550
567
|
for (const subchange of changes) {
|
|
551
568
|
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);
|
|
569
|
+
applyLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
|
|
553
570
|
} else {
|
|
554
571
|
let element;
|
|
555
572
|
if (change.embeddedKey === "$index") {
|
|
@@ -560,7 +577,10 @@ var applyArrayChange = (arr, change) => {
|
|
|
560
577
|
element = arr[index];
|
|
561
578
|
}
|
|
562
579
|
} else {
|
|
563
|
-
element = arr.find((el) =>
|
|
580
|
+
element = arr.find((el) => {
|
|
581
|
+
const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
|
|
582
|
+
return resolved !== void 0 && String(resolved) === String(subchange.key);
|
|
583
|
+
});
|
|
564
584
|
}
|
|
565
585
|
if (element) {
|
|
566
586
|
applyChangeset(element, subchange.changes);
|
|
@@ -576,7 +596,7 @@ var applyBranchChange = (obj, change) => {
|
|
|
576
596
|
return applyChangeset(obj, change.changes);
|
|
577
597
|
}
|
|
578
598
|
};
|
|
579
|
-
var revertLeafChange = (obj, change, embeddedKey = "$index") => {
|
|
599
|
+
var revertLeafChange = (obj, change, embeddedKey = "$index", isPath) => {
|
|
580
600
|
const { type, key, value, oldValue } = change;
|
|
581
601
|
if (key === "$root") {
|
|
582
602
|
switch (type) {
|
|
@@ -606,7 +626,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
|
|
|
606
626
|
}
|
|
607
627
|
switch (type) {
|
|
608
628
|
case "ADD" /* ADD */:
|
|
609
|
-
return removeKey(obj, key, embeddedKey);
|
|
629
|
+
return removeKey(obj, key, embeddedKey, isPath);
|
|
610
630
|
case "UPDATE" /* UPDATE */:
|
|
611
631
|
return modifyKeyValue(obj, key, oldValue);
|
|
612
632
|
case "REMOVE" /* REMOVE */:
|
|
@@ -616,7 +636,7 @@ var revertLeafChange = (obj, change, embeddedKey = "$index") => {
|
|
|
616
636
|
var revertArrayChange = (arr, change) => {
|
|
617
637
|
for (const subchange of change.changes) {
|
|
618
638
|
if (subchange.value != null || subchange.type === "REMOVE" /* REMOVE */) {
|
|
619
|
-
revertLeafChange(arr, subchange, change.embeddedKey);
|
|
639
|
+
revertLeafChange(arr, subchange, change.embeddedKey, change.embeddedKeyIsPath);
|
|
620
640
|
} else {
|
|
621
641
|
let element;
|
|
622
642
|
if (change.embeddedKey === "$index") {
|
|
@@ -627,7 +647,10 @@ var revertArrayChange = (arr, change) => {
|
|
|
627
647
|
element = arr[index];
|
|
628
648
|
}
|
|
629
649
|
} else {
|
|
630
|
-
element = arr.find((el) =>
|
|
650
|
+
element = arr.find((el) => {
|
|
651
|
+
const resolved = resolveProperty(el, change.embeddedKey, change.embeddedKeyIsPath);
|
|
652
|
+
return resolved !== void 0 && String(resolved) === String(subchange.key);
|
|
653
|
+
});
|
|
631
654
|
}
|
|
632
655
|
if (element) {
|
|
633
656
|
revertChangeset(element, subchange.changes);
|
|
@@ -647,9 +670,17 @@ function append(basePath, nextSegment) {
|
|
|
647
670
|
return nextSegment.includes(".") ? `${basePath}[${nextSegment}]` : `${basePath}.${nextSegment}`;
|
|
648
671
|
}
|
|
649
672
|
var IDENT_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
650
|
-
|
|
673
|
+
var NESTED_PATH_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*$/;
|
|
674
|
+
function filterExpression(basePath, filterKey, filterValue, isPath) {
|
|
651
675
|
const escapedValue = `'${filterValue.replace(/'/g, "''")}'`;
|
|
652
|
-
|
|
676
|
+
let memberAccess;
|
|
677
|
+
if (isPath && NESTED_PATH_RE.test(filterKey)) {
|
|
678
|
+
memberAccess = "." + filterKey;
|
|
679
|
+
} else if (IDENT_RE.test(filterKey)) {
|
|
680
|
+
memberAccess = `.${filterKey}`;
|
|
681
|
+
} else {
|
|
682
|
+
memberAccess = `['${filterKey.replace(/'/g, "''")}']`;
|
|
683
|
+
}
|
|
653
684
|
return `${basePath}[?(@${memberAccess}==${escapedValue})]`;
|
|
654
685
|
}
|
|
655
686
|
|
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 // Nested path when resolvedKey contains '.' and matches NESTED_PATH_RE.\n // Function keys qualify directly; string keys qualify only if the sample\n // element does not expose resolvedKey as a literal property.\n const sampleEl = [...newObj, ...oldObj].find((el) => el != null && typeof el === 'object');\n const isNestedPath = typeof resolvedKey === 'string' && resolvedKey.includes('.') && NESTED_PATH_RE.test(resolvedKey)\n && (isFunctionKey || !(sampleEl != null && resolvedKey in sampleEl));\n return [\n {\n type: Operation.UPDATE,\n key: getKey(path),\n embeddedKey: resolvedKey,\n ...(isNestedPath ? { 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 const maybeNestedPath = typeof uniqKey === 'string' && uniqKey.includes('.') && NESTED_PATH_RE.test(uniqKey);\n const keyFunction = typeof uniqKey === 'string'\n ? (maybeNestedPath\n ? (item: any) => (item != null && typeof item === 'object' && uniqKey in item) ? item[uniqKey] : resolveProperty(item, uniqKey, true)\n : (item: any) => item != null ? item[uniqKey] : undefined)\n : 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 !== undefined && 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 !== undefined && 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 !== undefined && 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.
|
|
3
|
+
"version": "4.10.4",
|
|
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",
|