@prisma-next/cli 0.12.0-dev.22 → 0.12.0-dev.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/cli.mjs +6 -6
  2. package/dist/commands/migrate.d.mts +1 -1
  3. package/dist/commands/migration-graph.d.mts +4 -4
  4. package/dist/commands/migration-graph.mjs +164 -1
  5. package/dist/commands/migration-graph.mjs.map +1 -0
  6. package/dist/commands/migration-list.d.mts +3 -3
  7. package/dist/commands/migration-list.d.mts.map +1 -1
  8. package/dist/commands/migration-list.mjs +4 -6
  9. package/dist/commands/migration-list.mjs.map +1 -1
  10. package/dist/commands/migration-log.d.mts +3 -3
  11. package/dist/commands/migration-log.mjs +1 -1
  12. package/dist/commands/migration-plan.d.mts +1 -1
  13. package/dist/commands/migration-plan.mjs +1 -1
  14. package/dist/commands/migration-show.d.mts +1 -1
  15. package/dist/commands/migration-status.d.mts +1 -1
  16. package/dist/commands/ref.d.mts +1 -1
  17. package/dist/commands/telemetry/index.mjs +1 -1
  18. package/dist/exports/control-api.d.mts +1 -1
  19. package/dist/exports/init-output.mjs +1 -1
  20. package/dist/{global-flags-DSkV6iYT.d.mts → global-flags-DG4uY5tV.d.mts} +1 -1
  21. package/dist/{global-flags-DSkV6iYT.d.mts.map → global-flags-DG4uY5tV.d.mts.map} +1 -1
  22. package/dist/{init-S2vxszo_.mjs → init-B6kKrmf7.mjs} +2 -2
  23. package/dist/{init-S2vxszo_.mjs.map → init-B6kKrmf7.mjs.map} +1 -1
  24. package/dist/{migration-graph-CeBB07Cc.mjs → migration-graph-tree-render-BQdhKBO8.mjs} +405 -165
  25. package/dist/migration-graph-tree-render-BQdhKBO8.mjs.map +1 -0
  26. package/dist/{migration-log-Cj-T-r0o.mjs → migration-log-BzPmks3c.mjs} +2 -2
  27. package/dist/{migration-log-Cj-T-r0o.mjs.map → migration-log-BzPmks3c.mjs.map} +1 -1
  28. package/dist/{migration-plan-BQAbZkj_.mjs → migration-plan-CaeKCKp4.mjs} +1 -1
  29. package/dist/{migration-plan-BQAbZkj_.mjs.map → migration-plan-CaeKCKp4.mjs.map} +1 -1
  30. package/dist/{migration-types-Bhmj0RSa.d.mts → migration-types-CAQ-0TEE.d.mts} +1 -1
  31. package/dist/{migration-types-Bhmj0RSa.d.mts.map → migration-types-CAQ-0TEE.d.mts.map} +1 -1
  32. package/dist/{output-BD61elic.mjs → output-CF_hqzI-.mjs} +1 -1
  33. package/dist/{output-BD61elic.mjs.map → output-CF_hqzI-.mjs.map} +1 -1
  34. package/dist/{telemetry-Bu85x2Gy.mjs → telemetry-Q88WHwlv.mjs} +1 -1
  35. package/dist/{telemetry-Bu85x2Gy.mjs.map → telemetry-Q88WHwlv.mjs.map} +1 -1
  36. package/dist/{terminal-ui-BgLiAOYi.d.mts → terminal-ui-C3xGyxW-.d.mts} +1 -1
  37. package/dist/{terminal-ui-BgLiAOYi.d.mts.map → terminal-ui-C3xGyxW-.d.mts.map} +1 -1
  38. package/dist/{types-C8OcDFBe.d.mts → types-DiC683UW.d.mts} +1 -1
  39. package/dist/{types-C8OcDFBe.d.mts.map → types-DiC683UW.d.mts.map} +1 -1
  40. package/package.json +18 -18
  41. package/src/commands/migration-list.ts +11 -15
  42. package/src/utils/formatters/migration-graph-tree-render.ts +31 -1
  43. package/src/utils/formatters/migration-list-data-column.ts +0 -93
  44. package/src/utils/formatters/migration-list-graph-topology.ts +1 -7
  45. package/src/utils/formatters/migration-list-render.ts +102 -70
  46. package/dist/migration-graph-CeBB07Cc.mjs.map +0 -1
  47. package/dist/migration-list-styler-CsMECsY4.mjs +0 -414
  48. package/dist/migration-list-styler-CsMECsY4.mjs.map +0 -1
