prisma-next 0.12.0-dev.27 → 0.12.0-dev.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +12 -12
- package/dist/{client-V7BkIQrQ.mjs → client-xeWpMlq1.mjs} +22 -11
- package/dist/client-xeWpMlq1.mjs.map +1 -0
- package/dist/{command-helpers-DlrUCI7s.mjs → command-helpers-DK_5ItoJ.mjs} +253 -2
- package/dist/command-helpers-DK_5ItoJ.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 +1 -1
- package/dist/commands/migrate.mjs +5 -6
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.d.mts +12 -15
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +84 -51
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.d.mts +14 -5
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +1 -187
- package/dist/commands/migration-log.d.mts +2 -2
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-new.mjs +3 -3
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +3 -4
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +21 -3
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -3
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +3 -3
- package/dist/commands/telemetry/index.mjs +1 -1
- package/dist/{contract-at-errors-DlZHXSkI.mjs → contract-at-errors-DG3kjgoz.mjs} +2 -2
- package/dist/{contract-at-errors-DlZHXSkI.mjs.map → contract-at-errors-DG3kjgoz.mjs.map} +1 -1
- package/dist/{contract-emit-S53EyBRV.mjs → contract-emit-BO0l6fnT.mjs} +3 -3
- package/dist/{contract-emit-S53EyBRV.mjs.map → contract-emit-BO0l6fnT.mjs.map} +1 -1
- package/dist/{contract-emit-CaKp92-Q.mjs → contract-emit-C0Bs0VRj.mjs} +3 -3
- package/dist/{contract-emit-CaKp92-Q.mjs.map → contract-emit-C0Bs0VRj.mjs.map} +1 -1
- package/dist/{contract-infer-Cebb-_Qx.mjs → contract-infer-2wtPflGH.mjs} +3 -3
- package/dist/{contract-infer-Cebb-_Qx.mjs.map → contract-infer-2wtPflGH.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-Dvl1SJ4C.mjs → contract-space-aggregate-loader-Dbr3-jHF.mjs} +3 -3
- package/dist/{contract-space-aggregate-loader-Dvl1SJ4C.mjs.map → contract-space-aggregate-loader-Dbr3-jHF.mjs.map} +1 -1
- package/dist/{db-verify-B1OoWEWn.mjs → db-verify-CxHiSiTG.mjs} +4 -4
- package/dist/{db-verify-B1OoWEWn.mjs.map → db-verify-CxHiSiTG.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/{framework-components-DCAT1uUC.mjs → framework-components-CxOVKAAh.mjs} +2 -2
- package/dist/{framework-components-DCAT1uUC.mjs.map → framework-components-CxOVKAAh.mjs.map} +1 -1
- package/dist/{init-Kf3T4A4W.mjs → init-R272pxux.mjs} +3 -3
- package/dist/{init-Kf3T4A4W.mjs.map → init-R272pxux.mjs.map} +1 -1
- package/dist/{inspect-live-schema-DTqflZ8X.mjs → inspect-live-schema-RekOwfi5.mjs} +3 -3
- package/dist/{inspect-live-schema-DTqflZ8X.mjs.map → inspect-live-schema-RekOwfi5.mjs.map} +1 -1
- package/dist/{migration-check-Ccyd0QKb.mjs → migration-check-Dc0cOhKH.mjs} +2 -2
- package/dist/{migration-check-Ccyd0QKb.mjs.map → migration-check-Dc0cOhKH.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-DI7_SFL0.mjs → migration-command-scaffold-ApB3NxWY.mjs} +3 -3
- package/dist/{migration-command-scaffold-DI7_SFL0.mjs.map → migration-command-scaffold-ApB3NxWY.mjs.map} +1 -1
- package/dist/{migration-graph-tree-render-DyDBuJEX.mjs → migration-graph-space-render-dmLLWift.mjs} +389 -210
- package/dist/migration-graph-space-render-dmLLWift.mjs.map +1 -0
- package/dist/migration-list-C5sXrl0U.mjs +228 -0
- package/dist/migration-list-C5sXrl0U.mjs.map +1 -0
- package/dist/{migration-list-types-DV9PBc7Z.d.mts → migration-list-types-DS63IdFd.d.mts} +1 -1
- package/dist/{migration-list-types-DV9PBc7Z.d.mts.map → migration-list-types-DS63IdFd.d.mts.map} +1 -1
- package/dist/{migration-log-Des4seHP.mjs → migration-log-DD_vCbYW.mjs} +4 -4
- package/dist/{migration-log-Des4seHP.mjs.map → migration-log-DD_vCbYW.mjs.map} +1 -1
- package/dist/{migration-plan-DxDTBzGS.mjs → migration-plan-CeTjQOIG.mjs} +5 -5
- package/dist/{migration-plan-DxDTBzGS.mjs.map → migration-plan-CeTjQOIG.mjs.map} +1 -1
- package/dist/{migration-status-CCwqA-vi.mjs → migration-status-qV8ctwPy.mjs} +61 -45
- package/dist/migration-status-qV8ctwPy.mjs.map +1 -0
- package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-V1o-9LVK.mjs} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-V1o-9LVK.mjs.map} +1 -1
- package/dist/{telemetry-LFFQmqHd.mjs → telemetry-S-NGi9U6.mjs} +2 -2
- package/dist/{telemetry-LFFQmqHd.mjs.map → telemetry-S-NGi9U6.mjs.map} +1 -1
- package/dist/{terminal-ui-C3xGyxW-.d.mts → terminal-ui-5Y6mrg93.d.mts} +1 -1
- package/dist/{terminal-ui-C3xGyxW-.d.mts.map → terminal-ui-5Y6mrg93.d.mts.map} +1 -1
- package/dist/{types-BdS8PoKM.d.mts → types-Mh7mdPHM.d.mts} +5 -1
- package/dist/types-Mh7mdPHM.d.mts.map +1 -0
- package/dist/{verify-C0TARc6h.mjs → verify-BdI-BgYi.mjs} +2 -2
- package/dist/{verify-C0TARc6h.mjs.map → verify-BdI-BgYi.mjs.map} +1 -1
- package/package.json +11 -11
- package/dist/client-V7BkIQrQ.mjs.map +0 -1
- package/dist/command-helpers-DlrUCI7s.mjs.map +0 -1
- package/dist/commands/migration-list.mjs.map +0 -1
- package/dist/migration-graph-tree-render-DyDBuJEX.mjs.map +0 -1
- package/dist/migration-status-CCwqA-vi.mjs.map +0 -1
- package/dist/migration-types-CAQ-0TEE.d.mts +0 -15
- package/dist/migration-types-CAQ-0TEE.d.mts.map +0 -1
- package/dist/migrations-B3H6RTXb.mjs +0 -228
- package/dist/migrations-B3H6RTXb.mjs.map +0 -1
- package/dist/types-BdS8PoKM.d.mts.map +0 -1
package/dist/{migration-graph-tree-render-DyDBuJEX.mjs → migration-graph-space-render-dmLLWift.mjs}
RENAMED
|
@@ -945,7 +945,12 @@ function compareNodesTipsFirst(a, b, rank) {
|
|
|
945
945
|
* at the same rank — stable across edge-insertion order and correct under
|
|
946
946
|
* diamonds, cross-links, and rollbacks.
|
|
947
947
|
*/
|
|
948
|
-
function
|
|
948
|
+
function maxRank(rank) {
|
|
949
|
+
let max = 0;
|
|
950
|
+
for (const value of rank.values()) if (value > max) max = value;
|
|
951
|
+
return max;
|
|
952
|
+
}
|
|
953
|
+
function layerNodesByLongestForwardPath(componentNodes, topology, graph, contractHash) {
|
|
949
954
|
const forwardOut = /* @__PURE__ */ new Map();
|
|
950
955
|
for (const node of componentNodes) forwardOut.set(node, []);
|
|
951
956
|
for (const edges of graph.forwardChain.values()) for (const edge of edges) {
|
|
@@ -975,6 +980,7 @@ function layerNodesByLongestForwardPath(componentNodes, topology, graph) {
|
|
|
975
980
|
if (!changed) break;
|
|
976
981
|
}
|
|
977
982
|
for (const node of componentNodes) if (!rank.has(node)) rank.set(node, 0);
|
|
983
|
+
if (contractHash !== void 0 && contractHash !== EMPTY_CONTRACT_HASH && componentNodes.has(contractHash) && (forwardOut.get(contractHash) ?? []).length === 0) rank.set(contractHash, maxRank(rank) + 1);
|
|
978
984
|
return [...componentNodes].sort((a, b) => compareNodesTipsFirst(a, b, rank));
|
|
979
985
|
}
|
|
980
986
|
/**
|
|
@@ -1000,6 +1006,77 @@ function layerNodesByLongestForwardPath(componentNodes, topology, graph) {
|
|
|
1000
1006
|
function detachedContractHash(graph, contractHash) {
|
|
1001
1007
|
return contractHash !== void 0 && contractHash !== EMPTY_CONTRACT_HASH && !graph.nodes.has(contractHash) ? contractHash : void 0;
|
|
1002
1008
|
}
|
|
1009
|
+
function isForwardLeaf(node, edges) {
|
|
1010
|
+
return !edges.some((e) => e.kind === "forward" && e.from === node && e.from !== e.to);
|
|
1011
|
+
}
|
|
1012
|
+
function forwardReachableFrom(start, forwardTo) {
|
|
1013
|
+
const reachable = new Set([start]);
|
|
1014
|
+
const queue = [start];
|
|
1015
|
+
while (queue.length > 0) {
|
|
1016
|
+
const node = queue.shift();
|
|
1017
|
+
if (node === void 0) continue;
|
|
1018
|
+
for (const next of forwardTo.get(node) ?? []) if (!reachable.has(next)) {
|
|
1019
|
+
reachable.add(next);
|
|
1020
|
+
queue.push(next);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return reachable;
|
|
1024
|
+
}
|
|
1025
|
+
function buildForwardToMap(edges) {
|
|
1026
|
+
const forwardTo = /* @__PURE__ */ new Map();
|
|
1027
|
+
for (const edge of edges) {
|
|
1028
|
+
if (edge.kind !== "forward" || edge.from === edge.to) continue;
|
|
1029
|
+
const bucket = forwardTo.get(edge.from);
|
|
1030
|
+
if (bucket) bucket.push(edge.to);
|
|
1031
|
+
else forwardTo.set(edge.from, [edge.to]);
|
|
1032
|
+
}
|
|
1033
|
+
return forwardTo;
|
|
1034
|
+
}
|
|
1035
|
+
function sortEdgesForContractHashTrunk(edges, contractHash) {
|
|
1036
|
+
if (contractHash === void 0 || contractHash === EMPTY_CONTRACT_HASH || !isForwardLeaf(contractHash, edges)) return edges;
|
|
1037
|
+
const preferredLeaf = contractHash;
|
|
1038
|
+
const forwardTo = buildForwardToMap(edges);
|
|
1039
|
+
const reachability = /* @__PURE__ */ new Map();
|
|
1040
|
+
function canReachContractHash(from) {
|
|
1041
|
+
let cached = reachability.get(from);
|
|
1042
|
+
if (cached === void 0) {
|
|
1043
|
+
cached = forwardReachableFrom(from, forwardTo);
|
|
1044
|
+
reachability.set(from, cached);
|
|
1045
|
+
}
|
|
1046
|
+
return cached.has(preferredLeaf);
|
|
1047
|
+
}
|
|
1048
|
+
function trunkBias(edge) {
|
|
1049
|
+
if (edge.kind !== "forward" || edge.from === edge.to) return 0;
|
|
1050
|
+
if (edge.to === preferredLeaf) return 2;
|
|
1051
|
+
if (canReachContractHash(edge.to)) return 1;
|
|
1052
|
+
return 0;
|
|
1053
|
+
}
|
|
1054
|
+
return edges.map((edge, index) => ({
|
|
1055
|
+
edge,
|
|
1056
|
+
index,
|
|
1057
|
+
bias: trunkBias(edge)
|
|
1058
|
+
})).sort((a, b) => {
|
|
1059
|
+
if (a.edge.from !== b.edge.from) return a.index - b.index;
|
|
1060
|
+
if (a.bias !== b.bias) return b.bias - a.bias;
|
|
1061
|
+
return a.index - b.index;
|
|
1062
|
+
}).map(({ edge }) => edge);
|
|
1063
|
+
}
|
|
1064
|
+
function rebuildEdgeLookupMaps(edges) {
|
|
1065
|
+
const edgesByFrom = /* @__PURE__ */ new Map();
|
|
1066
|
+
const edgesByTo = /* @__PURE__ */ new Map();
|
|
1067
|
+
for (const classified of edges) {
|
|
1068
|
+
const fromBucket = edgesByFrom.get(classified.from);
|
|
1069
|
+
if (fromBucket) fromBucket.push(classified);
|
|
1070
|
+
else edgesByFrom.set(classified.from, [classified]);
|
|
1071
|
+
const toBucket = edgesByTo.get(classified.to);
|
|
1072
|
+
if (toBucket) toBucket.push(classified);
|
|
1073
|
+
else edgesByTo.set(classified.to, [classified]);
|
|
1074
|
+
}
|
|
1075
|
+
return {
|
|
1076
|
+
edgesByFrom,
|
|
1077
|
+
edgesByTo
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1003
1080
|
function buildMigrationGraphRows(graph, options = {}) {
|
|
1004
1081
|
const emptyModel = {
|
|
1005
1082
|
nodes: [],
|
|
@@ -1016,32 +1093,25 @@ function buildMigrationGraphRows(graph, options = {}) {
|
|
|
1016
1093
|
}
|
|
1017
1094
|
const topology = classifyMigrationGraphTopology(graph);
|
|
1018
1095
|
const edges = [];
|
|
1019
|
-
const edgesByFrom = /* @__PURE__ */ new Map();
|
|
1020
|
-
const edgesByTo = /* @__PURE__ */ new Map();
|
|
1021
1096
|
for (const edgeList of graph.forwardChain.values()) for (const edge of edgeList) {
|
|
1022
1097
|
const kind = topology.kindByMigrationHash.get(edge.migrationHash) ?? "forward";
|
|
1023
|
-
|
|
1098
|
+
edges.push({
|
|
1024
1099
|
migrationHash: edge.migrationHash,
|
|
1025
1100
|
from: edge.from,
|
|
1026
1101
|
to: edge.to,
|
|
1027
1102
|
dirName: edge.dirName,
|
|
1028
1103
|
kind
|
|
1029
|
-
};
|
|
1030
|
-
edges.push(classified);
|
|
1031
|
-
const fromBucket = edgesByFrom.get(edge.from);
|
|
1032
|
-
if (fromBucket) fromBucket.push(classified);
|
|
1033
|
-
else edgesByFrom.set(edge.from, [classified]);
|
|
1034
|
-
const toBucket = edgesByTo.get(edge.to);
|
|
1035
|
-
if (toBucket) toBucket.push(classified);
|
|
1036
|
-
else edgesByTo.set(edge.to, [classified]);
|
|
1104
|
+
});
|
|
1037
1105
|
}
|
|
1106
|
+
const sortedEdges = sortEdgesForContractHashTrunk(edges, options.contractHash);
|
|
1107
|
+
const { edgesByFrom, edgesByTo } = rebuildEdgeLookupMaps(sortedEdges);
|
|
1038
1108
|
const components = weaklyConnectedComponents(graph);
|
|
1039
1109
|
const nodes = [];
|
|
1040
1110
|
for (let i = 0; i < components.length; i++) {
|
|
1041
1111
|
if (i > 0) nodes.push(null);
|
|
1042
1112
|
const component = components[i];
|
|
1043
1113
|
if (component === void 0) continue;
|
|
1044
|
-
const ordered = layerNodesByLongestForwardPath(component, topology, graph);
|
|
1114
|
+
const ordered = layerNodesByLongestForwardPath(component, topology, graph, options.contractHash);
|
|
1045
1115
|
for (const node of ordered) nodes.push(node);
|
|
1046
1116
|
}
|
|
1047
1117
|
const detached = detachedContractHash(graph, options.contractHash);
|
|
@@ -1051,7 +1121,7 @@ function buildMigrationGraphRows(graph, options = {}) {
|
|
|
1051
1121
|
}
|
|
1052
1122
|
return {
|
|
1053
1123
|
nodes,
|
|
1054
|
-
edges,
|
|
1124
|
+
edges: sortedEdges,
|
|
1055
1125
|
edgesByFrom,
|
|
1056
1126
|
edgesByTo
|
|
1057
1127
|
};
|
|
@@ -1080,6 +1150,126 @@ function laneColorForColumn(column) {
|
|
|
1080
1150
|
if (column <= 0) return (text) => text;
|
|
1081
1151
|
return LANE_COLOR_CYCLE[(column - 1) % LANE_COLOR_CYCLE.length] ?? ((text) => text);
|
|
1082
1152
|
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Style a structural glyph by its resolved colour column. Column 0 and the
|
|
1155
|
+
* neutral sentinel render dim (`dimLane`); columns ≥ 1 take a palette hue.
|
|
1156
|
+
*/
|
|
1157
|
+
function stylerForLaneColumn(colorColumn, colorize, dimLane) {
|
|
1158
|
+
if (!colorize || colorColumn <= 0) return dimLane;
|
|
1159
|
+
return laneColorForColumn(colorColumn);
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Resolve per-cell colour columns for a node/arc row. Scanning right-to-left
|
|
1163
|
+
* lets each arc segment inherit the hue of the arc it leads into.
|
|
1164
|
+
*/
|
|
1165
|
+
function resolveRowArcLaneColors(cells) {
|
|
1166
|
+
const lane = new Array(cells.length);
|
|
1167
|
+
const connector = new Array(cells.length);
|
|
1168
|
+
const dash = new Array(cells.length);
|
|
1169
|
+
let arcCorner = 0;
|
|
1170
|
+
let landingAnchor = 0;
|
|
1171
|
+
for (let column = cells.length - 1; column >= 0; column--) {
|
|
1172
|
+
const cell = cells[column];
|
|
1173
|
+
connector[column] = landingAnchor !== 0 ? landingAnchor : arcCorner;
|
|
1174
|
+
switch (cell?.kind) {
|
|
1175
|
+
case "arc-branch-corner":
|
|
1176
|
+
arcCorner = column;
|
|
1177
|
+
lane[column] = column;
|
|
1178
|
+
dash[column] = column;
|
|
1179
|
+
break;
|
|
1180
|
+
case "arc-land-corner":
|
|
1181
|
+
arcCorner = column;
|
|
1182
|
+
landingAnchor = column;
|
|
1183
|
+
lane[column] = column;
|
|
1184
|
+
dash[column] = column;
|
|
1185
|
+
break;
|
|
1186
|
+
case "arc-branch-tee":
|
|
1187
|
+
lane[column] = column;
|
|
1188
|
+
dash[column] = column;
|
|
1189
|
+
break;
|
|
1190
|
+
case "arc-land-tee":
|
|
1191
|
+
lane[column] = column;
|
|
1192
|
+
dash[column] = landingAnchor === 0 ? column : landingAnchor;
|
|
1193
|
+
landingAnchor = column;
|
|
1194
|
+
break;
|
|
1195
|
+
case "arc-crossing":
|
|
1196
|
+
case "arc-land-bridge": {
|
|
1197
|
+
const served = landingAnchor !== 0 ? landingAnchor : arcCorner;
|
|
1198
|
+
lane[column] = served;
|
|
1199
|
+
dash[column] = served;
|
|
1200
|
+
break;
|
|
1201
|
+
}
|
|
1202
|
+
case "horizontal-pass":
|
|
1203
|
+
lane[column] = arcCorner === 0 ? column : arcCorner;
|
|
1204
|
+
dash[column] = lane[column] ?? column;
|
|
1205
|
+
break;
|
|
1206
|
+
case "node":
|
|
1207
|
+
lane[column] = column;
|
|
1208
|
+
dash[column] = column;
|
|
1209
|
+
arcCorner = 0;
|
|
1210
|
+
landingAnchor = 0;
|
|
1211
|
+
break;
|
|
1212
|
+
default:
|
|
1213
|
+
lane[column] = column;
|
|
1214
|
+
dash[column] = column;
|
|
1215
|
+
arcCorner = 0;
|
|
1216
|
+
landingAnchor = 0;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
return {
|
|
1220
|
+
lane,
|
|
1221
|
+
connector,
|
|
1222
|
+
dash
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Resolve per-cell connector colours. Scanning right-to-left, a corner or an
|
|
1227
|
+
* intermediate tee anchors its own lane, but a tee's trailing dash leads into
|
|
1228
|
+
* the branch on its right.
|
|
1229
|
+
*/
|
|
1230
|
+
function resolveConnectorLaneColors(cells, startLane) {
|
|
1231
|
+
const glyph = new Array(cells.length);
|
|
1232
|
+
const dash = new Array(cells.length);
|
|
1233
|
+
let owner = 0;
|
|
1234
|
+
for (let column = cells.length - 1; column >= 0; column--) switch (cells[column]?.kind) {
|
|
1235
|
+
case "branch-corner":
|
|
1236
|
+
case "merge-corner":
|
|
1237
|
+
owner = column;
|
|
1238
|
+
glyph[column] = column;
|
|
1239
|
+
dash[column] = column;
|
|
1240
|
+
break;
|
|
1241
|
+
case "branch-tee":
|
|
1242
|
+
case "merge-tee":
|
|
1243
|
+
if (column === startLane) {
|
|
1244
|
+
const served = owner === 0 ? column : owner;
|
|
1245
|
+
glyph[column] = column;
|
|
1246
|
+
dash[column] = served;
|
|
1247
|
+
} else {
|
|
1248
|
+
dash[column] = owner === 0 ? column : owner;
|
|
1249
|
+
glyph[column] = column;
|
|
1250
|
+
owner = column;
|
|
1251
|
+
}
|
|
1252
|
+
break;
|
|
1253
|
+
case "arc-crossing":
|
|
1254
|
+
glyph[column] = column;
|
|
1255
|
+
dash[column] = owner === 0 ? column : owner;
|
|
1256
|
+
owner = column;
|
|
1257
|
+
break;
|
|
1258
|
+
case "horizontal-pass": {
|
|
1259
|
+
const served = owner === 0 ? column : owner;
|
|
1260
|
+
glyph[column] = served;
|
|
1261
|
+
dash[column] = served;
|
|
1262
|
+
break;
|
|
1263
|
+
}
|
|
1264
|
+
default:
|
|
1265
|
+
glyph[column] = column;
|
|
1266
|
+
dash[column] = column;
|
|
1267
|
+
}
|
|
1268
|
+
return {
|
|
1269
|
+
glyph,
|
|
1270
|
+
dash
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1083
1273
|
function migrationListForwardArrow(glyphMode) {
|
|
1084
1274
|
return glyphMode === "ascii" ? "->" : "→";
|
|
1085
1275
|
}
|
|
@@ -1089,6 +1279,10 @@ function migrationListEmptySource(glyphMode) {
|
|
|
1089
1279
|
function abbreviateContractHash(hash) {
|
|
1090
1280
|
return (hash.startsWith("sha256:") ? hash.slice(7) : hash).slice(0, 7);
|
|
1091
1281
|
}
|
|
1282
|
+
function padFromHashColumn(text, width) {
|
|
1283
|
+
const padding = Math.max(0, width - stringWidth(text));
|
|
1284
|
+
return `${" ".repeat(padding)}${text}`;
|
|
1285
|
+
}
|
|
1092
1286
|
//#endregion
|
|
1093
1287
|
//#region src/utils/formatters/migration-list-render.ts
|
|
1094
1288
|
const IDENTITY_MIGRATION_LIST_STYLER = {
|
|
@@ -1155,24 +1349,25 @@ function buildRefsByHashFromListEntries(entries) {
|
|
|
1155
1349
|
function formatEmptyStateLine(spaceId, style) {
|
|
1156
1350
|
return style.emptyState(`There are no migrations in migrations/${spaceId}/ yet`);
|
|
1157
1351
|
}
|
|
1158
|
-
function
|
|
1159
|
-
if (treeOutput.length === 0) return treeOutput;
|
|
1160
|
-
return treeOutput.split("\n").map((line) => line.length === 0 ? line : `${indent}${line}`).join("\n");
|
|
1161
|
-
}
|
|
1162
|
-
function renderSpaceTreeBlock(spaceId, migrations, multiSpace, glyphMode, style, colorize) {
|
|
1352
|
+
function renderSpaceTreeBlock(spaceId, migrations, multiSpace, glyphMode, style, colorize, liveContractHash, graphForSpace, globalMaxEdgeTreePrefixWidth, globalMaxDirNameWidth) {
|
|
1163
1353
|
if (migrations.length === 0) {
|
|
1164
1354
|
const emptyLine = formatEmptyStateLine(spaceId, style);
|
|
1165
1355
|
if (!multiSpace) return [emptyLine];
|
|
1166
1356
|
return [style.spaceHeading(`${spaceId}:`), ` ${emptyLine}`];
|
|
1167
1357
|
}
|
|
1168
|
-
const treeOutput =
|
|
1169
|
-
|
|
1170
|
-
|
|
1358
|
+
const treeOutput = renderMigrationGraphSpaceTree({
|
|
1359
|
+
graph: graphForSpace(spaceId) ?? migrationGraphFromListEntries(migrations),
|
|
1360
|
+
migrations,
|
|
1361
|
+
liveContractHash,
|
|
1362
|
+
glyphMode,
|
|
1171
1363
|
colorize,
|
|
1172
|
-
|
|
1364
|
+
refsByHash: buildRefsByHashFromListEntries(migrations),
|
|
1365
|
+
styler: style,
|
|
1366
|
+
...globalMaxEdgeTreePrefixWidth !== void 0 ? { globalMaxEdgeTreePrefixWidth } : {},
|
|
1367
|
+
...globalMaxDirNameWidth !== void 0 ? { globalMaxDirNameWidth } : {}
|
|
1173
1368
|
});
|
|
1174
1369
|
if (!multiSpace) return treeOutput.length === 0 ? [] : [treeOutput];
|
|
1175
|
-
const indented =
|
|
1370
|
+
const indented = indentMigrationGraphTreeBlock(treeOutput, " ");
|
|
1176
1371
|
return [style.spaceHeading(`${spaceId}:`), indented];
|
|
1177
1372
|
}
|
|
1178
1373
|
/**
|
|
@@ -1186,11 +1381,19 @@ function renderSpaceTreeBlock(spaceId, migrations, multiSpace, glyphMode, style,
|
|
|
1186
1381
|
function renderMigrationListWithStyle(result, style, glyphMode = "unicode", options = {}) {
|
|
1187
1382
|
const multiSpace = result.spaces.length > 1;
|
|
1188
1383
|
const colorize = options.colorize ?? false;
|
|
1384
|
+
const liveContractHash = options.liveContractHash ?? EMPTY_CONTRACT_HASH;
|
|
1385
|
+
const graphForSpace = options.graphForSpace ?? (() => void 0);
|
|
1386
|
+
const globalLayoutInputs = multiSpace ? result.spaces.filter((space) => space.migrations.length > 0).map((space) => ({
|
|
1387
|
+
graph: graphForSpace(space.spaceId) ?? migrationGraphFromListEntries(space.migrations),
|
|
1388
|
+
liveContractHash
|
|
1389
|
+
})) : [];
|
|
1390
|
+
const globalMaxEdgeTreePrefixWidth = globalLayoutInputs.length > 0 ? computeGlobalMaxEdgeTreePrefixWidth(globalLayoutInputs) : void 0;
|
|
1391
|
+
const globalMaxDirNameWidth = globalLayoutInputs.length > 0 ? computeGlobalMaxDirNameWidth(globalLayoutInputs) : void 0;
|
|
1189
1392
|
const lines = [];
|
|
1190
1393
|
for (let index = 0; index < result.spaces.length; index++) {
|
|
1191
1394
|
const space = result.spaces[index];
|
|
1192
1395
|
if (index > 0) lines.push("");
|
|
1193
|
-
lines.push(...renderSpaceTreeBlock(space.spaceId, space.migrations, multiSpace, glyphMode, style, colorize));
|
|
1396
|
+
lines.push(...renderSpaceTreeBlock(space.spaceId, space.migrations, multiSpace, glyphMode, style, colorize, liveContractHash, graphForSpace, globalMaxEdgeTreePrefixWidth, globalMaxDirNameWidth));
|
|
1194
1397
|
}
|
|
1195
1398
|
if (result.spaces.reduce((count, space) => count + space.migrations.length, 0) > 0) {
|
|
1196
1399
|
lines.push("");
|
|
@@ -1200,6 +1403,21 @@ function renderMigrationListWithStyle(result, style, glyphMode = "unicode", opti
|
|
|
1200
1403
|
}
|
|
1201
1404
|
//#endregion
|
|
1202
1405
|
//#region src/utils/formatters/migration-list-styler.ts
|
|
1406
|
+
function hasMarkersFormatter(styler) {
|
|
1407
|
+
return "markers" in styler && typeof styler.markers === "function";
|
|
1408
|
+
}
|
|
1409
|
+
function styleMarkerName(name) {
|
|
1410
|
+
return name === "contract" ? bold(green(name)) : green(name);
|
|
1411
|
+
}
|
|
1412
|
+
function plainMarkers(names) {
|
|
1413
|
+
return `<${names.join(", ")}>`;
|
|
1414
|
+
}
|
|
1415
|
+
function formatContractNodeOverlays(styler, markers, refs) {
|
|
1416
|
+
const parts = [];
|
|
1417
|
+
if (markers.length > 0) parts.push(hasMarkersFormatter(styler) ? styler.markers(markers) : plainMarkers(markers));
|
|
1418
|
+
if (refs.length > 0) parts.push(styler.refs(refs));
|
|
1419
|
+
return parts.join(" ");
|
|
1420
|
+
}
|
|
1203
1421
|
/**
|
|
1204
1422
|
* The current contract overlay marker. Unlike user refs, this names the user's
|
|
1205
1423
|
* declared desired state — the implicit base/target for `plan` / `migrate` —
|
|
@@ -1208,7 +1426,7 @@ function renderMigrationListWithStyle(result, style, glyphMode = "unicode", opti
|
|
|
1208
1426
|
*/
|
|
1209
1427
|
const CONTRACT_MARKER_NAME = "contract";
|
|
1210
1428
|
function styleRefName(name) {
|
|
1211
|
-
return
|
|
1429
|
+
return green(name);
|
|
1212
1430
|
}
|
|
1213
1431
|
/**
|
|
1214
1432
|
* Build a {@link MigrationListStyler} that decorates `migration list`
|
|
@@ -1226,14 +1444,18 @@ function styleRefName(name) {
|
|
|
1226
1444
|
* - `glyph` (`→` / `⟲` / `∅`): dim
|
|
1227
1445
|
* - `lane` (graph gutter lines `│` and fan/join connectors `├─┐` / `├─┘`): dim
|
|
1228
1446
|
* - `invariants` (`{...}`): yellow
|
|
1229
|
-
* - `
|
|
1230
|
-
* green-bold (
|
|
1447
|
+
* - `markers` (`<...>`): green; the `contract` desired-state marker inside is
|
|
1448
|
+
* green-bold (`db` is plain green)
|
|
1449
|
+
* - `refs` (`(...)`): green (the active ref is bolded separately by the tree styler)
|
|
1231
1450
|
* - `spaceHeading` (`<spaceId>:`): bold
|
|
1232
1451
|
* - `summary`: dim
|
|
1233
1452
|
* - `emptyState`: dim
|
|
1234
1453
|
*/
|
|
1235
1454
|
function createAnsiMigrationListStyler(opts) {
|
|
1236
|
-
if (!opts.useColor) return
|
|
1455
|
+
if (!opts.useColor) return {
|
|
1456
|
+
...IDENTITY_MIGRATION_LIST_STYLER,
|
|
1457
|
+
markers: plainMarkers
|
|
1458
|
+
};
|
|
1237
1459
|
return {
|
|
1238
1460
|
kind: (text) => text,
|
|
1239
1461
|
dirName: (text) => bold(text),
|
|
@@ -1242,6 +1464,12 @@ function createAnsiMigrationListStyler(opts) {
|
|
|
1242
1464
|
glyph: (text) => dim(text),
|
|
1243
1465
|
lane: (text) => dim(text),
|
|
1244
1466
|
invariants: (ids) => yellow(`{${ids.join(", ")}}`),
|
|
1467
|
+
markers: (names) => {
|
|
1468
|
+
const open = green("<");
|
|
1469
|
+
const close = green(">");
|
|
1470
|
+
const separator = green(", ");
|
|
1471
|
+
return open + names.map(styleMarkerName).join(separator) + close;
|
|
1472
|
+
},
|
|
1245
1473
|
refs: (names) => {
|
|
1246
1474
|
const open = green("(");
|
|
1247
1475
|
const close = green(")");
|
|
@@ -1332,161 +1560,14 @@ function arrowForEdgeKind(kind, palette) {
|
|
|
1332
1560
|
return palette.edgeArrow[kind];
|
|
1333
1561
|
}
|
|
1334
1562
|
/**
|
|
1335
|
-
* The leftmost lane (column 0) renders with the neutral dim lane style rather
|
|
1336
|
-
* than a palette hue — in the common single-lane case it has nothing to be told
|
|
1337
|
-
* apart from. Used as the "no owning arc" sentinel during colour resolution.
|
|
1338
|
-
*/
|
|
1339
|
-
const NEUTRAL_LANE = 0;
|
|
1340
|
-
/**
|
|
1341
1563
|
* Forced bold for branch-coloured names. A branched name pairs its lane hue
|
|
1342
1564
|
* (also forced, via {@link laneColorForColumn}) with bold; both must emit even
|
|
1343
1565
|
* when colorette's ambient TTY detection is off, so the colorized branch name
|
|
1344
1566
|
* is deterministically bold + hue rather than hue-only.
|
|
1345
1567
|
*/
|
|
1346
1568
|
const { bold: forcedBold } = createColors({ useColor: true });
|
|
1347
|
-
/**
|
|
1348
|
-
* Resolve per-cell colour columns for a row. Scanning right-to-left lets each
|
|
1349
|
-
* arc segment inherit the hue of the arc it leads into.
|
|
1350
|
-
*
|
|
1351
|
-
* On a converging-landing line (`○◂──────┴─┴─╯`), every horizontal dash segment
|
|
1352
|
-
* takes the hue of the **nearest landing anchor** — the next `arc-land-tee` or
|
|
1353
|
-
* `arc-land-corner` — to its right, i.e. the branch it leads into: the bridge
|
|
1354
|
-
* run leads into the first converging arc, and each tee's trailing `─` leads
|
|
1355
|
-
* into the next arc out. Tee/corner junction glyphs keep their own column hue.
|
|
1356
|
-
* This mirrors the forward connector's `┬─` rule (see
|
|
1357
|
-
* {@link resolveConnectorLaneColors}). A single (non-converging) landing has
|
|
1358
|
-
* only the corner as an anchor, so its whole horizontal run reads as one hue.
|
|
1359
|
-
*
|
|
1360
|
-
* The source side (`○─`, `arc-branch-tee`, `arc-branch-corner`) and pure
|
|
1361
|
-
* horizontal passes are unaffected: they track the nearest corner to the right
|
|
1362
|
-
* (`arcCorner`), so a routed back-arc's source fan still reads as one hue. A
|
|
1363
|
-
* crossing can only be one colour, so it takes the arc owning the horizontal
|
|
1364
|
-
* run at this row; the crossed vertical lane is occluded at that one cell and
|
|
1365
|
-
* reappears on the next row.
|
|
1366
|
-
*/
|
|
1367
|
-
function resolveRowLaneColors(cells) {
|
|
1368
|
-
const lane = new Array(cells.length);
|
|
1369
|
-
const connector = new Array(cells.length);
|
|
1370
|
-
const dash = new Array(cells.length);
|
|
1371
|
-
let arcCorner = NEUTRAL_LANE;
|
|
1372
|
-
let landingAnchor = NEUTRAL_LANE;
|
|
1373
|
-
for (let column = cells.length - 1; column >= 0; column--) {
|
|
1374
|
-
const cell = cells[column];
|
|
1375
|
-
connector[column] = landingAnchor !== NEUTRAL_LANE ? landingAnchor : arcCorner;
|
|
1376
|
-
switch (cell?.kind) {
|
|
1377
|
-
case "arc-branch-corner":
|
|
1378
|
-
arcCorner = column;
|
|
1379
|
-
lane[column] = column;
|
|
1380
|
-
dash[column] = column;
|
|
1381
|
-
break;
|
|
1382
|
-
case "arc-land-corner":
|
|
1383
|
-
arcCorner = column;
|
|
1384
|
-
landingAnchor = column;
|
|
1385
|
-
lane[column] = column;
|
|
1386
|
-
dash[column] = column;
|
|
1387
|
-
break;
|
|
1388
|
-
case "arc-branch-tee":
|
|
1389
|
-
lane[column] = column;
|
|
1390
|
-
dash[column] = column;
|
|
1391
|
-
break;
|
|
1392
|
-
case "arc-land-tee":
|
|
1393
|
-
lane[column] = column;
|
|
1394
|
-
dash[column] = landingAnchor === NEUTRAL_LANE ? column : landingAnchor;
|
|
1395
|
-
landingAnchor = column;
|
|
1396
|
-
break;
|
|
1397
|
-
case "arc-crossing":
|
|
1398
|
-
case "arc-land-bridge": {
|
|
1399
|
-
const served = landingAnchor !== NEUTRAL_LANE ? landingAnchor : arcCorner;
|
|
1400
|
-
lane[column] = served;
|
|
1401
|
-
dash[column] = served;
|
|
1402
|
-
break;
|
|
1403
|
-
}
|
|
1404
|
-
case "horizontal-pass":
|
|
1405
|
-
lane[column] = arcCorner === NEUTRAL_LANE ? column : arcCorner;
|
|
1406
|
-
dash[column] = lane[column] ?? column;
|
|
1407
|
-
break;
|
|
1408
|
-
case "node":
|
|
1409
|
-
lane[column] = column;
|
|
1410
|
-
dash[column] = column;
|
|
1411
|
-
arcCorner = NEUTRAL_LANE;
|
|
1412
|
-
landingAnchor = NEUTRAL_LANE;
|
|
1413
|
-
break;
|
|
1414
|
-
default:
|
|
1415
|
-
lane[column] = column;
|
|
1416
|
-
dash[column] = column;
|
|
1417
|
-
arcCorner = NEUTRAL_LANE;
|
|
1418
|
-
landingAnchor = NEUTRAL_LANE;
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
return {
|
|
1422
|
-
lane,
|
|
1423
|
-
connector,
|
|
1424
|
-
dash
|
|
1425
|
-
};
|
|
1426
|
-
}
|
|
1427
|
-
/**
|
|
1428
|
-
* Resolve per-cell connector colours. Scanning right-to-left, a corner or an
|
|
1429
|
-
* intermediate tee anchors its own lane (its junction glyph takes that column),
|
|
1430
|
-
* but a tee's **trailing dash leads into the branch on its right** (the next
|
|
1431
|
-
* branch point), so `┬─` reads as "this lane, then on toward the next" rather
|
|
1432
|
-
* than tinting the dash with the left lane. The leading tee at `startLane` (the
|
|
1433
|
-
* fork/merge origin) and pure horizontal segments inherit the nearest branch
|
|
1434
|
-
* point to their right whole-cell, so the run into a branch — or collapsing
|
|
1435
|
-
* into a merge corner — stays continuous. An `arc-crossing` keeps its junction
|
|
1436
|
-
* glyph at its own column but re-anchors `owner` like an intermediate tee so
|
|
1437
|
-
* dashes on both sides lead into the nearest branch on their right. Pass-through
|
|
1438
|
-
* verticals outside the run keep their own column (column 0 stays neutral).
|
|
1439
|
-
*/
|
|
1440
|
-
function resolveConnectorLaneColors(cells, startLane) {
|
|
1441
|
-
const glyph = new Array(cells.length);
|
|
1442
|
-
const dash = new Array(cells.length);
|
|
1443
|
-
let owner = NEUTRAL_LANE;
|
|
1444
|
-
for (let column = cells.length - 1; column >= 0; column--) switch (cells[column]?.kind) {
|
|
1445
|
-
case "branch-corner":
|
|
1446
|
-
case "merge-corner":
|
|
1447
|
-
owner = column;
|
|
1448
|
-
glyph[column] = column;
|
|
1449
|
-
dash[column] = column;
|
|
1450
|
-
break;
|
|
1451
|
-
case "branch-tee":
|
|
1452
|
-
case "merge-tee":
|
|
1453
|
-
if (column === startLane) {
|
|
1454
|
-
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
1455
|
-
glyph[column] = column;
|
|
1456
|
-
dash[column] = served;
|
|
1457
|
-
} else {
|
|
1458
|
-
dash[column] = owner === NEUTRAL_LANE ? column : owner;
|
|
1459
|
-
glyph[column] = column;
|
|
1460
|
-
owner = column;
|
|
1461
|
-
}
|
|
1462
|
-
break;
|
|
1463
|
-
case "arc-crossing":
|
|
1464
|
-
glyph[column] = column;
|
|
1465
|
-
dash[column] = owner === NEUTRAL_LANE ? column : owner;
|
|
1466
|
-
owner = column;
|
|
1467
|
-
break;
|
|
1468
|
-
case "horizontal-pass": {
|
|
1469
|
-
const served = owner === NEUTRAL_LANE ? column : owner;
|
|
1470
|
-
glyph[column] = served;
|
|
1471
|
-
dash[column] = served;
|
|
1472
|
-
break;
|
|
1473
|
-
}
|
|
1474
|
-
default:
|
|
1475
|
-
glyph[column] = column;
|
|
1476
|
-
dash[column] = column;
|
|
1477
|
-
}
|
|
1478
|
-
return {
|
|
1479
|
-
glyph,
|
|
1480
|
-
dash
|
|
1481
|
-
};
|
|
1482
|
-
}
|
|
1483
|
-
/**
|
|
1484
|
-
* Style a structural glyph by its resolved colour column. Column 0 and the
|
|
1485
|
-
* neutral sentinel render dim (`style.lane`); columns ≥ 1 take a palette hue.
|
|
1486
|
-
*/
|
|
1487
1569
|
function laneStylerForColumn(colorColumn, colorize, style) {
|
|
1488
|
-
|
|
1489
|
-
return laneColorForColumn(colorColumn);
|
|
1570
|
+
return stylerForLaneColumn(colorColumn, colorize, style.lane);
|
|
1490
1571
|
}
|
|
1491
1572
|
/**
|
|
1492
1573
|
* Tint a branch-owned token (direction arrow, migration name) by its edge's
|
|
@@ -1496,10 +1577,19 @@ function laneStylerForColumn(colorColumn, colorize, style) {
|
|
|
1496
1577
|
* colour. With colour off, the fallback (also colourless) is used unchanged.
|
|
1497
1578
|
*/
|
|
1498
1579
|
function branchStylerOrDefault(column, colorize, fallback) {
|
|
1499
|
-
if (!colorize || column <=
|
|
1580
|
+
if (!colorize || column <= 0) return fallback;
|
|
1500
1581
|
return laneColorForColumn(column);
|
|
1501
1582
|
}
|
|
1502
1583
|
/**
|
|
1584
|
+
* Render a crossing tee (`┼─`): the junction stays dim/neutral so neither arc
|
|
1585
|
+
* steals the cell; the trailing dash takes the served lane hue.
|
|
1586
|
+
*/
|
|
1587
|
+
function renderArcCrossing(pair, dashColumn, colorize, style) {
|
|
1588
|
+
const junction = colorize ? style.lane : (text) => text;
|
|
1589
|
+
const dash = laneStylerForColumn(dashColumn, colorize, style);
|
|
1590
|
+
return junction(pair.slice(0, 1)) + dash(pair.slice(1));
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1503
1593
|
* Render a connector tee (`├─` / `┬─` / `┴─`) with its junction glyph and its
|
|
1504
1594
|
* trailing dash coloured independently: the junction anchors its own lane while
|
|
1505
1595
|
* the dash leads into the branch on its right.
|
|
@@ -1526,7 +1616,7 @@ function renderCellPair(cell, column, colors, colorize, style, palette) {
|
|
|
1526
1616
|
const lane = laneStylerForColumn(laneColumn, colorize, style);
|
|
1527
1617
|
switch (cell.kind) {
|
|
1528
1618
|
case "node": {
|
|
1529
|
-
const arcColumn = colors.connector[column] ??
|
|
1619
|
+
const arcColumn = colors.connector[column] ?? 0;
|
|
1530
1620
|
if (cell.arcLand === true) return renderNodeMarkerPair(palette.arcLand, column, arcColumn, colorize, style);
|
|
1531
1621
|
if (cell.arcTee === true) return renderNodeMarkerPair(palette.arcTee, column, arcColumn, colorize, style);
|
|
1532
1622
|
return lane(palette.node);
|
|
@@ -1581,7 +1671,7 @@ function renderConnectorRow(row, gridWidth, colorize, style, palette) {
|
|
|
1581
1671
|
out += lane(palette.horizontalPass);
|
|
1582
1672
|
break;
|
|
1583
1673
|
case "arc-crossing":
|
|
1584
|
-
out +=
|
|
1674
|
+
out += renderArcCrossing(palette.arcCrossing, dashColumn, colorize, style);
|
|
1585
1675
|
break;
|
|
1586
1676
|
default: out += " ";
|
|
1587
1677
|
}
|
|
@@ -1605,15 +1695,24 @@ function abbreviateHash(hash, hashLength, emptySource) {
|
|
|
1605
1695
|
}
|
|
1606
1696
|
const MIN_HASH_DATA_COLUMN = 25;
|
|
1607
1697
|
function overlayNamesForContract(contractHash, opts) {
|
|
1608
|
-
const
|
|
1698
|
+
const markers = [];
|
|
1699
|
+
const refs = [];
|
|
1609
1700
|
const userRefs = opts.refsByHash?.get(contractHash);
|
|
1610
|
-
if (userRefs)
|
|
1611
|
-
if (opts.
|
|
1612
|
-
if (opts.
|
|
1613
|
-
|
|
1701
|
+
if (userRefs) refs.push(...[...userRefs].sort((a, b) => a.localeCompare(b)));
|
|
1702
|
+
if (opts.contractHash === contractHash && contractHash !== EMPTY_CONTRACT_HASH) markers.push(CONTRACT_MARKER_NAME);
|
|
1703
|
+
if (opts.dbHash === contractHash) markers.push(DB_MARKER_NAME);
|
|
1704
|
+
markers.sort((a, b) => {
|
|
1705
|
+
if (a === "contract") return -1;
|
|
1706
|
+
if (b === "contract") return 1;
|
|
1707
|
+
return a.localeCompare(b);
|
|
1708
|
+
});
|
|
1709
|
+
return {
|
|
1710
|
+
markers,
|
|
1711
|
+
refs
|
|
1712
|
+
};
|
|
1614
1713
|
}
|
|
1615
1714
|
function createTreeStyler(opts) {
|
|
1616
|
-
const base = createAnsiMigrationListStyler({ useColor: opts.colorize });
|
|
1715
|
+
const base = opts.styler ?? createAnsiMigrationListStyler({ useColor: opts.colorize });
|
|
1617
1716
|
const activeRefName = opts.activeRefName;
|
|
1618
1717
|
if (!opts.colorize || activeRefName === void 0) return base;
|
|
1619
1718
|
return {
|
|
@@ -1628,6 +1727,8 @@ function formatEdgeAnnotationSuffix(migrationHash, opts, style) {
|
|
|
1628
1727
|
const annotation = opts.edgeAnnotationsByHash?.get(migrationHash);
|
|
1629
1728
|
if (annotation === void 0) return "";
|
|
1630
1729
|
const segments = [];
|
|
1730
|
+
if (annotation.operationCount !== void 0) segments.push(`${annotation.operationCount} ops`);
|
|
1731
|
+
if (annotation.invariants !== void 0 && annotation.invariants.length > 0) segments.push(style.invariants(annotation.invariants));
|
|
1631
1732
|
const status = annotation.status;
|
|
1632
1733
|
if (status !== void 0) {
|
|
1633
1734
|
const glyphs = overlayStatusGlyphs(opts.glyphMode ?? "unicode");
|
|
@@ -1639,17 +1740,15 @@ function formatEdgeAnnotationSuffix(migrationHash, opts, style) {
|
|
|
1639
1740
|
segments.push(styler(`${glyph} ${label}`));
|
|
1640
1741
|
}
|
|
1641
1742
|
}
|
|
1642
|
-
if (annotation.operationCount !== void 0) segments.push(`${annotation.operationCount} ops`);
|
|
1643
|
-
if (annotation.invariants !== void 0 && annotation.invariants.length > 0) segments.push(style.invariants(annotation.invariants));
|
|
1644
1743
|
if (segments.length === 0) return "";
|
|
1645
|
-
return
|
|
1744
|
+
return ` ${segments.join(" ")}`;
|
|
1646
1745
|
}
|
|
1647
1746
|
function formatEdgeHashColumn(edge, style, hashLength, palette) {
|
|
1648
1747
|
if (edge.kind === "self") {
|
|
1649
1748
|
const hash = abbreviateHash(edge.from, hashLength, palette.emptySource);
|
|
1650
|
-
return `${style.sourceHash(hash)} ${style.glyph(palette.forwardArrow)} ${style.destHash(hash)}`;
|
|
1749
|
+
return `${padFromHashColumn(style.sourceHash(hash), hashLength)} ${style.glyph(palette.forwardArrow)} ${style.destHash(hash)}`;
|
|
1651
1750
|
}
|
|
1652
|
-
return `${edge.from === EMPTY_CONTRACT_HASH ? style.glyph(palette.emptySource)
|
|
1751
|
+
return `${edge.from === EMPTY_CONTRACT_HASH ? padFromHashColumn(style.glyph(palette.emptySource), hashLength) : padFromHashColumn(style.sourceHash(abbreviateHash(edge.from, hashLength, palette.emptySource)), hashLength)} ${style.glyph(palette.forwardArrow)} ${style.destHash(abbreviateHash(edge.to, hashLength, palette.emptySource))}`;
|
|
1653
1752
|
}
|
|
1654
1753
|
function padVisible(text, targetWidth) {
|
|
1655
1754
|
const padding = Math.max(0, targetWidth - stringWidth(text));
|
|
@@ -1679,6 +1778,21 @@ function edgeLabelColumn(row, wideLabelColumn) {
|
|
|
1679
1778
|
if (row.edge?.from === EMPTY_CONTRACT_HASH && laneIndex === 0) return (laneIndex + 1) * 2 + LABEL_GAP;
|
|
1680
1779
|
return row.cells.some((cell, index) => index > laneIndex && cell.kind === "vertical-pass") ? row.cells.length * 2 + LABEL_GAP : (laneIndex + 1) * 2 + LABEL_GAP;
|
|
1681
1780
|
}
|
|
1781
|
+
function maxEdgeTreePrefixWidth(rows, wideLabelColumn) {
|
|
1782
|
+
let max = 0;
|
|
1783
|
+
for (const row of rows) {
|
|
1784
|
+
if (row.kind !== "edge" || row.edge === void 0) continue;
|
|
1785
|
+
max = Math.max(max, edgeLabelColumn(row, wideLabelColumn));
|
|
1786
|
+
}
|
|
1787
|
+
return max;
|
|
1788
|
+
}
|
|
1789
|
+
function computeMaxEdgeTreePrefixWidthForLayout(model) {
|
|
1790
|
+
const wideLabelColumn = gridUsesSkipRollbackArcs(model.rows) ? gridWidthForModel(model.rows) * 2 + 4 : void 0;
|
|
1791
|
+
return maxEdgeTreePrefixWidth(model.rows, wideLabelColumn);
|
|
1792
|
+
}
|
|
1793
|
+
function computeMaxDirNameLengthForLayout(model) {
|
|
1794
|
+
return maxDirNameLength(model.rows.filter((row) => row.kind === "edge" && row.edge !== void 0).map((row) => row.edge));
|
|
1795
|
+
}
|
|
1682
1796
|
function nodeHasArcDecoration(row) {
|
|
1683
1797
|
return row.cells.some((cell) => cell.kind === "node" && (cell.arcTee === true || cell.arcLand === true));
|
|
1684
1798
|
}
|
|
@@ -1690,6 +1804,9 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1690
1804
|
const wideLabelColumn = gridUsesSkipRollbackArcs(model.rows) ? gridWidth * 2 + 4 : void 0;
|
|
1691
1805
|
const dirNameGap = wideLabelColumn !== void 0 ? 3 : LABEL_GAP;
|
|
1692
1806
|
const maxDirNameLen = maxDirNameLength(model.rows.filter((row) => row.kind === "edge" && row.edge !== void 0).map((row) => row.edge));
|
|
1807
|
+
const effectiveMaxDirNameLen = opts.globalMaxDirNameWidth ?? maxDirNameLen;
|
|
1808
|
+
const maxEdgePrefixWidth = opts.globalMaxEdgeTreePrefixWidth ?? maxEdgeTreePrefixWidth(model.rows, wideLabelColumn);
|
|
1809
|
+
const edgeDirNameWidth = rowDirNameWidth(maxEdgePrefixWidth, effectiveMaxDirNameLen, dirNameGap);
|
|
1693
1810
|
const lines = [];
|
|
1694
1811
|
for (let rowIndex = 0; rowIndex < model.rows.length; rowIndex++) {
|
|
1695
1812
|
const row = model.rows[rowIndex];
|
|
@@ -1702,7 +1819,7 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1702
1819
|
lines.push(trimTrailingWhitespace(renderConnectorRow(row, gridWidth, opts.colorize, style, palette)));
|
|
1703
1820
|
continue;
|
|
1704
1821
|
}
|
|
1705
|
-
const cellColors =
|
|
1822
|
+
const cellColors = resolveRowArcLaneColors(row.cells);
|
|
1706
1823
|
let gutter = row.cells.map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1707
1824
|
let laneSpan = row.cells.length;
|
|
1708
1825
|
if (row.kind === "node") if ((row.contractHash ?? EMPTY_CONTRACT_HASH) === EMPTY_CONTRACT_HASH) laneSpan = 1;
|
|
@@ -1714,31 +1831,31 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1714
1831
|
}
|
|
1715
1832
|
laneSpan = lastActiveColumn >= 0 ? lastActiveColumn + 1 : 1;
|
|
1716
1833
|
}
|
|
1717
|
-
const labelColumn = row.kind === "edge" ?
|
|
1834
|
+
const labelColumn = row.kind === "edge" ? maxEdgePrefixWidth : wideLabelColumn !== void 0 && (nodeHasArcDecoration(row) || row.contractHash !== void 0) ? wideLabelColumn : laneSpan * 2 + LABEL_GAP;
|
|
1718
1835
|
if (row.kind === "edge" && row.edge?.from === EMPTY_CONTRACT_HASH && (row.laneIndex ?? 0) === 0) gutter = row.cells.slice(0, 1).map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1719
1836
|
else if (row.kind === "node" && laneSpan < row.cells.length && !nodeHasArcDecoration(row)) gutter = row.cells.slice(0, laneSpan).map((cell, column) => renderCellPair(cell, column, cellColors, opts.colorize, style, palette)).join("");
|
|
1720
1837
|
else if (gutter.length < laneSpan * 2) gutter = gutter.padEnd(laneSpan * 2, " ");
|
|
1721
|
-
const dirNameWidth = rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);
|
|
1722
|
-
const dataColumn = labelColumn + dirNameWidth;
|
|
1838
|
+
const dirNameWidth = row.kind === "edge" ? edgeDirNameWidth : rowDirNameWidth(labelColumn, maxDirNameLen, dirNameGap);
|
|
1723
1839
|
const gutterPad = padVisible(gutter, labelColumn);
|
|
1724
1840
|
if (row.kind === "node") {
|
|
1725
1841
|
const contractHash = row.contractHash ?? EMPTY_CONTRACT_HASH;
|
|
1726
1842
|
if (contractHash === EMPTY_CONTRACT_HASH) {
|
|
1727
1843
|
const trailingLanes = row.cells.slice(1).map((cell, offset) => renderCellPair(cell, offset + 1, cellColors, opts.colorize, style, palette)).join("");
|
|
1728
1844
|
const emptyGutter = palette.emptySource.padEnd(2, " ") + trailingLanes;
|
|
1729
|
-
const
|
|
1730
|
-
if (
|
|
1845
|
+
const overlays = overlayNamesForContract(contractHash, opts);
|
|
1846
|
+
if (overlays.markers.length === 0 && overlays.refs.length === 0) {
|
|
1731
1847
|
lines.push(trimTrailingWhitespace(emptyGutter));
|
|
1732
1848
|
continue;
|
|
1733
1849
|
}
|
|
1734
|
-
const overlay = style.refs
|
|
1735
|
-
lines.push(trimTrailingWhitespace(`${
|
|
1850
|
+
const overlay = formatContractNodeOverlays(style, overlays.markers, overlays.refs);
|
|
1851
|
+
lines.push(trimTrailingWhitespace(`${emptyGutter}${" ".repeat(LABEL_GAP)}${overlay}`));
|
|
1736
1852
|
continue;
|
|
1737
1853
|
}
|
|
1738
1854
|
const hashText = style.sourceHash(abbreviateHash(contractHash, hashLength, palette.emptySource));
|
|
1739
|
-
const
|
|
1740
|
-
const
|
|
1741
|
-
const
|
|
1855
|
+
const overlays = overlayNamesForContract(contractHash, opts);
|
|
1856
|
+
const hasOverlays = overlays.markers.length > 0 || overlays.refs.length > 0;
|
|
1857
|
+
const overlayPad = hasOverlays ? " ".repeat(LABEL_GAP) : "";
|
|
1858
|
+
const overlay = hasOverlays ? formatContractNodeOverlays(style, overlays.markers, overlays.refs) : "";
|
|
1742
1859
|
lines.push(trimTrailingWhitespace(`${gutterPad}${hashText}${overlayPad}${overlay}`));
|
|
1743
1860
|
continue;
|
|
1744
1861
|
}
|
|
@@ -1746,23 +1863,30 @@ function renderMigrationGraphTree(model, opts) {
|
|
|
1746
1863
|
if (edge === void 0) continue;
|
|
1747
1864
|
const dirNamePadding = " ".repeat(Math.max(0, dirNameWidth - edge.dirName.length));
|
|
1748
1865
|
const laneIndex = row.laneIndex ?? 0;
|
|
1749
|
-
const dirName = `${(opts.colorize && laneIndex >
|
|
1866
|
+
const dirName = `${(opts.colorize && laneIndex > 0 ? (text) => forcedBold(laneColorForColumn(laneIndex)(text)) : style.dirName)(edge.dirName)}${dirNamePadding}`;
|
|
1750
1867
|
const hashColumn = formatEdgeHashColumn(edge, style, hashLength, palette);
|
|
1751
1868
|
const annotationSuffix = formatEdgeAnnotationSuffix(edge.migrationHash, opts, style);
|
|
1752
1869
|
lines.push(trimTrailingWhitespace(`${gutterPad}${dirName}${hashColumn}${annotationSuffix}`));
|
|
1753
1870
|
}
|
|
1754
1871
|
return lines.join("\n");
|
|
1755
1872
|
}
|
|
1873
|
+
function formatLegendExampleMarkers(colorize) {
|
|
1874
|
+
if (!colorize) return "<contract, db>";
|
|
1875
|
+
const open = green("<");
|
|
1876
|
+
const close = green(">");
|
|
1877
|
+
const separator = green(", ");
|
|
1878
|
+
return open + green("contract") + separator + green("db") + close;
|
|
1879
|
+
}
|
|
1756
1880
|
/**
|
|
1757
|
-
* A compact key for the
|
|
1758
|
-
* in-lane direction arrows, the empty baseline, the
|
|
1759
|
-
*
|
|
1881
|
+
* A compact key for the tree visual language: the contract node glyph, the
|
|
1882
|
+
* in-lane direction arrows, the empty baseline, the system-marker `<…>` and
|
|
1883
|
+
* user-ref `(…)` bracket conventions (two illustrative example lines), and a
|
|
1760
1884
|
* worked sample of the data-column `from → to` migration hash arrow.
|
|
1761
1885
|
*
|
|
1762
1886
|
* Honors the same glyph palette (unicode vs ASCII) and `colorize` gate as the
|
|
1763
1887
|
* tree renderer, so the key matches whatever the graph itself drew and stays
|
|
1764
1888
|
* pipe-safe (zero ANSI when color is off). The caller adds the trailing blank
|
|
1765
|
-
* line that separates this stderr key from the
|
|
1889
|
+
* line that separates this stderr key from the tree on stdout.
|
|
1766
1890
|
*/
|
|
1767
1891
|
function renderMigrationGraphLegend(opts) {
|
|
1768
1892
|
const palette = paletteFor(opts.glyphMode ?? "unicode");
|
|
@@ -1771,17 +1895,72 @@ function renderMigrationGraphLegend(opts) {
|
|
|
1771
1895
|
const sampleArrow = `${style.sourceHash("aaaaaa")} ${style.glyph(palette.forwardArrow)} ${style.destHash("bbbbbb")}`;
|
|
1772
1896
|
const statusGlyphs = overlayStatusGlyphs(opts.glyphMode ?? "unicode");
|
|
1773
1897
|
const appliedPending = opts.colorize ? ` ${green(statusGlyphs.applied)} ${style.summary("applied")} ${yellow(statusGlyphs.pending)} ${style.summary("pending")}` : ` ${statusGlyphs.applied} ${style.summary("applied")} ${statusGlyphs.pending} ${style.summary("pending")}`;
|
|
1898
|
+
const exampleMarkers = formatLegendExampleMarkers(opts.colorize);
|
|
1899
|
+
const exampleRefs = opts.colorize ? style.refs(["prod", "staging"]) : "(prod, staging)";
|
|
1774
1900
|
return [
|
|
1775
1901
|
"Legend:",
|
|
1776
1902
|
` ${style.kind(node)} ${style.summary("contract")} ${style.kind(palette.edgeArrow.forward)} ${style.summary("forward")} ${style.kind(palette.edgeArrow.rollback)} ${style.summary("rollback")}`,
|
|
1777
1903
|
` ${style.kind(palette.edgeArrow.self)} ${style.summary("migration without schema change")}`,
|
|
1778
1904
|
appliedPending,
|
|
1779
1905
|
` ${style.kind(palette.emptySource)} ${style.summary("empty database (baseline)")}`,
|
|
1780
|
-
` ${
|
|
1906
|
+
` ${exampleMarkers} ${style.summary("live markers (contract on disk, database state)")}`,
|
|
1907
|
+
` ${exampleRefs} ${style.summary("user-defined refs")}`,
|
|
1781
1908
|
` ${sampleArrow} ${style.summary("migration from contract aaaaaa to bbbbbb")}`
|
|
1782
1909
|
].join("\n");
|
|
1783
1910
|
}
|
|
1784
1911
|
//#endregion
|
|
1785
|
-
|
|
1912
|
+
//#region src/utils/formatters/migration-graph-space-render.ts
|
|
1913
|
+
function mergeMigrationEdgeAnnotations(listOverlay, statusOverlay) {
|
|
1914
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1915
|
+
for (const [migrationHash, listAnnotation] of listOverlay) {
|
|
1916
|
+
const statusAnnotation = statusOverlay.get(migrationHash);
|
|
1917
|
+
merged.set(migrationHash, {
|
|
1918
|
+
...listAnnotation,
|
|
1919
|
+
...statusAnnotation?.status !== void 0 ? { status: statusAnnotation.status } : {}
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
return merged;
|
|
1923
|
+
}
|
|
1924
|
+
function computeGlobalMaxEdgeTreePrefixWidth(inputs) {
|
|
1925
|
+
let globalMax = 0;
|
|
1926
|
+
for (const input of inputs) {
|
|
1927
|
+
const layout = buildMigrationGraphLayout(buildMigrationGraphRows(input.graph, { contractHash: input.liveContractHash }));
|
|
1928
|
+
globalMax = Math.max(globalMax, computeMaxEdgeTreePrefixWidthForLayout(layout));
|
|
1929
|
+
}
|
|
1930
|
+
return globalMax;
|
|
1931
|
+
}
|
|
1932
|
+
function computeGlobalMaxDirNameWidth(inputs) {
|
|
1933
|
+
let globalMax = 0;
|
|
1934
|
+
for (const input of inputs) {
|
|
1935
|
+
const layout = buildMigrationGraphLayout(buildMigrationGraphRows(input.graph, { contractHash: input.liveContractHash }));
|
|
1936
|
+
globalMax = Math.max(globalMax, computeMaxDirNameLengthForLayout(layout));
|
|
1937
|
+
}
|
|
1938
|
+
return globalMax;
|
|
1939
|
+
}
|
|
1940
|
+
function renderMigrationGraphSpaceTreeInternal(input) {
|
|
1941
|
+
const layout = buildMigrationGraphLayout(buildMigrationGraphRows(input.graph, { contractHash: input.liveContractHash }));
|
|
1942
|
+
const listOverlay = buildEdgeAnnotationsByHashFromListEntries(input.migrations);
|
|
1943
|
+
const edgeAnnotationsByHash = input.statusOverlayByHash === void 0 ? listOverlay : mergeMigrationEdgeAnnotations(listOverlay, input.statusOverlayByHash);
|
|
1944
|
+
return renderMigrationGraphTree(layout, {
|
|
1945
|
+
refsByHash: input.refsByHash ?? buildRefsByHashFromListEntries(input.migrations),
|
|
1946
|
+
contractHash: input.liveContractHash,
|
|
1947
|
+
edgeAnnotationsByHash,
|
|
1948
|
+
colorize: input.colorize,
|
|
1949
|
+
glyphMode: input.glyphMode,
|
|
1950
|
+
...input.dbHash !== void 0 ? { dbHash: input.dbHash } : {},
|
|
1951
|
+
...input.styler !== void 0 ? { styler: input.styler } : {},
|
|
1952
|
+
...input.globalMaxEdgeTreePrefixWidth !== void 0 ? { globalMaxEdgeTreePrefixWidth: input.globalMaxEdgeTreePrefixWidth } : {},
|
|
1953
|
+
...input.globalMaxDirNameWidth !== void 0 ? { globalMaxDirNameWidth: input.globalMaxDirNameWidth } : {}
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
function renderMigrationGraphSpaceTree(input) {
|
|
1957
|
+
return renderMigrationGraphSpaceTreeInternal(input);
|
|
1958
|
+
}
|
|
1959
|
+
function indentMigrationGraphTreeBlock(treeOutput, indent) {
|
|
1960
|
+
if (treeOutput.length === 0) return treeOutput;
|
|
1961
|
+
return treeOutput.split("\n").map((line) => line.length === 0 ? line : `${indent}${line}`).join("\n");
|
|
1962
|
+
}
|
|
1963
|
+
//#endregion
|
|
1964
|
+
export { renderMigrationGraphLegend as a, renderMigrationListWithStyle as c, renderMigrationGraphSpaceTree as i, abbreviateContractHash as l, computeGlobalMaxEdgeTreePrefixWidth as n, createAnsiMigrationListStyler as o, indentMigrationGraphTreeBlock as r, IDENTITY_MIGRATION_LIST_STYLER as s, computeGlobalMaxDirNameWidth as t };
|
|
1786
1965
|
|
|
1787
|
-
//# sourceMappingURL=migration-graph-
|
|
1966
|
+
//# sourceMappingURL=migration-graph-space-render-dmLLWift.mjs.map
|