@kubb/core 5.0.0-alpha.3 → 5.0.0-alpha.30
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 +1632 -0
- package/dist/hooks.cjs +12 -27
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +11 -36
- package/dist/hooks.js +13 -27
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +1410 -823
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +597 -95
- package/dist/index.js +1391 -818
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/Kubb.ts +40 -58
- package/src/{PluginManager.ts → PluginDriver.ts} +165 -177
- package/src/build.ts +167 -44
- package/src/config.ts +9 -8
- package/src/constants.ts +40 -7
- package/src/createAdapter.ts +25 -0
- package/src/createPlugin.ts +30 -0
- package/src/createStorage.ts +58 -0
- package/src/defineGenerator.ts +126 -0
- package/src/defineLogger.ts +13 -3
- package/src/definePresets.ts +16 -0
- package/src/defineResolver.ts +457 -0
- package/src/hooks/index.ts +1 -6
- package/src/hooks/useDriver.ts +11 -0
- package/src/hooks/useMode.ts +5 -5
- package/src/hooks/usePlugin.ts +3 -3
- package/src/index.ts +18 -7
- package/src/renderNode.tsx +25 -0
- package/src/storages/fsStorage.ts +2 -2
- package/src/storages/memoryStorage.ts +2 -2
- package/src/types.ts +589 -52
- package/src/utils/FunctionParams.ts +2 -2
- package/src/utils/TreeNode.ts +45 -7
- package/src/utils/diagnostics.ts +4 -1
- package/src/utils/executeStrategies.ts +29 -10
- package/src/utils/formatters.ts +10 -21
- package/src/utils/getBarrelFiles.ts +83 -10
- package/src/utils/getConfigs.ts +8 -22
- package/src/utils/getPreset.ts +78 -0
- package/src/utils/linters.ts +23 -3
- package/src/utils/packageJSON.ts +76 -0
- package/dist/types-CiPWLv-5.d.ts +0 -1001
- package/src/BarrelManager.ts +0 -74
- package/src/PackageManager.ts +0 -180
- package/src/PromiseManager.ts +0 -40
- package/src/defineAdapter.ts +0 -22
- package/src/definePlugin.ts +0 -12
- package/src/defineStorage.ts +0 -56
- package/src/errors.ts +0 -1
- package/src/hooks/useKubb.ts +0 -22
- package/src/hooks/usePluginManager.ts +0 -11
- package/src/utils/getPlugins.ts +0 -23
package/src/build.ts
CHANGED
|
@@ -1,45 +1,73 @@
|
|
|
1
1
|
import { dirname, relative, resolve } from 'node:path'
|
|
2
|
-
import { AsyncEventEmitter, exists, formatMs, getElapsedMs, getRelativePath, URLPath } from '@internals/utils'
|
|
3
|
-
import
|
|
4
|
-
import type {
|
|
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'
|
|
5
6
|
import { createFabric } from '@kubb/react-fabric'
|
|
6
7
|
import { typescriptParser } from '@kubb/react-fabric/parsers'
|
|
7
8
|
import { fsPlugin } from '@kubb/react-fabric/plugins'
|
|
8
9
|
import { isInputPath } from './config.ts'
|
|
9
10
|
import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
11
|
+
import { PluginDriver } from './PluginDriver.ts'
|
|
12
|
+
import { applyHookResult } from './renderNode.tsx'
|
|
12
13
|
import { fsStorage } from './storages/fsStorage.ts'
|
|
13
|
-
import type { AdapterSource, Config,
|
|
14
|
+
import type { AdapterSource, Config, KubbEvents, Plugin, PluginContext, Storage, UserConfig } from './types.ts'
|
|
14
15
|
import { getDiagnosticInfo } from './utils/diagnostics.ts'
|
|
15
16
|
import type { FileMetaBase } from './utils/getBarrelFiles.ts'
|
|
17
|
+
import { getBarrelFiles } from './utils/getBarrelFiles.ts'
|
|
16
18
|
|
|
17
19
|
type BuildOptions = {
|
|
18
20
|
config: UserConfig
|
|
19
21
|
events?: AsyncEventEmitter<KubbEvents>
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Full output produced by a successful or failed build.
|
|
26
|
+
*/
|
|
22
27
|
type BuildOutput = {
|
|
28
|
+
/**
|
|
29
|
+
* Plugins that threw during installation, paired with the caught error.
|
|
30
|
+
*/
|
|
23
31
|
failedPlugins: Set<{ plugin: Plugin; error: Error }>
|
|
24
|
-
fabric:
|
|
25
|
-
files: Array<
|
|
26
|
-
|
|
32
|
+
fabric: FabricType
|
|
33
|
+
files: Array<FabricFile.ResolvedFile>
|
|
34
|
+
driver: PluginDriver
|
|
35
|
+
/**
|
|
36
|
+
* Elapsed time in milliseconds for each plugin, keyed by plugin name.
|
|
37
|
+
*/
|
|
27
38
|
pluginTimings: Map<string, number>
|
|
28
39
|
error?: Error
|
|
29
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Raw generated source, keyed by absolute file path.
|
|
42
|
+
*/
|
|
43
|
+
sources: Map<FabricFile.Path, string>
|
|
30
44
|
}
|
|
31
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Intermediate result returned by {@link setup} and accepted by {@link safeBuild}.
|
|
48
|
+
*/
|
|
32
49
|
type SetupResult = {
|
|
33
50
|
events: AsyncEventEmitter<KubbEvents>
|
|
34
|
-
fabric:
|
|
35
|
-
|
|
36
|
-
sources: Map<
|
|
51
|
+
fabric: FabricType
|
|
52
|
+
driver: PluginDriver
|
|
53
|
+
sources: Map<FabricFile.Path, string>
|
|
37
54
|
}
|
|
38
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Initializes all Kubb infrastructure for a build without executing any plugins.
|
|
58
|
+
*
|
|
59
|
+
* - Validates the input path (when applicable).
|
|
60
|
+
* - Applies config defaults (`root`, `output.*`, `devtools`).
|
|
61
|
+
* - Creates the Fabric instance and wires storage, format, and lint hooks.
|
|
62
|
+
* - Runs the adapter (if configured) to produce the universal `RootNode`.
|
|
63
|
+
*
|
|
64
|
+
* Pass the returned {@link SetupResult} directly to {@link safeBuild} or {@link build}
|
|
65
|
+
* via the `overrides` argument to reuse the same infrastructure across multiple runs.
|
|
66
|
+
*/
|
|
39
67
|
export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
40
68
|
const { config: userConfig, events = new AsyncEventEmitter<KubbEvents>() } = options
|
|
41
69
|
|
|
42
|
-
const sources: Map<
|
|
70
|
+
const sources: Map<FabricFile.Path, string> = new Map<FabricFile.Path, string>()
|
|
43
71
|
const diagnosticInfo = getDiagnosticInfo()
|
|
44
72
|
|
|
45
73
|
if (Array.isArray(userConfig.input)) {
|
|
@@ -110,7 +138,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
110
138
|
// storage or fall back to fsStorage (backwards-compatible default).
|
|
111
139
|
// Keys are root-relative (e.g. `src/gen/api/getPets.ts`) so fsStorage()
|
|
112
140
|
// needs no configuration — it resolves them against process.cwd().
|
|
113
|
-
const storage:
|
|
141
|
+
const storage: Storage | null = definedConfig.output.write === false ? null : (definedConfig.output.storage ?? fsStorage())
|
|
114
142
|
|
|
115
143
|
if (definedConfig.output.clean) {
|
|
116
144
|
await events.emit('debug', {
|
|
@@ -165,7 +193,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
165
193
|
],
|
|
166
194
|
})
|
|
167
195
|
|
|
168
|
-
const
|
|
196
|
+
const pluginDriver = new PluginDriver(definedConfig, {
|
|
169
197
|
fabric,
|
|
170
198
|
events,
|
|
171
199
|
concurrency: DEFAULT_CONCURRENCY,
|
|
@@ -180,15 +208,15 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
180
208
|
logs: [`Running adapter: ${definedConfig.adapter.name}`],
|
|
181
209
|
})
|
|
182
210
|
|
|
183
|
-
|
|
184
|
-
|
|
211
|
+
pluginDriver.adapter = definedConfig.adapter
|
|
212
|
+
pluginDriver.rootNode = await definedConfig.adapter.parse(source)
|
|
185
213
|
|
|
186
214
|
await events.emit('debug', {
|
|
187
215
|
date: new Date(),
|
|
188
216
|
logs: [
|
|
189
217
|
`✓ Adapter '${definedConfig.adapter.name}' resolved RootNode`,
|
|
190
|
-
` • Schemas: ${
|
|
191
|
-
` • Operations: ${
|
|
218
|
+
` • Schemas: ${pluginDriver.rootNode.schemas.length}`,
|
|
219
|
+
` • Operations: ${pluginDriver.rootNode.operations.length}`,
|
|
192
220
|
],
|
|
193
221
|
})
|
|
194
222
|
}
|
|
@@ -196,13 +224,19 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
196
224
|
return {
|
|
197
225
|
events,
|
|
198
226
|
fabric,
|
|
199
|
-
|
|
227
|
+
driver: pluginDriver,
|
|
200
228
|
sources,
|
|
201
229
|
}
|
|
202
230
|
}
|
|
203
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Runs a full Kubb build and throws on any error or plugin failure.
|
|
234
|
+
*
|
|
235
|
+
* Internally delegates to {@link safeBuild} and rethrows collected errors.
|
|
236
|
+
* Pass an existing {@link SetupResult} via `overrides` to skip the setup phase.
|
|
237
|
+
*/
|
|
204
238
|
export async function build(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
205
|
-
const { fabric, files,
|
|
239
|
+
const { fabric, files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides)
|
|
206
240
|
|
|
207
241
|
if (error) {
|
|
208
242
|
throw error
|
|
@@ -218,27 +252,88 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
|
|
|
218
252
|
failedPlugins,
|
|
219
253
|
fabric,
|
|
220
254
|
files,
|
|
221
|
-
|
|
255
|
+
driver,
|
|
222
256
|
pluginTimings,
|
|
223
257
|
error: undefined,
|
|
224
258
|
sources,
|
|
225
259
|
}
|
|
226
260
|
}
|
|
227
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Walks the AST and dispatches nodes to a plugin's direct AST hooks
|
|
264
|
+
* (`schema`, `operation`, `operations`).
|
|
265
|
+
*
|
|
266
|
+
* - Each hook accepts a single handler **or an array** — all entries are called in sequence.
|
|
267
|
+
* - Nodes that are excluded by `exclude`/`include` plugin options are skipped automatically.
|
|
268
|
+
* - Return values are handled via `applyHookResult`: React elements are rendered,
|
|
269
|
+
* `FabricFile.File[]` are written via upsert, and `void` is a no-op (manual handling).
|
|
270
|
+
* - Barrel files are generated automatically when `output.barrelType` is set.
|
|
271
|
+
*/
|
|
272
|
+
async function runPluginAstHooks(plugin: Plugin, context: PluginContext): Promise<void> {
|
|
273
|
+
const { adapter, rootNode, resolver, fabric } = context
|
|
274
|
+
const { exclude, include, override } = plugin.options
|
|
275
|
+
|
|
276
|
+
if (!adapter || !rootNode) {
|
|
277
|
+
throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const collectedOperations: Array<OperationNode> = []
|
|
281
|
+
|
|
282
|
+
await walk(rootNode, {
|
|
283
|
+
depth: 'shallow',
|
|
284
|
+
async schema(node) {
|
|
285
|
+
if (!plugin.schema) return
|
|
286
|
+
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
|
|
287
|
+
const options = resolver.resolveOptions(transformedNode, { options: plugin.options, exclude, include, override })
|
|
288
|
+
if (options === null) return
|
|
289
|
+
const result = await plugin.schema.call(context, transformedNode, options)
|
|
290
|
+
|
|
291
|
+
await applyHookResult(result, fabric)
|
|
292
|
+
},
|
|
293
|
+
async operation(node) {
|
|
294
|
+
const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
|
|
295
|
+
const options = resolver.resolveOptions(transformedNode, { options: plugin.options, exclude, include, override })
|
|
296
|
+
if (options !== null) {
|
|
297
|
+
collectedOperations.push(transformedNode)
|
|
298
|
+
if (plugin.operation) {
|
|
299
|
+
const result = await plugin.operation.call(context, transformedNode, options)
|
|
300
|
+
await applyHookResult(result, fabric)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
if (plugin.operations && collectedOperations.length > 0) {
|
|
307
|
+
const result = await plugin.operations.call(context, collectedOperations, plugin.options)
|
|
308
|
+
|
|
309
|
+
await applyHookResult(result, fabric)
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Runs a full Kubb build and captures errors instead of throwing.
|
|
315
|
+
*
|
|
316
|
+
* - Installs each plugin in order, recording failures in `failedPlugins`.
|
|
317
|
+
* - Generates the root barrel file when `output.barrelType` is set.
|
|
318
|
+
* - Writes all files through Fabric.
|
|
319
|
+
*
|
|
320
|
+
* Returns a {@link BuildOutput} even on failure — inspect `error` and
|
|
321
|
+
* `failedPlugins` to determine whether the build succeeded.
|
|
322
|
+
*/
|
|
228
323
|
export async function safeBuild(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
229
|
-
const { fabric,
|
|
324
|
+
const { fabric, driver, events, sources } = overrides ? overrides : await setup(options)
|
|
230
325
|
|
|
231
326
|
const failedPlugins = new Set<{ plugin: Plugin; error: Error }>()
|
|
232
327
|
// in ms
|
|
233
328
|
const pluginTimings = new Map<string, number>()
|
|
234
|
-
const config =
|
|
329
|
+
const config = driver.config
|
|
235
330
|
|
|
236
331
|
try {
|
|
237
|
-
for (const plugin of
|
|
238
|
-
const context =
|
|
332
|
+
for (const plugin of driver.plugins.values()) {
|
|
333
|
+
const context = driver.getContext(plugin)
|
|
239
334
|
const hrStart = process.hrtime()
|
|
240
|
-
|
|
241
|
-
const
|
|
335
|
+
const { output } = plugin.options ?? {}
|
|
336
|
+
const root = resolve(config.root, config.output.path)
|
|
242
337
|
|
|
243
338
|
try {
|
|
244
339
|
const timestamp = new Date()
|
|
@@ -247,10 +342,26 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
247
342
|
|
|
248
343
|
await events.emit('debug', {
|
|
249
344
|
date: timestamp,
|
|
250
|
-
logs: ['
|
|
345
|
+
logs: ['Starting plugin...', ` • Plugin Name: ${plugin.name}`],
|
|
251
346
|
})
|
|
252
347
|
|
|
253
|
-
|
|
348
|
+
// Call buildStart() for any custom plugin logic
|
|
349
|
+
await plugin.buildStart.call(context)
|
|
350
|
+
|
|
351
|
+
// Dispatch schema/operation/operations hooks (direct hooks or composed via composeGenerators)
|
|
352
|
+
if (plugin.schema || plugin.operation || plugin.operations) {
|
|
353
|
+
await runPluginAstHooks(plugin, context)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (output) {
|
|
357
|
+
const barrelFiles = await getBarrelFiles(fabric.files, {
|
|
358
|
+
type: output.barrelType ?? 'named',
|
|
359
|
+
root,
|
|
360
|
+
output,
|
|
361
|
+
meta: { pluginName: plugin.name },
|
|
362
|
+
})
|
|
363
|
+
await context.upsertFile(...barrelFiles)
|
|
364
|
+
}
|
|
254
365
|
|
|
255
366
|
const duration = getElapsedMs(hrStart)
|
|
256
367
|
pluginTimings.set(plugin.name, duration)
|
|
@@ -259,7 +370,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
259
370
|
|
|
260
371
|
await events.emit('debug', {
|
|
261
372
|
date: new Date(),
|
|
262
|
-
logs: [`✓ Plugin
|
|
373
|
+
logs: [`✓ Plugin started successfully (${formatMs(duration)})`],
|
|
263
374
|
})
|
|
264
375
|
} catch (caughtError) {
|
|
265
376
|
const error = caughtError as Error
|
|
@@ -275,7 +386,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
275
386
|
await events.emit('debug', {
|
|
276
387
|
date: errorTimestamp,
|
|
277
388
|
logs: [
|
|
278
|
-
'✗ Plugin
|
|
389
|
+
'✗ Plugin start failed',
|
|
279
390
|
` • Plugin Name: ${plugin.name}`,
|
|
280
391
|
` • Error: ${error.constructor.name} - ${error.message}`,
|
|
281
392
|
' • Stack Trace:',
|
|
@@ -311,10 +422,10 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
311
422
|
existingBarrel?.exports?.flatMap((e) => (Array.isArray(e.name) ? e.name : [e.name])).filter((n): n is string => Boolean(n)) ?? [],
|
|
312
423
|
)
|
|
313
424
|
|
|
314
|
-
const rootFile:
|
|
425
|
+
const rootFile: FabricFile.File = {
|
|
315
426
|
path: rootPath,
|
|
316
427
|
baseName: BARREL_FILENAME,
|
|
317
|
-
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config,
|
|
428
|
+
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }),
|
|
318
429
|
sources: [],
|
|
319
430
|
imports: [],
|
|
320
431
|
meta: {},
|
|
@@ -332,11 +443,19 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
332
443
|
|
|
333
444
|
await fabric.write({ extension: config.output.extension })
|
|
334
445
|
|
|
446
|
+
// Call buildEnd() on each plugin after all files are written
|
|
447
|
+
for (const plugin of driver.plugins.values()) {
|
|
448
|
+
if (plugin.buildEnd) {
|
|
449
|
+
const context = driver.getContext(plugin)
|
|
450
|
+
await plugin.buildEnd.call(context)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
335
454
|
return {
|
|
336
455
|
failedPlugins,
|
|
337
456
|
fabric,
|
|
338
457
|
files,
|
|
339
|
-
|
|
458
|
+
driver,
|
|
340
459
|
pluginTimings,
|
|
341
460
|
sources,
|
|
342
461
|
}
|
|
@@ -345,7 +464,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
345
464
|
failedPlugins,
|
|
346
465
|
fabric,
|
|
347
466
|
files: [],
|
|
348
|
-
|
|
467
|
+
driver,
|
|
349
468
|
pluginTimings,
|
|
350
469
|
error: error as Error,
|
|
351
470
|
sources,
|
|
@@ -354,16 +473,16 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
354
473
|
}
|
|
355
474
|
|
|
356
475
|
type BuildBarrelExportsParams = {
|
|
357
|
-
barrelFiles:
|
|
476
|
+
barrelFiles: FabricFile.ResolvedFile[]
|
|
358
477
|
rootDir: string
|
|
359
478
|
existingExports: Set<string>
|
|
360
479
|
config: Config
|
|
361
|
-
|
|
480
|
+
driver: PluginDriver
|
|
362
481
|
}
|
|
363
482
|
|
|
364
|
-
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config,
|
|
483
|
+
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): FabricFile.Export[] {
|
|
365
484
|
const pluginNameMap = new Map<string, Plugin>()
|
|
366
|
-
for (const plugin of
|
|
485
|
+
for (const plugin of driver.plugins.values()) {
|
|
367
486
|
pluginNameMap.set(plugin.name, plugin)
|
|
368
487
|
}
|
|
369
488
|
|
|
@@ -377,7 +496,7 @@ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, plu
|
|
|
377
496
|
|
|
378
497
|
const meta = file.meta as FileMetaBase | undefined
|
|
379
498
|
const plugin = meta?.pluginName ? pluginNameMap.get(meta.pluginName) : undefined
|
|
380
|
-
const pluginOptions = plugin?.options
|
|
499
|
+
const pluginOptions = plugin?.options
|
|
381
500
|
|
|
382
501
|
if (!pluginOptions || pluginOptions.output?.barrelType === false) {
|
|
383
502
|
return []
|
|
@@ -393,7 +512,7 @@ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, plu
|
|
|
393
512
|
name: exportName,
|
|
394
513
|
path: getRelativePath(rootDir, file.path),
|
|
395
514
|
isTypeOnly: config.output.barrelType === 'all' ? containsOnlyTypes : source.isTypeOnly,
|
|
396
|
-
} satisfies
|
|
515
|
+
} satisfies FabricFile.Export,
|
|
397
516
|
]
|
|
398
517
|
})
|
|
399
518
|
})
|
|
@@ -407,7 +526,7 @@ function inputToAdapterSource(config: Config): AdapterSource {
|
|
|
407
526
|
if (Array.isArray(config.input)) {
|
|
408
527
|
return {
|
|
409
528
|
type: 'paths',
|
|
410
|
-
paths: config.input.map((i) => resolve(config.root, i.path)),
|
|
529
|
+
paths: config.input.map((i) => (new URLPath(i.path).isURL ? i.path : resolve(config.root, i.path))),
|
|
411
530
|
}
|
|
412
531
|
}
|
|
413
532
|
|
|
@@ -415,6 +534,10 @@ function inputToAdapterSource(config: Config): AdapterSource {
|
|
|
415
534
|
return { type: 'data', data: config.input.data }
|
|
416
535
|
}
|
|
417
536
|
|
|
537
|
+
if (new URLPath(config.input.path).isURL) {
|
|
538
|
+
return { type: 'path', path: config.input.path }
|
|
539
|
+
}
|
|
540
|
+
|
|
418
541
|
const resolved = resolve(config.root, config.input.path)
|
|
419
542
|
return { type: 'path', path: resolved }
|
|
420
543
|
}
|
package/src/config.ts
CHANGED
|
@@ -5,12 +5,14 @@ import type { InputPath, UserConfig } from './types.ts'
|
|
|
5
5
|
* CLI options derived from command-line flags.
|
|
6
6
|
*/
|
|
7
7
|
export type CLIOptions = {
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Path to `kubb.config.js`.
|
|
10
|
+
*/
|
|
9
11
|
config?: string
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Enable watch mode for input files.
|
|
14
|
+
*/
|
|
12
15
|
watch?: boolean
|
|
13
|
-
|
|
14
16
|
/**
|
|
15
17
|
* Logging verbosity for CLI usage.
|
|
16
18
|
*
|
|
@@ -20,12 +22,11 @@ export type CLIOptions = {
|
|
|
20
22
|
* @default 'silent'
|
|
21
23
|
*/
|
|
22
24
|
logLevel?: 'silent' | 'info' | 'debug'
|
|
23
|
-
|
|
24
|
-
/** Run Kubb with Bun */
|
|
25
|
-
bun?: boolean
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* All accepted forms of a Kubb configuration.
|
|
29
|
+
*/
|
|
29
30
|
export type ConfigInput = PossiblePromise<UserConfig | UserConfig[]> | ((cli: CLIOptions) => PossiblePromise<UserConfig | UserConfig[]>)
|
|
30
31
|
|
|
31
32
|
/**
|
package/src/constants.ts
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FabricFile } from '@kubb/fabric-core/types'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Base URL for the Kubb Studio web app.
|
|
5
|
+
*/
|
|
3
6
|
export const DEFAULT_STUDIO_URL = 'https://studio.kubb.dev' as const
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Default number of plugins that may run concurrently during a build.
|
|
10
|
+
*/
|
|
9
11
|
export const DEFAULT_CONCURRENCY = 15
|
|
10
12
|
|
|
13
|
+
/**
|
|
14
|
+
* File name used for generated barrel (index) files.
|
|
15
|
+
*/
|
|
11
16
|
export const BARREL_FILENAME = 'index.ts' as const
|
|
12
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Default banner style written at the top of every generated file.
|
|
20
|
+
*/
|
|
13
21
|
export const DEFAULT_BANNER = 'simple' as const
|
|
14
22
|
|
|
15
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Default file-extension mapping used when no explicit mapping is configured.
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_EXTENSION: Record<FabricFile.Extname, FabricFile.Extname | ''> = { '.ts': '.ts' }
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Characters recognized as path separators on both POSIX and Windows.
|
|
30
|
+
*/
|
|
31
|
+
export const PATH_SEPARATORS = new Set(['/', '\\'] as const)
|
|
18
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Numeric log-level thresholds used internally to compare verbosity.
|
|
35
|
+
*
|
|
36
|
+
* Higher numbers are more verbose.
|
|
37
|
+
*/
|
|
19
38
|
export const logLevel = {
|
|
20
39
|
silent: Number.NEGATIVE_INFINITY,
|
|
21
40
|
error: 0,
|
|
@@ -25,6 +44,13 @@ export const logLevel = {
|
|
|
25
44
|
debug: 5,
|
|
26
45
|
} as const
|
|
27
46
|
|
|
47
|
+
/**
|
|
48
|
+
* CLI command descriptors for each supported linter.
|
|
49
|
+
*
|
|
50
|
+
* Each entry contains the executable `command`, an `args` factory that maps an
|
|
51
|
+
* output path to the correct argument list, and an `errorMessage` shown when
|
|
52
|
+
* the linter is not found.
|
|
53
|
+
*/
|
|
28
54
|
export const linters = {
|
|
29
55
|
eslint: {
|
|
30
56
|
command: 'eslint',
|
|
@@ -43,6 +69,13 @@ export const linters = {
|
|
|
43
69
|
},
|
|
44
70
|
} as const
|
|
45
71
|
|
|
72
|
+
/**
|
|
73
|
+
* CLI command descriptors for each supported code formatter.
|
|
74
|
+
*
|
|
75
|
+
* Each entry contains the executable `command`, an `args` factory that maps an
|
|
76
|
+
* output path to the correct argument list, and an `errorMessage` shown when
|
|
77
|
+
* the formatter is not found.
|
|
78
|
+
*/
|
|
46
79
|
export const formatters = {
|
|
47
80
|
prettier: {
|
|
48
81
|
command: 'prettier',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Adapter, AdapterFactoryOptions } from './types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builder type for an {@link Adapter} — takes options and returns the adapter instance.
|
|
5
|
+
*/
|
|
6
|
+
type AdapterBuilder<T extends AdapterFactoryOptions> = (options: T['options']) => Adapter<T>
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates an adapter factory. Call the returned function with optional options to get the adapter instance.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* export const myAdapter = createAdapter<MyAdapter>((options) => {
|
|
13
|
+
* return {
|
|
14
|
+
* name: 'my-adapter',
|
|
15
|
+
* options,
|
|
16
|
+
* async parse(source) { ... },
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* // instantiate
|
|
21
|
+
* const adapter = myAdapter({ validate: true })
|
|
22
|
+
*/
|
|
23
|
+
export function createAdapter<T extends AdapterFactoryOptions = AdapterFactoryOptions>(build: AdapterBuilder<T>): (options?: T['options']) => Adapter<T> {
|
|
24
|
+
return (options) => build(options ?? ({} as T['options']))
|
|
25
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PluginFactoryOptions, UserPluginWithLifeCycle } from './types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builder type for a {@link UserPluginWithLifeCycle} — takes options and returns the plugin instance.
|
|
5
|
+
*/
|
|
6
|
+
type PluginBuilder<T extends PluginFactoryOptions = PluginFactoryOptions> = (options: T['options']) => UserPluginWithLifeCycle<T>
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a plugin factory. Call the returned function with optional options to get the plugin instance.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* export const myPlugin = createPlugin<MyPlugin>((options) => {
|
|
14
|
+
* return {
|
|
15
|
+
* name: 'my-plugin',
|
|
16
|
+
* get options() { return options },
|
|
17
|
+
* resolvePath(baseName) { ... },
|
|
18
|
+
* resolveName(name, type) { ... },
|
|
19
|
+
* }
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* // instantiate
|
|
23
|
+
* const plugin = myPlugin({ output: { path: 'src/gen' } })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function createPlugin<T extends PluginFactoryOptions = PluginFactoryOptions>(
|
|
27
|
+
build: PluginBuilder<T>,
|
|
28
|
+
): (options?: T['options']) => UserPluginWithLifeCycle<T> {
|
|
29
|
+
return (options) => build(options ?? ({} as T['options']))
|
|
30
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type Storage = {
|
|
2
|
+
/**
|
|
3
|
+
* Identifier used for logging and debugging (e.g. `'fs'`, `'s3'`).
|
|
4
|
+
*/
|
|
5
|
+
readonly name: string
|
|
6
|
+
/**
|
|
7
|
+
* Returns `true` when an entry for `key` exists in storage.
|
|
8
|
+
*/
|
|
9
|
+
hasItem(key: string): Promise<boolean>
|
|
10
|
+
/**
|
|
11
|
+
* Returns the stored string value, or `null` when `key` does not exist.
|
|
12
|
+
*/
|
|
13
|
+
getItem(key: string): Promise<string | null>
|
|
14
|
+
/**
|
|
15
|
+
* Persists `value` under `key`, creating any required structure.
|
|
16
|
+
*/
|
|
17
|
+
setItem(key: string, value: string): Promise<void>
|
|
18
|
+
/**
|
|
19
|
+
* Removes the entry for `key`. No-ops when the key does not exist.
|
|
20
|
+
*/
|
|
21
|
+
removeItem(key: string): Promise<void>
|
|
22
|
+
/**
|
|
23
|
+
* Returns all keys, optionally filtered to those starting with `base`.
|
|
24
|
+
*/
|
|
25
|
+
getKeys(base?: string): Promise<Array<string>>
|
|
26
|
+
/**
|
|
27
|
+
* Removes all entries, optionally scoped to those starting with `base`.
|
|
28
|
+
*/
|
|
29
|
+
clear(base?: string): Promise<void>
|
|
30
|
+
/**
|
|
31
|
+
* Optional teardown hook called after the build completes.
|
|
32
|
+
*/
|
|
33
|
+
dispose?(): Promise<void>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Creates a storage factory. Call the returned function with optional options to get the storage instance.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* export const memoryStorage = createStorage(() => {
|
|
41
|
+
* const store = new Map<string, string>()
|
|
42
|
+
* return {
|
|
43
|
+
* name: 'memory',
|
|
44
|
+
* async hasItem(key) { return store.has(key) },
|
|
45
|
+
* async getItem(key) { return store.get(key) ?? null },
|
|
46
|
+
* async setItem(key, value) { store.set(key, value) },
|
|
47
|
+
* async removeItem(key) { store.delete(key) },
|
|
48
|
+
* async getKeys(base) {
|
|
49
|
+
* const keys = [...store.keys()]
|
|
50
|
+
* return base ? keys.filter((k) => k.startsWith(base)) : keys
|
|
51
|
+
* },
|
|
52
|
+
* async clear(base) { if (!base) store.clear() },
|
|
53
|
+
* }
|
|
54
|
+
* })
|
|
55
|
+
*/
|
|
56
|
+
export function createStorage<TOptions = Record<string, never>>(build: (options: TOptions) => Storage): (options?: TOptions) => Storage {
|
|
57
|
+
return (options) => build(options ?? ({} as TOptions))
|
|
58
|
+
}
|