@prisma-next/cli 0.3.0-pr.94.3 → 0.3.0-pr.95.2
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/chunk-AGOTG4L3.js +965 -0
- package/dist/chunk-AGOTG4L3.js.map +1 -0
- package/dist/chunk-HLLI4YL7.js +180 -0
- package/dist/chunk-HLLI4YL7.js.map +1 -0
- package/dist/chunk-HWYQOCAJ.js +47 -0
- package/dist/chunk-HWYQOCAJ.js.map +1 -0
- package/dist/chunk-VG2R7DGF.js +735 -0
- package/dist/chunk-VG2R7DGF.js.map +1 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2764 -2522
- package/dist/cli.js.map +1 -1
- package/dist/commands/contract-emit.d.ts +3 -0
- package/dist/commands/contract-emit.d.ts.map +1 -0
- package/dist/commands/contract-emit.js +10 -0
- package/dist/commands/contract-emit.js.map +1 -0
- package/dist/commands/db-init.d.ts +3 -0
- package/dist/commands/db-init.d.ts.map +1 -0
- package/dist/commands/db-init.js +257 -0
- package/dist/commands/db-init.js.map +1 -0
- package/dist/commands/db-introspect.d.ts +3 -0
- package/dist/commands/db-introspect.d.ts.map +1 -0
- package/dist/commands/db-introspect.js +155 -0
- package/dist/commands/db-introspect.js.map +1 -0
- package/dist/commands/db-schema-verify.d.ts +3 -0
- package/dist/commands/db-schema-verify.d.ts.map +1 -0
- package/dist/commands/db-schema-verify.js +171 -0
- package/dist/commands/db-schema-verify.js.map +1 -0
- package/dist/commands/db-sign.d.ts +3 -0
- package/dist/commands/db-sign.d.ts.map +1 -0
- package/dist/commands/db-sign.js +195 -0
- package/dist/commands/db-sign.js.map +1 -0
- package/dist/commands/db-verify.d.ts +3 -0
- package/dist/commands/db-verify.d.ts.map +1 -0
- package/dist/commands/db-verify.js +193 -0
- package/dist/commands/db-verify.js.map +1 -0
- package/dist/{config-loader.d.mts → config-loader.d.ts} +3 -8
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +7 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/control-api/client.d.ts +13 -0
- package/dist/control-api/client.d.ts.map +1 -0
- package/dist/control-api/operations/db-init.d.ts +29 -0
- package/dist/control-api/operations/db-init.d.ts.map +1 -0
- package/dist/control-api/types.d.ts +387 -0
- package/dist/control-api/types.d.ts.map +1 -0
- package/dist/exports/config-types.d.ts +3 -0
- package/dist/exports/config-types.d.ts.map +1 -0
- package/dist/exports/config-types.js +6 -0
- package/dist/exports/config-types.js.map +1 -0
- package/dist/exports/control-api.d.ts +13 -0
- package/dist/exports/control-api.d.ts.map +1 -0
- package/dist/exports/control-api.js +7 -0
- package/dist/exports/control-api.js.map +1 -0
- package/dist/exports/index.d.ts +4 -0
- package/dist/exports/index.d.ts.map +1 -0
- package/dist/exports/index.js +176 -0
- package/dist/exports/index.js.map +1 -0
- package/dist/{exports/index.d.mts → load-ts-contract.d.ts} +5 -10
- package/dist/load-ts-contract.d.ts.map +1 -0
- package/dist/utils/cli-errors.d.ts +7 -0
- package/dist/utils/cli-errors.d.ts.map +1 -0
- package/dist/utils/command-helpers.d.ts +12 -0
- package/dist/utils/command-helpers.d.ts.map +1 -0
- package/dist/utils/framework-components.d.ts +70 -0
- package/dist/utils/framework-components.d.ts.map +1 -0
- package/dist/utils/global-flags.d.ts +25 -0
- package/dist/utils/global-flags.d.ts.map +1 -0
- package/dist/utils/output.d.ts +142 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/progress-adapter.d.ts +26 -0
- package/dist/utils/progress-adapter.d.ts.map +1 -0
- package/dist/utils/result-handler.d.ts +15 -0
- package/dist/utils/result-handler.d.ts.map +1 -0
- package/package.json +54 -29
- package/dist/client-CoxxGz_7.mjs +0 -692
- package/dist/client-CoxxGz_7.mjs.map +0 -1
- package/dist/commands/contract-emit.d.mts +0 -7
- package/dist/commands/contract-emit.d.mts.map +0 -1
- package/dist/commands/contract-emit.mjs +0 -139
- package/dist/commands/contract-emit.mjs.map +0 -1
- package/dist/commands/db-init.d.mts +0 -7
- package/dist/commands/db-init.d.mts.map +0 -1
- package/dist/commands/db-init.mjs +0 -178
- package/dist/commands/db-init.mjs.map +0 -1
- package/dist/commands/db-introspect.d.mts +0 -7
- package/dist/commands/db-introspect.d.mts.map +0 -1
- package/dist/commands/db-introspect.mjs +0 -120
- package/dist/commands/db-introspect.mjs.map +0 -1
- package/dist/commands/db-schema-verify.d.mts +0 -7
- package/dist/commands/db-schema-verify.d.mts.map +0 -1
- package/dist/commands/db-schema-verify.mjs +0 -116
- package/dist/commands/db-schema-verify.mjs.map +0 -1
- package/dist/commands/db-sign.d.mts +0 -7
- package/dist/commands/db-sign.d.mts.map +0 -1
- package/dist/commands/db-sign.mjs +0 -138
- package/dist/commands/db-sign.mjs.map +0 -1
- package/dist/commands/db-verify.d.mts +0 -7
- package/dist/commands/db-verify.d.mts.map +0 -1
- package/dist/commands/db-verify.mjs +0 -128
- package/dist/commands/db-verify.mjs.map +0 -1
- package/dist/config-loader-B-pobG0R.mjs +0 -42
- package/dist/config-loader-B-pobG0R.mjs.map +0 -1
- package/dist/config-loader.d.mts.map +0 -1
- package/dist/config-loader.mjs +0 -3
- package/dist/exports/config-types.d.mts +0 -2
- package/dist/exports/config-types.mjs +0 -3
- package/dist/exports/control-api.d.mts +0 -405
- package/dist/exports/control-api.d.mts.map +0 -1
- package/dist/exports/control-api.mjs +0 -3
- package/dist/exports/index.d.mts.map +0 -1
- package/dist/exports/index.mjs +0 -128
- package/dist/exports/index.mjs.map +0 -1
- package/dist/result-handler-Do_4Fi4U.mjs +0 -959
- package/dist/result-handler-Do_4Fi4U.mjs.map +0 -1
|
@@ -1,959 +0,0 @@
|
|
|
1
|
-
import { relative } from "node:path";
|
|
2
|
-
import { bgGreen, blue, bold, cyan, dim, green, magenta, red, yellow } from "colorette";
|
|
3
|
-
import stringWidth from "string-width";
|
|
4
|
-
import stripAnsi from "strip-ansi";
|
|
5
|
-
import wrapAnsi from "wrap-ansi";
|
|
6
|
-
import ora from "ora";
|
|
7
|
-
|
|
8
|
-
//#region src/utils/command-helpers.ts
|
|
9
|
-
/**
|
|
10
|
-
* Sets both short and long descriptions for a command.
|
|
11
|
-
* The short description is used in command trees and headers.
|
|
12
|
-
* The long description is shown at the bottom of help output.
|
|
13
|
-
*/
|
|
14
|
-
function setCommandDescriptions(command, shortDescription, longDescription) {
|
|
15
|
-
command.description(shortDescription);
|
|
16
|
-
if (longDescription) command._longDescription = longDescription;
|
|
17
|
-
return command;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Gets the long description from a command if it was set via setCommandDescriptions.
|
|
21
|
-
*/
|
|
22
|
-
function getLongDescription(command) {
|
|
23
|
-
return command._longDescription;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/utils/global-flags.ts
|
|
28
|
-
/**
|
|
29
|
-
* Parses global flags from CLI options.
|
|
30
|
-
* Handles verbosity flags (-v, -vv, --trace), JSON output, quiet mode, timestamps, and color.
|
|
31
|
-
*/
|
|
32
|
-
function parseGlobalFlags(options) {
|
|
33
|
-
const flags = {};
|
|
34
|
-
if (options.json === true || options.json === "object") flags.json = "object";
|
|
35
|
-
else if (options.json === "ndjson") flags.json = "ndjson";
|
|
36
|
-
if (options.quiet || options.q) flags.quiet = true;
|
|
37
|
-
if (options.vv || options.trace) flags.verbose = 2;
|
|
38
|
-
else if (options.verbose || options.v) flags.verbose = 1;
|
|
39
|
-
else flags.verbose = 0;
|
|
40
|
-
if (options.timestamps) flags.timestamps = true;
|
|
41
|
-
if (process.env["NO_COLOR"] || flags.json) flags.color = false;
|
|
42
|
-
else if (options["no-color"]) flags.color = false;
|
|
43
|
-
else if (options.color !== void 0) flags.color = options.color;
|
|
44
|
-
else flags.color = process.stdout.isTTY && !process.env["CI"];
|
|
45
|
-
return flags;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
//#endregion
|
|
49
|
-
//#region src/utils/output.ts
|
|
50
|
-
/**
|
|
51
|
-
* Formats a timestamp for output.
|
|
52
|
-
*/
|
|
53
|
-
function formatTimestamp() {
|
|
54
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Creates a prefix string if timestamps are enabled.
|
|
58
|
-
*/
|
|
59
|
-
function createPrefix(flags) {
|
|
60
|
-
return flags.timestamps ? `[${formatTimestamp()}] ` : "";
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Checks if verbose output is enabled at the specified level.
|
|
64
|
-
*/
|
|
65
|
-
function isVerbose(flags, level) {
|
|
66
|
-
return (flags.verbose ?? 0) >= level;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Creates a color-aware formatter function.
|
|
70
|
-
* Returns a function that applies the color only if colors are enabled.
|
|
71
|
-
*/
|
|
72
|
-
function createColorFormatter(useColor, colorFn) {
|
|
73
|
-
return useColor ? colorFn : (text) => text;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Formats text with dim styling if colors are enabled.
|
|
77
|
-
*/
|
|
78
|
-
function formatDim(useColor, text) {
|
|
79
|
-
return useColor ? dim(text) : text;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Formats human-readable output for contract emit.
|
|
83
|
-
*/
|
|
84
|
-
function formatEmitOutput(result, flags) {
|
|
85
|
-
if (flags.quiet) return "";
|
|
86
|
-
const lines = [];
|
|
87
|
-
const prefix = createPrefix(flags);
|
|
88
|
-
const jsonPath = relative(process.cwd(), result.files.json);
|
|
89
|
-
const dtsPath = relative(process.cwd(), result.files.dts);
|
|
90
|
-
lines.push(`${prefix}✔ Emitted contract.json → ${jsonPath}`);
|
|
91
|
-
lines.push(`${prefix}✔ Emitted contract.d.ts → ${dtsPath}`);
|
|
92
|
-
lines.push(`${prefix} coreHash: ${result.coreHash}`);
|
|
93
|
-
if (result.profileHash) lines.push(`${prefix} profileHash: ${result.profileHash}`);
|
|
94
|
-
if (isVerbose(flags, 1)) lines.push(`${prefix} Total time: ${result.timings.total}ms`);
|
|
95
|
-
return lines.join("\n");
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Formats JSON output for contract emit.
|
|
99
|
-
*/
|
|
100
|
-
function formatEmitJson(result) {
|
|
101
|
-
const output = {
|
|
102
|
-
ok: true,
|
|
103
|
-
coreHash: result.coreHash,
|
|
104
|
-
...result.profileHash ? { profileHash: result.profileHash } : {},
|
|
105
|
-
outDir: result.outDir,
|
|
106
|
-
files: result.files,
|
|
107
|
-
timings: result.timings
|
|
108
|
-
};
|
|
109
|
-
return JSON.stringify(output, null, 2);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Formats error output for human-readable display.
|
|
113
|
-
*/
|
|
114
|
-
function formatErrorOutput(error, flags) {
|
|
115
|
-
const lines = [];
|
|
116
|
-
const prefix = createPrefix(flags);
|
|
117
|
-
const useColor = flags.color !== false;
|
|
118
|
-
const formatRed = createColorFormatter(useColor, red);
|
|
119
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
120
|
-
lines.push(`${prefix}${formatRed("✖")} ${error.summary} (${error.code})`);
|
|
121
|
-
if (error.why) lines.push(`${prefix}${formatDimText(` Why: ${error.why}`)}`);
|
|
122
|
-
if (error.fix) lines.push(`${prefix}${formatDimText(` Fix: ${error.fix}`)}`);
|
|
123
|
-
if (error.where?.path) {
|
|
124
|
-
const whereLine = error.where.line ? `${error.where.path}:${error.where.line}` : error.where.path;
|
|
125
|
-
lines.push(`${prefix}${formatDimText(` Where: ${whereLine}`)}`);
|
|
126
|
-
}
|
|
127
|
-
if (error.meta?.["conflicts"]) {
|
|
128
|
-
const conflicts = error.meta["conflicts"];
|
|
129
|
-
if (conflicts.length > 0) {
|
|
130
|
-
const maxToShow = isVerbose(flags, 1) ? conflicts.length : Math.min(3, conflicts.length);
|
|
131
|
-
const header = isVerbose(flags, 1) ? " Conflicts:" : ` Conflicts (showing ${maxToShow} of ${conflicts.length}):`;
|
|
132
|
-
lines.push(`${prefix}${formatDimText(header)}`);
|
|
133
|
-
for (const conflict of conflicts.slice(0, maxToShow)) lines.push(`${prefix}${formatDimText(` - [${conflict.kind}] ${conflict.summary}`)}`);
|
|
134
|
-
if (!isVerbose(flags, 1) && conflicts.length > maxToShow) lines.push(`${prefix}${formatDimText(" Re-run with -v/--verbose to see all conflicts")}`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
if (error.meta?.["issues"]) {
|
|
138
|
-
const issues = error.meta["issues"];
|
|
139
|
-
if (issues.length > 0) {
|
|
140
|
-
const maxToShow = isVerbose(flags, 1) ? issues.length : Math.min(3, issues.length);
|
|
141
|
-
const header = isVerbose(flags, 1) ? " Issues:" : ` Issues (showing ${maxToShow} of ${issues.length}):`;
|
|
142
|
-
lines.push(`${prefix}${formatDimText(header)}`);
|
|
143
|
-
for (const issue of issues.slice(0, maxToShow)) {
|
|
144
|
-
const kind = issue.kind ?? "issue";
|
|
145
|
-
const message = issue.message ?? "";
|
|
146
|
-
lines.push(`${prefix}${formatDimText(` - [${kind}] ${message}`)}`);
|
|
147
|
-
}
|
|
148
|
-
if (!isVerbose(flags, 1) && issues.length > maxToShow) lines.push(`${prefix}${formatDimText(" Re-run with -v/--verbose to see all issues")}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (error.docsUrl && isVerbose(flags, 1)) lines.push(formatDimText(error.docsUrl));
|
|
152
|
-
if (isVerbose(flags, 2) && error.meta) lines.push(`${prefix}${formatDimText(` Meta: ${JSON.stringify(error.meta, null, 2)}`)}`);
|
|
153
|
-
return lines.join("\n");
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Formats error output as JSON.
|
|
157
|
-
*/
|
|
158
|
-
function formatErrorJson(error) {
|
|
159
|
-
return JSON.stringify(error, null, 2);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Formats human-readable output for database verify.
|
|
163
|
-
*/
|
|
164
|
-
function formatVerifyOutput(result, flags) {
|
|
165
|
-
if (flags.quiet) return "";
|
|
166
|
-
const lines = [];
|
|
167
|
-
const prefix = createPrefix(flags);
|
|
168
|
-
const useColor = flags.color !== false;
|
|
169
|
-
const formatGreen = createColorFormatter(useColor, green);
|
|
170
|
-
const formatRed = createColorFormatter(useColor, red);
|
|
171
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
172
|
-
if (result.ok) {
|
|
173
|
-
lines.push(`${prefix}${formatGreen("✔")} ${result.summary}`);
|
|
174
|
-
lines.push(`${prefix}${formatDimText(` coreHash: ${result.contract.coreHash}`)}`);
|
|
175
|
-
if (result.contract.profileHash) lines.push(`${prefix}${formatDimText(` profileHash: ${result.contract.profileHash}`)}`);
|
|
176
|
-
} else lines.push(`${prefix}${formatRed("✖")} ${result.summary} (${result.code})`);
|
|
177
|
-
if (isVerbose(flags, 1)) {
|
|
178
|
-
if (result.codecCoverageSkipped) lines.push(`${prefix}${formatDimText(" Codec coverage check skipped (helper returned no supported types)")}`);
|
|
179
|
-
lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
180
|
-
}
|
|
181
|
-
return lines.join("\n");
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Formats JSON output for database verify.
|
|
185
|
-
*/
|
|
186
|
-
function formatVerifyJson(result) {
|
|
187
|
-
const output = {
|
|
188
|
-
ok: result.ok,
|
|
189
|
-
...result.code ? { code: result.code } : {},
|
|
190
|
-
summary: result.summary,
|
|
191
|
-
contract: result.contract,
|
|
192
|
-
...result.marker ? { marker: result.marker } : {},
|
|
193
|
-
target: result.target,
|
|
194
|
-
...result.missingCodecs ? { missingCodecs: result.missingCodecs } : {},
|
|
195
|
-
...result.meta ? { meta: result.meta } : {},
|
|
196
|
-
timings: result.timings
|
|
197
|
-
};
|
|
198
|
-
return JSON.stringify(output, null, 2);
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Formats JSON output for database introspection.
|
|
202
|
-
*/
|
|
203
|
-
function formatIntrospectJson(result) {
|
|
204
|
-
return JSON.stringify(result, null, 2);
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Renders a schema tree structure from CoreSchemaView.
|
|
208
|
-
* Matches the style of renderSchemaVerificationTree for consistency.
|
|
209
|
-
*/
|
|
210
|
-
function renderSchemaTree(node, flags, options) {
|
|
211
|
-
const { isLast, prefix, useColor, formatDimText, isRoot = false } = options;
|
|
212
|
-
const lines = [];
|
|
213
|
-
let formattedLabel = node.label;
|
|
214
|
-
if (useColor) switch (node.kind) {
|
|
215
|
-
case "root":
|
|
216
|
-
formattedLabel = bold(node.label);
|
|
217
|
-
break;
|
|
218
|
-
case "entity": {
|
|
219
|
-
const tableMatch = node.label.match(/^table\s+(.+)$/);
|
|
220
|
-
if (tableMatch?.[1]) {
|
|
221
|
-
const tableName = tableMatch[1];
|
|
222
|
-
formattedLabel = `${dim("table")} ${cyan(tableName)}`;
|
|
223
|
-
} else formattedLabel = cyan(node.label);
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
case "collection":
|
|
227
|
-
formattedLabel = dim(node.label);
|
|
228
|
-
break;
|
|
229
|
-
case "field": {
|
|
230
|
-
const columnMatch = node.label.match(/^([^:]+):\s*(.+)$/);
|
|
231
|
-
if (columnMatch?.[1] && columnMatch[2]) {
|
|
232
|
-
const columnName = columnMatch[1];
|
|
233
|
-
const rest = columnMatch[2];
|
|
234
|
-
const typeMatch = rest.match(/^([^\s(]+)\s*(\([^)]+\))$/);
|
|
235
|
-
if (typeMatch?.[1] && typeMatch[2]) {
|
|
236
|
-
const typeDisplay = typeMatch[1];
|
|
237
|
-
const nullability = typeMatch[2];
|
|
238
|
-
formattedLabel = `${cyan(columnName)}: ${typeDisplay} ${dim(nullability)}`;
|
|
239
|
-
} else formattedLabel = `${cyan(columnName)}: ${rest}`;
|
|
240
|
-
} else formattedLabel = node.label;
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
case "index": {
|
|
244
|
-
const pkMatch = node.label.match(/^primary key:\s*(.+)$/);
|
|
245
|
-
if (pkMatch?.[1]) {
|
|
246
|
-
const columnNames = pkMatch[1];
|
|
247
|
-
formattedLabel = `${dim("primary key")}: ${cyan(columnNames)}`;
|
|
248
|
-
} else {
|
|
249
|
-
const uniqueMatch = node.label.match(/^unique\s+(.+)$/);
|
|
250
|
-
if (uniqueMatch?.[1]) {
|
|
251
|
-
const name = uniqueMatch[1];
|
|
252
|
-
formattedLabel = `${dim("unique")} ${cyan(name)}`;
|
|
253
|
-
} else {
|
|
254
|
-
const indexMatch = node.label.match(/^(unique\s+)?index\s+(.+)$/);
|
|
255
|
-
if (indexMatch?.[2]) {
|
|
256
|
-
const prefix$1 = indexMatch[1] ? `${dim("unique")} ` : "";
|
|
257
|
-
const name = indexMatch[2];
|
|
258
|
-
formattedLabel = `${prefix$1}${dim("index")} ${cyan(name)}`;
|
|
259
|
-
} else formattedLabel = dim(node.label);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
case "extension": {
|
|
265
|
-
const extMatch = node.label.match(/^([^\s]+)\s+(extension is enabled)$/);
|
|
266
|
-
if (extMatch?.[1] && extMatch[2]) {
|
|
267
|
-
const extName = extMatch[1];
|
|
268
|
-
const rest = extMatch[2];
|
|
269
|
-
formattedLabel = `${cyan(extName)} ${dim(rest)}`;
|
|
270
|
-
} else formattedLabel = magenta(node.label);
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
default:
|
|
274
|
-
formattedLabel = node.label;
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
if (isRoot) lines.push(formattedLabel);
|
|
278
|
-
else {
|
|
279
|
-
const treePrefix = `${prefix}${formatDimText(isLast ? "└" : "├")}─ `;
|
|
280
|
-
const isRootChild = prefix === "";
|
|
281
|
-
const prefixHasVerticalBar = stripAnsi(prefix).includes("│");
|
|
282
|
-
if (isRootChild) lines.push(`${treePrefix}${formattedLabel}`);
|
|
283
|
-
else if (prefixHasVerticalBar) lines.push(`${treePrefix}${formattedLabel}`);
|
|
284
|
-
else lines.push(`${formatDimText("│")} ${treePrefix}${formattedLabel}`);
|
|
285
|
-
}
|
|
286
|
-
if (node.children && node.children.length > 0) {
|
|
287
|
-
const childPrefix = isRoot ? "" : isLast ? `${prefix} ` : `${prefix}${formatDimText("│")} `;
|
|
288
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
289
|
-
const child = node.children[i];
|
|
290
|
-
if (!child) continue;
|
|
291
|
-
const childLines = renderSchemaTree(child, flags, {
|
|
292
|
-
isLast: i === node.children.length - 1,
|
|
293
|
-
prefix: childPrefix,
|
|
294
|
-
useColor,
|
|
295
|
-
formatDimText,
|
|
296
|
-
isRoot: false
|
|
297
|
-
});
|
|
298
|
-
lines.push(...childLines);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
return lines;
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Formats human-readable output for database introspection.
|
|
305
|
-
*/
|
|
306
|
-
function formatIntrospectOutput(result, schemaView, flags) {
|
|
307
|
-
if (flags.quiet) return "";
|
|
308
|
-
const lines = [];
|
|
309
|
-
const prefix = createPrefix(flags);
|
|
310
|
-
const useColor = flags.color !== false;
|
|
311
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
312
|
-
if (schemaView) {
|
|
313
|
-
const prefixedTreeLines = renderSchemaTree(schemaView.root, flags, {
|
|
314
|
-
isLast: true,
|
|
315
|
-
prefix: "",
|
|
316
|
-
useColor,
|
|
317
|
-
formatDimText,
|
|
318
|
-
isRoot: true
|
|
319
|
-
}).map((line) => `${prefix}${line}`);
|
|
320
|
-
lines.push(...prefixedTreeLines);
|
|
321
|
-
} else {
|
|
322
|
-
lines.push(`${prefix}✔ ${result.summary}`);
|
|
323
|
-
if (isVerbose(flags, 1)) {
|
|
324
|
-
lines.push(`${prefix} Target: ${result.target.familyId}/${result.target.id}`);
|
|
325
|
-
if (result.meta?.dbUrl) lines.push(`${prefix} Database: ${result.meta.dbUrl}`);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
if (isVerbose(flags, 1)) lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
329
|
-
return lines.join("\n");
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Renders a schema verification tree structure from SchemaVerificationNode.
|
|
333
|
-
* Similar to renderSchemaTree but for verification nodes with status-based colors and glyphs.
|
|
334
|
-
*/
|
|
335
|
-
function renderSchemaVerificationTree(node, flags, options) {
|
|
336
|
-
const { isLast, prefix, useColor, formatDimText, isRoot = false } = options;
|
|
337
|
-
const lines = [];
|
|
338
|
-
let statusGlyph = "";
|
|
339
|
-
let statusColor = (text) => text;
|
|
340
|
-
if (useColor) switch (node.status) {
|
|
341
|
-
case "pass":
|
|
342
|
-
statusGlyph = "✔";
|
|
343
|
-
statusColor = green;
|
|
344
|
-
break;
|
|
345
|
-
case "warn":
|
|
346
|
-
statusGlyph = "⚠";
|
|
347
|
-
statusColor = (text) => useColor ? yellow(text) : text;
|
|
348
|
-
break;
|
|
349
|
-
case "fail":
|
|
350
|
-
statusGlyph = "✖";
|
|
351
|
-
statusColor = red;
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
else switch (node.status) {
|
|
355
|
-
case "pass":
|
|
356
|
-
statusGlyph = "✔";
|
|
357
|
-
break;
|
|
358
|
-
case "warn":
|
|
359
|
-
statusGlyph = "⚠";
|
|
360
|
-
break;
|
|
361
|
-
case "fail":
|
|
362
|
-
statusGlyph = "✖";
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
let labelColor = (text) => text;
|
|
366
|
-
let formattedLabel = node.name;
|
|
367
|
-
if (useColor) switch (node.kind) {
|
|
368
|
-
case "contract":
|
|
369
|
-
case "schema":
|
|
370
|
-
labelColor = bold;
|
|
371
|
-
formattedLabel = labelColor(node.name);
|
|
372
|
-
break;
|
|
373
|
-
case "table": {
|
|
374
|
-
const tableMatch = node.name.match(/^table\s+(.+)$/);
|
|
375
|
-
if (tableMatch?.[1]) {
|
|
376
|
-
const tableName = tableMatch[1];
|
|
377
|
-
formattedLabel = `${dim("table")} ${cyan(tableName)}`;
|
|
378
|
-
} else formattedLabel = dim(node.name);
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
case "columns":
|
|
382
|
-
labelColor = dim;
|
|
383
|
-
formattedLabel = labelColor(node.name);
|
|
384
|
-
break;
|
|
385
|
-
case "column": {
|
|
386
|
-
const columnMatch = node.name.match(/^([^:]+):\s*(.+)$/);
|
|
387
|
-
if (columnMatch?.[1] && columnMatch[2]) {
|
|
388
|
-
const columnName = columnMatch[1];
|
|
389
|
-
const rest = columnMatch[2];
|
|
390
|
-
const typeMatch = rest.match(/^([^\s→]+)\s*→\s*([^\s(]+)\s*(\([^)]+\))$/);
|
|
391
|
-
if (typeMatch?.[1] && typeMatch[2] && typeMatch[3]) {
|
|
392
|
-
const contractType = typeMatch[1];
|
|
393
|
-
const nativeType = typeMatch[2];
|
|
394
|
-
const nullability = typeMatch[3];
|
|
395
|
-
formattedLabel = `${cyan(columnName)}: ${contractType} → ${dim(nativeType)} ${dim(nullability)}`;
|
|
396
|
-
} else formattedLabel = `${cyan(columnName)}: ${rest}`;
|
|
397
|
-
} else formattedLabel = node.name;
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
case "type":
|
|
401
|
-
case "nullability":
|
|
402
|
-
labelColor = (text) => text;
|
|
403
|
-
formattedLabel = labelColor(node.name);
|
|
404
|
-
break;
|
|
405
|
-
case "primaryKey": {
|
|
406
|
-
const pkMatch = node.name.match(/^primary key:\s*(.+)$/);
|
|
407
|
-
if (pkMatch?.[1]) {
|
|
408
|
-
const columnNames = pkMatch[1];
|
|
409
|
-
formattedLabel = `${dim("primary key")}: ${cyan(columnNames)}`;
|
|
410
|
-
} else formattedLabel = dim(node.name);
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
case "foreignKey":
|
|
414
|
-
case "unique":
|
|
415
|
-
case "index":
|
|
416
|
-
labelColor = dim;
|
|
417
|
-
formattedLabel = labelColor(node.name);
|
|
418
|
-
break;
|
|
419
|
-
case "extension": {
|
|
420
|
-
const dbMatch = node.name.match(/^database is\s+(.+)$/);
|
|
421
|
-
if (dbMatch?.[1]) {
|
|
422
|
-
const dbName = dbMatch[1];
|
|
423
|
-
formattedLabel = `${dim("database is")} ${cyan(dbName)}`;
|
|
424
|
-
} else {
|
|
425
|
-
const extMatch = node.name.match(/^([^\s]+)\s+(extension is enabled)$/);
|
|
426
|
-
if (extMatch?.[1] && extMatch[2]) {
|
|
427
|
-
const extName = extMatch[1];
|
|
428
|
-
const rest = extMatch[2];
|
|
429
|
-
formattedLabel = `${cyan(extName)} ${dim(rest)}`;
|
|
430
|
-
} else {
|
|
431
|
-
labelColor = magenta;
|
|
432
|
-
formattedLabel = labelColor(node.name);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
break;
|
|
436
|
-
}
|
|
437
|
-
default:
|
|
438
|
-
formattedLabel = node.name;
|
|
439
|
-
break;
|
|
440
|
-
}
|
|
441
|
-
else formattedLabel = node.name;
|
|
442
|
-
const statusGlyphColored = statusColor(statusGlyph);
|
|
443
|
-
let nodeLabel = formattedLabel;
|
|
444
|
-
if ((node.status === "fail" || node.status === "warn") && node.message && node.message.length > 0) {
|
|
445
|
-
const messageText = formatDimText(`(${node.message})`);
|
|
446
|
-
nodeLabel = `${formattedLabel} ${messageText}`;
|
|
447
|
-
}
|
|
448
|
-
if (isRoot) lines.push(`${statusGlyphColored} ${nodeLabel}`);
|
|
449
|
-
else {
|
|
450
|
-
const treePrefix = `${prefix}${formatDimText(isLast ? "└" : "├")}─ `;
|
|
451
|
-
const isRootChild = prefix === "";
|
|
452
|
-
const prefixHasVerticalBar = stripAnsi(prefix).includes("│");
|
|
453
|
-
if (isRootChild) lines.push(`${treePrefix}${statusGlyphColored} ${nodeLabel}`);
|
|
454
|
-
else if (prefixHasVerticalBar) lines.push(`${treePrefix}${statusGlyphColored} ${nodeLabel}`);
|
|
455
|
-
else lines.push(`${formatDimText("│")} ${treePrefix}${statusGlyphColored} ${nodeLabel}`);
|
|
456
|
-
}
|
|
457
|
-
if (node.children && node.children.length > 0) {
|
|
458
|
-
const childPrefix = isRoot ? "" : isLast ? `${prefix} ` : `${prefix}${formatDimText("│")} `;
|
|
459
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
460
|
-
const child = node.children[i];
|
|
461
|
-
if (!child) continue;
|
|
462
|
-
const childLines = renderSchemaVerificationTree(child, flags, {
|
|
463
|
-
isLast: i === node.children.length - 1,
|
|
464
|
-
prefix: childPrefix,
|
|
465
|
-
useColor,
|
|
466
|
-
formatDimText,
|
|
467
|
-
isRoot: false
|
|
468
|
-
});
|
|
469
|
-
lines.push(...childLines);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return lines;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Formats human-readable output for database schema verification.
|
|
476
|
-
*/
|
|
477
|
-
function formatSchemaVerifyOutput(result, flags) {
|
|
478
|
-
if (flags.quiet) return "";
|
|
479
|
-
const lines = [];
|
|
480
|
-
const prefix = createPrefix(flags);
|
|
481
|
-
const useColor = flags.color !== false;
|
|
482
|
-
const formatGreen = createColorFormatter(useColor, green);
|
|
483
|
-
const formatRed = createColorFormatter(useColor, red);
|
|
484
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
485
|
-
const prefixedTreeLines = renderSchemaVerificationTree(result.schema.root, flags, {
|
|
486
|
-
isLast: true,
|
|
487
|
-
prefix: "",
|
|
488
|
-
useColor,
|
|
489
|
-
formatDimText,
|
|
490
|
-
isRoot: true
|
|
491
|
-
}).map((line) => `${prefix}${line}`);
|
|
492
|
-
lines.push(...prefixedTreeLines);
|
|
493
|
-
if (isVerbose(flags, 1)) {
|
|
494
|
-
lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
495
|
-
lines.push(`${prefix}${formatDimText(` pass=${result.schema.counts.pass} warn=${result.schema.counts.warn} fail=${result.schema.counts.fail}`)}`);
|
|
496
|
-
}
|
|
497
|
-
lines.push("");
|
|
498
|
-
if (result.ok) lines.push(`${prefix}${formatGreen("✔")} ${result.summary}`);
|
|
499
|
-
else {
|
|
500
|
-
const codeText = result.code ? ` (${result.code})` : "";
|
|
501
|
-
lines.push(`${prefix}${formatRed("✖")} ${result.summary}${codeText}`);
|
|
502
|
-
}
|
|
503
|
-
return lines.join("\n");
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Formats JSON output for database schema verification.
|
|
507
|
-
*/
|
|
508
|
-
function formatSchemaVerifyJson(result) {
|
|
509
|
-
return JSON.stringify(result, null, 2);
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
* Formats human-readable output for database sign.
|
|
513
|
-
*/
|
|
514
|
-
function formatSignOutput(result, flags) {
|
|
515
|
-
if (flags.quiet) return "";
|
|
516
|
-
const lines = [];
|
|
517
|
-
const prefix = createPrefix(flags);
|
|
518
|
-
const useColor = flags.color !== false;
|
|
519
|
-
const formatGreen = createColorFormatter(useColor, green);
|
|
520
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
521
|
-
if (result.ok) {
|
|
522
|
-
lines.push(`${prefix}${formatGreen("✔")} Database signed`);
|
|
523
|
-
const previousHash = result.marker.previous?.coreHash ?? "none";
|
|
524
|
-
const currentHash = result.contract.coreHash;
|
|
525
|
-
lines.push(`${prefix}${formatDimText(` from: ${previousHash}`)}`);
|
|
526
|
-
lines.push(`${prefix}${formatDimText(` to: ${currentHash}`)}`);
|
|
527
|
-
if (isVerbose(flags, 1)) {
|
|
528
|
-
if (result.contract.profileHash) lines.push(`${prefix}${formatDimText(` profileHash: ${result.contract.profileHash}`)}`);
|
|
529
|
-
if (result.marker.previous?.profileHash) lines.push(`${prefix}${formatDimText(` previous profileHash: ${result.marker.previous.profileHash}`)}`);
|
|
530
|
-
lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return lines.join("\n");
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Formats JSON output for database sign.
|
|
537
|
-
*/
|
|
538
|
-
function formatSignJson(result) {
|
|
539
|
-
return JSON.stringify(result, null, 2);
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Formats human-readable output for db init plan mode.
|
|
543
|
-
*/
|
|
544
|
-
function formatDbInitPlanOutput(result, flags) {
|
|
545
|
-
if (flags.quiet) return "";
|
|
546
|
-
const lines = [];
|
|
547
|
-
const prefix = createPrefix(flags);
|
|
548
|
-
const useColor = flags.color !== false;
|
|
549
|
-
const formatGreen = createColorFormatter(useColor, green);
|
|
550
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
551
|
-
const operationCount = result.plan?.operations.length ?? 0;
|
|
552
|
-
lines.push(`${prefix}${formatGreen("✔")} Planned ${operationCount} operation(s)`);
|
|
553
|
-
if (result.plan?.operations && result.plan.operations.length > 0) {
|
|
554
|
-
lines.push(`${prefix}${formatDimText("│")}`);
|
|
555
|
-
for (let i = 0; i < result.plan.operations.length; i++) {
|
|
556
|
-
const op = result.plan.operations[i];
|
|
557
|
-
if (!op) continue;
|
|
558
|
-
const treeChar = i === result.plan.operations.length - 1 ? "└" : "├";
|
|
559
|
-
const opClass = formatDimText(`[${op.operationClass}]`);
|
|
560
|
-
lines.push(`${prefix}${formatDimText(treeChar)}─ ${op.label} ${opClass}`);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
if (result.plan?.destination) {
|
|
564
|
-
lines.push(`${prefix}`);
|
|
565
|
-
lines.push(`${prefix}${formatDimText(`Destination hash: ${result.plan.destination.coreHash}`)}`);
|
|
566
|
-
}
|
|
567
|
-
if (isVerbose(flags, 1)) lines.push(`${prefix}${formatDimText(`Total time: ${result.timings.total}ms`)}`);
|
|
568
|
-
lines.push(`${prefix}`);
|
|
569
|
-
lines.push(`${prefix}${formatDimText("This is a dry run. No changes were applied.")}`);
|
|
570
|
-
lines.push(`${prefix}${formatDimText("Run without --plan to apply changes.")}`);
|
|
571
|
-
return lines.join("\n");
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Formats human-readable output for db init apply mode.
|
|
575
|
-
*/
|
|
576
|
-
function formatDbInitApplyOutput(result, flags) {
|
|
577
|
-
if (flags.quiet) return "";
|
|
578
|
-
const lines = [];
|
|
579
|
-
const prefix = createPrefix(flags);
|
|
580
|
-
const useColor = flags.color !== false;
|
|
581
|
-
const formatGreen = createColorFormatter(useColor, green);
|
|
582
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
583
|
-
if (result.ok) {
|
|
584
|
-
const executed = result.execution?.operationsExecuted ?? 0;
|
|
585
|
-
lines.push(`${prefix}${formatGreen("✔")} Applied ${executed} operation(s)`);
|
|
586
|
-
if (result.marker) {
|
|
587
|
-
lines.push(`${prefix}${formatDimText(` Marker written: ${result.marker.coreHash}`)}`);
|
|
588
|
-
if (result.marker.profileHash) lines.push(`${prefix}${formatDimText(` Profile hash: ${result.marker.profileHash}`)}`);
|
|
589
|
-
}
|
|
590
|
-
if (isVerbose(flags, 1)) lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
591
|
-
}
|
|
592
|
-
return lines.join("\n");
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* Formats JSON output for db init command.
|
|
596
|
-
*/
|
|
597
|
-
function formatDbInitJson(result) {
|
|
598
|
-
return JSON.stringify(result, null, 2);
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Fixed width for left column in help output.
|
|
602
|
-
*/
|
|
603
|
-
const LEFT_COLUMN_WIDTH = 20;
|
|
604
|
-
/**
|
|
605
|
-
* Minimum width for right column wrapping in help output.
|
|
606
|
-
*/
|
|
607
|
-
const RIGHT_COLUMN_MIN_WIDTH = 40;
|
|
608
|
-
/**
|
|
609
|
-
* Maximum width for right column wrapping in help output (when terminal is wide enough).
|
|
610
|
-
*/
|
|
611
|
-
const RIGHT_COLUMN_MAX_WIDTH = 90;
|
|
612
|
-
/**
|
|
613
|
-
* Gets the terminal width, or returns a default if not available.
|
|
614
|
-
*/
|
|
615
|
-
function getTerminalWidth() {
|
|
616
|
-
const terminalWidth = process.stdout.columns;
|
|
617
|
-
const defaultWidth = Number.parseInt(process.env["CLI_WIDTH"] || "80", 10);
|
|
618
|
-
return terminalWidth || defaultWidth;
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* Calculates the available width for the right column based on terminal width.
|
|
622
|
-
* Format: "│ " (2) + left column (20) + " " (2) + right column = total
|
|
623
|
-
* So: right column = terminal width - 2 - 20 - 2 = terminal width - 24
|
|
624
|
-
*/
|
|
625
|
-
function calculateRightColumnWidth() {
|
|
626
|
-
const availableWidth = getTerminalWidth() - 2 - LEFT_COLUMN_WIDTH - 2;
|
|
627
|
-
return Math.max(RIGHT_COLUMN_MIN_WIDTH, Math.min(availableWidth, RIGHT_COLUMN_MAX_WIDTH));
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* Creates an arrow segment badge with green background and white text.
|
|
631
|
-
* Body: green background with white "prisma-next" text
|
|
632
|
-
* Tip: dark grey arrow pointing right (Powerline separator)
|
|
633
|
-
*/
|
|
634
|
-
function createPrismaNextBadge(useColor) {
|
|
635
|
-
if (!useColor) return "prisma-next";
|
|
636
|
-
return `${bgGreen(bold(" prisma-next "))}${green("")}`;
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Creates a padding function.
|
|
640
|
-
*/
|
|
641
|
-
function createPadFunction() {
|
|
642
|
-
return (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Formats a header line: brand + operation + intent
|
|
646
|
-
*/
|
|
647
|
-
function formatHeaderLine(options) {
|
|
648
|
-
if (options.operation) return `${options.brand} ${options.operation} → ${options.intent}`;
|
|
649
|
-
return `${options.brand} ${options.intent}`;
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Formats a "Read more" URL line.
|
|
653
|
-
* The "Read more" label is in default color (not cyan), and the URL is blue.
|
|
654
|
-
*/
|
|
655
|
-
function formatReadMoreLine(options) {
|
|
656
|
-
const labelPadded = createPadFunction()("Read more", options.maxLabelWidth);
|
|
657
|
-
const valueColored = options.useColor ? blue(options.url) : options.url;
|
|
658
|
-
return `${options.formatDimText("│")} ${labelPadded} ${valueColored}`;
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* Pads text to a fixed width, accounting for ANSI escape codes.
|
|
662
|
-
* Uses string-width to measure the actual display width.
|
|
663
|
-
*/
|
|
664
|
-
function padToFixedWidth(text, width) {
|
|
665
|
-
const actualWidth = stringWidth(text);
|
|
666
|
-
const padding = Math.max(0, width - actualWidth);
|
|
667
|
-
return text + " ".repeat(padding);
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Wraps text to fit within a specified width using wrap-ansi.
|
|
671
|
-
* Preserves ANSI escape codes and breaks at word boundaries.
|
|
672
|
-
*/
|
|
673
|
-
function wrapTextAnsi(text, width) {
|
|
674
|
-
return wrapAnsi(text, width, {
|
|
675
|
-
hard: false,
|
|
676
|
-
trim: true
|
|
677
|
-
}).split("\n");
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Formats a default value as "default: <value>" with dimming.
|
|
681
|
-
*/
|
|
682
|
-
function formatDefaultValue(value, useColor) {
|
|
683
|
-
const defaultText = `default: ${String(value)}`;
|
|
684
|
-
return useColor ? dim(defaultText) : defaultText;
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* Renders a command tree structure.
|
|
688
|
-
* Handles both single-level (subcommands of a command) and multi-level (top-level commands with subcommands) trees.
|
|
689
|
-
*/
|
|
690
|
-
function renderCommandTree(options) {
|
|
691
|
-
const { commands, useColor, formatDimText, hasItemsAfter, continuationPrefix } = options;
|
|
692
|
-
const lines = [];
|
|
693
|
-
if (commands.length === 0) return lines;
|
|
694
|
-
for (let i = 0; i < commands.length; i++) {
|
|
695
|
-
const cmd = commands[i];
|
|
696
|
-
if (!cmd) continue;
|
|
697
|
-
const subcommands = cmd.commands.filter((subcmd) => !subcmd.name().startsWith("_"));
|
|
698
|
-
const isLastCommand = i === commands.length - 1;
|
|
699
|
-
if (subcommands.length > 0) {
|
|
700
|
-
const treePrefix = `${isLastCommand && !hasItemsAfter ? formatDimText("└") : formatDimText("├")}─ `;
|
|
701
|
-
const remainingWidth = LEFT_COLUMN_WIDTH - stringWidth(stripAnsi(treePrefix));
|
|
702
|
-
const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);
|
|
703
|
-
const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;
|
|
704
|
-
lines.push(`${formatDimText("│")} ${treePrefix}${commandNameColored}`);
|
|
705
|
-
for (let j = 0; j < subcommands.length; j++) {
|
|
706
|
-
const subcmd = subcommands[j];
|
|
707
|
-
if (!subcmd) continue;
|
|
708
|
-
const isLastSubcommand = j === subcommands.length - 1;
|
|
709
|
-
const shortDescription = subcmd.description() || "";
|
|
710
|
-
const treeChar = isLastSubcommand ? "└" : "├";
|
|
711
|
-
const continuation = continuationPrefix ?? (isLastCommand && isLastSubcommand && !hasItemsAfter ? " " : formatDimText("│"));
|
|
712
|
-
const subTreePrefix = `${continuation === " " ? " " : continuation} ${formatDimText(treeChar)}─ `;
|
|
713
|
-
const subRemainingWidth = LEFT_COLUMN_WIDTH - stringWidth(stripAnsi(subTreePrefix));
|
|
714
|
-
const subcommandNamePadded = padToFixedWidth(subcmd.name(), subRemainingWidth);
|
|
715
|
-
const subcommandNameColored = useColor ? cyan(subcommandNamePadded) : subcommandNamePadded;
|
|
716
|
-
lines.push(`${formatDimText("│")} ${subTreePrefix}${subcommandNameColored} ${shortDescription}`);
|
|
717
|
-
}
|
|
718
|
-
} else {
|
|
719
|
-
const treePrefix = `${isLastCommand && !hasItemsAfter ? formatDimText("└") : formatDimText("├")}─ `;
|
|
720
|
-
const remainingWidth = LEFT_COLUMN_WIDTH - stringWidth(stripAnsi(treePrefix));
|
|
721
|
-
const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);
|
|
722
|
-
const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;
|
|
723
|
-
const shortDescription = cmd.description() || "";
|
|
724
|
-
lines.push(`${formatDimText("│")} ${treePrefix}${commandNameColored} ${shortDescription}`);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
return lines;
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* Formats multiline description with "Prisma Next" in green.
|
|
731
|
-
* Wraps at the same right-hand boundary as the right column.
|
|
732
|
-
* The right edge is defined by: left column (20) + gap (2) + right column (90) = 112 characters total.
|
|
733
|
-
* Since the description line starts with "│ " (2 chars), the text wraps at 112 - 2 = 110 characters.
|
|
734
|
-
*/
|
|
735
|
-
function formatMultilineDescription(options) {
|
|
736
|
-
const lines = [];
|
|
737
|
-
const formatGreen = (text) => options.useColor ? green(text) : text;
|
|
738
|
-
const rightColumnWidth = calculateRightColumnWidth();
|
|
739
|
-
const wrapWidth = 2 + LEFT_COLUMN_WIDTH + 2 + rightColumnWidth - 2;
|
|
740
|
-
for (const descLine of options.descriptionLines) {
|
|
741
|
-
const wrappedLines = wrapTextAnsi(descLine.replace(/Prisma Next/g, (match) => formatGreen(match)), wrapWidth);
|
|
742
|
-
for (const wrappedLine of wrappedLines) lines.push(`${options.formatDimText("│")} ${wrappedLine}`);
|
|
743
|
-
}
|
|
744
|
-
return lines;
|
|
745
|
-
}
|
|
746
|
-
/**
|
|
747
|
-
* Formats the header in the new experimental visual style.
|
|
748
|
-
* This header appears at the start of command output, showing the operation,
|
|
749
|
-
* intent, documentation link, and parameters.
|
|
750
|
-
*/
|
|
751
|
-
function formatStyledHeader(options) {
|
|
752
|
-
const lines = [];
|
|
753
|
-
const useColor = options.flags.color !== false;
|
|
754
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
755
|
-
const brand = createPrismaNextBadge(useColor);
|
|
756
|
-
const operation = useColor ? bold(options.command) : options.command;
|
|
757
|
-
const intent = formatDimText(options.description);
|
|
758
|
-
lines.push(formatHeaderLine({
|
|
759
|
-
brand,
|
|
760
|
-
operation,
|
|
761
|
-
intent
|
|
762
|
-
}));
|
|
763
|
-
lines.push(formatDimText("│"));
|
|
764
|
-
for (const detail of options.details) {
|
|
765
|
-
const labelPadded = padToFixedWidth(`${detail.label}:`, LEFT_COLUMN_WIDTH);
|
|
766
|
-
const labelColored = useColor ? cyan(labelPadded) : labelPadded;
|
|
767
|
-
lines.push(`${formatDimText("│")} ${labelColored} ${detail.value}`);
|
|
768
|
-
}
|
|
769
|
-
if (options.url) {
|
|
770
|
-
lines.push(formatDimText("│"));
|
|
771
|
-
lines.push(formatReadMoreLine({
|
|
772
|
-
url: options.url,
|
|
773
|
-
maxLabelWidth: LEFT_COLUMN_WIDTH,
|
|
774
|
-
useColor,
|
|
775
|
-
formatDimText
|
|
776
|
-
}));
|
|
777
|
-
}
|
|
778
|
-
lines.push(formatDimText("└"));
|
|
779
|
-
return `${lines.join("\n")}\n`;
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Formats a success message in the styled output format.
|
|
783
|
-
*/
|
|
784
|
-
function formatSuccessMessage(flags) {
|
|
785
|
-
return `${createColorFormatter(flags.color !== false, green)("✔")} Success`;
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Maps command paths to their documentation URLs.
|
|
789
|
-
*/
|
|
790
|
-
function getCommandDocsUrl(commandPath) {
|
|
791
|
-
return {
|
|
792
|
-
"contract emit": "https://pris.ly/contract-emit",
|
|
793
|
-
"db verify": "https://pris.ly/db-verify"
|
|
794
|
-
}[commandPath];
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Builds the full command path from a command and its parents.
|
|
798
|
-
*/
|
|
799
|
-
function buildCommandPath(command) {
|
|
800
|
-
const parts = [];
|
|
801
|
-
let current = command;
|
|
802
|
-
while (current && current.name() !== "prisma-next") {
|
|
803
|
-
parts.unshift(current.name());
|
|
804
|
-
current = current.parent ?? void 0;
|
|
805
|
-
}
|
|
806
|
-
return parts.join(" ");
|
|
807
|
-
}
|
|
808
|
-
/**
|
|
809
|
-
* Formats help output for a command using the styled format.
|
|
810
|
-
*/
|
|
811
|
-
function formatCommandHelp(options) {
|
|
812
|
-
const { command, flags } = options;
|
|
813
|
-
const lines = [];
|
|
814
|
-
const useColor = flags.color !== false;
|
|
815
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
816
|
-
const commandPath = buildCommandPath(command);
|
|
817
|
-
const shortDescription = command.description() || "";
|
|
818
|
-
const longDescription = getLongDescription(command);
|
|
819
|
-
const brand = createPrismaNextBadge(useColor);
|
|
820
|
-
const operation = useColor ? bold(commandPath) : commandPath;
|
|
821
|
-
const intent = formatDimText(shortDescription);
|
|
822
|
-
lines.push(formatHeaderLine({
|
|
823
|
-
brand,
|
|
824
|
-
operation,
|
|
825
|
-
intent
|
|
826
|
-
}));
|
|
827
|
-
lines.push(formatDimText("│"));
|
|
828
|
-
const optionsList = command.options.map((opt) => {
|
|
829
|
-
return {
|
|
830
|
-
flags: opt.flags,
|
|
831
|
-
description: opt.description || "",
|
|
832
|
-
defaultValue: opt.defaultValue
|
|
833
|
-
};
|
|
834
|
-
});
|
|
835
|
-
const subcommands = command.commands.filter((cmd) => !cmd.name().startsWith("_"));
|
|
836
|
-
if (subcommands.length > 0) {
|
|
837
|
-
const treeLines = renderCommandTree({
|
|
838
|
-
commands: subcommands,
|
|
839
|
-
useColor,
|
|
840
|
-
formatDimText,
|
|
841
|
-
hasItemsAfter: optionsList.length > 0
|
|
842
|
-
});
|
|
843
|
-
lines.push(...treeLines);
|
|
844
|
-
}
|
|
845
|
-
if (subcommands.length > 0 && optionsList.length > 0) lines.push(formatDimText("│"));
|
|
846
|
-
if (optionsList.length > 0) for (const opt of optionsList) {
|
|
847
|
-
const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);
|
|
848
|
-
let flagsColored = flagsPadded;
|
|
849
|
-
if (useColor) {
|
|
850
|
-
flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match) => magenta(match));
|
|
851
|
-
flagsColored = cyan(flagsColored);
|
|
852
|
-
}
|
|
853
|
-
const rightColumnWidth = calculateRightColumnWidth();
|
|
854
|
-
const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);
|
|
855
|
-
lines.push(`${formatDimText("│")} ${flagsColored} ${wrappedDescription[0] || ""}`);
|
|
856
|
-
for (let i = 1; i < wrappedDescription.length; i++) {
|
|
857
|
-
const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
|
|
858
|
-
lines.push(`${formatDimText("│")} ${emptyLabel} ${wrappedDescription[i] || ""}`);
|
|
859
|
-
}
|
|
860
|
-
if (opt.defaultValue !== void 0) {
|
|
861
|
-
const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
|
|
862
|
-
const defaultText = formatDefaultValue(opt.defaultValue, useColor);
|
|
863
|
-
lines.push(`${formatDimText("│")} ${emptyLabel} ${defaultText}`);
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
const docsUrl = getCommandDocsUrl(commandPath);
|
|
867
|
-
if (docsUrl) {
|
|
868
|
-
lines.push(formatDimText("│"));
|
|
869
|
-
lines.push(formatReadMoreLine({
|
|
870
|
-
url: docsUrl,
|
|
871
|
-
maxLabelWidth: LEFT_COLUMN_WIDTH,
|
|
872
|
-
useColor,
|
|
873
|
-
formatDimText
|
|
874
|
-
}));
|
|
875
|
-
}
|
|
876
|
-
if (longDescription) {
|
|
877
|
-
lines.push(formatDimText("│"));
|
|
878
|
-
const descriptionLines = longDescription.split("\n").filter((line) => line.trim().length > 0);
|
|
879
|
-
lines.push(...formatMultilineDescription({
|
|
880
|
-
descriptionLines,
|
|
881
|
-
useColor,
|
|
882
|
-
formatDimText
|
|
883
|
-
}));
|
|
884
|
-
}
|
|
885
|
-
lines.push(formatDimText("└"));
|
|
886
|
-
return `${lines.join("\n")}\n`;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
//#endregion
|
|
890
|
-
//#region src/utils/progress-adapter.ts
|
|
891
|
-
/**
|
|
892
|
-
* Creates a progress adapter that converts control-api progress events
|
|
893
|
-
* into CLI spinner/progress output.
|
|
894
|
-
*
|
|
895
|
-
* The adapter:
|
|
896
|
-
* - Starts/succeeds spinners for top-level span boundaries
|
|
897
|
-
* - Prints per-operation lines for nested spans (e.g., migration operations under 'apply')
|
|
898
|
-
* - Respects quiet/json/non-TTY flags (no-op in those cases)
|
|
899
|
-
*
|
|
900
|
-
* @param options - Progress adapter configuration
|
|
901
|
-
* @returns An onProgress callback compatible with control-api operations
|
|
902
|
-
*/
|
|
903
|
-
function createProgressAdapter(options) {
|
|
904
|
-
const { flags } = options;
|
|
905
|
-
if (!(!flags.quiet && flags.json !== "object" && process.stdout.isTTY)) return () => {};
|
|
906
|
-
const activeSpans = /* @__PURE__ */ new Map();
|
|
907
|
-
return (event) => {
|
|
908
|
-
if (event.kind === "spanStart") {
|
|
909
|
-
if (event.parentSpanId) {
|
|
910
|
-
console.log(` → ${event.label}...`);
|
|
911
|
-
return;
|
|
912
|
-
}
|
|
913
|
-
const spinner = ora({
|
|
914
|
-
text: event.label,
|
|
915
|
-
color: flags.color !== false ? "cyan" : false
|
|
916
|
-
}).start();
|
|
917
|
-
activeSpans.set(event.spanId, {
|
|
918
|
-
spinner,
|
|
919
|
-
startTime: Date.now()
|
|
920
|
-
});
|
|
921
|
-
} else if (event.kind === "spanEnd") {
|
|
922
|
-
const spanState = activeSpans.get(event.spanId);
|
|
923
|
-
if (spanState) {
|
|
924
|
-
const elapsed = Date.now() - spanState.startTime;
|
|
925
|
-
if (event.outcome === "error") spanState.spinner.fail(`${spanState.spinner.text} (failed)`);
|
|
926
|
-
else if (event.outcome === "skipped") spanState.spinner.info(`${spanState.spinner.text} (skipped)`);
|
|
927
|
-
else spanState.spinner.succeed(`${spanState.spinner.text} (${elapsed}ms)`);
|
|
928
|
-
activeSpans.delete(event.spanId);
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
//#endregion
|
|
935
|
-
//#region src/utils/result-handler.ts
|
|
936
|
-
/**
|
|
937
|
-
* Processes a CLI command result, handling both success and error cases.
|
|
938
|
-
* Formats output appropriately and returns the exit code.
|
|
939
|
-
* Never throws - returns exit code for commands to use with process.exit().
|
|
940
|
-
*
|
|
941
|
-
* @param result - The result from a CLI command
|
|
942
|
-
* @param flags - Global flags for output formatting
|
|
943
|
-
* @param onSuccess - Optional callback for successful results (for custom success output)
|
|
944
|
-
* @returns The exit code that should be used (0 for success, non-zero for errors)
|
|
945
|
-
*/
|
|
946
|
-
function handleResult(result, flags, onSuccess) {
|
|
947
|
-
if (result.ok) {
|
|
948
|
-
if (onSuccess) onSuccess(result.value);
|
|
949
|
-
return 0;
|
|
950
|
-
}
|
|
951
|
-
const envelope = result.failure.toEnvelope();
|
|
952
|
-
if (flags.json) console.error(formatErrorJson(envelope));
|
|
953
|
-
else console.error(formatErrorOutput(envelope, flags));
|
|
954
|
-
return result.failure.domain === "CLI" ? 2 : 1;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
//#endregion
|
|
958
|
-
export { formatVerifyJson as _, formatDbInitJson as a, setCommandDescriptions as b, formatEmitOutput as c, formatSchemaVerifyJson as d, formatSchemaVerifyOutput as f, formatSuccessMessage as g, formatStyledHeader as h, formatDbInitApplyOutput as i, formatIntrospectJson as l, formatSignOutput as m, createProgressAdapter as n, formatDbInitPlanOutput as o, formatSignJson as p, formatCommandHelp as r, formatEmitJson as s, handleResult as t, formatIntrospectOutput as u, formatVerifyOutput as v, parseGlobalFlags as y };
|
|
959
|
-
//# sourceMappingURL=result-handler-Do_4Fi4U.mjs.map
|