@kubb/core 5.0.0-alpha.6 → 5.0.0-alpha.61

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.
Files changed (72) hide show
  1. package/README.md +3 -2
  2. package/dist/PluginDriver-Bc0HQM8V.js +948 -0
  3. package/dist/PluginDriver-Bc0HQM8V.js.map +1 -0
  4. package/dist/PluginDriver-Dyl2fwfQ.cjs +1039 -0
  5. package/dist/PluginDriver-Dyl2fwfQ.cjs.map +1 -0
  6. package/dist/index.cjs +691 -1798
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +279 -265
  9. package/dist/index.js +678 -1765
  10. package/dist/index.js.map +1 -1
  11. package/dist/mocks.cjs +138 -0
  12. package/dist/mocks.cjs.map +1 -0
  13. package/dist/mocks.d.ts +74 -0
  14. package/dist/mocks.js +133 -0
  15. package/dist/mocks.js.map +1 -0
  16. package/dist/types-mW3-Ihuf.d.ts +1903 -0
  17. package/package.json +51 -57
  18. package/src/FileManager.ts +110 -0
  19. package/src/FileProcessor.ts +86 -0
  20. package/src/Kubb.ts +205 -130
  21. package/src/PluginDriver.ts +424 -0
  22. package/src/constants.ts +20 -47
  23. package/src/createAdapter.ts +25 -0
  24. package/src/createKubb.ts +527 -0
  25. package/src/createRenderer.ts +57 -0
  26. package/src/createStorage.ts +58 -0
  27. package/src/defineGenerator.ts +88 -100
  28. package/src/defineLogger.ts +13 -3
  29. package/src/defineMiddleware.ts +59 -0
  30. package/src/defineParser.ts +45 -0
  31. package/src/definePlugin.ts +78 -7
  32. package/src/defineResolver.ts +521 -0
  33. package/src/devtools.ts +14 -14
  34. package/src/index.ts +13 -17
  35. package/src/mocks.ts +171 -0
  36. package/src/renderNode.ts +35 -0
  37. package/src/storages/fsStorage.ts +40 -11
  38. package/src/storages/memoryStorage.ts +4 -3
  39. package/src/types.ts +738 -218
  40. package/src/utils/diagnostics.ts +4 -1
  41. package/src/utils/isInputPath.ts +10 -0
  42. package/src/utils/packageJSON.ts +99 -0
  43. package/dist/PluginManager-vZodFEMe.d.ts +0 -1056
  44. package/dist/chunk-ByKO4r7w.cjs +0 -38
  45. package/dist/hooks.cjs +0 -60
  46. package/dist/hooks.cjs.map +0 -1
  47. package/dist/hooks.d.ts +0 -64
  48. package/dist/hooks.js +0 -56
  49. package/dist/hooks.js.map +0 -1
  50. package/src/BarrelManager.ts +0 -74
  51. package/src/PackageManager.ts +0 -180
  52. package/src/PluginManager.ts +0 -667
  53. package/src/PromiseManager.ts +0 -40
  54. package/src/build.ts +0 -419
  55. package/src/config.ts +0 -56
  56. package/src/defineAdapter.ts +0 -22
  57. package/src/defineStorage.ts +0 -56
  58. package/src/errors.ts +0 -1
  59. package/src/hooks/index.ts +0 -4
  60. package/src/hooks/useKubb.ts +0 -55
  61. package/src/hooks/useMode.ts +0 -11
  62. package/src/hooks/usePlugin.ts +0 -11
  63. package/src/hooks/usePluginManager.ts +0 -11
  64. package/src/utils/FunctionParams.ts +0 -155
  65. package/src/utils/TreeNode.ts +0 -215
  66. package/src/utils/executeStrategies.ts +0 -81
  67. package/src/utils/formatters.ts +0 -56
  68. package/src/utils/getBarrelFiles.ts +0 -79
  69. package/src/utils/getConfigs.ts +0 -30
  70. package/src/utils/getPlugins.ts +0 -23
  71. package/src/utils/linters.ts +0 -25
  72. package/src/utils/resolveOptions.ts +0 -93
