@prisma-next/cli 0.12.0-dev.7 → 0.12.0-dev.71

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 (214) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.mjs +180 -163
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/{client-KgJorIvG.mjs → client-CJzuo5wX.mjs} +222 -107
  5. package/dist/client-CJzuo5wX.mjs.map +1 -0
  6. package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-DGMvGBeX.mjs} +318 -25
  7. package/dist/command-helpers-DGMvGBeX.mjs.map +1 -0
  8. package/dist/commands/contract-emit.d.mts.map +1 -1
  9. package/dist/commands/contract-emit.mjs +1 -1
  10. package/dist/commands/contract-infer.d.mts.map +1 -1
  11. package/dist/commands/contract-infer.mjs +1 -1
  12. package/dist/commands/db-init.d.mts.map +1 -1
  13. package/dist/commands/db-init.mjs +4 -5
  14. package/dist/commands/db-init.mjs.map +1 -1
  15. package/dist/commands/db-schema.d.mts.map +1 -1
  16. package/dist/commands/db-schema.mjs +3 -3
  17. package/dist/commands/db-schema.mjs.map +1 -1
  18. package/dist/commands/db-sign.d.mts.map +1 -1
  19. package/dist/commands/db-sign.mjs +6 -6
  20. package/dist/commands/db-sign.mjs.map +1 -1
  21. package/dist/commands/db-update.d.mts.map +1 -1
  22. package/dist/commands/db-update.mjs +10 -7
  23. package/dist/commands/db-update.mjs.map +1 -1
  24. package/dist/commands/db-verify.d.mts.map +1 -1
  25. package/dist/commands/db-verify.mjs +1 -1
  26. package/dist/commands/migrate.d.mts +37 -3
  27. package/dist/commands/migrate.d.mts.map +1 -1
  28. package/dist/commands/migrate.mjs +298 -12
  29. package/dist/commands/migrate.mjs.map +1 -1
  30. package/dist/commands/migration-check.d.mts +55 -13
  31. package/dist/commands/migration-check.d.mts.map +1 -1
  32. package/dist/commands/migration-check.mjs +3 -2
  33. package/dist/commands/migration-graph.d.mts +16 -25
  34. package/dist/commands/migration-graph.d.mts.map +1 -1
  35. package/dist/commands/migration-graph.mjs +185 -2
  36. package/dist/commands/migration-graph.mjs.map +1 -0
  37. package/dist/commands/migration-list.d.mts +26 -27
  38. package/dist/commands/migration-list.d.mts.map +1 -1
  39. package/dist/commands/migration-list.mjs +2 -190
  40. package/dist/commands/migration-log.d.mts +9 -19
  41. package/dist/commands/migration-log.d.mts.map +1 -1
  42. package/dist/commands/migration-log.mjs +1 -137
  43. package/dist/commands/migration-new.d.mts.map +1 -1
  44. package/dist/commands/migration-new.mjs +6 -5
  45. package/dist/commands/migration-new.mjs.map +1 -1
  46. package/dist/commands/migration-plan.d.mts +1 -1
  47. package/dist/commands/migration-plan.d.mts.map +1 -1
  48. package/dist/commands/migration-plan.mjs +1 -1
  49. package/dist/commands/migration-show.d.mts +17 -21
  50. package/dist/commands/migration-show.d.mts.map +1 -1
  51. package/dist/commands/migration-show.mjs +24 -36
  52. package/dist/commands/migration-show.mjs.map +1 -1
  53. package/dist/commands/migration-status.d.mts +42 -144
  54. package/dist/commands/migration-status.d.mts.map +1 -1
  55. package/dist/commands/migration-status.mjs +3 -759
  56. package/dist/commands/ref.d.mts +1 -1
  57. package/dist/commands/ref.d.mts.map +1 -1
  58. package/dist/commands/ref.mjs +4 -4
  59. package/dist/commands/ref.mjs.map +1 -1
  60. package/dist/commands/telemetry/index.d.mts +7 -0
  61. package/dist/commands/telemetry/index.d.mts.map +1 -0
  62. package/dist/commands/telemetry/index.mjs +2 -0
  63. package/dist/{config-loader-B6sJjXTv.mjs → config-loader-p9JMrekQ.mjs} +1 -1
  64. package/dist/{config-loader-B6sJjXTv.mjs.map → config-loader-p9JMrekQ.mjs.map} +1 -1
  65. package/dist/config-loader.mjs +1 -1
  66. package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-CFXsstzm.mjs} +2 -2
  67. package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-CFXsstzm.mjs.map} +1 -1
  68. package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-B_qriF8B.mjs} +5 -5
  69. package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-B_qriF8B.mjs.map} +1 -1
  70. package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-C8HmtboH.mjs} +12 -7
  71. package/dist/contract-emit-C8HmtboH.mjs.map +1 -0
  72. package/dist/{contract-enrichment-a0V5Y_mL.mjs → contract-enrichment-gn9sWbPw.mjs} +1 -1
  73. package/dist/{contract-enrichment-a0V5Y_mL.mjs.map → contract-enrichment-gn9sWbPw.mjs.map} +1 -1
  74. package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-BYT_ra_U.mjs} +5 -5
  75. package/dist/contract-infer-BYT_ra_U.mjs.map +1 -0
  76. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-ClI1KN6d.mjs} +5 -5
  77. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-ClI1KN6d.mjs.map} +1 -1
  78. package/dist/{db-verify-v_vUKXTU.mjs → db-verify-C24FKhb7.mjs} +6 -6
  79. package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-C24FKhb7.mjs.map} +1 -1
  80. package/dist/exports/control-api.d.mts +5 -3
  81. package/dist/exports/control-api.d.mts.map +1 -1
  82. package/dist/exports/control-api.mjs +3 -3
  83. package/dist/exports/index.mjs +1 -1
  84. package/dist/exports/index.mjs.map +1 -1
  85. package/dist/exports/init-output.d.mts +1 -3
  86. package/dist/exports/init-output.d.mts.map +1 -1
  87. package/dist/exports/init-output.mjs +1 -1
  88. package/dist/{extension-pack-inputs-IDvjRCi3.mjs → extension-pack-inputs-1ySHqxKG.mjs} +1 -1
  89. package/dist/{extension-pack-inputs-IDvjRCi3.mjs.map → extension-pack-inputs-1ySHqxKG.mjs.map} +1 -1
  90. package/dist/{framework-components-fYXjz_in.mjs → framework-components-YVQHhPH7.mjs} +2 -2
  91. package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-YVQHhPH7.mjs.map} +1 -1
  92. package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-BpoOYtNZ.d.mts} +1 -1
  93. package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-BpoOYtNZ.d.mts.map} +1 -1
  94. package/dist/{init-Cv9UzWL5.mjs → init-0HwB-Vh8.mjs} +5 -58
  95. package/dist/init-0HwB-Vh8.mjs.map +1 -0
  96. package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-DF6IwcDl.mjs} +7 -5
  97. package/dist/inspect-live-schema-DF6IwcDl.mjs.map +1 -0
  98. package/dist/migration-check-soB5uZEQ.mjs +573 -0
  99. package/dist/migration-check-soB5uZEQ.mjs.map +1 -0
  100. package/dist/migration-cli.mjs +1 -1
  101. package/dist/migration-cli.mjs.map +1 -1
  102. package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-DA-Lhx6o.mjs} +5 -5
  103. package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-DA-Lhx6o.mjs.map} +1 -1
  104. package/dist/migration-graph-command-render-BAOzyYF6.mjs +1822 -0
  105. package/dist/migration-graph-command-render-BAOzyYF6.mjs.map +1 -0
  106. package/dist/migration-list-CihF6w5z.mjs +230 -0
  107. package/dist/migration-list-CihF6w5z.mjs.map +1 -0
  108. package/dist/migration-log-B75IArji.mjs +222 -0
  109. package/dist/migration-log-B75IArji.mjs.map +1 -0
  110. package/dist/migration-path-target-Ce6OZImp.mjs +38 -0
  111. package/dist/migration-path-target-Ce6OZImp.mjs.map +1 -0
  112. package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-z5Ing-TD.mjs} +9 -8
  113. package/dist/migration-plan-z5Ing-TD.mjs.map +1 -0
  114. package/dist/migration-status-Di82DGvo.mjs +446 -0
  115. package/dist/migration-status-Di82DGvo.mjs.map +1 -0
  116. package/dist/{output-B60Gw5fu.mjs → output-mEQ74_nd.mjs} +1 -1
  117. package/dist/{output-B60Gw5fu.mjs.map → output-mEQ74_nd.mjs.map} +1 -1
  118. package/dist/{progress-adapter-C644QK8l.mjs → progress-adapter-CjAeTxY_.mjs} +1 -1
  119. package/dist/{progress-adapter-C644QK8l.mjs.map → progress-adapter-CjAeTxY_.mjs.map} +1 -1
  120. package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-BkXlikCA.mjs} +1 -1
  121. package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-BkXlikCA.mjs.map} +1 -1
  122. package/dist/schemas-CeGMYFYX.d.mts +191 -0
  123. package/dist/schemas-CeGMYFYX.d.mts.map +1 -0
  124. package/dist/schemas-KhXMzNA_.mjs +112 -0
  125. package/dist/schemas-KhXMzNA_.mjs.map +1 -0
  126. package/dist/telemetry-BIM4beEO.mjs +122 -0
  127. package/dist/telemetry-BIM4beEO.mjs.map +1 -0
  128. package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-DGRNFWna.d.mts} +1 -1
  129. package/dist/terminal-ui-DGRNFWna.d.mts.map +1 -0
  130. package/dist/{types-Dt_SfqFm.d.mts → types-C_tYiJYx.d.mts} +53 -31
  131. package/dist/types-C_tYiJYx.d.mts.map +1 -0
  132. package/dist/{verify-DCA9Sldu.mjs → verify-DcOYZ1tH.mjs} +2 -2
  133. package/dist/{verify-DCA9Sldu.mjs.map → verify-DcOYZ1tH.mjs.map} +1 -1
  134. package/package.json +26 -22
  135. package/src/cli.ts +5 -0
  136. package/src/commands/contract-infer.ts +2 -2
  137. package/src/commands/db-update.ts +7 -1
  138. package/src/commands/init/index.ts +6 -35
  139. package/src/commands/init/init.ts +1 -14
  140. package/src/commands/init/inputs.ts +0 -75
  141. package/src/commands/inspect-live-schema.ts +10 -0
  142. package/src/commands/json/schemas.ts +195 -0
  143. package/src/commands/migrate.ts +527 -8
  144. package/src/commands/migration-check.ts +469 -134
  145. package/src/commands/migration-graph.ts +151 -119
  146. package/src/commands/migration-list.ts +72 -39
  147. package/src/commands/migration-log.ts +52 -102
  148. package/src/commands/migration-new.ts +2 -1
  149. package/src/commands/migration-plan.ts +2 -1
  150. package/src/commands/migration-show.ts +31 -66
  151. package/src/commands/migration-status-overlay.ts +61 -0
  152. package/src/commands/migration-status.ts +458 -1066
  153. package/src/commands/telemetry/index.ts +107 -0
  154. package/src/commands/telemetry/status.ts +67 -0
  155. package/src/control-api/client.ts +70 -9
  156. package/src/control-api/operations/contract-emit.ts +22 -2
  157. package/src/control-api/operations/db-init.ts +6 -3
  158. package/src/control-api/operations/{db-apply.ts → db-run.ts} +55 -14
  159. package/src/control-api/operations/db-update.ts +7 -4
  160. package/src/control-api/operations/db-verify.ts +15 -5
  161. package/src/control-api/operations/{migration-apply.ts → migrate.ts} +181 -80
  162. package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
  163. package/src/control-api/types.ts +56 -29
  164. package/src/utils/cli-errors.ts +70 -2
  165. package/src/utils/formatters/errors.ts +11 -0
  166. package/src/utils/formatters/migration-graph-command-render.ts +239 -0
  167. package/src/utils/formatters/migration-graph-grid-layout.ts +857 -0
  168. package/src/utils/formatters/migration-graph-labels.ts +406 -0
  169. package/src/utils/formatters/migration-graph-model.ts +94 -0
  170. package/src/utils/formatters/migration-graph-occlusion-render.ts +245 -0
  171. package/src/utils/formatters/migration-graph-rows.ts +128 -15
  172. package/src/utils/formatters/migration-graph-space-render.ts +188 -0
  173. package/src/utils/formatters/migration-list-data-column.ts +4 -91
  174. package/src/utils/formatters/migration-list-graph-topology.ts +72 -94
  175. package/src/utils/formatters/migration-list-render.ts +135 -71
  176. package/src/utils/formatters/migration-list-styler.ts +46 -5
  177. package/src/utils/formatters/migration-list-types.ts +5 -21
  178. package/src/utils/formatters/migration-log-table.ts +205 -0
  179. package/src/utils/formatters/migrations.ts +33 -11
  180. package/src/utils/global-flags.ts +35 -0
  181. package/src/utils/integrity-violation-to-check-failure.ts +28 -19
  182. package/src/utils/legend.ts +38 -0
  183. package/src/utils/migration-path-target.ts +60 -0
  184. package/src/utils/telemetry.ts +68 -32
  185. package/dist/client-KgJorIvG.mjs.map +0 -1
  186. package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
  187. package/dist/commands/migration-list.mjs.map +0 -1
  188. package/dist/commands/migration-log.mjs.map +0 -1
  189. package/dist/commands/migration-status.mjs.map +0 -1
  190. package/dist/contract-emit-D-4jrNve.mjs.map +0 -1
  191. package/dist/contract-infer-D8uEbJuu.mjs.map +0 -1
  192. package/dist/graph-render-rFAqZujX.mjs +0 -1081
  193. package/dist/graph-render-rFAqZujX.mjs.map +0 -1
  194. package/dist/init-Cv9UzWL5.mjs.map +0 -1
  195. package/dist/inspect-live-schema-C6ohV_oQ.mjs.map +0 -1
  196. package/dist/migration-check-BiBJoYYW.mjs +0 -341
  197. package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
  198. package/dist/migration-graph-BzxEsMZg.mjs +0 -1463
  199. package/dist/migration-graph-BzxEsMZg.mjs.map +0 -1
  200. package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
  201. package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
  202. package/dist/migration-plan-9DJ7q7_z.mjs.map +0 -1
  203. package/dist/migration-types-D2FW63pr.d.mts +0 -15
  204. package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
  205. package/dist/migrations-Cv2jxNNK.mjs +0 -228
  206. package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
  207. package/dist/terminal-ui-5Y6mrg93.d.mts.map +0 -1
  208. package/dist/types-Dt_SfqFm.d.mts.map +0 -1
  209. package/src/utils/formatters/graph-migration-mapper.ts +0 -235
  210. package/src/utils/formatters/graph-render.ts +0 -1323
  211. package/src/utils/formatters/graph-types.ts +0 -120
  212. package/src/utils/formatters/migration-graph-lane-colors.ts +0 -31
  213. package/src/utils/formatters/migration-graph-layout.ts +0 -1119
  214. package/src/utils/formatters/migration-graph-tree-render.ts +0 -755
