@kubb/cli 5.0.0-alpha.9 → 5.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -27
- package/bin/kubb.js +6 -0
- package/dist/agent-Bx2yllmS.js +68 -0
- package/dist/agent-Bx2yllmS.js.map +1 -0
- package/dist/agent-CeLwj5im.cjs +70 -0
- package/dist/agent-CeLwj5im.cjs.map +1 -0
- package/dist/{chunk--u3MIqq1.js → chunk-BvFE5Tac.js} +1 -0
- package/dist/constants-B2JTeRBb.js +42 -0
- package/dist/constants-B2JTeRBb.js.map +1 -0
- package/dist/constants-BINTA5VZ.cjs +77 -0
- package/dist/constants-BINTA5VZ.cjs.map +1 -0
- package/dist/constants-BYGmiFs0.cjs +139 -0
- package/dist/constants-BYGmiFs0.cjs.map +1 -0
- package/dist/constants-DSJ-Xrbv.js +116 -0
- package/dist/constants-DSJ-Xrbv.js.map +1 -0
- package/dist/define-Bdn8j5VM.cjs +54 -0
- package/dist/define-Bdn8j5VM.cjs.map +1 -0
- package/dist/define-m_fp-Aqm.js +43 -0
- package/dist/define-m_fp-Aqm.js.map +1 -0
- package/dist/errors-CINO1EIv.js +43 -0
- package/dist/errors-CINO1EIv.js.map +1 -0
- package/dist/{errors-DBW0N9w4.cjs → errors-CLCjoSg0.cjs} +22 -6
- package/dist/errors-CLCjoSg0.cjs.map +1 -0
- package/dist/{generate-Rly1EXBN.js → generate-BLvcvoIj.js} +12 -6
- package/dist/generate-BLvcvoIj.js.map +1 -0
- package/dist/{generate-DU5zzc54.cjs → generate-drLxTAnz.cjs} +11 -5
- package/dist/generate-drLxTAnz.cjs.map +1 -0
- package/dist/index.cjs +52 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +53 -22
- package/dist/index.js.map +1 -1
- package/dist/init-CGu7JZEF.js +53 -0
- package/dist/init-CGu7JZEF.js.map +1 -0
- package/dist/init-CyCjvIEF.cjs +53 -0
- package/dist/init-CyCjvIEF.cjs.map +1 -0
- package/dist/mcp-Cq2sylQC.js +39 -0
- package/dist/mcp-Cq2sylQC.js.map +1 -0
- package/dist/mcp-DSF5gpI-.cjs +39 -0
- package/dist/mcp-DSF5gpI-.cjs.map +1 -0
- package/dist/{package-BJ6ionm6.cjs → package-DZ-6zAIO.cjs} +2 -2
- package/dist/package-DZ-6zAIO.cjs.map +1 -0
- package/dist/package-OLYIpjqw.js +6 -0
- package/dist/package-OLYIpjqw.js.map +1 -0
- package/dist/{generate-BHNyeQXl.js → run-Bfbr3RaM.js} +781 -502
- package/dist/run-Bfbr3RaM.js.map +1 -0
- package/dist/run-BzpYYOQs.js +121 -0
- package/dist/run-BzpYYOQs.js.map +1 -0
- package/dist/run-CCZ24VKk.js +51 -0
- package/dist/run-CCZ24VKk.js.map +1 -0
- package/dist/run-CF97BWVa.js +244 -0
- package/dist/run-CF97BWVa.js.map +1 -0
- package/dist/run-CQbj3ley.cjs +52 -0
- package/dist/run-CQbj3ley.cjs.map +1 -0
- package/dist/{generate-Cq5RDTBL.cjs → run-CVlrIZoW.cjs} +786 -507
- package/dist/run-CVlrIZoW.cjs.map +1 -0
- package/dist/run-D0hmRpHy.js +49 -0
- package/dist/run-D0hmRpHy.js.map +1 -0
- package/dist/run-DwdAwnLG.cjs +125 -0
- package/dist/run-DwdAwnLG.cjs.map +1 -0
- package/dist/run-Lr0Ctnu0.cjs +50 -0
- package/dist/run-Lr0Ctnu0.cjs.map +1 -0
- package/dist/run-YsoCk5we.cjs +248 -0
- package/dist/run-YsoCk5we.cjs.map +1 -0
- package/dist/{shell-7HPrTCJ5.cjs → shell-475fQKaX.cjs} +8 -3
- package/dist/shell-475fQKaX.cjs.map +1 -0
- package/dist/{shell-DqqWsHCD.js → shell-CN6DNqeC.js} +9 -4
- package/dist/shell-CN6DNqeC.js.map +1 -0
- package/dist/{telemetry-DZ7IrLAU.cjs → telemetry-B2iWkY5e.cjs} +53 -13
- package/dist/telemetry-B2iWkY5e.cjs.map +1 -0
- package/dist/{telemetry-BF3SMlH6.js → telemetry-BkektVz6.js} +52 -12
- package/dist/telemetry-BkektVz6.js.map +1 -0
- package/dist/validate-CAUqLaGt.js +26 -0
- package/dist/validate-CAUqLaGt.js.map +1 -0
- package/dist/validate-J6AEd5zK.cjs +26 -0
- package/dist/validate-J6AEd5zK.cjs.map +1 -0
- package/package.json +57 -48
- package/src/commands/agent/start.ts +27 -8
- package/src/commands/agent.ts +3 -1
- package/src/commands/generate.ts +39 -8
- package/src/commands/init.ts +40 -4
- package/src/commands/mcp.ts +28 -4
- package/src/commands/validate.ts +11 -4
- package/src/constants.ts +5 -80
- package/src/index.ts +12 -13
- package/src/loggers/clackLogger.ts +98 -88
- package/src/loggers/fileSystemLogger.ts +37 -25
- package/src/loggers/githubActionsLogger.ts +35 -48
- package/src/loggers/plainLogger.ts +33 -45
- package/src/loggers/types.ts +6 -0
- package/src/loggers/utils.ts +155 -9
- package/src/runners/agent/run.ts +113 -0
- package/src/runners/agent/utils.ts +98 -0
- package/src/runners/generate/run.ts +276 -0
- package/src/runners/generate/utils.ts +209 -0
- package/src/runners/init/run.ts +211 -0
- package/src/{utils/packageManager.ts → runners/init/utils.ts} +10 -0
- package/src/runners/mcp/run.ts +55 -0
- package/src/runners/validate/run.ts +63 -0
- package/src/{utils/telemetry.ts → telemetry.ts} +28 -8
- package/bin/kubb.cjs +0 -18
- package/dist/agent-5mmp7QzF.js +0 -56
- package/dist/agent-5mmp7QzF.js.map +0 -1
- package/dist/agent-BKphjOIF.cjs +0 -58
- package/dist/agent-BKphjOIF.cjs.map +0 -1
- package/dist/agent-BapvKB4r.cjs +0 -92
- package/dist/agent-BapvKB4r.cjs.map +0 -1
- package/dist/agent-CBrpIMMU.js +0 -88
- package/dist/agent-CBrpIMMU.js.map +0 -1
- package/dist/constants-D0XHAHeZ.cjs +0 -178
- package/dist/constants-D0XHAHeZ.cjs.map +0 -1
- package/dist/constants-DJM9zCXm.js +0 -131
- package/dist/constants-DJM9zCXm.js.map +0 -1
- package/dist/define--M_JMcDC.js +0 -25
- package/dist/define--M_JMcDC.js.map +0 -1
- package/dist/define-D6Kfm7-Z.cjs +0 -36
- package/dist/define-D6Kfm7-Z.cjs.map +0 -1
- package/dist/errors-6mF_WKxg.js +0 -27
- package/dist/errors-6mF_WKxg.js.map +0 -1
- package/dist/errors-DBW0N9w4.cjs.map +0 -1
- package/dist/generate-BHNyeQXl.js.map +0 -1
- package/dist/generate-Cq5RDTBL.cjs.map +0 -1
- package/dist/generate-DU5zzc54.cjs.map +0 -1
- package/dist/generate-Rly1EXBN.js.map +0 -1
- package/dist/init-BK6inBTR.cjs +0 -306
- package/dist/init-BK6inBTR.cjs.map +0 -1
- package/dist/init-BQ6zfsnw.js +0 -302
- package/dist/init-BQ6zfsnw.js.map +0 -1
- package/dist/init-CN1JFyGX.cjs +0 -25
- package/dist/init-CN1JFyGX.cjs.map +0 -1
- package/dist/init-iN7e1XwI.js +0 -25
- package/dist/init-iN7e1XwI.js.map +0 -1
- package/dist/jiti-Cd3S0xwr.cjs +0 -16
- package/dist/jiti-Cd3S0xwr.cjs.map +0 -1
- package/dist/jiti-e08mD2Ph.js +0 -11
- package/dist/jiti-e08mD2Ph.js.map +0 -1
- package/dist/mcp-BiGUvbWP.js +0 -41
- package/dist/mcp-BiGUvbWP.js.map +0 -1
- package/dist/mcp-CONmm_xT.cjs +0 -42
- package/dist/mcp-CONmm_xT.cjs.map +0 -1
- package/dist/mcp-T7Q4nWbT.cjs +0 -16
- package/dist/mcp-T7Q4nWbT.cjs.map +0 -1
- package/dist/mcp-eP1S40LZ.js +0 -16
- package/dist/mcp-eP1S40LZ.js.map +0 -1
- package/dist/package-BJ6ionm6.cjs.map +0 -1
- package/dist/package-BKZ0H3Zf.js +0 -6
- package/dist/package-BKZ0H3Zf.js.map +0 -1
- package/dist/shell-7HPrTCJ5.cjs.map +0 -1
- package/dist/shell-DqqWsHCD.js.map +0 -1
- package/dist/telemetry-BF3SMlH6.js.map +0 -1
- package/dist/telemetry-DZ7IrLAU.cjs.map +0 -1
- package/dist/validate-BImbbx1t.js +0 -41
- package/dist/validate-BImbbx1t.js.map +0 -1
- package/dist/validate-DAZdX_0i.js +0 -25
- package/dist/validate-DAZdX_0i.js.map +0 -1
- package/dist/validate-DucFMytl.cjs +0 -25
- package/dist/validate-DucFMytl.cjs.map +0 -1
- package/dist/validate-ujLCYSWU.cjs +0 -42
- package/dist/validate-ujLCYSWU.cjs.map +0 -1
- package/src/runners/agent.ts +0 -102
- package/src/runners/generate.ts +0 -343
- package/src/runners/init.ts +0 -323
- package/src/runners/mcp.ts +0 -32
- package/src/runners/validate.ts +0 -35
- package/src/types.ts +0 -11
- package/src/utils/Writables.ts +0 -17
- package/src/utils/executeHooks.ts +0 -45
- package/src/utils/flags.ts +0 -10
- package/src/utils/getCosmiConfig.ts +0 -71
- package/src/utils/getSummary.ts +0 -68
- package/src/utils/jiti.ts +0 -9
- package/src/utils/runHook.ts +0 -75
- package/src/utils/watcher.ts +0 -19
|
@@ -1,30 +1,38 @@
|
|
|
1
|
-
import "./chunk
|
|
2
|
-
import { n as toCause, r as toError } from "./errors-
|
|
3
|
-
import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-
|
|
4
|
-
import { n as tokenize } from "./shell-
|
|
5
|
-
import { t as version } from "./package-
|
|
6
|
-
import { a as WATCHER_IGNORED_PATHS, i as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-
|
|
1
|
+
import "./chunk-BvFE5Tac.js";
|
|
2
|
+
import { n as toCause, r as toError } from "./errors-CINO1EIv.js";
|
|
3
|
+
import { a as canUseTTY, i as executeIfOnline, o as isGitHubActions, r as sendTelemetry, t as buildTelemetryEvent } from "./telemetry-BkektVz6.js";
|
|
4
|
+
import { n as tokenize } from "./shell-CN6DNqeC.js";
|
|
5
|
+
import { t as version } from "./package-OLYIpjqw.js";
|
|
6
|
+
import { a as WATCHER_IGNORED_PATHS, i as SUMMARY_SEPARATOR, t as KUBB_NPM_PACKAGE_URL } from "./constants-B2JTeRBb.js";
|
|
7
7
|
import { styleText } from "node:util";
|
|
8
8
|
import { EventEmitter } from "node:events";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
|
-
import "node:
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
import { readdirSync } from "node:fs";
|
|
11
12
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
12
13
|
import path, { dirname, relative, resolve } from "node:path";
|
|
13
14
|
import process$1 from "node:process";
|
|
14
15
|
import * as clack from "@clack/prompts";
|
|
15
|
-
import {
|
|
16
|
-
import { NonZeroExitError, x } from "tinyexec";
|
|
16
|
+
import { createKubb, defineLogger, isInputPath, logLevel } from "@kubb/core";
|
|
17
17
|
import { Writable } from "node:stream";
|
|
18
18
|
import { cosmiconfig } from "cosmiconfig";
|
|
19
19
|
import { createJiti } from "jiti";
|
|
20
|
+
import { NonZeroExitError, x } from "tinyexec";
|
|
20
21
|
//#region ../../internals/utils/src/asyncEventEmitter.ts
|
|
21
22
|
/**
|
|
22
|
-
*
|
|
23
|
+
* Typed `EventEmitter` that awaits all async listeners before resolving.
|
|
23
24
|
* Wraps Node's `EventEmitter` with full TypeScript event-map inference.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
|
|
29
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
30
|
+
* await emitter.emit('build', 'petstore') // all listeners awaited
|
|
31
|
+
* ```
|
|
24
32
|
*/
|
|
25
33
|
var AsyncEventEmitter = class {
|
|
26
34
|
/**
|
|
27
|
-
*
|
|
35
|
+
* Maximum number of listeners per event before Node emits a memory-leak warning.
|
|
28
36
|
* @default 10
|
|
29
37
|
*/
|
|
30
38
|
constructor(maxListener = 10) {
|
|
@@ -32,31 +40,48 @@ var AsyncEventEmitter = class {
|
|
|
32
40
|
}
|
|
33
41
|
#emitter = new EventEmitter();
|
|
34
42
|
/**
|
|
35
|
-
* Emits
|
|
43
|
+
* Emits `eventName` and awaits all registered listeners sequentially.
|
|
36
44
|
* Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* await emitter.emit('build', 'petstore')
|
|
49
|
+
* ```
|
|
37
50
|
*/
|
|
38
51
|
async emit(eventName, ...eventArgs) {
|
|
39
52
|
const listeners = this.#emitter.listeners(eventName);
|
|
40
53
|
if (listeners.length === 0) return;
|
|
41
|
-
|
|
54
|
+
for (const listener of listeners) try {
|
|
55
|
+
await listener(...eventArgs);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
let serializedArgs;
|
|
42
58
|
try {
|
|
43
|
-
|
|
44
|
-
} catch
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
serializedArgs = JSON.stringify(eventArgs);
|
|
48
|
-
} catch {
|
|
49
|
-
serializedArgs = String(eventArgs);
|
|
50
|
-
}
|
|
51
|
-
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
59
|
+
serializedArgs = JSON.stringify(eventArgs);
|
|
60
|
+
} catch {
|
|
61
|
+
serializedArgs = String(eventArgs);
|
|
52
62
|
}
|
|
53
|
-
|
|
63
|
+
throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
|
|
64
|
+
}
|
|
54
65
|
}
|
|
55
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Registers a persistent listener for `eventName`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* emitter.on('build', async (name) => { console.log(name) })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
56
74
|
on(eventName, handler) {
|
|
57
75
|
this.#emitter.on(eventName, handler);
|
|
58
76
|
}
|
|
59
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Registers a one-shot listener that removes itself after the first invocation.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* emitter.onOnce('build', async (name) => { console.log(name) })
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
60
85
|
onOnce(eventName, handler) {
|
|
61
86
|
const wrapper = (...args) => {
|
|
62
87
|
this.off(eventName, wrapper);
|
|
@@ -64,11 +89,37 @@ var AsyncEventEmitter = class {
|
|
|
64
89
|
};
|
|
65
90
|
this.on(eventName, wrapper);
|
|
66
91
|
}
|
|
67
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* Removes a previously registered listener.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* emitter.off('build', handler)
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
68
100
|
off(eventName, handler) {
|
|
69
101
|
this.#emitter.off(eventName, handler);
|
|
70
102
|
}
|
|
71
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Returns the number of listeners registered for `eventName`.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* emitter.on('build', handler)
|
|
109
|
+
* emitter.listenerCount('build') // 1
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
listenerCount(eventName) {
|
|
113
|
+
return this.#emitter.listenerCount(eventName);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Removes all listeners from every event channel.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* emitter.removeAll()
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
72
123
|
removeAll() {
|
|
73
124
|
this.#emitter.removeAllListeners();
|
|
74
125
|
}
|
|
@@ -76,8 +127,15 @@ var AsyncEventEmitter = class {
|
|
|
76
127
|
//#endregion
|
|
77
128
|
//#region ../../internals/utils/src/time.ts
|
|
78
129
|
/**
|
|
79
|
-
* Calculates elapsed time in milliseconds from a high-resolution start time.
|
|
80
|
-
* Rounds to 2 decimal places
|
|
130
|
+
* Calculates elapsed time in milliseconds from a high-resolution `process.hrtime` start time.
|
|
131
|
+
* Rounds to 2 decimal places for sub-millisecond precision without noise.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* const start = process.hrtime()
|
|
136
|
+
* doWork()
|
|
137
|
+
* getElapsedMs(start) // 42.35
|
|
138
|
+
* ```
|
|
81
139
|
*/
|
|
82
140
|
function getElapsedMs(hrStart) {
|
|
83
141
|
const [seconds, nanoseconds] = process.hrtime(hrStart);
|
|
@@ -85,8 +143,14 @@ function getElapsedMs(hrStart) {
|
|
|
85
143
|
return Math.round(ms * 100) / 100;
|
|
86
144
|
}
|
|
87
145
|
/**
|
|
88
|
-
* Converts a millisecond duration into a human-readable string.
|
|
89
|
-
*
|
|
146
|
+
* Converts a millisecond duration into a human-readable string (`ms`, `s`, or `m s`).
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* formatMs(250) // '250ms'
|
|
151
|
+
* formatMs(1500) // '1.50s'
|
|
152
|
+
* formatMs(90000) // '1m 30.0s'
|
|
153
|
+
* ```
|
|
90
154
|
*/
|
|
91
155
|
function formatMs(ms) {
|
|
92
156
|
if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
|
|
@@ -94,7 +158,14 @@ function formatMs(ms) {
|
|
|
94
158
|
return `${Math.round(ms)}ms`;
|
|
95
159
|
}
|
|
96
160
|
/**
|
|
97
|
-
*
|
|
161
|
+
* Formats the elapsed time since `hrStart` as a human-readable string.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* const start = process.hrtime()
|
|
166
|
+
* doWork()
|
|
167
|
+
* formatHrtime(start) // '1.50s'
|
|
168
|
+
* ```
|
|
98
169
|
*/
|
|
99
170
|
function formatHrtime(hrStart) {
|
|
100
171
|
return formatMs(getElapsedMs(hrStart));
|
|
@@ -136,18 +207,46 @@ function gradient(colorStops, text) {
|
|
|
136
207
|
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`;
|
|
137
208
|
}).join("");
|
|
138
209
|
}
|
|
139
|
-
/**
|
|
210
|
+
/**
|
|
211
|
+
* ANSI color functions for each part of the Kubb mascot illustration.
|
|
212
|
+
*/
|
|
140
213
|
const palette = {
|
|
214
|
+
/**
|
|
215
|
+
* Top cap of the skittle.
|
|
216
|
+
*/
|
|
141
217
|
lid: hex("#F55A17"),
|
|
218
|
+
/**
|
|
219
|
+
* Upper wood body.
|
|
220
|
+
*/
|
|
142
221
|
woodTop: hex("#F5A217"),
|
|
222
|
+
/**
|
|
223
|
+
* Middle wood body.
|
|
224
|
+
*/
|
|
143
225
|
woodMid: hex("#F58517"),
|
|
226
|
+
/**
|
|
227
|
+
* Base wood body.
|
|
228
|
+
*/
|
|
144
229
|
woodBase: hex("#B45309"),
|
|
230
|
+
/**
|
|
231
|
+
* Eye whites.
|
|
232
|
+
*/
|
|
145
233
|
eye: hex("#FFFFFF"),
|
|
234
|
+
/**
|
|
235
|
+
* Highlight accent.
|
|
236
|
+
*/
|
|
146
237
|
highlight: hex("#adadc6"),
|
|
238
|
+
/**
|
|
239
|
+
* Cheek blush.
|
|
240
|
+
*/
|
|
147
241
|
blush: hex("#FDA4AF")
|
|
148
242
|
};
|
|
149
243
|
/**
|
|
150
|
-
* Generates the Kubb mascot welcome banner.
|
|
244
|
+
* Generates the Kubb mascot welcome banner as an ANSI-colored string.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* console.log(getIntro({ title: 'kubb.config.ts', description: 'generating…', version: '5.0.0', areEyesOpen: true }))
|
|
249
|
+
* ```
|
|
151
250
|
*/
|
|
152
251
|
function getIntro({ title, description, version, areEyesOpen }) {
|
|
153
252
|
const kubbVersion = gradient([
|
|
@@ -165,7 +264,9 @@ function getIntro({ title, description, version, areEyesOpen }) {
|
|
|
165
264
|
${palette.woodBase("▀▀▀▀▀▀▀▀▀▀▀▀▀")}
|
|
166
265
|
`;
|
|
167
266
|
}
|
|
168
|
-
/**
|
|
267
|
+
/**
|
|
268
|
+
* ANSI color names used by {@link randomCliColor} for deterministic terminal coloring.
|
|
269
|
+
*/
|
|
169
270
|
const randomColors = [
|
|
170
271
|
"black",
|
|
171
272
|
"red",
|
|
@@ -178,15 +279,27 @@ const randomColors = [
|
|
|
178
279
|
"gray"
|
|
179
280
|
];
|
|
180
281
|
/**
|
|
181
|
-
*
|
|
282
|
+
* Wraps `text` in a deterministic ANSI color derived from the text's SHA-256 hash.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```ts
|
|
286
|
+
* randomCliColor('petstore') // '\x1b[33m' + 'petstore' + '\x1b[39m' (always the same color for 'petstore')
|
|
287
|
+
* ```
|
|
182
288
|
*/
|
|
183
289
|
function randomCliColor(text) {
|
|
184
290
|
if (!text) return "";
|
|
185
291
|
return styleText(randomColors[createHash("sha256").update(text).digest().readUInt32BE(0) % randomColors.length] ?? "white", text);
|
|
186
292
|
}
|
|
187
293
|
/**
|
|
188
|
-
* Formats a millisecond duration with
|
|
189
|
-
*
|
|
294
|
+
* Formats a millisecond duration with a threshold-based ANSI color.
|
|
295
|
+
* `≤ 500 ms` → green · `≤ 1 000 ms` → yellow · `> 1 000 ms` → red.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```ts
|
|
299
|
+
* formatMsWithColor(200) // '\x1b[32m200ms\x1b[39m'
|
|
300
|
+
* formatMsWithColor(800) // '\x1b[33m800ms\x1b[39m'
|
|
301
|
+
* formatMsWithColor(1500) // '\x1b[31m1.50s\x1b[39m'
|
|
302
|
+
* ```
|
|
190
303
|
*/
|
|
191
304
|
function formatMsWithColor(ms) {
|
|
192
305
|
const formatted = formatMs(ms);
|
|
@@ -195,27 +308,96 @@ function formatMsWithColor(ms) {
|
|
|
195
308
|
return styleText("red", formatted);
|
|
196
309
|
}
|
|
197
310
|
//#endregion
|
|
311
|
+
//#region ../../internals/utils/src/formatters.ts
|
|
312
|
+
/**
|
|
313
|
+
* CLI command descriptors for each supported code formatter.
|
|
314
|
+
*
|
|
315
|
+
* Each entry contains the executable `command`, an `args` factory that maps an
|
|
316
|
+
* output path to the correct argument list, and an `errorMessage` shown when
|
|
317
|
+
* the formatter is not found.
|
|
318
|
+
*/
|
|
319
|
+
const formatters = {
|
|
320
|
+
prettier: {
|
|
321
|
+
command: "prettier",
|
|
322
|
+
args: (outputPath) => [
|
|
323
|
+
"--ignore-unknown",
|
|
324
|
+
"--write",
|
|
325
|
+
outputPath
|
|
326
|
+
],
|
|
327
|
+
errorMessage: "Prettier not found"
|
|
328
|
+
},
|
|
329
|
+
biome: {
|
|
330
|
+
command: "biome",
|
|
331
|
+
args: (outputPath) => [
|
|
332
|
+
"format",
|
|
333
|
+
"--write",
|
|
334
|
+
outputPath
|
|
335
|
+
],
|
|
336
|
+
errorMessage: "Biome not found"
|
|
337
|
+
},
|
|
338
|
+
oxfmt: {
|
|
339
|
+
command: "oxfmt",
|
|
340
|
+
args: (outputPath) => [outputPath],
|
|
341
|
+
errorMessage: "Oxfmt not found"
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
async function isFormatterAvailable(formatter) {
|
|
345
|
+
return new Promise((resolve) => {
|
|
346
|
+
const child = spawn(formatter, ["--version"], { stdio: "ignore" });
|
|
347
|
+
child.on("close", (code) => resolve(code === 0));
|
|
348
|
+
child.on("error", () => resolve(false));
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Detects the first available code formatter on the current system.
|
|
353
|
+
*
|
|
354
|
+
* - Checks in preference order: `oxfmt`, `biome`, `prettier`.
|
|
355
|
+
* - Returns `null` when none are found.
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```ts
|
|
359
|
+
* const formatter = await detectFormatter()
|
|
360
|
+
* if (formatter) {
|
|
361
|
+
* console.log(`Using ${formatter} for formatting`)
|
|
362
|
+
* }
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
async function detectFormatter() {
|
|
366
|
+
const formatterNames = new Set([
|
|
367
|
+
"oxfmt",
|
|
368
|
+
"biome",
|
|
369
|
+
"prettier"
|
|
370
|
+
]);
|
|
371
|
+
for (const formatter of formatterNames) if (await isFormatterAvailable(formatter)) return formatter;
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
//#endregion
|
|
198
375
|
//#region ../../internals/utils/src/fs.ts
|
|
199
376
|
/**
|
|
200
377
|
* Writes `data` to `path`, trimming leading/trailing whitespace before saving.
|
|
201
|
-
* Skips the write
|
|
202
|
-
* identical to what is already on disk.
|
|
378
|
+
* Skips the write when the trimmed content is empty or identical to what is already on disk.
|
|
203
379
|
* Creates any missing parent directories automatically.
|
|
204
|
-
* When `sanity` is `true`, re-reads the file after writing and throws if the
|
|
205
|
-
*
|
|
380
|
+
* When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```ts
|
|
384
|
+
* await write('./src/Pet.ts', source) // writes and returns trimmed content
|
|
385
|
+
* await write('./src/Pet.ts', source) // null — file unchanged
|
|
386
|
+
* await write('./src/Pet.ts', ' ') // null — empty content skipped
|
|
387
|
+
* ```
|
|
206
388
|
*/
|
|
207
389
|
async function write(path, data, options = {}) {
|
|
208
390
|
const trimmed = data.trim();
|
|
209
|
-
if (trimmed === "") return
|
|
391
|
+
if (trimmed === "") return null;
|
|
210
392
|
const resolved = resolve(path);
|
|
211
393
|
if (typeof Bun !== "undefined") {
|
|
212
394
|
const file = Bun.file(resolved);
|
|
213
|
-
if ((await file.exists() ? await file.text() : null) === trimmed) return
|
|
395
|
+
if ((await file.exists() ? await file.text() : null) === trimmed) return null;
|
|
214
396
|
await Bun.write(resolved, trimmed);
|
|
215
397
|
return trimmed;
|
|
216
398
|
}
|
|
217
399
|
try {
|
|
218
|
-
if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return
|
|
400
|
+
if (await readFile(resolved, { encoding: "utf-8" }) === trimmed) return null;
|
|
219
401
|
} catch {}
|
|
220
402
|
await mkdir(dirname(resolved), { recursive: true });
|
|
221
403
|
await writeFile(resolved, trimmed, { encoding: "utf-8" });
|
|
@@ -227,102 +409,88 @@ async function write(path, data, options = {}) {
|
|
|
227
409
|
return trimmed;
|
|
228
410
|
}
|
|
229
411
|
//#endregion
|
|
230
|
-
//#region
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
pluginTimings: "Plugin Timings:",
|
|
247
|
-
output: "Output:"
|
|
248
|
-
};
|
|
249
|
-
const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
|
|
250
|
-
const summaryLines = [];
|
|
251
|
-
summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
|
|
252
|
-
if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
|
|
253
|
-
summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
|
|
254
|
-
if (pluginTimings && pluginTimings.size > 0) {
|
|
255
|
-
const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
|
|
256
|
-
summaryLines.push(`${labels.pluginTimings}`);
|
|
257
|
-
sortedTimings.forEach(([name, time]) => {
|
|
258
|
-
const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
|
|
259
|
-
const barLength = Math.min(Math.ceil(time / 100), 10);
|
|
260
|
-
const bar = styleText("dim", "█".repeat(barLength));
|
|
261
|
-
summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
|
|
262
|
-
});
|
|
412
|
+
//#region ../../internals/utils/src/linters.ts
|
|
413
|
+
/**
|
|
414
|
+
* Collects all files under `dir` recursively using Node's built-in fs APIs.
|
|
415
|
+
*
|
|
416
|
+
* Passing explicit file paths to oxlint (instead of a directory) bypasses
|
|
417
|
+
* oxlint's `.gitignore`-aware directory traversal, which would otherwise skip
|
|
418
|
+
* files that are listed in `.gitignore` (e.g. generated output directories).
|
|
419
|
+
*/
|
|
420
|
+
function findLintableFiles(dir) {
|
|
421
|
+
try {
|
|
422
|
+
return readdirSync(dir, {
|
|
423
|
+
withFileTypes: true,
|
|
424
|
+
recursive: true
|
|
425
|
+
}).filter((d) => d.isFile()).map((d) => `${d.parentPath}/${d.name}`);
|
|
426
|
+
} catch {
|
|
427
|
+
return [];
|
|
263
428
|
}
|
|
264
|
-
summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
|
|
265
|
-
return summaryLines;
|
|
266
429
|
}
|
|
267
|
-
//#endregion
|
|
268
|
-
//#region src/utils/runHook.ts
|
|
269
430
|
/**
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
431
|
+
* CLI command descriptors for each supported linter.
|
|
432
|
+
*
|
|
433
|
+
* Each entry contains the executable `command`, an `args` factory that maps an
|
|
434
|
+
* output path to the correct argument list, and an `errorMessage` shown when
|
|
435
|
+
* the linter is not found.
|
|
273
436
|
*/
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
} catch (err) {
|
|
294
|
-
if (!(err instanceof NonZeroExitError)) {
|
|
295
|
-
await context.emit("hook:end", {
|
|
296
|
-
command,
|
|
297
|
-
args,
|
|
298
|
-
id,
|
|
299
|
-
success: false,
|
|
300
|
-
error: toError(err)
|
|
301
|
-
});
|
|
302
|
-
await context.emit("error", toError(err));
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
const stderr = err.output?.stderr ?? "";
|
|
306
|
-
const stdout = err.output?.stdout ?? "";
|
|
307
|
-
await context.emit("debug", {
|
|
308
|
-
date: /* @__PURE__ */ new Date(),
|
|
309
|
-
logs: [stdout, stderr].filter(Boolean)
|
|
310
|
-
});
|
|
311
|
-
if (stderr) sink?.onStderr?.(stderr);
|
|
312
|
-
if (stdout) sink?.onStdout?.(stdout);
|
|
313
|
-
const errorMessage = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
|
|
314
|
-
await context.emit("hook:end", {
|
|
315
|
-
command,
|
|
316
|
-
args,
|
|
317
|
-
id,
|
|
318
|
-
success: false,
|
|
319
|
-
error: errorMessage
|
|
320
|
-
});
|
|
321
|
-
await context.emit("error", errorMessage);
|
|
437
|
+
const linters = {
|
|
438
|
+
eslint: {
|
|
439
|
+
command: "eslint",
|
|
440
|
+
args: (outputPath) => [outputPath, "--fix"],
|
|
441
|
+
errorMessage: "Eslint not found"
|
|
442
|
+
},
|
|
443
|
+
biome: {
|
|
444
|
+
command: "biome",
|
|
445
|
+
args: (outputPath) => [
|
|
446
|
+
"lint",
|
|
447
|
+
"--fix",
|
|
448
|
+
outputPath
|
|
449
|
+
],
|
|
450
|
+
errorMessage: "Biome not found"
|
|
451
|
+
},
|
|
452
|
+
oxlint: {
|
|
453
|
+
command: "oxlint",
|
|
454
|
+
args: (outputPath) => ["--fix", ...findLintableFiles(outputPath)],
|
|
455
|
+
errorMessage: "Oxlint not found"
|
|
322
456
|
}
|
|
457
|
+
};
|
|
458
|
+
async function isLinterAvailable(linter) {
|
|
459
|
+
return new Promise((resolve) => {
|
|
460
|
+
const child = spawn(linter, ["--version"], { stdio: "ignore" });
|
|
461
|
+
child.on("close", (code) => resolve(code === 0));
|
|
462
|
+
child.on("error", () => resolve(false));
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Detects the first available linter on the current system.
|
|
467
|
+
*
|
|
468
|
+
* - Checks in preference order: `oxlint`, `biome`, `eslint`.
|
|
469
|
+
* - Returns `null` when none are found.
|
|
470
|
+
*
|
|
471
|
+
* @example
|
|
472
|
+
* ```ts
|
|
473
|
+
* const linter = await detectLinter()
|
|
474
|
+
* if (linter) {
|
|
475
|
+
* console.log(`Using ${linter} for linting`)
|
|
476
|
+
* }
|
|
477
|
+
* ```
|
|
478
|
+
*/
|
|
479
|
+
async function detectLinter() {
|
|
480
|
+
const linterNames = new Set([
|
|
481
|
+
"oxlint",
|
|
482
|
+
"biome",
|
|
483
|
+
"eslint"
|
|
484
|
+
]);
|
|
485
|
+
for (const linter of linterNames) if (await isLinterAvailable(linter)) return linter;
|
|
486
|
+
return null;
|
|
323
487
|
}
|
|
324
488
|
//#endregion
|
|
325
|
-
//#region src/
|
|
489
|
+
//#region src/loggers/clackLogger.ts
|
|
490
|
+
/**
|
|
491
|
+
* Node.js `Writable` stream that forwards each chunk to a clack `taskLog` message.
|
|
492
|
+
* Used to pipe hook subprocess output into the clack task log UI.
|
|
493
|
+
*/
|
|
326
494
|
var ClackWritable = class extends Writable {
|
|
327
495
|
taskLog;
|
|
328
496
|
constructor(taskLog, opts) {
|
|
@@ -334,11 +502,8 @@ var ClackWritable = class extends Writable {
|
|
|
334
502
|
callback();
|
|
335
503
|
}
|
|
336
504
|
};
|
|
337
|
-
//#endregion
|
|
338
|
-
//#region src/loggers/clackLogger.ts
|
|
339
505
|
/**
|
|
340
|
-
*
|
|
341
|
-
* Provides a beautiful CLI UI with flat structure inspired by Claude's CLI patterns
|
|
506
|
+
* TTY logger with beautiful UI and progress indicators for local development.
|
|
342
507
|
*/
|
|
343
508
|
const clackLogger = defineLogger({
|
|
344
509
|
name: "clack",
|
|
@@ -386,7 +551,7 @@ const clackLogger = defineLogger({
|
|
|
386
551
|
state.spinner.stop(text);
|
|
387
552
|
state.isSpinning = false;
|
|
388
553
|
}
|
|
389
|
-
context.on("info", (message, info = "") => {
|
|
554
|
+
context.on("kubb:info", ({ message, info = "" }) => {
|
|
390
555
|
if (logLevel$8 <= logLevel.silent) return;
|
|
391
556
|
const text = getMessage([
|
|
392
557
|
styleText("blue", "ℹ"),
|
|
@@ -396,7 +561,7 @@ const clackLogger = defineLogger({
|
|
|
396
561
|
if (state.isSpinning) state.spinner.message(text);
|
|
397
562
|
else clack.log.info(text);
|
|
398
563
|
});
|
|
399
|
-
context.on("success", (message, info = "") => {
|
|
564
|
+
context.on("kubb:success", ({ message, info = "" }) => {
|
|
400
565
|
if (logLevel$8 <= logLevel.silent) return;
|
|
401
566
|
const text = getMessage([
|
|
402
567
|
styleText("blue", "✓"),
|
|
@@ -406,7 +571,7 @@ const clackLogger = defineLogger({
|
|
|
406
571
|
if (state.isSpinning) stopSpinner(text);
|
|
407
572
|
else clack.log.success(text);
|
|
408
573
|
});
|
|
409
|
-
context.on("warn", (message, info) => {
|
|
574
|
+
context.on("kubb:warn", ({ message, info }) => {
|
|
410
575
|
if (logLevel$8 < logLevel.warn) return;
|
|
411
576
|
const text = getMessage([
|
|
412
577
|
styleText("yellow", "⚠"),
|
|
@@ -415,7 +580,7 @@ const clackLogger = defineLogger({
|
|
|
415
580
|
].filter(Boolean).join(" "));
|
|
416
581
|
clack.log.warn(text);
|
|
417
582
|
});
|
|
418
|
-
context.on("error", (error) => {
|
|
583
|
+
context.on("kubb:error", ({ error }) => {
|
|
419
584
|
const caused = toCause(error);
|
|
420
585
|
const text = [styleText("red", "✗"), error.message].join(" ");
|
|
421
586
|
if (state.isSpinning) stopSpinner(getMessage(text));
|
|
@@ -430,19 +595,24 @@ const clackLogger = defineLogger({
|
|
|
430
595
|
}
|
|
431
596
|
}
|
|
432
597
|
});
|
|
433
|
-
context.on("version:new", (
|
|
598
|
+
context.on("kubb:version:new", ({ currentVersion, latestVersion }) => {
|
|
434
599
|
if (logLevel$8 <= logLevel.silent) return;
|
|
435
|
-
|
|
600
|
+
try {
|
|
601
|
+
clack.box(`\`v${currentVersion}\` → \`v${latestVersion}\`
|
|
436
602
|
Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
603
|
+
width: "auto",
|
|
604
|
+
formatBorder: (s) => styleText("yellow", s),
|
|
605
|
+
rounded: true,
|
|
606
|
+
withGuide: false,
|
|
607
|
+
contentAlign: "center",
|
|
608
|
+
titleAlign: "center"
|
|
609
|
+
});
|
|
610
|
+
} catch {
|
|
611
|
+
console.log(`Update available for Kubb: v${currentVersion} → v${latestVersion}`);
|
|
612
|
+
console.log("Run `npm install -g @kubb/cli` to update");
|
|
613
|
+
}
|
|
444
614
|
});
|
|
445
|
-
context.on("lifecycle:start", async (version) => {
|
|
615
|
+
context.on("kubb:lifecycle:start", async ({ version }) => {
|
|
446
616
|
console.log(`\n${getIntro({
|
|
447
617
|
title: "The ultimate toolkit for working with APIs",
|
|
448
618
|
description: "Ready to start",
|
|
@@ -451,24 +621,24 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
451
621
|
})}\n`);
|
|
452
622
|
reset();
|
|
453
623
|
});
|
|
454
|
-
context.on("config:start", () => {
|
|
624
|
+
context.on("kubb:config:start", () => {
|
|
455
625
|
if (logLevel$8 <= logLevel.silent) return;
|
|
456
626
|
const text = getMessage("Configuration started");
|
|
457
627
|
clack.intro(text);
|
|
458
628
|
startSpinner(getMessage("Configuration loading"));
|
|
459
629
|
});
|
|
460
|
-
context.on("config:end", (
|
|
630
|
+
context.on("kubb:config:end", () => {
|
|
461
631
|
if (logLevel$8 <= logLevel.silent) return;
|
|
462
632
|
const text = getMessage("Configuration completed");
|
|
463
633
|
clack.outro(text);
|
|
464
634
|
});
|
|
465
|
-
context.on("generation:start", (config) => {
|
|
635
|
+
context.on("kubb:generation:start", ({ config }) => {
|
|
466
636
|
reset();
|
|
467
637
|
state.totalPlugins = config.plugins?.length ?? 0;
|
|
468
638
|
const text = getMessage(["Generation started", config.name ? `for ${styleText("dim", config.name)}` : void 0].filter(Boolean).join(" "));
|
|
469
639
|
clack.intro(text);
|
|
470
640
|
});
|
|
471
|
-
context.on("plugin:start", (plugin) => {
|
|
641
|
+
context.on("kubb:plugin:start", ({ plugin }) => {
|
|
472
642
|
if (logLevel$8 <= logLevel.silent) return;
|
|
473
643
|
stopSpinner();
|
|
474
644
|
const progressBar = clack.progress({
|
|
@@ -486,7 +656,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
486
656
|
interval
|
|
487
657
|
});
|
|
488
658
|
});
|
|
489
|
-
context.on("plugin:end", (plugin,
|
|
659
|
+
context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
|
|
490
660
|
stopSpinner();
|
|
491
661
|
const active = state.activeProgress.get(plugin.name);
|
|
492
662
|
if (!active || logLevel$8 === logLevel.silent) return;
|
|
@@ -499,7 +669,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
499
669
|
state.activeProgress.delete(plugin.name);
|
|
500
670
|
showProgressStep();
|
|
501
671
|
});
|
|
502
|
-
context.on("files:processing:start", (files) => {
|
|
672
|
+
context.on("kubb:files:processing:start", ({ files }) => {
|
|
503
673
|
if (logLevel$8 <= logLevel.silent) return;
|
|
504
674
|
stopSpinner();
|
|
505
675
|
state.totalFiles = files.length;
|
|
@@ -510,11 +680,11 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
510
680
|
max: files.length,
|
|
511
681
|
size: 30
|
|
512
682
|
});
|
|
513
|
-
context.emit("info", text);
|
|
683
|
+
context.emit("kubb:info", { message: text });
|
|
514
684
|
progressBar.start(getMessage(text));
|
|
515
685
|
state.activeProgress.set("files", { progressBar });
|
|
516
686
|
});
|
|
517
|
-
context.on("file:processing:update", ({ file, config }) => {
|
|
687
|
+
context.on("kubb:file:processing:update", ({ file, config }) => {
|
|
518
688
|
if (logLevel$8 <= logLevel.silent) return;
|
|
519
689
|
stopSpinner();
|
|
520
690
|
state.processedFiles++;
|
|
@@ -523,7 +693,7 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
523
693
|
if (!active) return;
|
|
524
694
|
active.progressBar.advance(void 0, text);
|
|
525
695
|
});
|
|
526
|
-
context.on("files:processing:end", () => {
|
|
696
|
+
context.on("kubb:files:processing:end", () => {
|
|
527
697
|
if (logLevel$8 <= logLevel.silent) return;
|
|
528
698
|
stopSpinner();
|
|
529
699
|
const text = getMessage("Files written successfully");
|
|
@@ -533,71 +703,41 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
533
703
|
state.activeProgress.delete("files");
|
|
534
704
|
showProgressStep();
|
|
535
705
|
});
|
|
536
|
-
context.on("generation:end", (config) => {
|
|
706
|
+
context.on("kubb:generation:end", ({ config }) => {
|
|
537
707
|
const text = getMessage(config.name ? `Generation completed for ${styleText("dim", config.name)}` : "Generation completed");
|
|
538
708
|
clack.outro(text);
|
|
539
709
|
});
|
|
540
|
-
context.on("format:start", () => {
|
|
710
|
+
context.on("kubb:format:start", () => {
|
|
541
711
|
if (logLevel$8 <= logLevel.silent) return;
|
|
542
712
|
const text = getMessage("Format started");
|
|
543
713
|
clack.intro(text);
|
|
544
714
|
});
|
|
545
|
-
context.on("format:end", () => {
|
|
715
|
+
context.on("kubb:format:end", () => {
|
|
546
716
|
if (logLevel$8 <= logLevel.silent) return;
|
|
547
717
|
const text = getMessage("Format completed");
|
|
548
718
|
clack.outro(text);
|
|
549
719
|
});
|
|
550
|
-
context.on("lint:start", () => {
|
|
720
|
+
context.on("kubb:lint:start", () => {
|
|
551
721
|
if (logLevel$8 <= logLevel.silent) return;
|
|
552
722
|
const text = getMessage("Lint started");
|
|
553
723
|
clack.intro(text);
|
|
554
724
|
});
|
|
555
|
-
context.on("lint:end", () => {
|
|
725
|
+
context.on("kubb:lint:end", () => {
|
|
556
726
|
if (logLevel$8 <= logLevel.silent) return;
|
|
557
727
|
const text = getMessage("Lint completed");
|
|
558
728
|
clack.outro(text);
|
|
559
729
|
});
|
|
560
|
-
context.on("hook:start",
|
|
561
|
-
|
|
562
|
-
const text = getMessage(`Hook ${styleText("dim",
|
|
563
|
-
if (!id) return;
|
|
564
|
-
if (logLevel$8 <= logLevel.silent) {
|
|
565
|
-
await runHook({
|
|
566
|
-
id,
|
|
567
|
-
command,
|
|
568
|
-
args,
|
|
569
|
-
commandWithArgs,
|
|
570
|
-
context,
|
|
571
|
-
sink: {
|
|
572
|
-
onStderr: (s) => console.error(s),
|
|
573
|
-
onStdout: (s) => console.log(s)
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
730
|
+
context.on("kubb:hook:start", ({ command, args }) => {
|
|
731
|
+
if (logLevel$8 <= logLevel.silent) return;
|
|
732
|
+
const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} started`);
|
|
578
733
|
clack.intro(text);
|
|
579
|
-
const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
|
|
580
|
-
const writable = new ClackWritable(logger);
|
|
581
|
-
await runHook({
|
|
582
|
-
id,
|
|
583
|
-
command,
|
|
584
|
-
args,
|
|
585
|
-
commandWithArgs,
|
|
586
|
-
context,
|
|
587
|
-
stream: true,
|
|
588
|
-
sink: {
|
|
589
|
-
onLine: (line) => writable.write(line),
|
|
590
|
-
onStderr: (s) => logger.error(s),
|
|
591
|
-
onStdout: (s) => logger.message(s)
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
734
|
});
|
|
595
|
-
context.on("hook:end", ({ command, args }) => {
|
|
735
|
+
context.on("kubb:hook:end", ({ command, args }) => {
|
|
596
736
|
if (logLevel$8 <= logLevel.silent) return;
|
|
597
737
|
const text = getMessage(`Hook ${styleText("dim", formatCommandWithArgs(command, args))} successfully executed`);
|
|
598
738
|
clack.outro(text);
|
|
599
739
|
});
|
|
600
|
-
context.on("generation:summary", (config,
|
|
740
|
+
context.on("kubb:generation:summary", ({ config, pluginTimings, failedPlugins, filesCreated, status, hrStart }) => {
|
|
601
741
|
const summary = getSummary({
|
|
602
742
|
failedPlugins,
|
|
603
743
|
filesCreated,
|
|
@@ -610,28 +750,44 @@ Run \`npm install -g @kubb/cli\` to update`, "Update available for `Kubb`", {
|
|
|
610
750
|
summary.unshift("\n");
|
|
611
751
|
summary.push("\n");
|
|
612
752
|
const borderColor = status === "success" ? "green" : "red";
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
753
|
+
try {
|
|
754
|
+
clack.box(summary.join("\n"), getMessage(title), {
|
|
755
|
+
width: "auto",
|
|
756
|
+
formatBorder: (s) => styleText(borderColor, s),
|
|
757
|
+
rounded: true,
|
|
758
|
+
withGuide: false,
|
|
759
|
+
contentAlign: "left",
|
|
760
|
+
titleAlign: "center"
|
|
761
|
+
});
|
|
762
|
+
} catch {
|
|
763
|
+
console.log(summary.join("\n"));
|
|
764
|
+
}
|
|
621
765
|
});
|
|
622
|
-
context.on("lifecycle:end", () => {
|
|
766
|
+
context.on("kubb:lifecycle:end", () => {
|
|
623
767
|
reset();
|
|
624
768
|
});
|
|
769
|
+
return (commandWithArgs) => {
|
|
770
|
+
if (logLevel$8 <= logLevel.silent) return {
|
|
771
|
+
onStdout: (s) => console.log(s),
|
|
772
|
+
onStderr: (s) => console.error(s)
|
|
773
|
+
};
|
|
774
|
+
const logger = clack.taskLog({ title: getMessage(["Executing hook", logLevel$8 >= logLevel.info ? styleText("dim", commandWithArgs) : void 0].filter(Boolean).join(" ")) });
|
|
775
|
+
const writable = new ClackWritable(logger);
|
|
776
|
+
return {
|
|
777
|
+
stream: true,
|
|
778
|
+
onLine: (line) => writable.write(line),
|
|
779
|
+
onStdout: (s) => logger.message(s),
|
|
780
|
+
onStderr: (s) => logger.error(s)
|
|
781
|
+
};
|
|
782
|
+
};
|
|
625
783
|
}
|
|
626
784
|
});
|
|
627
785
|
//#endregion
|
|
628
786
|
//#region src/loggers/fileSystemLogger.ts
|
|
629
787
|
/**
|
|
630
|
-
* FileSystem logger
|
|
631
|
-
* Captures debug and verbose events and writes them to files in .kubb directory
|
|
788
|
+
* FileSystem logger that captures debug events and writes them to `.kubb` directory files.
|
|
632
789
|
*
|
|
633
|
-
*
|
|
634
|
-
* before these events, some cached logs may be lost.
|
|
790
|
+
* @note Logs are written on `kubb:lifecycle:end` or process exit. Cached logs may be lost if the process crashes before either event.
|
|
635
791
|
*/
|
|
636
792
|
const fileSystemLogger = defineLogger({
|
|
637
793
|
name: "filesystem",
|
|
@@ -656,67 +812,73 @@ const fileSystemLogger = defineLogger({
|
|
|
656
812
|
const pathName = resolve(process$1.cwd(), ".kubb", baseName);
|
|
657
813
|
if (!files[pathName]) files[pathName] = [];
|
|
658
814
|
if (log.logs.length > 0) {
|
|
659
|
-
const
|
|
660
|
-
|
|
815
|
+
const prefix = `[${log.date.toLocaleString()}] `;
|
|
816
|
+
const indent = " ".repeat(prefix.length);
|
|
817
|
+
const [first, ...rest] = log.logs;
|
|
818
|
+
files[pathName].push([prefix + first, ...rest.map((line) => indent + line)].join("\n"));
|
|
661
819
|
}
|
|
662
820
|
}
|
|
663
|
-
|
|
821
|
+
for (const [fileName, logs] of Object.entries(files)) await write(fileName, logs.join("\n"));
|
|
664
822
|
return Object.keys(files);
|
|
665
823
|
}
|
|
666
|
-
context.on("info", (message, info) => {
|
|
824
|
+
context.on("kubb:info", ({ message, info }) => {
|
|
667
825
|
state.cachedLogs.add({
|
|
668
826
|
date: /* @__PURE__ */ new Date(),
|
|
669
|
-
logs: [`ℹ ${message
|
|
827
|
+
logs: [`ℹ ${[message, info].filter(Boolean).join(" ")}`]
|
|
670
828
|
});
|
|
671
829
|
});
|
|
672
|
-
context.on("success", (message, info) => {
|
|
830
|
+
context.on("kubb:success", ({ message, info }) => {
|
|
673
831
|
state.cachedLogs.add({
|
|
674
832
|
date: /* @__PURE__ */ new Date(),
|
|
675
|
-
logs: [`✓ ${message
|
|
833
|
+
logs: [`✓ ${[message, info].filter(Boolean).join(" ")}`]
|
|
676
834
|
});
|
|
677
835
|
});
|
|
678
|
-
context.on("warn", (message, info) => {
|
|
836
|
+
context.on("kubb:warn", ({ message, info }) => {
|
|
679
837
|
state.cachedLogs.add({
|
|
680
838
|
date: /* @__PURE__ */ new Date(),
|
|
681
|
-
logs: [`⚠ ${message
|
|
839
|
+
logs: [`⚠ ${[message, info].filter(Boolean).join(" ")}`]
|
|
682
840
|
});
|
|
683
841
|
});
|
|
684
|
-
context.on("error", (error) => {
|
|
842
|
+
context.on("kubb:error", ({ error }) => {
|
|
685
843
|
state.cachedLogs.add({
|
|
686
844
|
date: /* @__PURE__ */ new Date(),
|
|
687
845
|
logs: [`✗ ${error.message}`, error.stack || "unknown stack"]
|
|
688
846
|
});
|
|
689
847
|
});
|
|
690
|
-
context.on("debug", (
|
|
848
|
+
context.on("kubb:debug", ({ date, fileName, logs }) => {
|
|
691
849
|
state.cachedLogs.add({
|
|
692
|
-
date
|
|
693
|
-
|
|
850
|
+
date,
|
|
851
|
+
fileName,
|
|
852
|
+
logs
|
|
694
853
|
});
|
|
695
854
|
});
|
|
696
|
-
context.on("plugin:start", (plugin) => {
|
|
855
|
+
context.on("kubb:plugin:start", ({ plugin }) => {
|
|
697
856
|
state.cachedLogs.add({
|
|
698
857
|
date: /* @__PURE__ */ new Date(),
|
|
699
|
-
logs: [
|
|
858
|
+
logs: [`► Generating ${plugin.name}`]
|
|
700
859
|
});
|
|
701
860
|
});
|
|
702
|
-
context.on("plugin:end", (plugin,
|
|
861
|
+
context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
|
|
703
862
|
const durationStr = formatMs(duration);
|
|
704
863
|
state.cachedLogs.add({
|
|
705
864
|
date: /* @__PURE__ */ new Date(),
|
|
706
|
-
logs: [success ?
|
|
865
|
+
logs: [success ? `✓ ${plugin.name} completed in ${durationStr}` : `✗ ${plugin.name} failed in ${durationStr}`]
|
|
707
866
|
});
|
|
708
867
|
});
|
|
709
|
-
context.on("files:processing:start", (files) => {
|
|
868
|
+
context.on("kubb:files:processing:start", ({ files }) => {
|
|
710
869
|
state.cachedLogs.add({
|
|
711
870
|
date: /* @__PURE__ */ new Date(),
|
|
712
|
-
logs: [
|
|
871
|
+
logs: [`► Writing ${files.length} files`, ...files.map((file) => ` ${file.path}`)]
|
|
713
872
|
});
|
|
714
873
|
});
|
|
715
|
-
context.on("generation:end", async (config) => {
|
|
874
|
+
context.on("kubb:generation:end", async ({ config }) => {
|
|
716
875
|
const writtenFilePaths = await writeLogs(config.name);
|
|
717
876
|
if (writtenFilePaths.length > 0) {
|
|
718
877
|
const files = writtenFilePaths.map((f) => relative(process$1.cwd(), f));
|
|
719
|
-
await context.emit("info",
|
|
878
|
+
await context.emit("kubb:info", {
|
|
879
|
+
message: "Debug files written to:",
|
|
880
|
+
info: files.join(", ")
|
|
881
|
+
});
|
|
720
882
|
}
|
|
721
883
|
reset();
|
|
722
884
|
});
|
|
@@ -731,8 +893,7 @@ const fileSystemLogger = defineLogger({
|
|
|
731
893
|
//#endregion
|
|
732
894
|
//#region src/loggers/githubActionsLogger.ts
|
|
733
895
|
/**
|
|
734
|
-
* GitHub Actions
|
|
735
|
-
* Uses Github group annotations for collapsible sections
|
|
896
|
+
* GitHub Actions logger using group annotations for collapsible sections in CI.
|
|
736
897
|
*/
|
|
737
898
|
const githubActionsLogger = defineLogger({
|
|
738
899
|
name: "github-actions",
|
|
@@ -770,7 +931,7 @@ const githubActionsLogger = defineLogger({
|
|
|
770
931
|
function closeGroup(_name) {
|
|
771
932
|
console.log("::endgroup::");
|
|
772
933
|
}
|
|
773
|
-
context.on("info", (message, info = "") => {
|
|
934
|
+
context.on("kubb:info", ({ message, info = "" }) => {
|
|
774
935
|
if (logLevel$7 <= logLevel.silent) return;
|
|
775
936
|
const text = getMessage([
|
|
776
937
|
styleText("blue", "ℹ"),
|
|
@@ -779,7 +940,7 @@ const githubActionsLogger = defineLogger({
|
|
|
779
940
|
].join(" "));
|
|
780
941
|
console.log(text);
|
|
781
942
|
});
|
|
782
|
-
context.on("success", (message, info = "") => {
|
|
943
|
+
context.on("kubb:success", ({ message, info = "" }) => {
|
|
783
944
|
if (logLevel$7 <= logLevel.silent) return;
|
|
784
945
|
const text = getMessage([
|
|
785
946
|
styleText("blue", "✓"),
|
|
@@ -788,7 +949,7 @@ const githubActionsLogger = defineLogger({
|
|
|
788
949
|
].filter(Boolean).join(" "));
|
|
789
950
|
console.log(text);
|
|
790
951
|
});
|
|
791
|
-
context.on("warn", (message, info = "") => {
|
|
952
|
+
context.on("kubb:warn", ({ message, info = "" }) => {
|
|
792
953
|
if (logLevel$7 <= logLevel.silent) return;
|
|
793
954
|
const text = getMessage([
|
|
794
955
|
styleText("yellow", "⚠"),
|
|
@@ -797,7 +958,7 @@ const githubActionsLogger = defineLogger({
|
|
|
797
958
|
].filter(Boolean).join(" "));
|
|
798
959
|
console.warn(`::warning::${text}`);
|
|
799
960
|
});
|
|
800
|
-
context.on("error", (error) => {
|
|
961
|
+
context.on("kubb:error", ({ error }) => {
|
|
801
962
|
const caused = toCause(error);
|
|
802
963
|
if (logLevel$7 <= logLevel.silent) return;
|
|
803
964
|
const message = error.message || String(error);
|
|
@@ -812,37 +973,37 @@ const githubActionsLogger = defineLogger({
|
|
|
812
973
|
}
|
|
813
974
|
}
|
|
814
975
|
});
|
|
815
|
-
context.on("lifecycle:start", (version) => {
|
|
976
|
+
context.on("kubb:lifecycle:start", ({ version }) => {
|
|
816
977
|
console.log(styleText("yellow", `Kubb ${version} 🧩`));
|
|
817
978
|
reset();
|
|
818
979
|
});
|
|
819
|
-
context.on("config:start", () => {
|
|
980
|
+
context.on("kubb:config:start", () => {
|
|
820
981
|
if (logLevel$7 <= logLevel.silent) return;
|
|
821
982
|
const text = getMessage("Configuration started");
|
|
822
983
|
openGroup("Configuration");
|
|
823
984
|
console.log(text);
|
|
824
985
|
});
|
|
825
|
-
context.on("config:end", (configs) => {
|
|
986
|
+
context.on("kubb:config:end", ({ configs }) => {
|
|
826
987
|
state.currentConfigs = configs;
|
|
827
988
|
if (logLevel$7 <= logLevel.silent) return;
|
|
828
989
|
const text = getMessage("Configuration completed");
|
|
829
990
|
console.log(text);
|
|
830
991
|
closeGroup("Configuration");
|
|
831
992
|
});
|
|
832
|
-
context.on("generation:start", (config) => {
|
|
993
|
+
context.on("kubb:generation:start", ({ config }) => {
|
|
833
994
|
reset();
|
|
834
995
|
state.totalPlugins = config.plugins?.length ?? 0;
|
|
835
996
|
const text = config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation";
|
|
836
997
|
if (state.currentConfigs.length > 1) openGroup(text);
|
|
837
998
|
if (state.currentConfigs.length === 1) console.log(getMessage(text));
|
|
838
999
|
});
|
|
839
|
-
context.on("plugin:start", (plugin) => {
|
|
1000
|
+
context.on("kubb:plugin:start", ({ plugin }) => {
|
|
840
1001
|
if (logLevel$7 <= logLevel.silent) return;
|
|
841
1002
|
const text = getMessage(`Generating ${styleText("bold", plugin.name)}`);
|
|
842
1003
|
if (state.currentConfigs.length === 1) openGroup(`Plugin: ${plugin.name}`);
|
|
843
1004
|
console.log(text);
|
|
844
1005
|
});
|
|
845
|
-
context.on("plugin:end", (plugin,
|
|
1006
|
+
context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
|
|
846
1007
|
if (logLevel$7 <= logLevel.silent) return;
|
|
847
1008
|
if (success) state.completedPlugins++;
|
|
848
1009
|
else state.failedPlugins++;
|
|
@@ -853,7 +1014,7 @@ const githubActionsLogger = defineLogger({
|
|
|
853
1014
|
if (state.currentConfigs.length === 1) closeGroup(`Plugin: ${plugin.name}`);
|
|
854
1015
|
showProgressStep();
|
|
855
1016
|
});
|
|
856
|
-
context.on("files:processing:start", (files) => {
|
|
1017
|
+
context.on("kubb:files:processing:start", ({ files }) => {
|
|
857
1018
|
if (logLevel$7 <= logLevel.silent) return;
|
|
858
1019
|
state.totalFiles = files.length;
|
|
859
1020
|
state.processedFiles = 0;
|
|
@@ -861,73 +1022,60 @@ const githubActionsLogger = defineLogger({
|
|
|
861
1022
|
const text = getMessage(`Writing ${files.length} files`);
|
|
862
1023
|
console.log(text);
|
|
863
1024
|
});
|
|
864
|
-
context.on("files:processing:end", () => {
|
|
1025
|
+
context.on("kubb:files:processing:end", () => {
|
|
865
1026
|
if (logLevel$7 <= logLevel.silent) return;
|
|
866
1027
|
const text = getMessage("Files written successfully");
|
|
867
1028
|
console.log(text);
|
|
868
1029
|
if (state.currentConfigs.length === 1) closeGroup("File Generation");
|
|
869
1030
|
showProgressStep();
|
|
870
1031
|
});
|
|
871
|
-
context.on("file:processing:update", () => {
|
|
1032
|
+
context.on("kubb:file:processing:update", () => {
|
|
872
1033
|
if (logLevel$7 <= logLevel.silent) return;
|
|
873
1034
|
state.processedFiles++;
|
|
874
1035
|
});
|
|
875
|
-
context.on("generation:end", (config) => {
|
|
1036
|
+
context.on("kubb:generation:end", ({ config }) => {
|
|
876
1037
|
const text = getMessage(config.name ? `${styleText("blue", "✓")} Generation completed for ${styleText("dim", config.name)}` : `${styleText("blue", "✓")} Generation completed`);
|
|
877
1038
|
console.log(text);
|
|
878
1039
|
});
|
|
879
|
-
context.on("format:start", () => {
|
|
1040
|
+
context.on("kubb:format:start", () => {
|
|
880
1041
|
if (logLevel$7 <= logLevel.silent) return;
|
|
881
1042
|
const text = getMessage("Format started");
|
|
882
1043
|
if (state.currentConfigs.length === 1) openGroup("Formatting");
|
|
883
1044
|
console.log(text);
|
|
884
1045
|
});
|
|
885
|
-
context.on("format:end", () => {
|
|
1046
|
+
context.on("kubb:format:end", () => {
|
|
886
1047
|
if (logLevel$7 <= logLevel.silent) return;
|
|
887
1048
|
const text = getMessage("Format completed");
|
|
888
1049
|
console.log(text);
|
|
889
1050
|
if (state.currentConfigs.length === 1) closeGroup("Formatting");
|
|
890
1051
|
});
|
|
891
|
-
context.on("lint:start", () => {
|
|
1052
|
+
context.on("kubb:lint:start", () => {
|
|
892
1053
|
if (logLevel$7 <= logLevel.silent) return;
|
|
893
1054
|
const text = getMessage("Lint started");
|
|
894
1055
|
if (state.currentConfigs.length === 1) openGroup("Linting");
|
|
895
1056
|
console.log(text);
|
|
896
1057
|
});
|
|
897
|
-
context.on("lint:end", () => {
|
|
1058
|
+
context.on("kubb:lint:end", () => {
|
|
898
1059
|
if (logLevel$7 <= logLevel.silent) return;
|
|
899
1060
|
const text = getMessage("Lint completed");
|
|
900
1061
|
console.log(text);
|
|
901
1062
|
if (state.currentConfigs.length === 1) closeGroup("Linting");
|
|
902
1063
|
});
|
|
903
|
-
context.on("hook:start",
|
|
1064
|
+
context.on("kubb:hook:start", ({ command, args }) => {
|
|
1065
|
+
if (logLevel$7 <= logLevel.silent) return;
|
|
904
1066
|
const commandWithArgs = formatCommandWithArgs(command, args);
|
|
905
1067
|
const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} started`);
|
|
906
|
-
if (
|
|
907
|
-
|
|
908
|
-
console.log(text);
|
|
909
|
-
}
|
|
910
|
-
if (!id) return;
|
|
911
|
-
await runHook({
|
|
912
|
-
id,
|
|
913
|
-
command,
|
|
914
|
-
args,
|
|
915
|
-
commandWithArgs,
|
|
916
|
-
context,
|
|
917
|
-
sink: {
|
|
918
|
-
onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0,
|
|
919
|
-
onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
|
|
920
|
-
}
|
|
921
|
-
});
|
|
1068
|
+
if (state.currentConfigs.length === 1) openGroup(`Hook ${commandWithArgs}`);
|
|
1069
|
+
console.log(text);
|
|
922
1070
|
});
|
|
923
|
-
context.on("hook:end", ({ command, args }) => {
|
|
1071
|
+
context.on("kubb:hook:end", ({ command, args }) => {
|
|
924
1072
|
if (logLevel$7 <= logLevel.silent) return;
|
|
925
1073
|
const commandWithArgs = formatCommandWithArgs(command, args);
|
|
926
1074
|
const text = getMessage(`Hook ${styleText("dim", commandWithArgs)} completed`);
|
|
927
1075
|
console.log(text);
|
|
928
1076
|
if (state.currentConfigs.length === 1) closeGroup(`Hook ${commandWithArgs}`);
|
|
929
1077
|
});
|
|
930
|
-
context.on("generation:summary", (config,
|
|
1078
|
+
context.on("kubb:generation:summary", ({ config, status, hrStart, failedPlugins }) => {
|
|
931
1079
|
const pluginsCount = config.plugins?.length ?? 0;
|
|
932
1080
|
const successCount = pluginsCount - failedPlugins.size;
|
|
933
1081
|
const duration = formatHrtime(hrStart);
|
|
@@ -935,16 +1083,19 @@ const githubActionsLogger = defineLogger({
|
|
|
935
1083
|
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)}`);
|
|
936
1084
|
if (state.currentConfigs.length > 1) closeGroup(config.name ? `Generation for ${styleText("bold", config.name)}` : "Generation");
|
|
937
1085
|
});
|
|
938
|
-
context.on("lifecycle:end", () => {
|
|
1086
|
+
context.on("kubb:lifecycle:end", () => {
|
|
939
1087
|
reset();
|
|
940
1088
|
});
|
|
1089
|
+
return (_commandWithArgs) => ({
|
|
1090
|
+
onStdout: logLevel$7 > logLevel.silent ? (s) => console.log(s) : void 0,
|
|
1091
|
+
onStderr: logLevel$7 > logLevel.silent ? (s) => console.error(`::error::${s}`) : void 0
|
|
1092
|
+
});
|
|
941
1093
|
}
|
|
942
1094
|
});
|
|
943
1095
|
//#endregion
|
|
944
1096
|
//#region src/loggers/plainLogger.ts
|
|
945
1097
|
/**
|
|
946
|
-
* Plain console adapter for non-TTY environments
|
|
947
|
-
* Simple console.log output with indentation
|
|
1098
|
+
* Plain console adapter for non-TTY environments with simple `console.log` output.
|
|
948
1099
|
*/
|
|
949
1100
|
const plainLogger = defineLogger({
|
|
950
1101
|
name: "plain",
|
|
@@ -953,7 +1104,7 @@ const plainLogger = defineLogger({
|
|
|
953
1104
|
function getMessage(message) {
|
|
954
1105
|
return formatMessage(message, logLevel$6);
|
|
955
1106
|
}
|
|
956
|
-
context.on("info", (message, info) => {
|
|
1107
|
+
context.on("kubb:info", ({ message, info }) => {
|
|
957
1108
|
if (logLevel$6 <= logLevel.silent) return;
|
|
958
1109
|
const text = getMessage([
|
|
959
1110
|
"ℹ",
|
|
@@ -962,7 +1113,7 @@ const plainLogger = defineLogger({
|
|
|
962
1113
|
].join(" "));
|
|
963
1114
|
console.log(text);
|
|
964
1115
|
});
|
|
965
|
-
context.on("success", (message, info = "") => {
|
|
1116
|
+
context.on("kubb:success", ({ message, info = "" }) => {
|
|
966
1117
|
if (logLevel$6 <= logLevel.silent) return;
|
|
967
1118
|
const text = getMessage([
|
|
968
1119
|
"✓",
|
|
@@ -971,7 +1122,7 @@ const plainLogger = defineLogger({
|
|
|
971
1122
|
].filter(Boolean).join(" "));
|
|
972
1123
|
console.log(text);
|
|
973
1124
|
});
|
|
974
|
-
context.on("warn", (message, info) => {
|
|
1125
|
+
context.on("kubb:warn", ({ message, info }) => {
|
|
975
1126
|
if (logLevel$6 < logLevel.warn) return;
|
|
976
1127
|
const text = getMessage([
|
|
977
1128
|
"⚠",
|
|
@@ -980,7 +1131,7 @@ const plainLogger = defineLogger({
|
|
|
980
1131
|
].filter(Boolean).join(" "));
|
|
981
1132
|
console.log(text);
|
|
982
1133
|
});
|
|
983
|
-
context.on("error", (error) => {
|
|
1134
|
+
context.on("kubb:error", ({ error }) => {
|
|
984
1135
|
const caused = toCause(error);
|
|
985
1136
|
const text = getMessage(["✗", error.message].join(" "));
|
|
986
1137
|
console.log(text);
|
|
@@ -994,96 +1145,84 @@ const plainLogger = defineLogger({
|
|
|
994
1145
|
}
|
|
995
1146
|
}
|
|
996
1147
|
});
|
|
997
|
-
context.on("lifecycle:start", () => {
|
|
1148
|
+
context.on("kubb:lifecycle:start", () => {
|
|
998
1149
|
console.log("Kubb CLI 🧩");
|
|
999
1150
|
});
|
|
1000
|
-
context.on("config:start", () => {
|
|
1151
|
+
context.on("kubb:config:start", () => {
|
|
1001
1152
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1002
1153
|
const text = getMessage("Configuration started");
|
|
1003
1154
|
console.log(text);
|
|
1004
1155
|
});
|
|
1005
|
-
context.on("config:end", () => {
|
|
1156
|
+
context.on("kubb:config:end", () => {
|
|
1006
1157
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1007
1158
|
const text = getMessage("Configuration completed");
|
|
1008
1159
|
console.log(text);
|
|
1009
1160
|
});
|
|
1010
|
-
context.on("generation:start", () => {
|
|
1161
|
+
context.on("kubb:generation:start", () => {
|
|
1011
1162
|
const text = getMessage("Generation started");
|
|
1012
1163
|
console.log(text);
|
|
1013
1164
|
});
|
|
1014
|
-
context.on("plugin:start", (plugin) => {
|
|
1165
|
+
context.on("kubb:plugin:start", ({ plugin }) => {
|
|
1015
1166
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1016
1167
|
const text = getMessage(`Generating ${plugin.name}`);
|
|
1017
1168
|
console.log(text);
|
|
1018
1169
|
});
|
|
1019
|
-
context.on("plugin:end", (plugin,
|
|
1170
|
+
context.on("kubb:plugin:end", ({ plugin, duration, success }) => {
|
|
1020
1171
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1021
1172
|
const durationStr = formatMs(duration);
|
|
1022
1173
|
const text = getMessage(success ? `${plugin.name} completed in ${durationStr}` : `${plugin.name} failed in ${durationStr}`);
|
|
1023
1174
|
console.log(text);
|
|
1024
1175
|
});
|
|
1025
|
-
context.on("files:processing:start", (files) => {
|
|
1176
|
+
context.on("kubb:files:processing:start", ({ files }) => {
|
|
1026
1177
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1027
1178
|
const text = getMessage(`Writing ${files.length} files`);
|
|
1028
1179
|
console.log(text);
|
|
1029
1180
|
});
|
|
1030
|
-
context.on("file:processing:update", ({ file, config }) => {
|
|
1181
|
+
context.on("kubb:file:processing:update", ({ file, config }) => {
|
|
1031
1182
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1032
1183
|
const text = getMessage(`Writing ${relative(config.root, file.path)}`);
|
|
1033
1184
|
console.log(text);
|
|
1034
1185
|
});
|
|
1035
|
-
context.on("files:processing:end", () => {
|
|
1186
|
+
context.on("kubb:files:processing:end", () => {
|
|
1036
1187
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1037
1188
|
const text = getMessage("Files written successfully");
|
|
1038
1189
|
console.log(text);
|
|
1039
1190
|
});
|
|
1040
|
-
context.on("generation:end", (config) => {
|
|
1191
|
+
context.on("kubb:generation:end", ({ config }) => {
|
|
1041
1192
|
const text = getMessage(config.name ? `Generation completed for ${config.name}` : "Generation completed");
|
|
1042
1193
|
console.log(text);
|
|
1043
1194
|
});
|
|
1044
|
-
context.on("format:start", () => {
|
|
1195
|
+
context.on("kubb:format:start", () => {
|
|
1045
1196
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1046
1197
|
const text = getMessage("Format started");
|
|
1047
1198
|
console.log(text);
|
|
1048
1199
|
});
|
|
1049
|
-
context.on("format:end", () => {
|
|
1200
|
+
context.on("kubb:format:end", () => {
|
|
1050
1201
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1051
1202
|
const text = getMessage("Format completed");
|
|
1052
1203
|
console.log(text);
|
|
1053
1204
|
});
|
|
1054
|
-
context.on("lint:start", () => {
|
|
1205
|
+
context.on("kubb:lint:start", () => {
|
|
1055
1206
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1056
1207
|
const text = getMessage("Lint started");
|
|
1057
1208
|
console.log(text);
|
|
1058
1209
|
});
|
|
1059
|
-
context.on("lint:end", () => {
|
|
1210
|
+
context.on("kubb:lint:end", () => {
|
|
1060
1211
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1061
1212
|
const text = getMessage("Lint completed");
|
|
1062
1213
|
console.log(text);
|
|
1063
1214
|
});
|
|
1064
|
-
context.on("hook:start",
|
|
1065
|
-
|
|
1066
|
-
const text = getMessage(`Hook ${
|
|
1067
|
-
|
|
1068
|
-
if (!id) return;
|
|
1069
|
-
await runHook({
|
|
1070
|
-
id,
|
|
1071
|
-
command,
|
|
1072
|
-
args,
|
|
1073
|
-
commandWithArgs,
|
|
1074
|
-
context,
|
|
1075
|
-
sink: {
|
|
1076
|
-
onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0,
|
|
1077
|
-
onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0
|
|
1078
|
-
}
|
|
1079
|
-
});
|
|
1215
|
+
context.on("kubb:hook:start", ({ command, args }) => {
|
|
1216
|
+
if (logLevel$6 <= logLevel.silent) return;
|
|
1217
|
+
const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} started`);
|
|
1218
|
+
console.log(text);
|
|
1080
1219
|
});
|
|
1081
|
-
context.on("hook:end", ({ command, args }) => {
|
|
1220
|
+
context.on("kubb:hook:end", ({ command, args }) => {
|
|
1082
1221
|
if (logLevel$6 <= logLevel.silent) return;
|
|
1083
1222
|
const text = getMessage(`Hook ${formatCommandWithArgs(command, args)} completed`);
|
|
1084
1223
|
console.log(text);
|
|
1085
1224
|
});
|
|
1086
|
-
context.on("generation:summary", (config,
|
|
1225
|
+
context.on("kubb:generation:summary", ({ config, pluginTimings, status, hrStart, failedPlugins, filesCreated }) => {
|
|
1087
1226
|
const summary = getSummary({
|
|
1088
1227
|
failedPlugins,
|
|
1089
1228
|
filesCreated,
|
|
@@ -1096,6 +1235,10 @@ const plainLogger = defineLogger({
|
|
|
1096
1235
|
console.log(summary.join("\n"));
|
|
1097
1236
|
console.log(SUMMARY_SEPARATOR);
|
|
1098
1237
|
});
|
|
1238
|
+
return (_commandWithArgs) => ({
|
|
1239
|
+
onStdout: logLevel$6 > logLevel.silent ? (s) => console.log(s) : void 0,
|
|
1240
|
+
onStderr: logLevel$6 > logLevel.silent ? (s) => console.error(s) : void 0
|
|
1241
|
+
});
|
|
1099
1242
|
}
|
|
1100
1243
|
});
|
|
1101
1244
|
//#endregion
|
|
@@ -1150,310 +1293,446 @@ async function setupLogger(context, { logLevel: logLevel$5 }) {
|
|
|
1150
1293
|
const type = detectLogger();
|
|
1151
1294
|
const logger = logMapper[type];
|
|
1152
1295
|
if (!logger) throw new Error(`Unknown adapter type: ${type}`);
|
|
1153
|
-
const
|
|
1296
|
+
const makeSink = await logger.install(context, { logLevel: logLevel$5 });
|
|
1154
1297
|
if (logLevel$5 >= logLevel.debug) await fileSystemLogger.install(context, { logLevel: logLevel$5 });
|
|
1155
|
-
return
|
|
1298
|
+
return typeof makeSink === "function" ? makeSink : void 0;
|
|
1156
1299
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1300
|
+
/**
|
|
1301
|
+
* Builds the generation summary lines rendered in the end-of-run box.
|
|
1302
|
+
* Returns an array of styled strings, one per summary row.
|
|
1303
|
+
*/
|
|
1304
|
+
function getSummary({ failedPlugins, filesCreated, status, hrStart, config, pluginTimings }) {
|
|
1305
|
+
const duration = formatHrtime(hrStart);
|
|
1306
|
+
const pluginsCount = config.plugins?.length ?? 0;
|
|
1307
|
+
const successCount = pluginsCount - failedPlugins.size;
|
|
1308
|
+
const meta = {
|
|
1309
|
+
plugins: status === "success" ? `${styleText("green", `${successCount} successful`)}, ${pluginsCount} total` : `${styleText("green", `${successCount} successful`)}, ${styleText("red", `${failedPlugins.size} failed`)}, ${pluginsCount} total`,
|
|
1310
|
+
pluginsFailed: status === "failed" ? [...failedPlugins].map(({ plugin }) => randomCliColor(plugin.name)).join(", ") : void 0,
|
|
1311
|
+
filesCreated,
|
|
1312
|
+
time: styleText("green", duration),
|
|
1313
|
+
output: path.resolve(config.root, config.output.path)
|
|
1314
|
+
};
|
|
1315
|
+
const labels = {
|
|
1316
|
+
plugins: "Plugins:",
|
|
1317
|
+
failed: "Failed:",
|
|
1318
|
+
generated: "Generated:",
|
|
1319
|
+
pluginTimings: "Plugin Timings:",
|
|
1320
|
+
output: "Output:"
|
|
1321
|
+
};
|
|
1322
|
+
const maxLength = Math.max(0, ...[...Object.values(labels), ...pluginTimings ? Array.from(pluginTimings.keys()) : []].map((s) => s.length));
|
|
1323
|
+
const summaryLines = [];
|
|
1324
|
+
summaryLines.push(`${labels.plugins.padEnd(maxLength + 2)} ${meta.plugins}`);
|
|
1325
|
+
if (meta.pluginsFailed) summaryLines.push(`${labels.failed.padEnd(maxLength + 2)} ${meta.pluginsFailed}`);
|
|
1326
|
+
summaryLines.push(`${labels.generated.padEnd(maxLength + 2)} ${meta.filesCreated} files in ${meta.time}`);
|
|
1327
|
+
if (pluginTimings && pluginTimings.size > 0) {
|
|
1328
|
+
const sortedTimings = Array.from(pluginTimings.entries()).sort((a, b) => b[1] - a[1]);
|
|
1329
|
+
summaryLines.push(`${labels.pluginTimings}`);
|
|
1330
|
+
sortedTimings.forEach(([name, time]) => {
|
|
1331
|
+
const timeStr = time >= 1e3 ? `${(time / 1e3).toFixed(2)}s` : `${Math.round(time)}ms`;
|
|
1332
|
+
const barLength = Math.min(Math.ceil(time / 100), 10);
|
|
1333
|
+
const bar = styleText("dim", "█".repeat(barLength));
|
|
1334
|
+
summaryLines.push(`${styleText("dim", "•")} ${name.padEnd(maxLength + 1)}${bar} ${timeStr}`);
|
|
1181
1335
|
});
|
|
1182
|
-
await hookEndPromise;
|
|
1183
1336
|
}
|
|
1337
|
+
summaryLines.push(`${labels.output.padEnd(maxLength + 2)} ${meta.output}`);
|
|
1338
|
+
return summaryLines;
|
|
1184
1339
|
}
|
|
1185
1340
|
//#endregion
|
|
1186
|
-
//#region src/utils
|
|
1341
|
+
//#region src/runners/generate/utils.ts
|
|
1187
1342
|
const jiti = createJiti(import.meta.url, {
|
|
1188
1343
|
jsx: {
|
|
1189
1344
|
runtime: "automatic",
|
|
1190
|
-
importSource: "@kubb/
|
|
1345
|
+
importSource: "@kubb/renderer-jsx"
|
|
1191
1346
|
},
|
|
1192
|
-
|
|
1193
|
-
interopDefault: true
|
|
1347
|
+
moduleCache: false
|
|
1194
1348
|
});
|
|
1195
|
-
const tsLoader =
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1349
|
+
const tsLoader = (configFile) => jiti.import(configFile, { default: true });
|
|
1350
|
+
const MODULE_NAME = "kubb";
|
|
1351
|
+
const BASE_SEARCH_PLACES = [
|
|
1352
|
+
"package.json",
|
|
1353
|
+
`.${MODULE_NAME}rc`,
|
|
1354
|
+
`.${MODULE_NAME}rc.json`,
|
|
1355
|
+
`.${MODULE_NAME}rc.yaml`,
|
|
1356
|
+
`.${MODULE_NAME}rc.yml`,
|
|
1357
|
+
`.${MODULE_NAME}rc.ts`,
|
|
1358
|
+
`.${MODULE_NAME}rc.mts`,
|
|
1359
|
+
`.${MODULE_NAME}rc.cts`,
|
|
1360
|
+
`.${MODULE_NAME}rc.js`,
|
|
1361
|
+
`.${MODULE_NAME}rc.mjs`,
|
|
1362
|
+
`.${MODULE_NAME}rc.cjs`,
|
|
1363
|
+
`${MODULE_NAME}.config.ts`,
|
|
1364
|
+
`${MODULE_NAME}.config.mts`,
|
|
1365
|
+
`${MODULE_NAME}.config.cts`,
|
|
1366
|
+
`${MODULE_NAME}.config.js`,
|
|
1367
|
+
`${MODULE_NAME}.config.mjs`,
|
|
1368
|
+
`${MODULE_NAME}.config.cjs`
|
|
1369
|
+
];
|
|
1370
|
+
const SEARCH_PLACES = [
|
|
1371
|
+
"",
|
|
1372
|
+
".config/",
|
|
1373
|
+
"configs/"
|
|
1374
|
+
].flatMap((prefix) => BASE_SEARCH_PLACES.map((p) => `${prefix}${p}`));
|
|
1375
|
+
async function getCosmiConfig(configFile) {
|
|
1376
|
+
const explorer = cosmiconfig(MODULE_NAME, {
|
|
1216
1377
|
cache: false,
|
|
1217
|
-
searchPlaces:
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
}),
|
|
1224
|
-
...searchPlaces
|
|
1225
|
-
],
|
|
1226
|
-
loaders: { ".ts": tsLoader }
|
|
1378
|
+
searchPlaces: SEARCH_PLACES,
|
|
1379
|
+
loaders: {
|
|
1380
|
+
".ts": tsLoader,
|
|
1381
|
+
".mts": tsLoader,
|
|
1382
|
+
".cts": tsLoader
|
|
1383
|
+
}
|
|
1227
1384
|
});
|
|
1385
|
+
let result;
|
|
1228
1386
|
try {
|
|
1229
|
-
result =
|
|
1387
|
+
result = configFile ? await explorer.load(configFile) : await explorer.search();
|
|
1230
1388
|
} catch (error) {
|
|
1231
1389
|
throw new Error("Config failed loading", { cause: error });
|
|
1232
1390
|
}
|
|
1233
|
-
if (result?.
|
|
1391
|
+
if (!result?.config || result.isEmpty) throw new Error("Config not defined, create a kubb.config.js or pass through your config with the option --config");
|
|
1234
1392
|
return result;
|
|
1235
1393
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1394
|
+
/**
|
|
1395
|
+
* Discovers the Kubb config via cosmiconfig and resolves it into a normalized array of configs.
|
|
1396
|
+
* Every config in the result is guaranteed to have a `plugins` array.
|
|
1397
|
+
*/
|
|
1398
|
+
async function getConfigs({ configPath, input }) {
|
|
1399
|
+
const result = await getCosmiConfig(configPath);
|
|
1400
|
+
const resolved = await (typeof result.config === "function" ? result.config({ input }) : result.config);
|
|
1401
|
+
const userConfigs = Array.isArray(resolved) ? resolved : [resolved];
|
|
1402
|
+
return {
|
|
1403
|
+
configPath: result.filepath,
|
|
1404
|
+
configs: userConfigs.map((item) => ({
|
|
1405
|
+
...item,
|
|
1406
|
+
plugins: item.plugins ?? []
|
|
1407
|
+
}))
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Runs the `done` hooks defined in a Kubb config in sequence.
|
|
1412
|
+
*/
|
|
1413
|
+
async function executeHooks({ configHooks, hooks, makeSink }) {
|
|
1414
|
+
const commands = Array.isArray(configHooks.done) ? configHooks.done : [configHooks.done].filter(Boolean);
|
|
1415
|
+
for (const command of commands) {
|
|
1416
|
+
const [cmd, ...args] = tokenize(command);
|
|
1417
|
+
if (!cmd) continue;
|
|
1418
|
+
const hookId = createHash("sha256").update(command).digest("hex");
|
|
1419
|
+
const commandWithArgs = [cmd, ...args].join(" ");
|
|
1420
|
+
await hooks.emit("kubb:hook:start", {
|
|
1421
|
+
id: hookId,
|
|
1422
|
+
command: cmd,
|
|
1423
|
+
args
|
|
1424
|
+
});
|
|
1425
|
+
const { stream = false, onLine, onStdout, onStderr } = makeSink?.(commandWithArgs) ?? {};
|
|
1426
|
+
await runHook({
|
|
1427
|
+
id: hookId,
|
|
1428
|
+
command: cmd,
|
|
1429
|
+
args,
|
|
1430
|
+
commandWithArgs,
|
|
1431
|
+
context: hooks,
|
|
1432
|
+
stream,
|
|
1433
|
+
sink: {
|
|
1434
|
+
onLine,
|
|
1435
|
+
onStdout,
|
|
1436
|
+
onStderr
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
async function runHook({ id, command, args, commandWithArgs, context, stream = false, sink }) {
|
|
1442
|
+
const emitEnd = (success, error) => context.emit("kubb:hook:end", {
|
|
1443
|
+
command,
|
|
1444
|
+
args,
|
|
1445
|
+
id,
|
|
1446
|
+
success,
|
|
1447
|
+
error
|
|
1448
|
+
});
|
|
1449
|
+
try {
|
|
1450
|
+
const proc = x(command, [...args ?? []], {
|
|
1451
|
+
nodeOptions: { detached: process.platform !== "win32" },
|
|
1452
|
+
throwOnError: true
|
|
1453
|
+
});
|
|
1454
|
+
if (stream && sink?.onLine) for await (const line of proc) sink.onLine(line);
|
|
1455
|
+
const result = await proc;
|
|
1456
|
+
await context.emit("kubb:debug", {
|
|
1457
|
+
date: /* @__PURE__ */ new Date(),
|
|
1458
|
+
logs: [result.stdout.trimEnd()]
|
|
1459
|
+
});
|
|
1460
|
+
await context.emit("kubb:success", { message: `${styleText("dim", commandWithArgs)} successfully executed` });
|
|
1461
|
+
await emitEnd(true, null);
|
|
1462
|
+
} catch (err) {
|
|
1463
|
+
if (!(err instanceof NonZeroExitError)) {
|
|
1464
|
+
const error = toError(err);
|
|
1465
|
+
await emitEnd(false, error);
|
|
1466
|
+
await context.emit("kubb:error", { error });
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
const stderr = err.output?.stderr ?? "";
|
|
1470
|
+
const stdout = err.output?.stdout ?? "";
|
|
1471
|
+
await context.emit("kubb:debug", {
|
|
1472
|
+
date: /* @__PURE__ */ new Date(),
|
|
1473
|
+
logs: [stdout, stderr].filter(Boolean)
|
|
1474
|
+
});
|
|
1475
|
+
if (stderr) sink?.onStderr?.(stderr);
|
|
1476
|
+
if (stdout) sink?.onStdout?.(stdout);
|
|
1477
|
+
const error = /* @__PURE__ */ new Error(`Hook execute failed: ${commandWithArgs}`);
|
|
1478
|
+
await emitEnd(false, error);
|
|
1479
|
+
await context.emit("kubb:error", { error });
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Starts a file watcher on the given paths and calls `cb` on any change.
|
|
1484
|
+
* Ignores `.git` and `node_modules` directories.
|
|
1485
|
+
*/
|
|
1486
|
+
async function startWatcher(path, cb, log = {
|
|
1487
|
+
info: console.log,
|
|
1488
|
+
error: console.log
|
|
1489
|
+
}) {
|
|
1239
1490
|
const { watch } = await import("chokidar");
|
|
1240
1491
|
watch(path, {
|
|
1241
1492
|
ignorePermissionErrors: true,
|
|
1242
1493
|
ignored: WATCHER_IGNORED_PATHS
|
|
1243
1494
|
}).on("all", async (type, file) => {
|
|
1244
|
-
|
|
1495
|
+
log.info(styleText("yellow", styleText("bold", `Change detected: ${type} ${file}`)));
|
|
1245
1496
|
try {
|
|
1246
1497
|
await cb(path);
|
|
1247
1498
|
} catch (_e) {
|
|
1248
|
-
|
|
1499
|
+
log.error(styleText("red", "Watcher failed"));
|
|
1249
1500
|
}
|
|
1250
1501
|
});
|
|
1251
1502
|
}
|
|
1252
1503
|
//#endregion
|
|
1253
|
-
//#region src/runners/generate.ts
|
|
1254
|
-
|
|
1504
|
+
//#region src/runners/generate/run.ts
|
|
1505
|
+
/**
|
|
1506
|
+
* Registers a one-shot `kubb:hook:end` listener for `hookId` BEFORE the caller emits `kubb:hook:start`,
|
|
1507
|
+
* avoiding the race where a synchronous emitter fires end before the listener is attached.
|
|
1508
|
+
*/
|
|
1509
|
+
function waitForHookEnd(hooks, hookId, onSuccess, fallbackErrorMessage) {
|
|
1510
|
+
return new Promise((resolve, reject) => {
|
|
1511
|
+
const handler = (ctx) => {
|
|
1512
|
+
if (ctx.id !== hookId) return;
|
|
1513
|
+
hooks.off("kubb:hook:end", handler);
|
|
1514
|
+
if (!ctx.success) {
|
|
1515
|
+
reject(ctx.error ?? new Error(fallbackErrorMessage));
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
onSuccess().then(resolve).catch(reject);
|
|
1519
|
+
};
|
|
1520
|
+
hooks.on("kubb:hook:end", handler);
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
async function runToolPass({ toolValue, detect, toolMap, toolLabel, successPrefix, noToolMessage, configName, outputPath, logLevel: logLevel$1, hooks, onStart, onEnd }) {
|
|
1255
1524
|
await onStart();
|
|
1256
1525
|
let resolvedTool = toolValue;
|
|
1257
1526
|
if (resolvedTool === "auto") {
|
|
1258
1527
|
const detected = await detect();
|
|
1259
|
-
if (!detected) await
|
|
1528
|
+
if (!detected) await hooks.emit("kubb:warn", { message: noToolMessage });
|
|
1260
1529
|
else {
|
|
1261
1530
|
resolvedTool = detected;
|
|
1262
|
-
await
|
|
1531
|
+
await hooks.emit("kubb:info", { message: `Auto-detected ${toolLabel}: ${styleText("dim", resolvedTool)}` });
|
|
1263
1532
|
}
|
|
1264
1533
|
}
|
|
1534
|
+
let toolError;
|
|
1265
1535
|
if (resolvedTool && resolvedTool !== "auto" && resolvedTool in toolMap) {
|
|
1266
1536
|
const toolConfig = toolMap[resolvedTool];
|
|
1537
|
+
const hookId = createHash("sha256").update([configName, resolvedTool].filter(Boolean).join("-")).digest("hex");
|
|
1538
|
+
const successMessage = [
|
|
1539
|
+
`${successPrefix} with ${styleText("dim", resolvedTool)}`,
|
|
1540
|
+
logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
|
|
1541
|
+
"successfully"
|
|
1542
|
+
].filter(Boolean).join(" ");
|
|
1267
1543
|
try {
|
|
1268
|
-
const
|
|
1269
|
-
|
|
1270
|
-
const handler = ({ id, success, error }) => {
|
|
1271
|
-
if (id !== hookId) return;
|
|
1272
|
-
events.off("hook:end", handler);
|
|
1273
|
-
if (!success) {
|
|
1274
|
-
reject(error ?? /* @__PURE__ */ new Error(`${toolConfig.errorMessage}`));
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
|
-
events.emit("success", [
|
|
1278
|
-
`${successPrefix} with ${styleText("dim", resolvedTool)}`,
|
|
1279
|
-
logLevel$1 >= logLevel.info ? `on ${styleText("dim", outputPath)}` : void 0,
|
|
1280
|
-
"successfully"
|
|
1281
|
-
].filter(Boolean).join(" ")).then(resolve).catch(reject);
|
|
1282
|
-
};
|
|
1283
|
-
events.on("hook:end", handler);
|
|
1284
|
-
});
|
|
1285
|
-
await events.emit("hook:start", {
|
|
1544
|
+
const hookEndPromise = waitForHookEnd(hooks, hookId, () => hooks.emit("kubb:success", { message: successMessage }), toolConfig.errorMessage);
|
|
1545
|
+
await hooks.emit("kubb:hook:start", {
|
|
1286
1546
|
id: hookId,
|
|
1287
1547
|
command: toolConfig.command,
|
|
1288
1548
|
args: toolConfig.args(outputPath)
|
|
1289
1549
|
});
|
|
1290
1550
|
await hookEndPromise;
|
|
1291
1551
|
} catch (caughtError) {
|
|
1292
|
-
const err =
|
|
1293
|
-
|
|
1294
|
-
|
|
1552
|
+
const err = toError(caughtError);
|
|
1553
|
+
await hooks.emit("kubb:error", { error: err });
|
|
1554
|
+
toolError = err;
|
|
1295
1555
|
}
|
|
1296
1556
|
}
|
|
1297
1557
|
await onEnd();
|
|
1558
|
+
if (toolError) throw toolError;
|
|
1298
1559
|
}
|
|
1299
|
-
async function generate(
|
|
1300
|
-
const
|
|
1560
|
+
async function generate(options) {
|
|
1561
|
+
const { input, hooks, logLevel: logLevel$2, makeSink } = options;
|
|
1301
1562
|
const hrStart = process$1.hrtime();
|
|
1563
|
+
const inputPath = input ?? (options.config.input && "path" in options.config.input ? options.config.input.path : void 0);
|
|
1302
1564
|
const config = {
|
|
1303
|
-
...
|
|
1304
|
-
root: userConfig.root || process$1.cwd(),
|
|
1565
|
+
...options.config,
|
|
1305
1566
|
input: inputPath ? {
|
|
1306
|
-
...
|
|
1567
|
+
...options.config.input,
|
|
1307
1568
|
path: inputPath
|
|
1308
|
-
} :
|
|
1309
|
-
output
|
|
1310
|
-
write: true,
|
|
1311
|
-
barrelType: "named",
|
|
1312
|
-
extension: { ".ts": ".ts" },
|
|
1313
|
-
format: "prettier",
|
|
1314
|
-
...userConfig.output
|
|
1315
|
-
}
|
|
1569
|
+
} : options.config.input,
|
|
1570
|
+
...options.config.output
|
|
1316
1571
|
};
|
|
1317
|
-
|
|
1318
|
-
await
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1572
|
+
const kubb = createKubb(config, { hooks });
|
|
1573
|
+
await kubb.setup();
|
|
1574
|
+
await hooks.emit("kubb:generation:start", { config });
|
|
1575
|
+
await hooks.emit("kubb:info", {
|
|
1576
|
+
message: config.name ? `Setup generation ${styleText("bold", config.name)}` : "Setup generation",
|
|
1577
|
+
info: inputPath
|
|
1322
1578
|
});
|
|
1323
|
-
await
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
events
|
|
1327
|
-
}, {
|
|
1328
|
-
driver,
|
|
1329
|
-
fabric,
|
|
1330
|
-
events,
|
|
1331
|
-
sources
|
|
1579
|
+
await hooks.emit("kubb:info", {
|
|
1580
|
+
message: config.name ? `Build generation ${styleText("bold", config.name)}` : "Build generation",
|
|
1581
|
+
info: inputPath
|
|
1332
1582
|
});
|
|
1333
|
-
await
|
|
1583
|
+
const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild();
|
|
1584
|
+
await hooks.emit("kubb:info", { message: "Load summary" });
|
|
1585
|
+
const telemetryPlugins = Array.from(driver.plugins.values(), (p) => ({
|
|
1586
|
+
name: p.name,
|
|
1587
|
+
options: p.options
|
|
1588
|
+
}));
|
|
1589
|
+
const reportTelemetry = (status) => sendTelemetry(buildTelemetryEvent({
|
|
1590
|
+
command: "generate",
|
|
1591
|
+
kubbVersion: version,
|
|
1592
|
+
plugins: telemetryPlugins,
|
|
1593
|
+
hrStart,
|
|
1594
|
+
filesCreated: files.length,
|
|
1595
|
+
status
|
|
1596
|
+
}));
|
|
1334
1597
|
if (failedPlugins.size > 0 || error) {
|
|
1335
|
-
const allErrors = [error, ...Array.from(failedPlugins
|
|
1336
|
-
for (const err of allErrors) await
|
|
1337
|
-
await
|
|
1338
|
-
|
|
1598
|
+
const allErrors = [error, ...Array.from(failedPlugins, (it) => it.error)].filter(Boolean);
|
|
1599
|
+
for (const err of allErrors) await hooks.emit("kubb:error", { error: err });
|
|
1600
|
+
await hooks.emit("kubb:generation:end", {
|
|
1601
|
+
config,
|
|
1602
|
+
files,
|
|
1603
|
+
sources: kubb.sources
|
|
1604
|
+
});
|
|
1605
|
+
await hooks.emit("kubb:generation:summary", {
|
|
1606
|
+
config,
|
|
1339
1607
|
failedPlugins,
|
|
1340
1608
|
filesCreated: files.length,
|
|
1341
1609
|
status: "failed",
|
|
1342
1610
|
hrStart,
|
|
1343
1611
|
pluginTimings: logLevel$2 >= logLevel.verbose ? pluginTimings : void 0
|
|
1344
1612
|
});
|
|
1345
|
-
await
|
|
1346
|
-
command: "generate",
|
|
1347
|
-
kubbVersion: version,
|
|
1348
|
-
plugins: driver.plugins.map((p) => ({
|
|
1349
|
-
name: p.name,
|
|
1350
|
-
options: p.options
|
|
1351
|
-
})),
|
|
1352
|
-
hrStart,
|
|
1353
|
-
filesCreated: files.length,
|
|
1354
|
-
status: "failed"
|
|
1355
|
-
}));
|
|
1613
|
+
await reportTelemetry("failed");
|
|
1356
1614
|
process$1.exit(1);
|
|
1357
1615
|
}
|
|
1358
|
-
await
|
|
1359
|
-
|
|
1616
|
+
await hooks.emit("kubb:success", {
|
|
1617
|
+
message: "Generation succeeded",
|
|
1618
|
+
info: inputPath
|
|
1619
|
+
});
|
|
1620
|
+
await hooks.emit("kubb:generation:end", {
|
|
1621
|
+
config,
|
|
1622
|
+
files,
|
|
1623
|
+
sources: kubb.sources
|
|
1624
|
+
});
|
|
1360
1625
|
const outputPath = path.resolve(config.root, config.output.path);
|
|
1361
|
-
|
|
1626
|
+
const toolPasses = [config.output.format && {
|
|
1362
1627
|
toolValue: config.output.format,
|
|
1363
1628
|
detect: detectFormatter,
|
|
1364
1629
|
toolMap: formatters,
|
|
1365
1630
|
toolLabel: "formatter",
|
|
1366
1631
|
successPrefix: "Formatting",
|
|
1367
|
-
noToolMessage: "No formatter found (
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
events,
|
|
1372
|
-
onStart: () => events.emit("format:start"),
|
|
1373
|
-
onEnd: () => events.emit("format:end")
|
|
1374
|
-
});
|
|
1375
|
-
if (config.output.lint) await runToolPass({
|
|
1632
|
+
noToolMessage: "No formatter found (oxfmt, biome, or prettier). Skipping formatting.",
|
|
1633
|
+
onStart: () => hooks.emit("kubb:format:start"),
|
|
1634
|
+
onEnd: () => hooks.emit("kubb:format:end")
|
|
1635
|
+
}, config.output.lint && {
|
|
1376
1636
|
toolValue: config.output.lint,
|
|
1377
1637
|
detect: detectLinter,
|
|
1378
1638
|
toolMap: linters,
|
|
1379
1639
|
toolLabel: "linter",
|
|
1380
1640
|
successPrefix: "Linting",
|
|
1381
|
-
noToolMessage: "No linter found (
|
|
1641
|
+
noToolMessage: "No linter found (oxlint, biome, or eslint). Skipping linting.",
|
|
1642
|
+
onStart: () => hooks.emit("kubb:lint:start"),
|
|
1643
|
+
onEnd: () => hooks.emit("kubb:lint:end")
|
|
1644
|
+
}].filter(Boolean);
|
|
1645
|
+
for (const pass of toolPasses) await runToolPass({
|
|
1646
|
+
...pass,
|
|
1382
1647
|
configName: config.name,
|
|
1383
1648
|
outputPath,
|
|
1384
1649
|
logLevel: logLevel$2,
|
|
1385
|
-
|
|
1386
|
-
onStart: () => events.emit("lint:start"),
|
|
1387
|
-
onEnd: () => events.emit("lint:end")
|
|
1650
|
+
hooks
|
|
1388
1651
|
});
|
|
1389
1652
|
if (config.hooks) {
|
|
1390
|
-
await
|
|
1653
|
+
await hooks.emit("kubb:hooks:start");
|
|
1391
1654
|
await executeHooks({
|
|
1392
|
-
|
|
1393
|
-
|
|
1655
|
+
configHooks: config.hooks,
|
|
1656
|
+
hooks,
|
|
1657
|
+
makeSink
|
|
1394
1658
|
});
|
|
1395
|
-
await
|
|
1659
|
+
await hooks.emit("kubb:hooks:end");
|
|
1396
1660
|
}
|
|
1397
|
-
await
|
|
1661
|
+
await hooks.emit("kubb:generation:summary", {
|
|
1662
|
+
config,
|
|
1398
1663
|
failedPlugins,
|
|
1399
1664
|
filesCreated: files.length,
|
|
1400
1665
|
status: "success",
|
|
1401
1666
|
hrStart,
|
|
1402
1667
|
pluginTimings
|
|
1403
1668
|
});
|
|
1404
|
-
await
|
|
1405
|
-
command: "generate",
|
|
1406
|
-
kubbVersion: version,
|
|
1407
|
-
plugins: driver.plugins.map((p) => ({
|
|
1408
|
-
name: p.name,
|
|
1409
|
-
options: p.options
|
|
1410
|
-
})),
|
|
1411
|
-
hrStart,
|
|
1412
|
-
filesCreated: files.length,
|
|
1413
|
-
status: "success"
|
|
1414
|
-
}));
|
|
1669
|
+
await reportTelemetry("success");
|
|
1415
1670
|
}
|
|
1416
|
-
async function
|
|
1417
|
-
const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
|
|
1418
|
-
const events = new AsyncEventEmitter();
|
|
1419
|
-
await setupLogger(events, { logLevel: logLevel$3 });
|
|
1671
|
+
async function checkForUpdate(hooks) {
|
|
1420
1672
|
await executeIfOnline(async () => {
|
|
1421
1673
|
try {
|
|
1422
|
-
const
|
|
1423
|
-
if (
|
|
1674
|
+
const data = await (await fetch(KUBB_NPM_PACKAGE_URL)).json();
|
|
1675
|
+
if (data.version && version < data.version) await hooks.emit("kubb:version:new", {
|
|
1676
|
+
currentVersion: version,
|
|
1677
|
+
latestVersion: data.version
|
|
1678
|
+
});
|
|
1424
1679
|
} catch {}
|
|
1425
1680
|
});
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Runs the full Kubb generation lifecycle for the given CLI options.
|
|
1684
|
+
* Sets up the logger, checks for a newer version, loads configs, and calls `generate` for each config entry.
|
|
1685
|
+
*/
|
|
1686
|
+
async function run({ input, configPath, logLevel: logLevelKey, watch }) {
|
|
1687
|
+
const logLevel$3 = logLevel[logLevelKey] ?? logLevel.info;
|
|
1688
|
+
const hooks = new AsyncEventEmitter();
|
|
1689
|
+
const makeSink = await setupLogger(hooks, { logLevel: logLevel$3 });
|
|
1690
|
+
await checkForUpdate(hooks);
|
|
1426
1691
|
try {
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
await
|
|
1433
|
-
await
|
|
1692
|
+
const { configs, configPath: resolvedConfigPath } = await getConfigs({
|
|
1693
|
+
configPath,
|
|
1694
|
+
input
|
|
1695
|
+
});
|
|
1696
|
+
const relativeConfigPath = path.relative(process$1.cwd(), resolvedConfigPath);
|
|
1697
|
+
await hooks.emit("kubb:config:start");
|
|
1698
|
+
await hooks.emit("kubb:info", {
|
|
1699
|
+
message: "Config loaded",
|
|
1700
|
+
info: relativeConfigPath
|
|
1701
|
+
});
|
|
1702
|
+
await hooks.emit("kubb:success", {
|
|
1703
|
+
message: "Config loaded successfully",
|
|
1704
|
+
info: relativeConfigPath
|
|
1705
|
+
});
|
|
1706
|
+
await hooks.emit("kubb:config:end", { configs });
|
|
1707
|
+
await hooks.emit("kubb:lifecycle:start", { version });
|
|
1434
1708
|
for (const config of configs) if (isInputPath(config) && watch) await startWatcher([input || config.input.path], async (paths) => {
|
|
1435
|
-
|
|
1709
|
+
hooks.removeAll();
|
|
1436
1710
|
await generate({
|
|
1437
1711
|
input,
|
|
1438
1712
|
config,
|
|
1439
1713
|
logLevel: logLevel$3,
|
|
1440
|
-
|
|
1714
|
+
hooks,
|
|
1715
|
+
makeSink
|
|
1441
1716
|
});
|
|
1442
1717
|
clack.log.step(styleText("yellow", `Watching for changes in ${paths.join(" and ")}`));
|
|
1718
|
+
}, {
|
|
1719
|
+
info: (msg) => clack.log.info(msg),
|
|
1720
|
+
error: (msg) => clack.log.error(msg)
|
|
1443
1721
|
});
|
|
1444
1722
|
else await generate({
|
|
1445
1723
|
input,
|
|
1446
1724
|
config,
|
|
1447
1725
|
logLevel: logLevel$3,
|
|
1448
|
-
|
|
1726
|
+
hooks,
|
|
1727
|
+
makeSink
|
|
1449
1728
|
});
|
|
1450
|
-
await
|
|
1729
|
+
await hooks.emit("kubb:lifecycle:end");
|
|
1451
1730
|
} catch (error) {
|
|
1452
|
-
await
|
|
1731
|
+
await hooks.emit("kubb:error", { error: toError(error) });
|
|
1453
1732
|
process$1.exit(1);
|
|
1454
1733
|
}
|
|
1455
1734
|
}
|
|
1456
1735
|
//#endregion
|
|
1457
|
-
export {
|
|
1736
|
+
export { run };
|
|
1458
1737
|
|
|
1459
|
-
//# sourceMappingURL=
|
|
1738
|
+
//# sourceMappingURL=run-Bfbr3RaM.js.map
|