@@ -1,667 +0,0 @@
1
- import { basename, extname, resolve } from 'node:path'
2
- import { performance } from 'node:perf_hooks'
3
- import type { AsyncEventEmitter } from '@internals/utils'
4
- import { setUniqueName, transformReservedWord } from '@internals/utils'
5
- import type { RootNode } from '@kubb/ast/types'
6
- import type { Fabric as FabricType, KubbFile } from '@kubb/fabric-core/types'
7
- import { CORE_PLUGIN_NAME, DEFAULT_STUDIO_URL } from './constants.ts'
8
- import { openInStudio as openInStudioFn } from './devtools.ts'
9
- import { ValidationPluginError } from './errors.ts'
10
- import { isPromiseRejectedResult, PromiseManager } from './PromiseManager.ts'
11
- import type {
12
- Adapter,
13
- Config,
14
- DevtoolsOptions,
15
- KubbEvents,
16
- Plugin,
17
- PluginContext,
18
- PluginFactoryOptions,
19
- PluginLifecycle,
20
- PluginLifecycleHooks,
21
- PluginParameter,
22
- PluginWithLifeCycle,
23
- ResolveNameParams,
24
- ResolvePathParams,
25
- UserPlugin,
26
- } from './types.ts'
27
-
28
- type RequiredPluginLifecycle = Required<PluginLifecycle>
29
-
30
- export type Strategy = 'hookFirst' | 'hookForPlugin' | 'hookParallel' | 'hookSeq'
31
-
32
- type ParseResult<H extends PluginLifecycleHooks> = RequiredPluginLifecycle[H]
33
-
34
- type SafeParseResult<H extends PluginLifecycleHooks, Result = ReturnType<ParseResult<H>>> = {
35
- result: Result
36
- plugin: Plugin
37
- }
38
-
39
- // inspired by: https://github.com/rollup/rollup/blob/master/src/utils/PluginDriver.ts#
40
-
41
- type Options = {
42
- fabric: FabricType
43
- events: AsyncEventEmitter<KubbEvents>
44
- /**
45
- * @default Number.POSITIVE_INFINITY
46
- */
47
- concurrency?: number
48
- }
49
-
50
- export type GetFileOptions<TOptions = object> = {
51
- name: string
52
- mode?: KubbFile.Mode
53
- extname: KubbFile.Extname
54
- pluginName: string
55
- options?: TOptions
56
- }
57
-
58
- export function getMode(fileOrFolder: string | undefined | null): KubbFile.Mode {
59
- if (!fileOrFolder) {
60
- return 'split'
61
- }
62
- return extname(fileOrFolder) ? 'single' : 'split'
63
- }
64
-
65
- export class PluginManager {
66
- readonly config: Config
67
- readonly options: Options
68
-
69
- /**
70
- * The universal `@kubb/ast` `RootNode` produced by the adapter, set by
71
- * the build pipeline after the adapter's `parse()` resolves.
72
- */
73
- rootNode: RootNode | undefined = undefined
74
- adapter: Adapter | undefined = undefined
75
- #studioIsOpen = false
76
-
77
- readonly #plugins = new Set<Plugin>()
78
- readonly #usedPluginNames: Record<string, number> = {}
79
- readonly #promiseManager
80
-
81
- constructor(config: Config, options: Options) {
82
- this.config = config
83
- this.options = options
84
- this.#promiseManager = new PromiseManager({
85
- nullCheck: (state: SafeParseResult<'resolveName'> | null) => !!state?.result,
86
- })
87
- ;[...(config.plugins || [])].forEach((plugin) => {
88
- const parsedPlugin = this.#parse(plugin as UserPlugin)
89
-
90
- this.#plugins.add(parsedPlugin)
91
- })
92
- }
93
-
94
- get events() {
95
- return this.options.events
96
- }
97
-
98
- getContext<TOptions extends PluginFactoryOptions>(plugin: Plugin<TOptions>): PluginContext<TOptions> & Record<string, unknown> {
99
- const plugins = [...this.#plugins]
100
- const pluginManager = this
101
-
102
- const baseContext = {
103
- fabric: this.options.fabric,
104
- config: this.config,
105
- plugin,
106
- events: this.options.events,
107
- pluginManager: this,
108
- mode: getMode(resolve(this.config.root, this.config.output.path)),
109
- addFile: async (...files: Array<KubbFile.File>) => {
110
- await this.options.fabric.addFile(...files)
111
- },
112
- upsertFile: async (...files: Array<KubbFile.File>) => {
113
- await this.options.fabric.upsertFile(...files)
114
- },
115
- get rootNode(): RootNode | undefined {
116
- return pluginManager.rootNode
117
- },
118
- get adapter(): Adapter | undefined {
119
- return pluginManager.adapter
120
- },
121
- openInStudio(options?: DevtoolsOptions) {
122
- if (!pluginManager.config.devtools || pluginManager.#studioIsOpen) {
123
- return
124
- }
125
-
126
- if (typeof pluginManager.config.devtools !== 'object') {
127
- throw new Error('Devtools must be an object')
128
- }
129
-
130
- if (!pluginManager.rootNode || !pluginManager.adapter) {
131
- throw new Error('adapter is not defined, make sure you have set the parser in kubb.config.ts')
132
- }
133
-
134
- pluginManager.#studioIsOpen = true
135
-
136
- const studioUrl = pluginManager.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL
137
-
138
- return openInStudioFn(pluginManager.rootNode, studioUrl, options)
139
- },
140
- } as unknown as PluginContext<TOptions>
141
-
142
- const mergedExtras: Record<string, unknown> = {}
143
- for (const p of plugins) {
144
- if (typeof p.inject === 'function') {
145
- const result = (p.inject as (this: PluginContext, context: PluginContext) => unknown).call(
146
- baseContext as unknown as PluginContext,
147
- baseContext as unknown as PluginContext,
148
- )
149
- if (result !== null && typeof result === 'object') {
150
- Object.assign(mergedExtras, result)
151
- }
152
- }
153
- }
154
-
155
- return {
156
- ...baseContext,
157
- ...mergedExtras,
158
- }
159
- }
160
-
161
- get plugins(): Array<Plugin> {
162
- return this.#getSortedPlugins()
163
- }
164
-
165
- getFile<TOptions = object>({ name, mode, extname, pluginName, options }: GetFileOptions<TOptions>): KubbFile.File<{ pluginName: string }> {
166
- const resolvedName = mode ? (mode === 'single' ? '' : this.resolveName({ name, pluginName, type: 'file' })) : name
167
-
168
- const path = this.resolvePath({
169
- baseName: `${resolvedName}${extname}` as const,
170
- mode,
171
- pluginName,
172
- options,
173
- })
174
-
175
- if (!path) {
176
- throw new Error(`Filepath should be defined for resolvedName "${resolvedName}" and pluginName "${pluginName}"`)
177
- }
178
-
179
- return {
180
- path,
181
- baseName: basename(path) as KubbFile.File['baseName'],
182
- meta: {
183
- pluginName,
184
- },
185
- sources: [],
186
- imports: [],
187
- exports: [],
188
- }
189
- }
190
-
191
- resolvePath = <TOptions = object>(params: ResolvePathParams<TOptions>): KubbFile.Path => {
192
- const root = resolve(this.config.root, this.config.output.path)
193
- const defaultPath = resolve(root, params.baseName)
194
-
195
- if (params.pluginName) {
196
- const paths = this.hookForPluginSync({
197
- pluginName: params.pluginName,
198
- hookName: 'resolvePath',
199
- parameters: [params.baseName, params.mode, params.options as object],
200
- })
201
-
202
- return paths?.at(0) || defaultPath
203
- }
204
-
205
- const firstResult = this.hookFirstSync({
206
- hookName: 'resolvePath',
207
- parameters: [params.baseName, params.mode, params.options as object],
208
- })
209
-
210
- return firstResult?.result || defaultPath
211
- }
212
- //TODO refactor by using the order of plugins and the cache of the fileManager instead of guessing and recreating the name/path
213
- resolveName = (params: ResolveNameParams): string => {
214
- if (params.pluginName) {
215
- const names = this.hookForPluginSync({
216
- pluginName: params.pluginName,
217
- hookName: 'resolveName',
218
- parameters: [params.name.trim(), params.type],
219
- })
220
-
221
- const uniqueNames = new Set(names)
222
-
223
- return transformReservedWord([...uniqueNames].at(0) || params.name)
224
- }
225
-
226
- const name = this.hookFirstSync({
227
- hookName: 'resolveName',
228
- parameters: [params.name.trim(), params.type],
229
- })?.result
230
-
231
- return transformReservedWord(name ?? params.name)
232
- }
233
-
234
- /**
235
- * Run a specific hookName for plugin x.
236
- */
237
- async hookForPlugin<H extends PluginLifecycleHooks>({
238
- pluginName,
239
- hookName,
240
- parameters,
241
- }: {
242
- pluginName: string
243
- hookName: H
244
- parameters: PluginParameter<H>
245
- }): Promise<Array<ReturnType<ParseResult<H>> | null>> {
246
- const plugins = this.getPluginsByName(hookName, pluginName)
247
-
248
- this.events.emit('plugins:hook:progress:start', {
249
- hookName,
250
- plugins,
251
- })
252
-
253
- const items: Array<ReturnType<ParseResult<H>>> = []
254
-
255
- for (const plugin of plugins) {
256
- const result = await this.#execute<H>({
257
- strategy: 'hookFirst',
258
- hookName,
259
- parameters,
260
- plugin,
261
- })
262
-
263
- if (result !== undefined && result !== null) {
264
- items.push(result)
265
- }
266
- }
267
-
268
- this.events.emit('plugins:hook:progress:end', { hookName })
269
-
270
- return items
271
- }
272
- /**
273
- * Run a specific hookName for plugin x.
274
- */
275
-
276
- hookForPluginSync<H extends PluginLifecycleHooks>({
277
- pluginName,
278
- hookName,
279
- parameters,
280
- }: {
281
- pluginName: string
282
- hookName: H
283
- parameters: PluginParameter<H>
284
- }): Array<ReturnType<ParseResult<H>>> | null {
285
- const plugins = this.getPluginsByName(hookName, pluginName)
286
-
287
- const result = plugins
288
- .map((plugin) => {
289
- return this.#executeSync<H>({
290
- strategy: 'hookFirst',
291
- hookName,
292
- parameters,
293
- plugin,
294
- })
295
- })
296
- .filter((x): x is NonNullable<typeof x> => x !== null)
297
-
298
- return result
299
- }
300
-
301
- /**
302
- * Returns the first non-null result.
303
- */
304
- async hookFirst<H extends PluginLifecycleHooks>({
305
- hookName,
306
- parameters,
307
- skipped,
308
- }: {
309
- hookName: H
310
- parameters: PluginParameter<H>
311
- skipped?: ReadonlySet<Plugin> | null
312
- }): Promise<SafeParseResult<H>> {
313
- const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
314
- return skipped ? !skipped.has(plugin) : true
315
- })
316
-
317
- this.events.emit('plugins:hook:progress:start', { hookName, plugins })
318
-
319
- const promises = plugins.map((plugin) => {
320
- return async () => {
321
- const value = await this.#execute<H>({
322
- strategy: 'hookFirst',
323
- hookName,
324
- parameters,
325
- plugin,
326
- })
327
-
328
- return Promise.resolve({
329
- plugin,
330
- result: value,
331
- } as SafeParseResult<H>)
332
- }
333
- })
334
-
335
- const result = await this.#promiseManager.run('first', promises)
336
-
337
- this.events.emit('plugins:hook:progress:end', { hookName })
338
-
339
- return result
340
- }
341
-
342
- /**
343
- * Returns the first non-null result.
344
- */
345
- hookFirstSync<H extends PluginLifecycleHooks>({
346
- hookName,
347
- parameters,
348
- skipped,
349
- }: {
350
- hookName: H
351
- parameters: PluginParameter<H>
352
- skipped?: ReadonlySet<Plugin> | null
353
- }): SafeParseResult<H> | null {
354
- let parseResult: SafeParseResult<H> | null = null
355
- const plugins = this.#getSortedPlugins(hookName).filter((plugin) => {
356
- return skipped ? !skipped.has(plugin) : true
357
- })
358
-
359
- for (const plugin of plugins) {
360
- parseResult = {
361
- result: this.#executeSync<H>({
362
- strategy: 'hookFirst',
363
- hookName,
364
- parameters,
365
- plugin,
366
- }),
367
- plugin,
368
- } as SafeParseResult<H>
369
-
370
- if (parseResult?.result != null) {
371
- break
372
- }
373
- }
374
-
375
- return parseResult
376
- }
377
-
378
- /**
379
- * Runs all plugins in parallel based on `this.plugin` order and `pre`/`post` settings.
380
- */
381
- async hookParallel<H extends PluginLifecycleHooks, TOutput = void>({
382
- hookName,
383
- parameters,
384
- }: {
385
- hookName: H
386
- parameters?: Parameters<RequiredPluginLifecycle[H]> | undefined
387
- }): Promise<Awaited<TOutput>[]> {
388
- const plugins = this.#getSortedPlugins(hookName)
389
- this.events.emit('plugins:hook:progress:start', { hookName, plugins })
390
-
391
- const pluginStartTimes = new Map<Plugin, number>()
392
-
393
- const promises = plugins.map((plugin) => {
394
- return () => {
395
- pluginStartTimes.set(plugin, performance.now())
396
- return this.#execute({
397
- strategy: 'hookParallel',
398
- hookName,
399
- parameters,
400
- plugin,
401
- }) as Promise<TOutput>
402
- }
403
- })
404
-
405
- const results = await this.#promiseManager.run('parallel', promises, {
406
- concurrency: this.options.concurrency,
407
- })
408
-
409
- results.forEach((result, index) => {
410
- if (isPromiseRejectedResult<Error>(result)) {
411
- const plugin = this.#getSortedPlugins(hookName)[index]
412
-
413
- if (plugin) {
414
- const startTime = pluginStartTimes.get(plugin) ?? performance.now()
415
- this.events.emit('error', result.reason, {
416
- plugin,
417
- hookName,
418
- strategy: 'hookParallel',
419
- duration: Math.round(performance.now() - startTime),
420
- parameters,
421
- })
422
- }
423
- }
424
- })
425
-
426
- this.events.emit('plugins:hook:progress:end', { hookName })
427
-
428
- return results.reduce((acc, result) => {
429
- if (result.status === 'fulfilled') {
430
- acc.push(result.value)
431
- }
432
- return acc
433
- }, [] as Awaited<TOutput>[])
434
- }
435
-
436
- /**
437
- * Chains plugins
438
- */
439
- async hookSeq<H extends PluginLifecycleHooks>({ hookName, parameters }: { hookName: H; parameters?: PluginParameter<H> }): Promise<void> {
440
- const plugins = this.#getSortedPlugins(hookName)
441
- this.events.emit('plugins:hook:progress:start', { hookName, plugins })
442
-
443
- const promises = plugins.map((plugin) => {
444
- return () =>
445
- this.#execute({
446
- strategy: 'hookSeq',
447
- hookName,
448
- parameters,
449
- plugin,
450
- })
451
- })
452
-
453
- await this.#promiseManager.run('seq', promises)
454
-
455
- this.events.emit('plugins:hook:progress:end', { hookName })
456
- }
457
-
458
- #getSortedPlugins(hookName?: keyof PluginLifecycle): Array<Plugin> {
459
- const plugins = [...this.#plugins]
460
-
461
- if (hookName) {
462
- return plugins.filter((plugin) => hookName in plugin)
463
- }
464
- // TODO add test case for sorting with pre/post
465
-
466
- return plugins
467
- .map((plugin) => {
468
- if (plugin.pre) {
469
- let missingPlugins = plugin.pre.filter((pluginName) => !plugins.find((pluginToFind) => pluginToFind.name === pluginName))
470
-
471
- // when adapter is set, we can ignore the depends on plugin-oas, in v5 this will not be needed anymore
472
- if (missingPlugins.includes('plugin-oas') && this.adapter) {
473
- missingPlugins = missingPlugins.filter((pluginName) => pluginName !== 'plugin-oas')
474
- }
475
-
476
- if (missingPlugins.length > 0) {
477
- throw new ValidationPluginError(`The plugin '${plugin.name}' has a pre set that references missing plugins for '${missingPlugins.join(', ')}'`)
478
- }
479
- }
480
-
481
- return plugin
482
- })
483
- .sort((a, b) => {
484
- if (b.pre?.includes(a.name)) {
485
- return 1
486
- }
487
- if (b.post?.includes(a.name)) {
488
- return -1
489
- }
490
- return 0
491
- })
492
- }
493
-
494
- getPluginByName(pluginName: string): Plugin | undefined {
495
- const plugins = [...this.#plugins]
496
-
497
- return plugins.find((item) => item.name === pluginName)
498
- }
499
-
500
- getPluginsByName(hookName: keyof PluginWithLifeCycle, pluginName: string): Plugin[] {
501
- const plugins = [...this.plugins]
502
-
503
- const pluginByPluginName = plugins.filter((plugin) => hookName in plugin).filter((item) => item.name === pluginName)
504
-
505
- if (!pluginByPluginName?.length) {
506
- // fallback on the core plugin when there is no match
507
-
508
- const corePlugin = plugins.find((plugin) => plugin.name === CORE_PLUGIN_NAME && hookName in plugin)
509
-
510
- return corePlugin ? [corePlugin] : []
511
- }
512
-
513
- return pluginByPluginName
514
- }
515
-
516
- /**
517
- * Run an async plugin hook and return the result.
518
- * @param hookName Name of the plugin hook. Must be either in `PluginHooks` or `OutputPluginValueHooks`.
519
- * @param args Arguments passed to the plugin hook.
520
- * @param plugin The actual pluginObject to run.
521
- */
522
- #emitProcessingEnd<H extends PluginLifecycleHooks>({
523
- startTime,
524
- output,
525
- strategy,
526
- hookName,
527
- plugin,
528
- parameters,
529
- }: {
530
- startTime: number
531
- output: unknown
532
- strategy: Strategy
533
- hookName: H
534
- plugin: PluginWithLifeCycle
535
- parameters: unknown[] | undefined
536
- }): void {
537
- this.events.emit('plugins:hook:processing:end', {
538
- duration: Math.round(performance.now() - startTime),
539
- parameters,
540
- output,
541
- strategy,
542
- hookName,
543
- plugin,
544
- })
545
- }
546
-
547
- // Implementation signature
548
- #execute<H extends PluginLifecycleHooks>({
549
- strategy,
550
- hookName,
551
- parameters,
552
- plugin,
553
- }: {
554
- strategy: Strategy
555
- hookName: H
556
- parameters: unknown[] | undefined
557
- plugin: PluginWithLifeCycle
558
- }): Promise<ReturnType<ParseResult<H>> | null> | null {
559
- const hook = plugin[hookName]
560
-
561
- if (!hook) {
562
- return null
563
- }
564
-
565
- this.events.emit('plugins:hook:processing:start', {
566
- strategy,
567
- hookName,
568
- parameters,
569
- plugin,
570
- })
571
-
572
- const startTime = performance.now()
573
-
574
- const task = (async () => {
575
- try {
576
- const output =
577
- typeof hook === 'function' ? await Promise.resolve((hook as (...args: unknown[]) => unknown).apply(this.getContext(plugin), parameters ?? [])) : hook
578
-
579
- this.#emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters })
580
-
581
- return output as ReturnType<ParseResult<H>>
582
- } catch (error) {
583
- this.events.emit('error', error as Error, {
584
- plugin,
585
- hookName,
586
- strategy,
587
- duration: Math.round(performance.now() - startTime),
588
- })
589
-
590
- return null
591
- }
592
- })()
593
-
594
- return task
595
- }
596
-
597
- /**
598
- * Run a sync plugin hook and return the result.
599
- * @param hookName Name of the plugin hook. Must be in `PluginHooks`.
600
- * @param args Arguments passed to the plugin hook.
601
- * @param plugin The actual plugin
602
- */
603
- #executeSync<H extends PluginLifecycleHooks>({
604
- strategy,
605
- hookName,
606
- parameters,
607
- plugin,
608
- }: {
609
- strategy: Strategy
610
- hookName: H
611
- parameters: PluginParameter<H>
612
- plugin: PluginWithLifeCycle
613
- }): ReturnType<ParseResult<H>> | null {
614
- const hook = plugin[hookName]
615
-
616
- if (!hook) {
617
- return null
618
- }
619
-
620
- this.events.emit('plugins:hook:processing:start', {
621
- strategy,
622
- hookName,
623
- parameters,
624
- plugin,
625
- })
626
-
627
- const startTime = performance.now()
628
-
629
- try {
630
- const output =
631
- typeof hook === 'function'
632
- ? ((hook as (...args: unknown[]) => unknown).apply(this.getContext(plugin), parameters) as ReturnType<ParseResult<H>>)
633
- : (hook as ReturnType<ParseResult<H>>)
634
-
635
- this.#emitProcessingEnd({ startTime, output, strategy, hookName, plugin, parameters })
636
-
637
- return output
638
- } catch (error) {
639
- this.events.emit('error', error as Error, {
640
- plugin,
641
- hookName,
642
- strategy,
643
- duration: Math.round(performance.now() - startTime),
644
- })
645
-
646
- return null
647
- }
648
- }
649
-
650
- #parse(plugin: UserPlugin): Plugin {
651
- const usedPluginNames = this.#usedPluginNames
652
-
653
- setUniqueName(plugin.name, usedPluginNames)
654
-
655
- const usageCount = usedPluginNames[plugin.name]
656
- if (usageCount && usageCount > 1) {
657
- throw new ValidationPluginError(
658
- `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.`,
659
- )
660
- }
661
-
662
- return {
663
- install() {},
664
- ...plugin,
665
- } as unknown as Plugin
666
- }
667
- }
@@ -1,40 +0,0 @@
1
- import type { Strategy, StrategySwitch } from './utils/executeStrategies.ts'
2
- import { hookFirst, hookParallel, hookSeq } from './utils/executeStrategies.ts'
3
-
4
- type PromiseFunc<T = unknown, T2 = never> = () => T2 extends never ? Promise<T> : Promise<T> | T2
5
-
6
- type Options<TState = unknown> = {
7
- nullCheck?: (state: TState) => boolean
8
- }
9
-
10
- export class PromiseManager<TState = unknown> {
11
- #options: Options<TState> = {}
12
-
13
- constructor(options: Options<TState> = {}) {
14
- this.#options = options
15
- }
16
-
17
- run<TInput extends Array<PromiseFunc<TValue, null>>, TValue, TStrategy extends Strategy, TOutput = StrategySwitch<TStrategy, TInput, TValue>>(
18
- strategy: TStrategy,
19
- promises: TInput,
20
- { concurrency = Number.POSITIVE_INFINITY }: { concurrency?: number } = {},
21
- ): TOutput {
22
- if (strategy === 'seq') {
23
- return hookSeq<TInput, TValue, TOutput>(promises)
24
- }
25
-
26
- if (strategy === 'first') {
27
- return hookFirst<TInput, TValue, TOutput>(promises, this.#options.nullCheck as ((state: unknown) => boolean) | undefined)
28
- }
29
-
30
- if (strategy === 'parallel') {
31
- return hookParallel<TInput, TValue, TOutput>(promises, concurrency)
32
- }
33
-
34
- throw new Error(`${strategy} not implemented`)
35
- }
36
- }
37
-
38
- export function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {
39
- return result.status === 'rejected'
40
- }