@@ -26,10 +26,7 @@ import {
26
26
  setCommandSeeAlso,
27
27
  } from '../utils/command-helpers';
28
28
  import { buildReadAggregate } from '../utils/contract-space-aggregate-loader';
29
- import {
30
- buildMigrationListTopologyBySpace,
31
- renderMigrationListWithStyle,
32
- } from '../utils/formatters/migration-list-render';
29
+ import { renderMigrationListWithStyle } from '../utils/formatters/migration-list-render';
33
30
  import { createAnsiMigrationListStyler } from '../utils/formatters/migration-list-styler';
34
31
  import type {
35
32
  MigrationListEntry,
@@ -143,8 +140,9 @@ export function renderMigrationListHumanOutput(
143
140
  options: MigrationListHumanRenderOptions,
144
141
  ): string {
145
142
  const styler = createAnsiMigrationListStyler({ useColor: options.useColor });
146
- const topologyBySpaceId = buildMigrationListTopologyBySpace(result);
147
- return renderMigrationListWithStyle(result, styler, options.glyphMode, topologyBySpaceId);
143
+ return renderMigrationListWithStyle(result, styler, options.glyphMode, {
144
+ colorize: options.useColor,
145
+ });
148
146
  }
149
147
 
150
148
  /**
@@ -222,7 +220,7 @@ export async function executeMigrationListCommand(
222
220
  if (!flags.json && !flags.quiet) {
223
221
  const header = formatStyledHeader({
224
222
  command: 'migration list',
225
- description: 'List on-disk migrations, latest first, per contract space',
223
+ description: 'List on-disk migrations per contract space',
226
224
  details: [
227
225
  { label: 'config', value: configPath },
228
226
  { label: 'migrations', value: migrationsRelative },
@@ -253,15 +251,13 @@ export function createMigrationListCommand(): Command {
253
251
  const command = new Command('list');
254
252
  setCommandDescriptions(
255
253
  command,
256
- 'List on-disk migrations, latest first, per contract space',
254
+ 'List on-disk migrations per contract space',
257
255
  'Enumerates every on-disk migration under migrations/<space>/ for every\n' +
258
- 'contract space found on disk, latest first. Offline — does not consult\n' +
259
- 'the database. Each row leads with a kind glyph (* forward, ↩ rollback,\n' +
260
- ' self), then dirName, then source destination contract hashes\n' +
261
- '(7-char git-style). Self-edges show a single hash. Invariants render as\n' +
262
- '{...}; refs on the destination as (production, db). Pass --space <id>\n' +
263
- 'to narrow to one contract space. --ascii forces ASCII kind glyphs\n' +
264
- '(orthogonal to --no-color).',
256
+ 'contract space found on disk. Offline — does not consult the database.\n' +
257
+ 'Human output draws the shared migration graph tree with operation counts,\n' +
258
+ 'invariants on each migration row, and refs on destination contract nodes.\n' +
259
+ 'Pass --space <id> to narrow to one contract space. --ascii forces ASCII\n' +
260
+ 'tree glyphs (orthogonal to --no-color).',
265
261
  );
266
262
  setCommandExamples(command, [
267
263
  'prisma-next migration list',
@@ -27,8 +27,15 @@ const LABEL_GAP = 2;
27
27
  */
28
28
  const DB_MARKER_NAME = 'db';
29
29
 
30
+ export interface MigrationEdgeAnnotation {
31
+ readonly status?: 'applied' | 'pending';
32
+ readonly operationCount?: number;
33
+ readonly invariants?: readonly string[];
34
+ }
35
+
30
36
  export interface RenderMigrationGraphTreeOptions {
31
37
  readonly refsByHash?: ReadonlyMap<string, readonly string[]>;
38
+ readonly edgeAnnotationsByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;
32
39
  readonly dbHash?: string;
33
40
  readonly contractHash?: string;
34
41
  readonly activeRefName?: string;
@@ -571,6 +578,28 @@ function createTreeStyler(opts: RenderMigrationGraphTreeOptions): MigrationListS
571
578
  };
572
579
  }
