@prisma-next/cli 0.12.0-dev.17 → 0.12.0-dev.3
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 +160 -177
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Cdxcme1x.mjs → client-KgJorIvG.mjs} +8 -21
- package/dist/client-KgJorIvG.mjs.map +1 -0
- package/dist/{command-helpers-Cmdqyhz9.mjs → command-helpers-Bbw1GbwL.mjs} +2 -32
- package/dist/{command-helpers-Cmdqyhz9.mjs.map → command-helpers-Bbw1GbwL.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 +5 -23
- 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 +2 -2
- 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/{contract-at-errors-Cz0z5PJi.mjs → contract-at-errors-BxP-TOMl.mjs} +2 -2
- package/dist/{contract-at-errors-Cz0z5PJi.mjs.map → contract-at-errors-BxP-TOMl.mjs.map} +1 -1
- package/dist/{contract-emit-CC9jDOmu.mjs → contract-emit-D-4jrNve.mjs} +3 -3
- package/dist/{contract-emit-CC9jDOmu.mjs.map → contract-emit-D-4jrNve.mjs.map} +1 -1
- package/dist/{contract-emit-DPMij44i.mjs → contract-emit-DxcGl4Uq.mjs} +3 -3
- package/dist/{contract-emit-DPMij44i.mjs.map → contract-emit-DxcGl4Uq.mjs.map} +1 -1
- package/dist/{contract-infer-DaFPNrZH.mjs → contract-infer-D8uEbJuu.mjs} +3 -3
- package/dist/{contract-infer-DaFPNrZH.mjs.map → contract-infer-D8uEbJuu.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-CirAEsM8.mjs → contract-space-aggregate-loader-DvZwdkrr.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-CirAEsM8.mjs.map → contract-space-aggregate-loader-DvZwdkrr.mjs.map} +1 -1
- package/dist/{db-verify-BSA1a_W_.mjs → db-verify-v_vUKXTU.mjs} +4 -4
- package/dist/{db-verify-BSA1a_W_.mjs.map → db-verify-v_vUKXTU.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-DynSvww4.mjs → framework-components-fYXjz_in.mjs} +2 -2
- package/dist/{framework-components-DynSvww4.mjs.map → framework-components-fYXjz_in.mjs.map} +1 -1
- package/dist/{global-flags-DG4uY5tV.d.mts → global-flags-DEHjV8_s.d.mts} +1 -1
- package/dist/{global-flags-DG4uY5tV.d.mts.map → global-flags-DEHjV8_s.d.mts.map} +1 -1
- package/dist/{init-B6kKrmf7.mjs → init-Cv9UzWL5.mjs} +58 -5
- package/dist/init-Cv9UzWL5.mjs.map +1 -0
- package/dist/{inspect-live-schema-Dn56wDhG.mjs → inspect-live-schema-C6ohV_oQ.mjs} +3 -3
- package/dist/{inspect-live-schema-Dn56wDhG.mjs.map → inspect-live-schema-C6ohV_oQ.mjs.map} +1 -1
- package/dist/{migration-check-DzH1u-O1.mjs → migration-check-BiBJoYYW.mjs} +2 -2
- package/dist/{migration-check-DzH1u-O1.mjs.map → migration-check-BiBJoYYW.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-V52dV2Tv.mjs → migration-command-scaffold-CjvwO6at.mjs} +3 -3
- package/dist/{migration-command-scaffold-V52dV2Tv.mjs.map → migration-command-scaffold-CjvwO6at.mjs.map} +1 -1
- package/dist/{migration-graph-Cm3oee8C.mjs → migration-graph-D7DVUElV.mjs} +80 -326
- package/dist/migration-graph-D7DVUElV.mjs.map +1 -0
- package/dist/{migration-plan-CaeKCKp4.mjs → migration-plan-9DJ7q7_z.mjs} +5 -5
- package/dist/{migration-plan-CaeKCKp4.mjs.map → migration-plan-9DJ7q7_z.mjs.map} +1 -1
- package/dist/{migration-types-CAQ-0TEE.d.mts → migration-types-D2FW63pr.d.mts} +1 -1
- package/dist/{migration-types-CAQ-0TEE.d.mts.map → migration-types-D2FW63pr.d.mts.map} +1 -1
- package/dist/{migrations-DQ1t3XFL.mjs → migrations-Cv2jxNNK.mjs} +2 -2
- package/dist/{migrations-DQ1t3XFL.mjs.map → migrations-Cv2jxNNK.mjs.map} +1 -1
- package/dist/{output-CF_hqzI-.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-CF_hqzI-.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{terminal-ui-C3xGyxW-.d.mts → terminal-ui-5Y6mrg93.d.mts} +1 -1
- package/dist/{terminal-ui-C3xGyxW-.d.mts.map → terminal-ui-5Y6mrg93.d.mts.map} +1 -1
- package/dist/{types-DiC683UW.d.mts → types-Dt_SfqFm.d.mts} +2 -8
- package/dist/{types-DiC683UW.d.mts.map → types-Dt_SfqFm.d.mts.map} +1 -1
- package/dist/{verify-CreSJ1Mz.mjs → verify-DCA9Sldu.mjs} +2 -2
- package/dist/{verify-CreSJ1Mz.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
- package/package.json +18 -22
- package/src/cli.ts +0 -5
- package/src/commands/init/index.ts +35 -6
- package/src/commands/init/init.ts +14 -1
- package/src/commands/init/inputs.ts +75 -0
- package/src/commands/migration-graph.ts +2 -43
- package/src/commands/migration-status.ts +1 -1
- package/src/control-api/client.ts +1 -11
- package/src/control-api/operations/apply.ts +0 -1
- package/src/control-api/operations/migration-apply.ts +3 -10
- package/src/control-api/types.ts +1 -12
- package/src/utils/formatters/migration-graph-layout.ts +5 -27
- package/src/utils/formatters/migration-graph-tree-render.ts +51 -360
- package/src/utils/global-flags.ts +0 -35
- package/src/utils/telemetry.ts +32 -68
- package/dist/client-Cdxcme1x.mjs.map +0 -1
- package/dist/commands/telemetry/index.d.mts +0 -7
- package/dist/commands/telemetry/index.d.mts.map +0 -1
- package/dist/commands/telemetry/index.mjs +0 -2
- package/dist/init-B6kKrmf7.mjs.map +0 -1
- package/dist/migration-graph-Cm3oee8C.mjs.map +0 -1
- package/dist/telemetry-Q88WHwlv.mjs +0 -122
- package/dist/telemetry-Q88WHwlv.mjs.map +0 -1
- package/src/commands/telemetry/index.ts +0 -107
- package/src/commands/telemetry/status.ts +0 -67
- package/src/utils/formatters/migration-graph-lane-colors.ts +0 -31
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
2
|
-
import { bold
|
|
2
|
+
import { bold } from 'colorette';
|
|
3
3
|
import stringWidth from 'string-width';
|
|
4
4
|
import type { GlyphMode } from '../glyph-mode';
|
|
5
|
-
import { laneColorForColumn } from './migration-graph-lane-colors';
|
|
6
5
|
import type {
|
|
7
6
|
MigrationGraphGridModel,
|
|
8
7
|
MigrationGraphGridRow,
|
|
@@ -117,276 +116,56 @@ function arrowForEdgeKind(
|
|
|
117
116
|
return palette.edgeArrow[kind];
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
/**
|
|
121
|
-
* The leftmost lane (column 0) renders with the neutral dim lane style rather
|
|
122
|
-
* than a palette hue — in the common single-lane case it has nothing to be told
|
|
123
|
-
* apart from. Used as the "no owning arc" sentinel during colour resolution.
|
|
124
|
-
*/
|
|
125
|
-
const NEUTRAL_LANE = 0;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Forced bold for branch-coloured names. A branched name pairs its lane hue
|
|
129
|
-
* (also forced, via {@link laneColorForColumn}) with bold; both must emit even
|
|
130
|
-
* when colorette's ambient TTY detection is off, so the colorized branch name
|
|
131
|
-
* is deterministically bold + hue rather than hue-only.
|
|
132
|
-
*/
|
|
133
|
-
const { bold: forcedBold } = createColors({ useColor: true });
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* The colour-source column for each cell of a row, resolved together because a
|
|
137
|
-
* routed back-arc spans columns and must read as **one hue** rather than a
|
|
138
|
-
* per-column "rainbow". An arc's horizontal bridges, corners, and node-pair
|
|
139
|
-
* connector all take the arc's owning back-lane column (the corner that closes
|
|
140
|
-
* the arc), not the column they pass through.
|
|
141
|
-
*/
|
|
142
|
-
interface RowLaneColors {
|
|
143
|
-
/** Colour column for a cell's structural glyph (lane / spine / arc body). */
|
|
144
|
-
readonly lane: readonly number[];
|
|
145
|
-
/** Colour column for a node arc-pair's connector half (`◂` / `─`). */
|
|
146
|
-
readonly connector: readonly number[];
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Resolve per-cell colour columns for a row. Scanning right-to-left lets each
|
|
151
|
-
* arc bridge inherit the corner column that closes it (the arc's back-lane), so
|
|
152
|
-
* the whole arc — vertical run (already its own column), horizontal bridges,
|
|
153
|
-
* corners, crossings, and the `◂`/`─` connector — reads as a single continuous
|
|
154
|
-
* hue. A crossing can only be one colour, so rather than leave it dim (wrong for
|
|
155
|
-
* both crossing lines) it takes the arc owning the horizontal run at this row
|
|
156
|
-
* (the nearest corner to its right); the crossed vertical lane is simply
|
|
157
|
-
* occluded at that one cell and reappears on the next row.
|
|
158
|
-
*/
|
|
159
|
-
function resolveRowLaneColors(cells: readonly StructuralCell[]): RowLaneColors {
|
|
160
|
-
const lane = new Array<number>(cells.length);
|
|
161
|
-
const connector = new Array<number>(cells.length);
|
|
162
|
-
let arcCorner = NEUTRAL_LANE;
|
|
163
|
-
for (let column = cells.length - 1; column >= 0; column--) {
|
|
164
|
-
const cell = cells[column];
|
|
165
|
-
connector[column] = arcCorner;
|
|
166
|
-
switch (cell?.kind) {
|
|
167
|
-
case 'arc-branch-corner':
|
|
168
|
-
case 'arc-land-corner':
|
|
169
|
-
arcCorner = column;
|
|
170
|
-
lane[column] = column;
|
|
171
|
-
break;
|
|
172
|
-
case 'arc-branch-tee':
|
|
173
|
-
// An inner co-sourced arc's own back-lane junction: its vertical run
|
|
174
|
-
// continues below in this column, so it keeps its own column hue.
|
|
175
|
-
lane[column] = column;
|
|
176
|
-
break;
|
|
177
|
-
case 'arc-crossing':
|
|
178
|
-
case 'arc-land-bridge':
|
|
179
|
-
lane[column] = arcCorner;
|
|
180
|
-
break;
|
|
181
|
-
case 'horizontal-pass':
|
|
182
|
-
lane[column] = arcCorner === NEUTRAL_LANE ? column : arcCorner;
|
|
183
|
-
break;
|
|
184
|
-
case 'node':
|
|
185
|
-
lane[column] = column;
|
|
186
|
-
arcCorner = NEUTRAL_LANE;
|
|
187
|
-
break;
|
|
188
|
-
default:
|
|
189
|
-
lane[column] = column;
|
|
190
|
-
arcCorner = NEUTRAL_LANE;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return { lane, connector };
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Per-cell colour for a forward branch/merge connector row, split into the
|
|
198
|
-
* cell's junction `glyph` and its trailing `dash`. A connector's horizontal run
|
|
199
|
-
* is one logical line (a fork into new lanes, or a merge into a surviving lane)
|
|
200
|
-
* and reads best as the colour of the lane each segment serves — not dim-gray
|
|
201
|
-
* or a per-pass-through-column "rainbow".
|
|
202
|
-
*/
|
|
203
|
-
interface ConnectorLaneColors {
|
|
204
|
-
/** Colour column for a cell's junction glyph (`├` / `┬` / `┴` / `╮` / `╯`). */
|
|
205
|
-
readonly glyph: readonly number[];
|
|
206
|
-
/** Colour column for a tee's trailing `─` — the branch it leads into. */
|
|
207
|
-
readonly dash: readonly number[];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Resolve per-cell connector colours. Scanning right-to-left, a corner or an
|
|
212
|
-
* intermediate tee anchors its own lane (its junction glyph takes that column),
|
|
213
|
-
* but a tee's **trailing dash leads into the branch on its right** (the next
|
|
214
|
-
* branch point), so `┬─` reads as "this lane, then on toward the next" rather
|
|
215
|
-
* than tinting the dash with the left lane. The leading tee at `startLane` (the
|
|
216
|
-
* fork/merge origin) and pure horizontal segments inherit the nearest branch
|
|
217
|
-
* point to their right whole-cell, so the run into a branch — or collapsing
|
|
218
|
-
* into a merge corner — stays continuous. Pass-through verticals outside the
|
|
219
|
-
* run keep their own column (column 0 stays neutral).
|
|
220
|
-
*/
|
|
221
|
-
function resolveConnectorLaneColors(
|
|
222
|
-
cells: readonly StructuralCell[],
|
|
223
|
-
startLane: number,
|
|
224
|
-
): ConnectorLaneColors {
|
|
225
|
-
const glyph = new Array<number>(cells.length);
|
|
226
|
-
const dash = new Array<number>(cells.length);
|
|
227
|
-
let owner = NEUTRAL_LANE;
|
|
228
|
-
for (let column = cells.length - 1; column >= 0; column--) {
|
|
229
|
-
const cell = cells[column];
|
|
230
|
-
switch (cell?.kind) {
|
|
231
|
-
case 'branch-corner':
|
|
232
|
-
case 'merge-corner':
|
|
233
|
-
owner = column;
|
|
234
|
-
glyph[column] = column;
|
|
235
|
-
dash[column] = column;
|
|
236
|
-
break;
|
|
237
|
-
case 'branch-tee':
|
|
238
|
-
case 'merge-tee':
|
|
239
|
-
if (column === startLane) {
|
|
240
|
-
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
241
|
-
glyph[column] = column;
|
|
242
|
-
dash[column] = served;
|
|
243
|
-
} else {
|
|
244
|
-
dash[column] = owner === NEUTRAL_LANE ? column : owner;
|
|
245
|
-
glyph[column] = column;
|
|
246
|
-
owner = column;
|
|
247
|
-
}
|
|
248
|
-
break;
|
|
249
|
-
case 'arc-crossing':
|
|
250
|
-
glyph[column] = column;
|
|
251
|
-
dash[column] = column;
|
|
252
|
-
break;
|
|
253
|
-
case 'horizontal-pass': {
|
|
254
|
-
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
255
|
-
glyph[column] = served;
|
|
256
|
-
dash[column] = served;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
default:
|
|
260
|
-
glyph[column] = column;
|
|
261
|
-
dash[column] = column;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return { glyph, dash };
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Style a structural glyph by its resolved colour column. Column 0 and the
|
|
269
|
-
* neutral sentinel render dim (`style.lane`); columns ≥ 1 take a palette hue.
|
|
270
|
-
*/
|
|
271
|
-
function laneStylerForColumn(
|
|
272
|
-
colorColumn: number,
|
|
273
|
-
colorize: boolean,
|
|
274
|
-
style: MigrationListStyler,
|
|
275
|
-
): (text: string) => string {
|
|
276
|
-
if (!colorize || colorColumn <= NEUTRAL_LANE) {
|
|
277
|
-
return (text) => style.lane(text);
|
|
278
|
-
}
|
|
279
|
-
return laneColorForColumn(colorColumn);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Tint a branch-owned token (direction arrow, migration name) by its edge's
|
|
284
|
-
* lane so the whole branch row reads in one colour. Column 0 has nothing to be
|
|
285
|
-
* told apart from in the common linear chain, so it keeps the token's existing
|
|
286
|
-
* default styling (`fallback`) rather than a palette hue; only lanes ≥ 1 take a
|
|
287
|
-
* colour. With colour off, the fallback (also colourless) is used unchanged.
|
|
288
|
-
*/
|
|
289
|
-
function branchStylerOrDefault(
|
|
290
|
-
column: number,
|
|
291
|
-
colorize: boolean,
|
|
292
|
-
fallback: (text: string) => string,
|
|
293
|
-
): (text: string) => string {
|
|
294
|
-
if (!colorize || column <= NEUTRAL_LANE) {
|
|
295
|
-
return fallback;
|
|
296
|
-
}
|
|
297
|
-
return laneColorForColumn(column);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Render a connector tee (`├─` / `┬─` / `┴─`) with its junction glyph and its
|
|
302
|
-
* trailing dash coloured independently: the junction anchors its own lane while
|
|
303
|
-
* the dash leads into the branch on its right.
|
|
304
|
-
*/
|
|
305
|
-
function renderConnectorTee(
|
|
306
|
-
pair: string,
|
|
307
|
-
glyphColumn: number,
|
|
308
|
-
dashColumn: number,
|
|
309
|
-
colorize: boolean,
|
|
310
|
-
style: MigrationListStyler,
|
|
311
|
-
): string {
|
|
312
|
-
const glyph = laneStylerForColumn(glyphColumn, colorize, style);
|
|
313
|
-
if (glyphColumn === dashColumn) {
|
|
314
|
-
return glyph(pair);
|
|
315
|
-
}
|
|
316
|
-
return glyph(pair.slice(0, 1)) + laneStylerForColumn(dashColumn, colorize, style)(pair.slice(1));
|
|
317
|
-
}
|
|
318
|
-
|
|
319
119
|
/**
|
|
320
120
|
* A node-marker glyph pair (`○◂`, `○─`, `*<`, `*-`) is the contract node
|
|
321
|
-
* marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`).
|
|
322
|
-
* marker
|
|
323
|
-
*
|
|
324
|
-
*
|
|
121
|
+
* marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`).
|
|
122
|
+
* The marker is the signal and stays bright (`style.kind`); the connector is
|
|
123
|
+
* gutter and stays dim (`style.lane`) — consistent with the plain node marker,
|
|
124
|
+
* which is never dimmed.
|
|
325
125
|
*/
|
|
326
|
-
function renderNodeMarkerPair(
|
|
327
|
-
pair
|
|
328
|
-
nodeColumn: number,
|
|
329
|
-
arcColumn: number,
|
|
330
|
-
colorize: boolean,
|
|
331
|
-
style: MigrationListStyler,
|
|
332
|
-
): string {
|
|
333
|
-
const marker = laneStylerForColumn(nodeColumn, colorize, style);
|
|
334
|
-
const connector = laneStylerForColumn(arcColumn, colorize, style);
|
|
335
|
-
return marker(pair.slice(0, 1)) + connector(pair.slice(1));
|
|
126
|
+
function renderNodeMarkerPair(pair: string, style: MigrationListStyler): string {
|
|
127
|
+
return style.kind(pair.slice(0, 1)) + style.lane(pair.slice(1));
|
|
336
128
|
}
|
|
337
129
|
|
|
338
130
|
function renderCellPair(
|
|
339
131
|
cell: StructuralCell,
|
|
340
|
-
column: number,
|
|
341
|
-
colors: RowLaneColors,
|
|
342
|
-
colorize: boolean,
|
|
343
132
|
style: MigrationListStyler,
|
|
344
133
|
palette: MigrationGraphTreeGlyphPalette,
|
|
345
134
|
): string {
|
|
346
|
-
const laneColumn = colors.lane[column] ?? column;
|
|
347
|
-
const lane = laneStylerForColumn(laneColumn, colorize, style);
|
|
348
135
|
switch (cell.kind) {
|
|
349
|
-
case 'node':
|
|
350
|
-
|
|
351
|
-
if (cell.
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
if (cell.arcTee === true) {
|
|
355
|
-
return renderNodeMarkerPair(palette.arcTee, column, arcColumn, colorize, style);
|
|
356
|
-
}
|
|
357
|
-
return lane(palette.node);
|
|
358
|
-
}
|
|
136
|
+
case 'node':
|
|
137
|
+
if (cell.arcLand === true) return renderNodeMarkerPair(palette.arcLand, style);
|
|
138
|
+
if (cell.arcTee === true) return renderNodeMarkerPair(palette.arcTee, style);
|
|
139
|
+
return style.kind(palette.node);
|
|
359
140
|
case 'vertical-pass':
|
|
360
|
-
return lane(palette.verticalPass);
|
|
141
|
+
return style.lane(palette.verticalPass);
|
|
361
142
|
case 'edge-lane':
|
|
143
|
+
// The lane stays dim; the direction arrow (↑ / ↓ / ⟲) is the signal and
|
|
144
|
+
// stays bright, like the contract-node marker.
|
|
362
145
|
return cell.ownsLabel
|
|
363
|
-
? lane(palette.verticalPass.trimEnd()) +
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
colorize,
|
|
367
|
-
style.kind,
|
|
368
|
-
)(arrowForEdgeKind(cell.edgeKind, palette))
|
|
369
|
-
: lane(palette.verticalPass);
|
|
146
|
+
? style.lane(palette.verticalPass.trimEnd()) +
|
|
147
|
+
style.kind(arrowForEdgeKind(cell.edgeKind, palette))
|
|
148
|
+
: style.lane(palette.verticalPass);
|
|
370
149
|
case 'branch-tee':
|
|
371
|
-
return lane(palette.branchTee);
|
|
150
|
+
return style.lane(palette.branchTee);
|
|
372
151
|
case 'merge-tee':
|
|
373
|
-
return lane(palette.mergeTee);
|
|
152
|
+
return style.lane(palette.mergeTee);
|
|
374
153
|
case 'branch-corner':
|
|
375
|
-
return lane(palette.branchCorner);
|
|
154
|
+
return style.lane(palette.branchCorner);
|
|
376
155
|
case 'merge-corner':
|
|
377
|
-
return lane(palette.mergeCorner);
|
|
156
|
+
return style.lane(palette.mergeCorner);
|
|
378
157
|
case 'arc-branch-corner':
|
|
379
|
-
return lane(palette.arcBranchCorner);
|
|
158
|
+
return style.lane(palette.arcBranchCorner);
|
|
380
159
|
case 'arc-branch-tee':
|
|
381
|
-
return lane(palette.arcBranchTee);
|
|
160
|
+
return style.lane(palette.arcBranchTee);
|
|
382
161
|
case 'arc-land-corner':
|
|
383
|
-
return lane(palette.arcLandCorner);
|
|
162
|
+
return style.lane(palette.arcLandCorner);
|
|
384
163
|
case 'arc-crossing':
|
|
385
|
-
return lane(palette.
|
|
164
|
+
return style.lane(palette.arcCrossing);
|
|
386
165
|
case 'arc-land-bridge':
|
|
387
|
-
return lane(palette.arcLandBridge);
|
|
166
|
+
return style.lane(palette.arcLandBridge);
|
|
388
167
|
case 'horizontal-pass':
|
|
389
|
-
return lane(palette.horizontalPass);
|
|
168
|
+
return style.lane(palette.horizontalPass);
|
|
390
169
|
case 'empty':
|
|
391
170
|
return ' ';
|
|
392
171
|
}
|
|
@@ -395,56 +174,34 @@ function renderCellPair(
|
|
|
395
174
|
function renderConnectorRow(
|
|
396
175
|
row: MigrationGraphGridRow,
|
|
397
176
|
gridWidth: number,
|
|
398
|
-
colorize: boolean,
|
|
399
177
|
style: MigrationListStyler,
|
|
400
178
|
palette: MigrationGraphTreeGlyphPalette,
|
|
401
179
|
): string {
|
|
402
180
|
const isMerge = row.kind === 'merge-connector';
|
|
403
181
|
if (row.cells.length > 0) {
|
|
404
|
-
const colors = resolveConnectorLaneColors(row.cells, row.startLane ?? 0);
|
|
405
182
|
let seenTee = false;
|
|
406
183
|
let out = '';
|
|
407
|
-
for (
|
|
408
|
-
const cell = row.cells[column];
|
|
409
|
-
if (cell === undefined) continue;
|
|
410
|
-
const glyphColumn = colors.glyph[column] ?? column;
|
|
411
|
-
const dashColumn = colors.dash[column] ?? glyphColumn;
|
|
412
|
-
const lane = laneStylerForColumn(glyphColumn, colorize, style);
|
|
184
|
+
for (const cell of row.cells) {
|
|
413
185
|
switch (cell.kind) {
|
|
414
186
|
case 'branch-tee':
|
|
415
|
-
out +=
|
|
416
|
-
seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee,
|
|
417
|
-
glyphColumn,
|
|
418
|
-
dashColumn,
|
|
419
|
-
colorize,
|
|
420
|
-
style,
|
|
421
|
-
);
|
|
187
|
+
out += style.lane(seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee);
|
|
422
188
|
seenTee = true;
|
|
423
189
|
break;
|
|
424
190
|
case 'merge-tee':
|
|
425
|
-
out +=
|
|
426
|
-
seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee,
|
|
427
|
-
glyphColumn,
|
|
428
|
-
dashColumn,
|
|
429
|
-
colorize,
|
|
430
|
-
style,
|
|
431
|
-
);
|
|
191
|
+
out += style.lane(seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee);
|
|
432
192
|
seenTee = true;
|
|
433
193
|
break;
|
|
434
194
|
case 'branch-corner':
|
|
435
|
-
out += lane(palette.branchCorner);
|
|
195
|
+
out += style.lane(palette.branchCorner);
|
|
436
196
|
break;
|
|
437
197
|
case 'merge-corner':
|
|
438
|
-
out += lane(palette.mergeCorner);
|
|
198
|
+
out += style.lane(palette.mergeCorner);
|
|
439
199
|
break;
|
|
440
200
|
case 'vertical-pass':
|
|
441
|
-
out += lane(palette.verticalPass);
|
|
201
|
+
out += style.lane(palette.verticalPass);
|
|
442
202
|
break;
|
|
443
203
|
case 'horizontal-pass':
|
|
444
|
-
out += lane(palette.horizontalPass);
|
|
445
|
-
break;
|
|
446
|
-
case 'arc-crossing':
|
|
447
|
-
out += renderConnectorTee(palette.arcCrossing, glyphColumn, dashColumn, colorize, style);
|
|
204
|
+
out += style.lane(palette.horizontalPass);
|
|
448
205
|
break;
|
|
449
206
|
default:
|
|
450
207
|
out += ' ';
|
|
@@ -461,15 +218,13 @@ function renderConnectorRow(
|
|
|
461
218
|
|
|
462
219
|
const start = row.startLane ?? 0;
|
|
463
220
|
const end = row.endLane ?? start;
|
|
464
|
-
// The whole fork/merge run reads as one line in the served lane's hue (the
|
|
465
|
-
// corner it reaches); pass-through columns outside the run keep their own.
|
|
466
|
-
const runLane = laneStylerForColumn(end, colorize, style);
|
|
467
221
|
let out = '';
|
|
468
222
|
for (let column = 0; column < gridWidth; column++) {
|
|
469
223
|
if (column < start || column > end) out += ' ';
|
|
470
|
-
else if (column === start) out +=
|
|
471
|
-
else if (column === end)
|
|
472
|
-
|
|
224
|
+
else if (column === start) out += style.lane(palette.connectorBranchTee);
|
|
225
|
+
else if (column === end)
|
|
226
|
+
out += style.lane(isMerge ? palette.mergeCorner : palette.branchCorner);
|
|
227
|
+
else out += style.lane(isMerge ? palette.connectorMergeTeeCo : palette.connectorBranchTeeCo);
|
|
473
228
|
}
|
|
474
229
|
return out;
|
|
475
230
|
}
|
|
@@ -542,13 +297,6 @@ function padVisible(text: string, targetWidth: number): string {
|
|
|
542
297
|
return text + ' '.repeat(padding);
|
|
543
298
|
}
|
|
544
299
|
|
|
545
|
-
const ANSI_ESCAPE = '\x1b';
|
|
546
|
-
|
|
547
|
-
function trimTrailingWhitespace(line: string): string {
|
|
548
|
-
const trailingSpaceBeforeReset = new RegExp(`[\\t ]+((?:${ANSI_ESCAPE}\\[[0-9;]*m)+)$`);
|
|
549
|
-
return line.replace(trailingSpaceBeforeReset, '$1').replace(/\s+$/, '');
|
|
550
|
-
}
|
|
551
|
-
|
|
552
300
|
function gridWidthForModel(rows: readonly MigrationGraphGridRow[]): number {
|
|
553
301
|
return rows.reduce(
|
|
554
302
|
(max, row) =>
|
|
@@ -625,32 +373,19 @@ export function renderMigrationGraphTree(
|
|
|
625
373
|
}
|
|
626
374
|
|
|
627
375
|
if (row.kind === 'branch-connector' || row.kind === 'merge-connector') {
|
|
628
|
-
lines.push(
|
|
629
|
-
trimTrailingWhitespace(renderConnectorRow(row, gridWidth, opts.colorize, style, palette)),
|
|
630
|
-
);
|
|
376
|
+
lines.push(renderConnectorRow(row, gridWidth, style, palette).replace(/\s+$/, ''));
|
|
631
377
|
continue;
|
|
632
378
|
}
|
|
633
379
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
.map((cell, column) =>
|
|
637
|
-
renderCellPair(cell, column, cellColors, opts.colorize, style, palette),
|
|
638
|
-
)
|
|
639
|
-
.join('');
|
|
380
|
+
let gutter = row.cells.map((cell) => renderCellPair(cell, style, palette)).join('');
|
|
381
|
+
const prevRow = model.rows[rowIndex - 1];
|
|
640
382
|
let laneSpan = row.cells.length;
|
|
641
383
|
if (row.kind === 'node') {
|
|
642
384
|
const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;
|
|
643
|
-
if (contractHash === EMPTY_CONTRACT_HASH) {
|
|
385
|
+
if (prevRow?.kind === 'merge-connector' || contractHash === EMPTY_CONTRACT_HASH) {
|
|
644
386
|
laneSpan = 1;
|
|
645
387
|
} else {
|
|
646
|
-
|
|
647
|
-
for (let column = row.cells.length - 1; column >= 0; column--) {
|
|
648
|
-
if (row.cells[column]?.kind !== 'empty') {
|
|
649
|
-
lastActiveColumn = column;
|
|
650
|
-
break;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
laneSpan = lastActiveColumn >= 0 ? lastActiveColumn + 1 : 1;
|
|
388
|
+
laneSpan = row.cells.length;
|
|
654
389
|
}
|
|
655
390
|
}
|
|
656
391
|
const labelColumn =
|
|
@@ -667,16 +402,12 @@ export function renderMigrationGraphTree(
|
|
|
667
402
|
) {
|
|
668
403
|
gutter = row.cells
|
|
669
404
|
.slice(0, 1)
|
|
670
|
-
.map((cell,
|
|
671
|
-
renderCellPair(cell, column, cellColors, opts.colorize, style, palette),
|
|
672
|
-
)
|
|
405
|
+
.map((cell) => renderCellPair(cell, style, palette))
|
|
673
406
|
.join('');
|
|
674
407
|
} else if (row.kind === 'node' && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) {
|
|
675
408
|
gutter = row.cells
|
|
676
409
|
.slice(0, laneSpan)
|
|
677
|
-
.map((cell,
|
|
678
|
-
renderCellPair(cell, column, cellColors, opts.colorize, style, palette),
|
|
679
|
-
)
|
|
410
|
+
.map((cell) => renderCellPair(cell, style, palette))
|
|
680
411
|
.join('');
|
|
681
412
|
} else if (gutter.length < laneSpan * 2) {
|
|
682
413
|
gutter = gutter.padEnd(laneSpan * 2, ' ');
|
|
@@ -690,18 +421,16 @@ export function renderMigrationGraphTree(
|
|
|
690
421
|
if (contractHash === EMPTY_CONTRACT_HASH) {
|
|
691
422
|
const trailingLanes = row.cells
|
|
692
423
|
.slice(1)
|
|
693
|
-
.map((cell,
|
|
694
|
-
renderCellPair(cell, offset + 1, cellColors, opts.colorize, style, palette),
|
|
695
|
-
)
|
|
424
|
+
.map((cell) => renderCellPair(cell, style, palette))
|
|
696
425
|
.join('');
|
|
697
426
|
const emptyGutter = palette.emptySource.padEnd(2, ' ') + trailingLanes;
|
|
698
427
|
const overlayNames = overlayNamesForContract(contractHash, opts);
|
|
699
428
|
if (overlayNames.length === 0) {
|
|
700
|
-
lines.push(
|
|
429
|
+
lines.push(emptyGutter.replace(/\s+$/, ''));
|
|
701
430
|
continue;
|
|
702
431
|
}
|
|
703
432
|
const overlay = style.refs(overlayNames);
|
|
704
|
-
lines.push(
|
|
433
|
+
lines.push(`${padVisible(emptyGutter, dataColumn)}${overlay}`.replace(/\s+$/, ''));
|
|
705
434
|
continue;
|
|
706
435
|
}
|
|
707
436
|
const hashText = style.sourceHash(
|
|
@@ -713,7 +442,7 @@ export function renderMigrationGraphTree(
|
|
|
713
442
|
? ' '.repeat(Math.max(0, dataColumn - labelColumn - stringWidth(hashText)))
|
|
714
443
|
: '';
|
|
715
444
|
const overlay = overlayNames.length > 0 ? style.refs(overlayNames) : '';
|
|
716
|
-
lines.push(
|
|
445
|
+
lines.push(`${gutterPad}${hashText}${overlayPad}${overlay}`.replace(/\s+$/, ''));
|
|
717
446
|
continue;
|
|
718
447
|
}
|
|
719
448
|
|
|
@@ -721,48 +450,10 @@ export function renderMigrationGraphTree(
|
|
|
721
450
|
if (edge === undefined) continue;
|
|
722
451
|
|
|
723
452
|
const dirNamePadding = ' '.repeat(Math.max(0, dirNameWidth - edge.dirName.length));
|
|
724
|
-
const
|
|
725
|
-
// A branched name keeps its bold (via `style.dirName`) and adds the lane
|
|
726
|
-
// hue, so it reads as one with its lane/arrow; column-0 names stay bold-only.
|
|
727
|
-
const dirNameStyler =
|
|
728
|
-
opts.colorize && laneIndex > NEUTRAL_LANE
|
|
729
|
-
? (text: string) => forcedBold(laneColorForColumn(laneIndex)(text))
|
|
730
|
-
: style.dirName;
|
|
731
|
-
const dirName = `${dirNameStyler(edge.dirName)}${dirNamePadding}`;
|
|
453
|
+
const dirName = `${style.dirName(edge.dirName)}${dirNamePadding}`;
|
|
732
454
|
const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);
|
|
733
|
-
lines.push(
|
|
455
|
+
lines.push(`${gutterPad}${dirName}${hashColumn}`.replace(/\s+$/, ''));
|
|
734
456
|
}
|
|
735
457
|
|
|
736
458
|
return lines.join('\n');
|
|
737
459
|
}
|
|
738
|
-
|
|
739
|
-
export interface RenderMigrationGraphLegendOptions {
|
|
740
|
-
readonly colorize: boolean;
|
|
741
|
-
readonly glyphMode?: GlyphMode;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
/**
|
|
745
|
-
* A compact key for the `--tree` visual language: the contract marker, the
|
|
746
|
-
* in-lane direction arrows, the empty baseline, the `(refs)` overlay (including
|
|
747
|
-
* the reserved `db` live-database and `contract` working-schema markers), and a
|
|
748
|
-
* worked sample of the data-column `from → to` migration hash arrow.
|
|
749
|
-
*
|
|
750
|
-
* Honors the same glyph palette (unicode vs ASCII) and `colorize` gate as the
|
|
751
|
-
* tree renderer, so the key matches whatever the graph itself drew and stays
|
|
752
|
-
* pipe-safe (zero ANSI when color is off). The caller adds the trailing blank
|
|
753
|
-
* line that separates this stderr key from the graph on stdout.
|
|
754
|
-
*/
|
|
755
|
-
export function renderMigrationGraphLegend(opts: RenderMigrationGraphLegendOptions): string {
|
|
756
|
-
const palette = paletteFor(opts.glyphMode ?? 'unicode');
|
|
757
|
-
const style = createAnsiMigrationListStyler({ useColor: opts.colorize });
|
|
758
|
-
const node = palette.node.trimEnd();
|
|
759
|
-
const sampleArrow = `${style.sourceHash('aaaaaa')} ${style.glyph(palette.forwardArrow)} ${style.destHash('bbbbbb')}`;
|
|
760
|
-
return [
|
|
761
|
-
'Legend:',
|
|
762
|
-
` ${style.kind(node)} contract ${style.kind(palette.edgeArrow.forward)} forward ${style.kind(palette.edgeArrow.rollback)} rollback`,
|
|
763
|
-
` ${style.kind(palette.edgeArrow.self)} migration without schema change`,
|
|
764
|
-
` ${style.glyph(palette.emptySource)} empty database (baseline)`,
|
|
765
|
-
` ${style.refs(['refs'])} ${DB_MARKER_NAME} / ${CONTRACT_MARKER_NAME} markers`,
|
|
766
|
-
` ${sampleArrow} migration from contract aaaaaa to bbbbbb`,
|
|
767
|
-
].join('\n');
|
|
768
|
-
}
|
|
@@ -180,38 +180,3 @@ export function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {
|
|
|
180
180
|
|
|
181
181
|
return flags as GlobalFlags;
|
|
182
182
|
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Bridges the two TTY checks (stdout via `flags`, stdin via
|
|
186
|
-
* `process.stdin.isTTY`) into the `canPrompt` boolean the interactive
|
|
187
|
-
* `init` flow consumes.
|
|
188
|
-
*
|
|
189
|
-
* Per the [Style Guide § Interactivity](../../../../../../../docs/CLI%20Style%20Guide.md#interactivity):
|
|
190
|
-
*
|
|
191
|
-
* - `flags.interactive` governs *decoration* (TerminalUI, intro/outro,
|
|
192
|
-
* spinners) and is derived from stdout-TTY by `parseGlobalFlags`,
|
|
193
|
-
* honouring `--interactive` / `--no-interactive`.
|
|
194
|
-
* - Prompting additionally requires a stdin TTY — closing stdin is a
|
|
195
|
-
* common signal in CI / agent environments even when stdout stays
|
|
196
|
-
* attached.
|
|
197
|
-
* - `--interactive` is the explicit override: when the user passes it,
|
|
198
|
-
* we honour it (e.g. testing flows where stdin is stubbed).
|
|
199
|
-
*
|
|
200
|
-
* Single source of truth for the interactive-prompt decision: both the
|
|
201
|
-
* `init` action handler and the preAction telemetry bridge derive
|
|
202
|
-
* prompt-eligibility from this helper so they cannot drift. Lives in
|
|
203
|
-
* `global-flags` (alongside `parseGlobalFlags`) to keep
|
|
204
|
-
* `utils/telemetry` and `commands/init/index` free of an import cycle.
|
|
205
|
-
*
|
|
206
|
-
* Exported so callers and tests can derive the same value without
|
|
207
|
-
* touching `process` globals.
|
|
208
|
-
*/
|
|
209
|
-
export function deriveCanPrompt(opts: {
|
|
210
|
-
readonly flagsInteractive: boolean | undefined;
|
|
211
|
-
readonly optionInteractive: boolean | undefined;
|
|
212
|
-
readonly stdinIsTTY: boolean;
|
|
213
|
-
}): boolean {
|
|
214
|
-
if (opts.optionInteractive === true) return true;
|
|
215
|
-
if (opts.flagsInteractive === false) return false;
|
|
216
|
-
return opts.stdinIsTTY;
|
|
217
|
-
}
|