diff --git a/resources/js/lib/graph.ts b/resources/js/lib/graph.ts index 415b9bac3..fcc8d4ee3 100644 --- a/resources/js/lib/graph.ts +++ b/resources/js/lib/graph.ts @@ -56,8 +56,24 @@ export function graphEdges( drawing: ReadonlySet = new Set(), ): GraphEdge[] { const byId = new Map(nodes.map((node) => [node.id, node])); + const repliesByParent = new Map(); + const successorsByAfter = new Map(); const edges: GraphEdge[] = []; + for (const node of nodes) { + if (node.parent !== undefined) { + const replies = repliesByParent.get(node.parent) ?? []; + replies.push(node); + repliesByParent.set(node.parent, replies); + } + + if (node.after !== undefined) { + const successors = successorsByAfter.get(node.after) ?? []; + successors.push(node); + successorsByAfter.set(node.after, successors); + } + } + for (const node of nodes) { const previous = node.after === undefined ? undefined : byId.get(node.after); @@ -70,16 +86,12 @@ export function graphEdges( node.parent === undefined ? undefined : byId.get(node.parent); if (parent) { - const continues = nodes.some( + const continues = (successorsByAfter.get(parent.id) ?? []).some( (other) => - other.after === parent.id && - other.y > node.y && - !drawing.has(trunkId(parent, other)), + other.y > node.y && !drawing.has(trunkId(parent, other)), ); - const above = nodes - .filter( - (other) => other.parent === parent.id && other.y < node.y, - ) + const above = (repliesByParent.get(parent.id) ?? []) + .filter((other) => other.y < node.y) .reduce( (closest, other) => closest === undefined || other.y > closest.y diff --git a/tests/Unit/GraphEdges.test.ts b/tests/Unit/GraphEdges.test.ts index f894fde31..6f00516a7 100644 --- a/tests/Unit/GraphEdges.test.ts +++ b/tests/Unit/GraphEdges.test.ts @@ -588,3 +588,20 @@ void test('folds away the lines to and from folding replies, not the trunk runni false, ); }); + +void test('unrelated nodes do not affect the reply and continuation paths', () => { + const thread = [ + node({ id: 'parent', y: 40 }), + node({ id: 'first', x: 100, y: 160, parent: 'parent' }), + node({ id: 'next', y: 400, after: 'parent' }), + ]; + const baseline = graphEdges(thread).map((edge) => [edge.id, edge.d]); + const unrelated = Array.from({ length: 200 }, (_, index) => + node({ id: `unrelated-${index}`, y: index * 10 }), + ); + + assert.deepEqual( + graphEdges([...thread, ...unrelated]).map((edge) => [edge.id, edge.d]), + baseline, + ); +});