@@ -1,755 +0,0 @@
1
- import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
2
- import { bold, createColors } from 'colorette';
3
- import stringWidth from 'string-width';
4
- import type { GlyphMode } from '../glyph-mode';
5
- import { laneColorForColumn } from './migration-graph-lane-colors';
6
- import type {
7
- MigrationGraphGridModel,
8
- MigrationGraphGridRow,
9
- StructuralCell,
10
- } from './migration-graph-layout';
11
- import type { ClassifiedEdge } from './migration-graph-rows';
12
- import {
13
- MIGRATION_LIST_HASH_WIDTH,
14
- migrationListEmptySource,
15
- migrationListForwardArrow,
16
- } from './migration-list-data-column';
17
- import type { MigrationEdgeKind } from './migration-list-graph-topology';
18
- import type { MigrationListStyler } from './migration-list-render';
19
- import { CONTRACT_MARKER_NAME, createAnsiMigrationListStyler } from './migration-list-styler';
20
-
21
- const LABEL_GAP = 2;
22
-
23
- /**
24
- * The live-database overlay marker. Just another ref as far as styling goes —
25
- * the only emphasized markers are the active ref and the `contract`
26
- * desired-state marker (see {@link CONTRACT_MARKER_NAME}).
27
- */
28
- const DB_MARKER_NAME = 'db';
29
-
30
- export interface RenderMigrationGraphTreeOptions {
31
- readonly refsByHash?: ReadonlyMap<string, readonly string[]>;
32
- readonly dbHash?: string;
33
- readonly contractHash?: string;
34
- readonly activeRefName?: string;
35
- readonly hashLength?: number;
36
- readonly colorize: boolean;
37
- readonly glyphMode?: GlyphMode;
38
- }
39
-
40
- interface MigrationGraphTreeGlyphPalette {
41
- readonly node: string;
42
- readonly arcLand: string;
43
- readonly arcTee: string;
44
- readonly verticalPass: string;
45
- readonly branchTee: string;
46
- readonly mergeTee: string;
47
- readonly branchCorner: string;
48
- readonly mergeCorner: string;
49
- readonly arcBranchCorner: string;
50
- readonly arcBranchTee: string;
51
- readonly arcLandCorner: string;
52
- readonly arcCrossing: string;
53
- readonly arcLandBridge: string;
54
- readonly horizontalPass: string;
55
- readonly connectorBranchTee: string;
56
- readonly connectorBranchTeeCo: string;
57
- readonly connectorMergeTeeCo: string;
58
- readonly edgeArrow: Readonly<Record<MigrationEdgeKind, string>>;
59
- readonly forwardArrow: string;
60
- readonly emptySource: string;
61
- }
62
-
63
- const UNICODE_PALETTE: MigrationGraphTreeGlyphPalette = {
64
- node: '○ ',
65
- arcLand: '○◂',
66
- arcTee: '○─',
67
- verticalPass: '│ ',
68
- branchTee: '├─',
69
- mergeTee: '├─',
70
- branchCorner: '╮ ',
71
- mergeCorner: '╯ ',
72
- arcBranchCorner: '╮ ',
73
- arcBranchTee: '┬─',
74
- arcLandCorner: '╯ ',
75
- arcCrossing: '┼─',
76
- arcLandBridge: '──',
77
- horizontalPass: '──',
78
- connectorBranchTee: '├─',
79
- connectorBranchTeeCo: '┬─',
80
- connectorMergeTeeCo: '┴─',
81
- edgeArrow: { forward: '↑', rollback: '↓', self: '⟲' },
82
- forwardArrow: migrationListForwardArrow('unicode'),
83
- emptySource: migrationListEmptySource('unicode'),
84
- };
85
-
86
- const ASCII_PALETTE: MigrationGraphTreeGlyphPalette = {
87
- node: '* ',
88
- arcLand: '*<',
89
- arcTee: '*-',
90
- verticalPass: '| ',
91
- branchTee: '+-',
92
- mergeTee: '+-',
93
- branchCorner: '\\ ',
94
- mergeCorner: '/ ',
95
- arcBranchCorner: '\\ ',
96
- arcBranchTee: '+-',
97
- arcLandCorner: '/ ',
98
- arcCrossing: '+-',
99
- arcLandBridge: '--',
100
- horizontalPass: '--',
101
- connectorBranchTee: '+-',
102
- connectorBranchTeeCo: '+-',
103
- connectorMergeTeeCo: '+-',
104
- edgeArrow: { forward: '^', rollback: 'v', self: '@' },
105
- forwardArrow: migrationListForwardArrow('ascii'),
106
- emptySource: migrationListEmptySource('ascii'),
107
- };
108
-
109
- function paletteFor(mode: GlyphMode): MigrationGraphTreeGlyphPalette {
110
- return mode === 'ascii' ? ASCII_PALETTE : UNICODE_PALETTE;
111
- }
112
-
113
- function arrowForEdgeKind(
114
- kind: MigrationEdgeKind,
115
- palette: MigrationGraphTreeGlyphPalette,
116
- ): string {
117
- return palette.edgeArrow[kind];
118
- }
119
-
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] = served;
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 'horizontal-pass': {
250
- const served = owner === NEUTRAL_LANE ? column : owner;
251
- glyph[column] = served;
252
- dash[column] = served;
253
- break;
254
- }
255
- default:
256
- glyph[column] = column;
257
- dash[column] = column;
258
- }
259
- }
260
- return { glyph, dash };
261
- }
262
-
263
- /**
264
- * Style a structural glyph by its resolved colour column. Column 0 and the
265
- * neutral sentinel render dim (`style.lane`); columns ≥ 1 take a palette hue.
266
- */
267
- function laneStylerForColumn(
268
- colorColumn: number,
269
- colorize: boolean,
270
- style: MigrationListStyler,
271
- ): (text: string) => string {
272
- if (!colorize || colorColumn <= NEUTRAL_LANE) {
273
- return (text) => style.lane(text);
274
- }
275
- return laneColorForColumn(colorColumn);
276
- }
277
-
278
- /**
279
- * Tint a branch-owned token (direction arrow, migration name) by its edge's
280
- * lane so the whole branch row reads in one colour. Column 0 has nothing to be
281
- * told apart from in the common linear chain, so it keeps the token's existing
282
- * default styling (`fallback`) rather than a palette hue; only lanes ≥ 1 take a
283
- * colour. With colour off, the fallback (also colourless) is used unchanged.
284
- */
285
- function branchStylerOrDefault(
286
- column: number,
287
- colorize: boolean,
288
- fallback: (text: string) => string,
289
- ): (text: string) => string {
290
- if (!colorize || column <= NEUTRAL_LANE) {
291
- return fallback;
292
- }
293
- return laneColorForColumn(column);
294
- }
295
-
296
- /**
297
- * Render a connector tee (`├─` / `┬─` / `┴─`) with its junction glyph and its
298
- * trailing dash coloured independently: the junction anchors its own lane while
299
- * the dash leads into the branch on its right.
300
- */
301
- function renderConnectorTee(
302
- pair: string,
303
- glyphColumn: number,
304
- dashColumn: number,
305
- colorize: boolean,
306
- style: MigrationListStyler,
307
- ): string {
308
- const glyph = laneStylerForColumn(glyphColumn, colorize, style);
309
- if (glyphColumn === dashColumn) {
310
- return glyph(pair);
311
- }
312
- return glyph(pair.slice(0, 1)) + laneStylerForColumn(dashColumn, colorize, style)(pair.slice(1));
313
- }
314
-
315
- /**
316
- * A node-marker glyph pair (`○◂`, `○─`, `*<`, `*-`) is the contract node
317
- * marker (`○` / `*`) followed by an arc connector (`◂` / `─` / `<` / `-`). The
318
- * marker takes its own lane's hue (so each node visibly belongs to its branch);
319
- * the connector follows the arc it belongs to (its owning back-lane hue).
320
- * Direction arrows are handled elsewhere — they take their edge's lane hue too.
321
- */
322
- function renderNodeMarkerPair(
323
- pair: string,
324
- nodeColumn: number,
325
- arcColumn: number,
326
- colorize: boolean,
327
- style: MigrationListStyler,
328
- ): string {
329
- const marker = laneStylerForColumn(nodeColumn, colorize, style);
330
- const connector = laneStylerForColumn(arcColumn, colorize, style);
331
- return marker(pair.slice(0, 1)) + connector(pair.slice(1));
332
- }
333
-
334
- function renderCellPair(
335
- cell: StructuralCell,
336
- column: number,
337
- colors: RowLaneColors,
338
- colorize: boolean,
339
- style: MigrationListStyler,
340
- palette: MigrationGraphTreeGlyphPalette,
341
- ): string {
342
- const laneColumn = colors.lane[column] ?? column;
343
- const lane = laneStylerForColumn(laneColumn, colorize, style);
344
- switch (cell.kind) {
345
- case 'node': {
346
- const arcColumn = colors.connector[column] ?? NEUTRAL_LANE;
347
- if (cell.arcLand === true) {
348
- return renderNodeMarkerPair(palette.arcLand, column, arcColumn, colorize, style);
349
- }
350
- if (cell.arcTee === true) {
351
- return renderNodeMarkerPair(palette.arcTee, column, arcColumn, colorize, style);
352
- }
353
- return lane(palette.node);
354
- }
355
- case 'vertical-pass':
356
- return lane(palette.verticalPass);
357
- case 'edge-lane':
358
- return cell.ownsLabel
359
- ? lane(palette.verticalPass.trimEnd()) +
360
- branchStylerOrDefault(
361
- column,
362
- colorize,
363
- style.kind,
364
- )(arrowForEdgeKind(cell.edgeKind, palette))
365
- : lane(palette.verticalPass);
366
- case 'branch-tee':
367
- return lane(palette.branchTee);
368
- case 'merge-tee':
369
- return lane(palette.mergeTee);
370
- case 'branch-corner':
371
- return lane(palette.branchCorner);
372
- case 'merge-corner':
373
- return lane(palette.mergeCorner);
374
- case 'arc-branch-corner':
375
- return lane(palette.arcBranchCorner);
376
- case 'arc-branch-tee':
377
- return lane(palette.arcBranchTee);
378
- case 'arc-land-corner':
379
- return lane(palette.arcLandCorner);
380
- case 'arc-crossing':
381
- return lane(palette.arcCrossing);
382
- case 'arc-land-bridge':
383
- return lane(palette.arcLandBridge);
384
- case 'horizontal-pass':
385
- return lane(palette.horizontalPass);
386
- case 'empty':
387
- return ' ';
388
- }
389
- }
390
-
391
- function renderConnectorRow(
392
- row: MigrationGraphGridRow,
393
- gridWidth: number,
394
- colorize: boolean,
395
- style: MigrationListStyler,
396
- palette: MigrationGraphTreeGlyphPalette,
397
- ): string {
398
- const isMerge = row.kind === 'merge-connector';
399
- if (row.cells.length > 0) {
400
- const colors = resolveConnectorLaneColors(row.cells, row.startLane ?? 0);
401
- let seenTee = false;
402
- let out = '';
403
- for (let column = 0; column < row.cells.length; column++) {
404
- const cell = row.cells[column];
405
- if (cell === undefined) continue;
406
- const glyphColumn = colors.glyph[column] ?? column;
407
- const dashColumn = colors.dash[column] ?? glyphColumn;
408
- const lane = laneStylerForColumn(glyphColumn, colorize, style);
409
- switch (cell.kind) {
410
- case 'branch-tee':
411
- out += renderConnectorTee(
412
- seenTee ? palette.connectorBranchTeeCo : palette.connectorBranchTee,
413
- glyphColumn,
414
- dashColumn,
415
- colorize,
416
- style,
417
- );
418
- seenTee = true;
419
- break;
420
- case 'merge-tee':
421
- out += renderConnectorTee(
422
- seenTee ? palette.connectorMergeTeeCo : palette.connectorBranchTee,
423
- glyphColumn,
424
- dashColumn,
425
- colorize,
426
- style,
427
- );
428
- seenTee = true;
429
- break;
430
- case 'branch-corner':
431
- out += lane(palette.branchCorner);
432
- break;
433
- case 'merge-corner':
434
- out += lane(palette.mergeCorner);
435
- break;
436
- case 'vertical-pass':
437
- out += lane(palette.verticalPass);
438
- break;
439
- case 'horizontal-pass':
440
- out += lane(palette.horizontalPass);
441
- break;
442
- default:
443
- out += ' ';
444
- }
445
- }
446
- // The cells array is sized to the grid width at emit time; a back-arc lane
447
- // allocated by a later row can push the grid wider afterwards, so pad any
448
- // trailing columns rather than dropping the lanes that pass through here.
449
- for (let column = row.cells.length; column < gridWidth; column++) {
450
- out += ' ';
451
- }
452
- return out;
453
- }
454
-
455
- const start = row.startLane ?? 0;
456
- const end = row.endLane ?? start;
457
- // The whole fork/merge run reads as one line in the served lane's hue (the
458
- // corner it reaches); pass-through columns outside the run keep their own.
459
- const runLane = laneStylerForColumn(end, colorize, style);
460
- let out = '';
461
- for (let column = 0; column < gridWidth; column++) {
462
- if (column < start || column > end) out += ' ';
463
- else if (column === start) out += runLane(palette.connectorBranchTee);
464
- else if (column === end) out += runLane(isMerge ? palette.mergeCorner : palette.branchCorner);
465
- else out += runLane(isMerge ? palette.connectorMergeTeeCo : palette.connectorBranchTeeCo);
466
- }
467
- return out;
468
- }
469
-
470
- function abbreviateHash(hash: string, hashLength: number, emptySource: string): string {
471
- if (hash === EMPTY_CONTRACT_HASH) {
472
- return emptySource;
473
- }
474
- const stripped = hash.startsWith('sha256:') ? hash.slice(7) : hash;
475
- return stripped.slice(0, hashLength);
476
- }
477
-
478
- const MIN_HASH_DATA_COLUMN = 25;
479
-
480
- function overlayNamesForContract(
481
- contractHash: string,
482
- opts: RenderMigrationGraphTreeOptions,
483
- ): readonly string[] {
484
- const names: string[] = [];
485
- const userRefs = opts.refsByHash?.get(contractHash);
486
- if (userRefs) {
487
- names.push(...[...userRefs].sort((a, b) => a.localeCompare(b)));
488
- }
489
- if (opts.dbHash === contractHash) {
490
- names.push(DB_MARKER_NAME);
491
- }
492
- if (opts.contractHash === contractHash && contractHash !== EMPTY_CONTRACT_HASH) {
493
- names.push(CONTRACT_MARKER_NAME);
494
- }
495
- return names;
496
- }
497
-
498
- function createTreeStyler(opts: RenderMigrationGraphTreeOptions): MigrationListStyler {
499
- const base = createAnsiMigrationListStyler({ useColor: opts.colorize });
500
- const activeRefName = opts.activeRefName;
501
- if (!opts.colorize || activeRefName === undefined) {
502
- return base;
503
- }
504
- return {
505
- ...base,
506
- refs: (names) => {
507
- const styledNames = names.map((name) => (name === activeRefName ? bold(name) : name));
508
- return base.refs(styledNames);
509
- },
510
- };
511
- }
512
-
513
- function formatEdgeHashColumn(
514
- edge: ClassifiedEdge,
515
- style: MigrationListStyler,
516
- hashLength: number,
517
- palette: MigrationGraphTreeGlyphPalette,
518
- ): string {
519
- if (edge.kind === 'self') {
520
- const hash = abbreviateHash(edge.from, hashLength, palette.emptySource);
521
- return `${style.sourceHash(hash)} ${style.glyph(palette.forwardArrow)} ${style.destHash(hash)}`;
522
- }
523
- const source =
524
- edge.from === EMPTY_CONTRACT_HASH
525
- ? style.glyph(palette.emptySource) +
526
- ' '.repeat(Math.max(0, hashLength - palette.emptySource.length))
527
- : style.sourceHash(abbreviateHash(edge.from, hashLength, palette.emptySource));
528
- const arrow = style.glyph(palette.forwardArrow);
529
- const dest = style.destHash(abbreviateHash(edge.to, hashLength, palette.emptySource));
530
- return `${source} ${arrow} ${dest}`;
531
- }
532
-
533
- function padVisible(text: string, targetWidth: number): string {
534
- const padding = Math.max(0, targetWidth - stringWidth(text));
535
- return text + ' '.repeat(padding);
536
- }
537
-
538
- const ANSI_ESCAPE = '\x1b';
539
-
540
- function trimTrailingWhitespace(line: string): string {
541
- const trailingSpaceBeforeReset = new RegExp(`[\\t ]+((?:${ANSI_ESCAPE}\\[[0-9;]*m)+)$`);
542
- return line.replace(trailingSpaceBeforeReset, '$1').replace(/\s+$/, '');
543
- }
544
-
545
- function gridWidthForModel(rows: readonly MigrationGraphGridRow[]): number {
546
- return rows.reduce(
547
- (max, row) =>
548
- row.kind === 'node' || row.kind === 'edge' ? Math.max(max, row.cells.length) : max,
549
- 1,
550
- );
551
- }
552
-
553
- function maxDirNameLength(edges: readonly ClassifiedEdge[]): number {
554
- if (edges.length === 0) return 0;
555
- return Math.max(...edges.map((edge) => edge.dirName.length));
556
- }
557
-
558
- function rowDirNameWidth(labelColumn: number, maxDirNameLen: number, dirNameGap: number): number {
559
- return Math.max(maxDirNameLen + dirNameGap, MIN_HASH_DATA_COLUMN - labelColumn);
560
- }
561
-
562
- function gridUsesSkipRollbackArcs(rows: readonly MigrationGraphGridRow[]): boolean {
563
- return rows.some((row) =>
564
- row.cells.some(
565
- (cell) => cell.kind === 'edge-lane' && cell.adjacency === 'node-skipping-rollback',
566
- ),
567
- );
568
- }
569
-
570
- function edgeLabelColumn(row: MigrationGraphGridRow, wideLabelColumn: number | undefined): number {
571
- if (wideLabelColumn !== undefined) {
572
- return wideLabelColumn;
573
- }
574
- const laneIndex = row.laneIndex ?? 0;
575
- if (row.edge?.from === EMPTY_CONTRACT_HASH && laneIndex === 0) {
576
- return (laneIndex + 1) * 2 + LABEL_GAP;
577
- }
578
- const usesFullRowGutter = row.cells.some(
579
- (cell, index) => index > laneIndex && cell.kind === 'vertical-pass',
580
- );
581
- return usesFullRowGutter ? row.cells.length * 2 + LABEL_GAP : (laneIndex + 1) * 2 + LABEL_GAP;
582
- }
583
-
584
- function nodeHasArcDecoration(row: MigrationGraphGridRow): boolean {
585
- return row.cells.some(
586
- (cell) => cell.kind === 'node' && (cell.arcTee === true || cell.arcLand === true),
587
- );
588
- }
589
-
590
- export function renderMigrationGraphTree(
591
- model: MigrationGraphGridModel,
592
- opts: RenderMigrationGraphTreeOptions,
593
- ): string {
594
- const glyphMode = opts.glyphMode ?? 'unicode';
595
- const palette = paletteFor(glyphMode);
596
- const style = createTreeStyler(opts);
597
- const hashLength = opts.hashLength ?? MIGRATION_LIST_HASH_WIDTH;
598
- const gridWidth = gridWidthForModel(model.rows);
599
- const wideLabelColumn = gridUsesSkipRollbackArcs(model.rows) ? gridWidth * 2 + 4 : undefined;
600
- const dirNameGap = wideLabelColumn !== undefined ? 3 : LABEL_GAP;
601
- const allEdges = model.rows
602
- .filter(
603
- (row): row is MigrationGraphGridRow & { edge: ClassifiedEdge } =>
604
- row.kind === 'edge' && row.edge !== undefined,
605
- )
606
- .map((row) => row.edge);
607
- const maxDirNameLen = maxDirNameLength(allEdges);
608
-
609
- const lines: string[] = [];
610
-
611
- for (let rowIndex = 0; rowIndex < model.rows.length; rowIndex++) {
612
- const row = model.rows[rowIndex];
613
- if (row === undefined) continue;
614
-
615
- if (row.kind === 'component-separator') {
616
- lines.push('');
617
- continue;
618
- }
619
-
620
- if (row.kind === 'branch-connector' || row.kind === 'merge-connector') {
621
- lines.push(
622
- trimTrailingWhitespace(renderConnectorRow(row, gridWidth, opts.colorize, style, palette)),
623
- );
624
- continue;
625
- }
626
-
627
- const cellColors = resolveRowLaneColors(row.cells);
628
- let gutter = row.cells
629
- .map((cell, column) =>
630
- renderCellPair(cell, column, cellColors, opts.colorize, style, palette),
631
- )
632
- .join('');
633
- const prevRow = model.rows[rowIndex - 1];
634
- let laneSpan = row.cells.length;
635
- if (row.kind === 'node') {
636
- const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;
637
- if (prevRow?.kind === 'merge-connector' || contractHash === EMPTY_CONTRACT_HASH) {
638
- laneSpan = 1;
639
- } else {
640
- laneSpan = row.cells.length;
641
- }
642
- }
643
- const labelColumn =
644
- row.kind === 'edge'
645
- ? edgeLabelColumn(row, wideLabelColumn)
646
- : wideLabelColumn !== undefined &&
647
- (nodeHasArcDecoration(row) || row.contractHash !== undefined)
648
- ? wideLabelColumn
649
- : laneSpan * 2 + LABEL_GAP;
650
- if (
651
- row.kind === 'edge' &&
652
- row.edge?.from === EMPTY_CONTRACT_HASH &&
653
- (row.laneIndex ?? 0) === 0
654
- ) {
655
- gutter = row.cells
656
- .slice(0, 1)
657
- .map((cell, column) =>
658
- renderCellPair(cell, column, cellColors, opts.colorize, style, palette),
659
- )
660
- .join('');
661
- } else if (row.kind === 'node' && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) {
662
- gutter = row.cells
663
- .slice(0, laneSpan)
664
- .map((cell, column) =>
665
- renderCellPair(cell, column, cellColors, opts.colorize, style, palette),
666
- )
667
- .join('');
668
- } else if (gutter.length < laneSpan * 2) {
669
- gutter = gutter.padEnd(laneSpan * 2, ' ');
670
- }
671
- const dirNameWidth = rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);
672
- const dataColumn = labelColumn + dirNameWidth;
673
- const gutterPad = padVisible(gutter, labelColumn);
674
-
675
- if (row.kind === 'node') {
676
- const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;
677
- if (contractHash === EMPTY_CONTRACT_HASH) {
678
- const trailingLanes = row.cells
679
- .slice(1)
680
- .map((cell, offset) =>
681
- renderCellPair(cell, offset + 1, cellColors, opts.colorize, style, palette),
682
- )
683
- .join('');
684
- const emptyGutter = palette.emptySource.padEnd(2, ' ') + trailingLanes;
685
- const overlayNames = overlayNamesForContract(contractHash, opts);
686
- if (overlayNames.length === 0) {
687
- lines.push(trimTrailingWhitespace(emptyGutter));
688
- continue;
689
- }
690
- const overlay = style.refs(overlayNames);
691
- lines.push(trimTrailingWhitespace(`${padVisible(emptyGutter, dataColumn)}${overlay}`));
692
- continue;
693
- }
694
- const hashText = style.sourceHash(
695
- abbreviateHash(contractHash, hashLength, palette.emptySource),
696
- );
697
- const overlayNames = overlayNamesForContract(contractHash, opts);
698
- const overlayPad =
699
- overlayNames.length > 0
700
- ? ' '.repeat(Math.max(0, dataColumn - labelColumn - stringWidth(hashText)))
701
- : '';
702
- const overlay = overlayNames.length > 0 ? style.refs(overlayNames) : '';
703
- lines.push(trimTrailingWhitespace(`${gutterPad}${hashText}${overlayPad}${overlay}`));
704
- continue;
705
- }
706
-
707
- const edge = row.edge;
708
- if (edge === undefined) continue;
709
-
710
- const dirNamePadding = ' '.repeat(Math.max(0, dirNameWidth - edge.dirName.length));
711
- const laneIndex = row.laneIndex ?? 0;
712
- // A branched name keeps its bold (via `style.dirName`) and adds the lane
713
- // hue, so it reads as one with its lane/arrow; column-0 names stay bold-only.
714
- const dirNameStyler =
715
- opts.colorize && laneIndex > NEUTRAL_LANE
716
- ? (text: string) => forcedBold(laneColorForColumn(laneIndex)(text))
717
- : style.dirName;
718
- const dirName = `${dirNameStyler(edge.dirName)}${dirNamePadding}`;
719
- const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);
720
- lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}`));
721
- }
722
-
723
- return lines.join('\n');
724
- }
725
-
726
- export interface RenderMigrationGraphLegendOptions {
727
- readonly colorize: boolean;
728
- readonly glyphMode?: GlyphMode;
729
- }
730
-
731
- /**
732
- * A compact key for the `--tree` visual language: the contract marker, the
733
- * in-lane direction arrows, the empty baseline, the `(refs)` overlay (including
734
- * the reserved `db` live-database and `contract` working-schema markers), and a
735
- * worked sample of the data-column `from → to` migration hash arrow.
736
- *
737
- * Honors the same glyph palette (unicode vs ASCII) and `colorize` gate as the
738
- * tree renderer, so the key matches whatever the graph itself drew and stays
739
- * pipe-safe (zero ANSI when color is off). The caller adds the trailing blank
740
- * line that separates this stderr key from the graph on stdout.
741
- */
742
- export function renderMigrationGraphLegend(opts: RenderMigrationGraphLegendOptions): string {
743
- const palette = paletteFor(opts.glyphMode ?? 'unicode');
744
- const style = createAnsiMigrationListStyler({ useColor: opts.colorize });
745
- const node = palette.node.trimEnd();
746
- const sampleArrow = `${style.sourceHash('aaaaaa')} ${style.glyph(palette.forwardArrow)} ${style.destHash('bbbbbb')}`;
747
- return [
748
- 'Legend:',
749
- ` ${style.kind(node)} contract ${style.kind(palette.edgeArrow.forward)} forward ${style.kind(palette.edgeArrow.rollback)} rollback`,
750
- ` ${style.kind(palette.edgeArrow.self)} migration without schema change`,
751
- ` ${style.glyph(palette.emptySource)} empty database (baseline)`,
752
- ` ${style.refs(['refs'])} ${DB_MARKER_NAME} / ${CONTRACT_MARKER_NAME} markers`,
753
- ` ${sampleArrow} migration from contract aaaaaa to bbbbbb`,
754
- ].join('\n');
755
- }