573
580
 
581
+ function formatEdgeAnnotationSuffix(
582
+ migrationHash: string,
583
+ opts: RenderMigrationGraphTreeOptions,
584
+ style: MigrationListStyler,
585
+ ): string {
586
+ const annotation = opts.edgeAnnotationsByHash?.get(migrationHash);
587
+ if (annotation === undefined) {
588
+ return '';
589
+ }
590
+ const segments: string[] = [];
591
+ if (annotation.operationCount !== undefined) {
592
+ segments.push(`${annotation.operationCount} ops`);
593
+ }
594
+ if (annotation.invariants !== undefined && annotation.invariants.length > 0) {
595
+ segments.push(style.invariants(annotation.invariants));
596
+ }
597
+ if (segments.length === 0) {
598
+ return '';
599
+ }
600
+ return ` ${segments.join(' ')}`;
601
+ }
602
+
574
603
  function formatEdgeHashColumn(
575
604
  edge: ClassifiedEdge,
576
605
  style: MigrationListStyler,
@@ -784,7 +813,8 @@ export function renderMigrationGraphTree(
784
813
  : style.dirName;
785
814
  const dirName = `${dirNameStyler(edge.dirName)}${dirNamePadding}`;
786
815
  const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);
787
- lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}`));
816
+ const annotationSuffix = formatEdgeAnnotationSuffix(edge.migrationHash, opts, style);
817
+ lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}${annotationSuffix}`));
788
818
  }
789
819
 
790
820
  return lines.join('\n');
@@ -1,32 +1,10 @@
1
1
  import type { GlyphMode } from '../glyph-mode';
2
- import type { MigrationEdgeKind } from './migration-list-graph-topology';
3
- import type { MigrationListStyler } from './migration-list-render';
4
- import type { MigrationListEntry } from './migration-list-types';
5
2
 
6
3
  export const MIGRATION_LIST_HASH_WIDTH = 7;
7
4
  export const MIGRATION_LIST_EMPTY_SOURCE = '∅';
8
5
  export const MIGRATION_LIST_ASCII_EMPTY_SOURCE = '-';
9
6
  export const MIGRATION_LIST_FORWARD_EDGE_GLYPH = '→';
10
7
  export const MIGRATION_LIST_ASCII_FORWARD_EDGE_GLYPH = '->';
11
- export const MIGRATION_LIST_DECORATION_PREFIX = ' ';
12
-
13
- export const MIGRATION_LIST_UNICODE_KIND_GLYPH: Record<MigrationEdgeKind, string> = {
14
- forward: '*',
15
- rollback: '↩',
16
- self: '⟲',
17
- };
18
-
19
- export const MIGRATION_LIST_ASCII_KIND_GLYPH: Record<MigrationEdgeKind, string> = {
20
- forward: '*',
21
- rollback: '<',
22
- self: '~',
23
- };
24
-
25
- export function migrationListKindGlyph(glyphMode: GlyphMode, edgeKind: MigrationEdgeKind): string {
26
- return glyphMode === 'ascii'
27
- ? MIGRATION_LIST_ASCII_KIND_GLYPH[edgeKind]
28
- : MIGRATION_LIST_UNICODE_KIND_GLYPH[edgeKind];
29
- }
30
8
 
