@prisma-next/cli 0.12.0-dev.9 → 0.13.0-dev.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.
Files changed (214) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.mjs +180 -163
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/{client-KgJorIvG.mjs → client-CJzuo5wX.mjs} +222 -107
  5. package/dist/client-CJzuo5wX.mjs.map +1 -0
  6. package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-DGMvGBeX.mjs} +318 -25
  7. package/dist/command-helpers-DGMvGBeX.mjs.map +1 -0
  8. package/dist/commands/contract-emit.d.mts.map +1 -1
  9. package/dist/commands/contract-emit.mjs +1 -1
  10. package/dist/commands/contract-infer.d.mts.map +1 -1
  11. package/dist/commands/contract-infer.mjs +1 -1
  12. package/dist/commands/db-init.d.mts.map +1 -1
  13. package/dist/commands/db-init.mjs +4 -5
  14. package/dist/commands/db-init.mjs.map +1 -1
  15. package/dist/commands/db-schema.d.mts.map +1 -1
  16. package/dist/commands/db-schema.mjs +3 -3
  17. package/dist/commands/db-schema.mjs.map +1 -1
  18. package/dist/commands/db-sign.d.mts.map +1 -1
  19. package/dist/commands/db-sign.mjs +6 -6
  20. package/dist/commands/db-sign.mjs.map +1 -1
  21. package/dist/commands/db-update.d.mts.map +1 -1
  22. package/dist/commands/db-update.mjs +10 -7
  23. package/dist/commands/db-update.mjs.map +1 -1
  24. package/dist/commands/db-verify.d.mts.map +1 -1
  25. package/dist/commands/db-verify.mjs +1 -1
  26. package/dist/commands/migrate.d.mts +37 -3
  27. package/dist/commands/migrate.d.mts.map +1 -1
  28. package/dist/commands/migrate.mjs +298 -12
  29. package/dist/commands/migrate.mjs.map +1 -1
  30. package/dist/commands/migration-check.d.mts +55 -13
  31. package/dist/commands/migration-check.d.mts.map +1 -1
  32. package/dist/commands/migration-check.mjs +3 -2
  33. package/dist/commands/migration-graph.d.mts +16 -25
  34. package/dist/commands/migration-graph.d.mts.map +1 -1
  35. package/dist/commands/migration-graph.mjs +185 -2
  36. package/dist/commands/migration-graph.mjs.map +1 -0
  37. package/dist/commands/migration-list.d.mts +26 -27
  38. package/dist/commands/migration-list.d.mts.map +1 -1
  39. package/dist/commands/migration-list.mjs +2 -190
  40. package/dist/commands/migration-log.d.mts +9 -19
  41. package/dist/commands/migration-log.d.mts.map +1 -1
  42. package/dist/commands/migration-log.mjs +1 -137
  43. package/dist/commands/migration-new.d.mts.map +1 -1
  44. package/dist/commands/migration-new.mjs +6 -5
  45. package/dist/commands/migration-new.mjs.map +1 -1
  46. package/dist/commands/migration-plan.d.mts +1 -1
  47. package/dist/commands/migration-plan.d.mts.map +1 -1
  48. package/dist/commands/migration-plan.mjs +1 -1
  49. package/dist/commands/migration-show.d.mts +17 -21
  50. package/dist/commands/migration-show.d.mts.map +1 -1
  51. package/dist/commands/migration-show.mjs +24 -36
  52. package/dist/commands/migration-show.mjs.map +1 -1
  53. package/dist/commands/migration-status.d.mts +42 -144
  54. package/dist/commands/migration-status.d.mts.map +1 -1
  55. package/dist/commands/migration-status.mjs +3 -759
  56. package/dist/commands/ref.d.mts +1 -1
  57. package/dist/commands/ref.d.mts.map +1 -1
  58. package/dist/commands/ref.mjs +4 -4
  59. package/dist/commands/ref.mjs.map +1 -1
  60. package/dist/commands/telemetry/index.d.mts +7 -0
  61. package/dist/commands/telemetry/index.d.mts.map +1 -0
  62. package/dist/commands/telemetry/index.mjs +2 -0
  63. package/dist/{config-loader-B6sJjXTv.mjs → config-loader-p9JMrekQ.mjs} +1 -1
  64. package/dist/{config-loader-B6sJjXTv.mjs.map → config-loader-p9JMrekQ.mjs.map} +1 -1
  65. package/dist/config-loader.mjs +1 -1
  66. package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-CFXsstzm.mjs} +2 -2
  67. package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-CFXsstzm.mjs.map} +1 -1
  68. package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-B_qriF8B.mjs} +5 -5
  69. package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-B_qriF8B.mjs.map} +1 -1
  70. package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-C8HmtboH.mjs} +12 -7
  71. package/dist/contract-emit-C8HmtboH.mjs.map +1 -0
  72. package/dist/{contract-enrichment-a0V5Y_mL.mjs → contract-enrichment-gn9sWbPw.mjs} +1 -1
  73. package/dist/{contract-enrichment-a0V5Y_mL.mjs.map → contract-enrichment-gn9sWbPw.mjs.map} +1 -1
  74. package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-BYT_ra_U.mjs} +5 -5
  75. package/dist/contract-infer-BYT_ra_U.mjs.map +1 -0
  76. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-ClI1KN6d.mjs} +5 -5
  77. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-ClI1KN6d.mjs.map} +1 -1
  78. package/dist/{db-verify-v_vUKXTU.mjs → db-verify-C24FKhb7.mjs} +6 -6
  79. package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-C24FKhb7.mjs.map} +1 -1
  80. package/dist/exports/control-api.d.mts +5 -3
  81. package/dist/exports/control-api.d.mts.map +1 -1
  82. package/dist/exports/control-api.mjs +3 -3
  83. package/dist/exports/index.mjs +1 -1
  84. package/dist/exports/index.mjs.map +1 -1
  85. package/dist/exports/init-output.d.mts +1 -3
  86. package/dist/exports/init-output.d.mts.map +1 -1
  87. package/dist/exports/init-output.mjs +1 -1
  88. package/dist/{extension-pack-inputs-IDvjRCi3.mjs → extension-pack-inputs-1ySHqxKG.mjs} +1 -1
  89. package/dist/{extension-pack-inputs-IDvjRCi3.mjs.map → extension-pack-inputs-1ySHqxKG.mjs.map} +1 -1
  90. package/dist/{framework-components-fYXjz_in.mjs → framework-components-YVQHhPH7.mjs} +2 -2
  91. package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-YVQHhPH7.mjs.map} +1 -1
  92. package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-BpoOYtNZ.d.mts} +1 -1
  93. package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-BpoOYtNZ.d.mts.map} +1 -1
  94. package/dist/{init-Cv9UzWL5.mjs → init-0HwB-Vh8.mjs} +5 -58
  95. package/dist/init-0HwB-Vh8.mjs.map +1 -0
  96. package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-DF6IwcDl.mjs} +7 -5
  97. package/dist/inspect-live-schema-DF6IwcDl.mjs.map +1 -0
  98. package/dist/migration-check-soB5uZEQ.mjs +573 -0
  99. package/dist/migration-check-soB5uZEQ.mjs.map +1 -0
  100. package/dist/migration-cli.mjs +1 -1
  101. package/dist/migration-cli.mjs.map +1 -1
  102. package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-DA-Lhx6o.mjs} +5 -5
  103. package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-DA-Lhx6o.mjs.map} +1 -1
  104. package/dist/migration-graph-command-render-CEez7YUK.mjs +1960 -0
  105. package/dist/migration-graph-command-render-CEez7YUK.mjs.map +1 -0
  106. package/dist/migration-list-DlJJ_38Z.mjs +230 -0
  107. package/dist/migration-list-DlJJ_38Z.mjs.map +1 -0
  108. package/dist/migration-log-CG0qQAFm.mjs +222 -0
  109. package/dist/migration-log-CG0qQAFm.mjs.map +1 -0
  110. package/dist/migration-path-target-Ce6OZImp.mjs +38 -0
  111. package/dist/migration-path-target-Ce6OZImp.mjs.map +1 -0
  112. package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-z5Ing-TD.mjs} +9 -8
  113. package/dist/migration-plan-z5Ing-TD.mjs.map +1 -0
  114. package/dist/migration-status-CgWSoI_g.mjs +446 -0
  115. package/dist/migration-status-CgWSoI_g.mjs.map +1 -0
  116. package/dist/{output-B60Gw5fu.mjs → output-mEQ74_nd.mjs} +1 -1
  117. package/dist/{output-B60Gw5fu.mjs.map → output-mEQ74_nd.mjs.map} +1 -1
  118. package/dist/{progress-adapter-C644QK8l.mjs → progress-adapter-CjAeTxY_.mjs} +1 -1
  119. package/dist/{progress-adapter-C644QK8l.mjs.map → progress-adapter-CjAeTxY_.mjs.map} +1 -1
  120. package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-BkXlikCA.mjs} +1 -1
  121. package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-BkXlikCA.mjs.map} +1 -1
  122. package/dist/schemas-CeGMYFYX.d.mts +191 -0
  123. package/dist/schemas-CeGMYFYX.d.mts.map +1 -0
  124. package/dist/schemas-KhXMzNA_.mjs +112 -0
  125. package/dist/schemas-KhXMzNA_.mjs.map +1 -0
  126. package/dist/telemetry-BIM4beEO.mjs +122 -0
  127. package/dist/telemetry-BIM4beEO.mjs.map +1 -0
  128. package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-DGRNFWna.d.mts} +1 -1
  129. package/dist/terminal-ui-DGRNFWna.d.mts.map +1 -0
  130. package/dist/{types-Dt_SfqFm.d.mts → types-C_tYiJYx.d.mts} +53 -31
  131. package/dist/types-C_tYiJYx.d.mts.map +1 -0
  132. package/dist/{verify-DCA9Sldu.mjs → verify-DcOYZ1tH.mjs} +2 -2
  133. package/dist/{verify-DCA9Sldu.mjs.map → verify-DcOYZ1tH.mjs.map} +1 -1
  134. package/package.json +26 -22
  135. package/src/cli.ts +5 -0
  136. package/src/commands/contract-infer.ts +2 -2
  137. package/src/commands/db-update.ts +7 -1
  138. package/src/commands/init/index.ts +6 -35
  139. package/src/commands/init/init.ts +1 -14
  140. package/src/commands/init/inputs.ts +0 -75
  141. package/src/commands/inspect-live-schema.ts +10 -0
  142. package/src/commands/json/schemas.ts +195 -0
  143. package/src/commands/migrate.ts +527 -8
  144. package/src/commands/migration-check.ts +469 -134
  145. package/src/commands/migration-graph.ts +151 -119
  146. package/src/commands/migration-list.ts +72 -39
  147. package/src/commands/migration-log.ts +52 -102
  148. package/src/commands/migration-new.ts +2 -1
  149. package/src/commands/migration-plan.ts +2 -1
  150. package/src/commands/migration-show.ts +31 -66
  151. package/src/commands/migration-status-overlay.ts +61 -0
  152. package/src/commands/migration-status.ts +458 -1066
  153. package/src/commands/telemetry/index.ts +107 -0
  154. package/src/commands/telemetry/status.ts +67 -0
  155. package/src/control-api/client.ts +70 -9
  156. package/src/control-api/operations/contract-emit.ts +22 -2
  157. package/src/control-api/operations/db-init.ts +6 -3
  158. package/src/control-api/operations/{db-apply.ts → db-run.ts} +55 -14
  159. package/src/control-api/operations/db-update.ts +7 -4
  160. package/src/control-api/operations/db-verify.ts +15 -5
  161. package/src/control-api/operations/{migration-apply.ts → migrate.ts} +181 -80
  162. package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
  163. package/src/control-api/types.ts +56 -29
  164. package/src/utils/cli-errors.ts +70 -2
  165. package/src/utils/formatters/errors.ts +11 -0
  166. package/src/utils/formatters/migration-graph-command-render.ts +239 -0
  167. package/src/utils/formatters/migration-graph-grid-layout.ts +1134 -0
  168. package/src/utils/formatters/migration-graph-labels.ts +408 -0
  169. package/src/utils/formatters/migration-graph-model.ts +103 -0
  170. package/src/utils/formatters/migration-graph-occlusion-render.ts +258 -0
  171. package/src/utils/formatters/migration-graph-rows.ts +128 -15
  172. package/src/utils/formatters/migration-graph-space-render.ts +188 -0
  173. package/src/utils/formatters/migration-list-data-column.ts +4 -91
  174. package/src/utils/formatters/migration-list-graph-topology.ts +72 -94
  175. package/src/utils/formatters/migration-list-render.ts +135 -71
  176. package/src/utils/formatters/migration-list-styler.ts +46 -5
  177. package/src/utils/formatters/migration-list-types.ts +5 -21
  178. package/src/utils/formatters/migration-log-table.ts +205 -0
  179. package/src/utils/formatters/migrations.ts +33 -11
  180. package/src/utils/global-flags.ts +35 -0
  181. package/src/utils/integrity-violation-to-check-failure.ts +28 -19
  182. package/src/utils/legend.ts +38 -0
  183. package/src/utils/migration-path-target.ts +60 -0
  184. package/src/utils/telemetry.ts +68 -32
  185. package/dist/client-KgJorIvG.mjs.map +0 -1
  186. package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
  187. package/dist/commands/migration-list.mjs.map +0 -1
  188. package/dist/commands/migration-log.mjs.map +0 -1
  189. package/dist/commands/migration-status.mjs.map +0 -1
  190. package/dist/contract-emit-D-4jrNve.mjs.map +0 -1
  191. package/dist/contract-infer-D8uEbJuu.mjs.map +0 -1
  192. package/dist/graph-render-rFAqZujX.mjs +0 -1081
  193. package/dist/graph-render-rFAqZujX.mjs.map +0 -1
  194. package/dist/init-Cv9UzWL5.mjs.map +0 -1
  195. package/dist/inspect-live-schema-C6ohV_oQ.mjs.map +0 -1
  196. package/dist/migration-check-BiBJoYYW.mjs +0 -341
  197. package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
  198. package/dist/migration-graph-C9WC-7eO.mjs +0 -1478
  199. package/dist/migration-graph-C9WC-7eO.mjs.map +0 -1
  200. package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
  201. package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
  202. package/dist/migration-plan-9DJ7q7_z.mjs.map +0 -1
  203. package/dist/migration-types-D2FW63pr.d.mts +0 -15
  204. package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
  205. package/dist/migrations-Cv2jxNNK.mjs +0 -228
  206. package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
  207. package/dist/terminal-ui-5Y6mrg93.d.mts.map +0 -1
  208. package/dist/types-Dt_SfqFm.d.mts.map +0 -1
  209. package/src/utils/formatters/graph-migration-mapper.ts +0 -235
  210. package/src/utils/formatters/graph-render.ts +0 -1323
  211. package/src/utils/formatters/graph-types.ts +0 -120
  212. package/src/utils/formatters/migration-graph-lane-colors.ts +0 -31
  213. package/src/utils/formatters/migration-graph-layout.ts +0 -1141
  214. package/src/utils/formatters/migration-graph-tree-render.ts +0 -768
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-graph-command-render-CEez7YUK.mjs","names":["numBackLanes"],"sources":["../src/utils/formatters/migration-graph-occlusion-render.ts","../src/utils/formatters/migration-list-data-column.ts","../src/utils/formatters/migration-graph-grid-layout.ts","../src/utils/formatters/migration-list-graph-topology.ts","../src/utils/formatters/migration-graph-rows.ts","../src/utils/formatters/migration-graph-space-render.ts","../src/utils/formatters/migration-list-render.ts","../src/utils/formatters/migration-list-styler.ts","../src/utils/formatters/migration-graph-labels.ts","../src/utils/formatters/migration-graph-command-render.ts"],"sourcesContent":["/**\n * Occlusion renderer for the line/plane/occlusion migration-graph.\n *\n * Per cell: pick the topmost-plane line (lowest plane number = drawn on top),\n * look up its glyph, apply colour from the line's lane or role. Lower-plane\n * lines are occluded (not drawn).\n *\n * Colour is forced via createColors({ useColor: true }) regardless of NO_COLOR.\n */\n\nimport { createColors } from 'colorette';\nimport {\n type Cell,\n type CellLine,\n DEFAULT_COLS_PER_LANE,\n type Direction,\n type Grid,\n type PathRole,\n} from './migration-graph-model';\n\n// ---------------------------------------------------------------------------\n// Force-colour seam — always emits ANSI regardless of NO_COLOR.\n// Same technique as gallery-cells.ts.\n// ---------------------------------------------------------------------------\nconst palette = createColors({ useColor: true });\n\n// Lane colour palette: lane N → colour N+1 (lane0=white, lane1=cyan, …).\n// No red (reads as an error). The on-path highlight uses greenBright (SGR 92),\n// distinct from flat-lane green (SGR 32).\ntype Colorizer = (text: string) => string;\n\nconst LANE_COLORIZERS: Colorizer[] = [\n palette.white,\n palette.cyan,\n palette.yellow,\n palette.blueBright,\n palette.magenta,\n palette.green,\n];\n\nfunction laneColor(lane: number): Colorizer {\n return LANE_COLORIZERS[lane % LANE_COLORIZERS.length] ?? ((t) => t);\n}\n\n/**\n * The colourizer for a lane's hue (lane0 = white, lane1 = cyan, …). Exported\n * so the per-row LABEL renderer can tint a migration name in its lane's colour,\n * matching the node `○`, the edges, and the arrows drawn in the gutter — one\n * colour per lane across glyph and text.\n */\nexport function laneColorizer(lane: number): (text: string) => string {\n return laneColor(lane);\n}\n\n// ---------------------------------------------------------------------------\n// Focus colour: on-path → green, off-path → dim. Read straight off the line's\n// role; a defined role always overrides the lane rotation.\n// ---------------------------------------------------------------------------\nfunction roleColor(role: PathRole): Colorizer {\n return role === 'on-path' ? palette.greenBright : palette.dim;\n}\n\n// ---------------------------------------------------------------------------\n// Glyph alphabet — unicode and ASCII variants.\n// ---------------------------------------------------------------------------\nexport type GraphGlyphMode = 'unicode' | 'ascii';\n\ninterface GraphGlyphAlphabet {\n readonly vertical: string;\n readonly horizontal: string;\n readonly cornerUpRight: string;\n readonly cornerDownRight: string;\n readonly cornerUpLeft: string;\n readonly cornerDownLeft: string;\n readonly arrowUp: string;\n readonly arrowDown: string;\n readonly node: string;\n readonly selfLoop: string;\n readonly landingArrow: string;\n readonly fallback: string;\n}\n\nconst UNICODE_ALPHABET: GraphGlyphAlphabet = {\n vertical: '│',\n horizontal: '─',\n cornerUpRight: '╰',\n cornerDownRight: '╭',\n cornerUpLeft: '╯',\n cornerDownLeft: '╮',\n arrowUp: '↑',\n arrowDown: '↓',\n node: '○',\n selfLoop: '⟲',\n landingArrow: '◂',\n fallback: '?',\n};\n\nconst ASCII_ALPHABET: GraphGlyphAlphabet = {\n vertical: '|',\n horizontal: '-',\n cornerUpRight: '\\\\',\n cornerDownRight: '/',\n cornerUpLeft: '/',\n cornerDownLeft: '\\\\',\n arrowUp: '^',\n arrowDown: 'v',\n node: '*',\n selfLoop: '@',\n landingArrow: '<',\n fallback: '?',\n};\n\nfunction alphabetFor(mode: GraphGlyphMode): GraphGlyphAlphabet {\n return mode === 'ascii' ? ASCII_ALPHABET : UNICODE_ALPHABET;\n}\n\nfunction glyphFor(dirs: ReadonlySet<Direction>, alphabet: GraphGlyphAlphabet): string {\n const has = (d: Direction) => dirs.has(d);\n\n if (has('up') && has('down') && !has('left') && !has('right')) return alphabet.vertical;\n if (has('left') && has('right') && !has('up') && !has('down')) return alphabet.horizontal;\n if (has('up') && has('right') && !has('down') && !has('left')) return alphabet.cornerUpRight;\n if (has('down') && has('right') && !has('up') && !has('left')) return alphabet.cornerDownRight;\n if (has('up') && has('left') && !has('down') && !has('right')) return alphabet.cornerUpLeft;\n if (has('down') && has('left') && !has('up') && !has('right')) return alphabet.cornerDownLeft;\n if (has('up') && !has('down') && !has('left') && !has('right')) return alphabet.arrowUp;\n if (has('down') && !has('up') && !has('left') && !has('right')) return alphabet.arrowDown;\n\n // Fallback: shouldn't happen in well-formed grids\n return alphabet.fallback;\n}\n\n// ---------------------------------------------------------------------------\n// renderCell — project one cell to a coloured string fragment.\n// ---------------------------------------------------------------------------\n\nconst NO_COLOR: Colorizer = (t) => t;\n\nfunction renderCell(cell: Cell, colorEnabled: boolean, alphabet: GraphGlyphAlphabet): string {\n // Node marker overrides everything\n if (cell.node !== undefined) {\n // Every node uses ○ — the ∅ identifier is only used as the label, not as a\n // glyph, per the golden colour model. Colour by role (focus) or lane (flat).\n const colorize = !colorEnabled\n ? NO_COLOR\n : cell.node.role !== undefined\n ? roleColor(cell.node.role)\n : laneColor(cell.node.lane);\n return colorize(alphabet.node);\n }\n\n if (cell.lines.length === 0) {\n return ' ';\n }\n\n // Pick the drawn line by occlusion: lowest plane number wins (drawn on top).\n // At an equal plane, on-path beats off-path explicitly — never rely on array\n // order to break the tie (the single-owner invariant should already prevent\n // a same-plane on/off-path collision, but the priority is made explicit here).\n const topLine = cell.lines.reduce<CellLine>((best, current) => {\n if (current.plane < best.plane) return current;\n if (current.plane > best.plane) return best;\n if (current.line.role === 'on-path' && best.line.role !== 'on-path') return current;\n return best;\n }, cell.lines[0]!);\n\n const glyph =\n topLine.selfLoop === true\n ? alphabet.selfLoop\n : topLine.landingArrow === true\n ? alphabet.landingArrow\n : glyphFor(topLine.directions, alphabet);\n const colorize = !colorEnabled\n ? NO_COLOR\n : topLine.line.role !== undefined\n ? roleColor(topLine.line.role)\n : laneColor(topLine.line.lane);\n return colorize(glyph);\n}\n\n// ---------------------------------------------------------------------------\n// RenderGridOptions\n// ---------------------------------------------------------------------------\n\nexport interface RenderGridOptions {\n readonly colorize?: boolean;\n readonly colsPerLane?: number;\n readonly glyphMode?: GraphGlyphMode;\n}\n\n// ---------------------------------------------------------------------------\n// renderGrid — the main render function.\n//\n// Produces the final string: one line per grid row, each cell rendered to\n// a coloured character. Trailing empty cells are trimmed, but we always\n// include up to the last non-empty cell's connector column\n// (the full 2-col-per-lane width for the active lane count).\n// ---------------------------------------------------------------------------\n\n/**\n * Render a single grid row to a coloured string. A completely empty row returns\n * the empty string (the row is NOT dropped) so callers that pair grid rows with\n * an external per-row label list keep a 1:1 index correspondence. `renderGrid`\n * itself drops empty rows for its standalone output (but preserves separator rows).\n */\nexport function renderGridRow(\n row: readonly (Cell | undefined)[],\n opts: RenderGridOptions = {},\n): string {\n // Inter-component separator row — always renders as an empty line.\n if (row[0]?.separator === true) {\n return '';\n }\n\n // Find the last non-empty cell index\n let lastNonEmpty = -1;\n for (let i = row.length - 1; i >= 0; i--) {\n const cell = row[i];\n if (cell !== undefined && (cell.lines.length > 0 || cell.node !== undefined)) {\n lastNonEmpty = i;\n break;\n }\n }\n\n if (lastNonEmpty < 0) {\n return '';\n }\n\n // Extend to the next even column boundary (connector col of the current lane)\n // so that connector columns are always present for active lane ranges.\n const colsPerLane = opts.colsPerLane ?? DEFAULT_COLS_PER_LANE;\n const colorEnabled = opts.colorize ?? true;\n const alphabet = alphabetFor(opts.glyphMode ?? 'unicode');\n const lastLane = Math.floor(lastNonEmpty / colsPerLane);\n const lastConnectorCol = lastLane * colsPerLane + (colsPerLane - 1);\n const renderThrough = Math.max(lastNonEmpty, lastConnectorCol);\n\n let line = '';\n for (let col = 0; col <= Math.min(renderThrough, row.length - 1); col++) {\n const cell = row[col];\n line += cell === undefined ? ' ' : renderCell(cell, colorEnabled, alphabet);\n }\n return line;\n}\n\nexport function renderGrid(grid: Grid, opts: RenderGridOptions = {}): string {\n const lines: string[] = [];\n for (const row of grid) {\n const isSeparator = row[0]?.separator === true;\n const rendered = renderGridRow(row, opts);\n if (rendered === '' && !isSeparator) {\n // Completely empty non-separator row — skip in standalone output.\n continue;\n }\n lines.push(rendered);\n }\n return lines.join('\\n');\n}\n","import stringWidth from 'string-width';\nimport type { GlyphMode } from '../glyph-mode';\n\nexport const MIGRATION_LIST_HASH_WIDTH = 7;\nexport const MIGRATION_LIST_EMPTY_SOURCE = '∅';\nexport const MIGRATION_LIST_ASCII_EMPTY_SOURCE = '-';\nexport const MIGRATION_LIST_FORWARD_EDGE_GLYPH = '→';\nexport const MIGRATION_LIST_ASCII_FORWARD_EDGE_GLYPH = '->';\n\nexport function migrationListForwardArrow(glyphMode: GlyphMode): string {\n return glyphMode === 'ascii'\n ? MIGRATION_LIST_ASCII_FORWARD_EDGE_GLYPH\n : MIGRATION_LIST_FORWARD_EDGE_GLYPH;\n}\n\nexport function migrationListEmptySource(glyphMode: GlyphMode): string {\n return glyphMode === 'ascii' ? MIGRATION_LIST_ASCII_EMPTY_SOURCE : MIGRATION_LIST_EMPTY_SOURCE;\n}\n\nexport function abbreviateContractHash(hash: string): string {\n const stripped = hash.startsWith('sha256:') ? hash.slice(7) : hash;\n return stripped.slice(0, MIGRATION_LIST_HASH_WIDTH);\n}\n\nexport function padFromHashColumn(text: string, width: number): string {\n const padding = Math.max(0, width - stringWidth(text));\n return `${' '.repeat(padding)}${text}`;\n}\n","/**\n * Grid layout for the line/plane/occlusion migration-graph renderer.\n *\n * Produces a Grid (rows × cells) from a MigrationGraphRowModel. Each node\n * emits: fork connector, self-loop rows, node row, merge connector, and\n * inbound migration rows — in display order (tips first, then roots).\n */\n\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport {\n type Cell,\n type CellLine,\n DEFAULT_COLS_PER_LANE,\n type Direction,\n type Grid,\n type GridOptions,\n type Highlight,\n type LineRef,\n type NodeRef,\n type PathRole,\n} from './migration-graph-model';\nimport type { ClassifiedEdge, MigrationGraphRowModel } from './migration-graph-rows';\n\n// ---------------------------------------------------------------------------\n// Internal: lane + rank assignment\n// ---------------------------------------------------------------------------\n\ninterface LaneAssignment {\n nodeLane: Map<string, number>;\n nodeRank: Map<string, number>;\n /**\n * Per-edge lane override. Set for \"direct fork-to-merge\" branch edges whose\n * endpoints both land on lane 0 after merge reconciliation, but whose BFS\n * traversal allocated them a non-zero branch lane. Using this override lets\n * the branch edge render in its branch column even when the merge tip was\n * pulled back to the trunk lane.\n */\n edgeLane: Map<string, number>;\n /** Total number of lanes allocated. */\n numLanes: number;\n}\n\nfunction buildLaneAssignment(\n nodes: readonly (string | null)[],\n edges: readonly ClassifiedEdge[],\n): LaneAssignment {\n // Separate forward (non-self) edges\n const fwdEdges = edges.filter((e) => e.kind === 'forward' && e.from !== e.to);\n\n // Build outbound/inbound adjacency sorted by dirName\n const outbound = new Map<string, ClassifiedEdge[]>();\n const inbound = new Map<string, ClassifiedEdge[]>();\n for (const edge of fwdEdges) {\n const ob = outbound.get(edge.from);\n if (ob) ob.push(edge);\n else outbound.set(edge.from, [edge]);\n\n const ib = inbound.get(edge.to);\n if (ib) ib.push(edge);\n else inbound.set(edge.to, [edge]);\n }\n for (const list of outbound.values()) list.sort((a, b) => a.dirName.localeCompare(b.dirName));\n for (const list of inbound.values()) list.sort((a, b) => a.dirName.localeCompare(b.dirName));\n\n // Split nodes into per-component groups (null sentinels separate components)\n const components: string[][] = [];\n let current: string[] = [];\n for (const n of nodes) {\n if (n === null) {\n if (current.length > 0) components.push(current);\n current = [];\n } else {\n current.push(n);\n }\n }\n if (current.length > 0) components.push(current);\n\n // Global rank map (longest-forward-path; computed across all nodes together\n // so rollback edges crossing components don't interfere with rank within each)\n const allNodes = new Set<string>();\n for (const n of nodes) {\n if (n !== null) allNodes.add(n);\n }\n const nodeRank = new Map<string, number>();\n for (const n of allNodes) nodeRank.set(n, 0);\n for (let pass = 0; pass < allNodes.size; pass++) {\n let changed = false;\n for (const [from, es] of outbound) {\n const base = nodeRank.get(from) ?? 0;\n for (const e of es) {\n const next = base + 1;\n if (next > (nodeRank.get(e.to) ?? 0)) {\n nodeRank.set(e.to, next);\n changed = true;\n }\n }\n }\n if (!changed) break;\n }\n\n // Lane assignment: BFS per component, resetting nextLane to 0 for each.\n // Each component's roots start at lane 0, so disconnected components never\n // interleave lanes.\n const nodeLane = new Map<string, number>();\n // Per-edge lane: records the BFS-allocated branch lane for each edge. Used\n // to preserve branch-column rendering even after merge-tip reconciliation.\n const edgeLane = new Map<string, number>();\n let totalLanes = 0;\n\n for (const componentNodes of components) {\n const componentSet = new Set(componentNodes);\n let nextLane = 0;\n\n const roots: string[] = [];\n for (const n of componentNodes) {\n if ((inbound.get(n) ?? []).length === 0) roots.push(n);\n }\n roots.sort((a, b) => {\n if (a === EMPTY_CONTRACT_HASH) return -1;\n if (b === EMPTY_CONTRACT_HASH) return 1;\n return a.localeCompare(b);\n });\n\n const bfsQueue: Array<{ node: string; lane: number }> = [];\n for (const root of roots) {\n if (!nodeLane.has(root)) {\n nodeLane.set(root, nextLane++);\n bfsQueue.push({ node: root, lane: nodeLane.get(root)! });\n }\n }\n\n let head = 0;\n while (head < bfsQueue.length) {\n const item = bfsQueue[head++]!;\n const { node, lane } = item;\n const children = outbound.get(node) ?? [];\n let first = true;\n for (const childEdge of children) {\n const child = childEdge.to;\n if (!componentSet.has(child)) continue;\n if (!nodeLane.has(child)) {\n const childLane = first ? lane : nextLane++;\n nodeLane.set(child, childLane);\n bfsQueue.push({ node: child, lane: childLane });\n edgeLane.set(childEdge.migrationHash, childLane);\n } else {\n // Child already assigned — record this edge's lane as the max of the\n // parent's lane and the child's current lane (same as the original\n // Math.max formula). May be updated by reconciliation below for trunk\n // edges into reconciled merge nodes.\n edgeLane.set(childEdge.migrationHash, Math.max(lane, nodeLane.get(child)!));\n }\n first = false;\n }\n }\n\n // Isolated nodes within the component\n for (const n of componentNodes) {\n if (!nodeLane.has(n)) nodeLane.set(n, nextLane++);\n }\n\n // Merge-node lane reconciliation: a node with multiple inbound forward edges\n // should sit on the lane of its highest-rank parent (furthest along the\n // longest path). When a short arm and a long arm converge, the merge node\n // follows the long arm's lane.\n //\n // When a merge node's lane changes, update the edgeLane for all edges\n // pointing TO that node so they reflect the reconciled column. Edges from\n // nodes that were on a BRANCH (non-trunk) lane keep their original branch\n // lane so the branch column renders correctly.\n for (const n of componentNodes) {\n const parents = inbound.get(n);\n if (!parents || parents.length <= 1) continue;\n let trunkParent = parents[0]!.from;\n let trunkRank = nodeRank.get(trunkParent) ?? 0;\n let trunkLane = nodeLane.get(trunkParent) ?? 0;\n for (let i = 1; i < parents.length; i++) {\n const parent = parents[i]!.from;\n const rank = nodeRank.get(parent) ?? 0;\n const lane = nodeLane.get(parent) ?? 0;\n if (rank > trunkRank || (rank === trunkRank && lane < trunkLane)) {\n trunkParent = parent;\n trunkRank = rank;\n trunkLane = lane;\n }\n }\n const trunkParentLane = nodeLane.get(trunkParent) ?? 0;\n const currentNodeLane = nodeLane.get(n) ?? 0;\n if (currentNodeLane === trunkParentLane) continue;\n\n nodeLane.set(n, trunkParentLane);\n\n // Update edgeLane for each inbound edge:\n // - Trunk edge (from the highest-rank parent): use the trunk lane\n // - Branch edges: keep the ORIGINAL edgeLane (the branch column), so\n // the branch edge still renders in its allocated branch column.\n for (const parentEdge of parents) {\n const isFromTrunkParent = parentEdge.from === trunkParent;\n if (isFromTrunkParent) {\n edgeLane.set(parentEdge.migrationHash, trunkParentLane);\n }\n // Branch edges keep whatever lane they were assigned during BFS.\n }\n\n // Propagate the lane change to forward descendants that inherited the\n // old lane. BFS from this merge node through outbound edges: any\n // descendant still on oldLane moves to the new (trunk) lane. Stop the\n // traversal at nodes that are already on a different lane — they belong\n // to branches that forked independently and must not move.\n const bfsDescendants: string[] = [n];\n let descHead = 0;\n while (descHead < bfsDescendants.length) {\n const current = bfsDescendants[descHead++]!;\n const children = outbound.get(current) ?? [];\n for (const childEdge of children) {\n const child = childEdge.to;\n if (!componentSet.has(child)) continue;\n if ((nodeLane.get(child) ?? 0) !== currentNodeLane) continue;\n nodeLane.set(child, trunkParentLane);\n // Update the edge lane for the edge from current→child\n const existingEdgeLane = edgeLane.get(childEdge.migrationHash);\n if (existingEdgeLane !== undefined && existingEdgeLane === currentNodeLane) {\n edgeLane.set(childEdge.migrationHash, trunkParentLane);\n }\n bfsDescendants.push(child);\n }\n }\n }\n\n if (nextLane > totalLanes) totalLanes = nextLane;\n }\n\n return { nodeLane, nodeRank, edgeLane, numLanes: totalLanes };\n}\n\n// ---------------------------------------------------------------------------\n// Internal: display order\n// ---------------------------------------------------------------------------\n\ninterface NodeDisplay {\n hash: string;\n lane: number;\n rank: number;\n}\n\n/**\n * A `null` sentinel in the display order marks a component boundary.\n * The grid builder emits a separator row at each boundary.\n */\ntype NodeDisplayOrSeparator = NodeDisplay | null;\n\nfunction computeDisplayOrder(\n nodes: readonly (string | null)[],\n nodeLane: Map<string, number>,\n nodeRank: Map<string, number>,\n): NodeDisplayOrSeparator[] {\n const seen = new Set<string>();\n const result: NodeDisplayOrSeparator[] = [];\n\n // Collect each component's nodes then sort within it (rank desc, lane asc).\n // null sentinels mark component boundaries; they become separator entries.\n let componentBuffer: NodeDisplay[] = [];\n\n function flushComponent(): void {\n componentBuffer.sort((a, b) => b.rank - a.rank || a.lane - b.lane);\n for (const d of componentBuffer) result.push(d);\n componentBuffer = [];\n }\n\n for (const n of nodes) {\n if (n === null) {\n flushComponent();\n result.push(null);\n continue;\n }\n if (seen.has(n)) continue;\n seen.add(n);\n componentBuffer.push({ hash: n, lane: nodeLane.get(n) ?? 0, rank: nodeRank.get(n) ?? 0 });\n }\n flushComponent();\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: grid row builder\n// ---------------------------------------------------------------------------\n\ntype CellsRow = Cell[];\n\n/** Create an empty cell. */\nfunction emptyCell(): Cell {\n return { lines: [] };\n}\n\n// ---------------------------------------------------------------------------\n// buildGrid — main entry point\n// ---------------------------------------------------------------------------\n\nexport function buildGrid(\n rowModel: MigrationGraphRowModel,\n opts: GridOptions = {},\n highlight: Highlight = { mode: 'flat', onPath: new Set() },\n): Grid {\n const colsPerLane = opts.colsPerLane ?? DEFAULT_COLS_PER_LANE;\n const isFocus = highlight.mode === 'focus';\n\n const { nodeLane, nodeRank, edgeLane, numLanes } = buildLaneAssignment(\n rowModel.nodes,\n rowModel.edges,\n );\n\n const displayOrder = computeDisplayOrder(rowModel.nodes, nodeLane, nodeRank);\n\n // Display index per node (0 = topmost position; nulls skipped).\n const displayIndex = new Map<string, number>();\n let nodeIdx = 0;\n for (const d of displayOrder) {\n if (d !== null) {\n displayIndex.set(d.hash, nodeIdx++);\n }\n }\n\n // ── Back-arc planning ────────────────────────────────────────────────────\n // Each rollback edge runs against the forward grain. An *adjacent* rollback\n // (target is the display-neighbour directly below the source) is a plain ↓ in\n // the source's own lane. A *node-skipping* rollback is routed on its own\n // back-lane to the right: it tees off the source node row (○─╮), runs a\n // vertical │ down its back-lane, and lands into the target node (◂╯).\n //\n // Three independent numbers per routed back-arc:\n // geomLane — the column its rail occupies. Outermost (largest) goes to the\n // arc reaching the lowest target (ties: higher source first), so\n // interleaving spans cross and nested spans nest cleanly.\n // colourLane — the lane index used purely for colour (flat mode). Assigned\n // by greedy colouring (bottom-up walk; see below) so that no\n // two concurrently-active lanes/arcs share a palette colour,\n // and no arc reuses its origin branch's colour or green.\n // planeLane — the z-order index for occlusion within a shared back-lane.\n // Arcs sharing the same geomLane are sorted by sourceIndex\n // descending: the arc whose source is lowest in display\n // (largest sourceIndex = bottom-most visually) draws on top\n // (smallest planeLane number). Decoupled from colourLane.\n interface RoutedBackArc {\n readonly edge: ClassifiedEdge;\n readonly sourceIndex: number;\n readonly targetIndex: number;\n readonly geomLane: number;\n readonly colourLane: number;\n readonly planeLane: number;\n }\n\n const rollbackEdges = rowModel.edges.filter((e) => e.kind === 'rollback' && e.from !== e.to);\n\n const adjacentRollbacks: ClassifiedEdge[] = [];\n const skippingRollbacks: ClassifiedEdge[] = [];\n for (const e of rollbackEdges) {\n const si = displayIndex.get(e.from);\n const ti = displayIndex.get(e.to);\n if (si === undefined || ti === undefined) continue;\n // Adjacent: target sits directly below the source in display order.\n if (ti === si + 1) adjacentRollbacks.push(e);\n else skippingRollbacks.push(e);\n }\n\n // Convergence: group skipping rollbacks by their target node. Arcs sharing a\n // target share one geometric lane (rail column). Each distinct target gets its\n // own rail; arcs within the group compose via occlusion.\n //\n // geomLane ordering: outermost rail goes to the group whose target is lowest\n // in display order (largest target index — deepest in the chain). Within a\n // group, the group's representative target index drives the ordering.\n const targetGroups = new Map<string, ClassifiedEdge[]>();\n for (const e of skippingRollbacks) {\n const group = targetGroups.get(e.to);\n if (group) group.push(e);\n else targetGroups.set(e.to, [e]);\n }\n // Sort target-group keys: largest target index (lowest in display) → outermost lane.\n const sortedTargetKeys = [...targetGroups.keys()].sort((a, b) => {\n const ta = displayIndex.get(a) ?? 0;\n const tb = displayIndex.get(b) ?? 0;\n return tb - ta; // largest index first = outermost\n });\n const numTargetGroups = sortedTargetKeys.length;\n const geomLaneOf = new Map<string, number>();\n const outermostGroup = numLanes + numTargetGroups - 1;\n sortedTargetKeys.forEach((targetHash, i) => {\n const groupGeomLane = outermostGroup - i;\n for (const e of targetGroups.get(targetHash)!) {\n geomLaneOf.set(e.migrationHash, groupGeomLane);\n }\n });\n\n // ── planeLane: z-order for back-arcs ────────────────────────────────────\n // The arc whose source is furthest down the display (largest sourceIndex)\n // draws on top (lowest planeLane). This applies both within shared back-lanes\n // and at crossing points where arcs on different geomLanes overlap.\n // planeLane = totalNodes - sourceIndex gives: larger sourceIndex → smaller value.\n const totalDisplayNodes = displayOrder.filter((d) => d !== null).length;\n const planeLaneOf = new Map<string, number>();\n for (const e of skippingRollbacks) {\n const si = displayIndex.get(e.from) ?? 0;\n planeLaneOf.set(e.migrationHash, totalDisplayNodes - si);\n }\n\n // ── colourLane: greedy assignment (flat mode) ─────────────────────────────\n // Walk displayOrder bottom → top. Maintain the set of concurrently-active\n // palette-colour indices (forward lanes + active back-arc assignments). When\n // a new arc first becomes visible (at its target node, going upward), pick the\n // lowest palette index not in use. Additionally exclude:\n // - the arc's origin lane's colour (nodeLane.get(from) % PALETTE_SIZE)\n // - index 5 (green — reserved for focus on-path)\n // When the arc's source node is processed, release its colour.\n //\n // Forward lanes hold colour = laneIndex % PALETTE_SIZE (unchanged); back-arc\n // colourLane is set to the chosen palette index directly (0–5), so that\n // `colourLane % 6 == chosenIndex`.\n const PALETTE_SIZE = 6;\n const GREEN_PALETTE_IDX = 5;\n\n // Precompute per-arc display indices for the walk.\n const arcSourceIndex = new Map<string, number>();\n const arcTargetIndex = new Map<string, number>();\n for (const e of skippingRollbacks) {\n arcSourceIndex.set(e.migrationHash, displayIndex.get(e.from) ?? 0);\n arcTargetIndex.set(e.migrationHash, displayIndex.get(e.to) ?? 0);\n }\n\n // Build lookup: arcs by target node hash and source node hash.\n const arcsByTarget = new Map<string, ClassifiedEdge[]>();\n const arcsBySource = new Map<string, ClassifiedEdge[]>();\n for (const e of skippingRollbacks) {\n const tb = arcsByTarget.get(e.to);\n if (tb) tb.push(e);\n else arcsByTarget.set(e.to, [e]);\n const sb = arcsBySource.get(e.from);\n if (sb) sb.push(e);\n else arcsBySource.set(e.from, [e]);\n }\n\n // Greedy walk: bottom → top through displayOrder.\n const colourLaneOf = new Map<string, number>();\n // activeArcColours: migHash → palette index currently in use by that arc.\n const activeArcColours = new Map<string, number>();\n // activeFwdLaneColours: set of palette indices held by currently-active forward lanes.\n const activeFwdLaneColours = new Set<number>();\n\n for (let i = displayOrder.length - 1; i >= 0; i--) {\n const nd = displayOrder[i];\n if (nd === null || nd === undefined) continue; // separator or missing — skip\n\n const { hash: nodeHash } = nd;\n const nodeFwdLane = nodeLane.get(nodeHash) ?? 0;\n\n // 1. Activate this node's forward lane (if not already active from a lower node).\n activeFwdLaneColours.add(nodeFwdLane % PALETTE_SIZE);\n\n // 2. Assign colour to arcs that TARGET this node. They become visible\n // starting here, running upward to their source.\n const incomingArcs = arcsByTarget.get(nodeHash) ?? [];\n // Process in a stable order (dirName) for determinism.\n const sortedIncoming = [...incomingArcs].sort((a, b) => a.dirName.localeCompare(b.dirName));\n for (const arc of sortedIncoming) {\n const originLaneColour = (nodeLane.get(arc.from) ?? 0) % PALETTE_SIZE;\n // Colours currently occupied.\n const occupied = new Set<number>(activeFwdLaneColours);\n for (const c of activeArcColours.values()) occupied.add(c);\n occupied.add(GREEN_PALETTE_IDX);\n occupied.add(originLaneColour);\n // Pick the lowest free index; if all are taken, pick lowest excluding green.\n let chosen = -1;\n for (let ci = 0; ci < PALETTE_SIZE; ci++) {\n if (!occupied.has(ci)) {\n chosen = ci;\n break;\n }\n }\n if (chosen === -1) {\n // Palette exhausted — forced reuse. Pick lowest excluding green.\n for (let ci = 0; ci < PALETTE_SIZE; ci++) {\n if (ci !== GREEN_PALETTE_IDX) {\n chosen = ci;\n break;\n }\n }\n }\n colourLaneOf.set(arc.migrationHash, chosen === -1 ? 0 : chosen);\n activeArcColours.set(arc.migrationHash, chosen === -1 ? 0 : chosen);\n }\n\n // 3. Release arcs that SOURCE at this node. Their rail runs from here\n // downward; above this node they're gone.\n for (const arc of arcsBySource.get(nodeHash) ?? []) {\n activeArcColours.delete(arc.migrationHash);\n }\n }\n\n const routedBackArcs: RoutedBackArc[] = skippingRollbacks.map((e) => ({\n edge: e,\n sourceIndex: displayIndex.get(e.from) ?? 0,\n targetIndex: displayIndex.get(e.to) ?? 0,\n geomLane: geomLaneOf.get(e.migrationHash) ?? numLanes,\n colourLane: colourLaneOf.get(e.migrationHash) ?? 0,\n planeLane: planeLaneOf.get(e.migrationHash) ?? numLanes,\n }));\n\n const backArcsBySource = new Map<string, RoutedBackArc[]>();\n const backArcsByTarget = new Map<string, RoutedBackArc[]>();\n for (const arc of routedBackArcs) {\n const sb = backArcsBySource.get(arc.edge.from);\n if (sb) sb.push(arc);\n else backArcsBySource.set(arc.edge.from, [arc]);\n const tb = backArcsByTarget.get(arc.edge.to);\n if (tb) tb.push(arc);\n else backArcsByTarget.set(arc.edge.to, [arc]);\n }\n\n const adjacentBySource = new Map<string, ClassifiedEdge[]>();\n const adjacentByTarget = new Map<string, ClassifiedEdge[]>();\n for (const e of adjacentRollbacks) {\n const b = adjacentBySource.get(e.from);\n if (b) b.push(e);\n else adjacentBySource.set(e.from, [e]);\n const t = adjacentByTarget.get(e.to);\n if (t) t.push(e);\n else adjacentByTarget.set(e.to, [e]);\n }\n for (const list of adjacentBySource.values())\n list.sort((a, b) => a.dirName.localeCompare(b.dirName));\n\n const numBackLanes = numTargetGroups;\n const totalCols = (numLanes + numBackLanes) * colsPerLane;\n\n // Build edge lookup maps (classified)\n const fwdEdges = rowModel.edges.filter((e) => e.kind === 'forward' && e.from !== e.to);\n const selfEdges = rowModel.edges.filter((e) => e.kind === 'self');\n\n // outbound sorted by migrationHash\n const outboundFwd = new Map<string, ClassifiedEdge[]>();\n const inboundFwd = new Map<string, ClassifiedEdge[]>();\n for (const e of fwdEdges) {\n const ob = outboundFwd.get(e.from);\n if (ob) ob.push(e);\n else outboundFwd.set(e.from, [e]);\n const ib = inboundFwd.get(e.to);\n if (ib) ib.push(e);\n else inboundFwd.set(e.to, [e]);\n }\n for (const list of outboundFwd.values()) list.sort((a, b) => a.dirName.localeCompare(b.dirName));\n for (const list of inboundFwd.values()) list.sort((a, b) => a.dirName.localeCompare(b.dirName));\n\n const selfEdgesByNode = new Map<string, ClassifiedEdge[]>();\n for (const e of selfEdges) {\n const bucket = selfEdgesByNode.get(e.from);\n if (bucket) bucket.push(e);\n else selfEdgesByNode.set(e.from, [e]);\n }\n for (const list of selfEdgesByNode.values())\n list.sort((a, b) => a.dirName.localeCompare(b.dirName));\n\n // ── Role + plane: mode/z-order seam ──────────────────────────────────────\n // role(migrationHash): focus → on-path/off-path from highlight.onPath; flat → undefined.\n function roleOf(migrationHash: string): PathRole | undefined {\n if (!isFocus) return undefined;\n return highlight.onPath.has(migrationHash) ? 'on-path' : 'off-path';\n }\n\n // On-path node set: a node is on-path iff an on-path edge touches it (from or\n // to) — forward, self, OR rollback (a back-arc's endpoints are on its route).\n const onPathNodes = new Set<string>();\n if (isFocus) {\n for (const e of [...fwdEdges, ...selfEdges, ...rollbackEdges]) {\n if (highlight.onPath.has(e.migrationHash)) {\n onPathNodes.add(e.from);\n onPathNodes.add(e.to);\n }\n }\n }\n function nodeRoleOf(hash: string): PathRole | undefined {\n if (!isFocus) return undefined;\n return onPathNodes.has(hash) ? 'on-path' : 'off-path';\n }\n\n // planeOf — z-order. Lower number = drawn on top.\n // flat: trunk on top → plane = lane (lane 0 topmost).\n // focus: on-path on top → on-path = plane 0; off-path sits beneath it,\n // ordered by lane so a deterministic owner survives among off-path lines.\n function planeOf(lane: number, role: PathRole | undefined): number {\n if (!isFocus) return lane;\n return role === 'on-path' ? 0 : lane + 1;\n }\n\n // ── LineRef + cell builders (role-aware) ─────────────────────────────────\n function lineRefFor(edge: ClassifiedEdge, lane: number): LineRef {\n return {\n migrationHash: edge.migrationHash,\n dirName: edge.dirName,\n lane,\n role: roleOf(edge.migrationHash),\n };\n }\n\n /** Synthetic LineRef for a lane carrying a representative edge's role (pass-through). */\n function passLineRef(lane: number, dirName: string, migHash: string): LineRef {\n return { migrationHash: migHash, dirName, lane, role: roleOf(migHash) };\n }\n\n function vertCell(line: LineRef): Cell {\n return {\n lines: [\n {\n line,\n directions: new Set<Direction>(['up', 'down']),\n plane: planeOf(line.lane, line.role),\n },\n ],\n };\n }\n\n function dirCell(line: LineRef, dirs: ReadonlySet<Direction>): Cell {\n return { lines: [{ line, directions: dirs, plane: planeOf(line.lane, line.role) }] };\n }\n\n function nodeCell(nodeRef: NodeRef): Cell {\n return { node: nodeRef, lines: [] };\n }\n\n // Pass-through colour follows the edge CURRENTLY occupying a lane at this row,\n // not a lane-wide average. A single lane carries different edges (with different\n // roles) over its vertical extent — e.g. lane 0 below a fork carries the trunk\n // branch (off-path) above the fork node and the trunk's parent edge (on-path)\n // below it. We track the active edge per lane as we descend top-to-bottom and\n // colour pass-through verticals from it. `laneCurrentEdge[L]` = the edge whose\n // vertical body currently runs through lane L at the row being emitted.\n const laneCurrentEdge = new Map<number, ClassifiedEdge>();\n\n function getRepLine(lane: number): LineRef {\n const e = laneCurrentEdge.get(lane);\n if (e) return lineRefFor(e, lane);\n return passLineRef(lane, `lane${lane}`, `lane${lane}`);\n }\n\n // Active lanes: set of lane indices currently visible (vertical passes through them)\n const activeLanes = new Set<number>();\n\n const grid: Cell[][] = [];\n\n function makeRow(): CellsRow {\n return Array.from({ length: totalCols }, () => emptyCell());\n }\n\n // Place vertical pass-throughs for all active lanes in a row, skipping specified lanes.\n function placeVerticals(row: CellsRow, skip: Set<number>): void {\n for (const lane of activeLanes) {\n if (skip.has(lane)) continue;\n const railCol = lane * colsPerLane;\n const cell = row[railCol];\n if (cell !== undefined && cell.lines.length === 0 && !cell.node) {\n row[railCol] = vertCell(getRepLine(lane));\n }\n }\n }\n\n // ── Back-arc helpers ──────────────────────────────────────────────────────\n // Active routed back-arcs whose vertical currently runs through their geomLane.\n const activeBackArcs = new Set<RoutedBackArc>();\n\n // A back-arc's LineRef carries its colourLane (not its geomLane) so colour is\n // read off the lane that drives the rotation, independent of column placement.\n function backArcLine(arc: RoutedBackArc): LineRef {\n return {\n migrationHash: arc.edge.migrationHash,\n dirName: arc.edge.dirName,\n lane: arc.colourLane,\n role: roleOf(arc.edge.migrationHash),\n };\n }\n\n function backArcPlane(arc: RoutedBackArc): number {\n const role = roleOf(arc.edge.migrationHash);\n if (!isFocus) return arc.planeLane;\n return role === 'on-path' ? 0 : arc.planeLane + 1;\n }\n\n // Compose a CellLine into a row cell (never overwrite — occlusion arbitrates).\n function composeLine(\n row: CellsRow,\n col: number,\n line: LineRef,\n dirs: ReadonlySet<Direction>,\n plane: number,\n extra?: { landingArrow?: boolean },\n ): void {\n const existing = row[col];\n const cellLine: CellLine = {\n line,\n directions: dirs,\n plane,\n ...(extra?.landingArrow ? { landingArrow: true } : {}),\n };\n if (existing && (existing.lines.length > 0 || existing.node)) {\n row[col] = { ...existing, lines: [...existing.lines, cellLine] };\n } else {\n row[col] = { lines: [cellLine] };\n }\n }\n\n // Place verticals for every active back-arc on this row (in its geomLane rail).\n function placeBackVerticals(row: CellsRow): void {\n for (const arc of activeBackArcs) {\n const railCol = arc.geomLane * colsPerLane;\n composeLine(\n row,\n railCol,\n backArcLine(arc),\n new Set<Direction>(['up', 'down']),\n backArcPlane(arc),\n );\n }\n placeAdjacentOverlays(row);\n }\n\n // Adjacent rollbacks share the source's own lane: their vertical body overlays\n // the forward trunk between source and target. In focus, an on-path adjacent\n // rollback lifts that segment of the trunk to the top plane (drawn green); in\n // flat it sits at the same plane/colour as the trunk, so it is a no-op there.\n interface ActiveAdjacent {\n readonly lane: number;\n readonly edge: ClassifiedEdge;\n }\n const activeAdjacent = new Set<ActiveAdjacent>();\n\n function placeAdjacentOverlays(row: CellsRow): void {\n for (const adj of activeAdjacent) {\n const railCol = adj.lane * colsPerLane;\n const cell = row[railCol];\n if (cell?.node) continue; // never overlay a node marker\n const line = lineRefFor(adj.edge, adj.lane);\n composeLine(\n row,\n railCol,\n line,\n new Set<Direction>(['up', 'down']),\n planeOf(adj.lane, line.role),\n );\n }\n }\n\n // Tee a routed back-arc off its source node row: a horizontal bridge from the\n // node's connector column across to the back-lane rail, ending in a ╮ corner\n // (down+left). Composed (not overwritten) so it occludes / is occluded by any\n // back-arc vertical it crosses.\n function emitBackArcTee(row: CellsRow, nodeLaneNum: number, arc: RoutedBackArc): void {\n const nodeRail = nodeLaneNum * colsPerLane;\n const geomRail = arc.geomLane * colsPerLane;\n const line = backArcLine(arc);\n const plane = backArcPlane(arc);\n for (let col = nodeRail + 1; col < geomRail; col++) {\n composeLine(row, col, line, new Set<Direction>(['left', 'right']), plane);\n }\n composeLine(row, geomRail, line, new Set<Direction>(['down', 'left']), plane);\n }\n\n // Land a routed back-arc into its target node row: a ◂ arrowhead in the node's\n // connector column, a horizontal bridge across to the back-lane rail, ending in\n // a ╯ corner (up+left). Composed so the on-top arc draws the anchor and the\n // others yield their corners beneath it (occlusion arbitrates).\n function emitBackArcLanding(row: CellsRow, nodeLaneNum: number, arc: RoutedBackArc): void {\n const nodeRail = nodeLaneNum * colsPerLane;\n const geomRail = arc.geomLane * colsPerLane;\n const line = backArcLine(arc);\n const plane = backArcPlane(arc);\n composeLine(row, nodeRail + 1, line, new Set<Direction>(['left', 'right']), plane, {\n landingArrow: true,\n });\n for (let col = nodeRail + 2; col < geomRail; col++) {\n composeLine(row, col, line, new Set<Direction>(['left', 'right']), plane);\n }\n composeLine(row, geomRail, line, new Set<Direction>(['up', 'left']), plane);\n }\n\n // Emit a connector row (fork or merge).\n //\n // The CONTINUOUS lane gets the unbroken vertical/sweep; every other\n // participating lane yields into its own corner. In flat mode the continuous\n // lane is the trunk (lane of the node); in focus mode it is the on-path lane\n // (the inbound/outbound edge whose migration is on-path), so the chosen route\n // is drawn as one continuous green line sweeping the merge/fork.\n //\n // Geometry is identical regardless of which lane is continuous; only the\n // NODE-ANCHOR glyph at the trunk rail changes:\n // continuous == trunk → │ (vertical, the trunk passes straight through)\n // continuous == a branch → corner toward that branch\n // merge: ╰ (up+right) fork: ╭ (down+right)\n // The branch's own rail always carries its yield corner (merge ╮ / fork ╯), and\n // the cells between carry horizontals. The continuous (on-path) sweep is placed\n // on the top plane so it occludes the trunk's vertical at the node anchor.\n function emitConnectorRow(\n trunkLane: number,\n branchEntries: readonly { lane: number; edge: ClassifiedEdge }[],\n connectorType: 'fork' | 'merge',\n trunkEdge: ClassifiedEdge | undefined,\n ): CellsRow {\n const row = makeRow();\n const sorted = [...branchEntries].sort((a, b) => a.lane - b.lane);\n if (sorted.length === 0) return row;\n\n const branchByLane = new Map<number, ClassifiedEdge>();\n for (const b of sorted) branchByLane.set(b.lane, b.edge);\n\n // Continuous lane: the on-path participant in focus, else the trunk.\n let continuousLane = trunkLane;\n if (isFocus) {\n if (trunkEdge && highlight.onPath.has(trunkEdge.migrationHash)) {\n continuousLane = trunkLane;\n } else {\n const onPathBranch = sorted.find((b) => highlight.onPath.has(b.edge.migrationHash));\n if (onPathBranch) continuousLane = onPathBranch.lane;\n }\n }\n\n const trunkRailCol = trunkLane * colsPerLane;\n const continuousRailCol = continuousLane * colsPerLane;\n\n // Add a CellLine to a cell (compose, don't overwrite) so occlusion arbitrates.\n function addLine(col: number, line: LineRef, dirs: ReadonlySet<Direction>): void {\n const existing = row[col];\n const cellLine: CellLine = { line, directions: dirs, plane: planeOf(line.lane, line.role) };\n row[col] =\n existing && existing.lines.length > 0\n ? { ...existing, lines: [...existing.lines, cellLine] }\n : { lines: [cellLine] };\n }\n\n const cornerLeftDown: ReadonlySet<Direction> =\n connectorType === 'merge'\n ? new Set<Direction>(['left', 'down'])\n : new Set<Direction>(['left', 'up']);\n\n // ── Base plane: every yielding branch lays its own corner + the horizontal\n // segment to its left (up to the previous branch's rail). These sit on the\n // branch's lane plane; where the continuous sweep crosses them it occludes.\n for (let i = 0; i < sorted.length; i++) {\n const b = sorted[i]!;\n if (b.lane === continuousLane) continue; // continuous drawn separately, on top\n const branchLine = lineRefFor(b.edge, b.lane);\n const railCol = b.lane * colsPerLane;\n addLine(railCol, branchLine, cornerLeftDown);\n const leftBound = i === 0 ? trunkRailCol + 1 : sorted[i - 1]!.lane * colsPerLane + 1;\n for (let col = leftBound; col < railCol; col++) {\n addLine(col, branchLine, new Set<Direction>(['left', 'right']));\n }\n }\n\n // ── The continuous line ──────────────────────────────────────────────────\n const continuousLine: LineRef =\n continuousLane === trunkLane\n ? trunkEdge\n ? lineRefFor(trunkEdge, trunkLane)\n : getRepLine(trunkLane)\n : lineRefFor(branchByLane.get(continuousLane)!, continuousLane);\n\n if (continuousLane === trunkLane) {\n // Trunk passes straight through the node anchor (│), branches yield to it.\n addLine(trunkRailCol, continuousLine, new Set<Direction>(['up', 'down']));\n } else {\n // A branch is continuous: it sweeps from the node anchor across to its own\n // rail, on the TOP plane, occluding the trunk vertical and any intermediate\n // yielding branch corners it passes over.\n const anchorDirs: ReadonlySet<Direction> =\n connectorType === 'merge'\n ? new Set<Direction>(['up', 'right'])\n : new Set<Direction>(['down', 'right']);\n addLine(trunkRailCol, continuousLine, anchorDirs);\n for (let col = trunkRailCol + 1; col < continuousRailCol; col++) {\n addLine(col, continuousLine, new Set<Direction>(['left', 'right']));\n }\n addLine(continuousRailCol, continuousLine, cornerLeftDown);\n }\n\n // Other active lanes (not trunk, not branch): vertical pass-through.\n const skipSet = new Set<number>([trunkLane, ...sorted.map((b) => b.lane)]);\n placeVerticals(row, skipSet);\n placeBackVerticals(row);\n\n return row;\n }\n\n // Process each node in display order; null = component boundary → separator row\n for (const nodeDisplay of displayOrder) {\n if (nodeDisplay === null) {\n // Emit one blank separator row between disconnected components.\n const sepRow = makeRow();\n sepRow[0] = { lines: [], separator: true };\n grid.push(sepRow);\n continue;\n }\n\n const { hash: nodeHash } = nodeDisplay;\n const nodeLaneNum = nodeLane.get(nodeHash) ?? 0;\n\n activeLanes.add(nodeLaneNum);\n\n // ── 1. Fork connector (BEFORE the node row) ──────────────────────────\n const outEdges = outboundFwd.get(nodeHash) ?? [];\n if (outEdges.length > 1) {\n // Use the per-edge lane for branch children so that \"direct fork-to-merge\"\n // edges (whose target was reconciled back to trunk lane) still appear in\n // their allocated branch column.\n const trunkEdgeForFork = outEdges[0]!;\n const trunkChildLane =\n edgeLane.get(trunkEdgeForFork.migrationHash) ??\n nodeLane.get(trunkEdgeForFork.to) ??\n nodeLaneNum;\n const branchEntries = outEdges\n .slice(1)\n .map((e) => ({ lane: edgeLane.get(e.migrationHash) ?? nodeLane.get(e.to) ?? 0, edge: e }))\n .filter((b) => b.lane !== trunkChildLane && activeLanes.has(b.lane));\n\n if (branchEntries.length > 0) {\n const trunkEdge = outEdges[0];\n const connRow = emitConnectorRow(nodeLaneNum, branchEntries, 'fork', trunkEdge);\n grid.push(connRow);\n assertSingleOwner(connRow, isFocus);\n\n for (const b of branchEntries) activeLanes.delete(b.lane);\n }\n }\n\n // ── 2. Self-loop rows (BEFORE the node row) ───────────────────────────\n const selfMigrations = selfEdgesByNode.get(nodeHash) ?? [];\n for (const selfEdge of selfMigrations) {\n const row = makeRow();\n const railCol = nodeLaneNum * colsPerLane;\n const connCol = nodeLaneNum * colsPerLane + 1;\n const line = lineRefFor(selfEdge, nodeLaneNum);\n row[railCol] = vertCell(line);\n row[connCol] = {\n lines: [\n {\n line,\n directions: new Set<Direction>(),\n plane: planeOf(nodeLaneNum, line.role),\n selfLoop: true,\n },\n ],\n };\n placeVerticals(row, new Set([nodeLaneNum]));\n placeBackVerticals(row);\n grid.push(row);\n }\n\n // ── 3. Node row ────────────────────────────────────────────────────────\n {\n const row = makeRow();\n const railCol = nodeLaneNum * colsPerLane;\n const nodeRef: NodeRef = {\n contractHash: nodeHash,\n isEmpty: nodeHash === EMPTY_CONTRACT_HASH,\n lane: nodeLaneNum,\n role: nodeRoleOf(nodeHash),\n };\n row[railCol] = nodeCell(nodeRef);\n placeVerticals(row, new Set([nodeLaneNum]));\n\n // A back-arc landing ends its vertical at this row, replacing it with a ╯\n // corner — so deactivate landing arcs BEFORE placing back verticals. An\n // adjacent rollback's overlay likewise ends at its target node.\n const landingArcs = backArcsByTarget.get(nodeHash) ?? [];\n for (const arc of landingArcs) activeBackArcs.delete(arc);\n for (const adj of [...activeAdjacent]) {\n if (adj.edge.to === nodeHash) activeAdjacent.delete(adj);\n }\n\n placeBackVerticals(row);\n\n // Back-arc landing: arcs targeting this node sweep from the node anchor\n // (◂ arrowhead) across to their own rail corner (╯). The on-top arc draws\n // the anchor; others yield their corners beneath (occlusion arbitrates).\n for (const arc of landingArcs) {\n emitBackArcLanding(row, nodeLaneNum, arc);\n }\n\n // Back-arc tee: arcs sourced at this node tee off the node row into their\n // back-lane (─ bridge + ╮ corner). The vertical begins on the next row.\n const teeArcs = backArcsBySource.get(nodeHash) ?? [];\n for (const arc of teeArcs) {\n emitBackArcTee(row, nodeLaneNum, arc);\n }\n\n grid.push(row);\n\n // Activate the back-arc verticals AFTER the node row so the rail runs from\n // the next row down to (but not including) the target landing row.\n for (const arc of teeArcs) activeBackArcs.add(arc);\n\n // Activate adjacent-rollback overlays sourced here (their trunk overlay\n // runs from the next row down to the target node).\n for (const adj of adjacentBySource.get(nodeHash) ?? []) {\n activeAdjacent.add({ lane: nodeLaneNum, edge: adj });\n }\n }\n\n // Inbound forward edges run down their lanes below this node. Record each as\n // its lane's current edge NOW (before emitting the back-arc arrow rows, merge\n // connector, and migration rows) so pass-through verticals colour from the\n // forward edge actually occupying the trunk below this node.\n //\n // edgeLaneFor: resolve the lane for an inbound forward edge. Uses the\n // per-edge override from edgeLane (set during BFS for branch edges) when\n // available; falls back to Max(fromLane, toLane) for edges not in the map.\n function edgeLaneFor(edge: ClassifiedEdge): number {\n const override = edgeLane.get(edge.migrationHash);\n if (override !== undefined) return override;\n return Math.max(nodeLane.get(edge.from) ?? 0, nodeLane.get(edge.to) ?? 0);\n }\n\n // Sort inEdges so the trunk edge (lowest edgeLane = trunk column) comes\n // first. Ties broken by dirName. This ensures the merge connector treats\n // the trunk-column edge as the trunk regardless of alphabetical order.\n const inEdges = inboundFwd.get(nodeHash) ?? [];\n inEdges.sort((a, b) => {\n const aLane = edgeLaneFor(a);\n const bLane = edgeLaneFor(b);\n if (aLane !== bLane) return aLane - bLane;\n return a.dirName.localeCompare(b.dirName);\n });\n for (const edge of inEdges) {\n laneCurrentEdge.set(edgeLaneFor(edge), edge);\n }\n\n // ── 3b. Back-arc arrow rows ──────────────────────────────────────────────\n // For each routed arc sourced here, a │↓ arrow row in its back-lane sits\n // directly below the source node (before the source node's forward inbound\n // migration rows).\n {\n const teeArcs = backArcsBySource.get(nodeHash) ?? [];\n for (const arc of teeArcs) {\n const row = makeRow();\n const railCol = arc.geomLane * colsPerLane;\n const connCol = railCol + 1;\n const line = backArcLine(arc);\n const plane = backArcPlane(arc);\n composeLine(row, railCol, line, new Set<Direction>(['up', 'down']), plane);\n composeLine(row, connCol, line, new Set<Direction>(['down']), plane);\n placeVerticals(row, new Set<number>());\n placeBackVerticals(row);\n grid.push(row);\n }\n }\n\n // ── 4. Merge connector (AFTER the node row) ────────────────────────────\n if (inEdges.length > 1) {\n const branchEntries = inEdges.slice(1).map((e) => ({ lane: edgeLaneFor(e), edge: e }));\n\n const trunkEdge = inEdges[0];\n const connRow = emitConnectorRow(nodeLaneNum, branchEntries, 'merge', trunkEdge);\n grid.push(connRow);\n assertSingleOwner(connRow, isFocus);\n\n for (const b of branchEntries) activeLanes.add(b.lane);\n }\n\n // ── 5. Migration rows (one per inbound edge, ordered by edge lane) ─────\n for (const edge of inEdges) {\n const eLane = edgeLaneFor(edge);\n const row = makeRow();\n const railCol = eLane * colsPerLane;\n const connCol = eLane * colsPerLane + 1;\n const line = lineRefFor(edge, eLane);\n\n row[railCol] = vertCell(line);\n row[connCol] = dirCell(line, new Set<Direction>(['up']));\n\n placeVerticals(row, new Set([eLane]));\n placeBackVerticals(row);\n grid.push(row);\n }\n\n // ── 5b. Adjacent rollback ↓ rows ─────────────────────────────────────────\n // An adjacent rollback (target is the display-neighbour directly below) is a\n // plain ↓ in the source's own lane — mirror of the forward ↑ — emitted after\n // the source node's forward inbound rows, directly above the target node.\n {\n const adjacents = adjacentBySource.get(nodeHash) ?? [];\n for (const adj of adjacents) {\n const row = makeRow();\n const connCol = nodeLaneNum * colsPerLane + 1;\n const line = lineRefFor(adj, nodeLaneNum);\n const plane = planeOf(nodeLaneNum, line.role);\n // The rail │ belongs to the trunk passing through (drawn by placeVerticals\n // from the lane's current forward edge); only the ↓ arrow is the rollback.\n composeLine(row, connCol, line, new Set<Direction>(['down']), plane);\n placeVerticals(row, new Set<number>());\n placeBackVerticals(row);\n grid.push(row);\n }\n }\n\n // ── 6. Root lane deactivation ─────────────────────────────────────────\n if (inEdges.length === 0) {\n activeLanes.delete(nodeLaneNum);\n }\n }\n\n return grid;\n}\n\n// ---------------------------------------------------------------------------\n// Single-owner invariant — after building a connector row, assert that every\n// cell has at most one DRAWABLE owner once occlusion (topmost plane) is applied.\n// In focus mode a tie at the same plane between an on-path and an off-path line\n// would be a colour ambiguity, so we additionally assert that at the top plane\n// of each cell exactly one role survives.\n// ---------------------------------------------------------------------------\nfunction assertSingleOwner(row: CellsRow, isFocus: boolean): void {\n for (const cell of row) {\n if (cell.lines.length <= 1) continue;\n let topPlane = Number.POSITIVE_INFINITY;\n for (const cl of cell.lines) if (cl.plane < topPlane) topPlane = cl.plane;\n const top = cell.lines.filter((cl: CellLine) => cl.plane === topPlane);\n if (top.length > 1) {\n if (isFocus) {\n const roles = new Set(top.map((cl) => cl.line.role));\n if (roles.size > 1) {\n throw new Error(\n 'migration-graph layout: single-owner invariant violated — two differently-roled lines share the top plane in one cell',\n );\n }\n }\n }\n }\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport type { MigrationListEntry } from './migration-list-types';\n\nexport type MigrationEdgeKind = 'forward' | 'rollback' | 'self';\n\nexport interface MigrationListGraphTopology {\n readonly kindByMigrationHash: ReadonlyMap<string, MigrationEdgeKind>;\n readonly forwardInDegree: ReadonlyMap<string, number>;\n readonly forwardOutDegree: ReadonlyMap<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// Shared classifier — operates on a normalized edge shape for MigrationGraph.\n// ---------------------------------------------------------------------------\n\ninterface NormalizedEdge {\n readonly hash: string;\n readonly from: string;\n readonly to: string;\n readonly dirName: string;\n}\n\nfunction compareDirNameDesc(a: NormalizedEdge, b: NormalizedEdge): number {\n return b.dirName.localeCompare(a.dirName);\n}\n\nfunction bumpDegree(map: Map<string, number>, key: string): void {\n map.set(key, (map.get(key) ?? 0) + 1);\n}\n\nfunction compareNodesRootFirst(a: string, b: string): number {\n if (a === EMPTY_CONTRACT_HASH) return -1;\n if (b === EMPTY_CONTRACT_HASH) return 1;\n return a.localeCompare(b);\n}\n\n/**\n * Shortest-path distance of each node from the forward roots, over the given\n * candidate edges. Roots are the in-degree-0 nodes (baseline first, then lex);\n * a rooted component therefore distances every node by how many forward steps\n * it sits from a root. A component with no root (a pure cycle) is seeded from\n * its single lexically-smallest node so the cycle still gets a stable layering.\n *\n * Crucially this is *shortest* path, not longest: a backward (rollback) edge\n * `deep → shallow` never offers a shorter route to the already-shallower\n * target, so it is inert here. Distances are thus stable whether or not the\n * rollbacks are still in the candidate set — which is what lets the peel below\n * tell a genuine back-edge (target strictly shallower than source) apart from a\n * forward edge that merely happens to share the back-edge's cycle.\n */\nfunction forwardDistances(\n nodes: ReadonlySet<string>,\n candidates: readonly NormalizedEdge[],\n): Map<string, number> {\n const inDegree = new Map<string, number>();\n for (const node of nodes) {\n inDegree.set(node, 0);\n }\n for (const edge of candidates) {\n bumpDegree(inDegree, edge.to);\n }\n\n const roots = [...nodes].filter((node) => (inDegree.get(node) ?? 0) === 0);\n roots.sort(compareNodesRootFirst);\n const seeds = roots.length > 0 ? roots : [...nodes].sort(compareNodesRootFirst).slice(0, 1);\n\n const dist = new Map<string, number>();\n for (const seed of seeds) {\n dist.set(seed, 0);\n }\n\n const maxPasses = nodes.size;\n for (let pass = 0; pass < maxPasses; pass++) {\n let changed = false;\n for (const edge of candidates) {\n const base = dist.get(edge.from);\n if (base === undefined) continue;\n const next = base + 1;\n if (next < (dist.get(edge.to) ?? Number.POSITIVE_INFINITY)) {\n dist.set(edge.to, next);\n changed = true;\n }\n }\n if (!changed) break;\n }\n\n for (const node of nodes) {\n if (!dist.has(node)) {\n dist.set(node, 0);\n }\n }\n\n return dist;\n}\n\nfunction canReachForward(\n start: string,\n goal: string,\n candidates: readonly NormalizedEdge[],\n): boolean {\n if (start === goal) return true;\n\n const outgoing = new Map<string, string[]>();\n for (const edge of candidates) {\n const bucket = outgoing.get(edge.from);\n if (bucket) bucket.push(edge.to);\n else outgoing.set(edge.from, [edge.to]);\n }\n\n const visited = new Set<string>([start]);\n const queue = [start];\n while (queue.length > 0) {\n const node = queue.shift();\n if (node === undefined) continue;\n for (const next of outgoing.get(node) ?? []) {\n if (next === goal) return true;\n if (!visited.has(next)) {\n visited.add(next);\n queue.push(next);\n }\n }\n }\n\n return false;\n}\n\n/**\n * Demote node-skipping rollbacks left forward by the DFS. An edge `from → to`\n * is a rollback exactly when both hold:\n * 1. `to` is a forward-ancestor of `from` — `to` can still reach `from` over\n * the other forward edges, so the edge closes a cycle; and\n * 2. `to` is strictly shallower than `from` (smaller forward distance) — the\n * edge points back toward the root rather than advancing history.\n *\n * Condition 2 is the discriminator: in a cycle created by a rollback every edge\n * satisfies condition 1, but only the rollback itself runs deep → shallow. The\n * forward chain edges run shallow → deep and are never peeled, however many\n * rollbacks converge on the same target. Tight back-edges whose source and\n * target sit at the same distance (mutual two-node cycles) are already resolved\n * by the DFS immediate-parent rule, so they never reach this pass. One edge is\n * peeled per iteration (dirName-descending tie-break) and distances/reachability\n * are recomputed, making the outcome independent of edge input order.\n */\nfunction peelNodeSkippingRollbacks(\n nodes: ReadonlySet<string>,\n kindByMigrationHash: Map<string, MigrationEdgeKind>,\n nonSelf: readonly NormalizedEdge[],\n): void {\n let candidates = nonSelf.filter((edge) => kindByMigrationHash.get(edge.hash) === 'forward');\n\n while (candidates.length > 0) {\n const dist = forwardDistances(nodes, candidates);\n const backEdges = candidates.filter((edge) => {\n const toDist = dist.get(edge.to) ?? 0;\n const fromDist = dist.get(edge.from) ?? 0;\n if (toDist >= fromDist) return false;\n const without = candidates.filter((candidate) => candidate !== edge);\n return canReachForward(edge.to, edge.from, without);\n });\n if (backEdges.length === 0) break;\n\n backEdges.sort(compareDirNameDesc);\n const rollback = backEdges[0];\n if (rollback === undefined) break;\n\n kindByMigrationHash.set(rollback.hash, 'rollback');\n candidates = candidates.filter((edge) => edge !== rollback);\n }\n}\n\n/**\n * DFS with dirName-descending traversal. A GRAY target is a rollback only when it\n * is the immediate DFS parent of the source — cross-links to other GRAY nodes\n * stay forward. A follow-up peel pass demotes node-skipping rollbacks (target is\n * a forward-ancestor of the source and sits strictly shallower than it).\n */\nfunction classifyNormalizedEdges(edges: readonly NormalizedEdge[]): MigrationListGraphTopology {\n const nodes = new Set<string>();\n const kindByMigrationHash = new Map<string, MigrationEdgeKind>();\n const outgoingByFrom = new Map<string, NormalizedEdge[]>();\n const nonSelf: NormalizedEdge[] = [];\n\n for (const edge of edges) {\n nodes.add(edge.from);\n nodes.add(edge.to);\n\n if (edge.from === edge.to) {\n kindByMigrationHash.set(edge.hash, 'self');\n continue;\n }\n\n nonSelf.push(edge);\n const bucket = outgoingByFrom.get(edge.from);\n if (bucket) bucket.push(edge);\n else outgoingByFrom.set(edge.from, [edge]);\n }\n\n for (const bucket of outgoingByFrom.values()) {\n bucket.sort(compareDirNameDesc);\n }\n\n const nonSelfInDegree = new Map<string, number>();\n for (const node of nodes) {\n nonSelfInDegree.set(node, 0);\n }\n for (const bucket of outgoingByFrom.values()) {\n for (const edge of bucket) {\n bumpDegree(nonSelfInDegree, edge.to);\n }\n }\n\n const dfsRoots: string[] = [];\n for (const node of nodes) {\n if ((nonSelfInDegree.get(node) ?? 0) === 0) {\n dfsRoots.push(node);\n }\n }\n dfsRoots.sort((a, b) => {\n if (a === EMPTY_CONTRACT_HASH) return -1;\n if (b === EMPTY_CONTRACT_HASH) return 1;\n return a.localeCompare(b);\n });\n if (dfsRoots.length === 0) {\n dfsRoots.push(...[...nodes].sort((a, b) => a.localeCompare(b)));\n }\n\n const WHITE = 0;\n const GRAY = 1;\n const BLACK = 2;\n const color = new Map<string, number>();\n const dfsParent = new Map<string, string | undefined>();\n for (const node of nodes) {\n color.set(node, WHITE);\n }\n\n interface Frame {\n node: string;\n outgoing: readonly NormalizedEdge[];\n index: number;\n }\n const stack: Frame[] = [];\n\n function isImmediateDfsParent(ancestor: string, node: string): boolean {\n return dfsParent.get(node) === ancestor;\n }\n\n function pushFrame(node: string, parent: string | undefined): void {\n color.set(node, GRAY);\n dfsParent.set(node, parent);\n stack.push({ node, outgoing: outgoingByFrom.get(node) ?? [], index: 0 });\n }\n\n function runDfsFrom(root: string): void {\n if (color.get(root) !== WHITE) return;\n pushFrame(root, undefined);\n\n while (stack.length > 0) {\n const frame = stack[stack.length - 1];\n if (frame === undefined) break;\n if (frame.index >= frame.outgoing.length) {\n color.set(frame.node, BLACK);\n stack.pop();\n continue;\n }\n\n const edge = frame.outgoing[frame.index];\n frame.index += 1;\n if (edge === undefined) continue;\n\n const v = edge.to;\n const vColor = color.get(v);\n if (vColor === GRAY && isImmediateDfsParent(v, frame.node)) {\n kindByMigrationHash.set(edge.hash, 'rollback');\n } else {\n kindByMigrationHash.set(edge.hash, 'forward');\n if (vColor === WHITE) {\n pushFrame(v, frame.node);\n }\n }\n }\n }\n\n for (const root of dfsRoots) {\n runDfsFrom(root);\n }\n const remainingWhite = [...nodes].filter((node) => color.get(node) === WHITE);\n remainingWhite.sort((a, b) => a.localeCompare(b));\n for (const root of remainingWhite) {\n runDfsFrom(root);\n }\n\n peelNodeSkippingRollbacks(nodes, kindByMigrationHash, nonSelf);\n\n const forwardInDegree = new Map<string, number>();\n const forwardOutDegree = new Map<string, number>();\n\n for (const edge of edges) {\n if (kindByMigrationHash.get(edge.hash) !== 'forward') continue;\n bumpDegree(forwardOutDegree, edge.from);\n bumpDegree(forwardInDegree, edge.to);\n }\n\n return {\n kindByMigrationHash,\n forwardInDegree,\n forwardOutDegree,\n };\n}\n\nfunction canonicalFrom(from: string | null): string {\n return from ?? EMPTY_CONTRACT_HASH;\n}\n\n/**\n * Classify forward/rollback/self for a Tier-2 `MigrationListEntry[]` edge set.\n */\nexport function classifyMigrationListGraphTopology(\n entries: readonly MigrationListEntry[],\n): MigrationListGraphTopology {\n const normalized: NormalizedEdge[] = entries.map((entry) => ({\n hash: entry.hash,\n from: canonicalFrom(entry.fromContract),\n to: entry.toContract,\n dirName: entry.name,\n }));\n return classifyNormalizedEdges(normalized);\n}\n\n/**\n * Classify forward/rollback/self for a `MigrationGraph` edge set (Tier-3).\n */\nexport function classifyMigrationGraphTopology(graph: MigrationGraph): MigrationListGraphTopology {\n const normalized: NormalizedEdge[] = [];\n for (const edges of graph.forwardChain.values()) {\n for (const edge of edges) {\n normalized.push({\n hash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n dirName: edge.dirName,\n });\n }\n }\n return classifyNormalizedEdges(normalized);\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport {\n classifyMigrationGraphTopology,\n type MigrationEdgeKind,\n type MigrationListGraphTopology,\n} from './migration-list-graph-topology';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * A migration edge with its forward/rollback/self classification resolved.\n * `from` and `to` are contract hashes (EMPTY_CONTRACT_HASH for the baseline).\n */\nexport interface ClassifiedEdge {\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly dirName: string;\n readonly kind: MigrationEdgeKind;\n}\n\n/**\n * The pure-data output of the row-model stage.\n *\n * `nodes` is the vertical ordering of contract nodes: index 0 is the topmost\n * row (the tip), the last non-null entry is the bottommost root. `null`\n * sentinels separate disjoint components (the blank row in the rendered\n * output). Ordering within each component is deterministic: longest forward-\n * path rank from forward roots (tips at rank max, roots at 0), with lex-\n * ascending tie-break among same-rank siblings.\n *\n * `edges` carries every classified migration. `edgesByFrom` and `edgesByTo`\n * are pre-built lookup maps for the column allocator.\n */\nexport interface MigrationGraphRowModel {\n readonly nodes: readonly (string | null)[];\n readonly edges: readonly ClassifiedEdge[];\n readonly edgesByFrom: ReadonlyMap<string, readonly ClassifiedEdge[]>;\n readonly edgesByTo: ReadonlyMap<string, readonly ClassifiedEdge[]>;\n}\n\nexport interface BuildMigrationGraphRowsOptions {\n readonly contractHash?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Weak connectivity — identify disjoint components\n// ---------------------------------------------------------------------------\n\n/**\n * Return the weakly-connected components of `graph` as an array of node sets,\n * ordered so the component containing EMPTY_CONTRACT_HASH comes first (if\n * present), with remaining components sorted by their lex-smallest node hash.\n */\nfunction weaklyConnectedComponents(graph: MigrationGraph): readonly ReadonlySet<string>[] {\n const visited = new Set<string>();\n const adjacency = new Map<string, string[]>();\n\n function addAdjacent(a: string, b: string): void {\n const aList = adjacency.get(a);\n if (aList) aList.push(b);\n else adjacency.set(a, [b]);\n const bList = adjacency.get(b);\n if (bList) bList.push(a);\n else adjacency.set(b, [a]);\n }\n\n for (const edges of graph.forwardChain.values()) {\n for (const edge of edges) {\n if (edge.from !== edge.to) {\n addAdjacent(edge.from, edge.to);\n }\n }\n }\n\n // Ensure all nodes (including isolated self-loops) are reachable\n for (const node of graph.nodes) {\n if (!adjacency.has(node)) {\n adjacency.set(node, []);\n }\n }\n\n const components: Set<string>[] = [];\n\n function bfsComponent(start: string): Set<string> {\n const component = new Set<string>();\n const queue = [start];\n while (queue.length > 0) {\n const node = queue.shift();\n if (node === undefined || visited.has(node)) continue;\n visited.add(node);\n component.add(node);\n for (const neighbor of adjacency.get(node) ?? []) {\n if (!visited.has(neighbor)) {\n queue.push(neighbor);\n }\n }\n }\n return component;\n }\n\n // Deterministic: visit nodes in a fixed order (EMPTY first, then lex)\n const allNodes = [...graph.nodes].sort((a, b) => {\n if (a === EMPTY_CONTRACT_HASH) return -1;\n if (b === EMPTY_CONTRACT_HASH) return 1;\n return a.localeCompare(b);\n });\n\n for (const node of allNodes) {\n if (!visited.has(node)) {\n components.push(bfsComponent(node));\n }\n }\n\n // Order: EMPTY component first, others by lex-smallest node hash\n components.sort((a, b) => {\n const aHasEmpty = a.has(EMPTY_CONTRACT_HASH);\n const bHasEmpty = b.has(EMPTY_CONTRACT_HASH);\n if (aHasEmpty && !bHasEmpty) return -1;\n if (!aHasEmpty && bHasEmpty) return 1;\n const aMin = [...a].sort((x, y) => x.localeCompare(y))[0] ?? '';\n const bMin = [...b].sort((x, y) => x.localeCompare(y))[0] ?? '';\n return aMin.localeCompare(bMin);\n });\n\n return components;\n}\n\n// ---------------------------------------------------------------------------\n// Longest forward-path node ordering within a component\n// ---------------------------------------------------------------------------\n\nfunction forwardRootsInComponent(\n componentNodes: ReadonlySet<string>,\n topology: MigrationListGraphTopology,\n): readonly string[] {\n const roots: string[] = [];\n for (const node of componentNodes) {\n if ((topology.forwardInDegree.get(node) ?? 0) === 0) {\n roots.push(node);\n }\n }\n roots.sort((a, b) => {\n if (a === EMPTY_CONTRACT_HASH) return -1;\n if (b === EMPTY_CONTRACT_HASH) return 1;\n return a.localeCompare(b);\n });\n if (roots.length > 0) return roots;\n\n return [...componentNodes].sort((a, b) => {\n if (a === EMPTY_CONTRACT_HASH) return -1;\n if (b === EMPTY_CONTRACT_HASH) return 1;\n return a.localeCompare(b);\n });\n}\n\nfunction compareNodesTipsFirst(a: string, b: string, rank: ReadonlyMap<string, number>): number {\n const rankA = rank.get(a) ?? 0;\n const rankB = rank.get(b) ?? 0;\n if (rankA !== rankB) return rankB - rankA;\n if (a === EMPTY_CONTRACT_HASH) return 1;\n if (b === EMPTY_CONTRACT_HASH) return -1;\n return a.localeCompare(b);\n}\n\n/**\n * Layer nodes by longest forward-path rank from forward roots within the\n * component. Rank 0 is the root (bottom row); the maximum rank is the tip\n * (top row). Emits rank-descending with lex-ascending tie-break among siblings\n * at the same rank — stable across edge-insertion order and correct under\n * diamonds, cross-links, and rollbacks.\n */\nfunction maxRank(rank: ReadonlyMap<string, number>): number {\n let max = 0;\n for (const value of rank.values()) {\n if (value > max) max = value;\n }\n return max;\n}\n\nfunction layerNodesByLongestForwardPath(\n componentNodes: ReadonlySet<string>,\n topology: MigrationListGraphTopology,\n graph: MigrationGraph,\n contractHash: string | undefined,\n): readonly string[] {\n const forwardOut = new Map<string, string[]>();\n\n for (const node of componentNodes) {\n forwardOut.set(node, []);\n }\n\n for (const edges of graph.forwardChain.values()) {\n for (const edge of edges) {\n if (!componentNodes.has(edge.from) || !componentNodes.has(edge.to)) continue;\n if (edge.from === edge.to) continue;\n if (topology.kindByMigrationHash.get(edge.migrationHash) !== 'forward') continue;\n const bucket = forwardOut.get(edge.from);\n if (bucket) bucket.push(edge.to);\n }\n }\n\n const roots = forwardRootsInComponent(componentNodes, topology);\n const rank = new Map<string, number>();\n for (const root of roots) {\n rank.set(root, 0);\n }\n\n const maxPasses = componentNodes.size;\n for (let pass = 0; pass < maxPasses; pass++) {\n let changed = false;\n for (const node of componentNodes) {\n const base = rank.get(node);\n if (base === undefined) continue;\n for (const to of forwardOut.get(node) ?? []) {\n const next = base + 1;\n const prev = rank.get(to) ?? -1;\n if (next > prev) {\n rank.set(to, next);\n changed = true;\n }\n }\n }\n if (!changed) break;\n }\n\n for (const node of componentNodes) {\n if (!rank.has(node)) {\n rank.set(node, 0);\n }\n }\n\n if (\n contractHash !== undefined &&\n contractHash !== EMPTY_CONTRACT_HASH &&\n componentNodes.has(contractHash) &&\n (forwardOut.get(contractHash) ?? []).length === 0\n ) {\n rank.set(contractHash, maxRank(rank) + 1);\n }\n\n return [...componentNodes].sort((a, b) => compareNodesTipsFirst(a, b, rank));\n}\n\n// ---------------------------------------------------------------------------\n// Public builder\n// ---------------------------------------------------------------------------\n\n/**\n * Build the row model from a tolerant `MigrationGraph`.\n *\n * The row model is the first pure-data stage of the `migration graph` render\n * pipeline. It:\n * - classifies every edge as `forward`, `rollback`, or `self`;\n * - produces a deterministic vertical node ordering (tips at index 0, roots\n * at the end) within each weakly-connected component;\n * - separates disjoint components with `null` sentinels;\n * - optionally prepends a detached current contract as its own single-node\n * component when `contractHash` is not already in the graph.\n *\n * No columns, no lane allocation, no glyphs, no rendering.\n */\n/**\n * Resolve the detached current contract, if any: a real contract (not the\n * empty baseline) that no migration on disk produces, so it is absent from\n * the graph. Such a contract renders as a floating node rather than\n * decorating an existing one. Returns the hash when detached, else undefined.\n */\nfunction detachedContractHash(\n graph: MigrationGraph,\n contractHash: string | undefined,\n): string | undefined {\n return contractHash !== undefined &&\n contractHash !== EMPTY_CONTRACT_HASH &&\n !graph.nodes.has(contractHash)\n ? contractHash\n : undefined;\n}\n\nfunction isForwardLeaf(node: string, edges: readonly ClassifiedEdge[]): boolean {\n return !edges.some((e) => e.kind === 'forward' && e.from === node && e.from !== e.to);\n}\n\nfunction forwardReachableFrom(\n start: string,\n forwardTo: ReadonlyMap<string, readonly string[]>,\n): ReadonlySet<string> {\n const reachable = new Set<string>([start]);\n const queue = [start];\n while (queue.length > 0) {\n const node = queue.shift();\n if (node === undefined) continue;\n for (const next of forwardTo.get(node) ?? []) {\n if (!reachable.has(next)) {\n reachable.add(next);\n queue.push(next);\n }\n }\n }\n return reachable;\n}\n\nfunction buildForwardToMap(edges: readonly ClassifiedEdge[]): Map<string, string[]> {\n const forwardTo = new Map<string, string[]>();\n for (const edge of edges) {\n if (edge.kind !== 'forward' || edge.from === edge.to) continue;\n const bucket = forwardTo.get(edge.from);\n if (bucket) bucket.push(edge.to);\n else forwardTo.set(edge.from, [edge.to]);\n }\n return forwardTo;\n}\n\nfunction sortEdgesForContractHashTrunk(\n edges: ClassifiedEdge[],\n contractHash: string | undefined,\n): ClassifiedEdge[] {\n if (\n contractHash === undefined ||\n contractHash === EMPTY_CONTRACT_HASH ||\n !isForwardLeaf(contractHash, edges)\n ) {\n return edges;\n }\n\n const preferredLeaf = contractHash;\n const forwardTo = buildForwardToMap(edges);\n const reachability = new Map<string, ReadonlySet<string>>();\n function canReachContractHash(from: string): boolean {\n let cached = reachability.get(from);\n if (cached === undefined) {\n cached = forwardReachableFrom(from, forwardTo);\n reachability.set(from, cached);\n }\n return cached.has(preferredLeaf);\n }\n\n function trunkBias(edge: ClassifiedEdge): number {\n if (edge.kind !== 'forward' || edge.from === edge.to) return 0;\n if (edge.to === preferredLeaf) return 2;\n if (canReachContractHash(edge.to)) return 1;\n return 0;\n }\n\n return edges\n .map((edge, index) => ({ edge, index, bias: trunkBias(edge) }))\n .sort((a, b) => {\n if (a.edge.from !== b.edge.from) return a.index - b.index;\n if (a.bias !== b.bias) return b.bias - a.bias;\n return a.index - b.index;\n })\n .map(({ edge }) => edge);\n}\n\nfunction rebuildEdgeLookupMaps(edges: readonly ClassifiedEdge[]): {\n edgesByFrom: Map<string, ClassifiedEdge[]>;\n edgesByTo: Map<string, ClassifiedEdge[]>;\n} {\n const edgesByFrom = new Map<string, ClassifiedEdge[]>();\n const edgesByTo = new Map<string, ClassifiedEdge[]>();\n for (const classified of edges) {\n const fromBucket = edgesByFrom.get(classified.from);\n if (fromBucket) fromBucket.push(classified);\n else edgesByFrom.set(classified.from, [classified]);\n\n const toBucket = edgesByTo.get(classified.to);\n if (toBucket) toBucket.push(classified);\n else edgesByTo.set(classified.to, [classified]);\n }\n return { edgesByFrom, edgesByTo };\n}\n\nexport function buildMigrationGraphRows(\n graph: MigrationGraph,\n options: BuildMigrationGraphRowsOptions = {},\n): MigrationGraphRowModel {\n const emptyModel: MigrationGraphRowModel = {\n nodes: [],\n edges: [],\n edgesByFrom: new Map(),\n edgesByTo: new Map(),\n };\n\n if (graph.nodes.size === 0) {\n const detached = detachedContractHash(graph, options.contractHash);\n return detached !== undefined ? { ...emptyModel, nodes: [detached] } : emptyModel;\n }\n\n // 1. Classify all edges (shared classifier: DFS plus a peel pass that demotes\n // node-skipping rollbacks, so the forward subgraph is acyclic)\n const topology = classifyMigrationGraphTopology(graph);\n\n // 2. Build classified edge list\n const edges: ClassifiedEdge[] = [];\n\n for (const edgeList of graph.forwardChain.values()) {\n for (const edge of edgeList) {\n const kind = topology.kindByMigrationHash.get(edge.migrationHash) ?? 'forward';\n edges.push({\n migrationHash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n dirName: edge.dirName,\n kind,\n });\n }\n }\n\n const sortedEdges = sortEdgesForContractHashTrunk(edges, options.contractHash);\n const { edgesByFrom, edgesByTo } = rebuildEdgeLookupMaps(sortedEdges);\n\n // 3. Find weakly-connected components (ordered: EMPTY first, then lex)\n const components = weaklyConnectedComponents(graph);\n\n // 4. Layer nodes by longest forward path per component, separate with null\n const nodes: (string | null)[] = [];\n for (let i = 0; i < components.length; i++) {\n if (i > 0) nodes.push(null);\n const component = components[i];\n if (component === undefined) continue;\n const ordered = layerNodesByLongestForwardPath(\n component,\n topology,\n graph,\n options.contractHash,\n );\n for (const node of ordered) {\n nodes.push(node);\n }\n }\n\n const detached = detachedContractHash(graph, options.contractHash);\n if (detached !== undefined) {\n if (nodes.length > 0) {\n nodes.unshift(null);\n }\n nodes.unshift(detached);\n }\n\n return {\n nodes,\n edges: sortedEdges,\n edgesByFrom,\n edgesByTo,\n };\n}\n","import type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport type { GlyphMode } from '../glyph-mode';\nimport {\n computeLabelColumn,\n computeMaxDirNameWidth,\n renderMigrationGraphCommand,\n} from './migration-graph-command-render';\nimport { buildGrid } from './migration-graph-grid-layout';\nimport type { MigrationEdgeAnnotation } from './migration-graph-labels';\nimport type { Highlight } from './migration-graph-model';\nimport { buildMigrationGraphRows } from './migration-graph-rows';\nimport {\n buildEdgeAnnotationsByHashFromListEntries,\n buildRefsByHashFromListEntries,\n type MigrationListStyler,\n} from './migration-list-render';\nimport type { MigrationListEntry } from './migration-list-types';\n\nexport { buildEdgeAnnotationsByHashFromListEntries } from './migration-list-render';\n\nexport function mergeMigrationEdgeAnnotations(\n listOverlay: ReadonlyMap<string, MigrationEdgeAnnotation>,\n statusOverlay: ReadonlyMap<string, MigrationEdgeAnnotation>,\n): ReadonlyMap<string, MigrationEdgeAnnotation> {\n const merged = new Map<string, MigrationEdgeAnnotation>();\n for (const [migrationHash, listAnnotation] of listOverlay) {\n const statusAnnotation = statusOverlay.get(migrationHash);\n merged.set(migrationHash, {\n ...listAnnotation,\n ...(statusAnnotation?.status !== undefined ? { status: statusAnnotation.status } : {}),\n });\n }\n return merged;\n}\n\n/**\n * Translate `migrate --show` per-edge path-highlight annotations into a\n * {@link Highlight}. With any `pathHighlight` present the result is focus mode\n * (on-path lifted green, off-path dim); otherwise flat (lane-rotation colour).\n */\nexport function highlightFromEdgeAnnotations(\n edgeAnnotationsByHash: ReadonlyMap<string, MigrationEdgeAnnotation>,\n): Highlight {\n const onPath = new Set<string>();\n let anyPathHighlight = false;\n for (const [migrationHash, annotation] of edgeAnnotationsByHash) {\n if (annotation.pathHighlight === undefined) continue;\n anyPathHighlight = true;\n if (annotation.pathHighlight === 'on-path') onPath.add(migrationHash);\n }\n return anyPathHighlight ? { mode: 'focus', onPath } : { mode: 'flat', onPath: new Set() };\n}\n\nexport interface RenderMigrationGraphSpaceTreeInput {\n readonly graph: MigrationGraph;\n readonly migrations: readonly MigrationListEntry[];\n readonly liveContractHash: string;\n readonly glyphMode: GlyphMode;\n readonly colorize: boolean;\n readonly refsByHash?: ReadonlyMap<string, readonly string[]>;\n readonly statusOverlayByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;\n readonly dbHash?: string;\n readonly styler?: MigrationListStyler;\n /**\n * Cross-space override for the gutter→label column (the widest gutter across\n * sibling space sections, plus the label gap). Named for historical\n * continuity with the previous renderer's prefix-width input.\n */\n readonly globalMaxEdgeTreePrefixWidth?: number;\n readonly globalMaxDirNameWidth?: number;\n /**\n * Whether this render is for the app space. When false, `contractHash` is not\n * forwarded to `buildMigrationGraphRows` (suppressing the floating working-\n * contract node) and the `@contract` marker is suppressed. Defaults to `true`.\n */\n readonly isAppSpace?: boolean;\n}\n\nexport interface ComputeGlobalMaxEdgeTreePrefixWidthInput {\n readonly graph: MigrationGraph;\n readonly liveContractHash: string;\n}\n\nfunction buildGridForInput(input: ComputeGlobalMaxEdgeTreePrefixWidthInput): {\n readonly grid: ReturnType<typeof buildGrid>;\n readonly rowModel: ReturnType<typeof buildMigrationGraphRows>;\n} {\n const rowModel = buildMigrationGraphRows(input.graph, { contractHash: input.liveContractHash });\n const grid = buildGrid(rowModel, {}, { mode: 'flat', onPath: new Set() });\n return { grid, rowModel };\n}\n\n/**\n * The widest gutter→label column across the given space layouts. Cross-space\n * callers pass this back in so every section's labels share one column.\n */\nexport function computeGlobalMaxEdgeTreePrefixWidth(\n inputs: readonly ComputeGlobalMaxEdgeTreePrefixWidthInput[],\n glyphMode: GlyphMode = 'unicode',\n): number {\n let globalMax = 0;\n for (const input of inputs) {\n const { grid } = buildGridForInput(input);\n globalMax = Math.max(globalMax, computeLabelColumn(grid, glyphMode));\n }\n return globalMax;\n}\n\nexport function computeGlobalMaxDirNameWidth(\n inputs: readonly ComputeGlobalMaxEdgeTreePrefixWidthInput[],\n): number {\n let globalMax = 0;\n for (const input of inputs) {\n const { rowModel } = buildGridForInput(input);\n globalMax = Math.max(globalMax, computeMaxDirNameWidth(rowModel));\n }\n return globalMax;\n}\n\nfunction renderMigrationGraphSpaceTreeInternal(input: RenderMigrationGraphSpaceTreeInput): string {\n const appSpace = input.isAppSpace !== false;\n const rowModel = buildMigrationGraphRows(input.graph, {\n ...(appSpace ? { contractHash: input.liveContractHash } : {}),\n });\n const listOverlay = buildEdgeAnnotationsByHashFromListEntries(input.migrations);\n const edgeAnnotationsByHash =\n input.statusOverlayByHash === undefined\n ? listOverlay\n : mergeMigrationEdgeAnnotations(listOverlay, input.statusOverlayByHash);\n const highlight = highlightFromEdgeAnnotations(edgeAnnotationsByHash);\n const grid = buildGrid(rowModel, {}, highlight);\n\n return renderMigrationGraphCommand({\n grid,\n rowModel,\n colorize: input.colorize,\n glyphMode: input.glyphMode,\n contractHash: input.liveContractHash,\n isAppSpace: appSpace,\n edgeAnnotationsByHash,\n refsByHash: input.refsByHash ?? buildRefsByHashFromListEntries(input.migrations),\n ...(input.dbHash !== undefined ? { dbHash: input.dbHash } : {}),\n ...(input.styler !== undefined ? { styler: input.styler } : {}),\n ...(input.globalMaxEdgeTreePrefixWidth !== undefined\n ? { globalLabelColumn: input.globalMaxEdgeTreePrefixWidth }\n : {}),\n ...(input.globalMaxDirNameWidth !== undefined\n ? { globalMaxDirNameWidth: input.globalMaxDirNameWidth }\n : {}),\n });\n}\n\nexport function renderMigrationGraphSpaceTree(input: RenderMigrationGraphSpaceTreeInput): string {\n return renderMigrationGraphSpaceTreeInternal(input);\n}\n\nexport function renderMigrationGraphSpaceTrees(\n inputs: readonly RenderMigrationGraphSpaceTreeInput[],\n): readonly string[] {\n const globalInputs: ComputeGlobalMaxEdgeTreePrefixWidthInput[] = inputs.map((input) => ({\n graph: input.graph,\n liveContractHash: input.liveContractHash,\n }));\n const glyphMode = inputs[0]?.glyphMode ?? 'unicode';\n const globalLabelColumn =\n inputs.length > 1 ? computeGlobalMaxEdgeTreePrefixWidth(globalInputs, glyphMode) : undefined;\n const globalMaxDirName =\n inputs.length > 1 ? computeGlobalMaxDirNameWidth(globalInputs) : undefined;\n return inputs.map((input) =>\n renderMigrationGraphSpaceTreeInternal({\n ...input,\n ...(globalLabelColumn !== undefined\n ? { globalMaxEdgeTreePrefixWidth: globalLabelColumn }\n : {}),\n ...(globalMaxDirName !== undefined ? { globalMaxDirNameWidth: globalMaxDirName } : {}),\n }),\n );\n}\n\nexport function indentMigrationGraphTreeBlock(treeOutput: string, indent: string): string {\n if (treeOutput.length === 0) {\n return treeOutput;\n }\n return treeOutput\n .split('\\n')\n .map((line) => (line.length === 0 ? line : `${indent}${line}`))\n .join('\\n');\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport type { GlyphMode } from '../glyph-mode';\nimport type { MigrationEdgeAnnotation } from './migration-graph-labels';\nimport {\n computeGlobalMaxDirNameWidth,\n computeGlobalMaxEdgeTreePrefixWidth,\n indentMigrationGraphTreeBlock,\n renderMigrationGraphSpaceTree,\n} from './migration-graph-space-render';\nimport type { MigrationListEntry, MigrationListResult } from './migration-list-types';\n\nexport type { GlyphMode } from '../glyph-mode';\nexport type { MigrationEdgeKind } from './migration-list-graph-topology';\nexport type {\n MigrationListEntry,\n MigrationListResult,\n MigrationSpaceListEntry,\n} from './migration-list-types';\n\n/**\n * Semantic styler for `migration list` output tokens. Token-typed so\n * the renderer composes presentation-neutral fragments and the styler\n * decides how each token kind is decorated (ANSI codes, plain text,\n * etc.). The renderer pads with raw spaces *outside* styled tokens so\n * visible column widths stay stable regardless of what the styler\n * emits — adding ANSI escape sequences never disturbs alignment.\n *\n * `invariants` and `refs` receive the underlying string arrays rather\n * than a pre-joined string so per-element styling (e.g. distinguishing\n * the live-DB `db` marker from user-named refs) is possible without\n * having to re-parse a joined block.\n */\nexport interface MigrationListStyler {\n kind(text: string): string;\n dirName(text: string): string;\n sourceHash(text: string): string;\n destHash(text: string): string;\n glyph(text: string): string;\n lane(text: string): string;\n invariants(ids: readonly string[]): string;\n refs(names: readonly string[]): string;\n spaceHeading(text: string): string;\n summary(text: string): string;\n emptyState(text: string): string;\n}\n\nexport const IDENTITY_MIGRATION_LIST_STYLER: MigrationListStyler = {\n kind: (text) => text,\n dirName: (text) => text,\n sourceHash: (text) => text,\n destHash: (text) => text,\n glyph: (text) => text,\n lane: (text) => text,\n invariants: (ids) => `{${ids.join(', ')}}`,\n refs: (names) => `(${names.join(', ')})`,\n spaceHeading: (text) => text,\n summary: (text) => text,\n emptyState: (text) => text,\n};\n\nfunction canonicalFrom(from: string | null): string {\n return from ?? EMPTY_CONTRACT_HASH;\n}\n\nexport function migrationGraphFromListEntries(\n entries: readonly MigrationListEntry[],\n): MigrationGraph {\n const nodes = new Set<string>();\n const forwardChain = new Map<string, MigrationEdge[]>();\n const reverseChain = new Map<string, MigrationEdge[]>();\n const migrationByHash = new Map<string, MigrationEdge>();\n\n for (const entry of entries) {\n const from = canonicalFrom(entry.fromContract);\n const edge: MigrationEdge = {\n from,\n to: entry.toContract,\n migrationHash: entry.hash,\n dirName: entry.name,\n createdAt: entry.createdAt,\n invariants: entry.providedInvariants,\n };\n nodes.add(from);\n nodes.add(entry.toContract);\n const forward = forwardChain.get(from);\n if (forward) forward.push(edge);\n else forwardChain.set(from, [edge]);\n const reverse = reverseChain.get(entry.toContract);\n if (reverse) reverse.push(edge);\n else reverseChain.set(entry.toContract, [edge]);\n migrationByHash.set(entry.hash, edge);\n }\n\n return { nodes, forwardChain, reverseChain, migrationByHash };\n}\n\nexport function buildEdgeAnnotationsByHashFromListEntries(\n entries: readonly MigrationListEntry[],\n): ReadonlyMap<string, MigrationEdgeAnnotation> {\n const annotations = new Map<string, MigrationEdgeAnnotation>();\n for (const entry of entries) {\n annotations.set(entry.hash, {\n operationCount: entry.operationCount,\n invariants: entry.providedInvariants,\n });\n }\n return annotations;\n}\n\nexport function buildRefsByHashFromListEntries(\n entries: readonly MigrationListEntry[],\n): ReadonlyMap<string, readonly string[]> {\n const refsByHash = new Map<string, readonly string[]>();\n for (const entry of entries) {\n if (entry.refs.length > 0) {\n refsByHash.set(entry.toContract, entry.refs);\n }\n }\n return refsByHash;\n}\n\nfunction formatEmptyStateLine(spaceId: string, style: MigrationListStyler): string {\n return style.emptyState(`There are no migrations in migrations/${spaceId}/ yet`);\n}\n\nfunction renderSpaceTreeBlock(\n spaceId: string,\n migrations: readonly MigrationListEntry[],\n multiSpace: boolean,\n glyphMode: GlyphMode,\n style: MigrationListStyler,\n colorize: boolean,\n liveContractHash: string,\n graphForSpace: (spaceId: string) => MigrationGraph | undefined,\n appSpaceId: string | undefined,\n globalMaxEdgeTreePrefixWidth?: number,\n globalMaxDirNameWidth?: number,\n): readonly string[] {\n if (migrations.length === 0) {\n const emptyLine = formatEmptyStateLine(spaceId, style);\n if (!multiSpace) {\n return [emptyLine];\n }\n return [style.spaceHeading(`${spaceId}:`), ` ${emptyLine}`];\n }\n\n const graph = graphForSpace(spaceId) ?? migrationGraphFromListEntries(migrations);\n const isAppSpace = appSpaceId === undefined ? undefined : spaceId === appSpaceId;\n const treeOutput = renderMigrationGraphSpaceTree({\n graph,\n migrations,\n liveContractHash,\n glyphMode,\n colorize,\n refsByHash: buildRefsByHashFromListEntries(migrations),\n styler: style,\n ...(isAppSpace !== undefined ? { isAppSpace } : {}),\n ...(globalMaxEdgeTreePrefixWidth !== undefined ? { globalMaxEdgeTreePrefixWidth } : {}),\n ...(globalMaxDirNameWidth !== undefined ? { globalMaxDirNameWidth } : {}),\n });\n\n if (!multiSpace) {\n return treeOutput.length === 0 ? [] : [treeOutput];\n }\n\n const indented = indentMigrationGraphTreeBlock(treeOutput, ' ');\n return [style.spaceHeading(`${spaceId}:`), indented];\n}\n\nexport interface RenderMigrationListWithStyleOptions {\n readonly colorize?: boolean;\n readonly liveContractHash?: string;\n readonly graphForSpace?: (spaceId: string) => MigrationGraph | undefined;\n /**\n * The space ID that is the app contract space. When provided, `@contract`\n * and the floating working-contract node are shown only for this space.\n * When absent, the renderer falls back to the default (`isAppSpace: true`\n * for every space), which is safe for single-space callers.\n */\n readonly appSpaceId?: string;\n}\n\n/**\n * Compose the styled `migration list` human output via the shared tree\n * renderer. Each on-disk migration is one edge row with package-fact\n * annotations; refs decorate destination contract nodes.\n *\n * `options.colorize` must match whether `style` emits ANSI (e.g. both true for\n * `createAnsiMigrationListStyler({ useColor: true })`).\n */\nexport function renderMigrationListWithStyle(\n result: MigrationListResult,\n style: MigrationListStyler,\n glyphMode: GlyphMode = 'unicode',\n options: RenderMigrationListWithStyleOptions = {},\n): string {\n const multiSpace = result.spaces.length > 1;\n const colorize = options.colorize ?? false;\n const liveContractHash = options.liveContractHash ?? EMPTY_CONTRACT_HASH;\n const graphForSpace = options.graphForSpace ?? (() => undefined);\n const appSpaceId = options.appSpaceId;\n const globalLayoutInputs = multiSpace\n ? result.spaces\n .filter((space) => space.migrations.length > 0)\n .map((space) => ({\n graph: graphForSpace(space.space) ?? migrationGraphFromListEntries(space.migrations),\n liveContractHash,\n }))\n : [];\n const globalMaxEdgeTreePrefixWidth =\n globalLayoutInputs.length > 0\n ? computeGlobalMaxEdgeTreePrefixWidth(globalLayoutInputs)\n : undefined;\n const globalMaxDirNameWidth =\n globalLayoutInputs.length > 0 ? computeGlobalMaxDirNameWidth(globalLayoutInputs) : undefined;\n const lines: string[] = [];\n\n for (let index = 0; index < result.spaces.length; index++) {\n const space = result.spaces[index]!;\n if (index > 0) {\n lines.push('');\n }\n lines.push(\n ...renderSpaceTreeBlock(\n space.space,\n space.migrations,\n multiSpace,\n glyphMode,\n style,\n colorize,\n liveContractHash,\n graphForSpace,\n appSpaceId,\n globalMaxEdgeTreePrefixWidth,\n globalMaxDirNameWidth,\n ),\n );\n }\n\n const totalMigrations = result.spaces.reduce(\n (count, space) => count + space.migrations.length,\n 0,\n );\n if (totalMigrations > 0) {\n lines.push('');\n lines.push(style.summary(result.summary));\n }\n\n return lines.join('\\n');\n}\n\nexport function renderMigrationList(result: MigrationListResult): string {\n return renderMigrationListWithStyle(result, IDENTITY_MIGRATION_LIST_STYLER);\n}\n","import { bold, cyan, cyanBright, dim, green, yellow } from 'colorette';\nimport { IDENTITY_MIGRATION_LIST_STYLER, type MigrationListStyler } from './migration-list-render';\n\nexport type MigrationListStylerWithMarkers = MigrationListStyler & {\n markers(names: readonly string[]): string;\n};\n\nfunction hasMarkersFormatter(\n styler: MigrationListStyler,\n): styler is MigrationListStylerWithMarkers {\n return 'markers' in styler && typeof styler.markers === 'function';\n}\n\nfunction styleMarkerName(name: string): string {\n return name === CONTRACT_MARKER_NAME ? bold(green(name)) : green(name);\n}\n\nfunction plainMarkers(names: readonly string[]): string {\n return names.map((name) => `@${name}`).join(' ');\n}\n\nexport function formatContractNodeOverlays(\n styler: MigrationListStyler,\n markers: readonly string[],\n refs: readonly string[],\n): string {\n const parts: string[] = [];\n if (markers.length > 0) {\n parts.push(hasMarkersFormatter(styler) ? styler.markers(markers) : plainMarkers(markers));\n }\n if (refs.length > 0) {\n parts.push(styler.refs(refs));\n }\n return parts.join(' ');\n}\n\n/**\n * The current contract overlay marker. Unlike user refs, this names the user's\n * declared desired state — the implicit base/target for `plan` / `migrate` —\n * not a stored label. It is emphasized (bold) so it stands out from plain refs\n * (including the live-database `db` marker, which is just another ref).\n */\nexport const CONTRACT_MARKER_NAME = 'contract';\n\nfunction styleRefName(name: string): string {\n return green(name);\n}\n\n/**\n * Build a {@link MigrationListStyler} that decorates `migration list`\n * tokens with ANSI SGR codes. When `useColor` is `false` (non-TTY,\n * `--no-color`, `NO_COLOR=1`, piped output) the function returns the\n * shared identity styler so callers get plain text with zero ANSI\n * bytes — pipe-friendly by construction.\n *\n * Palette:\n *\n * - `dirName`: bold\n * - `sourceHash`: dim cyan\n * - `destHash`: bright cyan\n * - `kind` (`*` / `↩` / `⟲`): bright — the signal; lanes and arrows dim\n * - `glyph` (`→` / `⟲` / `∅`): dim\n * - `lane` (graph gutter lines `│` and fan/join connectors `├─┐` / `├─┘`): dim\n * - `invariants` (`{...}`): yellow\n * - `markers` (`@contract @db`): green; the `contract` desired-state marker is\n * green-bold (`db` is plain green); the `@` sigil is applied to each name\n * - `refs` (`(...)`): green (the active ref is bolded separately by the tree styler)\n * - `spaceHeading` (`<spaceId>:`): bold\n * - `summary`: dim\n * - `emptyState`: dim\n */\nexport function createAnsiMigrationListStyler(opts: {\n readonly useColor: boolean;\n}): MigrationListStylerWithMarkers {\n if (!opts.useColor) {\n return {\n ...IDENTITY_MIGRATION_LIST_STYLER,\n markers: plainMarkers,\n };\n }\n return {\n // Kind glyphs stay bright in both flat and graph views; lanes carry the dim gutter.\n kind: (text) => text,\n dirName: (text) => bold(text),\n sourceHash: (text) => dim(cyan(text)),\n destHash: (text) => cyanBright(text),\n glyph: (text) => dim(text),\n lane: (text) => dim(text),\n invariants: (ids) => yellow(`{${ids.join(', ')}}`),\n markers: (names) => {\n const sigil = green('@');\n return names.map((name) => sigil + styleMarkerName(name)).join(' ');\n },\n refs: (names) => {\n const open = green('(');\n const close = green(')');\n const separator = green(', ');\n return open + names.map(styleRefName).join(separator) + close;\n },\n spaceHeading: (text) => bold(text),\n summary: (text) => dim(text),\n emptyState: (text) => dim(text),\n };\n}\n","/**\n * Per-row label formatting for the command graph renderer.\n *\n * The command graph renderer ({@link renderMigrationGraphCommand}) derives the\n * graph structure — rows, gutter, lane colours — from the grid pipeline. The\n * per-row LABEL (contract hash + markers + refs for node rows;\n * migration name + `from → to` + ops/status/will-run for migration rows) is\n * formatted here. This module owns ONLY label text + styling; it knows nothing\n * about lanes, gutters, or grid geometry.\n *\n * The label format (hash abbreviation, `from → to` arrow column, `@contract`/\n * `@db` markers, `(refs)`, ops/status/will-run suffix, the legend) is the same\n * as the previous renderer — that part was never the bug.\n */\n\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { bold, createColors, green, yellow } from 'colorette';\nimport type { GlyphMode } from '../glyph-mode';\nimport { laneColorizer } from './migration-graph-occlusion-render';\nimport type { ClassifiedEdge } from './migration-graph-rows';\nimport {\n MIGRATION_LIST_HASH_WIDTH,\n migrationListEmptySource,\n migrationListForwardArrow,\n padFromHashColumn,\n} from './migration-list-data-column';\nimport type { MigrationEdgeKind } from './migration-list-graph-topology';\nimport type { MigrationListStyler } from './migration-list-render';\nimport {\n CONTRACT_MARKER_NAME,\n createAnsiMigrationListStyler,\n formatContractNodeOverlays,\n} from './migration-list-styler';\n\n/**\n * The live-database overlay marker. Just another ref as far as styling goes —\n * the only emphasized markers are the active ref and the `contract`\n * desired-state marker (see {@link CONTRACT_MARKER_NAME}).\n */\nconst DB_MARKER_NAME = 'db';\n\nexport interface MigrationEdgeAnnotation {\n readonly status?: 'applied' | 'pending';\n readonly operationCount?: number;\n readonly invariants?: readonly string[];\n /**\n * Path-highlight annotation for `migrate --show` preview.\n * - `'on-path'`: migration is on the chosen path; rendered in bright green.\n * - `'off-path'`: migration is off the chosen path; fully drawn but dim grey.\n */\n readonly pathHighlight?: 'on-path' | 'off-path';\n}\n\n/**\n * Inputs that drive label formatting. A subset of the command renderer's\n * options — everything the label functions read.\n */\nexport interface MigrationGraphLabelOptions {\n readonly refsByHash?: ReadonlyMap<string, readonly string[]>;\n readonly edgeAnnotationsByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;\n readonly dbHash?: string;\n readonly contractHash?: string;\n readonly isAppSpace?: boolean;\n readonly activeRefName?: string;\n readonly hashLength?: number;\n readonly colorize: boolean;\n readonly glyphMode?: GlyphMode;\n readonly styler?: MigrationListStyler;\n}\n\n/**\n * Forced-color functions that always emit ANSI regardless of the ambient TTY\n * environment (NO_COLOR, piped output). Used so on-path green / off-path dim are\n * deterministically emitted in tests that request colour while NO_COLOR is set.\n */\nconst { dim: forcedDim } = createColors({ useColor: true });\nconst { greenBright: forcedGreen } = createColors({ useColor: true });\n\n/**\n * The two label styles used in `migrate --show` path-highlight mode.\n *\n * - `onPath`: bold name, neutral hashes (the on-path lane glyphs are coloured\n * green by the grid renderer, not here).\n * - `offPath`: uniform dim grey on the name and the whole hash column.\n *\n * To change the on-path / off-path label colour in future, edit this object.\n */\nexport const PATH_HIGHLIGHT_STYLES = {\n onPath: (_style: MigrationListStyler, colorize: boolean) => ({\n lane: colorize ? forcedGreen : (text: string) => text,\n arrow: (text: string) => text,\n dirName: (text: string) => bold(text),\n hashOverride: undefined,\n }),\n offPath: (colorize: boolean) => ({\n lane: colorize ? forcedDim : (text: string) => text,\n arrow: colorize ? forcedDim : (text: string) => text,\n dirName: colorize ? forcedDim : (text: string) => text,\n hashOverride: colorize ? forcedDim : undefined,\n }),\n} as const;\n\nfunction abbreviateHash(hash: string, hashLength: number, emptySource: string): string {\n if (hash === EMPTY_CONTRACT_HASH) {\n return emptySource;\n }\n const stripped = hash.startsWith('sha256:') ? hash.slice(7) : hash;\n return stripped.slice(0, hashLength);\n}\n\ninterface ContractOverlayNames {\n readonly markers: readonly string[];\n readonly refs: readonly string[];\n}\n\nfunction overlayNamesForContract(\n contractHash: string,\n opts: MigrationGraphLabelOptions,\n): ContractOverlayNames {\n const markers: string[] = [];\n const refs: string[] = [];\n const userRefs = opts.refsByHash?.get(contractHash);\n if (userRefs) {\n refs.push(...[...userRefs].sort((a, b) => a.localeCompare(b)));\n }\n if (\n opts.isAppSpace !== false &&\n opts.contractHash === contractHash &&\n contractHash !== EMPTY_CONTRACT_HASH\n ) {\n markers.push(CONTRACT_MARKER_NAME);\n }\n if (opts.dbHash === contractHash) {\n markers.push(DB_MARKER_NAME);\n }\n markers.sort((a, b) => {\n if (a === CONTRACT_MARKER_NAME) return -1;\n if (b === CONTRACT_MARKER_NAME) return 1;\n return a.localeCompare(b);\n });\n return { markers, refs };\n}\n\nexport function createLabelStyler(opts: MigrationGraphLabelOptions): MigrationListStyler {\n const base = opts.styler ?? createAnsiMigrationListStyler({ useColor: opts.colorize });\n const activeRefName = opts.activeRefName;\n if (!opts.colorize || activeRefName === undefined) {\n return base;\n }\n return {\n ...base,\n refs: (names) => {\n const styledNames = names.map((name) => (name === activeRefName ? bold(name) : name));\n return base.refs(styledNames);\n },\n };\n}\n\nfunction overlayStatusGlyphs(mode: GlyphMode): {\n readonly applied: string;\n readonly pending: string;\n} {\n return mode === 'ascii' ? { applied: '+', pending: '>' } : { applied: '✓', pending: '⧗' };\n}\n\nfunction formatEdgeAnnotationSuffix(\n migrationHash: string,\n opts: MigrationGraphLabelOptions,\n style: MigrationListStyler,\n): string {\n const annotation = opts.edgeAnnotationsByHash?.get(migrationHash);\n if (annotation === undefined) {\n return '';\n }\n const isOffPath = annotation.pathHighlight === 'off-path';\n const segments: string[] = [];\n if (annotation.operationCount !== undefined) {\n segments.push(`${annotation.operationCount} ops`);\n }\n if (annotation.invariants !== undefined && annotation.invariants.length > 0) {\n segments.push(style.invariants(annotation.invariants));\n }\n const status = annotation.status;\n if (status !== undefined) {\n const glyphs = overlayStatusGlyphs(opts.glyphMode ?? 'unicode');\n const glyph = status === 'applied' ? glyphs.applied : glyphs.pending;\n const label = status === 'applied' ? 'applied' : 'pending';\n if (!opts.colorize) {\n segments.push(`${glyph} ${label}`);\n } else {\n const styler = status === 'applied' ? green : yellow;\n segments.push(styler(`${glyph} ${label}`));\n }\n }\n if (annotation.pathHighlight === 'on-path') {\n const glyph = opts.glyphMode === 'ascii' ? '>' : '↑';\n segments.push(`${glyph} will run`);\n }\n if (segments.length === 0) {\n return '';\n }\n const suffix = ` ${segments.join(' ')}`;\n return opts.colorize && isOffPath ? forcedDim(suffix) : suffix;\n}\n\n/**\n * Format the `from → to` hash data column for an edge row.\n *\n * When `hashOverride` is provided (off-path → `dim`), it replaces ALL sub-stylers\n * so dim reaches every character without inner ANSI codes overriding it.\n */\nfunction formatEdgeHashColumn(\n edge: ClassifiedEdge,\n style: MigrationListStyler,\n hashLength: number,\n glyphMode: GlyphMode,\n hashOverride?: (text: string) => string,\n): string {\n const emptySource = migrationListEmptySource(glyphMode);\n const forwardArrow = migrationListForwardArrow(glyphMode);\n const src = hashOverride ?? style.sourceHash;\n const dst = hashOverride ?? style.destHash;\n const glyph = hashOverride ?? style.glyph;\n if (edge.kind === 'self') {\n const hash = abbreviateHash(edge.from, hashLength, emptySource);\n const source = padFromHashColumn(src(hash), hashLength);\n return `${source} ${glyph(forwardArrow)} ${dst(hash)}`;\n }\n const source =\n edge.from === EMPTY_CONTRACT_HASH\n ? padFromHashColumn(glyph(emptySource), hashLength)\n : padFromHashColumn(src(abbreviateHash(edge.from, hashLength, emptySource)), hashLength);\n const arrow = glyph(forwardArrow);\n const dest = dst(abbreviateHash(edge.to, hashLength, emptySource));\n return `${source} ${arrow} ${dest}`;\n}\n\n// ---------------------------------------------------------------------------\n// Public label builders used by the command renderer.\n// ---------------------------------------------------------------------------\n\n/**\n * The label text for a contract node row: the abbreviated hash (or the `∅`\n * empty-source token for the baseline) followed by its `@contract`/`@db` markers\n * and `(refs)`, with two spaces between the hash and the overlay block.\n */\nexport function formatNodeLabel(\n contractHash: string,\n opts: MigrationGraphLabelOptions,\n nodeHighlight?: 'on-path' | 'off-path' | undefined,\n): string {\n const style = createLabelStyler(opts);\n const hashLength = opts.hashLength ?? MIGRATION_LIST_HASH_WIDTH;\n const emptySource = migrationListEmptySource(opts.glyphMode ?? 'unicode');\n const overlays = overlayNamesForContract(contractHash, opts);\n const hasOverlays = overlays.markers.length > 0 || overlays.refs.length > 0;\n const offPath = nodeHighlight === 'off-path' && opts.colorize;\n // The baseline's label is the ∅ empty-source token (the gutter draws ○ for\n // every node, including the baseline); a real contract's label is its hash.\n const hashText =\n contractHash === EMPTY_CONTRACT_HASH\n ? (offPath ? forcedDim : style.glyph)(emptySource)\n : (offPath ? forcedDim : style.sourceHash)(\n abbreviateHash(contractHash, hashLength, emptySource),\n );\n if (!hasOverlays) return hashText;\n const overlay = formatContractNodeOverlays(style, overlays.markers, overlays.refs);\n return `${hashText} ${overlay}`;\n}\n\n/**\n * The label text for a migration row: the migration name (padded to\n * `dirNameWidth`) followed by the `from → to` hash column and the annotation\n * suffix (ops / status / will-run).\n *\n * In flat mode the name is tinted with its lane's hue (`lane` ≥ 0), so the node\n * `○`, the edges/arrows in the gutter, and the name all read in one colour. In\n * focus mode the on-path/off-path role overrides the lane hue (bold / dim).\n */\nexport function formatMigrationLabel(\n edge: ClassifiedEdge,\n dirNameWidth: number,\n opts: MigrationGraphLabelOptions,\n lane?: number,\n): string {\n const style = createLabelStyler(opts);\n const hashLength = opts.hashLength ?? MIGRATION_LIST_HASH_WIDTH;\n const glyphMode = opts.glyphMode ?? 'unicode';\n const highlight = opts.edgeAnnotationsByHash?.get(edge.migrationHash)?.pathHighlight;\n\n let dirNameStyler: (text: string) => string;\n let hashOverride: ((text: string) => string) | undefined;\n if (highlight === 'on-path') {\n // On-path: tint the name with the on-path green (matching the route's green\n // glyphs in the gutter), not bolded.\n dirNameStyler = opts.colorize ? forcedGreen : (text) => text;\n hashOverride = undefined;\n } else if (highlight === 'off-path') {\n dirNameStyler = opts.colorize ? forcedDim : style.dirName;\n hashOverride = opts.colorize ? forcedDim : undefined;\n } else if (opts.colorize && lane !== undefined) {\n // Flat mode: tint the name with the lane hue (matching the lane's\n // node/edge/arrow colour in the gutter), not bolded.\n dirNameStyler = (text) => laneColorizer(lane)(text);\n hashOverride = undefined;\n } else {\n dirNameStyler = style.dirName;\n hashOverride = undefined;\n }\n\n const dirNamePadding = ' '.repeat(Math.max(0, dirNameWidth - edge.dirName.length));\n const dirName = `${dirNameStyler(edge.dirName)}${dirNamePadding}`;\n const hashColumn = formatEdgeHashColumn(edge, style, hashLength, glyphMode, hashOverride);\n const annotationSuffix = formatEdgeAnnotationSuffix(edge.migrationHash, opts, style);\n return `${dirName}${hashColumn}${annotationSuffix}`;\n}\n\n/**\n * Format a single on-path migration row for the `migrate --show` run-list.\n * Shares PATH_HIGHLIGHT_STYLES.onPath with the graph tree so the run-list and\n * the graph are byte-for-byte identical in their name/hash columns.\n */\nexport function formatOnPathMigrationRow(\n dirName: string,\n from: string,\n to: string,\n dirNameWidth: number,\n colorize: boolean,\n glyphMode: GlyphMode,\n): string {\n const style = createAnsiMigrationListStyler({ useColor: colorize });\n const s = PATH_HIGHLIGHT_STYLES.onPath(style, colorize);\n const styledDirName = `${s.dirName(dirName)}${' '.repeat(Math.max(0, dirNameWidth - dirName.length))}`;\n const hashLength = MIGRATION_LIST_HASH_WIDTH;\n const emptySource = migrationListEmptySource(glyphMode);\n const forwardArrow = migrationListForwardArrow(glyphMode);\n const fromAbbr =\n from === EMPTY_CONTRACT_HASH\n ? padFromHashColumn(style.glyph(emptySource), hashLength)\n : padFromHashColumn(\n style.sourceHash(abbreviateHash(from, hashLength, emptySource)),\n hashLength,\n );\n const toAbbr =\n to === EMPTY_CONTRACT_HASH\n ? style.glyph(emptySource)\n : style.destHash(abbreviateHash(to, hashLength, emptySource));\n const arrow = style.glyph(forwardArrow);\n return `${styledDirName} ${fromAbbr} ${arrow} ${toAbbr}`;\n}\n\nexport interface RenderMigrationGraphLegendOptions {\n readonly colorize: boolean;\n readonly glyphMode?: GlyphMode;\n}\n\nfunction legendGlyphs(mode: GlyphMode): {\n readonly node: string;\n readonly forward: string;\n readonly rollback: string;\n readonly self: string;\n} {\n return mode === 'ascii'\n ? { node: '*', forward: '^', rollback: 'v', self: '@' }\n : { node: '○', forward: '↑', rollback: '↓', self: '⟲' };\n}\n\nfunction formatLegendExampleMarkers(colorize: boolean): string {\n if (!colorize) {\n return '@contract @db';\n }\n const sigil = green('@');\n return `${sigil + bold(green('contract'))} ${sigil}${green('db')}`;\n}\n\n/**\n * A compact key for the tree visual language: the contract node glyph, the\n * in-lane direction arrows, the empty baseline, the system-marker `@…` and\n * user-ref `(…)` conventions, and a worked sample of the data-column hash arrow.\n */\nexport function renderMigrationGraphLegend(opts: RenderMigrationGraphLegendOptions): string {\n const glyphMode = opts.glyphMode ?? 'unicode';\n const style = createAnsiMigrationListStyler({ useColor: opts.colorize });\n const glyphs = legendGlyphs(glyphMode);\n const emptySource = migrationListEmptySource(glyphMode);\n const forwardArrow = migrationListForwardArrow(glyphMode);\n const sampleArrow = `${style.sourceHash('aaaaaa')} ${style.glyph(forwardArrow)} ${style.destHash('bbbbbb')}`;\n const statusGlyphs = overlayStatusGlyphs(glyphMode);\n const appliedPending = opts.colorize\n ? ` ${green(statusGlyphs.applied)} ${style.summary('applied')} ${yellow(statusGlyphs.pending)} ${style.summary('pending')}`\n : ` ${statusGlyphs.applied} ${style.summary('applied')} ${statusGlyphs.pending} ${style.summary('pending')}`;\n const exampleMarkers = formatLegendExampleMarkers(opts.colorize);\n const exampleRefs = opts.colorize ? style.refs(['prod', 'staging']) : '(prod, staging)';\n const lines = [\n 'Legend:',\n ` ${style.kind(glyphs.node)} ${style.summary('contract')} ${style.kind(glyphs.forward)} ${style.summary('forward')} ${style.kind(glyphs.rollback)} ${style.summary('rollback')}`,\n ` ${style.kind(glyphs.self)} ${style.summary('migration without schema change')}`,\n appliedPending,\n ` ${style.kind(emptySource)} ${style.summary('empty database (baseline)')}`,\n ` ${exampleMarkers} ${style.summary('reserved markers — also typeable as --from/--to tokens')}`,\n ` ${exampleRefs} ${style.summary('user-defined refs')}`,\n ` ${sampleArrow} ${style.summary('migration from contract aaaaaa to bbbbbb')}`,\n ];\n return lines.join('\\n');\n}\n\n// Re-export the edge kind type alias for downstream label callers.\nexport type { MigrationEdgeKind };\n","/**\n * Command graph renderer: composes the gutter (from the grid) with per-row labels.\n *\n * Pipeline: buildMigrationGraphRows → buildGrid → renderMigrationGraphCommand\n *\n * Each grid row is classified by its cells: a node row gets a contract label;\n * a migration arrow row gets a migration label; connector rows get no label.\n * Label format and styling live in `./migration-graph-labels`.\n */\n\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport stringWidth from 'string-width';\nimport type { GlyphMode } from '../glyph-mode';\nimport {\n formatMigrationLabel,\n formatNodeLabel,\n type MigrationEdgeAnnotation,\n type MigrationGraphLabelOptions,\n} from './migration-graph-labels';\nimport type { Cell, CellLine, Grid } from './migration-graph-model';\nimport { renderGridRow } from './migration-graph-occlusion-render';\nimport type { ClassifiedEdge, MigrationGraphRowModel } from './migration-graph-rows';\nimport type { MigrationListStyler } from './migration-list-render';\n\nconst LABEL_GAP = 2;\nconst MIN_HASH_DATA_COLUMN = 25;\n\nexport interface RenderMigrationGraphCommandInput {\n readonly grid: Grid;\n readonly rowModel: MigrationGraphRowModel;\n readonly colorize: boolean;\n readonly glyphMode: GlyphMode;\n readonly refsByHash?: ReadonlyMap<string, readonly string[]>;\n readonly edgeAnnotationsByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;\n readonly dbHash?: string;\n readonly contractHash?: string;\n readonly isAppSpace?: boolean;\n readonly activeRefName?: string;\n readonly styler?: MigrationListStyler;\n /** Cross-space override for the gutter→label column (max gutter width). */\n readonly globalLabelColumn?: number;\n /** Cross-space override for the migration-name column width. */\n readonly globalMaxDirNameWidth?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Row classification — derive each grid row's identity from its own cells.\n// ---------------------------------------------------------------------------\n\ntype RowIdentity =\n | { readonly kind: 'node'; readonly contractHash: string }\n | { readonly kind: 'migration'; readonly edge: ClassifiedEdge; readonly lane: number }\n | { readonly kind: 'none' };\n\n/**\n * Classify a grid row by its own cells:\n * - a cell carrying a NodeRef → node row (contract label);\n * - a cell whose top line is an arrow ({up}/{down}/self-loop) → migration row;\n * - otherwise → no label.\n *\n * A migration's arrow appears in exactly one grid row (the forward `↑` row, the\n * adjacent-rollback `↓` row, or the self-loop `⟲` row), so each migration gets\n * exactly one label, on the row that draws its arrow.\n *\n * Two distinct migrations with identical content (same from/to/ops) hash to the\n * SAME migration hash, so the arrow line is matched on BOTH its hash and its\n * `dirName` (which the LineRef carries per-row) — otherwise both rows would\n * resolve to one edge and the other migration's name would be lost.\n */\nfunction classifyRow(\n row: readonly Cell[],\n edgesByHash: ReadonlyMap<string, readonly ClassifiedEdge[]>,\n): RowIdentity {\n for (const cell of row) {\n if (cell.node !== undefined) {\n return { kind: 'node', contractHash: cell.node.contractHash };\n }\n }\n for (const cell of row) {\n const arrow = arrowLine(cell);\n if (arrow === undefined) continue;\n const candidates = edgesByHash.get(arrow.line.migrationHash) ?? [];\n const edge = candidates.find((e) => e.dirName === arrow.line.dirName) ?? candidates[0];\n if (edge !== undefined) return { kind: 'migration', edge, lane: arrow.line.lane };\n }\n return { kind: 'none' };\n}\n\n/**\n * Return the cell's arrow line if it carries one — a self-loop, or a line whose\n * directions are exactly `{up}` or `{down}` (the migration-direction arrows).\n * Connector/corner/vertical lines are not arrows and yield `undefined`.\n */\nfunction arrowLine(cell: Cell): CellLine | undefined {\n for (const line of cell.lines) {\n if (line.selfLoop === true) return line;\n if (line.landingArrow === true) continue;\n const dirs = line.directions;\n if (dirs.size !== 1) continue;\n if (dirs.has('up') || dirs.has('down')) return line;\n }\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Node path-highlight resolution (focus mode).\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve each contract's path-highlight role from the edges incident on it.\n * On-path wins: a contract touched by any on-path edge is on-path. Empty unless\n * focus-mode annotations are present.\n */\nfunction resolveNodeHighlights(\n rowModel: MigrationGraphRowModel,\n edgeAnnotationsByHash: ReadonlyMap<string, MigrationEdgeAnnotation> | undefined,\n): Map<string, 'on-path' | 'off-path'> {\n const result = new Map<string, 'on-path' | 'off-path'>();\n if (edgeAnnotationsByHash === undefined) return result;\n for (const edge of rowModel.edges) {\n const highlight = edgeAnnotationsByHash.get(edge.migrationHash)?.pathHighlight;\n if (highlight === undefined) continue;\n for (const hash of [edge.from, edge.to]) {\n if (hash === EMPTY_CONTRACT_HASH) continue;\n if (result.get(hash) !== 'on-path') result.set(hash, highlight);\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Width helpers\n// ---------------------------------------------------------------------------\n\nfunction maxDirNameLength(edges: readonly ClassifiedEdge[]): number {\n let max = 0;\n for (const edge of edges) max = Math.max(max, edge.dirName.length);\n return max;\n}\n\n/**\n * The label column for a render: the widest gutter (visible width) across every\n * row, plus the label gap. Labels begin here so they line up regardless of how\n * deep the lane structure runs on any one row. A cross-space override widens it\n * so sibling space sections share one column.\n */\nexport function computeLabelColumn(grid: Grid, glyphMode: GlyphMode): number {\n let maxGutter = 0;\n for (const row of grid) {\n const gutter = renderGridRow(row, { colorize: false, glyphMode });\n maxGutter = Math.max(maxGutter, stringWidth(gutter));\n }\n return maxGutter + LABEL_GAP;\n}\n\nexport function computeMaxDirNameWidth(rowModel: MigrationGraphRowModel): number {\n return maxDirNameLength(rowModel.edges);\n}\n\nfunction padVisible(text: string, targetWidth: number): string {\n const padding = Math.max(0, targetWidth - stringWidth(text));\n return text + ' '.repeat(padding);\n}\n\nconst ANSI_ESCAPE = '\\x1b';\n\nfunction trimTrailingWhitespace(line: string): string {\n const trailingSpaceBeforeReset = new RegExp(`[\\\\t ]+((?:${ANSI_ESCAPE}\\\\[[0-9;]*m)+)$`);\n return line.replace(trailingSpaceBeforeReset, '$1').replace(/\\s+$/, '');\n}\n\n// ---------------------------------------------------------------------------\n// Render\n// ---------------------------------------------------------------------------\n\nexport function renderMigrationGraphCommand(input: RenderMigrationGraphCommandInput): string {\n const { grid, rowModel } = input;\n const glyphMode = input.glyphMode;\n\n // Edges grouped by hash — a list, not a single entry, because two distinct\n // migrations with identical content collide on one hash. classifyRow then\n // disambiguates by the row's own dirName.\n const edgesByHash = new Map<string, ClassifiedEdge[]>();\n for (const edge of rowModel.edges) {\n const bucket = edgesByHash.get(edge.migrationHash);\n if (bucket) bucket.push(edge);\n else edgesByHash.set(edge.migrationHash, [edge]);\n }\n\n const labelOpts: MigrationGraphLabelOptions = {\n colorize: input.colorize,\n glyphMode,\n ...ifDefined('refsByHash', input.refsByHash),\n ...ifDefined('edgeAnnotationsByHash', input.edgeAnnotationsByHash),\n ...ifDefined('dbHash', input.dbHash),\n ...ifDefined('contractHash', input.contractHash),\n ...ifDefined('isAppSpace', input.isAppSpace),\n ...ifDefined('activeRefName', input.activeRefName),\n ...ifDefined('styler', input.styler),\n };\n\n const nodeHighlights = resolveNodeHighlights(rowModel, input.edgeAnnotationsByHash);\n\n const labelColumn = input.globalLabelColumn ?? computeLabelColumn(grid, glyphMode);\n const maxDirNameLen = input.globalMaxDirNameWidth ?? maxDirNameLength(rowModel.edges);\n // The migration-name column is at least wide enough to push the `from → to`\n // hash column to MIN_HASH_DATA_COLUMN, matching the historical layout.\n const dirNameWidth = Math.max(maxDirNameLen + LABEL_GAP, MIN_HASH_DATA_COLUMN - labelColumn);\n\n const lines: string[] = [];\n for (const row of grid) {\n const gutter = renderGridRow(row, { colorize: input.colorize, glyphMode });\n const identity = classifyRow(row, edgesByHash);\n\n if (identity.kind === 'none') {\n // Connector / pass-through / back-arc rows carry no label. A wholly empty\n // grid row (the blank line between disjoint components) renders as a blank.\n lines.push(trimTrailingWhitespace(gutter));\n continue;\n }\n\n const gutterPad = padVisible(gutter, labelColumn);\n if (identity.kind === 'node') {\n const label = formatNodeLabel(\n identity.contractHash,\n labelOpts,\n nodeHighlights.get(identity.contractHash),\n );\n lines.push(trimTrailingWhitespace(label.length === 0 ? gutter : `${gutterPad}${label}`));\n continue;\n }\n\n const label = formatMigrationLabel(identity.edge, dirNameWidth, labelOpts, identity.lane);\n lines.push(trimTrailingWhitespace(`${gutterPad}${label}`));\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}