@kubb/core 5.0.0-alpha.2 → 5.0.0-alpha.20

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.
Files changed (55) hide show
  1. package/dist/{types-B7eZvqwD.d.ts → PluginDriver-BkSenc-R.d.ts} +521 -299
  2. package/dist/hooks.cjs +101 -8
  3. package/dist/hooks.cjs.map +1 -1
  4. package/dist/hooks.d.ts +83 -4
  5. package/dist/hooks.js +99 -8
  6. package/dist/hooks.js.map +1 -1
  7. package/dist/index.cjs +850 -536
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +438 -89
  10. package/dist/index.js +839 -532
  11. package/dist/index.js.map +1 -1
  12. package/package.json +6 -6
  13. package/src/Kubb.ts +37 -55
  14. package/src/{PluginManager.ts → PluginDriver.ts} +51 -40
  15. package/src/build.ts +74 -29
  16. package/src/config.ts +9 -8
  17. package/src/constants.ts +44 -1
  18. package/src/createAdapter.ts +25 -0
  19. package/src/createPlugin.ts +28 -0
  20. package/src/createStorage.ts +58 -0
  21. package/src/defineGenerator.ts +134 -0
  22. package/src/defineLogger.ts +13 -3
  23. package/src/definePreset.ts +23 -0
  24. package/src/definePresets.ts +16 -0
  25. package/src/defineResolver.ts +131 -0
  26. package/src/hooks/index.ts +2 -1
  27. package/src/hooks/useKubb.ts +160 -0
  28. package/src/hooks/useMode.ts +5 -2
  29. package/src/hooks/usePlugin.ts +5 -2
  30. package/src/hooks/usePluginDriver.ts +11 -0
  31. package/src/index.ts +12 -6
  32. package/src/renderNode.tsx +108 -0
  33. package/src/storages/fsStorage.ts +2 -2
  34. package/src/storages/memoryStorage.ts +2 -2
  35. package/src/types.ts +150 -38
  36. package/src/utils/FunctionParams.ts +2 -2
  37. package/src/utils/TreeNode.ts +24 -1
  38. package/src/utils/diagnostics.ts +4 -1
  39. package/src/utils/executeStrategies.ts +23 -10
  40. package/src/utils/formatters.ts +10 -21
  41. package/src/utils/getBarrelFiles.ts +79 -9
  42. package/src/utils/getConfigs.ts +8 -22
  43. package/src/utils/getPreset.ts +41 -0
  44. package/src/utils/linters.ts +23 -3
  45. package/src/utils/mergeResolvers.ts +8 -0
  46. package/src/utils/packageJSON.ts +76 -0
  47. package/src/BarrelManager.ts +0 -74
  48. package/src/PackageManager.ts +0 -180
  49. package/src/PromiseManager.ts +0 -40
  50. package/src/defineAdapter.ts +0 -22
  51. package/src/definePlugin.ts +0 -12
  52. package/src/defineStorage.ts +0 -56
  53. package/src/errors.ts +0 -1
  54. package/src/hooks/usePluginManager.ts +0 -8
  55. 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 { BuildError } from './errors.ts'
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, DefineStorage, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
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: Fabric
28
+ fabric: FabricType
25
29
  files: Array<KubbFile.ResolvedFile>
