@kubb/mcp 5.0.0-beta.62 → 5.0.0-beta.64

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/src/utils.ts DELETED
@@ -1,129 +0,0 @@
1
- import { existsSync } from 'node:fs'
2
- import path from 'node:path'
3
- import { createModuleLoader } from '@internals/shared'
4
- import { isPromise } from '@internals/utils'
5
- import type { CLIOptions, Config, PossibleConfig, SerializedDiagnostic } from '@kubb/core'
6
- import { ALLOWED_CONFIG_EXTENSIONS, NotifyTypes } from './constants.ts'
7
-
8
- /**
9
- * Renders serialized diagnostics as a plain-text block for an AI assistant. Each entry
10
- * keeps the stable `code`, the source pointer, the suggested fix, and the docs link, so
11
- * the agent can act on the problem rather than parsing a bare message. No ANSI styling,
12
- * unlike the CLI renderer.
13
- */
14
- export function formatDiagnostics(diagnostics: ReadonlyArray<SerializedDiagnostic>): string {
15
- return diagnostics.map((diagnostic) => formatDiagnostic(diagnostic)).join('\n\n')
16
- }
17
-
18
- function formatDiagnostic(diagnostic: SerializedDiagnostic): string {
19
- const { code, severity, message, location, help, plugin, docsUrl } = diagnostic
20
- const rule = plugin ? `${plugin}(${code})` : code
21
- const lines = [`${severity} ${rule}: ${message}`]
22
-
23
- if (location && 'pointer' in location) {
24
- lines.push(` at ${location.pointer}`)
25
- }
26
- if (help) {
27
- lines.push(` help: ${help}`)
28
- }
29
- if (docsUrl) {
30
- lines.push(` docs: ${docsUrl}`)
31
- }
32
-
33
- return lines.join('\n')
34
- }
35
-
36
- type NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>
37
-
38
- const loader = createModuleLoader()
39
-
40
- const loadedModules = new Map<string, unknown>()
41
-
42
- async function loadModule(filePath: string): Promise<unknown> {
43
- const ext = path.extname(filePath)
44
- if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
45
- throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`)
46
- }
47
- if (loadedModules.has(filePath)) {
48
- return loadedModules.get(filePath)
49
- }
50
- const mod = await loader.load(filePath, { default: true })
51
- loadedModules.set(filePath, mod)
52
- return mod
53
- }
54
-
55
- export async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {
56
- if (configPath) {
57
- const ext = path.extname(configPath)
58
- if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
59
- const msg = `Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`
60
- await notify(NotifyTypes.CONFIG_ERROR, msg)
61
- throw new Error(msg)
62
- }
63
- const base = path.resolve(process.cwd())
64
- const resolvedConfigPath = path.resolve(base, configPath)
65
- const relative = path.relative(base, resolvedConfigPath)
66
- if (relative.startsWith('..') || path.isAbsolute(relative)) {
67
- const msg = 'Invalid config file path: must be within the current working directory'
68
- await notify(NotifyTypes.CONFIG_ERROR, msg)
69
- throw new Error(msg)
70
- }
71
- const cwd = path.dirname(resolvedConfigPath)
72
- try {
73
- const userConfig = (await loadModule(resolvedConfigPath)) as Config
74
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)
75
- return { userConfig, cwd }
76
- } catch (error) {
77
- const msg = `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
78
- await notify(NotifyTypes.CONFIG_ERROR, msg)
79
- throw new Error(msg)
80
- }
81
- }
82
-
83
- const cwd = process.cwd()
84
- const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']
85
-
86
- for (const configFileName of configFileNames) {
87
- const configFilePath = path.resolve(process.cwd(), configFileName)
88
- if (!existsSync(configFilePath)) continue
89
- try {
90
- const userConfig = (await loadModule(configFilePath)) as Config
91
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)
92
- return { userConfig, cwd }
93
- } catch (err) {
94
- await notify(NotifyTypes.CONFIG_ERROR, `Failed to load ${configFileName}: ${err instanceof Error ? err.message : String(err)}`)
95
- }
96
- }
97
-
98
- await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')
99
- throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)
100
- }
101
-
102
- /**
103
- * Determine the root directory based on userConfig.root and resolvedConfigDir
104
- * 1. If userConfig.root exists and is absolute, use it as-is
105
- * 2. If userConfig.root exists and is relative, resolve it relative to config directory
106
- * 3. Otherwise, use the config directory as root
107
- */
108
- export function resolveCwd(userConfig: Config, cwd: string): string {
109
- if (userConfig.root) {
110
- if (path.isAbsolute(userConfig.root)) {
111
- return userConfig.root
112
- }
113
-
114
- return path.resolve(cwd, userConfig.root)
115
- }
116
-
117
- return cwd
118
- }
119
-
120
- export type ResolveUserConfigOptions = {
121
- configPath?: string
122
- logLevel?: string
123
- }
124
-
125
- export async function resolveUserConfig(config: PossibleConfig<CLIOptions>, options: ResolveUserConfigOptions): Promise<Config> {
126
- const result = typeof config === 'function' ? config({ logLevel: options.logLevel as CLIOptions['logLevel'], config: options.configPath }) : config
127
- const resolved = isPromise(result) ? await result : result
128
- return (Array.isArray(resolved) ? resolved[0] : resolved) as Config
129
- }