@kubb/core 4.36.1 → 5.0.0-alpha.10

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 (47) hide show
  1. package/dist/{types-D30QAz2y.d.ts → PluginDriver-BkFepPdm.d.ts} +354 -291
  2. package/dist/hooks.cjs +85 -8
  3. package/dist/hooks.cjs.map +1 -1
  4. package/dist/hooks.d.ts +66 -4
  5. package/dist/hooks.js +83 -8
  6. package/dist/hooks.js.map +1 -1
  7. package/dist/index.cjs +346 -315
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +91 -77
  10. package/dist/index.js +338 -305
  11. package/dist/index.js.map +1 -1
  12. package/package.json +7 -7
  13. package/src/Kubb.ts +27 -55
  14. package/src/{PluginManager.ts → PluginDriver.ts} +69 -82
  15. package/src/build.ts +32 -33
  16. package/src/constants.ts +1 -1
  17. package/src/createAdapter.ts +25 -0
  18. package/src/createPlugin.ts +28 -0
  19. package/src/createStorage.ts +58 -0
  20. package/src/defineGenerator.ts +134 -0
  21. package/src/defineLogger.ts +13 -3
  22. package/src/defineResolver.ts +131 -0
  23. package/src/hooks/index.ts +2 -1
  24. package/src/hooks/useKubb.ts +143 -0
  25. package/src/hooks/useMode.ts +5 -2
  26. package/src/hooks/usePlugin.ts +5 -2
  27. package/src/hooks/usePluginDriver.ts +11 -0
  28. package/src/index.ts +7 -7
  29. package/src/storages/fsStorage.ts +2 -2
  30. package/src/storages/memoryStorage.ts +2 -2
  31. package/src/types.ts +94 -48
  32. package/src/utils/FunctionParams.ts +2 -2
  33. package/src/utils/TreeNode.ts +1 -1
  34. package/src/utils/formatters.ts +1 -1
  35. package/src/utils/getBarrelFiles.ts +73 -11
  36. package/src/utils/getConfigs.ts +3 -21
  37. package/src/utils/linters.ts +1 -1
  38. package/src/utils/packageJSON.ts +61 -0
  39. package/src/BarrelManager.ts +0 -74
  40. package/src/PackageManager.ts +0 -180
  41. package/src/PromiseManager.ts +0 -40
  42. package/src/defineAdapter.ts +0 -22
  43. package/src/definePlugin.ts +0 -12
  44. package/src/defineStorage.ts +0 -56
  45. package/src/errors.ts +0 -1
  46. package/src/hooks/usePluginManager.ts +0 -8
  47. package/src/utils/getPlugins.ts +0 -23
