@prisma-next/cli 0.12.0-dev.4 → 0.12.0-dev.41
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/README.md +2 -2
- package/dist/cli.mjs +180 -163
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-KgJorIvG.mjs → client-Dk-zRFuT.mjs} +83 -58
- package/dist/client-Dk-zRFuT.mjs.map +1 -0
- package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-xvg9oq4T.mjs} +301 -23
- package/dist/command-helpers-xvg9oq4T.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +4 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.mjs +4 -4
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +10 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +2 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +6 -8
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +55 -1
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +2 -2
- package/dist/commands/migration-graph.d.mts +25 -7
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +170 -2
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts +24 -26
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +2 -190
- package/dist/commands/migration-log.d.mts +20 -15
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +1 -137
- 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 -4
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +13 -25
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +41 -141
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -759
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +3 -3
- package/dist/commands/telemetry/index.d.mts +7 -0
- package/dist/commands/telemetry/index.d.mts.map +1 -0
- package/dist/commands/telemetry/index.mjs +2 -0
- package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-Wj3u4Xco.mjs} +2 -2
- package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-Wj3u4Xco.mjs.map} +1 -1
- package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-CZU0UO6M.mjs} +3 -3
- package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-CZU0UO6M.mjs.map} +1 -1
- package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-FetLZ3jn.mjs} +5 -5
- package/dist/{contract-emit-D-4jrNve.mjs.map → contract-emit-FetLZ3jn.mjs.map} +1 -1
- package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-3wtOsS_H.mjs} +3 -3
- package/dist/{contract-infer-D8uEbJuu.mjs.map → contract-infer-3wtOsS_H.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-BdRPfM3Q.mjs} +63 -5
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-BdRPfM3Q.mjs.map} +1 -1
- package/dist/{db-verify-v_vUKXTU.mjs → db-verify-BisylXFZ.mjs} +4 -4
- package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-BisylXFZ.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +2 -2
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-fYXjz_in.mjs → framework-components-Be4inY3I.mjs} +2 -2
- package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-Be4inY3I.mjs.map} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-DG4uY5tV.d.mts} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-DG4uY5tV.d.mts.map} +1 -1
- package/dist/{init-Cv9UzWL5.mjs → init-BTE2U7lG.mjs} +5 -58
- package/dist/init-BTE2U7lG.mjs.map +1 -0
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-Cy9Y4wsL.mjs} +3 -3
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs.map → inspect-live-schema-Cy9Y4wsL.mjs.map} +1 -1
- package/dist/{migration-check-BiBJoYYW.mjs → migration-check-CUavU7U9.mjs} +236 -88
- package/dist/migration-check-CUavU7U9.mjs.map +1 -0
- package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-BxOxtyJ6.mjs} +3 -3
- package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-BxOxtyJ6.mjs.map} +1 -1
- package/dist/migration-graph-space-render-ByJ83gxp.mjs +1966 -0
- package/dist/migration-graph-space-render-ByJ83gxp.mjs.map +1 -0
- package/dist/migration-list-jK6QeczE.mjs +228 -0
- package/dist/migration-list-jK6QeczE.mjs.map +1 -0
- package/dist/migration-list-types-DS63IdFd.d.mts +23 -0
- package/dist/migration-list-types-DS63IdFd.d.mts.map +1 -0
- package/dist/migration-log-DWI6dZyi.mjs +215 -0
- package/dist/migration-log-DWI6dZyi.mjs.map +1 -0
- package/dist/migration-path-target-DqcrbOis.mjs +24 -0
- package/dist/migration-path-target-DqcrbOis.mjs.map +1 -0
- package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-NHdlUwPG.mjs} +5 -6
- package/dist/{migration-plan-9DJ7q7_z.mjs.map → migration-plan-NHdlUwPG.mjs.map} +1 -1
- package/dist/migration-status-DI6Ldjbo.mjs +439 -0
- package/dist/migration-status-DI6Ldjbo.mjs.map +1 -0
- package/dist/{output-B60Gw5fu.mjs → output-CF_hqzI-.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-CF_hqzI-.mjs.map} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-CJY9zOv7.mjs} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-CJY9zOv7.mjs.map} +1 -1
- package/dist/telemetry-DQP0BvKv.mjs +122 -0
- package/dist/telemetry-DQP0BvKv.mjs.map +1 -0
- package/dist/{types-Dt_SfqFm.d.mts → types-Cculk5KV.d.mts} +44 -31
- package/dist/types-Cculk5KV.d.mts.map +1 -0
- package/dist/{verify-DCA9Sldu.mjs → verify-tvHRBBVP.mjs} +2 -2
- package/dist/{verify-DCA9Sldu.mjs.map → verify-tvHRBBVP.mjs.map} +1 -1
- package/package.json +22 -19
- package/src/cli.ts +5 -0
- package/src/commands/db-update.ts +7 -1
- package/src/commands/init/index.ts +6 -35
- package/src/commands/init/init.ts +1 -14
- package/src/commands/init/inputs.ts +0 -75
- package/src/commands/migrate.ts +6 -6
- package/src/commands/migration-check.ts +340 -117
- package/src/commands/migration-graph.ts +163 -90
- package/src/commands/migration-list.ts +55 -25
- package/src/commands/migration-log.ts +49 -98
- package/src/commands/migration-show.ts +10 -38
- package/src/commands/migration-status-overlay.ts +61 -0
- package/src/commands/migration-status.ts +440 -1056
- package/src/commands/telemetry/index.ts +107 -0
- package/src/commands/telemetry/status.ts +67 -0
- package/src/control-api/client.ts +20 -9
- package/src/control-api/operations/contract-emit.ts +2 -2
- package/src/control-api/operations/db-init.ts +3 -3
- package/src/control-api/operations/{db-apply.ts → db-run.ts} +37 -10
- package/src/control-api/operations/db-update.ts +4 -4
- package/src/control-api/operations/{migration-apply.ts → migrate.ts} +32 -24
- package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
- package/src/control-api/types.ts +46 -29
- package/src/utils/cli-errors.ts +47 -2
- package/src/utils/formatters/errors.ts +11 -0
- package/src/utils/formatters/migration-graph-lane-colors.ts +194 -0
- package/src/utils/formatters/migration-graph-layout.ts +51 -7
- package/src/utils/formatters/migration-graph-rows.ts +128 -15
- package/src/utils/formatters/migration-graph-space-render.ts +138 -0
- package/src/utils/formatters/migration-graph-tree-render.ts +405 -77
- package/src/utils/formatters/migration-list-data-column.ts +4 -91
- package/src/utils/formatters/migration-list-graph-topology.ts +68 -90
- package/src/utils/formatters/migration-list-render.ts +122 -70
- package/src/utils/formatters/migration-list-styler.ts +48 -5
- package/src/utils/formatters/migration-log-table.ts +200 -0
- package/src/utils/formatters/migrations.ts +25 -1
- package/src/utils/global-flags.ts +35 -0
- package/src/utils/legend.ts +38 -0
- package/src/utils/migration-path-target.ts +39 -0
- package/src/utils/telemetry.ts +68 -32
- package/dist/client-KgJorIvG.mjs.map +0 -1
- package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
- package/dist/commands/migration-list.mjs.map +0 -1
- package/dist/commands/migration-log.mjs.map +0 -1
- package/dist/commands/migration-status.mjs.map +0 -1
- package/dist/extension-pack-inputs-IDvjRCi3.mjs +0 -62
- package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +0 -1
- package/dist/graph-render-rFAqZujX.mjs +0 -1081
- package/dist/graph-render-rFAqZujX.mjs.map +0 -1
- package/dist/init-Cv9UzWL5.mjs.map +0 -1
- package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
- package/dist/migration-graph-D7DVUElV.mjs +0 -1232
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
- package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
- package/dist/migration-types-D2FW63pr.d.mts +0 -15
- package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
- package/dist/migrations-Cv2jxNNK.mjs +0 -228
- package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
- package/dist/types-Dt_SfqFm.d.mts.map +0 -1
- package/src/utils/formatters/graph-migration-mapper.ts +0 -235
- package/src/utils/formatters/graph-render.ts +0 -1323
- package/src/utils/formatters/graph-types.ts +0 -120
|
@@ -21,6 +21,7 @@ export type StructuralCell =
|
|
|
21
21
|
| { readonly kind: 'arc-branch-corner' }
|
|
22
22
|
| { readonly kind: 'arc-branch-tee' }
|
|
23
23
|
| { readonly kind: 'arc-land-corner' }
|
|
24
|
+
| { readonly kind: 'arc-land-tee' }
|
|
24
25
|
| { readonly kind: 'arc-crossing' }
|
|
25
26
|
| { readonly kind: 'arc-land-bridge' }
|
|
26
27
|
| {
|
|
@@ -379,6 +380,7 @@ function emptyCells(width: number): StructuralCell[] {
|
|
|
379
380
|
function buildBranchConnectorCells(
|
|
380
381
|
startLane: number,
|
|
381
382
|
endLane: number,
|
|
383
|
+
fanTargetLanes: ReadonlySet<number>,
|
|
382
384
|
activeLanes: ReadonlySet<number>,
|
|
383
385
|
gridWidth: number,
|
|
384
386
|
): StructuralCell[] {
|
|
@@ -393,7 +395,13 @@ function buildBranchConnectorCells(
|
|
|
393
395
|
} else if (lane === endLane) {
|
|
394
396
|
cells[lane] = { kind: 'branch-corner' };
|
|
395
397
|
} else if (lane > startLane && lane < endLane) {
|
|
396
|
-
|
|
398
|
+
if (fanTargetLanes.has(lane)) {
|
|
399
|
+
cells[lane] = { kind: 'branch-tee' };
|
|
400
|
+
} else if (activeLanes.has(lane)) {
|
|
401
|
+
cells[lane] = { kind: 'arc-crossing' };
|
|
402
|
+
} else {
|
|
403
|
+
cells[lane] = { kind: 'branch-tee' };
|
|
404
|
+
}
|
|
397
405
|
}
|
|
398
406
|
}
|
|
399
407
|
return cells;
|
|
@@ -402,6 +410,7 @@ function buildBranchConnectorCells(
|
|
|
402
410
|
function buildMergeConnectorCells(
|
|
403
411
|
startLane: number,
|
|
404
412
|
endLane: number,
|
|
413
|
+
fanTargetLanes: ReadonlySet<number>,
|
|
405
414
|
activeLanes: ReadonlySet<number>,
|
|
406
415
|
gridWidth: number,
|
|
407
416
|
): StructuralCell[] {
|
|
@@ -416,7 +425,13 @@ function buildMergeConnectorCells(
|
|
|
416
425
|
} else if (lane === endLane) {
|
|
417
426
|
cells[lane] = { kind: 'merge-corner' };
|
|
418
427
|
} else if (lane > startLane && lane < endLane) {
|
|
419
|
-
|
|
428
|
+
if (fanTargetLanes.has(lane)) {
|
|
429
|
+
cells[lane] = { kind: 'merge-tee' };
|
|
430
|
+
} else if (activeLanes.has(lane)) {
|
|
431
|
+
cells[lane] = { kind: 'arc-crossing' };
|
|
432
|
+
} else {
|
|
433
|
+
cells[lane] = { kind: 'horizontal-pass' };
|
|
434
|
+
}
|
|
420
435
|
}
|
|
421
436
|
}
|
|
422
437
|
return cells;
|
|
@@ -689,6 +704,15 @@ function applySkipRollbackRouting(
|
|
|
689
704
|
.map((other) => other.backLane);
|
|
690
705
|
const maxCoSourcedLane = Math.max(...coSourcedLanes);
|
|
691
706
|
|
|
707
|
+
// Back-lanes of arcs that converge on this same target node. They share the
|
|
708
|
+
// node's landing row, so each inner lane reads as a `┴` junction (the outer
|
|
709
|
+
// arcs' horizontal bridge passes through it on the way to the node) and only
|
|
710
|
+
// the outermost closes the corner with `╯`.
|
|
711
|
+
const coLandingLanes = routes
|
|
712
|
+
.filter((other) => other.edge.to === edge.to)
|
|
713
|
+
.map((other) => other.backLane);
|
|
714
|
+
const maxCoLandingLane = Math.max(...coLandingLanes);
|
|
715
|
+
|
|
692
716
|
const sourceRow = result[sourceRowIndex];
|
|
693
717
|
if (sourceRow !== undefined) {
|
|
694
718
|
const cells = sourceRow.cells;
|
|
@@ -750,6 +774,7 @@ function applySkipRollbackRouting(
|
|
|
750
774
|
const existing = cells[backLane];
|
|
751
775
|
if (
|
|
752
776
|
existing?.kind !== 'arc-land-corner' &&
|
|
777
|
+
existing?.kind !== 'arc-land-tee' &&
|
|
753
778
|
existing?.kind !== 'arc-land-bridge' &&
|
|
754
779
|
existing?.kind !== 'arc-branch-corner' &&
|
|
755
780
|
existing?.kind !== 'arc-branch-tee' &&
|
|
@@ -766,6 +791,12 @@ function applySkipRollbackRouting(
|
|
|
766
791
|
const contractHash = targetRow.contractHash ?? EMPTY_CONTRACT_HASH;
|
|
767
792
|
cells[targetCol] = { kind: 'node', contractHash, arcLand: true };
|
|
768
793
|
for (let lane = targetCol + 1; lane < backLane; lane += 1) {
|
|
794
|
+
// An inner converging arc's own landing junction: the outer arcs' bridge
|
|
795
|
+
// passes through it (`┴`) while its own vertical run closes here.
|
|
796
|
+
if (coLandingLanes.includes(lane)) {
|
|
797
|
+
cells[lane] = { kind: 'arc-land-tee' };
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
769
800
|
// A bridged lane that carries another arc OR a forward vertical still
|
|
770
801
|
// active at this row must cross over it (`┼`) rather than overwrite it
|
|
771
802
|
// with a bare bridge (`──`).
|
|
@@ -774,7 +805,8 @@ function applySkipRollbackRouting(
|
|
|
774
805
|
existing !== undefined &&
|
|
775
806
|
existing.kind !== 'empty' &&
|
|
776
807
|
existing.kind !== 'horizontal-pass' &&
|
|
777
|
-
existing.kind !== 'arc-land-bridge'
|
|
808
|
+
existing.kind !== 'arc-land-bridge' &&
|
|
809
|
+
existing.kind !== 'arc-land-tee';
|
|
778
810
|
const crossed =
|
|
779
811
|
occupied ||
|
|
780
812
|
routes.some(
|
|
@@ -785,7 +817,10 @@ function applySkipRollbackRouting(
|
|
|
785
817
|
);
|
|
786
818
|
cells[lane] = crossed ? { kind: 'arc-crossing' } : { kind: 'arc-land-bridge' };
|
|
787
819
|
}
|
|
788
|
-
|
|
820
|
+
// Inner converging arcs close as a landing tee so the outermost arc's
|
|
821
|
+
// bridge reads through to the node; only the outermost arc draws `╯`.
|
|
822
|
+
cells[backLane] =
|
|
823
|
+
backLane < maxCoLandingLane ? { kind: 'arc-land-tee' } : { kind: 'arc-land-corner' };
|
|
789
824
|
for (const other of routes) {
|
|
790
825
|
if (other.backLane <= backLane) continue;
|
|
791
826
|
if (!routeCrossesRow(other, targetRowIndex, result)) continue;
|
|
@@ -793,6 +828,7 @@ function applySkipRollbackRouting(
|
|
|
793
828
|
const existing = cells[other.backLane];
|
|
794
829
|
if (
|
|
795
830
|
existing?.kind !== 'arc-land-corner' &&
|
|
831
|
+
existing?.kind !== 'arc-land-tee' &&
|
|
796
832
|
existing?.kind !== 'arc-land-bridge' &&
|
|
797
833
|
existing?.kind !== 'node'
|
|
798
834
|
) {
|
|
@@ -922,13 +958,14 @@ function layoutComponent(
|
|
|
922
958
|
const endLane = Math.max(...laneIndices);
|
|
923
959
|
ensureGridWidth(endLane + 1);
|
|
924
960
|
const activeLanes = new Set(activeLaneIndices());
|
|
961
|
+
const fanTargetLanes = new Set(laneIndices);
|
|
925
962
|
rows.push({
|
|
926
963
|
kind: 'merge-connector',
|
|
927
964
|
contractHash,
|
|
928
965
|
startLane,
|
|
929
966
|
endLane,
|
|
930
967
|
branchCount: laneIndices.length,
|
|
931
|
-
cells: buildMergeConnectorCells(startLane, endLane, activeLanes, gridWidth),
|
|
968
|
+
cells: buildMergeConnectorCells(startLane, endLane, fanTargetLanes, activeLanes, gridWidth),
|
|
932
969
|
});
|
|
933
970
|
for (const index of laneIndices) {
|
|
934
971
|
if (index !== startLane) setLane(index, null);
|
|
@@ -941,6 +978,7 @@ function layoutComponent(
|
|
|
941
978
|
startLane: number,
|
|
942
979
|
endLane: number,
|
|
943
980
|
branchCount: number,
|
|
981
|
+
fanTargetLanes: readonly number[],
|
|
944
982
|
): void {
|
|
945
983
|
ensureGridWidth(endLane + 1);
|
|
946
984
|
const activeLanes = new Set(activeLaneIndices());
|
|
@@ -950,7 +988,13 @@ function layoutComponent(
|
|
|
950
988
|
startLane,
|
|
951
989
|
endLane,
|
|
952
990
|
branchCount,
|
|
953
|
-
cells: buildBranchConnectorCells(
|
|
991
|
+
cells: buildBranchConnectorCells(
|
|
992
|
+
startLane,
|
|
993
|
+
endLane,
|
|
994
|
+
new Set(fanTargetLanes),
|
|
995
|
+
activeLanes,
|
|
996
|
+
gridWidth,
|
|
997
|
+
),
|
|
954
998
|
});
|
|
955
999
|
}
|
|
956
1000
|
|
|
@@ -1046,7 +1090,7 @@ function layoutComponent(
|
|
|
1046
1090
|
|
|
1047
1091
|
if (groups.length >= 2) {
|
|
1048
1092
|
const endLane = Math.max(...laneForGroup);
|
|
1049
|
-
emitBranchConnector(node, column, endLane, groups.length);
|
|
1093
|
+
emitBranchConnector(node, column, endLane, groups.length, laneForGroup);
|
|
1050
1094
|
}
|
|
1051
1095
|
|
|
1052
1096
|
for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
|
@@ -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
|
-
|
|
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(
|
|
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 {
|
|
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
|
+
}
|