@kubb/core 5.0.0-beta.7 → 5.0.0-beta.71

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 (49) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +20 -123
  3. package/dist/diagnostics-CJtO1uSM.d.ts +2892 -0
  4. package/dist/index.cjs +2340 -1129
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.ts +80 -289
  7. package/dist/index.js +2330 -1124
  8. package/dist/index.js.map +1 -1
  9. package/dist/memoryStorage-B4VTTIpQ.js +905 -0
  10. package/dist/memoryStorage-B4VTTIpQ.js.map +1 -0
  11. package/dist/memoryStorage-CfycFGzX.cjs +1043 -0
  12. package/dist/memoryStorage-CfycFGzX.cjs.map +1 -0
  13. package/dist/mocks.cjs +84 -24
  14. package/dist/mocks.cjs.map +1 -1
  15. package/dist/mocks.d.ts +37 -11
  16. package/dist/mocks.js +86 -28
  17. package/dist/mocks.js.map +1 -1
  18. package/package.json +9 -23
  19. package/dist/PluginDriver-BkTRD2H2.js +0 -946
  20. package/dist/PluginDriver-BkTRD2H2.js.map +0 -1
  21. package/dist/PluginDriver-Cadu4ORh.cjs +0 -1037
  22. package/dist/PluginDriver-Cadu4ORh.cjs.map +0 -1
  23. package/dist/types-ChyWgIgi.d.ts +0 -2159
  24. package/src/FileManager.ts +0 -115
  25. package/src/FileProcessor.ts +0 -86
  26. package/src/Kubb.ts +0 -300
  27. package/src/PluginDriver.ts +0 -426
  28. package/src/constants.ts +0 -35
  29. package/src/createAdapter.ts +0 -32
  30. package/src/createKubb.ts +0 -573
  31. package/src/createRenderer.ts +0 -57
  32. package/src/createStorage.ts +0 -70
  33. package/src/defineGenerator.ts +0 -87
  34. package/src/defineLogger.ts +0 -36
  35. package/src/defineMiddleware.ts +0 -62
  36. package/src/defineParser.ts +0 -44
  37. package/src/definePlugin.ts +0 -83
  38. package/src/defineResolver.ts +0 -521
  39. package/src/devtools.ts +0 -59
  40. package/src/index.ts +0 -20
  41. package/src/mocks.ts +0 -178
  42. package/src/renderNode.ts +0 -35
  43. package/src/storages/fsStorage.ts +0 -114
  44. package/src/storages/memoryStorage.ts +0 -55
  45. package/src/types.ts +0 -1305
  46. package/src/utils/diagnostics.ts +0 -18
  47. package/src/utils/isInputPath.ts +0 -10
  48. package/src/utils/packageJSON.ts +0 -99
  49. /package/dist/{chunk--u3MIqq1.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/src/createKubb.ts DELETED
@@ -1,573 +0,0 @@
1
- import { resolve } from 'node:path'
2
- import { AsyncEventEmitter, BuildError, exists, formatMs, getElapsedMs, URLPath } from '@internals/utils'
3
- import type { FileNode, OperationNode } from '@kubb/ast'
4
- import { collectUsedSchemaNames, transform, walk } from '@kubb/ast'
5
- import { DEFAULT_BANNER, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
6
- import type { RendererFactory } from './createRenderer.ts'
7
- import type { Generator } from './defineGenerator.ts'
8
- import type { Parser } from './defineParser.ts'
9
- import type { Plugin } from './definePlugin.ts'
10
- import { FileProcessor } from './FileProcessor.ts'
11
- import type { Kubb } from './Kubb.ts'
12
- import { PluginDriver } from './PluginDriver.ts'
13
- import { applyHookResult } from './renderNode.ts'
14
- import { fsStorage } from './storages/fsStorage.ts'
15
- import type { AdapterSource, Config, GeneratorContext, KubbHooks, Middleware, NormalizedPlugin, Storage, UserConfig } from './types.ts'
16
- import { getDiagnosticInfo } from './utils/diagnostics.ts'
17
- import { isInputPath } from './utils/isInputPath.ts'
18
-
19
- type SetupOptions = {
20
- hooks?: AsyncEventEmitter<KubbHooks>
21
- }
22
-
23
- /**
24
- * Full output produced by a successful or failed build.
25
- */
26
- export type BuildOutput = {
27
- /**
28
- * Plugins that threw during installation, paired with the caught error.
29
- */
30
- failedPlugins: Set<{ plugin: Plugin; error: Error }>
31
- files: Array<FileNode>
32
- driver: PluginDriver
33
- /**
34
- * Elapsed time in milliseconds for each plugin, keyed by plugin name.
35
- */
36
- pluginTimings: Map<string, number>
37
- error?: Error
38
- /**
39
- * Raw generated source, keyed by absolute file path.
40
- */
41
- sources: Map<string, string>
42
- }
43
-
44
- type SetupResult = {
45
- hooks: AsyncEventEmitter<KubbHooks>
46
- driver: PluginDriver
47
- sources: Map<string, string>
48
- config: Config
49
- storage: Storage | null
50
- }
51
-
52
- async function setup(userConfig: UserConfig, options: SetupOptions = {}): Promise<SetupResult> {
53
- const hooks = options.hooks ?? new AsyncEventEmitter<KubbHooks>()
54
-
55
- const sources: Map<string, string> = new Map<string, string>()
56
- const diagnosticInfo = getDiagnosticInfo()
57
-
58
- if (Array.isArray(userConfig.input)) {
59
- await hooks.emit('kubb:warn', { message: 'This feature is still under development — use with caution' })
60
- }
61
-
62
- await hooks.emit('kubb:debug', {
63
- date: new Date(),
64
- logs: [
65
- 'Configuration:',
66
- ` • Name: ${userConfig.name || 'unnamed'}`,
67
- ` • Root: ${userConfig.root || process.cwd()}`,
68
- ` • Output: ${userConfig.output?.path || 'not specified'}`,
69
- ` • Plugins: ${userConfig.plugins?.length || 0}`,
70
- 'Output Settings:',
71
- ` • Storage: ${userConfig.storage ? `custom(${userConfig.storage.name})` : userConfig.output?.write === false ? 'disabled' : 'filesystem (default)'}`,
72
- ` • Formatter: ${userConfig.output?.format || 'none'}`,
73
- ` • Linter: ${userConfig.output?.lint || 'none'}`,
74
- 'Environment:',
75
- Object.entries(diagnosticInfo)
76
- .map(([key, value]) => ` • ${key}: ${value}`)
77
- .join('\n'),
78
- ],
79
- })
80
-
81
- try {
82
- if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
83
- await exists(userConfig.input.path)
84
-
85
- await hooks.emit('kubb:debug', {
86
- date: new Date(),
87
- logs: [`✓ Input file validated: ${userConfig.input.path}`],
88
- })
89
- }
90
- } catch (caughtError) {
91
- if (isInputPath(userConfig)) {
92
- const error = caughtError as Error
93
-
94
- throw new Error(
95
- `Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${userConfig.input.path}`,
96
- {
97
- cause: error,
98
- },
99
- )
100
- }
101
- }
102
-
103
- const config: Config = {
104
- ...userConfig,
105
- root: userConfig.root || process.cwd(),
106
- parsers: userConfig.parsers ?? [],
107
- adapter: userConfig.adapter,
108
- output: {
109
- format: false,
110
- lint: false,
111
- write: true,
112
- extension: DEFAULT_EXTENSION,
113
- defaultBanner: DEFAULT_BANNER,
114
- ...userConfig.output,
115
- },
116
- devtools: userConfig.devtools
117
- ? {
118
- studioUrl: DEFAULT_STUDIO_URL,
119
- ...(typeof userConfig.devtools === 'boolean' ? {} : userConfig.devtools),
120
- }
121
- : undefined,
122
- plugins: (userConfig.plugins ?? []) as unknown as Config['plugins'],
123
- }
124
-
125
- const storage: Storage | null = config.output.write === false ? null : (config.storage ?? fsStorage())
126
-
127
- if (config.output.clean) {
128
- await hooks.emit('kubb:debug', {
129
- date: new Date(),
130
- logs: ['Cleaning output directories', ` • Output: ${config.output.path}`],
131
- })
132
- await storage?.clear(resolve(config.root, config.output.path))
133
- }
134
-
135
- const driver = new PluginDriver(config, {
136
- hooks,
137
- })
138
-
139
- // Register middleware hooks after all plugin hooks are registered.
140
- // Because AsyncEventEmitter calls listeners in registration order,
141
- // middleware hooks for any event fire after all plugin hooks for that event.
142
- function registerMiddlewareHook<K extends keyof KubbHooks & string>(event: K, middlewareHooks: Middleware['hooks']) {
143
- const handler = middlewareHooks[event]
144
- if (handler) {
145
- hooks.on(event, handler)
146
- }
147
- }
148
-
149
- for (const middleware of config.middleware ?? []) {
150
- for (const event of Object.keys(middleware.hooks) as Array<keyof KubbHooks & string>) {
151
- registerMiddlewareHook(event, middleware.hooks)
152
- }
153
- }
154
-
155
- if (config.adapter) {
156
- const source = inputToAdapterSource(config)
157
-
158
- await hooks.emit('kubb:debug', {
159
- date: new Date(),
160
- logs: [`Running adapter: ${config.adapter.name}`],
161
- })
162
-
163
- driver.adapter = config.adapter
164
- driver.inputNode = await config.adapter.parse(source)
165
-
166
- await hooks.emit('kubb:debug', {
167
- date: new Date(),
168
- logs: [
169
- `✓ Adapter '${config.adapter.name}' resolved InputNode`,
170
- ` • Schemas: ${driver.inputNode.schemas.length}`,
171
- ` • Operations: ${driver.inputNode.operations.length}`,
172
- ],
173
- })
174
- }
175
-
176
- return {
177
- config,
178
- hooks,
179
- driver,
180
- sources,
181
- storage,
182
- }
183
- }
184
-
185
- /**
186
- * Walks the AST and dispatches nodes to a plugin's direct AST hooks
187
- * (`schema`, `operation`, `operations`).
188
- *
189
- * When `include` contains only operation-scoped filters (`tag`, `operationId`, `path`,
190
- * `method`, `contentType`) and no `schemaName` filter, the function pre-computes the set
191
- * of top-level schema names transitively reachable from the included operations and skips
192
- * schemas that fall outside that set. This ensures that component schemas referenced
193
- * exclusively by excluded operations are not generated.
194
- */
195
- async function runPluginAstHooks(plugin: NormalizedPlugin, context: GeneratorContext): Promise<void> {
196
- const { adapter, inputNode, resolver, driver } = context
197
- const { exclude, include, override } = plugin.options
198
-
199
- if (!adapter || !inputNode) {
200
- throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`)
201
- }
202
-
203
- function resolveRenderer(gen: Generator): RendererFactory | undefined {
204
- return gen.renderer === null ? undefined : (gen.renderer ?? plugin.renderer ?? context.config.renderer)
205
- }
206
-
207
- const generators = plugin.generators ?? []
208
- const collectedOperations: Array<OperationNode> = []
209
-
210
- const generatorContext = {
211
- ...context,
212
- resolver: driver.getResolver(plugin.name),
213
- }
214
-
215
- // When `include` has operation-based filters (tag, operationId, path, method, contentType)
216
- // but no schema-level filters (schemaName), pre-compute the set of top-level schema names
217
- // that are transitively referenced by the included operations. Schemas outside that set are
218
- // skipped so that types belonging exclusively to excluded operations are not generated.
219
- const operationFilterTypes = new Set(['tag', 'operationId', 'path', 'method', 'contentType'])
220
- const hasOperationBasedIncludes = include?.some(({ type }) => operationFilterTypes.has(type)) ?? false
221
- const hasSchemaNameIncludes = include?.some(({ type }) => type === 'schemaName') ?? false
222
-
223
- let allowedSchemaNames: Set<string> | undefined
224
- if (hasOperationBasedIncludes && !hasSchemaNameIncludes) {
225
- const includedOps = inputNode.operations.filter((op) => resolver.resolveOptions(op, { options: plugin.options, exclude, include, override }) !== null)
226
- allowedSchemaNames = collectUsedSchemaNames(includedOps, inputNode.schemas)
227
- }
228
-
229
- await walk(inputNode, {
230
- depth: 'shallow',
231
- async schema(node) {
232
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
233
-
234
- // Skip named top-level schemas that are not reachable from any included operation.
235
- if (allowedSchemaNames !== undefined && transformedNode.name && !allowedSchemaNames.has(transformedNode.name)) {
236
- return
237
- }
238
-
239
- const options = resolver.resolveOptions(transformedNode, {
240
- options: plugin.options,
241
- exclude,
242
- include,
243
- override,
244
- })
245
- if (options === null) return
246
-
247
- const ctx = { ...generatorContext, options }
248
-
249
- for (const gen of generators) {
250
- if (!gen.schema) continue
251
- const result = await gen.schema(transformedNode, ctx)
252
- await applyHookResult(result, driver, resolveRenderer(gen))
253
- }
254
-
255
- await driver.hooks.emit('kubb:generate:schema', transformedNode, ctx)
256
- },
257
- async operation(node) {
258
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node
259
- const options = resolver.resolveOptions(transformedNode, {
260
- options: plugin.options,
261
- exclude,
262
- include,
263
- override,
264
- })
265
- if (options !== null) {
266
- collectedOperations.push(transformedNode)
267
-
268
- const ctx = { ...generatorContext, options }
269
-
270
- for (const gen of generators) {
271
- if (!gen.operation) continue
272
- const result = await gen.operation(transformedNode, ctx)
273
- await applyHookResult(result, driver, resolveRenderer(gen))
274
- }
275
-
276
- await driver.hooks.emit('kubb:generate:operation', transformedNode, ctx)
277
- }
278
- },
279
- })
280
-
281
- if (collectedOperations.length > 0) {
282
- const ctx = { ...generatorContext, options: plugin.options }
283
-
284
- for (const gen of generators) {
285
- if (!gen.operations) continue
286
- const result = await gen.operations(collectedOperations, ctx)
287
- await applyHookResult(result, driver, resolveRenderer(gen))
288
- }
289
-
290
- await driver.hooks.emit('kubb:generate:operations', collectedOperations, ctx)
291
- }
292
- }
293
-
294
- async function safeBuild(setupResult: SetupResult): Promise<BuildOutput> {
295
- const { driver, hooks, sources, storage } = setupResult
296
-
297
- const failedPlugins = new Set<{ plugin: Plugin; error: Error }>()
298
- const pluginTimings = new Map<string, number>()
299
- const config = driver.config
300
-
301
- try {
302
- await driver.emitSetupHooks()
303
-
304
- if (driver.adapter && driver.inputNode) {
305
- await hooks.emit('kubb:build:start', {
306
- config,
307
- adapter: driver.adapter,
308
- inputNode: driver.inputNode,
309
- getPlugin: driver.getPlugin.bind(driver),
310
- get files() {
311
- return driver.fileManager.files
312
- },
313
- upsertFile: (...files) => driver.fileManager.upsert(...files),
314
- })
315
- }
316
-
317
- for (const plugin of driver.plugins.values()) {
318
- const context = driver.getContext(plugin)
319
- const hrStart = process.hrtime()
320
-
321
- try {
322
- const timestamp = new Date()
323
-
324
- await hooks.emit('kubb:plugin:start', { plugin })
325
-
326
- await hooks.emit('kubb:debug', {
327
- date: timestamp,
328
- logs: ['Starting plugin...', ` • Plugin Name: ${plugin.name}`],
329
- })
330
-
331
- if (plugin.generators?.length || driver.hasRegisteredGenerators(plugin.name)) {
332
- await runPluginAstHooks(plugin, context)
333
- }
334
-
335
- const duration = getElapsedMs(hrStart)
336
- pluginTimings.set(plugin.name, duration)
337
-
338
- await hooks.emit('kubb:plugin:end', {
339
- plugin,
340
- duration,
341
- success: true,
342
- config,
343
- get files() {
344
- return driver.fileManager.files
345
- },
346
- upsertFile: (...files) => driver.fileManager.upsert(...files),
347
- })
348
-
349
- await hooks.emit('kubb:debug', {
350
- date: new Date(),
351
- logs: [`✓ Plugin started successfully (${formatMs(duration)})`],
352
- })
353
- } catch (caughtError) {
354
- const error = caughtError as Error
355
- const errorTimestamp = new Date()
356
- const duration = getElapsedMs(hrStart)
357
-
358
- await hooks.emit('kubb:plugin:end', {
359
- plugin,
360
- duration,
361
- success: false,
362
- error,
363
- config,
364
- get files() {
365
- return driver.fileManager.files
366
- },
367
- upsertFile: (...files) => driver.fileManager.upsert(...files),
368
- })
369
-
370
- await hooks.emit('kubb:debug', {
371
- date: errorTimestamp,
372
- logs: [
373
- '✗ Plugin start failed',
374
- ` • Plugin Name: ${plugin.name}`,
375
- ` • Error: ${error.constructor.name} - ${error.message}`,
376
- ' • Stack Trace:',
377
- error.stack || 'No stack trace available',
378
- ],
379
- })
380
-
381
- failedPlugins.add({ plugin, error })
382
- }
383
- }
384
-
385
- await hooks.emit('kubb:plugins:end', {
386
- config,
387
- get files() {
388
- return driver.fileManager.files
389
- },
390
- upsertFile: (...files) => driver.fileManager.upsert(...files),
391
- })
392
-
393
- const files = driver.fileManager.files
394
-
395
- const parsersMap = new Map<FileNode['extname'], Parser>()
396
- for (const parser of config.parsers) {
397
- if (parser.extNames) {
398
- for (const extname of parser.extNames) {
399
- parsersMap.set(extname, parser)
400
- }
401
- }
402
- }
403
-
404
- const fileProcessor = new FileProcessor()
405
-
406
- await hooks.emit('kubb:debug', {
407
- date: new Date(),
408
- logs: [`Writing ${files.length} files...`],
409
- })
410
-
411
- await fileProcessor.run(files, {
412
- parsers: parsersMap,
413
- extension: config.output.extension,
414
- onStart: async (processingFiles) => {
415
- await hooks.emit('kubb:files:processing:start', { files: processingFiles })
416
- },
417
- onUpdate: async ({ file, source, processed, total, percentage }) => {
418
- await hooks.emit('kubb:file:processing:update', {
419
- file,
420
- source,
421
- processed,
422
- total,
423
- percentage,
424
- config,
425
- })
426
- if (source) {
427
- await storage?.setItem(file.path, source)
428
- sources.set(file.path, source)
429
- }
430
- },
431
- onEnd: async (processedFiles) => {
432
- await hooks.emit('kubb:files:processing:end', { files: processedFiles })
433
- await hooks.emit('kubb:debug', {
434
- date: new Date(),
435
- logs: [`✓ File write process completed for ${processedFiles.length} files`],
436
- })
437
- },
438
- })
439
-
440
- await hooks.emit('kubb:build:end', {
441
- files,
442
- config,
443
- outputDir: resolve(config.root, config.output.path),
444
- })
445
-
446
- return {
447
- failedPlugins,
448
- files,
449
- driver,
450
- pluginTimings,
451
- sources,
452
- }
453
- } catch (error) {
454
- return {
455
- failedPlugins,
456
- files: [],
457
- driver,
458
- pluginTimings,
459
- error: error as Error,
460
- sources,
461
- }
462
- } finally {
463
- driver.dispose()
464
- }
465
- }
466
-
467
- async function build(setupResult: SetupResult): Promise<BuildOutput> {
468
- const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(setupResult)
469
-
470
- if (error) {
471
- throw error
472
- }
473
-
474
- if (failedPlugins.size > 0) {
475
- const errors = [...failedPlugins].map(({ error }) => error)
476
-
477
- throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors })
478
- }
479
-
480
- return {
481
- failedPlugins,
482
- files,
483
- driver,
484
- pluginTimings,
485
- error: undefined,
486
- sources,
487
- }
488
- }
489
-
490
- function inputToAdapterSource(config: Config): AdapterSource {
491
- const input = config.input
492
- if (!input) {
493
- throw new Error('[kubb] input is required when using an adapter. Provide input.path or input.data in your config.')
494
- }
495
-
496
- if (Array.isArray(input)) {
497
- return {
498
- type: 'paths',
499
- paths: input.map((i) => (new URLPath(i.path).isURL ? i.path : resolve(config.root, i.path))),
500
- }
501
- }
502
-
503
- if ('data' in input) {
504
- return { type: 'data', data: input.data }
505
- }
506
-
507
- if (new URLPath(input.path).isURL) {
508
- return { type: 'path', path: input.path }
509
- }
510
-
511
- const resolved = resolve(config.root, input.path)
512
- return { type: 'path', path: resolved }
513
- }
514
-
515
- type CreateKubbOptions = {
516
- hooks?: AsyncEventEmitter<KubbHooks>
517
- }
518
-
519
- /**
520
- * Creates a Kubb instance bound to a single config entry.
521
- *
522
- * Accepts a user-facing config shape and resolves it to a full {@link Config} during
523
- * `setup()`. The instance then holds shared state (`hooks`, `sources`, `driver`, `config`)
524
- * across the `setup → build` lifecycle. Attach event listeners to `kubb.hooks` before
525
- * calling `setup()` or `build()`.
526
- *
527
- * @example
528
- * ```ts
529
- * const kubb = createKubb(userConfig)
530
- *
531
- * kubb.hooks.on('kubb:plugin:end', ({ plugin, duration }) => {
532
- * console.log(`${plugin.name} completed in ${duration}ms`)
533
- * })
534
- *
535
- * const { files, failedPlugins } = await kubb.safeBuild()
536
- * ```
537
- */
538
- export function createKubb(userConfig: UserConfig, options: CreateKubbOptions = {}): Kubb {
539
- const hooks = options.hooks ?? new AsyncEventEmitter<KubbHooks>()
540
- let setupResult: SetupResult | undefined
541
-
542
- const instance: Kubb = {
543
- get hooks() {
544
- return hooks
545
- },
546
- get sources() {
547
- return setupResult?.sources ?? new Map()
548
- },
549
- get driver() {
550
- return setupResult?.driver
551
- },
552
- get config() {
553
- return setupResult?.config
554
- },
555
- async setup() {
556
- setupResult = await setup(userConfig, { hooks })
557
- },
558
- async build() {
559
- if (!setupResult) {
560
- await instance.setup()
561
- }
562
- return build(setupResult!)
563
- },
564
- async safeBuild() {
565
- if (!setupResult) {
566
- await instance.setup()
567
- }
568
- return safeBuild(setupResult!)
569
- },
570
- }
571
-
572
- return instance
573
- }
@@ -1,57 +0,0 @@
1
- import type { FileNode } from '@kubb/ast'
2
-
3
- /**
4
- * Minimal interface any Kubb renderer must satisfy.
5
- *
6
- * The generic `TElement` is the type of the element the renderer accepts —
7
- * e.g. `KubbReactElement` for `@kubb/renderer-jsx`, or a custom type for
8
- * your own renderer. Defaults to `unknown` so that generators which do not
9
- * care about the element type continue to work without specifying it.
10
- *
11
- * This allows core to drive rendering without a hard dependency on
12
- * `@kubb/renderer-jsx` or any specific renderer implementation.
13
- */
14
- export type Renderer<TElement = unknown> = {
15
- render(element: TElement): Promise<void>
16
- unmount(error?: Error | number | null): void
17
- readonly files: Array<FileNode>
18
- }
19
-
20
- /**
21
- * A factory function that produces a fresh {@link Renderer} per render.
22
- *
23
- * Generators use this to declare which renderer handles their output.
24
- */
25
- export type RendererFactory<TElement = unknown> = () => Renderer<TElement>
26
-
27
- /**
28
- * Creates a renderer factory for use in generator definitions.
29
- *
30
- * Wrap your renderer factory function with this helper to register it as the
31
- * renderer for a generator. Core will call this factory once per render cycle
32
- * to obtain a fresh renderer instance.
33
- *
34
- * @example
35
- * ```ts
36
- * // packages/renderer-jsx/src/index.ts
37
- * export const jsxRenderer = createRenderer(() => {
38
- * const runtime = new Runtime()
39
- * return {
40
- * async render(element) { await runtime.render(element) },
41
- * get files() { return runtime.nodes },
42
- * unmount(error) { runtime.unmount(error) },
43
- * }
44
- * })
45
- *
46
- * // packages/plugin-zod/src/generators/zodGenerator.tsx
47
- * import { jsxRenderer } from '@kubb/renderer-jsx'
48
- * export const zodGenerator = defineGenerator<PluginZod>({
49
- * name: 'zod',
50
- * renderer: jsxRenderer,
51
- * schema(node, options) { return <File ...>...</File> },
52
- * })
53
- * ```
54
- */
55
- export function createRenderer<TElement = unknown>(factory: RendererFactory<TElement>): RendererFactory<TElement> {
56
- return factory
57
- }
@@ -1,70 +0,0 @@
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
- * Factory for implementing custom storage backends that control where generated files are written.
38
- *
39
- * Takes a builder function `(options: TOptions) => Storage` and returns a factory `(options?: TOptions) => Storage`.
40
- * Kubb provides filesystem and in-memory implementations out of the box.
41
- *
42
- * @note Call the returned factory with optional options to instantiate the storage adapter.
43
- *
44
- * @example
45
- * ```ts
46
- * import { createStorage } from '@kubb/core'
47
- *
48
- * export const memoryStorage = createStorage(() => {
49
- * const store = new Map<string, string>()
50
- * return {
51
- * name: 'memory',
52
- * async hasItem(key) { return store.has(key) },
53
- * async getItem(key) { return store.get(key) ?? null },
54
- * async setItem(key, value) { store.set(key, value) },
55
- * async removeItem(key) { store.delete(key) },
56
- * async getKeys(base) {
57
- * const keys = [...store.keys()]
58
- * return base ? keys.filter((k) => k.startsWith(base)) : keys
59
- * },
60
- * async clear(base) { if (!base) store.clear() },
61
- * }
62
- * })
63
- *
64
- * // Instantiate:
65
- * const storage = memoryStorage()
66
- * ```
67
- */
68
- export function createStorage<TOptions = Record<string, never>>(build: (options: TOptions) => Storage): (options?: TOptions) => Storage {
69
- return (options) => build(options ?? ({} as TOptions))
70
- }