@kubb/core 2.0.0-canary.20231030T124958 → 2.0.1
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 +1 -1
- package/dist/chunk-4A7WG6IA.js +128 -0
- package/dist/chunk-4A7WG6IA.js.map +1 -0
- package/dist/chunk-54P4AWHI.js +71 -0
- package/dist/chunk-54P4AWHI.js.map +1 -0
- package/dist/chunk-5TK7TMV6.cjs +131 -0
- package/dist/chunk-5TK7TMV6.cjs.map +1 -0
- package/dist/chunk-7S67BJXQ.js +85 -0
- package/dist/chunk-7S67BJXQ.js.map +1 -0
- package/dist/chunk-E3ANGQ5N.cjs +2290 -0
- package/dist/chunk-E3ANGQ5N.cjs.map +1 -0
- package/dist/chunk-H47IKRXJ.cjs +129 -0
- package/dist/chunk-H47IKRXJ.cjs.map +1 -0
- package/dist/chunk-HIE46T3F.js +129 -0
- package/dist/chunk-HIE46T3F.js.map +1 -0
- package/dist/chunk-K2H7BYQB.js +155 -0
- package/dist/chunk-K2H7BYQB.js.map +1 -0
- package/dist/chunk-NAWI7UXW.js +67 -0
- package/dist/chunk-NAWI7UXW.js.map +1 -0
- package/dist/chunk-PLVKILIY.cjs +162 -0
- package/dist/chunk-PLVKILIY.cjs.map +1 -0
- package/dist/chunk-W2FP7ZWW.cjs +71 -0
- package/dist/chunk-W2FP7ZWW.cjs.map +1 -0
- package/dist/chunk-WZQO3EPM.cjs +91 -0
- package/dist/chunk-WZQO3EPM.cjs.map +1 -0
- package/dist/chunk-XDHI63G7.cjs +104 -0
- package/dist/chunk-XDHI63G7.cjs.map +1 -0
- package/dist/chunk-XPOF4D5N.js +18 -0
- package/dist/chunk-XPOF4D5N.js.map +1 -0
- package/dist/fs.cjs +31 -0
- package/dist/fs.cjs.map +1 -0
- package/dist/fs.d.cts +5 -0
- package/dist/fs.d.ts +5 -0
- package/dist/fs.js +11 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.cjs +1866 -977
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +302 -319
- package/dist/index.d.ts +302 -319
- package/dist/index.js +1071 -846
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +26 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +32 -0
- package/dist/logger.d.ts +32 -0
- package/dist/logger.js +8 -0
- package/dist/logger.js.map +1 -0
- package/dist/transformers.cjs +124 -0
- package/dist/transformers.cjs.map +1 -0
- package/dist/transformers.d.cts +55 -0
- package/dist/transformers.d.ts +55 -0
- package/dist/transformers.js +95 -0
- package/dist/transformers.js.map +1 -0
- package/dist/utils.cjs +23 -1163
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -143
- package/dist/utils.d.ts +2 -143
- package/dist/utils.js +15 -1118
- package/dist/utils.js.map +1 -1
- package/dist/write-A6VgHkYA.d.cts +10 -0
- package/dist/write-A6VgHkYA.d.ts +10 -0
- package/package.json +40 -23
- package/src/BarrelManager.ts +113 -0
- package/src/FileManager.ts +581 -0
- package/src/Generator.ts +34 -0
- package/src/PackageManager.ts +178 -0
- package/src/PluginManager.ts +645 -0
- package/src/PromiseManager.ts +51 -0
- package/src/build.ts +221 -0
- package/src/config.ts +22 -0
- package/src/errors.ts +12 -0
- package/src/fs/clean.ts +5 -0
- package/src/fs/index.ts +3 -0
- package/src/fs/read.ts +68 -0
- package/src/fs/write.ts +79 -0
- package/src/index.ts +27 -0
- package/src/logger.ts +121 -0
- package/src/plugin.ts +80 -0
- package/src/transformers/casing.ts +9 -0
- package/src/transformers/combineCodes.ts +3 -0
- package/src/transformers/createJSDocBlockText.ts +9 -0
- package/src/transformers/escape.ts +31 -0
- package/src/transformers/indent.ts +3 -0
- package/src/transformers/index.ts +36 -0
- package/src/transformers/nameSorter.ts +9 -0
- package/src/transformers/searchAndReplace.ts +25 -0
- package/src/transformers/transformReservedWord.ts +97 -0
- package/src/transformers/trim.ts +7 -0
- package/src/types.ts +334 -0
- package/src/utils/EventEmitter.ts +24 -0
- package/src/utils/FunctionParams.ts +86 -0
- package/src/utils/TreeNode.ts +125 -0
- package/src/utils/URLPath.ts +133 -0
- package/src/utils/cache.ts +35 -0
- package/src/utils/executeStrategies.ts +83 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/promise.ts +13 -0
- package/src/utils/renderTemplate.ts +31 -0
- package/src/utils/timeout.ts +7 -0
- package/src/utils/uniqueName.ts +20 -0
package/src/build.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import c from 'tinyrainbow'
|
|
2
|
+
|
|
3
|
+
import { clean } from './fs/clean.ts'
|
|
4
|
+
import { read } from './fs/read.ts'
|
|
5
|
+
import { URLPath } from './utils/URLPath.ts'
|
|
6
|
+
import { isInputPath } from './config.ts'
|
|
7
|
+
import { FileManager } from './FileManager.ts'
|
|
8
|
+
import { createLogger, LogLevel, randomCliColour } from './logger.ts'
|
|
9
|
+
import { PluginManager } from './PluginManager.ts'
|
|
10
|
+
import { isPromise } from './PromiseManager.ts'
|
|
11
|
+
|
|
12
|
+
import type { KubbFile } from './FileManager.ts'
|
|
13
|
+
import type { Logger } from './logger.ts'
|
|
14
|
+
import type { KubbPlugin, PluginContext, PluginParameter, TransformResult } from './types.ts'
|
|
15
|
+
|
|
16
|
+
type BuildOptions = {
|
|
17
|
+
config: PluginContext['config']
|
|
18
|
+
/**
|
|
19
|
+
* @default Logger without the spinner
|
|
20
|
+
*/
|
|
21
|
+
logger?: Logger
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type BuildOutput = {
|
|
25
|
+
files: FileManager['files']
|
|
26
|
+
pluginManager: PluginManager
|
|
27
|
+
/**
|
|
28
|
+
* Only for safeBuild
|
|
29
|
+
*/
|
|
30
|
+
error?: Error
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function transformReducer(
|
|
34
|
+
this: PluginContext,
|
|
35
|
+
_previousCode: string,
|
|
36
|
+
result: TransformResult | Promise<TransformResult>,
|
|
37
|
+
_plugin: KubbPlugin,
|
|
38
|
+
): Promise<string | null> {
|
|
39
|
+
return result
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function setup(options: BuildOptions): Promise<PluginManager> {
|
|
43
|
+
const { config, logger = createLogger({ logLevel: LogLevel.silent }) } = options
|
|
44
|
+
let count = 0
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
if (isInputPath(config) && !new URLPath(config.input.path).isURL) {
|
|
48
|
+
await read(config.input.path)
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
if (isInputPath(config)) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
'Cannot read file/URL defined in `input.path` or set with `kubb generate PATH` in the CLI of your Kubb config ' + c.dim(config.input.path),
|
|
54
|
+
{
|
|
55
|
+
cause: e,
|
|
56
|
+
},
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (config.output.clean) {
|
|
62
|
+
await clean(config.output.path)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const task = async (file: KubbFile.ResolvedFile): Promise<KubbFile.ResolvedFile> => {
|
|
66
|
+
const { path } = file
|
|
67
|
+
|
|
68
|
+
let source: string | null = FileManager.getSource(file)
|
|
69
|
+
|
|
70
|
+
const { result: loadedResult } = await pluginManager.hookFirst({
|
|
71
|
+
hookName: 'load',
|
|
72
|
+
parameters: [path],
|
|
73
|
+
})
|
|
74
|
+
if (loadedResult && isPromise(loadedResult)) {
|
|
75
|
+
source = await loadedResult
|
|
76
|
+
}
|
|
77
|
+
if (loadedResult && !isPromise(loadedResult)) {
|
|
78
|
+
source = loadedResult
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (source) {
|
|
82
|
+
source = await pluginManager.hookReduceArg0({
|
|
83
|
+
hookName: 'transform',
|
|
84
|
+
parameters: [source, path],
|
|
85
|
+
reduce: transformReducer,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if (config.output.write || config.output.write === undefined) {
|
|
89
|
+
if (file.meta?.pluginKey) {
|
|
90
|
+
// run only for pluginKey defined in the meta of the file
|
|
91
|
+
await pluginManager.hookForPlugin({
|
|
92
|
+
pluginKey: file.meta?.pluginKey,
|
|
93
|
+
hookName: 'writeFile',
|
|
94
|
+
parameters: [source, path],
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await pluginManager.hookFirst({
|
|
99
|
+
hookName: 'writeFile',
|
|
100
|
+
parameters: [source, path],
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
...file,
|
|
107
|
+
source: source || '',
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const pluginManager = new PluginManager(config, { logger, task })
|
|
112
|
+
|
|
113
|
+
pluginManager.on('execute', (executer) => {
|
|
114
|
+
const { hookName, parameters, plugin } = executer
|
|
115
|
+
|
|
116
|
+
if (hookName === 'writeFile' && logger.spinner) {
|
|
117
|
+
const [code] = parameters as PluginParameter<'writeFile'>
|
|
118
|
+
|
|
119
|
+
if (logger.logLevel === LogLevel.debug) {
|
|
120
|
+
logger.debug(`PluginKey ${c.dim(JSON.stringify(plugin.key))} \nwith source\n\n${code}`)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
pluginManager.queue.on('add', () => {
|
|
126
|
+
if (logger.logLevel !== LogLevel.info) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (logger.spinner && count === 0) {
|
|
131
|
+
logger.spinner?.start(`💾 Writing`)
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
pluginManager.queue.on('active', () => {
|
|
136
|
+
if (logger.logLevel !== LogLevel.info) {
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (logger.spinner && pluginManager.queue.size > 0) {
|
|
141
|
+
const text = `Item: ${count} Size: ${pluginManager.queue.size} Pending: ${pluginManager.queue.pending}`
|
|
142
|
+
|
|
143
|
+
logger.spinner.suffixText = c.dim(text)
|
|
144
|
+
}
|
|
145
|
+
;++count
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
pluginManager.queue.on('completed', () => {
|
|
149
|
+
if (logger.logLevel !== LogLevel.info) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (logger.spinner) {
|
|
154
|
+
const text = `Item: ${count} Size: ${pluginManager.queue.size} Pending: ${pluginManager.queue.pending}`
|
|
155
|
+
|
|
156
|
+
logger.spinner.suffixText = c.dim(text)
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
pluginManager.on('executed', (executer) => {
|
|
161
|
+
const { hookName, plugin, output, parameters } = executer
|
|
162
|
+
|
|
163
|
+
if (logger.logLevel === LogLevel.debug) {
|
|
164
|
+
const logs = [
|
|
165
|
+
`${randomCliColour(plugin.name)} Executing ${hookName}`,
|
|
166
|
+
parameters && `${c.bgWhite(`Parameters`)} ${randomCliColour(plugin.name)} ${hookName}`,
|
|
167
|
+
JSON.stringify(parameters, undefined, 2),
|
|
168
|
+
output && `${c.bgWhite('Output')} ${randomCliColour(plugin.name)} ${hookName}`,
|
|
169
|
+
output,
|
|
170
|
+
].filter(Boolean)
|
|
171
|
+
|
|
172
|
+
logger.debug(logs.join('\n'))
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
return pluginManager
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function build(options: BuildOptions): Promise<BuildOutput> {
|
|
180
|
+
const pluginManager = await setup(options)
|
|
181
|
+
|
|
182
|
+
const { fileManager, logger } = pluginManager
|
|
183
|
+
|
|
184
|
+
await pluginManager.hookParallel({
|
|
185
|
+
hookName: 'buildStart',
|
|
186
|
+
parameters: [options.config],
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
await pluginManager.hookParallel({ hookName: 'buildEnd' })
|
|
190
|
+
|
|
191
|
+
if (logger.logLevel === LogLevel.info && logger.spinner) {
|
|
192
|
+
logger.spinner.suffixText = ''
|
|
193
|
+
logger.spinner.succeed(`💾 Writing completed`)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return { files: fileManager.files.map((file) => ({ ...file, source: FileManager.getSource(file) })), pluginManager }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
|
|
200
|
+
const pluginManager = await setup(options)
|
|
201
|
+
|
|
202
|
+
const { fileManager, logger } = pluginManager
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
await pluginManager.hookParallel({
|
|
206
|
+
hookName: 'buildStart',
|
|
207
|
+
parameters: [options.config],
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
await pluginManager.hookParallel({ hookName: 'buildEnd' })
|
|
211
|
+
|
|
212
|
+
if (logger.logLevel === LogLevel.info && logger.spinner) {
|
|
213
|
+
logger.spinner.suffixText = ''
|
|
214
|
+
logger.spinner.succeed(`💾 Writing completed`)
|
|
215
|
+
}
|
|
216
|
+
} catch (e) {
|
|
217
|
+
return { files: fileManager.files.map((file) => ({ ...file, source: FileManager.getSource(file) })), pluginManager, error: e as Error }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return { files: fileManager.files.map((file) => ({ ...file, source: FileManager.getSource(file) })), pluginManager }
|
|
221
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PossiblePromise } from '@kubb/types'
|
|
2
|
+
import type { CLIOptions, InputPath, KubbConfig, KubbUserConfig } from './types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Type helper to make it easier to use kubb.config.js
|
|
6
|
+
* accepts a direct {@link KubbConfig} object, or a function that returns it.
|
|
7
|
+
* The function receives a {@link ConfigEnv} object that exposes two properties:
|
|
8
|
+
*/
|
|
9
|
+
export function defineConfig(
|
|
10
|
+
options:
|
|
11
|
+
| PossiblePromise<KubbUserConfig | Array<KubbUserConfig>>
|
|
12
|
+
| ((
|
|
13
|
+
/** The options derived from the CLI flags */
|
|
14
|
+
cliOptions: CLIOptions,
|
|
15
|
+
) => PossiblePromise<KubbUserConfig | Array<KubbUserConfig>>),
|
|
16
|
+
): typeof options {
|
|
17
|
+
return options
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isInputPath(result: KubbConfig | undefined): result is KubbConfig<InputPath> {
|
|
21
|
+
return !!result && 'path' in (result as any)
|
|
22
|
+
}
|
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/fs/clean.ts
ADDED
package/src/fs/index.ts
ADDED
package/src/fs/read.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { basename, extname, relative } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra'
|
|
4
|
+
import { switcher } from 'js-runtime'
|
|
5
|
+
|
|
6
|
+
function slash(path: string, platform: 'windows' | 'mac' | 'linux' = 'linux') {
|
|
7
|
+
const isWindowsPath = /^\\\\\?\\/.test(path)
|
|
8
|
+
|
|
9
|
+
if (['linux', 'mac'].includes(platform) && !isWindowsPath) {
|
|
10
|
+
// linux and mac
|
|
11
|
+
return path.replaceAll(/\\/g, '/').replace('../', '').trimEnd()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// windows
|
|
15
|
+
return path.replaceAll(/\\/g, '/').replace('../', '').trimEnd()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getRelativePath(rootDir?: string | null, filePath?: string | null, platform: 'windows' | 'mac' | 'linux' = 'linux'): string {
|
|
19
|
+
if (!rootDir || !filePath) {
|
|
20
|
+
throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const relativePath = relative(rootDir, filePath)
|
|
24
|
+
|
|
25
|
+
// On Windows, paths are separated with a "\"
|
|
26
|
+
// However, web browsers use "/" no matter the platform
|
|
27
|
+
const slashedPath = slash(relativePath, platform)
|
|
28
|
+
|
|
29
|
+
if (slashedPath.startsWith('../')) {
|
|
30
|
+
return slashedPath.replace(basename(slashedPath), basename(slashedPath, extname(filePath)))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `./${slashedPath.replace(basename(slashedPath), basename(slashedPath, extname(filePath)))}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const reader = switcher(
|
|
37
|
+
{
|
|
38
|
+
node: async (path: string) => {
|
|
39
|
+
return fs.readFile(path, { encoding: 'utf8' })
|
|
40
|
+
},
|
|
41
|
+
bun: async (path: string) => {
|
|
42
|
+
const file = Bun.file(path)
|
|
43
|
+
|
|
44
|
+
return file.text()
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
'node',
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const syncReader = switcher(
|
|
51
|
+
{
|
|
52
|
+
node: (path: string) => {
|
|
53
|
+
return fs.readFileSync(path, { encoding: 'utf8' })
|
|
54
|
+
},
|
|
55
|
+
bun: () => {
|
|
56
|
+
throw new Error('Bun cannot read sync')
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
'node',
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
export async function read(path: string): Promise<string> {
|
|
63
|
+
return reader(path)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function readSync(path: string): string {
|
|
67
|
+
return syncReader(path)
|
|
68
|
+
}
|
package/src/fs/write.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra'
|
|
4
|
+
import { switcher } from 'js-runtime'
|
|
5
|
+
|
|
6
|
+
type Options = { sanity?: boolean }
|
|
7
|
+
|
|
8
|
+
const writer = switcher(
|
|
9
|
+
{
|
|
10
|
+
node: async (path: string, data: string, { sanity }: Options) => {
|
|
11
|
+
try {
|
|
12
|
+
const oldContent = await fs.readFile(resolve(path), { encoding: 'utf-8' })
|
|
13
|
+
if (oldContent?.toString() === data?.toString()) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
} catch (_err) {
|
|
17
|
+
/* empty */
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
await fs.outputFile(resolve(path), data, { encoding: 'utf-8' })
|
|
21
|
+
|
|
22
|
+
if (sanity) {
|
|
23
|
+
const savedData = await fs.readFile(resolve(path), { encoding: 'utf-8' })
|
|
24
|
+
|
|
25
|
+
if (savedData?.toString() !== data?.toString()) {
|
|
26
|
+
throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return savedData
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return data
|
|
33
|
+
},
|
|
34
|
+
bun: async (path: string, data: string, { sanity }: Options) => {
|
|
35
|
+
try {
|
|
36
|
+
await Bun.write(resolve(path), data)
|
|
37
|
+
|
|
38
|
+
if (sanity) {
|
|
39
|
+
const file = Bun.file(resolve(path))
|
|
40
|
+
const savedData = await file.text()
|
|
41
|
+
|
|
42
|
+
if (savedData?.toString() !== data?.toString()) {
|
|
43
|
+
throw new Error(`Sanity check failed for ${path}\n\nData[${data.length}]:\n${data}\n\nSaved[${savedData.length}]:\n${savedData}\n`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return savedData
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return data
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.log(e, resolve(path))
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
'node',
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export async function write(data: string, path: string, options: Options = {}): Promise<string | undefined> {
|
|
59
|
+
if (data.trim() === '') {
|
|
60
|
+
return undefined
|
|
61
|
+
}
|
|
62
|
+
return writer(path, data.trim(), options)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function writeLog(data: string): Promise<string | undefined> {
|
|
66
|
+
if (data.trim() === '') {
|
|
67
|
+
return undefined
|
|
68
|
+
}
|
|
69
|
+
const path = resolve(process.cwd(), 'kubb-log.log')
|
|
70
|
+
let previousLogs = ''
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
previousLogs = await fs.readFile(resolve(path), { encoding: 'utf-8' })
|
|
74
|
+
} catch (_err) {
|
|
75
|
+
/* empty */
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return writer(path, [previousLogs, data.trim()].filter(Boolean).join('\n\n\n'), { sanity: false })
|
|
79
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { build } from './build.ts'
|
|
2
|
+
|
|
3
|
+
import type { ObjValueTuple, TupleToUnion } from '@kubb/types'
|
|
4
|
+
|
|
5
|
+
export { build, safeBuild } from './build.ts'
|
|
6
|
+
export { defineConfig, isInputPath } from './config.ts'
|
|
7
|
+
export { Warning } from './errors.ts'
|
|
8
|
+
export { FileManager, KubbFile } 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 type * from './types.ts'
|
|
16
|
+
|
|
17
|
+
export interface _Register {}
|
|
18
|
+
export type Plugins = _Register
|
|
19
|
+
export type OptionsPlugins = { [K in keyof Plugins]: Plugins[K]['options'] }
|
|
20
|
+
|
|
21
|
+
export type OptionsOfPlugin<K extends keyof Plugins> = Plugins[K]['options']
|
|
22
|
+
|
|
23
|
+
export type PluginUnion = TupleToUnion<ObjValueTuple<OptionsPlugins>>
|
|
24
|
+
|
|
25
|
+
export type Plugin = keyof Plugins
|
|
26
|
+
|
|
27
|
+
export default build
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import seedrandom from 'seedrandom'
|
|
2
|
+
import c, { createColors } from 'tinyrainbow'
|
|
3
|
+
|
|
4
|
+
import { writeLog } from './fs/write.ts'
|
|
5
|
+
|
|
6
|
+
import type { Ora } from 'ora'
|
|
7
|
+
import type { Formatter } from 'tinyrainbow'
|
|
8
|
+
|
|
9
|
+
export const LogLevel = {
|
|
10
|
+
silent: 'silent',
|
|
11
|
+
info: 'info',
|
|
12
|
+
debug: 'debug',
|
|
13
|
+
} as const
|
|
14
|
+
|
|
15
|
+
export type LogLevel = keyof typeof LogLevel
|
|
16
|
+
|
|
17
|
+
export type Logger = {
|
|
18
|
+
/**
|
|
19
|
+
* Optional config name to show in CLI output
|
|
20
|
+
*/
|
|
21
|
+
name?: string
|
|
22
|
+
logLevel: LogLevel
|
|
23
|
+
log: (message: string | null) => void
|
|
24
|
+
error: (message: string | null) => void
|
|
25
|
+
info: (message: string | null) => void
|
|
26
|
+
warn: (message: string | null) => void
|
|
27
|
+
debug: (message: string | null) => Promise<void>
|
|
28
|
+
spinner?: Ora
|
|
29
|
+
logs: string[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Props = {
|
|
33
|
+
name?: string
|
|
34
|
+
logLevel: LogLevel
|
|
35
|
+
spinner?: Ora
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createLogger({ logLevel, name, spinner }: Props): Logger {
|
|
39
|
+
const logs: string[] = []
|
|
40
|
+
const log: Logger['log'] = (message) => {
|
|
41
|
+
if (message && spinner) {
|
|
42
|
+
spinner.text = message
|
|
43
|
+
logs.push(message)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const error: Logger['error'] = (message) => {
|
|
48
|
+
if (message) {
|
|
49
|
+
throw new Error(message || 'Something went wrong')
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const warn: Logger['warn'] = (message) => {
|
|
54
|
+
if (message && spinner) {
|
|
55
|
+
spinner.warn(c.yellow(message))
|
|
56
|
+
logs.push(message)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const info: Logger['warn'] = (message) => {
|
|
61
|
+
if (message && spinner && logLevel !== LogLevel.silent) {
|
|
62
|
+
spinner.info(message)
|
|
63
|
+
logs.push(message)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const debug: Logger['debug'] = async (message) => {
|
|
68
|
+
if (message) {
|
|
69
|
+
await writeLog(message)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const logger: Logger = {
|
|
74
|
+
name,
|
|
75
|
+
logLevel,
|
|
76
|
+
log,
|
|
77
|
+
error,
|
|
78
|
+
warn,
|
|
79
|
+
info,
|
|
80
|
+
debug,
|
|
81
|
+
spinner,
|
|
82
|
+
logs,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return logger
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const defaultColours = ['black', 'blue', 'darkBlue', 'cyan', 'gray', 'green', 'darkGreen', 'magenta', 'red', 'darkRed', 'yellow', 'darkYellow'] as const
|
|
89
|
+
|
|
90
|
+
export function randomColour(text?: string, colours = defaultColours): string {
|
|
91
|
+
if (!text) {
|
|
92
|
+
return 'white'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const random = seedrandom(text)
|
|
96
|
+
const colour = colours.at(Math.floor(random() * colours.length)) || 'white'
|
|
97
|
+
|
|
98
|
+
return colour
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function randomCliColour(text?: string, colors = defaultColours): string {
|
|
102
|
+
const colours = createColors(true)
|
|
103
|
+
|
|
104
|
+
if (!text) {
|
|
105
|
+
return colours.white(text)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const colour = randomColour(text, colors)
|
|
109
|
+
const isDark = colour.includes('dark')
|
|
110
|
+
const key = colour.replace('dark', '').toLowerCase() as keyof typeof colours
|
|
111
|
+
const formatter: Formatter = colours[key] as Formatter
|
|
112
|
+
|
|
113
|
+
if (isDark) {
|
|
114
|
+
return c.bold(formatter(text))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (typeof formatter !== 'function') {
|
|
118
|
+
throw new Error('Formatter for picoColor is not of type function/Formatter')
|
|
119
|
+
}
|
|
120
|
+
return formatter(text)
|
|
121
|
+
}
|
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, KubbUserPluginWithLifeCycle, PluginContext, PluginFactoryOptions } from './types.ts'
|
|
8
|
+
|
|
9
|
+
type KubbPluginFactory<T extends PluginFactoryOptions = PluginFactoryOptions> = (options: T['options']) => KubbUserPluginWithLifeCycle<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: () => Array<KubbPlugin>
|
|
25
|
+
plugin?: PluginContext['plugin']
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// not publicly exported
|
|
29
|
+
export type CorePluginOptions = PluginFactoryOptions<'core', Options, Options, PluginContext, never>
|
|
30
|
+
|
|
31
|
+
export const pluginName = 'core' satisfies CorePluginOptions['name']
|
|
32
|
+
export const pluginKey: CorePluginOptions['key'] = [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: ['core'],
|
|
41
|
+
|
|
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
|
+
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { camelCase as changeCaseCamel, pascalCase as changePascalCase } from 'change-case'
|
|
2
|
+
|
|
3
|
+
export function camelCase(text: string): string {
|
|
4
|
+
return changeCaseCamel(text, { delimiter: '', mergeAmbiguousCharacters: true })
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function pascalCase(text: string): string {
|
|
8
|
+
return changePascalCase(text, { delimiter: '', mergeAmbiguousCharacters: true })
|
|
9
|
+
}
|