| 10 | * @returns An array of difference pairs. |
| 11 | */ |
| 12 | export function compareJSON(ltree: Tree, rtree: Tree): DiffPair[] { |
| 13 | const Diff = (node: Node, type: DiffType, includeBound: boolean = true) => { |
| 14 | return includeBound ? newDiff(node.boundOffset, node.boundLength, type) : newDiff(node.offset, node.length, type); |
| 15 | }; |
| 16 | |
| 17 | // Converts inline diffs to global diffs. |
| 18 | const newInlineDiffs = (node: Node, inlineDiffs: Diff[]) => |
| 19 | inlineDiffs.map((d) => { |
| 20 | d.offset += node.offset; |
| 21 | return d; |
| 22 | }); |
| 23 | |
| 24 | const pairs: DiffPair[] = []; |
| 25 | |
| 26 | const comparer = { |
| 27 | // Compares two nodes. |
| 28 | diff(lnode: Node, rnode: Node) { |
| 29 | if (lnode.type !== rnode.type) { |
| 30 | pairs.push({ |
| 31 | left: Diff(lnode, "del", false), |
| 32 | right: Diff(rnode, "ins", false), |
| 33 | }); |
| 34 | return; |
| 35 | } |
| 36 | |
| 37 | if (lnode.type === "array") { |
| 38 | this.diffArray(lnode, rnode); |
| 39 | } else if (lnode.type === "object") { |
| 40 | this.diffObject(lnode, rnode); |
| 41 | } else if (lnode.type === "string" || lnode.type === "number") { |
| 42 | const { left: leftInlineDiffs, right: rightInlineDiffs } = classify( |
| 43 | compareInlineTexts(getRawValue(lnode)!, getRawValue(rnode)!), |
| 44 | ); |
| 45 | |
| 46 | if (leftInlineDiffs.length || rightInlineDiffs.length) { |
| 47 | const left = Diff(lnode, "del", false); |
| 48 | const right = Diff(rnode, "ins", false); |
| 49 | left.inlineDiffs = newInlineDiffs(lnode, leftInlineDiffs); |
| 50 | right.inlineDiffs = newInlineDiffs(rnode, rightInlineDiffs); |
| 51 | pairs.push({ left, right }); |
| 52 | } |
| 53 | // Other types are easy to identify differences, so there is no need for inline comparison. |
| 54 | } else if (lnode.value !== rnode.value) { |
| 55 | pairs.push({ |
| 56 | left: Diff(lnode, "del", false), |
| 57 | right: Diff(rnode, "ins", false), |
| 58 | }); |
| 59 | } |
| 60 | }, |
| 61 | |
| 62 | // Compares two arrays. |
| 63 | diffArray(lnode: Node, rnode: Node) { |
| 64 | const diffs = compareArray( |
| 65 | ltree.mapChildren(lnode, (child) => ltree.getNodeToken(child)), |
| 66 | rtree.mapChildren(rnode, (child) => rtree.getNodeToken(child)), |
| 67 | ); |
| 68 | const { left, right } = classify(diffs); |
| 69 | const n = Math.max(left.length, right.length); |