@@ -0,0 +1,143 @@
1
+ import path from 'node:path'
2
+ import type { RootNode } from '@kubb/ast/types'
3
+ import type { KubbFile } from '@kubb/fabric-core/types'
4
+ import { useFabric } from '@kubb/react-fabric'
5
+ import type { GetFileOptions, PluginDriver } from '../PluginDriver.ts'
6
+ import type { Config, Plugin, PluginFactoryOptions, ResolveNameParams, ResolvePathParams } from '../types.ts'
7
+
8
+ type ResolvePathOptions = {
9
+ pluginName?: string
10
+ group?: {
11
+ tag?: string
12
+ path?: string
13
+ }
14
+ type?: ResolveNameParams['type']
15
+ }
16
+
17
+ type UseKubbReturn<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
18
+ plugin: Plugin<TOptions>
19
+ mode: KubbFile.Mode
20
+ config: Config
21
+ /**
22
+ * Returns the plugin whose `name` matches `pluginName`, defaulting to the current plugin.
23
+ */
24
+ getPluginByName: (pluginName?: string) => Plugin | undefined
25
+ /**
26
+ * Resolves a file reference, defaulting `pluginName` to the current plugin.
27
+ */
28
+ getFile: (params: Omit<GetFileOptions<ResolvePathOptions>, 'pluginName'> & { pluginName?: string }) => KubbFile.File<{ pluginName: string }>
29
+ /**
30
+ * Resolves a name, defaulting `pluginName` to the current plugin.
31
+ */
32
+ resolveName: (params: Omit<ResolveNameParams, 'pluginName'> & { pluginName?: string }) => string
33
+ /**
34
+ * Resolves a path, defaulting `pluginName` to the current plugin.
35
+ */
36
+ resolvePath: <TPathOptions = object>(params: Omit<ResolvePathParams<TPathOptions>, 'pluginName'> & { pluginName?: string }) => KubbFile.Path
37
+ /**
38
+ * Resolves the banner using the plugin's `output.banner` option.
39
+ * Falls back to the default "Generated by Kubb" banner when `output.banner` is unset.
40
+ * When `output.banner` is a function and no node is provided, returns the default banner.
41
+ */
42
+ resolveBanner: (node?: RootNode) => string | undefined
43
+ /**
44
+ * Resolves the footer using the plugin's `output.footer` option.
45
+ * Returns `undefined` when no footer is configured.
46
+ * When `output.footer` is a function and no node is provided, returns `undefined`.
47
+ */
48
+ resolveFooter: (node?: RootNode) => string | undefined
49
+ }
50
+
51
+ /**
52
+ * Generates the default "Generated by Kubb" banner from node metadata.
53
+ */
54
+ function buildDefaultBanner({ title, description, version, config }: { title?: string; description?: string; version?: string; config: Config }): string {
55
+ try {
56
+ let source = ''
57
+ if (Array.isArray(config.input)) {
58
+ const first = config.input[0]
59
+ if (first && 'path' in first) {
60
+ source = path.basename(first.path)
61
+ }
62
+ } else if ('path' in config.input) {
63
+ source = path.basename(config.input.path)
64
+ } else if ('data' in config.input) {
65
+ source = 'text content'
66
+ }
67
+
68
+ let banner = '/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n'
69
+
70
+ if (config.output.defaultBanner === 'simple') {
71
+ banner += '*/\n'
72
+ return banner
73
+ }
74
+
75
+ if (source) {
76
+ banner += `* Source: ${source}\n`
77
+ }
78
+
79
+ if (title) {
80
+ banner += `* Title: ${title}\n`
81
+ }
82
+
83
+ if (description) {
84
+ const formattedDescription = description.replace(/\n/gm, '\n* ')
85
+ banner += `* Description: ${formattedDescription}\n`
86
+ }
87
+
88
+ if (version) {
89
+ banner += `* OpenAPI spec version: ${version}\n`
90
+ }
91
+
92
+ banner += '*/\n'
93
+ return banner
94
+ } catch (_error) {
95
+ return '/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/'
96
+ }
97
+ }
98
+
99
+ export function useKubb<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(): UseKubbReturn<TOptions> {
100
+ const { meta } = useFabric<{
101
+ plugin: Plugin<TOptions>
102
+ mode: KubbFile.Mode
103
+ driver: PluginDriver
104
+ }>()
105
+
106
+ const config = meta.driver.config
107
+ const defaultPluginName = meta.plugin.name
108
+
109
+ const output = (
110
+ meta.plugin.options as { output?: { banner?: string | ((node: RootNode) => string); footer?: string | ((node: RootNode) => string) } } | undefined
111
+ )?.output
112
+
113
+ return {
114
+ plugin: meta.plugin as Plugin<TOptions>,
115
+ mode: meta.mode,
116
+ config,
117
+ getPluginByName: (pluginName = defaultPluginName) => meta.driver.getPluginByName.call(meta.driver, pluginName),
118
+ getFile: ({ pluginName = defaultPluginName, ...rest }) => meta.driver.getFile.call(meta.driver, { pluginName, ...rest }),
119
+ resolveName: ({ pluginName = defaultPluginName, ...rest }) => meta.driver.resolveName.call(meta.driver, { pluginName, ...rest }),
120
+ resolvePath: ({ pluginName = defaultPluginName, ...rest }) => meta.driver.resolvePath.call(meta.driver, { pluginName, ...rest }),
121
+ resolveBanner: (node?: RootNode) => {
122
+ if (typeof output?.banner === 'function') {
123
+ return node ? output.banner(node) : buildDefaultBanner({ config })
124
+ }
125
+ if (typeof output?.banner === 'string') {
126
+ return output.banner
127
+ }
128
+ if (config.output.defaultBanner === false) {
129
+ return undefined
130
+ }
131
+ return buildDefaultBanner({ config })
132
+ },
133
+ resolveFooter: (node?: RootNode) => {
134
+ if (typeof output?.footer === 'function') {
135
+ return node ? output.footer(node) : undefined
136
+ }
137
+ if (typeof output?.footer === 'string') {
138
+ return output.footer
139
+ }
140
+ return undefined
141
+ },
142
+ }
143
+ }
@@ -1,8 +1,11 @@
1
1
  import type { KubbFile } from '@kubb/fabric-core/types'
