From f3984ec6bef2861a1a769499a319760766b37708 Mon Sep 17 00:00:00 2001 From: Harsh Kapse Date: Fri, 14 Aug 2026 18:03:13 +0530 Subject: [PATCH] fix(engine): prevent large-distance line jumps in LineDiff DP backtrack --- internal/engine/linediff.go | 15 +- .../expected.json | 1370 +---------------- 2 files changed, 34 insertions(+), 1351 deletions(-) diff --git a/internal/engine/linediff.go b/internal/engine/linediff.go index e0cf304..6cda82c 100644 --- a/internal/engine/linediff.go +++ b/internal/engine/linediff.go @@ -50,9 +50,20 @@ func LineDiff(linesA, linesB []string) map[int]int { i, j := lenA, lenB for i > 0 && j > 0 { if subA[i-1] == subB[j-1] { - matchedA[start+i-1] = start + j - 1 + bestJ := j + if i-j > 20 || j-i > 20 { + for k := j - 1; k >= 1; k-- { + if subA[i-1] == subB[k-1] && dp[(i-1)*stride+(k-1)]+1 == dp[i*stride+j] { + if i-k <= 20 && k-i <= 20 { + bestJ = k + break + } + } + } + } + matchedA[start+i-1] = start + bestJ - 1 i-- - j-- + j = bestJ - 1 } else if dp[(i-1)*stride+j] >= dp[i*stride+(j-1)] { i-- } else { diff --git a/tests/testdata/json_schemastore_workflow_step_reorder/expected.json b/tests/testdata/json_schemastore_workflow_step_reorder/expected.json index f8cc5bd..6c63c3f 100644 --- a/tests/testdata/json_schemastore_workflow_step_reorder/expected.json +++ b/tests/testdata/json_schemastore_workflow_step_reorder/expected.json @@ -26,1098 +26,11 @@ "start_byte": 301, "end_byte": 55016 }, - "position": 5 - }, - { - "action": "update", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 0 - ], - "type": "string", - "label": "\"container\"", - "start_byte": 4123, - "end_byte": 4134 - }, - "old_value": "\"container\"", - "new_value": "\"jobContainer\"", - "dest_node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 0 - ], - "type": "string", - "label": "\"jobContainer\"", - "start_byte": 4123, - "end_byte": 4137 - } - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 0 - ], - "type": "string", - "label": "\"serviceContainer\"", - "start_byte": 7151, - "end_byte": 7169 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5 - ], - "type": "pair", - "start_byte": 7151, - "end_byte": 11225 - }, - "position": 0 - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 2 - ], - "type": "pair", - "start_byte": 7081, - "end_byte": 7102 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 4139, - "end_byte": 7145 - }, - "position": 2, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 3 - ], - "type": "pair", - "start_byte": 7110, - "end_byte": 7139 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 4139, - "end_byte": 7145 - }, - "position": 3, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 0 - ], - "type": "pair", - "start_byte": 7179, - "end_byte": 7195 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 7171, - "end_byte": 11225 - }, - "position": 0, - "subtree": true - }, - { - "action": "move", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 2 - ], - "type": "pair", - "start_byte": 7259, - "end_byte": 7280 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 7171, - "end_byte": 11225 - }, - "position": 2, - "old_parent": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 4136, - "end_byte": 7323 - }, - "old_position": 2, - "subtree": true, - "dest_start_byte": 11161, - "dest_end_byte": 11182, - "group_id": "group-1" - }, - { - "action": "move", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 3 - ], - "type": "pair", - "start_byte": 7288, - "end_byte": 7317 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 7171, - "end_byte": 11225 - }, - "position": 3, - "old_parent": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 4136, - "end_byte": 7323 - }, - "old_position": 3, - "subtree": true, - "dest_start_byte": 11190, - "dest_end_byte": 11219, - "group_id": "group-1" - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 0 - ], - "type": "string", - "label": "\"properties\"", - "start_byte": 7203, - "end_byte": 7215 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1 - ], - "type": "pair", - "start_byte": 7203, - "end_byte": 11153 - }, - "position": 0 - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 0 - ], - "type": "pair", - "start_byte": 7227, - "end_byte": 7575 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1 - ], - "type": "object", - "start_byte": 7217, - "end_byte": 11153 - }, - "position": 0, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 1 - ], - "type": "pair", - "start_byte": 7585, - "end_byte": 8230 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1 - ], - "type": "object", - "start_byte": 7217, - "end_byte": 11153 - }, - "position": 1, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 2 - ], - "type": "pair", - "start_byte": 8240, - "end_byte": 8526 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1 - ], - "type": "object", - "start_byte": 7217, - "end_byte": 11153 - }, - "position": 2, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 3 - ], - "type": "pair", - "start_byte": 8536, - "end_byte": 9038 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1 - ], - "type": "object", - "start_byte": 7217, - "end_byte": 11153 - }, - "position": 3, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 6 - ], - "type": "pair", - "start_byte": 10193, - "end_byte": 10641 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1 - ], - "type": "object", - "start_byte": 7217, - "end_byte": 11153 - }, - "position": 6, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 0 - ], - "type": "string", - "label": "\"volumes\"", - "start_byte": 9048, - "end_byte": 9057 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4 - ], - "type": "pair", - "start_byte": 9048, - "end_byte": 9809 - }, - "position": 0 - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5, - 0 - ], - "type": "string", - "label": "\"options\"", - "start_byte": 9819, - "end_byte": 9828 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5 - ], - "type": "pair", - "start_byte": 9819, - "end_byte": 10183 - }, - "position": 0 - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7, - 0 - ], - "type": "string", - "label": "\"entrypoint\"", - "start_byte": 10651, - "end_byte": 10663 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7 - ], - "type": "pair", - "start_byte": 10651, - "end_byte": 11145 - }, - "position": 0 - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1, - 2 - ], - "type": "pair", - "start_byte": 6587, - "end_byte": 6602 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 5967, - "end_byte": 6700 - }, - "position": 2, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1, - 3 - ], - "type": "pair", - "start_byte": 6614, - "end_byte": 6665 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 5967, - "end_byte": 6700 - }, - "position": 3, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1, - 4 - ], - "type": "pair", - "start_byte": 6677, - "end_byte": 6690 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 5967, - "end_byte": 6700 - }, - "position": 4, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 5, - 1, - 1 - ], - "type": "pair", - "start_byte": 6868, - "end_byte": 7027 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 6721, - "end_byte": 7065 - }, - "position": 1, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 5, - 1, - 2 - ], - "type": "pair", - "start_byte": 7039, - "end_byte": 7055 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 6721, - "end_byte": 7065 - }, - "position": 2, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1, - 0 - ], - "type": "pair", - "start_byte": 9071, - "end_byte": 9203 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 9059, - "end_byte": 9809 - }, - "position": 0, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1, - 1 - ], - "type": "pair", - "start_byte": 9215, - "end_byte": 9684 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 9059, - "end_byte": 9809 - }, - "position": 1, - "subtree": true - }, - { - "action": "move", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1, - 2 - ], - "type": "pair", - "start_byte": 6733, - "end_byte": 6748 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 9059, - "end_byte": 9809 - }, - "position": 2, - "old_parent": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 6081, - "end_byte": 6846 - }, - "old_position": 2, - "subtree": true, - "dest_start_byte": 9696, - "dest_end_byte": 9711, - "group_id": "group-2" - }, - { - "action": "move", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1, - 3 - ], - "type": "pair", - "start_byte": 6760, - "end_byte": 6811 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 9059, - "end_byte": 9809 - }, - "position": 3, - "old_parent": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 6081, - "end_byte": 6846 - }, - "old_position": 3, - "subtree": true, - "dest_start_byte": 9723, - "dest_end_byte": 9774, - "group_id": "group-2" - }, - { - "action": "move", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1, - 4 - ], - "type": "pair", - "start_byte": 6823, - "end_byte": 6836 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 9059, - "end_byte": 9809 - }, - "position": 4, - "old_parent": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 4, - 1 - ], - "type": "object", - "start_byte": 6081, - "end_byte": 6846 - }, - "old_position": 4, - "subtree": true, - "dest_start_byte": 9786, - "dest_end_byte": 9799, - "group_id": "group-2" - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5, - 1, - 0 - ], - "type": "pair", - "start_byte": 9842, - "end_byte": 9974 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 9830, - "end_byte": 10183 - }, - "position": 0, + "position": 5, "subtree": true }, { - "action": "move", + "action": "update", "node": { "tree": "before", "path": [ @@ -1125,238 +38,29 @@ 4, 1, 4, - 1, - 1, - 1, - 5, - 1, - 1 - ], - "type": "pair", - "start_byte": 7046, - "end_byte": 7205 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 9830, - "end_byte": 10183 - }, - "position": 1, - "old_parent": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 6867, - "end_byte": 7243 - }, - "old_position": 1, - "subtree": true, - "dest_start_byte": 9986, - "dest_end_byte": 10145, - "group_id": "group-3" - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5, - 1, - 2 - ], - "type": "pair", - "start_byte": 10157, - "end_byte": 10173 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 5, - 1 - ], - "type": "object", - "start_byte": 9830, - "end_byte": 10183 - }, - "position": 2, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7, - 1, 0 ], - "type": "pair", - "start_byte": 10677, - "end_byte": 10812 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7, - 1 - ], - "type": "object", - "start_byte": 10665, - "end_byte": 11145 - }, - "position": 0, - "subtree": true - }, - { - "action": "insert", - "node": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7, - 1, - 1 - ], - "type": "pair", - "start_byte": 10824, - "end_byte": 11107 - }, - "parent": { - "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7, - 1 - ], - "type": "object", - "start_byte": 10665, - "end_byte": 11145 - }, - "position": 1, - "subtree": true - }, - { - "action": "move", - "node": { - "tree": "before", - "path": [ - 0, - 4, - 1, - 4, - 1, - 1, - 1, - 5, - 1, - 2 - ], - "type": "pair", - "start_byte": 7217, - "end_byte": 7233 + "type": "string", + "label": "\"container\"", + "start_byte": 4123, + "end_byte": 4134 }, - "parent": { + "old_value": "\"container\"", + "new_value": "\"jobContainer\"", + "dest_node": { "tree": "after", - "path": [ - 0, - 4, - 1, - 5, - 1, - 1, - 1, - 7, - 1 - ], - "type": "object", - "start_byte": 10665, - "end_byte": 11145 - }, - "position": 2, - "old_parent": { - "tree": "before", "path": [ 0, 4, 1, 4, - 1, - 1, - 1, - 5, - 1 + 0 ], - "type": "object", - "start_byte": 6867, - "end_byte": 7243 - }, - "old_position": 2, - "subtree": true, - "dest_start_byte": 11119, - "dest_end_byte": 11135, - "group_id": "group-3" + "type": "string", + "label": "\"jobContainer\"", + "start_byte": 4123, + "end_byte": 4137 + } }, { "action": "update", @@ -2213,26 +917,14 @@ }, { "left_line": 109, - "right_line": -1 - }, - { - "left_line": 110, - "right_line": -1 - }, - { - "left_line": 111, - "right_line": -1 - }, - { - "left_line": -1, "right_line": 109 }, { - "left_line": -1, + "left_line": 110, "right_line": 110 }, { - "left_line": -1, + "left_line": 111, "right_line": 111 }, { @@ -2241,10 +933,6 @@ }, { "left_line": 113, - "right_line": -1 - }, - { - "left_line": -1, "right_line": 113 }, { @@ -2261,18 +949,10 @@ }, { "left_line": 117, - "right_line": -1 - }, - { - "left_line": 118, - "right_line": -1 - }, - { - "left_line": -1, "right_line": 117 }, { - "left_line": -1, + "left_line": 118, "right_line": 118 }, { @@ -2285,22 +965,14 @@ }, { "left_line": 121, - "right_line": -1 - }, - { - "left_line": 122, - "right_line": -1 - }, - { - "left_line": -1, "right_line": 121 }, { - "left_line": -1, + "left_line": 122, "right_line": 122 }, { - "left_line": -1, + "left_line": 123, "right_line": 123 }, { @@ -2580,7 +1252,7 @@ "right_line": 192 }, { - "left_line": 123, + "left_line": -1, "right_line": 193 }, {