@kubb/core 5.0.0-alpha.4 → 5.0.0-alpha.41

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