@prisma-next/cli 0.12.0-dev.28 → 0.12.0-dev.29

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 (102) hide show
  1. package/dist/cli.mjs +12 -12
  2. package/dist/{client-nygCs15r.mjs → client-xeWpMlq1.mjs} +4 -4
  3. package/dist/client-xeWpMlq1.mjs.map +1 -0
  4. package/dist/{command-helpers-D7TK5Y9e.mjs → command-helpers-DK_5ItoJ.mjs} +16 -2
  5. package/dist/command-helpers-DK_5ItoJ.mjs.map +1 -0
  6. package/dist/commands/contract-emit.mjs +1 -1
  7. package/dist/commands/contract-infer.mjs +1 -1
  8. package/dist/commands/db-init.mjs +3 -3
  9. package/dist/commands/db-schema.mjs +3 -3
  10. package/dist/commands/db-sign.mjs +4 -4
  11. package/dist/commands/db-update.mjs +4 -4
  12. package/dist/commands/db-verify.mjs +1 -1
  13. package/dist/commands/migrate.d.mts +1 -1
  14. package/dist/commands/migrate.mjs +4 -4
  15. package/dist/commands/migration-check.mjs +1 -1
  16. package/dist/commands/migration-graph.d.mts +12 -15
  17. package/dist/commands/migration-graph.d.mts.map +1 -1
  18. package/dist/commands/migration-graph.mjs +84 -51
  19. package/dist/commands/migration-graph.mjs.map +1 -1
  20. package/dist/commands/migration-list.d.mts +13 -4
  21. package/dist/commands/migration-list.d.mts.map +1 -1
  22. package/dist/commands/migration-list.mjs +1 -187
  23. package/dist/commands/migration-log.d.mts +2 -2
  24. package/dist/commands/migration-log.mjs +1 -1
  25. package/dist/commands/migration-new.mjs +3 -3
  26. package/dist/commands/migration-plan.d.mts +1 -1
  27. package/dist/commands/migration-plan.mjs +1 -1
  28. package/dist/commands/migration-show.d.mts +1 -1
  29. package/dist/commands/migration-show.mjs +2 -2
  30. package/dist/commands/migration-status.d.mts +20 -2
  31. package/dist/commands/migration-status.d.mts.map +1 -1
  32. package/dist/commands/migration-status.mjs +2 -3
  33. package/dist/commands/ref.d.mts +1 -1
  34. package/dist/commands/ref.mjs +2 -2
  35. package/dist/commands/telemetry/index.mjs +1 -1
  36. package/dist/{contract-at-errors-CK3qoqZf.mjs → contract-at-errors-DG3kjgoz.mjs} +2 -2
  37. package/dist/{contract-at-errors-CK3qoqZf.mjs.map → contract-at-errors-DG3kjgoz.mjs.map} +1 -1
  38. package/dist/{contract-emit-Dzf73HdD.mjs → contract-emit-BO0l6fnT.mjs} +3 -3
  39. package/dist/{contract-emit-Dzf73HdD.mjs.map → contract-emit-BO0l6fnT.mjs.map} +1 -1
  40. package/dist/{contract-emit-DwlIz5Zg.mjs → contract-emit-C0Bs0VRj.mjs} +3 -3
  41. package/dist/{contract-emit-DwlIz5Zg.mjs.map → contract-emit-C0Bs0VRj.mjs.map} +1 -1
  42. package/dist/{contract-infer-Bzh___GO.mjs → contract-infer-2wtPflGH.mjs} +3 -3
  43. package/dist/{contract-infer-Bzh___GO.mjs.map → contract-infer-2wtPflGH.mjs.map} +1 -1
  44. package/dist/{contract-space-aggregate-loader-5zmOENc4.mjs → contract-space-aggregate-loader-Dbr3-jHF.mjs} +2 -2
  45. package/dist/{contract-space-aggregate-loader-5zmOENc4.mjs.map → contract-space-aggregate-loader-Dbr3-jHF.mjs.map} +1 -1
  46. package/dist/{db-verify-CNz036sw.mjs → db-verify-CxHiSiTG.mjs} +4 -4
  47. package/dist/{db-verify-CNz036sw.mjs.map → db-verify-CxHiSiTG.mjs.map} +1 -1
  48. package/dist/exports/control-api.d.mts +1 -1
  49. package/dist/exports/control-api.mjs +2 -2
  50. package/dist/exports/index.mjs +1 -1
  51. package/dist/exports/init-output.mjs +1 -1
  52. package/dist/{framework-components-CyM_xYCY.mjs → framework-components-CxOVKAAh.mjs} +2 -2
  53. package/dist/{framework-components-CyM_xYCY.mjs.map → framework-components-CxOVKAAh.mjs.map} +1 -1
  54. package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-DG4uY5tV.d.mts} +1 -1
  55. package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-DG4uY5tV.d.mts.map} +1 -1
  56. package/dist/{init-DJsQpr_6.mjs → init-R272pxux.mjs} +4 -4
  57. package/dist/{init-DJsQpr_6.mjs.map → init-R272pxux.mjs.map} +1 -1
  58. package/dist/{inspect-live-schema-DE76Ou4D.mjs → inspect-live-schema-RekOwfi5.mjs} +3 -3
  59. package/dist/{inspect-live-schema-DE76Ou4D.mjs.map → inspect-live-schema-RekOwfi5.mjs.map} +1 -1
  60. package/dist/{migration-check-CL2MzDRX.mjs → migration-check-Dc0cOhKH.mjs} +2 -2
  61. package/dist/{migration-check-CL2MzDRX.mjs.map → migration-check-Dc0cOhKH.mjs.map} +1 -1
  62. package/dist/{migration-command-scaffold-194pA8F5.mjs → migration-command-scaffold-ApB3NxWY.mjs} +3 -3
  63. package/dist/{migration-command-scaffold-194pA8F5.mjs.map → migration-command-scaffold-ApB3NxWY.mjs.map} +1 -1
  64. package/dist/{migration-graph-tree-render-CVmV9sWr.mjs → migration-graph-space-render-dmLLWift.mjs} +389 -210
  65. package/dist/migration-graph-space-render-dmLLWift.mjs.map +1 -0
  66. package/dist/migration-list-C5sXrl0U.mjs +228 -0
  67. package/dist/migration-list-C5sXrl0U.mjs.map +1 -0
  68. package/dist/{migration-log-CP6skD5b.mjs → migration-log-DD_vCbYW.mjs} +4 -4
  69. package/dist/{migration-log-CP6skD5b.mjs.map → migration-log-DD_vCbYW.mjs.map} +1 -1
  70. package/dist/{migration-plan-D61N1hID.mjs → migration-plan-CeTjQOIG.mjs} +5 -5
  71. package/dist/{migration-plan-D61N1hID.mjs.map → migration-plan-CeTjQOIG.mjs.map} +1 -1
  72. package/dist/{migration-status--ejfYqWS.mjs → migration-status-qV8ctwPy.mjs} +61 -45
  73. package/dist/migration-status-qV8ctwPy.mjs.map +1 -0
  74. package/dist/{output-B60Gw5fu.mjs → output-CF_hqzI-.mjs} +1 -1
  75. package/dist/{output-B60Gw5fu.mjs.map → output-CF_hqzI-.mjs.map} +1 -1
  76. package/dist/{telemetry-CnfdMrpv.mjs → telemetry-S-NGi9U6.mjs} +2 -2
  77. package/dist/{telemetry-CnfdMrpv.mjs.map → telemetry-S-NGi9U6.mjs.map} +1 -1
  78. package/dist/{types-BYwWOyYJ.d.mts → types-Mh7mdPHM.d.mts} +1 -1
  79. package/dist/{types-BYwWOyYJ.d.mts.map → types-Mh7mdPHM.d.mts.map} +1 -1
  80. package/dist/{verify-By66Zu3y.mjs → verify-BdI-BgYi.mjs} +2 -2
  81. package/dist/{verify-By66Zu3y.mjs.map → verify-BdI-BgYi.mjs.map} +1 -1
  82. package/package.json +18 -18
  83. package/src/commands/migration-graph.ts +125 -58
  84. package/src/commands/migration-list.ts +43 -9
  85. package/src/commands/migration-status.ts +106 -74
  86. package/src/control-api/operations/db-apply.ts +7 -4
  87. package/src/utils/cli-errors.ts +17 -0
  88. package/src/utils/formatters/migration-graph-lane-colors.ts +164 -1
  89. package/src/utils/formatters/migration-graph-rows.ts +128 -15
  90. package/src/utils/formatters/migration-graph-space-render.ts +138 -0
  91. package/src/utils/formatters/migration-graph-tree-render.ts +149 -239
  92. package/src/utils/formatters/migration-list-data-column.ts +6 -0
  93. package/src/utils/formatters/migration-list-render.ts +43 -23
  94. package/src/utils/formatters/migration-list-styler.ts +48 -5
  95. package/src/utils/legend.ts +38 -0
  96. package/dist/client-nygCs15r.mjs.map +0 -1
  97. package/dist/command-helpers-D7TK5Y9e.mjs.map +0 -1
  98. package/dist/commands/migration-list.mjs.map +0 -1
  99. package/dist/migration-graph-tree-render-CVmV9sWr.mjs.map +0 -1
  100. package/dist/migration-status--ejfYqWS.mjs.map +0 -1
  101. package/dist/migration-types-D2FW63pr.d.mts +0 -15
  102. package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