26
- pluginManager: PluginManager
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: Fabric
35
- pluginManager: PluginManager
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: DefineStorage | null = definedConfig.output.write === false ? null : (definedConfig.output.storage ?? fsStorage())
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 pluginManager = new PluginManager(definedConfig, {
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
- pluginManager.rootNode = await definedConfig.adapter.parse(source)
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: ${pluginManager.rootNode.schemas.length}`,
190
- ` • Operations: ${pluginManager.rootNode.operations.length}`,
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
- pluginManager,
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, pluginManager, failedPlugins, pluginTimings, error, sources } = await safeBuild(options, overrides)
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
- pluginManager,
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, pluginManager, events, sources } = overrides ? overrides : await setup(options)
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 = pluginManager.config
274
+ const config = driver.config
234
275
 
235
276
  try {
236
- for (const plugin of pluginManager.plugins) {
237
- const context = pluginManager.getContext(plugin)
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, pluginManager }),
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
- pluginManager,
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
- pluginManager,
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
- pluginManager: PluginManager
401
+ driver: PluginDriver
361
402
  }
362
403
 
363
- function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, pluginManager }: BuildBarrelExportsParams): KubbFile.Export[] {
404
+ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, driver }: BuildBarrelExportsParams): KubbFile.Export[] {
364
405
  const pluginNameMap = new Map<string, Plugin>()
365
- for (const plugin of pluginManager.plugins) {
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
- /** Path to `kubb.config.js` */
8
+ /**
9
+ * Path to `kubb.config.js`.
10
+ */
9
11
  config?: string
10
-
11
- /** Enable watch mode for input files */
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
- /** All accepted forms of a Kubb configuration. */
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
- export const PATH_SEPARATORS = ['/', '\\'] as const
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,134 @@
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
+ adapter: Adapter
14
+ options: Plugin<TPlugin>['options']
15
+ nodes: Array<OperationNode>
16
+ }
17
+
18
+ /**
19
+ * Props for the `operation` lifecycle — receives a single operation node.
20
+ */
21
+ export type OperationV2Props<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
22
+ config: Config
23
+ adapter: Adapter
24
+ options: Plugin<TPlugin>['options']
25
+ node: OperationNode
26
+ }
27
+
28
+ /**
29
+ * Props for the `schema` lifecycle — receives a single schema node.
30
+ */
31
+ export type SchemaV2Props<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
32
+ config: Config
33
+ adapter: Adapter
34
+ options: Plugin<TPlugin>['options']
35
+ node: SchemaNode
36
+ }
37
+
38
+ type UserCoreGeneratorV2<TPlugin extends PluginFactoryOptions> = {
39
+ name: string
40
+ type: 'core'
41
+ version?: '2'
42
+ operations?(props: OperationsV2Props<TPlugin>): Promise<Array<KubbFile.File>>
43
+ operation?(props: OperationV2Props<TPlugin>): Promise<Array<KubbFile.File>>
44
+ schema?(props: SchemaV2Props<TPlugin>): Promise<Array<KubbFile.File>>
45
+ }
46
+
47
+ type UserReactGeneratorV2<TPlugin extends PluginFactoryOptions> = {
48
+ name: string
49
+ type: 'react'
50
+ version?: '2'
51
+ Operations?(props: OperationsV2Props<TPlugin>): FabricReactNode
52
+ Operation?(props: OperationV2Props<TPlugin>): FabricReactNode
53
+ Schema?(props: SchemaV2Props<TPlugin>): FabricReactNode
54
+ }
55
+
56
+ export type CoreGeneratorV2<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
57
+ name: string
58
+ type: 'core'
59
+ version: '2'
60
+ operations(props: OperationsV2Props<TPlugin>): Promise<Array<KubbFile.File>>
61
+ operation(props: OperationV2Props<TPlugin>): Promise<Array<KubbFile.File>>
62
+ schema(props: SchemaV2Props<TPlugin>): Promise<Array<KubbFile.File>>
63
+ }
64
+
65
+ export type ReactGeneratorV2<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = {
66
+ name: string
67
+ type: 'react'
68
+ version: '2'
69
+ Operations(props: OperationsV2Props<TPlugin>): FabricReactNode
70
+ Operation(props: OperationV2Props<TPlugin>): FabricReactNode
71
+ Schema(props: SchemaV2Props<TPlugin>): FabricReactNode
72
+ }
73
+
74
+ export type Generator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions> = UserCoreGeneratorV2<TPlugin> | UserReactGeneratorV2<TPlugin>
75
+
76
+ /**
77
+ * Defines a generator with no-op defaults for any omitted lifecycle methods.
78
+ * Works for both `core` (async file output) and `react` (JSX component) generators.
79
+ *
80
+ * @example
81
+ * // react generator
82
+ * export const typeGenerator = defineGenerator<PluginTs>({
83
+ * name: 'typescript',
84
+ * type: 'react',
85
+ * Operation({ node, options }) { return <File>...</File> },
86
+ * Schema({ node, options }) { return <File>...</File> },
87
+ * })
88
+ *
89
+ * @example
90
+ * // core generator
91
+ * export const myGenerator = defineGenerator<MyPlugin>({
92
+ * name: 'my-generator',
93
+ * type: 'core',
94
+ * async operation({ node, options }) { return [{ path: '...', content: '...' }] },
95
+ * })
96
+ */
97
+ export function defineGenerator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions>(
98
+ generator: UserReactGeneratorV2<TPlugin>,
99
+ ): ReactGeneratorV2<TPlugin>
100
+
101
+ export function defineGenerator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions>(generator: UserCoreGeneratorV2<TPlugin>): CoreGeneratorV2<TPlugin>
102
+ export function defineGenerator<TPlugin extends PluginFactoryOptions = PluginFactoryOptions>(
103
+ generator: UserCoreGeneratorV2<TPlugin> | UserReactGeneratorV2<TPlugin>,
104
+ ): unknown {
105
+ if (generator.type === 'react') {
106
+ return {
107
+ version: '2',
108
+ Operations() {
109
+ return null
110
+ },
111
+ Operation() {
112
+ return null
113
+ },
114
+ Schema() {
115
+ return null
116
+ },
117
+ ...generator,
118
+ }
119
+ }
120
+
121
+ return {
122
+ version: '2',
123
+ async operations() {
124
+ return []
125
+ },
126
+ async operation() {
127
+ return []
128
+ },
129
+ async schema() {
130
+ return []
131
+ },
132
+ ...generator,
133
+ }
134
+ }
@@ -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,23 @@
1
+ import type { Visitor } from '@kubb/ast/types'
2
+ import type { Preset, Resolver } from './types.ts'
3
+
4
+ /**
5
+ * Creates a typed preset object that bundles a name, resolvers, and optional
6
+ * transformers — 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
+ export function definePreset<TResolver extends Resolver = Resolver, TName extends string = string>(
19
+ name: TName,
20
+ { resolvers, transformers }: { resolvers: Array<TResolver>; transformers?: Array<Visitor> },
21
+ ): Preset<TResolver> & { name: TName } {
22
+ return { name, resolvers, transformers }
23
+ }
@@ -0,0 +1,16 @@
1
+ import type { Preset, Presets, Resolver } from './types.ts'
2
+
3
+ /**
4
+ * Creates a typed presets registry object — a named collection of {@link Preset} entries.
5
+ *
6
+ * @example
7
+ * import { definePreset, definePresets } from '@kubb/core'
8
+ * import { resolverTsLegacy } from '@kubb/plugin-ts'
9
+ *
10
+ * export const myPresets = definePresets({
11
+ * kubbV4: definePreset('kubbV4', { resolvers: [resolverTsLegacy] }),
12
+ * })
13
+ */
14
+ export function definePresets<TResolver extends Resolver = Resolver>(presets: Presets<TResolver>): Presets<TResolver> {
15
+ return presets
16
+ }