@kubb/core 5.0.0-alpha.21 → 5.0.0-alpha.23
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/{PluginDriver-CEQPafXV.d.ts → PluginDriver-P920mak9.d.ts} +135 -54
- package/dist/hooks.cjs +3 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +6 -3
- package/dist/hooks.js +3 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +135 -228
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +26 -69
- package/dist/index.js +136 -227
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Kubb.ts +5 -5
- package/src/PluginDriver.ts +110 -154
- package/src/build.ts +11 -11
- package/src/constants.ts +2 -12
- package/src/defineGenerator.ts +29 -7
- package/src/defineResolver.ts +13 -19
- package/src/hooks/useDriver.ts +3 -0
- package/src/hooks/useMode.ts +3 -3
- package/src/index.ts +0 -2
- package/src/renderNode.tsx +9 -6
- package/src/types.ts +67 -35
- package/src/utils/TreeNode.ts +22 -7
- package/src/utils/getBarrelFiles.ts +9 -6
- package/src/utils/getConfigs.ts +1 -1
- package/src/utils/getPreset.ts +3 -3
- package/src/utils/mergeResolvers.ts +9 -1
- package/src/defineBuilder.ts +0 -26
- package/src/definePreset.ts +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/core",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.23",
|
|
4
4
|
"description": "Core functionality for Kubb's plugin-based code generation system, providing the foundation for transforming OpenAPI specifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"remeda": "^2.33.6",
|
|
72
72
|
"semver": "^7.7.4",
|
|
73
73
|
"tinyexec": "^1.0.4",
|
|
74
|
-
"@kubb/ast": "5.0.0-alpha.
|
|
74
|
+
"@kubb/ast": "5.0.0-alpha.23"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@types/semver": "^7.7.1",
|
package/src/Kubb.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FabricFile } from '@kubb/fabric-core/types'
|
|
2
2
|
import type { Strategy } from './PluginDriver.ts'
|
|
3
3
|
import type { Config, Plugin, PluginLifecycleHooks } from './types'
|
|
4
4
|
|
|
@@ -76,7 +76,7 @@ export interface KubbEvents {
|
|
|
76
76
|
/**
|
|
77
77
|
* Emitted when code generation phase completes.
|
|
78
78
|
*/
|
|
79
|
-
'generation:end': [config: Config, files: Array<
|
|
79
|
+
'generation:end': [config: Config, files: Array<FabricFile.ResolvedFile>, sources: Map<FabricFile.Path, string>]
|
|
80
80
|
/**
|
|
81
81
|
* Emitted with a summary of the generation results.
|
|
82
82
|
* Contains summary lines, title, and success status.
|
|
@@ -160,7 +160,7 @@ export interface KubbEvents {
|
|
|
160
160
|
* Emitted when file processing starts.
|
|
161
161
|
* Contains the list of files to be processed.
|
|
162
162
|
*/
|
|
163
|
-
'files:processing:start': [files: Array<
|
|
163
|
+
'files:processing:start': [files: Array<FabricFile.ResolvedFile>]
|
|
164
164
|
/**
|
|
165
165
|
* Emitted for each file being processed, providing progress updates.
|
|
166
166
|
* Contains processed count, total count, percentage, and file details.
|
|
@@ -186,7 +186,7 @@ export interface KubbEvents {
|
|
|
186
186
|
/**
|
|
187
187
|
* The file being processed.
|
|
188
188
|
*/
|
|
189
|
-
file:
|
|
189
|
+
file: FabricFile.ResolvedFile
|
|
190
190
|
/**
|
|
191
191
|
* Kubb configuration (not present in Fabric).
|
|
192
192
|
* Provides access to the current config during file processing.
|
|
@@ -198,7 +198,7 @@ export interface KubbEvents {
|
|
|
198
198
|
* Emitted when file processing completes.
|
|
199
199
|
* Contains the list of processed files.
|
|
200
200
|
*/
|
|
201
|
-
'files:processing:end': [files: Array<
|
|
201
|
+
'files:processing:end': [files: Array<FabricFile.ResolvedFile>]
|
|
202
202
|
|
|
203
203
|
/**
|
|
204
204
|
* Emitted when a plugin starts executing.
|
package/src/PluginDriver.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { basename, extname, resolve } from 'node:path'
|
|
2
2
|
import { performance } from 'node:perf_hooks'
|
|
3
3
|
import type { AsyncEventEmitter } from '@internals/utils'
|
|
4
|
-
import { isPromiseRejectedResult,
|
|
4
|
+
import { isPromiseRejectedResult, transformReservedWord } from '@internals/utils'
|
|
5
5
|
import type { RootNode } from '@kubb/ast/types'
|
|
6
|
-
import type { Fabric as FabricType
|
|
7
|
-
import {
|
|
6
|
+
import type { FabricFile, Fabric as FabricType } from '@kubb/fabric-core/types'
|
|
7
|
+
import { DEFAULT_STUDIO_URL } from './constants.ts'
|
|
8
8
|
import { openInStudio as openInStudioFn } from './devtools.ts'
|
|
9
9
|
|
|
10
10
|
import type {
|
|
@@ -21,12 +21,19 @@ import type {
|
|
|
21
21
|
PluginWithLifeCycle,
|
|
22
22
|
ResolveNameParams,
|
|
23
23
|
ResolvePathParams,
|
|
24
|
-
UserPlugin,
|
|
25
24
|
} from './types.ts'
|
|
26
25
|
import { hookFirst, hookParallel, hookSeq } from './utils/executeStrategies.ts'
|
|
27
26
|
|
|
28
27
|
type RequiredPluginLifecycle = Required<PluginLifecycle>
|
|
29
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Hook dispatch strategy used by the `PluginDriver`.
|
|
31
|
+
*
|
|
32
|
+
* - `hookFirst` — stops at the first non-null result.
|
|
33
|
+
* - `hookForPlugin` — calls only the matching plugin.
|
|
34
|
+
* - `hookParallel` — calls all plugins concurrently.
|
|
35
|
+
* - `hookSeq` — calls all plugins in order, threading the result.
|
|
36
|
+
*/
|
|
30
37
|
export type Strategy = 'hookFirst' | 'hookForPlugin' | 'hookParallel' | 'hookSeq'
|
|
31
38
|
|
|
32
39
|
type ParseResult<H extends PluginLifecycleHooks> = RequiredPluginLifecycle[H]
|
|
@@ -47,15 +54,27 @@ type Options = {
|
|
|
47
54
|
concurrency?: number
|
|
48
55
|
}
|
|
49
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Parameters accepted by `PluginDriver.getFile` to resolve a generated file descriptor.
|
|
59
|
+
*/
|
|
50
60
|
export type GetFileOptions<TOptions = object> = {
|
|
51
61
|
name: string
|
|
52
|
-
mode?:
|
|
53
|
-
extname:
|
|
62
|
+
mode?: FabricFile.Mode
|
|
63
|
+
extname: FabricFile.Extname
|
|
54
64
|
pluginName: string
|
|
55
65
|
options?: TOptions
|
|
56
66
|
}
|
|
57
67
|
|
|
58
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Returns `'single'` when `fileOrFolder` has a file extension, `'split'` otherwise.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* getMode('src/gen/types.ts') // 'single'
|
|
74
|
+
* getMode('src/gen/types') // 'split'
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function getMode(fileOrFolder: string | undefined | null): FabricFile.Mode {
|
|
59
78
|
if (!fileOrFolder) {
|
|
60
79
|
return 'split'
|
|
61
80
|
}
|
|
@@ -76,17 +95,21 @@ export class PluginDriver {
|
|
|
76
95
|
adapter: Adapter | undefined = undefined
|
|
77
96
|
#studioIsOpen = false
|
|
78
97
|
|
|
79
|
-
readonly
|
|
80
|
-
readonly #usedPluginNames: Record<string, number> = {}
|
|
98
|
+
readonly plugins = new Map<string, Plugin>()
|
|
81
99
|
|
|
82
100
|
constructor(config: Config, options: Options) {
|
|
83
101
|
this.config = config
|
|
84
102
|
this.options = options
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
config.plugins
|
|
104
|
+
.map((plugin) => Object.assign({ install() {} }, plugin) as unknown as Plugin)
|
|
105
|
+
.sort((a, b) => {
|
|
106
|
+
if (b.pre?.includes(a.name)) return 1
|
|
107
|
+
if (b.post?.includes(a.name)) return -1
|
|
108
|
+
return 0
|
|
109
|
+
})
|
|
110
|
+
.forEach((plugin) => {
|
|
111
|
+
this.plugins.set(plugin.name, plugin)
|
|
112
|
+
})
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
get events() {
|
|
@@ -94,20 +117,19 @@ export class PluginDriver {
|
|
|
94
117
|
}
|
|
95
118
|
|
|
96
119
|
getContext<TOptions extends PluginFactoryOptions>(plugin: Plugin<TOptions>): PluginContext<TOptions> & Record<string, unknown> {
|
|
97
|
-
const plugins = [...this.#plugins]
|
|
98
120
|
const driver = this
|
|
99
121
|
|
|
100
122
|
const baseContext = {
|
|
101
|
-
fabric:
|
|
102
|
-
config:
|
|
123
|
+
fabric: driver.options.fabric,
|
|
124
|
+
config: driver.config,
|
|
103
125
|
plugin,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
addFile: async (...files: Array<
|
|
126
|
+
getPlugin: driver.getPlugin.bind(driver),
|
|
127
|
+
events: driver.options.events,
|
|
128
|
+
driver: driver,
|
|
129
|
+
addFile: async (...files: Array<FabricFile.File>) => {
|
|
108
130
|
await this.options.fabric.addFile(...files)
|
|
109
131
|
},
|
|
110
|
-
upsertFile: async (...files: Array<
|
|
132
|
+
upsertFile: async (...files: Array<FabricFile.File>) => {
|
|
111
133
|
await this.options.fabric.upsertFile(...files)
|
|
112
134
|
},
|
|
113
135
|
get rootNode(): RootNode | undefined {
|
|
@@ -116,6 +138,9 @@ export class PluginDriver {
|
|
|
116
138
|
get adapter(): Adapter | undefined {
|
|
117
139
|
return driver.adapter
|
|
118
140
|
},
|
|
141
|
+
get resolver() {
|
|
142
|
+
return plugin.resolver
|
|
143
|
+
},
|
|
119
144
|
openInStudio(options?: DevtoolsOptions) {
|
|
120
145
|
if (!driver.config.devtools || driver.#studioIsOpen) {
|
|
121
146
|
return
|
|
@@ -138,9 +163,10 @@ export class PluginDriver {
|
|
|
138
163
|
} as unknown as PluginContext<TOptions>
|
|
139
164
|
|
|
140
165
|
const mergedExtras: Record<string, unknown> = {}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
166
|
+
|
|
167
|
+
for (const plugin of this.plugins.values()) {
|
|
168
|
+
if (typeof plugin.inject === 'function') {
|
|
169
|
+
const result = (plugin.inject as (this: PluginContext, context: PluginContext) => unknown).call(
|
|
144
170
|
baseContext as unknown as PluginContext,
|
|
145
171
|
baseContext as unknown as PluginContext,
|
|
146
172
|
)
|
|
@@ -155,12 +181,10 @@ export class PluginDriver {
|
|
|
155
181
|
...mergedExtras,
|
|
156
182
|
}
|
|
157
183
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
getFile<TOptions = object>({ name, mode, extname, pluginName, options }: GetFileOptions<TOptions>): KubbFile.File<{ pluginName: string }> {
|
|
184
|
+
/**
|
|
185
|
+
* @deprecated use resolvers context instead
|
|
186
|
+
*/
|
|
187
|
+
getFile<TOptions = object>({ name, mode, extname, pluginName, options }: GetFileOptions<TOptions>): FabricFile.File<{ pluginName: string }> {
|
|
164
188
|
const resolvedName = mode ? (mode === 'single' ? '' : this.resolveName({ name, pluginName, type: 'file' })) : name
|
|
165
189
|
|
|
166
190
|
const path = this.resolvePath({
|
|
@@ -176,7 +200,7 @@ export class PluginDriver {
|
|
|
176
200
|
|
|
177
201
|
return {
|
|
178
202
|
path,
|
|
179
|
-
baseName: basename(path) as
|
|
203
|
+
baseName: basename(path) as FabricFile.File['baseName'],
|
|
180
204
|
meta: {
|
|
181
205
|
pluginName,
|
|
182
206
|
},
|
|
@@ -186,7 +210,10 @@ export class PluginDriver {
|
|
|
186
210
|
}
|
|
187
211
|
}
|
|
188
212
|
|
|
189
|
-
|
|
213
|
+
/**
|
|
214
|
+
* @deprecated use resolvers context instead
|
|
215
|
+
*/
|
|
216
|
+
resolvePath = <TOptions = object>(params: ResolvePathParams<TOptions>): FabricFile.Path => {
|
|
190
217
|
const root = resolve(this.config.root, this.config.output.path)
|
|
191
218
|
const defaultPath = resolve(root, params.baseName)
|
|
192
219
|
|
|
@@ -207,7 +234,9 @@ export class PluginDriver {
|
|
|
207
234
|
|
|
208
235
|
return firstResult?.result || defaultPath
|
|
209
236
|
}
|
|
210
|
-
|
|
237
|
+
/**
|
|
238
|
+
* @deprecated use resolvers context instead
|
|
239
|
+
*/
|
|
211
240
|
resolveName = (params: ResolveNameParams): string => {
|
|
212
241
|
if (params.pluginName) {
|
|
213
242
|
const names = this.hookForPluginSync({
|
|
@@ -216,9 +245,7 @@ export class PluginDriver {
|
|
|
216
245
|
parameters: [params.name.trim(), params.type],
|
|
217
246
|
})
|
|
218
247
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return transformReservedWord([...uniqueNames].at(0) || params.name)
|
|
248
|
+
return transformReservedWord(names?.at(0) ?? params.name)
|
|
222
249
|
}
|
|
223
250
|
|
|
224
251
|
const name = this.hookFirstSync({
|
|
@@ -241,36 +268,32 @@ export class PluginDriver {
|
|
|
241
268
|
hookName: H
|
|
242
269
|
parameters: PluginParameter<H>
|
|
243
270
|
}): Promise<Array<ReturnType<ParseResult<H>> | null>> {
|
|
244
|
-
const
|
|
271
|
+
const plugin = this.plugins.get(pluginName)
|
|
272
|
+
|
|
273
|
+
if (!plugin) {
|
|
274
|
+
return [null]
|
|
275
|
+
}
|
|
245
276
|
|
|
246
277
|
this.events.emit('plugins:hook:progress:start', {
|
|
247
278
|
hookName,
|
|
248
|
-
plugins,
|
|
279
|
+
plugins: [plugin],
|
|
249
280
|
})
|
|
250
281
|
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
parameters,
|
|
258
|
-
plugin,
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
if (result !== undefined && result !== null) {
|
|
262
|
-
items.push(result)
|
|
263
|
-
}
|
|
264
|
-
}
|
|
282
|
+
const result = await this.#execute<H>({
|
|
283
|
+
strategy: 'hookFirst',
|
|
284
|
+
hookName,
|
|
285
|
+
parameters,
|
|
286
|
+
plugin,
|
|
287
|
+
})
|
|
265
288
|
|
|
266
289
|
this.events.emit('plugins:hook:progress:end', { hookName })
|
|
267
290
|
|
|
268
|
-
return
|
|
291
|
+
return [result]
|
|
269
292
|
}
|
|
293
|
+
|
|
270
294
|
/**
|
|
271
295
|
* Run a specific hookName for plugin x.
|
|
272
296
|
*/
|
|
273
|
-
|
|
274
297
|
hookForPluginSync<H extends PluginLifecycleHooks>({
|
|
275
298
|
pluginName,
|
|
276
299
|
hookName,
|
|
@@ -280,20 +303,20 @@ export class PluginDriver {
|
|
|
280
303
|
hookName: H
|
|
281
304
|
parameters: PluginParameter<H>
|
|
282
305
|
}): Array<ReturnType<ParseResult<H>>> | null {
|
|
283
|
-
const
|
|
306
|
+
const plugin = this.plugins.get(pluginName)
|
|
284
307
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
strategy: 'hookFirst',
|
|
289
|
-
hookName,
|
|
290
|
-
parameters,
|
|
291
|
-
plugin,
|
|
292
|
-
})
|
|
293
|
-
})
|
|
294
|
-
.filter((x): x is NonNullable<typeof x> => x !== null)
|
|
308
|
+
if (!plugin) {
|
|
309
|
+
return null
|
|
310
|
+
}
|
|
295
311
|
|
|
296
|
-
|
|
312
|
+
const result = this.#executeSync<H>({
|
|
313
|
+
strategy: 'hookFirst',
|
|
314
|
+
hookName,
|
|
315
|
+
parameters,
|
|
316
|
+
plugin,
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
return result !== null ? [result] : []
|
|
297
320
|
}
|
|
298
321
|
|
|
299
322
|
/**
|
|
@@ -308,9 +331,10 @@ export class PluginDriver {
|
|
|
308
331
|
parameters: PluginParameter<H>
|
|
309
332
|
skipped?: ReadonlySet<Plugin> | null
|
|
310
333
|
}): Promise<SafeParseResult<H>> {
|
|
311
|
-
const plugins =
|
|
312
|
-
|
|
313
|
-
|
|
334
|
+
const plugins: Array<Plugin> = []
|
|
335
|
+
for (const plugin of this.plugins.values()) {
|
|
336
|
+
if (hookName in plugin && (skipped ? !skipped.has(plugin) : true)) plugins.push(plugin)
|
|
337
|
+
}
|
|
314
338
|
|
|
315
339
|
this.events.emit('plugins:hook:progress:start', { hookName, plugins })
|
|
316
340
|
|
|
@@ -350,11 +374,11 @@ export class PluginDriver {
|
|
|
350
374
|
skipped?: ReadonlySet<Plugin> | null
|
|
351
375
|
}): SafeParseResult<H> | null {
|
|
352
376
|
let parseResult: SafeParseResult<H> | null = null
|
|
353
|
-
const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
|
|
354
|
-
return skipped ? !skipped.has(plugin) : true
|
|
355
|
-
})
|
|
356
377
|
|
|
357
|
-
for (const plugin of plugins) {
|
|
378
|
+
for (const plugin of this.plugins.values()) {
|
|
379
|
+
if (!(hookName in plugin)) continue
|
|
380
|
+
if (skipped?.has(plugin)) continue
|
|
381
|
+
|
|
358
382
|
parseResult = {
|
|
359
383
|
result: this.#executeSync<H>({
|
|
360
384
|
strategy: 'hookFirst',
|
|
@@ -365,9 +389,7 @@ export class PluginDriver {
|
|
|
365
389
|
plugin,
|
|
366
390
|
} as SafeParseResult<H>
|
|
367
391
|
|
|
368
|
-
if (parseResult
|
|
369
|
-
break
|
|
370
|
-
}
|
|
392
|
+
if (parseResult.result != null) break
|
|
371
393
|
}
|
|
372
394
|
|
|
373
395
|
return parseResult
|
|
@@ -383,7 +405,10 @@ export class PluginDriver {
|
|
|
383
405
|
hookName: H
|
|
384
406
|
parameters?: Parameters<RequiredPluginLifecycle[H]> | undefined
|
|
385
407
|
}): Promise<Awaited<TOutput>[]> {
|
|
386
|
-
const plugins =
|
|
408
|
+
const plugins: Array<Plugin> = []
|
|
409
|
+
for (const plugin of this.plugins.values()) {
|
|
410
|
+
if (hookName in plugin) plugins.push(plugin)
|
|
411
|
+
}
|
|
387
412
|
this.events.emit('plugins:hook:progress:start', { hookName, plugins })
|
|
388
413
|
|
|
389
414
|
const pluginStartTimes = new Map<Plugin, number>()
|
|
@@ -404,7 +429,7 @@ export class PluginDriver {
|
|
|
404
429
|
|
|
405
430
|
results.forEach((result, index) => {
|
|
406
431
|
if (isPromiseRejectedResult<Error>(result)) {
|
|
407
|
-
const plugin =
|
|
432
|
+
const plugin = plugins[index]
|
|
408
433
|
|
|
409
434
|
if (plugin) {
|
|
410
435
|
const startTime = pluginStartTimes.get(plugin) ?? performance.now()
|
|
@@ -433,7 +458,10 @@ export class PluginDriver {
|
|
|
433
458
|
* Chains plugins
|
|
434
459
|
*/
|
|
435
460
|
async hookSeq<H extends PluginLifecycleHooks>({ hookName, parameters }: { hookName: H; parameters?: PluginParameter<H> }): Promise<void> {
|
|
436
|
-
const plugins =
|
|
461
|
+
const plugins: Array<Plugin> = []
|
|
462
|
+
for (const plugin of this.plugins.values()) {
|
|
463
|
+
if (hookName in plugin) plugins.push(plugin)
|
|
464
|
+
}
|
|
437
465
|
this.events.emit('plugins:hook:progress:start', { hookName, plugins })
|
|
438
466
|
|
|
439
467
|
const promises = plugins.map((plugin) => {
|
|
@@ -451,62 +479,8 @@ export class PluginDriver {
|
|
|
451
479
|
this.events.emit('plugins:hook:progress:end', { hookName })
|
|
452
480
|
}
|
|
453
481
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (hookName) {
|
|
458
|
-
return plugins.filter((plugin) => hookName in plugin)
|
|
459
|
-
}
|
|
460
|
-
// TODO add test case for sorting with pre/post
|
|
461
|
-
|
|
462
|
-
return plugins
|
|
463
|
-
.map((plugin) => {
|
|
464
|
-
if (plugin.pre) {
|
|
465
|
-
let missingPlugins = plugin.pre.filter((pluginName) => !plugins.find((pluginToFind) => pluginToFind.name === pluginName))
|
|
466
|
-
|
|
467
|
-
// when adapter is set, we can ignore the depends on plugin-oas, in v5 this will not be needed anymore
|
|
468
|
-
if (missingPlugins.includes('plugin-oas') && this.adapter) {
|
|
469
|
-
missingPlugins = missingPlugins.filter((pluginName) => pluginName !== 'plugin-oas')
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (missingPlugins.length > 0) {
|
|
473
|
-
throw new ValidationPluginError(`The plugin '${plugin.name}' has a pre set that references missing plugins for '${missingPlugins.join(', ')}'`)
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
return plugin
|
|
478
|
-
})
|
|
479
|
-
.sort((a, b) => {
|
|
480
|
-
if (b.pre?.includes(a.name)) {
|
|
481
|
-
return 1
|
|
482
|
-
}
|
|
483
|
-
if (b.post?.includes(a.name)) {
|
|
484
|
-
return -1
|
|
485
|
-
}
|
|
486
|
-
return 0
|
|
487
|
-
})
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
getPluginByName(pluginName: string): Plugin | undefined {
|
|
491
|
-
const plugins = [...this.#plugins]
|
|
492
|
-
|
|
493
|
-
return plugins.find((item) => item.name === pluginName)
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
getPluginsByName(hookName: keyof PluginWithLifeCycle, pluginName: string): Plugin[] {
|
|
497
|
-
const plugins = [...this.plugins]
|
|
498
|
-
|
|
499
|
-
const pluginByPluginName = plugins.filter((plugin) => hookName in plugin).filter((item) => item.name === pluginName)
|
|
500
|
-
|
|
501
|
-
if (!pluginByPluginName?.length) {
|
|
502
|
-
// fallback on the core plugin when there is no match
|
|
503
|
-
|
|
504
|
-
const corePlugin = plugins.find((plugin) => plugin.name === CORE_PLUGIN_NAME && hookName in plugin)
|
|
505
|
-
|
|
506
|
-
return corePlugin ? [corePlugin] : []
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
return pluginByPluginName
|
|
482
|
+
getPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(pluginName: string): Plugin<TOptions> | undefined {
|
|
483
|
+
return this.plugins.get(pluginName) as Plugin<TOptions> | undefined
|
|
510
484
|
}
|
|
511
485
|
|
|
512
486
|
/**
|
|
@@ -642,22 +616,4 @@ export class PluginDriver {
|
|
|
642
616
|
return null
|
|
643
617
|
}
|
|
644
618
|
}
|
|
645
|
-
|
|
646
|
-
#parse(plugin: UserPlugin): Plugin {
|
|
647
|
-
const usedPluginNames = this.#usedPluginNames
|
|
648
|
-
|
|
649
|
-
setUniqueName(plugin.name, usedPluginNames)
|
|
650
|
-
|
|
651
|
-
const usageCount = usedPluginNames[plugin.name]
|
|
652
|
-
if (usageCount && usageCount > 1) {
|
|
653
|
-
throw new ValidationPluginError(
|
|
654
|
-
`Duplicate plugin "${plugin.name}" detected. Each plugin can only be used once. Use a different configuration instead of adding multiple instances of the same plugin.`,
|
|
655
|
-
)
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
return {
|
|
659
|
-
install() {},
|
|
660
|
-
...plugin,
|
|
661
|
-
} as unknown as Plugin
|
|
662
|
-
}
|
|
663
619
|
}
|
package/src/build.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { dirname, relative, resolve } from 'node:path'
|
|
2
2
|
import { AsyncEventEmitter, BuildError, exists, formatMs, getElapsedMs, getRelativePath, URLPath } from '@internals/utils'
|
|
3
|
-
import type { Fabric as FabricType
|
|
3
|
+
import type { FabricFile, Fabric as FabricType } from '@kubb/fabric-core/types'
|
|
4
4
|
import { createFabric } from '@kubb/react-fabric'
|
|
5
5
|
import { typescriptParser } from '@kubb/react-fabric/parsers'
|
|
6
6
|
import { fsPlugin } from '@kubb/react-fabric/plugins'
|
|
@@ -26,7 +26,7 @@ type BuildOutput = {
|
|
|
26
26
|
*/
|
|
27
27
|
failedPlugins: Set<{ plugin: Plugin; error: Error }>
|
|
28
28
|
fabric: FabricType
|
|
29
|
-
files: Array<
|
|
29
|
+
files: Array<FabricFile.ResolvedFile>
|
|
30
30
|
driver: PluginDriver
|
|
31
31
|
/**
|
|
32
32
|
* Elapsed time in milliseconds for each plugin, keyed by plugin name.
|
|
@@ -36,7 +36,7 @@ type BuildOutput = {
|
|
|
36
36
|
/**
|
|
37
37
|
* Raw generated source, keyed by absolute file path.
|
|
38
38
|
*/
|
|
39
|
-
sources: Map<
|
|
39
|
+
sources: Map<FabricFile.Path, string>
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -46,7 +46,7 @@ type SetupResult = {
|
|
|
46
46
|
events: AsyncEventEmitter<KubbEvents>
|
|
47
47
|
fabric: FabricType
|
|
48
48
|
driver: PluginDriver
|
|
49
|
-
sources: Map<
|
|
49
|
+
sources: Map<FabricFile.Path, string>
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
@@ -63,7 +63,7 @@ type SetupResult = {
|
|
|
63
63
|
export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
64
64
|
const { config: userConfig, events = new AsyncEventEmitter<KubbEvents>() } = options
|
|
65
65
|
|
|
66
|
-
const sources: Map<
|
|
66
|
+
const sources: Map<FabricFile.Path, string> = new Map<FabricFile.Path, string>()
|
|
67
67
|
const diagnosticInfo = getDiagnosticInfo()
|
|
68
68
|
|
|
69
69
|
if (Array.isArray(userConfig.input)) {
|
|
@@ -274,7 +274,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
274
274
|
const config = driver.config
|
|
275
275
|
|
|
276
276
|
try {
|
|
277
|
-
for (const plugin of driver.plugins) {
|
|
277
|
+
for (const plugin of driver.plugins.values()) {
|
|
278
278
|
const context = driver.getContext(plugin)
|
|
279
279
|
const hrStart = process.hrtime()
|
|
280
280
|
|
|
@@ -351,7 +351,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
351
351
|
existingBarrel?.exports?.flatMap((e) => (Array.isArray(e.name) ? e.name : [e.name])).filter((n): n is string => Boolean(n)) ?? [],
|
|
352
352
|
)
|
|
353
353
|
|
|
354
|
-
const rootFile:
|
|
354
|
+
const rootFile: FabricFile.File = {
|
|
355
355
|
path: rootPath,
|
|
356
356
|
baseName: BARREL_FILENAME,
|
|
357
357
|
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }),
|
|
@@ -394,16 +394,16 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
394
394
|
}
|
|
395
395
|
|
|
396
396
|
type BuildBarrelExportsParams = {
|
|
397
|
-
barrelFiles:
|
|
397
|
+
barrelFiles: FabricFile.ResolvedFile[]
|
|
398
398
|
rootDir: string
|
|
399
399
|
existingExports: Set<string>
|
|
400
400
|
config: Config
|
|
401
401
|
driver: PluginDriver
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
-
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams):
|
|
404
|
+
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): FabricFile.Export[] {
|
|
405
405
|
const pluginNameMap = new Map<string, Plugin>()
|
|
406
|
-
for (const plugin of driver.plugins) {
|
|
406
|
+
for (const plugin of driver.plugins.values()) {
|
|
407
407
|
pluginNameMap.set(plugin.name, plugin)
|
|
408
408
|
}
|
|
409
409
|
|
|
@@ -433,7 +433,7 @@ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, dri
|
|
|
433
433
|
name: exportName,
|
|
434
434
|
path: getRelativePath(rootDir, file.path),
|
|
435
435
|
isTypeOnly: config.output.barrelType === 'all' ? containsOnlyTypes : source.isTypeOnly,
|
|
436
|
-
} satisfies
|
|
436
|
+
} satisfies FabricFile.Export,
|
|
437
437
|
]
|
|
438
438
|
})
|
|
439
439
|
})
|
package/src/constants.ts
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FabricFile } from '@kubb/fabric-core/types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Base URL for the Kubb Studio web app.
|
|
5
5
|
*/
|
|
6
6
|
export const DEFAULT_STUDIO_URL = 'https://studio.kubb.dev' as const
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Internal plugin name used to identify the core Kubb runtime.
|
|
10
|
-
*/
|
|
11
|
-
export const CORE_PLUGIN_NAME = 'core' as const
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Maximum number of event-emitter listeners before Node.js emits a warning.
|
|
15
|
-
*/
|
|
16
|
-
export const DEFAULT_MAX_LISTENERS = 100
|
|
17
|
-
|
|
18
8
|
/**
|
|
19
9
|
* Default number of plugins that may run concurrently during a build.
|
|
20
10
|
*/
|
|
@@ -33,7 +23,7 @@ export const DEFAULT_BANNER = 'simple' as const
|
|
|
33
23
|
/**
|
|
34
24
|
* Default file-extension mapping used when no explicit mapping is configured.
|
|
35
25
|
*/
|
|
36
|
-
export const DEFAULT_EXTENSION: Record<
|
|
26
|
+
export const DEFAULT_EXTENSION: Record<FabricFile.Extname, FabricFile.Extname | ''> = { '.ts': '.ts' }
|
|
37
27
|
|
|
38
28
|
/**
|
|
39
29
|
* Characters recognized as path separators on both POSIX and Windows.
|