@kubb/cli
Advanced tools
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-7k6Ul15n.js"; | ||
| import { a as agentDefaults } from "./constants-CM3dJzjK.js"; | ||
| //#endregion | ||
| //#region src/commands/agent.ts | ||
| const command = defineCommand({ | ||
| name: "agent", | ||
| description: "Manage the Kubb Agent server", | ||
| subCommands: [defineCommand({ | ||
| name: "start", | ||
| description: "Start the Agent server", | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| port: { | ||
| type: "string", | ||
| description: `Port for the server (default: ${agentDefaults.port})`, | ||
| short: "p" | ||
| }, | ||
| host: { | ||
| type: "string", | ||
| description: "Host for the server", | ||
| default: agentDefaults.host | ||
| }, | ||
| "allow-write": { | ||
| type: "boolean", | ||
| description: "Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.", | ||
| default: false | ||
| }, | ||
| "allow-all": { | ||
| type: "boolean", | ||
| description: "Grant all permissions (implies --allow-write).", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values }) { | ||
| const { runAgentStart } = await import("./agent-fcClds-t.js"); | ||
| await runAgentStart({ | ||
| port: values.port !== void 0 ? values.port : void 0, | ||
| host: values.host, | ||
| configPath: values.config, | ||
| allowWrite: values["allow-write"], | ||
| allowAll: values["allow-all"], | ||
| version | ||
| }); | ||
| } | ||
| })] | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=agent-BBrW4jlM.js.map |
| {"version":3,"file":"agent-BBrW4jlM.js","names":["command","startCommand"],"sources":["../src/commands/agent/start.ts","../src/commands/agent.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../../package.json'\nimport { agentDefaults } from '../../constants.ts'\n\nexport const command = defineCommand({\n name: 'start',\n description: 'Start the Agent server',\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n port: { type: 'string', description: `Port for the server (default: ${agentDefaults.port})`, short: 'p' },\n host: { type: 'string', description: 'Host for the server', default: agentDefaults.host },\n 'allow-write': {\n type: 'boolean',\n description: 'Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.',\n default: false,\n },\n 'allow-all': { type: 'boolean', description: 'Grant all permissions (implies --allow-write).', default: false },\n },\n async run({ values }) {\n const { runAgentStart } = await import('../../runners/agent.ts')\n\n await runAgentStart({\n port: values.port !== undefined ? values.port : undefined,\n host: values.host,\n configPath: values.config,\n allowWrite: values['allow-write'],\n allowAll: values['allow-all'],\n version,\n })\n },\n})\n","import { defineCommand } from '@internals/utils'\nimport { command as startCommand } from './agent/start.ts'\n\nexport const command = defineCommand({\n name: 'agent',\n description: 'Manage the Kubb Agent server',\n subCommands: [startCommand],\n})\n"],"mappings":";;;;;;ACGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,aAAa,CDFQ,cAAc;EACnC,MAAM;EACN,aAAa;EACb,SAAS;GACP,QAAQ;IAAE,MAAM;IAAU,aAAa;IAA2B,OAAO;IAAK;GAC9E,MAAM;IAAE,MAAM;IAAU,aAAa,iCAAiC,cAAc,KAAK;IAAI,OAAO;IAAK;GACzG,MAAM;IAAE,MAAM;IAAU,aAAa;IAAuB,SAAS,cAAc;IAAM;GACzF,eAAe;IACb,MAAM;IACN,aAAa;IACb,SAAS;IACV;GACD,aAAa;IAAE,MAAM;IAAW,aAAa;IAAkD,SAAS;IAAO;GAChH;EACD,MAAM,IAAI,EAAE,UAAU;GACpB,MAAM,EAAE,kBAAkB,MAAM,OAAO;AAEvC,SAAM,cAAc;IAClB,MAAM,OAAO,SAAS,KAAA,IAAY,OAAO,OAAO,KAAA;IAChD,MAAM,OAAO;IACb,YAAY,OAAO;IACnB,YAAY,OAAO;IACnB,UAAU,OAAO;IACjB;IACD,CAAC;;EAEL,CAAC,CCxB2B;CAC5B,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-m-LvDtUC.cjs"); | ||
| const require_constants = require("./constants-BTUap0zs.cjs"); | ||
| //#region src/commands/agent/start.ts | ||
| const command$1 = require_define.defineCommand({ | ||
| name: "start", | ||
| description: "Start the Agent server", | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| port: { | ||
| type: "string", | ||
| description: `Port for the server (default: ${require_constants.agentDefaults.port})`, | ||
| short: "p" | ||
| }, | ||
| host: { | ||
| type: "string", | ||
| description: "Host for the server", | ||
| default: require_constants.agentDefaults.host | ||
| }, | ||
| "allow-write": { | ||
| type: "boolean", | ||
| description: "Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.", | ||
| default: false | ||
| }, | ||
| "allow-all": { | ||
| type: "boolean", | ||
| description: "Grant all permissions (implies --allow-write).", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values }) { | ||
| const { runAgentStart } = await Promise.resolve().then(() => require("./agent-bJ5FNFnA.cjs")); | ||
| await runAgentStart({ | ||
| port: values.port !== void 0 ? values.port : void 0, | ||
| host: values.host, | ||
| configPath: values.config, | ||
| allowWrite: values["allow-write"], | ||
| allowAll: values["allow-all"], | ||
| version: require_package.version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/commands/agent.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "agent", | ||
| description: "Manage the Kubb Agent server", | ||
| subCommands: [command$1] | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=agent-DMy_bQ-M.cjs.map |
| {"version":3,"file":"agent-DMy_bQ-M.cjs","names":["command","defineCommand","agentDefaults","defineCommand","startCommand"],"sources":["../src/commands/agent/start.ts","../src/commands/agent.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../../package.json'\nimport { agentDefaults } from '../../constants.ts'\n\nexport const command = defineCommand({\n name: 'start',\n description: 'Start the Agent server',\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n port: { type: 'string', description: `Port for the server (default: ${agentDefaults.port})`, short: 'p' },\n host: { type: 'string', description: 'Host for the server', default: agentDefaults.host },\n 'allow-write': {\n type: 'boolean',\n description: 'Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.',\n default: false,\n },\n 'allow-all': { type: 'boolean', description: 'Grant all permissions (implies --allow-write).', default: false },\n },\n async run({ values }) {\n const { runAgentStart } = await import('../../runners/agent.ts')\n\n await runAgentStart({\n port: values.port !== undefined ? values.port : undefined,\n host: values.host,\n configPath: values.config,\n allowWrite: values['allow-write'],\n allowAll: values['allow-all'],\n version,\n })\n },\n})\n","import { defineCommand } from '@internals/utils'\nimport { command as startCommand } from './agent/start.ts'\n\nexport const command = defineCommand({\n name: 'agent',\n description: 'Manage the Kubb Agent server',\n subCommands: [startCommand],\n})\n"],"mappings":";;;;;AAIA,MAAaA,YAAUC,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS;EACP,QAAQ;GAAE,MAAM;GAAU,aAAa;GAA2B,OAAO;GAAK;EAC9E,MAAM;GAAE,MAAM;GAAU,aAAa,iCAAiCC,kBAAAA,cAAc,KAAK;GAAI,OAAO;GAAK;EACzG,MAAM;GAAE,MAAM;GAAU,aAAa;GAAuB,SAASA,kBAAAA,cAAc;GAAM;EACzF,eAAe;GACb,MAAM;GACN,aAAa;GACb,SAAS;GACV;EACD,aAAa;GAAE,MAAM;GAAW,aAAa;GAAkD,SAAS;GAAO;EAChH;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,kBAAkB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,uBAAA,CAAA;AAEhC,QAAM,cAAc;GAClB,MAAM,OAAO,SAAS,KAAA,IAAY,OAAO,OAAO,KAAA;GAChD,MAAM,OAAO;GACb,YAAY,OAAO;GACnB,YAAY,OAAO;GACnB,UAAU,OAAO;GACjB,SAAA,gBAAA;GACD,CAAC;;CAEL,CAAC;;;AC3BF,MAAa,UAAUC,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,aAAa,CAACC,UAAa;CAC5B,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| //#region src/commands/generate.ts | ||
| const command = require("./define-D6Kfm7-Z.cjs").defineCommand({ | ||
| name: "generate", | ||
| description: "[input] Generate files based on a 'kubb.config.ts' file", | ||
| arguments: ["[input]"], | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| logLevel: { | ||
| type: "string", | ||
| description: "Info, silent, verbose or debug", | ||
| short: "l", | ||
| default: "info", | ||
| hint: "silent|info|verbose|debug", | ||
| enum: [ | ||
| "silent", | ||
| "info", | ||
| "verbose", | ||
| "debug" | ||
| ] | ||
| }, | ||
| watch: { | ||
| type: "boolean", | ||
| description: "Watch mode based on the input file", | ||
| short: "w", | ||
| default: false | ||
| }, | ||
| debug: { | ||
| type: "boolean", | ||
| description: "Override logLevel to debug", | ||
| short: "d", | ||
| default: false | ||
| }, | ||
| verbose: { | ||
| type: "boolean", | ||
| description: "Override logLevel to verbose", | ||
| short: "v", | ||
| default: false | ||
| }, | ||
| silent: { | ||
| type: "boolean", | ||
| description: "Override logLevel to silent", | ||
| short: "s", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values, positionals }) { | ||
| const logLevel = values.debug ? "debug" : values.verbose ? "verbose" : values.silent ? "silent" : values.logLevel; | ||
| const { runGenerateCommand } = await Promise.resolve().then(() => require("./generate-DyK2S7hv.cjs")); | ||
| await runGenerateCommand({ | ||
| input: positionals[0], | ||
| configPath: values.config, | ||
| logLevel, | ||
| watch: values.watch | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=generate-CkyN7qeb.cjs.map |
| {"version":3,"file":"generate-CkyN7qeb.cjs","names":["defineCommand"],"sources":["../src/commands/generate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\n\nexport const command = defineCommand({\n name: 'generate',\n description: \"[input] Generate files based on a 'kubb.config.ts' file\",\n arguments: ['[input]'],\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n logLevel: {\n type: 'string',\n description: 'Info, silent, verbose or debug',\n short: 'l',\n default: 'info',\n hint: 'silent|info|verbose|debug',\n enum: ['silent', 'info', 'verbose', 'debug'],\n },\n watch: { type: 'boolean', description: 'Watch mode based on the input file', short: 'w', default: false },\n debug: { type: 'boolean', description: 'Override logLevel to debug', short: 'd', default: false },\n verbose: { type: 'boolean', description: 'Override logLevel to verbose', short: 'v', default: false },\n silent: { type: 'boolean', description: 'Override logLevel to silent', short: 's', default: false },\n },\n async run({ values, positionals }) {\n const logLevel = values.debug ? 'debug' : values.verbose ? 'verbose' : values.silent ? 'silent' : values.logLevel\n const { runGenerateCommand } = await import('../runners/generate.ts')\n\n await runGenerateCommand({ input: positionals[0], configPath: values.config, logLevel, watch: values.watch })\n },\n})\n"],"mappings":";;AAEA,MAAa,2CAAUA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,WAAW,CAAC,UAAU;CACtB,SAAS;EACP,QAAQ;GAAE,MAAM;GAAU,aAAa;GAA2B,OAAO;GAAK;EAC9E,UAAU;GACR,MAAM;GACN,aAAa;GACb,OAAO;GACP,SAAS;GACT,MAAM;GACN,MAAM;IAAC;IAAU;IAAQ;IAAW;IAAQ;GAC7C;EACD,OAAO;GAAE,MAAM;GAAW,aAAa;GAAsC,OAAO;GAAK,SAAS;GAAO;EACzG,OAAO;GAAE,MAAM;GAAW,aAAa;GAA8B,OAAO;GAAK,SAAS;GAAO;EACjG,SAAS;GAAE,MAAM;GAAW,aAAa;GAAgC,OAAO;GAAK,SAAS;GAAO;EACrG,QAAQ;GAAE,MAAM;GAAW,aAAa;GAA+B,OAAO;GAAK,SAAS;GAAO;EACpG;CACD,MAAM,IAAI,EAAE,QAAQ,eAAe;EACjC,MAAM,WAAW,OAAO,QAAQ,UAAU,OAAO,UAAU,YAAY,OAAO,SAAS,WAAW,OAAO;EACzG,MAAM,EAAE,uBAAuB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,0BAAA,CAAA;AAErC,QAAM,mBAAmB;GAAE,OAAO,YAAY;GAAI,YAAY,OAAO;GAAQ;GAAU,OAAO,OAAO;GAAO,CAAC;;CAEhH,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| //#region src/commands/generate.ts | ||
| const command = defineCommand({ | ||
| name: "generate", | ||
| description: "[input] Generate files based on a 'kubb.config.ts' file", | ||
| arguments: ["[input]"], | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| logLevel: { | ||
| type: "string", | ||
| description: "Info, silent, verbose or debug", | ||
| short: "l", | ||
| default: "info", | ||
| hint: "silent|info|verbose|debug", | ||
| enum: [ | ||
| "silent", | ||
| "info", | ||
| "verbose", | ||
| "debug" | ||
| ] | ||
| }, | ||
| watch: { | ||
| type: "boolean", | ||
| description: "Watch mode based on the input file", | ||
| short: "w", | ||
| default: false | ||
| }, | ||
| debug: { | ||
| type: "boolean", | ||
| description: "Override logLevel to debug", | ||
| short: "d", | ||
| default: false | ||
| }, | ||
| verbose: { | ||
| type: "boolean", | ||
| description: "Override logLevel to verbose", | ||
| short: "v", | ||
| default: false | ||
| }, | ||
| silent: { | ||
| type: "boolean", | ||
| description: "Override logLevel to silent", | ||
| short: "s", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values, positionals }) { | ||
| const logLevel = values.debug ? "debug" : values.verbose ? "verbose" : values.silent ? "silent" : values.logLevel; | ||
| const { runGenerateCommand } = await import("./generate-sIkyxxtw.js"); | ||
| await runGenerateCommand({ | ||
| input: positionals[0], | ||
| configPath: values.config, | ||
| logLevel, | ||
| watch: values.watch | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=generate-DBo220P3.js.map |
| {"version":3,"file":"generate-DBo220P3.js","names":[],"sources":["../src/commands/generate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\n\nexport const command = defineCommand({\n name: 'generate',\n description: \"[input] Generate files based on a 'kubb.config.ts' file\",\n arguments: ['[input]'],\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n logLevel: {\n type: 'string',\n description: 'Info, silent, verbose or debug',\n short: 'l',\n default: 'info',\n hint: 'silent|info|verbose|debug',\n enum: ['silent', 'info', 'verbose', 'debug'],\n },\n watch: { type: 'boolean', description: 'Watch mode based on the input file', short: 'w', default: false },\n debug: { type: 'boolean', description: 'Override logLevel to debug', short: 'd', default: false },\n verbose: { type: 'boolean', description: 'Override logLevel to verbose', short: 'v', default: false },\n silent: { type: 'boolean', description: 'Override logLevel to silent', short: 's', default: false },\n },\n async run({ values, positionals }) {\n const logLevel = values.debug ? 'debug' : values.verbose ? 'verbose' : values.silent ? 'silent' : values.logLevel\n const { runGenerateCommand } = await import('../runners/generate.ts')\n\n await runGenerateCommand({ input: positionals[0], configPath: values.config, logLevel, watch: values.watch })\n },\n})\n"],"mappings":";;;AAEA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,WAAW,CAAC,UAAU;CACtB,SAAS;EACP,QAAQ;GAAE,MAAM;GAAU,aAAa;GAA2B,OAAO;GAAK;EAC9E,UAAU;GACR,MAAM;GACN,aAAa;GACb,OAAO;GACP,SAAS;GACT,MAAM;GACN,MAAM;IAAC;IAAU;IAAQ;IAAW;IAAQ;GAC7C;EACD,OAAO;GAAE,MAAM;GAAW,aAAa;GAAsC,OAAO;GAAK,SAAS;GAAO;EACzG,OAAO;GAAE,MAAM;GAAW,aAAa;GAA8B,OAAO;GAAK,SAAS;GAAO;EACjG,SAAS;GAAE,MAAM;GAAW,aAAa;GAAgC,OAAO;GAAK,SAAS;GAAO;EACrG,QAAQ;GAAE,MAAM;GAAW,aAAa;GAA+B,OAAO;GAAK,SAAS;GAAO;EACpG;CACD,MAAM,IAAI,EAAE,QAAQ,eAAe;EACjC,MAAM,WAAW,OAAO,QAAQ,UAAU,OAAO,UAAU,YAAY,OAAO,SAAS,WAAW,OAAO;EACzG,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAE5C,QAAM,mBAAmB;GAAE,OAAO,YAAY;GAAI,YAAY,OAAO;GAAQ;GAAU,OAAO,OAAO;GAAO,CAAC;;CAEhH,CAAC"} |
| const require_chunk = require("./chunk-ByKO4r7w.cjs"); | ||
| const require_errors = require("./errors-DBW0N9w4.cjs"); | ||
| const require_telemetry = require("./telemetry-CEm85k_X.cjs"); | ||
| const require_shell = require("./shell-7HPrTCJ5.cjs"); | ||
| const require_package = require("./package-m-LvDtUC.cjs"); | ||
| const require_constants = require("./constants-BTUap0zs.cjs"); | ||
| let node_util = require("node:util"); | ||
| let node_events = require("node:events"); | ||
| let node_crypto = require("node:crypto"); | ||
| require("node:fs"); | ||
| let node_fs_promises = require("node:fs/promises"); | ||
| 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 _clack_prompts = require("@clack/prompts"); | ||
| _clack_prompts = require_chunk.__toESM(_clack_prompts); | ||
| let _kubb_core = require("@kubb/core"); | ||
| let tinyexec = require("tinyexec"); | ||
| let node_stream = require("node:stream"); | ||
| let cosmiconfig = require("cosmiconfig"); | ||
| let jiti = require("jiti"); | ||
| //#region ../../internals/utils/src/asyncEventEmitter.ts | ||
| /** | ||
| * A typed EventEmitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript event-map inference. | ||
| */ | ||
| var AsyncEventEmitter = class { | ||
| /** | ||
| * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new node_events.EventEmitter(); | ||
| /** | ||
| * Emits an event and awaits all registered listeners in parallel. | ||
| * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments. | ||
| */ | ||
| async emit(eventName, ...eventArgs) { | ||
| const listeners = this.#emitter.listeners(eventName); | ||
| if (listeners.length === 0) return; | ||
| await Promise.all(listeners.map(async (listener) => { | ||
| try { | ||
| return await listener(...eventArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(eventArgs); | ||
| } catch { | ||
| serializedArgs = String(eventArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: require_errors.toError(err) }); | ||
| } | ||
| })); | ||
| } | ||
| /** Registers a persistent listener for the given event. */ | ||
| on(eventName, handler) { | ||
| this.#emitter.on(eventName, handler); | ||
| } | ||
| /** Registers a one-shot listener that removes itself after the first invocation. */ | ||
| onOnce(eventName, handler) { | ||
| const wrapper = (...args) => { | ||
| this.off(eventName, wrapper); | ||
| return handler(...args); | ||
| }; | ||
| this.on(eventName, wrapper); | ||
| } | ||
| /** Removes a previously registered listener. */ | ||
| off(eventName, handler) { | ||
| this.#emitter.off(eventName, handler); | ||
| } | ||
| /** Removes all listeners from every event channel. */ | ||
| removeAll() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region ../../internals/utils/src/time.ts | ||
| /** | ||
| * Calculates elapsed time in milliseconds from a high-resolution start time. | ||
| * Rounds to 2 decimal places to provide sub-millisecond precision without noise. | ||
| */ | ||
| function getElapsedMs(hrStart) { | ||
| const [seconds, nanoseconds] = process.hrtime(hrStart); | ||
| const ms = seconds * 1e3 + nanoseconds / 1e6; | ||
| return Math.round(ms * 100) / 100; | ||
| } | ||
| /** | ||
| * Converts a millisecond duration into a human-readable string. | ||
| * Adjusts units (ms, s, m s) based on the magnitude of the duration. | ||
| */ | ||
| function formatMs(ms) { | ||
| if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`; | ||
| if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`; | ||
| return `${Math.round(ms)}ms`; | ||
| } | ||
| /** | ||
| * Convenience helper: formats the elapsed time since `hrStart` in one step. | ||
| */ | ||
| function formatHrtime(hrStart) { | ||
| return formatMs(getElapsedMs(hrStart)); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/colors.ts | ||
| /** | ||
| * Parses a CSS hex color string (`#RGB`) into its RGB channels. | ||
| * Falls back to `255` for any channel that cannot be parsed. | ||
| */ | ||
| function parseHex(color) { | ||
| const int = Number.parseInt(color.replace("#", ""), 16); | ||
| return Number.isNaN(int) ? { | ||
| r: 255, | ||
| g: 255, | ||
| b: 255 | ||
| } : { | ||
| r: int >> 16 & 255, | ||
| g: int >> 8 & 255, | ||
| b: int & 255 | ||
| }; | ||
| } | ||
| /** | ||
| * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence | ||
| * for the given hex color. | ||
| */ | ||
| function hex(color) { | ||
| const { r, g, b } = parseHex(color); | ||
| return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`; | ||
| } | ||
| function gradient(colorStops, text) { | ||
| const chars = text.split(""); | ||
| return chars.map((char, i) => { | ||
| const t = chars.length <= 1 ? 0 : i / (chars.length - 1); | ||
| const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2); | ||
| const lt = t * (colorStops.length - 1) - seg; | ||
| const from = parseHex(colorStops[seg]); | ||
| const to = parseHex(colorStops[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(""); | ||
| } | ||
| /** ANSI color functions for each part of the Kubb mascot illustration. */ | ||
| const palette = { | ||
| 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 welcome banner. | ||
| */ | ||
| function getIntro({ title, description, version, areEyesOpen }) { | ||
| const kubbVersion = gradient([ | ||
| "#F58517", | ||
| "#F5A217", | ||
| "#F55A17" | ||
| ], `KUBB v${version}`); | ||
| const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───"); | ||
| const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───"); | ||
| return ` | ||
| ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")} | ||
| ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion} | ||
| ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${(0, node_util.styleText)("gray", title)} | ||
| ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${(0, node_util.styleText)("yellow", "➜")} ${(0, node_util.styleText)("white", description)} | ||
| ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")} | ||
| `; | ||
| } | ||
| /** ANSI color names available for terminal output. */ | ||
| const randomColors = [ | ||
| "black", | ||
| "red", | ||
| "green", | ||
| "yellow", | ||
| "blue", | ||
| "white", | ||
| "magenta", | ||
| "cyan", | ||
| "gray" | ||
| ]; | ||
| /** | ||
| * Returns the text wrapped in a deterministic ANSI color derived from the text's SHA-256 hash. | ||
| */ | ||
| function randomCliColor(text) { | ||
| if (!text) return ""; | ||
| return (0, node_util.styleText)(randomColors[(0, node_crypto.createHash)("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text); | ||
| } | ||
| /** | ||
| * Formats a millisecond duration with an ANSI color based on thresholds: | ||
| * green ≤ 500 ms · yellow ≤ 1 000 ms · red > 1 000 ms | ||
| */ | ||
| function formatMsWithColor(ms) { | ||
| const formatted = 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 ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write and returns `undefined` when the trimmed content is empty or | ||
| * identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the | ||
| * content does not match. | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return void 0; | ||
| const resolved = (0, node_path.resolve)(path); | ||
| if (typeof Bun !== "undefined") { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return void 0; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }) === trimmed) return void 0; | ||
| } catch {} | ||
| await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true }); | ||
| await (0, node_fs_promises.writeFile)(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getSummary.ts | ||
| function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) { | ||
| const duration = 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 sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]); | ||
| 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 / 100), 10); | ||
| 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/runHook.ts | ||
| /** | ||
| * Execute a hook command, emit debug/hook:end events, and forward output to | ||
| * an optional HookOutputSink. All three logger adapters share this function | ||
| * so the process-spawning logic lives in exactly one place. | ||
| */ | ||
| async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) { | ||
| try { | ||
| const proc = (0, tinyexec.x)(command, [...args ?? []], { | ||
| nodeOptions: { detached: true }, | ||
| throwOnError: true | ||
| }); | ||
| if (stream && sink?.onLine) for await (const line of proc) sink.onLine(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) { | ||
| if (!(err instanceof tinyexec.NonZeroExitError)) { | ||
| await context.emit("hook:end", { | ||
| command, | ||
| args, | ||
| id, | ||
| success: false, | ||
| error: require_errors.toError(err) | ||
| }); | ||
| await context.emit("error", require_errors.toError(err)); | ||
| return; | ||
| } | ||
| const stderr = err.output?.stderr ?? ""; | ||
| const stdout = err.output?.stdout ?? ""; | ||
| await context.emit("debug", { | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [stdout, stderr].filter(Boolean) | ||
| }); | ||
| if (stderr) sink?.onStderr?.(stderr); | ||
| if (stdout) sink?.onStdout?.(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); | ||
| } | ||
| } | ||
| //#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 line = buildProgressLine(state); | ||
| if (line) _clack_prompts.log.step(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel); | ||
| } | ||
| 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 = require_errors.toCause(error); | ||
| 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; | ||
| try { | ||
| _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" | ||
| }); | ||
| } catch { | ||
| console.log(`Update available for Kubb: v${version} → v${latestVersion}`); | ||
| console.log("Run `npm install -g @kubb/cli` to update"); | ||
| } | ||
| }); | ||
| 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) => { | ||
| reset(); | ||
| 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); | ||
| }); | ||
| 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", 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 = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} started`); | ||
| if (!id) return; | ||
| if (logLevel <= _kubb_core.logLevel.silent) { | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStderr: (s) => console.error(s), | ||
| onStdout: (s) => console.log(s) | ||
| } | ||
| }); | ||
| 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); | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| stream: true, | ||
| sink: { | ||
| onLine: (line) => writable.write(line), | ||
| onStderr: (s) => logger.error(s), | ||
| onStdout: (s) => logger.message(s) | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const text = getMessage(`Hook ${(0, node_util.styleText)("dim", formatCommandWithArgs(command, args))} 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"); | ||
| const borderColor = status === "success" ? "green" : "red"; | ||
| try { | ||
| _clack_prompts.box(summary.join("\n"), getMessage(title), { | ||
| width: "auto", | ||
| formatBorder: (s) => (0, node_util.styleText)(borderColor, s), | ||
| rounded: true, | ||
| withGuide: false, | ||
| contentAlign: "left", | ||
| titleAlign: "center" | ||
| }); | ||
| } catch { | ||
| console.log(summary.join("\n")); | ||
| } | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#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)(node_process.default.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(([fileName, logs]) => 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}`] | ||
| }); | ||
| }); | ||
| context.on("success", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✓ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`⚠ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("error", (error) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✗ ${error.message}`, error.stack || "unknown stack"] | ||
| }); | ||
| }); | ||
| context.on("debug", (message) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: message.logs | ||
| }); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Generating ${plugin.name}`] | ||
| }); | ||
| }); | ||
| context.on("plugin:end", (plugin, { duration, success }) => { | ||
| const durationStr = formatMs(duration); | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`] | ||
| }); | ||
| }); | ||
| context.on("files:processing:start", (files) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)] | ||
| }); | ||
| }); | ||
| 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)(node_process.default.cwd(), f)); | ||
| await context.emit("info", "Debug files written to:", files.join(", ")); | ||
| } | ||
| reset(); | ||
| }); | ||
| const exitHandler = () => { | ||
| if (state.cachedLogs.size > 0) writeLogs().catch(() => {}); | ||
| }; | ||
| node_process.default.once("exit", exitHandler); | ||
| node_process.default.once("SIGINT", exitHandler); | ||
| node_process.default.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(); | ||
| state.currentConfigs = []; | ||
| } | ||
| function showProgressStep() { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const line = buildProgressLine(state); | ||
| if (line) console.log(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel); | ||
| } | ||
| 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 = require_errors.toCause(error); | ||
| 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) => { | ||
| reset(); | ||
| 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)); | ||
| }); | ||
| 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", 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"); | ||
| showProgressStep(); | ||
| }); | ||
| context.on("file:processing:update", () => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| state.processedFiles++; | ||
| }); | ||
| 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 = formatCommandWithArgs(command, args); | ||
| 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; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| 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 = 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"); | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#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 ?? _kubb_core.logLevel.info; | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel); | ||
| } | ||
| 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 = require_errors.toCause(error); | ||
| 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("Generation 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 = 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 = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${commandWithArgs} started`); | ||
| if (logLevel > _kubb_core.logLevel.silent) console.log(text); | ||
| if (!id) return; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(s) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} 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(require_constants.SUMMARY_SEPARATOR); | ||
| console.log(summary.join("\n")); | ||
| console.log(require_constants.SUMMARY_SEPARATOR); | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/utils.ts | ||
| /** | ||
| * Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose. | ||
| * Shared across all logger adapters to avoid duplication. | ||
| */ | ||
| function formatMessage(message, logLevel) { | ||
| 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}`; | ||
| return message; | ||
| } | ||
| /** | ||
| * Build the progress summary line shared by clack and GitHub Actions loggers. | ||
| * Returns null when there is nothing to display. | ||
| */ | ||
| function buildProgressLine(state) { | ||
| const parts = []; | ||
| const duration = 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) return null; | ||
| parts.push(`${(0, node_util.styleText)("green", duration)} elapsed`); | ||
| return parts.join((0, node_util.styleText)("dim", " | ")); | ||
| } | ||
| /** | ||
| * Join a command and its optional args into a single display string. | ||
| * e.g. ("prettier", ["--write", "."]) → "prettier --write ." | ||
| */ | ||
| function formatCommandWithArgs(command, args) { | ||
| return args?.length ? `${command} ${args.join(" ")}` : command; | ||
| } | ||
| function detectLogger() { | ||
| if (require_telemetry.isGitHubActions()) return "github-actions"; | ||
| if (require_telemetry.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] = require_shell.tokenize(command); | ||
| if (!cmd) continue; | ||
| const hookId = (0, node_crypto.createHash)("sha256").update(command).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`)); | ||
| return; | ||
| } | ||
| events.emit("success", `${(0, node_util.styleText)("dim", command)} successfully executed`).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: cmd, | ||
| args | ||
| }); | ||
| await hookEndPromise; | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getCosmiConfig.ts | ||
| const jiti$1 = (0, jiti.createJiti)(require("url").pathToFileURL(__filename).href, { | ||
| jsx: { | ||
| runtime: "automatic", | ||
| importSource: "@kubb/react-fabric" | ||
| }, | ||
| sourceMaps: true, | ||
| interopDefault: true | ||
| }); | ||
| const tsLoader = async (configFile) => { | ||
| return await jiti$1.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.mts`, | ||
| `.${moduleName}rc.cts`, | ||
| `.${moduleName}rc.js`, | ||
| `.${moduleName}rc.mjs`, | ||
| `.${moduleName}rc.cjs`, | ||
| `${moduleName}.config.ts`, | ||
| `${moduleName}.config.mts`, | ||
| `${moduleName}.config.cts`, | ||
| `${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, | ||
| ".mts": tsLoader, | ||
| ".cts": 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 function startWatcher(path, cb) { | ||
| const { watch } = await import("chokidar"); | ||
| watch(path, { | ||
| ignorePermissionErrors: true, | ||
| ignored: require_constants.WATCHER_IGNORED_PATHS | ||
| }).on("all", async (type, file) => { | ||
| console.log((0, node_util.styleText)("yellow", (0, node_util.styleText)("bold", `Change detected: ${type} ${file}`))); | ||
| try { | ||
| await cb(path); | ||
| } catch (_e) { | ||
| console.log((0, node_util.styleText)("red", "Watcher failed")); | ||
| } | ||
| }); | ||
| } | ||
| //#endregion | ||
| //#region src/runners/generate.ts | ||
| async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel, events, onStart, onEnd }) { | ||
| await onStart(); | ||
| let resolvedTool = toolValue; | ||
| if (resolvedTool === "auto") { | ||
| const detected = await detect(); | ||
| if (!detected) await events.emit("warn", noToolMessage); | ||
| else { | ||
| resolvedTool = detected; | ||
| await events.emit("info", `Auto-detected ${toolLabel}: ${(0, node_util.styleText)("dim", resolvedTool)}`); | ||
| } | ||
| } | ||
| if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) { | ||
| const toolConfig = toolMap[resolvedTool]; | ||
| try { | ||
| const hookId = (0, node_crypto.createHash)("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`)); | ||
| return; | ||
| } | ||
| events.emit("success", [ | ||
| `${successPrefix} with ${(0, node_util.styleText)("dim", resolvedTool)}`, | ||
| logLevel >= _kubb_core.logLevel.info ? `on ${(0, node_util.styleText)("dim", outputPath)}` : void 0, | ||
| "successfully" | ||
| ].filter(Boolean).join(" ")).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: toolConfig.command, | ||
| args: toolConfig.args(outputPath) | ||
| }); | ||
| await hookEndPromise; | ||
| } catch (caughtError) { | ||
| const err = new Error(toolConfig.errorMessage); | ||
| err.cause = caughtError; | ||
| await events.emit("error", err); | ||
| } | ||
| } | ||
| await onEnd(); | ||
| } | ||
| 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) { | ||
| const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean); | ||
| for (const err of allErrors) await events.emit("error", err); | ||
| await events.emit("generation:end", config, files, sources); | ||
| await events.emit("generation:summary", config, { | ||
| failedPlugins, | ||
| filesCreated: files.length, | ||
| status: "failed", | ||
| hrStart, | ||
| pluginTimings: logLevel >= _kubb_core.logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| await require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: require_package.version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "failed" | ||
| })); | ||
| node_process.default.exit(1); | ||
| } | ||
| await events.emit("success", "Generation successfully", inputPath); | ||
| await events.emit("generation:end", config, files, sources); | ||
| const outputPath = node_path.default.resolve(config.root, config.output.path); | ||
| if (config.output.format) await runToolPass({ | ||
| toolValue: config.output.format, | ||
| detect: _kubb_core.detectFormatter, | ||
| toolMap: _kubb_core.formatters, | ||
| toolLabel: "formatter", | ||
| successPrefix: "Formatting", | ||
| noToolMessage: "No formatter found (biome, prettier, or oxfmt). Skipping formatting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel, | ||
| events, | ||
| onStart: () => events.emit("format:start"), | ||
| onEnd: () => events.emit("format:end") | ||
| }); | ||
| if (config.output.lint) await runToolPass({ | ||
| toolValue: config.output.lint, | ||
| detect: _kubb_core.detectLinter, | ||
| toolMap: _kubb_core.linters, | ||
| toolLabel: "linter", | ||
| successPrefix: "Linting", | ||
| noToolMessage: "No linter found (biome, oxlint, or eslint). Skipping linting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel, | ||
| events, | ||
| onStart: () => events.emit("lint:start"), | ||
| onEnd: () => 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: "success", | ||
| hrStart, | ||
| pluginTimings | ||
| }); | ||
| await require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: require_package.version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "success" | ||
| })); | ||
| } | ||
| async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) { | ||
| const logLevel = _kubb_core.logLevel[logLevelKey] ?? _kubb_core.logLevel.info; | ||
| const events = new AsyncEventEmitter(); | ||
| const promiseManager = new _kubb_core.PromiseManager(); | ||
| await setupLogger(events, { logLevel }); | ||
| await require_telemetry.executeIfOnline(async () => { | ||
| try { | ||
| const latestVersion = (await (await fetch(require_constants.KUBB_NPM_PACKAGE_URL)).json()).version; | ||
| if (latestVersion && require_package.version < latestVersion) await events.emit("version:new", require_package.version, latestVersion); | ||
| } catch {} | ||
| }); | ||
| try { | ||
| const result = await getCosmiConfig("kubb", configPath); | ||
| const configs = await (0, _kubb_core.getConfigs)(result.config, { input }); | ||
| await events.emit("config:start"); | ||
| await events.emit("info", "Config loaded", node_path.default.relative(node_process.default.cwd(), result.filepath)); | ||
| await events.emit("success", "Config loaded successfully", node_path.default.relative(node_process.default.cwd(), result.filepath)); | ||
| await events.emit("config:end", configs); | ||
| await events.emit("lifecycle:start", require_package.version); | ||
| const promises = configs.map((config) => { | ||
| return async () => { | ||
| if ((0, _kubb_core.isInputPath)(config) && watch) { | ||
| await startWatcher([input || config.input.path], async (paths) => { | ||
| events.removeAll(); | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel, | ||
| events | ||
| }); | ||
| _clack_prompts.log.step((0, node_util.styleText)("yellow", `Watching for changes in ${paths.join(" and ")}`)); | ||
| }); | ||
| return; | ||
| } | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel, | ||
| events | ||
| }); | ||
| }; | ||
| }); | ||
| await promiseManager.run("seq", promises); | ||
| await events.emit("lifecycle:end"); | ||
| } catch (error) { | ||
| await events.emit("error", require_errors.toError(error)); | ||
| node_process.default.exit(1); | ||
| } | ||
| } | ||
| //#endregion | ||
| exports.runGenerateCommand = runGenerateCommand; | ||
| //# sourceMappingURL=generate-DyK2S7hv.cjs.map |
Sorry, the diff of this file is too big to display
| import "./chunk--u3MIqq1.js"; | ||
| import { n as toCause, r as toError } from "./errors-6mF_WKxg.js"; | ||
| import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-CHWsjyeK.js"; | ||
| import { n as tokenize } from "./shell-DqqWsHCD.js"; | ||
| import { t as version } from "./package-7k6Ul15n.js"; | ||
| import { i as WATCHER_IGNORED_PATHS, r as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-CM3dJzjK.js"; | ||
| import { styleText } from "node:util"; | ||
| import { EventEmitter } from "node:events"; | ||
| import { createHash } from "node:crypto"; | ||
| import "node:fs"; | ||
| import { mkdir, readFile, writeFile } from "node:fs/promises"; | ||
| import path, { dirname, relative, resolve } from "node:path"; | ||
| import process$1 from "node:process"; | ||
| import * as clack from "@clack/prompts"; | ||
| import { PromiseManager, defineLogger, detectFormatter, detectLinter, formatters, getConfigs, isInputPath, linters, logLevel, safeBuild, setup } from "@kubb/core"; | ||
| import { NonZeroExitError, x } from "tinyexec"; | ||
| import { Writable } from "node:stream"; | ||
| import { cosmiconfig } from "cosmiconfig"; | ||
| import { createJiti } from "jiti"; | ||
| //#region ../../internals/utils/src/asyncEventEmitter.ts | ||
| /** | ||
| * A typed EventEmitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript event-map inference. | ||
| */ | ||
| var AsyncEventEmitter = class { | ||
| /** | ||
| * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new EventEmitter(); | ||
| /** | ||
| * Emits an event and awaits all registered listeners in parallel. | ||
| * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments. | ||
| */ | ||
| async emit(eventName, ...eventArgs) { | ||
| const listeners = this.#emitter.listeners(eventName); | ||
| if (listeners.length === 0) return; | ||
| await Promise.all(listeners.map(async (listener) => { | ||
| try { | ||
| return await listener(...eventArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(eventArgs); | ||
| } catch { | ||
| serializedArgs = String(eventArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) }); | ||
| } | ||
| })); | ||
| } | ||
| /** Registers a persistent listener for the given event. */ | ||
| on(eventName, handler) { | ||
| this.#emitter.on(eventName, handler); | ||
| } | ||
| /** Registers a one-shot listener that removes itself after the first invocation. */ | ||
| onOnce(eventName, handler) { | ||
| const wrapper = (...args) => { | ||
| this.off(eventName, wrapper); | ||
| return handler(...args); | ||
| }; | ||
| this.on(eventName, wrapper); | ||
| } | ||
| /** Removes a previously registered listener. */ | ||
| off(eventName, handler) { | ||
| this.#emitter.off(eventName, handler); | ||
| } | ||
| /** Removes all listeners from every event channel. */ | ||
| removeAll() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region ../../internals/utils/src/time.ts | ||
| /** | ||
| * Calculates elapsed time in milliseconds from a high-resolution start time. | ||
| * Rounds to 2 decimal places to provide sub-millisecond precision without noise. | ||
| */ | ||
| function getElapsedMs(hrStart) { | ||
| const [seconds, nanoseconds] = process.hrtime(hrStart); | ||
| const ms = seconds * 1e3 + nanoseconds / 1e6; | ||
| return Math.round(ms * 100) / 100; | ||
| } | ||
| /** | ||
| * Converts a millisecond duration into a human-readable string. | ||
| * Adjusts units (ms, s, m s) based on the magnitude of the duration. | ||
| */ | ||
| function formatMs(ms) { | ||
| if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`; | ||
| if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`; | ||
| return `${Math.round(ms)}ms`; | ||
| } | ||
| /** | ||
| * Convenience helper: formats the elapsed time since `hrStart` in one step. | ||
| */ | ||
| function formatHrtime(hrStart) { | ||
| return formatMs(getElapsedMs(hrStart)); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/colors.ts | ||
| /** | ||
| * Parses a CSS hex color string (`#RGB`) into its RGB channels. | ||
| * Falls back to `255` for any channel that cannot be parsed. | ||
| */ | ||
| function parseHex(color) { | ||
| const int = Number.parseInt(color.replace("#", ""), 16); | ||
| return Number.isNaN(int) ? { | ||
| r: 255, | ||
| g: 255, | ||
| b: 255 | ||
| } : { | ||
| r: int >> 16 & 255, | ||
| g: int >> 8 & 255, | ||
| b: int & 255 | ||
| }; | ||
| } | ||
| /** | ||
| * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence | ||
| * for the given hex color. | ||
| */ | ||
| function hex(color) { | ||
| const { r, g, b } = parseHex(color); | ||
| return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`; | ||
| } | ||
| function gradient(colorStops, text) { | ||
| const chars = text.split(""); | ||
| return chars.map((char, i) => { | ||
| const t = chars.length <= 1 ? 0 : i / (chars.length - 1); | ||
| const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2); | ||
| const lt = t * (colorStops.length - 1) - seg; | ||
| const from = parseHex(colorStops[seg]); | ||
| const to = parseHex(colorStops[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(""); | ||
| } | ||
| /** ANSI color functions for each part of the Kubb mascot illustration. */ | ||
| const palette = { | ||
| 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 welcome banner. | ||
| */ | ||
| function getIntro({ title, description, version, areEyesOpen }) { | ||
| const kubbVersion = gradient([ | ||
| "#F58517", | ||
| "#F5A217", | ||
| "#F55A17" | ||
| ], `KUBB v${version}`); | ||
| const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───"); | ||
| const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───"); | ||
| return ` | ||
| ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")} | ||
| ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion} | ||
| ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${styleText("gray", title)} | ||
| ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${styleText("yellow", "➜")} ${styleText("white", description)} | ||
| ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")} | ||
| `; | ||
| } | ||
| /** ANSI color names available for terminal output. */ | ||
| const randomColors = [ | ||
| "black", | ||
| "red", | ||
| "green", | ||
| "yellow", | ||
| "blue", | ||
| "white", | ||
| "magenta", | ||
| "cyan", | ||
| "gray" | ||
| ]; | ||
| /** | ||
| * Returns the text wrapped in a deterministic ANSI color derived from the text's SHA-256 hash. | ||
| */ | ||
| function randomCliColor(text) { | ||
| if (!text) return ""; | ||
| return styleText(randomColors[createHash("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text); | ||
| } | ||
| /** | ||
| * Formats a millisecond duration with an ANSI color based on thresholds: | ||
| * green ≤ 500 ms · yellow ≤ 1 000 ms · red > 1 000 ms | ||
| */ | ||
| function formatMsWithColor(ms) { | ||
| const formatted = formatMs(ms); | ||
| if (ms <= 500) return styleText("green", formatted); | ||
| if (ms <= 1e3) return styleText("yellow", formatted); | ||
| return styleText("red", formatted); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write and returns `undefined` when the trimmed content is empty or | ||
| * identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the | ||
| * content does not match. | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return void 0; | ||
| const resolved = resolve(path); | ||
| if (typeof Bun !== "undefined") { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return void 0; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return void 0; | ||
| } catch {} | ||
| await mkdir(dirname(resolved), { recursive: true }); | ||
| await writeFile(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await readFile(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getSummary.ts | ||
| function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) { | ||
| const duration = formatHrtime(hrStart); | ||
| const pluginsCount = config.plugins?.length ?? 0; | ||
| const successCount = pluginsCount - failedPlugins.size; | ||
| const meta = { | ||
| plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`, | ||
| pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0, | ||
| filesCreated, | ||
| time: styleText("green", duration), | ||
| output: path.isAbsolute(config.root) ? path.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 sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]); | ||
| 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 / 100), 10); | ||
| const bar = styleText("dim", "█".repeat(barLength)); | ||
| summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`); | ||
| }); | ||
| } | ||
| summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`); | ||
| return summaryLines; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/runHook.ts | ||
| /** | ||
| * Execute a hook command, emit debug/hook:end events, and forward output to | ||
| * an optional HookOutputSink. All three logger adapters share this function | ||
| * so the process-spawning logic lives in exactly one place. | ||
| */ | ||
| async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) { | ||
| try { | ||
| const proc = x(command, [...args ?? []], { | ||
| nodeOptions: { detached: true }, | ||
| throwOnError: true | ||
| }); | ||
| if (stream && sink?.onLine) for await (const line of proc) sink.onLine(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) { | ||
| if (!(err instanceof NonZeroExitError)) { | ||
| await context.emit("hook:end", { | ||
| command, | ||
| args, | ||
| id, | ||
| success: false, | ||
| error: toError(err) | ||
| }); | ||
| await context.emit("error", toError(err)); | ||
| return; | ||
| } | ||
| const stderr = err.output?.stderr ?? ""; | ||
| const stdout = err.output?.stdout ?? ""; | ||
| await context.emit("debug", { | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [stdout, stderr].filter(Boolean) | ||
| }); | ||
| if (stderr) sink?.onStderr?.(stderr); | ||
| if (stdout) sink?.onStdout?.(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); | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/utils/Writables.ts | ||
| var ClackWritable = class extends Writable { | ||
| taskLog; | ||
| constructor(taskLog, opts) { | ||
| super(opts); | ||
| this.taskLog = taskLog; | ||
| } | ||
| _write(chunk, _encoding, callback) { | ||
| this.taskLog.message(`${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 = defineLogger({ | ||
| name: "clack", | ||
| install(context, options) { | ||
| const logLevel$8 = options?.logLevel ?? logLevel.info; | ||
| const state = { | ||
| totalPlugins: 0, | ||
| completedPlugins: 0, | ||
| failedPlugins: 0, | ||
| totalFiles: 0, | ||
| processedFiles: 0, | ||
| hrStart: process$1.hrtime(), | ||
| spinner: clack.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 = process$1.hrtime(); | ||
| state.spinner = clack.spinner(); | ||
| state.isSpinning = false; | ||
| state.activeProgress.clear(); | ||
| } | ||
| function showProgressStep() { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const line = buildProgressLine(state); | ||
| if (line) clack.log.step(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel$8); | ||
| } | ||
| 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$8 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "ℹ"), | ||
| message, | ||
| styleText("dim", info) | ||
| ].join(" ")); | ||
| if (state.isSpinning) state.spinner.message(text); | ||
| else clack.log.info(text); | ||
| }); | ||
| context.on("success", (message, info = "") => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "✓"), | ||
| message, | ||
| logLevel$8 >= logLevel.info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| if (state.isSpinning) stopSpinner(text); | ||
| else clack.log.success(text); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| if (logLevel$8 < logLevel.warn) return; | ||
| const text = getMessage([ | ||
| styleText("yellow", "⚠"), | ||
| message, | ||
| logLevel$8 >= logLevel.info && info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| clack.log.warn(text); | ||
| }); | ||
| context.on("error", (error) => { | ||
| const caused = toCause(error); | ||
| const text = [styleText("red", "✗"), error.message].join(" "); | ||
| if (state.isSpinning) stopSpinner(getMessage(text)); | ||
| else clack.log.error(getMessage(text)); | ||
| if (logLevel$8 >= logLevel.debug && error.stack) { | ||
| const frames = error.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) clack.log.message(getMessage(styleText("dim", frame.trim()))); | ||
| if (caused?.stack) { | ||
| clack.log.message(styleText("dim", `└─ caused by ${caused.message}`)); | ||
| const frames = caused.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) clack.log.message(getMessage(` ${styleText("dim", frame.trim())}`)); | ||
| } | ||
| } | ||
| }); | ||
| context.on("version:new", (version, latestVersion) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| try { | ||
| clack.box(`\`v${version}\` → \`v${latestVersion}\` | ||
| Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", { | ||
| width: "auto", | ||
| formatBorder: (s) => styleText("yellow", s), | ||
| rounded: true, | ||
| withGuide: false, | ||
| contentAlign: "center", | ||
| titleAlign: "center" | ||
| }); | ||
| } catch { | ||
| console.log(`Update available for Kubb: v${version} → v${latestVersion}`); | ||
| console.log("Run `npm install -g @kubb/cli` to update"); | ||
| } | ||
| }); | ||
| 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$8 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration started"); | ||
| clack.intro(text); | ||
| startSpinner(getMessage("Configuration loading")); | ||
| }); | ||
| context.on("config:end", (_configs) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("generation:start", (config) => { | ||
| reset(); | ||
| state.totalPlugins = config.plugins?.length ?? 0; | ||
| const text = getMessage(["Generation started", config.name ? `for ${styleText("dim", config.name)}` : void 0].filter(Boolean).join(" ")); | ||
| clack.intro(text); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| stopSpinner(); | ||
| const progressBar = clack.progress({ | ||
| style: "block", | ||
| max: 100, | ||
| size: 30 | ||
| }); | ||
| const text = getMessage(`Generating ${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$8 === logLevel.silent) return; | ||
| clearInterval(active.interval); | ||
| if (success) state.completedPlugins++; | ||
| else state.failedPlugins++; | ||
| const durationStr = formatMsWithColor(duration); | ||
| const text = getMessage(success ? `${styleText("bold", plugin.name)} completed in ${durationStr}` : `${styleText("bold", plugin.name)} failed in ${styleText("red", formatMs(duration))}`); | ||
| active.progressBar.stop(text); | ||
| state.activeProgress.delete(plugin.name); | ||
| showProgressStep(); | ||
| }); | ||
| context.on("files:processing:start", (files) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| stopSpinner(); | ||
| state.totalFiles = files.length; | ||
| state.processedFiles = 0; | ||
| const text = `Writing ${files.length} files`; | ||
| const progressBar = clack.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$8 <= logLevel.silent) return; | ||
| stopSpinner(); | ||
| state.processedFiles++; | ||
| const text = `Writing ${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$8 <= 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 ${styleText("dim", config.name)}` : "Generation completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("format:start", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Format started"); | ||
| clack.intro(text); | ||
| }); | ||
| context.on("format:end", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Format completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("lint:start", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Lint started"); | ||
| clack.intro(text); | ||
| }); | ||
| context.on("lint:end", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Lint completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("hook:start", async ({ id, command, args }) => { | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`); | ||
| if (!id) return; | ||
| if (logLevel$8 <= logLevel.silent) { | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStderr: (s) => console.error(s), | ||
| onStdout: (s) => console.log(s) | ||
| } | ||
| }); | ||
| return; | ||
| } | ||
| clack.intro(text); | ||
| const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) }); | ||
| const writable = new ClackWritable(logger); | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| stream: true, | ||
| sink: { | ||
| onLine: (line) => writable.write(line), | ||
| onStderr: (s) => logger.error(s), | ||
| onStdout: (s) => logger.message(s) | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} successfully executed`); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("generation:summary", (config, { pluginTimings, failedPlugins, filesCreated, status, hrStart }) => { | ||
| const summary = getSummary({ | ||
| failedPlugins, | ||
| filesCreated, | ||
| config, | ||
| status, | ||
| hrStart, | ||
| pluginTimings: logLevel$8 >= logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| const title = config.name || ""; | ||
| summary.unshift("\n"); | ||
| summary.push("\n"); | ||
| const borderColor = status === "success" ? "green" : "red"; | ||
| try { | ||
| clack.box(summary.join("\n"), getMessage(title), { | ||
| width: "auto", | ||
| formatBorder: (s) => styleText(borderColor, s), | ||
| rounded: true, | ||
| withGuide: false, | ||
| contentAlign: "left", | ||
| titleAlign: "center" | ||
| }); | ||
| } catch { | ||
| console.log(summary.join("\n")); | ||
| } | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#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 = 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 = resolve(process$1.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(([fileName, logs]) => 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}`] | ||
| }); | ||
| }); | ||
| context.on("success", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✓ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`⚠ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("error", (error) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✗ ${error.message}`, error.stack || "unknown stack"] | ||
| }); | ||
| }); | ||
| context.on("debug", (message) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: message.logs | ||
| }); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Generating ${plugin.name}`] | ||
| }); | ||
| }); | ||
| context.on("plugin:end", (plugin, { duration, success }) => { | ||
| const durationStr = formatMs(duration); | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`] | ||
| }); | ||
| }); | ||
| context.on("files:processing:start", (files) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)] | ||
| }); | ||
| }); | ||
| context.on("generation:end", async (config) => { | ||
| const writtenFilePaths = await writeLogs(config.name); | ||
| if (writtenFilePaths.length > 0) { | ||
| const files = writtenFilePaths.map((f) => relative(process$1.cwd(), f)); | ||
| await context.emit("info", "Debug files written to:", files.join(", ")); | ||
| } | ||
| reset(); | ||
| }); | ||
| const exitHandler = () => { | ||
| if (state.cachedLogs.size > 0) writeLogs().catch(() => {}); | ||
| }; | ||
| process$1.once("exit", exitHandler); | ||
| process$1.once("SIGINT", exitHandler); | ||
| process$1.once("SIGTERM", exitHandler); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/githubActionsLogger.ts | ||
| /** | ||
| * GitHub Actions adapter for CI environments | ||
| * Uses Github group annotations for collapsible sections | ||
| */ | ||
| const githubActionsLogger = defineLogger({ | ||
| name: "github-actions", | ||
| install(context, options) { | ||
| const logLevel$7 = options?.logLevel ?? 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(); | ||
| state.currentConfigs = []; | ||
| } | ||
| function showProgressStep() { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const line = buildProgressLine(state); | ||
| if (line) console.log(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel$7); | ||
| } | ||
| function openGroup(name) { | ||
| console.log(`::group::${name}`); | ||
| } | ||
| function closeGroup(_name) { | ||
| console.log("::endgroup::"); | ||
| } | ||
| context.on("info", (message, info = "") => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "ℹ"), | ||
| message, | ||
| styleText("dim", info) | ||
| ].join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("success", (message, info = "") => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "✓"), | ||
| message, | ||
| logLevel$7 >= logLevel.info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("warn", (message, info = "") => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("yellow", "⚠"), | ||
| message, | ||
| logLevel$7 >= logLevel.info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.warn(`::warning::${text}`); | ||
| }); | ||
| context.on("error", (error) => { | ||
| const caused = toCause(error); | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const message = error.message || String(error); | ||
| console.error(`::error::${message}`); | ||
| if (logLevel$7 >= logLevel.debug && error.stack) { | ||
| const frames = error.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) console.log(getMessage(styleText("dim", frame.trim()))); | ||
| if (caused?.stack) { | ||
| console.log(styleText("dim", `└─ caused by ${caused.message}`)); | ||
| const frames = caused.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) console.log(getMessage(` ${styleText("dim", frame.trim())}`)); | ||
| } | ||
| } | ||
| }); | ||
| context.on("lifecycle:start", (version) => { | ||
| console.log(styleText("yellow", `Kubb ${version} 🧩`)); | ||
| reset(); | ||
| }); | ||
| context.on("config:start", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration started"); | ||
| openGroup("Configuration"); | ||
| console.log(text); | ||
| }); | ||
| context.on("config:end", (configs) => { | ||
| state.currentConfigs = configs; | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration completed"); | ||
| console.log(text); | ||
| closeGroup("Configuration"); | ||
| }); | ||
| context.on("generation:start", (config) => { | ||
| reset(); | ||
| state.totalPlugins = config.plugins?.length ?? 0; | ||
| const text = config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation"; | ||
| if (state.currentConfigs.length > 1) openGroup(text); | ||
| if (state.currentConfigs.length === 1) console.log(getMessage(text)); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage(`Generating ${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$7 <= logLevel.silent) return; | ||
| if (success) state.completedPlugins++; | ||
| else state.failedPlugins++; | ||
| const durationStr = formatMsWithColor(duration); | ||
| const text = getMessage(success ? `${styleText("bold", plugin.name)} completed in ${durationStr}` : `${styleText("bold", plugin.name)} failed in ${styleText("red", 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$7 <= 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$7 <= logLevel.silent) return; | ||
| const text = getMessage("Files written successfully"); | ||
| console.log(text); | ||
| if (state.currentConfigs.length === 1) closeGroup("File Generation"); | ||
| showProgressStep(); | ||
| }); | ||
| context.on("file:processing:update", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| state.processedFiles++; | ||
| }); | ||
| context.on("generation:end", (config) => { | ||
| const text = getMessage(config.name ? `${styleText("blue", "✓")} Generation completed for ${styleText("dim", config.name)}` : `${styleText("blue", "✓")} Generation completed`); | ||
| console.log(text); | ||
| }); | ||
| context.on("format:start", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Format started"); | ||
| if (state.currentConfigs.length === 1) openGroup("Formatting"); | ||
| console.log(text); | ||
| }); | ||
| context.on("format:end", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Format completed"); | ||
| console.log(text); | ||
| if (state.currentConfigs.length === 1) closeGroup("Formatting"); | ||
| }); | ||
| context.on("lint:start", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Lint started"); | ||
| if (state.currentConfigs.length === 1) openGroup("Linting"); | ||
| console.log(text); | ||
| }); | ||
| context.on("lint:end", () => { | ||
| if (logLevel$7 <= 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 = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`); | ||
| if (logLevel$7 > logLevel.silent) { | ||
| if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`); | ||
| console.log(text); | ||
| } | ||
| if (!id) return; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${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 = formatHrtime(hrStart); | ||
| if (state.currentConfigs.length > 1) console.log(" "); | ||
| console.log(status === "success" ? `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ${pluginsCount} total, ${styleText("green", duration)}` : `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${styleText("green", duration)}`); | ||
| if (state.currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation"); | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/plainLogger.ts | ||
| /** | ||
| * Plain console adapter for non-TTY environments | ||
| * Simple console.log output with indentation | ||
| */ | ||
| const plainLogger = defineLogger({ | ||
| name: "plain", | ||
| install(context, options) { | ||
| const logLevel$6 = options?.logLevel ?? logLevel.info; | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel$6); | ||
| } | ||
| context.on("info", (message, info) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| "ℹ", | ||
| message, | ||
| info | ||
| ].join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("success", (message, info = "") => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| "✓", | ||
| message, | ||
| logLevel$6 >= logLevel.info ? info : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| if (logLevel$6 < logLevel.warn) return; | ||
| const text = getMessage([ | ||
| "⚠", | ||
| message, | ||
| logLevel$6 >= logLevel.info ? info : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("error", (error) => { | ||
| const caused = toCause(error); | ||
| const text = getMessage(["✗", error.message].join(" ")); | ||
| console.log(text); | ||
| if (logLevel$6 >= 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$6 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("config:end", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration completed"); | ||
| console.log(text); | ||
| }); | ||
| context.on("generation:start", () => { | ||
| const text = getMessage("Generation started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Generating ${plugin.name}`); | ||
| console.log(text); | ||
| }); | ||
| context.on("plugin:end", (plugin, { duration, success }) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const durationStr = 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$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Writing ${files.length} files`); | ||
| console.log(text); | ||
| }); | ||
| context.on("file:processing:update", ({ file, config }) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Writing ${relative(config.root, file.path)}`); | ||
| console.log(text); | ||
| }); | ||
| context.on("files:processing:end", () => { | ||
| if (logLevel$6 <= 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$6 <= logLevel.silent) return; | ||
| const text = getMessage("Format started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("format:end", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Format completed"); | ||
| console.log(text); | ||
| }); | ||
| context.on("lint:start", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Lint started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("lint:end", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Lint completed"); | ||
| console.log(text); | ||
| }); | ||
| context.on("hook:start", async ({ id, command, args }) => { | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${commandWithArgs} started`); | ||
| if (logLevel$6 > logLevel.silent) console.log(text); | ||
| if (!id) return; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} completed`); | ||
| console.log(text); | ||
| }); | ||
| context.on("generation:summary", (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => { | ||
| const summary = getSummary({ | ||
| failedPlugins, | ||
| filesCreated, | ||
| config, | ||
| status, | ||
| hrStart, | ||
| pluginTimings: logLevel$6 >= logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| console.log(SUMMARY_SEPARATOR); | ||
| console.log(summary.join("\n")); | ||
| console.log(SUMMARY_SEPARATOR); | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/utils.ts | ||
| /** | ||
| * Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose. | ||
| * Shared across all logger adapters to avoid duplication. | ||
| */ | ||
| function formatMessage(message, logLevel$4) { | ||
| if (logLevel$4 >= logLevel.verbose) return `${styleText("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { | ||
| hour12: false, | ||
| hour: "2-digit", | ||
| minute: "2-digit", | ||
| second: "2-digit" | ||
| })}]`)} ${message}`; | ||
| return message; | ||
| } | ||
| /** | ||
| * Build the progress summary line shared by clack and GitHub Actions loggers. | ||
| * Returns null when there is nothing to display. | ||
| */ | ||
| function buildProgressLine(state) { | ||
| const parts = []; | ||
| const duration = formatHrtime(state.hrStart); | ||
| if (state.totalPlugins > 0) { | ||
| const pluginStr = state.failedPlugins > 0 ? `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins} ${styleText("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins}`; | ||
| parts.push(pluginStr); | ||
| } | ||
| if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`); | ||
| if (parts.length === 0) return null; | ||
| parts.push(`${styleText("green", duration)} elapsed`); | ||
| return parts.join(styleText("dim", " | ")); | ||
| } | ||
| /** | ||
| * Join a command and its optional args into a single display string. | ||
| * e.g. ("prettier", ["--write", "."]) → "prettier --write ." | ||
| */ | ||
| function formatCommandWithArgs(command, args) { | ||
| return args?.length ? `${command} ${args.join(" ")}` : command; | ||
| } | ||
| 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: logLevel$5 }) { | ||
| const type = detectLogger(); | ||
| const logger = logMapper[type]; | ||
| if (!logger) throw new Error(`Unknown adapter type: ${type}`); | ||
| const cleanup = await logger.install(context, { logLevel: logLevel$5 }); | ||
| if (logLevel$5 >= logLevel.debug) await fileSystemLogger.install(context, { logLevel: logLevel$5 }); | ||
| 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] = tokenize(command); | ||
| if (!cmd) continue; | ||
| const hookId = createHash("sha256").update(command).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`)); | ||
| return; | ||
| } | ||
| events.emit("success", `${styleText("dim", command)} successfully executed`).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: cmd, | ||
| args | ||
| }); | ||
| await hookEndPromise; | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getCosmiConfig.ts | ||
| const jiti = createJiti(import.meta.url, { | ||
| jsx: { | ||
| runtime: "automatic", | ||
| importSource: "@kubb/react-fabric" | ||
| }, | ||
| sourceMaps: true, | ||
| interopDefault: true | ||
| }); | ||
| const tsLoader = async (configFile) => { | ||
| return await jiti.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.mts`, | ||
| `.${moduleName}rc.cts`, | ||
| `.${moduleName}rc.js`, | ||
| `.${moduleName}rc.mjs`, | ||
| `.${moduleName}rc.cjs`, | ||
| `${moduleName}.config.ts`, | ||
| `${moduleName}.config.mts`, | ||
| `${moduleName}.config.cts`, | ||
| `${moduleName}.config.js`, | ||
| `${moduleName}.config.mjs`, | ||
| `${moduleName}.config.cjs` | ||
| ]; | ||
| const explorer = cosmiconfig(moduleName, { | ||
| cache: false, | ||
| searchPlaces: [ | ||
| ...searchPlaces.map((searchPlace) => { | ||
| return `.config/${searchPlace}`; | ||
| }), | ||
| ...searchPlaces.map((searchPlace) => { | ||
| return `configs/${searchPlace}`; | ||
| }), | ||
| ...searchPlaces | ||
| ], | ||
| loaders: { | ||
| ".ts": tsLoader, | ||
| ".mts": tsLoader, | ||
| ".cts": 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 function startWatcher(path, cb) { | ||
| const { watch } = await import("chokidar"); | ||
| watch(path, { | ||
| ignorePermissionErrors: true, | ||
| ignored: WATCHER_IGNORED_PATHS | ||
| }).on("all", async (type, file) => { | ||
| console.log(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`))); | ||
| try { | ||
| await cb(path); | ||
| } catch (_e) { | ||
| console.log(styleText("red", "Watcher failed")); | ||
| } | ||
| }); | ||
| } | ||
| //#endregion | ||
| //#region src/runners/generate.ts | ||
| async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, events, onStart, onEnd }) { | ||
| await onStart(); | ||
| let resolvedTool = toolValue; | ||
| if (resolvedTool === "auto") { | ||
| const detected = await detect(); | ||
| if (!detected) await events.emit("warn", noToolMessage); | ||
| else { | ||
| resolvedTool = detected; | ||
| await events.emit("info", `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}`); | ||
| } | ||
| } | ||
| if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) { | ||
| const toolConfig = toolMap[resolvedTool]; | ||
| try { | ||
| const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`)); | ||
| return; | ||
| } | ||
| events.emit("success", [ | ||
| `${successPrefix} with ${styleText("dim", resolvedTool)}`, | ||
| logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0, | ||
| "successfully" | ||
| ].filter(Boolean).join(" ")).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: toolConfig.command, | ||
| args: toolConfig.args(outputPath) | ||
| }); | ||
| await hookEndPromise; | ||
| } catch (caughtError) { | ||
| const err = new Error(toolConfig.errorMessage); | ||
| err.cause = caughtError; | ||
| await events.emit("error", err); | ||
| } | ||
| } | ||
| await onEnd(); | ||
| } | ||
| async function generate({ input, config: userConfig, events, logLevel: logLevel$2 }) { | ||
| const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0); | ||
| const hrStart = process$1.hrtime(); | ||
| const config = { | ||
| ...userConfig, | ||
| root: userConfig.root || process$1.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 ${styleText("bold", config.name)}` : "Setup generation", inputPath); | ||
| const { sources, fabric, pluginManager } = await setup({ | ||
| config, | ||
| events | ||
| }); | ||
| await events.emit("info", config.name ? `Build generation ${styleText("bold", config.name)}` : "Build generation", inputPath); | ||
| const { files, failedPlugins, pluginTimings, error } = await safeBuild({ | ||
| config, | ||
| events | ||
| }, { | ||
| pluginManager, | ||
| fabric, | ||
| events, | ||
| sources | ||
| }); | ||
| await events.emit("info", "Load summary"); | ||
| if (failedPlugins.size > 0 || error) { | ||
| const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean); | ||
| for (const err of allErrors) await events.emit("error", err); | ||
| await events.emit("generation:end", config, files, sources); | ||
| await events.emit("generation:summary", config, { | ||
| failedPlugins, | ||
| filesCreated: files.length, | ||
| status: "failed", | ||
| hrStart, | ||
| pluginTimings: logLevel$2 >= logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| await sendTelemetry(buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "failed" | ||
| })); | ||
| process$1.exit(1); | ||
| } | ||
| await events.emit("success", "Generation successfully", inputPath); | ||
| await events.emit("generation:end", config, files, sources); | ||
| const outputPath = path.resolve(config.root, config.output.path); | ||
| if (config.output.format) await runToolPass({ | ||
| toolValue: config.output.format, | ||
| detect: detectFormatter, | ||
| toolMap: formatters, | ||
| toolLabel: "formatter", | ||
| successPrefix: "Formatting", | ||
| noToolMessage: "No formatter found (biome, prettier, or oxfmt). Skipping formatting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel: logLevel$2, | ||
| events, | ||
| onStart: () => events.emit("format:start"), | ||
| onEnd: () => events.emit("format:end") | ||
| }); | ||
| if (config.output.lint) await runToolPass({ | ||
| toolValue: config.output.lint, | ||
| detect: detectLinter, | ||
| toolMap: linters, | ||
| toolLabel: "linter", | ||
| successPrefix: "Linting", | ||
| noToolMessage: "No linter found (biome, oxlint, or eslint). Skipping linting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel: logLevel$2, | ||
| events, | ||
| onStart: () => events.emit("lint:start"), | ||
| onEnd: () => 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: "success", | ||
| hrStart, | ||
| pluginTimings | ||
| }); | ||
| await sendTelemetry(buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "success" | ||
| })); | ||
| } | ||
| async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) { | ||
| const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info; | ||
| const events = new AsyncEventEmitter(); | ||
| const promiseManager = new PromiseManager(); | ||
| await setupLogger(events, { logLevel: logLevel$3 }); | ||
| await executeIfOnline(async () => { | ||
| try { | ||
| const latestVersion = (await (await fetch(KUBB_NPM_PACKAGE_URL)).json()).version; | ||
| if (latestVersion && version < latestVersion) await events.emit("version:new", version, latestVersion); | ||
| } catch {} | ||
| }); | ||
| try { | ||
| const result = await getCosmiConfig("kubb", configPath); | ||
| const configs = await getConfigs(result.config, { input }); | ||
| await events.emit("config:start"); | ||
| await events.emit("info", "Config loaded", path.relative(process$1.cwd(), result.filepath)); | ||
| await events.emit("success", "Config loaded successfully", path.relative(process$1.cwd(), result.filepath)); | ||
| await events.emit("config:end", configs); | ||
| await events.emit("lifecycle:start", version); | ||
| const promises = configs.map((config) => { | ||
| return async () => { | ||
| if (isInputPath(config) && watch) { | ||
| await startWatcher([input || config.input.path], async (paths) => { | ||
| events.removeAll(); | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel: logLevel$3, | ||
| events | ||
| }); | ||
| clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`)); | ||
| }); | ||
| return; | ||
| } | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel: logLevel$3, | ||
| events | ||
| }); | ||
| }; | ||
| }); | ||
| await promiseManager.run("seq", promises); | ||
| await events.emit("lifecycle:end"); | ||
| } catch (error) { | ||
| await events.emit("error", toError(error)); | ||
| process$1.exit(1); | ||
| } | ||
| } | ||
| //#endregion | ||
| export { runGenerateCommand }; | ||
| //# sourceMappingURL=generate-sIkyxxtw.js.map |
Sorry, the diff of this file is too big to display
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-7k6Ul15n.js"; | ||
| //#region src/commands/init.ts | ||
| const command = defineCommand({ | ||
| name: "init", | ||
| description: "Initialize a new Kubb project with interactive setup", | ||
| options: { yes: { | ||
| type: "boolean", | ||
| description: "Skip prompts and use default options", | ||
| short: "y", | ||
| default: false | ||
| } }, | ||
| async run({ values }) { | ||
| const { runInit } = await import("./init-C-InrmSY.js"); | ||
| await runInit({ | ||
| yes: values.yes, | ||
| version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=init-BkN1O1VV.js.map |
| {"version":3,"file":"init-BkN1O1VV.js","names":[],"sources":["../src/commands/init.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'init',\n description: 'Initialize a new Kubb project with interactive setup',\n options: {\n yes: { type: 'boolean', description: 'Skip prompts and use default options', short: 'y', default: false },\n },\n async run({ values }) {\n const { runInit } = await import('../runners/init.ts')\n\n await runInit({ yes: values.yes, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,KAAK;EAAE,MAAM;EAAW,aAAa;EAAwC,OAAO;EAAK,SAAS;EAAO,EAC1G;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,YAAY,MAAM,OAAO;AAEjC,QAAM,QAAQ;GAAE,KAAK,OAAO;GAAK;GAAS,CAAC;;CAE9C,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-m-LvDtUC.cjs"); | ||
| //#region src/commands/init.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "init", | ||
| description: "Initialize a new Kubb project with interactive setup", | ||
| options: { yes: { | ||
| type: "boolean", | ||
| description: "Skip prompts and use default options", | ||
| short: "y", | ||
| default: false | ||
| } }, | ||
| async run({ values }) { | ||
| const { runInit } = await Promise.resolve().then(() => require("./init-hmolV6B4.cjs")); | ||
| await runInit({ | ||
| yes: values.yes, | ||
| version: require_package.version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=init-DL8L1JpC.cjs.map |
| {"version":3,"file":"init-DL8L1JpC.cjs","names":["defineCommand"],"sources":["../src/commands/init.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'init',\n description: 'Initialize a new Kubb project with interactive setup',\n options: {\n yes: { type: 'boolean', description: 'Skip prompts and use default options', short: 'y', default: false },\n },\n async run({ values }) {\n const { runInit } = await import('../runners/init.ts')\n\n await runInit({ yes: values.yes, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAUA,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,KAAK;EAAE,MAAM;EAAW,aAAa;EAAwC,OAAO;EAAK,SAAS;EAAO,EAC1G;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,YAAY,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,sBAAA,CAAA;AAE1B,QAAM,QAAQ;GAAE,KAAK,OAAO;GAAK,SAAA,gBAAA;GAAS,CAAC;;CAE9C,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-m-LvDtUC.cjs"); | ||
| //#region src/commands/mcp.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "mcp", | ||
| description: "Start the server to enable the MCP client to interact with the LLM.", | ||
| async run() { | ||
| const { runMcp } = await Promise.resolve().then(() => require("./mcp-X8kKSlov.cjs")); | ||
| await runMcp({ version: require_package.version }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=mcp-BQMtExMD.cjs.map |
| {"version":3,"file":"mcp-BQMtExMD.cjs","names":["defineCommand"],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'mcp',\n description: 'Start the server to enable the MCP client to interact with the LLM.',\n async run() {\n const { runMcp } = await import('../runners/mcp.ts')\n\n await runMcp({ version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAUA,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,MAAM,MAAM;EACV,MAAM,EAAE,WAAW,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,qBAAA,CAAA;AAEzB,QAAM,OAAO,EAAE,SAAA,gBAAA,SAAS,CAAC;;CAE5B,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-7k6Ul15n.js"; | ||
| //#region src/commands/mcp.ts | ||
| const command = defineCommand({ | ||
| name: "mcp", | ||
| description: "Start the server to enable the MCP client to interact with the LLM.", | ||
| async run() { | ||
| const { runMcp } = await import("./mcp-Cwbv3dfC.js"); | ||
| await runMcp({ version }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=mcp-DaibPZuu.js.map |
| {"version":3,"file":"mcp-DaibPZuu.js","names":[],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'mcp',\n description: 'Start the server to enable the MCP client to interact with the LLM.',\n async run() {\n const { runMcp } = await import('../runners/mcp.ts')\n\n await runMcp({ version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,MAAM,MAAM;EACV,MAAM,EAAE,WAAW,MAAM,OAAO;AAEhC,QAAM,OAAO,EAAE,SAAS,CAAC;;CAE5B,CAAC"} |
| //#region package.json | ||
| var version = "4.37.8"; | ||
| //#endregion | ||
| export { version as t }; | ||
| //# sourceMappingURL=package-7k6Ul15n.js.map |
| {"version":3,"file":"package-7k6Ul15n.js","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""} |
| //#region package.json | ||
| var version = "4.37.8"; | ||
| //#endregion | ||
| Object.defineProperty(exports, "version", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return version; | ||
| } | ||
| }); | ||
| //# sourceMappingURL=package-m-LvDtUC.cjs.map |
| {"version":3,"file":"package-m-LvDtUC.cjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-7k6Ul15n.js"; | ||
| //#region src/commands/validate.ts | ||
| const command = defineCommand({ | ||
| name: "validate", | ||
| description: "Validate a Swagger/OpenAPI file", | ||
| options: { input: { | ||
| type: "string", | ||
| description: "Path to Swagger/OpenAPI file", | ||
| short: "i", | ||
| required: true | ||
| } }, | ||
| async run({ values }) { | ||
| const { runValidate } = await import("./validate-BGyxLev8.js"); | ||
| await runValidate({ | ||
| input: values.input, | ||
| version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=validate-BOjhbG3R.js.map |
| {"version":3,"file":"validate-BOjhbG3R.js","names":[],"sources":["../src/commands/validate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'validate',\n description: 'Validate a Swagger/OpenAPI file',\n options: {\n input: { type: 'string', description: 'Path to Swagger/OpenAPI file', short: 'i', required: true },\n },\n async run({ values }) {\n const { runValidate } = await import('../runners/validate.ts')\n\n await runValidate({ input: values.input, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,OAAO;EAAE,MAAM;EAAU,aAAa;EAAgC,OAAO;EAAK,UAAU;EAAM,EACnG;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,gBAAgB,MAAM,OAAO;AAErC,QAAM,YAAY;GAAE,OAAO,OAAO;GAAO;GAAS,CAAC;;CAEtD,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-m-LvDtUC.cjs"); | ||
| //#region src/commands/validate.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "validate", | ||
| description: "Validate a Swagger/OpenAPI file", | ||
| options: { input: { | ||
| type: "string", | ||
| description: "Path to Swagger/OpenAPI file", | ||
| short: "i", | ||
| required: true | ||
| } }, | ||
| async run({ values }) { | ||
| const { runValidate } = await Promise.resolve().then(() => require("./validate-DYVo8-Fj.cjs")); | ||
| await runValidate({ | ||
| input: values.input, | ||
| version: require_package.version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=validate-CVlSxr9b.cjs.map |
| {"version":3,"file":"validate-CVlSxr9b.cjs","names":["defineCommand"],"sources":["../src/commands/validate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'validate',\n description: 'Validate a Swagger/OpenAPI file',\n options: {\n input: { type: 'string', description: 'Path to Swagger/OpenAPI file', short: 'i', required: true },\n },\n async run({ values }) {\n const { runValidate } = await import('../runners/validate.ts')\n\n await runValidate({ input: values.input, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAUA,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,OAAO;EAAE,MAAM;EAAU,aAAa;EAAgC,OAAO;EAAK,UAAU;EAAM,EACnG;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,gBAAgB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,0BAAA,CAAA;AAE9B,QAAM,YAAY;GAAE,OAAO,OAAO;GAAO,SAAA,gBAAA;GAAS,CAAC;;CAEtD,CAAC"} |
+6
-6
@@ -5,3 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const require_telemetry = require("./telemetry-CEm85k_X.cjs"); | ||
| const require_package = require("./package-CSJQyhYO.cjs"); | ||
| const require_package = require("./package-m-LvDtUC.cjs"); | ||
| let node_util = require("node:util"); | ||
@@ -235,7 +235,7 @@ //#region ../../internals/utils/src/cli/schema.ts | ||
| const [{ command: generateCommand }, { command: validateCommand }, { command: mcpCommand }, { command: agentCommand }, { command: initCommand }] = await Promise.all([ | ||
| Promise.resolve().then(() => require("./generate-DQ_S_FW_.cjs")), | ||
| Promise.resolve().then(() => require("./validate-BRzEtRj7.cjs")), | ||
| Promise.resolve().then(() => require("./mcp-uDMa0yKp.cjs")), | ||
| Promise.resolve().then(() => require("./agent-DyNZKnlF.cjs")), | ||
| Promise.resolve().then(() => require("./init-CibN8lng.cjs")) | ||
| Promise.resolve().then(() => require("./generate-CkyN7qeb.cjs")), | ||
| Promise.resolve().then(() => require("./validate-CVlSxr9b.cjs")), | ||
| Promise.resolve().then(() => require("./mcp-BQMtExMD.cjs")), | ||
| Promise.resolve().then(() => require("./agent-DMy_bQ-M.cjs")), | ||
| Promise.resolve().then(() => require("./init-DL8L1JpC.cjs")) | ||
| ]); | ||
@@ -242,0 +242,0 @@ await cli.run([ |
+6
-6
| import "./chunk--u3MIqq1.js"; | ||
| import { t as defineCLIAdapter } from "./define--M_JMcDC.js"; | ||
| import { n as isTelemetryDisabled } from "./telemetry-CHWsjyeK.js"; | ||
| import { t as version } from "./package-Zc7qipPx.js"; | ||
| import { t as version } from "./package-7k6Ul15n.js"; | ||
| import { parseArgs, styleText } from "node:util"; | ||
@@ -233,7 +233,7 @@ //#region ../../internals/utils/src/cli/schema.ts | ||
| const [{ command: generateCommand }, { command: validateCommand }, { command: mcpCommand }, { command: agentCommand }, { command: initCommand }] = await Promise.all([ | ||
| import("./generate-Qcw6Ilwk.js"), | ||
| import("./validate-IUvDwpX1.js"), | ||
| import("./mcp-DwRXOXZV.js"), | ||
| import("./agent-B4l6tvKC.js"), | ||
| import("./init-DqWUHya_.js") | ||
| import("./generate-DBo220P3.js"), | ||
| import("./validate-BOjhbG3R.js"), | ||
| import("./mcp-DaibPZuu.js"), | ||
| import("./agent-BBrW4jlM.js"), | ||
| import("./init-BkN1O1VV.js") | ||
| ]); | ||
@@ -240,0 +240,0 @@ await cli.run([ |
+5
-5
| { | ||
| "name": "@kubb/cli", | ||
| "version": "4.37.7", | ||
| "version": "4.37.8", | ||
| "description": "Command-line interface for Kubb, enabling easy generation of TypeScript, React-Query, Zod, and other code from OpenAPI specifications.", | ||
@@ -61,3 +61,3 @@ "keywords": [ | ||
| "tinyexec": "^1.0.4", | ||
| "@kubb/core": "4.37.7" | ||
| "@kubb/core": "4.37.8" | ||
| }, | ||
@@ -67,5 +67,5 @@ "devDependencies": { | ||
| "@internals/utils": "0.0.0", | ||
| "@kubb/agent": "4.37.7", | ||
| "@kubb/mcp": "4.37.7", | ||
| "@kubb/oas": "4.37.7" | ||
| "@kubb/agent": "4.37.8", | ||
| "@kubb/mcp": "4.37.8", | ||
| "@kubb/oas": "4.37.8" | ||
| }, | ||
@@ -72,0 +72,0 @@ "engines": { |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-Zc7qipPx.js"; | ||
| import { a as agentDefaults } from "./constants-CM3dJzjK.js"; | ||
| //#endregion | ||
| //#region src/commands/agent.ts | ||
| const command = defineCommand({ | ||
| name: "agent", | ||
| description: "Manage the Kubb Agent server", | ||
| subCommands: [defineCommand({ | ||
| name: "start", | ||
| description: "Start the Agent server", | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| port: { | ||
| type: "string", | ||
| description: `Port for the server (default: ${agentDefaults.port})`, | ||
| short: "p" | ||
| }, | ||
| host: { | ||
| type: "string", | ||
| description: "Host for the server", | ||
| default: agentDefaults.host | ||
| }, | ||
| "allow-write": { | ||
| type: "boolean", | ||
| description: "Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.", | ||
| default: false | ||
| }, | ||
| "allow-all": { | ||
| type: "boolean", | ||
| description: "Grant all permissions (implies --allow-write).", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values }) { | ||
| const { runAgentStart } = await import("./agent-fcClds-t.js"); | ||
| await runAgentStart({ | ||
| port: values.port !== void 0 ? values.port : void 0, | ||
| host: values.host, | ||
| configPath: values.config, | ||
| allowWrite: values["allow-write"], | ||
| allowAll: values["allow-all"], | ||
| version | ||
| }); | ||
| } | ||
| })] | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=agent-B4l6tvKC.js.map |
| {"version":3,"file":"agent-B4l6tvKC.js","names":["command","startCommand"],"sources":["../src/commands/agent/start.ts","../src/commands/agent.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../../package.json'\nimport { agentDefaults } from '../../constants.ts'\n\nexport const command = defineCommand({\n name: 'start',\n description: 'Start the Agent server',\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n port: { type: 'string', description: `Port for the server (default: ${agentDefaults.port})`, short: 'p' },\n host: { type: 'string', description: 'Host for the server', default: agentDefaults.host },\n 'allow-write': {\n type: 'boolean',\n description: 'Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.',\n default: false,\n },\n 'allow-all': { type: 'boolean', description: 'Grant all permissions (implies --allow-write).', default: false },\n },\n async run({ values }) {\n const { runAgentStart } = await import('../../runners/agent.ts')\n\n await runAgentStart({\n port: values.port !== undefined ? values.port : undefined,\n host: values.host,\n configPath: values.config,\n allowWrite: values['allow-write'],\n allowAll: values['allow-all'],\n version,\n })\n },\n})\n","import { defineCommand } from '@internals/utils'\nimport { command as startCommand } from './agent/start.ts'\n\nexport const command = defineCommand({\n name: 'agent',\n description: 'Manage the Kubb Agent server',\n subCommands: [startCommand],\n})\n"],"mappings":";;;;;;ACGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,aAAa,CDFQ,cAAc;EACnC,MAAM;EACN,aAAa;EACb,SAAS;GACP,QAAQ;IAAE,MAAM;IAAU,aAAa;IAA2B,OAAO;IAAK;GAC9E,MAAM;IAAE,MAAM;IAAU,aAAa,iCAAiC,cAAc,KAAK;IAAI,OAAO;IAAK;GACzG,MAAM;IAAE,MAAM;IAAU,aAAa;IAAuB,SAAS,cAAc;IAAM;GACzF,eAAe;IACb,MAAM;IACN,aAAa;IACb,SAAS;IACV;GACD,aAAa;IAAE,MAAM;IAAW,aAAa;IAAkD,SAAS;IAAO;GAChH;EACD,MAAM,IAAI,EAAE,UAAU;GACpB,MAAM,EAAE,kBAAkB,MAAM,OAAO;AAEvC,SAAM,cAAc;IAClB,MAAM,OAAO,SAAS,KAAA,IAAY,OAAO,OAAO,KAAA;IAChD,MAAM,OAAO;IACb,YAAY,OAAO;IACnB,YAAY,OAAO;IACnB,UAAU,OAAO;IACjB;IACD,CAAC;;EAEL,CAAC,CCxB2B;CAC5B,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-CSJQyhYO.cjs"); | ||
| const require_constants = require("./constants-BTUap0zs.cjs"); | ||
| //#region src/commands/agent/start.ts | ||
| const command$1 = require_define.defineCommand({ | ||
| name: "start", | ||
| description: "Start the Agent server", | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| port: { | ||
| type: "string", | ||
| description: `Port for the server (default: ${require_constants.agentDefaults.port})`, | ||
| short: "p" | ||
| }, | ||
| host: { | ||
| type: "string", | ||
| description: "Host for the server", | ||
| default: require_constants.agentDefaults.host | ||
| }, | ||
| "allow-write": { | ||
| type: "boolean", | ||
| description: "Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.", | ||
| default: false | ||
| }, | ||
| "allow-all": { | ||
| type: "boolean", | ||
| description: "Grant all permissions (implies --allow-write).", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values }) { | ||
| const { runAgentStart } = await Promise.resolve().then(() => require("./agent-bJ5FNFnA.cjs")); | ||
| await runAgentStart({ | ||
| port: values.port !== void 0 ? values.port : void 0, | ||
| host: values.host, | ||
| configPath: values.config, | ||
| allowWrite: values["allow-write"], | ||
| allowAll: values["allow-all"], | ||
| version: require_package.version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/commands/agent.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "agent", | ||
| description: "Manage the Kubb Agent server", | ||
| subCommands: [command$1] | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=agent-DyNZKnlF.cjs.map |
| {"version":3,"file":"agent-DyNZKnlF.cjs","names":["command","defineCommand","agentDefaults","defineCommand","startCommand"],"sources":["../src/commands/agent/start.ts","../src/commands/agent.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../../package.json'\nimport { agentDefaults } from '../../constants.ts'\n\nexport const command = defineCommand({\n name: 'start',\n description: 'Start the Agent server',\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n port: { type: 'string', description: `Port for the server (default: ${agentDefaults.port})`, short: 'p' },\n host: { type: 'string', description: 'Host for the server', default: agentDefaults.host },\n 'allow-write': {\n type: 'boolean',\n description: 'Allow writing generated files to the filesystem. When not set, no files are written and the config patch is not persisted.',\n default: false,\n },\n 'allow-all': { type: 'boolean', description: 'Grant all permissions (implies --allow-write).', default: false },\n },\n async run({ values }) {\n const { runAgentStart } = await import('../../runners/agent.ts')\n\n await runAgentStart({\n port: values.port !== undefined ? values.port : undefined,\n host: values.host,\n configPath: values.config,\n allowWrite: values['allow-write'],\n allowAll: values['allow-all'],\n version,\n })\n },\n})\n","import { defineCommand } from '@internals/utils'\nimport { command as startCommand } from './agent/start.ts'\n\nexport const command = defineCommand({\n name: 'agent',\n description: 'Manage the Kubb Agent server',\n subCommands: [startCommand],\n})\n"],"mappings":";;;;;AAIA,MAAaA,YAAUC,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS;EACP,QAAQ;GAAE,MAAM;GAAU,aAAa;GAA2B,OAAO;GAAK;EAC9E,MAAM;GAAE,MAAM;GAAU,aAAa,iCAAiCC,kBAAAA,cAAc,KAAK;GAAI,OAAO;GAAK;EACzG,MAAM;GAAE,MAAM;GAAU,aAAa;GAAuB,SAASA,kBAAAA,cAAc;GAAM;EACzF,eAAe;GACb,MAAM;GACN,aAAa;GACb,SAAS;GACV;EACD,aAAa;GAAE,MAAM;GAAW,aAAa;GAAkD,SAAS;GAAO;EAChH;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,kBAAkB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,uBAAA,CAAA;AAEhC,QAAM,cAAc;GAClB,MAAM,OAAO,SAAS,KAAA,IAAY,OAAO,OAAO,KAAA;GAChD,MAAM,OAAO;GACb,YAAY,OAAO;GACnB,YAAY,OAAO;GACnB,UAAU,OAAO;GACjB,SAAA,gBAAA;GACD,CAAC;;CAEL,CAAC;;;AC3BF,MAAa,UAAUC,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,aAAa,CAACC,UAAa;CAC5B,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as toCause, r as toError } from "./errors-6mF_WKxg.js"; | ||
| import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-CHWsjyeK.js"; | ||
| import { n as tokenize } from "./shell-DqqWsHCD.js"; | ||
| import { t as version } from "./package-Zc7qipPx.js"; | ||
| import { i as WATCHER_IGNORED_PATHS, r as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-CM3dJzjK.js"; | ||
| import { styleText } from "node:util"; | ||
| import { EventEmitter } from "node:events"; | ||
| import { createHash } from "node:crypto"; | ||
| import "node:fs"; | ||
| import { mkdir, readFile, writeFile } from "node:fs/promises"; | ||
| import path, { dirname, relative, resolve } from "node:path"; | ||
| import process$1 from "node:process"; | ||
| import * as clack from "@clack/prompts"; | ||
| import { PromiseManager, defineLogger, detectFormatter, detectLinter, formatters, getConfigs, isInputPath, linters, logLevel, safeBuild, setup } from "@kubb/core"; | ||
| import { NonZeroExitError, x } from "tinyexec"; | ||
| import { Writable } from "node:stream"; | ||
| import { cosmiconfig } from "cosmiconfig"; | ||
| import { createJiti } from "jiti"; | ||
| //#region ../../internals/utils/src/asyncEventEmitter.ts | ||
| /** | ||
| * A typed EventEmitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript event-map inference. | ||
| */ | ||
| var AsyncEventEmitter = class { | ||
| /** | ||
| * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new EventEmitter(); | ||
| /** | ||
| * Emits an event and awaits all registered listeners in parallel. | ||
| * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments. | ||
| */ | ||
| async emit(eventName, ...eventArgs) { | ||
| const listeners = this.#emitter.listeners(eventName); | ||
| if (listeners.length === 0) return; | ||
| await Promise.all(listeners.map(async (listener) => { | ||
| try { | ||
| return await listener(...eventArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(eventArgs); | ||
| } catch { | ||
| serializedArgs = String(eventArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) }); | ||
| } | ||
| })); | ||
| } | ||
| /** Registers a persistent listener for the given event. */ | ||
| on(eventName, handler) { | ||
| this.#emitter.on(eventName, handler); | ||
| } | ||
| /** Registers a one-shot listener that removes itself after the first invocation. */ | ||
| onOnce(eventName, handler) { | ||
| const wrapper = (...args) => { | ||
| this.off(eventName, wrapper); | ||
| return handler(...args); | ||
| }; | ||
| this.on(eventName, wrapper); | ||
| } | ||
| /** Removes a previously registered listener. */ | ||
| off(eventName, handler) { | ||
| this.#emitter.off(eventName, handler); | ||
| } | ||
| /** Removes all listeners from every event channel. */ | ||
| removeAll() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region ../../internals/utils/src/time.ts | ||
| /** | ||
| * Calculates elapsed time in milliseconds from a high-resolution start time. | ||
| * Rounds to 2 decimal places to provide sub-millisecond precision without noise. | ||
| */ | ||
| function getElapsedMs(hrStart) { | ||
| const [seconds, nanoseconds] = process.hrtime(hrStart); | ||
| const ms = seconds * 1e3 + nanoseconds / 1e6; | ||
| return Math.round(ms * 100) / 100; | ||
| } | ||
| /** | ||
| * Converts a millisecond duration into a human-readable string. | ||
| * Adjusts units (ms, s, m s) based on the magnitude of the duration. | ||
| */ | ||
| function formatMs(ms) { | ||
| if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`; | ||
| if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`; | ||
| return `${Math.round(ms)}ms`; | ||
| } | ||
| /** | ||
| * Convenience helper: formats the elapsed time since `hrStart` in one step. | ||
| */ | ||
| function formatHrtime(hrStart) { | ||
| return formatMs(getElapsedMs(hrStart)); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/colors.ts | ||
| /** | ||
| * Parses a CSS hex color string (`#RGB`) into its RGB channels. | ||
| * Falls back to `255` for any channel that cannot be parsed. | ||
| */ | ||
| function parseHex(color) { | ||
| const int = Number.parseInt(color.replace("#", ""), 16); | ||
| return Number.isNaN(int) ? { | ||
| r: 255, | ||
| g: 255, | ||
| b: 255 | ||
| } : { | ||
| r: int >> 16 & 255, | ||
| g: int >> 8 & 255, | ||
| b: int & 255 | ||
| }; | ||
| } | ||
| /** | ||
| * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence | ||
| * for the given hex color. | ||
| */ | ||
| function hex(color) { | ||
| const { r, g, b } = parseHex(color); | ||
| return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`; | ||
| } | ||
| function gradient(colorStops, text) { | ||
| const chars = text.split(""); | ||
| return chars.map((char, i) => { | ||
| const t = chars.length <= 1 ? 0 : i / (chars.length - 1); | ||
| const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2); | ||
| const lt = t * (colorStops.length - 1) - seg; | ||
| const from = parseHex(colorStops[seg]); | ||
| const to = parseHex(colorStops[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(""); | ||
| } | ||
| /** ANSI color functions for each part of the Kubb mascot illustration. */ | ||
| const palette = { | ||
| 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 welcome banner. | ||
| */ | ||
| function getIntro({ title, description, version, areEyesOpen }) { | ||
| const kubbVersion = gradient([ | ||
| "#F58517", | ||
| "#F5A217", | ||
| "#F55A17" | ||
| ], `KUBB v${version}`); | ||
| const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───"); | ||
| const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───"); | ||
| return ` | ||
| ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")} | ||
| ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion} | ||
| ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${styleText("gray", title)} | ||
| ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${styleText("yellow", "➜")} ${styleText("white", description)} | ||
| ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")} | ||
| `; | ||
| } | ||
| /** ANSI color names available for terminal output. */ | ||
| const randomColors = [ | ||
| "black", | ||
| "red", | ||
| "green", | ||
| "yellow", | ||
| "blue", | ||
| "white", | ||
| "magenta", | ||
| "cyan", | ||
| "gray" | ||
| ]; | ||
| /** | ||
| * Returns the text wrapped in a deterministic ANSI color derived from the text's SHA-256 hash. | ||
| */ | ||
| function randomCliColor(text) { | ||
| if (!text) return ""; | ||
| return styleText(randomColors[createHash("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text); | ||
| } | ||
| /** | ||
| * Formats a millisecond duration with an ANSI color based on thresholds: | ||
| * green ≤ 500 ms · yellow ≤ 1 000 ms · red > 1 000 ms | ||
| */ | ||
| function formatMsWithColor(ms) { | ||
| const formatted = formatMs(ms); | ||
| if (ms <= 500) return styleText("green", formatted); | ||
| if (ms <= 1e3) return styleText("yellow", formatted); | ||
| return styleText("red", formatted); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write and returns `undefined` when the trimmed content is empty or | ||
| * identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the | ||
| * content does not match. | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return void 0; | ||
| const resolved = resolve(path); | ||
| if (typeof Bun !== "undefined") { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return void 0; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return void 0; | ||
| } catch {} | ||
| await mkdir(dirname(resolved), { recursive: true }); | ||
| await writeFile(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await readFile(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getSummary.ts | ||
| function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) { | ||
| const duration = formatHrtime(hrStart); | ||
| const pluginsCount = config.plugins?.length ?? 0; | ||
| const successCount = pluginsCount - failedPlugins.size; | ||
| const meta = { | ||
| plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`, | ||
| pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0, | ||
| filesCreated, | ||
| time: styleText("green", duration), | ||
| output: path.isAbsolute(config.root) ? path.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 sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]); | ||
| 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 / 100), 10); | ||
| const bar = styleText("dim", "█".repeat(barLength)); | ||
| summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`); | ||
| }); | ||
| } | ||
| summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`); | ||
| return summaryLines; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/runHook.ts | ||
| /** | ||
| * Execute a hook command, emit debug/hook:end events, and forward output to | ||
| * an optional HookOutputSink. All three logger adapters share this function | ||
| * so the process-spawning logic lives in exactly one place. | ||
| */ | ||
| async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) { | ||
| try { | ||
| const proc = x(command, [...args ?? []], { | ||
| nodeOptions: { detached: true }, | ||
| throwOnError: true | ||
| }); | ||
| if (stream && sink?.onLine) for await (const line of proc) sink.onLine(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) { | ||
| if (!(err instanceof NonZeroExitError)) { | ||
| await context.emit("hook:end", { | ||
| command, | ||
| args, | ||
| id, | ||
| success: false, | ||
| error: toError(err) | ||
| }); | ||
| await context.emit("error", toError(err)); | ||
| return; | ||
| } | ||
| const stderr = err.output?.stderr ?? ""; | ||
| const stdout = err.output?.stdout ?? ""; | ||
| await context.emit("debug", { | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [stdout, stderr].filter(Boolean) | ||
| }); | ||
| if (stderr) sink?.onStderr?.(stderr); | ||
| if (stdout) sink?.onStdout?.(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); | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/utils/Writables.ts | ||
| var ClackWritable = class extends Writable { | ||
| taskLog; | ||
| constructor(taskLog, opts) { | ||
| super(opts); | ||
| this.taskLog = taskLog; | ||
| } | ||
| _write(chunk, _encoding, callback) { | ||
| this.taskLog.message(`${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 = defineLogger({ | ||
| name: "clack", | ||
| install(context, options) { | ||
| const logLevel$8 = options?.logLevel ?? logLevel.info; | ||
| const state = { | ||
| totalPlugins: 0, | ||
| completedPlugins: 0, | ||
| failedPlugins: 0, | ||
| totalFiles: 0, | ||
| processedFiles: 0, | ||
| hrStart: process$1.hrtime(), | ||
| spinner: clack.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 = process$1.hrtime(); | ||
| state.spinner = clack.spinner(); | ||
| state.isSpinning = false; | ||
| state.activeProgress.clear(); | ||
| } | ||
| function showProgressStep() { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const line = buildProgressLine(state); | ||
| if (line) clack.log.step(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel$8); | ||
| } | ||
| 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$8 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "ℹ"), | ||
| message, | ||
| styleText("dim", info) | ||
| ].join(" ")); | ||
| if (state.isSpinning) state.spinner.message(text); | ||
| else clack.log.info(text); | ||
| }); | ||
| context.on("success", (message, info = "") => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "✓"), | ||
| message, | ||
| logLevel$8 >= logLevel.info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| if (state.isSpinning) stopSpinner(text); | ||
| else clack.log.success(text); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| if (logLevel$8 < logLevel.warn) return; | ||
| const text = getMessage([ | ||
| styleText("yellow", "⚠"), | ||
| message, | ||
| logLevel$8 >= logLevel.info && info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| clack.log.warn(text); | ||
| }); | ||
| context.on("error", (error) => { | ||
| const caused = toCause(error); | ||
| const text = [styleText("red", "✗"), error.message].join(" "); | ||
| if (state.isSpinning) stopSpinner(getMessage(text)); | ||
| else clack.log.error(getMessage(text)); | ||
| if (logLevel$8 >= logLevel.debug && error.stack) { | ||
| const frames = error.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) clack.log.message(getMessage(styleText("dim", frame.trim()))); | ||
| if (caused?.stack) { | ||
| clack.log.message(styleText("dim", `└─ caused by ${caused.message}`)); | ||
| const frames = caused.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) clack.log.message(getMessage(` ${styleText("dim", frame.trim())}`)); | ||
| } | ||
| } | ||
| }); | ||
| context.on("version:new", (version, latestVersion) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| try { | ||
| clack.box(`\`v${version}\` → \`v${latestVersion}\` | ||
| Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", { | ||
| width: "auto", | ||
| formatBorder: (s) => styleText("yellow", s), | ||
| rounded: true, | ||
| withGuide: false, | ||
| contentAlign: "center", | ||
| titleAlign: "center" | ||
| }); | ||
| } catch { | ||
| console.log(`Update available for Kubb: v${version} → v${latestVersion}`); | ||
| console.log("Run `npm install -g @kubb/cli` to update"); | ||
| } | ||
| }); | ||
| 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$8 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration started"); | ||
| clack.intro(text); | ||
| startSpinner(getMessage("Configuration loading")); | ||
| }); | ||
| context.on("config:end", (_configs) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("generation:start", (config) => { | ||
| reset(); | ||
| state.totalPlugins = config.plugins?.length ?? 0; | ||
| const text = getMessage(["Generation started", config.name ? `for ${styleText("dim", config.name)}` : void 0].filter(Boolean).join(" ")); | ||
| clack.intro(text); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| stopSpinner(); | ||
| const progressBar = clack.progress({ | ||
| style: "block", | ||
| max: 100, | ||
| size: 30 | ||
| }); | ||
| const text = getMessage(`Generating ${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$8 === logLevel.silent) return; | ||
| clearInterval(active.interval); | ||
| if (success) state.completedPlugins++; | ||
| else state.failedPlugins++; | ||
| const durationStr = formatMsWithColor(duration); | ||
| const text = getMessage(success ? `${styleText("bold", plugin.name)} completed in ${durationStr}` : `${styleText("bold", plugin.name)} failed in ${styleText("red", formatMs(duration))}`); | ||
| active.progressBar.stop(text); | ||
| state.activeProgress.delete(plugin.name); | ||
| showProgressStep(); | ||
| }); | ||
| context.on("files:processing:start", (files) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| stopSpinner(); | ||
| state.totalFiles = files.length; | ||
| state.processedFiles = 0; | ||
| const text = `Writing ${files.length} files`; | ||
| const progressBar = clack.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$8 <= logLevel.silent) return; | ||
| stopSpinner(); | ||
| state.processedFiles++; | ||
| const text = `Writing ${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$8 <= 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 ${styleText("dim", config.name)}` : "Generation completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("format:start", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Format started"); | ||
| clack.intro(text); | ||
| }); | ||
| context.on("format:end", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Format completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("lint:start", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Lint started"); | ||
| clack.intro(text); | ||
| }); | ||
| context.on("lint:end", () => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage("Lint completed"); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("hook:start", async ({ id, command, args }) => { | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`); | ||
| if (!id) return; | ||
| if (logLevel$8 <= logLevel.silent) { | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStderr: (s) => console.error(s), | ||
| onStdout: (s) => console.log(s) | ||
| } | ||
| }); | ||
| return; | ||
| } | ||
| clack.intro(text); | ||
| const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) }); | ||
| const writable = new ClackWritable(logger); | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| stream: true, | ||
| sink: { | ||
| onLine: (line) => writable.write(line), | ||
| onStderr: (s) => logger.error(s), | ||
| onStdout: (s) => logger.message(s) | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel$8 <= logLevel.silent) return; | ||
| const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} successfully executed`); | ||
| clack.outro(text); | ||
| }); | ||
| context.on("generation:summary", (config, { pluginTimings, failedPlugins, filesCreated, status, hrStart }) => { | ||
| const summary = getSummary({ | ||
| failedPlugins, | ||
| filesCreated, | ||
| config, | ||
| status, | ||
| hrStart, | ||
| pluginTimings: logLevel$8 >= logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| const title = config.name || ""; | ||
| summary.unshift("\n"); | ||
| summary.push("\n"); | ||
| const borderColor = status === "success" ? "green" : "red"; | ||
| try { | ||
| clack.box(summary.join("\n"), getMessage(title), { | ||
| width: "auto", | ||
| formatBorder: (s) => styleText(borderColor, s), | ||
| rounded: true, | ||
| withGuide: false, | ||
| contentAlign: "left", | ||
| titleAlign: "center" | ||
| }); | ||
| } catch { | ||
| console.log(summary.join("\n")); | ||
| } | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#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 = 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 = resolve(process$1.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(([fileName, logs]) => 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}`] | ||
| }); | ||
| }); | ||
| context.on("success", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✓ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`⚠ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("error", (error) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✗ ${error.message}`, error.stack || "unknown stack"] | ||
| }); | ||
| }); | ||
| context.on("debug", (message) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: message.logs | ||
| }); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Generating ${plugin.name}`] | ||
| }); | ||
| }); | ||
| context.on("plugin:end", (plugin, { duration, success }) => { | ||
| const durationStr = formatMs(duration); | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`] | ||
| }); | ||
| }); | ||
| context.on("files:processing:start", (files) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)] | ||
| }); | ||
| }); | ||
| context.on("generation:end", async (config) => { | ||
| const writtenFilePaths = await writeLogs(config.name); | ||
| if (writtenFilePaths.length > 0) { | ||
| const files = writtenFilePaths.map((f) => relative(process$1.cwd(), f)); | ||
| await context.emit("info", "Debug files written to:", files.join(", ")); | ||
| } | ||
| reset(); | ||
| }); | ||
| const exitHandler = () => { | ||
| if (state.cachedLogs.size > 0) writeLogs().catch(() => {}); | ||
| }; | ||
| process$1.once("exit", exitHandler); | ||
| process$1.once("SIGINT", exitHandler); | ||
| process$1.once("SIGTERM", exitHandler); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/githubActionsLogger.ts | ||
| /** | ||
| * GitHub Actions adapter for CI environments | ||
| * Uses Github group annotations for collapsible sections | ||
| */ | ||
| const githubActionsLogger = defineLogger({ | ||
| name: "github-actions", | ||
| install(context, options) { | ||
| const logLevel$7 = options?.logLevel ?? 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(); | ||
| state.currentConfigs = []; | ||
| } | ||
| function showProgressStep() { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const line = buildProgressLine(state); | ||
| if (line) console.log(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel$7); | ||
| } | ||
| function openGroup(name) { | ||
| console.log(`::group::${name}`); | ||
| } | ||
| function closeGroup(_name) { | ||
| console.log("::endgroup::"); | ||
| } | ||
| context.on("info", (message, info = "") => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "ℹ"), | ||
| message, | ||
| styleText("dim", info) | ||
| ].join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("success", (message, info = "") => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("blue", "✓"), | ||
| message, | ||
| logLevel$7 >= logLevel.info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("warn", (message, info = "") => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| styleText("yellow", "⚠"), | ||
| message, | ||
| logLevel$7 >= logLevel.info ? styleText("dim", info) : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.warn(`::warning::${text}`); | ||
| }); | ||
| context.on("error", (error) => { | ||
| const caused = toCause(error); | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const message = error.message || String(error); | ||
| console.error(`::error::${message}`); | ||
| if (logLevel$7 >= logLevel.debug && error.stack) { | ||
| const frames = error.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) console.log(getMessage(styleText("dim", frame.trim()))); | ||
| if (caused?.stack) { | ||
| console.log(styleText("dim", `└─ caused by ${caused.message}`)); | ||
| const frames = caused.stack.split("\n").slice(1, 4); | ||
| for (const frame of frames) console.log(getMessage(` ${styleText("dim", frame.trim())}`)); | ||
| } | ||
| } | ||
| }); | ||
| context.on("lifecycle:start", (version) => { | ||
| console.log(styleText("yellow", `Kubb ${version} 🧩`)); | ||
| reset(); | ||
| }); | ||
| context.on("config:start", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration started"); | ||
| openGroup("Configuration"); | ||
| console.log(text); | ||
| }); | ||
| context.on("config:end", (configs) => { | ||
| state.currentConfigs = configs; | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration completed"); | ||
| console.log(text); | ||
| closeGroup("Configuration"); | ||
| }); | ||
| context.on("generation:start", (config) => { | ||
| reset(); | ||
| state.totalPlugins = config.plugins?.length ?? 0; | ||
| const text = config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation"; | ||
| if (state.currentConfigs.length > 1) openGroup(text); | ||
| if (state.currentConfigs.length === 1) console.log(getMessage(text)); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage(`Generating ${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$7 <= logLevel.silent) return; | ||
| if (success) state.completedPlugins++; | ||
| else state.failedPlugins++; | ||
| const durationStr = formatMsWithColor(duration); | ||
| const text = getMessage(success ? `${styleText("bold", plugin.name)} completed in ${durationStr}` : `${styleText("bold", plugin.name)} failed in ${styleText("red", 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$7 <= 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$7 <= logLevel.silent) return; | ||
| const text = getMessage("Files written successfully"); | ||
| console.log(text); | ||
| if (state.currentConfigs.length === 1) closeGroup("File Generation"); | ||
| showProgressStep(); | ||
| }); | ||
| context.on("file:processing:update", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| state.processedFiles++; | ||
| }); | ||
| context.on("generation:end", (config) => { | ||
| const text = getMessage(config.name ? `${styleText("blue", "✓")} Generation completed for ${styleText("dim", config.name)}` : `${styleText("blue", "✓")} Generation completed`); | ||
| console.log(text); | ||
| }); | ||
| context.on("format:start", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Format started"); | ||
| if (state.currentConfigs.length === 1) openGroup("Formatting"); | ||
| console.log(text); | ||
| }); | ||
| context.on("format:end", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Format completed"); | ||
| console.log(text); | ||
| if (state.currentConfigs.length === 1) closeGroup("Formatting"); | ||
| }); | ||
| context.on("lint:start", () => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const text = getMessage("Lint started"); | ||
| if (state.currentConfigs.length === 1) openGroup("Linting"); | ||
| console.log(text); | ||
| }); | ||
| context.on("lint:end", () => { | ||
| if (logLevel$7 <= 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 = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`); | ||
| if (logLevel$7 > logLevel.silent) { | ||
| if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`); | ||
| console.log(text); | ||
| } | ||
| if (!id) return; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel$7 <= logLevel.silent) return; | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${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 = formatHrtime(hrStart); | ||
| if (state.currentConfigs.length > 1) console.log(" "); | ||
| console.log(status === "success" ? `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ${pluginsCount} total, ${styleText("green", duration)}` : `Kubb Summary: ${styleText("blue", "✓")} ${`${successCount} successful`}, ✗ ${`${failedPlugins.size} failed`}, ${pluginsCount} total, ${styleText("green", duration)}`); | ||
| if (state.currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation"); | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/plainLogger.ts | ||
| /** | ||
| * Plain console adapter for non-TTY environments | ||
| * Simple console.log output with indentation | ||
| */ | ||
| const plainLogger = defineLogger({ | ||
| name: "plain", | ||
| install(context, options) { | ||
| const logLevel$6 = options?.logLevel ?? logLevel.info; | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel$6); | ||
| } | ||
| context.on("info", (message, info) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| "ℹ", | ||
| message, | ||
| info | ||
| ].join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("success", (message, info = "") => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage([ | ||
| "✓", | ||
| message, | ||
| logLevel$6 >= logLevel.info ? info : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| if (logLevel$6 < logLevel.warn) return; | ||
| const text = getMessage([ | ||
| "⚠", | ||
| message, | ||
| logLevel$6 >= logLevel.info ? info : void 0 | ||
| ].filter(Boolean).join(" ")); | ||
| console.log(text); | ||
| }); | ||
| context.on("error", (error) => { | ||
| const caused = toCause(error); | ||
| const text = getMessage(["✗", error.message].join(" ")); | ||
| console.log(text); | ||
| if (logLevel$6 >= 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$6 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("config:end", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Configuration completed"); | ||
| console.log(text); | ||
| }); | ||
| context.on("generation:start", () => { | ||
| const text = getMessage("Generation started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Generating ${plugin.name}`); | ||
| console.log(text); | ||
| }); | ||
| context.on("plugin:end", (plugin, { duration, success }) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const durationStr = 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$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Writing ${files.length} files`); | ||
| console.log(text); | ||
| }); | ||
| context.on("file:processing:update", ({ file, config }) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Writing ${relative(config.root, file.path)}`); | ||
| console.log(text); | ||
| }); | ||
| context.on("files:processing:end", () => { | ||
| if (logLevel$6 <= 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$6 <= logLevel.silent) return; | ||
| const text = getMessage("Format started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("format:end", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Format completed"); | ||
| console.log(text); | ||
| }); | ||
| context.on("lint:start", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Lint started"); | ||
| console.log(text); | ||
| }); | ||
| context.on("lint:end", () => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage("Lint completed"); | ||
| console.log(text); | ||
| }); | ||
| context.on("hook:start", async ({ id, command, args }) => { | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${commandWithArgs} started`); | ||
| if (logLevel$6 > logLevel.silent) console.log(text); | ||
| if (!id) return; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel$6 <= logLevel.silent) return; | ||
| const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} completed`); | ||
| console.log(text); | ||
| }); | ||
| context.on("generation:summary", (config, { pluginTimings, status, hrStart, failedPlugins, filesCreated }) => { | ||
| const summary = getSummary({ | ||
| failedPlugins, | ||
| filesCreated, | ||
| config, | ||
| status, | ||
| hrStart, | ||
| pluginTimings: logLevel$6 >= logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| console.log(SUMMARY_SEPARATOR); | ||
| console.log(summary.join("\n")); | ||
| console.log(SUMMARY_SEPARATOR); | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/utils.ts | ||
| /** | ||
| * Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose. | ||
| * Shared across all logger adapters to avoid duplication. | ||
| */ | ||
| function formatMessage(message, logLevel$4) { | ||
| if (logLevel$4 >= logLevel.verbose) return `${styleText("dim", `[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { | ||
| hour12: false, | ||
| hour: "2-digit", | ||
| minute: "2-digit", | ||
| second: "2-digit" | ||
| })}]`)} ${message}`; | ||
| return message; | ||
| } | ||
| /** | ||
| * Build the progress summary line shared by clack and GitHub Actions loggers. | ||
| * Returns null when there is nothing to display. | ||
| */ | ||
| function buildProgressLine(state) { | ||
| const parts = []; | ||
| const duration = formatHrtime(state.hrStart); | ||
| if (state.totalPlugins > 0) { | ||
| const pluginStr = state.failedPlugins > 0 ? `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins} ${styleText("red", `(${state.failedPlugins} failed)`)}` : `Plugins ${styleText("green", state.completedPlugins.toString())}/${state.totalPlugins}`; | ||
| parts.push(pluginStr); | ||
| } | ||
| if (state.totalFiles > 0) parts.push(`Files ${styleText("green", state.processedFiles.toString())}/${state.totalFiles}`); | ||
| if (parts.length === 0) return null; | ||
| parts.push(`${styleText("green", duration)} elapsed`); | ||
| return parts.join(styleText("dim", " | ")); | ||
| } | ||
| /** | ||
| * Join a command and its optional args into a single display string. | ||
| * e.g. ("prettier", ["--write", "."]) → "prettier --write ." | ||
| */ | ||
| function formatCommandWithArgs(command, args) { | ||
| return args?.length ? `${command} ${args.join(" ")}` : command; | ||
| } | ||
| 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: logLevel$5 }) { | ||
| const type = detectLogger(); | ||
| const logger = logMapper[type]; | ||
| if (!logger) throw new Error(`Unknown adapter type: ${type}`); | ||
| const cleanup = await logger.install(context, { logLevel: logLevel$5 }); | ||
| if (logLevel$5 >= logLevel.debug) await fileSystemLogger.install(context, { logLevel: logLevel$5 }); | ||
| 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] = tokenize(command); | ||
| if (!cmd) continue; | ||
| const hookId = createHash("sha256").update(command).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`)); | ||
| return; | ||
| } | ||
| events.emit("success", `${styleText("dim", command)} successfully executed`).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: cmd, | ||
| args | ||
| }); | ||
| await hookEndPromise; | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getCosmiConfig.ts | ||
| const jiti = createJiti(import.meta.url, { | ||
| jsx: { | ||
| runtime: "automatic", | ||
| importSource: "@kubb/react-fabric" | ||
| }, | ||
| sourceMaps: true, | ||
| interopDefault: true | ||
| }); | ||
| const tsLoader = async (configFile) => { | ||
| return await jiti.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.mts`, | ||
| `.${moduleName}rc.cts`, | ||
| `.${moduleName}rc.js`, | ||
| `.${moduleName}rc.mjs`, | ||
| `.${moduleName}rc.cjs`, | ||
| `${moduleName}.config.ts`, | ||
| `${moduleName}.config.mts`, | ||
| `${moduleName}.config.cts`, | ||
| `${moduleName}.config.js`, | ||
| `${moduleName}.config.mjs`, | ||
| `${moduleName}.config.cjs` | ||
| ]; | ||
| const explorer = cosmiconfig(moduleName, { | ||
| cache: false, | ||
| searchPlaces: [ | ||
| ...searchPlaces.map((searchPlace) => { | ||
| return `.config/${searchPlace}`; | ||
| }), | ||
| ...searchPlaces.map((searchPlace) => { | ||
| return `configs/${searchPlace}`; | ||
| }), | ||
| ...searchPlaces | ||
| ], | ||
| loaders: { | ||
| ".ts": tsLoader, | ||
| ".mts": tsLoader, | ||
| ".cts": 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 function startWatcher(path, cb) { | ||
| const { watch } = await import("chokidar"); | ||
| watch(path, { | ||
| ignorePermissionErrors: true, | ||
| ignored: WATCHER_IGNORED_PATHS | ||
| }).on("all", async (type, file) => { | ||
| console.log(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`))); | ||
| try { | ||
| await cb(path); | ||
| } catch (_e) { | ||
| console.log(styleText("red", "Watcher failed")); | ||
| } | ||
| }); | ||
| } | ||
| //#endregion | ||
| //#region src/runners/generate.ts | ||
| async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, events, onStart, onEnd }) { | ||
| await onStart(); | ||
| let resolvedTool = toolValue; | ||
| if (resolvedTool === "auto") { | ||
| const detected = await detect(); | ||
| if (!detected) await events.emit("warn", noToolMessage); | ||
| else { | ||
| resolvedTool = detected; | ||
| await events.emit("info", `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}`); | ||
| } | ||
| } | ||
| if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) { | ||
| const toolConfig = toolMap[resolvedTool]; | ||
| try { | ||
| const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`)); | ||
| return; | ||
| } | ||
| events.emit("success", [ | ||
| `${successPrefix} with ${styleText("dim", resolvedTool)}`, | ||
| logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0, | ||
| "successfully" | ||
| ].filter(Boolean).join(" ")).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: toolConfig.command, | ||
| args: toolConfig.args(outputPath) | ||
| }); | ||
| await hookEndPromise; | ||
| } catch (caughtError) { | ||
| const err = new Error(toolConfig.errorMessage); | ||
| err.cause = caughtError; | ||
| await events.emit("error", err); | ||
| } | ||
| } | ||
| await onEnd(); | ||
| } | ||
| async function generate({ input, config: userConfig, events, logLevel: logLevel$2 }) { | ||
| const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0); | ||
| const hrStart = process$1.hrtime(); | ||
| const config = { | ||
| ...userConfig, | ||
| root: userConfig.root || process$1.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 ${styleText("bold", config.name)}` : "Setup generation", inputPath); | ||
| const { sources, fabric, pluginManager } = await setup({ | ||
| config, | ||
| events | ||
| }); | ||
| await events.emit("info", config.name ? `Build generation ${styleText("bold", config.name)}` : "Build generation", inputPath); | ||
| const { files, failedPlugins, pluginTimings, error } = await safeBuild({ | ||
| config, | ||
| events | ||
| }, { | ||
| pluginManager, | ||
| fabric, | ||
| events, | ||
| sources | ||
| }); | ||
| await events.emit("info", "Load summary"); | ||
| if (failedPlugins.size > 0 || error) { | ||
| const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean); | ||
| for (const err of allErrors) await events.emit("error", err); | ||
| await events.emit("generation:end", config, files, sources); | ||
| await events.emit("generation:summary", config, { | ||
| failedPlugins, | ||
| filesCreated: files.length, | ||
| status: "failed", | ||
| hrStart, | ||
| pluginTimings: logLevel$2 >= logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| await sendTelemetry(buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "failed" | ||
| })); | ||
| process$1.exit(1); | ||
| } | ||
| await events.emit("success", "Generation successfully", inputPath); | ||
| await events.emit("generation:end", config, files, sources); | ||
| const outputPath = path.resolve(config.root, config.output.path); | ||
| if (config.output.format) await runToolPass({ | ||
| toolValue: config.output.format, | ||
| detect: detectFormatter, | ||
| toolMap: formatters, | ||
| toolLabel: "formatter", | ||
| successPrefix: "Formatting", | ||
| noToolMessage: "No formatter found (biome, prettier, or oxfmt). Skipping formatting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel: logLevel$2, | ||
| events, | ||
| onStart: () => events.emit("format:start"), | ||
| onEnd: () => events.emit("format:end") | ||
| }); | ||
| if (config.output.lint) await runToolPass({ | ||
| toolValue: config.output.lint, | ||
| detect: detectLinter, | ||
| toolMap: linters, | ||
| toolLabel: "linter", | ||
| successPrefix: "Linting", | ||
| noToolMessage: "No linter found (biome, oxlint, or eslint). Skipping linting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel: logLevel$2, | ||
| events, | ||
| onStart: () => events.emit("lint:start"), | ||
| onEnd: () => 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: "success", | ||
| hrStart, | ||
| pluginTimings | ||
| }); | ||
| await sendTelemetry(buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "success" | ||
| })); | ||
| } | ||
| async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) { | ||
| const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info; | ||
| const events = new AsyncEventEmitter(); | ||
| const promiseManager = new PromiseManager(); | ||
| await setupLogger(events, { logLevel: logLevel$3 }); | ||
| await executeIfOnline(async () => { | ||
| try { | ||
| const latestVersion = (await (await fetch(KUBB_NPM_PACKAGE_URL)).json()).version; | ||
| if (latestVersion && version < latestVersion) await events.emit("version:new", version, latestVersion); | ||
| } catch {} | ||
| }); | ||
| try { | ||
| const result = await getCosmiConfig("kubb", configPath); | ||
| const configs = await getConfigs(result.config, { input }); | ||
| await events.emit("config:start"); | ||
| await events.emit("info", "Config loaded", path.relative(process$1.cwd(), result.filepath)); | ||
| await events.emit("success", "Config loaded successfully", path.relative(process$1.cwd(), result.filepath)); | ||
| await events.emit("config:end", configs); | ||
| await events.emit("lifecycle:start", version); | ||
| const promises = configs.map((config) => { | ||
| return async () => { | ||
| if (isInputPath(config) && watch) { | ||
| await startWatcher([input || config.input.path], async (paths) => { | ||
| events.removeAll(); | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel: logLevel$3, | ||
| events | ||
| }); | ||
| clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`)); | ||
| }); | ||
| return; | ||
| } | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel: logLevel$3, | ||
| events | ||
| }); | ||
| }; | ||
| }); | ||
| await promiseManager.run("seq", promises); | ||
| await events.emit("lifecycle:end"); | ||
| } catch (error) { | ||
| await events.emit("error", toError(error)); | ||
| process$1.exit(1); | ||
| } | ||
| } | ||
| //#endregion | ||
| export { runGenerateCommand }; | ||
| //# sourceMappingURL=generate-B7Ckt_LG.js.map |
Sorry, the diff of this file is too big to display
| const require_chunk = require("./chunk-ByKO4r7w.cjs"); | ||
| const require_errors = require("./errors-DBW0N9w4.cjs"); | ||
| const require_telemetry = require("./telemetry-CEm85k_X.cjs"); | ||
| const require_shell = require("./shell-7HPrTCJ5.cjs"); | ||
| const require_package = require("./package-CSJQyhYO.cjs"); | ||
| const require_constants = require("./constants-BTUap0zs.cjs"); | ||
| let node_util = require("node:util"); | ||
| let node_events = require("node:events"); | ||
| let node_crypto = require("node:crypto"); | ||
| require("node:fs"); | ||
| let node_fs_promises = require("node:fs/promises"); | ||
| 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 _clack_prompts = require("@clack/prompts"); | ||
| _clack_prompts = require_chunk.__toESM(_clack_prompts); | ||
| let _kubb_core = require("@kubb/core"); | ||
| let tinyexec = require("tinyexec"); | ||
| let node_stream = require("node:stream"); | ||
| let cosmiconfig = require("cosmiconfig"); | ||
| let jiti = require("jiti"); | ||
| //#region ../../internals/utils/src/asyncEventEmitter.ts | ||
| /** | ||
| * A typed EventEmitter that awaits all async listeners before resolving. | ||
| * Wraps Node's `EventEmitter` with full TypeScript event-map inference. | ||
| */ | ||
| var AsyncEventEmitter = class { | ||
| /** | ||
| * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning. | ||
| * @default 10 | ||
| */ | ||
| constructor(maxListener = 10) { | ||
| this.#emitter.setMaxListeners(maxListener); | ||
| } | ||
| #emitter = new node_events.EventEmitter(); | ||
| /** | ||
| * Emits an event and awaits all registered listeners in parallel. | ||
| * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments. | ||
| */ | ||
| async emit(eventName, ...eventArgs) { | ||
| const listeners = this.#emitter.listeners(eventName); | ||
| if (listeners.length === 0) return; | ||
| await Promise.all(listeners.map(async (listener) => { | ||
| try { | ||
| return await listener(...eventArgs); | ||
| } catch (err) { | ||
| let serializedArgs; | ||
| try { | ||
| serializedArgs = JSON.stringify(eventArgs); | ||
| } catch { | ||
| serializedArgs = String(eventArgs); | ||
| } | ||
| throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: require_errors.toError(err) }); | ||
| } | ||
| })); | ||
| } | ||
| /** Registers a persistent listener for the given event. */ | ||
| on(eventName, handler) { | ||
| this.#emitter.on(eventName, handler); | ||
| } | ||
| /** Registers a one-shot listener that removes itself after the first invocation. */ | ||
| onOnce(eventName, handler) { | ||
| const wrapper = (...args) => { | ||
| this.off(eventName, wrapper); | ||
| return handler(...args); | ||
| }; | ||
| this.on(eventName, wrapper); | ||
| } | ||
| /** Removes a previously registered listener. */ | ||
| off(eventName, handler) { | ||
| this.#emitter.off(eventName, handler); | ||
| } | ||
| /** Removes all listeners from every event channel. */ | ||
| removeAll() { | ||
| this.#emitter.removeAllListeners(); | ||
| } | ||
| }; | ||
| //#endregion | ||
| //#region ../../internals/utils/src/time.ts | ||
| /** | ||
| * Calculates elapsed time in milliseconds from a high-resolution start time. | ||
| * Rounds to 2 decimal places to provide sub-millisecond precision without noise. | ||
| */ | ||
| function getElapsedMs(hrStart) { | ||
| const [seconds, nanoseconds] = process.hrtime(hrStart); | ||
| const ms = seconds * 1e3 + nanoseconds / 1e6; | ||
| return Math.round(ms * 100) / 100; | ||
| } | ||
| /** | ||
| * Converts a millisecond duration into a human-readable string. | ||
| * Adjusts units (ms, s, m s) based on the magnitude of the duration. | ||
| */ | ||
| function formatMs(ms) { | ||
| if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`; | ||
| if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`; | ||
| return `${Math.round(ms)}ms`; | ||
| } | ||
| /** | ||
| * Convenience helper: formats the elapsed time since `hrStart` in one step. | ||
| */ | ||
| function formatHrtime(hrStart) { | ||
| return formatMs(getElapsedMs(hrStart)); | ||
| } | ||
| //#endregion | ||
| //#region ../../internals/utils/src/colors.ts | ||
| /** | ||
| * Parses a CSS hex color string (`#RGB`) into its RGB channels. | ||
| * Falls back to `255` for any channel that cannot be parsed. | ||
| */ | ||
| function parseHex(color) { | ||
| const int = Number.parseInt(color.replace("#", ""), 16); | ||
| return Number.isNaN(int) ? { | ||
| r: 255, | ||
| g: 255, | ||
| b: 255 | ||
| } : { | ||
| r: int >> 16 & 255, | ||
| g: int >> 8 & 255, | ||
| b: int & 255 | ||
| }; | ||
| } | ||
| /** | ||
| * Returns a function that wraps a string in a 24-bit ANSI true-color escape sequence | ||
| * for the given hex color. | ||
| */ | ||
| function hex(color) { | ||
| const { r, g, b } = parseHex(color); | ||
| return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`; | ||
| } | ||
| function gradient(colorStops, text) { | ||
| const chars = text.split(""); | ||
| return chars.map((char, i) => { | ||
| const t = chars.length <= 1 ? 0 : i / (chars.length - 1); | ||
| const seg = Math.min(Math.floor(t * (colorStops.length - 1)), colorStops.length - 2); | ||
| const lt = t * (colorStops.length - 1) - seg; | ||
| const from = parseHex(colorStops[seg]); | ||
| const to = parseHex(colorStops[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(""); | ||
| } | ||
| /** ANSI color functions for each part of the Kubb mascot illustration. */ | ||
| const palette = { | ||
| 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 welcome banner. | ||
| */ | ||
| function getIntro({ title, description, version, areEyesOpen }) { | ||
| const kubbVersion = gradient([ | ||
| "#F58517", | ||
| "#F5A217", | ||
| "#F55A17" | ||
| ], `KUBB v${version}`); | ||
| const eyeTop = areEyesOpen ? palette.eye("█▀█") : palette.eye("───"); | ||
| const eyeBottom = areEyesOpen ? palette.eye("▀▀▀") : palette.eye("───"); | ||
| return ` | ||
| ${palette.lid("▄▄▄▄▄▄▄▄▄▄▄▄▄")} | ||
| ${palette.woodTop("█ ")}${palette.highlight("▄▄")}${palette.woodTop(" ")}${palette.highlight("▄▄")}${palette.woodTop(" █")} ${kubbVersion} | ||
| ${palette.woodMid("█ ")}${eyeTop}${palette.woodMid(" ")}${eyeTop}${palette.woodMid(" █")} ${(0, node_util.styleText)("gray", title)} | ||
| ${palette.woodMid("█ ")}${eyeBottom}${palette.woodMid(" ")}${palette.blush("◡")}${palette.woodMid(" ")}${eyeBottom}${palette.woodMid(" █")} ${(0, node_util.styleText)("yellow", "➜")} ${(0, node_util.styleText)("white", description)} | ||
| ${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")} | ||
| `; | ||
| } | ||
| /** ANSI color names available for terminal output. */ | ||
| const randomColors = [ | ||
| "black", | ||
| "red", | ||
| "green", | ||
| "yellow", | ||
| "blue", | ||
| "white", | ||
| "magenta", | ||
| "cyan", | ||
| "gray" | ||
| ]; | ||
| /** | ||
| * Returns the text wrapped in a deterministic ANSI color derived from the text's SHA-256 hash. | ||
| */ | ||
| function randomCliColor(text) { | ||
| if (!text) return ""; | ||
| return (0, node_util.styleText)(randomColors[(0, node_crypto.createHash)("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text); | ||
| } | ||
| /** | ||
| * Formats a millisecond duration with an ANSI color based on thresholds: | ||
| * green ≤ 500 ms · yellow ≤ 1 000 ms · red > 1 000 ms | ||
| */ | ||
| function formatMsWithColor(ms) { | ||
| const formatted = 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 ../../internals/utils/src/fs.ts | ||
| /** | ||
| * Writes `data` to `path`, trimming leading/trailing whitespace before saving. | ||
| * Skips the write and returns `undefined` when the trimmed content is empty or | ||
| * identical to what is already on disk. | ||
| * Creates any missing parent directories automatically. | ||
| * When `sanity` is `true`, re-reads the file after writing and throws if the | ||
| * content does not match. | ||
| */ | ||
| async function write(path, data, options = {}) { | ||
| const trimmed = data.trim(); | ||
| if (trimmed === "") return void 0; | ||
| const resolved = (0, node_path.resolve)(path); | ||
| if (typeof Bun !== "undefined") { | ||
| const file = Bun.file(resolved); | ||
| if ((await file.exists() ? await file.text() : null) === trimmed) return void 0; | ||
| await Bun.write(resolved, trimmed); | ||
| return trimmed; | ||
| } | ||
| try { | ||
| if (await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }) === trimmed) return void 0; | ||
| } catch {} | ||
| await (0, node_fs_promises.mkdir)((0, node_path.dirname)(resolved), { recursive: true }); | ||
| await (0, node_fs_promises.writeFile)(resolved, trimmed, { encoding: "utf-8" }); | ||
| if (options.sanity) { | ||
| const savedData = await (0, node_fs_promises.readFile)(resolved, { encoding: "utf-8" }); | ||
| if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`); | ||
| return savedData; | ||
| } | ||
| return trimmed; | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getSummary.ts | ||
| function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) { | ||
| const duration = 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 sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]); | ||
| 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 / 100), 10); | ||
| 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/runHook.ts | ||
| /** | ||
| * Execute a hook command, emit debug/hook:end events, and forward output to | ||
| * an optional HookOutputSink. All three logger adapters share this function | ||
| * so the process-spawning logic lives in exactly one place. | ||
| */ | ||
| async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) { | ||
| try { | ||
| const proc = (0, tinyexec.x)(command, [...args ?? []], { | ||
| nodeOptions: { detached: true }, | ||
| throwOnError: true | ||
| }); | ||
| if (stream && sink?.onLine) for await (const line of proc) sink.onLine(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) { | ||
| if (!(err instanceof tinyexec.NonZeroExitError)) { | ||
| await context.emit("hook:end", { | ||
| command, | ||
| args, | ||
| id, | ||
| success: false, | ||
| error: require_errors.toError(err) | ||
| }); | ||
| await context.emit("error", require_errors.toError(err)); | ||
| return; | ||
| } | ||
| const stderr = err.output?.stderr ?? ""; | ||
| const stdout = err.output?.stdout ?? ""; | ||
| await context.emit("debug", { | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [stdout, stderr].filter(Boolean) | ||
| }); | ||
| if (stderr) sink?.onStderr?.(stderr); | ||
| if (stdout) sink?.onStdout?.(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); | ||
| } | ||
| } | ||
| //#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 line = buildProgressLine(state); | ||
| if (line) _clack_prompts.log.step(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel); | ||
| } | ||
| 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 = require_errors.toCause(error); | ||
| 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; | ||
| try { | ||
| _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" | ||
| }); | ||
| } catch { | ||
| console.log(`Update available for Kubb: v${version} → v${latestVersion}`); | ||
| console.log("Run `npm install -g @kubb/cli` to update"); | ||
| } | ||
| }); | ||
| 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) => { | ||
| reset(); | ||
| 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); | ||
| }); | ||
| 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", 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 = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${(0, node_util.styleText)("dim", commandWithArgs)} started`); | ||
| if (!id) return; | ||
| if (logLevel <= _kubb_core.logLevel.silent) { | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStderr: (s) => console.error(s), | ||
| onStdout: (s) => console.log(s) | ||
| } | ||
| }); | ||
| 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); | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| stream: true, | ||
| sink: { | ||
| onLine: (line) => writable.write(line), | ||
| onStderr: (s) => logger.error(s), | ||
| onStdout: (s) => logger.message(s) | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const text = getMessage(`Hook ${(0, node_util.styleText)("dim", formatCommandWithArgs(command, args))} 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"); | ||
| const borderColor = status === "success" ? "green" : "red"; | ||
| try { | ||
| _clack_prompts.box(summary.join("\n"), getMessage(title), { | ||
| width: "auto", | ||
| formatBorder: (s) => (0, node_util.styleText)(borderColor, s), | ||
| rounded: true, | ||
| withGuide: false, | ||
| contentAlign: "left", | ||
| titleAlign: "center" | ||
| }); | ||
| } catch { | ||
| console.log(summary.join("\n")); | ||
| } | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#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)(node_process.default.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(([fileName, logs]) => 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}`] | ||
| }); | ||
| }); | ||
| context.on("success", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✓ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("warn", (message, info) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`⚠ ${message} ${info}`] | ||
| }); | ||
| }); | ||
| context.on("error", (error) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`✗ ${error.message}`, error.stack || "unknown stack"] | ||
| }); | ||
| }); | ||
| context.on("debug", (message) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: message.logs | ||
| }); | ||
| }); | ||
| context.on("plugin:start", (plugin) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Generating ${plugin.name}`] | ||
| }); | ||
| }); | ||
| context.on("plugin:end", (plugin, { duration, success }) => { | ||
| const durationStr = formatMs(duration); | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`] | ||
| }); | ||
| }); | ||
| context.on("files:processing:start", (files) => { | ||
| state.cachedLogs.add({ | ||
| date: /* @__PURE__ */ new Date(), | ||
| logs: [`Start ${files.length} writing:`, ...files.map((file) => file.path)] | ||
| }); | ||
| }); | ||
| 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)(node_process.default.cwd(), f)); | ||
| await context.emit("info", "Debug files written to:", files.join(", ")); | ||
| } | ||
| reset(); | ||
| }); | ||
| const exitHandler = () => { | ||
| if (state.cachedLogs.size > 0) writeLogs().catch(() => {}); | ||
| }; | ||
| node_process.default.once("exit", exitHandler); | ||
| node_process.default.once("SIGINT", exitHandler); | ||
| node_process.default.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(); | ||
| state.currentConfigs = []; | ||
| } | ||
| function showProgressStep() { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const line = buildProgressLine(state); | ||
| if (line) console.log(getMessage(line)); | ||
| } | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel); | ||
| } | ||
| 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 = require_errors.toCause(error); | ||
| 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) => { | ||
| reset(); | ||
| 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)); | ||
| }); | ||
| 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", 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"); | ||
| showProgressStep(); | ||
| }); | ||
| context.on("file:processing:update", () => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| state.processedFiles++; | ||
| }); | ||
| 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 = formatCommandWithArgs(command, args); | ||
| 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; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const commandWithArgs = formatCommandWithArgs(command, args); | ||
| 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 = 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"); | ||
| }); | ||
| context.on("lifecycle:end", () => { | ||
| reset(); | ||
| }); | ||
| } | ||
| }); | ||
| //#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 ?? _kubb_core.logLevel.info; | ||
| function getMessage(message) { | ||
| return formatMessage(message, logLevel); | ||
| } | ||
| 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 = require_errors.toCause(error); | ||
| 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("Generation 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 = 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 = formatCommandWithArgs(command, args); | ||
| const text = getMessage(`Hook ${commandWithArgs} started`); | ||
| if (logLevel > _kubb_core.logLevel.silent) console.log(text); | ||
| if (!id) return; | ||
| await runHook({ | ||
| id, | ||
| command, | ||
| args, | ||
| commandWithArgs, | ||
| context, | ||
| sink: { | ||
| onStdout: logLevel > _kubb_core.logLevel.silent ? (s) => console.log(s) : void 0, | ||
| onStderr: logLevel > _kubb_core.logLevel.silent ? (s) => console.error(s) : void 0 | ||
| } | ||
| }); | ||
| }); | ||
| context.on("hook:end", ({ command, args }) => { | ||
| if (logLevel <= _kubb_core.logLevel.silent) return; | ||
| const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} 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(require_constants.SUMMARY_SEPARATOR); | ||
| console.log(summary.join("\n")); | ||
| console.log(require_constants.SUMMARY_SEPARATOR); | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/loggers/utils.ts | ||
| /** | ||
| * Optionally prefix a message with a [HH:MM:SS] timestamp when logLevel >= verbose. | ||
| * Shared across all logger adapters to avoid duplication. | ||
| */ | ||
| function formatMessage(message, logLevel) { | ||
| 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}`; | ||
| return message; | ||
| } | ||
| /** | ||
| * Build the progress summary line shared by clack and GitHub Actions loggers. | ||
| * Returns null when there is nothing to display. | ||
| */ | ||
| function buildProgressLine(state) { | ||
| const parts = []; | ||
| const duration = 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) return null; | ||
| parts.push(`${(0, node_util.styleText)("green", duration)} elapsed`); | ||
| return parts.join((0, node_util.styleText)("dim", " | ")); | ||
| } | ||
| /** | ||
| * Join a command and its optional args into a single display string. | ||
| * e.g. ("prettier", ["--write", "."]) → "prettier --write ." | ||
| */ | ||
| function formatCommandWithArgs(command, args) { | ||
| return args?.length ? `${command} ${args.join(" ")}` : command; | ||
| } | ||
| function detectLogger() { | ||
| if (require_telemetry.isGitHubActions()) return "github-actions"; | ||
| if (require_telemetry.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] = require_shell.tokenize(command); | ||
| if (!cmd) continue; | ||
| const hookId = (0, node_crypto.createHash)("sha256").update(command).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`Hook failed: ${command}`)); | ||
| return; | ||
| } | ||
| events.emit("success", `${(0, node_util.styleText)("dim", command)} successfully executed`).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: cmd, | ||
| args | ||
| }); | ||
| await hookEndPromise; | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/utils/getCosmiConfig.ts | ||
| const jiti$1 = (0, jiti.createJiti)(require("url").pathToFileURL(__filename).href, { | ||
| jsx: { | ||
| runtime: "automatic", | ||
| importSource: "@kubb/react-fabric" | ||
| }, | ||
| sourceMaps: true, | ||
| interopDefault: true | ||
| }); | ||
| const tsLoader = async (configFile) => { | ||
| return await jiti$1.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.mts`, | ||
| `.${moduleName}rc.cts`, | ||
| `.${moduleName}rc.js`, | ||
| `.${moduleName}rc.mjs`, | ||
| `.${moduleName}rc.cjs`, | ||
| `${moduleName}.config.ts`, | ||
| `${moduleName}.config.mts`, | ||
| `${moduleName}.config.cts`, | ||
| `${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, | ||
| ".mts": tsLoader, | ||
| ".cts": 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 function startWatcher(path, cb) { | ||
| const { watch } = await import("chokidar"); | ||
| watch(path, { | ||
| ignorePermissionErrors: true, | ||
| ignored: require_constants.WATCHER_IGNORED_PATHS | ||
| }).on("all", async (type, file) => { | ||
| console.log((0, node_util.styleText)("yellow", (0, node_util.styleText)("bold", `Change detected: ${type} ${file}`))); | ||
| try { | ||
| await cb(path); | ||
| } catch (_e) { | ||
| console.log((0, node_util.styleText)("red", "Watcher failed")); | ||
| } | ||
| }); | ||
| } | ||
| //#endregion | ||
| //#region src/runners/generate.ts | ||
| async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel, events, onStart, onEnd }) { | ||
| await onStart(); | ||
| let resolvedTool = toolValue; | ||
| if (resolvedTool === "auto") { | ||
| const detected = await detect(); | ||
| if (!detected) await events.emit("warn", noToolMessage); | ||
| else { | ||
| resolvedTool = detected; | ||
| await events.emit("info", `Auto-detected ${toolLabel}: ${(0, node_util.styleText)("dim", resolvedTool)}`); | ||
| } | ||
| } | ||
| if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) { | ||
| const toolConfig = toolMap[resolvedTool]; | ||
| try { | ||
| const hookId = (0, node_crypto.createHash)("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex"); | ||
| const hookEndPromise = new Promise((resolve, reject) => { | ||
| const handler = ({ id, success, error }) => { | ||
| if (id !== hookId) return; | ||
| events.off("hook:end", handler); | ||
| if (!success) { | ||
| reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`)); | ||
| return; | ||
| } | ||
| events.emit("success", [ | ||
| `${successPrefix} with ${(0, node_util.styleText)("dim", resolvedTool)}`, | ||
| logLevel >= _kubb_core.logLevel.info ? `on ${(0, node_util.styleText)("dim", outputPath)}` : void 0, | ||
| "successfully" | ||
| ].filter(Boolean).join(" ")).then(resolve).catch(reject); | ||
| }; | ||
| events.on("hook:end", handler); | ||
| }); | ||
| await events.emit("hook:start", { | ||
| id: hookId, | ||
| command: toolConfig.command, | ||
| args: toolConfig.args(outputPath) | ||
| }); | ||
| await hookEndPromise; | ||
| } catch (caughtError) { | ||
| const err = new Error(toolConfig.errorMessage); | ||
| err.cause = caughtError; | ||
| await events.emit("error", err); | ||
| } | ||
| } | ||
| await onEnd(); | ||
| } | ||
| 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) { | ||
| const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean); | ||
| for (const err of allErrors) await events.emit("error", err); | ||
| await events.emit("generation:end", config, files, sources); | ||
| await events.emit("generation:summary", config, { | ||
| failedPlugins, | ||
| filesCreated: files.length, | ||
| status: "failed", | ||
| hrStart, | ||
| pluginTimings: logLevel >= _kubb_core.logLevel.verbose ? pluginTimings : void 0 | ||
| }); | ||
| await require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: require_package.version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "failed" | ||
| })); | ||
| node_process.default.exit(1); | ||
| } | ||
| await events.emit("success", "Generation successfully", inputPath); | ||
| await events.emit("generation:end", config, files, sources); | ||
| const outputPath = node_path.default.resolve(config.root, config.output.path); | ||
| if (config.output.format) await runToolPass({ | ||
| toolValue: config.output.format, | ||
| detect: _kubb_core.detectFormatter, | ||
| toolMap: _kubb_core.formatters, | ||
| toolLabel: "formatter", | ||
| successPrefix: "Formatting", | ||
| noToolMessage: "No formatter found (biome, prettier, or oxfmt). Skipping formatting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel, | ||
| events, | ||
| onStart: () => events.emit("format:start"), | ||
| onEnd: () => events.emit("format:end") | ||
| }); | ||
| if (config.output.lint) await runToolPass({ | ||
| toolValue: config.output.lint, | ||
| detect: _kubb_core.detectLinter, | ||
| toolMap: _kubb_core.linters, | ||
| toolLabel: "linter", | ||
| successPrefix: "Linting", | ||
| noToolMessage: "No linter found (biome, oxlint, or eslint). Skipping linting.", | ||
| configName: config.name, | ||
| outputPath, | ||
| logLevel, | ||
| events, | ||
| onStart: () => events.emit("lint:start"), | ||
| onEnd: () => 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: "success", | ||
| hrStart, | ||
| pluginTimings | ||
| }); | ||
| await require_telemetry.sendTelemetry(require_telemetry.buildTelemetryEvent({ | ||
| command: "generate", | ||
| kubbVersion: require_package.version, | ||
| plugins: pluginManager.plugins.map((p) => ({ | ||
| name: p.name, | ||
| options: p.options | ||
| })), | ||
| hrStart, | ||
| filesCreated: files.length, | ||
| status: "success" | ||
| })); | ||
| } | ||
| async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }) { | ||
| const logLevel = _kubb_core.logLevel[logLevelKey] ?? _kubb_core.logLevel.info; | ||
| const events = new AsyncEventEmitter(); | ||
| const promiseManager = new _kubb_core.PromiseManager(); | ||
| await setupLogger(events, { logLevel }); | ||
| await require_telemetry.executeIfOnline(async () => { | ||
| try { | ||
| const latestVersion = (await (await fetch(require_constants.KUBB_NPM_PACKAGE_URL)).json()).version; | ||
| if (latestVersion && require_package.version < latestVersion) await events.emit("version:new", require_package.version, latestVersion); | ||
| } catch {} | ||
| }); | ||
| try { | ||
| const result = await getCosmiConfig("kubb", configPath); | ||
| const configs = await (0, _kubb_core.getConfigs)(result.config, { input }); | ||
| await events.emit("config:start"); | ||
| await events.emit("info", "Config loaded", node_path.default.relative(node_process.default.cwd(), result.filepath)); | ||
| await events.emit("success", "Config loaded successfully", node_path.default.relative(node_process.default.cwd(), result.filepath)); | ||
| await events.emit("config:end", configs); | ||
| await events.emit("lifecycle:start", require_package.version); | ||
| const promises = configs.map((config) => { | ||
| return async () => { | ||
| if ((0, _kubb_core.isInputPath)(config) && watch) { | ||
| await startWatcher([input || config.input.path], async (paths) => { | ||
| events.removeAll(); | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel, | ||
| events | ||
| }); | ||
| _clack_prompts.log.step((0, node_util.styleText)("yellow", `Watching for changes in ${paths.join(" and ")}`)); | ||
| }); | ||
| return; | ||
| } | ||
| await generate({ | ||
| input, | ||
| config, | ||
| logLevel, | ||
| events | ||
| }); | ||
| }; | ||
| }); | ||
| await promiseManager.run("seq", promises); | ||
| await events.emit("lifecycle:end"); | ||
| } catch (error) { | ||
| await events.emit("error", require_errors.toError(error)); | ||
| node_process.default.exit(1); | ||
| } | ||
| } | ||
| //#endregion | ||
| exports.runGenerateCommand = runGenerateCommand; | ||
| //# sourceMappingURL=generate-C2sBooAl.cjs.map |
Sorry, the diff of this file is too big to display
| require("./chunk-ByKO4r7w.cjs"); | ||
| //#region src/commands/generate.ts | ||
| const command = require("./define-D6Kfm7-Z.cjs").defineCommand({ | ||
| name: "generate", | ||
| description: "[input] Generate files based on a 'kubb.config.ts' file", | ||
| arguments: ["[input]"], | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| logLevel: { | ||
| type: "string", | ||
| description: "Info, silent, verbose or debug", | ||
| short: "l", | ||
| default: "info", | ||
| hint: "silent|info|verbose|debug", | ||
| enum: [ | ||
| "silent", | ||
| "info", | ||
| "verbose", | ||
| "debug" | ||
| ] | ||
| }, | ||
| watch: { | ||
| type: "boolean", | ||
| description: "Watch mode based on the input file", | ||
| short: "w", | ||
| default: false | ||
| }, | ||
| debug: { | ||
| type: "boolean", | ||
| description: "Override logLevel to debug", | ||
| short: "d", | ||
| default: false | ||
| }, | ||
| verbose: { | ||
| type: "boolean", | ||
| description: "Override logLevel to verbose", | ||
| short: "v", | ||
| default: false | ||
| }, | ||
| silent: { | ||
| type: "boolean", | ||
| description: "Override logLevel to silent", | ||
| short: "s", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values, positionals }) { | ||
| const logLevel = values.debug ? "debug" : values.verbose ? "verbose" : values.silent ? "silent" : values.logLevel; | ||
| const { runGenerateCommand } = await Promise.resolve().then(() => require("./generate-C2sBooAl.cjs")); | ||
| await runGenerateCommand({ | ||
| input: positionals[0], | ||
| configPath: values.config, | ||
| logLevel, | ||
| watch: values.watch | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=generate-DQ_S_FW_.cjs.map |
| {"version":3,"file":"generate-DQ_S_FW_.cjs","names":["defineCommand"],"sources":["../src/commands/generate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\n\nexport const command = defineCommand({\n name: 'generate',\n description: \"[input] Generate files based on a 'kubb.config.ts' file\",\n arguments: ['[input]'],\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n logLevel: {\n type: 'string',\n description: 'Info, silent, verbose or debug',\n short: 'l',\n default: 'info',\n hint: 'silent|info|verbose|debug',\n enum: ['silent', 'info', 'verbose', 'debug'],\n },\n watch: { type: 'boolean', description: 'Watch mode based on the input file', short: 'w', default: false },\n debug: { type: 'boolean', description: 'Override logLevel to debug', short: 'd', default: false },\n verbose: { type: 'boolean', description: 'Override logLevel to verbose', short: 'v', default: false },\n silent: { type: 'boolean', description: 'Override logLevel to silent', short: 's', default: false },\n },\n async run({ values, positionals }) {\n const logLevel = values.debug ? 'debug' : values.verbose ? 'verbose' : values.silent ? 'silent' : values.logLevel\n const { runGenerateCommand } = await import('../runners/generate.ts')\n\n await runGenerateCommand({ input: positionals[0], configPath: values.config, logLevel, watch: values.watch })\n },\n})\n"],"mappings":";;AAEA,MAAa,2CAAUA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,WAAW,CAAC,UAAU;CACtB,SAAS;EACP,QAAQ;GAAE,MAAM;GAAU,aAAa;GAA2B,OAAO;GAAK;EAC9E,UAAU;GACR,MAAM;GACN,aAAa;GACb,OAAO;GACP,SAAS;GACT,MAAM;GACN,MAAM;IAAC;IAAU;IAAQ;IAAW;IAAQ;GAC7C;EACD,OAAO;GAAE,MAAM;GAAW,aAAa;GAAsC,OAAO;GAAK,SAAS;GAAO;EACzG,OAAO;GAAE,MAAM;GAAW,aAAa;GAA8B,OAAO;GAAK,SAAS;GAAO;EACjG,SAAS;GAAE,MAAM;GAAW,aAAa;GAAgC,OAAO;GAAK,SAAS;GAAO;EACrG,QAAQ;GAAE,MAAM;GAAW,aAAa;GAA+B,OAAO;GAAK,SAAS;GAAO;EACpG;CACD,MAAM,IAAI,EAAE,QAAQ,eAAe;EACjC,MAAM,WAAW,OAAO,QAAQ,UAAU,OAAO,UAAU,YAAY,OAAO,SAAS,WAAW,OAAO;EACzG,MAAM,EAAE,uBAAuB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,0BAAA,CAAA;AAErC,QAAM,mBAAmB;GAAE,OAAO,YAAY;GAAI,YAAY,OAAO;GAAQ;GAAU,OAAO,OAAO;GAAO,CAAC;;CAEhH,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| //#region src/commands/generate.ts | ||
| const command = defineCommand({ | ||
| name: "generate", | ||
| description: "[input] Generate files based on a 'kubb.config.ts' file", | ||
| arguments: ["[input]"], | ||
| options: { | ||
| config: { | ||
| type: "string", | ||
| description: "Path to the Kubb config", | ||
| short: "c" | ||
| }, | ||
| logLevel: { | ||
| type: "string", | ||
| description: "Info, silent, verbose or debug", | ||
| short: "l", | ||
| default: "info", | ||
| hint: "silent|info|verbose|debug", | ||
| enum: [ | ||
| "silent", | ||
| "info", | ||
| "verbose", | ||
| "debug" | ||
| ] | ||
| }, | ||
| watch: { | ||
| type: "boolean", | ||
| description: "Watch mode based on the input file", | ||
| short: "w", | ||
| default: false | ||
| }, | ||
| debug: { | ||
| type: "boolean", | ||
| description: "Override logLevel to debug", | ||
| short: "d", | ||
| default: false | ||
| }, | ||
| verbose: { | ||
| type: "boolean", | ||
| description: "Override logLevel to verbose", | ||
| short: "v", | ||
| default: false | ||
| }, | ||
| silent: { | ||
| type: "boolean", | ||
| description: "Override logLevel to silent", | ||
| short: "s", | ||
| default: false | ||
| } | ||
| }, | ||
| async run({ values, positionals }) { | ||
| const logLevel = values.debug ? "debug" : values.verbose ? "verbose" : values.silent ? "silent" : values.logLevel; | ||
| const { runGenerateCommand } = await import("./generate-B7Ckt_LG.js"); | ||
| await runGenerateCommand({ | ||
| input: positionals[0], | ||
| configPath: values.config, | ||
| logLevel, | ||
| watch: values.watch | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=generate-Qcw6Ilwk.js.map |
| {"version":3,"file":"generate-Qcw6Ilwk.js","names":[],"sources":["../src/commands/generate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\n\nexport const command = defineCommand({\n name: 'generate',\n description: \"[input] Generate files based on a 'kubb.config.ts' file\",\n arguments: ['[input]'],\n options: {\n config: { type: 'string', description: 'Path to the Kubb config', short: 'c' },\n logLevel: {\n type: 'string',\n description: 'Info, silent, verbose or debug',\n short: 'l',\n default: 'info',\n hint: 'silent|info|verbose|debug',\n enum: ['silent', 'info', 'verbose', 'debug'],\n },\n watch: { type: 'boolean', description: 'Watch mode based on the input file', short: 'w', default: false },\n debug: { type: 'boolean', description: 'Override logLevel to debug', short: 'd', default: false },\n verbose: { type: 'boolean', description: 'Override logLevel to verbose', short: 'v', default: false },\n silent: { type: 'boolean', description: 'Override logLevel to silent', short: 's', default: false },\n },\n async run({ values, positionals }) {\n const logLevel = values.debug ? 'debug' : values.verbose ? 'verbose' : values.silent ? 'silent' : values.logLevel\n const { runGenerateCommand } = await import('../runners/generate.ts')\n\n await runGenerateCommand({ input: positionals[0], configPath: values.config, logLevel, watch: values.watch })\n },\n})\n"],"mappings":";;;AAEA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,WAAW,CAAC,UAAU;CACtB,SAAS;EACP,QAAQ;GAAE,MAAM;GAAU,aAAa;GAA2B,OAAO;GAAK;EAC9E,UAAU;GACR,MAAM;GACN,aAAa;GACb,OAAO;GACP,SAAS;GACT,MAAM;GACN,MAAM;IAAC;IAAU;IAAQ;IAAW;IAAQ;GAC7C;EACD,OAAO;GAAE,MAAM;GAAW,aAAa;GAAsC,OAAO;GAAK,SAAS;GAAO;EACzG,OAAO;GAAE,MAAM;GAAW,aAAa;GAA8B,OAAO;GAAK,SAAS;GAAO;EACjG,SAAS;GAAE,MAAM;GAAW,aAAa;GAAgC,OAAO;GAAK,SAAS;GAAO;EACrG,QAAQ;GAAE,MAAM;GAAW,aAAa;GAA+B,OAAO;GAAK,SAAS;GAAO;EACpG;CACD,MAAM,IAAI,EAAE,QAAQ,eAAe;EACjC,MAAM,WAAW,OAAO,QAAQ,UAAU,OAAO,UAAU,YAAY,OAAO,SAAS,WAAW,OAAO;EACzG,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAE5C,QAAM,mBAAmB;GAAE,OAAO,YAAY;GAAI,YAAY,OAAO;GAAQ;GAAU,OAAO,OAAO;GAAO,CAAC;;CAEhH,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-CSJQyhYO.cjs"); | ||
| //#region src/commands/init.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "init", | ||
| description: "Initialize a new Kubb project with interactive setup", | ||
| options: { yes: { | ||
| type: "boolean", | ||
| description: "Skip prompts and use default options", | ||
| short: "y", | ||
| default: false | ||
| } }, | ||
| async run({ values }) { | ||
| const { runInit } = await Promise.resolve().then(() => require("./init-hmolV6B4.cjs")); | ||
| await runInit({ | ||
| yes: values.yes, | ||
| version: require_package.version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=init-CibN8lng.cjs.map |
| {"version":3,"file":"init-CibN8lng.cjs","names":["defineCommand"],"sources":["../src/commands/init.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'init',\n description: 'Initialize a new Kubb project with interactive setup',\n options: {\n yes: { type: 'boolean', description: 'Skip prompts and use default options', short: 'y', default: false },\n },\n async run({ values }) {\n const { runInit } = await import('../runners/init.ts')\n\n await runInit({ yes: values.yes, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAUA,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,KAAK;EAAE,MAAM;EAAW,aAAa;EAAwC,OAAO;EAAK,SAAS;EAAO,EAC1G;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,YAAY,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,sBAAA,CAAA;AAE1B,QAAM,QAAQ;GAAE,KAAK,OAAO;GAAK,SAAA,gBAAA;GAAS,CAAC;;CAE9C,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-Zc7qipPx.js"; | ||
| //#region src/commands/init.ts | ||
| const command = defineCommand({ | ||
| name: "init", | ||
| description: "Initialize a new Kubb project with interactive setup", | ||
| options: { yes: { | ||
| type: "boolean", | ||
| description: "Skip prompts and use default options", | ||
| short: "y", | ||
| default: false | ||
| } }, | ||
| async run({ values }) { | ||
| const { runInit } = await import("./init-C-InrmSY.js"); | ||
| await runInit({ | ||
| yes: values.yes, | ||
| version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=init-DqWUHya_.js.map |
| {"version":3,"file":"init-DqWUHya_.js","names":[],"sources":["../src/commands/init.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'init',\n description: 'Initialize a new Kubb project with interactive setup',\n options: {\n yes: { type: 'boolean', description: 'Skip prompts and use default options', short: 'y', default: false },\n },\n async run({ values }) {\n const { runInit } = await import('../runners/init.ts')\n\n await runInit({ yes: values.yes, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,KAAK;EAAE,MAAM;EAAW,aAAa;EAAwC,OAAO;EAAK,SAAS;EAAO,EAC1G;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,YAAY,MAAM,OAAO;AAEjC,QAAM,QAAQ;GAAE,KAAK,OAAO;GAAK;GAAS,CAAC;;CAE9C,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-Zc7qipPx.js"; | ||
| //#region src/commands/mcp.ts | ||
| const command = defineCommand({ | ||
| name: "mcp", | ||
| description: "Start the server to enable the MCP client to interact with the LLM.", | ||
| async run() { | ||
| const { runMcp } = await import("./mcp-Cwbv3dfC.js"); | ||
| await runMcp({ version }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=mcp-DwRXOXZV.js.map |
| {"version":3,"file":"mcp-DwRXOXZV.js","names":[],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'mcp',\n description: 'Start the server to enable the MCP client to interact with the LLM.',\n async run() {\n const { runMcp } = await import('../runners/mcp.ts')\n\n await runMcp({ version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,MAAM,MAAM;EACV,MAAM,EAAE,WAAW,MAAM,OAAO;AAEhC,QAAM,OAAO,EAAE,SAAS,CAAC;;CAE5B,CAAC"} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-CSJQyhYO.cjs"); | ||
| //#region src/commands/mcp.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "mcp", | ||
| description: "Start the server to enable the MCP client to interact with the LLM.", | ||
| async run() { | ||
| const { runMcp } = await Promise.resolve().then(() => require("./mcp-X8kKSlov.cjs")); | ||
| await runMcp({ version: require_package.version }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=mcp-uDMa0yKp.cjs.map |
| {"version":3,"file":"mcp-uDMa0yKp.cjs","names":["defineCommand"],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'mcp',\n description: 'Start the server to enable the MCP client to interact with the LLM.',\n async run() {\n const { runMcp } = await import('../runners/mcp.ts')\n\n await runMcp({ version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAUA,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,MAAM,MAAM;EACV,MAAM,EAAE,WAAW,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,qBAAA,CAAA;AAEzB,QAAM,OAAO,EAAE,SAAA,gBAAA,SAAS,CAAC;;CAE5B,CAAC"} |
| //#region package.json | ||
| var version = "4.37.7"; | ||
| //#endregion | ||
| Object.defineProperty(exports, "version", { | ||
| enumerable: true, | ||
| get: function() { | ||
| return version; | ||
| } | ||
| }); | ||
| //# sourceMappingURL=package-CSJQyhYO.cjs.map |
| {"version":3,"file":"package-CSJQyhYO.cjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""} |
| //#region package.json | ||
| var version = "4.37.7"; | ||
| //#endregion | ||
| export { version as t }; | ||
| //# sourceMappingURL=package-Zc7qipPx.js.map |
| {"version":3,"file":"package-Zc7qipPx.js","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""} |
| require("./chunk-ByKO4r7w.cjs"); | ||
| const require_define = require("./define-D6Kfm7-Z.cjs"); | ||
| const require_package = require("./package-CSJQyhYO.cjs"); | ||
| //#region src/commands/validate.ts | ||
| const command = require_define.defineCommand({ | ||
| name: "validate", | ||
| description: "Validate a Swagger/OpenAPI file", | ||
| options: { input: { | ||
| type: "string", | ||
| description: "Path to Swagger/OpenAPI file", | ||
| short: "i", | ||
| required: true | ||
| } }, | ||
| async run({ values }) { | ||
| const { runValidate } = await Promise.resolve().then(() => require("./validate-DYVo8-Fj.cjs")); | ||
| await runValidate({ | ||
| input: values.input, | ||
| version: require_package.version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| exports.command = command; | ||
| //# sourceMappingURL=validate-BRzEtRj7.cjs.map |
| {"version":3,"file":"validate-BRzEtRj7.cjs","names":["defineCommand"],"sources":["../src/commands/validate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'validate',\n description: 'Validate a Swagger/OpenAPI file',\n options: {\n input: { type: 'string', description: 'Path to Swagger/OpenAPI file', short: 'i', required: true },\n },\n async run({ values }) {\n const { runValidate } = await import('../runners/validate.ts')\n\n await runValidate({ input: values.input, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAUA,eAAAA,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,OAAO;EAAE,MAAM;EAAU,aAAa;EAAgC,OAAO;EAAK,UAAU;EAAM,EACnG;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,gBAAgB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,0BAAA,CAAA;AAE9B,QAAM,YAAY;GAAE,OAAO,OAAO;GAAO,SAAA,gBAAA;GAAS,CAAC;;CAEtD,CAAC"} |
| import "./chunk--u3MIqq1.js"; | ||
| import { n as defineCommand } from "./define--M_JMcDC.js"; | ||
| import { t as version } from "./package-Zc7qipPx.js"; | ||
| //#region src/commands/validate.ts | ||
| const command = defineCommand({ | ||
| name: "validate", | ||
| description: "Validate a Swagger/OpenAPI file", | ||
| options: { input: { | ||
| type: "string", | ||
| description: "Path to Swagger/OpenAPI file", | ||
| short: "i", | ||
| required: true | ||
| } }, | ||
| async run({ values }) { | ||
| const { runValidate } = await import("./validate-BGyxLev8.js"); | ||
| await runValidate({ | ||
| input: values.input, | ||
| version | ||
| }); | ||
| } | ||
| }); | ||
| //#endregion | ||
| export { command }; | ||
| //# sourceMappingURL=validate-IUvDwpX1.js.map |
| {"version":3,"file":"validate-IUvDwpX1.js","names":[],"sources":["../src/commands/validate.ts"],"sourcesContent":["import { defineCommand } from '@internals/utils'\nimport { version } from '../../package.json'\n\nexport const command = defineCommand({\n name: 'validate',\n description: 'Validate a Swagger/OpenAPI file',\n options: {\n input: { type: 'string', description: 'Path to Swagger/OpenAPI file', short: 'i', required: true },\n },\n async run({ values }) {\n const { runValidate } = await import('../runners/validate.ts')\n\n await runValidate({ input: values.input, version })\n },\n})\n"],"mappings":";;;;AAGA,MAAa,UAAU,cAAc;CACnC,MAAM;CACN,aAAa;CACb,SAAS,EACP,OAAO;EAAE,MAAM;EAAU,aAAa;EAAgC,OAAO;EAAK,UAAU;EAAM,EACnG;CACD,MAAM,IAAI,EAAE,UAAU;EACpB,MAAM,EAAE,gBAAgB,MAAM,OAAO;AAErC,QAAM,YAAY;GAAE,OAAO,OAAO;GAAO;GAAS,CAAC;;CAEtD,CAAC"} |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 22 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 22 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
+ Added
+ Added
- Removed
- Removed
Updated