@@ -173,10 +173,19 @@ function compareNodesTipsFirst(a: string, b: string, rank: ReadonlyMap<string, n
173
173
  * at the same rank — stable across edge-insertion order and correct under
174
174
  * diamonds, cross-links, and rollbacks.
175
175
  */
176
+ function maxRank(rank: ReadonlyMap<string, number>): number {
177
+ let max = 0;
178
+ for (const value of rank.values()) {
179
+ if (value > max) max = value;
180
+ }
181
+ return max;
182
+ }
183
+
176
184
  function layerNodesByLongestForwardPath(
177
185
  componentNodes: ReadonlySet<string>,
178
186
  topology: MigrationListGraphTopology,
179
187
  graph: MigrationGraph,
188
+ contractHash: string | undefined,
180
189
  ): readonly string[] {
181
190
  const forwardOut = new Map<string, string[]>();
182
191
 
@@ -224,6 +233,15 @@ function layerNodesByLongestForwardPath(
224
233
  }
225
234
  }
226
235
 
236
+ if (
237
+ contractHash !== undefined &&
238
+ contractHash !== EMPTY_CONTRACT_HASH &&
239
+ componentNodes.has(contractHash) &&
240
+ (forwardOut.get(contractHash) ?? []).length === 0
241
+ ) {
242
+ rank.set(contractHash, maxRank(rank) + 1);
243
+ }
244
+
227
245
  return [...componentNodes].sort((a, b) => compareNodesTipsFirst(a, b, rank));
228
246
  }
