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

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/core",
3
- "version": "5.0.0-alpha.6",
3
+ "version": "5.0.0-alpha.7",
4
4
  "description": "Core functionality for Kubb's plugin-based code generation system, providing the foundation for transforming OpenAPI specifications.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -71,7 +71,7 @@
71
71
  "remeda": "^2.33.6",
72
72
  "semver": "^7.7.4",
73
73
  "tinyexec": "^1.0.4",
74
- "@kubb/ast": "5.0.0-alpha.6"
74
+ "@kubb/ast": "5.0.0-alpha.7"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@types/semver": "^7.7.1",
package/src/Kubb.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { KubbFile } from '@kubb/fabric-core/types'
2
- import type { Strategy } from './PluginManager.ts'
2
+ import type { Strategy } from './PluginDriver.ts'
3
3
  import type { Config, Plugin, PluginLifecycleHooks } from './types'
4
4
 
5
5
  type DebugEvent = {
@@ -1,13 +1,12 @@
1
1
  import { basename, extname, resolve } from 'node:path'
2
2
  import { performance } from 'node:perf_hooks'
3
3
  import type { AsyncEventEmitter } from '@internals/utils'
4
- import { setUniqueName, transformReservedWord } from '@internals/utils'
4
+ import { isPromiseRejectedResult, setUniqueName, transformReservedWord } from '@internals/utils'
5
5
  import type { RootNode } from '@kubb/ast/types'
6
6
  import type { Fabric as FabricType, KubbFile } from '@kubb/fabric-core/types'
7
7
  import { CORE_PLUGIN_NAME, DEFAULT_STUDIO_URL } from './constants.ts'
8
8
  import { openInStudio as openInStudioFn } from './devtools.ts'
9
9
  import { ValidationPluginError } from './errors.ts'
10
- import { isPromiseRejectedResult, PromiseManager } from './PromiseManager.ts'
11
10
  import type {
12
11
  Adapter,
13
12
  Config,
@@ -24,6 +23,7 @@ import type {
24
23
  ResolvePathParams,
25
24
  UserPlugin,
26
25
  } from './types.ts'
26
+ import { hookFirst, hookParallel, hookSeq } from './utils/executeStrategies.ts'
27
27
 
28
28
  type RequiredPluginLifecycle = Required<PluginLifecycle>
29
29
 
@@ -62,7 +62,9 @@ export function getMode(fileOrFolder: string | undefined | null): KubbFile.Mode
62
62
  return extname(fileOrFolder) ? 'single' : 'split'
63
63
  }
64
64
 
65
- export class PluginManager {
65
+ const hookFirstNullCheck = (state: unknown) => !!(state as SafeParseResult<'resolveName'> | null)?.result
66
+
67
+ export class PluginDriver {
66
68
  readonly config: Config
67
69
  readonly options: Options
68
70
 
@@ -76,14 +78,10 @@ export class PluginManager {
76
78
 
77
79
  readonly #plugins = new Set<Plugin>()
78
80
  readonly #usedPluginNames: Record<string, number> = {}
79
- readonly #promiseManager
80
81
 
81
82
  constructor(config: Config, options: Options) {
82
83
  this.config = config
83
84
  this.options = options
84
- this.#promiseManager = new PromiseManager({
85
- nullCheck: (state: SafeParseResult<'resolveName'> | null) => !!state?.result,
86
- })
87
85
  ;[...(config.plugins || [])].forEach((plugin) => {
88
86
  const parsedPlugin = this.#parse(plugin as UserPlugin)
89
87
 
@@ -97,14 +95,14 @@ export class PluginManager {
97
95
 
98
96
  getContext<TOptions extends PluginFactoryOptions>(plugin: Plugin<TOptions>): PluginContext<TOptions> & Record<string, unknown> {
99
97
  const plugins = [...this.#plugins]
100
- const pluginManager = this
98
+ const driver = this
101
99
 
102
100
  const baseContext = {
103
101
  fabric: this.options.fabric,
104
102
  config: this.config,
105
103
  plugin,
106
104
  events: this.options.events,
107
- pluginManager: this,
105
+ driver: this,
108
106
  mode: getMode(resolve(this.config.root, this.config.output.path)),
109
107
  addFile: async (...files: Array<KubbFile.File>) => {
110
108
  await this.options.fabric.addFile(...files)
@@ -113,29 +111,29 @@ export class PluginManager {
113
111
  await this.options.fabric.upsertFile(...files)
114
112
  },
115
113
  get rootNode(): RootNode | undefined {
116
- return pluginManager.rootNode
114
+ return driver.rootNode
117
115
  },
118
116
  get adapter(): Adapter | undefined {
119
- return pluginManager.adapter
117
+ return driver.adapter
120
118
  },
121
119
  openInStudio(options?: DevtoolsOptions) {
122
- if (!pluginManager.config.devtools || pluginManager.#studioIsOpen) {
120
+ if (!driver.config.devtools || driver.#studioIsOpen) {
123
121
  return
124
122
  }
125
123
 
126
- if (typeof pluginManager.config.devtools !== 'object') {
124
+ if (typeof driver.config.devtools !== 'object') {
127
125
  throw new Error('Devtools must be an object')
128
126
  }
129
127
 
130
- if (!pluginManager.rootNode || !pluginManager.adapter) {
128
+ if (!driver.rootNode || !driver.adapter) {
131
129
  throw new Error('adapter is not defined, make sure you have set the parser in kubb.config.ts')
132
130
  }
133
131
 
134
- pluginManager.#studioIsOpen = true
132
+ driver.#studioIsOpen = true
135
133
 
136
- const studioUrl = pluginManager.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL
134
+ const studioUrl = driver.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL
137
135
 
138
- return openInStudioFn(pluginManager.rootNode, studioUrl, options)
136
+ return openInStudioFn(driver.rootNode, studioUrl, options)
139
137
  },
140
138
  } as unknown as PluginContext<TOptions>
141
139
 
@@ -332,7 +330,7 @@ export class PluginManager {
332
330
  }
333
331
  })
334
332
 
335
- const result = await this.#promiseManager.run('first', promises)
333
+ const result = await hookFirst(promises, hookFirstNullCheck)
336
334
 
337
335
  this.events.emit('plugins:hook:progress:end', { hookName })
338
336
 
@@ -402,9 +400,7 @@ export class PluginManager {
402
400
  }
403
401
  })
404
402
 
405
- const results = await this.#promiseManager.run('parallel', promises, {
406
- concurrency: this.options.concurrency,
407
- })
403
+ const results = await hookParallel(promises, this.options.concurrency)
408
404
 
409
405
  results.forEach((result, index) => {
410
406
  if (isPromiseRejectedResult<Error>(result)) {
@@ -450,7 +446,7 @@ export class PluginManager {
450
446
  })
451
447
  })
452
448
 
453
- await this.#promiseManager.run('seq', promises)
449
+ await hookSeq(promises)
454
450
 
455
451
  this.events.emit('plugins:hook:progress:end', { hookName })
456
452
  }
package/src/build.ts CHANGED
@@ -7,7 +7,7 @@ import { fsPlugin } from '@kubb/react-fabric/plugins'
7
7
  import { isInputPath } from './config.ts'
8
8
  import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
9
9
  import { BuildError } from './errors.ts'
10
- import { PluginManager } from './PluginManager.ts'
10
+ import { PluginDriver } from './PluginDriver.ts'
11
11
  import { fsStorage } from './storages/fsStorage.ts'
12
12
  import type { AdapterSource, Config, DefineStorage, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
13
13
  import { getDiagnosticInfo } from './utils/diagnostics.ts'
@@ -22,7 +22,7 @@ type BuildOutput = {
22
22
  failedPlugins: Set<{ plugin: Plugin; error: Error }>
23
23
  fabric: FabricType
24
24
  files: Array<KubbFile.ResolvedFile>
25
- pluginManager: PluginManager
25
+ driver: PluginDriver
26
26
  pluginTimings: Map<string, number>
27
27
  error?: Error
28
28
  sources: Map<KubbFile.Path, string>
@@ -31,7 +31,7 @@ type BuildOutput = {
31
31
  type SetupResult = {
32
32
  events: AsyncEventEmitter<KubbEvents>
33
33
  fabric: FabricType
34
- pluginManager: PluginManager
34
+ driver: PluginDriver
35
35
  sources: Map<KubbFile.Path, string>
36
36
  }
37
37
 
@@ -164,7 +164,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
164
164
  ],
165
165
  })
166
166
 
167
- const pluginManager = new PluginManager(definedConfig, {
167
+ const pluginDriver = new PluginDriver(definedConfig, {
168
168
  fabric,
169
169
  events,
170
170
  concurrency: DEFAULT_CONCURRENCY,
@@ -179,15 +179,15 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
179
179
  logs: [`Running adapter: ${definedConfig.adapter.name}`],
180
180
  })
181
181
 
182
- pluginManager.adapter = definedConfig.adapter
183
- pluginManager.rootNode = await definedConfig.adapter.parse(source)
182
+ pluginDriver.adapter = definedConfig.adapter
183
+ pluginDriver.rootNode = await definedConfig.adapter.parse(source)
184
184
 
185
185
  await events.emit('debug', {
186
186
  date: new Date(),
187
187
  logs: [
188
188
  `✓ Adapter '${definedConfig.adapter.name}' resolved RootNode`,
189
- ` • Schemas: ${pluginManager.rootNode.schemas.length}`,
190
- ` • Operations: ${pluginManager.rootNode.operations.length}`,
189
+ ` • Schemas: ${pluginDriver.rootNode.schemas.length}`,
190
+ ` • Operations: ${pluginDriver.rootNode.operations.length}`,
191
191
  ],
192
192
  })
193
193
  }
@@ -195,13 +195,13 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
195
195
  return {
196
196
  events,
197
197
  fabric,
198
- pluginManager,
198
+ driver: pluginDriver,
199
199
  sources,
200
200
  }
201
201
  }
202
202
 
203
203
  export async function build(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
204
- const { fabric, files, pluginManager, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides)
204
+ const { fabric, files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides)
205
205
 
206
206
  if (error) {
207
207
  throw error
@@ -217,7 +217,7 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
217
217
  failedPlugins,
218
218
  fabric,
219
219
  files,
220
- pluginManager,
220
+ driver,
221
221
  pluginTimings,
222
222
  error: undefined,
223
223
  sources,
@@ -225,16 +225,16 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
225
225
  }
226
226
 
227
227
  export async function safeBuild(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
228
- const { fabric, pluginManager, events, sources } = overrides ? overrides : await setup(options)
228
+ const { fabric, driver, events, sources } = overrides ? overrides : await setup(options)
229
229
 
230
230
  const failedPlugins = new Set<{ plugin: Plugin; error: Error }>()
231
231
  // in ms
232
232
  const pluginTimings = new Map<string, number>()
233
- const config = pluginManager.config
233
+ const config = driver.config
234
234
 
235
235
  try {
236
- for (const plugin of pluginManager.plugins) {
237
- const context = pluginManager.getContext(plugin)
236
+ for (const plugin of driver.plugins) {
237
+ const context = driver.getContext(plugin)
238
238
  const hrStart = process.hrtime()
239
239
 
240
240
  const installer = plugin.install.bind(context)
@@ -313,7 +313,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
313
313
  const rootFile: KubbFile.File = {
314
314
  path: rootPath,
315
315
  baseName: BARREL_FILENAME,
316
- exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, pluginManager }),
316
+ exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }),
317
317
  sources: [],
318
318
  imports: [],
319
319
  meta: {},
@@ -335,7 +335,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
335
335
  failedPlugins,
336
336
  fabric,
337
337
  files,
338
- pluginManager,
338
+ driver,
339
339
  pluginTimings,
340
340
  sources,
341
341
  }
@@ -344,7 +344,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
344
344
  failedPlugins,
345
345
  fabric,
346
346
  files: [],
347
- pluginManager,
347
+ driver,
348
348
  pluginTimings,
349
349
  error: error as Error,
350
350
  sources,
@@ -357,12 +357,12 @@ type BuildBarrelExportsParams = {
357
357
  rootDir: string
358
358
  existingExports: Set<string>
359
359
  config: Config
360
- pluginManager: PluginManager
360
+ driver: PluginDriver
361
361
  }
362
362
 
363
- function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, pluginManager }: BuildBarrelExportsParams): KubbFile.Export[] {
363
+ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): KubbFile.Export[] {
364
364
  const pluginNameMap = new Map<string, Plugin>()
365
- for (const plugin of pluginManager.plugins) {
365
+ for (const plugin of driver.plugins) {
366
366
  pluginNameMap.set(plugin.name, plugin)
367
367
  }
368
368
 
@@ -1,4 +1,4 @@
1
1
  export { useKubb } from './useKubb.ts'
2
2
  export { useMode } from './useMode.ts'
3
3
  export { usePlugin } from './usePlugin.ts'
4
- export { usePluginManager } from './usePluginManager.ts'
4
+ export { usePluginDriver } from './usePluginDriver.ts'
@@ -1,6 +1,8 @@
1
+ import path from 'node:path'
2
+ import type { RootNode } from '@kubb/ast/types'
1
3
  import type { KubbFile } from '@kubb/fabric-core/types'
2
4
  import { useFabric } from '@kubb/react-fabric'
3
- import type { GetFileOptions, PluginManager } from '../PluginManager.ts'
5
+ import type { GetFileOptions, PluginDriver } from '../PluginDriver.ts'
4
6
  import type { Config, Plugin, PluginFactoryOptions, ResolveNameParams, ResolvePathParams } from '../types.ts'
5
7
 
6
8
  type ResolvePathOptions = {
@@ -32,24 +34,105 @@ type UseKubbReturn<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
32
34
  * Resolves a path, defaulting `pluginName` to the current plugin.
33
35
  */
34
36
  resolvePath: <TPathOptions = object>(params: Omit<ResolvePathParams<TPathOptions>, 'pluginName'> & { pluginName?: string }) => KubbFile.Path
37
+ /**
38
+ * Resolves the banner for the given node using the plugin's `output.banner` option.
39
+ * Returns a string when `output.banner` is a string or a function, `undefined` otherwise.
40
+ */
41
+ resolveBanner: (node: RootNode) => string | undefined
42
+ /**
43
+ * Resolves the footer for the given node using the plugin's `output.footer` option.
44
+ * Returns a string when `output.footer` is a string or a function, `undefined` otherwise.
45
+ */
46
+ resolveFooter: (node: RootNode) => string | undefined
47
+ }
48
+
49
+ /**
50
+ * Generates the default "Generated by Kubb" banner from node metadata.
51
+ */
52
+ function buildDefaultBanner({ title, description, version, config }: { title?: string; description?: string; version?: string; config: Config }): string {
53
+ try {
54
+ let source = ''
55
+ if (Array.isArray(config.input)) {
56
+ const first = config.input[0]
57
+ if (first && 'path' in first) {
58
+ source = path.basename(first.path)
59
+ }
60
+ } else if ('path' in config.input) {
61
+ source = path.basename(config.input.path)
62
+ } else if ('data' in config.input) {
63
+ source = 'text content'
64
+ }
65
+
66
+ let banner = '/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n'
67
+
68
+ if (config.output.defaultBanner === 'simple') {
69
+ banner += '*/\n'
70
+ return banner
71
+ }
72
+
73
+ if (source) {
74
+ banner += `* Source: ${source}\n`
75
+ }
76
+
77
+ if (title) {
78
+ banner += `* Title: ${title}\n`
79
+ }
80
+
81
+ if (description) {
82
+ const formattedDescription = description.replace(/\n/gm, '\n* ')
83
+ banner += `* Description: ${formattedDescription}\n`
84
+ }
85
+
86
+ if (version) {
87
+ banner += `* OpenAPI spec version: ${version}\n`
88
+ }
89
+
90
+ banner += '*/\n'
91
+ return banner
92
+ } catch (_error) {
93
+ return '/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/'
94
+ }
35
95
  }
36
96
 
37
97
  export function useKubb<TOptions extends PluginFactoryOptions = PluginFactoryOptions>(): UseKubbReturn<TOptions> {
38
98
  const { meta } = useFabric<{
39
99
  plugin: Plugin<TOptions>
40
100
  mode: KubbFile.Mode
41
- pluginManager: PluginManager
101
+ driver: PluginDriver
42
102
  }>()
43
103
 
104
+ const config = meta.driver.config
44
105
  const defaultPluginName = meta.plugin.name
45
106
 
107
+ const output = (
108
+ meta.plugin.options as { output?: { banner?: string | ((node: RootNode) => string); footer?: string | ((node: RootNode) => string) } } | undefined
109
+ )?.output
110
+
46
111
  return {
47
112
  plugin: meta.plugin as Plugin<TOptions>,
48
113
  mode: meta.mode,
49
- config: meta.pluginManager.config,
50
- getPluginByName: (pluginName = defaultPluginName) => meta.pluginManager.getPluginByName.call(meta.pluginManager, pluginName),
51
- getFile: ({ pluginName = defaultPluginName, ...rest }) => meta.pluginManager.getFile.call(meta.pluginManager, { pluginName, ...rest }),
52
- resolveName: ({ pluginName = defaultPluginName, ...rest }) => meta.pluginManager.resolveName.call(meta.pluginManager, { pluginName, ...rest }),
53
- resolvePath: ({ pluginName = defaultPluginName, ...rest }) => meta.pluginManager.resolvePath.call(meta.pluginManager, { pluginName, ...rest }),
114
+ config,
115
+ getPluginByName: (pluginName = defaultPluginName) => meta.driver.getPluginByName.call(meta.driver, pluginName),
116
+ getFile: ({ pluginName = defaultPluginName, ...rest }) => meta.driver.getFile.call(meta.driver, { pluginName, ...rest }),
117
+ resolveName: ({ pluginName = defaultPluginName, ...rest }) => meta.driver.resolveName.call(meta.driver, { pluginName, ...rest }),
118
+ resolvePath: ({ pluginName = defaultPluginName, ...rest }) => meta.driver.resolvePath.call(meta.driver, { pluginName, ...rest }),
119
+ resolveBanner: (node: RootNode) => {
120
+ if (typeof output?.banner === 'function') {
121
+ return output.banner(node)
122
+ }
123
+ if (typeof output?.banner === 'string') {
124
+ return output.banner
125
+ }
126
+ return buildDefaultBanner({ config })
127
+ },
128
+ resolveFooter: (node: RootNode) => {
129
+ if (typeof output?.footer === 'function') {
130
+ return output.footer(node)
131
+ }
132
+ if (typeof output?.footer === 'string') {
133
+ return output.footer
134
+ }
135
+ return undefined
136
+ },
54
137
  }
55
138
  }
@@ -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
@@ -9,8 +9,7 @@ export { defineLogger } from './defineLogger.ts'
9
9
  export { definePlugin } from './definePlugin.ts'
10
10
  export { defineStorage } from './defineStorage.ts'
11
11
  export { PackageManager } from './PackageManager.ts'
12
- export { getMode, PluginManager } from './PluginManager.ts'
13
- export { PromiseManager } from './PromiseManager.ts'
12
+ export { getMode, PluginDriver } from './PluginDriver.ts'
14
13
  export { fsStorage } from './storages/fsStorage.ts'
15
14
  export { memoryStorage } from './storages/memoryStorage.ts'
16
15
  export * from './types.ts'
package/src/types.ts CHANGED
@@ -4,7 +4,7 @@ import type { Fabric as FabricType, KubbFile } from '@kubb/fabric-core/types'
4
4
  import type { DEFAULT_STUDIO_URL, logLevel } from './constants.ts'
5
5
  import type { DefineStorage } from './defineStorage.ts'
6
6
  import type { KubbEvents } from './Kubb.ts'
7
- import type { PluginManager } from './PluginManager.ts'
7
+ import type { PluginDriver } from './PluginDriver.ts'
8
8
 
9
9
  export type { Printer, PrinterFactoryOptions } from '@kubb/ast/types'
10
10
 
@@ -32,7 +32,7 @@ export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins'
32
32
  /**
33
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.
34
34
  */
35
- // 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
36
36
  plugins?: Array<Omit<UnknownUserPlugin, 'inject'>>
37
37
  }
38
38
 
@@ -340,7 +340,7 @@ export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
340
340
 
341
341
  install: (this: PluginContext<TOptions>, context: PluginContext<TOptions>) => PossiblePromise<void>
342
342
  /**
343
- * Define a context that can be used by other plugins, see `PluginManager' where we convert from `UserPlugin` to `Plugin`(used when calling `definePlugin`).
343
+ * Define a context that can be used by other plugins, see `PluginDriver' where we convert from `UserPlugin` to `Plugin`(used when calling `definePlugin`).
344
344
  */
345
345
  inject: (this: PluginContext<TOptions>, context: PluginContext<TOptions>) => TOptions['context']
346
346
  }
@@ -400,7 +400,7 @@ export type ResolveNameParams = {
400
400
  export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
401
401
  fabric: FabricType
402
402
  config: Config
403
- pluginManager: PluginManager
403
+ driver: PluginDriver
404
404
  /**
405
405
  * Only add when the file does not exist yet
406
406
  */
@@ -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
@@ -1,7 +1,9 @@
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
5
  import type { BarrelType } from '../types.ts'
6
+ import { TreeNode } from './TreeNode.ts'
5
7
 
6
8
  export type FileMetaBase = {
7
9
  pluginName?: string
@@ -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) => {