@kubb/core 5.0.0-alpha.42 → 5.0.0-alpha.44
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-CgXFtmNP.js → PluginDriver-Bt_UCn7-.js} +88 -739
- package/dist/PluginDriver-Bt_UCn7-.js.map +1 -0
- package/dist/{PluginDriver-BQwm8hDd.cjs → PluginDriver-rVSfG8tW.cjs} +91 -751
- package/dist/PluginDriver-rVSfG8tW.cjs.map +1 -0
- package/dist/index.cjs +185 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +186 -14
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +5 -33
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +5 -5
- package/dist/mocks.js +5 -33
- package/dist/mocks.js.map +1 -1
- package/dist/{types-C6NCtNqM.d.ts → types-BUgxQiWY.d.ts} +72 -500
- package/package.json +4 -7
- package/src/FileManager.ts +20 -21
- package/src/FileProcessor.ts +2 -0
- package/src/Kubb.ts +3 -47
- package/src/PluginDriver.ts +54 -580
- package/src/constants.ts +9 -3
- package/src/createKubb.ts +6 -16
- package/src/definePlugin.ts +12 -34
- package/src/defineResolver.ts +23 -8
- package/src/mocks.ts +10 -84
- package/src/types.ts +40 -342
- package/src/utils/getBarrelFiles.ts +9 -3
- package/src/utils/packageJSON.ts +27 -3
- package/dist/PluginDriver-BQwm8hDd.cjs.map +0 -1
- package/dist/PluginDriver-CgXFtmNP.js.map +0 -1
- package/src/createPlugin.ts +0 -31
- package/src/utils/executeStrategies.ts +0 -84
package/src/PluginDriver.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { performance } from 'node:perf_hooks'
|
|
1
|
+
import { extname, resolve } from 'node:path'
|
|
3
2
|
import type { AsyncEventEmitter } from '@internals/utils'
|
|
4
|
-
import {
|
|
5
|
-
import type { FileNode, InputNode } from '@kubb/ast'
|
|
3
|
+
import type { FileNode, InputNode, OperationNode, SchemaNode } from '@kubb/ast'
|
|
6
4
|
import { createFile } from '@kubb/ast'
|
|
7
5
|
import { DEFAULT_STUDIO_URL } from './constants.ts'
|
|
8
6
|
import type { Generator } from './defineGenerator.ts'
|
|
9
|
-
import
|
|
7
|
+
import type { Plugin } from './definePlugin.ts'
|
|
10
8
|
import { defineResolver } from './defineResolver.ts'
|
|
11
9
|
import { openInStudio as openInStudioFn } from './devtools.ts'
|
|
12
10
|
import { FileManager } from './FileManager.ts'
|
|
@@ -16,66 +14,20 @@ import type {
|
|
|
16
14
|
Adapter,
|
|
17
15
|
Config,
|
|
18
16
|
DevtoolsOptions,
|
|
19
|
-
|
|
17
|
+
GeneratorContext,
|
|
20
18
|
KubbHooks,
|
|
21
19
|
KubbPluginSetupContext,
|
|
22
|
-
|
|
23
|
-
Plugin,
|
|
24
|
-
PluginContext,
|
|
20
|
+
NormalizedPlugin,
|
|
25
21
|
PluginFactoryOptions,
|
|
26
|
-
PluginLifecycle,
|
|
27
|
-
PluginLifecycleHooks,
|
|
28
|
-
PluginParameter,
|
|
29
|
-
PluginWithLifeCycle,
|
|
30
|
-
ResolveNameParams,
|
|
31
|
-
ResolvePathParams,
|
|
32
22
|
Resolver,
|
|
33
23
|
} from './types.ts'
|
|
34
|
-
import { hookFirst, hookParallel, hookSeq } from './utils/executeStrategies.ts'
|
|
35
|
-
|
|
36
|
-
type RequiredPluginLifecycle = Required<PluginLifecycle>
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Hook dispatch strategy used by the `PluginDriver`.
|
|
40
|
-
*
|
|
41
|
-
* - `hookFirst` — stops at the first non-null result.
|
|
42
|
-
* - `hookForPlugin` — calls only the matching plugin.
|
|
43
|
-
* - `hookParallel` — calls all plugins concurrently.
|
|
44
|
-
* - `hookSeq` — calls all plugins in order, threading the result.
|
|
45
|
-
*/
|
|
46
|
-
export type Strategy = 'hookFirst' | 'hookForPlugin' | 'hookParallel' | 'hookSeq'
|
|
47
|
-
|
|
48
|
-
type ParseResult<H extends PluginLifecycleHooks> = RequiredPluginLifecycle[H]
|
|
49
|
-
|
|
50
|
-
type SafeParseResult<H extends PluginLifecycleHooks, Result = ReturnType<ParseResult<H>>> = {
|
|
51
|
-
result: Result
|
|
52
|
-
plugin: Plugin
|
|
53
|
-
}
|
|
54
24
|
|
|
55
25
|
// inspired by: https://github.com/rollup/rollup/blob/master/src/utils/PluginDriver.ts#
|
|
56
26
|
|
|
57
27
|
type Options = {
|
|
58
|
-
hooks
|
|
59
|
-
/**
|
|
60
|
-
* @default Number.POSITIVE_INFINITY
|
|
61
|
-
*/
|
|
62
|
-
concurrency?: number
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Parameters accepted by `PluginDriver.getFile` to resolve a generated file descriptor.
|
|
67
|
-
*/
|
|
68
|
-
export type GetFileOptions<TOptions = object> = {
|
|
69
|
-
name: string
|
|
70
|
-
mode?: 'single' | 'split'
|
|
71
|
-
extname: FileNode['extname']
|
|
72
|
-
pluginName: string
|
|
73
|
-
options?: TOptions
|
|
28
|
+
hooks: AsyncEventEmitter<KubbHooks>
|
|
74
29
|
}
|
|
75
30
|
|
|
76
|
-
|
|
77
|
-
const hookFirstNullCheck = (state: unknown) => !!(state as SafeParseResult<'resolveName'> | null)?.result
|
|
78
|
-
|
|
79
31
|
export class PluginDriver {
|
|
80
32
|
readonly config: Config
|
|
81
33
|
readonly options: Options
|
|
@@ -94,7 +46,7 @@ export class PluginDriver {
|
|
|
94
46
|
return 'split'
|
|
95
47
|
}
|
|
96
48
|
return extname(fileOrFolder) ? 'single' : 'split'
|
|
97
|
-
}
|
|
49
|
+
}
|
|
98
50
|
|
|
99
51
|
/**
|
|
100
52
|
* The universal `@kubb/ast` `InputNode` produced by the adapter, set by
|
|
@@ -111,7 +63,7 @@ export class PluginDriver {
|
|
|
111
63
|
*/
|
|
112
64
|
readonly fileManager = new FileManager()
|
|
113
65
|
|
|
114
|
-
readonly plugins = new Map<string,
|
|
66
|
+
readonly plugins = new Map<string, NormalizedPlugin>()
|
|
115
67
|
|
|
116
68
|
/**
|
|
117
69
|
* Tracks which plugins have generators registered via `addGenerator()` (event-based path).
|
|
@@ -124,17 +76,9 @@ export class PluginDriver {
|
|
|
124
76
|
|
|
125
77
|
constructor(config: Config, options: Options) {
|
|
126
78
|
this.config = config
|
|
127
|
-
this.options =
|
|
128
|
-
...options,
|
|
129
|
-
hooks: options.hooks,
|
|
130
|
-
}
|
|
79
|
+
this.options = options
|
|
131
80
|
config.plugins
|
|
132
|
-
.map((rawPlugin) =>
|
|
133
|
-
if (isHookStylePlugin(rawPlugin)) {
|
|
134
|
-
return this.#normalizeHookStylePlugin(rawPlugin as HookStylePlugin)
|
|
135
|
-
}
|
|
136
|
-
return { ...rawPlugin, buildStart: rawPlugin.buildStart ?? (() => {}), buildEnd: rawPlugin.buildEnd ?? (() => {}) } as unknown as Plugin
|
|
137
|
-
})
|
|
81
|
+
.map((rawPlugin) => this.#normalizePlugin(rawPlugin as Plugin))
|
|
138
82
|
.filter((plugin) => {
|
|
139
83
|
if (typeof plugin.apply === 'function') {
|
|
140
84
|
return plugin.apply(config)
|
|
@@ -152,53 +96,20 @@ export class PluginDriver {
|
|
|
152
96
|
}
|
|
153
97
|
|
|
154
98
|
get hooks() {
|
|
155
|
-
if (!this.options.hooks) {
|
|
156
|
-
throw new Error('hooks are not defined')
|
|
157
|
-
}
|
|
158
99
|
return this.options.hooks
|
|
159
100
|
}
|
|
160
101
|
|
|
161
102
|
/**
|
|
162
|
-
* Creates
|
|
103
|
+
* Creates an `NormalizedPlugin` from a hook-style plugin and registers
|
|
163
104
|
* its lifecycle handlers on the `AsyncEventEmitter`.
|
|
164
|
-
*
|
|
165
|
-
* The normalized plugin has an empty `buildStart` — generators registered via
|
|
166
|
-
* `addGenerator()` in `kubb:plugin:setup` are stored on `normalizedPlugin.generators`
|
|
167
|
-
* and used by `runPluginAstHooks` during the build.
|
|
168
105
|
*/
|
|
169
|
-
#
|
|
170
|
-
const generators: Plugin['generators'] = []
|
|
171
|
-
const driver = this
|
|
172
|
-
// The options shape is the minimal struct required by Plugin. Hook-style plugins
|
|
173
|
-
// use generators registered via addGenerator() and resolvers set via setResolver().
|
|
174
|
-
// `inject` and `resolver` are required by the Plugin type but are irrelevant for hook-style
|
|
175
|
-
// plugins: inject is a no-op and resolver is set dynamically via setResolver() in kubb:plugin:setup.
|
|
176
|
-
//
|
|
177
|
-
// `resolveName` and `resolvePath` bridge the legacy PluginDriver.resolveName/resolvePath
|
|
178
|
-
// lifecycle so that other plugins calling `driver.resolveName({ pluginName })` or
|
|
179
|
-
// `driver.getFile({ pluginName })` still get correct results from hook-style plugins.
|
|
106
|
+
#normalizePlugin(hookPlugin: Plugin): NormalizedPlugin {
|
|
180
107
|
const normalizedPlugin = {
|
|
181
108
|
name: hookPlugin.name,
|
|
182
109
|
dependencies: hookPlugin.dependencies,
|
|
183
110
|
options: { output: { path: '.' }, exclude: [], override: [] },
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
resolveName(name: string, type?: ResolveNameParams['type']) {
|
|
187
|
-
const resolver = driver.getResolver(hookPlugin.name)
|
|
188
|
-
return resolver.default(name, type)
|
|
189
|
-
},
|
|
190
|
-
resolvePath(baseName: FileNode['baseName'], pathMode?: 'single' | 'split', resolveOptions?: Record<string, unknown>) {
|
|
191
|
-
const resolver = driver.getResolver(hookPlugin.name)
|
|
192
|
-
const opts = normalizedPlugin.options as Record<string, unknown>
|
|
193
|
-
const group = resolveOptions?.group as Record<string, string> | undefined
|
|
194
|
-
return resolver.resolvePath(
|
|
195
|
-
{ baseName, pathMode, tag: group?.tag, path: group?.path },
|
|
196
|
-
{ root: resolve(driver.config.root, driver.config.output.path), output: opts.output as Output, group: opts.group as Group | undefined },
|
|
197
|
-
)
|
|
198
|
-
},
|
|
199
|
-
buildStart() {},
|
|
200
|
-
buildEnd() {},
|
|
201
|
-
} as unknown as Plugin
|
|
111
|
+
} as unknown as NormalizedPlugin
|
|
112
|
+
|
|
202
113
|
this.registerPluginHooks(hookPlugin, normalizedPlugin)
|
|
203
114
|
return normalizedPlugin
|
|
204
115
|
}
|
|
@@ -215,8 +126,10 @@ export class PluginDriver {
|
|
|
215
126
|
*
|
|
216
127
|
* External tooling can subscribe to any of these events via `hooks.on(...)` to observe
|
|
217
128
|
* the plugin lifecycle without modifying plugin behavior.
|
|
129
|
+
*
|
|
130
|
+
* @internal
|
|
218
131
|
*/
|
|
219
|
-
registerPluginHooks(hookPlugin:
|
|
132
|
+
registerPluginHooks(hookPlugin: Plugin, normalizedPlugin: NormalizedPlugin): void {
|
|
220
133
|
const { hooks } = hookPlugin
|
|
221
134
|
|
|
222
135
|
// kubb:plugin:setup gets special treatment: the globally emitted context is wrapped with
|
|
@@ -242,15 +155,8 @@ export class PluginDriver {
|
|
|
242
155
|
setOptions: (opts) => {
|
|
243
156
|
normalizedPlugin.options = { ...normalizedPlugin.options, ...opts }
|
|
244
157
|
},
|
|
245
|
-
injectFile: (
|
|
246
|
-
|
|
247
|
-
baseName: file.baseName,
|
|
248
|
-
path: file.path,
|
|
249
|
-
sources: file.sources ?? [],
|
|
250
|
-
imports: [],
|
|
251
|
-
exports: [],
|
|
252
|
-
})
|
|
253
|
-
this.fileManager.add(fileNode)
|
|
158
|
+
injectFile: ({ sources = [], ...rest }) => {
|
|
159
|
+
this.fileManager.add(createFile({ imports: [], exports: [], sources, ...rest }))
|
|
254
160
|
},
|
|
255
161
|
}
|
|
256
162
|
return hooks['kubb:plugin:setup']!(pluginCtx)
|
|
@@ -263,6 +169,7 @@ export class PluginDriver {
|
|
|
263
169
|
// All other hooks are registered as direct pass-through listeners on the shared emitter.
|
|
264
170
|
for (const [event, handler] of Object.entries(hooks) as Array<[keyof KubbHooks, ((...args: never[]) => void | Promise<void>) | undefined]>) {
|
|
265
171
|
if (event === 'kubb:plugin:setup' || !handler) continue
|
|
172
|
+
|
|
266
173
|
this.hooks.on(event, handler as never)
|
|
267
174
|
this.#trackHookListener(event, handler as (...args: never[]) => void | Promise<void>)
|
|
268
175
|
}
|
|
@@ -275,16 +182,17 @@ export class PluginDriver {
|
|
|
275
182
|
* Call this once from `safeBuild` before the plugin execution loop begins.
|
|
276
183
|
*/
|
|
277
184
|
async emitSetupHooks(): Promise<void> {
|
|
185
|
+
const noop = () => {}
|
|
278
186
|
await this.hooks.emit('kubb:plugin:setup', {
|
|
279
187
|
config: this.config,
|
|
280
|
-
addGenerator: () => {},
|
|
281
|
-
setResolver: () => {},
|
|
282
|
-
setTransformer: () => {},
|
|
283
|
-
setRenderer: () => {},
|
|
284
|
-
setOptions: () => {},
|
|
285
|
-
injectFile: () => {},
|
|
286
|
-
updateConfig: () => {},
|
|
287
188
|
options: {},
|
|
189
|
+
addGenerator: noop,
|
|
190
|
+
setResolver: noop,
|
|
191
|
+
setTransformer: noop,
|
|
192
|
+
setRenderer: noop,
|
|
193
|
+
setOptions: noop,
|
|
194
|
+
injectFile: noop,
|
|
195
|
+
updateConfig: noop,
|
|
288
196
|
})
|
|
289
197
|
}
|
|
290
198
|
|
|
@@ -309,7 +217,7 @@ export class PluginDriver {
|
|
|
309
217
|
}
|
|
310
218
|
|
|
311
219
|
if (gen.schema) {
|
|
312
|
-
const schemaHandler = async (node:
|
|
220
|
+
const schemaHandler = async (node: SchemaNode, ctx: GeneratorContext) => {
|
|
313
221
|
if (ctx.plugin.name !== pluginName) return
|
|
314
222
|
const result = await gen.schema!(node, ctx)
|
|
315
223
|
await applyHookResult(result, this, resolveRenderer())
|
|
@@ -320,7 +228,7 @@ export class PluginDriver {
|
|
|
320
228
|
}
|
|
321
229
|
|
|
322
230
|
if (gen.operation) {
|
|
323
|
-
const operationHandler = async (node:
|
|
231
|
+
const operationHandler = async (node: OperationNode, ctx: GeneratorContext) => {
|
|
324
232
|
if (ctx.plugin.name !== pluginName) return
|
|
325
233
|
const result = await gen.operation!(node, ctx)
|
|
326
234
|
await applyHookResult(result, this, resolveRenderer())
|
|
@@ -331,7 +239,7 @@ export class PluginDriver {
|
|
|
331
239
|
}
|
|
332
240
|
|
|
333
241
|
if (gen.operations) {
|
|
334
|
-
const operationsHandler = async (nodes:
|
|
242
|
+
const operationsHandler = async (nodes: Array<OperationNode>, ctx: GeneratorContext) => {
|
|
335
243
|
if (ctx.plugin.name !== pluginName) return
|
|
336
244
|
const result = await gen.operations!(nodes, ctx)
|
|
337
245
|
await applyHookResult(result, this, resolveRenderer())
|
|
@@ -355,6 +263,12 @@ export class PluginDriver {
|
|
|
355
263
|
return this.#pluginsWithEventGenerators.has(pluginName)
|
|
356
264
|
}
|
|
357
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Unregisters all plugin lifecycle listeners from the shared event emitter.
|
|
268
|
+
* Called at the end of a build to prevent listener leaks across repeated builds.
|
|
269
|
+
*
|
|
270
|
+
* @internal
|
|
271
|
+
*/
|
|
358
272
|
dispose(): void {
|
|
359
273
|
for (const [event, handlers] of this.#hookListeners) {
|
|
360
274
|
for (const handler of handlers) {
|
|
@@ -388,33 +302,32 @@ export class PluginDriver {
|
|
|
388
302
|
return resolver
|
|
389
303
|
}
|
|
390
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Merges `partial` with the plugin's default resolver and stores the result.
|
|
307
|
+
* Also mirrors it onto `plugin.resolver` so callers using `getPlugin(name).resolver`
|
|
308
|
+
* get the up-to-date resolver without going through `getResolver()`.
|
|
309
|
+
*/
|
|
391
310
|
setPluginResolver(pluginName: string, partial: Partial<Resolver>): void {
|
|
392
311
|
const defaultResolver = this.#createDefaultResolver(pluginName)
|
|
393
312
|
const merged = { ...defaultResolver, ...partial }
|
|
394
313
|
this.#resolvers.set(pluginName, merged)
|
|
395
|
-
// Mirror the resolved resolver onto the plugin so that consumers using
|
|
396
|
-
// `getPlugin(name).resolver` get the correct resolver without going through getResolver().
|
|
397
314
|
const plugin = this.plugins.get(pluginName)
|
|
398
315
|
if (plugin) {
|
|
399
316
|
plugin.resolver = merged
|
|
400
317
|
}
|
|
401
318
|
}
|
|
402
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Returns the resolver for the given plugin.
|
|
322
|
+
*
|
|
323
|
+
* Resolution order: dynamic resolver set via `setPluginResolver` → static resolver on the
|
|
324
|
+
* plugin → lazily created default resolver (identity name, no path transforms).
|
|
325
|
+
*/
|
|
403
326
|
getResolver(pluginName: string): Resolver {
|
|
404
|
-
|
|
405
|
-
if (dynamicResolver) {
|
|
406
|
-
return dynamicResolver
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const pluginResolver = this.plugins.get(pluginName)?.resolver
|
|
410
|
-
if (pluginResolver) {
|
|
411
|
-
return pluginResolver
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return this.#createDefaultResolver(pluginName)
|
|
327
|
+
return this.#resolvers.get(pluginName) ?? this.plugins.get(pluginName)?.resolver ?? this.#createDefaultResolver(pluginName)
|
|
415
328
|
}
|
|
416
329
|
|
|
417
|
-
getContext<TOptions extends PluginFactoryOptions>(plugin:
|
|
330
|
+
getContext<TOptions extends PluginFactoryOptions>(plugin: NormalizedPlugin<TOptions>): GeneratorContext<TOptions> & Record<string, unknown> {
|
|
418
331
|
const driver = this
|
|
419
332
|
|
|
420
333
|
const baseContext = {
|
|
@@ -429,7 +342,7 @@ export class PluginDriver {
|
|
|
429
342
|
plugin,
|
|
430
343
|
getPlugin: driver.getPlugin.bind(driver),
|
|
431
344
|
requirePlugin: driver.requirePlugin.bind(driver),
|
|
432
|
-
driver
|
|
345
|
+
driver,
|
|
433
346
|
addFile: async (...files: Array<FileNode>) => {
|
|
434
347
|
driver.fileManager.add(...files)
|
|
435
348
|
},
|
|
@@ -476,326 +389,15 @@ export class PluginDriver {
|
|
|
476
389
|
|
|
477
390
|
return openInStudioFn(driver.inputNode, studioUrl, options)
|
|
478
391
|
},
|
|
479
|
-
} as unknown as
|
|
480
|
-
|
|
481
|
-
let mergedExtras: Record<string, unknown> = {}
|
|
482
|
-
|
|
483
|
-
for (const p of this.plugins.values()) {
|
|
484
|
-
if (typeof p.inject === 'function') {
|
|
485
|
-
const result = (p.inject as (this: PluginContext) => unknown).call(baseContext as unknown as PluginContext)
|
|
486
|
-
if (result !== null && typeof result === 'object') {
|
|
487
|
-
mergedExtras = { ...mergedExtras, ...(result as Record<string, unknown>) }
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
return {
|
|
493
|
-
...baseContext,
|
|
494
|
-
...mergedExtras,
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* @deprecated use resolvers context instead
|
|
499
|
-
*/
|
|
500
|
-
getFile<TOptions = object>({ name, mode, extname, pluginName, options }: GetFileOptions<TOptions>): FileNode<{ pluginName: string }> {
|
|
501
|
-
const resolvedName = mode ? (mode === 'single' ? '' : this.resolveName({ name, pluginName, type: 'file' })) : name
|
|
502
|
-
|
|
503
|
-
const path = this.resolvePath({
|
|
504
|
-
baseName: `${resolvedName}${extname}` as const,
|
|
505
|
-
mode,
|
|
506
|
-
pluginName,
|
|
507
|
-
options,
|
|
508
|
-
})
|
|
509
|
-
|
|
510
|
-
if (!path) {
|
|
511
|
-
throw new Error(`Filepath should be defined for resolvedName "${resolvedName}" and pluginName "${pluginName}"`)
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
return createFile<{ pluginName: string }>({
|
|
515
|
-
path,
|
|
516
|
-
baseName: basename(path) as `${string}.${string}`,
|
|
517
|
-
meta: {
|
|
518
|
-
pluginName,
|
|
519
|
-
},
|
|
520
|
-
sources: [],
|
|
521
|
-
imports: [],
|
|
522
|
-
exports: [],
|
|
523
|
-
})
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* @deprecated use resolvers context instead
|
|
528
|
-
*/
|
|
529
|
-
resolvePath = <TOptions = object>(params: ResolvePathParams<TOptions>): string => {
|
|
530
|
-
const root = resolve(this.config.root, this.config.output.path)
|
|
531
|
-
const defaultPath = resolve(root, params.baseName)
|
|
532
|
-
|
|
533
|
-
if (params.pluginName) {
|
|
534
|
-
const paths = this.hookForPluginSync({
|
|
535
|
-
pluginName: params.pluginName,
|
|
536
|
-
hookName: 'resolvePath',
|
|
537
|
-
parameters: [params.baseName, params.mode, params.options as object],
|
|
538
|
-
})
|
|
539
|
-
|
|
540
|
-
return paths?.at(0) || defaultPath
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
const firstResult = this.hookFirstSync({
|
|
544
|
-
hookName: 'resolvePath',
|
|
545
|
-
parameters: [params.baseName, params.mode, params.options as object],
|
|
546
|
-
})
|
|
547
|
-
|
|
548
|
-
return firstResult?.result || defaultPath
|
|
549
|
-
}
|
|
550
|
-
/**
|
|
551
|
-
* @deprecated use resolvers context instead
|
|
552
|
-
*/
|
|
553
|
-
resolveName = (params: ResolveNameParams): string => {
|
|
554
|
-
if (params.pluginName) {
|
|
555
|
-
const names = this.hookForPluginSync({
|
|
556
|
-
pluginName: params.pluginName,
|
|
557
|
-
hookName: 'resolveName',
|
|
558
|
-
parameters: [params.name.trim(), params.type],
|
|
559
|
-
})
|
|
560
|
-
|
|
561
|
-
return transformReservedWord(names?.at(0) ?? params.name)
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const name = this.hookFirstSync({
|
|
565
|
-
hookName: 'resolveName',
|
|
566
|
-
parameters: [params.name.trim(), params.type],
|
|
567
|
-
})?.result
|
|
568
|
-
|
|
569
|
-
return transformReservedWord(name ?? params.name)
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Run a specific hookName for plugin x.
|
|
574
|
-
*/
|
|
575
|
-
async hookForPlugin<H extends PluginLifecycleHooks>({
|
|
576
|
-
pluginName,
|
|
577
|
-
hookName,
|
|
578
|
-
parameters,
|
|
579
|
-
}: {
|
|
580
|
-
pluginName: string
|
|
581
|
-
hookName: H
|
|
582
|
-
parameters: PluginParameter<H>
|
|
583
|
-
}): Promise<Array<ReturnType<ParseResult<H>> | null>> {
|
|
584
|
-
const plugin = this.plugins.get(pluginName)
|
|
585
|
-
|
|
586
|
-
if (!plugin) {
|
|
587
|
-
return [null]
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
this.hooks.emit('kubb:plugins:hook:progress:start', {
|
|
591
|
-
hookName,
|
|
592
|
-
plugins: [plugin],
|
|
593
|
-
})
|
|
594
|
-
|
|
595
|
-
const result = await this.#execute<H>({
|
|
596
|
-
strategy: 'hookFirst',
|
|
597
|
-
hookName,
|
|
598
|
-
parameters,
|
|
599
|
-
plugin,
|
|
600
|
-
})
|
|
601
|
-
|
|
602
|
-
this.hooks.emit('kubb:plugins:hook:progress:end', { hookName })
|
|
392
|
+
} as unknown as GeneratorContext<TOptions>
|
|
603
393
|
|
|
604
|
-
return
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
* Run a specific hookName for plugin x.
|
|
609
|
-
*/
|
|
610
|
-
hookForPluginSync<H extends PluginLifecycleHooks>({
|
|
611
|
-
pluginName,
|
|
612
|
-
hookName,
|
|
613
|
-
parameters,
|
|
614
|
-
}: {
|
|
615
|
-
pluginName: string
|
|
616
|
-
hookName: H
|
|
617
|
-
parameters: PluginParameter<H>
|
|
618
|
-
}): Array<ReturnType<ParseResult<H>>> | null {
|
|
619
|
-
const plugin = this.plugins.get(pluginName)
|
|
620
|
-
|
|
621
|
-
if (!plugin) {
|
|
622
|
-
return null
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
const result = this.#executeSync<H>({
|
|
626
|
-
strategy: 'hookFirst',
|
|
627
|
-
hookName,
|
|
628
|
-
parameters,
|
|
629
|
-
plugin,
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
return result !== null ? [result] : []
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Returns the first non-null result.
|
|
637
|
-
*/
|
|
638
|
-
async hookFirst<H extends PluginLifecycleHooks>({
|
|
639
|
-
hookName,
|
|
640
|
-
parameters,
|
|
641
|
-
skipped,
|
|
642
|
-
}: {
|
|
643
|
-
hookName: H
|
|
644
|
-
parameters: PluginParameter<H>
|
|
645
|
-
skipped?: ReadonlySet<Plugin> | null
|
|
646
|
-
}): Promise<SafeParseResult<H>> {
|
|
647
|
-
const plugins: Array<Plugin> = []
|
|
648
|
-
for (const plugin of this.plugins.values()) {
|
|
649
|
-
if (hookName in plugin && (skipped ? !skipped.has(plugin) : true)) plugins.push(plugin)
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
this.hooks.emit('kubb:plugins:hook:progress:start', { hookName, plugins })
|
|
653
|
-
|
|
654
|
-
const promises = plugins.map((plugin) => {
|
|
655
|
-
return async () => {
|
|
656
|
-
const value = await this.#execute<H>({
|
|
657
|
-
strategy: 'hookFirst',
|
|
658
|
-
hookName,
|
|
659
|
-
parameters,
|
|
660
|
-
plugin,
|
|
661
|
-
})
|
|
662
|
-
|
|
663
|
-
return Promise.resolve({
|
|
664
|
-
plugin,
|
|
665
|
-
result: value,
|
|
666
|
-
} as SafeParseResult<H>)
|
|
667
|
-
}
|
|
668
|
-
})
|
|
669
|
-
|
|
670
|
-
const result = await hookFirst(promises, hookFirstNullCheck)
|
|
671
|
-
|
|
672
|
-
this.hooks.emit('kubb:plugins:hook:progress:end', { hookName })
|
|
673
|
-
|
|
674
|
-
return result
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Returns the first non-null result.
|
|
679
|
-
*/
|
|
680
|
-
hookFirstSync<H extends PluginLifecycleHooks>({
|
|
681
|
-
hookName,
|
|
682
|
-
parameters,
|
|
683
|
-
skipped,
|
|
684
|
-
}: {
|
|
685
|
-
hookName: H
|
|
686
|
-
parameters: PluginParameter<H>
|
|
687
|
-
skipped?: ReadonlySet<Plugin> | null
|
|
688
|
-
}): SafeParseResult<H> | null {
|
|
689
|
-
let parseResult: SafeParseResult<H> | null = null
|
|
690
|
-
|
|
691
|
-
for (const plugin of this.plugins.values()) {
|
|
692
|
-
if (!(hookName in plugin)) continue
|
|
693
|
-
if (skipped?.has(plugin)) continue
|
|
694
|
-
|
|
695
|
-
parseResult = {
|
|
696
|
-
result: this.#executeSync<H>({
|
|
697
|
-
strategy: 'hookFirst',
|
|
698
|
-
hookName,
|
|
699
|
-
parameters,
|
|
700
|
-
plugin,
|
|
701
|
-
}),
|
|
702
|
-
plugin,
|
|
703
|
-
} as SafeParseResult<H>
|
|
704
|
-
|
|
705
|
-
if (parseResult.result != null) break
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
return parseResult
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
/**
|
|
712
|
-
* Runs all plugins in parallel based on `this.plugin` order and `dependencies` settings.
|
|
713
|
-
*/
|
|
714
|
-
async hookParallel<H extends PluginLifecycleHooks, TOutput = void>({
|
|
715
|
-
hookName,
|
|
716
|
-
parameters,
|
|
717
|
-
}: {
|
|
718
|
-
hookName: H
|
|
719
|
-
parameters?: Parameters<RequiredPluginLifecycle[H]> | undefined
|
|
720
|
-
}): Promise<Awaited<TOutput>[]> {
|
|
721
|
-
const plugins: Array<Plugin> = []
|
|
722
|
-
for (const plugin of this.plugins.values()) {
|
|
723
|
-
if (hookName in plugin) plugins.push(plugin)
|
|
724
|
-
}
|
|
725
|
-
this.hooks.emit('kubb:plugins:hook:progress:start', { hookName, plugins })
|
|
726
|
-
|
|
727
|
-
const pluginStartTimes = new Map<Plugin, number>()
|
|
728
|
-
|
|
729
|
-
const promises = plugins.map((plugin) => {
|
|
730
|
-
return () => {
|
|
731
|
-
pluginStartTimes.set(plugin, performance.now())
|
|
732
|
-
return this.#execute({
|
|
733
|
-
strategy: 'hookParallel',
|
|
734
|
-
hookName,
|
|
735
|
-
parameters,
|
|
736
|
-
plugin,
|
|
737
|
-
}) as Promise<TOutput>
|
|
738
|
-
}
|
|
739
|
-
})
|
|
740
|
-
|
|
741
|
-
const results = await hookParallel(promises, this.options.concurrency)
|
|
742
|
-
|
|
743
|
-
results.forEach((result, index) => {
|
|
744
|
-
if (isPromiseRejectedResult<Error>(result)) {
|
|
745
|
-
const plugin = plugins[index]
|
|
746
|
-
|
|
747
|
-
if (plugin) {
|
|
748
|
-
const startTime = pluginStartTimes.get(plugin) ?? performance.now()
|
|
749
|
-
this.hooks.emit('kubb:error', result.reason, {
|
|
750
|
-
plugin,
|
|
751
|
-
hookName,
|
|
752
|
-
strategy: 'hookParallel',
|
|
753
|
-
duration: Math.round(performance.now() - startTime),
|
|
754
|
-
parameters,
|
|
755
|
-
})
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
})
|
|
759
|
-
|
|
760
|
-
this.hooks.emit('kubb:plugins:hook:progress:end', { hookName })
|
|
761
|
-
|
|
762
|
-
return results.reduce((acc, result) => {
|
|
763
|
-
if (result.status === 'fulfilled') {
|
|
764
|
-
acc.push(result.value)
|
|
765
|
-
}
|
|
766
|
-
return acc
|
|
767
|
-
}, [] as Awaited<TOutput>[])
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* Execute a lifecycle hook sequentially for all plugins that implement it.
|
|
772
|
-
*/
|
|
773
|
-
async hookSeq<H extends PluginLifecycleHooks>({ hookName, parameters }: { hookName: H; parameters?: PluginParameter<H> }): Promise<void> {
|
|
774
|
-
const plugins: Array<Plugin> = []
|
|
775
|
-
for (const plugin of this.plugins.values()) {
|
|
776
|
-
if (hookName in plugin) plugins.push(plugin)
|
|
777
|
-
}
|
|
778
|
-
this.hooks.emit('kubb:plugins:hook:progress:start', { hookName, plugins })
|
|
779
|
-
|
|
780
|
-
const promises = plugins.map((plugin) => {
|
|
781
|
-
return () =>
|
|
782
|
-
this.#execute({
|
|
783
|
-
strategy: 'hookSeq',
|
|
784
|
-
hookName,
|
|
785
|
-
parameters,
|
|
786
|
-
plugin,
|
|
787
|
-
})
|
|
788
|
-
})
|
|
789
|
-
|
|
790
|
-
await hookSeq(promises)
|
|
791
|
-
|
|
792
|
-
this.hooks.emit('kubb:plugins:hook:progress:end', { hookName })
|
|
394
|
+
return baseContext
|
|
793
395
|
}
|
|
794
396
|
|
|
795
397
|
getPlugin<TName extends keyof Kubb.PluginRegistry>(pluginName: TName): Plugin<Kubb.PluginRegistry[TName]> | undefined
|
|
796
398
|
getPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(pluginName: string): Plugin<TOptions> | undefined
|
|
797
399
|
getPlugin(pluginName: string): Plugin | undefined {
|
|
798
|
-
return this.plugins.get(pluginName)
|
|
400
|
+
return this.plugins.get(pluginName)
|
|
799
401
|
}
|
|
800
402
|
|
|
801
403
|
/**
|
|
@@ -810,132 +412,4 @@ export class PluginDriver {
|
|
|
810
412
|
}
|
|
811
413
|
return plugin
|
|
812
414
|
}
|
|
813
|
-
|
|
814
|
-
/**
|
|
815
|
-
* Emit hook-processing completion metadata after a plugin hook resolves.
|
|
816
|
-
*/
|
|
817
|
-
#emitProcessingEnd<H extends PluginLifecycleHooks>({
|
|
818
|
-
startTime,
|
|
819
|
-
output,
|
|
820
|
-
strategy,
|
|
821
|
-
hookName,
|
|
822
|
-
plugin,
|
|
823
|
-
parameters,
|
|
824
|
-
}: {
|
|
825
|
-
startTime: number
|
|
826
|
-
output: unknown
|
|
827
|
-
strategy: Strategy
|
|
828
|
-
hookName: H
|
|
829
|
-
plugin: PluginWithLifeCycle
|
|
830
|
-
parameters: unknown[] | undefined
|
|
831
|
-
}): void {
|
|
832
|
-
this.hooks.emit('kubb:plugins:hook:processing:end', {
|
|
833
|
-
duration: Math.round(performance.now() - startTime),
|
|
834
|
-
parameters,
|
|
835
|
-
output,
|
|
836
|
-
strategy,
|
|
837
|
-
hookName,
|
|
838
|
-
plugin,
|
|
839
|
-
})
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// Implementation signature
|
|
843
|
-
#execute<H extends PluginLifecycleHooks>({
|
|
844
|
-
strategy,
|
|
845
|
-
hookName,
|
|
846
|
-
parameters,
|
|
847
|
-
plugin,
|
|
848
|
-
}: {
|
|
849
|
-
strategy: Strategy
|
|
850
|
-
hookName: H
|
|
851
|
-
parameters: unknown[] | undefined
|
|
852
|
-
plugin: PluginWithLifeCycle
|
|
853
|
-
}): Promise<ReturnType<ParseResult<H>> | null> | null {
|
|
854
|
-
const hook = plugin[hookName]
|
|
855
|
-
|
|
856
|
-
if (!hook) {
|
|
857
|
-
return null
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
this.hooks.emit('kubb:plugins:hook:processing:start', {
|
|
861
|
-
strategy,
|
|
862
|
-
hookName,
|
|
863
|
-
parameters,
|
|
864
|
-
plugin,
|
|
865
|
-
})
|
|
866
|
-
|
|
867
|
-
const startTime = performance.now()
|
|
868
|
-
|
|
869
|
-
const task = (async () => {
|
|
870
|
-
try {
|
|
871
|
-
const output =
|
|
872
|
-
typeof hook === 'function' ? await Promise.resolve((hook as (...args: unknown[]) => unknown).apply(this.getContext(plugin), parameters ?? [])) : hook
|
|
873
|
-
|
|
874
|
-
this.#emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters })
|
|
875
|
-
|
|
876
|
-
return output as ReturnType<ParseResult<H>>
|
|
877
|
-
} catch (error) {
|
|
878
|
-
this.hooks.emit('kubb:error', error as Error, {
|
|
879
|
-
plugin,
|
|
880
|
-
hookName,
|
|
881
|
-
strategy,
|
|
882
|
-
duration: Math.round(performance.now() - startTime),
|
|
883
|
-
})
|
|
884
|
-
|
|
885
|
-
return null
|
|
886
|
-
}
|
|
887
|
-
})()
|
|
888
|
-
|
|
889
|
-
return task
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
/**
|
|
893
|
-
* Execute a plugin lifecycle hook synchronously and return its output.
|
|
894
|
-
*/
|
|
895
|
-
#executeSync<H extends PluginLifecycleHooks>({
|
|
896
|
-
strategy,
|
|
897
|
-
hookName,
|
|
898
|
-
parameters,
|
|
899
|
-
plugin,
|
|
900
|
-
}: {
|
|
901
|
-
strategy: Strategy
|
|
902
|
-
hookName: H
|
|
903
|
-
parameters: PluginParameter<H>
|
|
904
|
-
plugin: PluginWithLifeCycle
|
|
905
|
-
}): ReturnType<ParseResult<H>> | null {
|
|
906
|
-
const hook = plugin[hookName]
|
|
907
|
-
|
|
908
|
-
if (!hook) {
|
|
909
|
-
return null
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
this.hooks.emit('kubb:plugins:hook:processing:start', {
|
|
913
|
-
strategy,
|
|
914
|
-
hookName,
|
|
915
|
-
parameters,
|
|
916
|
-
plugin,
|
|
917
|
-
})
|
|
918
|
-
|
|
919
|
-
const startTime = performance.now()
|
|
920
|
-
|
|
921
|
-
try {
|
|
922
|
-
const output =
|
|
923
|
-
typeof hook === 'function'
|
|
924
|
-
? ((hook as (...args: unknown[]) => unknown).apply(this.getContext(plugin), parameters) as ReturnType<ParseResult<H>>)
|
|
925
|
-
: (hook as ReturnType<ParseResult<H>>)
|
|
926
|
-
|
|
927
|
-
this.#emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters })
|
|
928
|
-
|
|
929
|
-
return output
|
|
930
|
-
} catch (error) {
|
|
931
|
-
this.hooks.emit('kubb:error', error as Error, {
|
|
932
|
-
plugin,
|
|
933
|
-
hookName,
|
|
934
|
-
strategy,
|
|
935
|
-
duration: Math.round(performance.now() - startTime),
|
|
936
|
-
})
|
|
937
|
-
|
|
938
|
-
return null
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
415
|
}
|