prisma-next 0.12.0-dev.2 → 0.12.0-dev.20
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 +177 -160
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-KgJorIvG.mjs → client-Cdxcme1x.mjs} +21 -8
- package/dist/client-Cdxcme1x.mjs.map +1 -0
- package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-Cmdqyhz9.mjs} +32 -2
- package/dist/{command-helpers-Bbw1GbwL.mjs.map → command-helpers-Cmdqyhz9.mjs.map} +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +4 -4
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.mjs +4 -4
- package/dist/commands/db-update.mjs +5 -5
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.mjs +5 -5
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.d.mts +23 -5
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -2
- package/dist/commands/migration-list.d.mts +3 -3
- package/dist/commands/migration-list.mjs +3 -3
- package/dist/commands/migration-log.d.mts +3 -3
- package/dist/commands/migration-log.mjs +3 -3
- package/dist/commands/migration-new.mjs +3 -3
- package/dist/commands/migration-plan.d.mts +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +3 -3
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.mjs +4 -4
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +2 -2
- package/dist/commands/telemetry/index.d.mts +7 -0
- package/dist/commands/telemetry/index.d.mts.map +1 -0
- package/dist/commands/telemetry/index.mjs +2 -0
- package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-Cz0z5PJi.mjs} +2 -2
- package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-Cz0z5PJi.mjs.map} +1 -1
- package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-CC9jDOmu.mjs} +3 -3
- package/dist/{contract-emit-D-4jrNve.mjs.map → contract-emit-CC9jDOmu.mjs.map} +1 -1
- package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-DPMij44i.mjs} +3 -3
- package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-DPMij44i.mjs.map} +1 -1
- package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-DaFPNrZH.mjs} +3 -3
- package/dist/{contract-infer-D8uEbJuu.mjs.map → contract-infer-DaFPNrZH.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-CirAEsM8.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-CirAEsM8.mjs.map} +1 -1
- package/dist/{db-verify-v_vUKXTU.mjs → db-verify-BSA1a_W_.mjs} +4 -4
- package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-BSA1a_W_.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-fYXjz_in.mjs → framework-components-DynSvww4.mjs} +2 -2
- package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-DynSvww4.mjs.map} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-DG4uY5tV.d.mts} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-DG4uY5tV.d.mts.map} +1 -1
- package/dist/{init-Cv9UzWL5.mjs → init-B6kKrmf7.mjs} +5 -58
- package/dist/init-B6kKrmf7.mjs.map +1 -0
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-Dn56wDhG.mjs} +3 -3
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs.map → inspect-live-schema-Dn56wDhG.mjs.map} +1 -1
- package/dist/{migration-check-BiBJoYYW.mjs → migration-check-DzH1u-O1.mjs} +2 -2
- package/dist/{migration-check-BiBJoYYW.mjs.map → migration-check-DzH1u-O1.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-V52dV2Tv.mjs} +3 -3
- package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-V52dV2Tv.mjs.map} +1 -1
- package/dist/{migration-graph-D7DVUElV.mjs → migration-graph-DKl_IYsF.mjs} +377 -85
- package/dist/migration-graph-DKl_IYsF.mjs.map +1 -0
- package/dist/{migration-list-styler-BRwF4-gy.mjs → migration-list-styler-COQbZmXk.mjs} +61 -46
- package/dist/migration-list-styler-COQbZmXk.mjs.map +1 -0
- package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-CaeKCKp4.mjs} +5 -5
- package/dist/{migration-plan-9DJ7q7_z.mjs.map → migration-plan-CaeKCKp4.mjs.map} +1 -1
- package/dist/{migration-types-D2FW63pr.d.mts → migration-types-CAQ-0TEE.d.mts} +1 -1
- package/dist/{migration-types-D2FW63pr.d.mts.map → migration-types-CAQ-0TEE.d.mts.map} +1 -1
- package/dist/{migrations-Cv2jxNNK.mjs → migrations-DQ1t3XFL.mjs} +2 -2
- package/dist/{migrations-Cv2jxNNK.mjs.map → migrations-DQ1t3XFL.mjs.map} +1 -1
- package/dist/{output-B60Gw5fu.mjs → output-CF_hqzI-.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-CF_hqzI-.mjs.map} +1 -1
- package/dist/telemetry-Q88WHwlv.mjs +122 -0
- package/dist/telemetry-Q88WHwlv.mjs.map +1 -0
- package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-C3xGyxW-.d.mts} +1 -1
- package/dist/{terminal-ui-5Y6mrg93.d.mts.map → terminal-ui-C3xGyxW-.d.mts.map} +1 -1
- package/dist/{types-Dt_SfqFm.d.mts → types-DiC683UW.d.mts} +8 -2
- package/dist/{types-Dt_SfqFm.d.mts.map → types-DiC683UW.d.mts.map} +1 -1
- package/dist/{verify-DCA9Sldu.mjs → verify-CreSJ1Mz.mjs} +2 -2
- package/dist/{verify-DCA9Sldu.mjs.map → verify-CreSJ1Mz.mjs.map} +1 -1
- package/package.json +11 -11
- package/dist/client-KgJorIvG.mjs.map +0 -1
- package/dist/init-Cv9UzWL5.mjs.map +0 -1
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { r as buildReadAggregate } from "./contract-space-aggregate-loader-
|
|
2
|
+
import { E as formatStyledHeader, _ as parseGlobalFlagsOrExit, b as handleResult, d as setCommandSeeAlso, l as setCommandDescriptions, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "./command-helpers-Cmdqyhz9.mjs";
|
|
3
|
+
import { r as buildReadAggregate } from "./contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
4
4
|
import { i as migrationGraphToRenderInput, n as graphRenderer } from "./graph-render-rFAqZujX.mjs";
|
|
5
|
-
import { a as migrationListEmptySource, n as createAnsiMigrationListStyler, o as migrationListForwardArrow, s as classifyMigrationGraphTopology, t as CONTRACT_MARKER_NAME } from "./migration-list-styler-
|
|
5
|
+
import { a as migrationListEmptySource, n as createAnsiMigrationListStyler, o as migrationListForwardArrow, s as classifyMigrationGraphTopology, t as CONTRACT_MARKER_NAME } from "./migration-list-styler-COQbZmXk.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
|
|
@@ -171,7 +171,7 @@ function classifyEdgeAdjacency(edge, position) {
|
|
|
171
171
|
function emptyCells(width) {
|
|
172
172
|
return Array.from({ length: width }, () => ({ kind: "empty" }));
|
|
173
173
|
}
|
|
174
|
-
function buildBranchConnectorCells(startLane, endLane, activeLanes, gridWidth) {
|
|
174
|
+
function buildBranchConnectorCells(startLane, endLane, fanTargetLanes, activeLanes, gridWidth) {
|
|
175
175
|
const cells = emptyCells(gridWidth);
|
|
176
176
|
for (let lane = 0; lane < gridWidth; lane++) {
|
|
177
177
|
if (activeLanes.has(lane) && (lane < startLane || lane > endLane)) {
|
|
@@ -180,11 +180,13 @@ function buildBranchConnectorCells(startLane, endLane, activeLanes, gridWidth) {
|
|
|
180
180
|
}
|
|
181
181
|
if (lane === startLane) cells[lane] = { kind: "branch-tee" };
|
|
182
182
|
else if (lane === endLane) cells[lane] = { kind: "branch-corner" };
|
|
183
|
-
else if (lane > startLane && lane < endLane) cells[lane] = { kind: "branch-tee" };
|
|
183
|
+
else if (lane > startLane && lane < endLane) if (fanTargetLanes.has(lane)) cells[lane] = { kind: "branch-tee" };
|
|
184
|
+
else if (activeLanes.has(lane)) cells[lane] = { kind: "arc-crossing" };
|
|
185
|
+
else cells[lane] = { kind: "branch-tee" };
|
|
184
186
|
}
|
|
185
187
|
return cells;
|
|
186
188
|
}
|
|
187
|
-
function buildMergeConnectorCells(startLane, endLane, activeLanes, gridWidth) {
|
|
189
|
+
function buildMergeConnectorCells(startLane, endLane, fanTargetLanes, activeLanes, gridWidth) {
|
|
188
190
|
const cells = emptyCells(gridWidth);
|
|
189
191
|
for (let lane = 0; lane < gridWidth; lane++) {
|
|
190
192
|
if (activeLanes.has(lane) && (lane < startLane || lane > endLane)) {
|
|
@@ -193,7 +195,9 @@ function buildMergeConnectorCells(startLane, endLane, activeLanes, gridWidth) {
|
|
|
193
195
|
}
|
|
194
196
|
if (lane === startLane) cells[lane] = { kind: "merge-tee" };
|
|
195
197
|
else if (lane === endLane) cells[lane] = { kind: "merge-corner" };
|
|
196
|
-
else if (lane > startLane && lane < endLane)
|
|
198
|
+
else if (lane > startLane && lane < endLane) if (fanTargetLanes.has(lane)) cells[lane] = { kind: "merge-tee" };
|
|
199
|
+
else if (activeLanes.has(lane)) cells[lane] = { kind: "arc-crossing" };
|
|
200
|
+
else cells[lane] = { kind: "horizontal-pass" };
|
|
197
201
|
}
|
|
198
202
|
return cells;
|
|
199
203
|
}
|
|
@@ -358,6 +362,8 @@ function applySkipRollbackRouting(rows, skipRollbacks, position, nodeColumn, edg
|
|
|
358
362
|
edgeColumn.set(edge.migrationHash, backLane);
|
|
359
363
|
const coSourcedLanes = routes.filter((other) => other.edge.from === edge.from).map((other) => other.backLane);
|
|
360
364
|
const maxCoSourcedLane = Math.max(...coSourcedLanes);
|
|
365
|
+
const coLandingLanes = routes.filter((other) => other.edge.to === edge.to).map((other) => other.backLane);
|
|
366
|
+
const maxCoLandingLane = Math.max(...coLandingLanes);
|
|
361
367
|
const sourceRow = result[sourceRowIndex];
|
|
362
368
|
if (sourceRow !== void 0) {
|
|
363
369
|
const cells = sourceRow.cells;
|
|
@@ -402,7 +408,7 @@ function applySkipRollbackRouting(rows, skipRollbacks, position, nodeColumn, edg
|
|
|
402
408
|
const cells = row.cells;
|
|
403
409
|
ensureCellWidth(cells, backLane + 1);
|
|
404
410
|
const existing = cells[backLane];
|
|
405
|
-
if (existing?.kind !== "arc-land-corner" && existing?.kind !== "arc-land-bridge" && existing?.kind !== "arc-branch-corner" && existing?.kind !== "arc-branch-tee" && existing?.kind !== "arc-crossing") cells[backLane] = { kind: "vertical-pass" };
|
|
411
|
+
if (existing?.kind !== "arc-land-corner" && existing?.kind !== "arc-land-tee" && existing?.kind !== "arc-land-bridge" && existing?.kind !== "arc-branch-corner" && existing?.kind !== "arc-branch-tee" && existing?.kind !== "arc-crossing") cells[backLane] = { kind: "vertical-pass" };
|
|
406
412
|
}
|
|
407
413
|
const targetRow = result[targetRowIndex];
|
|
408
414
|
if (targetRow !== void 0) {
|
|
@@ -414,16 +420,20 @@ function applySkipRollbackRouting(rows, skipRollbacks, position, nodeColumn, edg
|
|
|
414
420
|
arcLand: true
|
|
415
421
|
};
|
|
416
422
|
for (let lane = targetCol + 1; lane < backLane; lane += 1) {
|
|
423
|
+
if (coLandingLanes.includes(lane)) {
|
|
424
|
+
cells[lane] = { kind: "arc-land-tee" };
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
417
427
|
const existing = cells[lane];
|
|
418
|
-
cells[lane] = existing !== void 0 && existing.kind !== "empty" && existing.kind !== "horizontal-pass" && existing.kind !== "arc-land-bridge" || routes.some((other) => other.edge.migrationHash !== edge.migrationHash && other.backLane === lane && routeCrossesRow(other, targetRowIndex, result)) ? { kind: "arc-crossing" } : { kind: "arc-land-bridge" };
|
|
428
|
+
cells[lane] = existing !== void 0 && existing.kind !== "empty" && existing.kind !== "horizontal-pass" && existing.kind !== "arc-land-bridge" && existing.kind !== "arc-land-tee" || routes.some((other) => other.edge.migrationHash !== edge.migrationHash && other.backLane === lane && routeCrossesRow(other, targetRowIndex, result)) ? { kind: "arc-crossing" } : { kind: "arc-land-bridge" };
|
|
419
429
|
}
|
|
420
|
-
cells[backLane] = { kind: "arc-land-corner" };
|
|
430
|
+
cells[backLane] = backLane < maxCoLandingLane ? { kind: "arc-land-tee" } : { kind: "arc-land-corner" };
|
|
421
431
|
for (const other of routes) {
|
|
422
432
|
if (other.backLane <= backLane) continue;
|
|
423
433
|
if (!routeCrossesRow(other, targetRowIndex, result)) continue;
|
|
424
434
|
ensureCellWidth(cells, other.backLane + 1);
|
|
425
435
|
const existing = cells[other.backLane];
|
|
426
|
-
if (existing?.kind !== "arc-land-corner" && existing?.kind !== "arc-land-bridge" && existing?.kind !== "node") cells[other.backLane] = { kind: "vertical-pass" };
|
|
436
|
+
if (existing?.kind !== "arc-land-corner" && existing?.kind !== "arc-land-tee" && existing?.kind !== "arc-land-bridge" && existing?.kind !== "node") cells[other.backLane] = { kind: "vertical-pass" };
|
|
427
437
|
}
|
|
428
438
|
}
|
|
429
439
|
}
|
|
@@ -504,18 +514,19 @@ function layoutComponent(componentNodes, allEdges) {
|
|
|
504
514
|
const endLane = Math.max(...laneIndices);
|
|
505
515
|
ensureGridWidth(endLane + 1);
|
|
506
516
|
const activeLanes = new Set(activeLaneIndices());
|
|
517
|
+
const fanTargetLanes = new Set(laneIndices);
|
|
507
518
|
rows.push({
|
|
508
519
|
kind: "merge-connector",
|
|
509
520
|
contractHash,
|
|
510
521
|
startLane,
|
|
511
522
|
endLane,
|
|
512
523
|
branchCount: laneIndices.length,
|
|
513
|
-
cells: buildMergeConnectorCells(startLane, endLane, activeLanes, gridWidth)
|
|
524
|
+
cells: buildMergeConnectorCells(startLane, endLane, fanTargetLanes, activeLanes, gridWidth)
|
|
514
525
|
});
|
|
515
526
|
for (const index of laneIndices) if (index !== startLane) setLane(index, null);
|
|
516
527
|
return startLane;
|
|
517
528
|
}
|
|
518
|
-
function emitBranchConnector(contractHash, startLane, endLane, branchCount) {
|
|
529
|
+
function emitBranchConnector(contractHash, startLane, endLane, branchCount, fanTargetLanes) {
|
|
519
530
|
ensureGridWidth(endLane + 1);
|
|
520
531
|
const activeLanes = new Set(activeLaneIndices());
|
|
521
532
|
rows.push({
|
|
@@ -524,7 +535,7 @@ function layoutComponent(componentNodes, allEdges) {
|
|
|
524
535
|
startLane,
|
|
525
536
|
endLane,
|
|
526
537
|
branchCount,
|
|
527
|
-
cells: buildBranchConnectorCells(startLane, endLane, activeLanes, gridWidth)
|
|
538
|
+
cells: buildBranchConnectorCells(startLane, endLane, new Set(fanTargetLanes), activeLanes, gridWidth)
|
|
528
539
|
});
|
|
529
540
|
}
|
|
530
541
|
function emitEdgeRow(edge, lane, convergenceProducer) {
|
|
@@ -597,7 +608,7 @@ function layoutComponent(componentNodes, allEdges) {
|
|
|
597
608
|
}
|
|
598
609
|
if (groups.length >= 2) {
|
|
599
610
|
const endLane = Math.max(...laneForGroup);
|
|
600
|
-
emitBranchConnector(node, column, endLane, groups.length);
|
|
611
|
+
emitBranchConnector(node, column, endLane, groups.length, laneForGroup);
|
|
601
612
|
}
|
|
602
613
|
for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
|
603
614
|
const group = groups[groupIndex];
|
|
@@ -835,6 +846,30 @@ function buildMigrationGraphRows(graph, options = {}) {
|
|
|
835
846
|
};
|
|
836
847
|
}
|
|
837
848
|
//#endregion
|
|
849
|
+
//#region src/utils/formatters/migration-graph-lane-colors.ts
|
|
850
|
+
const { magenta: magenta$1, cyan: cyan$1, green: green$1, yellow: yellow$1, blueBright, red: red$1 } = createColors({ useColor: true });
|
|
851
|
+
const LANE_COLOR_CYCLE = [
|
|
852
|
+
magenta$1,
|
|
853
|
+
cyan$1,
|
|
854
|
+
green$1,
|
|
855
|
+
yellow$1,
|
|
856
|
+
blueBright,
|
|
857
|
+
red$1
|
|
858
|
+
];
|
|
859
|
+
/**
|
|
860
|
+
* The hue for a gutter column. The leftmost lane (column 0) is **neutral** — it
|
|
861
|
+
* has nothing to be told apart from in the common single-lane linear case, so
|
|
862
|
+
* the renderer dims it rather than tinting it; the rotating palette is reserved
|
|
863
|
+
* for columns ≥ 1 (where a second lane exists to distinguish). Callers must dim
|
|
864
|
+
* column 0 themselves; this returns identity for it as a guard. A lane freed and
|
|
865
|
+
* reused by a later branch keeps its column's hue — coloring is by position, not
|
|
866
|
+
* branch identity, exactly like `git log --graph`.
|
|
867
|
+
*/
|
|
868
|
+
function laneColorForColumn(column) {
|
|
869
|
+
if (column <= 0) return (text) => text;
|
|
870
|
+
return LANE_COLOR_CYCLE[(column - 1) % LANE_COLOR_CYCLE.length] ?? ((text) => text);
|
|
871
|
+
}
|
|
872
|
+
//#endregion
|
|
838
873
|
//#region src/utils/formatters/migration-graph-tree-render.ts
|
|
839
874
|
const LABEL_GAP = 2;
|
|
840
875
|
/**
|
|
@@ -855,6 +890,7 @@ const UNICODE_PALETTE = {
|
|
|
855
890
|
arcBranchCorner: "╮ ",
|
|
856
891
|
arcBranchTee: "┬─",
|
|
857
892
|
arcLandCorner: "╯ ",
|
|
893
|
+
arcLandTee: "┴─",
|
|
858
894
|
arcCrossing: "┼─",
|
|
859
895
|
arcLandBridge: "──",
|
|
860
896
|
horizontalPass: "──",
|
|
@@ -881,6 +917,7 @@ const ASCII_PALETTE = {
|
|
|
881
917
|
arcBranchCorner: "\\ ",
|
|
882
918
|
arcBranchTee: "+-",
|
|
883
919
|
arcLandCorner: "/ ",
|
|
920
|
+
arcLandTee: "+-",
|
|
884
921
|
arcCrossing: "+-",
|
|
885
922
|
arcLandBridge: "--",
|
|
886
923
|
horizontalPass: "--",
|
|
@@ -902,74 +939,271 @@ function arrowForEdgeKind(kind, palette) {
|
|
|
902
939
|
return palette.edgeArrow[kind];
|
|
903
940
|
}
|
|
904
941
|
/**
|
|
942
|
+
* The leftmost lane (column 0) renders with the neutral dim lane style rather
|
|
943
|
+
* than a palette hue — in the common single-lane case it has nothing to be told
|
|
944
|
+
* apart from. Used as the "no owning arc" sentinel during colour resolution.
|
|
945
|
+
*/
|
|
946
|
+
const NEUTRAL_LANE = 0;
|
|
947
|
+
/**
|
|
948
|
+
* Forced bold for branch-coloured names. A branched name pairs its lane hue
|
|
949
|
+
* (also forced, via {@link laneColorForColumn}) with bold; both must emit even
|
|
950
|
+
* when colorette's ambient TTY detection is off, so the colorized branch name
|
|
951
|
+
* is deterministically bold + hue rather than hue-only.
|
|
952
|
+
*/
|
|
953
|
+
const { bold: forcedBold } = createColors({ useColor: true });
|
|
954
|
+
/**
|
|
955
|
+
* Resolve per-cell colour columns for a row. Scanning right-to-left lets each
|
|
956
|
+
* arc segment inherit the hue of the arc it leads into.
|
|
957
|
+
*
|
|
958
|
+
* On a converging-landing line (`○◂──────┴─┴─╯`), every horizontal dash segment
|
|
959
|
+
* takes the hue of the **nearest landing anchor** — the next `arc-land-tee` or
|
|
960
|
+
* `arc-land-corner` — to its right, i.e. the branch it leads into: the bridge
|
|
961
|
+
* run leads into the first converging arc, and each tee's trailing `─` leads
|
|
962
|
+
* into the next arc out. Tee/corner junction glyphs keep their own column hue.
|
|
963
|
+
* This mirrors the forward connector's `┬─` rule (see
|
|
964
|
+
* {@link resolveConnectorLaneColors}). A single (non-converging) landing has
|
|
965
|
+
* only the corner as an anchor, so its whole horizontal run reads as one hue.
|
|
966
|
+
*
|
|
967
|
+
* The source side (`○─`, `arc-branch-tee`, `arc-branch-corner`) and pure
|
|
968
|
+
* horizontal passes are unaffected: they track the nearest corner to the right
|
|
969
|
+
* (`arcCorner`), so a routed back-arc's source fan still reads as one hue. A
|
|
970
|
+
* crossing can only be one colour, so it takes the arc owning the horizontal
|
|
971
|
+
* run at this row; the crossed vertical lane is occluded at that one cell and
|
|
972
|
+
* reappears on the next row.
|
|
973
|
+
*/
|
|
974
|
+
function resolveRowLaneColors(cells) {
|
|
975
|
+
const lane = new Array(cells.length);
|
|
976
|
+
const connector = new Array(cells.length);
|
|
977
|
+
const dash = new Array(cells.length);
|
|
978
|
+
let arcCorner = NEUTRAL_LANE;
|
|
979
|
+
let landingAnchor = NEUTRAL_LANE;
|
|
980
|
+
for (let column = cells.length - 1; column >= 0; column--) {
|
|
981
|
+
const cell = cells[column];
|
|
982
|
+
connector[column] = landingAnchor !== NEUTRAL_LANE ? landingAnchor : arcCorner;
|
|
983
|
+
switch (cell?.kind) {
|
|
984
|
+
case "arc-branch-corner":
|
|
985
|
+
arcCorner = column;
|
|
986
|
+
lane[column] = column;
|
|
987
|
+
dash[column] = column;
|
|
988
|
+
break;
|
|
989
|
+
case "arc-land-corner":
|
|
990
|
+
arcCorner = column;
|
|
991
|
+
landingAnchor = column;
|
|
992
|
+
lane[column] = column;
|
|
993
|
+
dash[column] = column;
|
|
994
|
+
break;
|
|
995
|
+
case "arc-branch-tee":
|
|
996
|
+
lane[column] = column;
|
|
997
|
+
dash[column] = column;
|
|
998
|
+
break;
|
|
999
|
+
case "arc-land-tee":
|
|
1000
|
+
lane[column] = column;
|
|
1001
|
+
dash[column] = landingAnchor === NEUTRAL_LANE ? column : landingAnchor;
|
|
1002
|
+
landingAnchor = column;
|
|
1003
|
+
break;
|
|
1004
|
+
case "arc-crossing":
|
|
1005
|
+
case "arc-land-bridge": {
|
|
1006
|
+
const served = landingAnchor !== NEUTRAL_LANE ? landingAnchor : arcCorner;
|
|
1007
|
+
lane[column] = served;
|
|
1008
|
+
dash[column] = served;
|
|
1009
|
+
break;
|
|
1010
|
+
}
|
|
1011
|
+
case "horizontal-pass":
|
|
1012
|
+
lane[column] = arcCorner === NEUTRAL_LANE ? column : arcCorner;
|
|
1013
|
+
dash[column] = lane[column] ?? column;
|
|
1014
|
+
break;
|
|
1015
|
+
case "node":
|
|
1016
|
+
lane[column] = column;
|
|
1017
|
+
dash[column] = column;
|
|
1018
|
+
arcCorner = NEUTRAL_LANE;
|
|
1019
|
+
landingAnchor = NEUTRAL_LANE;
|
|
1020
|
+
break;
|
|
1021
|
+
default:
|
|
1022
|
+
lane[column] = column;
|
|
1023
|
+
dash[column] = column;
|
|
1024
|
+
arcCorner = NEUTRAL_LANE;
|
|
1025
|
+
landingAnchor = NEUTRAL_LANE;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
return {
|
|
1029
|
+
lane,
|
|
1030
|
+
connector,
|
|
1031
|
+
dash
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Resolve per-cell connector colours. Scanning right-to-left, a corner or an
|
|
1036
|
+
* intermediate tee anchors its own lane (its junction glyph takes that column),
|
|
1037
|
+
* but a tee's **trailing dash leads into the branch on its right** (the next
|
|
1038
|
+
* branch point), so `┬─` reads as "this lane, then on toward the next" rather
|
|
1039
|
+
* than tinting the dash with the left lane. The leading tee at `startLane` (the
|
|
1040
|
+
* fork/merge origin) and pure horizontal segments inherit the nearest branch
|
|
1041
|
+
* point to their right whole-cell, so the run into a branch — or collapsing
|
|
1042
|
+
* into a merge corner — stays continuous. An `arc-crossing` keeps its junction
|
|
1043
|
+
* glyph at its own column but re-anchors `owner` like an intermediate tee so
|
|
1044
|
+
* dashes on both sides lead into the nearest branch on their right. Pass-through
|
|
1045
|
+
* verticals outside the run keep their own column (column 0 stays neutral).
|
|
1046
|
+
*/
|
|
1047
|
+
function resolveConnectorLaneColors(cells, startLane) {
|
|
1048
|
+
const glyph = new Array(cells.length);
|
|
1049
|
+
const dash = new Array(cells.length);
|
|
1050
|
+
let owner = NEUTRAL_LANE;
|
|
1051
|
+
for (let column = cells.length - 1; column >= 0; column--) switch (cells[column]?.kind) {
|
|
1052
|
+
case "branch-corner":
|
|
1053
|
+
case "merge-corner":
|
|
1054
|
+
owner = column;
|
|
1055
|
+
glyph[column] = column;
|
|
1056
|
+
dash[column] = column;
|
|
1057
|
+
break;
|
|
1058
|
+
case "branch-tee":
|
|
1059
|
+
case "merge-tee":
|
|
1060
|
+
if (column === startLane) {
|
|
1061
|
+
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
1062
|
+
glyph[column] = column;
|
|
1063
|
+
dash[column] = served;
|
|
1064
|
+
} else {
|
|
1065
|
+
dash[column] = owner === NEUTRAL_LANE ? column : owner;
|
|
1066
|
+
glyph[column] = column;
|
|
1067
|
+
owner = column;
|
|
1068
|
+
}
|
|
1069
|
+
break;
|
|
1070
|
+
case "arc-crossing":
|
|
1071
|
+
glyph[column] = column;
|
|
1072
|
+
dash[column] = owner === NEUTRAL_LANE ? column : owner;
|
|
1073
|
+
owner = column;
|
|
1074
|
+
break;
|
|
1075
|
+
case "horizontal-pass": {
|
|
1076
|
+
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
1077
|
+
glyph[column] = served;
|
|
1078
|
+
dash[column] = served;
|
|
1079
|
+
break;
|
|
1080
|
+
}
|
|
1081
|
+
default:
|
|
1082
|
+
glyph[column] = column;
|
|
1083
|
+
dash[column] = column;
|
|
1084
|
+
}
|
|
1085
|
+
return {
|
|
1086
|
+
glyph,
|
|
1087
|
+
dash
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Style a structural glyph by its resolved colour column. Column 0 and the
|
|
1092
|
+
* neutral sentinel render dim (`style.lane`); columns ≥ 1 take a palette hue.
|
|
1093
|
+
*/
|
|
1094
|
+
function laneStylerForColumn(colorColumn, colorize, style) {
|
|
1095
|
+
if (!colorize || colorColumn <= NEUTRAL_LANE) return (text) => style.lane(text);
|
|
1096
|
+
return laneColorForColumn(colorColumn);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Tint a branch-owned token (direction arrow, migration name) by its edge's
|
|
1100
|
+
* lane so the whole branch row reads in one colour. Column 0 has nothing to be
|
|
1101
|
+
* told apart from in the common linear chain, so it keeps the token's existing
|
|
1102
|
+
* default styling (`fallback`) rather than a palette hue; only lanes ≥ 1 take a
|
|
1103
|
+
* colour. With colour off, the fallback (also colourless) is used unchanged.
|
|
1104
|
+
*/
|
|
1105
|
+
function branchStylerOrDefault(column, colorize, fallback) {
|
|
1106
|
+
if (!colorize || column <= NEUTRAL_LANE) return fallback;
|
|
1107
|
+
return laneColorForColumn(column);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Render a connector tee (`├─` / `┬─` / `┴─`) with its junction glyph and its
|
|
1111
|
+
* trailing dash coloured independently: the junction anchors its own lane while
|
|
1112
|
+
* the dash leads into the branch on its right.
|
|
1113
|
+
*/
|
|
1114
|
+
function renderConnectorTee(pair, glyphColumn, dashColumn, colorize, style) {
|
|
1115
|
+
const glyph = laneStylerForColumn(glyphColumn, colorize, style);
|
|
1116
|
+
if (glyphColumn === dashColumn) return glyph(pair);
|
|
1117
|
+
return glyph(pair.slice(0, 1)) + laneStylerForColumn(dashColumn, colorize, style)(pair.slice(1));
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
905
1120
|
* A node-marker glyph pair (`○◂`, `○─`, `*<`, `*-`) is the contract node
|
|
906
|
-
* marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`).
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
*
|
|
1121
|
+
* marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`). The
|
|
1122
|
+
* marker takes its own lane's hue (so each node visibly belongs to its branch);
|
|
1123
|
+
* the connector follows the arc it belongs to (its owning back-lane hue).
|
|
1124
|
+
* Direction arrows are handled elsewhere — they take their edge's lane hue too.
|
|
910
1125
|
*/
|
|
911
|
-
function renderNodeMarkerPair(pair, style) {
|
|
912
|
-
|
|
1126
|
+
function renderNodeMarkerPair(pair, nodeColumn, arcColumn, colorize, style) {
|
|
1127
|
+
const marker = laneStylerForColumn(nodeColumn, colorize, style);
|
|
1128
|
+
const connector = laneStylerForColumn(arcColumn, colorize, style);
|
|
1129
|
+
return marker(pair.slice(0, 1)) + connector(pair.slice(1));
|
|
913
1130
|
}
|
|
914
|
-
function renderCellPair(cell, style, palette) {
|
|
1131
|
+
function renderCellPair(cell, column, colors, colorize, style, palette) {
|
|
1132
|
+
const laneColumn = colors.lane[column] ?? column;
|
|
1133
|
+
const lane = laneStylerForColumn(laneColumn, colorize, style);
|
|
915
1134
|
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 "
|
|
1135
|
+
case "node": {
|
|
1136
|
+
const arcColumn = colors.connector[column] ?? NEUTRAL_LANE;
|
|
1137
|
+
if (cell.arcLand === true) return renderNodeMarkerPair(palette.arcLand, column, arcColumn, colorize, style);
|
|
1138
|
+
if (cell.arcTee === true) return renderNodeMarkerPair(palette.arcTee, column, arcColumn, colorize, style);
|
|
1139
|
+
return lane(palette.node);
|
|
1140
|
+
}
|
|
1141
|
+
case "vertical-pass": return lane(palette.verticalPass);
|
|
1142
|
+
case "edge-lane": return cell.ownsLabel ? lane(palette.verticalPass.trimEnd()) + branchStylerOrDefault(column, colorize, style.kind)(arrowForEdgeKind(cell.edgeKind, palette)) : lane(palette.verticalPass);
|
|
1143
|
+
case "branch-tee": return lane(palette.branchTee);
|
|
1144
|
+
case "merge-tee": return lane(palette.mergeTee);
|
|
1145
|
+
case "branch-corner": return lane(palette.branchCorner);
|
|
1146
|
+
case "merge-corner": return lane(palette.mergeCorner);
|
|
1147
|
+
case "arc-branch-corner": return lane(palette.arcBranchCorner);
|
|
1148
|
+
case "arc-branch-tee": return lane(palette.arcBranchTee);
|
|
1149
|
+
case "arc-land-corner": return lane(palette.arcLandCorner);
|
|
1150
|
+
case "arc-land-tee": return renderConnectorTee(palette.arcLandTee, laneColumn, colors.dash[column] ?? laneColumn, colorize, style);
|
|
1151
|
+
case "arc-crossing": return lane(palette.arcLandBridge);
|
|
1152
|
+
case "arc-land-bridge": return lane(palette.arcLandBridge);
|
|
1153
|
+
case "horizontal-pass": return lane(palette.horizontalPass);
|
|
932
1154
|
case "empty": return " ";
|
|
933
1155
|
}
|
|
934
1156
|
}
|
|
935
|
-
function renderConnectorRow(row, gridWidth, style, palette) {
|
|
1157
|
+
function renderConnectorRow(row, gridWidth, colorize, style, palette) {
|
|
936
1158
|
const isMerge = row.kind === "merge-connector";
|
|
937
1159
|
if (row.cells.length > 0) {
|
|
1160
|
+
const colors = resolveConnectorLaneColors(row.cells, row.startLane ?? 0);
|
|
938
1161
|
let seenTee = false;
|
|
939
1162
|
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
|
-
|
|
1163
|
+
for (let column = 0; column < row.cells.length; column++) {
|
|
1164
|
+
const cell = row.cells[column];
|
|
1165
|
+
if (cell === void 0) continue;
|
|
1166
|
+
const glyphColumn = colors.glyph[column] ?? column;
|
|
1167
|
+
const dashColumn = colors.dash[column] ?? glyphColumn;
|
|
1168
|
+
const lane = laneStylerForColumn(glyphColumn, colorize, style);
|
|
1169
|
+
switch (cell.kind) {
|
|
1170
|
+
case "branch-tee":
|
|
1171
|
+
out += renderConnectorTee(seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee, glyphColumn, dashColumn, colorize, style);
|
|
1172
|
+
seenTee = true;
|
|
1173
|
+
break;
|
|
1174
|
+
case "merge-tee":
|
|
1175
|
+
out += renderConnectorTee(seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee, glyphColumn, dashColumn, colorize, style);
|
|
1176
|
+
seenTee = true;
|
|
1177
|
+
break;
|
|
1178
|
+
case "branch-corner":
|
|
1179
|
+
out += lane(palette.branchCorner);
|
|
1180
|
+
break;
|
|
1181
|
+
case "merge-corner":
|
|
1182
|
+
out += lane(palette.mergeCorner);
|
|
1183
|
+
break;
|
|
1184
|
+
case "vertical-pass":
|
|
1185
|
+
out += lane(palette.verticalPass);
|
|
1186
|
+
break;
|
|
1187
|
+
case "horizontal-pass":
|
|
1188
|
+
out += lane(palette.horizontalPass);
|
|
1189
|
+
break;
|
|
1190
|
+
case "arc-crossing":
|
|
1191
|
+
out += renderConnectorTee(palette.arcCrossing, glyphColumn, dashColumn, colorize, style);
|
|
1192
|
+
break;
|
|
1193
|
+
default: out += " ";
|
|
1194
|
+
}
|
|
962
1195
|
}
|
|
963
1196
|
for (let column = row.cells.length; column < gridWidth; column++) out += " ";
|
|
964
1197
|
return out;
|
|
965
1198
|
}
|
|
966
1199
|
const start = row.startLane ?? 0;
|
|
967
1200
|
const end = row.endLane ?? start;
|
|
1201
|
+
const runLane = laneStylerForColumn(end, colorize, style);
|
|
968
1202
|
let out = "";
|
|
969
1203
|
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 +=
|
|
1204
|
+
else if (column === start) out += runLane(palette.connectorBranchTee);
|
|
1205
|
+
else if (column === end) out += runLane(isMerge ? palette.mergeCorner : palette.branchCorner);
|
|
1206
|
+
else out += runLane(isMerge ? palette.connectorMergeTeeCo : palette.connectorBranchTeeCo);
|
|
973
1207
|
return out;
|
|
974
1208
|
}
|
|
975
1209
|
function abbreviateHash(hash, hashLength, emptySource) {
|
|
@@ -1008,6 +1242,11 @@ function padVisible(text, targetWidth) {
|
|
|
1008
1242
|
const padding = Math.max(0, targetWidth - stringWidth(text));
|
|
1009
1243
|
return text + " ".repeat(padding);
|
|
1010
1244
|
}
|
|
1245
|
+
const ANSI_ESCAPE = "\x1B";
|
|
1246
|
+
function trimTrailingWhitespace(line) {
|
|
1247
|
+
const trailingSpaceBeforeReset = new RegExp(`[\\t ]+((?:${ANSI_ESCAPE}\\[[0-9;]*m)+)$`);
|
|
1248
|
+
return line.replace(trailingSpaceBeforeReset, "$1").replace(/\s+$/, "");
|
|
1249
|
+
}
|
|
1011
1250
|
function gridWidthForModel(rows) {
|
|
1012
1251
|
return rows.reduce((max, row) => row.kind === "node" || row.kind === "edge" ? Math.max(max, row.cells.length) : max, 1);
|
|
1013
1252
|
}
|
|
@@ -1047,20 +1286,24 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1047
1286
|
continue;
|
|
1048
1287
|
}
|
|
1049
1288
|
if (row.kind === "branch-connector" || row.kind === "merge-connector") {
|
|
1050
|
-
lines.push(renderConnectorRow(row, gridWidth, style, palette)
|
|
1289
|
+
lines.push(trimTrailingWhitespace(renderConnectorRow(row, gridWidth, opts.colorize, style, palette)));
|
|
1051
1290
|
continue;
|
|
1052
1291
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1292
|
+
const cellColors = resolveRowLaneColors(row.cells);
|
|
1293
|
+
let gutter = row.cells.map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1055
1294
|
let laneSpan = row.cells.length;
|
|
1056
|
-
if (row.kind === "node")
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1295
|
+
if (row.kind === "node") if ((row.contractHash ?? EMPTY_CONTRACT_HASH) === EMPTY_CONTRACT_HASH) laneSpan = 1;
|
|
1296
|
+
else {
|
|
1297
|
+
let lastActiveColumn = -1;
|
|
1298
|
+
for (let column = row.cells.length - 1; column >= 0; column--) if (row.cells[column]?.kind !== "empty") {
|
|
1299
|
+
lastActiveColumn = column;
|
|
1300
|
+
break;
|
|
1301
|
+
}
|
|
1302
|
+
laneSpan = lastActiveColumn >= 0 ? lastActiveColumn + 1 : 1;
|
|
1060
1303
|
}
|
|
1061
1304
|
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("");
|
|
1305
|
+
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("");
|
|
1306
|
+
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
1307
|
else if (gutter.length < laneSpan * 2) gutter = gutter.padEnd(laneSpan * 2, " ");
|
|
1065
1308
|
const dirNameWidth = rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);
|
|
1066
1309
|
const dataColumn = labelColumn + dirNameWidth;
|
|
@@ -1068,35 +1311,76 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1068
1311
|
if (row.kind === "node") {
|
|
1069
1312
|
const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;
|
|
1070
1313
|
if (contractHash === EMPTY_CONTRACT_HASH) {
|
|
1071
|
-
const trailingLanes = row.cells.slice(1).map((cell) => renderCellPair(cell, style, palette)).join("");
|
|
1314
|
+
const trailingLanes = row.cells.slice(1).map((cell, offset) => renderCellPair(cell, offset + 1, cellColors, opts.colorize, style, palette)).join("");
|
|
1072
1315
|
const emptyGutter = palette.emptySource.padEnd(2, " ") + trailingLanes;
|
|
1073
1316
|
const overlayNames = overlayNamesForContract(contractHash, opts);
|
|
1074
1317
|
if (overlayNames.length === 0) {
|
|
1075
|
-
lines.push(emptyGutter
|
|
1318
|
+
lines.push(trimTrailingWhitespace(emptyGutter));
|
|
1076
1319
|
continue;
|
|
1077
1320
|
}
|
|
1078
1321
|
const overlay = style.refs(overlayNames);
|
|
1079
|
-
lines.push(`${padVisible(emptyGutter, dataColumn)}${overlay}
|
|
1322
|
+
lines.push(trimTrailingWhitespace(`${padVisible(emptyGutter, dataColumn)}${overlay}`));
|
|
1080
1323
|
continue;
|
|
1081
1324
|
}
|
|
1082
1325
|
const hashText = style.sourceHash(abbreviateHash(contractHash, hashLength, palette.emptySource));
|
|
1083
1326
|
const overlayNames = overlayNamesForContract(contractHash, opts);
|
|
1084
1327
|
const overlayPad = overlayNames.length > 0 ? " ".repeat(Math.max(0, dataColumn - labelColumn - stringWidth(hashText))) : "";
|
|
1085
1328
|
const overlay = overlayNames.length > 0 ? style.refs(overlayNames) : "";
|
|
1086
|
-
lines.push(`${gutterPad}${hashText}${overlayPad}${overlay}
|
|
1329
|
+
lines.push(trimTrailingWhitespace(`${gutterPad}${hashText}${overlayPad}${overlay}`));
|
|
1087
1330
|
continue;
|
|
1088
1331
|
}
|
|
1089
1332
|
const edge = row.edge;
|
|
1090
1333
|
if (edge === void 0) continue;
|
|
1091
1334
|
const dirNamePadding = " ".repeat(Math.max(0, dirNameWidth - edge.dirName.length));
|
|
1092
|
-
const
|
|
1335
|
+
const laneIndex = row.laneIndex ?? 0;
|
|
1336
|
+
const dirName = `${(opts.colorize && laneIndex > NEUTRAL_LANE ? (text) => forcedBold(laneColorForColumn(laneIndex)(text)) : style.dirName)(edge.dirName)}${dirNamePadding}`;
|
|
1093
1337
|
const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);
|
|
1094
|
-
lines.push(`${gutterPad}${dirName}${hashColumn}
|
|
1338
|
+
lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}`));
|
|
1095
1339
|
}
|
|
1096
1340
|
return lines.join("\n");
|
|
1097
1341
|
}
|
|
1342
|
+
/**
|
|
1343
|
+
* A compact key for the `--tree` visual language: the contract marker, the
|
|
1344
|
+
* in-lane direction arrows, the empty baseline, the `(refs)` overlay (including
|
|
1345
|
+
* the reserved `db` live-database and `contract` working-schema markers), and a
|
|
1346
|
+
* worked sample of the data-column `from → to` migration hash arrow.
|
|
1347
|
+
*
|
|
1348
|
+
* Honors the same glyph palette (unicode vs ASCII) and `colorize` gate as the
|
|
1349
|
+
* tree renderer, so the key matches whatever the graph itself drew and stays
|
|
1350
|
+
* pipe-safe (zero ANSI when color is off). The caller adds the trailing blank
|
|
1351
|
+
* line that separates this stderr key from the graph on stdout.
|
|
1352
|
+
*/
|
|
1353
|
+
function renderMigrationGraphLegend(opts) {
|
|
1354
|
+
const palette = paletteFor(opts.glyphMode ?? "unicode");
|
|
1355
|
+
const style = createAnsiMigrationListStyler({ useColor: opts.colorize });
|
|
1356
|
+
const node = palette.node.trimEnd();
|
|
1357
|
+
const sampleArrow = `${style.sourceHash("aaaaaa")} ${style.glyph(palette.forwardArrow)} ${style.destHash("bbbbbb")}`;
|
|
1358
|
+
return [
|
|
1359
|
+
"Legend:",
|
|
1360
|
+
` ${style.kind(node)} ${style.summary("contract")} ${style.kind(palette.edgeArrow.forward)} ${style.summary("forward")} ${style.kind(palette.edgeArrow.rollback)} ${style.summary("rollback")}`,
|
|
1361
|
+
` ${style.kind(palette.edgeArrow.self)} ${style.summary("migration without schema change")}`,
|
|
1362
|
+
` ${style.kind(palette.emptySource)} ${style.summary("empty database (baseline)")}`,
|
|
1363
|
+
` ${style.refs(["refs"])} ${style.summary(`${DB_MARKER_NAME} / ${CONTRACT_MARKER_NAME} markers`)}`,
|
|
1364
|
+
` ${sampleArrow} ${style.summary("migration from contract aaaaaa to bbbbbb")}`
|
|
1365
|
+
].join("\n");
|
|
1366
|
+
}
|
|
1098
1367
|
//#endregion
|
|
1099
1368
|
//#region src/commands/migration-graph.ts
|
|
1369
|
+
/**
|
|
1370
|
+
* `--legend` describes the `--tree` visual language, so passing it auto-enables
|
|
1371
|
+
* the tree path (it has nothing to say about the legacy dagre default).
|
|
1372
|
+
*/
|
|
1373
|
+
function migrationGraphUsesTree(options) {
|
|
1374
|
+
return options.tree === true || options.legend === true;
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* The legend is decoration printed alongside the command header on stderr, so
|
|
1378
|
+
* it is suppressed for the machine-readable / silent paths (`--json`, `--dot`,
|
|
1379
|
+
* `--quiet`) exactly as the header is.
|
|
1380
|
+
*/
|
|
1381
|
+
function migrationGraphShowsLegend(options, flags) {
|
|
1382
|
+
return options.legend === true && options.dot !== true && flags.json !== true && flags.quiet !== true;
|
|
1383
|
+
}
|
|
1100
1384
|
async function executeMigrationGraphCommand(options, flags, ui) {
|
|
1101
1385
|
const config = await loadConfig(options.config);
|
|
1102
1386
|
const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(options.config, config);
|
|
@@ -1114,6 +1398,13 @@ async function executeMigrationGraphCommand(options, flags, ui) {
|
|
|
1114
1398
|
flags
|
|
1115
1399
|
});
|
|
1116
1400
|
ui.stderr(header);
|
|
1401
|
+
if (migrationGraphShowsLegend(options, flags)) {
|
|
1402
|
+
ui.stderr(renderMigrationGraphLegend({
|
|
1403
|
+
colorize: flags.color !== false,
|
|
1404
|
+
glyphMode: ui.resolveGlyphMode(options.ascii === true)
|
|
1405
|
+
}));
|
|
1406
|
+
ui.stderr("");
|
|
1407
|
+
}
|
|
1117
1408
|
}
|
|
1118
1409
|
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
1119
1410
|
if (!loaded.ok) return loaded;
|
|
@@ -1139,7 +1430,8 @@ function createMigrationGraphCommand() {
|
|
|
1139
1430
|
"prisma-next migration graph --json",
|
|
1140
1431
|
"prisma-next migration graph --dot",
|
|
1141
1432
|
"prisma-next migration graph --tree",
|
|
1142
|
-
"prisma-next migration graph --tree --ascii"
|
|
1433
|
+
"prisma-next migration graph --tree --ascii",
|
|
1434
|
+
"prisma-next migration graph --legend"
|
|
1143
1435
|
]);
|
|
1144
1436
|
setCommandSeeAlso(command, [
|
|
1145
1437
|
{
|
|
@@ -1159,7 +1451,7 @@ function createMigrationGraphCommand() {
|
|
|
1159
1451
|
oneLiner: "Display migration package contents"
|
|
1160
1452
|
}
|
|
1161
1453
|
]);
|
|
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) => {
|
|
1454
|
+
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
1455
|
const flags = parseGlobalFlagsOrExit(options);
|
|
1164
1456
|
const ui = createTerminalUI(flags);
|
|
1165
1457
|
const exitCode = handleResult(await executeMigrationGraphCommand(options, flags, ui), flags, ui, (graphResult) => {
|
|
@@ -1186,7 +1478,7 @@ function createMigrationGraphCommand() {
|
|
|
1186
1478
|
edges,
|
|
1187
1479
|
summary: graphResult.summary
|
|
1188
1480
|
}, null, 2));
|
|
1189
|
-
} else if (!flags.quiet) if (options
|
|
1481
|
+
} else if (!flags.quiet) if (migrationGraphUsesTree(options)) {
|
|
1190
1482
|
const refsByHash = /* @__PURE__ */ new Map();
|
|
1191
1483
|
for (const ref of graphResult.refs) {
|
|
1192
1484
|
const existing = refsByHash.get(ref.hash);
|
|
@@ -1227,6 +1519,6 @@ function createMigrationGraphCommand() {
|
|
|
1227
1519
|
return command;
|
|
1228
1520
|
}
|
|
1229
1521
|
//#endregion
|
|
1230
|
-
export { executeMigrationGraphCommand as n, createMigrationGraphCommand as t };
|
|
1522
|
+
export { migrationGraphUsesTree as i, executeMigrationGraphCommand as n, migrationGraphShowsLegend as r, createMigrationGraphCommand as t };
|
|
1231
1523
|
|
|
1232
|
-
//# sourceMappingURL=migration-graph-
|
|
1524
|
+
//# sourceMappingURL=migration-graph-DKl_IYsF.mjs.map
|