@kubb/cli
Version:
Command-line interface for Kubb, enabling easy generation of TypeScript, React-Query, Zod, and other code from OpenAPI specifications.
1,372 lines (1,357 loc) • 53.8 kB
JavaScript
const require_chunk = require('./chunk-CNbaEX1y.cjs');
const require_package = require('./package-oo3QhWS5.cjs');
let citty = require("citty");
let node_path = require("node:path");
node_path = require_chunk.__toESM(node_path);
let node_process = require("node:process");
node_process = require_chunk.__toESM(node_process);
let node_util = require("node:util");
let _clack_prompts = require("@clack/prompts");
_clack_prompts = require_chunk.__toESM(_clack_prompts);
let _kubb_core = require("@kubb/core");
let _kubb_core_utils = require("@kubb/core/utils");
let tinyexec = require("tinyexec");
let node_crypto = require("node:crypto");
let node_stream = require("node:stream");
let _kubb_core_fs = require("@kubb/core/fs");
let cosmiconfig = require("cosmiconfig");
let jiti = require("jiti");
//#region src/utils/formatMsWithColor.ts
/**
* Formats milliseconds with color based on duration thresholds:
* - Green: <= 500ms
* - Yellow: > 500ms and <= 1000ms
* - Red: > 1000ms
*/
function formatMsWithColor(ms) {
const formatted = (0, _kubb_core_utils.formatMs)(ms);
if (ms <= 500) return (0, node_util.styleText)("green", formatted);
if (ms <= 1e3) return (0, node_util.styleText)("yellow", formatted);
return (0, node_util.styleText)("red", formatted);
}
//#endregion
//#region src/utils/getIntro.ts
/**
* ANSI True Color (24-bit) utilities for terminal output
* Supports hex color codes without external dependencies like chalk
*/
/**
* Convert hex color to ANSI 24-bit true color escape sequence
* @param color - Hex color code (with or without #), e.g., '#FF5500' or 'FF5500'
* @returns Function that wraps text with the color
*/
function hex(color) {
const cleanHex = color.replace("#", "");
const r = Number.parseInt(cleanHex.slice(0, 2), 16);
const g = Number.parseInt(cleanHex.slice(2, 4), 16);
const b = Number.parseInt(cleanHex.slice(4, 6), 16);
const safeR = Number.isNaN(r) ? 255 : r;
const safeG = Number.isNaN(g) ? 255 : g;
const safeB = Number.isNaN(b) ? 255 : b;
return (text) => `\x1b[38;2;${safeR};${safeG};${safeB}m${text}\x1b[0m`;
}
function hexToRgb(color) {
const c = color.replace("#", "");
return {
r: Number.parseInt(c.slice(0, 2), 16),
g: Number.parseInt(c.slice(2, 4), 16),
b: Number.parseInt(c.slice(4, 6), 16)
};
}
function gradient(colors) {
return (text) => {
const chars = [...text];
return chars.map((char, i) => {
const t = chars.length <= 1 ? 0 : i / (chars.length - 1);
const seg = Math.min(Math.floor(t * (colors.length - 1)), colors.length - 2);
const lt = t * (colors.length - 1) - seg;
const from = hexToRgb(colors[seg]);
const to = hexToRgb(colors[seg + 1]);
return `\x1b[38;2;${Math.round(from.r + (to.r - from.r) * lt)};${Math.round(from.g + (to.g - from.g) * lt)};${Math.round(from.b + (to.b - from.b) * lt)}m${char}\x1b[0m`;
}).join("");
};
}
const colors = {
lid: hex("#F55A17"),
woodTop: hex("#F5A217"),
woodMid: hex("#F58517"),
woodBase: hex("#B45309"),
eye: hex("#FFFFFF"),
highlight: hex("#adadc6"),
blush: hex("#FDA4AF")
};
/**
* Generates the Kubb mascot face welcome message
* @param version - The version string to display
* @returns Formatted mascot face string
*/
function getIntro({ title, description, version, areEyesOpen }) {
const kubbVersion = gradient([
"#F58517",
"#F5A217",
"#F55A17"
])(`KUBB v${version}`);
const eyeTop = areEyesOpen ? colors.eye("█▀█") : colors.eye("───");
const eyeBottom = areEyesOpen ? colors.eye("▀▀▀") : colors.eye("───");
return `
${colors.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")}
${colors.woodTop("█ ")}${colors.highlight("▄▄")}${colors.woodTop(" ")}${colors.highlight("▄▄")}${colors.woodTop(" █")} ${kubbVersion}
${colors.woodMid("█ ")}${eyeTop}${colors.woodMid(" ")}${eyeTop}${colors.woodMid(" █")} ${(0, node_util.styleText)("gray", title)}
${colors.woodMid("█ ")}${eyeBottom}${colors.woodMid(" ")}${colors.blush("◡")}${colors.woodMid(" ")}${eyeBottom}${colors.woodMid(" █")} ${(0, node_util.styleText)("yellow", "➜")} ${(0, node_util.styleText)("white", description)}
${colors.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}
`;
}
//#endregion
//#region src/utils/randomColor.ts
function randomColor(text) {
if (!text) return "white";
const defaultColors = [
"black",
"red",
"green",
"yellow",
"blue",
"red",
"green",
"magenta",
"cyan",
"gray"
];
return defaultColors[(0, node_crypto.createHash)("sha256").update(text).digest().readUInt32BE(0) % defaultColors.length] ?? "white";
}
function randomCliColor(text) {
if (!text) return "";
return (0, node_util.styleText)(randomColor(text), text);
}
//#endregion
//#region src/utils/getSummary.ts
function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
const duration = (0, _kubb_core_utils.formatHrtime)(hrStart);
const pluginsCount = config.plugins?.length || 0;
const successCount = pluginsCount - failedPlugins.size;
const meta = {
plugins: status === "success" ? `${(0, node_util.styleText)("green", `${successCount} successful`)}, ${pluginsCount} total` : `${(0, node_util.styleText)("green", `${successCount} successful`)}, ${(0, node_util.styleText)("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
pluginsFailed: status === "failed" ? [...failedPlugins]?.map(({ plugin }) => randomCliColor(plugin.name))?.join(", ") : void 0,
filesCreated,
time: (0, node_util.styleText)("green", duration),
output: node_path.default.isAbsolute(config.root) ? node_path.default.resolve(config.root, config.output.path) : config.root
};
const labels = {
plugins: "Plugins:",
failed: "Failed:",
generated: "Generated:",
pluginTimings: "Plugin Timings:",
output: "Output:"
};
const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
const summaryLines = [];
summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
if (pluginTimings && pluginTimings.size > 0) {
const TIME_SCALE_DIVISOR = 100;
const MAX_BAR_LENGTH = 10;
const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
if (sortedTimings.length > 0) {
summaryLines.push(`${labels.pluginTimings}`);
sortedTimings.forEach(([name, time]) => {
const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
const barLength = Math.min(Math.ceil(time / TIME_SCALE_DIVISOR), MAX_BAR_LENGTH);
const bar = (0, node_util.styleText)("dim", "█".repeat(barLength));
summaryLines.push(`${(0, node_util.styleText)("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
});
}
}
summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
return summaryLines;
}
//#endregion
//#region src/utils/Writables.ts
var ClackWritable = class extends node_stream.Writable {
taskLog;
constructor(taskLog, opts) {
super(opts);
this.taskLog = taskLog;
}
_write(chunk, _encoding, callback) {
this.taskLog.message(`${(0, node_util.styleText)("dim", chunk?.toString())}`);
callback();
}
};
//#endregion
//#region src/loggers/clackLogger.ts
/**
* Clack adapter for local TTY environments
* Provides a beautiful CLI UI with flat structure inspired by Claude's CLI patterns
*/
const clackLogger = (0, _kubb_core.defineLogger)({
name: "clack",
install(context, options) {
const logLevel = options?.logLevel || _kubb_core.LogLevel.info;
const state = {
totalPlugins: 0,
completedPlugins: 0,
failedPlugins: 0,
totalFiles: 0,
processedFiles: 0,
hrStart: node_process.default.hrtime(),
spinner: _clack_prompts.spinner(),
isSpinning: false,
activeProgress: /* @__PURE__ */ new Map()
};
function reset() {
for (const [_key, active] of state.activeProgress) {
if (active.interval) clearInterval(active.interval);
active.progressBar?.stop();
}
state.totalPlugins = 0;
state.completedPlugins = 0;
state.failedPlugins = 0;
state.totalFiles = 0;
state.processedFiles = 0;
state.hrStart = node_process.default.hrtime();
state.spinner = _clack_prompts.spinner();
state.isSpinning = false;
state.activeProgress.clear();
}
function showProgressStep() {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const parts = [];
const duration = (0, _kubb_core_utils.formatHrtime)(state.hrStart);
if (state.totalPlugins > 0) {
const pluginStr = state.failedPlugins > 0 ? `Plugins ${(0, node_util.styleText)("green", state.completedPlugins.toString())}/${state.totalPlugins} ${(0, node_util.styleText)("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${(0, node_util.styleText)("green", state.completedPlugins.toString())}/${state.totalPlugins}`;
parts.push(pluginStr);
}
if (state.totalFiles > 0) parts.push(`Files ${(0, node_util.styleText)("green", state.processedFiles.toString())}/${state.totalFiles}`);
if (parts.length > 0) {
parts.push(`${(0, node_util.styleText)("green", duration)} elapsed`);
_clack_prompts.log.step(getMessage(parts.join((0, node_util.styleText)("dim", " | "))));
}
}
function getMessage(message) {
if (logLevel >= _kubb_core.LogLevel.verbose) return [(0, node_util.styleText)("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
})}]`), message].join(" ");
return message;
}
function startSpinner(text) {
state.spinner.start(text);
state.isSpinning = true;
}
function stopSpinner(text) {
state.spinner.stop(text);
state.isSpinning = false;
}
context.on("info", (message, info = "") => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
(0, node_util.styleText)("blue", "ℹ"),
message,
(0, node_util.styleText)("dim", info)
].join(" "));
if (state.isSpinning) state.spinner.message(text);
else _clack_prompts.log.info(text);
});
context.on("success", (message, info = "") => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
(0, node_util.styleText)("blue", "✓"),
message,
logLevel >= _kubb_core.LogLevel.info ? (0, node_util.styleText)("dim", info) : void 0
].filter(Boolean).join(" "));
if (state.isSpinning) stopSpinner(text);
else _clack_prompts.log.success(text);
});
context.on("warn", (message, info) => {
if (logLevel < _kubb_core.LogLevel.warn) return;
const text = getMessage([
(0, node_util.styleText)("yellow", "⚠"),
message,
logLevel >= _kubb_core.LogLevel.info && info ? (0, node_util.styleText)("dim", info) : void 0
].filter(Boolean).join(" "));
_clack_prompts.log.warn(text);
});
context.on("error", (error) => {
const caused = error.cause;
const text = [(0, node_util.styleText)("red", "✗"), error.message].join(" ");
if (state.isSpinning) stopSpinner(getMessage(text));
else _clack_prompts.log.error(getMessage(text));
if (logLevel >= _kubb_core.LogLevel.debug && error.stack) {
const frames = error.stack.split("\n").slice(1, 4);
for (const frame of frames) _clack_prompts.log.message(getMessage((0, node_util.styleText)("dim", frame.trim())));
if (caused?.stack) {
_clack_prompts.log.message((0, node_util.styleText)("dim", `└─ caused by ${caused.message}`));
const frames = caused.stack.split("\n").slice(1, 4);
for (const frame of frames) _clack_prompts.log.message(getMessage(` ${(0, node_util.styleText)("dim", frame.trim())}`));
}
}
});
context.on("version:new", (version, latestVersion) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
_clack_prompts.box(`\`v${version}\` → \`v${latestVersion}\`
Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
width: "auto",
formatBorder: (s) => (0, node_util.styleText)("yellow", s),
rounded: true,
withGuide: false,
contentAlign: "center",
titleAlign: "center"
});
});
context.on("lifecycle:start", async (version) => {
console.log(`\n${getIntro({
title: "The ultimate toolkit for working with APIs",
description: "Ready to start",
version,
areEyesOpen: true
})}\n`);
reset();
});
context.on("config:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Configuration started");
_clack_prompts.intro(text);
startSpinner(getMessage("Configuration loading"));
});
context.on("config:end", (_configs) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Configuration completed");
_clack_prompts.outro(text);
});
context.on("generation:start", (config) => {
state.totalPlugins = config.plugins?.length || 0;
const text = getMessage(["Generation started", config.name ? `for ${(0, node_util.styleText)("dim", config.name)}` : void 0].filter(Boolean).join(" "));
_clack_prompts.intro(text);
reset();
});
context.on("plugin:start", (plugin) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
stopSpinner();
const progressBar = _clack_prompts.progress({
style: "block",
max: 100,
size: 30
});
const text = getMessage(`Generating ${(0, node_util.styleText)("bold", plugin.name)}`);
progressBar.start(text);
const interval = setInterval(() => {
progressBar.advance();
}, 100);
state.activeProgress.set(plugin.name, {
progressBar,
interval
});
});
context.on("plugin:end", (plugin, { duration, success }) => {
stopSpinner();
const active = state.activeProgress.get(plugin.name);
if (!active || logLevel === _kubb_core.LogLevel.silent) return;
clearInterval(active.interval);
if (success) state.completedPlugins++;
else state.failedPlugins++;
const durationStr = formatMsWithColor(duration);
const text = getMessage(success ? `${(0, node_util.styleText)("bold", plugin.name)} completed in ${durationStr}` : `${(0, node_util.styleText)("bold", plugin.name)} failed in ${(0, node_util.styleText)("red", (0, _kubb_core_utils.formatMs)(duration))}`);
active.progressBar.stop(text);
state.activeProgress.delete(plugin.name);
showProgressStep();
});
context.on("files:processing:start", (files) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
stopSpinner();
state.totalFiles = files.length;
state.processedFiles = 0;
const text = `Writing ${files.length} files`;
const progressBar = _clack_prompts.progress({
style: "block",
max: files.length,
size: 30
});
context.emit("info", text);
progressBar.start(getMessage(text));
state.activeProgress.set("files", { progressBar });
});
context.on("file:processing:update", ({ file, config }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
stopSpinner();
state.processedFiles++;
const text = `Writing ${(0, node_path.relative)(config.root, file.path)}`;
const active = state.activeProgress.get("files");
if (!active) return;
active.progressBar.advance(void 0, text);
});
context.on("files:processing:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
stopSpinner();
const text = getMessage("Files written successfully");
const active = state.activeProgress.get("files");
if (!active) return;
active.progressBar.stop(text);
state.activeProgress.delete("files");
showProgressStep();
});
context.on("generation:end", (config) => {
const text = getMessage(config.name ? `Generation completed for ${(0, node_util.styleText)("dim", config.name)}` : "Generation completed");
_clack_prompts.outro(text);
});
context.on("format:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Format started");
_clack_prompts.intro(text);
});
context.on("format:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Format completed");
_clack_prompts.outro(text);
});
context.on("lint:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Lint started");
_clack_prompts.intro(text);
});
context.on("lint:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Lint completed");
_clack_prompts.outro(text);
});
context.on("hook:start", async ({ id, command, args }) => {
const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} started`);
if (!id) return;
if (logLevel <= _kubb_core.LogLevel.silent) {
try {
const result = await (0, tinyexec.x)(command, [...args ?? []], {
nodeOptions: { detached: true },
throwOnError: true
});
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [result.stdout.trimEnd()]
});
await context.emit("hook:end", {
command,
args,
id,
success: true,
error: null
});
} catch (err) {
const error = err;
const stderr = error.output?.stderr ?? "";
const stdout = error.output?.stdout ?? "";
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [stdout, stderr].filter(Boolean)
});
if (stderr) console.error(stderr);
if (stdout) console.log(stdout);
const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
await context.emit("hook:end", {
command,
args,
id,
success: false,
error: errorMessage
});
await context.emit("error", errorMessage);
}
return;
}
_clack_prompts.intro(text);
const logger = _clack_prompts.taskLog({ title: getMessage(["Executing hook", logLevel >= _kubb_core.LogLevel.info ? (0, node_util.styleText)("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
const writable = new ClackWritable(logger);
try {
const proc = (0, tinyexec.x)(command, [...args ?? []], {
nodeOptions: { detached: true },
throwOnError: true
});
for await (const line of proc) writable.write(line);
const result = await proc;
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [result.stdout.trimEnd()]
});
await context.emit("hook:end", {
command,
args,
id,
success: true,
error: null
});
} catch (err) {
const error = err;
const stderr = error.output?.stderr ?? "";
const stdout = error.output?.stdout ?? "";
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [stdout, stderr].filter(Boolean)
});
if (stderr) logger.error(stderr);
if (stdout) logger.message(stdout);
const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
await context.emit("hook:end", {
command,
args,
id,
success: false,
error: errorMessage
});
await context.emit("error", errorMessage);
}
});
context.on("hook:end", ({ command, args }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage(`Hook ${(0, node_util.styleText)("dim", args?.length ? `${command} ${args.join(" ")}` : command)} successfully executed`);
_clack_prompts.outro(text);
});
context.on("generation:summary", (config, { pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
const summary = getSummary({
failedPlugins,
filesCreated,
config,
status,
hrStart,
pluginTimings: logLevel >= _kubb_core.LogLevel.verbose ? pluginTimings : void 0
});
const title = config.name || "";
summary.unshift("\n");
summary.push("\n");
if (status === "success") {
_clack_prompts.box(summary.join("\n"), getMessage(title), {
width: "auto",
formatBorder: (s) => (0, node_util.styleText)("green", s),
rounded: true,
withGuide: false,
contentAlign: "left",
titleAlign: "center"
});
return;
}
_clack_prompts.box(summary.join("\n"), getMessage(title), {
width: "auto",
formatBorder: (s) => (0, node_util.styleText)("red", s),
rounded: true,
withGuide: false,
contentAlign: "left",
titleAlign: "center"
});
});
context.on("lifecycle:end", () => {
reset();
});
}
});
//#endregion
//#region src/loggers/envDetection.ts
/**
* Check if running in GitHub Actions environment
*/
function isGitHubActions() {
return !!process.env.GITHUB_ACTIONS;
}
/**
* Check if running in any CI environment
*/
function isCIEnvironment() {
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);
}
/**
* Check if TTY is available for interactive output
*/
function canUseTTY() {
return !!process.stdout.isTTY && !isCIEnvironment();
}
//#endregion
//#region src/loggers/fileSystemLogger.ts
/**
* FileSystem logger for debug log persistence
* Captures debug and verbose events and writes them to files in .kubb directory
*
* Note: Logs are written on lifecycle:end or process exit. If the process crashes
* before these events, some cached logs may be lost.
*/
const fileSystemLogger = (0, _kubb_core.defineLogger)({
name: "filesystem",
install(context) {
const state = {
cachedLogs: /* @__PURE__ */ new Set(),
startDate: Date.now()
};
function reset() {
state.cachedLogs = /* @__PURE__ */ new Set();
state.startDate = Date.now();
}
async function writeLogs(name) {
if (state.cachedLogs.size === 0) return [];
const files = {};
for (const log of state.cachedLogs) {
const baseName = log.fileName || `${[
"kubb",
name,
state.startDate
].filter(Boolean).join("-")}.log`;
const pathName = (0, node_path.resolve)(process.cwd(), ".kubb", baseName);
if (!files[pathName]) files[pathName] = [];
if (log.logs.length > 0) {
const timestamp = log.date.toLocaleString();
files[pathName].push(`[${timestamp}]\n${log.logs.join("\n")}`);
}
}
await Promise.all(Object.entries(files).map(async ([fileName, logs]) => {
return (0, _kubb_core_fs.write)(fileName, logs.join("\n\n"));
}));
return Object.keys(files);
}
context.on("info", (message, info) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [`ℹ ${message} ${info}`],
fileName: void 0
});
});
context.on("success", (message, info) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [`✓ ${message} ${info}`],
fileName: void 0
});
});
context.on("warn", (message, info) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [`⚠ ${message} ${info}`],
fileName: void 0
});
});
context.on("error", (error) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [`✗ ${error.message}`, error.stack || "unknown stack"],
fileName: void 0
});
});
context.on("debug", (message) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: message.logs,
fileName: void 0
});
});
context.on("plugin:start", (plugin) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [`Generating ${plugin.name}`],
fileName: void 0
});
});
context.on("plugin:end", (plugin, { duration, success }) => {
const durationStr = (0, _kubb_core_utils.formatMs)(duration);
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`],
fileName: void 0
});
});
context.on("files:processing:start", (files) => {
state.cachedLogs.add({
date: /* @__PURE__ */ new Date(),
logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)],
fileName: void 0
});
});
context.on("generation:end", async (config) => {
const writtenFilePaths = await writeLogs(config.name);
if (writtenFilePaths.length > 0) {
const files = writtenFilePaths.map((f) => (0, node_path.relative)(process.cwd(), f));
await context.emit("info", "Debug files written to:", files.join(", "));
}
reset();
});
context.on("lifecycle:end", async () => {});
const exitHandler = () => {
if (state.cachedLogs.size > 0) writeLogs().catch(() => {});
};
process.once("exit", exitHandler);
process.once("SIGINT", exitHandler);
process.once("SIGTERM", exitHandler);
}
});
//#endregion
//#region src/loggers/githubActionsLogger.ts
/**
* GitHub Actions adapter for CI environments
* Uses Github group annotations for collapsible sections
*/
const githubActionsLogger = (0, _kubb_core.defineLogger)({
name: "github-actions",
install(context, options) {
const logLevel = options?.logLevel || _kubb_core.LogLevel.info;
const state = {
totalPlugins: 0,
completedPlugins: 0,
failedPlugins: 0,
totalFiles: 0,
processedFiles: 0,
hrStart: process.hrtime(),
currentConfigs: []
};
function reset() {
state.totalPlugins = 0;
state.completedPlugins = 0;
state.failedPlugins = 0;
state.totalFiles = 0;
state.processedFiles = 0;
state.hrStart = process.hrtime();
}
function showProgressStep() {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const parts = [];
const duration = (0, _kubb_core_utils.formatHrtime)(state.hrStart);
if (state.totalPlugins > 0) {
const pluginStr = state.failedPlugins > 0 ? `Plugins ${(0, node_util.styleText)("green", state.completedPlugins.toString())}/${state.totalPlugins} ${(0, node_util.styleText)("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${(0, node_util.styleText)("green", state.completedPlugins.toString())}/${state.totalPlugins}`;
parts.push(pluginStr);
}
if (state.totalFiles > 0) parts.push(`Files ${(0, node_util.styleText)("green", state.processedFiles.toString())}/${state.totalFiles}`);
if (parts.length > 0) {
parts.push(`${(0, node_util.styleText)("green", duration)} elapsed`);
console.log(getMessage(parts.join((0, node_util.styleText)("dim", " | "))));
}
}
function getMessage(message) {
if (logLevel >= _kubb_core.LogLevel.verbose) return [(0, node_util.styleText)("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
})}]`), message].join(" ");
return message;
}
function openGroup(name) {
console.log(`::group::${name}`);
}
function closeGroup(_name) {
console.log("::endgroup::");
}
context.on("info", (message, info = "") => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
(0, node_util.styleText)("blue", "ℹ"),
message,
(0, node_util.styleText)("dim", info)
].join(" "));
console.log(text);
});
context.on("success", (message, info = "") => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
(0, node_util.styleText)("blue", "✓"),
message,
logLevel >= _kubb_core.LogLevel.info ? (0, node_util.styleText)("dim", info) : void 0
].filter(Boolean).join(" "));
console.log(text);
});
context.on("warn", (message, info = "") => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
(0, node_util.styleText)("yellow", "⚠"),
message,
logLevel >= _kubb_core.LogLevel.info ? (0, node_util.styleText)("dim", info) : void 0
].filter(Boolean).join(" "));
console.warn(`::warning::${text}`);
});
context.on("error", (error) => {
const caused = error.cause;
if (logLevel <= _kubb_core.LogLevel.silent) return;
const message = error.message || String(error);
console.error(`::error::${message}`);
if (logLevel >= _kubb_core.LogLevel.debug && error.stack) {
const frames = error.stack.split("\n").slice(1, 4);
for (const frame of frames) console.log(getMessage((0, node_util.styleText)("dim", frame.trim())));
if (caused?.stack) {
console.log((0, node_util.styleText)("dim", `└─ caused by ${caused.message}`));
const frames = caused.stack.split("\n").slice(1, 4);
for (const frame of frames) console.log(getMessage(` ${(0, node_util.styleText)("dim", frame.trim())}`));
}
}
});
context.on("lifecycle:start", (version) => {
console.log((0, node_util.styleText)("yellow", `Kubb ${version} 🧩`));
reset();
});
context.on("config:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Configuration started");
openGroup("Configuration");
console.log(text);
});
context.on("config:end", (configs) => {
state.currentConfigs = configs;
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Configuration completed");
console.log(text);
closeGroup("Configuration");
});
context.on("generation:start", (config) => {
state.totalPlugins = config.plugins?.length || 0;
const text = config.name ? `Generation for ${(0, node_util.styleText)("bold", config.name)}` : "Generation";
if (state.currentConfigs.length > 1) openGroup(text);
if (state.currentConfigs.length === 1) console.log(getMessage(text));
reset();
});
context.on("plugin:start", (plugin) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage(`Generating ${(0, node_util.styleText)("bold", plugin.name)}`);
if (state.currentConfigs.length === 1) openGroup(`Plugin: ${plugin.name}`);
console.log(text);
});
context.on("plugin:end", (plugin, { duration, success }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
if (success) state.completedPlugins++;
else state.failedPlugins++;
const durationStr = formatMsWithColor(duration);
const text = getMessage(success ? `${(0, node_util.styleText)("bold", plugin.name)} completed in ${durationStr}` : `${(0, node_util.styleText)("bold", plugin.name)} failed in ${(0, node_util.styleText)("red", (0, _kubb_core_utils.formatMs)(duration))}`);
console.log(text);
if (state.currentConfigs.length > 1) console.log(" ");
if (state.currentConfigs.length === 1) closeGroup(`Plugin: ${plugin.name}`);
showProgressStep();
});
context.on("files:processing:start", (files) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
state.totalFiles = files.length;
state.processedFiles = 0;
if (state.currentConfigs.length === 1) openGroup("File Generation");
const text = getMessage(`Writing ${files.length} files`);
console.log(text);
});
context.on("files:processing:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Files written successfully");
console.log(text);
if (state.currentConfigs.length === 1) closeGroup("File Generation");
});
context.on("file:processing:update", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
state.processedFiles++;
});
context.on("files:processing:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
showProgressStep();
});
context.on("generation:end", (config) => {
const text = getMessage(config.name ? `${(0, node_util.styleText)("blue", "✓")} Generation completed for ${(0, node_util.styleText)("dim", config.name)}` : `${(0, node_util.styleText)("blue", "✓")} Generation completed`);
console.log(text);
});
context.on("format:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Format started");
if (state.currentConfigs.length === 1) openGroup("Formatting");
console.log(text);
});
context.on("format:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Format completed");
console.log(text);
if (state.currentConfigs.length === 1) closeGroup("Formatting");
});
context.on("lint:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Lint started");
if (state.currentConfigs.length === 1) openGroup("Linting");
console.log(text);
});
context.on("lint:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Lint completed");
console.log(text);
if (state.currentConfigs.length === 1) closeGroup("Linting");
});
context.on("hook:start", async ({ id, command, args }) => {
const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} started`);
if (logLevel > _kubb_core.LogLevel.silent) {
if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
console.log(text);
}
if (!id) return;
try {
const result = await (0, tinyexec.x)(command, [...args ?? []], {
nodeOptions: { detached: true },
throwOnError: true
});
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [result.stdout.trimEnd()]
});
if (logLevel > _kubb_core.LogLevel.silent) console.log(result.stdout.trimEnd());
await context.emit("hook:end", {
command,
args,
id,
success: true,
error: null
});
} catch (err) {
const error = err;
const stderr = error.output?.stderr ?? "";
const stdout = error.output?.stdout ?? "";
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [stdout, stderr].filter(Boolean)
});
if (stderr) console.error(`::error::${stderr}`);
if (stdout) console.log(stdout);
const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
await context.emit("hook:end", {
command,
args,
id,
success: false,
error: errorMessage
});
await context.emit("error", errorMessage);
}
});
context.on("hook:end", ({ command, args }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} completed`);
console.log(text);
if (state.currentConfigs.length === 1) closeGroup(`Hook ${commandWithArgs}`);
});
context.on("generation:summary", (config, { status, hrStart, failedPlugins }) => {
const pluginsCount = config.plugins?.length || 0;
const successCount = pluginsCount - failedPlugins.size;
const duration = (0, _kubb_core_utils.formatHrtime)(hrStart);
if (state.currentConfigs.length > 1) console.log(" ");
console.log(status === "success" ? `Kubb Summary: ${(0, node_util.styleText)("blue", "✓")} ${`${successCount} successful`}, ${pluginsCount} total, ${(0, node_util.styleText)("green", duration)}` : `Kubb Summary: ${(0, node_util.styleText)("blue", "✓")} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${(0, node_util.styleText)("green", duration)}`);
if (state.currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${(0, node_util.styleText)("bold", config.name)}` : "Generation");
});
}
});
//#endregion
//#region src/loggers/plainLogger.ts
/**
* Plain console adapter for non-TTY environments
* Simple console.log output with indentation
*/
const plainLogger = (0, _kubb_core.defineLogger)({
name: "plain",
install(context, options) {
const logLevel = options?.logLevel || 3;
function getMessage(message) {
if (logLevel >= _kubb_core.LogLevel.verbose) return [`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
})}]`, message].join(" ");
return message;
}
context.on("info", (message, info) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
"ℹ",
message,
info
].join(" "));
console.log(text);
});
context.on("success", (message, info = "") => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage([
"✓",
message,
logLevel >= _kubb_core.LogLevel.info ? info : void 0
].filter(Boolean).join(" "));
console.log(text);
});
context.on("warn", (message, info) => {
if (logLevel < _kubb_core.LogLevel.warn) return;
const text = getMessage([
"⚠",
message,
logLevel >= _kubb_core.LogLevel.info ? info : void 0
].filter(Boolean).join(" "));
console.log(text);
});
context.on("error", (error) => {
const caused = error.cause;
const text = getMessage(["✗", error.message].join(" "));
console.log(text);
if (logLevel >= _kubb_core.LogLevel.debug && error.stack) {
const frames = error.stack.split("\n").slice(1, 4);
for (const frame of frames) console.log(getMessage(frame.trim()));
if (caused?.stack) {
console.log(`└─ caused by ${caused.message}`);
const frames = caused.stack.split("\n").slice(1, 4);
for (const frame of frames) console.log(getMessage(` ${frame.trim()}`));
}
}
});
context.on("lifecycle:start", () => {
console.log("Kubb CLI 🧩");
});
context.on("config:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Configuration started");
console.log(text);
});
context.on("config:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Configuration completed");
console.log(text);
});
context.on("generation:start", () => {
const text = getMessage("Configuration started");
console.log(text);
});
context.on("plugin:start", (plugin) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage(`Generating ${plugin.name}`);
console.log(text);
});
context.on("plugin:end", (plugin, { duration, success }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const durationStr = (0, _kubb_core_utils.formatMs)(duration);
const text = getMessage(success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`);
console.log(text);
});
context.on("files:processing:start", (files) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage(`Writing ${files.length} files`);
console.log(text);
});
context.on("file:processing:update", ({ file, config }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage(`Writing ${(0, node_path.relative)(config.root, file.path)}`);
console.log(text);
});
context.on("files:processing:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Files written successfully");
console.log(text);
});
context.on("generation:end", (config) => {
const text = getMessage(config.name ? `Generation completed for ${config.name}` : "Generation completed");
console.log(text);
});
context.on("format:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Format started");
console.log(text);
});
context.on("format:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Format completed");
console.log(text);
});
context.on("lint:start", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Lint started");
console.log(text);
});
context.on("lint:end", () => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage("Lint completed");
console.log(text);
});
context.on("hook:start", async ({ id, command, args }) => {
const commandWithArgs = args?.length ? `${command} ${args.join(" ")}` : command;
const text = getMessage(`Hook ${commandWithArgs} started`);
if (logLevel > _kubb_core.LogLevel.silent) console.log(text);
if (!id) return;
try {
const result = await (0, tinyexec.x)(command, [...args ?? []], {
nodeOptions: { detached: true },
throwOnError: true
});
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [result.stdout.trimEnd()]
});
if (logLevel > _kubb_core.LogLevel.silent) console.log(result.stdout.trimEnd());
await context.emit("hook:end", {
command,
args,
id,
success: true,
error: null
});
} catch (err) {
const error = err;
const stderr = error.output?.stderr ?? "";
const stdout = error.output?.stdout ?? "";
await context.emit("debug", {
date: /* @__PURE__ */ new Date(),
logs: [stdout, stderr].filter(Boolean)
});
if (stderr) console.error(stderr);
if (stdout) console.log(stdout);
const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
await context.emit("hook:end", {
command,
args,
id,
success: false,
error: errorMessage
});
await context.emit("error", errorMessage);
}
});
context.on("hook:end", ({ command, args }) => {
if (logLevel <= _kubb_core.LogLevel.silent) return;
const text = getMessage(`Hook ${args?.length ? `${command} ${args.join(" ")}` : command} completed`);
console.log(text);
});
context.on("generation:summary", (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
const summary = getSummary({
failedPlugins,
filesCreated,
config,
status,
hrStart,
pluginTimings: logLevel >= _kubb_core.LogLevel.verbose ? pluginTimings : void 0
});
console.log("---------------------------");
console.log(summary.join("\n"));
console.log("---------------------------");
});
}
});
//#endregion
//#region src/loggers/utils.ts
function detectLogger() {
if (isGitHubActions()) return "github-actions";
if (canUseTTY()) return "clack";
return "plain";
}
const logMapper = {
clack: clackLogger,
plain: plainLogger,
"github-actions": githubActionsLogger
};
async function setupLogger(context, { logLevel }) {
const type = detectLogger();
const logger = logMapper[type];
if (!logger) throw new Error(`Unknown adapter type: ${type}`);
const cleanup = await logger.install(context, { logLevel });
if (logLevel >= _kubb_core.LogLevel.debug) await fileSystemLogger.install(context, { logLevel });
return cleanup;
}
//#endregion
//#region src/utils/executeHooks.ts
async function executeHooks({ hooks, events }) {
const commands = Array.isArray(hooks.done) ? hooks.done : [hooks.done].filter(Boolean);
for (const command of commands) {
const [cmd, ...args] = (0, _kubb_core_utils.tokenize)(command);
if (!cmd) continue;
const hookId = (0, node_crypto.createHash)("sha256").update(command).digest("hex");
await events.emit("hook:start", {
id: hookId,
command: cmd,
args
});
await events.onOnce("hook:end", async ({ success, error }) => {
if (!success) throw error;
await events.emit("success", `${(0, node_util.styleText)("dim", command)} successfully executed`);
});
}
}
//#endregion
//#region src/runners/generate.ts
async function generate({ input, config: userConfig, events, logLevel }) {
const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0);
const hrStart = node_process.default.hrtime();
const config = {
...userConfig,
root: userConfig.root || node_process.default.cwd(),
input: inputPath ? {
...userConfig.input,
path: inputPath
} : userConfig.input,
output: {
write: true,
barrelType: "named",
extension: { ".ts": ".ts" },
format: "prettier",
...userConfig.output
}
};
await events.emit("generation:start", config);
await events.emit("info", config.name ? `Setup generation ${(0, node_util.styleText)("bold", config.name)}` : "Setup generation", inputPath);
const { sources, fabric, pluginManager } = await (0, _kubb_core.setup)({
config,
events
});
await events.emit("info", config.name ? `Build generation ${(0, node_util.styleText)("bold", config.name)}` : "Build generation", inputPath);
const { files, failedPlugins, pluginTimings, error } = await (0, _kubb_core.safeBuild)({
config,
events
}, {
pluginManager,
fabric,
events,
sources
});
await events.emit("info", "Load summary");
if (failedPlugins.size > 0 || error) {
[error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean).forEach((err) => {
events.emit("error", err);
});
await events.emit("generation:end", config, files, sources);
await events.emit("generation:summary", config, {
failedPlugins,
filesCreated: files.length,
status: failedPlugins.size > 0 || error ? "failed" : "success",
hrStart,
pluginTimings: logLevel >= _kubb_core.LogLevel.verbose ? pluginTimings : void 0
});
node_process.default.exit(1);
}
await events.emit("success", "Generation successfully", inputPath);
await events.emit("generation:end", config, files, sources);
if (config.output.format) {
await events.emit("format:start");
let formatter = config.output.format;
if (formatter === "auto") {
const detectedFormatter = await (0, _kubb_core_utils.detectFormatter)();
if (!detectedFormatter) await events.emit("warn", "No formatter found (biome, prettier, or oxfmt). Skipping formatting.");
else {
formatter = detectedFormatter;
await events.emit("info", `Auto-detected formatter: ${(0, node_util.styleText)("dim", formatter)}`);
}
}
if (formatter && formatter !== "auto" && formatter in _kubb_core_utils.formatters) {
const formatterConfig = _kubb_core_utils.formatters[formatter];
const outputPath = node_path.default.resolve(config.root, config.output.path);
try {
const hookId = (0, node_crypto.createHash)("sha256").update([config.name, formatter].filter(Boolean).join("-")).digest("hex");
await events.emit("hook:start", {
id: hookId,
command: formatterConfig.command,
args: formatterConfig.args(outputPath)
});
await events.onOnce("hook:end", async ({ success, error }) => {
if (!success) throw error;
await events.emit("success", [
`Formatting with ${(0, node_util.styleText)("dim", formatter)}`,
logLevel >= _kubb_core.LogLevel.info ? `on ${(0, node_util.styleText)("dim", outputPath)}` : void 0,
"successfully"
].filter(Boolean).join(" "));
});
} catch (caughtError) {
const error = new Error(formatterConfig.errorMessage);
error.cause = caughtError;
await events.emit("error", error);
}
}
await events.emit("format:end");
}
if (config.output.lint) {
await events.emit("lint:start");
let linter = config.output.lint;
if (linter === "auto") {
const detectedLinter = await (0, _kubb_core_utils.detectLinter)();
if (!detectedLinter) await events.emit("warn", "No linter found (biome, oxlint, or eslint). Skipping linting.");
else {
linter = detectedLinter;
await events.emit("info", `Auto-detected linter: ${(0, node_util.styleText)("dim", linter)}`);
}
}
if (linter && linter !== "auto" && linter in _kubb_core_utils.linters) {
const linterConfig = _kubb_core_utils.linters[linter];
const outputPath = node_path.default.resolve(config.root, config.output.path);
try {
const hookId = (0, node_crypto.createHash)("sha256").update([config.name, linter].filter(Boolean).join("-")).digest("hex");
await events.emit("hook:start", {
id: hookId,
command: linterConfig.command,
args: linterConfig.args(outputPath)
});
await events.onOnce("hook:end", async ({ success, error }) => {
if (!success) throw error;
await events.emit("success", [
`Linting with ${(0, node_util.styleText)("dim", linter)}`,
logLevel >= _kubb_core.LogLevel.info ? `on ${(0, node_util.styleText)("dim", outputPath)}` : void 0,
"successfully"
].filter(Boolean).join(" "));
});
} catch (caughtError) {
const error = new Error(linterConfig.errorMessage);
error.cause = caughtError;
await events.emit("error", error);
}
}
await events.emit("lint:end");
}
if (config.hooks) {
await events.emit("hooks:start");
await executeHooks({
hooks: config.hooks,
events
});
await events.emit("hooks:end");
}
await events.emit("generation:summary", config, {
failedPlugins,
filesCreated: files.length,
status: failedPlugins.size > 0 || error ? "failed" : "success",
hrStart,
pluginTimings
});
}
//#endregion
//#region src/utils/getCosmiConfig.ts
const tsLoader = async (configFile) => {
return await (0, jiti.createJiti)(require("url").pathToFileURL(__filename).href, {
jsx: {
runtime: "automatic",
importSource: "@kubb/react-fabric"
},
sourceMaps: true,
interopDefault: true
}).import(configFile, { default: true });
};
async function getCosmiConfig(moduleName, config) {
let result;
const searchPlaces = [
"package.json",
`.${moduleName}rc`,
`.${moduleName}rc.json`,
`.${moduleName}rc.yaml`,
`.${moduleName}rc.yml`,
`.${moduleName}rc.ts`,
`.${moduleName}rc.js`,
`.${moduleName}rc.mjs`,
`.${moduleName}rc.cjs`,
`${moduleName}.config.ts`,
`${moduleName}.config.js`,
`${moduleName}.config.mjs`,
`${moduleName}.config.cjs`
];
const explorer = (0, cosmiconfig.cosmiconfig)(moduleName, {
cache: false,
searchPlaces: [
...searchPlaces.map((searchPlace) => {
return `.config/${searchPlace}`;
}),
...searchPlaces.map((searchPlace) => {
return `configs/${searchPlace}`;
}),
...searchPlaces
],
loaders: { ".ts": tsLoader }
});
try {
result = config ? await explorer.load(config) : await explorer.search();
} catch (error) {
throw new Error("Config failed loading", { cause: error });
}
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");
return result;
}
//#endregion
//#region src/utils/watcher.ts
async func