@kubb/cli 5.11.4 → 5.11.5
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/{Telemetry-CwaVQsvD.js → Telemetry-BlAR8vxu.js} +3 -31
- package/dist/Telemetry-BlAR8vxu.js.map +1 -0
- package/dist/{Telemetry-Be1nltUh.cjs → Telemetry-CF1YNdR-.cjs} +2 -42
- package/dist/Telemetry-CF1YNdR-.cjs.map +1 -0
- package/dist/{background-mKdZ5HRx.cjs → background-CaZZul1n.cjs} +5 -4
- package/dist/background-CaZZul1n.cjs.map +1 -0
- package/dist/{background-CQPyCSn0.js → background-DKyMPeHm.js} +7 -5
- package/dist/background-DKyMPeHm.js.map +1 -0
- package/dist/{background-aTbwrgui.js → background-DUHqYiuQ.js} +1 -1
- package/dist/config-Bh00Hwpw.js +132 -0
- package/dist/config-Bh00Hwpw.js.map +1 -0
- package/dist/config-D63Gum4F.cjs +169 -0
- package/dist/config-D63Gum4F.cjs.map +1 -0
- package/dist/config-iVdOcpro.js +1 -0
- package/dist/credentials-CZK6zPLv.js.map +1 -1
- package/dist/credentials-DDaKqtJn.cjs.map +1 -1
- package/dist/errors-Cl69p_vI.cjs +43 -0
- package/dist/errors-Cl69p_vI.cjs.map +1 -0
- package/dist/errors-DmC83ALX.js +32 -0
- package/dist/errors-DmC83ALX.js.map +1 -0
- package/dist/index.cjs +872 -307
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +863 -298
- package/dist/index.js.map +1 -1
- package/dist/registry-CfYNeyOc.cjs +272 -0
- package/dist/registry-CfYNeyOc.cjs.map +1 -0
- package/dist/registry-D688-8EH.js +200 -0
- package/dist/registry-D688-8EH.js.map +1 -0
- package/dist/reporters-BHyW4d5Q.js +817 -0
- package/dist/reporters-BHyW4d5Q.js.map +1 -0
- package/dist/reporters-DrQJfnU2.cjs +829 -0
- package/dist/reporters-DrQJfnU2.cjs.map +1 -0
- package/dist/run-B4SKmzAG.js +1 -0
- package/dist/{run-Bczs5vbI.cjs → run-BldagXO-.cjs} +4 -3
- package/dist/{run-Bczs5vbI.cjs.map → run-BldagXO-.cjs.map} +1 -1
- package/dist/{run-B6VxJ_VM.js → run-C1FHgzNR.js} +3 -2
- package/dist/{run-B6VxJ_VM.js.map → run-C1FHgzNR.js.map} +1 -1
- package/dist/run-CYHpe0V_.cjs +227 -0
- package/dist/run-CYHpe0V_.cjs.map +1 -0
- package/dist/run-CaJbZO-f.cjs +94 -0
- package/dist/run-CaJbZO-f.cjs.map +1 -0
- package/dist/run-Cj-HJxYW.js +93 -0
- package/dist/run-Cj-HJxYW.js.map +1 -0
- package/dist/{run-BWRmQxtE.cjs → run-DkBJkKor.cjs} +172 -76
- package/dist/run-DkBJkKor.cjs.map +1 -0
- package/dist/run-S3xKq4bj.js +224 -0
- package/dist/run-S3xKq4bj.js.map +1 -0
- package/dist/{run-YHth5Afz.js → run-vBNko5TH.js} +166 -70
- package/dist/run-vBNko5TH.js.map +1 -0
- package/dist/{snapshot-D_rXnnMH.cjs → snapshot-CsIJRKEL.cjs} +50 -63
- package/dist/snapshot-CsIJRKEL.cjs.map +1 -0
- package/dist/{snapshot-Cilp10vE.js → snapshot-Cvo94y5d.js} +48 -61
- package/dist/snapshot-Cvo94y5d.js.map +1 -0
- package/dist/status-C-NPN63r.cjs +78 -0
- package/dist/status-C-NPN63r.cjs.map +1 -0
- package/dist/status-DTsZxa5Y.js +77 -0
- package/dist/status-DTsZxa5Y.js.map +1 -0
- package/dist/studioWorker.js +2 -2
- package/dist/summary-C22oNZu_.cjs +46 -0
- package/dist/summary-C22oNZu_.cjs.map +1 -0
- package/dist/summary-F11HQput.js +41 -0
- package/dist/summary-F11HQput.js.map +1 -0
- package/dist/text-28DwO_5A.cjs +341 -0
- package/dist/text-28DwO_5A.cjs.map +1 -0
- package/dist/text-BThr2r0T.js +239 -0
- package/dist/text-BThr2r0T.js.map +1 -0
- package/dist/utils-BLXM2UkN.cjs +727 -0
- package/dist/utils-BLXM2UkN.cjs.map +1 -0
- package/dist/utils-Cv3YUnSi.js +612 -0
- package/dist/utils-Cv3YUnSi.js.map +1 -0
- package/package.json +7 -7
- package/dist/Telemetry-Be1nltUh.cjs.map +0 -1
- package/dist/Telemetry-CwaVQsvD.js.map +0 -1
- package/dist/background-CQPyCSn0.js.map +0 -1
- package/dist/background-mKdZ5HRx.cjs.map +0 -1
- package/dist/config-B56ZuVhi.js +0 -95
- package/dist/config-B56ZuVhi.js.map +0 -1
- package/dist/config-Cs4N79Fm.cjs +0 -113
- package/dist/config-Cs4N79Fm.cjs.map +0 -1
- package/dist/output-HgzJqkSF.cjs +0 -1076
- package/dist/output-HgzJqkSF.cjs.map +0 -1
- package/dist/output-PhkPtNP7.js +0 -937
- package/dist/output-PhkPtNP7.js.map +0 -1
- package/dist/registry-DYUhC7rH.js +0 -115
- package/dist/registry-DYUhC7rH.js.map +0 -1
- package/dist/registry-tk-v78fd.cjs +0 -157
- package/dist/registry-tk-v78fd.cjs.map +0 -1
- package/dist/run-AfjIBtiL.js +0 -39
- package/dist/run-AfjIBtiL.js.map +0 -1
- package/dist/run-BWRmQxtE.cjs.map +0 -1
- package/dist/run-B_Gr9TJ4.cjs +0 -345
- package/dist/run-B_Gr9TJ4.cjs.map +0 -1
- package/dist/run-CwrI0wRy.js +0 -1
- package/dist/run-DDoJGjWT.cjs +0 -40
- package/dist/run-DDoJGjWT.cjs.map +0 -1
- package/dist/run-SYKj8-Q5.js +0 -343
- package/dist/run-SYKj8-Q5.js.map +0 -1
- package/dist/run-YHth5Afz.js.map +0 -1
- package/dist/snapshot-Cilp10vE.js.map +0 -1
- package/dist/snapshot-D_rXnnMH.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { t as __name } from "./rolldown-runtime-CRm0XQPb.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { t as getErrorMessage } from "./errors-DmC83ALX.js";
|
|
3
|
+
import { a as getElapsedMs, i as formatMs, r as version, t as isDisabled } from "./Telemetry-BlAR8vxu.js";
|
|
4
|
+
import { d as withSpinner, g as exists, n as diffFiles, o as readOutputFiles, u as createSpinner, v as read, y as write } from "./utils-Cv3YUnSi.js";
|
|
5
|
+
import { _ as isRichOutput, a as logOutro, c as logBlock, d as logStep, f as logWarn, i as logIntro, l as logError, r as isInteractiveRun, t as pluralize } from "./text-BThr2r0T.js";
|
|
6
|
+
import { a as installSpec, c as toRegistryId, f as wantsMascot, i as incompatibility, l as toShortId, n as closestIds, o as isOutdated, r as fetchRegistryIndex, s as registryUrl, t as bumpOf, u as getBanner } from "./registry-D688-8EH.js";
|
|
7
|
+
import { a as initDefaults, i as KUBB_PACKAGE_NAME, n as findConfigFile, r as KUBB_CONFIG_FILENAME, t as getConfigs } from "./config-Bh00Hwpw.js";
|
|
8
|
+
import { t as logCommandSummary } from "./summary-F11HQput.js";
|
|
5
9
|
import { styleText } from "node:util";
|
|
6
10
|
import dryrun, { pluginId as dryRunId } from "@gunshi/plugin-dryrun";
|
|
7
11
|
import { cli, define, defineWithTypes } from "gunshi";
|
|
@@ -9,8 +13,8 @@ import process$1 from "node:process";
|
|
|
9
13
|
import { x } from "tinyexec";
|
|
10
14
|
import path from "node:path";
|
|
11
15
|
import fs from "node:fs";
|
|
12
|
-
import { Diagnostics, readInstalledPackages } from "@kubb/core";
|
|
13
16
|
import * as clack from "@clack/prompts";
|
|
17
|
+
import { Diagnostics, Hookable, createKubb, readInstalledPackages } from "@kubb/core";
|
|
14
18
|
//#region src/commands/shared.ts
|
|
15
19
|
const configArg = { config: {
|
|
16
20
|
type: "string",
|
|
@@ -108,7 +112,8 @@ function resolveLogLevel({ verbose, silent, logLevel }) {
|
|
|
108
112
|
}
|
|
109
113
|
const command$13 = defineWithTypes()({
|
|
110
114
|
name: "generate",
|
|
111
|
-
|
|
115
|
+
rendering: { header: null },
|
|
116
|
+
description: "Generate types, clients, hooks, and schemas from an OpenAPI specification.",
|
|
112
117
|
examples: [
|
|
113
118
|
"kubb generate # generate from kubb.config.ts",
|
|
114
119
|
"kubb generate ./openapi.yaml # generate from this spec instead of the config input",
|
|
@@ -156,7 +161,7 @@ const command$13 = defineWithTypes()({
|
|
|
156
161
|
async run(ctx) {
|
|
157
162
|
const { values } = ctx;
|
|
158
163
|
const logLevel = resolveLogLevel(values);
|
|
159
|
-
const { run } = await import("./run-
|
|
164
|
+
const { run } = await import("./run-S3xKq4bj.js");
|
|
160
165
|
await run({
|
|
161
166
|
input: values.input,
|
|
162
167
|
configPath: values.config,
|
|
@@ -172,7 +177,7 @@ const command$13 = defineWithTypes()({
|
|
|
172
177
|
/** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/mcp`. */
|
|
173
178
|
const command$12 = define({
|
|
174
179
|
name: "mcp",
|
|
175
|
-
description: "Start
|
|
180
|
+
description: "Start an MCP server for code generation from an AI assistant.",
|
|
176
181
|
examples: [
|
|
177
182
|
"kubb mcp",
|
|
178
183
|
"# Then add to your MCP client config:",
|
|
@@ -180,7 +185,7 @@ const command$12 = define({
|
|
|
180
185
|
].join("\n"),
|
|
181
186
|
rendering: { header: null },
|
|
182
187
|
async run() {
|
|
183
|
-
const { run } = await import("./run-
|
|
188
|
+
const { run } = await import("./run-C1FHgzNR.js");
|
|
184
189
|
await run();
|
|
185
190
|
}
|
|
186
191
|
});
|
|
@@ -195,7 +200,7 @@ function studioCommand({ action, block, ...definition }) {
|
|
|
195
200
|
...definition,
|
|
196
201
|
toKebab: true,
|
|
197
202
|
async run({ values }) {
|
|
198
|
-
const { runStudio } = await import("./run-
|
|
203
|
+
const { runStudio } = await import("./run-B4SKmzAG.js");
|
|
199
204
|
await runStudio(values, action, { block });
|
|
200
205
|
}
|
|
201
206
|
});
|
|
@@ -225,7 +230,7 @@ const command$11 = studioCommand({
|
|
|
225
230
|
},
|
|
226
231
|
block: true,
|
|
227
232
|
async action(options) {
|
|
228
|
-
const { connect } = await import("./run-
|
|
233
|
+
const { connect } = await import("./run-B4SKmzAG.js");
|
|
229
234
|
await connect(options);
|
|
230
235
|
}
|
|
231
236
|
});
|
|
@@ -237,7 +242,7 @@ const command$10 = studioCommand({
|
|
|
237
242
|
examples: ["kubb studio login", "kubb studio login --url http://localhost:3000"].join("\n"),
|
|
238
243
|
args: command$11.args,
|
|
239
244
|
async action(options) {
|
|
240
|
-
const { login } = await import("./run-
|
|
245
|
+
const { login } = await import("./run-B4SKmzAG.js");
|
|
241
246
|
await login(options);
|
|
242
247
|
}
|
|
243
248
|
});
|
|
@@ -249,7 +254,7 @@ const command$9 = studioCommand({
|
|
|
249
254
|
examples: "kubb studio logout",
|
|
250
255
|
args: {},
|
|
251
256
|
async action() {
|
|
252
|
-
const { stopWorker } = await import("./background-
|
|
257
|
+
const { stopWorker } = await import("./background-DUHqYiuQ.js");
|
|
253
258
|
const { clearCredentials } = await import("./credentials-C8tjAhTo.js");
|
|
254
259
|
await stopWorker();
|
|
255
260
|
await clearCredentials();
|
|
@@ -292,7 +297,7 @@ const command$8 = define({
|
|
|
292
297
|
...logLevelArg
|
|
293
298
|
},
|
|
294
299
|
async run(ctx) {
|
|
295
|
-
const { runner } = await import("./snapshot-
|
|
300
|
+
const { runner } = await import("./snapshot-Cvo94y5d.js");
|
|
296
301
|
await runner(ctx);
|
|
297
302
|
}
|
|
298
303
|
});
|
|
@@ -303,7 +308,7 @@ const command$7 = studioCommand({
|
|
|
303
308
|
description: "Keep this project connected to Kubb Studio in the background.",
|
|
304
309
|
args: command$11.args,
|
|
305
310
|
async action(options) {
|
|
306
|
-
const { startWorker } = await import("./background-
|
|
311
|
+
const { startWorker } = await import("./background-DUHqYiuQ.js");
|
|
307
312
|
await startWorker(options);
|
|
308
313
|
}
|
|
309
314
|
});
|
|
@@ -311,7 +316,7 @@ const stopCommand = define({
|
|
|
311
316
|
name: "stop",
|
|
312
317
|
description: "Stop this project's background connection and keep its pairing.",
|
|
313
318
|
async run() {
|
|
314
|
-
const { stopWorker } = await import("./background-
|
|
319
|
+
const { stopWorker } = await import("./background-DUHqYiuQ.js");
|
|
315
320
|
await stopWorker();
|
|
316
321
|
console.log("Background connection stopped.");
|
|
317
322
|
}
|
|
@@ -324,32 +329,21 @@ const command$6 = studioCommand({
|
|
|
324
329
|
examples: "kubb studio status",
|
|
325
330
|
args: { url: studioConnectionArgs.url },
|
|
326
331
|
async action(options) {
|
|
327
|
-
const { getWorkerLogPath, getWorkerStatus } = await import("./background-
|
|
332
|
+
const { getWorkerLogPath, getWorkerStatus } = await import("./background-DUHqYiuQ.js");
|
|
328
333
|
const { readCredentials } = await import("./credentials-C8tjAhTo.js");
|
|
329
|
-
const {
|
|
330
|
-
const worker = await getWorkerStatus();
|
|
331
|
-
console.log(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
console.log(styleText("dim", "No saved permissions for this project. Run `kubb studio` to connect and choose."));
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
console.log(styleText("dim", "Saved permissions"));
|
|
346
|
-
for (const row of formatPermissionRows({
|
|
347
|
-
allowRead: remembered.allowRead === true,
|
|
348
|
-
allowReadAst: remembered.allowReadAst === true,
|
|
349
|
-
allowWrite: remembered.allowWrite === true,
|
|
350
|
-
allowConfigEdit: remembered.allowConfigEdit === true,
|
|
351
|
-
allowExec: remembered.allowExec === true
|
|
352
|
-
})) console.log(row);
|
|
334
|
+
const { formatStatus } = await import("./status-DTsZxa5Y.js");
|
|
335
|
+
const [worker, credentials] = await Promise.all([getWorkerStatus(), readCredentials()]);
|
|
336
|
+
console.log([
|
|
337
|
+
"",
|
|
338
|
+
...formatStatus({
|
|
339
|
+
studioUrl: options.studioUrl,
|
|
340
|
+
credentials,
|
|
341
|
+
worker,
|
|
342
|
+
project: process$1.cwd(),
|
|
343
|
+
logPath: getWorkerLogPath()
|
|
344
|
+
}),
|
|
345
|
+
""
|
|
346
|
+
].join("\n"));
|
|
353
347
|
}
|
|
354
348
|
});
|
|
355
349
|
//#endregion
|
|
@@ -394,16 +388,22 @@ function routeStudioFlags(args) {
|
|
|
394
388
|
/** The runner is imported when the command runs, so listing `kubb --help` never loads `@kubb/adapter-oas`. */
|
|
395
389
|
const command$4 = define({
|
|
396
390
|
name: "validate",
|
|
397
|
-
description: "
|
|
391
|
+
description: "Check a specification with the configured adapter before generating.",
|
|
398
392
|
examples: ["kubb validate ./openapi.yaml", "kubb validate https://petstore3.swagger.io/api/v3/openapi.json"].join("\n"),
|
|
399
|
-
args: {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
393
|
+
args: {
|
|
394
|
+
...configArg,
|
|
395
|
+
input: {
|
|
396
|
+
type: "positional",
|
|
397
|
+
description: "Path or URL to the specification to validate",
|
|
398
|
+
required: true
|
|
399
|
+
}
|
|
400
|
+
},
|
|
404
401
|
async run({ values }) {
|
|
405
|
-
const { run } = await import("./run-
|
|
406
|
-
await run({
|
|
402
|
+
const { run } = await import("./run-Cj-HJxYW.js");
|
|
403
|
+
await run({
|
|
404
|
+
input: values.input,
|
|
405
|
+
configPath: values.config
|
|
406
|
+
});
|
|
407
407
|
}
|
|
408
408
|
});
|
|
409
409
|
//#endregion
|
|
@@ -420,6 +420,8 @@ const DEPRECATED_FLAGS = {
|
|
|
420
420
|
dryRun: "dry-run",
|
|
421
421
|
packageVersion: "package-version"
|
|
422
422
|
};
|
|
423
|
+
/** Flags a single command renamed, rewritten only for that command, since the old name is a common word. */
|
|
424
|
+
const DEPRECATED_COMMAND_FLAGS = { update: { check: "dry-run" } };
|
|
423
425
|
const FLAG_PATTERN = /^--([a-zA-Z][\w-]*)(=.*)?$/;
|
|
424
426
|
/**
|
|
425
427
|
* Rewrites a deprecated camelCase flag to its kebab-case replacement and warns on stderr, so a
|
|
@@ -427,10 +429,11 @@ const FLAG_PATTERN = /^--([a-zA-Z][\w-]*)(=.*)?$/;
|
|
|
427
429
|
* of failing with an unknown-option error.
|
|
428
430
|
*/
|
|
429
431
|
function resolveDeprecatedFlags(args) {
|
|
432
|
+
const commandFlags = DEPRECATED_COMMAND_FLAGS[args[0] ?? ""] ?? {};
|
|
430
433
|
return args.map((arg) => {
|
|
431
434
|
const match = FLAG_PATTERN.exec(arg);
|
|
432
435
|
const name = match?.[1];
|
|
433
|
-
const replacement = name ? DEPRECATED_FLAGS[name] : void 0;
|
|
436
|
+
const replacement = name ? DEPRECATED_FLAGS[name] ?? commandFlags[name] : void 0;
|
|
434
437
|
if (!name || !replacement) return arg;
|
|
435
438
|
console.error(`${styleText("yellow", "Warning:")} --${name} is deprecated, use --${replacement} instead. --${name} will be removed in a future major version.`);
|
|
436
439
|
return `--${replacement}${match?.[2] ?? ""}`;
|
|
@@ -460,25 +463,29 @@ const packageManagers = {
|
|
|
460
463
|
name: "pnpm",
|
|
461
464
|
lockFiles: ["pnpm-lock.yaml"],
|
|
462
465
|
initCommand: ["init"],
|
|
463
|
-
installCommand: ["add", "-D"]
|
|
466
|
+
installCommand: ["add", "-D"],
|
|
467
|
+
runCommand: []
|
|
464
468
|
},
|
|
465
469
|
yarn: {
|
|
466
470
|
name: "yarn",
|
|
467
471
|
lockFiles: ["yarn.lock"],
|
|
468
472
|
initCommand: ["init", "-y"],
|
|
469
|
-
installCommand: ["add", "-D"]
|
|
473
|
+
installCommand: ["add", "-D"],
|
|
474
|
+
runCommand: []
|
|
470
475
|
},
|
|
471
476
|
bun: {
|
|
472
477
|
name: "bun",
|
|
473
478
|
lockFiles: ["bun.lock", "bun.lockb"],
|
|
474
479
|
initCommand: ["init", "-y"],
|
|
475
|
-
installCommand: ["add", "-d"]
|
|
480
|
+
installCommand: ["add", "-d"],
|
|
481
|
+
runCommand: ["run"]
|
|
476
482
|
},
|
|
477
483
|
npm: {
|
|
478
484
|
name: "npm",
|
|
479
485
|
lockFiles: ["package-lock.json"],
|
|
480
486
|
initCommand: ["init", "-y"],
|
|
481
|
-
installCommand: ["install", "--save-dev"]
|
|
487
|
+
installCommand: ["install", "--save-dev"],
|
|
488
|
+
runCommand: ["run"]
|
|
482
489
|
}
|
|
483
490
|
};
|
|
484
491
|
/** Detects the package manager for `cwd`: the `packageManager` field in `package.json`, then a lock file, then `npm`. */
|
|
@@ -506,27 +513,191 @@ async function initPackageJson(cwd, packageManager) {
|
|
|
506
513
|
throwOnError: true
|
|
507
514
|
});
|
|
508
515
|
}
|
|
516
|
+
const INSTALL_TIMEOUT_MS = 3e5;
|
|
509
517
|
/**
|
|
510
|
-
* Installs the given packages at `cwd` using the detected package manager.
|
|
518
|
+
* Installs the given packages at `cwd` using the detected package manager. Each output line goes
|
|
519
|
+
* to `onLine`, so the caller can show it while the install runs; a failed install also keeps the
|
|
520
|
+
* end of the output in the error.
|
|
511
521
|
*/
|
|
512
|
-
async function installPackages(packages, packageManager, cwd = process$1.cwd()) {
|
|
513
|
-
|
|
522
|
+
async function installPackages(packages, packageManager, cwd = process$1.cwd(), onLine) {
|
|
523
|
+
const args = [...packageManager.installCommand, ...packages];
|
|
524
|
+
const result = x(packageManager.name, args, {
|
|
514
525
|
nodeOptions: {
|
|
515
526
|
cwd,
|
|
516
|
-
stdio:
|
|
527
|
+
stdio: [
|
|
528
|
+
"ignore",
|
|
529
|
+
"pipe",
|
|
530
|
+
"pipe"
|
|
531
|
+
]
|
|
517
532
|
},
|
|
518
|
-
|
|
533
|
+
timeout: INSTALL_TIMEOUT_MS,
|
|
534
|
+
throwOnError: false
|
|
519
535
|
});
|
|
536
|
+
const lines = [];
|
|
537
|
+
for await (const line of result) {
|
|
538
|
+
lines.push(line);
|
|
539
|
+
onLine?.(line);
|
|
540
|
+
}
|
|
541
|
+
if (result.exitCode === 0) return;
|
|
542
|
+
if (result.exitCode === void 0) throw new Error(`\`${packageManager.name} ${args.join(" ")}\` timed out after ${INSTALL_TIMEOUT_MS / 6e4} minutes`);
|
|
543
|
+
const output = lines.slice(-20).join("\n");
|
|
544
|
+
throw new Error(`\`${packageManager.name} ${args.join(" ")}\` failed with exit code ${result.exitCode}${output ? `:\n${output}` : ""}`);
|
|
520
545
|
}
|
|
521
546
|
/**
|
|
522
|
-
* What the
|
|
523
|
-
*
|
|
547
|
+
* What the selected plugins' `manifests` say is missing from the selection: a `dependencies`
|
|
548
|
+
* entry, or a `client` plugin next to a `consumer`. Empty when nothing is missing.
|
|
524
549
|
* `optionalDependencies` are skipped, since `kubb init` writes the default options.
|
|
525
550
|
*/
|
|
526
|
-
function missingPluginDependencies(
|
|
551
|
+
function missingPluginDependencies(manifests) {
|
|
552
|
+
const selected = manifests.map((manifest) => manifest.name);
|
|
527
553
|
const hasClient = manifests.some((manifest) => manifest.role === "client");
|
|
528
554
|
return manifests.flatMap((manifest) => [...(manifest.dependencies ?? []).filter((name) => !selected.includes(name)).map((name) => `${manifest.name} needs ${name}.`), ...manifest.role === "consumer" && !hasClient ? [`${manifest.name} needs a client plugin, such as plugin-axios or plugin-fetch.`] : []]);
|
|
529
555
|
}
|
|
556
|
+
async function readPackageJson(cwd) {
|
|
557
|
+
try {
|
|
558
|
+
return JSON.parse(await read(path.join(cwd, "package.json")));
|
|
559
|
+
} catch {
|
|
560
|
+
return {};
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const SPEC_FILE = /^(openapi|swagger)[\w.-]*\.(ya?ml|json)$/i;
|
|
564
|
+
const SKIPPED_DIRS = /* @__PURE__ */ new Set([
|
|
565
|
+
"node_modules",
|
|
566
|
+
"dist",
|
|
567
|
+
"build",
|
|
568
|
+
"coverage"
|
|
569
|
+
]);
|
|
570
|
+
/**
|
|
571
|
+
* Finds OpenAPI spec files up to `depth` folders below `cwd`, shallowest first, as `./`-relative
|
|
572
|
+
* paths. Walks one level at a time and stops after `limit` files, so a large repo stays fast.
|
|
573
|
+
*/
|
|
574
|
+
async function findSpecFiles(cwd, { depth = 3, limit = 20 } = {}) {
|
|
575
|
+
const found = [];
|
|
576
|
+
let level = [""];
|
|
577
|
+
for (let current = 0; current <= depth && level.length && found.length < limit; current++) {
|
|
578
|
+
const listings = await Promise.all(level.map(async (dir) => ({
|
|
579
|
+
dir,
|
|
580
|
+
entries: await fs.promises.readdir(path.join(cwd, dir), { withFileTypes: true }).catch(() => [])
|
|
581
|
+
})));
|
|
582
|
+
level = [];
|
|
583
|
+
for (const { dir, entries } of listings) for (const entry of entries.toSorted((a, b) => a.name.localeCompare(b.name))) {
|
|
584
|
+
if (entry.isFile() && SPEC_FILE.test(entry.name)) found.push(`./${path.posix.join(dir, entry.name)}`);
|
|
585
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && !SKIPPED_DIRS.has(entry.name)) level.push(path.posix.join(dir, entry.name));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return found.slice(0, limit);
|
|
589
|
+
}
|
|
590
|
+
const SPEC_HEAD_BYTES = 262144;
|
|
591
|
+
const METHOD = "(?:get|put|post|delete|options|head|patch|trace)";
|
|
592
|
+
/**
|
|
593
|
+
* Reads the OpenAPI or Swagger version and counts the operations from the first 256 KB of the
|
|
594
|
+
* file, so a large spec is never parsed. The count is left out when the file is longer.
|
|
595
|
+
*/
|
|
596
|
+
async function readSpecInfo(file) {
|
|
597
|
+
const handle = await fs.promises.open(file);
|
|
598
|
+
try {
|
|
599
|
+
const buffer = Buffer.alloc(SPEC_HEAD_BYTES);
|
|
600
|
+
const { bytesRead } = await handle.read(buffer, 0, SPEC_HEAD_BYTES, 0);
|
|
601
|
+
const head = buffer.toString("utf-8", 0, bytesRead);
|
|
602
|
+
const complete = bytesRead < SPEC_HEAD_BYTES;
|
|
603
|
+
const version = head.match(/^\s*["']?(?:openapi|swagger)["']?\s*:\s*["']?(\d[\d.]*)/m)?.[1];
|
|
604
|
+
const methods = new RegExp(`^\\s*["']?${METHOD}["']?\\s*:\\s*(?:\\{|$)`, "gm");
|
|
605
|
+
return {
|
|
606
|
+
version,
|
|
607
|
+
operations: complete ? head.match(methods)?.length ?? 0 : void 0
|
|
608
|
+
};
|
|
609
|
+
} finally {
|
|
610
|
+
await handle.close();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
/** Finds a plugin by registry id, slug, or short name, so `ts`, `plugin-ts`, and `kubb-labs/plugin-ts` all match. */
|
|
614
|
+
function findPlugin({ plugins, id }) {
|
|
615
|
+
const ids = id.includes("/") ? [id] : [`kubb-labs/${id}`, `kubb-labs/plugin-${id}`];
|
|
616
|
+
return plugins.find((entry) => ids.includes(entry.id));
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Turns the comma-separated `--plugins` value into registry entries.
|
|
620
|
+
*
|
|
621
|
+
* @throws when an id is not in `plugins`.
|
|
622
|
+
*/
|
|
623
|
+
function parsePluginsFlag({ plugins, value }) {
|
|
624
|
+
const ids = value.split(",").map((id) => id.trim()).filter(Boolean);
|
|
625
|
+
const unknown = ids.filter((id) => !findPlugin({
|
|
626
|
+
plugins,
|
|
627
|
+
id
|
|
628
|
+
}));
|
|
629
|
+
if (unknown.length) throw new Diagnostics.Error({
|
|
630
|
+
code: Diagnostics.code.pluginNotFound,
|
|
631
|
+
severity: "error",
|
|
632
|
+
message: `Not in the Kubb registry: ${unknown.join(", ")}. Browse the plugins at https://kubb.dev/extensions.`,
|
|
633
|
+
help: "Use plugin ids from https://kubb.dev/extensions, such as plugin-ts or ts."
|
|
634
|
+
});
|
|
635
|
+
return ids.map((id) => findPlugin({
|
|
636
|
+
plugins,
|
|
637
|
+
id
|
|
638
|
+
}));
|
|
639
|
+
}
|
|
640
|
+
/** Adds `"generate": "kubb generate"` to the `package.json` scripts at `cwd`. Returns `false`, and changes nothing, when a `generate` script exists. */
|
|
641
|
+
async function addGenerateScript(cwd) {
|
|
642
|
+
const file = path.join(cwd, "package.json");
|
|
643
|
+
const source = await read(file);
|
|
644
|
+
const packageJson = JSON.parse(source);
|
|
645
|
+
if (packageJson.scripts?.generate !== void 0) return false;
|
|
646
|
+
const indent = source.match(/^[ \t]+/m)?.[0] ?? " ";
|
|
647
|
+
const updated = {
|
|
648
|
+
...packageJson,
|
|
649
|
+
scripts: {
|
|
650
|
+
...packageJson.scripts,
|
|
651
|
+
generate: "kubb generate"
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
await write(file, JSON.stringify(updated, null, indent));
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
/** Reads the `generate` script from the `package.json` at `cwd`. */
|
|
658
|
+
async function generateScript(cwd) {
|
|
659
|
+
return (await readPackageJson(cwd)).scripts?.generate;
|
|
660
|
+
}
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/runners/installWithSpinner.ts
|
|
663
|
+
/** How many package manager lines stay visible under the install title while it runs. */
|
|
664
|
+
const LOG_LINES = 6;
|
|
665
|
+
/**
|
|
666
|
+
* Installs `packages` and reports how long it took. A rich terminal shows the package manager's
|
|
667
|
+
* last lines under the title while the install runs and clears them when it succeeds; a plain one
|
|
668
|
+
* prints the start and end lines. A failed install keeps the output, reports the failure and rethrows.
|
|
669
|
+
*/
|
|
670
|
+
async function installWithSpinner({ packages, names, packageManager, cwd, install = installPackages }) {
|
|
671
|
+
const start = process$1.hrtime();
|
|
672
|
+
const task = createTask(`Installing ${names} with ${packageManager.name}`);
|
|
673
|
+
try {
|
|
674
|
+
await install(packages, packageManager, cwd, task.message);
|
|
675
|
+
} catch (error) {
|
|
676
|
+
task.error("Install failed");
|
|
677
|
+
throw error;
|
|
678
|
+
}
|
|
679
|
+
task.success(`Installed ${names} with ${packageManager.name} in ${formatMs(getElapsedMs(start))}`);
|
|
680
|
+
}
|
|
681
|
+
function createTask(title) {
|
|
682
|
+
if (isRichOutput()) {
|
|
683
|
+
const log = clack.taskLog({
|
|
684
|
+
title,
|
|
685
|
+
limit: LOG_LINES
|
|
686
|
+
});
|
|
687
|
+
return {
|
|
688
|
+
message: (line) => log.message(line),
|
|
689
|
+
error: (text) => log.error(text, { showLog: false }),
|
|
690
|
+
success: (text) => log.success(text)
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const spinner = createSpinner();
|
|
694
|
+
spinner.start(title);
|
|
695
|
+
return {
|
|
696
|
+
message: () => {},
|
|
697
|
+
error: (text) => spinner.error(text),
|
|
698
|
+
success: (text) => spinner.stop(text)
|
|
699
|
+
};
|
|
700
|
+
}
|
|
530
701
|
//#endregion
|
|
531
702
|
//#region src/runners/add/run.ts
|
|
532
703
|
/** The import and the `defineConfig` property to merge into `kubb.config.ts` by hand. */
|
|
@@ -543,55 +714,108 @@ function toSnippet({ artifact, manifest }) {
|
|
|
543
714
|
property[manifest.kind]
|
|
544
715
|
].join("\n");
|
|
545
716
|
}
|
|
546
|
-
/**
|
|
547
|
-
|
|
548
|
-
|
|
717
|
+
/** The `add-plugin` edits for `details`, and the manifests the edits read their export names from. */
|
|
718
|
+
function toConfigEdits(details) {
|
|
719
|
+
return {
|
|
720
|
+
edits: details.map(({ artifact }) => ({
|
|
721
|
+
operation: "add-plugin",
|
|
722
|
+
plugin: artifact.package
|
|
723
|
+
})),
|
|
724
|
+
extensions: new Map(details.map(({ artifact, manifest }) => [artifact.package, {
|
|
725
|
+
package: artifact.package,
|
|
726
|
+
version: artifact.version,
|
|
727
|
+
manifest
|
|
728
|
+
}]))
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
/** The lines adding `details` would put in the config `source`, trimmed, or why it could not add them. */
|
|
732
|
+
async function previewConfig({ details, source }) {
|
|
549
733
|
try {
|
|
550
|
-
const {
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
operation: "add-plugin",
|
|
555
|
-
plugin: artifact.package
|
|
556
|
-
}],
|
|
557
|
-
extensions: /* @__PURE__ */ new Map([[artifact.package, {
|
|
558
|
-
package: artifact.package,
|
|
559
|
-
version: artifact.version,
|
|
560
|
-
manifest
|
|
561
|
-
}]])
|
|
734
|
+
const { applyConfigEdits } = await import("@kubb/studio");
|
|
735
|
+
const result = applyConfigEdits({
|
|
736
|
+
source,
|
|
737
|
+
...toConfigEdits(details)
|
|
562
738
|
});
|
|
563
|
-
|
|
739
|
+
const failed = result.outcomes.find((outcome) => !outcome.applied);
|
|
740
|
+
if (failed) return { reason: failed.reason ?? "the config file was not changed" };
|
|
741
|
+
const remaining = source.split("\n");
|
|
742
|
+
return { lines: result.source.split("\n").filter((line) => {
|
|
743
|
+
const index = remaining.indexOf(line);
|
|
744
|
+
if (index !== -1) remaining.splice(index, 1);
|
|
745
|
+
return index === -1;
|
|
746
|
+
}).map((line) => line.trim()) };
|
|
564
747
|
} catch (error) {
|
|
565
|
-
return getErrorMessage(error);
|
|
748
|
+
return { reason: getErrorMessage(error) };
|
|
566
749
|
}
|
|
567
750
|
}
|
|
568
|
-
async function selectExtension(registry) {
|
|
569
|
-
|
|
570
|
-
value: entry.id,
|
|
571
|
-
label: entry.manifest.displayName,
|
|
572
|
-
hint: `${entry.id} · ${entry.kind} ${entry.artifact.version} · ${entry.manifest.description}`
|
|
573
|
-
}));
|
|
574
|
-
if (!options.length) throw new Diagnostics.Error({
|
|
751
|
+
async function selectExtension({ entries, versions, registry }) {
|
|
752
|
+
if (!entries.length) throw new Diagnostics.Error({
|
|
575
753
|
code: Diagnostics.code.unknown,
|
|
576
754
|
severity: "error",
|
|
577
755
|
message: `The registry at ${registry} lists no extensions.`,
|
|
578
756
|
help: "Check that `KUBB_REGISTRY` points at a Kubb registry, or unset it to use https://kubb.dev/registry."
|
|
579
757
|
});
|
|
758
|
+
const searchText = new Map(entries.map((entry) => [entry.id, `${entry.id} ${entry.manifest.displayName} ${entry.manifest.description}`.toLowerCase()]));
|
|
759
|
+
const options = entries.toSorted((a, b) => a.id.localeCompare(b.id)).map((entry) => {
|
|
760
|
+
const installed = versions.has(entry.artifact.package);
|
|
761
|
+
return {
|
|
762
|
+
value: entry.id,
|
|
763
|
+
label: toShortId(entry.id),
|
|
764
|
+
hint: installed ? "installed" : summarize(entry.manifest.description),
|
|
765
|
+
disabled: installed
|
|
766
|
+
};
|
|
767
|
+
});
|
|
580
768
|
const id = await clack.autocomplete({
|
|
581
|
-
message:
|
|
769
|
+
message: `Add an extension · ${entries.length} in the registry`,
|
|
770
|
+
placeholder: "Search",
|
|
582
771
|
options,
|
|
583
|
-
filter: (search, option) =>
|
|
772
|
+
filter: (search, option) => searchText.get(option.value)?.includes(search.toLowerCase()) ?? false
|
|
584
773
|
});
|
|
585
774
|
return clack.isCancel(id) ? void 0 : id;
|
|
586
775
|
}
|
|
776
|
+
/** Asks whether to also add the required plugins the config lacks. `--yes` adds them. */
|
|
777
|
+
async function confirmDependencies({ entry, missing, yes }) {
|
|
778
|
+
if (!missing.length || yes) return true;
|
|
779
|
+
const names = missing.map((dependency) => dependency.manifest.name).join(", ");
|
|
780
|
+
const answer = await clack.select({
|
|
781
|
+
message: `${entry.manifest.name} needs ${names}. Add ${names} as well?`,
|
|
782
|
+
options: [{
|
|
783
|
+
value: true,
|
|
784
|
+
label: `Yes, add ${missing.length === 1 ? "both" : "all"}`,
|
|
785
|
+
hint: "recommended"
|
|
786
|
+
}, {
|
|
787
|
+
value: false,
|
|
788
|
+
label: `Only ${entry.manifest.name}`,
|
|
789
|
+
hint: "generate fails until you add it"
|
|
790
|
+
}],
|
|
791
|
+
initialValue: true
|
|
792
|
+
});
|
|
793
|
+
return clack.isCancel(answer) ? void 0 : answer;
|
|
794
|
+
}
|
|
795
|
+
/** The first sentence of a registry description, cut to one terminal line. */
|
|
796
|
+
function summarize(description, max = 64) {
|
|
797
|
+
const sentence = description.split(/\.\s/)[0].replace(/\.$/, "");
|
|
798
|
+
return sentence.length > max ? `${sentence.slice(0, max - 1).trimEnd()}…` : sentence;
|
|
799
|
+
}
|
|
587
800
|
/**
|
|
588
801
|
* Installs an extension from the Kubb registry at its reviewed version and, for a plugin, adds it to
|
|
589
|
-
* `kubb.config.ts
|
|
590
|
-
*
|
|
802
|
+
* `kubb.config.ts`, offering to add the plugins it needs as well. Without an id, asks which one.
|
|
803
|
+
* Previews the packages and config lines before asking. Refuses when the running Kubb or Node.js
|
|
804
|
+
* version is outside its compatibility.
|
|
591
805
|
*/
|
|
592
806
|
async function run$4({ id: input, configPath, yes, install }) {
|
|
593
807
|
const cwd = process$1.cwd();
|
|
594
|
-
|
|
808
|
+
const hrStart = process$1.hrtime();
|
|
809
|
+
const summary = (title, status, lines) => logCommandSummary({
|
|
810
|
+
title,
|
|
811
|
+
status,
|
|
812
|
+
hrStart,
|
|
813
|
+
block: true,
|
|
814
|
+
lines
|
|
815
|
+
});
|
|
816
|
+
const installedPackages = [];
|
|
817
|
+
const configured = [];
|
|
818
|
+
logIntro({ title: isInteractiveRun({ yes }) ? void 0 : styleText("bgCyan", styleText("black", " Kubb Add ")) });
|
|
595
819
|
try {
|
|
596
820
|
const registry = registryUrl();
|
|
597
821
|
if (!input && yes) throw new Diagnostics.Error({
|
|
@@ -600,16 +824,38 @@ async function run$4({ id: input, configPath, yes, install }) {
|
|
|
600
824
|
message: "Pass a registry id, such as plugin-zod, when using --yes.",
|
|
601
825
|
help: "Run `kubb add plugin-zod --yes`, or drop `--yes` to pick from a list."
|
|
602
826
|
});
|
|
603
|
-
const
|
|
827
|
+
const inputId = input ? toRegistryId(input) : void 0;
|
|
828
|
+
const foundConfig = configPath ? path.resolve(configPath) : findConfigFile(cwd);
|
|
829
|
+
const [entries, installed, configSource] = await withSpinner({
|
|
830
|
+
message: "Reading the registry",
|
|
831
|
+
promise: Promise.all([
|
|
832
|
+
fetchRegistryIndex({ registry }),
|
|
833
|
+
readInstalledPackages({ root: cwd }),
|
|
834
|
+
foundConfig ? read(foundConfig).catch(() => void 0) : void 0
|
|
835
|
+
])
|
|
836
|
+
});
|
|
837
|
+
const versions = new Map(installed.map((item) => [item.package, item.version]));
|
|
838
|
+
const id = inputId ?? await selectExtension({
|
|
839
|
+
entries,
|
|
840
|
+
versions,
|
|
841
|
+
registry
|
|
842
|
+
});
|
|
604
843
|
if (!id) {
|
|
605
|
-
|
|
844
|
+
summary("Add canceled", "canceled", [" No changes made"]);
|
|
606
845
|
return;
|
|
607
846
|
}
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
847
|
+
const entry = entries.find((candidate) => candidate.id === id);
|
|
848
|
+
if (!entry) {
|
|
849
|
+
const suggestions = closestIds({
|
|
850
|
+
input: id,
|
|
851
|
+
ids: entries.map((entry) => entry.id)
|
|
852
|
+
}).map(toShortId);
|
|
853
|
+
summary(`No extension named ${input ?? id}`, "failed", [...suggestions.map((suggestion) => ` kubb add ${suggestion}`), " Browse all kubb.dev/extensions"]);
|
|
854
|
+
process$1.exitCode = 1;
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
const { artifact, manifest } = entry;
|
|
858
|
+
const kind = manifest.kind.charAt(0).toUpperCase() + manifest.kind.slice(1);
|
|
613
859
|
const problem = incompatibility(manifest);
|
|
614
860
|
if (problem) throw new Diagnostics.Error({
|
|
615
861
|
code: Diagnostics.code.incompatibleExtension,
|
|
@@ -617,53 +863,108 @@ async function run$4({ id: input, configPath, yes, install }) {
|
|
|
617
863
|
message: problem,
|
|
618
864
|
help: "Upgrade Kubb or Node.js to a version the extension supports."
|
|
619
865
|
});
|
|
620
|
-
const
|
|
621
|
-
const configFile = manifest.kind === "plugin" ? configPath ? path.resolve(configPath) : findConfigFile(cwd) : void 0;
|
|
866
|
+
const configFile = manifest.kind === "plugin" ? foundConfig : void 0;
|
|
622
867
|
if (manifest.kind === "plugin" && !configFile) throw new Diagnostics.Error({
|
|
623
868
|
code: Diagnostics.code.unknown,
|
|
624
869
|
severity: "error",
|
|
625
870
|
message: "No kubb.config.ts found. Run `kubb init` first, or pass --config.",
|
|
626
871
|
help: "Run `kubb init` to create a config, or pass its path with `--config`."
|
|
627
872
|
});
|
|
628
|
-
|
|
629
|
-
|
|
873
|
+
const configName = configFile ? path.relative(cwd, configFile) || configFile : void 0;
|
|
874
|
+
const byName = new Map(entries.map((candidate) => [candidate.manifest.name, candidate]));
|
|
875
|
+
const inConfig = (name) => {
|
|
876
|
+
const dependency = byName.get(name);
|
|
877
|
+
return dependency ? !!configSource?.includes(`${dependency.manifest.export}(`) : installed.some((item) => item.manifest?.name === name);
|
|
878
|
+
};
|
|
879
|
+
const dependencies = manifest.dependencies ?? [];
|
|
880
|
+
const missing = configFile ? dependencies.filter((name) => !inConfig(name)).flatMap((name) => byName.get(name) ?? []) : [];
|
|
881
|
+
const withDependencies = await confirmDependencies({
|
|
882
|
+
entry,
|
|
883
|
+
missing,
|
|
884
|
+
yes
|
|
885
|
+
});
|
|
886
|
+
if (withDependencies === void 0) {
|
|
887
|
+
summary("Add canceled", "canceled", [` ${kind} ${manifest.name}`, " No changes made"]);
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const targets = [...withDependencies ? missing : [], entry];
|
|
891
|
+
const specs = targets.filter((target) => target === entry || !versions.has(target.artifact.package)).map((target) => installSpec(target.artifact));
|
|
892
|
+
const dependencyStatus = (name) => {
|
|
893
|
+
if (inConfig(name)) return `${name} ${styleText("green", "✓ installed")}`;
|
|
894
|
+
return targets.some((target) => target.manifest.name === name) ? `${name} ${styleText("cyan", "+ adding")}` : `${name} ${styleText("yellow", "missing")}`;
|
|
895
|
+
};
|
|
896
|
+
const preview = configFile && configSource !== void 0 ? await previewConfig({
|
|
897
|
+
details: targets,
|
|
898
|
+
source: configSource
|
|
899
|
+
}) : void 0;
|
|
900
|
+
logStep(`${kind} ${styleText("cyan", manifest.name)} v${artifact.version} · ${summarize(manifest.description)}`);
|
|
901
|
+
logBlock([
|
|
902
|
+
...dependencies.length ? [`Needs ${dependencies.map(dependencyStatus).join(" ")}`] : [],
|
|
903
|
+
install ? `Installs ${specs.join(" ")}` : "Installs nothing (--no-install)",
|
|
904
|
+
...configName ? [`Config ${configName}`] : [`Config prints the ${manifest.kind} snippet to add`],
|
|
905
|
+
...preview && "lines" in preview ? preview.lines.map((line) => styleText("green", ` + ${line}`)) : [],
|
|
906
|
+
...preview && "reason" in preview ? [styleText("yellow", ` cannot edit it: ${preview.reason}`)] : []
|
|
907
|
+
]);
|
|
630
908
|
const confirmed = yes || await clack.confirm({
|
|
631
|
-
message: "
|
|
909
|
+
message: "Add it?",
|
|
632
910
|
initialValue: true
|
|
633
911
|
});
|
|
634
912
|
if (clack.isCancel(confirmed) || !confirmed) {
|
|
635
|
-
|
|
913
|
+
summary("Add canceled", "canceled", [` ${kind} ${manifest.name}`, " No changes made"]);
|
|
636
914
|
return;
|
|
637
915
|
}
|
|
916
|
+
const packageManager = detectPackageManager(cwd);
|
|
917
|
+
const packages = () => install ? `${installedPackages.length} installed with ${packageManager.name}` : "installation skipped (--no-install)";
|
|
638
918
|
if (install) {
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
919
|
+
const names = targets.filter((target) => specs.includes(installSpec(target.artifact))).map((target) => target.artifact.package);
|
|
920
|
+
await installWithSpinner({
|
|
921
|
+
packages: specs,
|
|
922
|
+
names: names.join(", "),
|
|
923
|
+
packageManager,
|
|
924
|
+
cwd
|
|
925
|
+
});
|
|
926
|
+
installedPackages.push(...names);
|
|
642
927
|
}
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
928
|
+
const unconfigured = configFile ? [] : [entry];
|
|
929
|
+
if (configFile) for (const target of targets) try {
|
|
930
|
+
const { writeConfigEdits } = await import("@kubb/studio");
|
|
931
|
+
const { outcomes, changed } = await writeConfigEdits({
|
|
932
|
+
filePath: configFile,
|
|
933
|
+
...toConfigEdits([target])
|
|
934
|
+
});
|
|
935
|
+
if (!outcomes[0]?.applied) throw new Error(outcomes[0]?.reason ?? "the config file was not changed");
|
|
936
|
+
if (changed) configured.push(target);
|
|
937
|
+
logStep(`${target.manifest.export}() configured in ${configName}`);
|
|
938
|
+
} catch (error) {
|
|
939
|
+
logWarn(`Could not edit ${configName}: ${getErrorMessage(error)}`);
|
|
940
|
+
unconfigured.push(target);
|
|
650
941
|
}
|
|
651
|
-
|
|
652
|
-
logBlock([
|
|
942
|
+
const manual = unconfigured.length > 0;
|
|
943
|
+
if (manual) logBlock([
|
|
653
944
|
"Add the import to your Kubb config and merge the property into its defineConfig call:",
|
|
654
945
|
"",
|
|
655
|
-
toSnippet(
|
|
946
|
+
...unconfigured.map((target) => toSnippet(target))
|
|
947
|
+
]);
|
|
948
|
+
const dependenciesMissing = !withDependencies && missing.length > 0;
|
|
949
|
+
summary(manual ? `${kind} needs configuration` : dependenciesMissing ? "Plugin configured; dependencies missing" : configured.length ? install ? "Plugin ready" : "Plugin configured" : "Plugin already configured", manual || dependenciesMissing ? "warning" : "success", [
|
|
950
|
+
` Packages ${packages()}`,
|
|
951
|
+
...configured.map((target) => styleText("green", ` + ${target.manifest.export}()`)),
|
|
952
|
+
"",
|
|
953
|
+
...!install ? [`Install ${specs.join(" ")} to use it.`] : [],
|
|
954
|
+
...dependenciesMissing ? [`Missing plugins ${missing.map((target) => target.manifest.name).join(", ")}`] : [],
|
|
955
|
+
manual ? "Add the snippet above, then run kubb generate." : "Next kubb generate",
|
|
956
|
+
`Options kubb.dev/extensions/${entry.id}`
|
|
656
957
|
]);
|
|
657
|
-
logOutro(styleText("green", install ? `Installed ${spec}. Add it with the snippet above.` : `Install ${spec} and add the snippet above.`));
|
|
658
958
|
} catch (error) {
|
|
659
959
|
logError(getErrorMessage(error));
|
|
960
|
+
summary("Add failed", "failed", installedPackages.length ? [` Packages ${installedPackages.join(", ")} installed`] : [" No changes made"]);
|
|
660
961
|
process$1.exitCode = 1;
|
|
661
962
|
}
|
|
662
963
|
}
|
|
663
964
|
__name(run$4, "run");
|
|
664
965
|
const command$3 = define({
|
|
665
966
|
name: "add",
|
|
666
|
-
description: "
|
|
967
|
+
description: "Find and install plugins, adapters, and parsers from the Kubb registry.",
|
|
667
968
|
examples: [
|
|
668
969
|
"kubb add",
|
|
669
970
|
"kubb add plugin-zod",
|
|
@@ -700,154 +1001,300 @@ function cancelAndExit(message = "Operation canceled.") {
|
|
|
700
1001
|
clack.cancel(message);
|
|
701
1002
|
process$1.exit(0);
|
|
702
1003
|
}
|
|
1004
|
+
function unwrap(value) {
|
|
1005
|
+
if (clack.isCancel(value)) cancelAndExit();
|
|
1006
|
+
return value;
|
|
1007
|
+
}
|
|
1008
|
+
/** The full `kubb.config.ts` for `choices`, with each plugin added the way `kubb add` adds it. */
|
|
1009
|
+
async function buildConfig({ inputPath, outputPath, plugins }) {
|
|
1010
|
+
const { applyConfigEdits } = await import("@kubb/studio");
|
|
1011
|
+
const { source, outcomes } = applyConfigEdits({
|
|
1012
|
+
source: generateConfigFile({
|
|
1013
|
+
inputPath,
|
|
1014
|
+
outputPath
|
|
1015
|
+
}),
|
|
1016
|
+
edits: plugins.map((entry) => ({
|
|
1017
|
+
operation: "add-plugin",
|
|
1018
|
+
plugin: entry.artifact.package
|
|
1019
|
+
})),
|
|
1020
|
+
extensions: new Map(plugins.map(({ artifact, manifest }) => [artifact.package, {
|
|
1021
|
+
package: artifact.package,
|
|
1022
|
+
version: artifact.version,
|
|
1023
|
+
manifest
|
|
1024
|
+
}]))
|
|
1025
|
+
});
|
|
1026
|
+
const failed = outcomes.find((outcome) => !outcome.applied);
|
|
1027
|
+
if (failed && failed.edit.operation === "add-plugin") throw new Diagnostics.Error({
|
|
1028
|
+
code: Diagnostics.code.unknown,
|
|
1029
|
+
severity: "error",
|
|
1030
|
+
message: `Could not add ${failed.edit.plugin} to ${KUBB_CONFIG_FILENAME}: ${failed.reason}`,
|
|
1031
|
+
help: `Run kubb init without that plugin, then add it with kubb add.`
|
|
1032
|
+
});
|
|
1033
|
+
return source;
|
|
1034
|
+
}
|
|
1035
|
+
/** Generates from the config at `configPath` without reporters, and returns how many files it wrote. */
|
|
1036
|
+
async function firstRun(configPath) {
|
|
1037
|
+
const { configs } = await getConfigs({ configPath });
|
|
1038
|
+
let files = 0;
|
|
1039
|
+
for (const config of configs) {
|
|
1040
|
+
const result = await createKubb(config).generate();
|
|
1041
|
+
if (!result.success) throw new Error(result.diagnostics.flatMap((diagnostic) => diagnostic.severity === "error" ? [diagnostic.message] : []).join("\n"));
|
|
1042
|
+
files += result.files.length;
|
|
1043
|
+
}
|
|
1044
|
+
return files;
|
|
1045
|
+
}
|
|
1046
|
+
/** The command that runs `kubb generate`: the `generate` script when it runs Kubb, otherwise `npx kubb generate`. */
|
|
1047
|
+
function generateCommand({ packageManager, script, watch }) {
|
|
1048
|
+
if (script !== "kubb generate") return `npx kubb generate${watch ? " --watch" : ""}`;
|
|
1049
|
+
const run = [
|
|
1050
|
+
packageManager.name,
|
|
1051
|
+
...packageManager.runCommand,
|
|
1052
|
+
"generate"
|
|
1053
|
+
].join(" ");
|
|
1054
|
+
if (!watch) return run;
|
|
1055
|
+
return packageManager.name === "npm" ? `${run} -- --watch` : `${run} --watch`;
|
|
1056
|
+
}
|
|
703
1057
|
/**
|
|
704
|
-
* Runs the
|
|
705
|
-
*
|
|
706
|
-
*
|
|
1058
|
+
* Runs the Kubb setup wizard: detects the package manager and specs, asks for the spec, plugins, and
|
|
1059
|
+
* output folder, shows the config for review, then installs, writes `kubb.config.ts`, adds a
|
|
1060
|
+
* `generate` script, and runs the first generation.
|
|
1061
|
+
* Pass `yes: true` to skip all prompts and print one line per step.
|
|
707
1062
|
*/
|
|
708
1063
|
async function run$3({ yes, input: inputFlag, output: outputFlag, plugins: pluginsFlag, dryRun }) {
|
|
709
1064
|
const cwd = process$1.cwd();
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
return
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
return defaultValue;
|
|
1065
|
+
/** Runs `task` behind a spinner, or prints one line when it is done in `--yes` mode. */
|
|
1066
|
+
async function step({ start, task, done, failed }) {
|
|
1067
|
+
const spinner = createSpinner();
|
|
1068
|
+
if (!yes) spinner.start(start);
|
|
1069
|
+
try {
|
|
1070
|
+
const result = await task();
|
|
1071
|
+
if (yes) console.log(`${styleText("green", "✓")} ${done(result)}`);
|
|
1072
|
+
else spinner.stop(done(result));
|
|
1073
|
+
return result;
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
if (!yes) spinner.error(failed);
|
|
1076
|
+
throw error;
|
|
723
1077
|
}
|
|
724
|
-
const result = await prompt();
|
|
725
|
-
if (clack.isCancel(result)) cancelAndExit();
|
|
726
|
-
return result;
|
|
727
1078
|
}
|
|
1079
|
+
if (!yes) logIntro({ title: isInteractiveRun({
|
|
1080
|
+
yes,
|
|
1081
|
+
dryRun: dryRun.enabled
|
|
1082
|
+
}) ? void 0 : "Set up Kubb" });
|
|
728
1083
|
try {
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
if (!
|
|
1084
|
+
const registry = fetchRegistryIndex({ registry: registryUrl() }).then((entries) => entries.filter((entry) => entry.kind === "plugin" && !incompatibility(entry.manifest)));
|
|
1085
|
+
registry.catch(() => {});
|
|
1086
|
+
if (!yes) import("@kubb/studio").catch(() => {});
|
|
1087
|
+
if (!await exists(path.join(cwd, "package.json"))) {
|
|
732
1088
|
if (!yes) {
|
|
733
|
-
|
|
1089
|
+
if (!unwrap(await clack.confirm({
|
|
734
1090
|
message: "No package.json found. Would you like to create one?",
|
|
735
1091
|
initialValue: true
|
|
736
|
-
});
|
|
737
|
-
if (clack.isCancel(shouldInit) || !shouldInit) cancelAndExit();
|
|
1092
|
+
}))) cancelAndExit();
|
|
738
1093
|
}
|
|
739
1094
|
const packageManager = detectPackageManager(cwd);
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1095
|
+
await step({
|
|
1096
|
+
start: `Initializing package.json with ${packageManager.name}`,
|
|
1097
|
+
task: () => initPackageJson(cwd, packageManager),
|
|
1098
|
+
done: () => `Created package.json with ${packageManager.name}`,
|
|
1099
|
+
failed: "Could not create package.json"
|
|
1100
|
+
});
|
|
744
1101
|
}
|
|
745
1102
|
const packageManager = detectPackageManager(cwd);
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
defaultValue: initDefaults.outputPath,
|
|
759
|
-
validate: (value) => {
|
|
760
|
-
if (!value) return "Output path is required";
|
|
761
|
-
}
|
|
762
|
-
}));
|
|
763
|
-
const defaultPlugins = initDefaults.plugins.flatMap((slug) => byId.get(toRegistryId(slug)) ?? []);
|
|
764
|
-
const pluginLabel = (entries) => styleText("cyan", entries.map((entry) => entry.manifest.displayName).join(", "));
|
|
765
|
-
const selectedPlugins = await (async () => {
|
|
766
|
-
if (pluginsFlag) {
|
|
767
|
-
const ids = pluginsFlag.split(",").map((id) => id.trim()).filter(Boolean);
|
|
768
|
-
const unknown = ids.filter((id) => !byId.has(toRegistryId(id)));
|
|
769
|
-
if (unknown.length) throw new Diagnostics.Error({
|
|
770
|
-
code: Diagnostics.code.pluginNotFound,
|
|
771
|
-
severity: "error",
|
|
772
|
-
message: `Not in the Kubb registry: ${unknown.join(", ")}. Browse the plugins at https://kubb.dev/extensions.`,
|
|
773
|
-
help: "Use plugin ids from https://kubb.dev/extensions, such as plugin-ts."
|
|
774
|
-
});
|
|
775
|
-
const entries = ids.map((id) => byId.get(toRegistryId(id)));
|
|
776
|
-
logInfo(`Using plugins: ${pluginLabel(entries)}`);
|
|
777
|
-
return entries;
|
|
778
|
-
}
|
|
779
|
-
if (yes) {
|
|
780
|
-
logInfo(`Using plugins: ${pluginLabel(defaultPlugins)}`);
|
|
781
|
-
return defaultPlugins;
|
|
1103
|
+
const specs = await findSpecFiles(cwd);
|
|
1104
|
+
if (!yes) {
|
|
1105
|
+
logStep(`Package manager ${packageManager.name}`);
|
|
1106
|
+
if (specs[0]) {
|
|
1107
|
+
const { version: specVersion, operations } = await readSpecInfo(path.join(cwd, specs[0]));
|
|
1108
|
+
const details = [
|
|
1109
|
+
specs[0].slice(2),
|
|
1110
|
+
specVersion ? `${specVersion.startsWith("2") ? "Swagger" : "OpenAPI"} ${specVersion}` : void 0,
|
|
1111
|
+
operations === void 0 ? void 0 : pluralize(operations, "operation"),
|
|
1112
|
+
specs.length > 1 ? `+${specs.length - 1} more` : void 0
|
|
1113
|
+
];
|
|
1114
|
+
logStep(`Found ${details.filter(Boolean).join(" · ")}`);
|
|
782
1115
|
}
|
|
783
|
-
|
|
784
|
-
|
|
1116
|
+
}
|
|
1117
|
+
const plugins = pluginsFlag || yes ? await registry : void 0;
|
|
1118
|
+
const defaultPlugins = (entries) => initDefaults.plugins.flatMap((id) => findPlugin({
|
|
1119
|
+
plugins: entries,
|
|
1120
|
+
id
|
|
1121
|
+
}) ?? []);
|
|
1122
|
+
const flagPlugins = pluginsFlag && plugins ? parsePluginsFlag({
|
|
1123
|
+
plugins,
|
|
1124
|
+
value: pluginsFlag
|
|
1125
|
+
}) : void 0;
|
|
1126
|
+
let choices = {
|
|
1127
|
+
inputPath: inputFlag ?? specs[0] ?? initDefaults.inputPath,
|
|
1128
|
+
outputPath: outputFlag ?? initDefaults.outputPath,
|
|
1129
|
+
plugins: flagPlugins ?? (plugins ? defaultPlugins(plugins) : [])
|
|
1130
|
+
};
|
|
1131
|
+
if (yes && !choices.plugins.length) throw new Error("The registry has no default plugin. Pass --plugins to choose one.");
|
|
1132
|
+
async function askInput(current) {
|
|
1133
|
+
const choice = specs.length ? unwrap(await clack.select({
|
|
1134
|
+
message: "Which spec should Kubb read?",
|
|
1135
|
+
options: [
|
|
1136
|
+
...specs.map((spec) => ({
|
|
1137
|
+
value: spec,
|
|
1138
|
+
label: spec,
|
|
1139
|
+
hint: "found in this repo"
|
|
1140
|
+
})),
|
|
1141
|
+
{
|
|
1142
|
+
value: "url",
|
|
1143
|
+
label: "A URL"
|
|
1144
|
+
},
|
|
1145
|
+
{
|
|
1146
|
+
value: "file",
|
|
1147
|
+
label: "Another file"
|
|
1148
|
+
}
|
|
1149
|
+
],
|
|
1150
|
+
initialValue: specs.includes(current) ? current : /^https?:\/\//.test(current) ? "url" : "file"
|
|
1151
|
+
})) : /^https?:\/\//.test(current) ? "url" : "file";
|
|
1152
|
+
if (specs.includes(choice)) return choice;
|
|
1153
|
+
const isUrl = choice === "url";
|
|
1154
|
+
const initial = isUrl === /^https?:\/\//.test(current) && !specs.includes(current) ? current : void 0;
|
|
1155
|
+
return unwrap(await clack.text({
|
|
1156
|
+
message: isUrl ? "Spec URL" : "Spec path",
|
|
1157
|
+
placeholder: isUrl ? "https://example.com/openapi.yaml" : initDefaults.inputPath,
|
|
1158
|
+
initialValue: initial,
|
|
1159
|
+
defaultValue: isUrl ? void 0 : initDefaults.inputPath,
|
|
1160
|
+
validate: (value) => {
|
|
1161
|
+
if (isUrl && !/^https?:\/\//.test(value ?? "")) return "Enter an http(s) URL";
|
|
1162
|
+
}
|
|
1163
|
+
}));
|
|
1164
|
+
}
|
|
1165
|
+
async function askPlugins(previous) {
|
|
1166
|
+
const plugins = await registry;
|
|
1167
|
+
const current = previous.length ? previous : defaultPlugins(plugins);
|
|
1168
|
+
const width = Math.max(...plugins.map((entry) => entry.manifest.displayName.length));
|
|
1169
|
+
const nameWidth = Math.max(...plugins.map((entry) => entry.manifest.name.length));
|
|
1170
|
+
const values = unwrap(await clack.multiselect({
|
|
1171
|
+
message: "What should Kubb generate?",
|
|
785
1172
|
options: plugins.map(({ id, manifest }) => ({
|
|
786
1173
|
value: id,
|
|
787
|
-
label: manifest.displayName,
|
|
788
|
-
hint: manifest.category
|
|
1174
|
+
label: `${manifest.displayName.padEnd(width)} ${styleText("dim", manifest.name.padEnd(nameWidth))}`.trimEnd()
|
|
789
1175
|
})),
|
|
790
|
-
initialValues:
|
|
1176
|
+
initialValues: current.map((entry) => entry.id),
|
|
791
1177
|
required: true
|
|
792
|
-
});
|
|
793
|
-
if (clack.isCancel(values)) cancelAndExit();
|
|
1178
|
+
}));
|
|
794
1179
|
return plugins.filter((entry) => values.includes(entry.id));
|
|
795
|
-
}
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1180
|
+
}
|
|
1181
|
+
const answered = yes || Boolean(inputFlag && outputFlag && pluginsFlag);
|
|
1182
|
+
if (!answered) {
|
|
1183
|
+
let firstPass = true;
|
|
1184
|
+
while (true) {
|
|
1185
|
+
choices = {
|
|
1186
|
+
inputPath: firstPass && inputFlag ? inputFlag : await askInput(choices.inputPath),
|
|
1187
|
+
plugins: firstPass && flagPlugins ? flagPlugins : await askPlugins(choices.plugins),
|
|
1188
|
+
outputPath: firstPass && outputFlag ? outputFlag : unwrap(await clack.text({
|
|
1189
|
+
message: "Output folder",
|
|
1190
|
+
placeholder: choices.outputPath,
|
|
1191
|
+
defaultValue: choices.outputPath
|
|
1192
|
+
}))
|
|
1193
|
+
};
|
|
1194
|
+
firstPass = false;
|
|
1195
|
+
const missing = missingPluginDependencies(choices.plugins.map((entry) => entry.manifest));
|
|
1196
|
+
if (missing.length) {
|
|
1197
|
+
logWarn(`${missing.join("\n")}\nAdd the missing plugins.`);
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
const config = await buildConfig(choices);
|
|
1201
|
+
const packages = [KUBB_PACKAGE_NAME, ...choices.plugins.map((entry) => entry.artifact.package)];
|
|
1202
|
+
logStep(`Review ${KUBB_CONFIG_FILENAME}`);
|
|
1203
|
+
logBlock([
|
|
1204
|
+
...config.trimEnd().split("\n"),
|
|
1205
|
+
"",
|
|
1206
|
+
`${styleText("dim", "Installs")} ${packages.join(" ")} with ${packageManager.name}`
|
|
1207
|
+
]);
|
|
1208
|
+
const configExists = await exists(path.join(cwd, KUBB_CONFIG_FILENAME));
|
|
1209
|
+
if (unwrap(await clack.select({
|
|
1210
|
+
message: configExists ? `kubb.config.ts exists. Overwrite it?` : "Create it?",
|
|
1211
|
+
options: [{
|
|
1212
|
+
value: true,
|
|
1213
|
+
label: "Yes"
|
|
1214
|
+
}, {
|
|
1215
|
+
value: false,
|
|
1216
|
+
label: "Change a choice"
|
|
1217
|
+
}]
|
|
1218
|
+
}))) break;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
const missing = missingPluginDependencies(choices.plugins.map((entry) => entry.manifest));
|
|
800
1222
|
if (missing.length) throw new Diagnostics.Error({
|
|
801
1223
|
code: Diagnostics.code.missingDependency,
|
|
802
1224
|
severity: "error",
|
|
803
1225
|
message: `${missing.join("\n")}\nAdd the missing plugins and run kubb init again.`
|
|
804
1226
|
});
|
|
805
|
-
const packagesToInstall = [`${KUBB_PACKAGE_NAME}@${version}`, ...selectedPlugins.map((entry) => installSpec(entry.artifact))];
|
|
806
|
-
const spinner = createSpinner();
|
|
807
|
-
spinner.start(`Installing ${packagesToInstall.length} packages with ${packageManager.name}`);
|
|
808
|
-
try {
|
|
809
|
-
await dryRun.run(() => installPackages(packagesToInstall, packageManager, cwd), { message: `install ${packagesToInstall.length} packages with ${packageManager.name}` });
|
|
810
|
-
spinner.stop(`Installed ${packagesToInstall.length} packages`);
|
|
811
|
-
} catch (error) {
|
|
812
|
-
spinner.stop("Installation failed");
|
|
813
|
-
throw error;
|
|
814
|
-
}
|
|
815
|
-
const configSpinner = createSpinner();
|
|
816
|
-
configSpinner.start(`Creating ${KUBB_CONFIG_FILENAME}`);
|
|
817
|
-
const configContent = generateConfigFile({
|
|
818
|
-
inputPath,
|
|
819
|
-
outputPath
|
|
820
|
-
});
|
|
821
1227
|
const configPath = path.join(cwd, KUBB_CONFIG_FILENAME);
|
|
822
|
-
if (
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
initialValue: false
|
|
828
|
-
});
|
|
829
|
-
if (clack.isCancel(shouldOverwrite) || !shouldOverwrite) cancelAndExit("Keeping existing configuration. Packages have been installed.");
|
|
830
|
-
}
|
|
831
|
-
configSpinner.start(`Overwriting ${KUBB_CONFIG_FILENAME}`);
|
|
1228
|
+
if (answered && !yes && await exists(configPath)) {
|
|
1229
|
+
if (!unwrap(await clack.confirm({
|
|
1230
|
+
message: `kubb.config.ts exists. Overwrite it?`,
|
|
1231
|
+
initialValue: false
|
|
1232
|
+
}))) cancelAndExit("Keeping existing configuration.");
|
|
832
1233
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1234
|
+
const packagesToInstall = [`${KUBB_PACKAGE_NAME}@${version}`, ...choices.plugins.map((entry) => installSpec(entry.artifact))];
|
|
1235
|
+
const packageNames = [KUBB_PACKAGE_NAME, ...choices.plugins.map((entry) => entry.artifact.package)];
|
|
1236
|
+
const dry = { message: `install ${packagesToInstall.length} packages with ${packageManager.name}` };
|
|
1237
|
+
if (yes) await step({
|
|
1238
|
+
start: "",
|
|
1239
|
+
task: async () => void await dryRun.run(() => installPackages(packagesToInstall, packageManager, cwd), dry),
|
|
1240
|
+
done: () => `Installed ${packageNames.join(" ")} with ${packageManager.name}`,
|
|
1241
|
+
failed: "Installation failed"
|
|
1242
|
+
});
|
|
1243
|
+
else await installWithSpinner({
|
|
1244
|
+
packages: packagesToInstall,
|
|
1245
|
+
names: `${packagesToInstall.length} packages`,
|
|
1246
|
+
packageManager,
|
|
1247
|
+
cwd,
|
|
1248
|
+
install: async (packages, packageManager, cwd, onLine) => void await dryRun.run(() => installPackages(packages, packageManager, cwd, onLine), dry)
|
|
1249
|
+
});
|
|
1250
|
+
await step({
|
|
1251
|
+
start: `Writing ${KUBB_CONFIG_FILENAME}`,
|
|
1252
|
+
task: async () => dryRun.run(async () => void await write(configPath, await buildConfig(choices)), { message: `write ${KUBB_CONFIG_FILENAME}` }),
|
|
1253
|
+
done: () => `Wrote ${KUBB_CONFIG_FILENAME}`,
|
|
1254
|
+
failed: `Could not write ${KUBB_CONFIG_FILENAME}`
|
|
1255
|
+
});
|
|
1256
|
+
const scriptAdded = await dryRun.run(() => addGenerateScript(cwd), {
|
|
1257
|
+
message: "add a generate script to package.json",
|
|
1258
|
+
resolve: async () => await generateScript(cwd) === void 0
|
|
1259
|
+
});
|
|
1260
|
+
if (scriptAdded && !yes) logStep("Added \"generate\": \"kubb generate\" to package.json");
|
|
1261
|
+
const script = scriptAdded ? "kubb generate" : await generateScript(cwd);
|
|
1262
|
+
const runStart = process$1.hrtime();
|
|
1263
|
+
try {
|
|
1264
|
+
await dryRun.run(() => step({
|
|
1265
|
+
start: "Running the first generation",
|
|
1266
|
+
task: () => firstRun(configPath),
|
|
1267
|
+
done: (files) => yes ? `Generated ${pluralize(files, "file")} in ${choices.outputPath}` : `First run ${pluralize(files, "file")} in ${choices.outputPath} · ${formatMs(getElapsedMs(runStart))}`,
|
|
1268
|
+
failed: "First run failed"
|
|
838
1269
|
}), {
|
|
839
|
-
message:
|
|
840
|
-
resolve: () =>
|
|
841
|
-
});
|
|
842
|
-
if (reason) throw new Diagnostics.Error({
|
|
843
|
-
code: Diagnostics.code.unknown,
|
|
844
|
-
severity: "error",
|
|
845
|
-
message: `Could not add ${entry.manifest.export}() to ${KUBB_CONFIG_FILENAME}: ${reason}`,
|
|
846
|
-
help: `Add ${entry.manifest.export}() to the plugins array in ${KUBB_CONFIG_FILENAME} by hand.`
|
|
1270
|
+
message: "run the first generation",
|
|
1271
|
+
resolve: () => 0
|
|
847
1272
|
});
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
1275
|
+
const message = `Kubb is set up, but the first run failed. Fix the error, then run ${generateCommand({
|
|
1276
|
+
packageManager,
|
|
1277
|
+
script,
|
|
1278
|
+
watch: false
|
|
1279
|
+
})}.`;
|
|
1280
|
+
if (yes) console.log(message);
|
|
1281
|
+
else logOutro(styleText("yellow", message));
|
|
1282
|
+
process$1.exitCode = 1;
|
|
1283
|
+
return;
|
|
848
1284
|
}
|
|
849
|
-
|
|
850
|
-
|
|
1285
|
+
if (yes) {
|
|
1286
|
+
console.log(`Kubb is set up. Run ${generateCommand({
|
|
1287
|
+
packageManager,
|
|
1288
|
+
script,
|
|
1289
|
+
watch: false
|
|
1290
|
+
})} after changing the spec.`);
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
logOutro(`${styleText("green", "✓ Kubb is set up")}\n ${styleText("dim", "Next")} ${generateCommand({
|
|
1294
|
+
packageManager,
|
|
1295
|
+
script,
|
|
1296
|
+
watch: true
|
|
1297
|
+
})}`);
|
|
851
1298
|
} catch (error) {
|
|
852
1299
|
logError(styleText("red", "An error occurred during initialization"));
|
|
853
1300
|
if (error instanceof Error) logError(error.message);
|
|
@@ -857,11 +1304,12 @@ async function run$3({ yes, input: inputFlag, output: outputFlag, plugins: plugi
|
|
|
857
1304
|
__name(run$3, "run");
|
|
858
1305
|
const command$2 = defineWithTypes()({
|
|
859
1306
|
name: "init",
|
|
860
|
-
description: "
|
|
1307
|
+
description: "Set up a config, install plugins, and run the first generation.",
|
|
861
1308
|
examples: [
|
|
862
1309
|
"kubb init",
|
|
863
1310
|
"kubb init --yes",
|
|
864
1311
|
"kubb init --input ./openapi.yaml --output ./src/gen --plugins plugin-ts,plugin-zod",
|
|
1312
|
+
"kubb init --yes --input ./openapi.yaml --plugins ts,zod --output src/api",
|
|
865
1313
|
"kubb init --plugins plugin-ts,plugin-axios,plugin-react-query",
|
|
866
1314
|
"kubb init --yes --dry-run"
|
|
867
1315
|
].join("\n"),
|
|
@@ -869,7 +1317,7 @@ const command$2 = defineWithTypes()({
|
|
|
869
1317
|
args: {
|
|
870
1318
|
yes: {
|
|
871
1319
|
type: "boolean",
|
|
872
|
-
description: "Skip prompts and use default
|
|
1320
|
+
description: "Skip prompts and use the detected spec, the default plugin, and the default output folder",
|
|
873
1321
|
short: "y",
|
|
874
1322
|
default: false
|
|
875
1323
|
},
|
|
@@ -887,7 +1335,7 @@ const command$2 = defineWithTypes()({
|
|
|
887
1335
|
},
|
|
888
1336
|
plugins: {
|
|
889
1337
|
type: "string",
|
|
890
|
-
description: "Comma-separated Kubb registry ids of the plugins to add, the same ids `kubb add` takes (plugin-ts, plugin-zod, acme/plugin-x)",
|
|
1338
|
+
description: "Comma-separated Kubb registry ids of the plugins to add, the same ids `kubb add` takes (plugin-ts, plugin-zod, acme/plugin-x), or short names (ts, zod)",
|
|
891
1339
|
metavar: "plugin-ts,plugin-zod,..."
|
|
892
1340
|
}
|
|
893
1341
|
},
|
|
@@ -900,6 +1348,13 @@ const command$2 = defineWithTypes()({
|
|
|
900
1348
|
})
|
|
901
1349
|
});
|
|
902
1350
|
//#endregion
|
|
1351
|
+
//#region src/ui/table.ts
|
|
1352
|
+
/** Pads each column to its widest cell, one line per row. */
|
|
1353
|
+
function formatTable(rows) {
|
|
1354
|
+
const widths = Array.from({ length: Math.max(0, ...rows.map((row) => row.length)) }, (_, index) => Math.max(...rows.map((row) => row[index]?.length ?? 0)));
|
|
1355
|
+
return rows.map((row) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ").trimEnd());
|
|
1356
|
+
}
|
|
1357
|
+
//#endregion
|
|
903
1358
|
//#region src/runners/list/run.ts
|
|
904
1359
|
/**
|
|
905
1360
|
* The installed packages that ship a `kubb-extension.json` or have a registry entry, with the
|
|
@@ -938,23 +1393,20 @@ async function run$2() {
|
|
|
938
1393
|
logOutro("No installed extensions found.");
|
|
939
1394
|
return;
|
|
940
1395
|
}
|
|
941
|
-
const
|
|
1396
|
+
const [head, ...body] = formatTable([[
|
|
942
1397
|
"ID",
|
|
943
1398
|
"PACKAGE",
|
|
944
1399
|
"INSTALLED",
|
|
945
1400
|
"REGISTRY",
|
|
946
1401
|
"UPDATE"
|
|
947
|
-
]
|
|
948
|
-
const cells = rows.map((row) => [
|
|
1402
|
+
], ...rows.map((row) => [
|
|
949
1403
|
row.id ?? "-",
|
|
950
1404
|
row.package,
|
|
951
1405
|
row.installed ?? "-",
|
|
952
1406
|
row.registry ?? "-",
|
|
953
1407
|
row.update ? "yes" : "no"
|
|
954
|
-
]);
|
|
955
|
-
|
|
956
|
-
const line = (cell) => cell.map((value, index) => value.padEnd(widths[index])).join(" ").trimEnd();
|
|
957
|
-
logBlock([styleText("dim", line(header)), ...cells.map(line)]);
|
|
1408
|
+
])]);
|
|
1409
|
+
logBlock([styleText("dim", head), ...body]);
|
|
958
1410
|
} catch (error) {
|
|
959
1411
|
logError(getErrorMessage(error));
|
|
960
1412
|
process$1.exitCode = 1;
|
|
@@ -963,82 +1415,193 @@ async function run$2() {
|
|
|
963
1415
|
__name(run$2, "run");
|
|
964
1416
|
const command$1 = define({
|
|
965
1417
|
name: "list",
|
|
966
|
-
description: "List
|
|
1418
|
+
description: "List installed extensions, their versions, and available updates.",
|
|
967
1419
|
examples: "kubb list",
|
|
968
1420
|
run: () => run$2()
|
|
969
1421
|
});
|
|
970
1422
|
//#endregion
|
|
971
1423
|
//#region src/runners/update/run.ts
|
|
972
1424
|
/**
|
|
973
|
-
*
|
|
974
|
-
*
|
|
1425
|
+
* Generates every config in this process, the way `kubb generate` does, and returns the output files
|
|
1426
|
+
* it changed. Runs after the install, so the config loads the new versions. `undefined` when the
|
|
1427
|
+
* config fails to load or a build fails.
|
|
1428
|
+
*/
|
|
1429
|
+
async function regenerate({ cwd, configPath }) {
|
|
1430
|
+
const spinner = createSpinner();
|
|
1431
|
+
spinner.start("Generating with the new versions");
|
|
1432
|
+
try {
|
|
1433
|
+
const [{ getConfigs }, { generate }] = await Promise.all([import("./config-iVdOcpro.js"), import("./run-S3xKq4bj.js")]);
|
|
1434
|
+
const { configs } = await getConfigs({ configPath });
|
|
1435
|
+
const dirs = configs.map((config) => path.resolve(config.root ?? cwd, config.output.path));
|
|
1436
|
+
const before = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]));
|
|
1437
|
+
const hooks = new Hookable();
|
|
1438
|
+
for (const config of configs) if (!await generate({
|
|
1439
|
+
config,
|
|
1440
|
+
hooks
|
|
1441
|
+
})) throw new Error("Generation failed");
|
|
1442
|
+
const after = new Map((await Promise.all(dirs.map(readOutputFiles))).flatMap((files) => [...files]));
|
|
1443
|
+
const diff = diffFiles(before, after);
|
|
1444
|
+
spinner.stop(diff.files.length ? `Generated: ${pluralize(diff.files.length, "file")} changed` : "Generated: no files changed");
|
|
1445
|
+
return {
|
|
1446
|
+
...diff,
|
|
1447
|
+
output: dirs.map((dir) => path.relative(cwd, dir) || ".").join(", ")
|
|
1448
|
+
};
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
spinner.error(`Generation failed: ${getErrorMessage(error)}`);
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Moves installed extensions to the version the registry pins. Shows each version change with its
|
|
1456
|
+
* bump, asks which to install with majors left out, installs them, and regenerates to show which
|
|
1457
|
+
* files changed. With `dryRun`, only lists the updates and installs nothing.
|
|
975
1458
|
*/
|
|
976
|
-
async function run$1({ ids,
|
|
1459
|
+
async function run$1({ ids, dryRun, yes }) {
|
|
977
1460
|
const cwd = process$1.cwd();
|
|
978
|
-
|
|
1461
|
+
const hrStart = process$1.hrtime();
|
|
1462
|
+
const installedPackages = [];
|
|
1463
|
+
const summary = (title, status, lines) => logCommandSummary({
|
|
1464
|
+
title,
|
|
1465
|
+
status,
|
|
1466
|
+
hrStart,
|
|
1467
|
+
block: true,
|
|
1468
|
+
lines
|
|
1469
|
+
});
|
|
1470
|
+
logIntro({ title: isInteractiveRun({
|
|
1471
|
+
yes,
|
|
1472
|
+
dryRun
|
|
1473
|
+
}) ? void 0 : styleText("bgCyan", styleText("black", " Kubb Update ")) });
|
|
979
1474
|
try {
|
|
980
1475
|
const wanted = new Set(ids.map(toRegistryId));
|
|
981
|
-
const [entries, installed] = await
|
|
1476
|
+
const [entries, installed] = await withSpinner({
|
|
1477
|
+
message: "Checking the registry",
|
|
1478
|
+
promise: Promise.all([fetchRegistryIndex({ registry: registryUrl() }), readInstalledPackages({ root: cwd })])
|
|
1479
|
+
});
|
|
982
1480
|
const versions = new Map(installed.map((item) => [item.package, item.version]));
|
|
983
1481
|
const tracked = entries.filter((entry) => versions.has(entry.artifact.package) && (!wanted.size || wanted.has(entry.id)));
|
|
984
1482
|
for (const id of wanted) if (!tracked.some((entry) => entry.id === id)) logWarn(`${id} is not installed, or not in the registry.`);
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1483
|
+
const current = ({ artifact }) => versions.get(artifact.package);
|
|
1484
|
+
const isMajor = (entry) => bumpOf({
|
|
1485
|
+
installed: current(entry),
|
|
1486
|
+
latest: entry.artifact.version
|
|
1487
|
+
}) === "major";
|
|
1488
|
+
const outdated = tracked.filter((entry) => isOutdated({
|
|
1489
|
+
installed: current(entry),
|
|
1490
|
+
latest: entry.artifact.version
|
|
1491
|
+
}));
|
|
1492
|
+
const proposals = outdated.filter((entry) => {
|
|
990
1493
|
const problem = incompatibility(entry.manifest);
|
|
991
1494
|
if (problem) logWarn(`Skipped ${entry.id}: ${problem}`);
|
|
992
1495
|
return !problem;
|
|
993
1496
|
});
|
|
994
1497
|
if (!proposals.length) {
|
|
995
|
-
|
|
1498
|
+
const title = outdated.length ? "No compatible updates available" : "Already up to date";
|
|
1499
|
+
summary(tracked.length ? title : "No installed extensions to update", outdated.length ? "warning" : "success", [` ${tracked.length - outdated.length} of ${tracked.length} up to date`, ...ids.length ? ["", `No updates for ${ids.join(", ")}.`] : []]);
|
|
996
1500
|
return;
|
|
997
1501
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1502
|
+
if (tracked.length) {
|
|
1503
|
+
const lines = formatTable([[
|
|
1504
|
+
"Extension",
|
|
1505
|
+
"Current",
|
|
1506
|
+
"Latest",
|
|
1507
|
+
""
|
|
1508
|
+
], ...tracked.map((entry) => {
|
|
1509
|
+
if (!outdated.includes(entry)) return [
|
|
1510
|
+
entry.artifact.package,
|
|
1511
|
+
current(entry) ?? "-",
|
|
1512
|
+
"up to date",
|
|
1513
|
+
""
|
|
1514
|
+
];
|
|
1515
|
+
const bump = bumpOf({
|
|
1516
|
+
installed: current(entry),
|
|
1517
|
+
latest: entry.artifact.version
|
|
1518
|
+
}) ?? "";
|
|
1519
|
+
return [
|
|
1520
|
+
entry.artifact.package,
|
|
1521
|
+
current(entry) ?? "not installed",
|
|
1522
|
+
entry.artifact.version,
|
|
1523
|
+
bump === "major" ? "major · breaking" : bump
|
|
1524
|
+
];
|
|
1525
|
+
})]);
|
|
1526
|
+
logStep(`Checked ${pluralize(tracked.length, "extension")} against the registry`);
|
|
1527
|
+
logBlock([styleText("dim", lines[0]), ...lines.slice(1).map((line, index) => {
|
|
1528
|
+
if (!outdated.includes(tracked[index])) return styleText("dim", line);
|
|
1529
|
+
return line.endsWith("major · breaking") ? styleText("yellow", line) : line;
|
|
1530
|
+
})]);
|
|
1531
|
+
}
|
|
1532
|
+
if (dryRun) {
|
|
1533
|
+
summary("Updates available", "planned", [`Dry run: nothing was installed. Run kubb update to install ${proposals.length === 1 ? "it" : "them"}.`]);
|
|
1003
1534
|
return;
|
|
1004
1535
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1536
|
+
const defaults = proposals.filter((entry) => !isMajor(entry));
|
|
1537
|
+
const chosen = yes ? defaults.map((entry) => entry.id) : await clack.multiselect({
|
|
1538
|
+
message: "Select the updates to install",
|
|
1539
|
+
options: proposals.map((entry) => ({
|
|
1540
|
+
value: entry.id,
|
|
1541
|
+
label: entry.artifact.package,
|
|
1542
|
+
hint: `${current(entry) ?? "not installed"} → ${entry.artifact.version}`
|
|
1543
|
+
})),
|
|
1544
|
+
initialValues: defaults.map((entry) => entry.id),
|
|
1545
|
+
required: false
|
|
1546
|
+
});
|
|
1547
|
+
if (clack.isCancel(chosen)) {
|
|
1548
|
+
summary("Update canceled", "canceled", [" No changes made"]);
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
const selected = proposals.filter((entry) => chosen.includes(entry.id));
|
|
1552
|
+
const skipped = proposals.filter((entry) => !selected.includes(entry)).map((entry) => {
|
|
1553
|
+
const kind = entry.manifest.kind.charAt(0).toUpperCase() + entry.manifest.kind.slice(1);
|
|
1554
|
+
return ` ${styleText("dim", "Skipped")} ${kind} ${entry.artifact.package} ${entry.artifact.version} ${styleText("dim", `run kubb update ${toShortId(entry.id)} later`)}`;
|
|
1555
|
+
});
|
|
1556
|
+
if (!selected.length) {
|
|
1557
|
+
summary("No updates installed", "canceled", [" No updates selected.", ...skipped]);
|
|
1558
|
+
return;
|
|
1022
1559
|
}
|
|
1023
|
-
const plural = selected.length === 1 ? "" : "s";
|
|
1024
1560
|
const packageManager = detectPackageManager(cwd);
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1561
|
+
const names = selected.map(({ artifact }) => artifact.package).join(", ");
|
|
1562
|
+
await installWithSpinner({
|
|
1563
|
+
packages: selected.map(({ artifact }) => installSpec(artifact)),
|
|
1564
|
+
names,
|
|
1565
|
+
packageManager,
|
|
1566
|
+
cwd
|
|
1567
|
+
});
|
|
1568
|
+
installedPackages.push(...selected.map((entry) => entry.artifact.package));
|
|
1569
|
+
const foundConfig = findConfigFile(cwd);
|
|
1570
|
+
const configPath = foundConfig && !yes && await clack.confirm({
|
|
1571
|
+
message: "Regenerate now? This rewrites the generated files.",
|
|
1572
|
+
initialValue: true
|
|
1573
|
+
}) === true ? foundConfig : void 0;
|
|
1574
|
+
const changed = configPath ? await regenerate({
|
|
1575
|
+
cwd,
|
|
1576
|
+
configPath
|
|
1577
|
+
}) : void 0;
|
|
1578
|
+
const generationFailed = Boolean(configPath && !changed);
|
|
1579
|
+
const fileCounts = {
|
|
1580
|
+
A: 0,
|
|
1581
|
+
M: 0,
|
|
1582
|
+
D: 0
|
|
1583
|
+
};
|
|
1584
|
+
for (const file of changed?.files ?? []) fileCounts[file.status]++;
|
|
1585
|
+
summary(generationFailed ? "Extensions updated; generation failed" : "Update complete", generationFailed ? "warning" : "success", [
|
|
1586
|
+
` Packages ${selected.length} installed with ${packageManager.name}${skipped.length ? ` · ${skipped.length} skipped` : ""}`,
|
|
1587
|
+
...skipped,
|
|
1588
|
+
...changed ? [` Files ${fileCounts.A} added · ${fileCounts.M} modified · ${fileCounts.D} deleted`] : [],
|
|
1589
|
+
...!configPath ? [" Regeneration not run"] : [],
|
|
1590
|
+
...generationFailed ? ["", "Fix the generation error, then run kubb generate."] : []
|
|
1591
|
+
]);
|
|
1030
1592
|
} catch (error) {
|
|
1031
1593
|
logError(getErrorMessage(error));
|
|
1594
|
+
summary("Update failed", "failed", installedPackages.length ? [` Packages ${installedPackages.join(", ")} installed`] : [" No changes made"]);
|
|
1032
1595
|
process$1.exitCode = 1;
|
|
1033
1596
|
}
|
|
1034
1597
|
}
|
|
1035
1598
|
__name(run$1, "run");
|
|
1036
|
-
const command =
|
|
1599
|
+
const command = defineWithTypes()({
|
|
1037
1600
|
name: "update",
|
|
1038
|
-
description: "Update installed extensions
|
|
1601
|
+
description: "Update installed extensions, regenerate, and summarize file changes.",
|
|
1039
1602
|
examples: [
|
|
1040
1603
|
"kubb update",
|
|
1041
|
-
"kubb update --
|
|
1604
|
+
"kubb update --dry-run",
|
|
1042
1605
|
"kubb update plugin-zod plugin-ts --yes"
|
|
1043
1606
|
].join("\n"),
|
|
1044
1607
|
args: {
|
|
@@ -1047,16 +1610,11 @@ const command = define({
|
|
|
1047
1610
|
description: "Registry ids to update, all installed extensions when omitted",
|
|
1048
1611
|
multiple: true
|
|
1049
1612
|
},
|
|
1050
|
-
check: {
|
|
1051
|
-
type: "boolean",
|
|
1052
|
-
description: "List the available updates without installing them",
|
|
1053
|
-
default: false
|
|
1054
|
-
},
|
|
1055
1613
|
...yesArg
|
|
1056
1614
|
},
|
|
1057
|
-
run: ({ values }) => run$1({
|
|
1615
|
+
run: ({ values, extensions }) => run$1({
|
|
1058
1616
|
ids: values.ids ?? [],
|
|
1059
|
-
|
|
1617
|
+
dryRun: extensions[dryRunId].enabled,
|
|
1060
1618
|
yes: values.yes
|
|
1061
1619
|
})
|
|
1062
1620
|
});
|
|
@@ -1077,7 +1635,7 @@ const QUIET_FLAGS = /* @__PURE__ */ new Set([
|
|
|
1077
1635
|
async function run(argv = process.argv.slice(2)) {
|
|
1078
1636
|
const args = routeStudioFlags(resolveDeprecatedFlags(argv));
|
|
1079
1637
|
const isQuietFlag = args.some((arg) => QUIET_FLAGS.has(arg));
|
|
1080
|
-
const
|
|
1638
|
+
const isJsonOutput = args.includes("--json") || args.some((arg, index) => /^--reporter=.*\bjson\b/.test(arg) || arg === "--reporter" && /\bjson\b/.test(args[index + 1] ?? ""));
|
|
1081
1639
|
if (!isDisabled() && !isQuietFlag) console.error(`${styleText("yellow", "Notice:")} Kubb collects anonymous telemetry data to help improve the tool. No personal data or file contents are collected. \nTo disable, set ${styleText("cyan", "KUBB_DISABLE_TELEMETRY=1")}.\n`);
|
|
1082
1640
|
await cli(args, command$13, {
|
|
1083
1641
|
name: "kubb",
|
|
@@ -1094,7 +1652,14 @@ async function run(argv = process.argv.slice(2)) {
|
|
|
1094
1652
|
list: command$1
|
|
1095
1653
|
},
|
|
1096
1654
|
fallbackToEntry: true,
|
|
1097
|
-
|
|
1655
|
+
renderHeader: isJsonOutput ? null : async (ctx) => {
|
|
1656
|
+
if (!wantsMascot({
|
|
1657
|
+
commandPath: ctx.commandPath,
|
|
1658
|
+
values: ctx.values
|
|
1659
|
+
})) return "";
|
|
1660
|
+
ctx.log(getBanner(version, ctx.commandPath.join(" ") || "generate"));
|
|
1661
|
+
return "";
|
|
1662
|
+
},
|
|
1098
1663
|
strict: true,
|
|
1099
1664
|
plugins: [dryrun({ name: "dry-run" })],
|
|
1100
1665
|
onErrorCommand: async (_ctx, error) => {
|