@kubb/core 2.0.0-alpha.3 → 2.0.0-alpha.4
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/dist/index.cjs +62 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -38
- package/dist/index.d.ts +18 -38
- package/dist/index.js +62 -72
- package/dist/index.js.map +1 -1
- package/dist/utils.cjs +12 -7
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +12 -7
- package/dist/utils.js.map +1 -1
- package/package.json +8 -7
- package/src/BarrelManager.ts +123 -0
- package/src/FileManager.ts +482 -0
- package/src/Generator.ts +34 -0
- package/src/PackageManager.ts +163 -0
- package/src/PluginManager.ts +640 -0
- package/src/PromiseManager.ts +48 -0
- package/src/SchemaGenerator.ts +8 -0
- package/src/build.ts +198 -0
- package/src/config.ts +21 -0
- package/src/errors.ts +12 -0
- package/src/index.ts +28 -0
- package/src/plugin.ts +80 -0
- package/src/types.ts +370 -0
- package/src/utils/EventEmitter.ts +24 -0
- package/src/utils/FunctionParams.ts +85 -0
- package/src/utils/Queue.ts +110 -0
- package/src/utils/TreeNode.ts +122 -0
- package/src/utils/URLPath.ts +128 -0
- package/src/utils/cache.ts +35 -0
- package/src/utils/clean.ts +5 -0
- package/src/utils/executeStrategies.ts +71 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/logger.ts +76 -0
- package/src/utils/promise.ts +13 -0
- package/src/utils/randomColour.ts +39 -0
- package/src/utils/read.ts +68 -0
- package/src/utils/renderTemplate.ts +31 -0
- package/src/utils/throttle.ts +30 -0
- package/src/utils/timeout.ts +7 -0
- package/src/utils/transformers/combineCodes.ts +3 -0
- package/src/utils/transformers/createJSDocBlockText.ts +15 -0
- package/src/utils/transformers/escape.ts +31 -0
- package/src/utils/transformers/indent.ts +3 -0
- package/src/utils/transformers/index.ts +20 -0
- package/src/utils/transformers/nameSorter.ts +9 -0
- package/src/utils/transformers/searchAndReplace.ts +25 -0
- package/src/utils/transformers/transformReservedWord.ts +97 -0
- package/src/utils/uniqueName.ts +20 -0
- package/src/utils/write.ts +63 -0
package/src/build.ts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import pc from 'picocolors'
|
|
2
|
+
|
|
3
|
+
import { clean } from './utils/clean.ts'
|
|
4
|
+
import { createLogger, LogLevel } from './utils/logger.ts'
|
|
5
|
+
import { randomPicoColour } from './utils/randomColour.ts'
|
|
6
|
+
import { read } from './utils/read.ts'
|
|
7
|
+
import { URLPath } from './utils/URLPath.ts'
|
|
8
|
+
import { isInputPath } from './config.ts'
|
|
9
|
+
import { FileManager } from './FileManager.ts'
|
|
10
|
+
import { PluginManager } from './PluginManager.ts'
|
|
11
|
+
import { isPromise } from './PromiseManager.ts'
|
|
12
|
+
|
|
13
|
+
import type { KubbFile } from './FileManager.ts'
|
|
14
|
+
import type { BuildOutput, KubbPlugin, PluginContext, PluginParameter, TransformResult } from './types.ts'
|
|
15
|
+
import type { Logger } from './utils/logger.ts'
|
|
16
|
+
import type { QueueJob } from './utils/Queue.ts'
|
|
17
|
+
|
|
18
|
+
type BuildOptions = {
|
|
19
|
+
config: PluginContext['config']
|
|
20
|
+
/**
|
|
21
|
+
* @default Logger without the spinner
|
|
22
|
+
*/
|
|
23
|
+
logger?: Logger
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function transformReducer(
|
|
27
|
+
this: PluginContext,
|
|
28
|
+
_previousCode: string,
|
|
29
|
+
result: TransformResult | Promise<TransformResult>,
|
|
30
|
+
_plugin: KubbPlugin,
|
|
31
|
+
): Promise<string | null> {
|
|
32
|
+
return result
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function setup(options: BuildOptions): Promise<PluginManager> {
|
|
36
|
+
const { config, logger = createLogger({ logLevel: LogLevel.silent }) } = options
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
if (isInputPath(config) && !new URLPath(config.input.path).isURL) {
|
|
40
|
+
await read(config.input.path)
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
if (isInputPath(config)) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
'Cannot read file/URL defined in `input.path` or set with `kubb generate PATH` in the CLI of your Kubb config ' + pc.dim(config.input.path),
|
|
46
|
+
{
|
|
47
|
+
cause: e,
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (config.output.clean) {
|
|
54
|
+
await clean(config.output.path)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const queueTask = async (file: KubbFile.File) => {
|
|
58
|
+
const { path } = file
|
|
59
|
+
|
|
60
|
+
let code: string | null = FileManager.getSource(file)
|
|
61
|
+
|
|
62
|
+
const { result: loadedResult } = await pluginManager.hookFirst({
|
|
63
|
+
hookName: 'load',
|
|
64
|
+
parameters: [path],
|
|
65
|
+
})
|
|
66
|
+
if (loadedResult && isPromise(loadedResult)) {
|
|
67
|
+
code = await loadedResult
|
|
68
|
+
}
|
|
69
|
+
if (loadedResult && !isPromise(loadedResult)) {
|
|
70
|
+
code = loadedResult
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (code) {
|
|
74
|
+
const transformedCode = await pluginManager.hookReduceArg0({
|
|
75
|
+
hookName: 'transform',
|
|
76
|
+
parameters: [code, path],
|
|
77
|
+
reduce: transformReducer,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
if (config.output.write || config.output.write === undefined) {
|
|
81
|
+
if (file.meta?.pluginKey) {
|
|
82
|
+
// run only for pluginKey defined in the meta of the file
|
|
83
|
+
return pluginManager.hookForPlugin({
|
|
84
|
+
pluginKey: file.meta?.pluginKey,
|
|
85
|
+
hookName: 'writeFile',
|
|
86
|
+
parameters: [transformedCode, path],
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return pluginManager.hookFirst({
|
|
91
|
+
hookName: 'writeFile',
|
|
92
|
+
parameters: [transformedCode, path],
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const pluginManager = new PluginManager(config, { logger, task: queueTask as QueueJob<KubbFile.ResolvedFile>, writeTimeout: 0 })
|
|
99
|
+
|
|
100
|
+
pluginManager.on('execute', (executer) => {
|
|
101
|
+
const { hookName, parameters, plugin } = executer
|
|
102
|
+
|
|
103
|
+
if (hookName === 'writeFile' && logger.spinner) {
|
|
104
|
+
const [code] = parameters as PluginParameter<'writeFile'>
|
|
105
|
+
|
|
106
|
+
if (logger.logLevel === LogLevel.info) {
|
|
107
|
+
logger.spinner.start(`💾 Writing`)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (logger.logLevel === 'debug') {
|
|
111
|
+
logger.info(`PluginKey ${pc.dim(JSON.stringify(plugin.key))} \nwith source\n\n${code}`)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
pluginManager.on('executed', (executer) => {
|
|
117
|
+
const { hookName, plugin, output, parameters } = executer
|
|
118
|
+
const messsage = `${randomPicoColour(plugin.name)} Executing ${hookName}`
|
|
119
|
+
|
|
120
|
+
if (logger.logLevel === LogLevel.info && logger.spinner) {
|
|
121
|
+
if (hookName === 'writeFile') {
|
|
122
|
+
const [_code, path] = parameters as PluginParameter<'writeFile'>
|
|
123
|
+
|
|
124
|
+
logger.spinner.suffixText = pc.dim(path)
|
|
125
|
+
} else {
|
|
126
|
+
logger.spinner.suffixText = messsage
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (logger.logLevel === LogLevel.debug) {
|
|
131
|
+
logger.info(messsage)
|
|
132
|
+
const logs = [
|
|
133
|
+
parameters && `${pc.bgWhite(`Parameters`)} ${randomPicoColour(plugin.name)} ${hookName}`,
|
|
134
|
+
JSON.stringify(parameters, undefined, 2),
|
|
135
|
+
output && `${pc.bgWhite('Output')} ${randomPicoColour(plugin.name)} ${hookName}`,
|
|
136
|
+
output,
|
|
137
|
+
].filter(Boolean)
|
|
138
|
+
|
|
139
|
+
console.log(logs.join('\n'))
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
return pluginManager
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function build(options: BuildOptions): Promise<BuildOutput> {
|
|
147
|
+
const pluginManager = await setup(options)
|
|
148
|
+
|
|
149
|
+
const { fileManager, logger } = pluginManager
|
|
150
|
+
|
|
151
|
+
await pluginManager.hookParallel<'validate', true>({
|
|
152
|
+
hookName: 'validate',
|
|
153
|
+
parameters: [pluginManager.plugins],
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
await pluginManager.hookParallel({
|
|
157
|
+
hookName: 'buildStart',
|
|
158
|
+
parameters: [options.config],
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
await pluginManager.hookParallel({ hookName: 'buildEnd' })
|
|
162
|
+
|
|
163
|
+
if (!fileManager.isExecuting && logger.spinner) {
|
|
164
|
+
logger.spinner.suffixText = ''
|
|
165
|
+
logger.spinner.succeed(`💾 Writing completed`)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return { files: fileManager.files.map((file) => ({ ...file, source: FileManager.getSource(file) })), pluginManager }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
|
|
172
|
+
const pluginManager = await setup(options)
|
|
173
|
+
|
|
174
|
+
const { fileManager, logger } = pluginManager
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
await pluginManager.hookParallel<'validate', true>({
|
|
178
|
+
hookName: 'validate',
|
|
179
|
+
parameters: [pluginManager.plugins],
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
await pluginManager.hookParallel({
|
|
183
|
+
hookName: 'buildStart',
|
|
184
|
+
parameters: [options.config],
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
await pluginManager.hookParallel({ hookName: 'buildEnd' })
|
|
188
|
+
|
|
189
|
+
if (!fileManager.isExecuting && logger.spinner) {
|
|
190
|
+
logger.spinner.suffixText = ''
|
|
191
|
+
logger.spinner.succeed(`💾 Writing completed`)
|
|
192
|
+
}
|
|
193
|
+
} catch (e) {
|
|
194
|
+
return { files: fileManager.files.map((file) => ({ ...file, source: FileManager.getSource(file) })), pluginManager, error: e as Error }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return { files: fileManager.files.map((file) => ({ ...file, source: FileManager.getSource(file) })), pluginManager }
|
|
198
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CLIOptions, InputPath, KubbConfig, KubbUserConfig, PossiblePromise } from './types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type helper to make it easier to use kubb.config.js
|
|
5
|
+
* accepts a direct {@link KubbConfig} object, or a function that returns it.
|
|
6
|
+
* The function receives a {@link ConfigEnv} object that exposes two properties:
|
|
7
|
+
*/
|
|
8
|
+
export function defineConfig(
|
|
9
|
+
options:
|
|
10
|
+
| PossiblePromise<KubbUserConfig | Array<KubbUserConfig>>
|
|
11
|
+
| ((
|
|
12
|
+
/** The options derived from the CLI flags */
|
|
13
|
+
cliOptions: CLIOptions,
|
|
14
|
+
) => PossiblePromise<KubbUserConfig | Array<KubbUserConfig>>),
|
|
15
|
+
): typeof options {
|
|
16
|
+
return options
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isInputPath(result: KubbConfig | undefined): result is KubbConfig<InputPath> {
|
|
20
|
+
return !!result && 'path' in (result as any)
|
|
21
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behaves as an Error to log a warning in the console(still stops the execution)
|
|
3
|
+
*/
|
|
4
|
+
export class Warning extends Error {
|
|
5
|
+
constructor(message?: string, options?: { cause: Error }) {
|
|
6
|
+
super(message, { cause: options?.cause })
|
|
7
|
+
|
|
8
|
+
this.name = 'Warning'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ValidationPluginError extends Error {}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { build } from './build.ts'
|
|
2
|
+
|
|
3
|
+
import type { ObjValueTuple, TupleToUnion } from './types.ts'
|
|
4
|
+
|
|
5
|
+
export { build, safeBuild } from './build.ts'
|
|
6
|
+
export * from './config.ts'
|
|
7
|
+
export * from './errors.ts'
|
|
8
|
+
export * from './FileManager.ts'
|
|
9
|
+
export { Generator } from './Generator.ts'
|
|
10
|
+
export { PackageManager } from './PackageManager.ts'
|
|
11
|
+
// dprint-ignore
|
|
12
|
+
export { createPlugin, pluginName as name, pluginName } from './plugin.ts'
|
|
13
|
+
export { PluginManager } from './PluginManager.ts'
|
|
14
|
+
export { PromiseManager } from './PromiseManager.ts'
|
|
15
|
+
export { SchemaGenerator } from './SchemaGenerator.ts'
|
|
16
|
+
export * from './types.ts'
|
|
17
|
+
|
|
18
|
+
export interface _Register {}
|
|
19
|
+
export type Plugins = _Register
|
|
20
|
+
export type OptionsPlugins = { [K in keyof Plugins]: Plugins[K]['options'] }
|
|
21
|
+
|
|
22
|
+
export type OptionsOfPlugin<K extends keyof Plugins> = Plugins[K]['options']
|
|
23
|
+
|
|
24
|
+
export type PluginUnion = TupleToUnion<ObjValueTuple<OptionsPlugins>>
|
|
25
|
+
|
|
26
|
+
export type Plugin = keyof Plugins
|
|
27
|
+
|
|
28
|
+
export default build
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { createPluginCache } from './utils/cache.ts'
|
|
4
|
+
|
|
5
|
+
import type { FileManager } from './FileManager.ts'
|
|
6
|
+
import type { PluginManager } from './PluginManager.ts'
|
|
7
|
+
import type { KubbPlugin, KubbUserPlugin, PluginContext, PluginFactoryOptions } from './types.ts'
|
|
8
|
+
|
|
9
|
+
type KubbPluginFactory<T extends PluginFactoryOptions = PluginFactoryOptions> = (options: T['options']) => KubbUserPlugin<T>
|
|
10
|
+
|
|
11
|
+
export function createPlugin<T extends PluginFactoryOptions = PluginFactoryOptions>(factory: KubbPluginFactory<T>) {
|
|
12
|
+
return (options: T['options']): ReturnType<KubbPluginFactory<T>> => {
|
|
13
|
+
return factory(options)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type Options = {
|
|
18
|
+
config: PluginContext['config']
|
|
19
|
+
fileManager: FileManager
|
|
20
|
+
pluginManager: PluginManager
|
|
21
|
+
resolvePath: PluginContext['resolvePath']
|
|
22
|
+
resolveName: PluginContext['resolveName']
|
|
23
|
+
logger: PluginContext['logger']
|
|
24
|
+
getPlugins: () => KubbPlugin[]
|
|
25
|
+
plugin?: PluginContext['plugin']
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// not publicly exported
|
|
29
|
+
export type CorePluginOptions = PluginFactoryOptions<'core', 'controller', Options, false, PluginContext>
|
|
30
|
+
|
|
31
|
+
export const pluginName = 'core' satisfies CorePluginOptions['name']
|
|
32
|
+
export const pluginKey: CorePluginOptions['key'] = ['controller', pluginName] satisfies CorePluginOptions['key']
|
|
33
|
+
|
|
34
|
+
export const definePlugin = createPlugin<CorePluginOptions>((options) => {
|
|
35
|
+
const { fileManager, pluginManager, resolvePath, resolveName, logger } = options
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
name: pluginName,
|
|
39
|
+
options,
|
|
40
|
+
key: ['controller', 'core'],
|
|
41
|
+
kind: 'controller',
|
|
42
|
+
api() {
|
|
43
|
+
return {
|
|
44
|
+
get config() {
|
|
45
|
+
return options.config
|
|
46
|
+
},
|
|
47
|
+
get plugins() {
|
|
48
|
+
return options.getPlugins()
|
|
49
|
+
},
|
|
50
|
+
get plugin() {
|
|
51
|
+
// see pluginManger.#execute where we override with `.call` the this with the correct plugin
|
|
52
|
+
return options.plugin as NonNullable<Options['plugin']>
|
|
53
|
+
},
|
|
54
|
+
logger,
|
|
55
|
+
fileManager,
|
|
56
|
+
pluginManager,
|
|
57
|
+
async addFile(...files) {
|
|
58
|
+
const resolvedFiles = await fileManager.add(...files)
|
|
59
|
+
|
|
60
|
+
if (!Array.isArray(resolvedFiles)) {
|
|
61
|
+
return [resolvedFiles]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return resolvedFiles
|
|
65
|
+
},
|
|
66
|
+
resolvePath,
|
|
67
|
+
resolveName,
|
|
68
|
+
cache: createPluginCache(),
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
resolvePath(baseName) {
|
|
72
|
+
const root = path.resolve(this.config.root, this.config.output.path)
|
|
73
|
+
|
|
74
|
+
return path.resolve(root, baseName)
|
|
75
|
+
},
|
|
76
|
+
resolveName(name) {
|
|
77
|
+
return name
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
})
|