@kubb/core 5.0.0-alpha.30 → 5.0.0-alpha.32
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/{PluginDriver-D110FoJ-.d.ts → PluginDriver-nm7tvGs9.d.ts} +336 -73
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +2 -3
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +374 -181
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +26 -149
- package/dist/index.js +377 -185
- package/dist/index.js.map +1 -1
- package/package.json +2 -4
- package/src/FileManager.ts +131 -0
- package/src/FileProcessor.ts +83 -0
- package/src/Kubb.ts +5 -5
- package/src/PluginDriver.ts +29 -23
- package/src/build.ts +118 -111
- package/src/constants.ts +7 -2
- package/src/{config.ts → defineConfig.ts} +2 -8
- package/src/defineGenerator.ts +12 -13
- package/src/defineParser.ts +57 -0
- package/src/defineResolver.ts +18 -22
- package/src/devtools.ts +14 -14
- package/src/hooks/useMode.ts +2 -3
- package/src/index.ts +3 -3
- package/src/renderNode.tsx +8 -7
- package/src/types.ts +103 -56
- package/src/utils/TreeNode.ts +7 -7
- package/src/utils/getBarrelFiles.ts +30 -28
- package/src/utils/getConfigs.ts +1 -1
- package/src/utils/isInputPath.ts +8 -0
package/src/build.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { dirname,
|
|
1
|
+
import { dirname, resolve } from 'node:path'
|
|
2
2
|
import { AsyncEventEmitter, BuildError, exists, formatMs, getElapsedMs, getRelativePath, URLPath } from '@internals/utils'
|
|
3
|
-
import { transform, walk } from '@kubb/ast'
|
|
4
|
-
import type { OperationNode } from '@kubb/ast/types'
|
|
5
|
-
import type { FabricFile, Fabric as FabricType } from '@kubb/fabric-core/types'
|
|
6
|
-
import { createFabric } from '@kubb/react-fabric'
|
|
7
|
-
import { typescriptParser } from '@kubb/react-fabric/parsers'
|
|
8
|
-
import { fsPlugin } from '@kubb/react-fabric/plugins'
|
|
9
|
-
import { isInputPath } from './config.ts'
|
|
3
|
+
import { createExport, createFile, transform, walk } from '@kubb/ast'
|
|
4
|
+
import type { ExportNode, FileNode, OperationNode } from '@kubb/ast/types'
|
|
10
5
|
import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
6
|
+
import type { Parser } from './defineParser.ts'
|
|
7
|
+
import { FileProcessor } from './FileProcessor.ts'
|
|
11
8
|
import { PluginDriver } from './PluginDriver.ts'
|
|
12
9
|
import { applyHookResult } from './renderNode.tsx'
|
|
13
10
|
import { fsStorage } from './storages/fsStorage.ts'
|
|
@@ -15,6 +12,7 @@ import type { AdapterSource, Config, KubbEvents, Plugin, PluginContext, Storage,
|
|
|
15
12
|
import { getDiagnosticInfo } from './utils/diagnostics.ts'
|
|
16
13
|
import type { FileMetaBase } from './utils/getBarrelFiles.ts'
|
|
17
14
|
import { getBarrelFiles } from './utils/getBarrelFiles.ts'
|
|
15
|
+
import { isInputPath } from './utils/isInputPath.ts'
|
|
18
16
|
|
|
19
17
|
type BuildOptions = {
|
|
20
18
|
config: UserConfig
|
|
@@ -29,8 +27,7 @@ type BuildOutput = {
|
|
|
29
27
|
* Plugins that threw during installation, paired with the caught error.
|
|
30
28
|
*/
|
|
31
29
|
failedPlugins: Set<{ plugin: Plugin; error: Error }>
|
|
32
|
-
|
|
33
|
-
files: Array<FabricFile.ResolvedFile>
|
|
30
|
+
files: Array<FileNode>
|
|
34
31
|
driver: PluginDriver
|
|
35
32
|
/**
|
|
36
33
|
* Elapsed time in milliseconds for each plugin, keyed by plugin name.
|
|
@@ -40,7 +37,7 @@ type BuildOutput = {
|
|
|
40
37
|
/**
|
|
41
38
|
* Raw generated source, keyed by absolute file path.
|
|
42
39
|
*/
|
|
43
|
-
sources: Map<
|
|
40
|
+
sources: Map<string, string>
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
/**
|
|
@@ -48,9 +45,10 @@ type BuildOutput = {
|
|
|
48
45
|
*/
|
|
49
46
|
type SetupResult = {
|
|
50
47
|
events: AsyncEventEmitter<KubbEvents>
|
|
51
|
-
fabric: FabricType
|
|
52
48
|
driver: PluginDriver
|
|
53
|
-
sources: Map<
|
|
49
|
+
sources: Map<string, string>
|
|
50
|
+
config: Config
|
|
51
|
+
storage: Storage | null
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
/**
|
|
@@ -59,7 +57,8 @@ type SetupResult = {
|
|
|
59
57
|
* - Validates the input path (when applicable).
|
|
60
58
|
* - Applies config defaults (`root`, `output.*`, `devtools`).
|
|
61
59
|
* - Creates the Fabric instance and wires storage, format, and lint hooks.
|
|
62
|
-
* - Runs the adapter (if configured) to produce the universal `
|
|
60
|
+
* - Runs the adapter (if configured) to produce the universal `InputNode`.
|
|
61
|
+
* When no adapter is supplied and `@kubb/adapter-oas` is installed as an
|
|
63
62
|
*
|
|
64
63
|
* Pass the returned {@link SetupResult} directly to {@link safeBuild} or {@link build}
|
|
65
64
|
* via the `overrides` argument to reuse the same infrastructure across multiple runs.
|
|
@@ -67,7 +66,7 @@ type SetupResult = {
|
|
|
67
66
|
export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
68
67
|
const { config: userConfig, events = new AsyncEventEmitter<KubbEvents>() } = options
|
|
69
68
|
|
|
70
|
-
const sources: Map<
|
|
69
|
+
const sources: Map<string, string> = new Map<string, string>()
|
|
71
70
|
const diagnosticInfo = getDiagnosticInfo()
|
|
72
71
|
|
|
73
72
|
if (Array.isArray(userConfig.input)) {
|
|
@@ -115,9 +114,15 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
116
|
|
|
118
|
-
|
|
117
|
+
if (!userConfig.adapter) {
|
|
118
|
+
throw new Error('Adapter should be defined')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const config: Config = {
|
|
119
122
|
root: userConfig.root || process.cwd(),
|
|
120
123
|
...userConfig,
|
|
124
|
+
parsers: userConfig.parsers ?? [],
|
|
125
|
+
adapter: userConfig.adapter,
|
|
121
126
|
output: {
|
|
122
127
|
write: true,
|
|
123
128
|
barrelType: 'named',
|
|
@@ -136,96 +141,54 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
136
141
|
|
|
137
142
|
// write: false is the explicit dry-run opt-out; otherwise use the provided
|
|
138
143
|
// storage or fall back to fsStorage (backwards-compatible default).
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
const storage: Storage | null =
|
|
144
|
+
// Storage keys are the absolute file.path values so fsStorage() resolves
|
|
145
|
+
// them correctly regardless of the current working directory.
|
|
146
|
+
const storage: Storage | null = config.output.write === false ? null : (config.output.storage ?? fsStorage())
|
|
142
147
|
|
|
143
|
-
if (
|
|
148
|
+
if (config.output.clean) {
|
|
144
149
|
await events.emit('debug', {
|
|
145
150
|
date: new Date(),
|
|
146
|
-
logs: ['Cleaning output directories', ` • Output: ${
|
|
151
|
+
logs: ['Cleaning output directories', ` • Output: ${config.output.path}`],
|
|
147
152
|
})
|
|
148
|
-
await storage?.clear(resolve(
|
|
153
|
+
await storage?.clear(resolve(config.root, config.output.path))
|
|
149
154
|
}
|
|
150
155
|
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
fabric.context.on('files:processing:start', (files) => {
|
|
156
|
-
events.emit('files:processing:start', files)
|
|
157
|
-
events.emit('debug', {
|
|
158
|
-
date: new Date(),
|
|
159
|
-
logs: [`Writing ${files.length} files...`],
|
|
160
|
-
})
|
|
156
|
+
const driver = new PluginDriver(config, {
|
|
157
|
+
events,
|
|
158
|
+
concurrency: DEFAULT_CONCURRENCY,
|
|
161
159
|
})
|
|
162
160
|
|
|
163
|
-
|
|
164
|
-
const { file, source } = params
|
|
165
|
-
await events.emit('file:processing:update', {
|
|
166
|
-
...params,
|
|
167
|
-
config: definedConfig,
|
|
168
|
-
source,
|
|
169
|
-
})
|
|
161
|
+
// Run the adapter to produce the universal InputNode.
|
|
170
162
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
})
|
|
163
|
+
const adapter = config.adapter
|
|
164
|
+
if (!adapter) {
|
|
165
|
+
throw new Error('No adapter configured. Please provide an adapter in your kubb.config.ts.')
|
|
166
|
+
}
|
|
167
|
+
const source = inputToAdapterSource(config)
|
|
178
168
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
date: new Date(),
|
|
183
|
-
logs: [`✓ File write process completed for ${files.length} files`],
|
|
184
|
-
})
|
|
169
|
+
await events.emit('debug', {
|
|
170
|
+
date: new Date(),
|
|
171
|
+
logs: [`Running adapter: ${adapter.name}`],
|
|
185
172
|
})
|
|
186
173
|
|
|
174
|
+
driver.adapter = adapter
|
|
175
|
+
driver.inputNode = await adapter.parse(source)
|
|
176
|
+
|
|
187
177
|
await events.emit('debug', {
|
|
188
178
|
date: new Date(),
|
|
189
179
|
logs: [
|
|
190
|
-
'
|
|
191
|
-
` •
|
|
192
|
-
` •
|
|
180
|
+
`✓ Adapter '${adapter.name}' resolved InputNode`,
|
|
181
|
+
` • Schemas: ${driver.inputNode.schemas.length}`,
|
|
182
|
+
` • Operations: ${driver.inputNode.operations.length}`,
|
|
193
183
|
],
|
|
194
184
|
})
|
|
195
185
|
|
|
196
|
-
const pluginDriver = new PluginDriver(definedConfig, {
|
|
197
|
-
fabric,
|
|
198
|
-
events,
|
|
199
|
-
concurrency: DEFAULT_CONCURRENCY,
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
// Run the adapter (if provided) to produce the universal RootNode
|
|
203
|
-
if (definedConfig.adapter) {
|
|
204
|
-
const source = inputToAdapterSource(definedConfig)
|
|
205
|
-
|
|
206
|
-
await events.emit('debug', {
|
|
207
|
-
date: new Date(),
|
|
208
|
-
logs: [`Running adapter: ${definedConfig.adapter.name}`],
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
pluginDriver.adapter = definedConfig.adapter
|
|
212
|
-
pluginDriver.rootNode = await definedConfig.adapter.parse(source)
|
|
213
|
-
|
|
214
|
-
await events.emit('debug', {
|
|
215
|
-
date: new Date(),
|
|
216
|
-
logs: [
|
|
217
|
-
`✓ Adapter '${definedConfig.adapter.name}' resolved RootNode`,
|
|
218
|
-
` • Schemas: ${pluginDriver.rootNode.schemas.length}`,
|
|
219
|
-
` • Operations: ${pluginDriver.rootNode.operations.length}`,
|
|
220
|
-
],
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
|
|
224
186
|
return {
|
|
187
|
+
config,
|
|
225
188
|
events,
|
|
226
|
-
|
|
227
|
-
driver: pluginDriver,
|
|
189
|
+
driver,
|
|
228
190
|
sources,
|
|
191
|
+
storage,
|
|
229
192
|
}
|
|
230
193
|
}
|
|
231
194
|
|
|
@@ -236,7 +199,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
236
199
|
* Pass an existing {@link SetupResult} via `overrides` to skip the setup phase.
|
|
237
200
|
*/
|
|
238
201
|
export async function build(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
239
|
-
const {
|
|
202
|
+
const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides)
|
|
240
203
|
|
|
241
204
|
if (error) {
|
|
242
205
|
throw error
|
|
@@ -250,7 +213,6 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
|
|
|
250
213
|
|
|
251
214
|
return {
|
|
252
215
|
failedPlugins,
|
|
253
|
-
fabric,
|
|
254
216
|
files,
|
|
255
217
|
driver,
|
|
256
218
|
pluginTimings,
|
|
@@ -266,20 +228,20 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
|
|
|
266
228
|
* - Each hook accepts a single handler **or an array** — all entries are called in sequence.
|
|
267
229
|
* - Nodes that are excluded by `exclude`/`include` plugin options are skipped automatically.
|
|
268
230
|
* - Return values are handled via `applyHookResult`: React elements are rendered,
|
|
269
|
-
* `
|
|
231
|
+
* `FileNode[]` are written via upsert, and `void` is a no-op (manual handling).
|
|
270
232
|
* - Barrel files are generated automatically when `output.barrelType` is set.
|
|
271
233
|
*/
|
|
272
234
|
async function runPluginAstHooks(plugin: Plugin, context: PluginContext): Promise<void> {
|
|
273
|
-
const { adapter,
|
|
235
|
+
const { adapter, inputNode, resolver, driver } = context
|
|
274
236
|
const { exclude, include, override } = plugin.options
|
|
275
237
|
|
|
276
|
-
if (!adapter || !
|
|
238
|
+
if (!adapter || !inputNode) {
|
|
277
239
|
throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`)
|
|
278
240
|
}
|
|
279
241
|
|
|
280
242
|
const collectedOperations: Array<OperationNode> = []
|
|
281
243
|
|
|
282
|
-
await walk(
|
|
244
|
+
await walk(inputNode, {
|
|
283
245
|
depth: 'shallow',
|
|
284
246
|
async schema(node) {
|
|
285
247
|
if (!plugin.schema) return
|
|
@@ -288,7 +250,7 @@ async function runPluginAstHooks(plugin: Plugin, context: PluginContext): Promis
|
|
|
288
250
|
if (options === null) return
|
|
289
251
|
const result = await plugin.schema.call(context, transformedNode, options)
|
|
290
252
|
|
|
291
|
-
await applyHookResult(result,
|
|
253
|
+
await applyHookResult(result, driver)
|
|
292
254
|
},
|
|
293
255
|
async operation(node) {
|
|
294
256
|
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
|
|
@@ -297,7 +259,7 @@ async function runPluginAstHooks(plugin: Plugin, context: PluginContext): Promis
|
|
|
297
259
|
collectedOperations.push(transformedNode)
|
|
298
260
|
if (plugin.operation) {
|
|
299
261
|
const result = await plugin.operation.call(context, transformedNode, options)
|
|
300
|
-
await applyHookResult(result,
|
|
262
|
+
await applyHookResult(result, driver)
|
|
301
263
|
}
|
|
302
264
|
}
|
|
303
265
|
},
|
|
@@ -306,7 +268,7 @@ async function runPluginAstHooks(plugin: Plugin, context: PluginContext): Promis
|
|
|
306
268
|
if (plugin.operations && collectedOperations.length > 0) {
|
|
307
269
|
const result = await plugin.operations.call(context, collectedOperations, plugin.options)
|
|
308
270
|
|
|
309
|
-
await applyHookResult(result,
|
|
271
|
+
await applyHookResult(result, driver)
|
|
310
272
|
}
|
|
311
273
|
}
|
|
312
274
|
|
|
@@ -315,13 +277,14 @@ async function runPluginAstHooks(plugin: Plugin, context: PluginContext): Promis
|
|
|
315
277
|
*
|
|
316
278
|
* - Installs each plugin in order, recording failures in `failedPlugins`.
|
|
317
279
|
* - Generates the root barrel file when `output.barrelType` is set.
|
|
318
|
-
* - Writes all files through
|
|
280
|
+
* - Writes all files through the driver's FileManager and FileProcessor.
|
|
319
281
|
*
|
|
320
282
|
* Returns a {@link BuildOutput} even on failure — inspect `error` and
|
|
321
283
|
* `failedPlugins` to determine whether the build succeeded.
|
|
322
284
|
*/
|
|
323
285
|
export async function safeBuild(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
324
|
-
const
|
|
286
|
+
const setupResult = overrides ? overrides : await setup(options)
|
|
287
|
+
const { driver, events, sources, storage } = setupResult
|
|
325
288
|
|
|
326
289
|
const failedPlugins = new Set<{ plugin: Plugin; error: Error }>()
|
|
327
290
|
// in ms
|
|
@@ -354,7 +317,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
354
317
|
}
|
|
355
318
|
|
|
356
319
|
if (output) {
|
|
357
|
-
const barrelFiles = await getBarrelFiles(
|
|
320
|
+
const barrelFiles = await getBarrelFiles(driver.fileManager.files, {
|
|
358
321
|
type: output.barrelType ?? 'named',
|
|
359
322
|
root,
|
|
360
323
|
output,
|
|
@@ -408,7 +371,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
408
371
|
logs: ['Generating barrel file', ` • Type: ${config.output.barrelType}`, ` • Path: ${rootPath}`],
|
|
409
372
|
})
|
|
410
373
|
|
|
411
|
-
const barrelFiles =
|
|
374
|
+
const barrelFiles = driver.fileManager.files.filter((file) => {
|
|
412
375
|
return file.sources.some((source) => source.isIndexable)
|
|
413
376
|
})
|
|
414
377
|
|
|
@@ -417,21 +380,21 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
417
380
|
logs: [`Found ${barrelFiles.length} indexable files for barrel export`],
|
|
418
381
|
})
|
|
419
382
|
|
|
420
|
-
const existingBarrel =
|
|
383
|
+
const existingBarrel = driver.fileManager.files.find((f) => f.path === rootPath)
|
|
421
384
|
const existingExports = new Set(
|
|
422
385
|
existingBarrel?.exports?.flatMap((e) => (Array.isArray(e.name) ? e.name : [e.name])).filter((n): n is string => Boolean(n)) ?? [],
|
|
423
386
|
)
|
|
424
387
|
|
|
425
|
-
const rootFile
|
|
388
|
+
const rootFile = createFile<object>({
|
|
426
389
|
path: rootPath,
|
|
427
390
|
baseName: BARREL_FILENAME,
|
|
428
|
-
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }),
|
|
391
|
+
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }).map((e) => createExport(e)),
|
|
429
392
|
sources: [],
|
|
430
393
|
imports: [],
|
|
431
394
|
meta: {},
|
|
432
|
-
}
|
|
395
|
+
})
|
|
433
396
|
|
|
434
|
-
|
|
397
|
+
driver.fileManager.upsert(rootFile)
|
|
435
398
|
|
|
436
399
|
await events.emit('debug', {
|
|
437
400
|
date: new Date(),
|
|
@@ -439,9 +402,55 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
439
402
|
})
|
|
440
403
|
}
|
|
441
404
|
|
|
442
|
-
const files =
|
|
405
|
+
const files = driver.fileManager.files
|
|
406
|
+
|
|
407
|
+
// Build a parsers map from config.parsers
|
|
408
|
+
const parsersMap = new Map<FileNode['extname'], Parser>()
|
|
409
|
+
for (const parser of config.parsers) {
|
|
410
|
+
if (parser.extNames) {
|
|
411
|
+
for (const extname of parser.extNames) {
|
|
412
|
+
parsersMap.set(extname, parser)
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
443
416
|
|
|
444
|
-
|
|
417
|
+
const fileProcessor = new FileProcessor()
|
|
418
|
+
|
|
419
|
+
await events.emit('debug', {
|
|
420
|
+
date: new Date(),
|
|
421
|
+
logs: [`Writing ${files.length} files...`],
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
await fileProcessor.run(files, {
|
|
425
|
+
parsers: parsersMap,
|
|
426
|
+
extension: config.output.extension,
|
|
427
|
+
onStart: async (processingFiles) => {
|
|
428
|
+
await events.emit('files:processing:start', processingFiles)
|
|
429
|
+
},
|
|
430
|
+
onUpdate: async ({ file, source, processed, total, percentage }) => {
|
|
431
|
+
await events.emit('file:processing:update', {
|
|
432
|
+
file,
|
|
433
|
+
source,
|
|
434
|
+
processed,
|
|
435
|
+
total,
|
|
436
|
+
percentage,
|
|
437
|
+
config,
|
|
438
|
+
})
|
|
439
|
+
if (source) {
|
|
440
|
+
// Use the absolute file.path as the storage key so fsStorage resolves
|
|
441
|
+
// it correctly regardless of the current working directory.
|
|
442
|
+
await storage?.setItem(file.path, source)
|
|
443
|
+
sources.set(file.path, source)
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
onEnd: async (processedFiles) => {
|
|
447
|
+
await events.emit('files:processing:end', processedFiles)
|
|
448
|
+
await events.emit('debug', {
|
|
449
|
+
date: new Date(),
|
|
450
|
+
logs: [`✓ File write process completed for ${processedFiles.length} files`],
|
|
451
|
+
})
|
|
452
|
+
},
|
|
453
|
+
})
|
|
445
454
|
|
|
446
455
|
// Call buildEnd() on each plugin after all files are written
|
|
447
456
|
for (const plugin of driver.plugins.values()) {
|
|
@@ -453,7 +462,6 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
453
462
|
|
|
454
463
|
return {
|
|
455
464
|
failedPlugins,
|
|
456
|
-
fabric,
|
|
457
465
|
files,
|
|
458
466
|
driver,
|
|
459
467
|
pluginTimings,
|
|
@@ -462,7 +470,6 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
462
470
|
} catch (error) {
|
|
463
471
|
return {
|
|
464
472
|
failedPlugins,
|
|
465
|
-
fabric,
|
|
466
473
|
files: [],
|
|
467
474
|
driver,
|
|
468
475
|
pluginTimings,
|
|
@@ -473,14 +480,14 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
473
480
|
}
|
|
474
481
|
|
|
475
482
|
type BuildBarrelExportsParams = {
|
|
476
|
-
barrelFiles:
|
|
483
|
+
barrelFiles: FileNode[]
|
|
477
484
|
rootDir: string
|
|
478
485
|
existingExports: Set<string>
|
|
479
486
|
config: Config
|
|
480
487
|
driver: PluginDriver
|
|
481
488
|
}
|
|
482
489
|
|
|
483
|
-
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams):
|
|
490
|
+
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): ExportNode[] {
|
|
484
491
|
const pluginNameMap = new Map<string, Plugin>()
|
|
485
492
|
for (const plugin of driver.plugins.values()) {
|
|
486
493
|
pluginNameMap.set(plugin.name, plugin)
|
|
@@ -508,11 +515,11 @@ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, dri
|
|
|
508
515
|
}
|
|
509
516
|
|
|
510
517
|
return [
|
|
511
|
-
{
|
|
518
|
+
createExport({
|
|
512
519
|
name: exportName,
|
|
513
520
|
path: getRelativePath(rootDir, file.path),
|
|
514
521
|
isTypeOnly: config.output.barrelType === 'all' ? containsOnlyTypes : source.isTypeOnly,
|
|
515
|
-
}
|
|
522
|
+
}),
|
|
516
523
|
]
|
|
517
524
|
})
|
|
518
525
|
})
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FileNode } from '@kubb/ast/types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Base URL for the Kubb Studio web app.
|
|
@@ -10,6 +10,11 @@ export const DEFAULT_STUDIO_URL = 'https://studio.kubb.dev' as const
|
|
|
10
10
|
*/
|
|
11
11
|
export const DEFAULT_CONCURRENCY = 15
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Maximum number of files processed in parallel by FileProcessor.
|
|
15
|
+
*/
|
|
16
|
+
export const PARALLEL_CONCURRENCY_LIMIT = 100
|
|
17
|
+
|
|
13
18
|
/**
|
|
14
19
|
* File name used for generated barrel (index) files.
|
|
15
20
|
*/
|
|
@@ -23,7 +28,7 @@ export const DEFAULT_BANNER = 'simple' as const
|
|
|
23
28
|
/**
|
|
24
29
|
* Default file-extension mapping used when no explicit mapping is configured.
|
|
25
30
|
*/
|
|
26
|
-
export const DEFAULT_EXTENSION: Record<
|
|
31
|
+
export const DEFAULT_EXTENSION: Record<FileNode['extname'], FileNode['extname'] | ''> = { '.ts': '.ts' }
|
|
27
32
|
|
|
28
33
|
/**
|
|
29
34
|
* Characters recognized as path separators on both POSIX and Windows.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PossiblePromise } from '@internals/utils'
|
|
2
|
-
import type {
|
|
2
|
+
import type { UserConfig } from './types.ts'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* CLI options derived from command-line flags.
|
|
@@ -42,16 +42,10 @@ export type ConfigInput = PossiblePromise<UserConfig | UserConfig[]> | ((cli: CL
|
|
|
42
42
|
* root: 'src',
|
|
43
43
|
* plugins: [myPlugin()],
|
|
44
44
|
* }))
|
|
45
|
+
* @deprecated as of Kubb v5, @kubb/core will not expose `defineConfig` anymore. use the `kubb` package instead
|
|
45
46
|
*/
|
|
46
47
|
export function defineConfig(config: (cli: CLIOptions) => PossiblePromise<UserConfig | UserConfig[]>): typeof config
|
|
47
48
|
export function defineConfig(config: PossiblePromise<UserConfig | UserConfig[]>): typeof config
|
|
48
49
|
export function defineConfig(config: ConfigInput): ConfigInput {
|
|
49
50
|
return config
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Type guard to check if a given config has an `input.path`.
|
|
54
|
-
*/
|
|
55
|
-
export function isInputPath(config: UserConfig | undefined): config is UserConfig<InputPath> {
|
|
56
|
-
return typeof config?.input === 'object' && config.input !== null && 'path' in config.input
|
|
57
|
-
}
|
package/src/defineGenerator.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { PossiblePromise } from '@internals/utils'
|
|
2
|
-
import type { OperationNode, SchemaNode } from '@kubb/ast/types'
|
|
3
|
-
import type { FabricFile } from '@kubb/fabric-core/types'
|
|
2
|
+
import type { FileNode, OperationNode, SchemaNode } from '@kubb/ast/types'
|
|
4
3
|
import type { FabricReactNode } from '@kubb/react-fabric/types'
|
|
5
4
|
import { applyHookResult } from './renderNode.tsx'
|
|
6
5
|
import type { GeneratorContext, PluginFactoryOptions } from './types.ts'
|
|
@@ -10,10 +9,10 @@ export type { GeneratorContext } from './types.ts'
|
|
|
10
9
|
/**
|
|
11
10
|
* A generator is a named object with optional `schema`, `operation`, and `operations`
|
|
12
11
|
* methods. Each method is called with `this = PluginContext` of the parent plugin,
|
|
13
|
-
* giving full access to `this.config`, `this.resolver`, `this.adapter`,
|
|
12
|
+
* giving full access to `this.config`, `this.resolver`, `this.adapter`,
|
|
14
13
|
* `this.driver`, etc.
|
|
15
14
|
*
|
|
16
|
-
* Return a React element, an array of `
|
|
15
|
+
* Return a React element, an array of `FileNode`, or `void` to handle file
|
|
17
16
|
* writing manually via `this.upsertFile`. Both React and core (non-React) generators
|
|
18
17
|
* use the same method signatures — the return type determines how output is handled.
|
|
19
18
|
*
|
|
@@ -36,32 +35,32 @@ export type Generator<TOptions extends PluginFactoryOptions = PluginFactoryOptio
|
|
|
36
35
|
name: string
|
|
37
36
|
/**
|
|
38
37
|
* Called for each schema node in the AST walk.
|
|
39
|
-
* `this` is the parent plugin's context with `adapter` and `
|
|
38
|
+
* `this` is the parent plugin's context with `adapter` and `inputNode` guaranteed present.
|
|
40
39
|
* `options` contains the per-node resolved options (after exclude/include/override).
|
|
41
40
|
*/
|
|
42
41
|
schema?: (
|
|
43
42
|
this: GeneratorContext<TOptions>,
|
|
44
43
|
node: SchemaNode,
|
|
45
44
|
options: TOptions['resolvedOptions'],
|
|
46
|
-
) => PossiblePromise<FabricReactNode | Array<
|
|
45
|
+
) => PossiblePromise<FabricReactNode | Array<FileNode> | void>
|
|
47
46
|
/**
|
|
48
47
|
* Called for each operation node in the AST walk.
|
|
49
|
-
* `this` is the parent plugin's context with `adapter` and `
|
|
48
|
+
* `this` is the parent plugin's context with `adapter` and `inputNode` guaranteed present.
|
|
50
49
|
*/
|
|
51
50
|
operation?: (
|
|
52
51
|
this: GeneratorContext<TOptions>,
|
|
53
52
|
node: OperationNode,
|
|
54
53
|
options: TOptions['resolvedOptions'],
|
|
55
|
-
) => PossiblePromise<FabricReactNode | Array<
|
|
54
|
+
) => PossiblePromise<FabricReactNode | Array<FileNode> | void>
|
|
56
55
|
/**
|
|
57
56
|
* Called once after all operations have been walked.
|
|
58
|
-
* `this` is the parent plugin's context with `adapter` and `
|
|
57
|
+
* `this` is the parent plugin's context with `adapter` and `inputNode` guaranteed present.
|
|
59
58
|
*/
|
|
60
59
|
operations?: (
|
|
61
60
|
this: GeneratorContext<TOptions>,
|
|
62
61
|
nodes: Array<OperationNode>,
|
|
63
62
|
options: TOptions['resolvedOptions'],
|
|
64
|
-
) => PossiblePromise<FabricReactNode | Array<
|
|
63
|
+
) => PossiblePromise<FabricReactNode | Array<FileNode> | void>
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
/**
|
|
@@ -103,7 +102,7 @@ export function mergeGenerators<TOptions extends PluginFactoryOptions = PluginFa
|
|
|
103
102
|
if (!gen.schema) continue
|
|
104
103
|
const result = await gen.schema.call(this, node, options)
|
|
105
104
|
|
|
106
|
-
await applyHookResult(result, this.
|
|
105
|
+
await applyHookResult(result, this.driver)
|
|
107
106
|
}
|
|
108
107
|
},
|
|
109
108
|
async operation(node, options) {
|
|
@@ -111,7 +110,7 @@ export function mergeGenerators<TOptions extends PluginFactoryOptions = PluginFa
|
|
|
111
110
|
if (!gen.operation) continue
|
|
112
111
|
const result = await gen.operation.call(this, node, options)
|
|
113
112
|
|
|
114
|
-
await applyHookResult(result, this.
|
|
113
|
+
await applyHookResult(result, this.driver)
|
|
115
114
|
}
|
|
116
115
|
},
|
|
117
116
|
async operations(nodes, options) {
|
|
@@ -119,7 +118,7 @@ export function mergeGenerators<TOptions extends PluginFactoryOptions = PluginFa
|
|
|
119
118
|
if (!gen.operations) continue
|
|
120
119
|
const result = await gen.operations.call(this, nodes, options)
|
|
121
120
|
|
|
122
|
-
await applyHookResult(result, this.
|
|
121
|
+
await applyHookResult(result, this.driver)
|
|
123
122
|
}
|
|
124
123
|
},
|
|
125
124
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { FileNode } from '@kubb/ast/types'
|
|
2
|
+
|
|
3
|
+
type PrintOptions = {
|
|
4
|
+
extname?: FileNode['extname']
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type Parser<TMeta extends object = any> = {
|
|
8
|
+
name: string
|
|
9
|
+
type: 'parser'
|
|
10
|
+
/**
|
|
11
|
+
* File extensions this parser handles.
|
|
12
|
+
* Use `undefined` to create a catch-all fallback parser.
|
|
13
|
+
*
|
|
14
|
+
* @example ['.ts', '.js']
|
|
15
|
+
*/
|
|
16
|
+
extNames: Array<FileNode['extname']> | undefined
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Will be removed once Fabric no longer requires it.
|
|
19
|
+
* @default () => {}
|
|
20
|
+
*/
|
|
21
|
+
install(...args: unknown[]): void | Promise<void>
|
|
22
|
+
/**
|
|
23
|
+
* Convert a resolved file to a string.
|
|
24
|
+
*/
|
|
25
|
+
parse(file: FileNode<TMeta>, options?: PrintOptions): Promise<string> | string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type UserParser<TMeta extends object = any> = Omit<Parser<TMeta>, 'type' | 'install'> & {
|
|
29
|
+
install?(...args: unknown[]): void | Promise<void>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Defines a parser with type safety.
|
|
34
|
+
*
|
|
35
|
+
* Use this function to create parsers that transform generated files to strings
|
|
36
|
+
* based on their extension.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { defineParser } from '@kubb/core'
|
|
41
|
+
*
|
|
42
|
+
* export const jsonParser = defineParser({
|
|
43
|
+
* name: 'json',
|
|
44
|
+
* extNames: ['.json'],
|
|
45
|
+
* parse(file) {
|
|
46
|
+
* return file.sources.map((s) => s.value).join('\n')
|
|
47
|
+
* },
|
|
48
|
+
* })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function defineParser<TMeta extends object = any>(parser: UserParser<TMeta>): Parser<TMeta> {
|
|
52
|
+
return {
|
|
53
|
+
install() {},
|
|
54
|
+
type: 'parser',
|
|
55
|
+
...parser,
|
|
56
|
+
}
|
|
57
|
+
}
|