229
247
 
@@ -262,6 +280,99 @@ function detachedContractHash(
262
280
  : undefined;
263
281
  }
264
282
 
283
+ function isForwardLeaf(node: string, edges: readonly ClassifiedEdge[]): boolean {
284
+ return !edges.some((e) => e.kind === 'forward' && e.from === node && e.from !== e.to);
285
+ }
286
+
287
+ function forwardReachableFrom(
288
+ start: string,
289
+ forwardTo: ReadonlyMap<string, readonly string[]>,
290
+ ): ReadonlySet<string> {
291
+ const reachable = new Set<string>([start]);
292
+ const queue = [start];
293
+ while (queue.length > 0) {
294
+ const node = queue.shift();
295
+ if (node === undefined) continue;
296
+ for (const next of forwardTo.get(node) ?? []) {
297
+ if (!reachable.has(next)) {
298
+ reachable.add(next);
299
+ queue.push(next);
300
+ }
301
+ }
302
+ }
303
+ return reachable;
304
+ }
305
+
306
+ function buildForwardToMap(edges: readonly ClassifiedEdge[]): Map<string, string[]> {
307
+ const forwardTo = new Map<string, string[]>();
308
+ for (const edge of edges) {
309
+ if (edge.kind !== 'forward' || edge.from === edge.to) continue;
310
+ const bucket = forwardTo.get(edge.from);
311
+ if (bucket) bucket.push(edge.to);
312
+ else forwardTo.set(edge.from, [edge.to]);
313
+ }
314
+ return forwardTo;
315
+ }
316
+
317
+ function sortEdgesForContractHashTrunk(
318
+ edges: ClassifiedEdge[],
319
+ contractHash: string | undefined,
320
+ ): ClassifiedEdge[] {
321
+ if (
322
+ contractHash === undefined ||
323
+ contractHash === EMPTY_CONTRACT_HASH ||
324
+ !isForwardLeaf(contractHash, edges)
325
+ ) {
326
+ return edges;
327
+ }
328
+
329
+ const preferredLeaf = contractHash;
330
+ const forwardTo = buildForwardToMap(edges);
331
+ const reachability = new Map<string, ReadonlySet<string>>();
332
+ function canReachContractHash(from: string): boolean {
333
+ let cached = reachability.get(from);
334
+ if (cached === undefined) {
335
+ cached = forwardReachableFrom(from, forwardTo);
336
+ reachability.set(from, cached);
337
+ }
338
+ return cached.has(preferredLeaf);
339
+ }
340
+
341
+ function trunkBias(edge: ClassifiedEdge): number {
342
+ if (edge.kind !== 'forward' || edge.from === edge.to) return 0;
343
+ if (edge.to === preferredLeaf) return 2;
344
+ if (canReachContractHash(edge.to)) return 1;
345
+ return 0;
346
+ }
347
+
348
+ return edges
349
+ .map((edge, index) => ({ edge, index, bias: trunkBias(edge) }))
350
+ .sort((a, b) => {
351
+ if (a.edge.from !== b.edge.from) return a.index - b.index;
352
+ if (a.bias !== b.bias) return b.bias - a.bias;
353
+ return a.index - b.index;
354
+ })
355
+ .map(({ edge }) => edge);
356
+ }
357
+
358
+ function rebuildEdgeLookupMaps(edges: readonly ClassifiedEdge[]): {
359
+ edgesByFrom: Map<string, ClassifiedEdge[]>;
360
+ edgesByTo: Map<string, ClassifiedEdge[]>;
361
+ } {
362
+ const edgesByFrom = new Map<string, ClassifiedEdge[]>();
363
+ const edgesByTo = new Map<string, ClassifiedEdge[]>();
364
+ for (const classified of edges) {
365
+ const fromBucket = edgesByFrom.get(classified.from);
366
+ if (fromBucket) fromBucket.push(classified);
367
+ else edgesByFrom.set(classified.from, [classified]);
368
+
369
+ const toBucket = edgesByTo.get(classified.to);
370
+ if (toBucket) toBucket.push(classified);
371
+ else edgesByTo.set(classified.to, [classified]);
372
+ }
373
+ return { edgesByFrom, edgesByTo };
374
+ }
375
+
265
376
  export function buildMigrationGraphRows(
266
377
  graph: MigrationGraph,
267
378
  options: BuildMigrationGraphRowsOptions = {},
@@ -284,31 +395,23 @@ export function buildMigrationGraphRows(
284
395
 
285
396
  // 2. Build classified edge list
286
397
  const edges: ClassifiedEdge[] = [];
287
- const edgesByFrom = new Map<string, ClassifiedEdge[]>();
288
- const edgesByTo = new Map<string, ClassifiedEdge[]>();
289
398
 
290
399
  for (const edgeList of graph.forwardChain.values()) {
291
400
  for (const edge of edgeList) {
292
401
  const kind = topology.kindByMigrationHash.get(edge.migrationHash) ?? 'forward';
293
- const classified: ClassifiedEdge = {
402
+ edges.push({
294
403
  migrationHash: edge.migrationHash,
295
404
  from: edge.from,
296
405
  to: edge.to,
297
406
  dirName: edge.dirName,
298
407
  kind,
299
- };
300
- edges.push(classified);
301
-
302
- const fromBucket = edgesByFrom.get(edge.from);
303
- if (fromBucket) fromBucket.push(classified);
304
- else edgesByFrom.set(edge.from, [classified]);
305
-
306
- const toBucket = edgesByTo.get(edge.to);
307
- if (toBucket) toBucket.push(classified);
308
- else edgesByTo.set(edge.to, [classified]);
408
+ });
309
409
  }
310
410
  }
311
411
 
412
+ const sortedEdges = sortEdgesForContractHashTrunk(edges, options.contractHash);
413
+ const { edgesByFrom, edgesByTo } = rebuildEdgeLookupMaps(sortedEdges);
414
+
312
415
  // 3. Find weakly-connected components (ordered: EMPTY first, then lex)
313
416
  const components = weaklyConnectedComponents(graph);
314
417
 
@@ -318,7 +421,12 @@ export function buildMigrationGraphRows(
318
421
  if (i > 0) nodes.push(null);
319
422
  const component = components[i];
320
423
  if (component === undefined) continue;
321
- const ordered = layerNodesByLongestForwardPath(component, topology, graph);
424
+ const ordered = layerNodesByLongestForwardPath(
425
+ component,
426
+ topology,
427
+ graph,
428
+ options.contractHash,
429
+ );
322
430
  for (const node of ordered) {
323
431
  nodes.push(node);
324
432
  }
@@ -332,5 +440,10 @@ export function buildMigrationGraphRows(
332
440
  nodes.unshift(detached);
333
441
  }
334
442
 
335
- return { nodes, edges, edgesByFrom, edgesByTo };
443
+ return {
444
+ nodes,
445
+ edges: sortedEdges,
446
+ edgesByFrom,
447
+ edgesByTo,
448
+ };
336
449
  }
@@ -0,0 +1,138 @@
1
+ import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
2
+ import type { GlyphMode } from '../glyph-mode';
3
+ import { buildMigrationGraphLayout } from './migration-graph-layout';
4
+ import { buildMigrationGraphRows } from './migration-graph-rows';
5
+ import {
6
+ computeMaxDirNameLengthForLayout,
7
+ computeMaxEdgeTreePrefixWidthForLayout,
8
+ type MigrationEdgeAnnotation,
9
+ renderMigrationGraphTree,
10
+ } from './migration-graph-tree-render';
11
+ import {
12
+ buildEdgeAnnotationsByHashFromListEntries,
13
+ buildRefsByHashFromListEntries,
14
+ type MigrationListStyler,
15
+ } from './migration-list-render';
16
+ import type { MigrationListEntry } from './migration-list-types';
17
+
18
+ export { buildEdgeAnnotationsByHashFromListEntries } from './migration-list-render';
19
+
20
+ export function mergeMigrationEdgeAnnotations(
21
+ listOverlay: ReadonlyMap<string, MigrationEdgeAnnotation>,
22
+ statusOverlay: ReadonlyMap<string, MigrationEdgeAnnotation>,
23
+ ): ReadonlyMap<string, MigrationEdgeAnnotation> {
24
+ const merged = new Map<string, MigrationEdgeAnnotation>();
25
+ for (const [migrationHash, listAnnotation] of listOverlay) {
26
+ const statusAnnotation = statusOverlay.get(migrationHash);
27
+ merged.set(migrationHash, {
28
+ ...listAnnotation,
29
+ ...(statusAnnotation?.status !== undefined ? { status: statusAnnotation.status } : {}),
30
+ });
31
+ }
32
+ return merged;
33
+ }
34
+
35
+ export interface RenderMigrationGraphSpaceTreeInput {
36
+ readonly graph: MigrationGraph;
37
+ readonly migrations: readonly MigrationListEntry[];
38
+ readonly liveContractHash: string;
39
+ readonly glyphMode: GlyphMode;
40
+ readonly colorize: boolean;
41
+ readonly refsByHash?: ReadonlyMap<string, readonly string[]>;
42
+ readonly statusOverlayByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;
43
+ readonly dbHash?: string;
44
+ readonly styler?: MigrationListStyler;
45
+ readonly globalMaxEdgeTreePrefixWidth?: number;
46
+ readonly globalMaxDirNameWidth?: number;
47
+ }
48
+
49
+ export interface ComputeGlobalMaxEdgeTreePrefixWidthInput {
50
+ readonly graph: MigrationGraph;
51
+ readonly liveContractHash: string;
52
+ }
53
+
54
+ export function computeGlobalMaxEdgeTreePrefixWidth(
55
+ inputs: readonly ComputeGlobalMaxEdgeTreePrefixWidthInput[],
56
+ ): number {
57
+ let globalMax = 0;
58
+ for (const input of inputs) {
59
+ const rowModel = buildMigrationGraphRows(input.graph, {
60
+ contractHash: input.liveContractHash,
61
+ });
62
+ const layout = buildMigrationGraphLayout(rowModel);
63
+ globalMax = Math.max(globalMax, computeMaxEdgeTreePrefixWidthForLayout(layout));
64
+ }
65
+ return globalMax;
66
+ }
67
+
68
+ export function computeGlobalMaxDirNameWidth(
69
+ inputs: readonly ComputeGlobalMaxEdgeTreePrefixWidthInput[],
70
+ ): number {
71
+ let globalMax = 0;
72
+ for (const input of inputs) {
73
+ const rowModel = buildMigrationGraphRows(input.graph, {
74
+ contractHash: input.liveContractHash,
75
+ });
76
+ const layout = buildMigrationGraphLayout(rowModel);
77
+ globalMax = Math.max(globalMax, computeMaxDirNameLengthForLayout(layout));
78
+ }
79
+ return globalMax;
80
+ }
81
+
82
+ function renderMigrationGraphSpaceTreeInternal(input: RenderMigrationGraphSpaceTreeInput): string {
83
+ const rowModel = buildMigrationGraphRows(input.graph, {
84
+ contractHash: input.liveContractHash,
85
+ });
86
+ const layout = buildMigrationGraphLayout(rowModel);
87
+ const listOverlay = buildEdgeAnnotationsByHashFromListEntries(input.migrations);
88
+ const edgeAnnotationsByHash =
89
+ input.statusOverlayByHash === undefined
90
+ ? listOverlay
91
+ : mergeMigrationEdgeAnnotations(listOverlay, input.statusOverlayByHash);
92
+ return renderMigrationGraphTree(layout, {
93
+ refsByHash: input.refsByHash ?? buildRefsByHashFromListEntries(input.migrations),
94
+ contractHash: input.liveContractHash,
95
+ edgeAnnotationsByHash,
96
+ colorize: input.colorize,
97
+ glyphMode: input.glyphMode,
98
+ ...(input.dbHash !== undefined ? { dbHash: input.dbHash } : {}),
99
+ ...(input.styler !== undefined ? { styler: input.styler } : {}),
100
+ ...(input.globalMaxEdgeTreePrefixWidth !== undefined
101
+ ? { globalMaxEdgeTreePrefixWidth: input.globalMaxEdgeTreePrefixWidth }
102
+ : {}),
103
+ ...(input.globalMaxDirNameWidth !== undefined
104
+ ? { globalMaxDirNameWidth: input.globalMaxDirNameWidth }
105
+ : {}),
106
+ });
107
+ }
108
+
109
+ export function renderMigrationGraphSpaceTree(input: RenderMigrationGraphSpaceTreeInput): string {
110
+ return renderMigrationGraphSpaceTreeInternal(input);
111
+ }
112
+
113
+ export function renderMigrationGraphSpaceTrees(
114
+ inputs: readonly RenderMigrationGraphSpaceTreeInput[],
115
+ ): readonly string[] {
116
+ const globalMaxTreePrefix =
117
+ inputs.length > 1 ? computeGlobalMaxEdgeTreePrefixWidth(inputs) : undefined;
118
+ const globalMaxDirName = inputs.length > 1 ? computeGlobalMaxDirNameWidth(inputs) : undefined;
119
+ return inputs.map((input) =>
120
+ renderMigrationGraphSpaceTreeInternal({
121
+ ...input,
122
+ ...(globalMaxTreePrefix !== undefined
123
+ ? { globalMaxEdgeTreePrefixWidth: globalMaxTreePrefix }
124
+ : {}),
125
+ ...(globalMaxDirName !== undefined ? { globalMaxDirNameWidth: globalMaxDirName } : {}),
126
+ }),
127
+ );
128
+ }
129
+
130
+ export function indentMigrationGraphTreeBlock(treeOutput: string, indent: string): string {
131
+ if (treeOutput.length === 0) {
132
+ return treeOutput;
133
+ }
134
+ return treeOutput
135
+ .split('\n')
136
+ .map((line) => (line.length === 0 ? line : `${indent}${line}`))
137
+ .join('\n');
138
+ }