@kubb/mcp 5.0.0-beta.1 → 5.0.0-beta.11
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 +57 -20
- package/dist/index.cjs +310 -153
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.js +304 -154
- package/dist/index.js.map +1 -1
- package/package.json +15 -11
- package/src/index.ts +5 -2
- package/src/schemas/generateSchema.ts +11 -10
- package/src/schemas/initSchema.ts +7 -0
- package/src/schemas/validateSchema.ts +5 -0
- package/src/server.ts +34 -41
- package/src/tools/generate.ts +113 -177
- package/src/tools/init.ts +37 -0
- package/src/tools/validate.ts +25 -0
- package/src/utils/loadUserConfig.ts +32 -31
- package/src/utils/resolveUserConfig.ts +5 -20
package/src/tools/generate.ts
CHANGED
|
@@ -1,210 +1,146 @@
|
|
|
1
|
-
import { AsyncEventEmitter } from '@internals/utils'
|
|
1
|
+
import { AsyncEventEmitter, toError } from '@internals/utils'
|
|
2
2
|
import { type Config, createKubb, type KubbHooks } from '@kubb/core'
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import type
|
|
3
|
+
import { defineTool } from 'tmcp/tool'
|
|
4
|
+
import { tool } from 'tmcp/utils'
|
|
5
|
+
import type * as v from 'valibot'
|
|
6
|
+
import { generateSchema } from '../schemas/generateSchema.ts'
|
|
6
7
|
import { NotifyTypes } from '../types.ts'
|
|
7
8
|
import { loadUserConfig } from '../utils/loadUserConfig.ts'
|
|
8
9
|
import { resolveCwd } from '../utils/resolveCwd.ts'
|
|
9
10
|
import { resolveUserConfig } from '../utils/resolveUserConfig.ts'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {
|
|
20
|
-
const { config: configPath, input, output, logLevel } = schema
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const hooks = new AsyncEventEmitter<KubbHooks>()
|
|
24
|
-
const messages: string[] = []
|
|
25
|
-
|
|
26
|
-
// Helper to send notifications
|
|
27
|
-
const notify = async (type: string, message: string, data?: Record<string, unknown>) => {
|
|
28
|
-
messages.push(`${type}: ${message}`)
|
|
29
|
-
|
|
30
|
-
await handler.sendNotification('kubb/progress', {
|
|
31
|
-
type,
|
|
32
|
-
message,
|
|
33
|
-
timestamp: new Date().toISOString(),
|
|
34
|
-
...data,
|
|
35
|
-
})
|
|
36
|
-
}
|
|
12
|
+
export const generateTool = defineTool(
|
|
13
|
+
{
|
|
14
|
+
name: 'generate',
|
|
15
|
+
description: 'Generate OpenAPI spec helpers using Kubb configuration',
|
|
16
|
+
schema: generateSchema,
|
|
17
|
+
},
|
|
18
|
+
async function generate(schema: v.InferInput<typeof generateSchema>) {
|
|
19
|
+
const { config: configPath, input, output, logLevel } = schema
|
|
37
20
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
})
|
|
21
|
+
try {
|
|
22
|
+
const hooks = new AsyncEventEmitter<KubbHooks>()
|
|
23
|
+
const messages: string[] = []
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
const notify = async (type: string, message: string, _data?: Record<string, unknown>) => {
|
|
26
|
+
messages.push(`${type}: ${message}`)
|
|
27
|
+
}
|
|
46
28
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
hooks.on('kubb:info', async ({ message }: { message: string }) => {
|
|
30
|
+
await notify(NotifyTypes.INFO, message)
|
|
31
|
+
})
|
|
50
32
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
33
|
+
hooks.on('kubb:success', async ({ message }: { message: string }) => {
|
|
34
|
+
await notify(NotifyTypes.SUCCESS, message)
|
|
35
|
+
})
|
|
54
36
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
})
|
|
37
|
+
hooks.on('kubb:error', async ({ error }: { error: Error }) => {
|
|
38
|
+
await notify(NotifyTypes.ERROR, error.message)
|
|
39
|
+
})
|
|
59
40
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
duration,
|
|
41
|
+
hooks.on('kubb:warn', async ({ message }: { message: string }) => {
|
|
42
|
+
await notify(NotifyTypes.WARN, message)
|
|
63
43
|
})
|
|
64
|
-
})
|
|
65
44
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
})
|
|
45
|
+
hooks.on('kubb:plugin:start', async ({ plugin }) => {
|
|
46
|
+
await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`)
|
|
47
|
+
})
|
|
70
48
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
49
|
+
hooks.on('kubb:plugin:end', async ({ plugin, duration }) => {
|
|
50
|
+
await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, { duration })
|
|
51
|
+
})
|
|
74
52
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
53
|
+
hooks.on('kubb:files:processing:start', async () => {
|
|
54
|
+
await notify(NotifyTypes.FILES_START, 'Starting file processing')
|
|
55
|
+
})
|
|
78
56
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})
|
|
57
|
+
hooks.on('kubb:file:processing:update', async ({ file }: { file: { name: string } }) => {
|
|
58
|
+
await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)
|
|
59
|
+
})
|
|
83
60
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
61
|
+
hooks.on('kubb:files:processing:end', async () => {
|
|
62
|
+
await notify(NotifyTypes.FILES_END, 'File processing complete')
|
|
63
|
+
})
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
65
|
+
hooks.on('kubb:generation:start', async () => {
|
|
66
|
+
await notify(NotifyTypes.GENERATION_START, 'Generation started')
|
|
67
|
+
})
|
|
91
68
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
cwd = configResult.cwd
|
|
69
|
+
hooks.on('kubb:generation:end', async () => {
|
|
70
|
+
await notify(NotifyTypes.GENERATION_END, 'Generation ended')
|
|
71
|
+
})
|
|
96
72
|
|
|
97
|
-
|
|
98
|
-
|
|
73
|
+
let userConfig: Config
|
|
74
|
+
let cwd: string
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const configResult = await loadUserConfig(configPath, { notify })
|
|
78
|
+
userConfig = configResult.userConfig
|
|
79
|
+
cwd = configResult.cwd
|
|
80
|
+
|
|
81
|
+
if (Array.isArray(userConfig)) {
|
|
82
|
+
throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
userConfig = await resolveUserConfig(userConfig, {
|
|
86
|
+
configPath,
|
|
87
|
+
logLevel,
|
|
88
|
+
})
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
91
|
+
await notify(NotifyTypes.CONFIG_ERROR, errorMessage)
|
|
92
|
+
return tool.error(errorMessage)
|
|
99
93
|
}
|
|
100
94
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
95
|
+
const inputPath = input ?? (userConfig.input && 'path' in userConfig.input ? userConfig.input.path : undefined)
|
|
96
|
+
|
|
97
|
+
const config: Config = {
|
|
98
|
+
...userConfig,
|
|
99
|
+
root: resolveCwd(userConfig, cwd),
|
|
100
|
+
input: inputPath
|
|
101
|
+
? {
|
|
102
|
+
...userConfig.input,
|
|
103
|
+
path: inputPath,
|
|
104
|
+
}
|
|
105
|
+
: userConfig.input,
|
|
106
|
+
output: output
|
|
107
|
+
? {
|
|
108
|
+
...userConfig.output,
|
|
109
|
+
path: output,
|
|
110
|
+
}
|
|
111
|
+
: userConfig.output,
|
|
116
112
|
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)
|
|
120
|
-
|
|
121
|
-
// Override config with CLI options
|
|
122
|
-
const config: Config = {
|
|
123
|
-
...userConfig,
|
|
124
|
-
root: resolveCwd(userConfig, cwd),
|
|
125
|
-
input: inputPath
|
|
126
|
-
? {
|
|
127
|
-
...userConfig.input,
|
|
128
|
-
path: inputPath,
|
|
129
|
-
}
|
|
130
|
-
: userConfig.input,
|
|
131
|
-
output: output
|
|
132
|
-
? {
|
|
133
|
-
...userConfig.output,
|
|
134
|
-
path: output,
|
|
135
|
-
}
|
|
136
|
-
: userConfig.output,
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {
|
|
140
|
-
root: config.root,
|
|
141
|
-
})
|
|
142
113
|
|
|
143
|
-
|
|
144
|
-
|
|
114
|
+
await notify(NotifyTypes.CONFIG_READY, 'Configuration ready')
|
|
115
|
+
await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')
|
|
145
116
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
117
|
+
const kubb = createKubb(config, { hooks })
|
|
118
|
+
await kubb.setup()
|
|
119
|
+
await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')
|
|
149
120
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
121
|
+
await notify(NotifyTypes.BUILD_START, 'Starting build')
|
|
122
|
+
const { files, failedPlugins, error } = await kubb.safeBuild()
|
|
123
|
+
await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)
|
|
153
124
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
125
|
+
if (error || failedPlugins.size > 0) {
|
|
126
|
+
const allErrors: Error[] = [
|
|
127
|
+
error,
|
|
128
|
+
...Array.from(failedPlugins)
|
|
129
|
+
.filter((it) => it.error)
|
|
130
|
+
.map((it) => it.error),
|
|
131
|
+
].filter(Boolean)
|
|
161
132
|
|
|
162
|
-
|
|
163
|
-
errorCount: allErrors.length,
|
|
164
|
-
errors: allErrors.map((err) => err.message),
|
|
165
|
-
})
|
|
133
|
+
await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`)
|
|
166
134
|
|
|
167
|
-
|
|
168
|
-
content: [
|
|
169
|
-
{
|
|
170
|
-
type: 'text',
|
|
171
|
-
text: `Build failed:\n${allErrors.map((err) => err.message).join('\n')}\n\n${messages.join('\n')}`,
|
|
172
|
-
},
|
|
173
|
-
],
|
|
174
|
-
isError: true,
|
|
135
|
+
return tool.error(`Build failed:\n${allErrors.map((err) => err.message).join('\n')}\n\n${messages.join('\n')}`)
|
|
175
136
|
}
|
|
176
|
-
}
|
|
177
137
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
{
|
|
185
|
-
type: 'text',
|
|
186
|
-
text: `Build completed successfully!\n\nGenerated ${files.length} files\n\n${messages.join('\n')}`,
|
|
187
|
-
},
|
|
188
|
-
],
|
|
189
|
-
}
|
|
190
|
-
} catch (caughtError) {
|
|
191
|
-
const error = caughtError as Error
|
|
192
|
-
|
|
193
|
-
await handler.sendNotification('kubb/progress', {
|
|
194
|
-
type: NotifyTypes.FATAL_ERROR,
|
|
195
|
-
message: error.message,
|
|
196
|
-
stack: error.stack,
|
|
197
|
-
timestamp: new Date().toISOString(),
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
return {
|
|
201
|
-
content: [
|
|
202
|
-
{
|
|
203
|
-
type: 'text',
|
|
204
|
-
text: `Build error: ${error.message}\n${error.stack || ''}`,
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
isError: true,
|
|
138
|
+
await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`)
|
|
139
|
+
|
|
140
|
+
return tool.text(`Build completed successfully!\n\nGenerated ${files.length} files\n\n${messages.join('\n')}`)
|
|
141
|
+
} catch (caughtError) {
|
|
142
|
+
const error = toError(caughtError)
|
|
143
|
+
return tool.error(`Build error: ${error.message}\n${error.stack ?? ''}`)
|
|
208
144
|
}
|
|
209
|
-
}
|
|
210
|
-
|
|
145
|
+
},
|
|
146
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { availablePlugins, generateConfigFile, KUBB_CONFIG_FILENAME, type PluginOption } from '@internals/shared'
|
|
5
|
+
import { defineTool } from 'tmcp/tool'
|
|
6
|
+
import { tool } from 'tmcp/utils'
|
|
7
|
+
import { initSchema } from '../schemas/initSchema.ts'
|
|
8
|
+
|
|
9
|
+
export function resolvePlugins(pluginsFlag: string | undefined): PluginOption[] {
|
|
10
|
+
if (!pluginsFlag) {
|
|
11
|
+
return []
|
|
12
|
+
}
|
|
13
|
+
const requested = pluginsFlag
|
|
14
|
+
.split(',')
|
|
15
|
+
.map((v) => v.trim())
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
return availablePlugins.filter((p) => requested.includes(p.value))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const initTool = defineTool(
|
|
21
|
+
{
|
|
22
|
+
name: 'init',
|
|
23
|
+
description: 'Scaffold a kubb.config.ts in the current directory (non-interactive). Does not install packages.',
|
|
24
|
+
schema: initSchema,
|
|
25
|
+
},
|
|
26
|
+
async ({ input = './openapi.yaml', output = './src/gen', plugins }) => {
|
|
27
|
+
const selected = resolvePlugins(plugins)
|
|
28
|
+
const content = generateConfigFile({ selectedPlugins: selected, inputPath: input, outputPath: output })
|
|
29
|
+
const dest = path.join(process.cwd(), KUBB_CONFIG_FILENAME)
|
|
30
|
+
if (fs.existsSync(dest)) {
|
|
31
|
+
return tool.error(`${KUBB_CONFIG_FILENAME} already exists at ${dest}. Delete it first before running init again.`)
|
|
32
|
+
}
|
|
33
|
+
fs.writeFileSync(dest, content, 'utf-8')
|
|
34
|
+
const packageList = ['kubb', ...selected.map((p) => p.packageName)].join(' ')
|
|
35
|
+
return tool.text(`Created kubb.config.ts\n\nInstall packages:\n npm install ${packageList}\n\nThen run:\n npx kubb generate`)
|
|
36
|
+
},
|
|
37
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineTool } from 'tmcp/tool'
|
|
2
|
+
import { tool } from 'tmcp/utils'
|
|
3
|
+
import { validateSchema } from '../schemas/validateSchema.ts'
|
|
4
|
+
|
|
5
|
+
export const validateTool = defineTool(
|
|
6
|
+
{
|
|
7
|
+
name: 'validate',
|
|
8
|
+
description: 'Validate an OpenAPI/Swagger specification file or URL',
|
|
9
|
+
schema: validateSchema,
|
|
10
|
+
},
|
|
11
|
+
async ({ input }) => {
|
|
12
|
+
let mod: typeof import('@kubb/adapter-oas')
|
|
13
|
+
try {
|
|
14
|
+
mod = await import('@kubb/adapter-oas')
|
|
15
|
+
} catch {
|
|
16
|
+
return tool.error('The validate tool requires @kubb/adapter-oas.\nInstall: npm install @kubb/adapter-oas')
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
await mod.adapterOas().validate(input, { throwOnError: true })
|
|
20
|
+
return tool.text(`Validation successful: ${input}`)
|
|
21
|
+
} catch (err) {
|
|
22
|
+
return tool.error(`Validation failed:\n${err instanceof Error ? err.message : String(err)}`)
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
)
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import type { Config } from '@kubb/core'
|
|
4
|
-
import {
|
|
4
|
+
import { createJiti } from 'jiti'
|
|
5
5
|
import { ALLOWED_CONFIG_EXTENSIONS } from '../constants.ts'
|
|
6
6
|
import { NotifyTypes } from '../types.ts'
|
|
7
7
|
|
|
8
8
|
type NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>
|
|
9
9
|
|
|
10
|
+
const jiti = createJiti(import.meta.url, {
|
|
11
|
+
jsx: {
|
|
12
|
+
runtime: 'automatic',
|
|
13
|
+
importSource: '@kubb/renderer-jsx',
|
|
14
|
+
},
|
|
15
|
+
moduleCache: false,
|
|
16
|
+
})
|
|
17
|
+
|
|
10
18
|
const loadedModules = new Map<string, unknown>()
|
|
11
19
|
|
|
12
20
|
async function loadModule(filePath: string): Promise<unknown> {
|
|
@@ -17,15 +25,12 @@ async function loadModule(filePath: string): Promise<unknown> {
|
|
|
17
25
|
if (loadedModules.has(filePath)) {
|
|
18
26
|
return loadedModules.get(filePath)
|
|
19
27
|
}
|
|
20
|
-
const
|
|
21
|
-
loadedModules.set(filePath,
|
|
22
|
-
return
|
|
28
|
+
const mod = await jiti.import(filePath, { default: true })
|
|
29
|
+
loadedModules.set(filePath, mod)
|
|
30
|
+
return mod
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
export async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {
|
|
26
|
-
let userConfig: Config | undefined
|
|
27
|
-
let cwd: string
|
|
28
|
-
|
|
29
34
|
if (configPath) {
|
|
30
35
|
const ext = path.extname(configPath)
|
|
31
36
|
if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
|
|
@@ -41,37 +46,33 @@ export async function loadUserConfig(configPath: string | undefined, { notify }:
|
|
|
41
46
|
await notify(NotifyTypes.CONFIG_ERROR, msg)
|
|
42
47
|
throw new Error(msg)
|
|
43
48
|
}
|
|
44
|
-
cwd = path.dirname(resolvedConfigPath)
|
|
45
|
-
|
|
49
|
+
const cwd = path.dirname(resolvedConfigPath)
|
|
46
50
|
try {
|
|
47
|
-
userConfig = (await loadModule(resolvedConfigPath)) as Config
|
|
51
|
+
const userConfig = (await loadModule(resolvedConfigPath)) as Config
|
|
48
52
|
await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)
|
|
53
|
+
return { userConfig, cwd }
|
|
49
54
|
} catch (error) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} else {
|
|
54
|
-
cwd = process.cwd()
|
|
55
|
-
const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']
|
|
56
|
-
|
|
57
|
-
for (const configFileName of configFileNames) {
|
|
58
|
-
const configFilePath = path.resolve(process.cwd(), configFileName)
|
|
59
|
-
if (!existsSync(configFilePath)) continue
|
|
60
|
-
try {
|
|
61
|
-
userConfig = (await loadModule(configFilePath)) as Config
|
|
62
|
-
await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)
|
|
63
|
-
break
|
|
64
|
-
} catch {
|
|
65
|
-
// Continue trying next config file
|
|
66
|
-
}
|
|
55
|
+
const msg = `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
|
|
56
|
+
await notify(NotifyTypes.CONFIG_ERROR, msg)
|
|
57
|
+
throw new Error(msg)
|
|
67
58
|
}
|
|
59
|
+
}
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
|
|
61
|
+
const cwd = process.cwd()
|
|
62
|
+
const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']
|
|
71
63
|
|
|
72
|
-
|
|
64
|
+
for (const configFileName of configFileNames) {
|
|
65
|
+
const configFilePath = path.resolve(process.cwd(), configFileName)
|
|
66
|
+
if (!existsSync(configFilePath)) continue
|
|
67
|
+
try {
|
|
68
|
+
const userConfig = (await loadModule(configFilePath)) as Config
|
|
69
|
+
await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)
|
|
70
|
+
return { userConfig, cwd }
|
|
71
|
+
} catch (err) {
|
|
72
|
+
await notify(NotifyTypes.CONFIG_ERROR, `Failed to load ${configFileName}: ${err instanceof Error ? err.message : String(err)}`)
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')
|
|
77
|
+
throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)
|
|
77
78
|
}
|
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
import { isPromise } from '@internals/utils'
|
|
2
|
-
import type { CLIOptions, Config } from '@kubb/core'
|
|
2
|
+
import type { CLIOptions, Config, PossibleConfig } from '@kubb/core'
|
|
3
3
|
|
|
4
4
|
export type ResolveUserConfigOptions = {
|
|
5
5
|
configPath?: string
|
|
6
6
|
logLevel?: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
let kubbUserConfig = Promise.resolve(config) as Promise<Config>
|
|
14
|
-
|
|
15
|
-
if (typeof config === 'function') {
|
|
16
|
-
const possiblePromise = (config as any)({
|
|
17
|
-
logLevel: options.logLevel,
|
|
18
|
-
config: options.configPath,
|
|
19
|
-
} as CLIOptions)
|
|
20
|
-
if (isPromise(possiblePromise)) {
|
|
21
|
-
kubbUserConfig = possiblePromise
|
|
22
|
-
} else {
|
|
23
|
-
kubbUserConfig = Promise.resolve(possiblePromise)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return (await kubbUserConfig) as Config
|
|
9
|
+
export async function resolveUserConfig(config: PossibleConfig<CLIOptions>, options: ResolveUserConfigOptions): Promise<Config> {
|
|
10
|
+
const result = typeof config === 'function' ? config({ logLevel: options.logLevel as CLIOptions['logLevel'], config: options.configPath }) : config
|
|
11
|
+
const resolved = isPromise(result) ? await result : result
|
|
12
|
+
return (Array.isArray(resolved) ? resolved[0] : resolved) as Config
|
|
28
13
|
}
|