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