2
- import { useApp } from '@kubb/react-fabric'
2
+ import { useFabric } from '@kubb/react-fabric'
3
3
 
4
+ /**
5
+ * @deprecated use `useKubb` instead
6
+ */
4
7
  export function useMode(): KubbFile.Mode {
5
- const { meta } = useApp<{ mode: KubbFile.Mode }>()
8
+ const { meta } = useFabric<{ mode: KubbFile.Mode }>()
6
9
 
7
10
  return meta.mode
8
11
  }
@@ -1,8 +1,11 @@
1
- import { useApp } from '@kubb/react-fabric'
1
+ import { useFabric } from '@kubb/react-fabric'
2
2
  import type { Plugin, PluginFactoryOptions } from '../types.ts'
3
3
 
4
+ /**
5
+ * @deprecated use useKubb instead
6
+ */
4
7
  export function usePlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(): Plugin<TOptions> {
5
- const { meta } = useApp<{ plugin: Plugin<TOptions> }>()
8
+ const { meta } = useFabric<{ plugin: Plugin<TOptions> }>()
6
9
 
7
10
  return meta.plugin
8
11
  }
@@ -0,0 +1,11 @@
1
+ import { useFabric } from '@kubb/react-fabric'
2
+ import type { PluginDriver } from '../PluginDriver.ts'
3
+
4
+ /**
5
+ * @deprecated use `useKubb` instead
6
+ */
7
+ export function usePluginDriver(): PluginDriver {
8
+ const { meta } = useFabric<{ driver: PluginDriver }>()
9
+
10
+ return meta.driver
11
+ }
package/src/index.ts CHANGED
@@ -1,15 +1,14 @@
1
- export { AsyncEventEmitter, URLPath } from '@internals/utils'
2
1
  export { definePrinter } from '@kubb/ast'
3
2
  export { build, build as default, safeBuild, setup } from './build.ts'
4
3
  export { type CLIOptions, type ConfigInput, defineConfig, isInputPath } from './config.ts'
5
4
  export { formatters, linters, logLevel } from './constants.ts'
6
- export { defineAdapter } from './defineAdapter.ts'
5
+ export { createAdapter } from './createAdapter.ts'
6
+ export { createPlugin } from './createPlugin.ts'
7
+ export { createStorage } from './createStorage.ts'
8
+ export { defineGenerator } from './defineGenerator.ts'
7
9
  export { defineLogger } from './defineLogger.ts'
8
- export { definePlugin } from './definePlugin.ts'
9
- export { defineStorage } from './defineStorage.ts'
10
- export { PackageManager } from './PackageManager.ts'
11
- export { getMode, PluginManager } from './PluginManager.ts'
12
- export { PromiseManager } from './PromiseManager.ts'
10
+ export { defaultResolveOptions, defineResolver } from './defineResolver.ts'
11
+ export { getMode, PluginDriver } from './PluginDriver.ts'
13
12
  export { fsStorage } from './storages/fsStorage.ts'
14
13
  export { memoryStorage } from './storages/memoryStorage.ts'
15
14
  export * from './types.ts'
@@ -20,3 +19,4 @@ export type { FileMetaBase } from './utils/getBarrelFiles.ts'
20
19
  export { getBarrelFiles } from './utils/getBarrelFiles.ts'
21
20
  export { getConfigs } from './utils/getConfigs.ts'
22
21
  export { detectLinter } from './utils/linters.ts'
22
+ export { satisfiesDependency } from './utils/packageJSON.ts'
@@ -2,7 +2,7 @@ import type { Dirent } from 'node:fs'
2
2
  import { access, readdir, readFile, rm } from 'node:fs/promises'
