@kubb/core 5.0.0-alpha.2 → 5.0.0-alpha.21
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/{types-B7eZvqwD.d.ts → PluginDriver-CEQPafXV.d.ts} +687 -298
- package/dist/hooks.cjs +15 -9
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +11 -5
- package/dist/hooks.js +16 -10
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +1131 -536
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +674 -89
- package/dist/index.js +1114 -532
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/Kubb.ts +37 -55
- package/src/{PluginManager.ts → PluginDriver.ts} +51 -40
- package/src/build.ts +74 -29
- package/src/config.ts +9 -8
- package/src/constants.ts +44 -1
- package/src/createAdapter.ts +25 -0
- package/src/createPlugin.ts +28 -0
- package/src/createStorage.ts +58 -0
- package/src/defineBuilder.ts +26 -0
- package/src/defineGenerator.ts +137 -0
- package/src/defineLogger.ts +13 -3
- package/src/definePreset.ts +27 -0
- package/src/definePresets.ts +16 -0
- package/src/defineResolver.ts +448 -0
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useDriver.ts +8 -0
- package/src/hooks/useMode.ts +5 -2
- package/src/hooks/usePlugin.ts +5 -2
- package/src/index.ts +21 -6
- package/src/renderNode.tsx +105 -0
- package/src/storages/fsStorage.ts +2 -2
- package/src/storages/memoryStorage.ts +2 -2
- package/src/types.ts +342 -42
- package/src/utils/FunctionParams.ts +2 -2
- package/src/utils/TreeNode.ts +24 -1
- package/src/utils/diagnostics.ts +4 -1
- package/src/utils/executeStrategies.ts +23 -10
- package/src/utils/formatters.ts +10 -21
- package/src/utils/getBarrelFiles.ts +79 -9
- package/src/utils/getConfigs.ts +8 -22
- package/src/utils/getPreset.ts +52 -0
- package/src/utils/linters.ts +23 -3
- package/src/utils/mergeResolvers.ts +8 -0
- package/src/utils/packageJSON.ts +76 -0
- 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/usePluginManager.ts +0 -8
- package/src/utils/getPlugins.ts +0 -23
package/src/build.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { dirname, relative, resolve } from 'node:path'
|
|
2
|
-
import { AsyncEventEmitter, exists, formatMs, getElapsedMs, getRelativePath, URLPath } from '@internals/utils'
|
|
3
|
-
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
4
|
-
import type { Fabric } from '@kubb/react-fabric'
|
|
2
|
+
import { AsyncEventEmitter, BuildError, exists, formatMs, getElapsedMs, getRelativePath, URLPath } from '@internals/utils'
|
|
3
|
+
import type { Fabric as FabricType, KubbFile } from '@kubb/fabric-core/types'
|
|
5
4
|
import { createFabric } from '@kubb/react-fabric'
|
|
6
5
|
import { typescriptParser } from '@kubb/react-fabric/parsers'
|
|
7
6
|
import { fsPlugin } from '@kubb/react-fabric/plugins'
|
|
8
7
|
import { isInputPath } from './config.ts'
|
|
9
8
|
import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
10
|
-
import {
|
|
11
|
-
import { PluginManager } from './PluginManager.ts'
|
|
9
|
+
import { PluginDriver } from './PluginDriver.ts'
|
|
12
10
|
import { fsStorage } from './storages/fsStorage.ts'
|
|
13
|
-
import type { AdapterSource, Config,
|
|
11
|
+
import type { AdapterSource, Config, KubbEvents, Output, Plugin, Storage, UserConfig } from './types.ts'
|
|
14
12
|
import { getDiagnosticInfo } from './utils/diagnostics.ts'
|
|
15
13
|
import type { FileMetaBase } from './utils/getBarrelFiles.ts'
|
|
16
14
|
|
|
@@ -19,23 +17,49 @@ type BuildOptions = {
|
|
|
19
17
|
events?: AsyncEventEmitter<KubbEvents>
|
|
20
18
|
}
|
|
21
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Full output produced by a successful or failed build.
|
|
22
|
+
*/
|
|
22
23
|
type BuildOutput = {
|
|
24
|
+
/**
|
|
25
|
+
* Plugins that threw during installation, paired with the caught error.
|
|
26
|
+
*/
|
|
23
27
|
failedPlugins: Set<{ plugin: Plugin; error: Error }>
|
|
24
|
-
fabric:
|
|
28
|
+
fabric: FabricType
|
|
25
29
|
files: Array<KubbFile.ResolvedFile>
|
|
26
|
-
|
|
30
|
+
driver: PluginDriver
|
|
31
|
+
/**
|
|
32
|
+
* Elapsed time in milliseconds for each plugin, keyed by plugin name.
|
|
33
|
+
*/
|
|
27
34
|
pluginTimings: Map<string, number>
|
|
28
35
|
error?: Error
|
|
36
|
+
/**
|
|
37
|
+
* Raw generated source, keyed by absolute file path.
|
|
38
|
+
*/
|
|
29
39
|
sources: Map<KubbFile.Path, string>
|
|
30
40
|
}
|
|
31
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Intermediate result returned by {@link setup} and accepted by {@link safeBuild}.
|
|
44
|
+
*/
|
|
32
45
|
type SetupResult = {
|
|
33
46
|
events: AsyncEventEmitter<KubbEvents>
|
|
34
|
-
fabric:
|
|
35
|
-
|
|
47
|
+
fabric: FabricType
|
|
48
|
+
driver: PluginDriver
|
|
36
49
|
sources: Map<KubbFile.Path, string>
|
|
37
50
|
}
|
|
38
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Initializes all Kubb infrastructure for a build without executing any plugins.
|
|
54
|
+
*
|
|
55
|
+
* - Validates the input path (when applicable).
|
|
56
|
+
* - Applies config defaults (`root`, `output.*`, `devtools`).
|
|
57
|
+
* - Creates the Fabric instance and wires storage, format, and lint hooks.
|
|
58
|
+
* - Runs the adapter (if configured) to produce the universal `RootNode`.
|
|
59
|
+
*
|
|
60
|
+
* Pass the returned {@link SetupResult} directly to {@link safeBuild} or {@link build}
|
|
61
|
+
* via the `overrides` argument to reuse the same infrastructure across multiple runs.
|
|
62
|
+
*/
|
|
39
63
|
export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
40
64
|
const { config: userConfig, events = new AsyncEventEmitter<KubbEvents>() } = options
|
|
41
65
|
|
|
@@ -110,7 +134,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
110
134
|
// storage or fall back to fsStorage (backwards-compatible default).
|
|
111
135
|
// Keys are root-relative (e.g. `src/gen/api/getPets.ts`) so fsStorage()
|
|
112
136
|
// needs no configuration — it resolves them against process.cwd().
|
|
113
|
-
const storage:
|
|
137
|
+
const storage: Storage | null = definedConfig.output.write === false ? null : (definedConfig.output.storage ?? fsStorage())
|
|
114
138
|
|
|
115
139
|
if (definedConfig.output.clean) {
|
|
116
140
|
await events.emit('debug', {
|
|
@@ -165,7 +189,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
165
189
|
],
|
|
166
190
|
})
|
|
167
191
|
|
|
168
|
-
const
|
|
192
|
+
const pluginDriver = new PluginDriver(definedConfig, {
|
|
169
193
|
fabric,
|
|
170
194
|
events,
|
|
171
195
|
concurrency: DEFAULT_CONCURRENCY,
|
|
@@ -180,14 +204,15 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
180
204
|
logs: [`Running adapter: ${definedConfig.adapter.name}`],
|
|
181
205
|
})
|
|
182
206
|
|
|
183
|
-
|
|
207
|
+
pluginDriver.adapter = definedConfig.adapter
|
|
208
|
+
pluginDriver.rootNode = await definedConfig.adapter.parse(source)
|
|
184
209
|
|
|
185
210
|
await events.emit('debug', {
|
|
186
211
|
date: new Date(),
|
|
187
212
|
logs: [
|
|
188
213
|
`✓ Adapter '${definedConfig.adapter.name}' resolved RootNode`,
|
|
189
|
-
` • Schemas: ${
|
|
190
|
-
` • Operations: ${
|
|
214
|
+
` • Schemas: ${pluginDriver.rootNode.schemas.length}`,
|
|
215
|
+
` • Operations: ${pluginDriver.rootNode.operations.length}`,
|
|
191
216
|
],
|
|
192
217
|
})
|
|
193
218
|
}
|
|
@@ -195,13 +220,19 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
195
220
|
return {
|
|
196
221
|
events,
|
|
197
222
|
fabric,
|
|
198
|
-
|
|
223
|
+
driver: pluginDriver,
|
|
199
224
|
sources,
|
|
200
225
|
}
|
|
201
226
|
}
|
|
202
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Runs a full Kubb build and throws on any error or plugin failure.
|
|
230
|
+
*
|
|
231
|
+
* Internally delegates to {@link safeBuild} and rethrows collected errors.
|
|
232
|
+
* Pass an existing {@link SetupResult} via `overrides` to skip the setup phase.
|
|
233
|
+
*/
|
|
203
234
|
export async function build(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
204
|
-
const { fabric, files,
|
|
235
|
+
const { fabric, files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides)
|
|
205
236
|
|
|
206
237
|
if (error) {
|
|
207
238
|
throw error
|
|
@@ -217,24 +248,34 @@ export async function build(options: BuildOptions, overrides?: SetupResult): Pro
|
|
|
217
248
|
failedPlugins,
|
|
218
249
|
fabric,
|
|
219
250
|
files,
|
|
220
|
-
|
|
251
|
+
driver,
|
|
221
252
|
pluginTimings,
|
|
222
253
|
error: undefined,
|
|
223
254
|
sources,
|
|
224
255
|
}
|
|
225
256
|
}
|
|
226
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Runs a full Kubb build and captures errors instead of throwing.
|
|
260
|
+
*
|
|
261
|
+
* - Installs each plugin in order, recording failures in `failedPlugins`.
|
|
262
|
+
* - Generates the root barrel file when `output.barrelType` is set.
|
|
263
|
+
* - Writes all files through Fabric.
|
|
264
|
+
*
|
|
265
|
+
* Returns a {@link BuildOutput} even on failure — inspect `error` and
|
|
266
|
+
* `failedPlugins` to determine whether the build succeeded.
|
|
267
|
+
*/
|
|
227
268
|
export async function safeBuild(options: BuildOptions, overrides?: SetupResult): Promise<BuildOutput> {
|
|
228
|
-
const { fabric,
|
|
269
|
+
const { fabric, driver, events, sources } = overrides ? overrides : await setup(options)
|
|
229
270
|
|
|
230
271
|
const failedPlugins = new Set<{ plugin: Plugin; error: Error }>()
|
|
231
272
|
// in ms
|
|
232
273
|
const pluginTimings = new Map<string, number>()
|
|
233
|
-
const config =
|
|
274
|
+
const config = driver.config
|
|
234
275
|
|
|
235
276
|
try {
|
|
236
|
-
for (const plugin of
|
|
237
|
-
const context =
|
|
277
|
+
for (const plugin of driver.plugins) {
|
|
278
|
+
const context = driver.getContext(plugin)
|
|
238
279
|
const hrStart = process.hrtime()
|
|
239
280
|
|
|
240
281
|
const installer = plugin.install.bind(context)
|
|
@@ -313,7 +354,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
313
354
|
const rootFile: KubbFile.File = {
|
|
314
355
|
path: rootPath,
|
|
315
356
|
baseName: BARREL_FILENAME,
|
|
316
|
-
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config,
|
|
357
|
+
exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }),
|
|
317
358
|
sources: [],
|
|
318
359
|
imports: [],
|
|
319
360
|
meta: {},
|
|
@@ -335,7 +376,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
335
376
|
failedPlugins,
|
|
336
377
|
fabric,
|
|
337
378
|
files,
|
|
338
|
-
|
|
379
|
+
driver,
|
|
339
380
|
pluginTimings,
|
|
340
381
|
sources,
|
|
341
382
|
}
|
|
@@ -344,7 +385,7 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
|
|
|
344
385
|
failedPlugins,
|
|
345
386
|
fabric,
|
|
346
387
|
files: [],
|
|
347
|
-
|
|
388
|
+
driver,
|
|
348
389
|
pluginTimings,
|
|
349
390
|
error: error as Error,
|
|
350
391
|
sources,
|
|
@@ -357,12 +398,12 @@ type BuildBarrelExportsParams = {
|
|
|
357
398
|
rootDir: string
|
|
358
399
|
existingExports: Set<string>
|
|
359
400
|
config: Config
|
|
360
|
-
|
|
401
|
+
driver: PluginDriver
|
|
361
402
|
}
|
|
362
403
|
|
|
363
|
-
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config,
|
|
404
|
+
function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): KubbFile.Export[] {
|
|
364
405
|
const pluginNameMap = new Map<string, Plugin>()
|
|
365
|
-
for (const plugin of
|
|
406
|
+
for (const plugin of driver.plugins) {
|
|
366
407
|
pluginNameMap.set(plugin.name, plugin)
|
|
367
408
|
}
|
|
368
409
|
|
|
@@ -406,7 +447,7 @@ function inputToAdapterSource(config: Config): AdapterSource {
|
|
|
406
447
|
if (Array.isArray(config.input)) {
|
|
407
448
|
return {
|
|
408
449
|
type: 'paths',
|
|
409
|
-
paths: config.input.map((i) => resolve(config.root, i.path)),
|
|
450
|
+
paths: config.input.map((i) => (new URLPath(i.path).isURL ? i.path : resolve(config.root, i.path))),
|
|
410
451
|
}
|
|
411
452
|
}
|
|
412
453
|
|
|
@@ -414,6 +455,10 @@ function inputToAdapterSource(config: Config): AdapterSource {
|
|
|
414
455
|
return { type: 'data', data: config.input.data }
|
|
415
456
|
}
|
|
416
457
|
|
|
458
|
+
if (new URLPath(config.input.path).isURL) {
|
|
459
|
+
return { type: 'path', path: config.input.path }
|
|
460
|
+
}
|
|
461
|
+
|
|
417
462
|
const resolved = resolve(config.root, config.input.path)
|
|
418
463
|
return { type: 'path', path: resolved }
|
|
419
464
|
}
|
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,50 @@
|
|
|
1
1
|
import type { KubbFile } 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
|
|
|
8
|
+
/**
|
|
9
|
+
* Internal plugin name used to identify the core Kubb runtime.
|
|
10
|
+
*/
|
|
5
11
|
export const CORE_PLUGIN_NAME = 'core' as const
|
|
6
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Maximum number of event-emitter listeners before Node.js emits a warning.
|
|
15
|
+
*/
|
|
7
16
|
export const DEFAULT_MAX_LISTENERS = 100
|
|
8
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Default number of plugins that may run concurrently during a build.
|
|
20
|
+
*/
|
|
9
21
|
export const DEFAULT_CONCURRENCY = 15
|
|
10
22
|
|
|
23
|
+
/**
|
|
24
|
+
* File name used for generated barrel (index) files.
|
|
25
|
+
*/
|
|
11
26
|
export const BARREL_FILENAME = 'index.ts' as const
|
|
12
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Default banner style written at the top of every generated file.
|
|
30
|
+
*/
|
|
13
31
|
export const DEFAULT_BANNER = 'simple' as const
|
|
14
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Default file-extension mapping used when no explicit mapping is configured.
|
|
35
|
+
*/
|
|
15
36
|
export const DEFAULT_EXTENSION: Record<KubbFile.Extname, KubbFile.Extname | ''> = { '.ts': '.ts' }
|
|
16
37
|
|
|
17
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Characters recognized as path separators on both POSIX and Windows.
|
|
40
|
+
*/
|
|
41
|
+
export const PATH_SEPARATORS = new Set(['/', '\\'] as const)
|
|
18
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Numeric log-level thresholds used internally to compare verbosity.
|
|
45
|
+
*
|
|
46
|
+
* Higher numbers are more verbose.
|
|
47
|
+
*/
|
|
19
48
|
export const logLevel = {
|
|
20
49
|
silent: Number.NEGATIVE_INFINITY,
|
|
21
50
|
error: 0,
|
|
@@ -25,6 +54,13 @@ export const logLevel = {
|
|
|
25
54
|
debug: 5,
|
|
26
55
|
} as const
|
|
27
56
|
|
|
57
|
+
/**
|
|
58
|
+
* CLI command descriptors for each supported linter.
|
|
59
|
+
*
|
|
60
|
+
* Each entry contains the executable `command`, an `args` factory that maps an
|
|
61
|
+
* output path to the correct argument list, and an `errorMessage` shown when
|
|
62
|
+
* the linter is not found.
|
|
63
|
+
*/
|
|
28
64
|
export const linters = {
|
|
29
65
|
eslint: {
|
|
30
66
|
command: 'eslint',
|
|
@@ -43,6 +79,13 @@ export const linters = {
|
|
|
43
79
|
},
|
|
44
80
|
} as const
|
|
45
81
|
|
|
82
|
+
/**
|
|
83
|
+
* CLI command descriptors for each supported code formatter.
|
|
84
|
+
*
|
|
85
|
+
* Each entry contains the executable `command`, an `args` factory that maps an
|
|
86
|
+
* output path to the correct argument list, and an `errorMessage` shown when
|
|
87
|
+
* the formatter is not found.
|
|
88
|
+
*/
|
|
46
89
|
export const formatters = {
|
|
47
90
|
prettier: {
|
|
48
91
|
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,28 @@
|
|
|
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
|
+
* export const myPlugin = createPlugin<MyPlugin>((options) => {
|
|
13
|
+
* return {
|
|
14
|
+
* name: 'my-plugin',
|
|
15
|
+
* options,
|
|
16
|
+
* resolvePath(baseName) { ... },
|
|
17
|
+
* resolveName(name, type) { ... },
|
|
18
|
+
* }
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* // instantiate
|
|
22
|
+
* const plugin = myPlugin({ output: { path: 'src/gen' } })
|
|
23
|
+
*/
|
|
24
|
+
export function createPlugin<T extends PluginFactoryOptions = PluginFactoryOptions>(
|
|
25
|
+
build: PluginBuilder<T>,
|
|
26
|
+
): (options?: T['options']) => UserPluginWithLifeCycle<T> {
|
|
27
|
+
return (options) => build(options ?? ({} as T['options']))
|
|
28
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PluginFactoryOptions } from './types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builder type for the plugin-specific builder fields.
|
|
5
|
+
* `name` is required; all other methods are defined by the concrete plugin builder type.
|
|
6
|
+
*/
|
|
7
|
+
type BuilderBuilder<T extends PluginFactoryOptions> = () => T['builder'] & ThisType<T['builder']>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Defines a builder for a plugin — a named collection of schema-building helpers that
|
|
11
|
+
* can be exported alongside the plugin and imported by other plugins or generators.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* export const builder = defineBuilder<PluginTs>(() => ({
|
|
15
|
+
* name: 'default',
|
|
16
|
+
* buildParamsSchema({ params, node, resolver }) {
|
|
17
|
+
* return createSchema({ type: 'object', properties: [] })
|
|
18
|
+
* },
|
|
19
|
+
* buildDataSchemaNode({ node, resolver }) {
|
|
20
|
+
* return createSchema({ type: 'object', properties: [] })
|
|
21
|
+
* },
|
|
22
|
+
* }))
|
|
23
|
+
*/
|
|
24
|
+
export function defineBuilder<T extends PluginFactoryOptions>(build: BuilderBuilder<T>): T['builder'] {
|
|
25
|
+
return build() as T['builder']
|
|
26
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { OperationNode, SchemaNode } from '@kubb/ast/types'
|
|
2
|
+
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
3
|
+
import type { FabricReactNode } from '@kubb/react-fabric/types'
|
|
4
|
+
import type { Adapter, Config, Plugin, PluginFactoryOptions } from './types.ts'
|
|
5
|
+
|
|
6
|
+
export type Version = '1' | '2'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Props for the `operations` lifecycle — receives all operation nodes at once.
|
|
10
|
+
*/
|
|
11
|
+
export type OperationsV2Props<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
|
|
12
|
+
config: Config
|
|
13
|
+
plugin: Plugin<TPlugin>
|
|
14
|
+
adapter: Adapter
|
|
15
|
+
options: Plugin<TPlugin>['options']
|
|
16
|
+
nodes: Array<OperationNode>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Props for the `operation` lifecycle — receives a single operation node.
|
|
21
|
+
*/
|
|
22
|
+
export type OperationV2Props<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
|
|
23
|
+
config: Config
|
|
24
|
+
adapter: Adapter
|
|
25
|
+
plugin: Plugin<TPlugin>
|
|
26
|
+
options: Plugin<TPlugin>['options']
|
|
27
|
+
node: OperationNode
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Props for the `schema` lifecycle — receives a single schema node.
|
|
32
|
+
*/
|
|
33
|
+
export type SchemaV2Props<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
|
|
34
|
+
config: Config
|
|
35
|
+
adapter: Adapter
|
|
36
|
+
plugin: Plugin<TPlugin>
|
|
37
|
+
options: Plugin<TPlugin>['options']
|
|
38
|
+
node: SchemaNode
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type UserCoreGeneratorV2<TPlugin extends PluginFactoryOptions> = {
|
|
42
|
+
name: string
|
|
43
|
+
type: 'core'
|
|
44
|
+
version?: '2'
|
|
45
|
+
operations?(props: OperationsV2Props<TPlugin>): Promise<Array<KubbFile.File>>
|
|
46
|
+
operation?(props: OperationV2Props<TPlugin>): Promise<Array<KubbFile.File>>
|
|
47
|
+
schema?(props: SchemaV2Props<TPlugin>): Promise<Array<KubbFile.File>>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type UserReactGeneratorV2<TPlugin extends PluginFactoryOptions> = {
|
|
51
|
+
name: string
|
|
52
|
+
type: 'react'
|
|
53
|
+
version?: '2'
|
|
54
|
+
Operations?(props: OperationsV2Props<TPlugin>): FabricReactNode
|
|
55
|
+
Operation?(props: OperationV2Props<TPlugin>): FabricReactNode
|
|
56
|
+
Schema?(props: SchemaV2Props<TPlugin>): FabricReactNode
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type CoreGeneratorV2<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
|
|
60
|
+
name: string
|
|
61
|
+
type: 'core'
|
|
62
|
+
version: '2'
|
|
63
|
+
operations(props: OperationsV2Props<TPlugin>): Promise<Array<KubbFile.File>>
|
|
64
|
+
operation(props: OperationV2Props<TPlugin>): Promise<Array<KubbFile.File>>
|
|
65
|
+
schema(props: SchemaV2Props<TPlugin>): Promise<Array<KubbFile.File>>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type ReactGeneratorV2<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
|
|
69
|
+
name: string
|
|
70
|
+
type: 'react'
|
|
71
|
+
version: '2'
|
|
72
|
+
Operations(props: OperationsV2Props<TPlugin>): FabricReactNode
|
|
73
|
+
Operation(props: OperationV2Props<TPlugin>): FabricReactNode
|
|
74
|
+
Schema(props: SchemaV2Props<TPlugin>): FabricReactNode
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type Generator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = UserCoreGeneratorV2<TPlugin> | UserReactGeneratorV2<TPlugin>
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Defines a generator with no-op defaults for any omitted lifecycle methods.
|
|
81
|
+
* Works for both `core` (async file output) and `react` (JSX component) generators.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // react generator
|
|
85
|
+
* export const typeGenerator = defineGenerator<PluginTs>({
|
|
86
|
+
* name: 'typescript',
|
|
87
|
+
* type: 'react',
|
|
88
|
+
* Operation({ node, options }) { return <File>...</File> },
|
|
89
|
+
* Schema({ node, options }) { return <File>...</File> },
|
|
90
|
+
* })
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // core generator
|
|
94
|
+
* export const myGenerator = defineGenerator<MyPlugin>({
|
|
95
|
+
* name: 'my-generator',
|
|
96
|
+
* type: 'core',
|
|
97
|
+
* async operation({ node, options }) { return [{ path: '...', content: '...' }] },
|
|
98
|
+
* })
|
|
99
|
+
*/
|
|
100
|
+
export function defineGenerator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions>(
|
|
101
|
+
generator: UserReactGeneratorV2<TPlugin>,
|
|
102
|
+
): ReactGeneratorV2<TPlugin>
|
|
103
|
+
|
|
104
|
+
export function defineGenerator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions>(generator: UserCoreGeneratorV2<TPlugin>): CoreGeneratorV2<TPlugin>
|
|
105
|
+
export function defineGenerator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions>(
|
|
106
|
+
generator: UserCoreGeneratorV2<TPlugin> | UserReactGeneratorV2<TPlugin>,
|
|
107
|
+
): unknown {
|
|
108
|
+
if (generator.type === 'react') {
|
|
109
|
+
return {
|
|
110
|
+
version: '2',
|
|
111
|
+
Operations() {
|
|
112
|
+
return null
|
|
113
|
+
},
|
|
114
|
+
Operation() {
|
|
115
|
+
return null
|
|
116
|
+
},
|
|
117
|
+
Schema() {
|
|
118
|
+
return null
|
|
119
|
+
},
|
|
120
|
+
...generator,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
version: '2',
|
|
126
|
+
async operations() {
|
|
127
|
+
return []
|
|
128
|
+
},
|
|
129
|
+
async operation() {
|
|
130
|
+
return []
|
|
131
|
+
},
|
|
132
|
+
async schema() {
|
|
133
|
+
return []
|
|
134
|
+
},
|
|
135
|
+
...generator,
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/defineLogger.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import type { Logger, LoggerOptions, UserLogger } from './types.ts'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Wraps a logger definition into a typed {@link Logger}.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* export const myLogger = defineLogger({
|
|
8
|
+
* name: 'my-logger',
|
|
9
|
+
* install(context, options) {
|
|
10
|
+
* context.on('info', (message) => console.log('ℹ', message))
|
|
11
|
+
* context.on('error', (error) => console.error('✗', error.message))
|
|
12
|
+
* },
|
|
13
|
+
* })
|
|
14
|
+
*/
|
|
3
15
|
export function defineLogger<Options extends LoggerOptions = LoggerOptions>(logger: UserLogger<Options>): Logger<Options> {
|
|
4
|
-
return
|
|
5
|
-
...logger,
|
|
6
|
-
}
|
|
16
|
+
return logger
|
|
7
17
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Visitor } from '@kubb/ast/types'
|
|
2
|
+
import type { Generator, Preset, Resolver } from './types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a typed preset object that bundles a name, resolvers, optional
|
|
6
|
+
* transformers, and optional generators — the building block for composable plugin presets.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { definePreset } from '@kubb/core'
|
|
10
|
+
* import { resolverTsLegacy } from '@kubb/plugin-ts'
|
|
11
|
+
*
|
|
12
|
+
* export const myPreset = definePreset('myPreset', { resolvers: [resolverTsLegacy] })
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // With custom transformers
|
|
16
|
+
* export const myPreset = definePreset('myPreset', { resolvers: [resolverTsLegacy], transformers: [myTransformer] })
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // With generators
|
|
20
|
+
* export const myPreset = definePreset('myPreset', { resolvers: [resolverTsLegacy], generators: [typeGeneratorLegacy] })
|
|
21
|
+
*/
|
|
22
|
+
export function definePreset<TResolver extends Resolver = Resolver, TName extends string = string>(
|
|
23
|
+
name: TName,
|
|
24
|
+
{ resolvers, transformers, generators }: { resolvers: Array<TResolver>; transformers?: Array<Visitor>; generators?: Array<Generator<any>> },
|
|
25
|
+
): Preset<TResolver> & { name: TName } {
|
|
26
|
+
return { name, resolvers, transformers, generators }
|
|
27
|
+
}
|