31
9
  export function migrationListForwardArrow(glyphMode: GlyphMode): string {
32
10
  return glyphMode === 'ascii'
@@ -42,74 +20,3 @@ export function abbreviateContractHash(hash: string): string {
42
20
  const stripped = hash.startsWith('sha256:') ? hash.slice(7) : hash;
43
21
  return stripped.slice(0, MIGRATION_LIST_HASH_WIDTH);
44
22
  }
45
-
46
- export function computeMigrationDirNameWidth(migrations: readonly MigrationListEntry[]): number {
47
- if (migrations.length === 0) return 0;
48
- return Math.max(...migrations.map((entry) => entry.dirName.length)) + 2;
49
- }
50
-
51
- function formatSourceColumn(
52
- from: string | null,
53
- style: MigrationListStyler,
54
- emptySource: string,
55
- ): string {
56
- if (from === null) {
57
- return style.glyph(emptySource) + ' '.repeat(MIGRATION_LIST_HASH_WIDTH - emptySource.length);
58
- }
59
- return style.sourceHash(abbreviateContractHash(from));
60
- }
61
-
62
- export function formatDecorations(
63
- providedInvariants: readonly string[],
64
- refs: readonly string[],
65
- style: MigrationListStyler,
66
- ): string {
67
- const blocks: string[] = [];
68
- if (providedInvariants.length > 0) {
69
- blocks.push(style.invariants(providedInvariants));
70
- }
71
- if (refs.length > 0) {
72
- blocks.push(style.refs(refs));
73
- }
74
- if (blocks.length === 0) return '';
75
- return `${MIGRATION_LIST_DECORATION_PREFIX}${blocks.join(' ')}`;
76
- }
77
-
78
- export interface MigrationDataColumnOptions {
79
- readonly dirNameWidth: number;
80
- readonly edgeKind: MigrationEdgeKind;
81
- readonly style: MigrationListStyler;
82
- readonly forwardArrow?: string;
83
- readonly emptySource?: string;
84
- }
85
-
86
- export function formatMigrationDataColumn(
87
- migration: MigrationListEntry,
88
- options: MigrationDataColumnOptions,
89
- ): string {
90
- const {
91
- dirNameWidth,
92
- edgeKind,
93
- style,
94
- forwardArrow = MIGRATION_LIST_FORWARD_EDGE_GLYPH,
95
- emptySource = MIGRATION_LIST_EMPTY_SOURCE,
96
- } = options;
97
- const dirNamePadding = ' '.repeat(Math.max(0, dirNameWidth - migration.dirName.length));
98
- const dirName = `${style.dirName(migration.dirName)}${dirNamePadding}`;
99
- const decorations = formatDecorations(migration.providedInvariants, migration.refs, style);
100
-
101
- if (edgeKind === 'self') {
102
- const contractHash = migration.from ?? migration.to;
103
- const hash = style.sourceHash(abbreviateContractHash(contractHash));
104
- return `${dirName}${hash}${decorations}`;
105
- }
106
-
107
- const source = formatSourceColumn(migration.from, style, emptySource);
108
- const arrow = style.glyph(forwardArrow);
109
- const dest = style.destHash(abbreviateContractHash(migration.to));
110
- return `${dirName}${source} ${arrow} ${dest}${decorations}`;
111
- }
112
-
113
- export function formatNodeLineDataColumn(contractHash: string, style: MigrationListStyler): string {
114
- return style.sourceHash(abbreviateContractHash(contractHash));
115
- }
@@ -11,8 +11,7 @@ export interface MigrationListGraphTopology {
11
11
  }
12
12
 
13
13
  // ---------------------------------------------------------------------------
14
- // Shared classifier — operates on a normalized edge shape common to both
15
- // MigrationListEntry (Tier-2) and MigrationEdge / MigrationGraph (Tier-3).
14
+ // Shared classifier — operates on a normalized edge shape for MigrationGraph.
16
15
  // ---------------------------------------------------------------------------
17
16
 
18
17
  interface NormalizedEdge {
@@ -315,9 +314,6 @@ function canonicalFrom(from: string | null): string {
315
314
 
316
315
  /**
317
316
  * Classify forward/rollback/self for a Tier-2 `MigrationListEntry[]` edge set.
318
- * Returns the kind of each migration plus the forward in/out degree of each
319
- * contract node. This is the established Tier-2 surface; its behaviour is
320
- * unchanged — only its implementation now delegates to the shared classifier.
321
317
  */
322
318
  export function classifyMigrationListGraphTopology(
323
319
  entries: readonly MigrationListEntry[],
@@ -333,8 +329,6 @@ export function classifyMigrationListGraphTopology(
333
329
 
334
330
  /**
335
331
  * Classify forward/rollback/self for a `MigrationGraph` edge set (Tier-3).
336
- * Delegates to the same shared classifier as `classifyMigrationListGraphTopology`
337
- * so both tiers agree on forward/rollback/self without duplicating logic.
338
332
  */
339
333
  export function classifyMigrationGraphTopology(graph: MigrationGraph): MigrationListGraphTopology {
340
334
  const normalized: NormalizedEdge[] = [];
@@ -1,16 +1,12 @@
1
+ import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
2
+ import type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';
1
3
  import type { GlyphMode } from '../glyph-mode';
4
+ import { buildMigrationGraphLayout } from './migration-graph-layout';
5
+ import { buildMigrationGraphRows } from './migration-graph-rows';
2
6
  import {
3
- computeMigrationDirNameWidth,
4
- formatMigrationDataColumn,
5
- migrationListEmptySource,
6
- migrationListForwardArrow,
7
- migrationListKindGlyph,
8
- } from './migration-list-data-column';
9
- import {
10
- classifyMigrationListGraphTopology,
11
- type MigrationEdgeKind,
12
- type MigrationListGraphTopology,
13
- } from './migration-list-graph-topology';
7
+ type MigrationEdgeAnnotation,
8
+ renderMigrationGraphTree,
9
+ } from './migration-graph-tree-render';
14
10
  import type { MigrationListEntry, MigrationListResult } from './migration-list-types';
15
11
 
16
12
  export type { GlyphMode } from '../glyph-mode';
@@ -62,42 +58,88 @@ export const IDENTITY_MIGRATION_LIST_STYLER: MigrationListStyler = {
62
58
  emptyState: (text) => text,
63
59
  };
64
60
 
65
- function resolveEdgeKind(
66
- migrationHash: string,
67
- kindByMigrationHash: ReadonlyMap<string, MigrationEdgeKind>,
68
- ): MigrationEdgeKind {
69
- return kindByMigrationHash.get(migrationHash) ?? 'forward';
61
+ function canonicalFrom(from: string | null): string {
62
+ return from ?? EMPTY_CONTRACT_HASH;
70
63
  }
71
64
 
72
- function formatMigrationRow(
73
- migration: MigrationListEntry,
74
- dirNameWidth: number,
75
- edgeKind: MigrationEdgeKind,
76
- glyphMode: GlyphMode,
77
- style: MigrationListStyler,
78
- ): string {
79
- const kindColumn = `${style.kind(migrationListKindGlyph(glyphMode, edgeKind))} `;
80
- const data = formatMigrationDataColumn(migration, {
81
- dirNameWidth,
82
- edgeKind,
83
- style,
84
- forwardArrow: migrationListForwardArrow(glyphMode),
85
- emptySource: migrationListEmptySource(glyphMode),
86
- });
87
- return `${kindColumn}${data}`;
65
+ export function migrationGraphFromListEntries(
66
+ entries: readonly MigrationListEntry[],
67
+ ): MigrationGraph {
68
+ const nodes = new Set<string>();
69
+ const forwardChain = new Map<string, MigrationEdge[]>();
70
+ const reverseChain = new Map<string, MigrationEdge[]>();
71
+ const migrationByHash = new Map<string, MigrationEdge>();
72
+
73
+ for (const entry of entries) {
74
+ const from = canonicalFrom(entry.from);
75
+ const edge: MigrationEdge = {
76
+ from,
77
+ to: entry.to,
78
+ migrationHash: entry.migrationHash,
79
+ dirName: entry.dirName,
80
+ createdAt: entry.createdAt,
81
+ invariants: entry.providedInvariants,
82
+ };
83
+ nodes.add(from);
84
+ nodes.add(entry.to);
85
+ const forward = forwardChain.get(from);
86
+ if (forward) forward.push(edge);
87
+ else forwardChain.set(from, [edge]);
88
+ const reverse = reverseChain.get(entry.to);
89
+ if (reverse) reverse.push(edge);
90
+ else reverseChain.set(entry.to, [edge]);
91
+ migrationByHash.set(entry.migrationHash, edge);
92
+ }
93
+
94
+ return { nodes, forwardChain, reverseChain, migrationByHash };
95
+ }
96
+
97
+ export function buildEdgeAnnotationsByHashFromListEntries(
98
+ entries: readonly MigrationListEntry[],
99
+ ): ReadonlyMap<string, MigrationEdgeAnnotation> {
100
+ const annotations = new Map<string, MigrationEdgeAnnotation>();
101
+ for (const entry of entries) {
102
+ annotations.set(entry.migrationHash, {
103
+ operationCount: entry.operationCount,
104
+ invariants: entry.providedInvariants,
105
+ });
106
+ }
107
+ return annotations;
108
+ }
109
+
110
+ export function buildRefsByHashFromListEntries(
111
+ entries: readonly MigrationListEntry[],
112
+ ): ReadonlyMap<string, readonly string[]> {
113
+ const refsByHash = new Map<string, readonly string[]>();
114
+ for (const entry of entries) {
115
+ if (entry.refs.length > 0) {
116
+ refsByHash.set(entry.to, entry.refs);
117
+ }
118
+ }
119
+ return refsByHash;
88
120
  }
89
121
 
90
122
  function formatEmptyStateLine(spaceId: string, style: MigrationListStyler): string {
91
123
  return style.emptyState(`There are no migrations in migrations/${spaceId}/ yet`);
92
124
  }
93
125
 
94
- function renderSpaceBlock(
126
+ function indentTreeBlock(treeOutput: string, indent: string): string {
127
+ if (treeOutput.length === 0) {
128
+ return treeOutput;
129
+ }
130
+ return treeOutput
131
+ .split('\n')
132
+ .map((line) => (line.length === 0 ? line : `${indent}${line}`))
133
+ .join('\n');
134
+ }
135
+
136
+ function renderSpaceTreeBlock(
95
137
  spaceId: string,
96
138
  migrations: readonly MigrationListEntry[],
97
139
  multiSpace: boolean,
98
140
  glyphMode: GlyphMode,
99
- kindByMigrationHash: ReadonlyMap<string, MigrationEdgeKind>,
100
141
  style: MigrationListStyler,
142
+ colorize: boolean,
101
143
  ): readonly string[] {
102
144
  if (migrations.length === 0) {
103
145
  const emptyLine = formatEmptyStateLine(spaceId, style);
@@ -107,50 +149,44 @@ function renderSpaceBlock(
107
149
  return [style.spaceHeading(`${spaceId}:`), ` ${emptyLine}`];
108
150
  }
109
151
 
110
- const dirNameWidth = computeMigrationDirNameWidth(migrations);
111
- const rows = migrations.map((entry) =>
112
- formatMigrationRow(
113
- entry,
114
- dirNameWidth,
115
- resolveEdgeKind(entry.migrationHash, kindByMigrationHash),
116
- glyphMode,
117
- style,
118
- ),
119
- );
152
+ const graph = migrationGraphFromListEntries(migrations);
153
+ const rowModel = buildMigrationGraphRows(graph);
154
+ const layout = buildMigrationGraphLayout(rowModel);
155
+ const treeOutput = renderMigrationGraphTree(layout, {
156
+ refsByHash: buildRefsByHashFromListEntries(migrations),
157
+ edgeAnnotationsByHash: buildEdgeAnnotationsByHashFromListEntries(migrations),
158
+ colorize,
159
+ glyphMode,
160
+ });
161
+
120
162
  if (!multiSpace) {
121
- return rows;
163
+ return treeOutput.length === 0 ? [] : [treeOutput];
122
164
  }
123
- return [style.spaceHeading(`${spaceId}:`), ...rows.map((row) => ` ${row}`)];
165
+
166
+ const indented = indentTreeBlock(treeOutput, ' ');
167
+ return [style.spaceHeading(`${spaceId}:`), indented];
124
168
  }
125
169
 
126
- export function buildMigrationListTopologyBySpace(
127
- result: MigrationListResult,
128
- ): ReadonlyMap<string, MigrationListGraphTopology> {
129
- const topologyBySpaceId = new Map<string, MigrationListGraphTopology>();
130
- for (const space of result.spaces) {
131
- topologyBySpaceId.set(space.spaceId, classifyMigrationListGraphTopology(space.migrations));
132
- }
133
- return topologyBySpaceId;
170
+ export interface RenderMigrationListWithStyleOptions {
171
+ readonly colorize?: boolean;
134
172
  }
135
173
 
136
174
  /**
137
- * Compose the styled `migration list` output. The renderer is
138
- * presentation-neutral every token passes through `style` before
139
- * landing in the output, so the same composition serves the pure-text
140
- * path ({@link renderMigrationList} via
141
- * {@link IDENTITY_MIGRATION_LIST_STYLER}) and the ANSI-styled CLI path
142
- * (via the ANSI styler the CLI shell wires up).
175
+ * Compose the styled `migration list` human output via the shared tree
176
+ * renderer. Each on-disk migration is one edge row with package-fact
177
+ * annotations; refs decorate destination contract nodes.
178
+ *
179
+ * `options.colorize` must match whether `style` emits ANSI (e.g. both true for
180
+ * `createAnsiMigrationListStyler({ useColor: true })`).
143
181
  */
144
182
  export function renderMigrationListWithStyle(
145
183
  result: MigrationListResult,
146
184
  style: MigrationListStyler,
147
185
  glyphMode: GlyphMode = 'unicode',
148
- topologyBySpaceId: ReadonlyMap<
149
- string,
150
- MigrationListGraphTopology
151
- > = buildMigrationListTopologyBySpace(result),
186
+ options: RenderMigrationListWithStyleOptions = {},
152
187
  ): string {
153
188
  const multiSpace = result.spaces.length > 1;
189
+ const colorize = options.colorize ?? false;
154
190
  const lines: string[] = [];
155
191
 
156
192
  for (let index = 0; index < result.spaces.length; index++) {
@@ -158,18 +194,14 @@ export function renderMigrationListWithStyle(
158
194
  if (index > 0) {
159
195
  lines.push('');
160
196
  }
161
- const topology = topologyBySpaceId.get(space.spaceId);
162
- const kindByMigrationHash =
163
- topology?.kindByMigrationHash ??
164
- classifyMigrationListGraphTopology(space.migrations).kindByMigrationHash;
165
197
  lines.push(
166
- ...renderSpaceBlock(
198
+ ...renderSpaceTreeBlock(
167
199
  space.spaceId,
168
200
  space.migrations,
169
201
  multiSpace,
170
202
  glyphMode,
171
- kindByMigrationHash,
172
203
  style,
204
+ colorize,
173
205
  ),
174
206
  );
175
207
  }