prisma-next 0.12.0-dev.5 → 0.12.0-dev.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +2 -2
- package/dist/commands/migration-graph.d.mts +19 -1
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -2
- package/dist/{migration-graph-D7DVUElV.mjs → migration-graph-BzxEsMZg.mjs} +296 -65
- package/dist/migration-graph-BzxEsMZg.mjs.map +1 -0
- package/package.json +11 -11
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { createDbUpdateCommand } from "./commands/db-update.mjs";
|
|
|
9
9
|
import { t as createDbVerifyCommand } from "./db-verify-v_vUKXTU.mjs";
|
|
10
10
|
import { createMigrateCommand } from "./commands/migrate.mjs";
|
|
11
11
|
import { t as createMigrationCheckCommand } from "./migration-check-BiBJoYYW.mjs";
|
|
12
|
-
import { t as createMigrationGraphCommand } from "./migration-graph-
|
|
12
|
+
import { t as createMigrationGraphCommand } from "./migration-graph-BzxEsMZg.mjs";
|
|
13
13
|
import { createMigrationListCommand } from "./commands/migration-list.mjs";
|
|
14
14
|
import { createMigrationLogCommand } from "./commands/migration-log.mjs";
|
|
15
15
|
import { createMigrationNewCommand } from "./commands/migration-new.mjs";
|
|
@@ -24,7 +24,7 @@ import { fileURLToPath } from "node:url";
|
|
|
24
24
|
import { readUserConfig, resolveGating, runTelemetry } from "@prisma-next/cli-telemetry";
|
|
25
25
|
import { distance } from "closest-match";
|
|
26
26
|
//#region package.json
|
|
27
|
-
var version = "0.12.0-dev.
|
|
27
|
+
var version = "0.12.0-dev.7";
|
|
28
28
|
//#endregion
|
|
29
29
|
//#region src/utils/telemetry.ts
|
|
30
30
|
/**
|
|
@@ -12,7 +12,25 @@ interface MigrationGraphOptions extends CommonCommandOptions {
|
|
|
12
12
|
readonly dot?: boolean;
|
|
13
13
|
readonly tree?: boolean;
|
|
14
14
|
readonly ascii?: boolean;
|
|
15
|
+
readonly legend?: boolean;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* `--legend` describes the `--tree` visual language, so passing it auto-enables
|
|
19
|
+
* the tree path (it has nothing to say about the legacy dagre default).
|
|
20
|
+
*/
|
|
21
|
+
declare function migrationGraphUsesTree(options: {
|
|
22
|
+
readonly tree?: boolean;
|
|
23
|
+
readonly legend?: boolean;
|
|
24
|
+
}): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The legend is decoration printed alongside the command header on stderr, so
|
|
27
|
+
* it is suppressed for the machine-readable / silent paths (`--json`, `--dot`,
|
|
28
|
+
* `--quiet`) exactly as the header is.
|
|
29
|
+
*/
|
|
30
|
+
declare function migrationGraphShowsLegend(options: {
|
|
31
|
+
readonly legend?: boolean;
|
|
32
|
+
readonly dot?: boolean;
|
|
33
|
+
}, flags: GlobalFlags): boolean;
|
|
16
34
|
interface MigrationGraphResult {
|
|
17
35
|
readonly ok: true;
|
|
18
36
|
readonly graph: MigrationGraph;
|
|
@@ -23,5 +41,5 @@ interface MigrationGraphResult {
|
|
|
23
41
|
declare function executeMigrationGraphCommand(options: MigrationGraphOptions, flags: GlobalFlags, ui: TerminalUI): Promise<Result<MigrationGraphResult, CliStructuredError>>;
|
|
24
42
|
declare function createMigrationGraphCommand(): Command;
|
|
25
43
|
//#endregion
|
|
26
|
-
export { MigrationGraphResult, createMigrationGraphCommand, executeMigrationGraphCommand };
|
|
44
|
+
export { MigrationGraphResult, createMigrationGraphCommand, executeMigrationGraphCommand, migrationGraphShowsLegend, migrationGraphUsesTree };
|
|
27
45
|
//# sourceMappingURL=migration-graph.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-graph.d.mts","names":[],"sources":["../../src/commands/migration-graph.ts"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"migration-graph.d.mts","names":[],"sources":["../../src/commands/migration-graph.ts"],"mappings":";;;;;;;;;UA6BU,qBAAA,SAA8B,oBAAoB;EAAA,SACjD,MAAA;EAAA,SACA,GAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;AAAA;;;;;iBAOK,sBAAA,CAAuB,OAAA;EAAA,SAC5B,IAAA;EAAA,SACA,MAAA;AAAA;;;;;;iBAUK,yBAAA,CACd,OAAA;EAAA,SAAoB,MAAA;EAAA,SAA2B,GAAA;AAAA,GAC/C,KAAA,EAAO,WAAW;AAAA,UAOH,oBAAA;EAAA,SACN,EAAA;EAAA,SACA,KAAA,EAAO,cAAA;EAAA,SACP,YAAA;EAAA,SACA,IAAA,WAAe,SAAS;EAAA,SACxB,OAAA;AAAA;AAAA,iBAGW,4BAAA,CACpB,OAAA,EAAS,qBAAA,EACT,KAAA,EAAO,WAAA,EACP,EAAA,EAAI,UAAA,GACH,OAAA,CAAQ,MAAA,CAAO,oBAAA,EAAsB,kBAAA;AAAA,iBAoDxB,2BAAA,CAAA,GAA+B,OAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as executeMigrationGraphCommand, t as createMigrationGraphCommand } from "../migration-graph-
|
|
2
|
-
export { createMigrationGraphCommand, executeMigrationGraphCommand };
|
|
1
|
+
import { i as migrationGraphUsesTree, n as executeMigrationGraphCommand, r as migrationGraphShowsLegend, t as createMigrationGraphCommand } from "../migration-graph-BzxEsMZg.mjs";
|
|
2
|
+
export { createMigrationGraphCommand, executeMigrationGraphCommand, migrationGraphShowsLegend, migrationGraphUsesTree };
|
|
@@ -5,7 +5,7 @@ import { i as migrationGraphToRenderInput, n as graphRenderer } from "./graph-re
|
|
|
5
5
|
import { a as migrationListEmptySource, n as createAnsiMigrationListStyler, o as migrationListForwardArrow, s as classifyMigrationGraphTopology, t as CONTRACT_MARKER_NAME } from "./migration-list-styler-BRwF4-gy.mjs";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { ok } from "@prisma-next/utils/result";
|
|
8
|
-
import { bold } from "colorette";
|
|
8
|
+
import { bold, createColors } from "colorette";
|
|
9
9
|
import stringWidth from "string-width";
|
|
10
10
|
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
11
11
|
//#region src/utils/formatters/migration-graph-layout.ts
|
|
@@ -835,6 +835,30 @@ function buildMigrationGraphRows(graph, options = {}) {
|
|
|
835
835
|
};
|
|
836
836
|
}
|
|
837
837
|
//#endregion
|
|
838
|
+
//#region src/utils/formatters/migration-graph-lane-colors.ts
|
|
839
|
+
const { magenta: magenta$1, cyan: cyan$1, green: green$1, yellow: yellow$1, blueBright, red: red$1 } = createColors({ useColor: true });
|
|
840
|
+
const LANE_COLOR_CYCLE = [
|
|
841
|
+
magenta$1,
|
|
842
|
+
cyan$1,
|
|
843
|
+
green$1,
|
|
844
|
+
yellow$1,
|
|
845
|
+
blueBright,
|
|
846
|
+
red$1
|
|
847
|
+
];
|
|
848
|
+
/**
|
|
849
|
+
* The hue for a gutter column. The leftmost lane (column 0) is **neutral** — it
|
|
850
|
+
* has nothing to be told apart from in the common single-lane linear case, so
|
|
851
|
+
* the renderer dims it rather than tinting it; the rotating palette is reserved
|
|
852
|
+
* for columns ≥ 1 (where a second lane exists to distinguish). Callers must dim
|
|
853
|
+
* column 0 themselves; this returns identity for it as a guard. A lane freed and
|
|
854
|
+
* reused by a later branch keeps its column's hue — coloring is by position, not
|
|
855
|
+
* branch identity, exactly like `git log --graph`.
|
|
856
|
+
*/
|
|
857
|
+
function laneColorForColumn(column) {
|
|
858
|
+
if (column <= 0) return (text) => text;
|
|
859
|
+
return LANE_COLOR_CYCLE[(column - 1) % LANE_COLOR_CYCLE.length] ?? ((text) => text);
|
|
860
|
+
}
|
|
861
|
+
//#endregion
|
|
838
862
|
//#region src/utils/formatters/migration-graph-tree-render.ts
|
|
839
863
|
const LABEL_GAP = 2;
|
|
840
864
|
/**
|
|
@@ -902,74 +926,226 @@ function arrowForEdgeKind(kind, palette) {
|
|
|
902
926
|
return palette.edgeArrow[kind];
|
|
903
927
|
}
|
|
904
928
|
/**
|
|
929
|
+
* The leftmost lane (column 0) renders with the neutral dim lane style rather
|
|
930
|
+
* than a palette hue — in the common single-lane case it has nothing to be told
|
|
931
|
+
* apart from. Used as the "no owning arc" sentinel during colour resolution.
|
|
932
|
+
*/
|
|
933
|
+
const NEUTRAL_LANE = 0;
|
|
934
|
+
/**
|
|
935
|
+
* Forced bold for branch-coloured names. A branched name pairs its lane hue
|
|
936
|
+
* (also forced, via {@link laneColorForColumn}) with bold; both must emit even
|
|
937
|
+
* when colorette's ambient TTY detection is off, so the colorized branch name
|
|
938
|
+
* is deterministically bold + hue rather than hue-only.
|
|
939
|
+
*/
|
|
940
|
+
const { bold: forcedBold } = createColors({ useColor: true });
|
|
941
|
+
/**
|
|
942
|
+
* Resolve per-cell colour columns for a row. Scanning right-to-left lets each
|
|
943
|
+
* arc bridge inherit the corner column that closes it (the arc's back-lane), so
|
|
944
|
+
* the whole arc — vertical run (already its own column), horizontal bridges,
|
|
945
|
+
* corners, crossings, and the `◂`/`─` connector — reads as a single continuous
|
|
946
|
+
* hue. A crossing can only be one colour, so rather than leave it dim (wrong for
|
|
947
|
+
* both crossing lines) it takes the arc owning the horizontal run at this row
|
|
948
|
+
* (the nearest corner to its right); the crossed vertical lane is simply
|
|
949
|
+
* occluded at that one cell and reappears on the next row.
|
|
950
|
+
*/
|
|
951
|
+
function resolveRowLaneColors(cells) {
|
|
952
|
+
const lane = new Array(cells.length);
|
|
953
|
+
const connector = new Array(cells.length);
|
|
954
|
+
let arcCorner = NEUTRAL_LANE;
|
|
955
|
+
for (let column = cells.length - 1; column >= 0; column--) {
|
|
956
|
+
const cell = cells[column];
|
|
957
|
+
connector[column] = arcCorner;
|
|
958
|
+
switch (cell?.kind) {
|
|
959
|
+
case "arc-branch-corner":
|
|
960
|
+
case "arc-land-corner":
|
|
961
|
+
arcCorner = column;
|
|
962
|
+
lane[column] = column;
|
|
963
|
+
break;
|
|
964
|
+
case "arc-branch-tee":
|
|
965
|
+
lane[column] = column;
|
|
966
|
+
break;
|
|
967
|
+
case "arc-crossing":
|
|
968
|
+
case "arc-land-bridge":
|
|
969
|
+
lane[column] = arcCorner;
|
|
970
|
+
break;
|
|
971
|
+
case "horizontal-pass":
|
|
972
|
+
lane[column] = arcCorner === NEUTRAL_LANE ? column : arcCorner;
|
|
973
|
+
break;
|
|
974
|
+
case "node":
|
|
975
|
+
lane[column] = column;
|
|
976
|
+
arcCorner = NEUTRAL_LANE;
|
|
977
|
+
break;
|
|
978
|
+
default:
|
|
979
|
+
lane[column] = column;
|
|
980
|
+
arcCorner = NEUTRAL_LANE;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return {
|
|
984
|
+
lane,
|
|
985
|
+
connector
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Resolve per-cell connector colours. Scanning right-to-left, a corner or an
|
|
990
|
+
* intermediate tee anchors its own lane (its junction glyph takes that column),
|
|
991
|
+
* but a tee's **trailing dash leads into the branch on its right** (the next
|
|
992
|
+
* branch point), so `┬─` reads as "this lane, then on toward the next" rather
|
|
993
|
+
* than tinting the dash with the left lane. The leading tee at `startLane` (the
|
|
994
|
+
* fork/merge origin) and pure horizontal segments inherit the nearest branch
|
|
995
|
+
* point to their right whole-cell, so the run into a branch — or collapsing
|
|
996
|
+
* into a merge corner — stays continuous. Pass-through verticals outside the
|
|
997
|
+
* run keep their own column (column 0 stays neutral).
|
|
998
|
+
*/
|
|
999
|
+
function resolveConnectorLaneColors(cells, startLane) {
|
|
1000
|
+
const glyph = new Array(cells.length);
|
|
1001
|
+
const dash = new Array(cells.length);
|
|
1002
|
+
let owner = NEUTRAL_LANE;
|
|
1003
|
+
for (let column = cells.length - 1; column >= 0; column--) switch (cells[column]?.kind) {
|
|
1004
|
+
case "branch-corner":
|
|
1005
|
+
case "merge-corner":
|
|
1006
|
+
owner = column;
|
|
1007
|
+
glyph[column] = column;
|
|
1008
|
+
dash[column] = column;
|
|
1009
|
+
break;
|
|
1010
|
+
case "branch-tee":
|
|
1011
|
+
case "merge-tee":
|
|
1012
|
+
if (column === startLane) {
|
|
1013
|
+
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
1014
|
+
glyph[column] = served;
|
|
1015
|
+
dash[column] = served;
|
|
1016
|
+
} else {
|
|
1017
|
+
dash[column] = owner === NEUTRAL_LANE ? column : owner;
|
|
1018
|
+
glyph[column] = column;
|
|
1019
|
+
owner = column;
|
|
1020
|
+
}
|
|
1021
|
+
break;
|
|
1022
|
+
case "horizontal-pass": {
|
|
1023
|
+
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
1024
|
+
glyph[column] = served;
|
|
1025
|
+
dash[column] = served;
|
|
1026
|
+
break;
|
|
1027
|
+
}
|
|
1028
|
+
default:
|
|
1029
|
+
glyph[column] = column;
|
|
1030
|
+
dash[column] = column;
|
|
1031
|
+
}
|
|
1032
|
+
return {
|
|
1033
|
+
glyph,
|
|
1034
|
+
dash
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Style a structural glyph by its resolved colour column. Column 0 and the
|
|
1039
|
+
* neutral sentinel render dim (`style.lane`); columns ≥ 1 take a palette hue.
|
|
1040
|
+
*/
|
|
1041
|
+
function laneStylerForColumn(colorColumn, colorize, style) {
|
|
1042
|
+
if (!colorize || colorColumn <= NEUTRAL_LANE) return (text) => style.lane(text);
|
|
1043
|
+
return laneColorForColumn(colorColumn);
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Tint a branch-owned token (direction arrow, migration name) by its edge's
|
|
1047
|
+
* lane so the whole branch row reads in one colour. Column 0 has nothing to be
|
|
1048
|
+
* told apart from in the common linear chain, so it keeps the token's existing
|
|
1049
|
+
* default styling (`fallback`) rather than a palette hue; only lanes ≥ 1 take a
|
|
1050
|
+
* colour. With colour off, the fallback (also colourless) is used unchanged.
|
|
1051
|
+
*/
|
|
1052
|
+
function branchStylerOrDefault(column, colorize, fallback) {
|
|
1053
|
+
if (!colorize || column <= NEUTRAL_LANE) return fallback;
|
|
1054
|
+
return laneColorForColumn(column);
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Render a connector tee (`├─` / `┬─` / `┴─`) with its junction glyph and its
|
|
1058
|
+
* trailing dash coloured independently: the junction anchors its own lane while
|
|
1059
|
+
* the dash leads into the branch on its right.
|
|
1060
|
+
*/
|
|
1061
|
+
function renderConnectorTee(pair, glyphColumn, dashColumn, colorize, style) {
|
|
1062
|
+
const glyph = laneStylerForColumn(glyphColumn, colorize, style);
|
|
1063
|
+
if (glyphColumn === dashColumn) return glyph(pair);
|
|
1064
|
+
return glyph(pair.slice(0, 1)) + laneStylerForColumn(dashColumn, colorize, style)(pair.slice(1));
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
905
1067
|
* A node-marker glyph pair (`○◂`, `○─`, `*<`, `*-`) is the contract node
|
|
906
|
-
* marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`).
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
*
|
|
1068
|
+
* marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`). The
|
|
1069
|
+
* marker takes its own lane's hue (so each node visibly belongs to its branch);
|
|
1070
|
+
* the connector follows the arc it belongs to (its owning back-lane hue).
|
|
1071
|
+
* Direction arrows are handled elsewhere — they take their edge's lane hue too.
|
|
910
1072
|
*/
|
|
911
|
-
function renderNodeMarkerPair(pair, style) {
|
|
912
|
-
|
|
1073
|
+
function renderNodeMarkerPair(pair, nodeColumn, arcColumn, colorize, style) {
|
|
1074
|
+
const marker = laneStylerForColumn(nodeColumn, colorize, style);
|
|
1075
|
+
const connector = laneStylerForColumn(arcColumn, colorize, style);
|
|
1076
|
+
return marker(pair.slice(0, 1)) + connector(pair.slice(1));
|
|
913
1077
|
}
|
|
914
|
-
function renderCellPair(cell, style, palette) {
|
|
1078
|
+
function renderCellPair(cell, column, colors, colorize, style, palette) {
|
|
1079
|
+
const lane = laneStylerForColumn(colors.lane[column] ?? column, colorize, style);
|
|
915
1080
|
switch (cell.kind) {
|
|
916
|
-
case "node":
|
|
917
|
-
|
|
918
|
-
if (cell.
|
|
919
|
-
return
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
case "
|
|
923
|
-
case "
|
|
924
|
-
case "branch-
|
|
925
|
-
case "merge-
|
|
926
|
-
case "
|
|
927
|
-
case "
|
|
928
|
-
case "arc-
|
|
929
|
-
case "arc-
|
|
930
|
-
case "arc-land-
|
|
931
|
-
case "
|
|
1081
|
+
case "node": {
|
|
1082
|
+
const arcColumn = colors.connector[column] ?? NEUTRAL_LANE;
|
|
1083
|
+
if (cell.arcLand === true) return renderNodeMarkerPair(palette.arcLand, column, arcColumn, colorize, style);
|
|
1084
|
+
if (cell.arcTee === true) return renderNodeMarkerPair(palette.arcTee, column, arcColumn, colorize, style);
|
|
1085
|
+
return lane(palette.node);
|
|
1086
|
+
}
|
|
1087
|
+
case "vertical-pass": return lane(palette.verticalPass);
|
|
1088
|
+
case "edge-lane": return cell.ownsLabel ? lane(palette.verticalPass.trimEnd()) + branchStylerOrDefault(column, colorize, style.kind)(arrowForEdgeKind(cell.edgeKind, palette)) : lane(palette.verticalPass);
|
|
1089
|
+
case "branch-tee": return lane(palette.branchTee);
|
|
1090
|
+
case "merge-tee": return lane(palette.mergeTee);
|
|
1091
|
+
case "branch-corner": return lane(palette.branchCorner);
|
|
1092
|
+
case "merge-corner": return lane(palette.mergeCorner);
|
|
1093
|
+
case "arc-branch-corner": return lane(palette.arcBranchCorner);
|
|
1094
|
+
case "arc-branch-tee": return lane(palette.arcBranchTee);
|
|
1095
|
+
case "arc-land-corner": return lane(palette.arcLandCorner);
|
|
1096
|
+
case "arc-crossing": return lane(palette.arcCrossing);
|
|
1097
|
+
case "arc-land-bridge": return lane(palette.arcLandBridge);
|
|
1098
|
+
case "horizontal-pass": return lane(palette.horizontalPass);
|
|
932
1099
|
case "empty": return " ";
|
|
933
1100
|
}
|
|
934
1101
|
}
|
|
935
|
-
function renderConnectorRow(row, gridWidth, style, palette) {
|
|
1102
|
+
function renderConnectorRow(row, gridWidth, colorize, style, palette) {
|
|
936
1103
|
const isMerge = row.kind === "merge-connector";
|
|
937
1104
|
if (row.cells.length > 0) {
|
|
1105
|
+
const colors = resolveConnectorLaneColors(row.cells, row.startLane ?? 0);
|
|
938
1106
|
let seenTee = false;
|
|
939
1107
|
let out = "";
|
|
940
|
-
for (
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1108
|
+
for (let column = 0; column < row.cells.length; column++) {
|
|
1109
|
+
const cell = row.cells[column];
|
|
1110
|
+
if (cell === void 0) continue;
|
|
1111
|
+
const glyphColumn = colors.glyph[column] ?? column;
|
|
1112
|
+
const dashColumn = colors.dash[column] ?? glyphColumn;
|
|
1113
|
+
const lane = laneStylerForColumn(glyphColumn, colorize, style);
|
|
1114
|
+
switch (cell.kind) {
|
|
1115
|
+
case "branch-tee":
|
|
1116
|
+
out += renderConnectorTee(seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee, glyphColumn, dashColumn, colorize, style);
|
|
1117
|
+
seenTee = true;
|
|
1118
|
+
break;
|
|
1119
|
+
case "merge-tee":
|
|
1120
|
+
out += renderConnectorTee(seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee, glyphColumn, dashColumn, colorize, style);
|
|
1121
|
+
seenTee = true;
|
|
1122
|
+
break;
|
|
1123
|
+
case "branch-corner":
|
|
1124
|
+
out += lane(palette.branchCorner);
|
|
1125
|
+
break;
|
|
1126
|
+
case "merge-corner":
|
|
1127
|
+
out += lane(palette.mergeCorner);
|
|
1128
|
+
break;
|
|
1129
|
+
case "vertical-pass":
|
|
1130
|
+
out += lane(palette.verticalPass);
|
|
1131
|
+
break;
|
|
1132
|
+
case "horizontal-pass":
|
|
1133
|
+
out += lane(palette.horizontalPass);
|
|
1134
|
+
break;
|
|
1135
|
+
default: out += " ";
|
|
1136
|
+
}
|
|
962
1137
|
}
|
|
963
1138
|
for (let column = row.cells.length; column < gridWidth; column++) out += " ";
|
|
964
1139
|
return out;
|
|
965
1140
|
}
|
|
966
1141
|
const start = row.startLane ?? 0;
|
|
967
1142
|
const end = row.endLane ?? start;
|
|
1143
|
+
const runLane = laneStylerForColumn(end, colorize, style);
|
|
968
1144
|
let out = "";
|
|
969
1145
|
for (let column = 0; column < gridWidth; column++) if (column < start || column > end) out += " ";
|
|
970
|
-
else if (column === start) out +=
|
|
971
|
-
else if (column === end) out +=
|
|
972
|
-
else out +=
|
|
1146
|
+
else if (column === start) out += runLane(palette.connectorBranchTee);
|
|
1147
|
+
else if (column === end) out += runLane(isMerge ? palette.mergeCorner : palette.branchCorner);
|
|
1148
|
+
else out += runLane(isMerge ? palette.connectorMergeTeeCo : palette.connectorBranchTeeCo);
|
|
973
1149
|
return out;
|
|
974
1150
|
}
|
|
975
1151
|
function abbreviateHash(hash, hashLength, emptySource) {
|
|
@@ -1008,6 +1184,11 @@ function padVisible(text, targetWidth) {
|
|
|
1008
1184
|
const padding = Math.max(0, targetWidth - stringWidth(text));
|
|
1009
1185
|
return text + " ".repeat(padding);
|
|
1010
1186
|
}
|
|
1187
|
+
const ANSI_ESCAPE = "\x1B";
|
|
1188
|
+
function trimTrailingWhitespace(line) {
|
|
1189
|
+
const trailingSpaceBeforeReset = new RegExp(`[\\t ]+((?:${ANSI_ESCAPE}\\[[0-9;]*m)+)$`);
|
|
1190
|
+
return line.replace(trailingSpaceBeforeReset, "$1").replace(/\s+$/, "");
|
|
1191
|
+
}
|
|
1011
1192
|
function gridWidthForModel(rows) {
|
|
1012
1193
|
return rows.reduce((max, row) => row.kind === "node" || row.kind === "edge" ? Math.max(max, row.cells.length) : max, 1);
|
|
1013
1194
|
}
|
|
@@ -1047,10 +1228,11 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1047
1228
|
continue;
|
|
1048
1229
|
}
|
|
1049
1230
|
if (row.kind === "branch-connector" || row.kind === "merge-connector") {
|
|
1050
|
-
lines.push(renderConnectorRow(row, gridWidth, style, palette)
|
|
1231
|
+
lines.push(trimTrailingWhitespace(renderConnectorRow(row, gridWidth, opts.colorize, style, palette)));
|
|
1051
1232
|
continue;
|
|
1052
1233
|
}
|
|
1053
|
-
|
|
1234
|
+
const cellColors = resolveRowLaneColors(row.cells);
|
|
1235
|
+
let gutter = row.cells.map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1054
1236
|
const prevRow = model.rows[rowIndex - 1];
|
|
1055
1237
|
let laneSpan = row.cells.length;
|
|
1056
1238
|
if (row.kind === "node") {
|
|
@@ -1059,8 +1241,8 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1059
1241
|
else laneSpan = row.cells.length;
|
|
1060
1242
|
}
|
|
1061
1243
|
const labelColumn = row.kind === "edge" ? edgeLabelColumn(row, wideLabelColumn) : wideLabelColumn !== void 0 && (nodeHasArcDecoration(row) || row.contractHash !== void 0) ? wideLabelColumn : laneSpan * 2 + LABEL_GAP;
|
|
1062
|
-
if (row.kind === "edge" && row.edge?.from === EMPTY_CONTRACT_HASH && (row.laneIndex ?? 0) === 0) gutter = row.cells.slice(0, 1).map((cell) => renderCellPair(cell, style, palette)).join("");
|
|
1063
|
-
else if (row.kind === "node" && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) gutter = row.cells.slice(0, laneSpan).map((cell) => renderCellPair(cell, style, palette)).join("");
|
|
1244
|
+
if (row.kind === "edge" && row.edge?.from === EMPTY_CONTRACT_HASH && (row.laneIndex ?? 0) === 0) gutter = row.cells.slice(0, 1).map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1245
|
+
else if (row.kind === "node" && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) gutter = row.cells.slice(0, laneSpan).map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1064
1246
|
else if (gutter.length < laneSpan * 2) gutter = gutter.padEnd(laneSpan * 2, " ");
|
|
1065
1247
|
const dirNameWidth = rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);
|
|
1066
1248
|
const dataColumn = labelColumn + dirNameWidth;
|
|
@@ -1068,35 +1250,76 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1068
1250
|
if (row.kind === "node") {
|
|
1069
1251
|
const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;
|
|
1070
1252
|
if (contractHash === EMPTY_CONTRACT_HASH) {
|
|
1071
|
-
const trailingLanes = row.cells.slice(1).map((cell) => renderCellPair(cell, style, palette)).join("");
|
|
1253
|
+
const trailingLanes = row.cells.slice(1).map((cell, offset) => renderCellPair(cell, offset + 1, cellColors, opts.colorize, style, palette)).join("");
|
|
1072
1254
|
const emptyGutter = palette.emptySource.padEnd(2, " ") + trailingLanes;
|
|
1073
1255
|
const overlayNames = overlayNamesForContract(contractHash, opts);
|
|
1074
1256
|
if (overlayNames.length === 0) {
|
|
1075
|
-
lines.push(emptyGutter
|
|
1257
|
+
lines.push(trimTrailingWhitespace(emptyGutter));
|
|
1076
1258
|
continue;
|
|
1077
1259
|
}
|
|
1078
1260
|
const overlay = style.refs(overlayNames);
|
|
1079
|
-
lines.push(`${padVisible(emptyGutter, dataColumn)}${overlay}
|
|
1261
|
+
lines.push(trimTrailingWhitespace(`${padVisible(emptyGutter, dataColumn)}${overlay}`));
|
|
1080
1262
|
continue;
|
|
1081
1263
|
}
|
|
1082
1264
|
const hashText = style.sourceHash(abbreviateHash(contractHash, hashLength, palette.emptySource));
|
|
1083
1265
|
const overlayNames = overlayNamesForContract(contractHash, opts);
|
|
1084
1266
|
const overlayPad = overlayNames.length > 0 ? " ".repeat(Math.max(0, dataColumn - labelColumn - stringWidth(hashText))) : "";
|
|
1085
1267
|
const overlay = overlayNames.length > 0 ? style.refs(overlayNames) : "";
|
|
1086
|
-
lines.push(`${gutterPad}${hashText}${overlayPad}${overlay}
|
|
1268
|
+
lines.push(trimTrailingWhitespace(`${gutterPad}${hashText}${overlayPad}${overlay}`));
|
|
1087
1269
|
continue;
|
|
1088
1270
|
}
|
|
1089
1271
|
const edge = row.edge;
|
|
1090
1272
|
if (edge === void 0) continue;
|
|
1091
1273
|
const dirNamePadding = " ".repeat(Math.max(0, dirNameWidth - edge.dirName.length));
|
|
1092
|
-
const
|
|
1274
|
+
const laneIndex = row.laneIndex ?? 0;
|
|
1275
|
+
const dirName = `${(opts.colorize && laneIndex > NEUTRAL_LANE ? (text) => forcedBold(laneColorForColumn(laneIndex)(text)) : style.dirName)(edge.dirName)}${dirNamePadding}`;
|
|
1093
1276
|
const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);
|
|
1094
|
-
lines.push(`${gutterPad}${dirName}${hashColumn}
|
|
1277
|
+
lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}`));
|
|
1095
1278
|
}
|
|
1096
1279
|
return lines.join("\n");
|
|
1097
1280
|
}
|
|
1281
|
+
/**
|
|
1282
|
+
* A compact key for the `--tree` visual language: the contract marker, the
|
|
1283
|
+
* in-lane direction arrows, the empty baseline, the `(refs)` overlay (including
|
|
1284
|
+
* the reserved `db` live-database and `contract` working-schema markers), and a
|
|
1285
|
+
* worked sample of the data-column `from → to` migration hash arrow.
|
|
1286
|
+
*
|
|
1287
|
+
* Honors the same glyph palette (unicode vs ASCII) and `colorize` gate as the
|
|
1288
|
+
* tree renderer, so the key matches whatever the graph itself drew and stays
|
|
1289
|
+
* pipe-safe (zero ANSI when color is off). The caller adds the trailing blank
|
|
1290
|
+
* line that separates this stderr key from the graph on stdout.
|
|
1291
|
+
*/
|
|
1292
|
+
function renderMigrationGraphLegend(opts) {
|
|
1293
|
+
const palette = paletteFor(opts.glyphMode ?? "unicode");
|
|
1294
|
+
const style = createAnsiMigrationListStyler({ useColor: opts.colorize });
|
|
1295
|
+
const node = palette.node.trimEnd();
|
|
1296
|
+
const sampleArrow = `${style.sourceHash("aaaaaa")} ${style.glyph(palette.forwardArrow)} ${style.destHash("bbbbbb")}`;
|
|
1297
|
+
return [
|
|
1298
|
+
"Legend:",
|
|
1299
|
+
` ${style.kind(node)} contract ${style.kind(palette.edgeArrow.forward)} forward ${style.kind(palette.edgeArrow.rollback)} rollback`,
|
|
1300
|
+
` ${style.kind(palette.edgeArrow.self)} migration without schema change`,
|
|
1301
|
+
` ${style.glyph(palette.emptySource)} empty database (baseline)`,
|
|
1302
|
+
` ${style.refs(["refs"])} ${DB_MARKER_NAME} / ${CONTRACT_MARKER_NAME} markers`,
|
|
1303
|
+
` ${sampleArrow} migration from contract aaaaaa to bbbbbb`
|
|
1304
|
+
].join("\n");
|
|
1305
|
+
}
|
|
1098
1306
|
//#endregion
|
|
1099
1307
|
//#region src/commands/migration-graph.ts
|
|
1308
|
+
/**
|
|
1309
|
+
* `--legend` describes the `--tree` visual language, so passing it auto-enables
|
|
1310
|
+
* the tree path (it has nothing to say about the legacy dagre default).
|
|
1311
|
+
*/
|
|
1312
|
+
function migrationGraphUsesTree(options) {
|
|
1313
|
+
return options.tree === true || options.legend === true;
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* The legend is decoration printed alongside the command header on stderr, so
|
|
1317
|
+
* it is suppressed for the machine-readable / silent paths (`--json`, `--dot`,
|
|
1318
|
+
* `--quiet`) exactly as the header is.
|
|
1319
|
+
*/
|
|
1320
|
+
function migrationGraphShowsLegend(options, flags) {
|
|
1321
|
+
return options.legend === true && options.dot !== true && flags.json !== true && flags.quiet !== true;
|
|
1322
|
+
}
|
|
1100
1323
|
async function executeMigrationGraphCommand(options, flags, ui) {
|
|
1101
1324
|
const config = await loadConfig(options.config);
|
|
1102
1325
|
const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(options.config, config);
|
|
@@ -1114,6 +1337,13 @@ async function executeMigrationGraphCommand(options, flags, ui) {
|
|
|
1114
1337
|
flags
|
|
1115
1338
|
});
|
|
1116
1339
|
ui.stderr(header);
|
|
1340
|
+
if (migrationGraphShowsLegend(options, flags)) {
|
|
1341
|
+
ui.stderr(renderMigrationGraphLegend({
|
|
1342
|
+
colorize: flags.color !== false,
|
|
1343
|
+
glyphMode: ui.resolveGlyphMode(options.ascii === true)
|
|
1344
|
+
}));
|
|
1345
|
+
ui.stderr("");
|
|
1346
|
+
}
|
|
1117
1347
|
}
|
|
1118
1348
|
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
1119
1349
|
if (!loaded.ok) return loaded;
|
|
@@ -1139,7 +1369,8 @@ function createMigrationGraphCommand() {
|
|
|
1139
1369
|
"prisma-next migration graph --json",
|
|
1140
1370
|
"prisma-next migration graph --dot",
|
|
1141
1371
|
"prisma-next migration graph --tree",
|
|
1142
|
-
"prisma-next migration graph --tree --ascii"
|
|
1372
|
+
"prisma-next migration graph --tree --ascii",
|
|
1373
|
+
"prisma-next migration graph --legend"
|
|
1143
1374
|
]);
|
|
1144
1375
|
setCommandSeeAlso(command, [
|
|
1145
1376
|
{
|
|
@@ -1159,7 +1390,7 @@ function createMigrationGraphCommand() {
|
|
|
1159
1390
|
oneLiner: "Display migration package contents"
|
|
1160
1391
|
}
|
|
1161
1392
|
]);
|
|
1162
|
-
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").option("--dot", "Output in Graphviz DOT format").option("--tree", "Experimental condensed annotated tree renderer").option("--ascii", "Use ASCII glyphs for --tree (pipe-friendly)").action(async (options) => {
|
|
1393
|
+
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").option("--dot", "Output in Graphviz DOT format").option("--tree", "Experimental condensed annotated tree renderer").option("--ascii", "Use ASCII glyphs for --tree (pipe-friendly)").option("--legend", "Print a key for the --tree glyphs and lane colors (implies --tree)").action(async (options) => {
|
|
1163
1394
|
const flags = parseGlobalFlagsOrExit(options);
|
|
1164
1395
|
const ui = createTerminalUI(flags);
|
|
1165
1396
|
const exitCode = handleResult(await executeMigrationGraphCommand(options, flags, ui), flags, ui, (graphResult) => {
|
|
@@ -1186,7 +1417,7 @@ function createMigrationGraphCommand() {
|
|
|
1186
1417
|
edges,
|
|
1187
1418
|
summary: graphResult.summary
|
|
1188
1419
|
}, null, 2));
|
|
1189
|
-
} else if (!flags.quiet) if (options
|
|
1420
|
+
} else if (!flags.quiet) if (migrationGraphUsesTree(options)) {
|
|
1190
1421
|
const refsByHash = /* @__PURE__ */ new Map();
|
|
1191
1422
|
for (const ref of graphResult.refs) {
|
|
1192
1423
|
const existing = refsByHash.get(ref.hash);
|
|
@@ -1227,6 +1458,6 @@ function createMigrationGraphCommand() {
|
|
|
1227
1458
|
return command;
|
|
1228
1459
|
}
|
|
1229
1460
|
//#endregion
|
|
1230
|
-
export { executeMigrationGraphCommand as n, createMigrationGraphCommand as t };
|
|
1461
|
+
export { migrationGraphUsesTree as i, executeMigrationGraphCommand as n, migrationGraphShowsLegend as r, createMigrationGraphCommand as t };
|
|
1231
1462
|
|
|
1232
|
-
//# sourceMappingURL=migration-graph-
|
|
1463
|
+
//# sourceMappingURL=migration-graph-BzxEsMZg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-graph-BzxEsMZg.mjs","names":["magenta","cyan","green","yellow","red"],"sources":["../src/utils/formatters/migration-graph-layout.ts","../src/utils/formatters/migration-graph-rows.ts","../src/utils/formatters/migration-graph-lane-colors.ts","../src/utils/formatters/migration-graph-tree-render.ts","../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { ClassifiedEdge, MigrationGraphRowModel } from './migration-graph-rows';\nimport type { MigrationEdgeKind } from './migration-list-graph-topology';\n\nexport type EdgeAdjacency = 'adjacent' | 'node-skipping-forward' | 'node-skipping-rollback';\n\nexport type StructuralCell =\n | { readonly kind: 'empty' }\n | {\n readonly kind: 'node';\n readonly contractHash: string;\n readonly arcTee?: boolean;\n readonly arcLand?: boolean;\n }\n | { readonly kind: 'vertical-pass' }\n | { readonly kind: 'horizontal-pass' }\n | { readonly kind: 'branch-tee' }\n | { readonly kind: 'branch-corner' }\n | { readonly kind: 'merge-tee' }\n | { readonly kind: 'merge-corner' }\n | { readonly kind: 'arc-branch-corner' }\n | { readonly kind: 'arc-branch-tee' }\n | { readonly kind: 'arc-land-corner' }\n | { readonly kind: 'arc-crossing' }\n | { readonly kind: 'arc-land-bridge' }\n | {\n readonly kind: 'edge-lane';\n readonly migrationHash: string;\n readonly edgeKind: MigrationEdgeKind;\n readonly ownsLabel: boolean;\n readonly adjacency: EdgeAdjacency;\n };\n\nexport type GridRowKind =\n | 'node'\n | 'edge'\n | 'branch-connector'\n | 'merge-connector'\n | 'component-separator';\n\nexport interface MigrationGraphGridRow {\n readonly kind: GridRowKind;\n readonly contractHash?: string;\n readonly edge?: ClassifiedEdge;\n readonly laneIndex?: number;\n readonly passThroughLanes?: readonly number[];\n readonly startLane?: number;\n readonly endLane?: number;\n readonly branchCount?: number;\n readonly convergenceProducer?: boolean;\n readonly cells: readonly StructuralCell[];\n}\n\nexport interface MigrationGraphGridModel {\n readonly rows: readonly MigrationGraphGridRow[];\n readonly nodeColumn: ReadonlyMap<string, number>;\n readonly edgeColumn: ReadonlyMap<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// Edge bucketing helpers\n// ---------------------------------------------------------------------------\n\nfunction forwardEdges(edges: readonly ClassifiedEdge[]): ClassifiedEdge[] {\n return edges.filter((e) => e.kind === 'forward');\n}\n\nfunction buildForwardProducersByTo(\n edges: readonly ClassifiedEdge[],\n): Map<string, ClassifiedEdge[]> {\n const byTo = new Map<string, ClassifiedEdge[]>();\n for (const edge of edges) {\n if (edge.kind !== 'forward') continue;\n const bucket = byTo.get(edge.to);\n if (bucket) bucket.push(edge);\n else byTo.set(edge.to, [edge]);\n }\n return byTo;\n}\n\nfunction buildForwardOutDegree(edges: readonly ClassifiedEdge[]): Map<string, number> {\n const out = new Map<string, number>();\n for (const edge of edges) {\n if (edge.kind !== 'forward' || edge.from === edge.to) continue;\n out.set(edge.from, (out.get(edge.from) ?? 0) + 1);\n }\n return out;\n}\n\nfunction buildForwardInDegree(edges: readonly ClassifiedEdge[]): Map<string, number> {\n const indeg = new Map<string, number>();\n for (const edge of forwardEdges(edges)) {\n if (edge.from === edge.to) continue;\n indeg.set(edge.to, (indeg.get(edge.to) ?? 0) + 1);\n }\n return indeg;\n}\n\n/**\n * Distinct source contracts among a contract's forward producers. A contract is\n * a *convergence* when this count is >= 2. Multiple migrations sharing one\n * source (a multi-edge) count once — they stack in a single lane rather than\n * fanning into a convergence.\n */\nfunction buildDistinctSourceCountByTo(edges: readonly ClassifiedEdge[]): Map<string, number> {\n const sources = new Map<string, Set<string>>();\n for (const edge of edges) {\n if (edge.kind !== 'forward' || edge.from === edge.to) continue;\n const set = sources.get(edge.to);\n if (set) set.add(edge.from);\n else sources.set(edge.to, new Set([edge.from]));\n }\n const counts = new Map<string, number>();\n for (const [to, set] of sources) counts.set(to, set.size);\n return counts;\n}\n\nfunction splitComponents(nodes: readonly (string | null)[]): readonly (readonly string[])[] {\n const components: string[][] = [];\n let current: string[] = [];\n for (const node of nodes) {\n if (node === null) {\n if (current.length > 0) {\n components.push(current);\n current = [];\n }\n continue;\n }\n current.push(node);\n }\n if (current.length > 0) components.push(current);\n return components;\n}\n\n// ---------------------------------------------------------------------------\n// Adjacency refinement (operates on the emitted rows)\n// ---------------------------------------------------------------------------\n\nfunction classifyForwardShortConvergenceAdjacency(\n rows: readonly MigrationGraphGridRow[],\n edgeRowIndex: number,\n edge: ClassifiedEdge,\n laneIndex: number,\n): EdgeAdjacency {\n for (let index = edgeRowIndex + 1; index < rows.length; index++) {\n const row = rows[index];\n if (row === undefined) break;\n if (row.kind === 'component-separator' || row.kind === 'branch-connector') continue;\n if (row.kind === 'merge-connector') continue;\n if (row.kind === 'edge') {\n if (row.laneIndex === laneIndex) return 'node-skipping-forward';\n continue;\n }\n if (row.kind === 'node' && row.contractHash === edge.from) {\n return 'adjacent';\n }\n }\n return 'node-skipping-forward';\n}\n\nfunction convergenceProducerUsesShortAdjacency(\n edge: ClassifiedEdge,\n laneIndex: number,\n forwardProducersByTo: ReadonlyMap<string, readonly ClassifiedEdge[]>,\n producerLaneByHash: ReadonlyMap<string, number>,\n): boolean {\n const producers = (forwardProducersByTo.get(edge.to) ?? []).filter(\n (candidate) => candidate.kind === 'forward',\n );\n if (producers.length < 2) return false;\n\n const fanLanes = [\n ...new Set(\n producers\n .map((producer) => producerLaneByHash.get(producer.migrationHash))\n .filter((candidate): candidate is number => candidate !== undefined),\n ),\n ].sort((a, b) => a - b);\n const fanStart = fanLanes[0];\n if (fanStart === undefined) return false;\n\n return laneIndex === fanStart;\n}\n\nfunction classifyForwardLayoutAdjacency(\n rows: readonly MigrationGraphGridRow[],\n edgeRowIndex: number,\n edge: ClassifiedEdge,\n laneIndex: number,\n passThroughLanes: readonly number[],\n nodeColumn: ReadonlyMap<string, number>,\n convergenceProducer: boolean,\n divergenceBranchEdge: boolean,\n): EdgeAdjacency {\n let sawObstruction = false;\n const passThroughLaneSet = new Set(passThroughLanes);\n\n for (let index = edgeRowIndex + 1; index < rows.length; index++) {\n const row = rows[index];\n if (row === undefined) break;\n if (row.kind === 'component-separator') continue;\n if (row.kind === 'merge-connector') {\n if (convergenceProducer) {\n if (row.contractHash === edge.from) sawObstruction = true;\n } else if (!divergenceBranchEdge && row.contractHash !== edge.from) {\n sawObstruction = true;\n }\n continue;\n }\n if (row.kind === 'branch-connector') continue;\n if (row.kind === 'edge') {\n if (row.laneIndex === laneIndex) return 'node-skipping-forward';\n if (!divergenceBranchEdge && row.edge !== undefined && row.edge.to !== edge.to) {\n sawObstruction = true;\n }\n continue;\n }\n if (row.kind === 'node' && row.contractHash !== undefined) {\n if (row.contractHash === edge.from) {\n return sawObstruction ? 'node-skipping-forward' : 'adjacent';\n }\n const nodeCol = nodeColumn.get(row.contractHash) ?? 0;\n // A divergence-branch lane runs unobstructed to its convergence point;\n // sibling-branch nodes sit in parallel lanes and never block it.\n if (!divergenceBranchEdge && !passThroughLaneSet.has(nodeCol)) {\n sawObstruction = true;\n }\n }\n }\n\n return 'node-skipping-forward';\n}\n\nfunction classifyLayoutAdjacency(\n rows: readonly MigrationGraphGridRow[],\n edgeRowIndex: number,\n edge: ClassifiedEdge,\n laneIndex: number,\n passThroughLanes: readonly number[],\n nodeColumn: ReadonlyMap<string, number>,\n position: ReadonlyMap<string, number>,\n forwardInDegree: ReadonlyMap<string, number>,\n convergenceProducer: boolean,\n divergenceBranchEdge: boolean,\n): EdgeAdjacency {\n if (edge.kind === 'self') return 'adjacent';\n\n const fromPos = position.get(edge.from);\n const toPos = position.get(edge.to);\n\n if (edge.kind === 'forward') {\n const inDegree = forwardInDegree.get(edge.to) ?? 0;\n if (inDegree <= 1 && fromPos !== undefined && toPos !== undefined && fromPos === toPos + 1) {\n return 'adjacent';\n }\n return classifyForwardLayoutAdjacency(\n rows,\n edgeRowIndex,\n edge,\n laneIndex,\n passThroughLanes,\n nodeColumn,\n convergenceProducer,\n divergenceBranchEdge,\n );\n }\n\n if (fromPos !== undefined && toPos !== undefined && toPos === fromPos + 1) {\n return 'adjacent';\n }\n\n for (let index = edgeRowIndex + 1; index < rows.length; index++) {\n const row = rows[index];\n if (row === undefined) break;\n if (\n row.kind === 'component-separator' ||\n row.kind === 'branch-connector' ||\n row.kind === 'merge-connector'\n ) {\n continue;\n }\n if (row.kind === 'edge') continue;\n if (row.kind === 'node') {\n return row.contractHash === edge.to ? 'adjacent' : 'node-skipping-rollback';\n }\n }\n return 'node-skipping-rollback';\n}\n\nfunction refineAdjacency(\n rows: readonly MigrationGraphGridRow[],\n nodeColumn: ReadonlyMap<string, number>,\n position: ReadonlyMap<string, number>,\n forwardInDegree: ReadonlyMap<string, number>,\n forwardOutDegree: ReadonlyMap<string, number>,\n edges: readonly ClassifiedEdge[],\n producerLaneByHash: ReadonlyMap<string, number>,\n): MigrationGraphGridRow[] {\n const forwardProducersByTo = buildForwardProducersByTo(edges);\n function branchLaneForEdge(producer: ClassifiedEdge): number | undefined {\n const children = edges.filter(\n (edge) => edge.from === producer.from && edge.kind === 'forward' && edge.from !== edge.to,\n );\n if (children.length < 2) return undefined;\n const index = children.findIndex((child) => child.migrationHash === producer.migrationHash);\n return index >= 0 ? index : undefined;\n }\n\n return rows.map((row, rowIndex) => {\n if (row.kind !== 'edge' || row.edge === undefined || row.laneIndex === undefined) {\n return row;\n }\n const divergenceBranchEdge =\n row.edge.kind === 'forward' &&\n !(row.convergenceProducer ?? false) &&\n (forwardOutDegree.get(row.edge.from) ?? 0) >= 2 &&\n branchLaneForEdge(row.edge) !== undefined;\n const adjacency =\n row.convergenceProducer === true &&\n convergenceProducerUsesShortAdjacency(\n row.edge,\n row.laneIndex,\n forwardProducersByTo,\n producerLaneByHash,\n )\n ? classifyForwardShortConvergenceAdjacency(rows, rowIndex, row.edge, row.laneIndex)\n : classifyLayoutAdjacency(\n rows,\n rowIndex,\n row.edge,\n row.laneIndex,\n row.passThroughLanes ?? [],\n nodeColumn,\n position,\n forwardInDegree,\n row.convergenceProducer ?? false,\n divergenceBranchEdge,\n );\n return {\n ...row,\n cells: buildEdgeCells(\n row.edge,\n row.laneIndex,\n row.passThroughLanes ?? [],\n adjacency,\n row.cells.length,\n ),\n };\n });\n}\n\nfunction classifyEdgeAdjacency(\n edge: ClassifiedEdge,\n position: ReadonlyMap<string, number>,\n): EdgeAdjacency {\n if (edge.kind === 'self') return 'adjacent';\n\n const fromPos = position.get(edge.from);\n const toPos = position.get(edge.to);\n if (fromPos === undefined || toPos === undefined) return 'adjacent';\n\n if (edge.kind === 'forward') {\n if (toPos >= fromPos) return 'adjacent';\n return fromPos === toPos + 1 ? 'adjacent' : 'node-skipping-forward';\n }\n\n if (toPos <= fromPos) return 'adjacent';\n return toPos === fromPos + 1 ? 'adjacent' : 'node-skipping-rollback';\n}\n\n// ---------------------------------------------------------------------------\n// Cell builders\n// ---------------------------------------------------------------------------\n\nfunction emptyCells(width: number): StructuralCell[] {\n return Array.from({ length: width }, () => ({ kind: 'empty' as const }));\n}\n\nfunction buildBranchConnectorCells(\n startLane: number,\n endLane: number,\n activeLanes: ReadonlySet<number>,\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (let lane = 0; lane < gridWidth; lane++) {\n if (activeLanes.has(lane) && (lane < startLane || lane > endLane)) {\n cells[lane] = { kind: 'vertical-pass' };\n continue;\n }\n if (lane === startLane) {\n cells[lane] = { kind: 'branch-tee' };\n } else if (lane === endLane) {\n cells[lane] = { kind: 'branch-corner' };\n } else if (lane > startLane && lane < endLane) {\n cells[lane] = { kind: 'branch-tee' };\n }\n }\n return cells;\n}\n\nfunction buildMergeConnectorCells(\n startLane: number,\n endLane: number,\n activeLanes: ReadonlySet<number>,\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (let lane = 0; lane < gridWidth; lane++) {\n if (activeLanes.has(lane) && (lane < startLane || lane > endLane)) {\n cells[lane] = { kind: 'vertical-pass' };\n continue;\n }\n if (lane === startLane) {\n cells[lane] = { kind: 'merge-tee' };\n } else if (lane === endLane) {\n cells[lane] = { kind: 'merge-corner' };\n } else if (lane > startLane && lane < endLane) {\n cells[lane] = activeLanes.has(lane) ? { kind: 'merge-tee' } : { kind: 'horizontal-pass' };\n }\n }\n return cells;\n}\n\nfunction buildNodeCells(\n contractHash: string,\n nodeColumn: number,\n activeLanes: readonly number[],\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (const lane of activeLanes) {\n if (lane !== nodeColumn && lane < gridWidth) {\n cells[lane] = { kind: 'vertical-pass' };\n }\n }\n if (nodeColumn < gridWidth) {\n cells[nodeColumn] = { kind: 'node', contractHash };\n }\n return cells;\n}\n\nfunction buildEdgeCells(\n edge: ClassifiedEdge,\n laneIndex: number,\n passThroughLanes: readonly number[],\n adjacency: EdgeAdjacency,\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (const lane of passThroughLanes) {\n if (lane < gridWidth) cells[lane] = { kind: 'vertical-pass' };\n }\n if (laneIndex < gridWidth) {\n cells[laneIndex] = {\n kind: 'edge-lane',\n migrationHash: edge.migrationHash,\n edgeKind: edge.kind,\n ownsLabel: true,\n adjacency,\n };\n }\n return cells;\n}\n\n// ---------------------------------------------------------------------------\n// Vertical ordering: tips-first DFS post-order over forward edges\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the vertical node order for a component: tips at the top (index 0),\n * roots at the bottom. This is a DFS post-order over forward edges starting\n * from forward roots, visiting children in their input (insertion) order. A\n * node is emitted only after all of its forward children, so convergence nodes\n * sit below every branch that feeds them and the longest contiguous chain reads\n * top-to-bottom without braiding.\n */\nfunction computeVerticalOrder(\n componentNodes: readonly string[],\n forwardChildren: ReadonlyMap<string, readonly ClassifiedEdge[]>,\n forwardInDegree: ReadonlyMap<string, number>,\n): string[] {\n const WHITE = 0;\n const GRAY = 1;\n const BLACK = 2;\n const color = new Map<string, number>();\n for (const node of componentNodes) color.set(node, WHITE);\n\n const sortRoots = (roots: readonly string[]): string[] =>\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 let roots = sortRoots(componentNodes.filter((n) => (forwardInDegree.get(n) ?? 0) === 0));\n if (roots.length === 0) roots = sortRoots(componentNodes);\n\n const result: string[] = [];\n\n interface Frame {\n node: string;\n children: readonly ClassifiedEdge[];\n index: number;\n }\n\n function runDfs(root: string): void {\n if (color.get(root) !== WHITE) return;\n const stack: Frame[] = [{ node: root, children: forwardChildren.get(root) ?? [], index: 0 }];\n color.set(root, GRAY);\n\n while (stack.length > 0) {\n const frame = stack[stack.length - 1];\n if (frame === undefined) break;\n if (frame.index >= frame.children.length) {\n color.set(frame.node, BLACK);\n result.push(frame.node);\n stack.pop();\n continue;\n }\n const child = frame.children[frame.index];\n frame.index += 1;\n if (child === undefined) continue;\n if (color.get(child.to) === WHITE) {\n color.set(child.to, GRAY);\n stack.push({ node: child.to, children: forwardChildren.get(child.to) ?? [], index: 0 });\n }\n }\n }\n\n for (const root of roots) runDfs(root);\n // Nodes unreachable via forward edges (e.g. rollback-only sources) follow in\n // component order.\n for (const node of componentNodes) {\n if (color.get(node) === WHITE) runDfs(node);\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Routed back-arcs for node-skipping rollbacks\n// ---------------------------------------------------------------------------\n\ninterface SkipRollbackRoute {\n readonly edge: ClassifiedEdge;\n readonly backLane: number;\n}\n\nfunction rollbackSpan(\n edge: ClassifiedEdge,\n position: ReadonlyMap<string, number>,\n): { readonly top: number; readonly bottom: number } {\n const top = position.get(edge.from) ?? 0;\n const bottom = position.get(edge.to) ?? top;\n return { top, bottom };\n}\n\nfunction spansOverlap(\n a: { readonly top: number; readonly bottom: number },\n b: { readonly top: number; readonly bottom: number },\n): boolean {\n return a.top <= b.bottom && b.top <= a.bottom;\n}\n\nfunction forwardMaxLane(\n rows: readonly MigrationGraphGridRow[],\n skipMigrationHashes: ReadonlySet<string>,\n): number {\n let max = 0;\n for (const row of rows) {\n if (\n row.kind === 'edge' &&\n row.edge !== undefined &&\n skipMigrationHashes.has(row.edge.migrationHash)\n ) {\n continue;\n }\n max = Math.max(max, row.laneIndex ?? 0);\n for (const lane of row.passThroughLanes ?? []) {\n max = Math.max(max, lane);\n }\n if (row.startLane !== undefined) {\n max = Math.max(max, row.startLane, row.endLane ?? row.startLane);\n }\n }\n return max;\n}\n\nfunction allocateSkipRollbackBackLanes(\n skipRollbacks: readonly ClassifiedEdge[],\n position: ReadonlyMap<string, number>,\n forwardMax: number,\n): Map<string, number> {\n const sorted = [...skipRollbacks].sort((a, b) => {\n const aTop = position.get(a.from) ?? 0;\n const bTop = position.get(b.from) ?? 0;\n if (aTop !== bTop) return aTop - bTop;\n return b.dirName.localeCompare(a.dirName);\n });\n\n const occupied: { readonly top: number; readonly bottom: number; readonly lane: number }[] = [];\n const lanes = new Map<string, number>();\n let nextLane = forwardMax + 1;\n\n for (const edge of sorted) {\n const span = rollbackSpan(edge, position);\n let lane = nextLane;\n while (occupied.some((entry) => entry.lane === lane && spansOverlap(entry, span))) {\n lane += 1;\n }\n occupied.push({ ...span, lane });\n lanes.set(edge.migrationHash, lane);\n nextLane = Math.max(nextLane, lane + 1);\n }\n\n return lanes;\n}\n\nfunction findNodeRowIndex(rows: readonly MigrationGraphGridRow[], contractHash: string): number {\n return rows.findIndex((row) => row.kind === 'node' && row.contractHash === contractHash);\n}\n\nfunction findEdgeRowIndex(rows: readonly MigrationGraphGridRow[], migrationHash: string): number {\n return rows.findIndex((row) => row.kind === 'edge' && row.edge?.migrationHash === migrationHash);\n}\n\n// A grid row with a mutable `cells` array. The routing pass clones the\n// immutable rows into this shape so it can paint arc cells in place without\n// stripping `readonly` with a cast.\ntype MutableGridRow = Omit<MigrationGraphGridRow, 'cells'> & { cells: StructuralCell[] };\n\nfunction ensureCellWidth(cells: StructuralCell[], width: number): void {\n while (cells.length < width) {\n cells.push({ kind: 'empty' });\n }\n}\n\nfunction cloneRow(row: MigrationGraphGridRow): MutableGridRow {\n return { ...row, cells: [...row.cells] };\n}\n\nfunction routeCrossesRow(\n route: SkipRollbackRoute,\n rowIndex: number,\n rows: readonly MigrationGraphGridRow[],\n): boolean {\n const sourceRow = findNodeRowIndex(rows, route.edge.from);\n const targetRow = findNodeRowIndex(rows, route.edge.to);\n if (sourceRow < 0 || targetRow < 0) return false;\n return rowIndex > sourceRow && rowIndex <= targetRow;\n}\n\nfunction applySkipRollbackRouting(\n rows: readonly MigrationGraphGridRow[],\n skipRollbacks: readonly ClassifiedEdge[],\n position: ReadonlyMap<string, number>,\n nodeColumn: ReadonlyMap<string, number>,\n edgeColumn: Map<string, number>,\n): MigrationGraphGridRow[] {\n if (skipRollbacks.length === 0) return [...rows];\n\n const skipHashes = new Set(skipRollbacks.map((edge) => edge.migrationHash));\n const forwardMax = forwardMaxLane(rows, skipHashes);\n const backLaneByHash = allocateSkipRollbackBackLanes(skipRollbacks, position, forwardMax);\n const routes: SkipRollbackRoute[] = skipRollbacks.map((edge) => ({\n edge,\n backLane: backLaneByHash.get(edge.migrationHash) ?? forwardMax + 1,\n }));\n\n const result = rows.map(cloneRow);\n\n for (const route of routes) {\n const { edge, backLane } = route;\n const nodeCol = nodeColumn.get(edge.from) ?? 0;\n const targetCol = nodeColumn.get(edge.to) ?? 0;\n const sourceRowIndex = findNodeRowIndex(result, edge.from);\n const targetRowIndex = findNodeRowIndex(result, edge.to);\n const edgeRowIndex = findEdgeRowIndex(result, edge.migrationHash);\n if (sourceRowIndex < 0 || targetRowIndex < 0 || edgeRowIndex < 0) continue;\n\n edgeColumn.set(edge.migrationHash, backLane);\n\n // Back-lanes of arcs that tee off this same source node. They share the\n // node's tee row, so each inner lane reads as a `┬` junction and only the\n // outermost gets the closing `╮`.\n const coSourcedLanes = routes\n .filter((other) => other.edge.from === edge.from)\n .map((other) => other.backLane);\n const maxCoSourcedLane = Math.max(...coSourcedLanes);\n\n const sourceRow = result[sourceRowIndex];\n if (sourceRow !== undefined) {\n const cells = sourceRow.cells;\n ensureCellWidth(cells, backLane + 1);\n const contractHash = sourceRow.contractHash ?? EMPTY_CONTRACT_HASH;\n cells[nodeCol] = { kind: 'node', contractHash, arcTee: true };\n for (let lane = nodeCol + 1; lane < backLane; lane += 1) {\n if (coSourcedLanes.includes(lane)) {\n cells[lane] = { kind: 'arc-branch-tee' };\n continue;\n }\n const existing = cells[lane];\n const occupied =\n existing !== undefined &&\n existing.kind !== 'empty' &&\n existing.kind !== 'horizontal-pass' &&\n existing.kind !== 'arc-land-bridge';\n const crossed =\n occupied ||\n routes.some(\n (other) =>\n other.edge.migrationHash !== edge.migrationHash &&\n other.backLane === lane &&\n routeCrossesRow(other, sourceRowIndex, result),\n );\n cells[lane] = crossed ? { kind: 'arc-crossing' } : { kind: 'horizontal-pass' };\n }\n cells[backLane] =\n backLane < maxCoSourcedLane ? { kind: 'arc-branch-tee' } : { kind: 'arc-branch-corner' };\n }\n\n const edgeRow = result[edgeRowIndex];\n if (edgeRow !== undefined) {\n // Mutate in place rather than rebuild from empty: a co-sourced arc's body\n // lane may already cross this row, and rebuilding would clobber it.\n const cells = edgeRow.cells;\n ensureCellWidth(cells, backLane + 1);\n cells[nodeCol] = { kind: 'vertical-pass' };\n cells[backLane] = {\n kind: 'edge-lane',\n migrationHash: edge.migrationHash,\n edgeKind: edge.kind,\n ownsLabel: true,\n adjacency: 'node-skipping-rollback',\n };\n result[edgeRowIndex] = { ...edgeRow, laneIndex: backLane, passThroughLanes: [nodeCol] };\n }\n\n // Fill the arc body vertically from just below the source tee down to the\n // row above the landing, skipping the rollback's own labelled edge row.\n // Starting below the source (rather than below the edge row) keeps a\n // co-sourced arc's lane connected across an earlier co-sourced edge row.\n for (let index = sourceRowIndex + 1; index < targetRowIndex; index += 1) {\n if (index === edgeRowIndex) continue;\n const row = result[index];\n if (row === undefined) continue;\n const cells = row.cells;\n ensureCellWidth(cells, backLane + 1);\n const existing = cells[backLane];\n if (\n existing?.kind !== 'arc-land-corner' &&\n existing?.kind !== 'arc-land-bridge' &&\n existing?.kind !== 'arc-branch-corner' &&\n existing?.kind !== 'arc-branch-tee' &&\n existing?.kind !== 'arc-crossing'\n ) {\n cells[backLane] = { kind: 'vertical-pass' };\n }\n }\n\n const targetRow = result[targetRowIndex];\n if (targetRow !== undefined) {\n const cells = targetRow.cells;\n ensureCellWidth(cells, backLane + 1);\n const contractHash = targetRow.contractHash ?? EMPTY_CONTRACT_HASH;\n cells[targetCol] = { kind: 'node', contractHash, arcLand: true };\n for (let lane = targetCol + 1; lane < backLane; lane += 1) {\n // A bridged lane that carries another arc OR a forward vertical still\n // active at this row must cross over it (`┼`) rather than overwrite it\n // with a bare bridge (`──`).\n const existing = cells[lane];\n const occupied =\n existing !== undefined &&\n existing.kind !== 'empty' &&\n existing.kind !== 'horizontal-pass' &&\n existing.kind !== 'arc-land-bridge';\n const crossed =\n occupied ||\n routes.some(\n (other) =>\n other.edge.migrationHash !== edge.migrationHash &&\n other.backLane === lane &&\n routeCrossesRow(other, targetRowIndex, result),\n );\n cells[lane] = crossed ? { kind: 'arc-crossing' } : { kind: 'arc-land-bridge' };\n }\n cells[backLane] = { kind: 'arc-land-corner' };\n for (const other of routes) {\n if (other.backLane <= backLane) continue;\n if (!routeCrossesRow(other, targetRowIndex, result)) continue;\n ensureCellWidth(cells, other.backLane + 1);\n const existing = cells[other.backLane];\n if (\n existing?.kind !== 'arc-land-corner' &&\n existing?.kind !== 'arc-land-bridge' &&\n existing?.kind !== 'node'\n ) {\n cells[other.backLane] = { kind: 'vertical-pass' };\n }\n }\n }\n }\n\n return result;\n}\n\nfunction collectNodeSkippingRollbacks(\n edges: readonly ClassifiedEdge[],\n position: ReadonlyMap<string, number>,\n): ClassifiedEdge[] {\n return edges.filter(\n (edge) =>\n edge.kind === 'rollback' &&\n classifyEdgeAdjacency(edge, position) === 'node-skipping-rollback',\n );\n}\n\n// ---------------------------------------------------------------------------\n// Lane allocation: one rule for all topologies\n// ---------------------------------------------------------------------------\n\ninterface DownwardGroup {\n readonly target: string;\n readonly edges: ClassifiedEdge[];\n}\n\nfunction layoutComponent(\n componentNodes: readonly string[],\n allEdges: readonly ClassifiedEdge[],\n): {\n rows: MigrationGraphGridRow[];\n nodeColumn: Map<string, number>;\n edgeColumn: Map<string, number>;\n} {\n const componentSet = new Set(componentNodes);\n const edges = allEdges.filter((e) => componentSet.has(e.from) && componentSet.has(e.to));\n\n const forwardChildren = new Map<string, ClassifiedEdge[]>();\n const producersByTo = new Map<string, ClassifiedEdge[]>();\n const rollbacksByFrom = new Map<string, ClassifiedEdge[]>();\n const selfByFrom = new Map<string, ClassifiedEdge[]>();\n for (const edge of edges) {\n if (edge.kind === 'self' || edge.from === edge.to) {\n const bucket = selfByFrom.get(edge.from);\n if (bucket) bucket.push(edge);\n else selfByFrom.set(edge.from, [edge]);\n continue;\n }\n if (edge.kind === 'forward') {\n const children = forwardChildren.get(edge.from);\n if (children) children.push(edge);\n else forwardChildren.set(edge.from, [edge]);\n const producers = producersByTo.get(edge.to);\n if (producers) producers.push(edge);\n else producersByTo.set(edge.to, [edge]);\n continue;\n }\n // rollback\n const bucket = rollbacksByFrom.get(edge.from);\n if (bucket) bucket.push(edge);\n else rollbacksByFrom.set(edge.from, [edge]);\n }\n\n const forwardInDegree = buildForwardInDegree(edges);\n const forwardOutDegree = buildForwardOutDegree(edges);\n const distinctSourceCountByTo = buildDistinctSourceCountByTo(edges);\n\n const order = computeVerticalOrder(componentNodes, forwardChildren, forwardInDegree);\n const position = new Map<string, number>();\n for (let index = 0; index < order.length; index++) {\n const node = order[index];\n if (node !== undefined) position.set(node, index);\n }\n\n const lanes: (string | null)[] = [];\n const rows: MigrationGraphGridRow[] = [];\n const nodeColumn = new Map<string, number>();\n const edgeColumn = new Map<string, number>();\n const producerLaneByHash = new Map<string, number>();\n let gridWidth = 1;\n\n function ensureGridWidth(minWidth: number): void {\n if (minWidth > gridWidth) gridWidth = minWidth;\n }\n\n function setLane(index: number, want: string | null): void {\n while (lanes.length <= index) lanes.push(null);\n lanes[index] = want;\n if (want !== null) ensureGridWidth(index + 1);\n }\n\n function activeLaneIndices(): number[] {\n const indices: number[] = [];\n for (let index = 0; index < lanes.length; index++) {\n if (lanes[index] !== null) indices.push(index);\n }\n return indices;\n }\n\n function passThroughExcept(lane: number): number[] {\n return activeLaneIndices().filter((index) => index !== lane);\n }\n\n function leftmostFreeLane(): number {\n for (let index = 0; index < lanes.length; index++) {\n if (lanes[index] === null) return index;\n }\n return lanes.length;\n }\n\n function lanesWanting(contract: string): number[] {\n const indices: number[] = [];\n for (let index = 0; index < lanes.length; index++) {\n if (lanes[index] === contract) indices.push(index);\n }\n return indices;\n }\n\n function emitMergeConnector(contractHash: string, laneIndices: readonly number[]): number {\n const startLane = Math.min(...laneIndices);\n const endLane = Math.max(...laneIndices);\n ensureGridWidth(endLane + 1);\n const activeLanes = new Set(activeLaneIndices());\n rows.push({\n kind: 'merge-connector',\n contractHash,\n startLane,\n endLane,\n branchCount: laneIndices.length,\n cells: buildMergeConnectorCells(startLane, endLane, activeLanes, gridWidth),\n });\n for (const index of laneIndices) {\n if (index !== startLane) setLane(index, null);\n }\n return startLane;\n }\n\n function emitBranchConnector(\n contractHash: string,\n startLane: number,\n endLane: number,\n branchCount: number,\n ): void {\n ensureGridWidth(endLane + 1);\n const activeLanes = new Set(activeLaneIndices());\n rows.push({\n kind: 'branch-connector',\n contractHash,\n startLane,\n endLane,\n branchCount,\n cells: buildBranchConnectorCells(startLane, endLane, activeLanes, gridWidth),\n });\n }\n\n function emitEdgeRow(edge: ClassifiedEdge, lane: number, convergenceProducer: boolean): void {\n const passThrough = passThroughExcept(lane);\n const adjacency = classifyEdgeAdjacency(edge, position);\n ensureGridWidth(Math.max(lane, ...passThrough, 0) + 1);\n const row: MigrationGraphGridRow = {\n kind: 'edge',\n edge,\n laneIndex: lane,\n passThroughLanes: passThrough,\n cells: buildEdgeCells(edge, lane, passThrough, adjacency, gridWidth),\n };\n rows.push(convergenceProducer ? { ...row, convergenceProducer: true } : row);\n edgeColumn.set(edge.migrationHash, lane);\n if (convergenceProducer) producerLaneByHash.set(edge.migrationHash, lane);\n }\n\n function emitNodeRow(contractHash: string, column: number): void {\n ensureGridWidth(column + 1);\n const passThrough = activeLaneIndices().filter((index) => index !== column);\n rows.push({\n kind: 'node',\n contractHash,\n cells: buildNodeCells(contractHash, column, passThrough, gridWidth),\n });\n nodeColumn.set(contractHash, column);\n }\n\n function producerGroups(node: string): DownwardGroup[] {\n const byTarget = new Map<string, DownwardGroup>();\n for (const producer of producersByTo.get(node) ?? []) {\n const group = byTarget.get(producer.from);\n if (group) group.edges.push(producer);\n else byTarget.set(producer.from, { target: producer.from, edges: [producer] });\n }\n const groups = [...byTarget.values()];\n // Lanes are ordered by where their target node lands vertically (soonest →\n // leftmost), which keeps lanes from crossing.\n groups.sort((a, b) => (position.get(a.target) ?? 0) - (position.get(b.target) ?? 0));\n for (const group of groups) {\n group.edges.sort((a, b) => b.dirName.localeCompare(a.dirName));\n }\n return groups;\n }\n\n function processNode(node: string): void {\n const wanting = lanesWanting(node);\n let column: number;\n if (wanting.length >= 2) {\n column = emitMergeConnector(node, wanting);\n } else if (wanting.length === 1) {\n column = wanting[0] ?? 0;\n } else {\n column = leftmostFreeLane();\n }\n\n // Self-edges sit immediately above their node, in its column.\n const selfEdges = [...(selfByFrom.get(node) ?? [])].sort((a, b) =>\n b.dirName.localeCompare(a.dirName),\n );\n for (const selfEdge of selfEdges) emitEdgeRow(selfEdge, column, false);\n\n emitNodeRow(node, column);\n\n const rollbacks = [...(rollbacksByFrom.get(node) ?? [])].sort((a, b) =>\n b.dirName.localeCompare(a.dirName),\n );\n const skipRollbacks: ClassifiedEdge[] = [];\n const adjacentRollbacks: ClassifiedEdge[] = [];\n for (const rollback of rollbacks) {\n if (classifyEdgeAdjacency(rollback, position) === 'node-skipping-rollback') {\n skipRollbacks.push(rollback);\n } else {\n adjacentRollbacks.push(rollback);\n }\n }\n for (const rollback of skipRollbacks) {\n emitEdgeRow(rollback, column, false);\n }\n\n const groups = producerGroups(node);\n const isConvergence = (distinctSourceCountByTo.get(node) ?? 0) >= 2;\n const laneForGroup: number[] = [];\n for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {\n const group = groups[groupIndex];\n if (group === undefined) continue;\n const lane = groupIndex === 0 ? column : leftmostFreeLane();\n laneForGroup[groupIndex] = lane;\n setLane(lane, group.target);\n }\n\n if (groups.length >= 2) {\n const endLane = Math.max(...laneForGroup);\n emitBranchConnector(node, column, endLane, groups.length);\n }\n\n for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {\n const group = groups[groupIndex];\n const lane = laneForGroup[groupIndex];\n if (group === undefined || lane === undefined) continue;\n for (const edge of group.edges) {\n emitEdgeRow(edge, lane, isConvergence);\n }\n }\n\n for (const rollback of adjacentRollbacks) {\n emitEdgeRow(rollback, column, false);\n }\n\n if (groups.length === 0) {\n // A root / leaf: its column lane terminates here.\n setLane(column, null);\n }\n }\n\n for (const node of order) processNode(node);\n\n const refined = refineAdjacency(\n rows,\n nodeColumn,\n position,\n forwardInDegree,\n forwardOutDegree,\n edges,\n producerLaneByHash,\n );\n const skipRollbacks = collectNodeSkippingRollbacks(edges, position);\n const routed = applySkipRollbackRouting(refined, skipRollbacks, position, nodeColumn, edgeColumn);\n\n return {\n rows: routed,\n nodeColumn,\n edgeColumn,\n };\n}\n\nexport function buildMigrationGraphLayout(\n rowModel: MigrationGraphRowModel,\n): MigrationGraphGridModel {\n if (rowModel.nodes.length === 0) {\n return { rows: [], nodeColumn: new Map(), edgeColumn: new Map() };\n }\n\n const components = splitComponents(rowModel.nodes);\n const allRows: MigrationGraphGridRow[] = [];\n const nodeColumn = new Map<string, number>();\n const edgeColumn = new Map<string, number>();\n\n for (let componentIndex = 0; componentIndex < components.length; componentIndex++) {\n if (componentIndex > 0) {\n allRows.push({ kind: 'component-separator', cells: [] });\n }\n\n const component = components[componentIndex];\n if (component === undefined || component.length === 0) continue;\n\n const result = layoutComponent(component, rowModel.edges);\n allRows.push(...result.rows);\n for (const [hash, column] of result.nodeColumn) nodeColumn.set(hash, column);\n for (const [hash, column] of result.edgeColumn) edgeColumn.set(hash, column);\n }\n\n return { rows: allRows, nodeColumn, edgeColumn };\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 layerNodesByLongestForwardPath(\n componentNodes: ReadonlySet<string>,\n topology: MigrationListGraphTopology,\n graph: MigrationGraph,\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 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\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 const edgesByFrom = new Map<string, ClassifiedEdge[]>();\n const edgesByTo = new Map<string, 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 const classified: ClassifiedEdge = {\n migrationHash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n dirName: edge.dirName,\n kind,\n };\n edges.push(classified);\n\n const fromBucket = edgesByFrom.get(edge.from);\n if (fromBucket) fromBucket.push(classified);\n else edgesByFrom.set(edge.from, [classified]);\n\n const toBucket = edgesByTo.get(edge.to);\n if (toBucket) toBucket.push(classified);\n else edgesByTo.set(edge.to, [classified]);\n }\n }\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(component, topology, graph);\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 { nodes, edges, edgesByFrom, edgesByTo };\n}\n","import { createColors } from 'colorette';\n\nexport type LaneColorizer = (text: string) => string;\n\nconst { magenta, cyan, green, yellow, blueBright, red } = createColors({ useColor: true });\n\nexport const LANE_COLOR_CYCLE: readonly LaneColorizer[] = [\n magenta,\n cyan,\n green,\n yellow,\n blueBright,\n red,\n];\n\n/**\n * The hue for a gutter column. The leftmost lane (column 0) is **neutral** — it\n * has nothing to be told apart from in the common single-lane linear case, so\n * the renderer dims it rather than tinting it; the rotating palette is reserved\n * for columns ≥ 1 (where a second lane exists to distinguish). Callers must dim\n * column 0 themselves; this returns identity for it as a guard. A lane freed and\n * reused by a later branch keeps its column's hue — coloring is by position, not\n * branch identity, exactly like `git log --graph`.\n */\nexport function laneColorForColumn(column: number): LaneColorizer {\n if (column <= 0) {\n return (text) => text;\n }\n const colorizer = LANE_COLOR_CYCLE[(column - 1) % LANE_COLOR_CYCLE.length];\n return colorizer ?? ((text) => text);\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { bold, createColors } from 'colorette';\nimport stringWidth from 'string-width';\nimport type { GlyphMode } from '../glyph-mode';\nimport { laneColorForColumn } from './migration-graph-lane-colors';\nimport type {\n MigrationGraphGridModel,\n MigrationGraphGridRow,\n StructuralCell,\n} from './migration-graph-layout';\nimport type { ClassifiedEdge } from './migration-graph-rows';\nimport {\n MIGRATION_LIST_HASH_WIDTH,\n migrationListEmptySource,\n migrationListForwardArrow,\n} from './migration-list-data-column';\nimport type { MigrationEdgeKind } from './migration-list-graph-topology';\nimport type { MigrationListStyler } from './migration-list-render';\nimport { CONTRACT_MARKER_NAME, createAnsiMigrationListStyler } from './migration-list-styler';\n\nconst LABEL_GAP = 2;\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 RenderMigrationGraphTreeOptions {\n readonly refsByHash?: ReadonlyMap<string, readonly string[]>;\n readonly dbHash?: string;\n readonly contractHash?: string;\n readonly activeRefName?: string;\n readonly hashLength?: number;\n readonly colorize: boolean;\n readonly glyphMode?: GlyphMode;\n}\n\ninterface MigrationGraphTreeGlyphPalette {\n readonly node: string;\n readonly arcLand: string;\n readonly arcTee: string;\n readonly verticalPass: string;\n readonly branchTee: string;\n readonly mergeTee: string;\n readonly branchCorner: string;\n readonly mergeCorner: string;\n readonly arcBranchCorner: string;\n readonly arcBranchTee: string;\n readonly arcLandCorner: string;\n readonly arcCrossing: string;\n readonly arcLandBridge: string;\n readonly horizontalPass: string;\n readonly connectorBranchTee: string;\n readonly connectorBranchTeeCo: string;\n readonly connectorMergeTeeCo: string;\n readonly edgeArrow: Readonly<Record<MigrationEdgeKind, string>>;\n readonly forwardArrow: string;\n readonly emptySource: string;\n}\n\nconst UNICODE_PALETTE: MigrationGraphTreeGlyphPalette = {\n node: '○ ',\n arcLand: '○◂',\n arcTee: '○─',\n verticalPass: '│ ',\n branchTee: '├─',\n mergeTee: '├─',\n branchCorner: '╮ ',\n mergeCorner: '╯ ',\n arcBranchCorner: '╮ ',\n arcBranchTee: '┬─',\n arcLandCorner: '╯ ',\n arcCrossing: '┼─',\n arcLandBridge: '──',\n horizontalPass: '──',\n connectorBranchTee: '├─',\n connectorBranchTeeCo: '┬─',\n connectorMergeTeeCo: '┴─',\n edgeArrow: { forward: '↑', rollback: '↓', self: '⟲' },\n forwardArrow: migrationListForwardArrow('unicode'),\n emptySource: migrationListEmptySource('unicode'),\n};\n\nconst ASCII_PALETTE: MigrationGraphTreeGlyphPalette = {\n node: '* ',\n arcLand: '*<',\n arcTee: '*-',\n verticalPass: '| ',\n branchTee: '+-',\n mergeTee: '+-',\n branchCorner: '\\\\ ',\n mergeCorner: '/ ',\n arcBranchCorner: '\\\\ ',\n arcBranchTee: '+-',\n arcLandCorner: '/ ',\n arcCrossing: '+-',\n arcLandBridge: '--',\n horizontalPass: '--',\n connectorBranchTee: '+-',\n connectorBranchTeeCo: '+-',\n connectorMergeTeeCo: '+-',\n edgeArrow: { forward: '^', rollback: 'v', self: '@' },\n forwardArrow: migrationListForwardArrow('ascii'),\n emptySource: migrationListEmptySource('ascii'),\n};\n\nfunction paletteFor(mode: GlyphMode): MigrationGraphTreeGlyphPalette {\n return mode === 'ascii' ? ASCII_PALETTE : UNICODE_PALETTE;\n}\n\nfunction arrowForEdgeKind(\n kind: MigrationEdgeKind,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n return palette.edgeArrow[kind];\n}\n\n/**\n * The leftmost lane (column 0) renders with the neutral dim lane style rather\n * than a palette hue — in the common single-lane case it has nothing to be told\n * apart from. Used as the \"no owning arc\" sentinel during colour resolution.\n */\nconst NEUTRAL_LANE = 0;\n\n/**\n * Forced bold for branch-coloured names. A branched name pairs its lane hue\n * (also forced, via {@link laneColorForColumn}) with bold; both must emit even\n * when colorette's ambient TTY detection is off, so the colorized branch name\n * is deterministically bold + hue rather than hue-only.\n */\nconst { bold: forcedBold } = createColors({ useColor: true });\n\n/**\n * The colour-source column for each cell of a row, resolved together because a\n * routed back-arc spans columns and must read as **one hue** rather than a\n * per-column \"rainbow\". An arc's horizontal bridges, corners, and node-pair\n * connector all take the arc's owning back-lane column (the corner that closes\n * the arc), not the column they pass through.\n */\ninterface RowLaneColors {\n /** Colour column for a cell's structural glyph (lane / spine / arc body). */\n readonly lane: readonly number[];\n /** Colour column for a node arc-pair's connector half (`◂` / `─`). */\n readonly connector: readonly number[];\n}\n\n/**\n * Resolve per-cell colour columns for a row. Scanning right-to-left lets each\n * arc bridge inherit the corner column that closes it (the arc's back-lane), so\n * the whole arc — vertical run (already its own column), horizontal bridges,\n * corners, crossings, and the `◂`/`─` connector — reads as a single continuous\n * hue. A crossing can only be one colour, so rather than leave it dim (wrong for\n * both crossing lines) it takes the arc owning the horizontal run at this row\n * (the nearest corner to its right); the crossed vertical lane is simply\n * occluded at that one cell and reappears on the next row.\n */\nfunction resolveRowLaneColors(cells: readonly StructuralCell[]): RowLaneColors {\n const lane = new Array<number>(cells.length);\n const connector = new Array<number>(cells.length);\n let arcCorner = NEUTRAL_LANE;\n for (let column = cells.length - 1; column >= 0; column--) {\n const cell = cells[column];\n connector[column] = arcCorner;\n switch (cell?.kind) {\n case 'arc-branch-corner':\n case 'arc-land-corner':\n arcCorner = column;\n lane[column] = column;\n break;\n case 'arc-branch-tee':\n // An inner co-sourced arc's own back-lane junction: its vertical run\n // continues below in this column, so it keeps its own column hue.\n lane[column] = column;\n break;\n case 'arc-crossing':\n case 'arc-land-bridge':\n lane[column] = arcCorner;\n break;\n case 'horizontal-pass':\n lane[column] = arcCorner === NEUTRAL_LANE ? column : arcCorner;\n break;\n case 'node':\n lane[column] = column;\n arcCorner = NEUTRAL_LANE;\n break;\n default:\n lane[column] = column;\n arcCorner = NEUTRAL_LANE;\n }\n }\n return { lane, connector };\n}\n\n/**\n * Per-cell colour for a forward branch/merge connector row, split into the\n * cell's junction `glyph` and its trailing `dash`. A connector's horizontal run\n * is one logical line (a fork into new lanes, or a merge into a surviving lane)\n * and reads best as the colour of the lane each segment serves — not dim-gray\n * or a per-pass-through-column \"rainbow\".\n */\ninterface ConnectorLaneColors {\n /** Colour column for a cell's junction glyph (`├` / `┬` / `┴` / `╮` / `╯`). */\n readonly glyph: readonly number[];\n /** Colour column for a tee's trailing `─` — the branch it leads into. */\n readonly dash: readonly number[];\n}\n\n/**\n * Resolve per-cell connector colours. Scanning right-to-left, a corner or an\n * intermediate tee anchors its own lane (its junction glyph takes that column),\n * but a tee's **trailing dash leads into the branch on its right** (the next\n * branch point), so `┬─` reads as \"this lane, then on toward the next\" rather\n * than tinting the dash with the left lane. The leading tee at `startLane` (the\n * fork/merge origin) and pure horizontal segments inherit the nearest branch\n * point to their right whole-cell, so the run into a branch — or collapsing\n * into a merge corner — stays continuous. Pass-through verticals outside the\n * run keep their own column (column 0 stays neutral).\n */\nfunction resolveConnectorLaneColors(\n cells: readonly StructuralCell[],\n startLane: number,\n): ConnectorLaneColors {\n const glyph = new Array<number>(cells.length);\n const dash = new Array<number>(cells.length);\n let owner = NEUTRAL_LANE;\n for (let column = cells.length - 1; column >= 0; column--) {\n const cell = cells[column];\n switch (cell?.kind) {\n case 'branch-corner':\n case 'merge-corner':\n owner = column;\n glyph[column] = column;\n dash[column] = column;\n break;\n case 'branch-tee':\n case 'merge-tee':\n if (column === startLane) {\n const served = owner === NEUTRAL_LANE ? column : owner;\n glyph[column] = served;\n dash[column] = served;\n } else {\n dash[column] = owner === NEUTRAL_LANE ? column : owner;\n glyph[column] = column;\n owner = column;\n }\n break;\n case 'horizontal-pass': {\n const served = owner === NEUTRAL_LANE ? column : owner;\n glyph[column] = served;\n dash[column] = served;\n break;\n }\n default:\n glyph[column] = column;\n dash[column] = column;\n }\n }\n return { glyph, dash };\n}\n\n/**\n * Style a structural glyph by its resolved colour column. Column 0 and the\n * neutral sentinel render dim (`style.lane`); columns ≥ 1 take a palette hue.\n */\nfunction laneStylerForColumn(\n colorColumn: number,\n colorize: boolean,\n style: MigrationListStyler,\n): (text: string) => string {\n if (!colorize || colorColumn <= NEUTRAL_LANE) {\n return (text) => style.lane(text);\n }\n return laneColorForColumn(colorColumn);\n}\n\n/**\n * Tint a branch-owned token (direction arrow, migration name) by its edge's\n * lane so the whole branch row reads in one colour. Column 0 has nothing to be\n * told apart from in the common linear chain, so it keeps the token's existing\n * default styling (`fallback`) rather than a palette hue; only lanes ≥ 1 take a\n * colour. With colour off, the fallback (also colourless) is used unchanged.\n */\nfunction branchStylerOrDefault(\n column: number,\n colorize: boolean,\n fallback: (text: string) => string,\n): (text: string) => string {\n if (!colorize || column <= NEUTRAL_LANE) {\n return fallback;\n }\n return laneColorForColumn(column);\n}\n\n/**\n * Render a connector tee (`├─` / `┬─` / `┴─`) with its junction glyph and its\n * trailing dash coloured independently: the junction anchors its own lane while\n * the dash leads into the branch on its right.\n */\nfunction renderConnectorTee(\n pair: string,\n glyphColumn: number,\n dashColumn: number,\n colorize: boolean,\n style: MigrationListStyler,\n): string {\n const glyph = laneStylerForColumn(glyphColumn, colorize, style);\n if (glyphColumn === dashColumn) {\n return glyph(pair);\n }\n return glyph(pair.slice(0, 1)) + laneStylerForColumn(dashColumn, colorize, style)(pair.slice(1));\n}\n\n/**\n * A node-marker glyph pair (`○◂`, `○─`, `*<`, `*-`) is the contract node\n * marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`). The\n * marker takes its own lane's hue (so each node visibly belongs to its branch);\n * the connector follows the arc it belongs to (its owning back-lane hue).\n * Direction arrows are handled elsewhere — they take their edge's lane hue too.\n */\nfunction renderNodeMarkerPair(\n pair: string,\n nodeColumn: number,\n arcColumn: number,\n colorize: boolean,\n style: MigrationListStyler,\n): string {\n const marker = laneStylerForColumn(nodeColumn, colorize, style);\n const connector = laneStylerForColumn(arcColumn, colorize, style);\n return marker(pair.slice(0, 1)) + connector(pair.slice(1));\n}\n\nfunction renderCellPair(\n cell: StructuralCell,\n column: number,\n colors: RowLaneColors,\n colorize: boolean,\n style: MigrationListStyler,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n const laneColumn = colors.lane[column] ?? column;\n const lane = laneStylerForColumn(laneColumn, colorize, style);\n switch (cell.kind) {\n case 'node': {\n const arcColumn = colors.connector[column] ?? NEUTRAL_LANE;\n if (cell.arcLand === true) {\n return renderNodeMarkerPair(palette.arcLand, column, arcColumn, colorize, style);\n }\n if (cell.arcTee === true) {\n return renderNodeMarkerPair(palette.arcTee, column, arcColumn, colorize, style);\n }\n return lane(palette.node);\n }\n case 'vertical-pass':\n return lane(palette.verticalPass);\n case 'edge-lane':\n return cell.ownsLabel\n ? lane(palette.verticalPass.trimEnd()) +\n branchStylerOrDefault(\n column,\n colorize,\n style.kind,\n )(arrowForEdgeKind(cell.edgeKind, palette))\n : lane(palette.verticalPass);\n case 'branch-tee':\n return lane(palette.branchTee);\n case 'merge-tee':\n return lane(palette.mergeTee);\n case 'branch-corner':\n return lane(palette.branchCorner);\n case 'merge-corner':\n return lane(palette.mergeCorner);\n case 'arc-branch-corner':\n return lane(palette.arcBranchCorner);\n case 'arc-branch-tee':\n return lane(palette.arcBranchTee);\n case 'arc-land-corner':\n return lane(palette.arcLandCorner);\n case 'arc-crossing':\n return lane(palette.arcCrossing);\n case 'arc-land-bridge':\n return lane(palette.arcLandBridge);\n case 'horizontal-pass':\n return lane(palette.horizontalPass);\n case 'empty':\n return ' ';\n }\n}\n\nfunction renderConnectorRow(\n row: MigrationGraphGridRow,\n gridWidth: number,\n colorize: boolean,\n style: MigrationListStyler,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n const isMerge = row.kind === 'merge-connector';\n if (row.cells.length > 0) {\n const colors = resolveConnectorLaneColors(row.cells, row.startLane ?? 0);\n let seenTee = false;\n let out = '';\n for (let column = 0; column < row.cells.length; column++) {\n const cell = row.cells[column];\n if (cell === undefined) continue;\n const glyphColumn = colors.glyph[column] ?? column;\n const dashColumn = colors.dash[column] ?? glyphColumn;\n const lane = laneStylerForColumn(glyphColumn, colorize, style);\n switch (cell.kind) {\n case 'branch-tee':\n out += renderConnectorTee(\n seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee,\n glyphColumn,\n dashColumn,\n colorize,\n style,\n );\n seenTee = true;\n break;\n case 'merge-tee':\n out += renderConnectorTee(\n seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee,\n glyphColumn,\n dashColumn,\n colorize,\n style,\n );\n seenTee = true;\n break;\n case 'branch-corner':\n out += lane(palette.branchCorner);\n break;\n case 'merge-corner':\n out += lane(palette.mergeCorner);\n break;\n case 'vertical-pass':\n out += lane(palette.verticalPass);\n break;\n case 'horizontal-pass':\n out += lane(palette.horizontalPass);\n break;\n default:\n out += ' ';\n }\n }\n // The cells array is sized to the grid width at emit time; a back-arc lane\n // allocated by a later row can push the grid wider afterwards, so pad any\n // trailing columns rather than dropping the lanes that pass through here.\n for (let column = row.cells.length; column < gridWidth; column++) {\n out += ' ';\n }\n return out;\n }\n\n const start = row.startLane ?? 0;\n const end = row.endLane ?? start;\n // The whole fork/merge run reads as one line in the served lane's hue (the\n // corner it reaches); pass-through columns outside the run keep their own.\n const runLane = laneStylerForColumn(end, colorize, style);\n let out = '';\n for (let column = 0; column < gridWidth; column++) {\n if (column < start || column > end) out += ' ';\n else if (column === start) out += runLane(palette.connectorBranchTee);\n else if (column === end) out += runLane(isMerge ? palette.mergeCorner : palette.branchCorner);\n else out += runLane(isMerge ? palette.connectorMergeTeeCo : palette.connectorBranchTeeCo);\n }\n return out;\n}\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\nconst MIN_HASH_DATA_COLUMN = 25;\n\nfunction overlayNamesForContract(\n contractHash: string,\n opts: RenderMigrationGraphTreeOptions,\n): readonly string[] {\n const names: string[] = [];\n const userRefs = opts.refsByHash?.get(contractHash);\n if (userRefs) {\n names.push(...[...userRefs].sort((a, b) => a.localeCompare(b)));\n }\n if (opts.dbHash === contractHash) {\n names.push(DB_MARKER_NAME);\n }\n if (opts.contractHash === contractHash && contractHash !== EMPTY_CONTRACT_HASH) {\n names.push(CONTRACT_MARKER_NAME);\n }\n return names;\n}\n\nfunction createTreeStyler(opts: RenderMigrationGraphTreeOptions): MigrationListStyler {\n const base = 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 formatEdgeHashColumn(\n edge: ClassifiedEdge,\n style: MigrationListStyler,\n hashLength: number,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n if (edge.kind === 'self') {\n const hash = abbreviateHash(edge.from, hashLength, palette.emptySource);\n return `${style.sourceHash(hash)} ${style.glyph(palette.forwardArrow)} ${style.destHash(hash)}`;\n }\n const source =\n edge.from === EMPTY_CONTRACT_HASH\n ? style.glyph(palette.emptySource) +\n ' '.repeat(Math.max(0, hashLength - palette.emptySource.length))\n : style.sourceHash(abbreviateHash(edge.from, hashLength, palette.emptySource));\n const arrow = style.glyph(palette.forwardArrow);\n const dest = style.destHash(abbreviateHash(edge.to, hashLength, palette.emptySource));\n return `${source} ${arrow} ${dest}`;\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\nfunction gridWidthForModel(rows: readonly MigrationGraphGridRow[]): number {\n return rows.reduce(\n (max, row) =>\n row.kind === 'node' || row.kind === 'edge' ? Math.max(max, row.cells.length) : max,\n 1,\n );\n}\n\nfunction maxDirNameLength(edges: readonly ClassifiedEdge[]): number {\n if (edges.length === 0) return 0;\n return Math.max(...edges.map((edge) => edge.dirName.length));\n}\n\nfunction rowDirNameWidth(labelColumn: number, maxDirNameLen: number, dirNameGap: number): number {\n return Math.max(maxDirNameLen + dirNameGap, MIN_HASH_DATA_COLUMN - labelColumn);\n}\n\nfunction gridUsesSkipRollbackArcs(rows: readonly MigrationGraphGridRow[]): boolean {\n return rows.some((row) =>\n row.cells.some(\n (cell) => cell.kind === 'edge-lane' && cell.adjacency === 'node-skipping-rollback',\n ),\n );\n}\n\nfunction edgeLabelColumn(row: MigrationGraphGridRow, wideLabelColumn: number | undefined): number {\n if (wideLabelColumn !== undefined) {\n return wideLabelColumn;\n }\n const laneIndex = row.laneIndex ?? 0;\n if (row.edge?.from === EMPTY_CONTRACT_HASH && laneIndex === 0) {\n return (laneIndex + 1) * 2 + LABEL_GAP;\n }\n const usesFullRowGutter = row.cells.some(\n (cell, index) => index > laneIndex && cell.kind === 'vertical-pass',\n );\n return usesFullRowGutter ? row.cells.length * 2 + LABEL_GAP : (laneIndex + 1) * 2 + LABEL_GAP;\n}\n\nfunction nodeHasArcDecoration(row: MigrationGraphGridRow): boolean {\n return row.cells.some(\n (cell) => cell.kind === 'node' && (cell.arcTee === true || cell.arcLand === true),\n );\n}\n\nexport function renderMigrationGraphTree(\n model: MigrationGraphGridModel,\n opts: RenderMigrationGraphTreeOptions,\n): string {\n const glyphMode = opts.glyphMode ?? 'unicode';\n const palette = paletteFor(glyphMode);\n const style = createTreeStyler(opts);\n const hashLength = opts.hashLength ?? MIGRATION_LIST_HASH_WIDTH;\n const gridWidth = gridWidthForModel(model.rows);\n const wideLabelColumn = gridUsesSkipRollbackArcs(model.rows) ? gridWidth * 2 + 4 : undefined;\n const dirNameGap = wideLabelColumn !== undefined ? 3 : LABEL_GAP;\n const allEdges = model.rows\n .filter(\n (row): row is MigrationGraphGridRow & { edge: ClassifiedEdge } =>\n row.kind === 'edge' && row.edge !== undefined,\n )\n .map((row) => row.edge);\n const maxDirNameLen = maxDirNameLength(allEdges);\n\n const lines: string[] = [];\n\n for (let rowIndex = 0; rowIndex < model.rows.length; rowIndex++) {\n const row = model.rows[rowIndex];\n if (row === undefined) continue;\n\n if (row.kind === 'component-separator') {\n lines.push('');\n continue;\n }\n\n if (row.kind === 'branch-connector' || row.kind === 'merge-connector') {\n lines.push(\n trimTrailingWhitespace(renderConnectorRow(row, gridWidth, opts.colorize, style, palette)),\n );\n continue;\n }\n\n const cellColors = resolveRowLaneColors(row.cells);\n let gutter = row.cells\n .map((cell, column) =>\n renderCellPair(cell, column, cellColors, opts.colorize, style, palette),\n )\n .join('');\n const prevRow = model.rows[rowIndex - 1];\n let laneSpan = row.cells.length;\n if (row.kind === 'node') {\n const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;\n if (prevRow?.kind === 'merge-connector' || contractHash === EMPTY_CONTRACT_HASH) {\n laneSpan = 1;\n } else {\n laneSpan = row.cells.length;\n }\n }\n const labelColumn =\n row.kind === 'edge'\n ? edgeLabelColumn(row, wideLabelColumn)\n : wideLabelColumn !== undefined &&\n (nodeHasArcDecoration(row) || row.contractHash !== undefined)\n ? wideLabelColumn\n : laneSpan * 2 + LABEL_GAP;\n if (\n row.kind === 'edge' &&\n row.edge?.from === EMPTY_CONTRACT_HASH &&\n (row.laneIndex ?? 0) === 0\n ) {\n gutter = row.cells\n .slice(0, 1)\n .map((cell, column) =>\n renderCellPair(cell, column, cellColors, opts.colorize, style, palette),\n )\n .join('');\n } else if (row.kind === 'node' && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) {\n gutter = row.cells\n .slice(0, laneSpan)\n .map((cell, column) =>\n renderCellPair(cell, column, cellColors, opts.colorize, style, palette),\n )\n .join('');\n } else if (gutter.length < laneSpan * 2) {\n gutter = gutter.padEnd(laneSpan * 2, ' ');\n }\n const dirNameWidth = rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);\n const dataColumn = labelColumn + dirNameWidth;\n const gutterPad = padVisible(gutter, labelColumn);\n\n if (row.kind === 'node') {\n const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;\n if (contractHash === EMPTY_CONTRACT_HASH) {\n const trailingLanes = row.cells\n .slice(1)\n .map((cell, offset) =>\n renderCellPair(cell, offset + 1, cellColors, opts.colorize, style, palette),\n )\n .join('');\n const emptyGutter = palette.emptySource.padEnd(2, ' ') + trailingLanes;\n const overlayNames = overlayNamesForContract(contractHash, opts);\n if (overlayNames.length === 0) {\n lines.push(trimTrailingWhitespace(emptyGutter));\n continue;\n }\n const overlay = style.refs(overlayNames);\n lines.push(trimTrailingWhitespace(`${padVisible(emptyGutter, dataColumn)}${overlay}`));\n continue;\n }\n const hashText = style.sourceHash(\n abbreviateHash(contractHash, hashLength, palette.emptySource),\n );\n const overlayNames = overlayNamesForContract(contractHash, opts);\n const overlayPad =\n overlayNames.length > 0\n ? ' '.repeat(Math.max(0, dataColumn - labelColumn - stringWidth(hashText)))\n : '';\n const overlay = overlayNames.length > 0 ? style.refs(overlayNames) : '';\n lines.push(trimTrailingWhitespace(`${gutterPad}${hashText}${overlayPad}${overlay}`));\n continue;\n }\n\n const edge = row.edge;\n if (edge === undefined) continue;\n\n const dirNamePadding = ' '.repeat(Math.max(0, dirNameWidth - edge.dirName.length));\n const laneIndex = row.laneIndex ?? 0;\n // A branched name keeps its bold (via `style.dirName`) and adds the lane\n // hue, so it reads as one with its lane/arrow; column-0 names stay bold-only.\n const dirNameStyler =\n opts.colorize && laneIndex > NEUTRAL_LANE\n ? (text: string) => forcedBold(laneColorForColumn(laneIndex)(text))\n : style.dirName;\n const dirName = `${dirNameStyler(edge.dirName)}${dirNamePadding}`;\n const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);\n lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}`));\n }\n\n return lines.join('\\n');\n}\n\nexport interface RenderMigrationGraphLegendOptions {\n readonly colorize: boolean;\n readonly glyphMode?: GlyphMode;\n}\n\n/**\n * A compact key for the `--tree` visual language: the contract marker, the\n * in-lane direction arrows, the empty baseline, the `(refs)` overlay (including\n * the reserved `db` live-database and `contract` working-schema markers), and a\n * worked sample of the data-column `from → to` migration hash arrow.\n *\n * Honors the same glyph palette (unicode vs ASCII) and `colorize` gate as the\n * tree renderer, so the key matches whatever the graph itself drew and stays\n * pipe-safe (zero ANSI when color is off). The caller adds the trailing blank\n * line that separates this stderr key from the graph on stdout.\n */\nexport function renderMigrationGraphLegend(opts: RenderMigrationGraphLegendOptions): string {\n const palette = paletteFor(opts.glyphMode ?? 'unicode');\n const style = createAnsiMigrationListStyler({ useColor: opts.colorize });\n const node = palette.node.trimEnd();\n const sampleArrow = `${style.sourceHash('aaaaaa')} ${style.glyph(palette.forwardArrow)} ${style.destHash('bbbbbb')}`;\n return [\n 'Legend:',\n ` ${style.kind(node)} contract ${style.kind(palette.edgeArrow.forward)} forward ${style.kind(palette.edgeArrow.rollback)} rollback`,\n ` ${style.kind(palette.edgeArrow.self)} migration without schema change`,\n ` ${style.glyph(palette.emptySource)} empty database (baseline)`,\n ` ${style.refs(['refs'])} ${DB_MARKER_NAME} / ${CONTRACT_MARKER_NAME} markers`,\n ` ${sampleArrow} migration from contract aaaaaa to bbbbbb`,\n ].join('\\n');\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { buildMigrationGraphLayout } from '../utils/formatters/migration-graph-layout';\nimport { buildMigrationGraphRows } from '../utils/formatters/migration-graph-rows';\nimport {\n renderMigrationGraphLegend,\n renderMigrationGraphTree,\n} from '../utils/formatters/migration-graph-tree-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationGraphOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly dot?: boolean;\n readonly tree?: boolean;\n readonly ascii?: boolean;\n readonly legend?: boolean;\n}\n\n/**\n * `--legend` describes the `--tree` visual language, so passing it auto-enables\n * the tree path (it has nothing to say about the legacy dagre default).\n */\nexport function migrationGraphUsesTree(options: {\n readonly tree?: boolean;\n readonly legend?: boolean;\n}): boolean {\n return options.tree === true || options.legend === true;\n}\n\n/**\n * The legend is decoration printed alongside the command header on stderr, so\n * it is suppressed for the machine-readable / silent paths (`--json`, `--dot`,\n * `--quiet`) exactly as the header is.\n */\nexport function migrationGraphShowsLegend(\n options: { readonly legend?: boolean; readonly dot?: boolean },\n flags: GlobalFlags,\n): boolean {\n return (\n options.legend === true && options.dot !== true && flags.json !== true && flags.quiet !== true\n );\n}\n\nexport interface MigrationGraphResult {\n readonly ok: true;\n readonly graph: MigrationGraph;\n readonly contractHash: string | null;\n readonly refs: readonly StatusRef[];\n readonly summary: string;\n}\n\nexport async function executeMigrationGraphCommand(\n options: MigrationGraphOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationGraphResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration graph',\n description: 'Show the migration graph topology',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n if (migrationGraphShowsLegend(options, flags)) {\n ui.stderr(\n renderMigrationGraphLegend({\n colorize: flags.color !== false,\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n }),\n );\n // Blank line separating the stderr key from the graph that follows on stdout.\n ui.stderr('');\n }\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return loaded;\n }\n\n const { aggregate, contractHash } = loaded.value;\n const graph = aggregate.app.graph();\n const refs: readonly StatusRef[] = Object.entries(aggregate.app.refs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: false,\n }));\n\n return ok({\n ok: true,\n graph,\n contractHash,\n refs,\n summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`,\n });\n}\n\nexport function createMigrationGraphCommand(): Command {\n const command = new Command('graph');\n setCommandDescriptions(\n command,\n 'Show the migration graph topology',\n 'Renders the migration graph topology. Offline — does not consult\\n' +\n 'the database. Use --tree for the condensed annotated tree\\n' +\n '(--ascii swaps box-drawing for pipe-friendly ASCII glyphs),\\n' +\n '--json for machine-readable output, or --dot for Graphviz DOT\\n' +\n 'format.',\n );\n setCommandExamples(command, [\n 'prisma-next migration graph',\n 'prisma-next migration graph --json',\n 'prisma-next migration graph --dot',\n 'prisma-next migration graph --tree',\n 'prisma-next migration graph --tree --ascii',\n 'prisma-next migration graph --legend',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dot', 'Output in Graphviz DOT format')\n .option('--tree', 'Experimental condensed annotated tree renderer')\n .option('--ascii', 'Use ASCII glyphs for --tree (pipe-friendly)')\n .option('--legend', 'Print a key for the --tree glyphs and lane colors (implies --tree)')\n .action(async (options: MigrationGraphOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationGraphCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (graphResult) => {\n // Explicit format flags win over the auto-JSON default. `flags.json`\n // is auto-enabled when stdout is non-TTY (per CLI Style Guide §\n // JSON Semantics); without this ordering, `migration graph --dot |\n // dot -Tsvg` pipes JSON into the GraphViz binary, which then\n // errors. `--dot` is the more specific instruction; honour it.\n if (options.dot) {\n const lines = ['digraph migrations {'];\n for (const edge of graphResult.graph.migrationByHash.values()) {\n const from = edge.from.slice(0, 12);\n const to = edge.to.slice(0, 12);\n lines.push(` \"${from}\" -> \"${to}\" [label=\"${edge.dirName}\"];`);\n }\n lines.push('}');\n ui.output(lines.join('\\n'));\n } else if (flags.json) {\n const nodes = [...graphResult.graph.nodes];\n const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({\n dirName: e.dirName,\n from: e.from,\n to: e.to,\n migrationHash: e.migrationHash,\n }));\n ui.output(\n JSON.stringify({ ok: true, nodes, edges, summary: graphResult.summary }, null, 2),\n );\n } else if (!flags.quiet) {\n if (migrationGraphUsesTree(options)) {\n const refsByHash = new Map<string, string[]>();\n for (const ref of graphResult.refs) {\n const existing = refsByHash.get(ref.hash);\n refsByHash.set(ref.hash, existing ? [...existing, ref.name] : [ref.name]);\n }\n const rowModel = buildMigrationGraphRows(graphResult.graph, {\n ...(graphResult.contractHash !== null\n ? { contractHash: graphResult.contractHash }\n : {}),\n });\n const layout = buildMigrationGraphLayout(rowModel);\n const activeRef = graphResult.refs.find((ref) => ref.active);\n const treeOutput = renderMigrationGraphTree(layout, {\n refsByHash,\n ...(graphResult.contractHash !== null\n ? { contractHash: graphResult.contractHash }\n : {}),\n ...(activeRef !== undefined ? { activeRefName: activeRef.name } : {}),\n colorize: flags.color !== false,\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n });\n // Emit the rendered tree to stdout (same stream as flat `migration list`),\n // not through clack's `log.message` rail: the graph is the command's\n // result (and its own box-drawing is the only vertical structure it\n // should carry), not a status line that needs the prompt gutter.\n ui.output(treeOutput);\n ui.output(`\\n${graphResult.summary}`);\n } else {\n const renderInput = migrationGraphToRenderInput({\n graph: graphResult.graph,\n mode: 'offline',\n markerHash: undefined,\n contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,\n refs: graphResult.refs,\n activeRefHash: undefined,\n activeRefName: undefined,\n edgeStatuses: [],\n });\n const graphOutput = graphRenderer.render(renderInput.graph, {\n ...renderInput.options,\n colorize: flags.color !== false,\n });\n ui.log(graphOutput);\n ui.log(`\\n${graphResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prisma-next",
|
|
3
|
-
"version": "0.12.0-dev.
|
|
3
|
+
"version": "0.12.0-dev.7",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@clack/prompts": "^1.4.0",
|
|
13
13
|
"@dagrejs/dagre": "^3.0.0",
|
|
14
|
-
"@prisma-next/config": "0.12.0-dev.
|
|
15
|
-
"@prisma-next/contract": "0.12.0-dev.
|
|
16
|
-
"@prisma-next/emitter": "0.12.0-dev.
|
|
17
|
-
"@prisma-next/errors": "0.12.0-dev.
|
|
18
|
-
"@prisma-next/framework-components": "0.12.0-dev.
|
|
19
|
-
"@prisma-next/migration-tools": "0.12.0-dev.
|
|
20
|
-
"@prisma-next/psl-printer": "0.12.0-dev.
|
|
21
|
-
"@prisma-next/cli-telemetry": "0.12.0-dev.
|
|
22
|
-
"@prisma-next/utils": "0.12.0-dev.
|
|
14
|
+
"@prisma-next/config": "0.12.0-dev.7",
|
|
15
|
+
"@prisma-next/contract": "0.12.0-dev.7",
|
|
16
|
+
"@prisma-next/emitter": "0.12.0-dev.7",
|
|
17
|
+
"@prisma-next/errors": "0.12.0-dev.7",
|
|
18
|
+
"@prisma-next/framework-components": "0.12.0-dev.7",
|
|
19
|
+
"@prisma-next/migration-tools": "0.12.0-dev.7",
|
|
20
|
+
"@prisma-next/psl-printer": "0.12.0-dev.7",
|
|
21
|
+
"@prisma-next/cli-telemetry": "0.12.0-dev.7",
|
|
22
|
+
"@prisma-next/utils": "0.12.0-dev.7",
|
|
23
23
|
"arktype": "^2.2.0",
|
|
24
24
|
"c12": "^3.3.4",
|
|
25
25
|
"ci-info": "^4.3.1",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"wrap-ansi": "^10.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@prisma-next/cli": "0.12.0-dev.
|
|
39
|
+
"@prisma-next/cli": "0.12.0-dev.7"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"typescript": ">=5.9"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"migration-graph-D7DVUElV.mjs","names":[],"sources":["../src/utils/formatters/migration-graph-layout.ts","../src/utils/formatters/migration-graph-rows.ts","../src/utils/formatters/migration-graph-tree-render.ts","../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { ClassifiedEdge, MigrationGraphRowModel } from './migration-graph-rows';\nimport type { MigrationEdgeKind } from './migration-list-graph-topology';\n\nexport type EdgeAdjacency = 'adjacent' | 'node-skipping-forward' | 'node-skipping-rollback';\n\nexport type StructuralCell =\n | { readonly kind: 'empty' }\n | {\n readonly kind: 'node';\n readonly contractHash: string;\n readonly arcTee?: boolean;\n readonly arcLand?: boolean;\n }\n | { readonly kind: 'vertical-pass' }\n | { readonly kind: 'horizontal-pass' }\n | { readonly kind: 'branch-tee' }\n | { readonly kind: 'branch-corner' }\n | { readonly kind: 'merge-tee' }\n | { readonly kind: 'merge-corner' }\n | { readonly kind: 'arc-branch-corner' }\n | { readonly kind: 'arc-branch-tee' }\n | { readonly kind: 'arc-land-corner' }\n | { readonly kind: 'arc-crossing' }\n | { readonly kind: 'arc-land-bridge' }\n | {\n readonly kind: 'edge-lane';\n readonly migrationHash: string;\n readonly edgeKind: MigrationEdgeKind;\n readonly ownsLabel: boolean;\n readonly adjacency: EdgeAdjacency;\n };\n\nexport type GridRowKind =\n | 'node'\n | 'edge'\n | 'branch-connector'\n | 'merge-connector'\n | 'component-separator';\n\nexport interface MigrationGraphGridRow {\n readonly kind: GridRowKind;\n readonly contractHash?: string;\n readonly edge?: ClassifiedEdge;\n readonly laneIndex?: number;\n readonly passThroughLanes?: readonly number[];\n readonly startLane?: number;\n readonly endLane?: number;\n readonly branchCount?: number;\n readonly convergenceProducer?: boolean;\n readonly cells: readonly StructuralCell[];\n}\n\nexport interface MigrationGraphGridModel {\n readonly rows: readonly MigrationGraphGridRow[];\n readonly nodeColumn: ReadonlyMap<string, number>;\n readonly edgeColumn: ReadonlyMap<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// Edge bucketing helpers\n// ---------------------------------------------------------------------------\n\nfunction forwardEdges(edges: readonly ClassifiedEdge[]): ClassifiedEdge[] {\n return edges.filter((e) => e.kind === 'forward');\n}\n\nfunction buildForwardProducersByTo(\n edges: readonly ClassifiedEdge[],\n): Map<string, ClassifiedEdge[]> {\n const byTo = new Map<string, ClassifiedEdge[]>();\n for (const edge of edges) {\n if (edge.kind !== 'forward') continue;\n const bucket = byTo.get(edge.to);\n if (bucket) bucket.push(edge);\n else byTo.set(edge.to, [edge]);\n }\n return byTo;\n}\n\nfunction buildForwardOutDegree(edges: readonly ClassifiedEdge[]): Map<string, number> {\n const out = new Map<string, number>();\n for (const edge of edges) {\n if (edge.kind !== 'forward' || edge.from === edge.to) continue;\n out.set(edge.from, (out.get(edge.from) ?? 0) + 1);\n }\n return out;\n}\n\nfunction buildForwardInDegree(edges: readonly ClassifiedEdge[]): Map<string, number> {\n const indeg = new Map<string, number>();\n for (const edge of forwardEdges(edges)) {\n if (edge.from === edge.to) continue;\n indeg.set(edge.to, (indeg.get(edge.to) ?? 0) + 1);\n }\n return indeg;\n}\n\n/**\n * Distinct source contracts among a contract's forward producers. A contract is\n * a *convergence* when this count is >= 2. Multiple migrations sharing one\n * source (a multi-edge) count once — they stack in a single lane rather than\n * fanning into a convergence.\n */\nfunction buildDistinctSourceCountByTo(edges: readonly ClassifiedEdge[]): Map<string, number> {\n const sources = new Map<string, Set<string>>();\n for (const edge of edges) {\n if (edge.kind !== 'forward' || edge.from === edge.to) continue;\n const set = sources.get(edge.to);\n if (set) set.add(edge.from);\n else sources.set(edge.to, new Set([edge.from]));\n }\n const counts = new Map<string, number>();\n for (const [to, set] of sources) counts.set(to, set.size);\n return counts;\n}\n\nfunction splitComponents(nodes: readonly (string | null)[]): readonly (readonly string[])[] {\n const components: string[][] = [];\n let current: string[] = [];\n for (const node of nodes) {\n if (node === null) {\n if (current.length > 0) {\n components.push(current);\n current = [];\n }\n continue;\n }\n current.push(node);\n }\n if (current.length > 0) components.push(current);\n return components;\n}\n\n// ---------------------------------------------------------------------------\n// Adjacency refinement (operates on the emitted rows)\n// ---------------------------------------------------------------------------\n\nfunction classifyForwardShortConvergenceAdjacency(\n rows: readonly MigrationGraphGridRow[],\n edgeRowIndex: number,\n edge: ClassifiedEdge,\n laneIndex: number,\n): EdgeAdjacency {\n for (let index = edgeRowIndex + 1; index < rows.length; index++) {\n const row = rows[index];\n if (row === undefined) break;\n if (row.kind === 'component-separator' || row.kind === 'branch-connector') continue;\n if (row.kind === 'merge-connector') continue;\n if (row.kind === 'edge') {\n if (row.laneIndex === laneIndex) return 'node-skipping-forward';\n continue;\n }\n if (row.kind === 'node' && row.contractHash === edge.from) {\n return 'adjacent';\n }\n }\n return 'node-skipping-forward';\n}\n\nfunction convergenceProducerUsesShortAdjacency(\n edge: ClassifiedEdge,\n laneIndex: number,\n forwardProducersByTo: ReadonlyMap<string, readonly ClassifiedEdge[]>,\n producerLaneByHash: ReadonlyMap<string, number>,\n): boolean {\n const producers = (forwardProducersByTo.get(edge.to) ?? []).filter(\n (candidate) => candidate.kind === 'forward',\n );\n if (producers.length < 2) return false;\n\n const fanLanes = [\n ...new Set(\n producers\n .map((producer) => producerLaneByHash.get(producer.migrationHash))\n .filter((candidate): candidate is number => candidate !== undefined),\n ),\n ].sort((a, b) => a - b);\n const fanStart = fanLanes[0];\n if (fanStart === undefined) return false;\n\n return laneIndex === fanStart;\n}\n\nfunction classifyForwardLayoutAdjacency(\n rows: readonly MigrationGraphGridRow[],\n edgeRowIndex: number,\n edge: ClassifiedEdge,\n laneIndex: number,\n passThroughLanes: readonly number[],\n nodeColumn: ReadonlyMap<string, number>,\n convergenceProducer: boolean,\n divergenceBranchEdge: boolean,\n): EdgeAdjacency {\n let sawObstruction = false;\n const passThroughLaneSet = new Set(passThroughLanes);\n\n for (let index = edgeRowIndex + 1; index < rows.length; index++) {\n const row = rows[index];\n if (row === undefined) break;\n if (row.kind === 'component-separator') continue;\n if (row.kind === 'merge-connector') {\n if (convergenceProducer) {\n if (row.contractHash === edge.from) sawObstruction = true;\n } else if (!divergenceBranchEdge && row.contractHash !== edge.from) {\n sawObstruction = true;\n }\n continue;\n }\n if (row.kind === 'branch-connector') continue;\n if (row.kind === 'edge') {\n if (row.laneIndex === laneIndex) return 'node-skipping-forward';\n if (!divergenceBranchEdge && row.edge !== undefined && row.edge.to !== edge.to) {\n sawObstruction = true;\n }\n continue;\n }\n if (row.kind === 'node' && row.contractHash !== undefined) {\n if (row.contractHash === edge.from) {\n return sawObstruction ? 'node-skipping-forward' : 'adjacent';\n }\n const nodeCol = nodeColumn.get(row.contractHash) ?? 0;\n // A divergence-branch lane runs unobstructed to its convergence point;\n // sibling-branch nodes sit in parallel lanes and never block it.\n if (!divergenceBranchEdge && !passThroughLaneSet.has(nodeCol)) {\n sawObstruction = true;\n }\n }\n }\n\n return 'node-skipping-forward';\n}\n\nfunction classifyLayoutAdjacency(\n rows: readonly MigrationGraphGridRow[],\n edgeRowIndex: number,\n edge: ClassifiedEdge,\n laneIndex: number,\n passThroughLanes: readonly number[],\n nodeColumn: ReadonlyMap<string, number>,\n position: ReadonlyMap<string, number>,\n forwardInDegree: ReadonlyMap<string, number>,\n convergenceProducer: boolean,\n divergenceBranchEdge: boolean,\n): EdgeAdjacency {\n if (edge.kind === 'self') return 'adjacent';\n\n const fromPos = position.get(edge.from);\n const toPos = position.get(edge.to);\n\n if (edge.kind === 'forward') {\n const inDegree = forwardInDegree.get(edge.to) ?? 0;\n if (inDegree <= 1 && fromPos !== undefined && toPos !== undefined && fromPos === toPos + 1) {\n return 'adjacent';\n }\n return classifyForwardLayoutAdjacency(\n rows,\n edgeRowIndex,\n edge,\n laneIndex,\n passThroughLanes,\n nodeColumn,\n convergenceProducer,\n divergenceBranchEdge,\n );\n }\n\n if (fromPos !== undefined && toPos !== undefined && toPos === fromPos + 1) {\n return 'adjacent';\n }\n\n for (let index = edgeRowIndex + 1; index < rows.length; index++) {\n const row = rows[index];\n if (row === undefined) break;\n if (\n row.kind === 'component-separator' ||\n row.kind === 'branch-connector' ||\n row.kind === 'merge-connector'\n ) {\n continue;\n }\n if (row.kind === 'edge') continue;\n if (row.kind === 'node') {\n return row.contractHash === edge.to ? 'adjacent' : 'node-skipping-rollback';\n }\n }\n return 'node-skipping-rollback';\n}\n\nfunction refineAdjacency(\n rows: readonly MigrationGraphGridRow[],\n nodeColumn: ReadonlyMap<string, number>,\n position: ReadonlyMap<string, number>,\n forwardInDegree: ReadonlyMap<string, number>,\n forwardOutDegree: ReadonlyMap<string, number>,\n edges: readonly ClassifiedEdge[],\n producerLaneByHash: ReadonlyMap<string, number>,\n): MigrationGraphGridRow[] {\n const forwardProducersByTo = buildForwardProducersByTo(edges);\n function branchLaneForEdge(producer: ClassifiedEdge): number | undefined {\n const children = edges.filter(\n (edge) => edge.from === producer.from && edge.kind === 'forward' && edge.from !== edge.to,\n );\n if (children.length < 2) return undefined;\n const index = children.findIndex((child) => child.migrationHash === producer.migrationHash);\n return index >= 0 ? index : undefined;\n }\n\n return rows.map((row, rowIndex) => {\n if (row.kind !== 'edge' || row.edge === undefined || row.laneIndex === undefined) {\n return row;\n }\n const divergenceBranchEdge =\n row.edge.kind === 'forward' &&\n !(row.convergenceProducer ?? false) &&\n (forwardOutDegree.get(row.edge.from) ?? 0) >= 2 &&\n branchLaneForEdge(row.edge) !== undefined;\n const adjacency =\n row.convergenceProducer === true &&\n convergenceProducerUsesShortAdjacency(\n row.edge,\n row.laneIndex,\n forwardProducersByTo,\n producerLaneByHash,\n )\n ? classifyForwardShortConvergenceAdjacency(rows, rowIndex, row.edge, row.laneIndex)\n : classifyLayoutAdjacency(\n rows,\n rowIndex,\n row.edge,\n row.laneIndex,\n row.passThroughLanes ?? [],\n nodeColumn,\n position,\n forwardInDegree,\n row.convergenceProducer ?? false,\n divergenceBranchEdge,\n );\n return {\n ...row,\n cells: buildEdgeCells(\n row.edge,\n row.laneIndex,\n row.passThroughLanes ?? [],\n adjacency,\n row.cells.length,\n ),\n };\n });\n}\n\nfunction classifyEdgeAdjacency(\n edge: ClassifiedEdge,\n position: ReadonlyMap<string, number>,\n): EdgeAdjacency {\n if (edge.kind === 'self') return 'adjacent';\n\n const fromPos = position.get(edge.from);\n const toPos = position.get(edge.to);\n if (fromPos === undefined || toPos === undefined) return 'adjacent';\n\n if (edge.kind === 'forward') {\n if (toPos >= fromPos) return 'adjacent';\n return fromPos === toPos + 1 ? 'adjacent' : 'node-skipping-forward';\n }\n\n if (toPos <= fromPos) return 'adjacent';\n return toPos === fromPos + 1 ? 'adjacent' : 'node-skipping-rollback';\n}\n\n// ---------------------------------------------------------------------------\n// Cell builders\n// ---------------------------------------------------------------------------\n\nfunction emptyCells(width: number): StructuralCell[] {\n return Array.from({ length: width }, () => ({ kind: 'empty' as const }));\n}\n\nfunction buildBranchConnectorCells(\n startLane: number,\n endLane: number,\n activeLanes: ReadonlySet<number>,\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (let lane = 0; lane < gridWidth; lane++) {\n if (activeLanes.has(lane) && (lane < startLane || lane > endLane)) {\n cells[lane] = { kind: 'vertical-pass' };\n continue;\n }\n if (lane === startLane) {\n cells[lane] = { kind: 'branch-tee' };\n } else if (lane === endLane) {\n cells[lane] = { kind: 'branch-corner' };\n } else if (lane > startLane && lane < endLane) {\n cells[lane] = { kind: 'branch-tee' };\n }\n }\n return cells;\n}\n\nfunction buildMergeConnectorCells(\n startLane: number,\n endLane: number,\n activeLanes: ReadonlySet<number>,\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (let lane = 0; lane < gridWidth; lane++) {\n if (activeLanes.has(lane) && (lane < startLane || lane > endLane)) {\n cells[lane] = { kind: 'vertical-pass' };\n continue;\n }\n if (lane === startLane) {\n cells[lane] = { kind: 'merge-tee' };\n } else if (lane === endLane) {\n cells[lane] = { kind: 'merge-corner' };\n } else if (lane > startLane && lane < endLane) {\n cells[lane] = activeLanes.has(lane) ? { kind: 'merge-tee' } : { kind: 'horizontal-pass' };\n }\n }\n return cells;\n}\n\nfunction buildNodeCells(\n contractHash: string,\n nodeColumn: number,\n activeLanes: readonly number[],\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (const lane of activeLanes) {\n if (lane !== nodeColumn && lane < gridWidth) {\n cells[lane] = { kind: 'vertical-pass' };\n }\n }\n if (nodeColumn < gridWidth) {\n cells[nodeColumn] = { kind: 'node', contractHash };\n }\n return cells;\n}\n\nfunction buildEdgeCells(\n edge: ClassifiedEdge,\n laneIndex: number,\n passThroughLanes: readonly number[],\n adjacency: EdgeAdjacency,\n gridWidth: number,\n): StructuralCell[] {\n const cells = emptyCells(gridWidth);\n for (const lane of passThroughLanes) {\n if (lane < gridWidth) cells[lane] = { kind: 'vertical-pass' };\n }\n if (laneIndex < gridWidth) {\n cells[laneIndex] = {\n kind: 'edge-lane',\n migrationHash: edge.migrationHash,\n edgeKind: edge.kind,\n ownsLabel: true,\n adjacency,\n };\n }\n return cells;\n}\n\n// ---------------------------------------------------------------------------\n// Vertical ordering: tips-first DFS post-order over forward edges\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the vertical node order for a component: tips at the top (index 0),\n * roots at the bottom. This is a DFS post-order over forward edges starting\n * from forward roots, visiting children in their input (insertion) order. A\n * node is emitted only after all of its forward children, so convergence nodes\n * sit below every branch that feeds them and the longest contiguous chain reads\n * top-to-bottom without braiding.\n */\nfunction computeVerticalOrder(\n componentNodes: readonly string[],\n forwardChildren: ReadonlyMap<string, readonly ClassifiedEdge[]>,\n forwardInDegree: ReadonlyMap<string, number>,\n): string[] {\n const WHITE = 0;\n const GRAY = 1;\n const BLACK = 2;\n const color = new Map<string, number>();\n for (const node of componentNodes) color.set(node, WHITE);\n\n const sortRoots = (roots: readonly string[]): string[] =>\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 let roots = sortRoots(componentNodes.filter((n) => (forwardInDegree.get(n) ?? 0) === 0));\n if (roots.length === 0) roots = sortRoots(componentNodes);\n\n const result: string[] = [];\n\n interface Frame {\n node: string;\n children: readonly ClassifiedEdge[];\n index: number;\n }\n\n function runDfs(root: string): void {\n if (color.get(root) !== WHITE) return;\n const stack: Frame[] = [{ node: root, children: forwardChildren.get(root) ?? [], index: 0 }];\n color.set(root, GRAY);\n\n while (stack.length > 0) {\n const frame = stack[stack.length - 1];\n if (frame === undefined) break;\n if (frame.index >= frame.children.length) {\n color.set(frame.node, BLACK);\n result.push(frame.node);\n stack.pop();\n continue;\n }\n const child = frame.children[frame.index];\n frame.index += 1;\n if (child === undefined) continue;\n if (color.get(child.to) === WHITE) {\n color.set(child.to, GRAY);\n stack.push({ node: child.to, children: forwardChildren.get(child.to) ?? [], index: 0 });\n }\n }\n }\n\n for (const root of roots) runDfs(root);\n // Nodes unreachable via forward edges (e.g. rollback-only sources) follow in\n // component order.\n for (const node of componentNodes) {\n if (color.get(node) === WHITE) runDfs(node);\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Routed back-arcs for node-skipping rollbacks\n// ---------------------------------------------------------------------------\n\ninterface SkipRollbackRoute {\n readonly edge: ClassifiedEdge;\n readonly backLane: number;\n}\n\nfunction rollbackSpan(\n edge: ClassifiedEdge,\n position: ReadonlyMap<string, number>,\n): { readonly top: number; readonly bottom: number } {\n const top = position.get(edge.from) ?? 0;\n const bottom = position.get(edge.to) ?? top;\n return { top, bottom };\n}\n\nfunction spansOverlap(\n a: { readonly top: number; readonly bottom: number },\n b: { readonly top: number; readonly bottom: number },\n): boolean {\n return a.top <= b.bottom && b.top <= a.bottom;\n}\n\nfunction forwardMaxLane(\n rows: readonly MigrationGraphGridRow[],\n skipMigrationHashes: ReadonlySet<string>,\n): number {\n let max = 0;\n for (const row of rows) {\n if (\n row.kind === 'edge' &&\n row.edge !== undefined &&\n skipMigrationHashes.has(row.edge.migrationHash)\n ) {\n continue;\n }\n max = Math.max(max, row.laneIndex ?? 0);\n for (const lane of row.passThroughLanes ?? []) {\n max = Math.max(max, lane);\n }\n if (row.startLane !== undefined) {\n max = Math.max(max, row.startLane, row.endLane ?? row.startLane);\n }\n }\n return max;\n}\n\nfunction allocateSkipRollbackBackLanes(\n skipRollbacks: readonly ClassifiedEdge[],\n position: ReadonlyMap<string, number>,\n forwardMax: number,\n): Map<string, number> {\n const sorted = [...skipRollbacks].sort((a, b) => {\n const aTop = position.get(a.from) ?? 0;\n const bTop = position.get(b.from) ?? 0;\n if (aTop !== bTop) return aTop - bTop;\n return b.dirName.localeCompare(a.dirName);\n });\n\n const occupied: { readonly top: number; readonly bottom: number; readonly lane: number }[] = [];\n const lanes = new Map<string, number>();\n let nextLane = forwardMax + 1;\n\n for (const edge of sorted) {\n const span = rollbackSpan(edge, position);\n let lane = nextLane;\n while (occupied.some((entry) => entry.lane === lane && spansOverlap(entry, span))) {\n lane += 1;\n }\n occupied.push({ ...span, lane });\n lanes.set(edge.migrationHash, lane);\n nextLane = Math.max(nextLane, lane + 1);\n }\n\n return lanes;\n}\n\nfunction findNodeRowIndex(rows: readonly MigrationGraphGridRow[], contractHash: string): number {\n return rows.findIndex((row) => row.kind === 'node' && row.contractHash === contractHash);\n}\n\nfunction findEdgeRowIndex(rows: readonly MigrationGraphGridRow[], migrationHash: string): number {\n return rows.findIndex((row) => row.kind === 'edge' && row.edge?.migrationHash === migrationHash);\n}\n\n// A grid row with a mutable `cells` array. The routing pass clones the\n// immutable rows into this shape so it can paint arc cells in place without\n// stripping `readonly` with a cast.\ntype MutableGridRow = Omit<MigrationGraphGridRow, 'cells'> & { cells: StructuralCell[] };\n\nfunction ensureCellWidth(cells: StructuralCell[], width: number): void {\n while (cells.length < width) {\n cells.push({ kind: 'empty' });\n }\n}\n\nfunction cloneRow(row: MigrationGraphGridRow): MutableGridRow {\n return { ...row, cells: [...row.cells] };\n}\n\nfunction routeCrossesRow(\n route: SkipRollbackRoute,\n rowIndex: number,\n rows: readonly MigrationGraphGridRow[],\n): boolean {\n const sourceRow = findNodeRowIndex(rows, route.edge.from);\n const targetRow = findNodeRowIndex(rows, route.edge.to);\n if (sourceRow < 0 || targetRow < 0) return false;\n return rowIndex > sourceRow && rowIndex <= targetRow;\n}\n\nfunction applySkipRollbackRouting(\n rows: readonly MigrationGraphGridRow[],\n skipRollbacks: readonly ClassifiedEdge[],\n position: ReadonlyMap<string, number>,\n nodeColumn: ReadonlyMap<string, number>,\n edgeColumn: Map<string, number>,\n): MigrationGraphGridRow[] {\n if (skipRollbacks.length === 0) return [...rows];\n\n const skipHashes = new Set(skipRollbacks.map((edge) => edge.migrationHash));\n const forwardMax = forwardMaxLane(rows, skipHashes);\n const backLaneByHash = allocateSkipRollbackBackLanes(skipRollbacks, position, forwardMax);\n const routes: SkipRollbackRoute[] = skipRollbacks.map((edge) => ({\n edge,\n backLane: backLaneByHash.get(edge.migrationHash) ?? forwardMax + 1,\n }));\n\n const result = rows.map(cloneRow);\n\n for (const route of routes) {\n const { edge, backLane } = route;\n const nodeCol = nodeColumn.get(edge.from) ?? 0;\n const targetCol = nodeColumn.get(edge.to) ?? 0;\n const sourceRowIndex = findNodeRowIndex(result, edge.from);\n const targetRowIndex = findNodeRowIndex(result, edge.to);\n const edgeRowIndex = findEdgeRowIndex(result, edge.migrationHash);\n if (sourceRowIndex < 0 || targetRowIndex < 0 || edgeRowIndex < 0) continue;\n\n edgeColumn.set(edge.migrationHash, backLane);\n\n // Back-lanes of arcs that tee off this same source node. They share the\n // node's tee row, so each inner lane reads as a `┬` junction and only the\n // outermost gets the closing `╮`.\n const coSourcedLanes = routes\n .filter((other) => other.edge.from === edge.from)\n .map((other) => other.backLane);\n const maxCoSourcedLane = Math.max(...coSourcedLanes);\n\n const sourceRow = result[sourceRowIndex];\n if (sourceRow !== undefined) {\n const cells = sourceRow.cells;\n ensureCellWidth(cells, backLane + 1);\n const contractHash = sourceRow.contractHash ?? EMPTY_CONTRACT_HASH;\n cells[nodeCol] = { kind: 'node', contractHash, arcTee: true };\n for (let lane = nodeCol + 1; lane < backLane; lane += 1) {\n if (coSourcedLanes.includes(lane)) {\n cells[lane] = { kind: 'arc-branch-tee' };\n continue;\n }\n const existing = cells[lane];\n const occupied =\n existing !== undefined &&\n existing.kind !== 'empty' &&\n existing.kind !== 'horizontal-pass' &&\n existing.kind !== 'arc-land-bridge';\n const crossed =\n occupied ||\n routes.some(\n (other) =>\n other.edge.migrationHash !== edge.migrationHash &&\n other.backLane === lane &&\n routeCrossesRow(other, sourceRowIndex, result),\n );\n cells[lane] = crossed ? { kind: 'arc-crossing' } : { kind: 'horizontal-pass' };\n }\n cells[backLane] =\n backLane < maxCoSourcedLane ? { kind: 'arc-branch-tee' } : { kind: 'arc-branch-corner' };\n }\n\n const edgeRow = result[edgeRowIndex];\n if (edgeRow !== undefined) {\n // Mutate in place rather than rebuild from empty: a co-sourced arc's body\n // lane may already cross this row, and rebuilding would clobber it.\n const cells = edgeRow.cells;\n ensureCellWidth(cells, backLane + 1);\n cells[nodeCol] = { kind: 'vertical-pass' };\n cells[backLane] = {\n kind: 'edge-lane',\n migrationHash: edge.migrationHash,\n edgeKind: edge.kind,\n ownsLabel: true,\n adjacency: 'node-skipping-rollback',\n };\n result[edgeRowIndex] = { ...edgeRow, laneIndex: backLane, passThroughLanes: [nodeCol] };\n }\n\n // Fill the arc body vertically from just below the source tee down to the\n // row above the landing, skipping the rollback's own labelled edge row.\n // Starting below the source (rather than below the edge row) keeps a\n // co-sourced arc's lane connected across an earlier co-sourced edge row.\n for (let index = sourceRowIndex + 1; index < targetRowIndex; index += 1) {\n if (index === edgeRowIndex) continue;\n const row = result[index];\n if (row === undefined) continue;\n const cells = row.cells;\n ensureCellWidth(cells, backLane + 1);\n const existing = cells[backLane];\n if (\n existing?.kind !== 'arc-land-corner' &&\n existing?.kind !== 'arc-land-bridge' &&\n existing?.kind !== 'arc-branch-corner' &&\n existing?.kind !== 'arc-branch-tee' &&\n existing?.kind !== 'arc-crossing'\n ) {\n cells[backLane] = { kind: 'vertical-pass' };\n }\n }\n\n const targetRow = result[targetRowIndex];\n if (targetRow !== undefined) {\n const cells = targetRow.cells;\n ensureCellWidth(cells, backLane + 1);\n const contractHash = targetRow.contractHash ?? EMPTY_CONTRACT_HASH;\n cells[targetCol] = { kind: 'node', contractHash, arcLand: true };\n for (let lane = targetCol + 1; lane < backLane; lane += 1) {\n // A bridged lane that carries another arc OR a forward vertical still\n // active at this row must cross over it (`┼`) rather than overwrite it\n // with a bare bridge (`──`).\n const existing = cells[lane];\n const occupied =\n existing !== undefined &&\n existing.kind !== 'empty' &&\n existing.kind !== 'horizontal-pass' &&\n existing.kind !== 'arc-land-bridge';\n const crossed =\n occupied ||\n routes.some(\n (other) =>\n other.edge.migrationHash !== edge.migrationHash &&\n other.backLane === lane &&\n routeCrossesRow(other, targetRowIndex, result),\n );\n cells[lane] = crossed ? { kind: 'arc-crossing' } : { kind: 'arc-land-bridge' };\n }\n cells[backLane] = { kind: 'arc-land-corner' };\n for (const other of routes) {\n if (other.backLane <= backLane) continue;\n if (!routeCrossesRow(other, targetRowIndex, result)) continue;\n ensureCellWidth(cells, other.backLane + 1);\n const existing = cells[other.backLane];\n if (\n existing?.kind !== 'arc-land-corner' &&\n existing?.kind !== 'arc-land-bridge' &&\n existing?.kind !== 'node'\n ) {\n cells[other.backLane] = { kind: 'vertical-pass' };\n }\n }\n }\n }\n\n return result;\n}\n\nfunction collectNodeSkippingRollbacks(\n edges: readonly ClassifiedEdge[],\n position: ReadonlyMap<string, number>,\n): ClassifiedEdge[] {\n return edges.filter(\n (edge) =>\n edge.kind === 'rollback' &&\n classifyEdgeAdjacency(edge, position) === 'node-skipping-rollback',\n );\n}\n\n// ---------------------------------------------------------------------------\n// Lane allocation: one rule for all topologies\n// ---------------------------------------------------------------------------\n\ninterface DownwardGroup {\n readonly target: string;\n readonly edges: ClassifiedEdge[];\n}\n\nfunction layoutComponent(\n componentNodes: readonly string[],\n allEdges: readonly ClassifiedEdge[],\n): {\n rows: MigrationGraphGridRow[];\n nodeColumn: Map<string, number>;\n edgeColumn: Map<string, number>;\n} {\n const componentSet = new Set(componentNodes);\n const edges = allEdges.filter((e) => componentSet.has(e.from) && componentSet.has(e.to));\n\n const forwardChildren = new Map<string, ClassifiedEdge[]>();\n const producersByTo = new Map<string, ClassifiedEdge[]>();\n const rollbacksByFrom = new Map<string, ClassifiedEdge[]>();\n const selfByFrom = new Map<string, ClassifiedEdge[]>();\n for (const edge of edges) {\n if (edge.kind === 'self' || edge.from === edge.to) {\n const bucket = selfByFrom.get(edge.from);\n if (bucket) bucket.push(edge);\n else selfByFrom.set(edge.from, [edge]);\n continue;\n }\n if (edge.kind === 'forward') {\n const children = forwardChildren.get(edge.from);\n if (children) children.push(edge);\n else forwardChildren.set(edge.from, [edge]);\n const producers = producersByTo.get(edge.to);\n if (producers) producers.push(edge);\n else producersByTo.set(edge.to, [edge]);\n continue;\n }\n // rollback\n const bucket = rollbacksByFrom.get(edge.from);\n if (bucket) bucket.push(edge);\n else rollbacksByFrom.set(edge.from, [edge]);\n }\n\n const forwardInDegree = buildForwardInDegree(edges);\n const forwardOutDegree = buildForwardOutDegree(edges);\n const distinctSourceCountByTo = buildDistinctSourceCountByTo(edges);\n\n const order = computeVerticalOrder(componentNodes, forwardChildren, forwardInDegree);\n const position = new Map<string, number>();\n for (let index = 0; index < order.length; index++) {\n const node = order[index];\n if (node !== undefined) position.set(node, index);\n }\n\n const lanes: (string | null)[] = [];\n const rows: MigrationGraphGridRow[] = [];\n const nodeColumn = new Map<string, number>();\n const edgeColumn = new Map<string, number>();\n const producerLaneByHash = new Map<string, number>();\n let gridWidth = 1;\n\n function ensureGridWidth(minWidth: number): void {\n if (minWidth > gridWidth) gridWidth = minWidth;\n }\n\n function setLane(index: number, want: string | null): void {\n while (lanes.length <= index) lanes.push(null);\n lanes[index] = want;\n if (want !== null) ensureGridWidth(index + 1);\n }\n\n function activeLaneIndices(): number[] {\n const indices: number[] = [];\n for (let index = 0; index < lanes.length; index++) {\n if (lanes[index] !== null) indices.push(index);\n }\n return indices;\n }\n\n function passThroughExcept(lane: number): number[] {\n return activeLaneIndices().filter((index) => index !== lane);\n }\n\n function leftmostFreeLane(): number {\n for (let index = 0; index < lanes.length; index++) {\n if (lanes[index] === null) return index;\n }\n return lanes.length;\n }\n\n function lanesWanting(contract: string): number[] {\n const indices: number[] = [];\n for (let index = 0; index < lanes.length; index++) {\n if (lanes[index] === contract) indices.push(index);\n }\n return indices;\n }\n\n function emitMergeConnector(contractHash: string, laneIndices: readonly number[]): number {\n const startLane = Math.min(...laneIndices);\n const endLane = Math.max(...laneIndices);\n ensureGridWidth(endLane + 1);\n const activeLanes = new Set(activeLaneIndices());\n rows.push({\n kind: 'merge-connector',\n contractHash,\n startLane,\n endLane,\n branchCount: laneIndices.length,\n cells: buildMergeConnectorCells(startLane, endLane, activeLanes, gridWidth),\n });\n for (const index of laneIndices) {\n if (index !== startLane) setLane(index, null);\n }\n return startLane;\n }\n\n function emitBranchConnector(\n contractHash: string,\n startLane: number,\n endLane: number,\n branchCount: number,\n ): void {\n ensureGridWidth(endLane + 1);\n const activeLanes = new Set(activeLaneIndices());\n rows.push({\n kind: 'branch-connector',\n contractHash,\n startLane,\n endLane,\n branchCount,\n cells: buildBranchConnectorCells(startLane, endLane, activeLanes, gridWidth),\n });\n }\n\n function emitEdgeRow(edge: ClassifiedEdge, lane: number, convergenceProducer: boolean): void {\n const passThrough = passThroughExcept(lane);\n const adjacency = classifyEdgeAdjacency(edge, position);\n ensureGridWidth(Math.max(lane, ...passThrough, 0) + 1);\n const row: MigrationGraphGridRow = {\n kind: 'edge',\n edge,\n laneIndex: lane,\n passThroughLanes: passThrough,\n cells: buildEdgeCells(edge, lane, passThrough, adjacency, gridWidth),\n };\n rows.push(convergenceProducer ? { ...row, convergenceProducer: true } : row);\n edgeColumn.set(edge.migrationHash, lane);\n if (convergenceProducer) producerLaneByHash.set(edge.migrationHash, lane);\n }\n\n function emitNodeRow(contractHash: string, column: number): void {\n ensureGridWidth(column + 1);\n const passThrough = activeLaneIndices().filter((index) => index !== column);\n rows.push({\n kind: 'node',\n contractHash,\n cells: buildNodeCells(contractHash, column, passThrough, gridWidth),\n });\n nodeColumn.set(contractHash, column);\n }\n\n function producerGroups(node: string): DownwardGroup[] {\n const byTarget = new Map<string, DownwardGroup>();\n for (const producer of producersByTo.get(node) ?? []) {\n const group = byTarget.get(producer.from);\n if (group) group.edges.push(producer);\n else byTarget.set(producer.from, { target: producer.from, edges: [producer] });\n }\n const groups = [...byTarget.values()];\n // Lanes are ordered by where their target node lands vertically (soonest →\n // leftmost), which keeps lanes from crossing.\n groups.sort((a, b) => (position.get(a.target) ?? 0) - (position.get(b.target) ?? 0));\n for (const group of groups) {\n group.edges.sort((a, b) => b.dirName.localeCompare(a.dirName));\n }\n return groups;\n }\n\n function processNode(node: string): void {\n const wanting = lanesWanting(node);\n let column: number;\n if (wanting.length >= 2) {\n column = emitMergeConnector(node, wanting);\n } else if (wanting.length === 1) {\n column = wanting[0] ?? 0;\n } else {\n column = leftmostFreeLane();\n }\n\n // Self-edges sit immediately above their node, in its column.\n const selfEdges = [...(selfByFrom.get(node) ?? [])].sort((a, b) =>\n b.dirName.localeCompare(a.dirName),\n );\n for (const selfEdge of selfEdges) emitEdgeRow(selfEdge, column, false);\n\n emitNodeRow(node, column);\n\n const rollbacks = [...(rollbacksByFrom.get(node) ?? [])].sort((a, b) =>\n b.dirName.localeCompare(a.dirName),\n );\n const skipRollbacks: ClassifiedEdge[] = [];\n const adjacentRollbacks: ClassifiedEdge[] = [];\n for (const rollback of rollbacks) {\n if (classifyEdgeAdjacency(rollback, position) === 'node-skipping-rollback') {\n skipRollbacks.push(rollback);\n } else {\n adjacentRollbacks.push(rollback);\n }\n }\n for (const rollback of skipRollbacks) {\n emitEdgeRow(rollback, column, false);\n }\n\n const groups = producerGroups(node);\n const isConvergence = (distinctSourceCountByTo.get(node) ?? 0) >= 2;\n const laneForGroup: number[] = [];\n for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {\n const group = groups[groupIndex];\n if (group === undefined) continue;\n const lane = groupIndex === 0 ? column : leftmostFreeLane();\n laneForGroup[groupIndex] = lane;\n setLane(lane, group.target);\n }\n\n if (groups.length >= 2) {\n const endLane = Math.max(...laneForGroup);\n emitBranchConnector(node, column, endLane, groups.length);\n }\n\n for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {\n const group = groups[groupIndex];\n const lane = laneForGroup[groupIndex];\n if (group === undefined || lane === undefined) continue;\n for (const edge of group.edges) {\n emitEdgeRow(edge, lane, isConvergence);\n }\n }\n\n for (const rollback of adjacentRollbacks) {\n emitEdgeRow(rollback, column, false);\n }\n\n if (groups.length === 0) {\n // A root / leaf: its column lane terminates here.\n setLane(column, null);\n }\n }\n\n for (const node of order) processNode(node);\n\n const refined = refineAdjacency(\n rows,\n nodeColumn,\n position,\n forwardInDegree,\n forwardOutDegree,\n edges,\n producerLaneByHash,\n );\n const skipRollbacks = collectNodeSkippingRollbacks(edges, position);\n const routed = applySkipRollbackRouting(refined, skipRollbacks, position, nodeColumn, edgeColumn);\n\n return {\n rows: routed,\n nodeColumn,\n edgeColumn,\n };\n}\n\nexport function buildMigrationGraphLayout(\n rowModel: MigrationGraphRowModel,\n): MigrationGraphGridModel {\n if (rowModel.nodes.length === 0) {\n return { rows: [], nodeColumn: new Map(), edgeColumn: new Map() };\n }\n\n const components = splitComponents(rowModel.nodes);\n const allRows: MigrationGraphGridRow[] = [];\n const nodeColumn = new Map<string, number>();\n const edgeColumn = new Map<string, number>();\n\n for (let componentIndex = 0; componentIndex < components.length; componentIndex++) {\n if (componentIndex > 0) {\n allRows.push({ kind: 'component-separator', cells: [] });\n }\n\n const component = components[componentIndex];\n if (component === undefined || component.length === 0) continue;\n\n const result = layoutComponent(component, rowModel.edges);\n allRows.push(...result.rows);\n for (const [hash, column] of result.nodeColumn) nodeColumn.set(hash, column);\n for (const [hash, column] of result.edgeColumn) edgeColumn.set(hash, column);\n }\n\n return { rows: allRows, nodeColumn, edgeColumn };\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 layerNodesByLongestForwardPath(\n componentNodes: ReadonlySet<string>,\n topology: MigrationListGraphTopology,\n graph: MigrationGraph,\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 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\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 const edgesByFrom = new Map<string, ClassifiedEdge[]>();\n const edgesByTo = new Map<string, 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 const classified: ClassifiedEdge = {\n migrationHash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n dirName: edge.dirName,\n kind,\n };\n edges.push(classified);\n\n const fromBucket = edgesByFrom.get(edge.from);\n if (fromBucket) fromBucket.push(classified);\n else edgesByFrom.set(edge.from, [classified]);\n\n const toBucket = edgesByTo.get(edge.to);\n if (toBucket) toBucket.push(classified);\n else edgesByTo.set(edge.to, [classified]);\n }\n }\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(component, topology, graph);\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 { nodes, edges, edgesByFrom, edgesByTo };\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { bold } from 'colorette';\nimport stringWidth from 'string-width';\nimport type { GlyphMode } from '../glyph-mode';\nimport type {\n MigrationGraphGridModel,\n MigrationGraphGridRow,\n StructuralCell,\n} from './migration-graph-layout';\nimport type { ClassifiedEdge } from './migration-graph-rows';\nimport {\n MIGRATION_LIST_HASH_WIDTH,\n migrationListEmptySource,\n migrationListForwardArrow,\n} from './migration-list-data-column';\nimport type { MigrationEdgeKind } from './migration-list-graph-topology';\nimport type { MigrationListStyler } from './migration-list-render';\nimport { CONTRACT_MARKER_NAME, createAnsiMigrationListStyler } from './migration-list-styler';\n\nconst LABEL_GAP = 2;\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 RenderMigrationGraphTreeOptions {\n readonly refsByHash?: ReadonlyMap<string, readonly string[]>;\n readonly dbHash?: string;\n readonly contractHash?: string;\n readonly activeRefName?: string;\n readonly hashLength?: number;\n readonly colorize: boolean;\n readonly glyphMode?: GlyphMode;\n}\n\ninterface MigrationGraphTreeGlyphPalette {\n readonly node: string;\n readonly arcLand: string;\n readonly arcTee: string;\n readonly verticalPass: string;\n readonly branchTee: string;\n readonly mergeTee: string;\n readonly branchCorner: string;\n readonly mergeCorner: string;\n readonly arcBranchCorner: string;\n readonly arcBranchTee: string;\n readonly arcLandCorner: string;\n readonly arcCrossing: string;\n readonly arcLandBridge: string;\n readonly horizontalPass: string;\n readonly connectorBranchTee: string;\n readonly connectorBranchTeeCo: string;\n readonly connectorMergeTeeCo: string;\n readonly edgeArrow: Readonly<Record<MigrationEdgeKind, string>>;\n readonly forwardArrow: string;\n readonly emptySource: string;\n}\n\nconst UNICODE_PALETTE: MigrationGraphTreeGlyphPalette = {\n node: '○ ',\n arcLand: '○◂',\n arcTee: '○─',\n verticalPass: '│ ',\n branchTee: '├─',\n mergeTee: '├─',\n branchCorner: '╮ ',\n mergeCorner: '╯ ',\n arcBranchCorner: '╮ ',\n arcBranchTee: '┬─',\n arcLandCorner: '╯ ',\n arcCrossing: '┼─',\n arcLandBridge: '──',\n horizontalPass: '──',\n connectorBranchTee: '├─',\n connectorBranchTeeCo: '┬─',\n connectorMergeTeeCo: '┴─',\n edgeArrow: { forward: '↑', rollback: '↓', self: '⟲' },\n forwardArrow: migrationListForwardArrow('unicode'),\n emptySource: migrationListEmptySource('unicode'),\n};\n\nconst ASCII_PALETTE: MigrationGraphTreeGlyphPalette = {\n node: '* ',\n arcLand: '*<',\n arcTee: '*-',\n verticalPass: '| ',\n branchTee: '+-',\n mergeTee: '+-',\n branchCorner: '\\\\ ',\n mergeCorner: '/ ',\n arcBranchCorner: '\\\\ ',\n arcBranchTee: '+-',\n arcLandCorner: '/ ',\n arcCrossing: '+-',\n arcLandBridge: '--',\n horizontalPass: '--',\n connectorBranchTee: '+-',\n connectorBranchTeeCo: '+-',\n connectorMergeTeeCo: '+-',\n edgeArrow: { forward: '^', rollback: 'v', self: '@' },\n forwardArrow: migrationListForwardArrow('ascii'),\n emptySource: migrationListEmptySource('ascii'),\n};\n\nfunction paletteFor(mode: GlyphMode): MigrationGraphTreeGlyphPalette {\n return mode === 'ascii' ? ASCII_PALETTE : UNICODE_PALETTE;\n}\n\nfunction arrowForEdgeKind(\n kind: MigrationEdgeKind,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n return palette.edgeArrow[kind];\n}\n\n/**\n * A node-marker glyph pair (`○◂`, `○─`, `*<`, `*-`) is the contract node\n * marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`).\n * The marker is the signal and stays bright (`style.kind`); the connector is\n * gutter and stays dim (`style.lane`) — consistent with the plain node marker,\n * which is never dimmed.\n */\nfunction renderNodeMarkerPair(pair: string, style: MigrationListStyler): string {\n return style.kind(pair.slice(0, 1)) + style.lane(pair.slice(1));\n}\n\nfunction renderCellPair(\n cell: StructuralCell,\n style: MigrationListStyler,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n switch (cell.kind) {\n case 'node':\n if (cell.arcLand === true) return renderNodeMarkerPair(palette.arcLand, style);\n if (cell.arcTee === true) return renderNodeMarkerPair(palette.arcTee, style);\n return style.kind(palette.node);\n case 'vertical-pass':\n return style.lane(palette.verticalPass);\n case 'edge-lane':\n // The lane stays dim; the direction arrow (↑ / ↓ / ⟲) is the signal and\n // stays bright, like the contract-node marker.\n return cell.ownsLabel\n ? style.lane(palette.verticalPass.trimEnd()) +\n style.kind(arrowForEdgeKind(cell.edgeKind, palette))\n : style.lane(palette.verticalPass);\n case 'branch-tee':\n return style.lane(palette.branchTee);\n case 'merge-tee':\n return style.lane(palette.mergeTee);\n case 'branch-corner':\n return style.lane(palette.branchCorner);\n case 'merge-corner':\n return style.lane(palette.mergeCorner);\n case 'arc-branch-corner':\n return style.lane(palette.arcBranchCorner);\n case 'arc-branch-tee':\n return style.lane(palette.arcBranchTee);\n case 'arc-land-corner':\n return style.lane(palette.arcLandCorner);\n case 'arc-crossing':\n return style.lane(palette.arcCrossing);\n case 'arc-land-bridge':\n return style.lane(palette.arcLandBridge);\n case 'horizontal-pass':\n return style.lane(palette.horizontalPass);\n case 'empty':\n return ' ';\n }\n}\n\nfunction renderConnectorRow(\n row: MigrationGraphGridRow,\n gridWidth: number,\n style: MigrationListStyler,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n const isMerge = row.kind === 'merge-connector';\n if (row.cells.length > 0) {\n let seenTee = false;\n let out = '';\n for (const cell of row.cells) {\n switch (cell.kind) {\n case 'branch-tee':\n out += style.lane(seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee);\n seenTee = true;\n break;\n case 'merge-tee':\n out += style.lane(seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee);\n seenTee = true;\n break;\n case 'branch-corner':\n out += style.lane(palette.branchCorner);\n break;\n case 'merge-corner':\n out += style.lane(palette.mergeCorner);\n break;\n case 'vertical-pass':\n out += style.lane(palette.verticalPass);\n break;\n case 'horizontal-pass':\n out += style.lane(palette.horizontalPass);\n break;\n default:\n out += ' ';\n }\n }\n // The cells array is sized to the grid width at emit time; a back-arc lane\n // allocated by a later row can push the grid wider afterwards, so pad any\n // trailing columns rather than dropping the lanes that pass through here.\n for (let column = row.cells.length; column < gridWidth; column++) {\n out += ' ';\n }\n return out;\n }\n\n const start = row.startLane ?? 0;\n const end = row.endLane ?? start;\n let out = '';\n for (let column = 0; column < gridWidth; column++) {\n if (column < start || column > end) out += ' ';\n else if (column === start) out += style.lane(palette.connectorBranchTee);\n else if (column === end)\n out += style.lane(isMerge ? palette.mergeCorner : palette.branchCorner);\n else out += style.lane(isMerge ? palette.connectorMergeTeeCo : palette.connectorBranchTeeCo);\n }\n return out;\n}\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\nconst MIN_HASH_DATA_COLUMN = 25;\n\nfunction overlayNamesForContract(\n contractHash: string,\n opts: RenderMigrationGraphTreeOptions,\n): readonly string[] {\n const names: string[] = [];\n const userRefs = opts.refsByHash?.get(contractHash);\n if (userRefs) {\n names.push(...[...userRefs].sort((a, b) => a.localeCompare(b)));\n }\n if (opts.dbHash === contractHash) {\n names.push(DB_MARKER_NAME);\n }\n if (opts.contractHash === contractHash && contractHash !== EMPTY_CONTRACT_HASH) {\n names.push(CONTRACT_MARKER_NAME);\n }\n return names;\n}\n\nfunction createTreeStyler(opts: RenderMigrationGraphTreeOptions): MigrationListStyler {\n const base = 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 formatEdgeHashColumn(\n edge: ClassifiedEdge,\n style: MigrationListStyler,\n hashLength: number,\n palette: MigrationGraphTreeGlyphPalette,\n): string {\n if (edge.kind === 'self') {\n const hash = abbreviateHash(edge.from, hashLength, palette.emptySource);\n return `${style.sourceHash(hash)} ${style.glyph(palette.forwardArrow)} ${style.destHash(hash)}`;\n }\n const source =\n edge.from === EMPTY_CONTRACT_HASH\n ? style.glyph(palette.emptySource) +\n ' '.repeat(Math.max(0, hashLength - palette.emptySource.length))\n : style.sourceHash(abbreviateHash(edge.from, hashLength, palette.emptySource));\n const arrow = style.glyph(palette.forwardArrow);\n const dest = style.destHash(abbreviateHash(edge.to, hashLength, palette.emptySource));\n return `${source} ${arrow} ${dest}`;\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\nfunction gridWidthForModel(rows: readonly MigrationGraphGridRow[]): number {\n return rows.reduce(\n (max, row) =>\n row.kind === 'node' || row.kind === 'edge' ? Math.max(max, row.cells.length) : max,\n 1,\n );\n}\n\nfunction maxDirNameLength(edges: readonly ClassifiedEdge[]): number {\n if (edges.length === 0) return 0;\n return Math.max(...edges.map((edge) => edge.dirName.length));\n}\n\nfunction rowDirNameWidth(labelColumn: number, maxDirNameLen: number, dirNameGap: number): number {\n return Math.max(maxDirNameLen + dirNameGap, MIN_HASH_DATA_COLUMN - labelColumn);\n}\n\nfunction gridUsesSkipRollbackArcs(rows: readonly MigrationGraphGridRow[]): boolean {\n return rows.some((row) =>\n row.cells.some(\n (cell) => cell.kind === 'edge-lane' && cell.adjacency === 'node-skipping-rollback',\n ),\n );\n}\n\nfunction edgeLabelColumn(row: MigrationGraphGridRow, wideLabelColumn: number | undefined): number {\n if (wideLabelColumn !== undefined) {\n return wideLabelColumn;\n }\n const laneIndex = row.laneIndex ?? 0;\n if (row.edge?.from === EMPTY_CONTRACT_HASH && laneIndex === 0) {\n return (laneIndex + 1) * 2 + LABEL_GAP;\n }\n const usesFullRowGutter = row.cells.some(\n (cell, index) => index > laneIndex && cell.kind === 'vertical-pass',\n );\n return usesFullRowGutter ? row.cells.length * 2 + LABEL_GAP : (laneIndex + 1) * 2 + LABEL_GAP;\n}\n\nfunction nodeHasArcDecoration(row: MigrationGraphGridRow): boolean {\n return row.cells.some(\n (cell) => cell.kind === 'node' && (cell.arcTee === true || cell.arcLand === true),\n );\n}\n\nexport function renderMigrationGraphTree(\n model: MigrationGraphGridModel,\n opts: RenderMigrationGraphTreeOptions,\n): string {\n const glyphMode = opts.glyphMode ?? 'unicode';\n const palette = paletteFor(glyphMode);\n const style = createTreeStyler(opts);\n const hashLength = opts.hashLength ?? MIGRATION_LIST_HASH_WIDTH;\n const gridWidth = gridWidthForModel(model.rows);\n const wideLabelColumn = gridUsesSkipRollbackArcs(model.rows) ? gridWidth * 2 + 4 : undefined;\n const dirNameGap = wideLabelColumn !== undefined ? 3 : LABEL_GAP;\n const allEdges = model.rows\n .filter(\n (row): row is MigrationGraphGridRow & { edge: ClassifiedEdge } =>\n row.kind === 'edge' && row.edge !== undefined,\n )\n .map((row) => row.edge);\n const maxDirNameLen = maxDirNameLength(allEdges);\n\n const lines: string[] = [];\n\n for (let rowIndex = 0; rowIndex < model.rows.length; rowIndex++) {\n const row = model.rows[rowIndex];\n if (row === undefined) continue;\n\n if (row.kind === 'component-separator') {\n lines.push('');\n continue;\n }\n\n if (row.kind === 'branch-connector' || row.kind === 'merge-connector') {\n lines.push(renderConnectorRow(row, gridWidth, style, palette).replace(/\\s+$/, ''));\n continue;\n }\n\n let gutter = row.cells.map((cell) => renderCellPair(cell, style, palette)).join('');\n const prevRow = model.rows[rowIndex - 1];\n let laneSpan = row.cells.length;\n if (row.kind === 'node') {\n const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;\n if (prevRow?.kind === 'merge-connector' || contractHash === EMPTY_CONTRACT_HASH) {\n laneSpan = 1;\n } else {\n laneSpan = row.cells.length;\n }\n }\n const labelColumn =\n row.kind === 'edge'\n ? edgeLabelColumn(row, wideLabelColumn)\n : wideLabelColumn !== undefined &&\n (nodeHasArcDecoration(row) || row.contractHash !== undefined)\n ? wideLabelColumn\n : laneSpan * 2 + LABEL_GAP;\n if (\n row.kind === 'edge' &&\n row.edge?.from === EMPTY_CONTRACT_HASH &&\n (row.laneIndex ?? 0) === 0\n ) {\n gutter = row.cells\n .slice(0, 1)\n .map((cell) => renderCellPair(cell, style, palette))\n .join('');\n } else if (row.kind === 'node' && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) {\n gutter = row.cells\n .slice(0, laneSpan)\n .map((cell) => renderCellPair(cell, style, palette))\n .join('');\n } else if (gutter.length < laneSpan * 2) {\n gutter = gutter.padEnd(laneSpan * 2, ' ');\n }\n const dirNameWidth = rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);\n const dataColumn = labelColumn + dirNameWidth;\n const gutterPad = padVisible(gutter, labelColumn);\n\n if (row.kind === 'node') {\n const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;\n if (contractHash === EMPTY_CONTRACT_HASH) {\n const trailingLanes = row.cells\n .slice(1)\n .map((cell) => renderCellPair(cell, style, palette))\n .join('');\n const emptyGutter = palette.emptySource.padEnd(2, ' ') + trailingLanes;\n const overlayNames = overlayNamesForContract(contractHash, opts);\n if (overlayNames.length === 0) {\n lines.push(emptyGutter.replace(/\\s+$/, ''));\n continue;\n }\n const overlay = style.refs(overlayNames);\n lines.push(`${padVisible(emptyGutter, dataColumn)}${overlay}`.replace(/\\s+$/, ''));\n continue;\n }\n const hashText = style.sourceHash(\n abbreviateHash(contractHash, hashLength, palette.emptySource),\n );\n const overlayNames = overlayNamesForContract(contractHash, opts);\n const overlayPad =\n overlayNames.length > 0\n ? ' '.repeat(Math.max(0, dataColumn - labelColumn - stringWidth(hashText)))\n : '';\n const overlay = overlayNames.length > 0 ? style.refs(overlayNames) : '';\n lines.push(`${gutterPad}${hashText}${overlayPad}${overlay}`.replace(/\\s+$/, ''));\n continue;\n }\n\n const edge = row.edge;\n if (edge === undefined) continue;\n\n const dirNamePadding = ' '.repeat(Math.max(0, dirNameWidth - edge.dirName.length));\n const dirName = `${style.dirName(edge.dirName)}${dirNamePadding}`;\n const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);\n lines.push(`${gutterPad}${dirName}${hashColumn}`.replace(/\\s+$/, ''));\n }\n\n return lines.join('\\n');\n}\n","import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { buildMigrationGraphLayout } from '../utils/formatters/migration-graph-layout';\nimport { buildMigrationGraphRows } from '../utils/formatters/migration-graph-rows';\nimport { renderMigrationGraphTree } from '../utils/formatters/migration-graph-tree-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationGraphOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly dot?: boolean;\n readonly tree?: boolean;\n readonly ascii?: boolean;\n}\n\nexport interface MigrationGraphResult {\n readonly ok: true;\n readonly graph: MigrationGraph;\n readonly contractHash: string | null;\n readonly refs: readonly StatusRef[];\n readonly summary: string;\n}\n\nexport async function executeMigrationGraphCommand(\n options: MigrationGraphOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationGraphResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration graph',\n description: 'Show the migration graph topology',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return loaded;\n }\n\n const { aggregate, contractHash } = loaded.value;\n const graph = aggregate.app.graph();\n const refs: readonly StatusRef[] = Object.entries(aggregate.app.refs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: false,\n }));\n\n return ok({\n ok: true,\n graph,\n contractHash,\n refs,\n summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`,\n });\n}\n\nexport function createMigrationGraphCommand(): Command {\n const command = new Command('graph');\n setCommandDescriptions(\n command,\n 'Show the migration graph topology',\n 'Renders the migration graph topology. Offline — does not consult\\n' +\n 'the database. Use --tree for the condensed annotated tree\\n' +\n '(--ascii swaps box-drawing for pipe-friendly ASCII glyphs),\\n' +\n '--json for machine-readable output, or --dot for Graphviz DOT\\n' +\n 'format.',\n );\n setCommandExamples(command, [\n 'prisma-next migration graph',\n 'prisma-next migration graph --json',\n 'prisma-next migration graph --dot',\n 'prisma-next migration graph --tree',\n 'prisma-next migration graph --tree --ascii',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dot', 'Output in Graphviz DOT format')\n .option('--tree', 'Experimental condensed annotated tree renderer')\n .option('--ascii', 'Use ASCII glyphs for --tree (pipe-friendly)')\n .action(async (options: MigrationGraphOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationGraphCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (graphResult) => {\n // Explicit format flags win over the auto-JSON default. `flags.json`\n // is auto-enabled when stdout is non-TTY (per CLI Style Guide §\n // JSON Semantics); without this ordering, `migration graph --dot |\n // dot -Tsvg` pipes JSON into the GraphViz binary, which then\n // errors. `--dot` is the more specific instruction; honour it.\n if (options.dot) {\n const lines = ['digraph migrations {'];\n for (const edge of graphResult.graph.migrationByHash.values()) {\n const from = edge.from.slice(0, 12);\n const to = edge.to.slice(0, 12);\n lines.push(` \"${from}\" -> \"${to}\" [label=\"${edge.dirName}\"];`);\n }\n lines.push('}');\n ui.output(lines.join('\\n'));\n } else if (flags.json) {\n const nodes = [...graphResult.graph.nodes];\n const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({\n dirName: e.dirName,\n from: e.from,\n to: e.to,\n migrationHash: e.migrationHash,\n }));\n ui.output(\n JSON.stringify({ ok: true, nodes, edges, summary: graphResult.summary }, null, 2),\n );\n } else if (!flags.quiet) {\n if (options.tree) {\n const refsByHash = new Map<string, string[]>();\n for (const ref of graphResult.refs) {\n const existing = refsByHash.get(ref.hash);\n refsByHash.set(ref.hash, existing ? [...existing, ref.name] : [ref.name]);\n }\n const rowModel = buildMigrationGraphRows(graphResult.graph, {\n ...(graphResult.contractHash !== null\n ? { contractHash: graphResult.contractHash }\n : {}),\n });\n const layout = buildMigrationGraphLayout(rowModel);\n const activeRef = graphResult.refs.find((ref) => ref.active);\n const treeOutput = renderMigrationGraphTree(layout, {\n refsByHash,\n ...(graphResult.contractHash !== null\n ? { contractHash: graphResult.contractHash }\n : {}),\n ...(activeRef !== undefined ? { activeRefName: activeRef.name } : {}),\n colorize: flags.color !== false,\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n });\n // Emit the rendered tree to stdout (same stream as flat `migration list`),\n // not through clack's `log.message` rail: the graph is the command's\n // result (and its own box-drawing is the only vertical structure it\n // should carry), not a status line that needs the prompt gutter.\n ui.output(treeOutput);\n ui.output(`\\n${graphResult.summary}`);\n } else {\n const renderInput = migrationGraphToRenderInput({\n graph: graphResult.graph,\n mode: 'offline',\n markerHash: undefined,\n contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,\n refs: graphResult.refs,\n activeRefHash: undefined,\n activeRefName: undefined,\n edgeStatuses: [],\n });\n const graphOutput = graphRenderer.render(renderInput.graph, {\n ...renderInput.options,\n colorize: flags.color !== false,\n });\n ui.log(graphOutput);\n ui.log(`\\n${graphResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|