@nodius/layouting 0.1.0 → 0.1.1
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/LICENSE +201 -201
- package/README.md +280 -126
- package/dist/algorithms/component-packing.d.ts +9 -0
- package/dist/algorithms/component-packing.d.ts.map +1 -0
- package/dist/algorithms/coordinate-assignment.d.ts +7 -0
- package/dist/algorithms/coordinate-assignment.d.ts.map +1 -0
- package/dist/algorithms/crossing-minimization.d.ts +7 -0
- package/dist/algorithms/crossing-minimization.d.ts.map +1 -0
- package/dist/algorithms/cycle-breaking.d.ts +8 -0
- package/dist/algorithms/cycle-breaking.d.ts.map +1 -0
- package/dist/algorithms/edge-routing.d.ts +17 -0
- package/dist/algorithms/edge-routing.d.ts.map +1 -0
- package/dist/algorithms/layer-assignment.d.ts +20 -0
- package/dist/algorithms/layer-assignment.d.ts.map +1 -0
- package/dist/algorithms/value-cluster.d.ts +15 -0
- package/dist/algorithms/value-cluster.d.ts.map +1 -0
- package/dist/algorithms/value-placement.d.ts +25 -0
- package/dist/algorithms/value-placement.d.ts.map +1 -0
- package/dist/debug.d.ts +20 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/graph.d.ts +50 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/incremental.d.ts +33 -0
- package/dist/incremental.d.ts.map +1 -0
- package/dist/index.d.ts +7 -176
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +904 -149
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +901 -148
- package/dist/index.mjs.map +1 -1
- package/dist/layout.d.ts +10 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/proposals.d.ts +31 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +5 -4
- package/dist/index.d.mts +0 -176
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/graph.ts","../src/algorithms/cycle-breaking.ts","../src/algorithms/layer-assignment.ts","../src/algorithms/crossing-minimization.ts","../src/algorithms/coordinate-assignment.ts","../src/algorithms/edge-routing.ts","../src/layout.ts","../src/incremental.ts"],"sourcesContent":["export { layout } from './layout';\nexport { IncrementalLayout } from './incremental';\nexport { countAllCrossings } from './algorithms/crossing-minimization';\n\nexport type {\n HandleSide,\n HandleType,\n LayoutDirection,\n Point,\n HandleInput,\n NodeInput,\n EdgeInput,\n LayoutInput,\n LayoutOptions,\n HandleOutput,\n NodeOutput,\n EdgeOutput,\n LayoutResult,\n} from './types';\n","/** Position on a node where a handle can be placed */\nexport type HandleSide = 'top' | 'right' | 'bottom' | 'left';\n\n/** Handle type - input receives connections, output sends connections */\nexport type HandleType = 'input' | 'output';\n\n/** Layout direction */\nexport type LayoutDirection = 'TB' | 'LR' | 'BT' | 'RL';\n\n/** A 2D point */\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Handle definition on a node */\nexport interface HandleInput {\n id: string;\n type: HandleType;\n position: HandleSide;\n /** Position along the side (0 = start, 1 = end). Default: 0.5 */\n offset?: number;\n}\n\n/** Node input definition */\nexport interface NodeInput {\n id: string;\n width: number;\n height: number;\n handles: HandleInput[];\n}\n\n/** Edge input definition */\nexport interface EdgeInput {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n}\n\n/** Complete layout input */\nexport interface LayoutInput {\n nodes: NodeInput[];\n edges: EdgeInput[];\n}\n\n/** Layout configuration options */\nexport interface LayoutOptions {\n /** Layout direction. Default: 'TB' */\n direction?: LayoutDirection;\n /** Minimum spacing between nodes in the same layer. Default: 40 */\n nodeSpacing?: number;\n /** Minimum spacing between layers. Default: 60 */\n layerSpacing?: number;\n /** Number of iterations for crossing minimization. Default: 24 */\n crossingMinimizationIterations?: number;\n /** Number of iterations for coordinate optimization. Default: 8 */\n coordinateOptimizationIterations?: number;\n /** Margin for edge routing (distance from node before turning). Default: 20 */\n edgeMargin?: number;\n}\n\n/** Resolved options with all defaults applied */\nexport interface ResolvedOptions {\n direction: LayoutDirection;\n nodeSpacing: number;\n layerSpacing: number;\n crossingMinimizationIterations: number;\n coordinateOptimizationIterations: number;\n edgeMargin: number;\n}\n\nexport function resolveOptions(options?: LayoutOptions): ResolvedOptions {\n return {\n direction: options?.direction ?? 'TB',\n nodeSpacing: options?.nodeSpacing ?? 40,\n layerSpacing: options?.layerSpacing ?? 60,\n crossingMinimizationIterations: options?.crossingMinimizationIterations ?? 24,\n coordinateOptimizationIterations: options?.coordinateOptimizationIterations ?? 8,\n edgeMargin: options?.edgeMargin ?? 20,\n };\n}\n\n/** Positioned handle in the output */\nexport interface HandleOutput {\n id: string;\n type: HandleType;\n position: HandleSide;\n x: number;\n y: number;\n}\n\n/** Positioned node in the output */\nexport interface NodeOutput {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n handles: HandleOutput[];\n}\n\n/** Routed edge in the output */\nexport interface EdgeOutput {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n points: Point[];\n}\n\n/** Complete layout result */\nexport interface LayoutResult {\n nodes: NodeOutput[];\n edges: EdgeOutput[];\n}\n","import { HandleInput, HandleSide, NodeInput, EdgeInput, Point } from './types';\n\nexport interface InternalNode {\n id: string;\n width: number;\n height: number;\n handles: HandleInput[];\n isDummy: boolean;\n layer: number;\n order: number;\n x: number;\n y: number;\n}\n\nexport interface InternalEdge {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n reversed: boolean;\n originalId: string;\n}\n\nexport class Graph {\n nodes: Map<string, InternalNode> = new Map();\n edges: Map<string, InternalEdge> = new Map();\n outEdges: Map<string, Set<string>> = new Map();\n inEdges: Map<string, Set<string>> = new Map();\n\n addNode(node: InternalNode): void {\n this.nodes.set(node.id, node);\n if (!this.outEdges.has(node.id)) this.outEdges.set(node.id, new Set());\n if (!this.inEdges.has(node.id)) this.inEdges.set(node.id, new Set());\n }\n\n addEdge(edge: InternalEdge): void {\n this.edges.set(edge.id, edge);\n if (!this.outEdges.has(edge.from)) this.outEdges.set(edge.from, new Set());\n if (!this.inEdges.has(edge.to)) this.inEdges.set(edge.to, new Set());\n this.outEdges.get(edge.from)!.add(edge.id);\n this.inEdges.get(edge.to)!.add(edge.id);\n }\n\n removeEdge(edgeId: string): void {\n const edge = this.edges.get(edgeId);\n if (!edge) return;\n this.outEdges.get(edge.from)?.delete(edgeId);\n this.inEdges.get(edge.to)?.delete(edgeId);\n this.edges.delete(edgeId);\n }\n\n removeNode(nodeId: string): void {\n const outEdgeIds = [...(this.outEdges.get(nodeId) || [])];\n const inEdgeIds = [...(this.inEdges.get(nodeId) || [])];\n for (const eid of outEdgeIds) this.removeEdge(eid);\n for (const eid of inEdgeIds) this.removeEdge(eid);\n this.nodes.delete(nodeId);\n this.outEdges.delete(nodeId);\n this.inEdges.delete(nodeId);\n }\n\n predecessors(nodeId: string): string[] {\n const result: string[] = [];\n const inEdgeIds = this.inEdges.get(nodeId);\n if (inEdgeIds) {\n for (const eid of inEdgeIds) {\n const edge = this.edges.get(eid);\n if (edge) result.push(edge.from);\n }\n }\n return result;\n }\n\n successors(nodeId: string): string[] {\n const result: string[] = [];\n const outEdgeIds = this.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const eid of outEdgeIds) {\n const edge = this.edges.get(eid);\n if (edge) result.push(edge.to);\n }\n }\n return result;\n }\n}\n\nexport function buildGraph(nodes: NodeInput[], edges: EdgeInput[]): Graph {\n const graph = new Graph();\n\n for (const node of nodes) {\n graph.addNode({\n id: node.id,\n width: node.width,\n height: node.height,\n handles: node.handles.map(h => ({ ...h, offset: h.offset ?? 0.5 })),\n isDummy: false,\n layer: -1,\n order: -1,\n x: 0,\n y: 0,\n });\n }\n\n for (const edge of edges) {\n graph.addEdge({\n id: edge.id,\n from: edge.from,\n to: edge.to,\n fromHandle: edge.fromHandle,\n toHandle: edge.toHandle,\n reversed: false,\n originalId: edge.id,\n });\n }\n\n return graph;\n}\n\n/** Compute the absolute position of a handle on a positioned node */\nexport function getHandlePosition(node: InternalNode, handleId: string): Point {\n const handle = node.handles.find(h => h.id === handleId);\n if (!handle) {\n return { x: node.x + node.width / 2, y: node.y + node.height / 2 };\n }\n\n const offset = handle.offset ?? 0.5;\n\n switch (handle.position) {\n case 'top':\n return { x: node.x + offset * node.width, y: node.y };\n case 'bottom':\n return { x: node.x + offset * node.width, y: node.y + node.height };\n case 'left':\n return { x: node.x, y: node.y + offset * node.height };\n case 'right':\n return { x: node.x + node.width, y: node.y + offset * node.height };\n }\n}\n\n/** Get the direction vector for exiting/entering a handle */\nexport function getHandleDirection(side: HandleSide): Point {\n switch (side) {\n case 'top': return { x: 0, y: -1 };\n case 'bottom': return { x: 0, y: 1 };\n case 'left': return { x: -1, y: 0 };\n case 'right': return { x: 1, y: 0 };\n }\n}\n","import { Graph } from '../graph';\n\n/**\n * Break cycles in the graph using DFS-based back edge detection.\n * Reverses back edges to make the graph a DAG.\n * Returns the set of reversed edge IDs.\n */\nexport function breakCycles(graph: Graph): Set<string> {\n const WHITE = 0, GRAY = 1, BLACK = 2;\n const state = new Map<string, number>();\n const reversed = new Set<string>();\n\n for (const nodeId of graph.nodes.keys()) {\n state.set(nodeId, WHITE);\n }\n\n // Process nodes with more outgoing than incoming edges first\n const nodeIds = [...graph.nodes.keys()].sort((a, b) => {\n const aDiff = (graph.outEdges.get(a)?.size || 0) - (graph.inEdges.get(a)?.size || 0);\n const bDiff = (graph.outEdges.get(b)?.size || 0) - (graph.inEdges.get(b)?.size || 0);\n return bDiff - aDiff;\n });\n\n function dfs(nodeId: string): void {\n state.set(nodeId, GRAY);\n\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const edgeId of outEdgeIds) {\n const edge = graph.edges.get(edgeId);\n if (!edge) continue;\n\n const targetState = state.get(edge.to);\n if (targetState === GRAY) {\n reversed.add(edgeId);\n } else if (targetState === WHITE) {\n dfs(edge.to);\n }\n }\n }\n\n state.set(nodeId, BLACK);\n }\n\n for (const nodeId of nodeIds) {\n if (state.get(nodeId) === WHITE) {\n dfs(nodeId);\n }\n }\n\n // Reverse the back edges in the graph\n for (const edgeId of reversed) {\n const edge = graph.edges.get(edgeId);\n if (!edge) continue;\n\n graph.removeEdge(edgeId);\n graph.addEdge({\n ...edge,\n from: edge.to,\n to: edge.from,\n fromHandle: edge.toHandle,\n toHandle: edge.fromHandle,\n reversed: !edge.reversed,\n });\n }\n\n return reversed;\n}\n","import { Graph } from '../graph';\n\n/**\n * Assign layers to nodes using the longest path algorithm.\n * Source nodes (no predecessors) get layer 0.\n * Each node's layer = max(predecessors' layers) + 1.\n */\nexport function assignLayers(graph: Graph): string[][] {\n const layers = new Map<string, number>();\n const visiting = new Set<string>();\n\n function computeLayer(nodeId: string): number {\n if (layers.has(nodeId)) return layers.get(nodeId)!;\n if (visiting.has(nodeId)) return 0;\n\n visiting.add(nodeId);\n\n const preds = graph.predecessors(nodeId);\n let maxPredLayer = -1;\n\n for (const pred of preds) {\n maxPredLayer = Math.max(maxPredLayer, computeLayer(pred));\n }\n\n const layer = maxPredLayer + 1;\n layers.set(nodeId, layer);\n\n const node = graph.nodes.get(nodeId);\n if (node) node.layer = layer;\n\n visiting.delete(nodeId);\n return layer;\n }\n\n for (const nodeId of graph.nodes.keys()) {\n computeLayer(nodeId);\n }\n\n // Build layers array\n let maxLayer = 0;\n for (const layer of layers.values()) {\n maxLayer = Math.max(maxLayer, layer);\n }\n\n const layersArray: string[][] = Array.from({ length: maxLayer + 1 }, () => []);\n for (const [nodeId, layer] of layers) {\n layersArray[layer].push(nodeId);\n }\n\n return layersArray;\n}\n\n/**\n * Insert dummy nodes for edges that span multiple layers.\n * Returns updated layers array.\n */\nexport function insertDummyNodes(graph: Graph, layers: string[][]): string[][] {\n let dummyCounter = 0;\n const edgesToProcess = [...graph.edges.values()];\n\n for (const edge of edgesToProcess) {\n const fromNode = graph.nodes.get(edge.from);\n const toNode = graph.nodes.get(edge.to);\n if (!fromNode || !toNode) continue;\n\n const fromLayer = fromNode.layer;\n const toLayer = toNode.layer;\n const span = toLayer - fromLayer;\n\n if (span <= 1) continue;\n\n // Remove original edge\n graph.removeEdge(edge.id);\n\n // Create chain of dummy nodes and edges\n let prevNodeId = edge.from;\n let prevHandleId = edge.fromHandle;\n\n for (let l = fromLayer + 1; l < toLayer; l++) {\n const dummyId = `__dummy_${dummyCounter++}`;\n\n graph.addNode({\n id: dummyId,\n width: 0,\n height: 0,\n handles: [\n { id: 'in', type: 'input', position: 'top', offset: 0.5 },\n { id: 'out', type: 'output', position: 'bottom', offset: 0.5 },\n ],\n isDummy: true,\n layer: l,\n order: -1,\n x: 0,\n y: 0,\n });\n\n layers[l].push(dummyId);\n\n graph.addEdge({\n id: `__dedge_${dummyCounter}_${l}_in`,\n from: prevNodeId,\n to: dummyId,\n fromHandle: prevHandleId,\n toHandle: 'in',\n reversed: edge.reversed,\n originalId: edge.originalId,\n });\n\n prevNodeId = dummyId;\n prevHandleId = 'out';\n }\n\n // Final edge to target\n graph.addEdge({\n id: `__dedge_${dummyCounter}_final`,\n from: prevNodeId,\n to: edge.to,\n fromHandle: prevHandleId,\n toHandle: edge.toHandle,\n reversed: edge.reversed,\n originalId: edge.originalId,\n });\n }\n\n return layers;\n}\n","import { Graph } from '../graph';\n\n/**\n * Minimize edge crossings using barycenter heuristic with transpose improvement.\n */\nexport function minimizeCrossings(\n graph: Graph,\n layers: string[][],\n iterations: number\n): string[][] {\n if (layers.length <= 1) return layers;\n\n const totalNodes = layers.reduce((s, l) => s + l.length, 0);\n\n // Adaptive: reduce iterations for large graphs\n const effectiveIter = totalNodes > 500\n ? Math.min(iterations, 6)\n : totalNodes > 200\n ? Math.min(iterations, 12)\n : iterations;\n\n // Skip transpose for very large layers\n const skipTranspose = totalNodes > 800;\n\n // Initialize node orders\n for (let l = 0; l < layers.length; l++) {\n for (let i = 0; i < layers[l].length; i++) {\n const node = graph.nodes.get(layers[l][i]);\n if (node) node.order = i;\n }\n }\n\n let bestLayers = layers.map(l => [...l]);\n let bestCrossings = countAllCrossings(graph, layers);\n let noImprovementCount = 0;\n\n for (let iter = 0; iter < effectiveIter; iter++) {\n // Down sweep\n for (let l = 1; l < layers.length; l++) {\n orderByBarycenter(graph, layers, l, 'up');\n }\n\n // Up sweep\n for (let l = layers.length - 2; l >= 0; l--) {\n orderByBarycenter(graph, layers, l, 'down');\n }\n\n // Transpose improvement\n if (!skipTranspose) {\n for (let l = 0; l < layers.length; l++) {\n if (layers[l].length <= 100) {\n transposeImprove(graph, layers, l);\n }\n }\n }\n\n const crossings = countAllCrossings(graph, layers);\n if (crossings < bestCrossings) {\n bestCrossings = crossings;\n bestLayers = layers.map(l => [...l]);\n noImprovementCount = 0;\n } else {\n noImprovementCount++;\n }\n\n if (crossings === 0 || noImprovementCount >= 3) break;\n }\n\n // Restore best ordering\n for (let l = 0; l < layers.length; l++) {\n layers[l] = bestLayers[l];\n for (let i = 0; i < layers[l].length; i++) {\n const node = graph.nodes.get(layers[l][i]);\n if (node) node.order = i;\n }\n }\n\n return layers;\n}\n\nfunction orderByBarycenter(\n graph: Graph,\n layers: string[][],\n layerIndex: number,\n direction: 'up' | 'down'\n): void {\n const layer = layers[layerIndex];\n const adjLayerIndex = direction === 'up' ? layerIndex - 1 : layerIndex + 1;\n\n if (adjLayerIndex < 0 || adjLayerIndex >= layers.length) return;\n\n // Build position lookup for adjacent layer using node.order\n const adjLayerSet = new Set(layers[adjLayerIndex]);\n\n const barycenters = new Map<string, number>();\n\n for (let i = 0; i < layer.length; i++) {\n const nodeId = layer[i];\n\n // Get neighbor positions directly using node.order\n let sum = 0;\n let count = 0;\n\n if (direction === 'up') {\n const inEdgeIds = graph.inEdges.get(nodeId);\n if (inEdgeIds) {\n for (const eid of inEdgeIds) {\n const edge = graph.edges.get(eid);\n if (edge && adjLayerSet.has(edge.from)) {\n const neighbor = graph.nodes.get(edge.from);\n if (neighbor) {\n sum += neighbor.order;\n count++;\n }\n }\n }\n }\n } else {\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const eid of outEdgeIds) {\n const edge = graph.edges.get(eid);\n if (edge && adjLayerSet.has(edge.to)) {\n const neighbor = graph.nodes.get(edge.to);\n if (neighbor) {\n sum += neighbor.order;\n count++;\n }\n }\n }\n }\n }\n\n barycenters.set(nodeId, count > 0 ? sum / count : i);\n }\n\n layer.sort((a, b) => barycenters.get(a)! - barycenters.get(b)!);\n\n for (let i = 0; i < layer.length; i++) {\n const node = graph.nodes.get(layer[i]);\n if (node) node.order = i;\n }\n}\n\nfunction transposeImprove(graph: Graph, layers: string[][], layerIndex: number): void {\n const layer = layers[layerIndex];\n if (layer.length <= 1) return;\n\n let improved = true;\n let passes = 0;\n\n while (improved && passes < 2) {\n improved = false;\n passes++;\n for (let i = 0; i < layer.length - 1; i++) {\n const nodeA = layer[i];\n const nodeB = layer[i + 1];\n\n const crossingsBefore = countPairCrossings(graph, layers, layerIndex, nodeA, nodeB);\n\n // Swap in-place\n layer[i] = nodeB;\n layer[i + 1] = nodeA;\n const nA = graph.nodes.get(nodeA);\n const nB = graph.nodes.get(nodeB);\n if (nA) nA.order = i + 1;\n if (nB) nB.order = i;\n\n const crossingsAfter = countPairCrossings(graph, layers, layerIndex, nodeB, nodeA);\n\n if (crossingsAfter < crossingsBefore) {\n improved = true;\n } else {\n // Revert\n layer[i] = nodeA;\n layer[i + 1] = nodeB;\n if (nA) nA.order = i;\n if (nB) nB.order = i + 1;\n }\n }\n }\n}\n\n/**\n * Count crossings involving a specific pair of adjacent nodes using node.order directly.\n */\nfunction countPairCrossings(\n graph: Graph,\n layers: string[][],\n layerIndex: number,\n nodeA: string,\n nodeB: string\n): number {\n let crossings = 0;\n\n // Check with upper layer\n if (layerIndex > 0) {\n const upperLayer = new Set(layers[layerIndex - 1]);\n\n const predsA: number[] = [];\n const predsB: number[] = [];\n\n const inA = graph.inEdges.get(nodeA);\n if (inA) {\n for (const eid of inA) {\n const edge = graph.edges.get(eid);\n if (edge && upperLayer.has(edge.from)) {\n const n = graph.nodes.get(edge.from);\n if (n) predsA.push(n.order);\n }\n }\n }\n\n const inB = graph.inEdges.get(nodeB);\n if (inB) {\n for (const eid of inB) {\n const edge = graph.edges.get(eid);\n if (edge && upperLayer.has(edge.from)) {\n const n = graph.nodes.get(edge.from);\n if (n) predsB.push(n.order);\n }\n }\n }\n\n for (const pA of predsA) {\n for (const pB of predsB) {\n if (pA > pB) crossings++;\n }\n }\n }\n\n // Check with lower layer\n if (layerIndex < layers.length - 1) {\n const lowerLayer = new Set(layers[layerIndex + 1]);\n\n const succsA: number[] = [];\n const succsB: number[] = [];\n\n const outA = graph.outEdges.get(nodeA);\n if (outA) {\n for (const eid of outA) {\n const edge = graph.edges.get(eid);\n if (edge && lowerLayer.has(edge.to)) {\n const n = graph.nodes.get(edge.to);\n if (n) succsA.push(n.order);\n }\n }\n }\n\n const outB = graph.outEdges.get(nodeB);\n if (outB) {\n for (const eid of outB) {\n const edge = graph.edges.get(eid);\n if (edge && lowerLayer.has(edge.to)) {\n const n = graph.nodes.get(edge.to);\n if (n) succsB.push(n.order);\n }\n }\n }\n\n for (const sA of succsA) {\n for (const sB of succsB) {\n if (sA > sB) crossings++;\n }\n }\n }\n\n return crossings;\n}\n\nexport function countAllCrossings(graph: Graph, layers: string[][]): number {\n let total = 0;\n for (let l = 0; l < layers.length - 1; l++) {\n total += countLayerCrossings(graph, layers[l], layers[l + 1]);\n }\n return total;\n}\n\n/**\n * Count crossings between two adjacent layers using merge-sort based\n * inversion counting. O(E log V) instead of O(E^2).\n */\nfunction countLayerCrossings(\n graph: Graph,\n upperLayer: string[],\n lowerLayer: string[]\n): number {\n const lowerPos = new Map<string, number>();\n lowerLayer.forEach((id, pos) => lowerPos.set(id, pos));\n\n // Collect edge endpoint pairs sorted by upper position\n const edgePairs: [number, number][] = [];\n for (let uPos = 0; uPos < upperLayer.length; uPos++) {\n const nodeId = upperLayer[uPos];\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (!outEdgeIds) continue;\n for (const eid of outEdgeIds) {\n const edge = graph.edges.get(eid);\n if (!edge) continue;\n const lp = lowerPos.get(edge.to);\n if (lp !== undefined) {\n edgePairs.push([uPos, lp]);\n }\n }\n }\n\n if (edgePairs.length <= 1) return 0;\n\n // Sort by upper position, then by lower\n edgePairs.sort((a, b) => a[0] - b[0] || a[1] - b[1]);\n\n // Count inversions in the lower positions\n const lowerPositions = edgePairs.map(e => e[1]);\n return mergeSortCount(lowerPositions);\n}\n\nfunction mergeSortCount(arr: number[]): number {\n if (arr.length <= 1) return 0;\n\n const mid = arr.length >> 1;\n const left = arr.slice(0, mid);\n const right = arr.slice(mid);\n\n let count = mergeSortCount(left) + mergeSortCount(right);\n\n let i = 0, j = 0, k = 0;\n while (i < left.length && j < right.length) {\n if (left[i] <= right[j]) {\n arr[k++] = left[i++];\n } else {\n count += left.length - i;\n arr[k++] = right[j++];\n }\n }\n\n while (i < left.length) arr[k++] = left[i++];\n while (j < right.length) arr[k++] = right[j++];\n\n return count;\n}\n","import { Graph } from '../graph';\nimport { LayoutDirection, ResolvedOptions } from '../types';\n\n/**\n * Assign x,y coordinates to all nodes using a median-based iterative approach.\n */\nexport function assignCoordinates(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions\n): void {\n const isHorizontal = options.direction === 'LR' || options.direction === 'RL';\n const isReversed = options.direction === 'BT' || options.direction === 'RL';\n\n assignRankPositions(graph, layers, options, isHorizontal, isReversed);\n assignOrderPositions(graph, layers, options, isHorizontal);\n optimizePositions(graph, layers, options, isHorizontal);\n}\n\n/**\n * Assign positions along the rank axis (y for TB/BT, x for LR/RL).\n */\nfunction assignRankPositions(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n isHorizontal: boolean,\n isReversed: boolean\n): void {\n // Compute layer sizes (max node size in rank direction)\n const layerSizes: number[] = [];\n for (const layer of layers) {\n let maxSize = 0;\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const size = isHorizontal ? node.width : node.height;\n maxSize = Math.max(maxSize, size);\n }\n layerSizes.push(maxSize);\n }\n\n // Compute cumulative positions\n const layerPositions: number[] = [];\n let pos = 0;\n for (let l = 0; l < layers.length; l++) {\n layerPositions.push(pos);\n pos += layerSizes[l] + options.layerSpacing;\n }\n\n // If reversed, flip positions\n if (isReversed) {\n const totalSize = pos - options.layerSpacing;\n for (let l = 0; l < layerPositions.length; l++) {\n layerPositions[l] = totalSize - layerPositions[l] - layerSizes[l];\n }\n }\n\n // Assign positions\n for (let l = 0; l < layers.length; l++) {\n for (const nodeId of layers[l]) {\n const node = graph.nodes.get(nodeId)!;\n const nodeSize = isHorizontal ? node.width : node.height;\n const offset = (layerSizes[l] - nodeSize) / 2;\n\n if (isHorizontal) {\n node.x = layerPositions[l] + offset;\n } else {\n node.y = layerPositions[l] + offset;\n }\n }\n }\n}\n\n/**\n * Assign positions along the order axis (x for TB/BT, y for LR/RL).\n * Initial even spacing, centered.\n */\nfunction assignOrderPositions(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n isHorizontal: boolean\n): void {\n for (const layer of layers) {\n let pos = 0;\n\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const size = isHorizontal ? node.height : node.width;\n\n if (isHorizontal) {\n node.y = pos;\n } else {\n node.x = pos;\n }\n\n pos += size + options.nodeSpacing;\n }\n\n // Center the layer\n const totalSize = pos - options.nodeSpacing;\n const centerOffset = -totalSize / 2;\n\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n if (isHorizontal) {\n node.y += centerOffset;\n } else {\n node.x += centerOffset;\n }\n }\n }\n}\n\n/**\n * Iteratively optimize positions by aligning nodes with their connected neighbors.\n */\nfunction optimizePositions(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n isHorizontal: boolean\n): void {\n for (let iter = 0; iter < options.coordinateOptimizationIterations; iter++) {\n // Down sweep\n for (let l = 0; l < layers.length; l++) {\n optimizeLayer(graph, layers[l], options, isHorizontal);\n }\n\n // Up sweep\n for (let l = layers.length - 1; l >= 0; l--) {\n optimizeLayer(graph, layers[l], options, isHorizontal);\n }\n }\n\n centerAllLayers(graph, layers, isHorizontal);\n}\n\nfunction optimizeLayer(\n graph: Graph,\n layer: string[],\n options: ResolvedOptions,\n isHorizontal: boolean\n): void {\n if (layer.length === 0) return;\n\n // Compute desired positions\n const desired = new Map<string, number>();\n\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const connected = [...graph.predecessors(nodeId), ...graph.successors(nodeId)];\n\n if (connected.length === 0) {\n desired.set(nodeId, getOrderPos(node, isHorizontal));\n continue;\n }\n\n // Median of connected nodes' center positions\n const positions = connected\n .map(cId => {\n const c = graph.nodes.get(cId)!;\n return getOrderPos(c, isHorizontal) + getOrderSize(c, isHorizontal) / 2;\n })\n .sort((a, b) => a - b);\n\n const nodeSize = getOrderSize(node, isHorizontal);\n const median = positions.length % 2 === 0\n ? (positions[positions.length / 2 - 1] + positions[positions.length / 2]) / 2\n : positions[Math.floor(positions.length / 2)];\n\n desired.set(nodeId, median - nodeSize / 2);\n }\n\n // Forward pass: apply desired positions with spacing constraints\n for (let i = 0; i < layer.length; i++) {\n const nodeId = layer[i];\n const node = graph.nodes.get(nodeId)!;\n let desiredPos = desired.get(nodeId)!;\n\n if (i > 0) {\n const prevId = layer[i - 1];\n const prev = graph.nodes.get(prevId)!;\n const prevEnd = getOrderPos(prev, isHorizontal) + getOrderSize(prev, isHorizontal);\n desiredPos = Math.max(desiredPos, prevEnd + options.nodeSpacing);\n }\n\n setOrderPos(node, isHorizontal, desiredPos);\n }\n\n // Backward pass: fix overlaps from right\n for (let i = layer.length - 2; i >= 0; i--) {\n const nodeId = layer[i];\n const node = graph.nodes.get(nodeId)!;\n const nextId = layer[i + 1];\n const next = graph.nodes.get(nextId)!;\n\n const nodeEnd = getOrderPos(node, isHorizontal) + getOrderSize(node, isHorizontal);\n const nextStart = getOrderPos(next, isHorizontal);\n\n if (nodeEnd + options.nodeSpacing > nextStart) {\n setOrderPos(node, isHorizontal, nextStart - options.nodeSpacing - getOrderSize(node, isHorizontal));\n }\n }\n}\n\nfunction centerAllLayers(\n graph: Graph,\n layers: string[][],\n isHorizontal: boolean\n): void {\n if (layers.length === 0) return;\n\n // Find global bounds\n let globalMin = Infinity;\n let globalMax = -Infinity;\n\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const pos = getOrderPos(node, isHorizontal);\n const size = getOrderSize(node, isHorizontal);\n globalMin = Math.min(globalMin, pos);\n globalMax = Math.max(globalMax, pos + size);\n }\n }\n\n // Shift everything so the layout starts at 0\n const offset = -globalMin;\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n setOrderPos(node, isHorizontal, getOrderPos(node, isHorizontal) + offset);\n }\n }\n\n // Also shift rank positions to start at 0\n let rankMin = Infinity;\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const pos = isHorizontal ? node.x : node.y;\n rankMin = Math.min(rankMin, pos);\n }\n }\n\n if (rankMin !== 0) {\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n if (isHorizontal) {\n node.x -= rankMin;\n } else {\n node.y -= rankMin;\n }\n }\n }\n }\n}\n\nfunction getOrderPos(node: { x: number; y: number }, isHorizontal: boolean): number {\n return isHorizontal ? node.y : node.x;\n}\n\nfunction setOrderPos(node: { x: number; y: number }, isHorizontal: boolean, value: number): void {\n if (isHorizontal) {\n node.y = value;\n } else {\n node.x = value;\n }\n}\n\nfunction getOrderSize(node: { width: number; height: number }, isHorizontal: boolean): number {\n return isHorizontal ? node.height : node.width;\n}\n","import { Graph, getHandlePosition, getHandleDirection } from '../graph';\nimport { Point, HandleSide, LayoutDirection } from '../types';\n\nexport interface RoutedEdge {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n points: Point[];\n}\n\n/**\n * Route all edges with orthogonal paths.\n * Reconstructs original edges from dummy node chains.\n */\nexport function routeEdges(\n graph: Graph,\n direction: LayoutDirection,\n edgeMargin: number\n): RoutedEdge[] {\n const chains = collectEdgeChains(graph);\n const routes: RoutedEdge[] = [];\n\n for (const chain of chains) {\n routes.push(routeChain(graph, chain, direction, edgeMargin));\n }\n\n return routes;\n}\n\ninterface EdgeChain {\n originalId: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n dummyNodes: string[];\n reversed: boolean;\n}\n\nfunction collectEdgeChains(graph: Graph): EdgeChain[] {\n const chains: EdgeChain[] = [];\n const visited = new Set<string>();\n\n for (const [edgeId, edge] of graph.edges) {\n if (visited.has(edgeId)) continue;\n\n const fromNode = graph.nodes.get(edge.from);\n if (!fromNode || fromNode.isDummy) continue;\n\n const dummyNodes: string[] = [];\n let currentEdge = edge;\n visited.add(edgeId);\n\n // Follow through dummy nodes\n while (true) {\n const toNode = graph.nodes.get(currentEdge.to);\n if (!toNode || !toNode.isDummy) break;\n\n dummyNodes.push(currentEdge.to);\n\n const outEdgeIds = graph.outEdges.get(currentEdge.to);\n if (!outEdgeIds || outEdgeIds.size === 0) break;\n\n // Find the edge with matching originalId\n let nextEdge = null;\n for (const eid of outEdgeIds) {\n const e = graph.edges.get(eid);\n if (e && e.originalId === edge.originalId) {\n nextEdge = e;\n visited.add(eid);\n break;\n }\n }\n\n if (!nextEdge) {\n // Fallback: take any outgoing edge\n const eid = outEdgeIds.values().next().value;\n if (!eid) break;\n nextEdge = graph.edges.get(eid);\n if (!nextEdge) break;\n visited.add(eid);\n }\n\n currentEdge = nextEdge;\n }\n\n chains.push({\n originalId: edge.originalId,\n from: edge.from,\n to: currentEdge.to,\n fromHandle: edge.fromHandle,\n toHandle: currentEdge.toHandle,\n dummyNodes,\n reversed: edge.reversed,\n });\n }\n\n return chains;\n}\n\nfunction routeChain(\n graph: Graph,\n chain: EdgeChain,\n direction: LayoutDirection,\n margin: number\n): RoutedEdge {\n const fromNode = graph.nodes.get(chain.from)!;\n const toNode = graph.nodes.get(chain.to)!;\n\n // Determine actual from/to based on reversal\n const actualFrom = chain.reversed ? chain.to : chain.from;\n const actualTo = chain.reversed ? chain.from : chain.to;\n const actualFromHandle = chain.reversed ? chain.toHandle : chain.fromHandle;\n const actualToHandle = chain.reversed ? chain.fromHandle : chain.toHandle;\n\n const sourceNode = chain.reversed ? toNode : fromNode;\n const targetNode = chain.reversed ? fromNode : toNode;\n\n const sourcePos = getHandlePosition(sourceNode, actualFromHandle);\n const targetPos = getHandlePosition(targetNode, actualToHandle);\n\n const sourceHandle = sourceNode.handles.find(h => h.id === actualFromHandle);\n const targetHandle = targetNode.handles.find(h => h.id === actualToHandle);\n\n const sourceSide = sourceHandle?.position || getDefaultSourceSide(direction);\n const targetSide = targetHandle?.position || getDefaultTargetSide(direction);\n\n // Build waypoints\n const rawPoints: Point[] = [];\n\n // Source handle\n rawPoints.push(sourcePos);\n\n // Exit point\n const exitDir = getHandleDirection(sourceSide);\n rawPoints.push({\n x: sourcePos.x + exitDir.x * margin,\n y: sourcePos.y + exitDir.y * margin,\n });\n\n // Dummy node positions (in correct order based on reversal)\n const dummies = chain.reversed ? [...chain.dummyNodes].reverse() : chain.dummyNodes;\n for (const dummyId of dummies) {\n const dummy = graph.nodes.get(dummyId)!;\n rawPoints.push({ x: dummy.x, y: dummy.y });\n }\n\n // Entry point\n const entryDir = getHandleDirection(targetSide);\n rawPoints.push({\n x: targetPos.x + entryDir.x * margin,\n y: targetPos.y + entryDir.y * margin,\n });\n\n // Target handle\n rawPoints.push(targetPos);\n\n // Make orthogonal\n const points = makeOrthogonal(rawPoints, direction);\n\n return {\n id: chain.originalId,\n from: actualFrom,\n to: actualTo,\n fromHandle: actualFromHandle,\n toHandle: actualToHandle,\n points,\n };\n}\n\n/**\n * Insert bends to make the path orthogonal (only horizontal/vertical segments).\n */\nfunction makeOrthogonal(points: Point[], direction: LayoutDirection): Point[] {\n if (points.length < 2) return points;\n\n const result: Point[] = [points[0]];\n const isVerticalFlow = direction === 'TB' || direction === 'BT';\n\n for (let i = 1; i < points.length; i++) {\n const prev = result[result.length - 1];\n const curr = points[i];\n\n const dx = Math.abs(prev.x - curr.x);\n const dy = Math.abs(prev.y - curr.y);\n\n // If already aligned, just add the point\n if (dx < 0.01 || dy < 0.01) {\n result.push(curr);\n continue;\n }\n\n // Need a bend\n if (isVerticalFlow) {\n // Prefer vertical-then-horizontal routing\n const midY = (prev.y + curr.y) / 2;\n result.push({ x: prev.x, y: midY });\n result.push({ x: curr.x, y: midY });\n } else {\n // Prefer horizontal-then-vertical routing\n const midX = (prev.x + curr.x) / 2;\n result.push({ x: midX, y: prev.y });\n result.push({ x: midX, y: curr.y });\n }\n\n result.push(curr);\n }\n\n return cleanupPoints(result);\n}\n\n/**\n * Remove redundant collinear points.\n */\nfunction cleanupPoints(points: Point[]): Point[] {\n if (points.length <= 2) return points;\n\n const result: Point[] = [points[0]];\n\n for (let i = 1; i < points.length - 1; i++) {\n const prev = result[result.length - 1];\n const curr = points[i];\n const next = points[i + 1];\n\n // Skip if collinear\n const sameX = Math.abs(prev.x - curr.x) < 0.01 && Math.abs(curr.x - next.x) < 0.01;\n const sameY = Math.abs(prev.y - curr.y) < 0.01 && Math.abs(curr.y - next.y) < 0.01;\n\n if (!sameX && !sameY) {\n result.push(curr);\n } else if (sameX || sameY) {\n // Collinear - skip this point\n continue;\n } else {\n result.push(curr);\n }\n }\n\n result.push(points[points.length - 1]);\n return result;\n}\n\nfunction getDefaultSourceSide(direction: LayoutDirection): HandleSide {\n switch (direction) {\n case 'TB': return 'bottom';\n case 'BT': return 'top';\n case 'LR': return 'right';\n case 'RL': return 'left';\n }\n}\n\nfunction getDefaultTargetSide(direction: LayoutDirection): HandleSide {\n switch (direction) {\n case 'TB': return 'top';\n case 'BT': return 'bottom';\n case 'LR': return 'left';\n case 'RL': return 'right';\n }\n}\n","import { LayoutInput, LayoutOptions, LayoutResult, NodeOutput, EdgeOutput, HandleOutput, resolveOptions, ResolvedOptions } from './types';\nimport { Graph, buildGraph, getHandlePosition } from './graph';\nimport { breakCycles } from './algorithms/cycle-breaking';\nimport { assignLayers, insertDummyNodes } from './algorithms/layer-assignment';\nimport { minimizeCrossings } from './algorithms/crossing-minimization';\nimport { assignCoordinates } from './algorithms/coordinate-assignment';\nimport { routeEdges } from './algorithms/edge-routing';\n\n/**\n * Compute a complete layout for the given graph.\n * This is the main entry point for one-shot layout computation.\n */\nexport function layout(input: LayoutInput, options?: LayoutOptions): LayoutResult {\n const resolved = resolveOptions(options);\n const graph = buildGraph(input.nodes, input.edges);\n return computeLayout(graph, resolved);\n}\n\n/**\n * Internal layout computation on an already-built graph.\n */\nexport function computeLayout(graph: Graph, options: ResolvedOptions): LayoutResult {\n if (graph.nodes.size === 0) {\n return { nodes: [], edges: [] };\n }\n\n // Phase 1: Break cycles\n breakCycles(graph);\n\n // Phase 2: Assign layers\n let layers = assignLayers(graph);\n\n // Phase 3: Insert dummy nodes for long edges\n layers = insertDummyNodes(graph, layers);\n\n // Phase 4: Minimize crossings\n layers = minimizeCrossings(graph, layers, options.crossingMinimizationIterations);\n\n // Phase 5: Assign coordinates\n assignCoordinates(graph, layers, options);\n\n // Phase 6: Route edges\n const routedEdges = routeEdges(graph, options.direction, options.edgeMargin);\n\n // Build output (exclude dummy nodes)\n return buildResult(graph, routedEdges);\n}\n\nfunction buildResult(graph: Graph, routedEdges: { id: string; from: string; to: string; fromHandle: string; toHandle: string; points: { x: number; y: number }[] }[]): LayoutResult {\n const nodes: NodeOutput[] = [];\n const edges: EdgeOutput[] = [];\n\n for (const [, node] of graph.nodes) {\n if (node.isDummy) continue;\n\n const handles: HandleOutput[] = node.handles.map(h => {\n const pos = getHandlePosition(node, h.id);\n return {\n id: h.id,\n type: h.type,\n position: h.position,\n x: pos.x,\n y: pos.y,\n };\n });\n\n nodes.push({\n id: node.id,\n x: node.x,\n y: node.y,\n width: node.width,\n height: node.height,\n handles,\n });\n }\n\n for (const route of routedEdges) {\n edges.push({\n id: route.id,\n from: route.from,\n to: route.to,\n fromHandle: route.fromHandle,\n toHandle: route.toHandle,\n points: route.points,\n });\n }\n\n return { nodes, edges };\n}\n","import { LayoutInput, LayoutOptions, LayoutResult, NodeInput, EdgeInput, resolveOptions, ResolvedOptions } from './types';\nimport { Graph, buildGraph, getHandlePosition } from './graph';\nimport { breakCycles } from './algorithms/cycle-breaking';\nimport { assignLayers, insertDummyNodes } from './algorithms/layer-assignment';\nimport { minimizeCrossings } from './algorithms/crossing-minimization';\nimport { assignCoordinates } from './algorithms/coordinate-assignment';\nimport { routeEdges } from './algorithms/edge-routing';\nimport { computeLayout } from './layout';\n\n/**\n * Incremental layout engine.\n * Maintains layout state and supports adding/removing nodes\n * without full recomputation.\n */\nexport class IncrementalLayout {\n private options: ResolvedOptions;\n private inputNodes: Map<string, NodeInput> = new Map();\n private inputEdges: Map<string, EdgeInput> = new Map();\n private lastResult: LayoutResult | null = null;\n private nodePositions: Map<string, { x: number; y: number }> = new Map();\n\n constructor(options?: LayoutOptions) {\n this.options = resolveOptions(options);\n }\n\n /**\n * Set the full graph and compute a complete layout.\n */\n setGraph(input: LayoutInput): LayoutResult {\n this.inputNodes.clear();\n this.inputEdges.clear();\n\n for (const node of input.nodes) {\n this.inputNodes.set(node.id, node);\n }\n for (const edge of input.edges) {\n this.inputEdges.set(edge.id, edge);\n }\n\n return this.recompute();\n }\n\n /**\n * Add nodes and edges incrementally.\n * Attempts to minimize layout changes for existing nodes.\n */\n addNodes(nodes: NodeInput[], edges?: EdgeInput[]): LayoutResult {\n for (const node of nodes) {\n this.inputNodes.set(node.id, node);\n }\n if (edges) {\n for (const edge of edges) {\n this.inputEdges.set(edge.id, edge);\n }\n }\n\n return this.recomputeIncremental(\n new Set(nodes.map(n => n.id)),\n new Set(edges?.map(e => e.id) || [])\n );\n }\n\n /**\n * Remove nodes (and their connected edges) from the layout.\n */\n removeNodes(nodeIds: string[]): LayoutResult {\n const removedSet = new Set(nodeIds);\n\n for (const id of nodeIds) {\n this.inputNodes.delete(id);\n }\n\n // Remove edges connected to removed nodes\n for (const [edgeId, edge] of this.inputEdges) {\n if (removedSet.has(edge.from) || removedSet.has(edge.to)) {\n this.inputEdges.delete(edgeId);\n }\n }\n\n // Remove from position cache\n for (const id of nodeIds) {\n this.nodePositions.delete(id);\n }\n\n return this.recompute();\n }\n\n /**\n * Add edges between existing nodes.\n */\n addEdges(edges: EdgeInput[]): LayoutResult {\n for (const edge of edges) {\n this.inputEdges.set(edge.id, edge);\n }\n return this.recomputeIncremental(\n new Set<string>(),\n new Set(edges.map(e => e.id))\n );\n }\n\n /**\n * Remove edges from the layout.\n */\n removeEdges(edgeIds: string[]): LayoutResult {\n for (const id of edgeIds) {\n this.inputEdges.delete(id);\n }\n return this.recompute();\n }\n\n /**\n * Get the current layout result.\n */\n getResult(): LayoutResult | null {\n return this.lastResult;\n }\n\n private recompute(): LayoutResult {\n const input: LayoutInput = {\n nodes: [...this.inputNodes.values()],\n edges: [...this.inputEdges.values()],\n };\n\n const graph = buildGraph(input.nodes, input.edges);\n this.lastResult = computeLayout(graph, this.options);\n\n // Cache positions for future incremental updates\n this.cachePositions();\n\n return this.lastResult;\n }\n\n private recomputeIncremental(\n newNodeIds: Set<string>,\n newEdgeIds: Set<string>\n ): LayoutResult {\n const input: LayoutInput = {\n nodes: [...this.inputNodes.values()],\n edges: [...this.inputEdges.values()],\n };\n\n const graph = buildGraph(input.nodes, input.edges);\n\n // Phase 1: Break cycles\n breakCycles(graph);\n\n // Phase 2: Assign layers\n let layers = assignLayers(graph);\n\n // Phase 3: Insert dummy nodes\n layers = insertDummyNodes(graph, layers);\n\n // Phase 4: Minimize crossings (full, but starting from hints)\n layers = minimizeCrossings(graph, layers, this.options.crossingMinimizationIterations);\n\n // Phase 5: Assign coordinates\n assignCoordinates(graph, layers, this.options);\n\n // Phase 6: Apply position stability for existing nodes\n this.applyStability(graph, newNodeIds);\n\n // Phase 7: Route edges\n const routedEdges = routeEdges(graph, this.options.direction, this.options.edgeMargin);\n\n // Build result\n this.lastResult = this.buildResult(graph, routedEdges);\n this.cachePositions();\n\n return this.lastResult;\n }\n\n /**\n * Apply stability: blend new positions with old positions for existing nodes.\n * This reduces visual disruption when adding new nodes.\n */\n private applyStability(graph: Graph, newNodeIds: Set<string>): void {\n if (this.nodePositions.size === 0) return;\n\n const STABILITY_WEIGHT = 0.3; // 30% old position, 70% new\n\n for (const [nodeId, node] of graph.nodes) {\n if (node.isDummy || newNodeIds.has(nodeId)) continue;\n\n const oldPos = this.nodePositions.get(nodeId);\n if (!oldPos) continue;\n\n // Blend positions\n node.x = node.x * (1 - STABILITY_WEIGHT) + oldPos.x * STABILITY_WEIGHT;\n node.y = node.y * (1 - STABILITY_WEIGHT) + oldPos.y * STABILITY_WEIGHT;\n }\n }\n\n private cachePositions(): void {\n if (!this.lastResult) return;\n this.nodePositions.clear();\n for (const node of this.lastResult.nodes) {\n this.nodePositions.set(node.id, { x: node.x, y: node.y });\n }\n }\n\n private buildResult(\n graph: Graph,\n routedEdges: { id: string; from: string; to: string; fromHandle: string; toHandle: string; points: { x: number; y: number }[] }[]\n ): LayoutResult {\n const nodes: LayoutResult['nodes'] = [];\n const edges: LayoutResult['edges'] = [];\n\n for (const [, node] of graph.nodes) {\n if (node.isDummy) continue;\n\n const handles = node.handles.map(h => {\n const pos = getHandlePosition(node, h.id);\n return {\n id: h.id,\n type: h.type,\n position: h.position,\n x: pos.x,\n y: pos.y,\n };\n });\n\n nodes.push({\n id: node.id,\n x: node.x,\n y: node.y,\n width: node.width,\n height: node.height,\n handles,\n });\n }\n\n for (const route of routedEdges) {\n edges.push({\n id: route.id,\n from: route.from,\n to: route.to,\n fromHandle: route.fromHandle,\n toHandle: route.toHandle,\n points: route.points,\n });\n }\n\n return { nodes, edges };\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/graph.ts","../src/algorithms/cycle-breaking.ts","../src/algorithms/layer-assignment.ts","../src/algorithms/crossing-minimization.ts","../src/algorithms/coordinate-assignment.ts","../src/algorithms/value-placement.ts","../src/algorithms/edge-routing.ts","../src/algorithms/component-packing.ts","../src/proposals.ts","../src/layout.ts","../src/incremental.ts","../src/debug.ts"],"sourcesContent":["export { layout } from './layout';\nexport { IncrementalLayout } from './incremental';\nexport { countAllCrossings } from './algorithms/crossing-minimization';\nexport { printLayout } from './debug';\n\nexport type {\n HandleSide,\n HandleType,\n LayoutDirection,\n EdgeKind,\n EdgeWeights,\n Point,\n HandleInput,\n NodeInput,\n EdgeInput,\n LayoutInput,\n LayoutOptions,\n HandleOutput,\n NodeOutput,\n EdgeOutput,\n LayoutResult,\n LayoutProposal,\n RotateProposal,\n ProposalCallback,\n} from './types';\n\nexport { rotateHandles } from './proposals';\n","/** Position on a node where a handle can be placed */\nexport type HandleSide = 'top' | 'right' | 'bottom' | 'left';\n\n/** Handle type - input receives connections, output sends connections */\nexport type HandleType = 'input' | 'output';\n\n/** Layout direction. 'TB' or 'LR' are the supported strict reading axes. */\nexport type LayoutDirection = 'TB' | 'LR' | 'BT' | 'RL';\n\n/**\n * Edge kind drives the layout weight:\n * - `control`: full strength; defines the execution rail (layer count).\n * - `data`: light weight; values are pulled onto the same layer as their consumer\n * instead of extending the rail.\n */\nexport type EdgeKind = 'control' | 'data';\n\n/** A 2D point */\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Handle definition on a node */\nexport interface HandleInput {\n id: string;\n type: HandleType;\n position: HandleSide;\n /** Position along the side (0 = start, 1 = end). Default: 0.5 */\n offset?: number;\n}\n\n/** Node input definition */\nexport interface NodeInput {\n id: string;\n width: number;\n height: number;\n handles: HandleInput[];\n /** Parent node id for compound (nested) layouts. */\n parentId?: string;\n}\n\n/** Edge input definition */\nexport interface EdgeInput {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n /** Default: 'control' */\n kind?: EdgeKind;\n /** Explicit weight override. Defaults: 1 (control), 0.25 (data). */\n weight?: number;\n}\n\n/** Complete layout input */\nexport interface LayoutInput {\n nodes: NodeInput[];\n edges: EdgeInput[];\n}\n\n/** Per-kind default weight overrides. */\nexport interface EdgeWeights {\n control?: number;\n data?: number;\n}\n\n/**\n * A proposal the layout engine emits to the calling application during a pass.\n * The app inspects it and decides whether to accept it, modify it, or reject it\n * by returning either the (possibly tweaked) proposed node or `null`/`undefined`\n * to keep the original.\n */\nexport interface RotateProposal {\n type: 'rotate';\n /** The node being analyzed. */\n nodeId: string;\n /** Same node as provided in the input. */\n current: NodeInput;\n /** The engine's proposed version after rotating handles. */\n proposed: NodeInput;\n /** Rotation in degrees (CW = positive). */\n rotation: 90 | -90 | 180;\n /** Reason this proposal was emitted (handle layout mismatches direction, etc.). */\n reason: string;\n}\n\nexport type LayoutProposal = RotateProposal;\n\nexport type ProposalCallback = (proposal: LayoutProposal) => NodeInput | null | undefined | void;\n\n/** Layout configuration options */\nexport interface LayoutOptions {\n /** Layout direction. Default: 'TB' */\n direction?: LayoutDirection;\n /** Minimum spacing between nodes in the same layer. Default: 40 */\n nodeSpacing?: number;\n /** Minimum spacing between layers. Default: 60 */\n layerSpacing?: number;\n /** Number of iterations for crossing minimization. Default: 24 */\n crossingMinimizationIterations?: number;\n /** Number of iterations for coordinate optimization. Default: 8 */\n coordinateOptimizationIterations?: number;\n /** Margin for edge routing (distance from node before turning). Default: 20 */\n edgeMargin?: number;\n /** Override default per-kind weights. */\n edgeWeights?: EdgeWeights;\n /** When true, disjoint components are packed side-by-side. Default: true */\n packComponents?: boolean;\n /** Padding around compound (parent) bounding boxes. Default: 24 */\n compoundPadding?: number;\n /**\n * Called once per node when the engine thinks a rotation of the node's\n * handles would suit the chosen direction better. Return the (possibly\n * tweaked) proposed node to accept, or `null`/nothing to keep the original.\n */\n onProposal?: ProposalCallback;\n}\n\n/** Resolved options with all defaults applied */\nexport interface ResolvedOptions {\n direction: LayoutDirection;\n nodeSpacing: number;\n layerSpacing: number;\n crossingMinimizationIterations: number;\n coordinateOptimizationIterations: number;\n edgeMargin: number;\n controlWeight: number;\n dataWeight: number;\n packComponents: boolean;\n compoundPadding: number;\n onProposal?: ProposalCallback;\n}\n\nexport function resolveOptions(options?: LayoutOptions): ResolvedOptions {\n return {\n direction: options?.direction ?? 'TB',\n nodeSpacing: options?.nodeSpacing ?? 40,\n layerSpacing: options?.layerSpacing ?? 60,\n crossingMinimizationIterations: options?.crossingMinimizationIterations ?? 24,\n coordinateOptimizationIterations: options?.coordinateOptimizationIterations ?? 8,\n edgeMargin: options?.edgeMargin ?? 20,\n controlWeight: options?.edgeWeights?.control ?? 1,\n dataWeight: options?.edgeWeights?.data ?? 0.25,\n packComponents: options?.packComponents ?? true,\n compoundPadding: options?.compoundPadding ?? 24,\n onProposal: options?.onProposal,\n };\n}\n\n/** Positioned handle in the output */\nexport interface HandleOutput {\n id: string;\n type: HandleType;\n position: HandleSide;\n x: number;\n y: number;\n}\n\n/** Positioned node in the output */\nexport interface NodeOutput {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n handles: HandleOutput[];\n /** Echoed back so consumers can reconstruct the hierarchy. */\n parentId?: string;\n}\n\n/** Routed edge in the output */\nexport interface EdgeOutput {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n points: Point[];\n kind: EdgeKind;\n}\n\n/** Complete layout result */\nexport interface LayoutResult {\n nodes: NodeOutput[];\n edges: EdgeOutput[];\n}\n","import { HandleInput, HandleSide, NodeInput, EdgeInput, Point, EdgeKind } from './types';\n\nexport interface InternalNode {\n id: string;\n width: number;\n height: number;\n handles: HandleInput[];\n isDummy: boolean;\n layer: number;\n order: number;\n x: number;\n y: number;\n parentId?: string;\n /** True if this node represents a compound (its size was computed from children). */\n isCompound: boolean;\n /** True when the node has no control edges and only participates in data edges. */\n isValue: boolean;\n}\n\nexport interface InternalEdge {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n reversed: boolean;\n originalId: string;\n kind: EdgeKind;\n weight: number;\n}\n\nexport class Graph {\n nodes: Map<string, InternalNode> = new Map();\n edges: Map<string, InternalEdge> = new Map();\n outEdges: Map<string, Set<string>> = new Map();\n inEdges: Map<string, Set<string>> = new Map();\n\n addNode(node: InternalNode): void {\n this.nodes.set(node.id, node);\n if (!this.outEdges.has(node.id)) this.outEdges.set(node.id, new Set());\n if (!this.inEdges.has(node.id)) this.inEdges.set(node.id, new Set());\n }\n\n addEdge(edge: InternalEdge): void {\n this.edges.set(edge.id, edge);\n if (!this.outEdges.has(edge.from)) this.outEdges.set(edge.from, new Set());\n if (!this.inEdges.has(edge.to)) this.inEdges.set(edge.to, new Set());\n this.outEdges.get(edge.from)!.add(edge.id);\n this.inEdges.get(edge.to)!.add(edge.id);\n }\n\n removeEdge(edgeId: string): void {\n const edge = this.edges.get(edgeId);\n if (!edge) return;\n this.outEdges.get(edge.from)?.delete(edgeId);\n this.inEdges.get(edge.to)?.delete(edgeId);\n this.edges.delete(edgeId);\n }\n\n removeNode(nodeId: string): void {\n const outEdgeIds = [...(this.outEdges.get(nodeId) || [])];\n const inEdgeIds = [...(this.inEdges.get(nodeId) || [])];\n for (const eid of outEdgeIds) this.removeEdge(eid);\n for (const eid of inEdgeIds) this.removeEdge(eid);\n this.nodes.delete(nodeId);\n this.outEdges.delete(nodeId);\n this.inEdges.delete(nodeId);\n }\n\n predecessors(nodeId: string): string[] {\n const result: string[] = [];\n const inEdgeIds = this.inEdges.get(nodeId);\n if (inEdgeIds) {\n for (const eid of inEdgeIds) {\n const edge = this.edges.get(eid);\n if (edge) result.push(edge.from);\n }\n }\n return result;\n }\n\n successors(nodeId: string): string[] {\n const result: string[] = [];\n const outEdgeIds = this.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const eid of outEdgeIds) {\n const edge = this.edges.get(eid);\n if (edge) result.push(edge.to);\n }\n }\n return result;\n }\n}\n\nexport interface BuildGraphContext {\n controlWeight: number;\n dataWeight: number;\n}\n\nexport function buildGraph(\n nodes: NodeInput[],\n edges: EdgeInput[],\n ctx: BuildGraphContext = { controlWeight: 1, dataWeight: 0.25 }\n): Graph {\n const graph = new Graph();\n\n for (const node of nodes) {\n graph.addNode({\n id: node.id,\n width: node.width,\n height: node.height,\n handles: node.handles.map(h => ({ ...h, offset: h.offset ?? 0.5 })),\n isDummy: false,\n layer: -1,\n order: -1,\n x: 0,\n y: 0,\n parentId: node.parentId,\n isCompound: false,\n isValue: false,\n });\n }\n\n for (const edge of edges) {\n const kind: EdgeKind = edge.kind ?? 'control';\n const defaultWeight = kind === 'control' ? ctx.controlWeight : ctx.dataWeight;\n graph.addEdge({\n id: edge.id,\n from: edge.from,\n to: edge.to,\n fromHandle: edge.fromHandle,\n toHandle: edge.toHandle,\n reversed: false,\n originalId: edge.id,\n kind,\n weight: edge.weight ?? defaultWeight,\n });\n }\n\n // A node is a \"value\" if every incident edge is data.\n // Floating values (no incoming edges + only data outgoing) and pure data sinks\n // both qualify — they should be pulled toward their consumer's layer\n // rather than extending the control rail.\n for (const [nodeId, node] of graph.nodes) {\n const ins = graph.inEdges.get(nodeId);\n const outs = graph.outEdges.get(nodeId);\n let hasControl = false;\n if (ins) {\n for (const eid of ins) {\n if (graph.edges.get(eid)?.kind === 'control') { hasControl = true; break; }\n }\n }\n if (!hasControl && outs) {\n for (const eid of outs) {\n if (graph.edges.get(eid)?.kind === 'control') { hasControl = true; break; }\n }\n }\n const incidentCount = (ins?.size ?? 0) + (outs?.size ?? 0);\n node.isValue = !hasControl && incidentCount > 0;\n }\n\n return graph;\n}\n\n/** Compute the absolute position of a handle on a positioned node */\nexport function getHandlePosition(node: InternalNode, handleId: string): Point {\n const handle = node.handles.find(h => h.id === handleId);\n if (!handle) {\n return { x: node.x + node.width / 2, y: node.y + node.height / 2 };\n }\n\n const offset = handle.offset ?? 0.5;\n\n switch (handle.position) {\n case 'top':\n return { x: node.x + offset * node.width, y: node.y };\n case 'bottom':\n return { x: node.x + offset * node.width, y: node.y + node.height };\n case 'left':\n return { x: node.x, y: node.y + offset * node.height };\n case 'right':\n return { x: node.x + node.width, y: node.y + offset * node.height };\n }\n}\n\n/** Get the direction vector for exiting/entering a handle */\nexport function getHandleDirection(side: HandleSide): Point {\n switch (side) {\n case 'top': return { x: 0, y: -1 };\n case 'bottom': return { x: 0, y: 1 };\n case 'left': return { x: -1, y: 0 };\n case 'right': return { x: 1, y: 0 };\n }\n}\n","import { Graph } from '../graph';\n\n/**\n * Break cycles in the graph using DFS-based back edge detection.\n * Reverses back edges to make the graph a DAG.\n * Returns the set of reversed edge IDs.\n */\nexport function breakCycles(graph: Graph): Set<string> {\n const WHITE = 0, GRAY = 1, BLACK = 2;\n const state = new Map<string, number>();\n const reversed = new Set<string>();\n\n for (const nodeId of graph.nodes.keys()) {\n state.set(nodeId, WHITE);\n }\n\n // Process nodes with more outgoing than incoming edges first\n const nodeIds = [...graph.nodes.keys()].sort((a, b) => {\n const aDiff = (graph.outEdges.get(a)?.size || 0) - (graph.inEdges.get(a)?.size || 0);\n const bDiff = (graph.outEdges.get(b)?.size || 0) - (graph.inEdges.get(b)?.size || 0);\n return bDiff - aDiff;\n });\n\n function dfs(nodeId: string): void {\n state.set(nodeId, GRAY);\n\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const edgeId of outEdgeIds) {\n const edge = graph.edges.get(edgeId);\n if (!edge) continue;\n\n const targetState = state.get(edge.to);\n if (targetState === GRAY) {\n reversed.add(edgeId);\n } else if (targetState === WHITE) {\n dfs(edge.to);\n }\n }\n }\n\n state.set(nodeId, BLACK);\n }\n\n for (const nodeId of nodeIds) {\n if (state.get(nodeId) === WHITE) {\n dfs(nodeId);\n }\n }\n\n // Reverse the back edges in the graph\n for (const edgeId of reversed) {\n const edge = graph.edges.get(edgeId);\n if (!edge) continue;\n\n graph.removeEdge(edgeId);\n graph.addEdge({\n ...edge,\n from: edge.to,\n to: edge.from,\n fromHandle: edge.toHandle,\n toHandle: edge.fromHandle,\n reversed: !edge.reversed,\n });\n }\n\n return reversed;\n}\n","import { Graph } from '../graph';\n\n/**\n * Two-pass layer assignment:\n *\n * Pass A (control rail): longest-path on the subgraph induced by control\n * edges between non-value nodes. This defines the canonical execution\n * timeline — value nodes do not extend it.\n *\n * Pass B (value pull): each value node is assigned the median layer of its\n * non-value neighbors. This snaps floating constants/imports onto the same\n * layer as the consumer that needs them, where they can be packed laterally.\n */\nexport function assignLayers(graph: Graph): string[][] {\n const layers = new Map<string, number>();\n const visiting = new Set<string>();\n\n // ----- Pass A: control rail -----\n function controlLayer(nodeId: string): number {\n if (layers.has(nodeId)) return layers.get(nodeId)!;\n if (visiting.has(nodeId)) return 0;\n\n const node = graph.nodes.get(nodeId);\n if (!node || node.isValue) return -1;\n\n visiting.add(nodeId);\n\n const inEdgeIds = graph.inEdges.get(nodeId);\n let maxPredLayer = -1;\n if (inEdgeIds) {\n for (const eid of inEdgeIds) {\n const edge = graph.edges.get(eid);\n if (!edge || edge.kind !== 'control') continue;\n const pred = graph.nodes.get(edge.from);\n if (!pred || pred.isValue) continue;\n maxPredLayer = Math.max(maxPredLayer, controlLayer(edge.from));\n }\n }\n\n const layer = maxPredLayer + 1;\n layers.set(nodeId, layer);\n node.layer = layer;\n visiting.delete(nodeId);\n return layer;\n }\n\n for (const [nodeId, node] of graph.nodes) {\n if (!node.isValue) controlLayer(nodeId);\n }\n\n // ----- Pass B: value pull -----\n for (const [nodeId, node] of graph.nodes) {\n if (!node.isValue) continue;\n\n const neighborLayers: number[] = [];\n\n const inEdgeIds = graph.inEdges.get(nodeId);\n if (inEdgeIds) {\n for (const eid of inEdgeIds) {\n const edge = graph.edges.get(eid);\n if (!edge) continue;\n const nbr = graph.nodes.get(edge.from);\n if (nbr && !nbr.isValue && layers.has(edge.from)) {\n neighborLayers.push(layers.get(edge.from)!);\n }\n }\n }\n\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const eid of outEdgeIds) {\n const edge = graph.edges.get(eid);\n if (!edge) continue;\n const nbr = graph.nodes.get(edge.to);\n if (nbr && !nbr.isValue && layers.has(edge.to)) {\n neighborLayers.push(layers.get(edge.to)!);\n }\n }\n }\n\n let layer: number;\n if (neighborLayers.length > 0) {\n neighborLayers.sort((a, b) => a - b);\n layer = neighborLayers[Math.floor(neighborLayers.length / 2)];\n } else {\n layer = 0;\n }\n layers.set(nodeId, layer);\n node.layer = layer;\n }\n\n // Catch-all: isolated nodes go on layer 0.\n for (const [nodeId, node] of graph.nodes) {\n if (!layers.has(nodeId)) {\n layers.set(nodeId, 0);\n node.layer = 0;\n }\n }\n\n // Normalize so the smallest layer is 0.\n let minLayer = Infinity;\n let maxLayer = -Infinity;\n for (const l of layers.values()) {\n if (l < minLayer) minLayer = l;\n if (l > maxLayer) maxLayer = l;\n }\n if (!isFinite(minLayer)) return [];\n if (minLayer !== 0) {\n for (const [id, l] of layers) {\n const adj = l - minLayer;\n layers.set(id, adj);\n const n = graph.nodes.get(id);\n if (n) n.layer = adj;\n }\n maxLayer -= minLayer;\n }\n\n const layersArray: string[][] = Array.from({ length: maxLayer + 1 }, () => []);\n for (const [nodeId, layer] of layers) {\n layersArray[layer].push(nodeId);\n }\n\n return layersArray;\n}\n\n/**\n * Insert dummy nodes only for control edges that span multiple layers.\n * Data edges keep their layer-span; routing handles them directly because\n * they're typically short and decorative.\n */\nexport function insertDummyNodes(graph: Graph, layers: string[][]): string[][] {\n let dummyCounter = 0;\n const edgesToProcess = [...graph.edges.values()];\n\n for (const edge of edgesToProcess) {\n if (edge.kind !== 'control') continue;\n\n const fromNode = graph.nodes.get(edge.from);\n const toNode = graph.nodes.get(edge.to);\n if (!fromNode || !toNode) continue;\n\n const fromLayer = fromNode.layer;\n const toLayer = toNode.layer;\n const span = toLayer - fromLayer;\n\n if (span <= 1) continue;\n\n graph.removeEdge(edge.id);\n\n let prevNodeId = edge.from;\n let prevHandleId = edge.fromHandle;\n\n for (let l = fromLayer + 1; l < toLayer; l++) {\n const dummyId = `__dummy_${dummyCounter++}`;\n\n graph.addNode({\n id: dummyId,\n width: 0,\n height: 0,\n handles: [\n { id: 'in', type: 'input', position: 'top', offset: 0.5 },\n { id: 'out', type: 'output', position: 'bottom', offset: 0.5 },\n ],\n isDummy: true,\n layer: l,\n order: -1,\n x: 0,\n y: 0,\n isCompound: false,\n isValue: false,\n });\n\n layers[l].push(dummyId);\n\n graph.addEdge({\n id: `__dedge_${dummyCounter}_${l}_in`,\n from: prevNodeId,\n to: dummyId,\n fromHandle: prevHandleId,\n toHandle: 'in',\n reversed: edge.reversed,\n originalId: edge.originalId,\n kind: edge.kind,\n weight: edge.weight,\n });\n\n prevNodeId = dummyId;\n prevHandleId = 'out';\n }\n\n graph.addEdge({\n id: `__dedge_${dummyCounter}_final`,\n from: prevNodeId,\n to: edge.to,\n fromHandle: prevHandleId,\n toHandle: edge.toHandle,\n reversed: edge.reversed,\n originalId: edge.originalId,\n kind: edge.kind,\n weight: edge.weight,\n });\n }\n\n return layers;\n}\n","import { Graph } from '../graph';\n\n/**\n * Minimize edge crossings using barycenter heuristic with transpose improvement.\n */\nexport function minimizeCrossings(\n graph: Graph,\n layers: string[][],\n iterations: number\n): string[][] {\n if (layers.length <= 1) return layers;\n\n const totalNodes = layers.reduce((s, l) => s + l.length, 0);\n\n // Adaptive: reduce iterations for large graphs\n const effectiveIter = totalNodes > 500\n ? Math.min(iterations, 6)\n : totalNodes > 200\n ? Math.min(iterations, 12)\n : iterations;\n\n // Skip transpose for very large layers\n const skipTranspose = totalNodes > 800;\n\n // Initialize node orders\n for (let l = 0; l < layers.length; l++) {\n for (let i = 0; i < layers[l].length; i++) {\n const node = graph.nodes.get(layers[l][i]);\n if (node) node.order = i;\n }\n }\n\n let bestLayers = layers.map(l => [...l]);\n let bestCrossings = countAllCrossings(graph, layers);\n let noImprovementCount = 0;\n\n for (let iter = 0; iter < effectiveIter; iter++) {\n // Down sweep\n for (let l = 1; l < layers.length; l++) {\n orderByBarycenter(graph, layers, l, 'up');\n }\n\n // Up sweep\n for (let l = layers.length - 2; l >= 0; l--) {\n orderByBarycenter(graph, layers, l, 'down');\n }\n\n // Transpose improvement\n if (!skipTranspose) {\n for (let l = 0; l < layers.length; l++) {\n if (layers[l].length <= 100) {\n transposeImprove(graph, layers, l);\n }\n }\n }\n\n const crossings = countAllCrossings(graph, layers);\n if (crossings < bestCrossings) {\n bestCrossings = crossings;\n bestLayers = layers.map(l => [...l]);\n noImprovementCount = 0;\n } else {\n noImprovementCount++;\n }\n\n if (crossings === 0 || noImprovementCount >= 3) break;\n }\n\n // Restore best ordering\n for (let l = 0; l < layers.length; l++) {\n layers[l] = bestLayers[l];\n for (let i = 0; i < layers[l].length; i++) {\n const node = graph.nodes.get(layers[l][i]);\n if (node) node.order = i;\n }\n }\n\n return layers;\n}\n\nfunction orderByBarycenter(\n graph: Graph,\n layers: string[][],\n layerIndex: number,\n direction: 'up' | 'down'\n): void {\n const layer = layers[layerIndex];\n const adjLayerIndex = direction === 'up' ? layerIndex - 1 : layerIndex + 1;\n\n if (adjLayerIndex < 0 || adjLayerIndex >= layers.length) return;\n\n // Build position lookup for adjacent layer using node.order\n const adjLayerSet = new Set(layers[adjLayerIndex]);\n\n const barycenters = new Map<string, number>();\n\n for (let i = 0; i < layer.length; i++) {\n const nodeId = layer[i];\n\n // Get neighbor positions directly using node.order\n let sum = 0;\n let count = 0;\n\n if (direction === 'up') {\n const inEdgeIds = graph.inEdges.get(nodeId);\n if (inEdgeIds) {\n for (const eid of inEdgeIds) {\n const edge = graph.edges.get(eid);\n if (edge && adjLayerSet.has(edge.from)) {\n const neighbor = graph.nodes.get(edge.from);\n if (neighbor) {\n sum += neighbor.order;\n count++;\n }\n }\n }\n }\n } else {\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (outEdgeIds) {\n for (const eid of outEdgeIds) {\n const edge = graph.edges.get(eid);\n if (edge && adjLayerSet.has(edge.to)) {\n const neighbor = graph.nodes.get(edge.to);\n if (neighbor) {\n sum += neighbor.order;\n count++;\n }\n }\n }\n }\n }\n\n barycenters.set(nodeId, count > 0 ? sum / count : i);\n }\n\n layer.sort((a, b) => barycenters.get(a)! - barycenters.get(b)!);\n\n for (let i = 0; i < layer.length; i++) {\n const node = graph.nodes.get(layer[i]);\n if (node) node.order = i;\n }\n}\n\nfunction transposeImprove(graph: Graph, layers: string[][], layerIndex: number): void {\n const layer = layers[layerIndex];\n if (layer.length <= 1) return;\n\n let improved = true;\n let passes = 0;\n\n while (improved && passes < 2) {\n improved = false;\n passes++;\n for (let i = 0; i < layer.length - 1; i++) {\n const nodeA = layer[i];\n const nodeB = layer[i + 1];\n\n const crossingsBefore = countPairCrossings(graph, layers, layerIndex, nodeA, nodeB);\n\n // Swap in-place\n layer[i] = nodeB;\n layer[i + 1] = nodeA;\n const nA = graph.nodes.get(nodeA);\n const nB = graph.nodes.get(nodeB);\n if (nA) nA.order = i + 1;\n if (nB) nB.order = i;\n\n const crossingsAfter = countPairCrossings(graph, layers, layerIndex, nodeB, nodeA);\n\n if (crossingsAfter < crossingsBefore) {\n improved = true;\n } else {\n // Revert\n layer[i] = nodeA;\n layer[i + 1] = nodeB;\n if (nA) nA.order = i;\n if (nB) nB.order = i + 1;\n }\n }\n }\n}\n\n/**\n * Count crossings involving a specific pair of adjacent nodes using node.order directly.\n */\nfunction countPairCrossings(\n graph: Graph,\n layers: string[][],\n layerIndex: number,\n nodeA: string,\n nodeB: string\n): number {\n let crossings = 0;\n\n // Check with upper layer\n if (layerIndex > 0) {\n const upperLayer = new Set(layers[layerIndex - 1]);\n\n const predsA: number[] = [];\n const predsB: number[] = [];\n\n const inA = graph.inEdges.get(nodeA);\n if (inA) {\n for (const eid of inA) {\n const edge = graph.edges.get(eid);\n if (edge && upperLayer.has(edge.from)) {\n const n = graph.nodes.get(edge.from);\n if (n) predsA.push(n.order);\n }\n }\n }\n\n const inB = graph.inEdges.get(nodeB);\n if (inB) {\n for (const eid of inB) {\n const edge = graph.edges.get(eid);\n if (edge && upperLayer.has(edge.from)) {\n const n = graph.nodes.get(edge.from);\n if (n) predsB.push(n.order);\n }\n }\n }\n\n for (const pA of predsA) {\n for (const pB of predsB) {\n if (pA > pB) crossings++;\n }\n }\n }\n\n // Check with lower layer\n if (layerIndex < layers.length - 1) {\n const lowerLayer = new Set(layers[layerIndex + 1]);\n\n const succsA: number[] = [];\n const succsB: number[] = [];\n\n const outA = graph.outEdges.get(nodeA);\n if (outA) {\n for (const eid of outA) {\n const edge = graph.edges.get(eid);\n if (edge && lowerLayer.has(edge.to)) {\n const n = graph.nodes.get(edge.to);\n if (n) succsA.push(n.order);\n }\n }\n }\n\n const outB = graph.outEdges.get(nodeB);\n if (outB) {\n for (const eid of outB) {\n const edge = graph.edges.get(eid);\n if (edge && lowerLayer.has(edge.to)) {\n const n = graph.nodes.get(edge.to);\n if (n) succsB.push(n.order);\n }\n }\n }\n\n for (const sA of succsA) {\n for (const sB of succsB) {\n if (sA > sB) crossings++;\n }\n }\n }\n\n return crossings;\n}\n\nexport function countAllCrossings(graph: Graph, layers: string[][]): number {\n let total = 0;\n for (let l = 0; l < layers.length - 1; l++) {\n total += countLayerCrossings(graph, layers[l], layers[l + 1]);\n }\n return total;\n}\n\n/**\n * Count crossings between two adjacent layers using merge-sort based\n * inversion counting. O(E log V) instead of O(E^2).\n */\nfunction countLayerCrossings(\n graph: Graph,\n upperLayer: string[],\n lowerLayer: string[]\n): number {\n const lowerPos = new Map<string, number>();\n lowerLayer.forEach((id, pos) => lowerPos.set(id, pos));\n\n // Collect edge endpoint pairs sorted by upper position\n const edgePairs: [number, number][] = [];\n for (let uPos = 0; uPos < upperLayer.length; uPos++) {\n const nodeId = upperLayer[uPos];\n const outEdgeIds = graph.outEdges.get(nodeId);\n if (!outEdgeIds) continue;\n for (const eid of outEdgeIds) {\n const edge = graph.edges.get(eid);\n if (!edge) continue;\n const lp = lowerPos.get(edge.to);\n if (lp !== undefined) {\n edgePairs.push([uPos, lp]);\n }\n }\n }\n\n if (edgePairs.length <= 1) return 0;\n\n // Sort by upper position, then by lower\n edgePairs.sort((a, b) => a[0] - b[0] || a[1] - b[1]);\n\n // Count inversions in the lower positions\n const lowerPositions = edgePairs.map(e => e[1]);\n return mergeSortCount(lowerPositions);\n}\n\nfunction mergeSortCount(arr: number[]): number {\n if (arr.length <= 1) return 0;\n\n const mid = arr.length >> 1;\n const left = arr.slice(0, mid);\n const right = arr.slice(mid);\n\n let count = mergeSortCount(left) + mergeSortCount(right);\n\n let i = 0, j = 0, k = 0;\n while (i < left.length && j < right.length) {\n if (left[i] <= right[j]) {\n arr[k++] = left[i++];\n } else {\n count += left.length - i;\n arr[k++] = right[j++];\n }\n }\n\n while (i < left.length) arr[k++] = left[i++];\n while (j < right.length) arr[k++] = right[j++];\n\n return count;\n}\n","import { Graph } from '../graph';\nimport { LayoutDirection, ResolvedOptions } from '../types';\n\n/**\n * Assign x,y coordinates to all nodes using a median-based iterative approach.\n */\nexport function assignCoordinates(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions\n): void {\n const isHorizontal = options.direction === 'LR' || options.direction === 'RL';\n const isReversed = options.direction === 'BT' || options.direction === 'RL';\n\n assignRankPositions(graph, layers, options, isHorizontal, isReversed);\n assignOrderPositions(graph, layers, options, isHorizontal);\n optimizePositions(graph, layers, options, isHorizontal);\n}\n\n/**\n * Assign positions along the rank axis (y for TB/BT, x for LR/RL).\n */\nfunction assignRankPositions(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n isHorizontal: boolean,\n isReversed: boolean\n): void {\n // Compute layer sizes (max node size in rank direction)\n const layerSizes: number[] = [];\n for (const layer of layers) {\n let maxSize = 0;\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const size = isHorizontal ? node.width : node.height;\n maxSize = Math.max(maxSize, size);\n }\n layerSizes.push(maxSize);\n }\n\n // Compute cumulative positions\n const layerPositions: number[] = [];\n let pos = 0;\n for (let l = 0; l < layers.length; l++) {\n layerPositions.push(pos);\n pos += layerSizes[l] + options.layerSpacing;\n }\n\n // If reversed, flip positions\n if (isReversed) {\n const totalSize = pos - options.layerSpacing;\n for (let l = 0; l < layerPositions.length; l++) {\n layerPositions[l] = totalSize - layerPositions[l] - layerSizes[l];\n }\n }\n\n // Assign positions\n for (let l = 0; l < layers.length; l++) {\n for (const nodeId of layers[l]) {\n const node = graph.nodes.get(nodeId)!;\n const nodeSize = isHorizontal ? node.width : node.height;\n const offset = (layerSizes[l] - nodeSize) / 2;\n\n if (isHorizontal) {\n node.x = layerPositions[l] + offset;\n } else {\n node.y = layerPositions[l] + offset;\n }\n }\n }\n}\n\n/**\n * Assign positions along the order axis (x for TB/BT, y for LR/RL).\n * Initial even spacing, centered.\n */\nfunction assignOrderPositions(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n isHorizontal: boolean\n): void {\n for (const layer of layers) {\n let pos = 0;\n\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const size = isHorizontal ? node.height : node.width;\n\n if (isHorizontal) {\n node.y = pos;\n } else {\n node.x = pos;\n }\n\n pos += size + options.nodeSpacing;\n }\n\n // Center the layer\n const totalSize = pos - options.nodeSpacing;\n const centerOffset = -totalSize / 2;\n\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n if (isHorizontal) {\n node.y += centerOffset;\n } else {\n node.x += centerOffset;\n }\n }\n }\n}\n\n/**\n * Iteratively optimize positions by aligning nodes with their connected neighbors.\n */\nfunction optimizePositions(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n isHorizontal: boolean\n): void {\n for (let iter = 0; iter < options.coordinateOptimizationIterations; iter++) {\n // Down sweep\n for (let l = 0; l < layers.length; l++) {\n optimizeLayer(graph, layers[l], options, isHorizontal);\n }\n\n // Up sweep\n for (let l = layers.length - 1; l >= 0; l--) {\n optimizeLayer(graph, layers[l], options, isHorizontal);\n }\n }\n\n centerAllLayers(graph, layers, isHorizontal);\n}\n\nfunction optimizeLayer(\n graph: Graph,\n layer: string[],\n options: ResolvedOptions,\n isHorizontal: boolean\n): void {\n if (layer.length === 0) return;\n\n // Compute desired positions\n const desired = new Map<string, number>();\n\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const connected = [...graph.predecessors(nodeId), ...graph.successors(nodeId)];\n\n if (connected.length === 0) {\n desired.set(nodeId, getOrderPos(node, isHorizontal));\n continue;\n }\n\n // Median of connected nodes' center positions\n const positions = connected\n .map(cId => {\n const c = graph.nodes.get(cId)!;\n return getOrderPos(c, isHorizontal) + getOrderSize(c, isHorizontal) / 2;\n })\n .sort((a, b) => a - b);\n\n const nodeSize = getOrderSize(node, isHorizontal);\n const median = positions.length % 2 === 0\n ? (positions[positions.length / 2 - 1] + positions[positions.length / 2]) / 2\n : positions[Math.floor(positions.length / 2)];\n\n desired.set(nodeId, median - nodeSize / 2);\n }\n\n // Forward pass: apply desired positions with spacing constraints\n for (let i = 0; i < layer.length; i++) {\n const nodeId = layer[i];\n const node = graph.nodes.get(nodeId)!;\n let desiredPos = desired.get(nodeId)!;\n\n if (i > 0) {\n const prevId = layer[i - 1];\n const prev = graph.nodes.get(prevId)!;\n const prevEnd = getOrderPos(prev, isHorizontal) + getOrderSize(prev, isHorizontal);\n desiredPos = Math.max(desiredPos, prevEnd + options.nodeSpacing);\n }\n\n setOrderPos(node, isHorizontal, desiredPos);\n }\n\n // Backward pass: fix overlaps from right\n for (let i = layer.length - 2; i >= 0; i--) {\n const nodeId = layer[i];\n const node = graph.nodes.get(nodeId)!;\n const nextId = layer[i + 1];\n const next = graph.nodes.get(nextId)!;\n\n const nodeEnd = getOrderPos(node, isHorizontal) + getOrderSize(node, isHorizontal);\n const nextStart = getOrderPos(next, isHorizontal);\n\n if (nodeEnd + options.nodeSpacing > nextStart) {\n setOrderPos(node, isHorizontal, nextStart - options.nodeSpacing - getOrderSize(node, isHorizontal));\n }\n }\n}\n\nfunction centerAllLayers(\n graph: Graph,\n layers: string[][],\n isHorizontal: boolean\n): void {\n if (layers.length === 0) return;\n\n // Find global bounds\n let globalMin = Infinity;\n let globalMax = -Infinity;\n\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const pos = getOrderPos(node, isHorizontal);\n const size = getOrderSize(node, isHorizontal);\n globalMin = Math.min(globalMin, pos);\n globalMax = Math.max(globalMax, pos + size);\n }\n }\n\n // Shift everything so the layout starts at 0\n const offset = -globalMin;\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n setOrderPos(node, isHorizontal, getOrderPos(node, isHorizontal) + offset);\n }\n }\n\n // Also shift rank positions to start at 0\n let rankMin = Infinity;\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n const pos = isHorizontal ? node.x : node.y;\n rankMin = Math.min(rankMin, pos);\n }\n }\n\n if (rankMin !== 0) {\n for (const layer of layers) {\n for (const nodeId of layer) {\n const node = graph.nodes.get(nodeId)!;\n if (isHorizontal) {\n node.x -= rankMin;\n } else {\n node.y -= rankMin;\n }\n }\n }\n }\n}\n\nfunction getOrderPos(node: { x: number; y: number }, isHorizontal: boolean): number {\n return isHorizontal ? node.y : node.x;\n}\n\nfunction setOrderPos(node: { x: number; y: number }, isHorizontal: boolean, value: number): void {\n if (isHorizontal) {\n node.y = value;\n } else {\n node.x = value;\n }\n}\n\nfunction getOrderSize(node: { width: number; height: number }, isHorizontal: boolean): number {\n return isHorizontal ? node.height : node.width;\n}\n","import { Graph } from '../graph';\nimport { LayoutDirection, ResolvedOptions } from '../types';\n\n/**\n * Sidecar placement for value nodes.\n *\n * Values (nodes whose every incident edge is a data edge) are NOT laid out\n * alongside the control rail — they are attached as sidecars to the flanks of\n * their dominant consumer once the rail is finalized. This way:\n *\n * - the rail stays perfectly aligned (its layout is computed without values)\n * - values cluster around the node that actually uses them\n * - extra values don't widen/displace the rail\n *\n * In TB direction, sidecars sit at the consumer's vertical center, alternating\n * left/right. In LR direction, they sit at the consumer's horizontal center,\n * alternating top/bottom.\n */\nexport function placeValueSidecars(\n graph: Graph,\n layers: string[][],\n options: ResolvedOptions,\n): void {\n const isHorizontal = options.direction === 'LR' || options.direction === 'RL';\n\n // Identify all values and which consumer each belongs to.\n interface Attachment {\n valueId: string;\n consumerId: string;\n }\n const attachments: Attachment[] = [];\n const orphanValues: string[] = [];\n\n for (const [nodeId, node] of graph.nodes) {\n if (!node.isValue || node.isDummy) continue;\n\n const consumer = findDominantConsumer(graph, nodeId);\n if (consumer) {\n attachments.push({ valueId: nodeId, consumerId: consumer });\n } else {\n orphanValues.push(nodeId);\n }\n }\n\n // Group attachments by consumer.\n const byConsumer = new Map<string, string[]>();\n for (const { valueId, consumerId } of attachments) {\n const arr = byConsumer.get(consumerId) ?? [];\n arr.push(valueId);\n byConsumer.set(consumerId, arr);\n }\n\n // For each consumer, split its values into the two sides and place them.\n for (const [consumerId, vIds] of byConsumer) {\n const consumer = graph.nodes.get(consumerId);\n if (!consumer) continue;\n\n const { beforeSide, afterSide } = splitValuesBySide(graph, consumerId, vIds, isHorizontal);\n\n if (isHorizontal) {\n // LR/RL: 'before' = above the consumer (decreasing Y), 'after' = below.\n const cxCenter = consumer.x + consumer.width / 2;\n let topEdge = consumer.y;\n for (const vid of beforeSide) {\n const v = graph.nodes.get(vid);\n if (!v) continue;\n v.y = topEdge - options.nodeSpacing - v.height;\n v.x = cxCenter - v.width / 2;\n topEdge = v.y;\n }\n let bottomEdge = consumer.y + consumer.height;\n for (const vid of afterSide) {\n const v = graph.nodes.get(vid);\n if (!v) continue;\n v.y = bottomEdge + options.nodeSpacing;\n v.x = cxCenter - v.width / 2;\n bottomEdge = v.y + v.height;\n }\n } else {\n // TB/BT: 'before' = left of consumer (decreasing X), 'after' = right.\n const cyCenter = consumer.y + consumer.height / 2;\n let leftEdge = consumer.x;\n for (const vid of beforeSide) {\n const v = graph.nodes.get(vid);\n if (!v) continue;\n v.x = leftEdge - options.nodeSpacing - v.width;\n v.y = cyCenter - v.height / 2;\n leftEdge = v.x;\n }\n let rightEdge = consumer.x + consumer.width;\n for (const vid of afterSide) {\n const v = graph.nodes.get(vid);\n if (!v) continue;\n v.x = rightEdge + options.nodeSpacing;\n v.y = cyCenter - v.height / 2;\n rightEdge = v.x + v.width;\n }\n }\n }\n\n // Orphan values: no consumer found — place them in a stack at the layout origin.\n // Should be rare; mostly happens for truly isolated nodes.\n let orphanX = 0, orphanY = 0;\n for (const orphanId of orphanValues) {\n const v = graph.nodes.get(orphanId);\n if (!v) continue;\n v.x = orphanX;\n v.y = orphanY;\n if (isHorizontal) orphanX += v.width + options.nodeSpacing;\n else orphanY += v.height + options.nodeSpacing;\n }\n}\n\n/**\n * The \"dominant consumer\" of a value is the non-value neighbor with the most\n * edges connecting them. If multiple tie, pick by id for stability.\n */\nfunction findDominantConsumer(graph: Graph, valueId: string): string | null {\n const counts = new Map<string, number>();\n\n const outs = graph.outEdges.get(valueId);\n if (outs) {\n for (const eid of outs) {\n const edge = graph.edges.get(eid);\n if (!edge) continue;\n const other = graph.nodes.get(edge.to);\n if (other && !other.isValue && !other.isDummy) {\n counts.set(edge.to, (counts.get(edge.to) ?? 0) + 1);\n }\n }\n }\n const ins = graph.inEdges.get(valueId);\n if (ins) {\n for (const eid of ins) {\n const edge = graph.edges.get(eid);\n if (!edge) continue;\n const other = graph.nodes.get(edge.from);\n if (other && !other.isValue && !other.isDummy) {\n counts.set(edge.from, (counts.get(edge.from) ?? 0) + 1);\n }\n }\n }\n\n let bestId: string | null = null;\n let bestCount = -1;\n for (const [id, count] of counts) {\n if (count > bestCount || (count === bestCount && bestId !== null && id < bestId)) {\n bestId = id;\n bestCount = count;\n }\n }\n return bestId;\n}\n\n/**\n * Split values into the two sides of a consumer, using each value's connecting\n * handle as a hint:\n * - handle on the consumer's `left` (TB) / `top` (LR) → \"before\" side\n * - handle on the consumer's `right` (TB) / `bottom` (LR) → \"after\" side\n * - otherwise → balance the two sides\n *\n * Within each side, values are sorted by the handle offset so they stack in\n * a predictable order along the perpendicular axis.\n */\nfunction splitValuesBySide(\n graph: Graph,\n consumerId: string,\n valueIds: string[],\n isHorizontal: boolean,\n): { beforeSide: string[]; afterSide: string[] } {\n const consumer = graph.nodes.get(consumerId);\n if (!consumer) return { beforeSide: [...valueIds].sort(), afterSide: [] };\n\n type Slot = { id: string; side: 'before' | 'after' | 'neutral'; offset: number };\n const slots: Slot[] = [];\n\n for (const vId of valueIds) {\n let side: Slot['side'] = 'neutral';\n let offset = 0.5;\n\n const inspectHandle = (handleId: string | undefined) => {\n if (!handleId) return;\n const handle = consumer.handles.find(h => h.id === handleId);\n if (!handle) return;\n offset = handle.offset ?? 0.5;\n if (isHorizontal) {\n if (handle.position === 'top') side = 'before';\n else if (handle.position === 'bottom') side = 'after';\n } else {\n if (handle.position === 'left') side = 'before';\n else if (handle.position === 'right') side = 'after';\n }\n };\n\n // Find the edge between value and consumer, then look at the handle ON the consumer.\n const outs = graph.outEdges.get(vId);\n if (outs) for (const eid of outs) {\n const e = graph.edges.get(eid);\n if (e && e.to === consumerId) { inspectHandle(e.toHandle); break; }\n }\n if (side === 'neutral') {\n const ins = graph.inEdges.get(vId);\n if (ins) for (const eid of ins) {\n const e = graph.edges.get(eid);\n if (e && e.from === consumerId) { inspectHandle(e.fromHandle); break; }\n }\n }\n\n slots.push({ id: vId, side, offset });\n }\n\n const before = slots.filter(s => s.side === 'before');\n const after = slots.filter(s => s.side === 'after');\n const neutral = slots.filter(s => s.side === 'neutral');\n\n // Balance neutrals across the two sides for compactness.\n for (const n of neutral) {\n if (before.length <= after.length) before.push(n);\n else after.push(n);\n }\n\n // Sort each side: smaller offset first (so values stack predictably, closest\n // to the matching handle nearest to the consumer body).\n const cmp = (a: Slot, b: Slot) => (a.offset - b.offset) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);\n before.sort(cmp);\n after.sort(cmp);\n\n return {\n beforeSide: before.map(s => s.id),\n afterSide: after.map(s => s.id),\n };\n}\n\nexport function isValueLayer(layer: string[], graph: Graph): boolean {\n for (const id of layer) {\n const n = graph.nodes.get(id);\n if (n && !n.isValue && !n.isDummy) return false;\n }\n return true;\n}\n\n/** Filter layers to keep only non-value, non-dummy nodes per layer. */\nexport function railLayers(layers: string[][], graph: Graph): string[][] {\n return layers.map(layer =>\n layer.filter(id => {\n const n = graph.nodes.get(id);\n return n && !n.isValue;\n }),\n );\n}\n\nexport function getDirection(direction: LayoutDirection): { isHorizontal: boolean } {\n return { isHorizontal: direction === 'LR' || direction === 'RL' };\n}\n","import { Graph, getHandlePosition, getHandleDirection } from '../graph';\nimport { Point, HandleSide, LayoutDirection, EdgeKind } from '../types';\n\nexport interface RoutedEdge {\n id: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n points: Point[];\n kind: EdgeKind;\n}\n\n/**\n * Route all edges with orthogonal paths.\n * Reconstructs original edges from dummy node chains.\n */\nexport function routeEdges(\n graph: Graph,\n direction: LayoutDirection,\n edgeMargin: number\n): RoutedEdge[] {\n const chains = collectEdgeChains(graph);\n const routes: RoutedEdge[] = [];\n\n for (const chain of chains) {\n routes.push(routeChain(graph, chain, direction, edgeMargin));\n }\n\n return routes;\n}\n\ninterface EdgeChain {\n originalId: string;\n from: string;\n to: string;\n fromHandle: string;\n toHandle: string;\n dummyNodes: string[];\n reversed: boolean;\n kind: EdgeKind;\n}\n\nfunction collectEdgeChains(graph: Graph): EdgeChain[] {\n const chains: EdgeChain[] = [];\n const visited = new Set<string>();\n\n for (const [edgeId, edge] of graph.edges) {\n if (visited.has(edgeId)) continue;\n\n const fromNode = graph.nodes.get(edge.from);\n if (!fromNode || fromNode.isDummy) continue;\n\n const dummyNodes: string[] = [];\n let currentEdge = edge;\n visited.add(edgeId);\n\n while (true) {\n const toNode = graph.nodes.get(currentEdge.to);\n if (!toNode || !toNode.isDummy) break;\n\n dummyNodes.push(currentEdge.to);\n\n const outEdgeIds = graph.outEdges.get(currentEdge.to);\n if (!outEdgeIds || outEdgeIds.size === 0) break;\n\n let nextEdge = null;\n for (const eid of outEdgeIds) {\n const e = graph.edges.get(eid);\n if (e && e.originalId === edge.originalId) {\n nextEdge = e;\n visited.add(eid);\n break;\n }\n }\n\n if (!nextEdge) {\n const eid = outEdgeIds.values().next().value;\n if (!eid) break;\n nextEdge = graph.edges.get(eid);\n if (!nextEdge) break;\n visited.add(eid);\n }\n\n currentEdge = nextEdge;\n }\n\n chains.push({\n originalId: edge.originalId,\n from: edge.from,\n to: currentEdge.to,\n fromHandle: edge.fromHandle,\n toHandle: currentEdge.toHandle,\n dummyNodes,\n reversed: edge.reversed,\n kind: edge.kind,\n });\n }\n\n return chains;\n}\n\nfunction routeChain(\n graph: Graph,\n chain: EdgeChain,\n direction: LayoutDirection,\n margin: number\n): RoutedEdge {\n const fromNode = graph.nodes.get(chain.from)!;\n const toNode = graph.nodes.get(chain.to)!;\n\n const actualFrom = chain.reversed ? chain.to : chain.from;\n const actualTo = chain.reversed ? chain.from : chain.to;\n const actualFromHandle = chain.reversed ? chain.toHandle : chain.fromHandle;\n const actualToHandle = chain.reversed ? chain.fromHandle : chain.toHandle;\n\n const sourceNode = chain.reversed ? toNode : fromNode;\n const targetNode = chain.reversed ? fromNode : toNode;\n\n const sourcePos = getHandlePosition(sourceNode, actualFromHandle);\n const targetPos = getHandlePosition(targetNode, actualToHandle);\n\n const sourceHandle = sourceNode.handles.find(h => h.id === actualFromHandle);\n const targetHandle = targetNode.handles.find(h => h.id === actualToHandle);\n\n const sourceSide = sourceHandle?.position || getDefaultSourceSide(direction);\n const targetSide = targetHandle?.position || getDefaultTargetSide(direction);\n\n const rawPoints: Point[] = [];\n\n rawPoints.push(sourcePos);\n\n const exitDir = getHandleDirection(sourceSide);\n rawPoints.push({\n x: sourcePos.x + exitDir.x * margin,\n y: sourcePos.y + exitDir.y * margin,\n });\n\n const dummies = chain.reversed ? [...chain.dummyNodes].reverse() : chain.dummyNodes;\n for (const dummyId of dummies) {\n const dummy = graph.nodes.get(dummyId)!;\n rawPoints.push({ x: dummy.x, y: dummy.y });\n }\n\n const entryDir = getHandleDirection(targetSide);\n rawPoints.push({\n x: targetPos.x + entryDir.x * margin,\n y: targetPos.y + entryDir.y * margin,\n });\n\n rawPoints.push(targetPos);\n\n const points = makeOrthogonal(rawPoints, direction);\n\n return {\n id: chain.originalId,\n from: actualFrom,\n to: actualTo,\n fromHandle: actualFromHandle,\n toHandle: actualToHandle,\n points,\n kind: chain.kind,\n };\n}\n\nfunction makeOrthogonal(points: Point[], direction: LayoutDirection): Point[] {\n if (points.length < 2) return points;\n\n const result: Point[] = [points[0]];\n const isVerticalFlow = direction === 'TB' || direction === 'BT';\n\n for (let i = 1; i < points.length; i++) {\n const prev = result[result.length - 1];\n const curr = points[i];\n\n const dx = Math.abs(prev.x - curr.x);\n const dy = Math.abs(prev.y - curr.y);\n\n if (dx < 0.01 || dy < 0.01) {\n result.push(curr);\n continue;\n }\n\n if (isVerticalFlow) {\n const midY = (prev.y + curr.y) / 2;\n result.push({ x: prev.x, y: midY });\n result.push({ x: curr.x, y: midY });\n } else {\n const midX = (prev.x + curr.x) / 2;\n result.push({ x: midX, y: prev.y });\n result.push({ x: midX, y: curr.y });\n }\n\n result.push(curr);\n }\n\n return cleanupPoints(result);\n}\n\nfunction cleanupPoints(points: Point[]): Point[] {\n if (points.length <= 2) return points;\n\n const result: Point[] = [points[0]];\n\n for (let i = 1; i < points.length - 1; i++) {\n const prev = result[result.length - 1];\n const curr = points[i];\n const next = points[i + 1];\n\n const sameX = Math.abs(prev.x - curr.x) < 0.01 && Math.abs(curr.x - next.x) < 0.01;\n const sameY = Math.abs(prev.y - curr.y) < 0.01 && Math.abs(curr.y - next.y) < 0.01;\n\n if (!sameX && !sameY) {\n result.push(curr);\n } else if (sameX || sameY) {\n continue;\n } else {\n result.push(curr);\n }\n }\n\n result.push(points[points.length - 1]);\n return result;\n}\n\nfunction getDefaultSourceSide(direction: LayoutDirection): HandleSide {\n switch (direction) {\n case 'TB': return 'bottom';\n case 'BT': return 'top';\n case 'LR': return 'right';\n case 'RL': return 'left';\n }\n}\n\nfunction getDefaultTargetSide(direction: LayoutDirection): HandleSide {\n switch (direction) {\n case 'TB': return 'top';\n case 'BT': return 'bottom';\n case 'LR': return 'left';\n case 'RL': return 'right';\n }\n}\n","import { EdgeOutput, NodeOutput, ResolvedOptions } from '../types';\n\n/**\n * Pack disjoint connected components side-by-side (in the order axis) so the\n * overall layout is roughly square instead of a long ribbon.\n *\n * Compound parents are kept as atomic groups: children move with their parent.\n */\nexport function packComponents(\n nodes: NodeOutput[],\n edges: EdgeOutput[],\n options: ResolvedOptions,\n): void {\n if (nodes.length === 0) return;\n\n // Walk the parentId chain to find the top-level ancestor of every node.\n const idToNode = new Map<string, NodeOutput>();\n for (const n of nodes) idToNode.set(n.id, n);\n const rootOf = new Map<string, string>();\n function topAncestor(id: string): string {\n if (rootOf.has(id)) return rootOf.get(id)!;\n const n = idToNode.get(id);\n if (!n || !n.parentId || !idToNode.has(n.parentId)) {\n rootOf.set(id, id);\n return id;\n }\n const r = topAncestor(n.parentId);\n rootOf.set(id, r);\n return r;\n }\n for (const n of nodes) topAncestor(n.id);\n\n // Union-find by edge connectivity, but only over top-level ancestors so\n // children of a single compound stay with the compound.\n const parent = new Map<string, string>();\n function find(x: string): string {\n let cur = x;\n while (parent.get(cur) !== cur) {\n const p = parent.get(cur)!;\n parent.set(cur, parent.get(p)!);\n cur = parent.get(cur)!;\n }\n return cur;\n }\n function union(a: string, b: string): void {\n const ra = find(a);\n const rb = find(b);\n if (ra !== rb) parent.set(ra, rb);\n }\n for (const n of nodes) parent.set(topAncestor(n.id), topAncestor(n.id));\n for (const e of edges) {\n const ra = topAncestor(e.from);\n const rb = topAncestor(e.to);\n if (idToNode.has(ra) && idToNode.has(rb)) union(ra, rb);\n }\n\n // Group every node (including children) by its component's representative.\n const groups = new Map<string, NodeOutput[]>();\n for (const n of nodes) {\n const root = topAncestor(n.id);\n const comp = find(root);\n const arr = groups.get(comp) ?? [];\n arr.push(n);\n groups.set(comp, arr);\n }\n\n if (groups.size <= 1) return;\n\n const isHorizontal = options.direction === 'LR' || options.direction === 'RL';\n\n // Build per-component bounding boxes (including their edge bend points).\n const edgesByComp = new Map<string, EdgeOutput[]>();\n for (const e of edges) {\n const root = topAncestor(e.from);\n const comp = find(root);\n const arr = edgesByComp.get(comp) ?? [];\n arr.push(e);\n edgesByComp.set(comp, arr);\n }\n\n interface CompBox {\n id: string;\n nodes: NodeOutput[];\n edges: EdgeOutput[];\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n }\n\n const boxes: CompBox[] = [];\n for (const [compId, group] of groups) {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const n of group) {\n if (n.x < minX) minX = n.x;\n if (n.y < minY) minY = n.y;\n if (n.x + n.width > maxX) maxX = n.x + n.width;\n if (n.y + n.height > maxY) maxY = n.y + n.height;\n }\n const compEdges = edgesByComp.get(compId) ?? [];\n for (const e of compEdges) {\n for (const p of e.points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n }\n boxes.push({ id: compId, nodes: group, edges: compEdges, minX, minY, maxX, maxY });\n }\n\n // Sort largest-first along the rank axis so we lead with the dominant component.\n boxes.sort((a, b) => {\n const sizeA = isHorizontal ? a.maxX - a.minX : a.maxY - a.minY;\n const sizeB = isHorizontal ? b.maxX - b.minX : b.maxY - b.minY;\n return sizeB - sizeA;\n });\n\n const gap = options.layerSpacing;\n let cursor = 0;\n for (const box of boxes) {\n if (isHorizontal) {\n // Pack vertically (order axis is Y for LR).\n const dy = cursor - box.minY;\n const dx = -box.minX;\n for (const n of box.nodes) {\n n.x += dx;\n n.y += dy;\n for (const h of n.handles) {\n h.x += dx;\n h.y += dy;\n }\n }\n for (const e of box.edges) {\n for (const p of e.points) {\n p.x += dx;\n p.y += dy;\n }\n }\n cursor += (box.maxY - box.minY) + gap;\n } else {\n // Pack horizontally (order axis is X for TB).\n const dx = cursor - box.minX;\n const dy = -box.minY;\n for (const n of box.nodes) {\n n.x += dx;\n n.y += dy;\n for (const h of n.handles) {\n h.x += dx;\n h.y += dy;\n }\n }\n for (const e of box.edges) {\n for (const p of e.points) {\n p.x += dx;\n p.y += dy;\n }\n }\n cursor += (box.maxX - box.minX) + gap;\n }\n }\n}\n","import {\n EdgeInput,\n HandleInput,\n HandleSide,\n LayoutDirection,\n LayoutInput,\n NodeInput,\n ResolvedOptions,\n} from './types';\n\n/**\n * Inspect every input node and offer rotation proposals to the application\n * when the node's handle layout doesn't match how the layout engine will end\n * up placing it.\n *\n * The expected handle orientation depends on the node's role:\n *\n * - **Rail nodes** (with at least one control edge): they flow along the\n * global direction. In TB: inputs on top, outputs on bottom.\n * - **Value nodes** (only data edges): they end up as sidecars on the side\n * of their consumer. Their handles must point TOWARD the consumer — i.e.\n * opposite to the consumer's handle. A value attached to a `left` handle\n * of the consumer will sit on the consumer's left flank, so its output\n * needs to face `right`.\n *\n * The application's `onProposal` callback may:\n * - accept by returning the proposed node (or a modified version)\n * - reject by returning `null` / `undefined` / nothing\n */\nexport function applyRotationProposals(input: LayoutInput, options: ResolvedOptions): LayoutInput {\n if (!options.onProposal) return input;\n\n const nodeIndex = new Map<string, NodeInput>(input.nodes.map(n => [n.id, n]));\n\n const newNodes = input.nodes.map(node => {\n const role = classifyNode(node, input.edges);\n const expected = expectedSidesFor(node, role, input.edges, nodeIndex, options.direction);\n\n const proposal = computeProposal(node, expected, options.direction, role);\n if (!proposal) return node;\n const accepted = options.onProposal!(proposal);\n return accepted ?? node;\n });\n\n return { nodes: newNodes, edges: input.edges };\n}\n\ntype NodeRole =\n | { kind: 'rail' }\n | { kind: 'value'; consumerSide: HandleSide | null }\n | { kind: 'isolated' };\n\nfunction classifyNode(node: NodeInput, edges: EdgeInput[]): NodeRole {\n const incident = edges.filter(e => e.from === node.id || e.to === node.id);\n if (incident.length === 0) return { kind: 'isolated' };\n\n const allData = incident.every(e => (e.kind ?? 'control') === 'data');\n if (!allData) return { kind: 'rail' };\n\n // Value node — find which side of the (first) consumer it lands on.\n // A value typically has a single consumer; if it has several, the first one\n // wins (the sidecar placement uses the dominant consumer too, so this is a\n // reasonable approximation at proposal time).\n for (const e of incident) {\n const consumerId = e.from === node.id ? e.to : e.from;\n const consumerHandleId = e.from === node.id ? e.toHandle : e.fromHandle;\n const sideHint = sideHintFromHandle(consumerId, consumerHandleId, edges, /* recursing */ false);\n if (sideHint) return { kind: 'value', consumerSide: sideHint };\n }\n return { kind: 'value', consumerSide: null };\n}\n\nfunction sideHintFromHandle(\n _consumerId: string,\n _handleId: string,\n _edges: EdgeInput[],\n _recursing: boolean,\n): HandleSide | null {\n // The handle's position is on the consumer's node — but we don't have direct\n // access to the consumer NodeInput here without an index. The caller of\n // `classifyNode` resolves this through `expectedSidesFor` below.\n return null;\n}\n\nfunction expectedSidesFor(\n node: NodeInput,\n role: NodeRole,\n edges: EdgeInput[],\n index: Map<string, NodeInput>,\n direction: LayoutDirection,\n): { input: HandleSide; output: HandleSide } {\n if (role.kind === 'isolated' || role.kind === 'rail') {\n return { input: inputSideFor(direction), output: outputSideFor(direction) };\n }\n\n // Value: figure out which side of the consumer the value will land on.\n const consumerHandleSide = findConsumerHandleSide(node, edges, index);\n if (!consumerHandleSide) {\n return { input: inputSideFor(direction), output: outputSideFor(direction) };\n }\n\n // Sidecar placement only re-positions along the layout's order axis:\n // - TB/BT (vertical flow): values go on the consumer's left/right\n // ↳ a 'left' handle on the consumer → value sits at left → value's\n // output handle must face 'right' to reach the consumer.\n // ↳ symmetric for 'right'.\n // ↳ a 'top'/'bottom' handle: the value will be balanced left/right by\n // `splitValuesBySide`. We bias to face horizontally (right) for TB.\n // - LR/RL (horizontal flow): values go above/below.\n // ↳ 'top' handle → value sits above → output 'bottom'.\n // ↳ 'bottom' handle → output 'top'.\n // ↳ 'left'/'right' handle: bias vertically (bottom for LR).\n const isVerticalFlow = direction === 'TB' || direction === 'BT';\n\n let outputSide: HandleSide;\n if (isVerticalFlow) {\n if (consumerHandleSide === 'left') outputSide = 'right';\n else if (consumerHandleSide === 'right') outputSide = 'left';\n else outputSide = 'right'; // neutral, default to facing right\n } else {\n if (consumerHandleSide === 'top') outputSide = 'bottom';\n else if (consumerHandleSide === 'bottom') outputSide = 'top';\n else outputSide = 'bottom';\n }\n\n return { input: outputSide, output: outputSide };\n}\n\nfunction findConsumerHandleSide(\n value: NodeInput,\n edges: EdgeInput[],\n index: Map<string, NodeInput>,\n): HandleSide | null {\n for (const e of edges) {\n const isFromValue = e.from === value.id;\n const isToValue = e.to === value.id;\n if (!isFromValue && !isToValue) continue;\n\n const consumerId = isFromValue ? e.to : e.from;\n const consumer = index.get(consumerId);\n if (!consumer) continue;\n\n const consumerHandleId = isFromValue ? e.toHandle : e.fromHandle;\n const consumerHandle = consumer.handles.find(h => h.id === consumerHandleId);\n if (consumerHandle) return consumerHandle.position;\n }\n return null;\n}\n\nfunction computeProposal(\n node: NodeInput,\n expected: { input: HandleSide; output: HandleSide },\n direction: LayoutDirection,\n role: NodeRole,\n): ReturnType<typeof buildProposal> | null {\n if (node.handles.length === 0) return null;\n const currentScore = score(node.handles, expected);\n if (currentScore.matchRatio >= 1) return null;\n\n const candidates: { rotation: 90 | -90 | 180; score: ReturnType<typeof score> }[] = [];\n for (const rot of [90, -90, 180] as const) {\n const rotated = rotateHandles(node.handles, rot);\n candidates.push({ rotation: rot, score: score(rotated, expected) });\n }\n\n candidates.sort((a, b) => b.score.matchRatio - a.score.matchRatio);\n const best = candidates[0];\n if (best.score.matchRatio <= currentScore.matchRatio) return null;\n\n return buildProposal(node, best.rotation, currentScore, best.score, direction, expected, role);\n}\n\nfunction buildProposal(\n node: NodeInput,\n rotation: 90 | -90 | 180,\n current: ReturnType<typeof score>,\n proposedScore: ReturnType<typeof score>,\n direction: LayoutDirection,\n expected: { input: HandleSide; output: HandleSide },\n role: NodeRole,\n) {\n const proposed: NodeInput = { ...node, handles: rotateHandles(node.handles, rotation) };\n const roleDesc = role.kind === 'value'\n ? `value node should face ${expected.output} (its sidecar lands opposite the consumer's handle)`\n : `direction ${direction} expects inputs on ${expected.input} and outputs on ${expected.output}`;\n return {\n type: 'rotate' as const,\n nodeId: node.id,\n current: node,\n proposed,\n rotation,\n reason: `${roleDesc}; ${current.matched}/${current.total} handles match, ${proposedScore.matched}/${proposedScore.total} after rotation`,\n };\n}\n\nfunction inputSideFor(direction: LayoutDirection): HandleSide {\n switch (direction) {\n case 'TB': return 'top';\n case 'BT': return 'bottom';\n case 'LR': return 'left';\n case 'RL': return 'right';\n }\n}\n\nfunction outputSideFor(direction: LayoutDirection): HandleSide {\n switch (direction) {\n case 'TB': return 'bottom';\n case 'BT': return 'top';\n case 'LR': return 'right';\n case 'RL': return 'left';\n }\n}\n\nfunction score(\n handles: HandleInput[],\n expected: { input: HandleSide; output: HandleSide },\n): { matched: number; total: number; matchRatio: number } {\n let matched = 0;\n let total = 0;\n for (const h of handles) {\n total++;\n if (h.type === 'input' && h.position === expected.input) matched++;\n else if (h.type === 'output' && h.position === expected.output) matched++;\n }\n return { matched, total, matchRatio: total === 0 ? 1 : matched / total };\n}\n\n/**\n * Rotate a set of handles by `rot` degrees clockwise. The handles' position\n * along the side (offset) is preserved.\n *\n * Note: width/height of the node are NOT swapped here. The caller is free to\n * swap them when accepting the proposal (most layouts use square-ish nodes,\n * so we don't enforce a dimension swap).\n */\nexport function rotateHandles(handles: HandleInput[], rot: 90 | -90 | 180): HandleInput[] {\n const rotateSide = (s: HandleSide): HandleSide => {\n if (rot === 180) {\n return s === 'top' ? 'bottom' : s === 'bottom' ? 'top' : s === 'left' ? 'right' : 'left';\n }\n if (rot === 90) {\n return s === 'top' ? 'right' : s === 'right' ? 'bottom' : s === 'bottom' ? 'left' : 'top';\n }\n return s === 'top' ? 'left' : s === 'left' ? 'bottom' : s === 'bottom' ? 'right' : 'top';\n };\n return handles.map(h => ({ ...h, position: rotateSide(h.position) }));\n}\n","import {\n LayoutInput,\n LayoutOptions,\n LayoutResult,\n NodeOutput,\n EdgeOutput,\n HandleOutput,\n NodeInput,\n EdgeInput,\n resolveOptions,\n ResolvedOptions,\n} from './types';\nimport { Graph, buildGraph, getHandlePosition } from './graph';\nimport { breakCycles } from './algorithms/cycle-breaking';\nimport { assignLayers, insertDummyNodes } from './algorithms/layer-assignment';\nimport { minimizeCrossings } from './algorithms/crossing-minimization';\nimport { assignCoordinates } from './algorithms/coordinate-assignment';\nimport { placeValueSidecars, railLayers } from './algorithms/value-placement';\nimport { routeEdges } from './algorithms/edge-routing';\nimport { packComponents } from './algorithms/component-packing';\nimport { applyRotationProposals } from './proposals';\n\n/** Vertical room reserved at the top of a compound for the parent's own label. */\nconst COMPOUND_HEADER = 28;\n\n/**\n * Compute a complete layout for the given graph, with full compound (nested)\n * support and disjoint-component packing.\n */\nexport function layout(input: LayoutInput, options?: LayoutOptions): LayoutResult {\n const resolved = resolveOptions(options);\n if (input.nodes.length === 0) return { nodes: [], edges: [] };\n const adjusted = applyRotationProposals(input, resolved);\n return layoutCompound(adjusted, resolved);\n}\n\n/** Flat (single-level) layout on an already-built graph. */\nexport function computeLayout(graph: Graph, options: ResolvedOptions): LayoutResult {\n if (graph.nodes.size === 0) return { nodes: [], edges: [] };\n\n breakCycles(graph);\n\n let layers = assignLayers(graph);\n layers = insertDummyNodes(graph, layers);\n\n // Rail-only layers drive crossings + coords. Values are attached afterwards.\n let rail = railLayers(layers, graph);\n rail = minimizeCrossings(graph, rail, options.crossingMinimizationIterations);\n assignCoordinates(graph, rail, options);\n\n // Attach value nodes as sidecars to their dominant consumer.\n placeValueSidecars(graph, layers, options);\n\n const routedEdges = routeEdges(graph, options.direction, options.edgeMargin);\n return buildResult(graph, routedEdges);\n}\n\nfunction buildResult(graph: Graph, routedEdges: ReturnType<typeof routeEdges>): LayoutResult {\n const nodes: NodeOutput[] = [];\n const edges: EdgeOutput[] = [];\n\n for (const [, node] of graph.nodes) {\n if (node.isDummy) continue;\n\n const handles: HandleOutput[] = node.handles.map(h => {\n const pos = getHandlePosition(node, h.id);\n return { id: h.id, type: h.type, position: h.position, x: pos.x, y: pos.y };\n });\n\n nodes.push({\n id: node.id,\n x: node.x,\n y: node.y,\n width: node.width,\n height: node.height,\n handles,\n parentId: node.parentId,\n });\n }\n\n for (const route of routedEdges) {\n edges.push({\n id: route.id,\n from: route.from,\n to: route.to,\n fromHandle: route.fromHandle,\n toHandle: route.toHandle,\n points: route.points,\n kind: route.kind,\n });\n }\n\n return { nodes, edges };\n}\n\n/**\n * Compound Sugiyama: process nests bottom-up so each compound has its size\n * computed from its laid-out children before it appears in a higher-level pass.\n */\nfunction layoutCompound(input: LayoutInput, options: ResolvedOptions): LayoutResult {\n const nodeMap = new Map(input.nodes.map(n => [n.id, n]));\n\n const childrenByParent = new Map<string, NodeInput[]>();\n const rootNodes: NodeInput[] = [];\n for (const n of input.nodes) {\n if (n.parentId && nodeMap.has(n.parentId)) {\n const arr = childrenByParent.get(n.parentId) ?? [];\n arr.push(n);\n childrenByParent.set(n.parentId, arr);\n } else {\n rootNodes.push(n);\n }\n }\n\n const compoundIds = new Set(childrenByParent.keys());\n\n // Compute nesting depth so we can process compounds deepest-first.\n const depthCache = new Map<string, number>();\n function depthOf(id: string): number {\n if (depthCache.has(id)) return depthCache.get(id)!;\n const n = nodeMap.get(id);\n const d = n?.parentId && nodeMap.has(n.parentId) ? depthOf(n.parentId) + 1 : 0;\n depthCache.set(id, d);\n return d;\n }\n for (const n of input.nodes) depthOf(n.id);\n\n const sortedCompounds = [...compoundIds].sort((a, b) => depthOf(b) - depthOf(a));\n\n // Sub-layouts of each compound, keyed by the compound's id.\n const subLayouts = new Map<string, LayoutResult>();\n // Final published sizes for each compound (after children were laid out).\n const compoundSize = new Map<string, { width: number; height: number }>();\n\n for (const compoundId of sortedCompounds) {\n const children = childrenByParent.get(compoundId) ?? [];\n if (children.length === 0) continue;\n\n const childIdSet = new Set(children.map(c => c.id));\n const subEdges = input.edges.filter(e => childIdSet.has(e.from) && childIdSet.has(e.to));\n\n // Swap in computed sizes for any nested compounds among the children.\n const sizedChildren = children.map(c => {\n const sz = compoundSize.get(c.id);\n return sz ? { ...c, width: sz.width, height: sz.height } : c;\n });\n\n // Force packComponents off inside compounds — children are presumed connected\n // (and packing inside a parent box would visually conflict).\n const subOptions: ResolvedOptions = { ...options, packComponents: false };\n const subInput: LayoutInput = { nodes: sizedChildren.map(stripParent), edges: subEdges };\n const subResult = layoutFlat(subInput, subOptions);\n subLayouts.set(compoundId, subResult);\n\n // Compound size: bounding box of children + padding + header for the label.\n const bbox = computeBoundingBox(subResult.nodes);\n const innerW = bbox.width + options.compoundPadding * 2;\n const innerH = bbox.height + options.compoundPadding * 2 + COMPOUND_HEADER;\n\n const original = nodeMap.get(compoundId)!;\n compoundSize.set(compoundId, {\n width: Math.max(innerW, original.width),\n height: Math.max(innerH, original.height),\n });\n }\n\n // Root-level layout: compounds participate with their inflated size.\n const sizedRootNodes = rootNodes.map(n => {\n const sz = compoundSize.get(n.id);\n return sz ? { ...n, width: sz.width, height: sz.height } : n;\n });\n const rootIdSet = new Set(rootNodes.map(n => n.id));\n const rootEdges = input.edges.filter(e => {\n // Edges between root-level entities (compound boundaries count as roots).\n return rootIdSet.has(e.from) && rootIdSet.has(e.to);\n });\n\n const rootResult = layoutFlat({ nodes: sizedRootNodes.map(stripParent), edges: rootEdges }, options);\n\n // Final assembly: drop root nodes in, then translate each compound's children\n // by an offset that places them inside their parent's interior.\n const finalNodes: NodeOutput[] = [];\n const finalEdges: EdgeOutput[] = [];\n\n // First, replay the root result. Compound parents stay as visible rectangles.\n for (const n of rootResult.nodes) {\n const wasCompound = compoundIds.has(n.id);\n finalNodes.push({\n ...n,\n parentId: nodeMap.get(n.id)?.parentId,\n });\n if (wasCompound) {\n placeCompoundChildren(n, compoundId => subLayouts.get(compoundId), finalNodes, finalEdges, options, nodeMap);\n }\n }\n finalEdges.push(...rootResult.edges);\n\n if (options.packComponents) {\n packComponents(finalNodes, finalEdges, options);\n }\n\n return { nodes: finalNodes, edges: finalEdges };\n}\n\n/**\n * Recursively place a compound's children inside the parent's bounding box.\n * Translates positions from the sub-layout's local coords to the parent's frame.\n */\nfunction placeCompoundChildren(\n parent: NodeOutput,\n getSub: (compoundId: string) => LayoutResult | undefined,\n finalNodes: NodeOutput[],\n finalEdges: EdgeOutput[],\n options: ResolvedOptions,\n nodeMap: Map<string, NodeInput>,\n): void {\n const sub = getSub(parent.id);\n if (!sub) return;\n\n const bbox = computeBoundingBox(sub.nodes);\n // local-origin = (bbox.minX, bbox.minY) -> map to parent.x + padding, parent.y + padding + header\n const dx = parent.x + options.compoundPadding - bbox.minX;\n const dy = parent.y + options.compoundPadding + COMPOUND_HEADER - bbox.minY;\n\n // Center horizontally inside available space if the parent was inflated past\n // the children's natural width.\n const availableW = parent.width - options.compoundPadding * 2;\n const slackX = (availableW - bbox.width) / 2;\n const availableH = parent.height - options.compoundPadding * 2 - COMPOUND_HEADER;\n const slackY = (availableH - bbox.height) / 2;\n const cx = dx + Math.max(0, slackX);\n const cy = dy + Math.max(0, slackY);\n\n for (const child of sub.nodes) {\n const placed: NodeOutput = {\n ...child,\n x: child.x + cx,\n y: child.y + cy,\n handles: child.handles.map(h => ({ ...h, x: h.x + cx, y: h.y + cy })),\n parentId: nodeMap.get(child.id)?.parentId ?? parent.id,\n };\n finalNodes.push(placed);\n if (getSub(child.id)) {\n placeCompoundChildren(placed, getSub, finalNodes, finalEdges, options, nodeMap);\n }\n }\n\n for (const edge of sub.edges) {\n finalEdges.push({\n ...edge,\n points: edge.points.map(p => ({ x: p.x + cx, y: p.y + cy })),\n });\n }\n}\n\n/** Strip parentId from a node copy so flat layout won't recurse. */\nfunction stripParent(n: NodeInput): NodeInput {\n const { parentId: _ignored, ...rest } = n;\n return rest;\n}\n\nfunction layoutFlat(input: LayoutInput, options: ResolvedOptions): LayoutResult {\n const graph = buildGraph(input.nodes, input.edges, {\n controlWeight: options.controlWeight,\n dataWeight: options.dataWeight,\n });\n return computeLayout(graph, options);\n}\n\nfunction computeBoundingBox(\n nodes: { x: number; y: number; width: number; height: number }[],\n): { minX: number; minY: number; maxX: number; maxY: number; width: number; height: number } {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const n of nodes) {\n if (n.x < minX) minX = n.x;\n if (n.y < minY) minY = n.y;\n if (n.x + n.width > maxX) maxX = n.x + n.width;\n if (n.y + n.height > maxY) maxY = n.y + n.height;\n }\n if (!isFinite(minX)) {\n minX = 0; minY = 0; maxX = 0; maxY = 0;\n }\n return { minX, minY, maxX, maxY, width: maxX - minX, height: maxY - minY };\n}\n","import {\n LayoutInput,\n LayoutOptions,\n LayoutResult,\n NodeInput,\n EdgeInput,\n resolveOptions,\n ResolvedOptions,\n} from './types';\nimport { layout } from './layout';\n\n/**\n * Incremental layout engine.\n * Maintains layout state and supports adding/removing nodes\n * without full recomputation.\n *\n * Compound layouts and value-pulled nodes are handled through the unified\n * `layout()` entry point, so any input change re-uses the same logic.\n */\nexport class IncrementalLayout {\n private resolvedOptions: ResolvedOptions;\n private options: LayoutOptions | undefined;\n private inputNodes: Map<string, NodeInput> = new Map();\n private inputEdges: Map<string, EdgeInput> = new Map();\n private lastResult: LayoutResult | null = null;\n private nodePositions: Map<string, { x: number; y: number }> = new Map();\n\n constructor(options?: LayoutOptions) {\n this.options = options;\n this.resolvedOptions = resolveOptions(options);\n }\n\n setGraph(input: LayoutInput): LayoutResult {\n this.inputNodes.clear();\n this.inputEdges.clear();\n for (const node of input.nodes) this.inputNodes.set(node.id, node);\n for (const edge of input.edges) this.inputEdges.set(edge.id, edge);\n return this.recompute();\n }\n\n addNodes(nodes: NodeInput[], edges?: EdgeInput[]): LayoutResult {\n for (const node of nodes) this.inputNodes.set(node.id, node);\n if (edges) for (const edge of edges) this.inputEdges.set(edge.id, edge);\n return this.recomputeWithStability(new Set(nodes.map(n => n.id)));\n }\n\n removeNodes(nodeIds: string[]): LayoutResult {\n const removedSet = new Set(nodeIds);\n for (const id of nodeIds) this.inputNodes.delete(id);\n for (const [edgeId, edge] of this.inputEdges) {\n if (removedSet.has(edge.from) || removedSet.has(edge.to)) {\n this.inputEdges.delete(edgeId);\n }\n }\n for (const id of nodeIds) this.nodePositions.delete(id);\n return this.recompute();\n }\n\n addEdges(edges: EdgeInput[]): LayoutResult {\n for (const edge of edges) this.inputEdges.set(edge.id, edge);\n return this.recomputeWithStability(new Set<string>());\n }\n\n removeEdges(edgeIds: string[]): LayoutResult {\n for (const id of edgeIds) this.inputEdges.delete(id);\n return this.recompute();\n }\n\n getResult(): LayoutResult | null {\n return this.lastResult;\n }\n\n private recompute(): LayoutResult {\n const input: LayoutInput = {\n nodes: [...this.inputNodes.values()],\n edges: [...this.inputEdges.values()],\n };\n this.lastResult = layout(input, this.options);\n this.cachePositions();\n return this.lastResult;\n }\n\n private recomputeWithStability(newNodeIds: Set<string>): LayoutResult {\n const input: LayoutInput = {\n nodes: [...this.inputNodes.values()],\n edges: [...this.inputEdges.values()],\n };\n\n const fresh = layout(input, this.options);\n this.lastResult = this.applyStability(fresh, newNodeIds);\n this.cachePositions();\n return this.lastResult;\n }\n\n /**\n * Blend the freshly computed positions with the previous ones, so existing\n * nodes don't jump too far when a small change happens.\n */\n private applyStability(fresh: LayoutResult, newNodeIds: Set<string>): LayoutResult {\n if (this.nodePositions.size === 0) return fresh;\n const STABILITY_WEIGHT = 0.3;\n\n const blended: LayoutResult = {\n nodes: fresh.nodes.map(n => {\n if (newNodeIds.has(n.id)) return n;\n const old = this.nodePositions.get(n.id);\n if (!old) return n;\n const dx = old.x - n.x;\n const dy = old.y - n.y;\n const x = n.x + dx * STABILITY_WEIGHT;\n const y = n.y + dy * STABILITY_WEIGHT;\n const ddx = x - n.x;\n const ddy = y - n.y;\n return {\n ...n,\n x,\n y,\n handles: n.handles.map(h => ({ ...h, x: h.x + ddx, y: h.y + ddy })),\n };\n }),\n edges: fresh.edges,\n };\n return blended;\n }\n\n private cachePositions(): void {\n if (!this.lastResult) return;\n this.nodePositions.clear();\n for (const node of this.lastResult.nodes) {\n this.nodePositions.set(node.id, { x: node.x, y: node.y });\n }\n }\n}\n","import { LayoutResult, NodeOutput, EdgeOutput } from './types';\n\n/**\n * Render a `LayoutResult` to a human-readable text block.\n *\n * Useful when iterating on the algorithm without opening a browser:\n * - a per-layer summary (Y bands in TB, X bands in LR-ish)\n * - per-node hierarchy + bbox\n * - per-edge endpoints and kind\n * - an ASCII grid (optional) sketching the final layout\n */\nexport interface PrintLayoutOptions {\n /** Include an ASCII grid sketch (default: true). */\n grid?: boolean;\n /** Grid resolution: characters per coordinate unit (default: auto). */\n gridScale?: number;\n /** Max grid width in characters (default: 80). */\n gridWidth?: number;\n}\n\nexport function printLayout(result: LayoutResult, options: PrintLayoutOptions = {}): string {\n const lines: string[] = [];\n const { nodes, edges } = result;\n\n if (nodes.length === 0) return '(empty layout)';\n\n // ----- bounding box -----\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const n of nodes) {\n if (n.x < minX) minX = n.x;\n if (n.y < minY) minY = n.y;\n if (n.x + n.width > maxX) maxX = n.x + n.width;\n if (n.y + n.height > maxY) maxY = n.y + n.height;\n }\n lines.push(`=== layout ${nodes.length} nodes, ${edges.length} edges ===`);\n lines.push(`bbox: x=[${minX.toFixed(0)}..${maxX.toFixed(0)}] y=[${minY.toFixed(0)}..${maxY.toFixed(0)}] (${(maxX - minX).toFixed(0)} x ${(maxY - minY).toFixed(0)})`);\n\n // ----- Y bands (TB-style) -----\n const byY = [...nodes].sort((a, b) => a.y - b.y || a.x - b.x);\n const bands: NodeOutput[][] = [];\n for (const n of byY) {\n const placed = bands.find(b => Math.abs(b[0].y - n.y) < 1);\n if (placed) placed.push(n);\n else bands.push([n]);\n }\n\n lines.push('');\n lines.push('--- Y bands ---');\n for (const band of bands) {\n const sorted = [...band].sort((a, b) => a.x - b.x);\n const summary = sorted.map(n => {\n const p = n.parentId ? `[${n.parentId}/]` : '';\n return `${p}${n.id}@(${n.x.toFixed(0)},${n.y.toFixed(0)} ${n.width}x${n.height})`;\n }).join(' ');\n lines.push(` y=${band[0].y.toFixed(0).padStart(4)} : ${summary}`);\n }\n\n // ----- hierarchy -----\n const byParent = new Map<string | undefined, NodeOutput[]>();\n for (const n of nodes) {\n const key = n.parentId;\n const arr = byParent.get(key) ?? [];\n arr.push(n);\n byParent.set(key, arr);\n }\n const compoundIds = new Set<string>();\n for (const k of byParent.keys()) {\n if (k && nodes.find(n => n.id === k)) compoundIds.add(k);\n }\n if (compoundIds.size > 0) {\n lines.push('');\n lines.push('--- hierarchy ---');\n function printSubtree(id: string | undefined, depth: number) {\n const children = byParent.get(id) ?? [];\n for (const c of children) {\n const prefix = ' '.repeat(depth);\n const tag = compoundIds.has(c.id) ? ' (compound)' : '';\n lines.push(`${prefix}- ${c.id}${tag} bbox=(${c.x.toFixed(0)},${c.y.toFixed(0)})..(${(c.x + c.width).toFixed(0)},${(c.y + c.height).toFixed(0)})`);\n if (compoundIds.has(c.id)) printSubtree(c.id, depth + 1);\n }\n }\n printSubtree(undefined, 0);\n }\n\n // ----- edges -----\n lines.push('');\n lines.push('--- edges ---');\n for (const e of edges) {\n const head = e.points[0];\n const tail = e.points[e.points.length - 1];\n lines.push(` [${e.kind}] ${e.from}.${e.fromHandle} → ${e.to}.${e.toHandle} (${head.x.toFixed(0)},${head.y.toFixed(0)}) → (${tail.x.toFixed(0)},${tail.y.toFixed(0)}) via ${e.points.length} pts`);\n }\n\n // ----- overlap check -----\n const overlaps = findOverlaps(nodes);\n if (overlaps.length > 0) {\n lines.push('');\n lines.push('--- OVERLAPS (problem!) ---');\n for (const o of overlaps) {\n lines.push(` ${o.a} overlaps ${o.b}`);\n }\n }\n\n if (options.grid !== false) {\n lines.push('');\n lines.push('--- ASCII grid ---');\n lines.push(asciiGrid(nodes, edges, options));\n }\n\n return lines.join('\\n');\n}\n\nfunction findOverlaps(nodes: NodeOutput[]): { a: string; b: string }[] {\n const out: { a: string; b: string }[] = [];\n const compoundIds = new Set<string>();\n for (const n of nodes) if (n.parentId) compoundIds.add(n.parentId);\n\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i + 1; j < nodes.length; j++) {\n const a = nodes[i];\n const b = nodes[j];\n // Skip compound-vs-child intentional overlap (compound contains its kids).\n if (a.id === b.parentId || b.id === a.parentId) continue;\n // Skip sibling values vs compound parent (handled by hierarchy).\n const overlapX = a.x < b.x + b.width && b.x < a.x + a.width;\n const overlapY = a.y < b.y + b.height && b.y < a.y + a.height;\n if (overlapX && overlapY) {\n out.push({ a: a.id, b: b.id });\n }\n }\n }\n return out;\n}\n\nfunction asciiGrid(nodes: NodeOutput[], edges: EdgeOutput[], options: PrintLayoutOptions): string {\n if (nodes.length === 0) return '';\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const n of nodes) {\n if (n.x < minX) minX = n.x;\n if (n.y < minY) minY = n.y;\n if (n.x + n.width > maxX) maxX = n.x + n.width;\n if (n.y + n.height > maxY) maxY = n.y + n.height;\n }\n for (const e of edges) for (const p of e.points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n\n const targetW = options.gridWidth ?? 80;\n const layoutW = Math.max(1, maxX - minX);\n const layoutH = Math.max(1, maxY - minY);\n const scaleX = options.gridScale ?? targetW / layoutW;\n // Characters are roughly twice as tall as wide -> halve Y scale.\n const scaleY = scaleX * 0.5;\n\n const w = Math.max(1, Math.ceil(layoutW * scaleX) + 1);\n const h = Math.max(1, Math.ceil(layoutH * scaleY) + 1);\n\n if (h > 80) return '(grid suppressed: too tall — pass {grid:false} to skip)';\n\n const grid: string[][] = Array.from({ length: h }, () => Array.from({ length: w }, () => ' '));\n\n const compoundIds = new Set<string>();\n for (const n of nodes) if (n.parentId) compoundIds.add(n.parentId);\n\n // Draw nodes\n for (const n of nodes) {\n const x0 = Math.round((n.x - minX) * scaleX);\n const y0 = Math.round((n.y - minY) * scaleY);\n const x1 = Math.max(x0, Math.round((n.x + n.width - minX) * scaleX) - 1);\n const y1 = Math.max(y0, Math.round((n.y + n.height - minY) * scaleY) - 1);\n const isCompound = compoundIds.has(n.id);\n const ch = isCompound ? '.' : '#';\n for (let y = y0; y <= y1 && y < h; y++) {\n for (let x = x0; x <= x1 && x < w; x++) {\n if (y < 0 || x < 0) continue;\n if (y === y0 || y === y1 || x === x0 || x === x1) grid[y][x] = ch;\n else if (isCompound) {\n // empty interior for compounds\n } else grid[y][x] = ch;\n }\n }\n // Label: first letters of id, centered top-left of box\n const label = n.id.slice(0, Math.min(n.id.length, Math.max(2, x1 - x0 - 1)));\n const lx = Math.max(0, x0 + 1);\n const ly = Math.max(0, y0);\n for (let i = 0; i < label.length && lx + i < w; i++) {\n if (ly < h) grid[ly][lx + i] = label[i];\n }\n }\n\n return grid.map(row => row.join('')).join('\\n');\n}\n"],"mappings":"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","names":["printSubtree"]}
|