@prisma-next/cli 0.11.0-dev.70 → 0.11.0-dev.72
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 +10 -10
- package/dist/{client-6WehTnUh.mjs → client-KgJorIvG.mjs} +4 -4
- package/dist/{client-6WehTnUh.mjs.map → client-KgJorIvG.mjs.map} +1 -1
- package/dist/{command-helpers-CoceqqMl.mjs → command-helpers-Bbw1GbwL.mjs} +3 -3
- package/dist/{command-helpers-CoceqqMl.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 +4 -4
- package/dist/commands/migration-graph.mjs +1 -1
- package/dist/commands/migration-list.d.mts +3 -6
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +189 -1
- package/dist/commands/migration-list.mjs.map +1 -0
- 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 +3 -3
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +2 -2
- package/dist/{contract-at-errors-Bhf2jnkp.mjs → contract-at-errors-BxP-TOMl.mjs} +2 -2
- package/dist/{contract-at-errors-Bhf2jnkp.mjs.map → contract-at-errors-BxP-TOMl.mjs.map} +1 -1
- package/dist/{contract-emit-DxEfEc-M.mjs → contract-emit-D-4jrNve.mjs} +3 -3
- package/dist/{contract-emit-DxEfEc-M.mjs.map → contract-emit-D-4jrNve.mjs.map} +1 -1
- package/dist/{contract-emit-C47r1loe.mjs → contract-emit-DxcGl4Uq.mjs} +3 -3
- package/dist/{contract-emit-C47r1loe.mjs.map → contract-emit-DxcGl4Uq.mjs.map} +1 -1
- package/dist/{contract-infer-BLiomU8g.mjs → contract-infer-D8uEbJuu.mjs} +3 -3
- package/dist/{contract-infer-BLiomU8g.mjs.map → contract-infer-D8uEbJuu.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-lafgkTwG.mjs → contract-space-aggregate-loader-DvZwdkrr.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-lafgkTwG.mjs.map → contract-space-aggregate-loader-DvZwdkrr.mjs.map} +1 -1
- package/dist/{db-verify-D44Qj3w9.mjs → db-verify-v_vUKXTU.mjs} +4 -4
- package/dist/{db-verify-D44Qj3w9.mjs.map → db-verify-v_vUKXTU.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +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-R_O3y5IW.mjs → framework-components-fYXjz_in.mjs} +2 -2
- package/dist/{framework-components-R_O3y5IW.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-DE-phHWK.mjs → init-Cv9UzWL5.mjs} +17 -18
- package/dist/init-Cv9UzWL5.mjs.map +1 -0
- package/dist/{inspect-live-schema-Ccnmg5bz.mjs → inspect-live-schema-C6ohV_oQ.mjs} +3 -3
- package/dist/{inspect-live-schema-Ccnmg5bz.mjs.map → inspect-live-schema-C6ohV_oQ.mjs.map} +1 -1
- package/dist/{migration-check-CKfQlAWR.mjs → migration-check-BiBJoYYW.mjs} +2 -2
- package/dist/{migration-check-CKfQlAWR.mjs.map → migration-check-BiBJoYYW.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-C_KuV0Gm.mjs → migration-command-scaffold-CjvwO6at.mjs} +3 -3
- package/dist/{migration-command-scaffold-C_KuV0Gm.mjs.map → migration-command-scaffold-CjvwO6at.mjs.map} +1 -1
- package/dist/{migration-graph-kPluRdF2.mjs → migration-graph-D7DVUElV.mjs} +4 -4
- package/dist/{migration-graph-kPluRdF2.mjs.map → migration-graph-D7DVUElV.mjs.map} +1 -1
- package/dist/{migration-list-styler-DeAwACt3.mjs → migration-list-styler-BRwF4-gy.mjs} +2 -5
- package/dist/{migration-list-styler-DeAwACt3.mjs.map → migration-list-styler-BRwF4-gy.mjs.map} +1 -1
- package/dist/{migration-plan-DHLa2Khm.mjs → migration-plan-9DJ7q7_z.mjs} +5 -5
- package/dist/{migration-plan-DHLa2Khm.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-CjO1DsYe.mjs → migrations-Cv2jxNNK.mjs} +2 -2
- package/dist/{migrations-CjO1DsYe.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-BbtqsQYY.d.mts → terminal-ui-5Y6mrg93.d.mts} +3 -3
- package/dist/{terminal-ui-BbtqsQYY.d.mts.map → terminal-ui-5Y6mrg93.d.mts.map} +1 -1
- package/dist/{types-Ci7TndCS.d.mts → types-Dt_SfqFm.d.mts} +1 -1
- package/dist/{types-Ci7TndCS.d.mts.map → types-Dt_SfqFm.d.mts.map} +1 -1
- package/dist/{verify-vl983Ed-.mjs → verify-DCA9Sldu.mjs} +2 -2
- package/dist/{verify-vl983Ed-.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
- package/package.json +33 -22
- package/src/commands/init/templates/env.ts +13 -14
- package/src/commands/migration-graph.ts +1 -1
- package/src/commands/migration-list.ts +5 -16
- package/src/utils/terminal-ui.ts +2 -2
- package/dist/init-DE-phHWK.mjs.map +0 -1
- package/dist/migration-list-CE35R5Ag.mjs +0 -505
- package/dist/migration-list-CE35R5Ag.mjs.map +0 -1
- package/src/utils/formatters/migration-list-graph-layout.ts +0 -268
- package/src/utils/formatters/migration-list-graph-render.ts +0 -311
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
2
|
-
import {
|
|
3
|
-
classifyMigrationListGraphTopology,
|
|
4
|
-
type MigrationEdgeKind,
|
|
5
|
-
type MigrationListGraphTopology,
|
|
6
|
-
} from './migration-list-graph-topology';
|
|
7
|
-
import type { MigrationListEntry } from './migration-list-types';
|
|
8
|
-
|
|
9
|
-
export type ConnectorKind = 'fanBelow' | 'joinAbove';
|
|
10
|
-
|
|
11
|
-
export interface MigrationLayoutRow {
|
|
12
|
-
readonly kind: 'migration';
|
|
13
|
-
readonly entry: MigrationListEntry;
|
|
14
|
-
readonly edgeKind: MigrationEdgeKind;
|
|
15
|
-
readonly laneIndex: number;
|
|
16
|
-
readonly passThroughLanes: readonly number[];
|
|
17
|
-
readonly woven: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface NodeLineLayoutRow {
|
|
21
|
-
readonly kind: 'nodeLine';
|
|
22
|
-
readonly contractHash: string;
|
|
23
|
-
readonly laneIndex: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface ConnectorLayoutRow {
|
|
27
|
-
readonly kind: 'connector';
|
|
28
|
-
readonly connectorKind: ConnectorKind;
|
|
29
|
-
readonly contractHash: string;
|
|
30
|
-
readonly startLane: number;
|
|
31
|
-
readonly endLane: number;
|
|
32
|
-
readonly branchCount: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export type LayoutRow = MigrationLayoutRow | NodeLineLayoutRow | ConnectorLayoutRow;
|
|
36
|
-
|
|
37
|
-
export interface MigrationListGraphLayout {
|
|
38
|
-
readonly rows: readonly LayoutRow[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface LaneState {
|
|
42
|
-
want: string;
|
|
43
|
-
active: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function canonicalFrom(from: string | null): string {
|
|
47
|
-
return from ?? EMPTY_CONTRACT_HASH;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function forwardInDegree(topology: MigrationListGraphTopology, hash: string): number {
|
|
51
|
-
return topology.forwardInDegree.get(hash) ?? 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function forwardOutDegree(topology: MigrationListGraphTopology, hash: string): number {
|
|
55
|
-
return topology.forwardOutDegree.get(hash) ?? 0;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function buildForwardProducersByTo(
|
|
59
|
-
entries: readonly MigrationListEntry[],
|
|
60
|
-
kindByMigrationHash: ReadonlyMap<string, MigrationEdgeKind>,
|
|
61
|
-
): Map<string, MigrationListEntry[]> {
|
|
62
|
-
const byTo = new Map<string, MigrationListEntry[]>();
|
|
63
|
-
for (const entry of entries) {
|
|
64
|
-
if (kindByMigrationHash.get(entry.migrationHash) !== 'forward') continue;
|
|
65
|
-
const bucket = byTo.get(entry.to);
|
|
66
|
-
if (bucket) bucket.push(entry);
|
|
67
|
-
else byTo.set(entry.to, [entry]);
|
|
68
|
-
}
|
|
69
|
-
return byTo;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function countForwardProducersTo(
|
|
73
|
-
forwardProducersByTo: Map<string, MigrationListEntry[]>,
|
|
74
|
-
contract: string,
|
|
75
|
-
): number {
|
|
76
|
-
return forwardProducersByTo.get(contract)?.length ?? 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function hasLaterForwardDepartingFrom(
|
|
80
|
-
entries: readonly MigrationListEntry[],
|
|
81
|
-
startIndex: number,
|
|
82
|
-
contract: string,
|
|
83
|
-
kindByMigrationHash: ReadonlyMap<string, MigrationEdgeKind>,
|
|
84
|
-
): boolean {
|
|
85
|
-
for (let index = startIndex + 1; index < entries.length; index++) {
|
|
86
|
-
const later = entries[index];
|
|
87
|
-
if (later === undefined) continue;
|
|
88
|
-
if (kindByMigrationHash.get(later.migrationHash) !== 'forward') continue;
|
|
89
|
-
if (canonicalFrom(later.from) === contract) return true;
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function computeMigrationListGraphLayout(
|
|
95
|
-
entries: readonly MigrationListEntry[],
|
|
96
|
-
topology: MigrationListGraphTopology = classifyMigrationListGraphTopology(entries),
|
|
97
|
-
): MigrationListGraphLayout {
|
|
98
|
-
const { kindByMigrationHash } = topology;
|
|
99
|
-
const forwardProducersByTo = buildForwardProducersByTo(entries, kindByMigrationHash);
|
|
100
|
-
const convergencesEmitted = new Set<string>();
|
|
101
|
-
const producerLaneByHash = new Map<string, number>();
|
|
102
|
-
const lanes: LaneState[] = [];
|
|
103
|
-
const rows: LayoutRow[] = [];
|
|
104
|
-
|
|
105
|
-
function emitNodeLine(contractHash: string): void {
|
|
106
|
-
rows.push({ kind: 'nodeLine', contractHash, laneIndex: 0 });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function emitConnector(
|
|
110
|
-
connectorKind: ConnectorKind,
|
|
111
|
-
contractHash: string,
|
|
112
|
-
startLane: number,
|
|
113
|
-
endLane: number,
|
|
114
|
-
branchCount: number,
|
|
115
|
-
): void {
|
|
116
|
-
rows.push({
|
|
117
|
-
kind: 'connector',
|
|
118
|
-
connectorKind,
|
|
119
|
-
contractHash,
|
|
120
|
-
startLane,
|
|
121
|
-
endLane,
|
|
122
|
-
branchCount,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function activeLaneIndices(): number[] {
|
|
127
|
-
const indices: number[] = [];
|
|
128
|
-
for (let index = 0; index < lanes.length; index++) {
|
|
129
|
-
if (lanes[index]?.active) indices.push(index);
|
|
130
|
-
}
|
|
131
|
-
return indices;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function lanesWanting(contract: string): number[] {
|
|
135
|
-
const indices: number[] = [];
|
|
136
|
-
for (let index = 0; index < lanes.length; index++) {
|
|
137
|
-
const lane = lanes[index];
|
|
138
|
-
if (lane?.active && lane.want === contract) indices.push(index);
|
|
139
|
-
}
|
|
140
|
-
return indices;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function ensureLane(index: number): void {
|
|
144
|
-
while (lanes.length <= index) {
|
|
145
|
-
lanes.push({ want: '', active: false });
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function openLaneAtRight(want: string): number {
|
|
150
|
-
const index = lanes.length;
|
|
151
|
-
lanes.push({ want, active: true });
|
|
152
|
-
return index;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function closeLane(index: number): void {
|
|
156
|
-
ensureLane(index);
|
|
157
|
-
const lane = lanes[index];
|
|
158
|
-
if (lane) lane.active = false;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function emitJoinAbove(contractHash: string, laneIndices: readonly number[]): void {
|
|
162
|
-
if (laneIndices.length < 2) return;
|
|
163
|
-
const startLane = Math.min(...laneIndices);
|
|
164
|
-
const endLane = Math.max(...laneIndices);
|
|
165
|
-
emitConnector('joinAbove', contractHash, startLane, endLane, laneIndices.length);
|
|
166
|
-
for (const index of laneIndices) {
|
|
167
|
-
if (index !== startLane) closeLane(index);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function emitConvergencePreamble(contract: string): void {
|
|
172
|
-
if (convergencesEmitted.has(contract)) return;
|
|
173
|
-
if (forwardInDegree(topology, contract) < 2) return;
|
|
174
|
-
|
|
175
|
-
const consumersWanting = lanesWanting(contract);
|
|
176
|
-
if (forwardOutDegree(topology, contract) >= 2 && consumersWanting.length >= 2) {
|
|
177
|
-
emitJoinAbove(contract, consumersWanting);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
emitNodeLine(contract);
|
|
181
|
-
const producers = forwardProducersByTo.get(contract) ?? [];
|
|
182
|
-
if (producers.length >= 2) {
|
|
183
|
-
emitConnector('fanBelow', contract, 0, producers.length - 1, producers.length);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
for (const [producerIndex, producer] of producers.entries()) {
|
|
187
|
-
ensureLane(producerIndex);
|
|
188
|
-
lanes[producerIndex] = { want: canonicalFrom(producer.from), active: true };
|
|
189
|
-
producerLaneByHash.set(producer.migrationHash, producerIndex);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
convergencesEmitted.add(contract);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function placeWoven(
|
|
196
|
-
entry: MigrationListEntry,
|
|
197
|
-
edgeKind: MigrationEdgeKind,
|
|
198
|
-
laneIndex: number,
|
|
199
|
-
): void {
|
|
200
|
-
const passThroughLanes = activeLaneIndices().filter((index) => index !== laneIndex);
|
|
201
|
-
rows.push({
|
|
202
|
-
kind: 'migration',
|
|
203
|
-
entry,
|
|
204
|
-
edgeKind,
|
|
205
|
-
laneIndex,
|
|
206
|
-
passThroughLanes,
|
|
207
|
-
woven: true,
|
|
208
|
-
});
|
|
209
|
-
ensureLane(laneIndex);
|
|
210
|
-
lanes[laneIndex] = { want: canonicalFrom(entry.from), active: true };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function placeUnwoven(entry: MigrationListEntry, edgeKind: MigrationEdgeKind): void {
|
|
214
|
-
const passThroughLanes = activeLaneIndices();
|
|
215
|
-
const laneIndex = passThroughLanes.length === 0 ? 0 : Math.max(...passThroughLanes) + 1;
|
|
216
|
-
rows.push({
|
|
217
|
-
kind: 'migration',
|
|
218
|
-
entry,
|
|
219
|
-
edgeKind,
|
|
220
|
-
laneIndex,
|
|
221
|
-
passThroughLanes,
|
|
222
|
-
woven: false,
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
for (let entryIndex = 0; entryIndex < entries.length; entryIndex++) {
|
|
227
|
-
const entry = entries[entryIndex]!;
|
|
228
|
-
const edgeKind = kindByMigrationHash.get(entry.migrationHash) ?? 'forward';
|
|
229
|
-
const to = entry.to;
|
|
230
|
-
|
|
231
|
-
if (edgeKind !== 'forward') {
|
|
232
|
-
placeUnwoven(entry, edgeKind);
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (forwardInDegree(topology, to) >= 2 && !convergencesEmitted.has(to)) {
|
|
237
|
-
emitConvergencePreamble(to);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const presetLane = producerLaneByHash.get(entry.migrationHash);
|
|
241
|
-
const wantingTo = lanesWanting(to);
|
|
242
|
-
|
|
243
|
-
if (wantingTo.length >= 2 && countForwardProducersTo(forwardProducersByTo, to) === 1) {
|
|
244
|
-
emitJoinAbove(to, wantingTo);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (presetLane !== undefined) {
|
|
248
|
-
placeWoven(entry, edgeKind, presetLane);
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const firstWanting = wantingTo[0];
|
|
253
|
-
if (firstWanting !== undefined) {
|
|
254
|
-
placeWoven(entry, edgeKind, firstWanting);
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (hasLaterForwardDepartingFrom(entries, entryIndex, to, kindByMigrationHash)) {
|
|
259
|
-
placeUnwoven(entry, edgeKind);
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const tipLaneIndex = openLaneAtRight(canonicalFrom(entry.from));
|
|
264
|
-
placeWoven(entry, edgeKind, tipLaneIndex);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return { rows };
|
|
268
|
-
}
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import type { GlyphMode } from '../glyph-mode';
|
|
2
|
-
import {
|
|
3
|
-
abbreviateContractHash,
|
|
4
|
-
computeMigrationDirNameWidth,
|
|
5
|
-
formatMigrationDataColumn,
|
|
6
|
-
formatNodeLineDataColumn,
|
|
7
|
-
MIGRATION_LIST_ASCII_KIND_GLYPH,
|
|
8
|
-
MIGRATION_LIST_UNICODE_KIND_GLYPH,
|
|
9
|
-
migrationListEmptySource,
|
|
10
|
-
migrationListForwardArrow,
|
|
11
|
-
} from './migration-list-data-column';
|
|
12
|
-
import type {
|
|
13
|
-
ConnectorLayoutRow,
|
|
14
|
-
LayoutRow,
|
|
15
|
-
MigrationLayoutRow,
|
|
16
|
-
MigrationListGraphLayout,
|
|
17
|
-
NodeLineLayoutRow,
|
|
18
|
-
} from './migration-list-graph-layout';
|
|
19
|
-
import { computeMigrationListGraphLayout } from './migration-list-graph-layout';
|
|
20
|
-
import type { MigrationListGraphTopology } from './migration-list-graph-topology';
|
|
21
|
-
import type { MigrationListStyler } from './migration-list-render';
|
|
22
|
-
import type { MigrationListEntry, MigrationListResult } from './migration-list-types';
|
|
23
|
-
|
|
24
|
-
export type { GlyphMode } from '../glyph-mode';
|
|
25
|
-
|
|
26
|
-
interface GlyphPalette {
|
|
27
|
-
readonly lane: string;
|
|
28
|
-
readonly node: string;
|
|
29
|
-
readonly forwardArrow: string;
|
|
30
|
-
readonly emptySource: string;
|
|
31
|
-
readonly kind: typeof MIGRATION_LIST_UNICODE_KIND_GLYPH;
|
|
32
|
-
readonly fanBelow: (branchCount: number) => string;
|
|
33
|
-
readonly joinAbove: (branchCount: number) => string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const UNICODE_PALETTE: GlyphPalette = {
|
|
37
|
-
lane: '│',
|
|
38
|
-
node: 'o',
|
|
39
|
-
forwardArrow: migrationListForwardArrow('unicode'),
|
|
40
|
-
emptySource: migrationListEmptySource('unicode'),
|
|
41
|
-
kind: MIGRATION_LIST_UNICODE_KIND_GLYPH,
|
|
42
|
-
fanBelow: (branchCount) => (branchCount === 2 ? '├─┐' : '├─┬─┐'),
|
|
43
|
-
joinAbove: (branchCount) => (branchCount === 2 ? '├─┘' : '└─┴─┘'),
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const ASCII_PALETTE: GlyphPalette = {
|
|
47
|
-
lane: '|',
|
|
48
|
-
node: 'o',
|
|
49
|
-
forwardArrow: migrationListForwardArrow('ascii'),
|
|
50
|
-
emptySource: migrationListEmptySource('ascii'),
|
|
51
|
-
kind: MIGRATION_LIST_ASCII_KIND_GLYPH,
|
|
52
|
-
fanBelow: (branchCount) => (branchCount === 2 ? '+-\\' : '+-|-\\'),
|
|
53
|
-
joinAbove: (branchCount) => (branchCount === 2 ? '+-/' : '/-+-/'),
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
function paletteFor(mode: GlyphMode): GlyphPalette {
|
|
57
|
-
return mode === 'ascii' ? ASCII_PALETTE : UNICODE_PALETTE;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function migrationEntries(layout: MigrationListGraphLayout): MigrationListEntry[] {
|
|
61
|
-
const entries: MigrationListEntry[] = [];
|
|
62
|
-
for (const row of layout.rows) {
|
|
63
|
-
if (row.kind === 'migration') entries.push(row.entry);
|
|
64
|
-
}
|
|
65
|
-
return entries;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function layoutMaxLaneIndex(layout: MigrationListGraphLayout): number {
|
|
69
|
-
let max = 0;
|
|
70
|
-
for (const row of layout.rows) {
|
|
71
|
-
if (row.kind === 'migration') {
|
|
72
|
-
max = Math.max(max, row.laneIndex, ...row.passThroughLanes);
|
|
73
|
-
} else if (row.kind === 'connector') {
|
|
74
|
-
max = Math.max(max, row.endLane);
|
|
75
|
-
} else {
|
|
76
|
-
max = Math.max(max, row.laneIndex);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return max;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function laneCell(glyph: string): string {
|
|
83
|
-
return `${glyph} `;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function emptyLaneCell(): string {
|
|
87
|
-
return ' ';
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function renderMigrationGutter(
|
|
91
|
-
row: MigrationLayoutRow,
|
|
92
|
-
maxLane: number,
|
|
93
|
-
palette: GlyphPalette,
|
|
94
|
-
style: MigrationListStyler,
|
|
95
|
-
): string {
|
|
96
|
-
const cells: string[] = [];
|
|
97
|
-
for (let lane = 0; lane <= maxLane; lane++) {
|
|
98
|
-
if (lane === row.laneIndex) {
|
|
99
|
-
cells.push(laneCell(style.kind(palette.kind[row.edgeKind])));
|
|
100
|
-
} else if (row.passThroughLanes.includes(lane)) {
|
|
101
|
-
cells.push(laneCell(style.lane(palette.lane)));
|
|
102
|
-
} else {
|
|
103
|
-
cells.push(emptyLaneCell());
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return cells.join('');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function renderNodeLineGutter(
|
|
110
|
-
row: NodeLineLayoutRow,
|
|
111
|
-
openLanes: ReadonlySet<number>,
|
|
112
|
-
maxLane: number,
|
|
113
|
-
palette: GlyphPalette,
|
|
114
|
-
style: MigrationListStyler,
|
|
115
|
-
): string {
|
|
116
|
-
const cells: string[] = [];
|
|
117
|
-
for (let lane = 0; lane <= maxLane; lane++) {
|
|
118
|
-
if (lane === row.laneIndex) {
|
|
119
|
-
cells.push(laneCell(palette.node));
|
|
120
|
-
} else if (openLanes.has(lane)) {
|
|
121
|
-
cells.push(laneCell(style.lane(palette.lane)));
|
|
122
|
-
} else {
|
|
123
|
-
cells.push(emptyLaneCell());
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return cells.join('');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function renderConnectorGutter(
|
|
130
|
-
row: ConnectorLayoutRow,
|
|
131
|
-
openLanes: ReadonlySet<number>,
|
|
132
|
-
maxLane: number,
|
|
133
|
-
palette: GlyphPalette,
|
|
134
|
-
style: MigrationListStyler,
|
|
135
|
-
): string {
|
|
136
|
-
const spanLaneCount = row.endLane - row.startLane + 1;
|
|
137
|
-
const spanWidth = spanLaneCount * 2;
|
|
138
|
-
let spanGlyph = (
|
|
139
|
-
row.connectorKind === 'fanBelow'
|
|
140
|
-
? palette.fanBelow(row.branchCount)
|
|
141
|
-
: palette.joinAbove(row.branchCount)
|
|
142
|
-
)
|
|
143
|
-
.padEnd(spanWidth, ' ')
|
|
144
|
-
.slice(0, spanWidth);
|
|
145
|
-
|
|
146
|
-
const hasOutsideOpen = [...openLanes].some((lane) => lane < row.startLane || lane > row.endLane);
|
|
147
|
-
if (!hasOutsideOpen && spanGlyph.endsWith(' ')) {
|
|
148
|
-
spanGlyph = spanGlyph.slice(0, -1);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
let gutter = '';
|
|
152
|
-
for (let lane = 0; lane < row.startLane; lane++) {
|
|
153
|
-
gutter += openLanes.has(lane) ? laneCell(style.lane(palette.lane)) : emptyLaneCell();
|
|
154
|
-
}
|
|
155
|
-
gutter += style.lane(spanGlyph);
|
|
156
|
-
for (let lane = row.endLane + 1; lane <= maxLane; lane++) {
|
|
157
|
-
gutter += openLanes.has(lane) ? laneCell(style.lane(palette.lane)) : emptyLaneCell();
|
|
158
|
-
}
|
|
159
|
-
return gutter;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function advanceOpenLanes(row: LayoutRow, openLanes: ReadonlySet<number>): ReadonlySet<number> {
|
|
163
|
-
if (row.kind === 'migration') {
|
|
164
|
-
return new Set([row.laneIndex, ...row.passThroughLanes]);
|
|
165
|
-
}
|
|
166
|
-
if (row.kind === 'connector') {
|
|
167
|
-
if (row.connectorKind === 'fanBelow') {
|
|
168
|
-
const next = new Set(openLanes);
|
|
169
|
-
for (let lane = row.startLane; lane <= row.endLane; lane++) {
|
|
170
|
-
next.add(lane);
|
|
171
|
-
}
|
|
172
|
-
return next;
|
|
173
|
-
}
|
|
174
|
-
const next = new Set(openLanes);
|
|
175
|
-
for (let lane = row.startLane + 1; lane <= row.endLane; lane++) {
|
|
176
|
-
next.delete(lane);
|
|
177
|
-
}
|
|
178
|
-
return next;
|
|
179
|
-
}
|
|
180
|
-
return openLanes;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function renderMigrationListGraphWithStyle(
|
|
184
|
-
layout: MigrationListGraphLayout,
|
|
185
|
-
style: MigrationListStyler,
|
|
186
|
-
glyphMode: GlyphMode,
|
|
187
|
-
): string {
|
|
188
|
-
const palette = paletteFor(glyphMode);
|
|
189
|
-
const migrations = migrationEntries(layout);
|
|
190
|
-
const layoutMaxLane = layoutMaxLaneIndex(layout);
|
|
191
|
-
const dirNameWidth = computeMigrationDirNameWidth(migrations);
|
|
192
|
-
const gutterMaxLane = layoutMaxLane;
|
|
193
|
-
const blockDataStart = (layoutMaxLane + 1) * 2;
|
|
194
|
-
// Migration and node-line gutters always occupy a fixed, ANSI-free visible
|
|
195
|
-
// width of two columns per lane. Padding is computed from this width rather
|
|
196
|
-
// than the rendered string length so dimmed lanes (which carry zero-width
|
|
197
|
-
// SGR bytes) stay column-aligned with the data that follows.
|
|
198
|
-
const gutterVisibleWidth = (gutterMaxLane + 1) * 2;
|
|
199
|
-
const lines: string[] = [];
|
|
200
|
-
let openLanes: ReadonlySet<number> = new Set();
|
|
201
|
-
|
|
202
|
-
function padToDataColumn(gutter: string, dataStart: number): string {
|
|
203
|
-
return gutter + ' '.repeat(Math.max(0, dataStart - gutterVisibleWidth));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
for (const row of layout.rows) {
|
|
207
|
-
if (row.kind === 'migration') {
|
|
208
|
-
const gutter = renderMigrationGutter(row, gutterMaxLane, palette, style);
|
|
209
|
-
const data = formatMigrationDataColumn(row.entry, {
|
|
210
|
-
dirNameWidth,
|
|
211
|
-
edgeKind: row.edgeKind,
|
|
212
|
-
style,
|
|
213
|
-
forwardArrow: palette.forwardArrow,
|
|
214
|
-
emptySource: palette.emptySource,
|
|
215
|
-
});
|
|
216
|
-
lines.push(`${padToDataColumn(gutter, blockDataStart)}${data}`);
|
|
217
|
-
} else if (row.kind === 'nodeLine') {
|
|
218
|
-
const gutter = renderNodeLineGutter(row, openLanes, gutterMaxLane, palette, style);
|
|
219
|
-
const data = formatNodeLineDataColumn(row.contractHash, style);
|
|
220
|
-
lines.push(`${padToDataColumn(gutter, blockDataStart)}${data}`);
|
|
221
|
-
} else {
|
|
222
|
-
lines.push(renderConnectorGutter(row, openLanes, gutterMaxLane, palette, style));
|
|
223
|
-
}
|
|
224
|
-
openLanes = advanceOpenLanes(row, openLanes);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return lines.map((line) => line.trimEnd()).join('\n');
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function renderMigrationListGraph(
|
|
231
|
-
layout: MigrationListGraphLayout,
|
|
232
|
-
style: MigrationListStyler,
|
|
233
|
-
glyphMode: GlyphMode,
|
|
234
|
-
): string {
|
|
235
|
-
return renderMigrationListGraphWithStyle(layout, style, glyphMode);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function formatGraphNodeLineHash(contractHash: string, style: MigrationListStyler): string {
|
|
239
|
-
return style.sourceHash(abbreviateContractHash(contractHash));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function formatGraphEmptyStateLine(spaceId: string, style: MigrationListStyler): string {
|
|
243
|
-
return style.emptyState(`There are no migrations in migrations/${spaceId}/ yet`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function renderGraphSpaceBlock(
|
|
247
|
-
spaceId: string,
|
|
248
|
-
migrations: readonly MigrationListEntry[],
|
|
249
|
-
multiSpace: boolean,
|
|
250
|
-
style: MigrationListStyler,
|
|
251
|
-
glyphMode: GlyphMode,
|
|
252
|
-
topology: MigrationListGraphTopology,
|
|
253
|
-
): readonly string[] {
|
|
254
|
-
if (migrations.length === 0) {
|
|
255
|
-
const emptyLine = formatGraphEmptyStateLine(spaceId, style);
|
|
256
|
-
if (!multiSpace) {
|
|
257
|
-
return [emptyLine];
|
|
258
|
-
}
|
|
259
|
-
return [style.spaceHeading(`${spaceId}:`), ` ${emptyLine}`];
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const layout = computeMigrationListGraphLayout(migrations, topology);
|
|
263
|
-
const graphBody = renderMigrationListGraphWithStyle(layout, style, glyphMode);
|
|
264
|
-
const rows = graphBody.split('\n');
|
|
265
|
-
if (!multiSpace) {
|
|
266
|
-
return rows;
|
|
267
|
-
}
|
|
268
|
-
return [style.spaceHeading(`${spaceId}:`), ...rows.map((row) => ` ${row}`)];
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export function renderMigrationListGraphResult(
|
|
272
|
-
result: MigrationListResult,
|
|
273
|
-
style: MigrationListStyler,
|
|
274
|
-
glyphMode: GlyphMode,
|
|
275
|
-
topologyBySpaceId: ReadonlyMap<string, MigrationListGraphTopology>,
|
|
276
|
-
): string {
|
|
277
|
-
const multiSpace = result.spaces.length > 1;
|
|
278
|
-
const lines: string[] = [];
|
|
279
|
-
|
|
280
|
-
for (let index = 0; index < result.spaces.length; index++) {
|
|
281
|
-
const space = result.spaces[index]!;
|
|
282
|
-
if (index > 0) {
|
|
283
|
-
lines.push('');
|
|
284
|
-
}
|
|
285
|
-
const topology = topologyBySpaceId.get(space.spaceId);
|
|
286
|
-
if (topology === undefined) {
|
|
287
|
-
throw new Error(`missing topology for space ${space.spaceId}`);
|
|
288
|
-
}
|
|
289
|
-
lines.push(
|
|
290
|
-
...renderGraphSpaceBlock(
|
|
291
|
-
space.spaceId,
|
|
292
|
-
space.migrations,
|
|
293
|
-
multiSpace,
|
|
294
|
-
style,
|
|
295
|
-
glyphMode,
|
|
296
|
-
topology,
|
|
297
|
-
),
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const totalMigrations = result.spaces.reduce(
|
|
302
|
-
(count, space) => count + space.migrations.length,
|
|
303
|
-
0,
|
|
304
|
-
);
|
|
305
|
-
if (totalMigrations > 0) {
|
|
306
|
-
lines.push('');
|
|
307
|
-
lines.push(style.summary(result.summary));
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return lines.join('\n');
|
|
311
|
-
}
|