@kubb/cli 1.1.11 → 1.1.13

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/init.ts DELETED
@@ -1,91 +0,0 @@
1
- import pathParser from 'node:path'
2
-
3
- import { write } from '@kubb/core'
4
-
5
- import { $ } from 'execa'
6
- import pc from 'picocolors'
7
-
8
- import type { LogLevel } from '@kubb/core'
9
- import type { Ora } from 'ora'
10
-
11
- export type Preset = 'simple'
12
-
13
- export type PackageManager = 'pnpm' | 'npm' | 'yarn'
14
-
15
- export type PresetMeta = {
16
- 'kubb.config': string
17
- packages: string[]
18
- }
19
-
20
- type RunProps = {
21
- spinner: Ora
22
- /**
23
- * @default `'silent'`
24
- */
25
- logLevel?: LogLevel
26
- /**
27
- * @default `'simple'`
28
- */
29
- preset?: Preset
30
- /**
31
- * @default `'pnpm'`
32
- */
33
- packageManager?: PackageManager
34
- }
35
-
36
- const presets: Record<Preset, PresetMeta> = {
37
- simple: {
38
- 'kubb.config': `
39
- import { defineConfig } from '@kubb/core'
40
- import createSwagger from '@kubb/swagger'
41
- import createSwaggerTS from '@kubb/swagger-ts'
42
- import createSwaggerTanstackQuery from '@kubb/swagger-tanstack-query'
43
-
44
- export default defineConfig({
45
- root: '.',
46
- input: {
47
- path: 'https://petstore3.swagger.io/api/v3/openapi.json',
48
- },
49
- output: {
50
- path: './src/gen',
51
- clean: true,
52
- },
53
- hooks: {
54
- done: 'echo "🎉 done"',
55
- },
56
- logLevel: 'info',
57
- plugins: [createSwagger({}), createSwaggerTS({ output: 'models', enumType: 'enum' }), createSwaggerTanstackQuery({ output: './hooks' })],
58
- })
59
- `,
60
- packages: ['@kubb/core', '@kubb/cli', '@kubb/swagger', '@kubb/swagger-ts', '@kubb/swagger-tanstack-query'],
61
- },
62
- }
63
-
64
- export async function init({ spinner, preset = 'simple', logLevel = 'silent', packageManager = 'pnpm' }: RunProps): Promise<void> {
65
- try {
66
- const presetMeta = presets[preset]
67
- const path = pathParser.resolve(process.cwd(), './kubb.config.js')
68
- const installCommand = packageManager === 'npm' ? 'install' : 'add'
69
-
70
- spinner.start(`📀 Writing \`kubb.config.js\` ${pc.dim(path)}`)
71
- await write(presetMeta['kubb.config'], path)
72
- spinner.succeed(`📀 Wrote \`kubb.config.js\` ${pc.dim(path)}`)
73
-
74
- const data = await Promise.all([
75
- $`npm init es6 -y`,
76
- ...presetMeta.packages.map(async (pack) => {
77
- spinner.start(`📀 Installing ${pc.dim(pack)}`)
78
- const { stdout } = await $({ preferLocal: false })`${packageManager} ${installCommand} ${pack}`
79
- spinner.succeed(`📀 Installed ${pc.dim(pack)}`)
80
-
81
- return stdout
82
- }),
83
- ])
84
-
85
- if (logLevel === 'info') {
86
- data.forEach((text) => console.log(text))
87
- }
88
- } catch (error) {
89
- spinner.fail(pc.red(`Something went wrong\n\n${(error as Error)?.message}`))
90
- }
91
- }
package/src/run.ts DELETED
@@ -1,179 +0,0 @@
1
- import pathParser from 'node:path'
2
-
3
- import { build, throttle, ParallelPluginError, PluginError } from '@kubb/core'
4
-
5
- import { execa } from 'execa'
6
- import pc from 'picocolors'
7
- import PrettyError from 'pretty-error'
8
- import { parseArgsStringToArgv } from 'string-argv'
9
-
10
- import { parseHrtimeToSeconds } from './utils/parseHrtimeToSeconds.ts'
11
- import { parseText } from './utils/parseText.ts'
12
-
13
- import type { BuildOutput, CLIOptions, KubbConfig, Logger, LogLevel } from '@kubb/core'
14
- import type { Ora } from 'ora'
15
- import { OraWritable } from './utils/OraWritable.ts'
16
-
17
- type RunProps = {
18
- config: KubbConfig
19
- spinner: Ora
20
- options: CLIOptions
21
- }
22
-
23
- export async function run({ config, options, spinner }: RunProps): Promise<void> {
24
- const hrstart = process.hrtime()
25
- const [log] = throttle<void, Parameters<Logger['log']>>((message, { logLevel, params }) => {
26
- if (logLevel === 'error') {
27
- spinner.fail(pc.red(`${message}\n\n` || `Something went wrong\n\n`))
28
- } else if (logLevel === 'info') {
29
- if (message) {
30
- spinner.text = message
31
- } else {
32
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
33
- spinner.text = `🪂 Executing ${params?.hookName || 'unknown'}(${pc.yellow(params?.pluginName || 'unknown')})`
34
- }
35
- }
36
- }, 100)
37
- const logger: Logger = {
38
- log,
39
- spinner,
40
- }
41
-
42
- const onDone = async (hooks: KubbConfig['hooks'], logLevel: LogLevel) => {
43
- if (!hooks?.done) {
44
- return
45
- }
46
-
47
- let commands: string[] = []
48
- if (typeof hooks?.done === 'string') {
49
- commands = [hooks.done]
50
- } else {
51
- commands = hooks.done
52
- }
53
-
54
- const promises = commands.map(async (command) => {
55
- const oraWritable = new OraWritable(spinner, command)
56
- const [cmd, ..._args] = [...parseArgsStringToArgv(command)]
57
- spinner.start(parseText(`🪂 Executing hooks(${pc.yellow('done')})`, { info: ` ${pc.dim(command)}` }, logLevel))
58
-
59
- const { stdout } = await execa(cmd, _args, {}).pipeStdout!(oraWritable)
60
- spinner.suffixText = ''
61
- oraWritable.destroy()
62
-
63
- if (logLevel === 'info') {
64
- spinner.succeed(parseText(`🪂 Executing hooks(${pc.yellow('done')})`, { info: ` ${pc.dim(command)}` }, logLevel))
65
-
66
- console.log(stdout)
67
- }
68
- })
69
-
70
- await Promise.all(promises)
71
-
72
- if (logLevel === 'silent') {
73
- spinner.succeed(parseText(`🪂 Executing hooks(${pc.yellow('done')})`, {}, logLevel))
74
- }
75
- }
76
-
77
- const printSummary = (pluginManager: BuildOutput['pluginManager'], status: 'success' | 'failed') => {
78
- const elapsedSeconds = parseHrtimeToSeconds(process.hrtime(hrstart))
79
-
80
- const buildStartPlugins = [
81
- ...new Set(pluginManager.executed.filter((item) => item.hookName === 'buildStart' && item.plugin.name !== 'core').map((item) => item.plugin.name)),
82
- ]
83
- const pluginsCount = config.plugins?.length || 0
84
- const files = pluginManager.fileManager.files.sort((a, b) => {
85
- if (!a.meta?.pluginName || !b.meta?.pluginName) {
86
- return 0
87
- }
88
- if (a.meta?.pluginName.length < b.meta?.pluginName.length) {
89
- return 1
90
- }
91
- if (a.meta?.pluginName.length > b.meta?.pluginName.length) {
92
- return -1
93
- }
94
- return 0
95
- })
96
-
97
- const meta = {
98
- plugins:
99
- status === 'success'
100
- ? `${pc.green(`${buildStartPlugins.length} successful`)}, ${pluginsCount} total`
101
- : `${pc.red(`${pluginsCount - buildStartPlugins.length} failed`)}, ${pluginsCount} total`,
102
- filesCreated: files.length,
103
- time: pc.yellow(`${elapsedSeconds}s`),
104
- output: pathParser.resolve(config.root, config.output.path),
105
- } as const
106
-
107
- console.log(`
108
- ${pc.bold('Plugins:')} ${meta.plugins}
109
- ${pc.bold('Generated:')} ${meta.filesCreated} files
110
- ${pc.bold('Time:')} ${meta.time}
111
- ${pc.bold('Output:')} ${meta.output}
112
- `)
113
-
114
- if (options.debug) {
115
- console.log(`${pc.bold('Generated files:')}`)
116
- console.log(`${files.map((file) => `${pc.blue(file.meta?.pluginName)} ${file.path}`).join('\n')}`)
117
- }
118
- }
119
-
120
- const printErrors = (error: Error) => {
121
- const pe = new PrettyError()
122
-
123
- if (options.debug) {
124
- spinner.fail(pc.red(`Something went wrong\n\n`))
125
- const causedError = error?.cause as Error
126
-
127
- console.log(pe.render(error))
128
-
129
- if (causedError) {
130
- console.log(pe.render(causedError))
131
- }
132
- } else {
133
- spinner.fail(pc.red(`Something went wrong\n\n${error?.message}`))
134
- }
135
- }
136
-
137
- try {
138
- const { root, ...userConfig } = config
139
- const logLevel = options.logLevel ?? userConfig.logLevel ?? 'silent'
140
- const inputPath = options.input ?? userConfig.input.path
141
-
142
- spinner.start(parseText(`🚀 Building`, { info: `(${pc.dim(inputPath)})` }, logLevel))
143
-
144
- const output = await build({
145
- config: {
146
- root: process.cwd(),
147
- ...userConfig,
148
- logLevel,
149
- input: {
150
- ...userConfig.input,
151
- path: inputPath,
152
- },
153
- output: {
154
- write: true,
155
- ...userConfig.output,
156
- },
157
- },
158
- logger,
159
- })
160
-
161
- spinner.succeed(parseText(`🚀 Build completed`, { info: `(${pc.dim(inputPath)})` }, logLevel))
162
-
163
- await onDone(config.hooks, logLevel)
164
-
165
- printSummary(output.pluginManager, 'success')
166
- } catch (error: any) {
167
- if (error instanceof ParallelPluginError) {
168
- error.errors.map((e) => printErrors(e))
169
- } else {
170
- printErrors(error as Error)
171
- }
172
-
173
- if (error instanceof PluginError || error instanceof ParallelPluginError) {
174
- printSummary(error.pluginManager, 'failed')
175
- }
176
-
177
- throw error
178
- }
179
- }
package/src/types.ts DELETED
@@ -1,7 +0,0 @@
1
- import type { defineConfig, KubbUserConfig } from '@kubb/core'
2
-
3
- export type CosmiconfigResult = {
4
- filepath: string
5
- isEmpty?: boolean
6
- config: ReturnType<typeof defineConfig> | KubbUserConfig
7
- }
@@ -1,20 +0,0 @@
1
- import type { WritableOptions } from 'node:stream'
2
- import { Writable } from 'node:stream'
3
- import type { Ora } from 'ora'
4
- import pc from 'picocolors'
5
-
6
- export class OraWritable extends Writable {
7
- public command: string
8
- public spinner: Ora
9
- constructor(spinner: Ora, command: string, opts?: WritableOptions) {
10
- super(opts)
11
-
12
- this.command = command
13
- this.spinner = spinner
14
- }
15
- _write(chunk: any, _encoding: NodeJS.BufferEncoding, callback: (error?: Error | null) => void) {
16
- this.spinner.suffixText = `\n\n${pc.bold(pc.blue(this.command))}: ${chunk?.toString()}`
17
-
18
- callback()
19
- }
20
- }
@@ -1,28 +0,0 @@
1
- import { isPromise } from '@kubb/core'
2
-
3
- import { getPlugins } from './getPlugins.ts'
4
-
5
- import type { CLIOptions, KubbConfig, KubbUserConfig } from '@kubb/core'
6
- import type { CosmiconfigResult } from '../types.ts'
7
-
8
- export async function getConfig(result: CosmiconfigResult, options: CLIOptions): Promise<KubbConfig> {
9
- const config = result?.config
10
- let kubbUserConfig: Promise<KubbUserConfig> = Promise.resolve(config) as Promise<KubbUserConfig>
11
-
12
- // for ts or js files
13
- if (typeof config === 'function') {
14
- const possiblePromise = config(options)
15
- if (isPromise(possiblePromise)) {
16
- kubbUserConfig = possiblePromise
17
- }
18
- kubbUserConfig = Promise.resolve(possiblePromise)
19
- }
20
-
21
- let JSONConfig = await kubbUserConfig
22
- JSONConfig = {
23
- ...JSONConfig,
24
- plugins: JSONConfig.plugins ? await getPlugins(JSONConfig.plugins) : undefined,
25
- }
26
-
27
- return JSONConfig as KubbConfig
28
- }
@@ -1,80 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-return */
2
- import { cosmiconfig } from 'cosmiconfig'
3
- import tsNode from 'ts-node'
4
- import yaml from 'yaml'
5
-
6
- import { importModule } from './importModule.ts'
7
-
8
- import type { CosmiconfigResult } from '../types.ts'
9
-
10
- const jsLoader = async (configFile: string) => {
11
- return importModule(configFile)
12
- }
13
- // TODO fix tsLoader for node 20
14
- // https://github.com/TypeStrong/ts-node/issues/1997
15
- const tsLoader = (configFile: string) => {
16
- // eslint-disable-next-line @typescript-eslint/no-empty-function
17
- let registerer = { enabled() {} }
18
-
19
- try {
20
- // Register TypeScript compiler instance
21
- registerer = tsNode.register({
22
- compilerOptions: { module: 'commonjs' },
23
- swc: true,
24
- typeCheck: false,
25
- })
26
-
27
- const module = require(configFile)
28
-
29
- return module.default
30
- } catch (err: any) {
31
- if (err.code === 'MODULE_NOT_FOUND') {
32
- throw new Error(`'ts-node' is required for the TypeScript configuration files. Make sure it is installed\nError: ${err.message}`)
33
- }
34
- console.log(err)
35
-
36
- throw err
37
- } finally {
38
- registerer.enabled()
39
- }
40
- }
41
-
42
- export async function getCosmiConfig(moduleName: string, config?: string) {
43
- const explorer = cosmiconfig(moduleName, {
44
- cache: false,
45
- searchPlaces: [
46
- 'package.json',
47
- `.${moduleName}rc`,
48
- `.${moduleName}rc.json`,
49
- `.${moduleName}rc.yaml`,
50
- `.${moduleName}rc.yml`,
51
- // TODO fix tsLoader
52
- `.${moduleName}rc.ts`,
53
- `.${moduleName}rc.js`,
54
- `.${moduleName}rc.cjs`,
55
- `.${moduleName}rc.mjs`,
56
- // TODO fix tsLoader
57
- `${moduleName}.config.ts`,
58
- `${moduleName}.config.js`,
59
- `${moduleName}.config.cjs`,
60
- `${moduleName}.config.mjs`,
61
- ],
62
- loaders: {
63
- '.yaml': (filepath, content) => yaml.parse(content),
64
- '.yml': (filepath, content) => yaml.parse(content),
65
- '.js': jsLoader,
66
- '.cjs': jsLoader,
67
- '.mjs': jsLoader,
68
- '.ts': tsLoader,
69
- noExt: jsLoader,
70
- },
71
- })
72
-
73
- const result = config ? await explorer.load(config) : await explorer.search()
74
-
75
- if (result?.isEmpty || !result || !result.config) {
76
- throw new Error('Config not defined, create a kubb.config.js or pass through your config with the option --config')
77
- }
78
-
79
- return result as CosmiconfigResult
80
- }
@@ -1,40 +0,0 @@
1
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
- // @ts-nocheck
3
-
4
- import { importModule } from './importModule.ts'
5
-
6
- import type { KubbJSONPlugin, KubbObjectPlugin, KubbUserConfig } from '@kubb/core'
7
-
8
- function isJSONPlugins(plugins: KubbUserConfig['plugins'] | KubbJSONPlugin[]): plugins is KubbJSONPlugin[] {
9
- return !!(plugins as KubbJSONPlugin[])?.some((plugin) => {
10
- return typeof plugin?.[0] === 'string'
11
- })
12
- }
13
-
14
- function isObjectPlugins(plugins: KubbUserConfig['plugins'] | KubbJSONPlugin[]): plugins is KubbObjectPlugin {
15
- return plugins instanceof Object && !Array.isArray(plugins)
16
- }
17
-
18
- async function importPlugin(name: string, options: object) {
19
- const importedPlugin = process.env.NODE_ENV === 'test' ? await import(name) : await importModule(name, process.cwd())
20
-
21
- return importedPlugin?.default ? importedPlugin.default(options) : importedPlugin(options)
22
- }
23
-
24
- export function getPlugins(plugins: KubbUserConfig['plugins'] | KubbJSONPlugin[]): Promise<KubbUserConfig['plugins']> {
25
- if (isObjectPlugins(plugins)) {
26
- const promises = Object.keys(plugins).map(async (name) => {
27
- return importPlugin(name, plugins[name as keyof typeof plugins])
28
- })
29
- return Promise.all(promises)
30
- }
31
-
32
- if (isJSONPlugins(plugins)) {
33
- const promises = plugins.map(async (plugin) => {
34
- const [name, options = {}] = plugin
35
- return importPlugin(name, options)
36
- })
37
- return Promise.all(promises)
38
- }
39
- return Promise.resolve(plugins)
40
- }
@@ -1,36 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-return */
2
- import mod from 'node:module'
3
- import { pathToFileURL } from 'node:url'
4
-
5
- const SLASHES = new Set(['/', '\\'])
6
-
7
- /**
8
- * Normalizes directories to have a trailing slash.
9
- * Resolve is pretty finicky -- if the directory name doesn't have
10
- * a trailing slash then it tries to look in the parent directory.
11
- * i.e., if the directory is "/usr/nzakas/foo" it will start the
12
- * search in /usr/nzakas. However, if the directory is "/user/nzakas/foo/",
13
- * then it will start the search in /user/nzakas/foo.
14
- * @param {string} directory The directory to check.
15
- * @returns {string} The normalized directory.
16
- */
17
- export function normalizeDirectory(directory: string) {
18
- if (!SLASHES.has(directory[directory.length - 1])) {
19
- return `${directory}/`
20
- }
21
-
22
- return directory
23
- }
24
-
25
- export async function importModule(path: string, cwd?: string): Promise<any> {
26
- let location = path
27
-
28
- if (cwd) {
29
- const require = mod.createRequire(normalizeDirectory(cwd))
30
- location = require.resolve(path)
31
- }
32
-
33
- const module = await import(pathToFileURL(location).href)
34
-
35
- return module?.default ?? module
36
- }
@@ -1,8 +0,0 @@
1
- export * from './getConfig.ts'
2
- export * from './getPlugins.ts'
3
- export * from './watcher.ts'
4
- export * from './getCosmiConfig.ts'
5
- export * from './importModule.ts'
6
- export * from './parseHrtimeToSeconds.ts'
7
- export * from './parseText.ts'
8
- export * from './OraWritable.ts'
@@ -1,3 +0,0 @@
1
- module.exports = function noop() {
2
- return 'cjs-noop'
3
- }
@@ -1,3 +0,0 @@
1
- export function noop() {
2
- return 'js-noop'
3
- }
@@ -1,4 +0,0 @@
1
- export function parseHrtimeToSeconds(hrtime: [number, number]) {
2
- const seconds = (hrtime[0] + hrtime[1] / 1e9).toFixed(3)
3
- return seconds
4
- }
@@ -1,5 +0,0 @@
1
- import type { LogLevel } from '@kubb/core'
2
-
3
- export function parseText(baseText: string, config: Partial<Record<LogLevel, string>>, logLevel: LogLevel = 'silent') {
4
- return `${baseText}${config[logLevel] || ''}`
5
- }
@@ -1,30 +0,0 @@
1
- import pc from 'picocolors'
2
-
3
- import type { Ora } from 'ora'
4
-
5
- type Options = {
6
- path: string[]
7
- spinner: Ora
8
- }
9
- export async function startWatcher(cb: (path: string[]) => Promise<void>, options: Options) {
10
- const { spinner, path } = options
11
- const { watch } = await import('chokidar')
12
-
13
- const ignored = ['**/{.git,node_modules}/**']
14
-
15
- const watcher = watch(path, {
16
- ignorePermissionErrors: true,
17
- ignored,
18
- })
19
- watcher.on('all', (type, file) => {
20
- spinner.succeed(pc.yellow(pc.bold(`Change detected: ${type} ${file}`)))
21
- // revert back
22
- spinner.spinner = 'clock'
23
-
24
- try {
25
- cb(options.path)
26
- } catch (e) {
27
- spinner.warn(pc.red('Watcher failed'))
28
- }
29
- })
30
- }