3
3
  import { join, resolve } from 'node:path'
4
4
  import { clean, write } from '@internals/utils'
5
- import { defineStorage } from '../defineStorage.ts'
5
+ import { createStorage } from '../createStorage.ts'
6
6
 
7
7
  /**
8
8
  * Built-in filesystem storage driver.
@@ -27,7 +27,7 @@ import { defineStorage } from '../defineStorage.ts'
27
27
  * })
28
28
  * ```
29
29
  */
30
- export const fsStorage = defineStorage(() => ({
30
+ export const fsStorage = createStorage(() => ({
31
31
  name: 'fs',
32
32
  async hasItem(key: string) {
33
33
  try {
@@ -1,4 +1,4 @@
1
- import { defineStorage } from '../defineStorage.ts'
1
+ import { createStorage } from '../createStorage.ts'
2
2
 
3
3
  /**
4
4
  * In-memory storage driver. Useful for testing and dry-run scenarios where
@@ -17,7 +17,7 @@ import { defineStorage } from '../defineStorage.ts'
17
17
  * })
18
18
  * ```
19
19
  */
20
- export const memoryStorage = defineStorage(() => {
20
+ export const memoryStorage = createStorage(() => {
21
21
  const store = new Map<string, string>()
22
22
 
23
23
  return {
package/src/types.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import type { AsyncEventEmitter, PossiblePromise } from '@internals/utils'
2
- import type { RootNode } from '@kubb/ast/types'
3
- import type { KubbFile } from '@kubb/fabric-core/types'
4
- import type { Fabric } from '@kubb/react-fabric'
2
+ import type { Node, RootNode, SchemaNode } from '@kubb/ast/types'
3
+ import type { Fabric as FabricType, KubbFile } from '@kubb/fabric-core/types'
5
4
  import type { DEFAULT_STUDIO_URL, logLevel } from './constants.ts'
6
- import type { DefineStorage } from './defineStorage.ts'
5
+ import type { Storage } from './createStorage.ts'
7
6
  import type { KubbEvents } from './Kubb.ts'
8
- import type { PluginManager } from './PluginManager.ts'
7
+ import type { PluginDriver } from './PluginDriver.ts'
9
8
 
10
9
  export type { Printer, PrinterFactoryOptions } from '@kubb/ast/types'
11
10
 
@@ -33,7 +32,7 @@ export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins'
33
32
  /**
34
33
  * An array of Kubb plugins used for generation. Each plugin may have additional configurable options (defined within the plugin itself). If a plugin relies on another plugin, an error will occur if the required dependency is missing. Refer to “pre” for more details.
35
34
  */
36
- // inject needs to be omitted because else we have a clash with the PluginManager instance
35
+ // inject needs to be omitted because else we have a clash with the PluginDriver instance
37
36
  plugins?: Array<Omit<UnknownUserPlugin, 'inject'>>
38
37
  }
39
38
 
@@ -98,6 +97,14 @@ export type Adapter<TOptions extends AdapterFactoryOptions = AdapterFactoryOptio
98
97
  options: TOptions['resolvedOptions']
99
98
  /** Convert the raw source into a universal `RootNode`. */
100
99
  parse: (source: AdapterSource) => PossiblePromise<RootNode>
100
+ /**
101
+ * Extracts `KubbFile.Import` entries needed by a `SchemaNode` tree.
102
+ * Populated after the first `parse()` call. Returns an empty array before that.
103
+ *
104
+ * The `resolve` callback receives the collision-corrected schema name and must
105
+ * return the `{ name, path }` pair for the import, or `undefined` to skip it.
106
+ */
107
+ getImports: (node: SchemaNode, resolve: (schemaName: string) => { name: string; path: string }) => Array<KubbFile.Import>
101
108
  }
102
109
 
103
110
  export type BarrelType = 'all' | 'named' | 'propagate'
@@ -165,16 +172,16 @@ export type Config<TInput = Input> = {
165
172
  /**
166
173
  * Storage backend for generated files.
167
174
  * Defaults to `fsStorage()` — the built-in filesystem driver.
168
- * Accepts any object implementing the {@link DefineStorage} interface.
175
+ * Accepts any object implementing the {@link Storage} interface.
169
176
  * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
170
177
  * @default fsStorage()
171
178
  * @example
172
179
  * ```ts
173
- * import { defineStorage, fsStorage } from '@kubb/core'
174
- * storage: defineStorage(fsStorage())
180
+ * import { memoryStorage } from '@kubb/core'
181
+ * storage: memoryStorage()
175
182
  * ```
176
183
  */
177
- storage?: DefineStorage
184
+ storage?: Storage
178
185
  /**
179
186
  * Specifies the formatting tool to be used.
180
187
  * - 'auto' automatically detects and uses biome or prettier (in that order of preference).
@@ -253,9 +260,47 @@ export type Config<TInput = Input> = {
253
260
 
254
261
  // plugin
255
262
 
263
+ type PatternFilter = {
264
+ type: string
265
+ pattern: string | RegExp
266
+ }
267
+
268
+ type PatternOverride<TOptions> = PatternFilter & {
269
+ options: Omit<Partial<TOptions>, 'override'>
270
+ }
271
+
272
+ export type ResolveOptionsContext<TOptions> = {
273
+ options: TOptions
274
+ exclude?: Array<PatternFilter>
275
+ include?: Array<PatternFilter>
276
+ override?: Array<PatternOverride<TOptions>>
277
+ }
278
+
279
+ /**
280
+ * Base constraint for all plugin resolver objects.
281
+ *
282
+ * `default` and `resolveOptions` are injected automatically by `defineResolver` — plugin
283
+ * authors may override them but never need to implement them from scratch.
284
+ * Concrete plugin resolver types extend this with their own helper methods.
285
+ */
286
+ export type Resolver = {
287
+ default(name: ResolveNameParams['name'], type?: ResolveNameParams['type']): string
288
+ resolveOptions<TOptions>(node: Node, context: ResolveOptionsContext<TOptions>): TOptions | null
289
+ }
290
+
291
+ /**
292
+ * The user-facing subset of a `Resolver` — everything except the methods injected by
293
+ * `defineResolver` (`default` and `resolveOptions`).
294
+ *
295
+ * When you pass a `UserResolver` to `defineResolver`, the standard `default` and
296
+ * `resolveOptions` implementations are injected automatically so plugin authors never
297
+ * need to define them by hand. Both can still be overridden by providing them explicitly.
298
+ */
299
+ export type UserResolver = Omit<Resolver, 'default' | 'resolveOptions'>
300
+
256
301
  export type PluginFactoryOptions<
257
302
  /**
258
- * Name to be used for the plugin, this will also be used for they key.
303
+ * Name to be used for the plugin.
259
304
  */
260
305
  TName extends string = string,
261
306
  /**
@@ -274,22 +319,20 @@ export type PluginFactoryOptions<
274
319
  * When calling `resolvePath` you can specify better types.
275
320
  */
276
321
  TResolvePathOptions extends object = object,
277
- > = {
278
- name: TName
279
322
  /**
280
- * Same behavior like what has been done with `QueryKey` in `@tanstack/react-query`
323
+ * Resolver object that encapsulates the naming and path-resolution helpers used by this plugin.
324
+ * Use `defineResolver` to define the resolver object and export it alongside the plugin.
281
325
  */
282
- key: PluginKey<TName | string>
326
+ TResolver extends Resolver = Resolver,
327
+ > = {
328
+ name: TName
283
329
  options: TOptions
284
330
  resolvedOptions: TResolvedOptions
285
331
  context: TContext
286
332
  resolvePathOptions: TResolvePathOptions
333
+ resolver: TResolver
287
334
  }
288
335
 
289
- export type PluginKey<TName> = [name: TName, identifier?: string | number]
290
-
291
- export type GetPluginFactoryOptions<TPlugin extends UserPlugin> = TPlugin extends UserPlugin<infer X> ? X : never
292
-
293
336
  export type UserPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
294
337
  /**
295
338
  * Unique name used for the plugin
@@ -315,7 +358,7 @@ export type UserPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOpti
315
358
 
316
359
  export type UserPluginWithLifeCycle<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = UserPlugin<TOptions> & PluginLifecycle<TOptions>
317
360
 
318
- export type UnknownUserPlugin = UserPlugin<PluginFactoryOptions<any, any, any, any, any>>
361
+ type UnknownUserPlugin = UserPlugin<PluginFactoryOptions<string, object, object, unknown, object>>
319
362
 
320
363
  export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
321
364
  /**
@@ -323,11 +366,6 @@ export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
323
366
  * @example @kubb/typescript
324
367
  */
325
368
  name: TOptions['name']
326
- /**
327
- * Internal key used when a developer uses more than one of the same plugin
328
- * @private
329
- */
330
- key: TOptions['key']
331
369
  /**
332
370
  * Specifies the preceding plugins for the current plugin. You can pass an array of preceding plugin names, and the current plugin is executed after these plugins.
333
371
  * Can be used to validate dependent plugins.
@@ -344,7 +382,7 @@ export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
344
382
 
345
383
  install: (this: PluginContext<TOptions>, context: PluginContext<TOptions>) => PossiblePromise<void>
346
384
  /**
347
- * Define a context that can be used by other plugins, see `PluginManager' where we convert from `UserPlugin` to `Plugin`(used when calling `definePlugin`).
385
+ * Defines a context that can be used by other plugins, see `PluginDriver` where we convert from `UserPlugin` to `Plugin` (used when calling `createPlugin`).
348
386
  */
349
387
  inject: (this: PluginContext<TOptions>, context: PluginContext<TOptions>) => TOptions['context']
350
388
  }
@@ -378,7 +416,7 @@ export type PluginLifecycleHooks = keyof PluginLifecycle
378
416
  export type PluginParameter<H extends PluginLifecycleHooks> = Parameters<Required<PluginLifecycle>[H]>
379
417
 
380
418
  export type ResolvePathParams<TOptions = object> = {
381
- pluginKey?: Plugin['key']
419
+ pluginName?: string
382
420
  baseName: KubbFile.BaseName
383
421
  mode?: KubbFile.Mode
384
422
  /**
@@ -389,7 +427,7 @@ export type ResolvePathParams<TOptions = object> = {
389
427
 
390
428
  export type ResolveNameParams = {
391
429
  name: string
392
- pluginKey?: Plugin['key']
430
+ pluginName?: string
393
431
  /**
394
432
  * Specifies the type of entity being named.
395
433
  * - 'file' customizes the name of the created file (uses camelCase).
@@ -402,9 +440,9 @@ export type ResolveNameParams = {
402
440
  }
403
441
 
404
442
  export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
405
- fabric: Fabric
443
+ fabric: FabricType
406
444
  config: Config
407
- pluginManager: PluginManager
445
+ driver: PluginDriver
408
446
  /**
409
447
  * Only add when the file does not exist yet
410
448
  */
@@ -419,18 +457,31 @@ export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryO
419
457
  * Current plugin
420
458
  */
421
459
  plugin: Plugin<TOptions>
422
- /**
423
- * Returns the universal `@kubb/ast` `RootNode` produced by the configured adapter.
424
- * Returns `undefined` when no adapter was set (legacy OAS-only usage).
425
- */
426
- rootNode: RootNode | undefined
460
+
427
461
  /**
428
462
  * Opens the Kubb Studio URL for the current `rootNode` in the default browser.
429
463
  * Falls back to printing the URL if the browser cannot be launched.
430
464
  * No-ops silently when no adapter has set a `rootNode`.
431
465
  */
432
466
  openInStudio: (options?: DevtoolsOptions) => Promise<void>
433
- } & Kubb.PluginContext
467
+ } & (
468
+ | {
469
+ /**
470
+ * Returns the universal `@kubb/ast` `RootNode` produced by the configured adapter.
471
+ * Returns `undefined` when no adapter was set (legacy OAS-only usage).
472
+ */
473
+ rootNode: RootNode
474
+ /**
475
+ * Return the adapter from `@kubb/ast`
476
+ */
477
+ adapter: Adapter
478
+ }
479
+ | {
480
+ rootNode?: never
481
+ adapter?: never
482
+ }
483
+ ) &
484
+ Kubb.PluginContext
434
485
  /**
435
486
  * Specify the export location for the files and define the behavior of the output
436
487
  */
@@ -459,10 +510,6 @@ export type Output<TOptions> = {
459
510
  override?: boolean
460
511
  }
461
512
 
462
- type GroupContext = {
463
- group: string
464
- }
465
-
466
513
  export type Group = {
467
514
  /**
468
515
  * Defines the type where to group the files.
@@ -472,9 +519,9 @@ export type Group = {
472
519
  */
473
520
  type: 'tag' | 'path'
474
521
  /**
475
- * Return the name of a group based on the group name, this used for the file and name generation
522
+ * Return the name of a group based on the group name, this is used for the file and name generation.
476
523
  */
477
- name?: (context: GroupContext) => string
524
+ name?: (context: { group: string }) => string
478
525
  }
479
526
 
480
527
  export type LoggerOptions = {
@@ -487,16 +534,15 @@ export type LoggerOptions = {
487
534
  /**
488
535
  * Shared context passed to all plugins, parsers, and Fabric internals.
489
536
  */
490
- export interface LoggerContext extends AsyncEventEmitter<KubbEvents> {}
491
-
492
- type Install<TOptions = unknown> = (context: LoggerContext, options?: TOptions) => void | Promise<void>
537
+ export type LoggerContext = AsyncEventEmitter<KubbEvents>
493
538
 
494
539
  export type Logger<TOptions extends LoggerOptions = LoggerOptions> = {
495
540
  name: string
496
- install: Install<TOptions>
541
+ install: (context: LoggerContext, options?: TOptions) => void | Promise<void>
497
542
  }
498
543
 
499
- export type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Omit<Logger<TOptions>, 'logLevel'>
544
+ export type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Logger<TOptions>
500
545
 
501
- export type { DefineStorage } from './defineStorage.ts'
546
+ export type { Storage } from './createStorage.ts'
547
+ export type { CoreGeneratorV2, Generator, ReactGeneratorV2 } from './defineGenerator.ts'
502
548
  export type { KubbEvents } from './Kubb.ts'
@@ -30,12 +30,12 @@ type FunctionParamsASTWithType = {
30
30
  default?: string
31
31
  }
32
32
  /**
33
- * @deprecated
33
+ * @deprecated use ast package instead
34
34
  */
35
35
  export type FunctionParamsAST = FunctionParamsASTWithoutType | FunctionParamsASTWithType
36
36
 
37
37
  /**
38
- * @deprecated
38
+ * @deprecated use ast package instead
39
39
  */
40
40
  export class FunctionParams {
41
41
  #items: Array<FunctionParamsAST | FunctionParamsAST[]> = []
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path'
2
2
  import type { KubbFile } from '@kubb/fabric-core/types'
3
- import { getMode } from '../PluginManager.ts'
3
+ import { getMode } from '../PluginDriver.ts'
4
4
 
5
5
  type BarrelData = {
6
6
  file?: KubbFile.File
@@ -44,7 +44,7 @@ async function isFormatterAvailable(formatter: Formatter): Promise<boolean> {
44
44
  * ```
45
45
  */
46
46
  export async function detectFormatter(): Promise<Formatter | undefined> {
47
- const formatterNames: Formatter[] = ['biome', 'oxfmt', 'prettier']
47
+ const formatterNames = new Set(['biome', 'oxfmt', 'prettier'] as const)
48
48
 
49
49
  for (const formatter of formatterNames) {
50
50
  if (await isFormatterAvailable(formatter)) {
@@ -1,10 +1,12 @@
1
+ /** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */
1
2
  import { join } from 'node:path'
3
+ import { getRelativePath } from '@internals/utils'
2
4
  import type { KubbFile } from '@kubb/fabric-core/types'
3
- import { BarrelManager } from '../BarrelManager.ts'
4
- import type { BarrelType, Plugin } from '../types.ts'
5
+ import type { BarrelType } from '../types.ts'
6
+ import { TreeNode } from './TreeNode.ts'
5
7
 
6
8
  export type FileMetaBase = {
7
- pluginKey?: Plugin['key']
9
+ pluginName?: string
8
10
  }
9
11
 
10
12
  type AddIndexesProps = {
@@ -27,6 +29,72 @@ type AddIndexesProps = {
27
29
  meta?: FileMetaBase
28
30
  }
29
31
 
32
+ function getBarrelFilesByRoot(root: string | undefined, files: Array<KubbFile.ResolvedFile>): Array<KubbFile.File> {
33
+ const cachedFiles = new Map<KubbFile.Path, KubbFile.File>()
34
+
35
+ TreeNode.build(files, root)?.forEach((treeNode) => {
36
+ if (!treeNode || !treeNode.children || !treeNode.parent?.data.path) {
37
+ return
38
+ }
39
+
40
+ const barrelFilePath = join(treeNode.parent?.data.path, 'index.ts') as KubbFile.Path
41
+ const barrelFile: KubbFile.File = {
42
+ path: barrelFilePath,
43
+ baseName: 'index.ts',
44
+ exports: [],
45
+ imports: [],
46
+ sources: [],
47
+ }
48
+ const previousBarrelFile = cachedFiles.get(barrelFile.path)
49
+ const leaves = treeNode.leaves
50
+
51
+ leaves.forEach((item) => {
52
+ if (!item.data.name) {
53
+ return
54
+ }
55
+
56
+ const sources = item.data.file?.sources || []
57
+
58
+ sources.forEach((source) => {
59
+ if (!item.data.file?.path || !source.isIndexable || !source.name) {
60
+ return
61
+ }
62
+ const alreadyContainInPreviousBarrelFile = previousBarrelFile?.sources.some(
63
+ (item) => item.name === source.name && item.isTypeOnly === source.isTypeOnly,
64
+ )
65
+
66
+ if (alreadyContainInPreviousBarrelFile) {
67
+ return
68
+ }
69
+
70
+ barrelFile.exports!.push({
71
+ name: [source.name],
72
+ path: getRelativePath(treeNode.parent?.data.path, item.data.path),
73
+ isTypeOnly: source.isTypeOnly,
74
+ })
75
+
76
+ barrelFile.sources.push({
77
+ name: source.name,
78
+ isTypeOnly: source.isTypeOnly,
79
+ //TODO use parser to generate import
80
+ value: '',
81
+ isExportable: false,
82
+ isIndexable: false,
83
+ })
84
+ })
85
+ })
86
+
87
+ if (previousBarrelFile) {
88
+ previousBarrelFile.sources.push(...barrelFile.sources)
89
+ previousBarrelFile.exports?.push(...(barrelFile.exports || []))
90
+ } else {
91
+ cachedFiles.set(barrelFile.path, barrelFile)
92
+ }
93
+ })
94
+
95
+ return [...cachedFiles.values()]
96
+ }
97
+
30
98
  function trimExtName(text: string): string {
31
99
  const dotIndex = text.lastIndexOf('.')
32
100
  // Only strip when the dot is found and no path separator follows it
@@ -37,24 +105,18 @@ function trimExtName(text: string): string {
37
105
  return text
38
106
  }
39
107
 
40
- export async function getBarrelFiles(files: Array<KubbFile.ResolvedFile>, { type, meta = {}, root, output }: AddIndexesProps): Promise<KubbFile.File[]> {
108
+ export async function getBarrelFiles(files: Array<KubbFile.ResolvedFile>, { type, meta = {}, root, output }: AddIndexesProps): Promise<Array<KubbFile.File>> {
41
109
  if (!type || type === 'propagate') {
42
110
  return []
43
111
  }
44
112
 
45
- const barrelManager = new BarrelManager()
46
-
47
113
  const pathToBuildFrom = join(root, output.path)
48
114
 
49
115
  if (trimExtName(pathToBuildFrom).endsWith('index')) {
50
116
  return []
51
117
  }
52
118
 
53
- const barrelFiles = barrelManager.getFiles({
54
- files,
55
- root: pathToBuildFrom,
56
- meta,
57
- })
119
+ const barrelFiles = getBarrelFilesByRoot(pathToBuildFrom, files)
58
120
 
59
121
  if (type === 'all') {
60
122
  return barrelFiles.map((file) => {