@prisma-next/cli 0.12.0-dev.67 → 0.12.0-dev.69
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 +5 -5
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +17 -11
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.mjs +2 -2
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.mjs +1 -1
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/{migration-check-soB5uZEQ.mjs → migration-check-VwM8xCZV.mjs} +2 -1
- package/dist/{migration-check-soB5uZEQ.mjs.map → migration-check-VwM8xCZV.mjs.map} +1 -1
- package/dist/migration-graph-command-render-BAOzyYF6.mjs +1822 -0
- package/dist/migration-graph-command-render-BAOzyYF6.mjs.map +1 -0
- package/dist/{migration-list-CyLslAtv.mjs → migration-list-CihF6w5z.mjs} +2 -2
- package/dist/migration-list-CihF6w5z.mjs.map +1 -0
- package/dist/{migration-log-BYt18y2H.mjs → migration-log-B75IArji.mjs} +2 -2
- package/dist/{migration-log-BYt18y2H.mjs.map → migration-log-B75IArji.mjs.map} +1 -1
- package/dist/{migration-status-ciYpjhtu.mjs → migration-status-CSVe6ZlD.mjs} +4 -3
- package/dist/migration-status-CSVe6ZlD.mjs.map +1 -0
- package/package.json +19 -18
- package/src/commands/migrate.ts +35 -26
- package/src/commands/migration-graph.ts +1 -1
- package/src/commands/migration-list.ts +1 -1
- package/src/commands/migration-status-overlay.ts +1 -1
- package/src/commands/migration-status.ts +4 -2
- package/src/utils/formatters/migration-graph-command-render.ts +239 -0
- package/src/utils/formatters/migration-graph-grid-layout.ts +857 -0
- package/src/utils/formatters/migration-graph-labels.ts +406 -0
- package/src/utils/formatters/migration-graph-model.ts +94 -0
- package/src/utils/formatters/migration-graph-occlusion-render.ts +245 -0
- package/src/utils/formatters/migration-graph-space-render.ts +73 -33
- package/src/utils/formatters/migration-list-render.ts +1 -1
- package/dist/migration-graph-space-render-Cpg0ql8v.mjs +0 -2370
- package/dist/migration-graph-space-render-Cpg0ql8v.mjs.map +0 -1
- package/dist/migration-list-CyLslAtv.mjs.map +0 -1
- package/dist/migration-status-ciYpjhtu.mjs.map +0 -1
- package/src/utils/formatters/migration-graph-lane-colors.ts +0 -194
- package/src/utils/formatters/migration-graph-layout.ts +0 -1308
- package/src/utils/formatters/migration-graph-tree-render.ts +0 -1337
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Occlusion renderer for the line/plane/occlusion migration-graph.
|
|
3
|
+
*
|
|
4
|
+
* Per cell: pick the topmost-plane line (lowest plane number = drawn on top),
|
|
5
|
+
* look up its glyph, apply colour from the line's lane or role. Lower-plane
|
|
6
|
+
* lines are occluded (not drawn).
|
|
7
|
+
*
|
|
8
|
+
* Colour is forced via createColors({ useColor: true }) regardless of NO_COLOR.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { createColors } from 'colorette';
|
|
12
|
+
import type { Cell, CellLine, Direction, Grid, PathRole } from './migration-graph-model';
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Force-colour seam — always emits ANSI regardless of NO_COLOR.
|
|
16
|
+
// Same technique as gallery-cells.ts.
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
const palette = createColors({ useColor: true });
|
|
19
|
+
|
|
20
|
+
// Lane colour palette: lane N → colour N+1 (lane0=white, lane1=cyan, …).
|
|
21
|
+
// No red (reads as an error). The on-path highlight uses greenBright (SGR 92),
|
|
22
|
+
// distinct from flat-lane green (SGR 32).
|
|
23
|
+
type Colorizer = (text: string) => string;
|
|
24
|
+
|
|
25
|
+
const LANE_COLORIZERS: Colorizer[] = [
|
|
26
|
+
palette.white,
|
|
27
|
+
palette.cyan,
|
|
28
|
+
palette.yellow,
|
|
29
|
+
palette.blueBright,
|
|
30
|
+
palette.magenta,
|
|
31
|
+
palette.green,
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
function laneColor(lane: number): Colorizer {
|
|
35
|
+
return LANE_COLORIZERS[lane % LANE_COLORIZERS.length] ?? ((t) => t);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The colourizer for a lane's hue (lane0 = white, lane1 = cyan, …). Exported
|
|
40
|
+
* so the per-row LABEL renderer can tint a migration name in its lane's colour,
|
|
41
|
+
* matching the node `○`, the edges, and the arrows drawn in the gutter — one
|
|
42
|
+
* colour per lane across glyph and text.
|
|
43
|
+
*/
|
|
44
|
+
export function laneColorizer(lane: number): (text: string) => string {
|
|
45
|
+
return laneColor(lane);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Focus colour: on-path → green, off-path → dim. Read straight off the line's
|
|
50
|
+
// role; a defined role always overrides the lane rotation.
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
function roleColor(role: PathRole): Colorizer {
|
|
53
|
+
return role === 'on-path' ? palette.greenBright : palette.dim;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Glyph alphabet — unicode and ASCII variants.
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
export type GraphGlyphMode = 'unicode' | 'ascii';
|
|
60
|
+
|
|
61
|
+
interface GraphGlyphAlphabet {
|
|
62
|
+
readonly vertical: string;
|
|
63
|
+
readonly horizontal: string;
|
|
64
|
+
readonly cornerUpRight: string;
|
|
65
|
+
readonly cornerDownRight: string;
|
|
66
|
+
readonly cornerUpLeft: string;
|
|
67
|
+
readonly cornerDownLeft: string;
|
|
68
|
+
readonly arrowUp: string;
|
|
69
|
+
readonly arrowDown: string;
|
|
70
|
+
readonly node: string;
|
|
71
|
+
readonly selfLoop: string;
|
|
72
|
+
readonly landingArrow: string;
|
|
73
|
+
readonly fallback: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const UNICODE_ALPHABET: GraphGlyphAlphabet = {
|
|
77
|
+
vertical: '│',
|
|
78
|
+
horizontal: '─',
|
|
79
|
+
cornerUpRight: '╰',
|
|
80
|
+
cornerDownRight: '╭',
|
|
81
|
+
cornerUpLeft: '╯',
|
|
82
|
+
cornerDownLeft: '╮',
|
|
83
|
+
arrowUp: '↑',
|
|
84
|
+
arrowDown: '↓',
|
|
85
|
+
node: '○',
|
|
86
|
+
selfLoop: '⟲',
|
|
87
|
+
landingArrow: '◂',
|
|
88
|
+
fallback: '?',
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const ASCII_ALPHABET: GraphGlyphAlphabet = {
|
|
92
|
+
vertical: '|',
|
|
93
|
+
horizontal: '-',
|
|
94
|
+
cornerUpRight: '\\',
|
|
95
|
+
cornerDownRight: '/',
|
|
96
|
+
cornerUpLeft: '/',
|
|
97
|
+
cornerDownLeft: '\\',
|
|
98
|
+
arrowUp: '^',
|
|
99
|
+
arrowDown: 'v',
|
|
100
|
+
node: '*',
|
|
101
|
+
selfLoop: '@',
|
|
102
|
+
landingArrow: '<',
|
|
103
|
+
fallback: '?',
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
function alphabetFor(mode: GraphGlyphMode): GraphGlyphAlphabet {
|
|
107
|
+
return mode === 'ascii' ? ASCII_ALPHABET : UNICODE_ALPHABET;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function glyphFor(dirs: ReadonlySet<Direction>, alphabet: GraphGlyphAlphabet): string {
|
|
111
|
+
const has = (d: Direction) => dirs.has(d);
|
|
112
|
+
|
|
113
|
+
if (has('up') && has('down') && !has('left') && !has('right')) return alphabet.vertical;
|
|
114
|
+
if (has('left') && has('right') && !has('up') && !has('down')) return alphabet.horizontal;
|
|
115
|
+
if (has('up') && has('right') && !has('down') && !has('left')) return alphabet.cornerUpRight;
|
|
116
|
+
if (has('down') && has('right') && !has('up') && !has('left')) return alphabet.cornerDownRight;
|
|
117
|
+
if (has('up') && has('left') && !has('down') && !has('right')) return alphabet.cornerUpLeft;
|
|
118
|
+
if (has('down') && has('left') && !has('up') && !has('right')) return alphabet.cornerDownLeft;
|
|
119
|
+
if (has('up') && !has('down') && !has('left') && !has('right')) return alphabet.arrowUp;
|
|
120
|
+
if (has('down') && !has('up') && !has('left') && !has('right')) return alphabet.arrowDown;
|
|
121
|
+
|
|
122
|
+
// Fallback: shouldn't happen in well-formed grids
|
|
123
|
+
return alphabet.fallback;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// renderCell — project one cell to a coloured string fragment.
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
const NO_COLOR: Colorizer = (t) => t;
|
|
131
|
+
|
|
132
|
+
function renderCell(cell: Cell, colorEnabled: boolean, alphabet: GraphGlyphAlphabet): string {
|
|
133
|
+
// Node marker overrides everything
|
|
134
|
+
if (cell.node !== undefined) {
|
|
135
|
+
// Every node uses ○ — the ∅ identifier is only used as the label, not as a
|
|
136
|
+
// glyph, per the golden colour model. Colour by role (focus) or lane (flat).
|
|
137
|
+
const colorize = !colorEnabled
|
|
138
|
+
? NO_COLOR
|
|
139
|
+
: cell.node.role !== undefined
|
|
140
|
+
? roleColor(cell.node.role)
|
|
141
|
+
: laneColor(cell.node.lane);
|
|
142
|
+
return colorize(alphabet.node);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (cell.lines.length === 0) {
|
|
146
|
+
return ' ';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Pick the drawn line by occlusion: lowest plane number wins (drawn on top).
|
|
150
|
+
// At an equal plane, on-path beats off-path explicitly — never rely on array
|
|
151
|
+
// order to break the tie (the single-owner invariant should already prevent
|
|
152
|
+
// a same-plane on/off-path collision, but the priority is made explicit here).
|
|
153
|
+
const topLine = cell.lines.reduce<CellLine>((best, current) => {
|
|
154
|
+
if (current.plane < best.plane) return current;
|
|
155
|
+
if (current.plane > best.plane) return best;
|
|
156
|
+
if (current.line.role === 'on-path' && best.line.role !== 'on-path') return current;
|
|
157
|
+
return best;
|
|
158
|
+
}, cell.lines[0]!);
|
|
159
|
+
|
|
160
|
+
const glyph =
|
|
161
|
+
topLine.selfLoop === true
|
|
162
|
+
? alphabet.selfLoop
|
|
163
|
+
: topLine.landingArrow === true
|
|
164
|
+
? alphabet.landingArrow
|
|
165
|
+
: glyphFor(topLine.directions, alphabet);
|
|
166
|
+
const colorize = !colorEnabled
|
|
167
|
+
? NO_COLOR
|
|
168
|
+
: topLine.line.role !== undefined
|
|
169
|
+
? roleColor(topLine.line.role)
|
|
170
|
+
: laneColor(topLine.line.lane);
|
|
171
|
+
return colorize(glyph);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// RenderGridOptions
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
export interface RenderGridOptions {
|
|
179
|
+
readonly colorize?: boolean;
|
|
180
|
+
readonly colsPerLane?: number;
|
|
181
|
+
readonly glyphMode?: GraphGlyphMode;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// renderGrid — the main render function.
|
|
186
|
+
//
|
|
187
|
+
// Produces the final string: one line per grid row, each cell rendered to
|
|
188
|
+
// a coloured character. Trailing empty cells are trimmed, but we always
|
|
189
|
+
// include up to the last non-empty cell's connector column
|
|
190
|
+
// (the full 2-col-per-lane width for the active lane count).
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Render a single grid row to a coloured string. A completely empty row returns
|
|
195
|
+
* the empty string (the row is NOT dropped) so callers that pair grid rows with
|
|
196
|
+
* an external per-row label list keep a 1:1 index correspondence. `renderGrid`
|
|
197
|
+
* itself drops empty rows for its standalone output.
|
|
198
|
+
*/
|
|
199
|
+
export function renderGridRow(
|
|
200
|
+
row: readonly (Cell | undefined)[],
|
|
201
|
+
opts: RenderGridOptions = {},
|
|
202
|
+
): string {
|
|
203
|
+
// Find the last non-empty cell index
|
|
204
|
+
let lastNonEmpty = -1;
|
|
205
|
+
for (let i = row.length - 1; i >= 0; i--) {
|
|
206
|
+
const cell = row[i];
|
|
207
|
+
if (cell !== undefined && (cell.lines.length > 0 || cell.node !== undefined)) {
|
|
208
|
+
lastNonEmpty = i;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (lastNonEmpty < 0) {
|
|
214
|
+
return '';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Extend to the next even column boundary (connector col of the current lane)
|
|
218
|
+
// so that connector columns are always present for active lane ranges.
|
|
219
|
+
const colsPerLane = opts.colsPerLane ?? 2;
|
|
220
|
+
const colorEnabled = opts.colorize ?? true;
|
|
221
|
+
const alphabet = alphabetFor(opts.glyphMode ?? 'unicode');
|
|
222
|
+
const lastLane = Math.floor(lastNonEmpty / colsPerLane);
|
|
223
|
+
const lastConnectorCol = lastLane * colsPerLane + (colsPerLane - 1);
|
|
224
|
+
const renderThrough = Math.max(lastNonEmpty, lastConnectorCol);
|
|
225
|
+
|
|
226
|
+
let line = '';
|
|
227
|
+
for (let col = 0; col <= Math.min(renderThrough, row.length - 1); col++) {
|
|
228
|
+
const cell = row[col];
|
|
229
|
+
line += cell === undefined ? ' ' : renderCell(cell, colorEnabled, alphabet);
|
|
230
|
+
}
|
|
231
|
+
return line;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function renderGrid(grid: Grid, opts: RenderGridOptions = {}): string {
|
|
235
|
+
const lines: string[] = [];
|
|
236
|
+
for (const row of grid) {
|
|
237
|
+
const rendered = renderGridRow(row, opts);
|
|
238
|
+
if (rendered === '') {
|
|
239
|
+
// Completely empty row — skip in standalone output.
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
lines.push(rendered);
|
|
243
|
+
}
|
|
244
|
+
return lines.join('\n');
|
|
245
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
|
|
2
2
|
import type { GlyphMode } from '../glyph-mode';
|
|
3
|
-
import { buildMigrationGraphLayout } from './migration-graph-layout';
|
|
4
|
-
import { buildMigrationGraphRows } from './migration-graph-rows';
|
|
5
3
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from './migration-graph-
|
|
4
|
+
computeLabelColumn,
|
|
5
|
+
computeMaxDirNameWidth,
|
|
6
|
+
renderMigrationGraphCommand,
|
|
7
|
+
} from './migration-graph-command-render';
|
|
8
|
+
import { buildGrid } from './migration-graph-grid-layout';
|
|
9
|
+
import type { MigrationEdgeAnnotation } from './migration-graph-labels';
|
|
10
|
+
import type { Highlight } from './migration-graph-model';
|
|
11
|
+
import { buildMigrationGraphRows } from './migration-graph-rows';
|
|
11
12
|
import {
|
|
12
13
|
buildEdgeAnnotationsByHashFromListEntries,
|
|
13
14
|
buildRefsByHashFromListEntries,
|
|
@@ -32,6 +33,24 @@ export function mergeMigrationEdgeAnnotations(
|
|
|
32
33
|
return merged;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Translate `migrate --show` per-edge path-highlight annotations into a
|
|
38
|
+
* {@link Highlight}. With any `pathHighlight` present the result is focus mode
|
|
39
|
+
* (on-path lifted green, off-path dim); otherwise flat (lane-rotation colour).
|
|
40
|
+
*/
|
|
41
|
+
export function highlightFromEdgeAnnotations(
|
|
42
|
+
edgeAnnotationsByHash: ReadonlyMap<string, MigrationEdgeAnnotation>,
|
|
43
|
+
): Highlight {
|
|
44
|
+
const onPath = new Set<string>();
|
|
45
|
+
let anyPathHighlight = false;
|
|
46
|
+
for (const [migrationHash, annotation] of edgeAnnotationsByHash) {
|
|
47
|
+
if (annotation.pathHighlight === undefined) continue;
|
|
48
|
+
anyPathHighlight = true;
|
|
49
|
+
if (annotation.pathHighlight === 'on-path') onPath.add(migrationHash);
|
|
50
|
+
}
|
|
51
|
+
return anyPathHighlight ? { mode: 'focus', onPath } : { mode: 'flat', onPath: new Set() };
|
|
52
|
+
}
|
|
53
|
+
|
|
35
54
|
export interface RenderMigrationGraphSpaceTreeInput {
|
|
36
55
|
readonly graph: MigrationGraph;
|
|
37
56
|
readonly migrations: readonly MigrationListEntry[];
|
|
@@ -42,14 +61,17 @@ export interface RenderMigrationGraphSpaceTreeInput {
|
|
|
42
61
|
readonly statusOverlayByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;
|
|
43
62
|
readonly dbHash?: string;
|
|
44
63
|
readonly styler?: MigrationListStyler;
|
|
64
|
+
/**
|
|
65
|
+
* Cross-space override for the gutter→label column (the widest gutter across
|
|
66
|
+
* sibling space sections, plus the label gap). Named for historical
|
|
67
|
+
* continuity with the previous renderer's prefix-width input.
|
|
68
|
+
*/
|
|
45
69
|
readonly globalMaxEdgeTreePrefixWidth?: number;
|
|
46
70
|
readonly globalMaxDirNameWidth?: number;
|
|
47
71
|
/**
|
|
48
|
-
* Whether this render is for the app space. When false, `contractHash` is
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* `renderMigrationGraphTree` (suppressing the `@contract` marker).
|
|
52
|
-
* Defaults to `true` so single-space callers are unaffected.
|
|
72
|
+
* Whether this render is for the app space. When false, `contractHash` is not
|
|
73
|
+
* forwarded to `buildMigrationGraphRows` (suppressing the floating working-
|
|
74
|
+
* contract node) and the `@contract` marker is suppressed. Defaults to `true`.
|
|
53
75
|
*/
|
|
54
76
|
readonly isAppSpace?: boolean;
|
|
55
77
|
}
|
|
@@ -59,16 +81,27 @@ export interface ComputeGlobalMaxEdgeTreePrefixWidthInput {
|
|
|
59
81
|
readonly liveContractHash: string;
|
|
60
82
|
}
|
|
61
83
|
|
|
84
|
+
function buildGridForInput(input: ComputeGlobalMaxEdgeTreePrefixWidthInput): {
|
|
85
|
+
readonly grid: ReturnType<typeof buildGrid>;
|
|
86
|
+
readonly rowModel: ReturnType<typeof buildMigrationGraphRows>;
|
|
87
|
+
} {
|
|
88
|
+
const rowModel = buildMigrationGraphRows(input.graph, { contractHash: input.liveContractHash });
|
|
89
|
+
const grid = buildGrid(rowModel, {}, { mode: 'flat', onPath: new Set() });
|
|
90
|
+
return { grid, rowModel };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The widest gutter→label column across the given space layouts. Cross-space
|
|
95
|
+
* callers pass this back in so every section's labels share one column.
|
|
96
|
+
*/
|
|
62
97
|
export function computeGlobalMaxEdgeTreePrefixWidth(
|
|
63
98
|
inputs: readonly ComputeGlobalMaxEdgeTreePrefixWidthInput[],
|
|
99
|
+
glyphMode: GlyphMode = 'unicode',
|
|
64
100
|
): number {
|
|
65
101
|
let globalMax = 0;
|
|
66
102
|
for (const input of inputs) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
const layout = buildMigrationGraphLayout(rowModel);
|
|
71
|
-
globalMax = Math.max(globalMax, computeMaxEdgeTreePrefixWidthForLayout(layout));
|
|
103
|
+
const { grid } = buildGridForInput(input);
|
|
104
|
+
globalMax = Math.max(globalMax, computeLabelColumn(grid, glyphMode));
|
|
72
105
|
}
|
|
73
106
|
return globalMax;
|
|
74
107
|
}
|
|
@@ -78,11 +111,8 @@ export function computeGlobalMaxDirNameWidth(
|
|
|
78
111
|
): number {
|
|
79
112
|
let globalMax = 0;
|
|
80
113
|
for (const input of inputs) {
|
|
81
|
-
const rowModel =
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
const layout = buildMigrationGraphLayout(rowModel);
|
|
85
|
-
globalMax = Math.max(globalMax, computeMaxDirNameLengthForLayout(layout));
|
|
114
|
+
const { rowModel } = buildGridForInput(input);
|
|
115
|
+
globalMax = Math.max(globalMax, computeMaxDirNameWidth(rowModel));
|
|
86
116
|
}
|
|
87
117
|
return globalMax;
|
|
88
118
|
}
|
|
@@ -92,23 +122,27 @@ function renderMigrationGraphSpaceTreeInternal(input: RenderMigrationGraphSpaceT
|
|
|
92
122
|
const rowModel = buildMigrationGraphRows(input.graph, {
|
|
93
123
|
...(appSpace ? { contractHash: input.liveContractHash } : {}),
|
|
94
124
|
});
|
|
95
|
-
const layout = buildMigrationGraphLayout(rowModel);
|
|
96
125
|
const listOverlay = buildEdgeAnnotationsByHashFromListEntries(input.migrations);
|
|
97
126
|
const edgeAnnotationsByHash =
|
|
98
127
|
input.statusOverlayByHash === undefined
|
|
99
128
|
? listOverlay
|
|
100
129
|
: mergeMigrationEdgeAnnotations(listOverlay, input.statusOverlayByHash);
|
|
101
|
-
|
|
102
|
-
|
|
130
|
+
const highlight = highlightFromEdgeAnnotations(edgeAnnotationsByHash);
|
|
131
|
+
const grid = buildGrid(rowModel, {}, highlight);
|
|
132
|
+
|
|
133
|
+
return renderMigrationGraphCommand({
|
|
134
|
+
grid,
|
|
135
|
+
rowModel,
|
|
136
|
+
colorize: input.colorize,
|
|
137
|
+
glyphMode: input.glyphMode,
|
|
103
138
|
contractHash: input.liveContractHash,
|
|
104
139
|
isAppSpace: appSpace,
|
|
105
140
|
edgeAnnotationsByHash,
|
|
106
|
-
|
|
107
|
-
glyphMode: input.glyphMode,
|
|
141
|
+
refsByHash: input.refsByHash ?? buildRefsByHashFromListEntries(input.migrations),
|
|
108
142
|
...(input.dbHash !== undefined ? { dbHash: input.dbHash } : {}),
|
|
109
143
|
...(input.styler !== undefined ? { styler: input.styler } : {}),
|
|
110
144
|
...(input.globalMaxEdgeTreePrefixWidth !== undefined
|
|
111
|
-
? {
|
|
145
|
+
? { globalLabelColumn: input.globalMaxEdgeTreePrefixWidth }
|
|
112
146
|
: {}),
|
|
113
147
|
...(input.globalMaxDirNameWidth !== undefined
|
|
114
148
|
? { globalMaxDirNameWidth: input.globalMaxDirNameWidth }
|
|
@@ -123,14 +157,20 @@ export function renderMigrationGraphSpaceTree(input: RenderMigrationGraphSpaceTr
|
|
|
123
157
|
export function renderMigrationGraphSpaceTrees(
|
|
124
158
|
inputs: readonly RenderMigrationGraphSpaceTreeInput[],
|
|
125
159
|
): readonly string[] {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
160
|
+
const globalInputs: ComputeGlobalMaxEdgeTreePrefixWidthInput[] = inputs.map((input) => ({
|
|
161
|
+
graph: input.graph,
|
|
162
|
+
liveContractHash: input.liveContractHash,
|
|
163
|
+
}));
|
|
164
|
+
const glyphMode = inputs[0]?.glyphMode ?? 'unicode';
|
|
165
|
+
const globalLabelColumn =
|
|
166
|
+
inputs.length > 1 ? computeGlobalMaxEdgeTreePrefixWidth(globalInputs, glyphMode) : undefined;
|
|
167
|
+
const globalMaxDirName =
|
|
168
|
+
inputs.length > 1 ? computeGlobalMaxDirNameWidth(globalInputs) : undefined;
|
|
129
169
|
return inputs.map((input) =>
|
|
130
170
|
renderMigrationGraphSpaceTreeInternal({
|
|
131
171
|
...input,
|
|
132
|
-
...(
|
|
133
|
-
? { globalMaxEdgeTreePrefixWidth:
|
|
172
|
+
...(globalLabelColumn !== undefined
|
|
173
|
+
? { globalMaxEdgeTreePrefixWidth: globalLabelColumn }
|
|
134
174
|
: {}),
|
|
135
175
|
...(globalMaxDirName !== undefined ? { globalMaxDirNameWidth: globalMaxDirName } : {}),
|
|
136
176
|
}),
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
2
2
|
import type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';
|
|
3
3
|
import type { GlyphMode } from '../glyph-mode';
|
|
4
|
+
import type { MigrationEdgeAnnotation } from './migration-graph-labels';
|
|
4
5
|
import {
|
|
5
6
|
computeGlobalMaxDirNameWidth,
|
|
6
7
|
computeGlobalMaxEdgeTreePrefixWidth,
|
|
7
8
|
indentMigrationGraphTreeBlock,
|
|
8
9
|
renderMigrationGraphSpaceTree,
|
|
9
10
|
} from './migration-graph-space-render';
|
|
10
|
-
import type { MigrationEdgeAnnotation } from './migration-graph-tree-render';
|
|
11
11
|
import type { MigrationListEntry, MigrationListResult } from './migration-list-types';
|
|
12
12
|
|
|
13
13
|
export type { GlyphMode } from '../glyph-mode';
|