@kubb/cli 4.11.3 → 4.12.0
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/generate-BujndwJK.cjs +1256 -0
- package/dist/generate-BujndwJK.cjs.map +1 -0
- package/dist/generate-BvrG5K00.js +1249 -0
- package/dist/generate-BvrG5K00.js.map +1 -0
- package/dist/index.cjs +9 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -30
- package/dist/index.js.map +1 -1
- package/dist/{mcp-BIRDY8xn.js → mcp-LLlOFV3c.js} +5 -6
- package/dist/mcp-LLlOFV3c.js.map +1 -0
- package/dist/{mcp-BQjDRDXR.cjs → mcp-N1IVyiXf.cjs} +5 -7
- package/dist/mcp-N1IVyiXf.cjs.map +1 -0
- package/dist/package-Bhc6C7cQ.js +6 -0
- package/dist/package-Bhc6C7cQ.js.map +1 -0
- package/dist/package-KuCpJxHt.cjs +12 -0
- package/dist/package-KuCpJxHt.cjs.map +1 -0
- package/dist/{validate-0i6Q9eIy.js → validate-BptoQ-63.js} +5 -6
- package/dist/validate-BptoQ-63.js.map +1 -0
- package/dist/{validate-6F-VPZR7.cjs → validate-Dn6hZ7Z4.cjs} +5 -7
- package/dist/validate-Dn6hZ7Z4.cjs.map +1 -0
- package/package.json +7 -7
- package/src/commands/generate.ts +52 -65
- package/src/commands/mcp.ts +4 -5
- package/src/commands/validate.ts +4 -5
- package/src/index.ts +8 -23
- package/src/loggers/clackLogger.ts +433 -0
- package/src/loggers/envDetection.ts +28 -0
- package/src/loggers/fileSystemLogger.ts +79 -0
- package/src/loggers/githubActionsLogger.ts +310 -0
- package/src/loggers/index.ts +7 -0
- package/src/loggers/plainLogger.ts +274 -0
- package/src/loggers/types.ts +1 -0
- package/src/loggers/utils.ts +49 -0
- package/src/runners/generate.ts +196 -208
- package/src/utils/Writables.ts +12 -8
- package/src/utils/executeHooks.ts +11 -18
- package/src/utils/getCosmiConfig.ts +6 -1
- package/src/utils/getSummary.ts +20 -42
- package/src/utils/randomColour.ts +26 -0
- package/src/utils/watcher.ts +2 -4
- package/dist/generate-CYBFB3tU.js +0 -221
- package/dist/generate-CYBFB3tU.js.map +0 -1
- package/dist/generate-CpBJ2Y-n.js +0 -342
- package/dist/generate-CpBJ2Y-n.js.map +0 -1
- package/dist/generate-DpHvARzf.cjs +0 -345
- package/dist/generate-DpHvARzf.cjs.map +0 -1
- package/dist/generate-KUqCSnZp.cjs +0 -225
- package/dist/generate-KUqCSnZp.cjs.map +0 -1
- package/dist/mcp-BIRDY8xn.js.map +0 -1
- package/dist/mcp-BQjDRDXR.cjs.map +0 -1
- package/dist/validate-0i6Q9eIy.js.map +0 -1
- package/dist/validate-6F-VPZR7.cjs.map +0 -1
|
@@ -0,0 +1,1249 @@
|
|
|
1
|
+
import { t as version } from "./package-Bhc6C7cQ.js";
|
|
2
|
+
import { defineCommand, showUsage } from "citty";
|
|
3
|
+
import path, { relative, resolve } from "node:path";
|
|
4
|
+
import * as process$2 from "node:process";
|
|
5
|
+
import process$1 from "node:process";
|
|
6
|
+
import * as clack from "@clack/prompts";
|
|
7
|
+
import { LogLevel, PromiseManager, defineLogger, isInputPath, safeBuild, setup } from "@kubb/core";
|
|
8
|
+
import { AsyncEventEmitter, isPromise } from "@kubb/core/utils";
|
|
9
|
+
import getLatestVersion from "latest-version";
|
|
10
|
+
import pc from "picocolors";
|
|
11
|
+
import { lt } from "semver";
|
|
12
|
+
import { execa } from "execa";
|
|
13
|
+
import gradientString from "gradient-string";
|
|
14
|
+
import seedrandom from "seedrandom";
|
|
15
|
+
import { Writable } from "node:stream";
|
|
16
|
+
import { write } from "@kubb/core/fs";
|
|
17
|
+
import { parseArgsStringToArgv } from "string-argv";
|
|
18
|
+
import { cosmiconfig } from "cosmiconfig";
|
|
19
|
+
import { createJiti } from "jiti";
|
|
20
|
+
|
|
21
|
+
//#region src/utils/parseHrtimeToSeconds.ts
|
|
22
|
+
function parseHrtimeToSeconds(hrtime) {
|
|
23
|
+
return (hrtime[0] + hrtime[1] / 1e9).toFixed(3);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/utils/randomColour.ts
|
|
28
|
+
function randomColour(text) {
|
|
29
|
+
if (!text) return "white";
|
|
30
|
+
const defaultColours = [
|
|
31
|
+
"black",
|
|
32
|
+
"red",
|
|
33
|
+
"green",
|
|
34
|
+
"yellow",
|
|
35
|
+
"blue",
|
|
36
|
+
"red",
|
|
37
|
+
"green",
|
|
38
|
+
"magenta",
|
|
39
|
+
"cyan",
|
|
40
|
+
"gray"
|
|
41
|
+
];
|
|
42
|
+
const random = seedrandom(text);
|
|
43
|
+
return defaultColours.at(Math.floor(random() * defaultColours.length)) || "white";
|
|
44
|
+
}
|
|
45
|
+
function randomCliColour(text) {
|
|
46
|
+
if (!text) return "";
|
|
47
|
+
const fn = pc[randomColour(text)];
|
|
48
|
+
return fn ? fn(text) : text;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/utils/getSummary.ts
|
|
53
|
+
function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
|
|
54
|
+
const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(hrStart));
|
|
55
|
+
const pluginsCount = config.plugins?.length || 0;
|
|
56
|
+
const successCount = pluginsCount - failedPlugins.size;
|
|
57
|
+
const meta = {
|
|
58
|
+
plugins: status === "success" ? `${pc.green(`${successCount} successful`)}, ${pluginsCount} total` : `${pc.green(`${successCount} successful`)}, ${pc.red(`${failedPlugins.size} failed`)}, ${pluginsCount} total`,
|
|
59
|
+
pluginsFailed: status === "failed" ? [...failedPlugins]?.map(({ plugin }) => randomCliColour(plugin.name))?.join(", ") : void 0,
|
|
60
|
+
filesCreated,
|
|
61
|
+
time: `${elapsedSeconds}s`,
|
|
62
|
+
output: path.isAbsolute(config.root) ? path.resolve(config.root, config.output.path) : config.root
|
|
63
|
+
};
|
|
64
|
+
const labels = {
|
|
65
|
+
plugins: "Plugins:",
|
|
66
|
+
failed: "Failed:",
|
|
67
|
+
generated: "Generated:",
|
|
68
|
+
pluginTimings: "Plugin Timings:",
|
|
69
|
+
output: "Output:"
|
|
70
|
+
};
|
|
71
|
+
const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
|
|
72
|
+
const summaryLines = [];
|
|
73
|
+
summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
|
|
74
|
+
if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
|
|
75
|
+
summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
|
|
76
|
+
if (pluginTimings && pluginTimings.size > 0) {
|
|
77
|
+
const TIME_SCALE_DIVISOR = 100;
|
|
78
|
+
const MAX_BAR_LENGTH = 10;
|
|
79
|
+
const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
|
|
80
|
+
if (sortedTimings.length > 0) {
|
|
81
|
+
summaryLines.push(`${labels.pluginTimings}`);
|
|
82
|
+
sortedTimings.forEach(([name, time]) => {
|
|
83
|
+
const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
|
|
84
|
+
const barLength = Math.min(Math.ceil(time / TIME_SCALE_DIVISOR), MAX_BAR_LENGTH);
|
|
85
|
+
const bar = pc.dim("█".repeat(barLength));
|
|
86
|
+
summaryLines.push(`${pc.dim("•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
|
|
91
|
+
return summaryLines;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/utils/Writables.ts
|
|
96
|
+
var ClackWritable = class extends Writable {
|
|
97
|
+
taskLog;
|
|
98
|
+
constructor(taskLog, opts) {
|
|
99
|
+
super(opts);
|
|
100
|
+
this.taskLog = taskLog;
|
|
101
|
+
}
|
|
102
|
+
_write(chunk, _encoding, callback) {
|
|
103
|
+
this.taskLog.message(`${pc.dim(chunk?.toString())}`);
|
|
104
|
+
callback();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/loggers/clackLogger.ts
|
|
110
|
+
/**
|
|
111
|
+
* Clack adapter for local TTY environments
|
|
112
|
+
* Provides a beautiful CLI UI with flat structure inspired by Claude's CLI patterns
|
|
113
|
+
*/
|
|
114
|
+
const clackLogger = defineLogger({
|
|
115
|
+
name: "clack",
|
|
116
|
+
install(context, options) {
|
|
117
|
+
const logLevel = options?.logLevel || LogLevel.info;
|
|
118
|
+
const activeProgress = /* @__PURE__ */ new Map();
|
|
119
|
+
const spinner = clack.spinner();
|
|
120
|
+
let isSpinning = false;
|
|
121
|
+
function getMessage(message) {
|
|
122
|
+
if (logLevel >= LogLevel.verbose) {
|
|
123
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
|
|
124
|
+
hour12: false,
|
|
125
|
+
hour: "2-digit",
|
|
126
|
+
minute: "2-digit",
|
|
127
|
+
second: "2-digit"
|
|
128
|
+
});
|
|
129
|
+
return [pc.dim(`[${timestamp}]`), message].join(" ");
|
|
130
|
+
}
|
|
131
|
+
return message;
|
|
132
|
+
}
|
|
133
|
+
function startSpinner(text) {
|
|
134
|
+
spinner.start(text);
|
|
135
|
+
isSpinning = true;
|
|
136
|
+
}
|
|
137
|
+
function stopSpinner(text) {
|
|
138
|
+
spinner.stop(text);
|
|
139
|
+
isSpinning = false;
|
|
140
|
+
}
|
|
141
|
+
context.on("info", (message, info = "") => {
|
|
142
|
+
if (logLevel <= LogLevel.silent) return;
|
|
143
|
+
const text = getMessage([
|
|
144
|
+
pc.blue("ℹ"),
|
|
145
|
+
message,
|
|
146
|
+
pc.dim(info)
|
|
147
|
+
].join(" "));
|
|
148
|
+
if (isSpinning) spinner.message(text);
|
|
149
|
+
else clack.log.info(text);
|
|
150
|
+
});
|
|
151
|
+
context.on("success", (message, info = "") => {
|
|
152
|
+
if (logLevel <= LogLevel.silent) return;
|
|
153
|
+
const text = getMessage([
|
|
154
|
+
pc.blue("✓"),
|
|
155
|
+
message,
|
|
156
|
+
logLevel >= LogLevel.info ? pc.dim(info) : void 0
|
|
157
|
+
].filter(Boolean).join(" "));
|
|
158
|
+
if (isSpinning) stopSpinner(text);
|
|
159
|
+
else clack.log.success(text);
|
|
160
|
+
});
|
|
161
|
+
context.on("warn", (message, info) => {
|
|
162
|
+
if (logLevel < LogLevel.warn) return;
|
|
163
|
+
const text = getMessage([
|
|
164
|
+
pc.yellow("⚠"),
|
|
165
|
+
message,
|
|
166
|
+
logLevel >= LogLevel.info ? pc.dim(info) : void 0
|
|
167
|
+
].filter(Boolean).join(" "));
|
|
168
|
+
clack.log.warn(text);
|
|
169
|
+
});
|
|
170
|
+
context.on("error", (error) => {
|
|
171
|
+
const caused = error.cause;
|
|
172
|
+
const text = [pc.red("✗"), error.message].join(" ");
|
|
173
|
+
if (isSpinning) stopSpinner(getMessage(text));
|
|
174
|
+
else clack.log.error(getMessage(text));
|
|
175
|
+
if (logLevel >= LogLevel.debug && error.stack) {
|
|
176
|
+
const frames = error.stack.split("\n").slice(1, 4);
|
|
177
|
+
for (const frame of frames) clack.log.message(getMessage(pc.dim(frame.trim())));
|
|
178
|
+
if (caused?.stack) {
|
|
179
|
+
clack.log.message(pc.dim(`└─ caused by ${caused.message}`));
|
|
180
|
+
const frames$1 = caused.stack.split("\n").slice(1, 4);
|
|
181
|
+
for (const frame of frames$1) clack.log.message(getMessage(` ${pc.dim(frame.trim())}`));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
context.on("version:new", (version$1, latestVersion) => {
|
|
186
|
+
if (logLevel <= LogLevel.silent) return;
|
|
187
|
+
clack.box(`\`v${version$1}\` → \`v${latestVersion}\`
|
|
188
|
+
Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
189
|
+
width: "auto",
|
|
190
|
+
formatBorder: pc.yellow,
|
|
191
|
+
rounded: true,
|
|
192
|
+
withGuide: false,
|
|
193
|
+
contentAlign: "center",
|
|
194
|
+
titleAlign: "center"
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
context.on("lifecycle:start", (version$1) => {
|
|
198
|
+
console.log(gradientString([
|
|
199
|
+
"#F58517",
|
|
200
|
+
"#F5A217",
|
|
201
|
+
"#F55A17"
|
|
202
|
+
])(`Kubb ${version$1} 🧩`));
|
|
203
|
+
});
|
|
204
|
+
context.on("config:start", () => {
|
|
205
|
+
if (logLevel <= LogLevel.silent) return;
|
|
206
|
+
const text = getMessage("Configuration started");
|
|
207
|
+
clack.intro(text);
|
|
208
|
+
startSpinner(getMessage("Configuration loading"));
|
|
209
|
+
});
|
|
210
|
+
context.on("config:end", () => {
|
|
211
|
+
if (logLevel <= LogLevel.silent) return;
|
|
212
|
+
const text = getMessage("Configuration completed");
|
|
213
|
+
clack.outro(text);
|
|
214
|
+
});
|
|
215
|
+
context.on("generation:start", (config) => {
|
|
216
|
+
const text = getMessage(["Generation started", config.name ? `for ${pc.dim(config.name)}` : void 0].filter(Boolean).join(" "));
|
|
217
|
+
clack.intro(text);
|
|
218
|
+
});
|
|
219
|
+
context.on("plugin:start", (plugin) => {
|
|
220
|
+
if (logLevel <= LogLevel.silent) return;
|
|
221
|
+
stopSpinner();
|
|
222
|
+
const progressBar = clack.progress({
|
|
223
|
+
style: "block",
|
|
224
|
+
max: 100,
|
|
225
|
+
size: 30
|
|
226
|
+
});
|
|
227
|
+
const text = getMessage(`Generating ${pc.bold(plugin.name)}`);
|
|
228
|
+
progressBar.start(text);
|
|
229
|
+
const interval = setInterval(() => {
|
|
230
|
+
progressBar.advance();
|
|
231
|
+
}, 50);
|
|
232
|
+
activeProgress.set(plugin.name, {
|
|
233
|
+
progressBar,
|
|
234
|
+
interval
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
context.on("plugin:end", (plugin, duration) => {
|
|
238
|
+
stopSpinner();
|
|
239
|
+
const active = activeProgress.get(plugin.name);
|
|
240
|
+
if (!active || logLevel === LogLevel.silent) return;
|
|
241
|
+
clearInterval(active.interval);
|
|
242
|
+
const durationStr = duration >= 1e3 ? `${(duration / 1e3).toFixed(2)}s` : `${duration}ms`;
|
|
243
|
+
const text = getMessage(`${pc.bold(plugin.name)} completed in ${pc.green(durationStr)}`);
|
|
244
|
+
active.progressBar.stop(text);
|
|
245
|
+
activeProgress.delete(plugin.name);
|
|
246
|
+
});
|
|
247
|
+
context.on("files:processing:start", (files) => {
|
|
248
|
+
if (logLevel <= LogLevel.silent) return;
|
|
249
|
+
stopSpinner();
|
|
250
|
+
const text = getMessage(`Writing ${files.length} files`);
|
|
251
|
+
const progressBar = clack.progress({
|
|
252
|
+
style: "block",
|
|
253
|
+
max: files.length,
|
|
254
|
+
size: 30
|
|
255
|
+
});
|
|
256
|
+
context.emit("info", text);
|
|
257
|
+
progressBar.start(text);
|
|
258
|
+
activeProgress.set("files", { progressBar });
|
|
259
|
+
});
|
|
260
|
+
context.on("file:processing:update", ({ file, config }) => {
|
|
261
|
+
if (logLevel <= LogLevel.silent) return;
|
|
262
|
+
stopSpinner();
|
|
263
|
+
const text = `Writing ${relative(config.root, file.path)}`;
|
|
264
|
+
const active = activeProgress.get("files");
|
|
265
|
+
if (!active) return;
|
|
266
|
+
active.progressBar.advance(void 0, text);
|
|
267
|
+
});
|
|
268
|
+
context.on("files:processing:end", () => {
|
|
269
|
+
if (logLevel <= LogLevel.silent) return;
|
|
270
|
+
stopSpinner();
|
|
271
|
+
const text = getMessage("Files written successfully");
|
|
272
|
+
const active = activeProgress.get("files");
|
|
273
|
+
if (!active) return;
|
|
274
|
+
active.progressBar.stop(text);
|
|
275
|
+
activeProgress.delete("files");
|
|
276
|
+
});
|
|
277
|
+
context.on("generation:end", (config) => {
|
|
278
|
+
const text = getMessage(config.name ? `Generation completed for ${pc.dim(config.name)}` : "Generation completed");
|
|
279
|
+
clack.outro(text);
|
|
280
|
+
});
|
|
281
|
+
context.on("hook:execute", async ({ command: command$1, args }, cb) => {
|
|
282
|
+
if (logLevel <= LogLevel.silent) {
|
|
283
|
+
try {
|
|
284
|
+
const result = await execa(command$1, args, {
|
|
285
|
+
detached: true,
|
|
286
|
+
stripFinalNewline: true
|
|
287
|
+
});
|
|
288
|
+
await context.emit("debug", {
|
|
289
|
+
date: /* @__PURE__ */ new Date(),
|
|
290
|
+
logs: [result.stdout]
|
|
291
|
+
});
|
|
292
|
+
cb();
|
|
293
|
+
} catch (err) {
|
|
294
|
+
const error = /* @__PURE__ */ new Error("Hook execute failed");
|
|
295
|
+
error.cause = err;
|
|
296
|
+
await context.emit("debug", {
|
|
297
|
+
date: /* @__PURE__ */ new Date(),
|
|
298
|
+
logs: [err.stdout]
|
|
299
|
+
});
|
|
300
|
+
await context.emit("error", error);
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const writable = new ClackWritable(clack.taskLog({ title: getMessage(["Executing hook", logLevel >= LogLevel.info ? pc.dim(`${command$1} ${args?.join(" ")}`) : void 0].filter(Boolean).join(" ")) }));
|
|
305
|
+
try {
|
|
306
|
+
const result = await execa(command$1, args, {
|
|
307
|
+
detached: true,
|
|
308
|
+
stdout: ["pipe", writable],
|
|
309
|
+
stripFinalNewline: true
|
|
310
|
+
});
|
|
311
|
+
await context.emit("debug", {
|
|
312
|
+
date: /* @__PURE__ */ new Date(),
|
|
313
|
+
logs: [result.stdout]
|
|
314
|
+
});
|
|
315
|
+
cb();
|
|
316
|
+
} catch (err) {
|
|
317
|
+
const error = /* @__PURE__ */ new Error("Hook execute failed");
|
|
318
|
+
error.cause = err;
|
|
319
|
+
await context.emit("debug", {
|
|
320
|
+
date: /* @__PURE__ */ new Date(),
|
|
321
|
+
logs: [err.stdout]
|
|
322
|
+
});
|
|
323
|
+
await context.emit("error", error);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
context.on("format:start", () => {
|
|
327
|
+
if (logLevel <= LogLevel.silent) return;
|
|
328
|
+
const text = getMessage("Format started");
|
|
329
|
+
clack.intro(text);
|
|
330
|
+
});
|
|
331
|
+
context.on("format:end", () => {
|
|
332
|
+
if (logLevel <= LogLevel.silent) return;
|
|
333
|
+
const text = getMessage("Format completed");
|
|
334
|
+
clack.outro(text);
|
|
335
|
+
});
|
|
336
|
+
context.on("lint:start", () => {
|
|
337
|
+
if (logLevel <= LogLevel.silent) return;
|
|
338
|
+
const text = getMessage("Lint started");
|
|
339
|
+
clack.intro(text);
|
|
340
|
+
});
|
|
341
|
+
context.on("lint:end", () => {
|
|
342
|
+
if (logLevel <= LogLevel.silent) return;
|
|
343
|
+
const text = getMessage("Lint completed");
|
|
344
|
+
clack.outro(text);
|
|
345
|
+
});
|
|
346
|
+
context.on("hook:start", (command$1) => {
|
|
347
|
+
if (logLevel <= LogLevel.silent) return;
|
|
348
|
+
const text = getMessage(`Hook ${pc.dim(command$1)} started`);
|
|
349
|
+
clack.intro(text);
|
|
350
|
+
});
|
|
351
|
+
context.on("hook:end", (command$1) => {
|
|
352
|
+
if (logLevel <= LogLevel.silent) return;
|
|
353
|
+
const text = getMessage(`Hook ${pc.dim(command$1)} completed`);
|
|
354
|
+
clack.outro(text);
|
|
355
|
+
});
|
|
356
|
+
context.on("generation:summary", (config, { pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
|
|
357
|
+
const summary = getSummary({
|
|
358
|
+
failedPlugins,
|
|
359
|
+
filesCreated,
|
|
360
|
+
config,
|
|
361
|
+
status,
|
|
362
|
+
hrStart,
|
|
363
|
+
pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : void 0
|
|
364
|
+
});
|
|
365
|
+
const title = config.name || "";
|
|
366
|
+
summary.unshift("\n");
|
|
367
|
+
summary.push("\n");
|
|
368
|
+
if (status === "success") {
|
|
369
|
+
clack.box(summary.join("\n"), getMessage(title), {
|
|
370
|
+
width: "auto",
|
|
371
|
+
formatBorder: pc.green,
|
|
372
|
+
rounded: true,
|
|
373
|
+
withGuide: false,
|
|
374
|
+
contentAlign: "left",
|
|
375
|
+
titleAlign: "center"
|
|
376
|
+
});
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
clack.box(summary.join("\n"), getMessage(title), {
|
|
380
|
+
width: "auto",
|
|
381
|
+
formatBorder: pc.red,
|
|
382
|
+
rounded: true,
|
|
383
|
+
withGuide: false,
|
|
384
|
+
contentAlign: "left",
|
|
385
|
+
titleAlign: "center"
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
context.on("lifecycle:end", () => {
|
|
389
|
+
for (const [_key, active] of activeProgress) {
|
|
390
|
+
if (active.interval) clearInterval(active.interval);
|
|
391
|
+
active.progressBar?.stop();
|
|
392
|
+
}
|
|
393
|
+
activeProgress.clear();
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/loggers/envDetection.ts
|
|
400
|
+
/**
|
|
401
|
+
* Check if running in GitHub Actions environment
|
|
402
|
+
*/
|
|
403
|
+
function isGitHubActions() {
|
|
404
|
+
return !!process.env.GITHUB_ACTIONS;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Check if running in any CI environment
|
|
408
|
+
*/
|
|
409
|
+
function isCIEnvironment() {
|
|
410
|
+
return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.JENKINS_URL || process.env.BUILDKITE);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Check if TTY is available for interactive output
|
|
414
|
+
*/
|
|
415
|
+
function canUseTTY() {
|
|
416
|
+
return !!process.stdout.isTTY && !isCIEnvironment();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region src/loggers/fileSystemLogger.ts
|
|
421
|
+
/**
|
|
422
|
+
* FileSystem logger for debug log persistence
|
|
423
|
+
* Captures debug and verbose events and writes them to files in .kubb directory
|
|
424
|
+
*
|
|
425
|
+
* Note: Logs are written on lifecycle:end or process exit. If the process crashes
|
|
426
|
+
* before these events, some cached logs may be lost.
|
|
427
|
+
*/
|
|
428
|
+
const fileSystemLogger = defineLogger({
|
|
429
|
+
name: "filesystem",
|
|
430
|
+
install(context) {
|
|
431
|
+
const cachedLogs = /* @__PURE__ */ new Set();
|
|
432
|
+
const startDate = Date.now();
|
|
433
|
+
async function writeLogs() {
|
|
434
|
+
if (cachedLogs.size === 0) return;
|
|
435
|
+
const files = {};
|
|
436
|
+
for (const log of cachedLogs) {
|
|
437
|
+
const fileName = resolve(process.cwd(), ".kubb", log.fileName || `kubb-${startDate}.log`);
|
|
438
|
+
if (!files[fileName]) files[fileName] = [];
|
|
439
|
+
if (log.logs.length > 0) {
|
|
440
|
+
const timestamp = log.date.toLocaleString();
|
|
441
|
+
files[fileName].push(`[${timestamp}]\n${log.logs.join("\n")}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
await Promise.all(Object.entries(files).map(async ([fileName, logs]) => {
|
|
445
|
+
return write(fileName, logs.join("\n\n"));
|
|
446
|
+
}));
|
|
447
|
+
cachedLogs.clear();
|
|
448
|
+
}
|
|
449
|
+
context.on("debug", (message) => {
|
|
450
|
+
cachedLogs.add({
|
|
451
|
+
date: /* @__PURE__ */ new Date(),
|
|
452
|
+
logs: message.logs,
|
|
453
|
+
fileName: void 0
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
context.on("lifecycle:end", async () => {
|
|
457
|
+
await writeLogs();
|
|
458
|
+
});
|
|
459
|
+
const exitHandler = () => {
|
|
460
|
+
if (cachedLogs.size > 0) writeLogs().catch(() => {});
|
|
461
|
+
};
|
|
462
|
+
process.once("exit", exitHandler);
|
|
463
|
+
process.once("SIGINT", exitHandler);
|
|
464
|
+
process.once("SIGTERM", exitHandler);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region src/loggers/githubActionsLogger.ts
|
|
470
|
+
/**
|
|
471
|
+
* GitHub Actions adapter for CI environments
|
|
472
|
+
* Uses ::group:: and ::endgroup:: annotations for collapsible sections
|
|
473
|
+
*/
|
|
474
|
+
const githubActionsLogger = defineLogger({
|
|
475
|
+
name: "github-actions",
|
|
476
|
+
install(context, options) {
|
|
477
|
+
const logLevel = options?.logLevel || LogLevel.info;
|
|
478
|
+
let currentConfigs = [];
|
|
479
|
+
function getMessage(message) {
|
|
480
|
+
if (logLevel >= LogLevel.verbose) {
|
|
481
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
|
|
482
|
+
hour12: false,
|
|
483
|
+
hour: "2-digit",
|
|
484
|
+
minute: "2-digit",
|
|
485
|
+
second: "2-digit"
|
|
486
|
+
});
|
|
487
|
+
return [pc.dim(`[${timestamp}]`), message].join(" ");
|
|
488
|
+
}
|
|
489
|
+
return message;
|
|
490
|
+
}
|
|
491
|
+
function openGroup(name) {
|
|
492
|
+
console.log(`::group::${name}`);
|
|
493
|
+
}
|
|
494
|
+
function closeGroup(_name) {
|
|
495
|
+
console.log("::endgroup::");
|
|
496
|
+
}
|
|
497
|
+
context.on("info", (message, info = "") => {
|
|
498
|
+
if (logLevel <= LogLevel.silent) return;
|
|
499
|
+
const text = getMessage([
|
|
500
|
+
pc.blue("ℹ"),
|
|
501
|
+
message,
|
|
502
|
+
pc.dim(info)
|
|
503
|
+
].join(" "));
|
|
504
|
+
console.log(text);
|
|
505
|
+
});
|
|
506
|
+
context.on("success", (message, info = "") => {
|
|
507
|
+
if (logLevel <= LogLevel.silent) return;
|
|
508
|
+
const text = getMessage([
|
|
509
|
+
pc.blue("✓"),
|
|
510
|
+
message,
|
|
511
|
+
logLevel >= LogLevel.info ? pc.dim(info) : void 0
|
|
512
|
+
].filter(Boolean).join(" "));
|
|
513
|
+
console.log(text);
|
|
514
|
+
});
|
|
515
|
+
context.on("warn", (message, info = "") => {
|
|
516
|
+
if (logLevel <= LogLevel.silent) return;
|
|
517
|
+
const text = getMessage([
|
|
518
|
+
pc.yellow("⚠"),
|
|
519
|
+
message,
|
|
520
|
+
logLevel >= LogLevel.info ? pc.dim(info) : void 0
|
|
521
|
+
].filter(Boolean).join(" "));
|
|
522
|
+
console.warn(`::warning::${text}`);
|
|
523
|
+
});
|
|
524
|
+
context.on("error", (error) => {
|
|
525
|
+
if (logLevel <= LogLevel.silent) return;
|
|
526
|
+
const message = error.message || String(error);
|
|
527
|
+
console.error(`::error::${message}`);
|
|
528
|
+
});
|
|
529
|
+
context.on("lifecycle:start", (version$1) => {
|
|
530
|
+
console.log(pc.yellow(`Kubb ${version$1} 🧩`));
|
|
531
|
+
});
|
|
532
|
+
context.on("config:start", () => {
|
|
533
|
+
if (logLevel <= LogLevel.silent) return;
|
|
534
|
+
const text = getMessage("Configuration started");
|
|
535
|
+
openGroup("Configuration");
|
|
536
|
+
console.log(text);
|
|
537
|
+
});
|
|
538
|
+
context.on("config:end", (configs) => {
|
|
539
|
+
currentConfigs = configs;
|
|
540
|
+
if (logLevel <= LogLevel.silent) return;
|
|
541
|
+
const text = getMessage("Configuration completed");
|
|
542
|
+
console.log(text);
|
|
543
|
+
closeGroup("Configuration");
|
|
544
|
+
});
|
|
545
|
+
context.on("generation:start", (config) => {
|
|
546
|
+
const text = config.name ? `Generation for ${pc.bold(config.name)}` : "Generation";
|
|
547
|
+
if (currentConfigs.length > 1) openGroup(text);
|
|
548
|
+
if (currentConfigs.length === 1) console.log(getMessage(text));
|
|
549
|
+
});
|
|
550
|
+
context.on("plugin:start", (plugin) => {
|
|
551
|
+
if (logLevel <= LogLevel.silent) return;
|
|
552
|
+
const text = getMessage(`Generating ${pc.bold(plugin.name)}`);
|
|
553
|
+
if (currentConfigs.length === 1) openGroup(`Plugin: ${plugin.name}`);
|
|
554
|
+
console.log(text);
|
|
555
|
+
});
|
|
556
|
+
context.on("plugin:end", (plugin, duration) => {
|
|
557
|
+
if (logLevel <= LogLevel.silent) return;
|
|
558
|
+
const durationStr = duration >= 1e3 ? `${(duration / 1e3).toFixed(2)}s` : `${duration}ms`;
|
|
559
|
+
const text = getMessage(`${pc.bold(plugin.name)} completed in ${pc.green(durationStr)}`);
|
|
560
|
+
console.log(text);
|
|
561
|
+
if (currentConfigs.length > 1) console.log(" ");
|
|
562
|
+
if (currentConfigs.length === 1) closeGroup(`Plugin: ${plugin.name}`);
|
|
563
|
+
});
|
|
564
|
+
context.on("files:processing:start", (files) => {
|
|
565
|
+
if (logLevel <= LogLevel.silent) return;
|
|
566
|
+
if (currentConfigs.length === 1) openGroup("File Generation");
|
|
567
|
+
const text = getMessage(`Writing ${files.length} files`);
|
|
568
|
+
console.log(text);
|
|
569
|
+
});
|
|
570
|
+
context.on("files:processing:end", () => {
|
|
571
|
+
if (logLevel <= LogLevel.silent) return;
|
|
572
|
+
const text = getMessage("Files written successfully");
|
|
573
|
+
console.log(text);
|
|
574
|
+
if (currentConfigs.length === 1) closeGroup("File Generation");
|
|
575
|
+
});
|
|
576
|
+
context.on("generation:end", (config) => {
|
|
577
|
+
const text = getMessage(config.name ? `${pc.blue("✓")} Generation completed for ${pc.dim(config.name)}` : `${pc.blue("✓")} Generation completed`);
|
|
578
|
+
console.log(text);
|
|
579
|
+
});
|
|
580
|
+
context.on("hook:execute", async ({ command: command$1, args }, cb) => {
|
|
581
|
+
try {
|
|
582
|
+
const result = await execa(command$1, args, {
|
|
583
|
+
detached: true,
|
|
584
|
+
stripFinalNewline: true
|
|
585
|
+
});
|
|
586
|
+
await context.emit("debug", {
|
|
587
|
+
date: /* @__PURE__ */ new Date(),
|
|
588
|
+
logs: [result.stdout]
|
|
589
|
+
});
|
|
590
|
+
console.log(result.stdout);
|
|
591
|
+
cb();
|
|
592
|
+
} catch (err) {
|
|
593
|
+
const error = /* @__PURE__ */ new Error("Hook execute failed");
|
|
594
|
+
error.cause = err;
|
|
595
|
+
await context.emit("debug", {
|
|
596
|
+
date: /* @__PURE__ */ new Date(),
|
|
597
|
+
logs: [err.stdout]
|
|
598
|
+
});
|
|
599
|
+
await context.emit("error", error);
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
context.on("format:start", () => {
|
|
603
|
+
if (logLevel <= LogLevel.silent) return;
|
|
604
|
+
const text = getMessage("Format started");
|
|
605
|
+
if (currentConfigs.length === 1) openGroup("Formatting");
|
|
606
|
+
console.log(text);
|
|
607
|
+
});
|
|
608
|
+
context.on("format:end", () => {
|
|
609
|
+
if (logLevel <= LogLevel.silent) return;
|
|
610
|
+
const text = getMessage("Format completed");
|
|
611
|
+
console.log(text);
|
|
612
|
+
if (currentConfigs.length === 1) closeGroup("Formatting");
|
|
613
|
+
});
|
|
614
|
+
context.on("lint:start", () => {
|
|
615
|
+
if (logLevel <= LogLevel.silent) return;
|
|
616
|
+
const text = getMessage("Lint started");
|
|
617
|
+
if (currentConfigs.length === 1) openGroup("Linting");
|
|
618
|
+
console.log(text);
|
|
619
|
+
});
|
|
620
|
+
context.on("lint:end", () => {
|
|
621
|
+
if (logLevel <= LogLevel.silent) return;
|
|
622
|
+
const text = getMessage("Lint completed");
|
|
623
|
+
console.log(text);
|
|
624
|
+
if (currentConfigs.length === 1) closeGroup("Linting");
|
|
625
|
+
});
|
|
626
|
+
context.on("hook:start", (command$1) => {
|
|
627
|
+
if (logLevel <= LogLevel.silent) return;
|
|
628
|
+
const text = getMessage(`Hook ${pc.dim(command$1)} started`);
|
|
629
|
+
if (currentConfigs.length === 1) openGroup(`Hook ${command$1}`);
|
|
630
|
+
console.log(text);
|
|
631
|
+
});
|
|
632
|
+
context.on("hook:end", (command$1) => {
|
|
633
|
+
if (logLevel <= LogLevel.silent) return;
|
|
634
|
+
const text = getMessage(`Hook ${pc.dim(command$1)} completed`);
|
|
635
|
+
console.log(text);
|
|
636
|
+
if (currentConfigs.length === 1) closeGroup(`Hook ${command$1}`);
|
|
637
|
+
});
|
|
638
|
+
context.on("generation:summary", (config, { status, failedPlugins }) => {
|
|
639
|
+
const pluginsCount = config.plugins?.length || 0;
|
|
640
|
+
const successCount = pluginsCount - failedPlugins.size;
|
|
641
|
+
if (currentConfigs.length > 1) console.log(" ");
|
|
642
|
+
console.log(status === "success" ? `Kubb Summary: ${pc.blue("✓")} ${`${successCount} successful`}, ${pluginsCount} total` : `Kubb Summary: ${pc.blue("✓")} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total`);
|
|
643
|
+
if (currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${pc.bold(config.name)}` : "Generation");
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
//#endregion
|
|
649
|
+
//#region src/loggers/plainLogger.ts
|
|
650
|
+
/**
|
|
651
|
+
* Plain console adapter for non-TTY environments
|
|
652
|
+
* Simple console.log output with indentation
|
|
653
|
+
*/
|
|
654
|
+
const plainLogger = defineLogger({
|
|
655
|
+
name: "plain",
|
|
656
|
+
install(context, options) {
|
|
657
|
+
const logLevel = options?.logLevel || 3;
|
|
658
|
+
function getMessage(message) {
|
|
659
|
+
if (logLevel >= LogLevel.verbose) return [`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
|
|
660
|
+
hour12: false,
|
|
661
|
+
hour: "2-digit",
|
|
662
|
+
minute: "2-digit",
|
|
663
|
+
second: "2-digit"
|
|
664
|
+
})}]`, message].join(" ");
|
|
665
|
+
return message;
|
|
666
|
+
}
|
|
667
|
+
context.on("info", (message, info) => {
|
|
668
|
+
if (logLevel <= LogLevel.silent) return;
|
|
669
|
+
const text = getMessage([
|
|
670
|
+
"ℹ",
|
|
671
|
+
message,
|
|
672
|
+
info
|
|
673
|
+
].join(" "));
|
|
674
|
+
console.log(text);
|
|
675
|
+
});
|
|
676
|
+
context.on("success", (message, info = "") => {
|
|
677
|
+
if (logLevel <= LogLevel.silent) return;
|
|
678
|
+
const text = getMessage([
|
|
679
|
+
"✓",
|
|
680
|
+
message,
|
|
681
|
+
logLevel >= LogLevel.info ? info : void 0
|
|
682
|
+
].filter(Boolean).join(" "));
|
|
683
|
+
console.log(text);
|
|
684
|
+
});
|
|
685
|
+
context.on("warn", (message, info) => {
|
|
686
|
+
if (logLevel < LogLevel.warn) return;
|
|
687
|
+
const text = getMessage([
|
|
688
|
+
"⚠",
|
|
689
|
+
message,
|
|
690
|
+
logLevel >= LogLevel.info ? info : void 0
|
|
691
|
+
].filter(Boolean).join(" "));
|
|
692
|
+
console.log(text);
|
|
693
|
+
});
|
|
694
|
+
context.on("error", (error) => {
|
|
695
|
+
const caused = error.cause;
|
|
696
|
+
const text = getMessage(["✗", error.message].join(" "));
|
|
697
|
+
console.log(text);
|
|
698
|
+
if (logLevel >= LogLevel.debug && error.stack) {
|
|
699
|
+
const frames = error.stack.split("\n").slice(1, 4);
|
|
700
|
+
for (const frame of frames) console.log(getMessage(frame.trim()));
|
|
701
|
+
if (caused?.stack) {
|
|
702
|
+
console.log(`└─ caused by ${caused.message}`);
|
|
703
|
+
const frames$1 = caused.stack.split("\n").slice(1, 4);
|
|
704
|
+
for (const frame of frames$1) console.log(getMessage(` ${frame.trim()}`));
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
context.on("lifecycle:start", () => {
|
|
709
|
+
console.log("Kubb CLI 🧩");
|
|
710
|
+
});
|
|
711
|
+
context.on("config:start", () => {
|
|
712
|
+
if (logLevel <= LogLevel.silent) return;
|
|
713
|
+
const text = getMessage("Configuration started");
|
|
714
|
+
console.log(text);
|
|
715
|
+
});
|
|
716
|
+
context.on("config:end", () => {
|
|
717
|
+
if (logLevel <= LogLevel.silent) return;
|
|
718
|
+
const text = getMessage("Configuration completed");
|
|
719
|
+
console.log(text);
|
|
720
|
+
});
|
|
721
|
+
context.on("generation:start", () => {
|
|
722
|
+
const text = getMessage("Configuration started");
|
|
723
|
+
console.log(text);
|
|
724
|
+
});
|
|
725
|
+
context.on("plugin:start", (plugin) => {
|
|
726
|
+
if (logLevel <= LogLevel.silent) return;
|
|
727
|
+
const text = getMessage(`Generating ${plugin.name}`);
|
|
728
|
+
console.log(text);
|
|
729
|
+
});
|
|
730
|
+
context.on("plugin:end", (plugin, duration) => {
|
|
731
|
+
if (logLevel <= LogLevel.silent) return;
|
|
732
|
+
const durationStr = duration >= 1e3 ? `${(duration / 1e3).toFixed(2)}s` : `${duration}ms`;
|
|
733
|
+
const text = getMessage(`${plugin.name} completed in ${durationStr}`);
|
|
734
|
+
console.log(text);
|
|
735
|
+
});
|
|
736
|
+
context.on("files:processing:start", (files) => {
|
|
737
|
+
if (logLevel <= LogLevel.silent) return;
|
|
738
|
+
const text = getMessage(`Writing ${files.length} files`);
|
|
739
|
+
console.log(text);
|
|
740
|
+
});
|
|
741
|
+
context.on("file:processing:update", ({ file, config }) => {
|
|
742
|
+
if (logLevel <= LogLevel.silent) return;
|
|
743
|
+
const text = getMessage(`Writing ${relative(config.root, file.path)}`);
|
|
744
|
+
console.log(text);
|
|
745
|
+
});
|
|
746
|
+
context.on("files:processing:end", () => {
|
|
747
|
+
if (logLevel <= LogLevel.silent) return;
|
|
748
|
+
const text = getMessage("Files written successfully");
|
|
749
|
+
console.log(text);
|
|
750
|
+
});
|
|
751
|
+
context.on("generation:end", (config) => {
|
|
752
|
+
const text = getMessage(config.name ? `Generation completed for ${config.name}` : "Generation completed");
|
|
753
|
+
console.log(text);
|
|
754
|
+
});
|
|
755
|
+
context.on("hook:execute", async ({ command: command$1, args }, cb) => {
|
|
756
|
+
try {
|
|
757
|
+
const result = await execa(command$1, args, {
|
|
758
|
+
detached: true,
|
|
759
|
+
stripFinalNewline: true
|
|
760
|
+
});
|
|
761
|
+
await context.emit("debug", {
|
|
762
|
+
date: /* @__PURE__ */ new Date(),
|
|
763
|
+
logs: [result.stdout]
|
|
764
|
+
});
|
|
765
|
+
console.log(result.stdout);
|
|
766
|
+
cb();
|
|
767
|
+
} catch (err) {
|
|
768
|
+
const error = /* @__PURE__ */ new Error("Hook execute failed");
|
|
769
|
+
error.cause = err;
|
|
770
|
+
await context.emit("debug", {
|
|
771
|
+
date: /* @__PURE__ */ new Date(),
|
|
772
|
+
logs: [err.stdout]
|
|
773
|
+
});
|
|
774
|
+
await context.emit("error", error);
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
context.on("format:start", () => {
|
|
778
|
+
if (logLevel <= LogLevel.silent) return;
|
|
779
|
+
const text = getMessage("Format started");
|
|
780
|
+
console.log(text);
|
|
781
|
+
});
|
|
782
|
+
context.on("format:end", () => {
|
|
783
|
+
if (logLevel <= LogLevel.silent) return;
|
|
784
|
+
const text = getMessage("Format completed");
|
|
785
|
+
console.log(text);
|
|
786
|
+
});
|
|
787
|
+
context.on("lint:start", () => {
|
|
788
|
+
if (logLevel <= LogLevel.silent) return;
|
|
789
|
+
const text = getMessage("Lint started");
|
|
790
|
+
console.log(text);
|
|
791
|
+
});
|
|
792
|
+
context.on("lint:end", () => {
|
|
793
|
+
if (logLevel <= LogLevel.silent) return;
|
|
794
|
+
const text = getMessage("Lint completed");
|
|
795
|
+
console.log(text);
|
|
796
|
+
});
|
|
797
|
+
context.on("hook:start", (command$1) => {
|
|
798
|
+
if (logLevel <= LogLevel.silent) return;
|
|
799
|
+
const text = getMessage(`Hook ${command$1} started`);
|
|
800
|
+
console.log(text);
|
|
801
|
+
});
|
|
802
|
+
context.on("hook:end", (command$1) => {
|
|
803
|
+
if (logLevel <= LogLevel.silent) return;
|
|
804
|
+
const text = getMessage(`Hook ${command$1} completed`);
|
|
805
|
+
console.log(text);
|
|
806
|
+
});
|
|
807
|
+
context.on("generation:summary", (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
|
|
808
|
+
const summary = getSummary({
|
|
809
|
+
failedPlugins,
|
|
810
|
+
filesCreated,
|
|
811
|
+
config,
|
|
812
|
+
status,
|
|
813
|
+
hrStart,
|
|
814
|
+
pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : void 0
|
|
815
|
+
});
|
|
816
|
+
console.log("---------------------------");
|
|
817
|
+
console.log(summary.join("\n"));
|
|
818
|
+
console.log("---------------------------");
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
//#endregion
|
|
824
|
+
//#region src/loggers/utils.ts
|
|
825
|
+
function detectLogger() {
|
|
826
|
+
if (isGitHubActions()) return "github-actions";
|
|
827
|
+
if (canUseTTY()) return "clack";
|
|
828
|
+
return "plain";
|
|
829
|
+
}
|
|
830
|
+
const logMapper = {
|
|
831
|
+
clack: clackLogger,
|
|
832
|
+
plain: plainLogger,
|
|
833
|
+
"github-actions": githubActionsLogger
|
|
834
|
+
};
|
|
835
|
+
async function setupLogger(context, { logLevel }) {
|
|
836
|
+
const type = detectLogger();
|
|
837
|
+
const logger = logMapper[type];
|
|
838
|
+
if (!logger) throw new Error(`Unknown adapter type: ${type}`);
|
|
839
|
+
const cleanup = await logger.install(context, { logLevel });
|
|
840
|
+
if (logLevel >= LogLevel.debug) await fileSystemLogger.install(context, { logLevel });
|
|
841
|
+
return cleanup;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
//#endregion
|
|
845
|
+
//#region src/utils/executeHooks.ts
|
|
846
|
+
async function executeHooks({ hooks, events }) {
|
|
847
|
+
const commands = Array.isArray(hooks.done) ? hooks.done : [hooks.done].filter(Boolean);
|
|
848
|
+
for (const command$1 of commands) {
|
|
849
|
+
const [cmd, ...args] = [...parseArgsStringToArgv(command$1)];
|
|
850
|
+
if (!cmd) continue;
|
|
851
|
+
await events.emit("hook:start", command$1);
|
|
852
|
+
await events.emit("hook:execute", {
|
|
853
|
+
command: cmd,
|
|
854
|
+
args
|
|
855
|
+
}, async () => {
|
|
856
|
+
await events.emit("success", `${pc.dim(command$1)} successfully executed`);
|
|
857
|
+
await events.emit("hook:end", command$1);
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
//#endregion
|
|
863
|
+
//#region src/runners/generate.ts
|
|
864
|
+
async function generate({ input, config, events, logLevel }) {
|
|
865
|
+
const { root = process$1.cwd(), ...userConfig } = config;
|
|
866
|
+
const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0);
|
|
867
|
+
const hrStart = process$1.hrtime();
|
|
868
|
+
const definedConfig = {
|
|
869
|
+
root,
|
|
870
|
+
...userConfig,
|
|
871
|
+
input: inputPath ? {
|
|
872
|
+
...userConfig.input,
|
|
873
|
+
path: inputPath
|
|
874
|
+
} : userConfig.input,
|
|
875
|
+
output: {
|
|
876
|
+
write: true,
|
|
877
|
+
barrelType: "named",
|
|
878
|
+
extension: { ".ts": ".ts" },
|
|
879
|
+
format: "prettier",
|
|
880
|
+
...userConfig.output
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
await events.emit("generation:start", definedConfig);
|
|
884
|
+
await events.emit("info", config.name ? `Setup generation ${pc.bold(config.name)}` : "Setup generation", inputPath);
|
|
885
|
+
const { fabric, pluginManager } = await setup({
|
|
886
|
+
config: definedConfig,
|
|
887
|
+
events
|
|
888
|
+
});
|
|
889
|
+
await events.emit("info", config.name ? `Build generation ${pc.bold(config.name)}` : "Build generation", inputPath);
|
|
890
|
+
const { files, failedPlugins, pluginTimings, error } = await safeBuild({
|
|
891
|
+
config: definedConfig,
|
|
892
|
+
events
|
|
893
|
+
}, {
|
|
894
|
+
pluginManager,
|
|
895
|
+
fabric,
|
|
896
|
+
events
|
|
897
|
+
});
|
|
898
|
+
await events.emit("info", "Load summary");
|
|
899
|
+
if (failedPlugins.size > 0 || error) {
|
|
900
|
+
[error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean).forEach((err) => {
|
|
901
|
+
events.emit("error", err);
|
|
902
|
+
});
|
|
903
|
+
await events.emit("generation:end", definedConfig);
|
|
904
|
+
await events.emit("generation:summary", definedConfig, {
|
|
905
|
+
failedPlugins,
|
|
906
|
+
filesCreated: files.length,
|
|
907
|
+
status: failedPlugins.size > 0 || error ? "failed" : "success",
|
|
908
|
+
hrStart,
|
|
909
|
+
pluginTimings: logLevel >= LogLevel.verbose ? pluginTimings : void 0
|
|
910
|
+
});
|
|
911
|
+
process$1.exit(1);
|
|
912
|
+
}
|
|
913
|
+
await events.emit("success", "Generation successfully", inputPath);
|
|
914
|
+
await events.emit("generation:end", definedConfig);
|
|
915
|
+
if (config.output.format) {
|
|
916
|
+
await events.emit("format:start");
|
|
917
|
+
await events.emit("info", [`Formatting with ${pc.dim(config.output.format)}`, logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0].filter(Boolean).join(" "));
|
|
918
|
+
if (config.output.format === "prettier") {
|
|
919
|
+
try {
|
|
920
|
+
await events.emit("hook:execute", {
|
|
921
|
+
command: "prettier",
|
|
922
|
+
args: [
|
|
923
|
+
"--ignore-unknown",
|
|
924
|
+
"--write",
|
|
925
|
+
path.resolve(definedConfig.root, definedConfig.output.path)
|
|
926
|
+
]
|
|
927
|
+
}, async () => {
|
|
928
|
+
await events.emit("success", [
|
|
929
|
+
`Formatting with ${pc.dim(config.output.format)}`,
|
|
930
|
+
logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0,
|
|
931
|
+
"successfully"
|
|
932
|
+
].filter(Boolean).join(" "));
|
|
933
|
+
});
|
|
934
|
+
} catch (e) {
|
|
935
|
+
await events.emit("error", e);
|
|
936
|
+
}
|
|
937
|
+
await events.emit("success", `Formatted with ${config.output.format}`);
|
|
938
|
+
}
|
|
939
|
+
if (config.output.format === "biome") try {
|
|
940
|
+
await events.emit("hook:execute", {
|
|
941
|
+
command: "biome",
|
|
942
|
+
args: [
|
|
943
|
+
"format",
|
|
944
|
+
"--write",
|
|
945
|
+
path.resolve(definedConfig.root, definedConfig.output.path)
|
|
946
|
+
]
|
|
947
|
+
}, async () => {
|
|
948
|
+
await events.emit("success", [
|
|
949
|
+
`Formatting with ${pc.dim(config.output.format)}`,
|
|
950
|
+
logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0,
|
|
951
|
+
"successfully"
|
|
952
|
+
].filter(Boolean).join(" "));
|
|
953
|
+
});
|
|
954
|
+
} catch (e) {
|
|
955
|
+
const error$1 = /* @__PURE__ */ new Error("Biome not found");
|
|
956
|
+
error$1.cause = e;
|
|
957
|
+
await events.emit("error", error$1);
|
|
958
|
+
}
|
|
959
|
+
await events.emit("format:end");
|
|
960
|
+
}
|
|
961
|
+
if (config.output.lint) {
|
|
962
|
+
await events.emit("lint:start");
|
|
963
|
+
await events.emit("info", [`Linting with ${pc.dim(config.output.lint)}`, logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0].filter(Boolean).join(" "));
|
|
964
|
+
if (config.output.lint === "eslint") try {
|
|
965
|
+
await events.emit("hook:execute", {
|
|
966
|
+
command: "eslint",
|
|
967
|
+
args: [path.resolve(definedConfig.root, definedConfig.output.path), "--fix"]
|
|
968
|
+
}, async () => {
|
|
969
|
+
await events.emit("success", [
|
|
970
|
+
`Linted with ${pc.dim(config.output.lint)}`,
|
|
971
|
+
logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0,
|
|
972
|
+
"successfully"
|
|
973
|
+
].filter(Boolean).join(" "));
|
|
974
|
+
});
|
|
975
|
+
} catch (e) {
|
|
976
|
+
const error$1 = /* @__PURE__ */ new Error("Eslint not found");
|
|
977
|
+
error$1.cause = e;
|
|
978
|
+
await events.emit("error", error$1);
|
|
979
|
+
}
|
|
980
|
+
if (config.output.lint === "biome") try {
|
|
981
|
+
await events.emit("hook:execute", {
|
|
982
|
+
command: "biome",
|
|
983
|
+
args: [
|
|
984
|
+
"lint",
|
|
985
|
+
"--fix",
|
|
986
|
+
path.resolve(definedConfig.root, definedConfig.output.path)
|
|
987
|
+
]
|
|
988
|
+
}, async () => {
|
|
989
|
+
await events.emit("success", [
|
|
990
|
+
`Linted with ${pc.dim(config.output.lint)}`,
|
|
991
|
+
logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0,
|
|
992
|
+
"successfully"
|
|
993
|
+
].filter(Boolean).join(" "));
|
|
994
|
+
});
|
|
995
|
+
} catch (e) {
|
|
996
|
+
const error$1 = /* @__PURE__ */ new Error("Biome not found");
|
|
997
|
+
error$1.cause = e;
|
|
998
|
+
await events.emit("error", error$1);
|
|
999
|
+
}
|
|
1000
|
+
if (config.output.lint === "oxlint") try {
|
|
1001
|
+
await events.emit("hook:execute", {
|
|
1002
|
+
command: "oxlint",
|
|
1003
|
+
args: ["--fix", path.resolve(definedConfig.root, definedConfig.output.path)]
|
|
1004
|
+
}, async () => {
|
|
1005
|
+
await events.emit("success", [
|
|
1006
|
+
`Linted with ${pc.dim(config.output.lint)}`,
|
|
1007
|
+
logLevel >= LogLevel.info ? `on ${pc.dim(path.resolve(definedConfig.root, definedConfig.output.path))}` : void 0,
|
|
1008
|
+
"successfully"
|
|
1009
|
+
].filter(Boolean).join(" "));
|
|
1010
|
+
});
|
|
1011
|
+
} catch (e) {
|
|
1012
|
+
const error$1 = /* @__PURE__ */ new Error("Oxlint not found");
|
|
1013
|
+
error$1.cause = e;
|
|
1014
|
+
await events.emit("error", error$1);
|
|
1015
|
+
}
|
|
1016
|
+
await events.emit("lint:end");
|
|
1017
|
+
}
|
|
1018
|
+
if (config.hooks) {
|
|
1019
|
+
await events.emit("hooks:start");
|
|
1020
|
+
await executeHooks({
|
|
1021
|
+
hooks: config.hooks,
|
|
1022
|
+
events
|
|
1023
|
+
});
|
|
1024
|
+
await events.emit("hooks:end");
|
|
1025
|
+
}
|
|
1026
|
+
await events.emit("generation:summary", definedConfig, {
|
|
1027
|
+
failedPlugins,
|
|
1028
|
+
filesCreated: files.length,
|
|
1029
|
+
status: failedPlugins.size > 0 || error ? "failed" : "success",
|
|
1030
|
+
hrStart,
|
|
1031
|
+
pluginTimings
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
//#endregion
|
|
1036
|
+
//#region src/utils/getPlugins.ts
|
|
1037
|
+
function isJSONPlugins(plugins) {
|
|
1038
|
+
return !!plugins?.some((plugin) => {
|
|
1039
|
+
return Array.isArray(plugin) && typeof plugin?.at(0) === "string";
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
function isObjectPlugins(plugins) {
|
|
1043
|
+
return plugins instanceof Object && !Array.isArray(plugins);
|
|
1044
|
+
}
|
|
1045
|
+
function getPlugins(plugins) {
|
|
1046
|
+
if (isObjectPlugins(plugins)) throw new Error("Object plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json");
|
|
1047
|
+
if (isJSONPlugins(plugins)) throw new Error("JSON plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json");
|
|
1048
|
+
return Promise.resolve(plugins);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
//#endregion
|
|
1052
|
+
//#region src/utils/getConfig.ts
|
|
1053
|
+
/**
|
|
1054
|
+
* Converting UserConfig to Config without a change in the object beside the JSON convert.
|
|
1055
|
+
*/
|
|
1056
|
+
async function getConfig(result, args) {
|
|
1057
|
+
const config = result?.config;
|
|
1058
|
+
let kubbUserConfig = Promise.resolve(config);
|
|
1059
|
+
if (typeof config === "function") {
|
|
1060
|
+
const possiblePromise = config(args);
|
|
1061
|
+
if (isPromise(possiblePromise)) kubbUserConfig = possiblePromise;
|
|
1062
|
+
kubbUserConfig = Promise.resolve(possiblePromise);
|
|
1063
|
+
}
|
|
1064
|
+
let JSONConfig = await kubbUserConfig;
|
|
1065
|
+
if (Array.isArray(JSONConfig)) {
|
|
1066
|
+
const results = [];
|
|
1067
|
+
for (const item of JSONConfig) {
|
|
1068
|
+
const plugins = item.plugins ? await getPlugins(item.plugins) : void 0;
|
|
1069
|
+
results.push({
|
|
1070
|
+
...item,
|
|
1071
|
+
plugins
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
return results;
|
|
1075
|
+
}
|
|
1076
|
+
JSONConfig = {
|
|
1077
|
+
...JSONConfig,
|
|
1078
|
+
plugins: JSONConfig.plugins ? await getPlugins(JSONConfig.plugins) : void 0
|
|
1079
|
+
};
|
|
1080
|
+
return JSONConfig;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
//#endregion
|
|
1084
|
+
//#region src/utils/getCosmiConfig.ts
|
|
1085
|
+
const tsLoader = async (configFile) => {
|
|
1086
|
+
return await createJiti(import.meta.url, {
|
|
1087
|
+
jsx: {
|
|
1088
|
+
runtime: "automatic",
|
|
1089
|
+
importSource: "@kubb/react-fabric"
|
|
1090
|
+
},
|
|
1091
|
+
sourceMaps: true
|
|
1092
|
+
}).import(configFile, { default: true });
|
|
1093
|
+
};
|
|
1094
|
+
async function getCosmiConfig(moduleName, config) {
|
|
1095
|
+
let result;
|
|
1096
|
+
const searchPlaces = [
|
|
1097
|
+
"package.json",
|
|
1098
|
+
`.${moduleName}rc`,
|
|
1099
|
+
`.${moduleName}rc.json`,
|
|
1100
|
+
`.${moduleName}rc.yaml`,
|
|
1101
|
+
`.${moduleName}rc.yml`,
|
|
1102
|
+
`.${moduleName}rc.ts`,
|
|
1103
|
+
`.${moduleName}rc.js`,
|
|
1104
|
+
`.${moduleName}rc.mjs`,
|
|
1105
|
+
`.${moduleName}rc.cjs`,
|
|
1106
|
+
`${moduleName}.config.ts`,
|
|
1107
|
+
`${moduleName}.config.js`,
|
|
1108
|
+
`${moduleName}.config.mjs`,
|
|
1109
|
+
`${moduleName}.config.cjs`
|
|
1110
|
+
];
|
|
1111
|
+
const explorer = cosmiconfig(moduleName, {
|
|
1112
|
+
cache: false,
|
|
1113
|
+
searchPlaces: [
|
|
1114
|
+
...searchPlaces.map((searchPlace) => {
|
|
1115
|
+
return `.config/${searchPlace}`;
|
|
1116
|
+
}),
|
|
1117
|
+
...searchPlaces.map((searchPlace) => {
|
|
1118
|
+
return `configs/${searchPlace}`;
|
|
1119
|
+
}),
|
|
1120
|
+
...searchPlaces
|
|
1121
|
+
],
|
|
1122
|
+
loaders: { ".ts": tsLoader }
|
|
1123
|
+
});
|
|
1124
|
+
try {
|
|
1125
|
+
result = config ? await explorer.load(config) : await explorer.search();
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
throw new Error("Config failed loading", { cause: e });
|
|
1128
|
+
}
|
|
1129
|
+
if (result?.isEmpty || !result || !result.config) throw new Error("Config not defined, create a kubb.config.js or pass through your config with the option --config");
|
|
1130
|
+
return result;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
//#endregion
|
|
1134
|
+
//#region src/utils/watcher.ts
|
|
1135
|
+
async function startWatcher(path$1, cb) {
|
|
1136
|
+
const { watch } = await import("chokidar");
|
|
1137
|
+
watch(path$1, {
|
|
1138
|
+
ignorePermissionErrors: true,
|
|
1139
|
+
ignored: "**/{.git,node_modules}/**"
|
|
1140
|
+
}).on("all", (type, file) => {
|
|
1141
|
+
console.log(pc.yellow(pc.bold(`Change detected: ${type} ${file}`)));
|
|
1142
|
+
try {
|
|
1143
|
+
cb(path$1);
|
|
1144
|
+
} catch (_e) {
|
|
1145
|
+
console.log(pc.red("Watcher failed"));
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
//#endregion
|
|
1151
|
+
//#region src/commands/generate.ts
|
|
1152
|
+
const command = defineCommand({
|
|
1153
|
+
meta: {
|
|
1154
|
+
name: "generate",
|
|
1155
|
+
description: "[input] Generate files based on a 'kubb.config.ts' file"
|
|
1156
|
+
},
|
|
1157
|
+
args: {
|
|
1158
|
+
config: {
|
|
1159
|
+
type: "string",
|
|
1160
|
+
description: "Path to the Kubb config",
|
|
1161
|
+
alias: "c"
|
|
1162
|
+
},
|
|
1163
|
+
logLevel: {
|
|
1164
|
+
type: "string",
|
|
1165
|
+
description: "Info, silent, verbose or debug",
|
|
1166
|
+
alias: "l",
|
|
1167
|
+
default: "info",
|
|
1168
|
+
valueHint: "silent|info|verbose|debug"
|
|
1169
|
+
},
|
|
1170
|
+
watch: {
|
|
1171
|
+
type: "boolean",
|
|
1172
|
+
description: "Watch mode based on the input file",
|
|
1173
|
+
alias: "w",
|
|
1174
|
+
default: false
|
|
1175
|
+
},
|
|
1176
|
+
debug: {
|
|
1177
|
+
type: "boolean",
|
|
1178
|
+
description: "Override logLevel to debug",
|
|
1179
|
+
alias: "d",
|
|
1180
|
+
default: false
|
|
1181
|
+
},
|
|
1182
|
+
verbose: {
|
|
1183
|
+
type: "boolean",
|
|
1184
|
+
description: "Override logLevel to verbose",
|
|
1185
|
+
alias: "v",
|
|
1186
|
+
default: false
|
|
1187
|
+
},
|
|
1188
|
+
help: {
|
|
1189
|
+
type: "boolean",
|
|
1190
|
+
description: "Show help",
|
|
1191
|
+
alias: "h",
|
|
1192
|
+
default: false
|
|
1193
|
+
}
|
|
1194
|
+
},
|
|
1195
|
+
async run(commandContext) {
|
|
1196
|
+
const { args } = commandContext;
|
|
1197
|
+
const input = args._[0];
|
|
1198
|
+
const events = new AsyncEventEmitter();
|
|
1199
|
+
const promiseManager = new PromiseManager();
|
|
1200
|
+
if (args.help) return showUsage(command);
|
|
1201
|
+
if (args.debug) args.logLevel = "debug";
|
|
1202
|
+
if (args.verbose) args.logLevel = "verbose";
|
|
1203
|
+
const logLevel = LogLevel[args.logLevel] || 3;
|
|
1204
|
+
await setupLogger(events, { logLevel });
|
|
1205
|
+
const latestVersion = await getLatestVersion("@kubb/cli");
|
|
1206
|
+
if (lt(version, latestVersion)) await events.emit("version:new", version, latestVersion);
|
|
1207
|
+
try {
|
|
1208
|
+
await events.emit("lifecycle:start", version);
|
|
1209
|
+
await events.emit("config:start");
|
|
1210
|
+
const result = await getCosmiConfig("kubb", args.config);
|
|
1211
|
+
await events.emit("info", "Config loaded", path.relative(process$2.cwd(), result.filepath));
|
|
1212
|
+
const config = await getConfig(result, args);
|
|
1213
|
+
const configs = Array.isArray(config) ? config : [config];
|
|
1214
|
+
await events.emit("success", "Config loaded successfully", path.relative(process$2.cwd(), result.filepath));
|
|
1215
|
+
await events.emit("config:end", configs);
|
|
1216
|
+
const promises = configs.map((config$1) => {
|
|
1217
|
+
return async () => {
|
|
1218
|
+
if (isInputPath(config$1) && args.watch) {
|
|
1219
|
+
await startWatcher([input || config$1.input.path], async (paths) => {
|
|
1220
|
+
await generate({
|
|
1221
|
+
input,
|
|
1222
|
+
config: config$1,
|
|
1223
|
+
logLevel,
|
|
1224
|
+
events
|
|
1225
|
+
});
|
|
1226
|
+
clack.log.step(pc.yellow(`Watching for changes in ${paths.join(" and ")}`));
|
|
1227
|
+
});
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
await generate({
|
|
1231
|
+
input,
|
|
1232
|
+
config: config$1,
|
|
1233
|
+
logLevel,
|
|
1234
|
+
events
|
|
1235
|
+
});
|
|
1236
|
+
};
|
|
1237
|
+
});
|
|
1238
|
+
await promiseManager.run("seq", promises);
|
|
1239
|
+
await events.emit("lifecycle:end");
|
|
1240
|
+
} catch (e) {
|
|
1241
|
+
await events.emit("error", e);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
var generate_default = command;
|
|
1246
|
+
|
|
1247
|
+
//#endregion
|
|
1248
|
+
export { generate_default as default };
|
|
1249
|
+
//# sourceMappingURL=generate-BvrG5K00.js.map
|