@kubb/cli 5.0.0-alpha.9 → 5.0.0-beta.2
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 +4 -2
- package/bin/kubb.js +6 -0
- package/dist/{agent-BKphjOIF.cjs → agent-0Nk--lcr.cjs} +5 -5
- package/dist/agent-0Nk--lcr.cjs.map +1 -0
- package/dist/agent-B_pirbeB.cjs +116 -0
- package/dist/agent-B_pirbeB.cjs.map +1 -0
- package/dist/{agent-5mmp7QzF.js → agent-DKeVuiUC.js} +5 -5
- package/dist/agent-DKeVuiUC.js.map +1 -0
- package/dist/agent-Ev5hU5hH.js +112 -0
- package/dist/agent-Ev5hU5hH.js.map +1 -0
- package/dist/{constants-D0XHAHeZ.cjs → constants-CnDXa1R6.cjs} +30 -60
- package/dist/constants-CnDXa1R6.cjs.map +1 -0
- package/dist/{constants-DJM9zCXm.js → constants-aL3CP_Wq.js} +23 -59
- package/dist/constants-aL3CP_Wq.js.map +1 -0
- package/dist/define-Bdn8j5VM.cjs +54 -0
- package/dist/define-Bdn8j5VM.cjs.map +1 -0
- package/dist/define-Ctii4bel.js +43 -0
- package/dist/define-Ctii4bel.js.map +1 -0
- package/dist/{errors-DBW0N9w4.cjs → errors-CLCjoSg0.cjs} +22 -6
- package/dist/errors-CLCjoSg0.cjs.map +1 -0
- package/dist/errors-CjPmyZHy.js +43 -0
- package/dist/errors-CjPmyZHy.js.map +1 -0
- package/dist/{generate-Rly1EXBN.js → generate-B3PZ6Dp-.js} +3 -3
- package/dist/generate-B3PZ6Dp-.js.map +1 -0
- package/dist/{generate-Cq5RDTBL.cjs → generate-B3jl4ukb.cjs} +559 -265
- package/dist/generate-B3jl4ukb.cjs.map +1 -0
- package/dist/{generate-DU5zzc54.cjs → generate-DL_7a7Wd.cjs} +3 -3
- package/dist/generate-DL_7a7Wd.cjs.map +1 -0
- package/dist/{generate-BHNyeQXl.js → generate-Dt_r0ELY.js} +552 -258
- package/dist/generate-Dt_r0ELY.js.map +1 -0
- package/dist/index.cjs +40 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +40 -18
- package/dist/index.js.map +1 -1
- package/dist/{init-iN7e1XwI.js → init-Bj94Nvt8.js} +4 -4
- package/dist/init-Bj94Nvt8.js.map +1 -0
- package/dist/{init-BK6inBTR.cjs → init-CZ5Xq2Hd.cjs} +45 -58
- package/dist/init-CZ5Xq2Hd.cjs.map +1 -0
- package/dist/{init-CN1JFyGX.cjs → init-CyN1oyTF.cjs} +4 -4
- package/dist/init-CyN1oyTF.cjs.map +1 -0
- package/dist/{init-BQ6zfsnw.js → init-eNRlotJK.js} +41 -54
- package/dist/init-eNRlotJK.js.map +1 -0
- package/dist/{mcp-eP1S40LZ.js → mcp-BzW703d7.js} +4 -4
- package/dist/{mcp-eP1S40LZ.js.map → mcp-BzW703d7.js.map} +1 -1
- package/dist/{mcp-CONmm_xT.cjs → mcp-CLcDV4Jm.cjs} +5 -6
- package/dist/mcp-CLcDV4Jm.cjs.map +1 -0
- package/dist/{mcp-BiGUvbWP.js → mcp-D7EIR9fR.js} +4 -5
- package/dist/mcp-D7EIR9fR.js.map +1 -0
- package/dist/{mcp-T7Q4nWbT.cjs → mcp-ZY-ONTOp.cjs} +4 -4
- package/dist/{mcp-T7Q4nWbT.cjs.map → mcp-ZY-ONTOp.cjs.map} +1 -1
- package/dist/{package-BJ6ionm6.cjs → package-D8wlStAg.cjs} +2 -2
- package/dist/package-D8wlStAg.cjs.map +1 -0
- package/dist/package-Yo-9_m5C.js +6 -0
- package/dist/package-Yo-9_m5C.js.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-DLzN4fRo.js} +8 -3
- package/dist/shell-DLzN4fRo.js.map +1 -0
- package/dist/{telemetry-DZ7IrLAU.cjs → telemetry-DN95_2pF.cjs} +50 -8
- package/dist/telemetry-DN95_2pF.cjs.map +1 -0
- package/dist/{telemetry-BF3SMlH6.js → telemetry-LgT_sdPe.js} +48 -6
- package/dist/telemetry-LgT_sdPe.js.map +1 -0
- package/dist/{validate-DAZdX_0i.js → validate-Dplr99xO.js} +4 -4
- package/dist/validate-Dplr99xO.js.map +1 -0
- package/dist/{validate-DucFMytl.cjs → validate-_8mBa63G.cjs} +4 -4
- package/dist/validate-_8mBa63G.cjs.map +1 -0
- package/dist/{validate-BImbbx1t.js → validate-kLJoT_hi.js} +5 -13
- package/dist/validate-kLJoT_hi.js.map +1 -0
- package/dist/{validate-ujLCYSWU.cjs → validate-yKKzqEZ5.cjs} +6 -14
- package/dist/validate-yKKzqEZ5.cjs.map +1 -0
- package/package.json +47 -46
- package/src/commands/agent/start.ts +20 -4
- package/src/commands/generate.ts +35 -6
- package/src/commands/init.ts +6 -1
- package/src/commands/validate.ts +6 -1
- package/src/constants.ts +19 -38
- package/src/index.ts +7 -10
- package/src/loggers/clackLogger.ts +54 -46
- package/src/loggers/fileSystemLogger.ts +15 -16
- package/src/loggers/githubActionsLogger.ts +23 -24
- package/src/loggers/plainLogger.ts +22 -23
- package/src/runners/agent.ts +81 -34
- package/src/runners/generate.ts +90 -100
- package/src/runners/init.ts +24 -51
- package/src/runners/mcp.ts +17 -4
- package/src/runners/validate.ts +19 -15
- package/src/utils/executeHooks.ts +15 -15
- package/src/utils/flags.ts +1 -2
- package/src/utils/getConfig.ts +10 -0
- package/src/utils/getCosmiConfig.ts +21 -12
- package/src/utils/getSummary.ts +1 -1
- package/src/utils/runHook.ts +29 -13
- package/src/utils/telemetry.ts +16 -3
- package/bin/kubb.cjs +0 -18
- package/dist/agent-5mmp7QzF.js.map +0 -1
- 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.map +0 -1
- 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.map +0 -1
- package/dist/init-BQ6zfsnw.js.map +0 -1
- package/dist/init-CN1JFyGX.cjs.map +0 -1
- 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.map +0 -1
- package/dist/mcp-CONmm_xT.cjs.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.map +0 -1
- package/dist/validate-DAZdX_0i.js.map +0 -1
- package/dist/validate-DucFMytl.cjs.map +0 -1
- package/dist/validate-ujLCYSWU.cjs.map +0 -1
- package/src/utils/jiti.ts +0 -9
package/src/runners/generate.ts
CHANGED
|
@@ -4,25 +4,13 @@ import process from 'node:process'
|
|
|
4
4
|
import { styleText } from 'node:util'
|
|
5
5
|
import * as clack from '@clack/prompts'
|
|
6
6
|
import type { AsyncEventEmitter } from '@internals/utils'
|
|
7
|
-
import { AsyncEventEmitter as AsyncEventEmitterClass, executeIfOnline, toError } from '@internals/utils'
|
|
8
|
-
import {
|
|
9
|
-
type CLIOptions,
|
|
10
|
-
type Config,
|
|
11
|
-
detectFormatter,
|
|
12
|
-
detectLinter,
|
|
13
|
-
formatters,
|
|
14
|
-
getConfigs,
|
|
15
|
-
isInputPath,
|
|
16
|
-
type KubbEvents,
|
|
17
|
-
linters,
|
|
18
|
-
logLevel as logLevelMap,
|
|
19
|
-
safeBuild,
|
|
20
|
-
setup,
|
|
21
|
-
} from '@kubb/core'
|
|
7
|
+
import { AsyncEventEmitter as AsyncEventEmitterClass, detectFormatter, detectLinter, executeIfOnline, formatters, linters, toError } from '@internals/utils'
|
|
8
|
+
import { type CLIOptions, type Config, createKubb, isInputPath, type KubbHooks, logLevel as logLevelMap } from '@kubb/core'
|
|
22
9
|
import { version } from '../../package.json'
|
|
23
10
|
import { KUBB_NPM_PACKAGE_URL } from '../constants.ts'
|
|
24
11
|
import { setupLogger } from '../loggers/utils.ts'
|
|
25
12
|
import { executeHooks } from '../utils/executeHooks.ts'
|
|
13
|
+
import { getConfigs } from '../utils/getConfig.ts'
|
|
26
14
|
import { getCosmiConfig } from '../utils/getCosmiConfig.ts'
|
|
27
15
|
import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
|
|
28
16
|
import { startWatcher } from '../utils/watcher.ts'
|
|
@@ -30,7 +18,7 @@ import { startWatcher } from '../utils/watcher.ts'
|
|
|
30
18
|
type GenerateProps = {
|
|
31
19
|
input?: string
|
|
32
20
|
config: Config
|
|
33
|
-
|
|
21
|
+
hooks: AsyncEventEmitter<KubbHooks>
|
|
34
22
|
logLevel: number
|
|
35
23
|
}
|
|
36
24
|
|
|
@@ -38,7 +26,7 @@ type ToolMap = typeof formatters | typeof linters
|
|
|
38
26
|
|
|
39
27
|
type RunToolPassOptions = {
|
|
40
28
|
toolValue: string
|
|
41
|
-
detect: () => Promise<string |
|
|
29
|
+
detect: () => Promise<string | null>
|
|
42
30
|
toolMap: ToolMap
|
|
43
31
|
/** Short noun used in "Auto-detected <toolLabel>:" message, e.g. "formatter" or "linter". */
|
|
44
32
|
toolLabel: string
|
|
@@ -48,7 +36,7 @@ type RunToolPassOptions = {
|
|
|
48
36
|
configName: string | undefined
|
|
49
37
|
outputPath: string
|
|
50
38
|
logLevel: number
|
|
51
|
-
|
|
39
|
+
hooks: AsyncEventEmitter<KubbHooks>
|
|
52
40
|
onStart: () => Promise<void>
|
|
53
41
|
onEnd: () => Promise<void>
|
|
54
42
|
}
|
|
@@ -63,7 +51,7 @@ async function runToolPass({
|
|
|
63
51
|
configName,
|
|
64
52
|
outputPath,
|
|
65
53
|
logLevel,
|
|
66
|
-
|
|
54
|
+
hooks,
|
|
67
55
|
onStart,
|
|
68
56
|
onEnd,
|
|
69
57
|
}: RunToolPassOptions) {
|
|
@@ -73,13 +61,15 @@ async function runToolPass({
|
|
|
73
61
|
if (resolvedTool === 'auto') {
|
|
74
62
|
const detected = await detect()
|
|
75
63
|
if (!detected) {
|
|
76
|
-
await
|
|
64
|
+
await hooks.emit('kubb:warn', { message: noToolMessage })
|
|
77
65
|
} else {
|
|
78
66
|
resolvedTool = detected
|
|
79
|
-
await
|
|
67
|
+
await hooks.emit('kubb:info', { message: `Auto-detected ${toolLabel}: ${styleText('dim', resolvedTool)}` })
|
|
80
68
|
}
|
|
81
69
|
}
|
|
82
70
|
|
|
71
|
+
let toolError: Error | undefined
|
|
72
|
+
|
|
83
73
|
if (resolvedTool && resolvedTool !== 'auto' && resolvedTool in toolMap) {
|
|
84
74
|
const toolConfig = toolMap[resolvedTool as keyof ToolMap]
|
|
85
75
|
|
|
@@ -87,33 +77,32 @@ async function runToolPass({
|
|
|
87
77
|
const hookId = createHash('sha256').update([configName, resolvedTool].filter(Boolean).join('-')).digest('hex')
|
|
88
78
|
|
|
89
79
|
// Wire up the hook:end listener BEFORE emitting hook:start to avoid the race condition
|
|
90
|
-
// where hook:end fires synchronously inside emit('hook:start') before the listener is registered.
|
|
80
|
+
// where hook:end fires synchronously inside emit('kubb:hook:start') before the listener is registered.
|
|
91
81
|
const hookEndPromise = new Promise<void>((resolve, reject) => {
|
|
92
|
-
const handler = (
|
|
93
|
-
if (id !== hookId) return
|
|
94
|
-
|
|
95
|
-
if (!success) {
|
|
96
|
-
reject(error ?? new Error(`${toolConfig.errorMessage}`))
|
|
82
|
+
const handler = (ctx: { id?: string; command: string; args?: readonly string[]; success: boolean; error: Error | null }) => {
|
|
83
|
+
if (ctx.id !== hookId) return
|
|
84
|
+
hooks.off('kubb:hook:end', handler)
|
|
85
|
+
if (!ctx.success) {
|
|
86
|
+
reject(ctx.error ?? new Error(`${toolConfig.errorMessage}`))
|
|
97
87
|
return
|
|
98
88
|
}
|
|
99
|
-
|
|
100
|
-
.emit(
|
|
101
|
-
|
|
102
|
-
[
|
|
89
|
+
hooks
|
|
90
|
+
.emit('kubb:success', {
|
|
91
|
+
message: [
|
|
103
92
|
`${successPrefix} with ${styleText('dim', resolvedTool)}`,
|
|
104
93
|
logLevel >= logLevelMap.info ? `on ${styleText('dim', outputPath)}` : undefined,
|
|
105
94
|
'successfully',
|
|
106
95
|
]
|
|
107
96
|
.filter(Boolean)
|
|
108
97
|
.join(' '),
|
|
109
|
-
)
|
|
98
|
+
})
|
|
110
99
|
.then(resolve)
|
|
111
100
|
.catch(reject)
|
|
112
101
|
}
|
|
113
|
-
|
|
102
|
+
hooks.on('kubb:hook:end', handler)
|
|
114
103
|
})
|
|
115
104
|
|
|
116
|
-
await
|
|
105
|
+
await hooks.emit('kubb:hook:start', {
|
|
117
106
|
id: hookId,
|
|
118
107
|
command: toolConfig.command,
|
|
119
108
|
args: toolConfig.args(outputPath),
|
|
@@ -121,59 +110,52 @@ async function runToolPass({
|
|
|
121
110
|
|
|
122
111
|
await hookEndPromise
|
|
123
112
|
} catch (caughtError) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
113
|
+
// Use the actual error from the hook. toolConfig.errorMessage (e.g. "Oxlint not found")
|
|
114
|
+
// is misleading when the binary was found and ran but exited with a non-zero code.
|
|
115
|
+
// runHook already emitted kubb:error for binary-not-found cases; here we surface the
|
|
116
|
+
// real reason (e.g. "Hook execute failed: oxlint --fix …") for non-zero exits.
|
|
117
|
+
const err = toError(caughtError)
|
|
118
|
+
await hooks.emit('kubb:error', { error: err })
|
|
119
|
+
toolError = err
|
|
127
120
|
}
|
|
128
121
|
}
|
|
129
122
|
|
|
130
123
|
await onEnd()
|
|
124
|
+
|
|
125
|
+
if (toolError) {
|
|
126
|
+
throw toolError
|
|
127
|
+
}
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
async function generate(
|
|
134
|
-
const
|
|
130
|
+
async function generate(options: GenerateProps): Promise<void> {
|
|
131
|
+
const { input, hooks, logLevel } = options
|
|
132
|
+
|
|
135
133
|
const hrStart = process.hrtime()
|
|
134
|
+
const inputPath = input ?? ('path' in options.config.input ? options.config.input.path : undefined)
|
|
136
135
|
|
|
137
136
|
const config: Config = {
|
|
138
|
-
...
|
|
139
|
-
root: userConfig.root || process.cwd(),
|
|
137
|
+
...options.config,
|
|
140
138
|
input: inputPath
|
|
141
139
|
? {
|
|
142
|
-
...
|
|
140
|
+
...options.config.input,
|
|
143
141
|
path: inputPath,
|
|
144
142
|
}
|
|
145
|
-
:
|
|
146
|
-
output
|
|
147
|
-
|
|
148
|
-
barrelType: 'named',
|
|
149
|
-
extension: {
|
|
150
|
-
'.ts': '.ts',
|
|
151
|
-
},
|
|
152
|
-
format: 'prettier',
|
|
153
|
-
...userConfig.output,
|
|
154
|
-
},
|
|
155
|
-
}
|
|
143
|
+
: options.config.input,
|
|
144
|
+
...options.config.output,
|
|
145
|
+
} satisfies Config
|
|
156
146
|
|
|
157
|
-
|
|
147
|
+
const kubb = createKubb(config, { hooks })
|
|
148
|
+
await kubb.setup()
|
|
158
149
|
|
|
159
|
-
await
|
|
150
|
+
await hooks.emit('kubb:generation:start', { config })
|
|
160
151
|
|
|
161
|
-
|
|
162
|
-
config,
|
|
163
|
-
events,
|
|
164
|
-
})
|
|
152
|
+
await hooks.emit('kubb:info', { message: config.name ? `Setup generation ${styleText('bold', config.name)}` : 'Setup generation', info: inputPath })
|
|
165
153
|
|
|
166
|
-
await
|
|
154
|
+
await hooks.emit('kubb:info', { message: config.name ? `Build generation ${styleText('bold', config.name)}` : 'Build generation', info: inputPath })
|
|
167
155
|
|
|
168
|
-
const { files, failedPlugins, pluginTimings, error } = await safeBuild(
|
|
169
|
-
{
|
|
170
|
-
config,
|
|
171
|
-
events,
|
|
172
|
-
},
|
|
173
|
-
{ driver, fabric, events, sources },
|
|
174
|
-
)
|
|
156
|
+
const { files, failedPlugins, pluginTimings, error, driver } = await kubb.safeBuild()
|
|
175
157
|
|
|
176
|
-
await
|
|
158
|
+
await hooks.emit('kubb:info', { message: 'Load summary' })
|
|
177
159
|
|
|
178
160
|
// Handle build failures (either from failed plugins or general errors)
|
|
179
161
|
|
|
@@ -188,12 +170,13 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
|
|
|
188
170
|
].filter(Boolean)
|
|
189
171
|
|
|
190
172
|
for (const err of allErrors) {
|
|
191
|
-
await
|
|
173
|
+
await hooks.emit('kubb:error', { error: err })
|
|
192
174
|
}
|
|
193
175
|
|
|
194
|
-
await
|
|
176
|
+
await hooks.emit('kubb:generation:end', { config, files, sources: kubb.sources })
|
|
195
177
|
|
|
196
|
-
await
|
|
178
|
+
await hooks.emit('kubb:generation:summary', {
|
|
179
|
+
config,
|
|
197
180
|
failedPlugins,
|
|
198
181
|
filesCreated: files.length,
|
|
199
182
|
status: 'failed',
|
|
@@ -205,7 +188,10 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
|
|
|
205
188
|
buildTelemetryEvent({
|
|
206
189
|
command: 'generate',
|
|
207
190
|
kubbVersion: version,
|
|
208
|
-
plugins: driver.plugins.
|
|
191
|
+
plugins: Array.from(driver.plugins.values(), (p) => ({
|
|
192
|
+
name: p.name,
|
|
193
|
+
options: p.options as Record<string, unknown>,
|
|
194
|
+
})),
|
|
209
195
|
hrStart,
|
|
210
196
|
filesCreated: files.length,
|
|
211
197
|
status: 'failed',
|
|
@@ -215,8 +201,8 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
|
|
|
215
201
|
process.exit(1)
|
|
216
202
|
}
|
|
217
203
|
|
|
218
|
-
await
|
|
219
|
-
await
|
|
204
|
+
await hooks.emit('kubb:success', { message: 'Generation successfully', info: inputPath })
|
|
205
|
+
await hooks.emit('kubb:generation:end', { config, files, sources: kubb.sources })
|
|
220
206
|
|
|
221
207
|
const outputPath = path.resolve(config.root, config.output.path)
|
|
222
208
|
|
|
@@ -227,13 +213,13 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
|
|
|
227
213
|
toolMap: formatters,
|
|
228
214
|
toolLabel: 'formatter',
|
|
229
215
|
successPrefix: 'Formatting',
|
|
230
|
-
noToolMessage: 'No formatter found (
|
|
216
|
+
noToolMessage: 'No formatter found (oxfmt, biome, or prettier). Skipping formatting.',
|
|
231
217
|
configName: config.name,
|
|
232
218
|
outputPath,
|
|
233
219
|
logLevel,
|
|
234
|
-
|
|
235
|
-
onStart: () =>
|
|
236
|
-
onEnd: () =>
|
|
220
|
+
hooks,
|
|
221
|
+
onStart: () => hooks.emit('kubb:format:start'),
|
|
222
|
+
onEnd: () => hooks.emit('kubb:format:end'),
|
|
237
223
|
})
|
|
238
224
|
}
|
|
239
225
|
|
|
@@ -244,25 +230,26 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
|
|
|
244
230
|
toolMap: linters,
|
|
245
231
|
toolLabel: 'linter',
|
|
246
232
|
successPrefix: 'Linting',
|
|
247
|
-
noToolMessage: 'No linter found (
|
|
233
|
+
noToolMessage: 'No linter found (oxlint, biome, or eslint). Skipping linting.',
|
|
248
234
|
configName: config.name,
|
|
249
235
|
outputPath,
|
|
250
236
|
logLevel,
|
|
251
|
-
|
|
252
|
-
onStart: () =>
|
|
253
|
-
onEnd: () =>
|
|
237
|
+
hooks,
|
|
238
|
+
onStart: () => hooks.emit('kubb:lint:start'),
|
|
239
|
+
onEnd: () => hooks.emit('kubb:lint:end'),
|
|
254
240
|
})
|
|
255
241
|
}
|
|
256
242
|
|
|
257
243
|
if (config.hooks) {
|
|
258
|
-
await
|
|
259
|
-
await executeHooks({
|
|
244
|
+
await hooks.emit('kubb:hooks:start')
|
|
245
|
+
await executeHooks({ configHooks: config.hooks, hooks })
|
|
260
246
|
|
|
261
|
-
await
|
|
247
|
+
await hooks.emit('kubb:hooks:end')
|
|
262
248
|
}
|
|
263
249
|
|
|
264
250
|
// Only reached when there are no failures (process.exit(1) is called above otherwise)
|
|
265
|
-
await
|
|
251
|
+
await hooks.emit('kubb:generation:summary', {
|
|
252
|
+
config,
|
|
266
253
|
failedPlugins,
|
|
267
254
|
filesCreated: files.length,
|
|
268
255
|
status: 'success',
|
|
@@ -273,7 +260,10 @@ async function generate({ input, config: userConfig, events, logLevel }: Generat
|
|
|
273
260
|
const telemetryEvent = buildTelemetryEvent({
|
|
274
261
|
command: 'generate',
|
|
275
262
|
kubbVersion: version,
|
|
276
|
-
plugins: driver.plugins.
|
|
263
|
+
plugins: Array.from(driver.plugins.values(), (p) => ({
|
|
264
|
+
name: p.name,
|
|
265
|
+
options: p.options as Record<string, unknown>,
|
|
266
|
+
})),
|
|
277
267
|
hrStart,
|
|
278
268
|
filesCreated: files.length,
|
|
279
269
|
status: 'success',
|
|
@@ -291,9 +281,9 @@ type GenerateCommandOptions = {
|
|
|
291
281
|
|
|
292
282
|
export async function runGenerateCommand({ input, configPath, logLevel: logLevelKey, watch }: GenerateCommandOptions): Promise<void> {
|
|
293
283
|
const logLevel = logLevelMap[logLevelKey as keyof typeof logLevelMap] ?? logLevelMap.info
|
|
294
|
-
const
|
|
284
|
+
const hooks = new AsyncEventEmitterClass<KubbHooks>()
|
|
295
285
|
|
|
296
|
-
await setupLogger(
|
|
286
|
+
await setupLogger(hooks, { logLevel })
|
|
297
287
|
|
|
298
288
|
await executeIfOnline(async () => {
|
|
299
289
|
try {
|
|
@@ -302,7 +292,7 @@ export async function runGenerateCommand({ input, configPath, logLevel: logLevel
|
|
|
302
292
|
const latestVersion = data.version
|
|
303
293
|
|
|
304
294
|
if (latestVersion && version < latestVersion) {
|
|
305
|
-
await
|
|
295
|
+
await hooks.emit('kubb:version:new', { currentVersion: version, latestVersion })
|
|
306
296
|
}
|
|
307
297
|
} catch {
|
|
308
298
|
// Ignore network errors for version check
|
|
@@ -313,31 +303,31 @@ export async function runGenerateCommand({ input, configPath, logLevel: logLevel
|
|
|
313
303
|
const result = await getCosmiConfig('kubb', configPath)
|
|
314
304
|
const configs = await getConfigs(result.config, { input } as CLIOptions)
|
|
315
305
|
|
|
316
|
-
await
|
|
317
|
-
await
|
|
318
|
-
await
|
|
319
|
-
await
|
|
306
|
+
await hooks.emit('kubb:config:start')
|
|
307
|
+
await hooks.emit('kubb:info', { message: 'Config loaded', info: path.relative(process.cwd(), result.filepath) })
|
|
308
|
+
await hooks.emit('kubb:success', { message: 'Config loaded successfully', info: path.relative(process.cwd(), result.filepath) })
|
|
309
|
+
await hooks.emit('kubb:config:end', { configs })
|
|
320
310
|
|
|
321
|
-
await
|
|
311
|
+
await hooks.emit('kubb:lifecycle:start', { version })
|
|
322
312
|
|
|
323
313
|
for (const config of configs) {
|
|
324
314
|
if (isInputPath(config) && watch) {
|
|
325
315
|
await startWatcher([input || config.input.path], async (paths) => {
|
|
326
316
|
// remove to avoid duplicate listeners after each change
|
|
327
|
-
|
|
317
|
+
hooks.removeAll()
|
|
328
318
|
|
|
329
|
-
await generate({ input, config, logLevel,
|
|
319
|
+
await generate({ input, config, logLevel, hooks })
|
|
330
320
|
|
|
331
321
|
clack.log.step(styleText('yellow', `Watching for changes in ${paths.join(' and ')}`))
|
|
332
322
|
})
|
|
333
323
|
} else {
|
|
334
|
-
await generate({ input, config, logLevel,
|
|
324
|
+
await generate({ input, config, logLevel, hooks })
|
|
335
325
|
}
|
|
336
326
|
}
|
|
337
327
|
|
|
338
|
-
await
|
|
328
|
+
await hooks.emit('kubb:lifecycle:end')
|
|
339
329
|
} catch (error) {
|
|
340
|
-
await
|
|
330
|
+
await hooks.emit('kubb:error', { error: toError(error) })
|
|
341
331
|
process.exit(1)
|
|
342
332
|
}
|
|
343
333
|
}
|
package/src/runners/init.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { styleText } from 'node:util'
|
|
|
5
5
|
import * as clack from '@clack/prompts'
|
|
6
6
|
import type { PackageManagerInfo } from '@internals/utils'
|
|
7
7
|
import { detectPackageManager } from '@internals/utils'
|
|
8
|
-
import { initDefaults, pluginDefaultConfigs } from '../constants.ts'
|
|
8
|
+
import { initDefaults, KUBB_CONFIG_FILENAME, pluginDefaultConfigs } from '../constants.ts'
|
|
9
9
|
import { hasPackageJson, initPackageJson, installPackages } from '../utils/packageManager.ts'
|
|
10
10
|
|
|
11
11
|
type PluginOption = {
|
|
@@ -14,67 +14,38 @@ type PluginOption = {
|
|
|
14
14
|
hint?: string
|
|
15
15
|
packageName: string
|
|
16
16
|
importName: string
|
|
17
|
-
category: '
|
|
17
|
+
category: 'types' | 'client' | 'framework' | 'validation' | 'testing' | 'mocks' | 'documentation' | 'ai'
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const availablePlugins: PluginOption[] = [
|
|
21
|
-
{
|
|
22
|
-
value: 'plugin-oas',
|
|
23
|
-
label: 'OpenAPI Parser',
|
|
24
|
-
hint: 'Required',
|
|
25
|
-
packageName: '@kubb/plugin-oas',
|
|
26
|
-
importName: 'pluginOas',
|
|
27
|
-
category: 'core',
|
|
28
|
-
},
|
|
29
21
|
{
|
|
30
22
|
value: 'plugin-ts',
|
|
31
23
|
label: 'TypeScript',
|
|
32
24
|
hint: 'Recommended',
|
|
33
25
|
packageName: '@kubb/plugin-ts',
|
|
34
26
|
importName: 'pluginTs',
|
|
35
|
-
category: '
|
|
27
|
+
category: 'types',
|
|
36
28
|
},
|
|
37
29
|
{
|
|
38
30
|
value: 'plugin-client',
|
|
39
31
|
label: 'Client (Fetch/Axios)',
|
|
40
32
|
packageName: '@kubb/plugin-client',
|
|
41
33
|
importName: 'pluginClient',
|
|
42
|
-
category: '
|
|
34
|
+
category: 'client',
|
|
43
35
|
},
|
|
44
36
|
{
|
|
45
37
|
value: 'plugin-react-query',
|
|
46
38
|
label: 'React Query / TanStack Query',
|
|
47
39
|
packageName: '@kubb/plugin-react-query',
|
|
48
40
|
importName: 'pluginReactQuery',
|
|
49
|
-
category: '
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
value: 'plugin-solid-query',
|
|
53
|
-
label: 'Solid Query',
|
|
54
|
-
packageName: '@kubb/plugin-solid-query',
|
|
55
|
-
importName: 'pluginSolidQuery',
|
|
56
|
-
category: 'query',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
value: 'plugin-svelte-query',
|
|
60
|
-
label: 'Svelte Query',
|
|
61
|
-
packageName: '@kubb/plugin-svelte-query',
|
|
62
|
-
importName: 'pluginSvelteQuery',
|
|
63
|
-
category: 'query',
|
|
41
|
+
category: 'framework',
|
|
64
42
|
},
|
|
65
43
|
{
|
|
66
44
|
value: 'plugin-vue-query',
|
|
67
45
|
label: 'Vue Query',
|
|
68
46
|
packageName: '@kubb/plugin-vue-query',
|
|
69
47
|
importName: 'pluginVueQuery',
|
|
70
|
-
category: '
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
value: 'plugin-swr',
|
|
74
|
-
label: 'SWR',
|
|
75
|
-
packageName: '@kubb/plugin-swr',
|
|
76
|
-
importName: 'pluginSwr',
|
|
77
|
-
category: 'query',
|
|
48
|
+
category: 'framework',
|
|
78
49
|
},
|
|
79
50
|
{
|
|
80
51
|
value: 'plugin-zod',
|
|
@@ -88,14 +59,14 @@ const availablePlugins: PluginOption[] = [
|
|
|
88
59
|
label: 'Faker.js Mocks',
|
|
89
60
|
packageName: '@kubb/plugin-faker',
|
|
90
61
|
importName: 'pluginFaker',
|
|
91
|
-
category: '
|
|
62
|
+
category: 'mocks',
|
|
92
63
|
},
|
|
93
64
|
{
|
|
94
65
|
value: 'plugin-msw',
|
|
95
66
|
label: 'MSW Handlers',
|
|
96
67
|
packageName: '@kubb/plugin-msw',
|
|
97
68
|
importName: 'pluginMsw',
|
|
98
|
-
category: '
|
|
69
|
+
category: 'mocks',
|
|
99
70
|
},
|
|
100
71
|
{
|
|
101
72
|
value: 'plugin-cypress',
|
|
@@ -104,12 +75,19 @@ const availablePlugins: PluginOption[] = [
|
|
|
104
75
|
importName: 'pluginCypress',
|
|
105
76
|
category: 'testing',
|
|
106
77
|
},
|
|
78
|
+
{
|
|
79
|
+
value: 'plugin-mcp',
|
|
80
|
+
label: 'MCP Server (AI / Model Context Protocol)',
|
|
81
|
+
packageName: '@kubb/plugin-mcp',
|
|
82
|
+
importName: 'pluginMcp',
|
|
83
|
+
category: 'ai',
|
|
84
|
+
},
|
|
107
85
|
{
|
|
108
86
|
value: 'plugin-redoc',
|
|
109
87
|
label: 'ReDoc Documentation',
|
|
110
88
|
packageName: '@kubb/plugin-redoc',
|
|
111
89
|
importName: 'pluginRedoc',
|
|
112
|
-
category: '
|
|
90
|
+
category: 'documentation',
|
|
113
91
|
},
|
|
114
92
|
]
|
|
115
93
|
|
|
@@ -123,7 +101,7 @@ function generateConfigFile(selectedPlugins: PluginOption[], inputPath: string,
|
|
|
123
101
|
})
|
|
124
102
|
.join('\n')
|
|
125
103
|
|
|
126
|
-
return `import { defineConfig } from '
|
|
104
|
+
return `import { defineConfig } from 'kubb'
|
|
127
105
|
${imports}
|
|
128
106
|
|
|
129
107
|
export default defineConfig({
|
|
@@ -251,13 +229,8 @@ export async function runInit({ yes, version }: InitOptions): Promise<void> {
|
|
|
251
229
|
selectedPlugins = availablePlugins.filter((plugin) => (selectedPluginValues as string[]).includes(plugin.value))
|
|
252
230
|
}
|
|
253
231
|
|
|
254
|
-
// Ensure plugin-oas is always included
|
|
255
|
-
if (!selectedPlugins.find((p) => p.value === 'plugin-oas')) {
|
|
256
|
-
selectedPlugins.unshift(availablePlugins.find((p) => p.value === 'plugin-oas')!)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
232
|
// Install packages
|
|
260
|
-
const packagesToInstall = ['
|
|
233
|
+
const packagesToInstall = ['kubb', ...selectedPlugins.map((p) => p.packageName)]
|
|
261
234
|
|
|
262
235
|
const spinner = clack.spinner()
|
|
263
236
|
spinner.start(`Installing ${packagesToInstall.length} packages with ${packageManager.name}`)
|
|
@@ -272,17 +245,17 @@ export async function runInit({ yes, version }: InitOptions): Promise<void> {
|
|
|
272
245
|
|
|
273
246
|
// Generate config file
|
|
274
247
|
const configSpinner = clack.spinner()
|
|
275
|
-
configSpinner.start(
|
|
248
|
+
configSpinner.start(`Creating ${KUBB_CONFIG_FILENAME}`)
|
|
276
249
|
|
|
277
250
|
const configContent = generateConfigFile(selectedPlugins, inputPath, outputPath)
|
|
278
|
-
const configPath = path.join(cwd,
|
|
251
|
+
const configPath = path.join(cwd, KUBB_CONFIG_FILENAME)
|
|
279
252
|
|
|
280
253
|
if (fs.existsSync(configPath)) {
|
|
281
|
-
configSpinner.stop(
|
|
254
|
+
configSpinner.stop(`${KUBB_CONFIG_FILENAME} already exists`)
|
|
282
255
|
|
|
283
256
|
if (!yes) {
|
|
284
257
|
const shouldOverwrite = await clack.confirm({
|
|
285
|
-
message:
|
|
258
|
+
message: `${KUBB_CONFIG_FILENAME} already exists. Overwrite?`,
|
|
286
259
|
initialValue: false,
|
|
287
260
|
})
|
|
288
261
|
|
|
@@ -291,12 +264,12 @@ export async function runInit({ yes, version }: InitOptions): Promise<void> {
|
|
|
291
264
|
}
|
|
292
265
|
}
|
|
293
266
|
|
|
294
|
-
configSpinner.start(
|
|
267
|
+
configSpinner.start(`Overwriting ${KUBB_CONFIG_FILENAME}`)
|
|
295
268
|
}
|
|
296
269
|
|
|
297
270
|
fs.writeFileSync(configPath, configContent, 'utf-8')
|
|
298
271
|
|
|
299
|
-
configSpinner.stop(
|
|
272
|
+
configSpinner.stop(`Created ${KUBB_CONFIG_FILENAME}`)
|
|
300
273
|
|
|
301
274
|
clack.outro(
|
|
302
275
|
styleText('green', '✓ All set!') +
|
package/src/runners/mcp.ts
CHANGED
|
@@ -2,7 +2,6 @@ import process from 'node:process'
|
|
|
2
2
|
import { styleText } from 'node:util'
|
|
3
3
|
import { getErrorMessage } from '@internals/utils'
|
|
4
4
|
import type * as McpModule from '@kubb/mcp'
|
|
5
|
-
import { jiti } from '../utils/jiti.ts'
|
|
6
5
|
import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
|
|
7
6
|
|
|
8
7
|
type McpOptions = {
|
|
@@ -12,7 +11,7 @@ type McpOptions = {
|
|
|
12
11
|
export async function runMcp({ version }: McpOptions): Promise<void> {
|
|
13
12
|
let mod: typeof McpModule
|
|
14
13
|
try {
|
|
15
|
-
mod = (await
|
|
14
|
+
mod = (await import('@kubb/mcp')) as typeof McpModule
|
|
16
15
|
} catch (_e) {
|
|
17
16
|
console.error(`Import of '@kubb/mcp' is required to start the MCP server`)
|
|
18
17
|
process.exit(1)
|
|
@@ -24,9 +23,23 @@ export async function runMcp({ version }: McpOptions): Promise<void> {
|
|
|
24
23
|
console.log('⏳ Starting MCP server...')
|
|
25
24
|
console.warn(styleText('yellow', 'This feature is still under development — use with caution'))
|
|
26
25
|
run()
|
|
27
|
-
await sendTelemetry(
|
|
26
|
+
await sendTelemetry(
|
|
27
|
+
buildTelemetryEvent({
|
|
28
|
+
command: 'mcp',
|
|
29
|
+
kubbVersion: version,
|
|
30
|
+
hrStart,
|
|
31
|
+
status: 'success',
|
|
32
|
+
}),
|
|
33
|
+
)
|
|
28
34
|
} catch (error) {
|
|
29
|
-
await sendTelemetry(
|
|
35
|
+
await sendTelemetry(
|
|
36
|
+
buildTelemetryEvent({
|
|
37
|
+
command: 'mcp',
|
|
38
|
+
kubbVersion: version,
|
|
39
|
+
hrStart,
|
|
40
|
+
status: 'failed',
|
|
41
|
+
}),
|
|
42
|
+
)
|
|
30
43
|
console.error(getErrorMessage(error))
|
|
31
44
|
}
|
|
32
45
|
}
|
package/src/runners/validate.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import process from 'node:process'
|
|
2
2
|
import { getErrorMessage } from '@internals/utils'
|
|
3
|
-
import
|
|
4
|
-
import { jiti } from '../utils/jiti.ts'
|
|
3
|
+
import { parseDocument, validateDocument } from '@kubb/adapter-oas'
|
|
5
4
|
import { buildTelemetryEvent, sendTelemetry } from '../utils/telemetry.ts'
|
|
6
5
|
|
|
7
6
|
type ValidateOptions = {
|
|
@@ -10,24 +9,29 @@ type ValidateOptions = {
|
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
export async function runValidate({ input, version }: ValidateOptions): Promise<void> {
|
|
13
|
-
let mod: typeof OasModule
|
|
14
|
-
try {
|
|
15
|
-
mod = (await jiti.import('@kubb/oas', { default: true })) as typeof OasModule
|
|
16
|
-
} catch (_e) {
|
|
17
|
-
console.error(`Import of '@kubb/oas' is required to do validation`)
|
|
18
|
-
process.exit(1)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const { parse } = mod
|
|
22
12
|
const hrStart = process.hrtime()
|
|
23
13
|
try {
|
|
24
|
-
const
|
|
25
|
-
await
|
|
14
|
+
const document = await parseDocument(input)
|
|
15
|
+
await validateDocument(document, { throwOnError: true })
|
|
26
16
|
|
|
27
|
-
await sendTelemetry(
|
|
17
|
+
await sendTelemetry(
|
|
18
|
+
buildTelemetryEvent({
|
|
19
|
+
command: 'validate',
|
|
20
|
+
kubbVersion: version,
|
|
21
|
+
hrStart,
|
|
22
|
+
status: 'success',
|
|
23
|
+
}),
|
|
24
|
+
)
|
|
28
25
|
console.log('✅ Validation success')
|
|
29
26
|
} catch (error) {
|
|
30
|
-
await sendTelemetry(
|
|
27
|
+
await sendTelemetry(
|
|
28
|
+
buildTelemetryEvent({
|
|
29
|
+
command: 'validate',
|
|
30
|
+
kubbVersion: version,
|
|
31
|
+
hrStart,
|
|
32
|
+
status: 'failed',
|
|
33
|
+
}),
|
|
34
|
+
)
|
|
31
35
|
console.error('❌ Validation failed')
|
|
32
36
|
console.error(getErrorMessage(error))
|
|
33
37
|
process.exit(1)
|