@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/dist/{PluginManager-vZodFEMe.d.ts → PluginDriver-Dma9KhLK.d.ts} +7 -7
- package/dist/hooks.cjs +53 -11
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +15 -4
- package/dist/hooks.js +51 -10
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +79 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -39
- package/dist/index.js +79 -105
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Kubb.ts +1 -1
- package/src/{PluginManager.ts → PluginDriver.ts} +18 -22
- package/src/build.ts +21 -21
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useKubb.ts +90 -7
- package/src/hooks/usePluginDriver.ts +11 -0
- package/src/index.ts +1 -2
- package/src/types.ts +4 -4
- package/src/utils/TreeNode.ts +1 -1
- package/src/utils/getBarrelFiles.ts +71 -9
- package/src/BarrelManager.ts +0 -74
- package/src/PromiseManager.ts +0 -40
- package/src/hooks/usePluginManager.ts +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/core",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
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.
|
|
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,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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
114
|
+
return driver.rootNode
|
|
117
115
|
},
|
|
118
116
|
get adapter(): Adapter | undefined {
|
|
119
|
-
return
|
|
117
|
+
return driver.adapter
|
|
120
118
|
},
|
|
121
119
|
openInStudio(options?: DevtoolsOptions) {
|
|
122
|
-
if (!
|
|
120
|
+
if (!driver.config.devtools || driver.#studioIsOpen) {
|
|
123
121
|
return
|
|
124
122
|
}
|
|
125
123
|
|
|
126
|
-
if (typeof
|
|
124
|
+
if (typeof driver.config.devtools !== 'object') {
|
|
127
125
|
throw new Error('Devtools must be an object')
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
if (!
|
|
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
|
-
|
|
132
|
+
driver.#studioIsOpen = true
|
|
135
133
|
|
|
136
|
-
const studioUrl =
|
|
134
|
+
const studioUrl = driver.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL
|
|
137
135
|
|
|
138
|
-
return openInStudioFn(
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
183
|
-
|
|
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: ${
|
|
190
|
-
` • Operations: ${
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
233
|
+
const config = driver.config
|
|
234
234
|
|
|
235
235
|
try {
|
|
236
|
-
for (const plugin of
|
|
237
|
-
const context =
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
360
|
+
driver: PluginDriver
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
-
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config,
|
|
363
|
+
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): KubbFile.Export[] {
|
|
364
364
|
const pluginNameMap = new Map<string, Plugin>()
|
|
365
|
-
for (const plugin of
|
|
365
|
+
for (const plugin of driver.plugins) {
|
|
366
366
|
pluginNameMap.set(plugin.name, plugin)
|
|
367
367
|
}
|
|
368
368
|
|
package/src/hooks/index.ts
CHANGED
package/src/hooks/useKubb.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
|
50
|
-
getPluginByName: (pluginName = defaultPluginName) => meta.
|
|
51
|
-
getFile: ({ pluginName = defaultPluginName, ...rest }) => meta.
|
|
52
|
-
resolveName: ({ pluginName = defaultPluginName, ...rest }) => meta.
|
|
53
|
-
resolvePath: ({ pluginName = defaultPluginName, ...rest }) => meta.
|
|
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,
|
|
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 {
|
|
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
|
|
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 `
|
|
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
|
-
|
|
403
|
+
driver: PluginDriver
|
|
404
404
|
/**
|
|
405
405
|
* Only add when the file does not exist yet
|
|
406
406
|
*/
|
package/src/utils/TreeNode.ts
CHANGED
|
@@ -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 =
|
|
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) => {
|