@kubb/core 5.0.0-beta.35 → 5.0.0-beta.37
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/{KubbDriver-T8W1wm4O.cjs → KubbDriver-CXoKVRxI.cjs} +1091 -413
- package/dist/KubbDriver-CXoKVRxI.cjs.map +1 -0
- package/dist/{KubbDriver-7JLUadUM.js → KubbDriver-CckeYpMG.js} +1050 -402
- package/dist/KubbDriver-CckeYpMG.js.map +1 -0
- package/dist/{createKubb-BKpcUB6g.d.ts → diagnostics-B0ONXReg.d.ts} +790 -287
- package/dist/index.cjs +48 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +40 -90
- package/dist/index.js.map +1 -1
- package/dist/mocks.cjs +23 -23
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +2 -2
- package/dist/mocks.js +23 -23
- package/dist/mocks.js.map +1 -1
- package/package.json +4 -4
- package/src/FileManager.ts +23 -18
- package/src/FileProcessor.ts +142 -24
- package/src/HookRegistry.ts +45 -0
- package/src/KubbDriver.ts +333 -319
- package/src/Transform.ts +58 -0
- package/src/constants.ts +105 -11
- package/src/createKubb.ts +95 -201
- package/src/createRenderer.ts +2 -2
- package/src/createReporter.ts +84 -0
- package/src/createStorage.ts +1 -1
- package/src/defineGenerator.ts +11 -7
- package/src/defineParser.ts +1 -1
- package/src/definePlugin.ts +10 -22
- package/src/defineResolver.ts +29 -24
- package/src/devtools.ts +2 -3
- package/src/diagnostics.ts +591 -0
- package/src/index.ts +11 -1
- package/src/mocks.ts +5 -5
- package/src/types.ts +16 -4
- package/dist/KubbDriver-7JLUadUM.js.map +0 -1
- package/dist/KubbDriver-T8W1wm4O.cjs.map +0 -1
package/src/createKubb.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
|
-
import { version as nodeVersion } from 'node:process'
|
|
3
2
|
import type { PossiblePromise } from '@internals/utils'
|
|
4
|
-
import { AsyncEventEmitter, BuildError
|
|
3
|
+
import { AsyncEventEmitter, BuildError } from '@internals/utils'
|
|
5
4
|
import type { FileNode, InputMeta, OperationNode, SchemaNode } from '@kubb/ast'
|
|
6
|
-
import {
|
|
7
|
-
import { DEFAULT_BANNER, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
5
|
+
import { DEFAULT_STUDIO_URL, HOOK_LISTENERS_PER_PLUGIN } from './constants.ts'
|
|
8
6
|
import type { Adapter } from './createAdapter.ts'
|
|
9
|
-
import type
|
|
7
|
+
import { type Diagnostic, DiagnosticError, Diagnostics, isProblemDiagnostic, type ProblemDiagnostic, type UpdateDiagnostic } from './diagnostics.ts'
|
|
10
8
|
import { createStorage, type Storage } from './createStorage.ts'
|
|
11
9
|
import type { GeneratorContext } from './defineGenerator.ts'
|
|
12
10
|
import type { Middleware } from './defineMiddleware.ts'
|
|
13
11
|
import type { Parser } from './defineParser.ts'
|
|
14
12
|
import type { KubbPluginEndContext, KubbPluginSetupContext, KubbPluginStartContext, Plugin } from './definePlugin.ts'
|
|
13
|
+
import type { ReporterName } from './createReporter.ts'
|
|
15
14
|
|
|
16
15
|
import { KubbDriver } from './KubbDriver.ts'
|
|
17
16
|
import { fsStorage } from './storages/fsStorage.ts'
|
|
@@ -26,10 +25,8 @@ import { fsStorage } from './storages/fsStorage.ts'
|
|
|
26
25
|
type ExtractRegistryKey<T, K extends PropertyKey> = K extends keyof T ? T[K] : {}
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Specify an absolute path or a path relative to the config file location.
|
|
32
|
-
* The adapter will parse this file (e.g., OpenAPI YAML or JSON) into the universal AST.
|
|
28
|
+
* Path to an input file to generate from, absolute or relative to the config file. The adapter
|
|
29
|
+
* parses it (e.g. an OpenAPI YAML or JSON spec) into the universal AST.
|
|
33
30
|
*/
|
|
34
31
|
export type InputPath = {
|
|
35
32
|
/**
|
|
@@ -45,10 +42,8 @@ export type InputPath = {
|
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
/**
|
|
48
|
-
* Inline
|
|
49
|
-
*
|
|
50
|
-
* Useful when you want to pass the specification directly instead of from a file.
|
|
51
|
-
* Can be a string (YAML/JSON) or a parsed object.
|
|
45
|
+
* Inline spec to generate from, passed directly instead of read from a file. A string
|
|
46
|
+
* (YAML/JSON) or a parsed object.
|
|
52
47
|
*/
|
|
53
48
|
export type InputData = {
|
|
54
49
|
/**
|
|
@@ -66,15 +61,9 @@ export type InputData = {
|
|
|
66
61
|
type Input = InputPath | InputData
|
|
67
62
|
|
|
68
63
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* - What to generate from (adapter + input)
|
|
73
|
-
* - Where to output generated code (output)
|
|
74
|
-
* - How to generate (plugins + middleware)
|
|
75
|
-
* - Runtime details (parsers, storage, renderer)
|
|
76
|
-
*
|
|
77
|
-
* See `UserConfig` for a relaxed version with sensible defaults.
|
|
64
|
+
* Resolved build configuration for a Kubb run: what to generate from (adapter, input), where to
|
|
65
|
+
* write it (output), how (plugins, middleware), and the runtime pieces (parsers, storage). See
|
|
66
|
+
* `UserConfig` for the relaxed form with defaults applied.
|
|
78
67
|
*
|
|
79
68
|
* @private
|
|
80
69
|
*/
|
|
@@ -91,16 +80,16 @@ export type Config<TInput = Input> = {
|
|
|
91
80
|
name?: string
|
|
92
81
|
/**
|
|
93
82
|
* Project root directory, absolute or relative to the config file. Already
|
|
94
|
-
* resolved on the `Config` instance
|
|
95
|
-
* form that defaults to `process.cwd()
|
|
83
|
+
* resolved on the `Config` instance (see `UserConfig` for the optional
|
|
84
|
+
* form that defaults to `process.cwd()`).
|
|
96
85
|
*/
|
|
97
86
|
root: string
|
|
98
87
|
/**
|
|
99
88
|
* Parsers that convert generated files into strings. Each parser handles a
|
|
100
|
-
* set of file extensions
|
|
89
|
+
* set of file extensions, and a fallback parser handles anything else.
|
|
101
90
|
*
|
|
102
|
-
* Already resolved on the `Config` instance
|
|
103
|
-
* optional form that defaults to `[parserTs, parserTsx, parserMd]
|
|
91
|
+
* Already resolved on the `Config` instance (see `UserConfig` for the
|
|
92
|
+
* optional form that defaults to `[parserTs, parserTsx, parserMd]`).
|
|
104
93
|
*
|
|
105
94
|
* @example
|
|
106
95
|
* ```ts
|
|
@@ -134,15 +123,13 @@ export type Config<TInput = Input> = {
|
|
|
134
123
|
/**
|
|
135
124
|
* Source file or data to generate code from.
|
|
136
125
|
* Use `input.path` for a file path or `input.data` for inline data.
|
|
137
|
-
* Required when an adapter is configured
|
|
126
|
+
* Required when an adapter is configured. Omit it when running in plugin-only mode.
|
|
138
127
|
*/
|
|
139
128
|
input?: TInput
|
|
140
129
|
output: {
|
|
141
130
|
/**
|
|
142
|
-
* Output directory for generated files, absolute or relative to `root`.
|
|
143
|
-
*
|
|
144
|
-
* All generated files will be written under this directory. Subdirectories can be created
|
|
145
|
-
* by plugins based on grouping strategy (by tag, path, etc.).
|
|
131
|
+
* Output directory for generated files, absolute or relative to `root`. Plugins can nest
|
|
132
|
+
* subdirectories under it by grouping strategy (tag, path).
|
|
146
133
|
*
|
|
147
134
|
* @example
|
|
148
135
|
* ```ts
|
|
@@ -153,10 +140,8 @@ export type Config<TInput = Input> = {
|
|
|
153
140
|
*/
|
|
154
141
|
path: string
|
|
155
142
|
/**
|
|
156
|
-
* Remove
|
|
157
|
-
*
|
|
158
|
-
* Useful to ensure old generated files aren't mixed with new ones.
|
|
159
|
-
* Set to `true` for fresh builds, `false` to preserve manual edits in output dir.
|
|
143
|
+
* Remove every file in the output directory before the build, so stale output isn't mixed
|
|
144
|
+
* with new files. Leave `false` to preserve manual edits in the output directory.
|
|
160
145
|
*
|
|
161
146
|
* @default false
|
|
162
147
|
* @example
|
|
@@ -166,10 +151,8 @@ export type Config<TInput = Input> = {
|
|
|
166
151
|
*/
|
|
167
152
|
clean?: boolean
|
|
168
153
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* Applies a code formatter to all generated files. Use `'auto'` to detect which formatter
|
|
172
|
-
* is available on your system. Pass `false` to skip formatting (useful for CI or specific workflows).
|
|
154
|
+
* Format the generated files after generation. `'auto'` runs the first formatter it finds
|
|
155
|
+
* (oxfmt, biome, or prettier), a named tool forces that one, and `false` skips formatting.
|
|
173
156
|
*
|
|
174
157
|
* @default false
|
|
175
158
|
* @example
|
|
@@ -181,10 +164,8 @@ export type Config<TInput = Input> = {
|
|
|
181
164
|
*/
|
|
182
165
|
format?: 'auto' | 'prettier' | 'biome' | 'oxfmt' | false
|
|
183
166
|
/**
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* Analyzes all generated files for style/correctness issues. Use `'auto'` to detect which linter
|
|
187
|
-
* is available on your system. Pass `false` to skip linting.
|
|
167
|
+
* Lint the generated files after generation. `'auto'` runs the first linter it finds
|
|
168
|
+
* (oxlint, biome, or eslint), a named tool forces that one, and `false` skips linting.
|
|
188
169
|
*
|
|
189
170
|
* @default false
|
|
190
171
|
* @example
|
|
@@ -196,10 +177,8 @@ export type Config<TInput = Input> = {
|
|
|
196
177
|
*/
|
|
197
178
|
lint?: 'auto' | 'eslint' | 'biome' | 'oxlint' | false
|
|
198
179
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* Useful when you want generated `.ts` imports to reference `.js` files or vice versa (e.g., for ESM dual packages).
|
|
202
|
-
* Keys are the original extension, values are the output extension. Use empty string `''` to omit extension.
|
|
180
|
+
* Rewrite import extensions in generated files, e.g. emit `.js` imports from `.ts` sources for
|
|
181
|
+
* ESM dual packages. Keys are the source extension, values the output, and `''` drops it.
|
|
203
182
|
*
|
|
204
183
|
* @default { '.ts': '.ts' }
|
|
205
184
|
* @example
|
|
@@ -210,10 +189,8 @@ export type Config<TInput = Input> = {
|
|
|
210
189
|
*/
|
|
211
190
|
extension?: Record<FileNode['extname'], FileNode['extname'] | ''>
|
|
212
191
|
/**
|
|
213
|
-
* Banner
|
|
214
|
-
*
|
|
215
|
-
* Useful for auto-generation notices or license headers. Choose a preset or write custom text.
|
|
216
|
-
* Use `'simple'` for a basic Kubb banner, `'full'` for detailed metadata, or `false` to omit.
|
|
192
|
+
* Banner prepended to every generated file. `'simple'` is the basic Kubb notice, `'full'` adds
|
|
193
|
+
* source, title, description, and API version, and `false` omits it.
|
|
217
194
|
*
|
|
218
195
|
* @default 'simple'
|
|
219
196
|
* @example
|
|
@@ -225,10 +202,8 @@ export type Config<TInput = Input> = {
|
|
|
225
202
|
*/
|
|
226
203
|
defaultBanner?: 'simple' | 'full' | false
|
|
227
204
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* Individual plugins can override this setting. This is useful for preventing accidental data loss
|
|
231
|
-
* when re-generating while you have local edits in the output folder.
|
|
205
|
+
* Overwrite existing files when `true`, skip files that already exist when `false`. Individual
|
|
206
|
+
* plugins can override it. Keep `false` to avoid clobbering local edits in the output folder.
|
|
232
207
|
*
|
|
233
208
|
* @default false
|
|
234
209
|
* @example
|
|
@@ -240,10 +215,8 @@ export type Config<TInput = Input> = {
|
|
|
240
215
|
override?: boolean
|
|
241
216
|
} & ExtractRegistryKey<Kubb.ConfigOptionsRegistry, 'output'>
|
|
242
217
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* Defaults to `fsStorage()` which writes to the file system. Pass `memoryStorage()` to keep files in RAM,
|
|
246
|
-
* or implement a custom `Storage` interface to write to cloud storage, databases, or other backends.
|
|
218
|
+
* Where generated files are persisted. Defaults to `fsStorage()` (disk). Pass `memoryStorage()`
|
|
219
|
+
* to keep files in RAM, or implement `Storage` for a custom backend such as cloud or a database.
|
|
247
220
|
*
|
|
248
221
|
* @default fsStorage()
|
|
249
222
|
* @example
|
|
@@ -261,13 +234,9 @@ export type Config<TInput = Input> = {
|
|
|
261
234
|
*/
|
|
262
235
|
storage: Storage
|
|
263
236
|
/**
|
|
264
|
-
* Plugins that
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
* programming languages or formats (TypeScript, Zod schemas, Faker data, etc.).
|
|
268
|
-
* Dependencies are enforced — an error is thrown if a plugin requires another plugin that isn't registered.
|
|
269
|
-
*
|
|
270
|
-
* Plugins can declare their own options via `PluginFactoryOptions`. See plugin documentation for details.
|
|
237
|
+
* Plugins that run during the build to generate code and transform the AST. Each one processes
|
|
238
|
+
* the adapter's AST and can emit files for a different target (TypeScript, Zod, Faker). A plugin
|
|
239
|
+
* that depends on another throws when that plugin isn't registered.
|
|
271
240
|
*
|
|
272
241
|
* @example
|
|
273
242
|
* ```ts
|
|
@@ -300,22 +269,6 @@ export type Config<TInput = Input> = {
|
|
|
300
269
|
* @see {@link defineMiddleware} to create custom middleware.
|
|
301
270
|
*/
|
|
302
271
|
middleware?: Array<Middleware>
|
|
303
|
-
/**
|
|
304
|
-
* Renderer that converts generated AST nodes to code strings.
|
|
305
|
-
*
|
|
306
|
-
* By default, Kubb uses the JSX renderer (`rendererJsx`). Pass a custom renderer to support
|
|
307
|
-
* different output formats (template engines, code generation DSLs, etc.).
|
|
308
|
-
*
|
|
309
|
-
* @default rendererJsx() // from @kubb/renderer-jsx
|
|
310
|
-
* @example
|
|
311
|
-
* ```ts
|
|
312
|
-
* import { rendererJsx } from '@kubb/renderer-jsx'
|
|
313
|
-
* renderer: rendererJsx()
|
|
314
|
-
* ```
|
|
315
|
-
*
|
|
316
|
-
* @see {@link Renderer} to implement a custom renderer.
|
|
317
|
-
*/
|
|
318
|
-
renderer?: RendererFactory
|
|
319
272
|
/**
|
|
320
273
|
* Kubb Studio cloud integration settings.
|
|
321
274
|
*
|
|
@@ -369,6 +322,22 @@ export type Config<TInput = Input> = {
|
|
|
369
322
|
*/
|
|
370
323
|
done?: string | Array<string>
|
|
371
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Reporters that render the run's output, like Vitest. List one or more by name;
|
|
327
|
+
* the CLI `--reporter` flag overrides this when set.
|
|
328
|
+
*
|
|
329
|
+
* - `cli` writes the end-of-run summary to the terminal.
|
|
330
|
+
* - `json` writes a machine-readable report to stdout, for CI.
|
|
331
|
+
* - `file` writes a debug log to `.kubb/<name>-<timestamp>.log`.
|
|
332
|
+
*
|
|
333
|
+
* @default ['cli']
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```ts
|
|
337
|
+
* reporters: ['cli', 'file']
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
reporters?: Array<ReporterName>
|
|
372
341
|
}
|
|
373
342
|
|
|
374
343
|
/**
|
|
@@ -376,7 +345,7 @@ export type Config<TInput = Input> = {
|
|
|
376
345
|
*
|
|
377
346
|
* `UserConfig` is what you pass to `defineConfig()`. It has optional `root`, `plugins`, `parsers`, and `adapter`
|
|
378
347
|
* fields (which fall back to sensible defaults). All other Config options are available, including `output`, `input`,
|
|
379
|
-
* `storage`, `middleware`, `
|
|
348
|
+
* `storage`, `middleware`, `devtools`, and `hooks`.
|
|
380
349
|
*
|
|
381
350
|
* @example
|
|
382
351
|
* ```ts
|
|
@@ -502,7 +471,6 @@ export interface KubbHooks {
|
|
|
502
471
|
'kubb:config:end': [ctx: KubbConfigEndContext]
|
|
503
472
|
'kubb:generation:start': [ctx: KubbGenerationStartContext]
|
|
504
473
|
'kubb:generation:end': [ctx: KubbGenerationEndContext]
|
|
505
|
-
'kubb:generation:summary': [ctx: KubbGenerationSummaryContext]
|
|
506
474
|
'kubb:format:start': []
|
|
507
475
|
'kubb:format:end': []
|
|
508
476
|
'kubb:lint:start': []
|
|
@@ -511,12 +479,11 @@ export interface KubbHooks {
|
|
|
511
479
|
'kubb:hooks:end': []
|
|
512
480
|
'kubb:hook:start': [ctx: KubbHookStartContext]
|
|
513
481
|
'kubb:hook:end': [ctx: KubbHookEndContext]
|
|
514
|
-
'kubb:version:new': [ctx: KubbVersionNewContext]
|
|
515
482
|
'kubb:info': [ctx: KubbInfoContext]
|
|
516
483
|
'kubb:error': [ctx: KubbErrorContext]
|
|
517
484
|
'kubb:success': [ctx: KubbSuccessContext]
|
|
518
485
|
'kubb:warn': [ctx: KubbWarnContext]
|
|
519
|
-
'kubb:
|
|
486
|
+
'kubb:diagnostic': [ctx: KubbDiagnosticContext]
|
|
520
487
|
'kubb:files:processing:start': [ctx: KubbFilesProcessingStartContext]
|
|
521
488
|
'kubb:files:processing:update': [ctx: KubbFilesProcessingUpdateContext]
|
|
522
489
|
'kubb:files:processing:end': [ctx: KubbFilesProcessingEndContext]
|
|
@@ -618,7 +585,7 @@ export type KubbGenerationEndContext = {
|
|
|
618
585
|
config: Config
|
|
619
586
|
/**
|
|
620
587
|
* Read-only view of the files written during this build.
|
|
621
|
-
* Reads go directly to `config.storage
|
|
588
|
+
* Reads go directly to `config.storage`, nothing extra is held in memory.
|
|
622
589
|
*
|
|
623
590
|
* @example Read a generated file
|
|
624
591
|
* `const code = await storage.getItem('/src/gen/pet.ts')`
|
|
@@ -631,44 +598,24 @@ export type KubbGenerationEndContext = {
|
|
|
631
598
|
* ```
|
|
632
599
|
*/
|
|
633
600
|
storage: Storage
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
export type KubbGenerationSummaryContext = {
|
|
637
601
|
/**
|
|
638
|
-
*
|
|
602
|
+
* Diagnostics collected during the build: error/warning/info problems plus a
|
|
603
|
+
* `timing` diagnostic per plugin. The end-of-run summary derives its failure counts
|
|
604
|
+
* and per-plugin timings from these. Set by the CLI runner, omitted by other callers.
|
|
639
605
|
*/
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* Plugins that threw during generation, paired with their errors.
|
|
643
|
-
*/
|
|
644
|
-
failedPlugins: Set<{ plugin: Plugin; error: Error }>
|
|
606
|
+
diagnostics?: Array<Diagnostic>
|
|
645
607
|
/**
|
|
646
608
|
* `'success'` when all plugins completed without errors, `'failed'` otherwise.
|
|
647
609
|
*/
|
|
648
|
-
status
|
|
610
|
+
status?: 'success' | 'failed'
|
|
649
611
|
/**
|
|
650
|
-
* High-resolution start time from `process.hrtime()
|
|
612
|
+
* High-resolution start time from `process.hrtime()`, used to compute the elapsed time.
|
|
651
613
|
*/
|
|
652
|
-
hrStart
|
|
614
|
+
hrStart?: [number, number]
|
|
653
615
|
/**
|
|
654
616
|
* Total number of files created during this run.
|
|
655
617
|
*/
|
|
656
|
-
filesCreated
|
|
657
|
-
/**
|
|
658
|
-
* Elapsed milliseconds per plugin, keyed by plugin name.
|
|
659
|
-
*/
|
|
660
|
-
pluginTimings?: Map<Plugin['name'], number>
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
export type KubbVersionNewContext = {
|
|
664
|
-
/**
|
|
665
|
-
* The installed Kubb version.
|
|
666
|
-
*/
|
|
667
|
-
currentVersion: string
|
|
668
|
-
/**
|
|
669
|
-
* The newest available version on npm.
|
|
670
|
-
*/
|
|
671
|
-
latestVersion: string
|
|
618
|
+
filesCreated?: number
|
|
672
619
|
}
|
|
673
620
|
|
|
674
621
|
export type KubbInfoContext = {
|
|
@@ -715,19 +662,11 @@ export type KubbWarnContext = {
|
|
|
715
662
|
info?: string
|
|
716
663
|
}
|
|
717
664
|
|
|
718
|
-
export type
|
|
719
|
-
/**
|
|
720
|
-
* Timestamp when the debug entry was created.
|
|
721
|
-
*/
|
|
722
|
-
date: Date
|
|
723
|
-
/**
|
|
724
|
-
* One or more log lines to emit.
|
|
725
|
-
*/
|
|
726
|
-
logs: Array<string>
|
|
665
|
+
export type KubbDiagnosticContext = {
|
|
727
666
|
/**
|
|
728
|
-
*
|
|
667
|
+
* The structured diagnostic to render: a build problem or a version-update notice.
|
|
729
668
|
*/
|
|
730
|
-
|
|
669
|
+
diagnostic: ProblemDiagnostic | UpdateDiagnostic
|
|
731
670
|
}
|
|
732
671
|
|
|
733
672
|
export type KubbFilesProcessingStartContext = {
|
|
@@ -747,7 +686,7 @@ export type KubbFileProcessingUpdate = {
|
|
|
747
686
|
*/
|
|
748
687
|
total: number
|
|
749
688
|
/**
|
|
750
|
-
* Completion percentage
|
|
689
|
+
* Completion percentage, `0` to `100`.
|
|
751
690
|
*/
|
|
752
691
|
percentage: number
|
|
753
692
|
/**
|
|
@@ -838,7 +777,11 @@ export type CLIOptions = {
|
|
|
838
777
|
*
|
|
839
778
|
* @default 'info'
|
|
840
779
|
*/
|
|
841
|
-
logLevel?: 'silent' | 'info' | 'verbose'
|
|
780
|
+
logLevel?: 'silent' | 'info' | 'verbose'
|
|
781
|
+
/**
|
|
782
|
+
* Reporters selected on the CLI via `--reporter`, overriding `config.reporters`.
|
|
783
|
+
*/
|
|
784
|
+
reporters?: Array<ReporterName>
|
|
842
785
|
}
|
|
843
786
|
|
|
844
787
|
/**
|
|
@@ -854,9 +797,12 @@ export type PossibleConfig<TCliOptions = undefined> =
|
|
|
854
797
|
*/
|
|
855
798
|
export type BuildOutput = {
|
|
856
799
|
/**
|
|
857
|
-
*
|
|
800
|
+
* Structured diagnostics collected during the build: error/warning/info problems
|
|
801
|
+
* (each with a code, severity, and where known a JSON-pointer location) plus a
|
|
802
|
+
* `timing` diagnostic per plugin. Includes a top-level diagnostic when the build
|
|
803
|
+
* threw before completing. Use {@link Diagnostics.hasError} to test for failure.
|
|
858
804
|
*/
|
|
859
|
-
|
|
805
|
+
diagnostics: Array<Diagnostic>
|
|
860
806
|
/**
|
|
861
807
|
* All files generated during this build.
|
|
862
808
|
*/
|
|
@@ -865,17 +811,9 @@ export type BuildOutput = {
|
|
|
865
811
|
* The plugin driver that orchestrated this build.
|
|
866
812
|
*/
|
|
867
813
|
driver: KubbDriver
|
|
868
|
-
/**
|
|
869
|
-
* Elapsed milliseconds per plugin, keyed by plugin name.
|
|
870
|
-
*/
|
|
871
|
-
pluginTimings: Map<string, number>
|
|
872
|
-
/**
|
|
873
|
-
* Top-level error when the build threw before completing, otherwise `undefined`.
|
|
874
|
-
*/
|
|
875
|
-
error?: Error
|
|
876
814
|
/**
|
|
877
815
|
* Read-only view of every file written during this build.
|
|
878
|
-
* Reads go straight to `config.storage
|
|
816
|
+
* Reads go straight to `config.storage`, nothing extra is held in memory.
|
|
879
817
|
*
|
|
880
818
|
* @example Read a generated file
|
|
881
819
|
* `const code = await buildOutput.storage.getItem('/src/gen/pet.ts')`
|
|
@@ -889,7 +827,7 @@ export type BuildOutput = {
|
|
|
889
827
|
/**
|
|
890
828
|
* Builds a `Storage` view scoped to the file paths produced by the current build.
|
|
891
829
|
* Reads delegate to the underlying `storage` so source bytes stay where they were
|
|
892
|
-
* written
|
|
830
|
+
* written. Writes register the key so subsequent reads and `getKeys` are scoped
|
|
893
831
|
* to this build's output.
|
|
894
832
|
*/
|
|
895
833
|
function createSourcesView(storage: Storage): Storage {
|
|
@@ -934,8 +872,8 @@ function resolveConfig(userConfig: UserConfig): Config {
|
|
|
934
872
|
output: {
|
|
935
873
|
format: false,
|
|
936
874
|
lint: false,
|
|
937
|
-
extension:
|
|
938
|
-
defaultBanner:
|
|
875
|
+
extension: { '.ts': '.ts' },
|
|
876
|
+
defaultBanner: 'simple',
|
|
939
877
|
...userConfig.output,
|
|
940
878
|
},
|
|
941
879
|
storage: userConfig.storage ?? fsStorage(),
|
|
@@ -949,22 +887,6 @@ function resolveConfig(userConfig: UserConfig): Config {
|
|
|
949
887
|
}
|
|
950
888
|
}
|
|
951
889
|
|
|
952
|
-
/**
|
|
953
|
-
* Returns a snapshot of the current runtime environment.
|
|
954
|
-
*
|
|
955
|
-
* Useful for attaching context to debug logs and error reports so that
|
|
956
|
-
* issues can be reproduced without manual information gathering.
|
|
957
|
-
*/
|
|
958
|
-
export function getDiagnosticInfo() {
|
|
959
|
-
return {
|
|
960
|
-
nodeVersion,
|
|
961
|
-
KubbVersion,
|
|
962
|
-
platform: process.platform,
|
|
963
|
-
arch: process.arch,
|
|
964
|
-
cwd: process.cwd(),
|
|
965
|
-
} as const
|
|
966
|
-
}
|
|
967
|
-
|
|
968
890
|
/**
|
|
969
891
|
* Type guard to check if a given config has an `input.path`.
|
|
970
892
|
*/
|
|
@@ -989,7 +911,7 @@ type CreateKubbOptions = {
|
|
|
989
911
|
* ```ts
|
|
990
912
|
* const kubb = createKubb(userConfig)
|
|
991
913
|
* kubb.hooks.on('kubb:plugin:end', ({ plugin, duration }) => console.log(plugin.name, duration))
|
|
992
|
-
* const { files,
|
|
914
|
+
* const { files, diagnostics } = await kubb.safeBuild()
|
|
993
915
|
* ```
|
|
994
916
|
*/
|
|
995
917
|
export class Kubb {
|
|
@@ -1027,22 +949,12 @@ export class Kubb {
|
|
|
1027
949
|
const driver = new KubbDriver(config, { hooks: this.hooks })
|
|
1028
950
|
const storage = createSourcesView(config.storage)
|
|
1029
951
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
await exists(this.#userConfig.input.path)
|
|
1035
|
-
await this.hooks.emit('kubb:debug', { date: new Date(), logs: [`✓ Input file validated: ${this.#userConfig.input.path}`] })
|
|
1036
|
-
} catch (caughtError) {
|
|
1037
|
-
throw new Error(
|
|
1038
|
-
`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${this.#userConfig.input.path}`,
|
|
1039
|
-
{ cause: caughtError as Error },
|
|
1040
|
-
)
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
952
|
+
// Each generator a plugin registers adds a listener to the shared hooks emitter, so size the
|
|
953
|
+
// ceiling to the plugin count. Without this, a multi-generator plugin set trips Node's
|
|
954
|
+
// EventEmitter leak warning at the default 10.
|
|
955
|
+
this.hooks.setMaxListeners(Math.max(10, config.plugins.length * HOOK_LISTENERS_PER_PLUGIN))
|
|
1043
956
|
|
|
1044
957
|
if (config.output.clean) {
|
|
1045
|
-
await this.hooks.emit('kubb:debug', { date: new Date(), logs: ['Cleaning output directories', ` • Output: ${config.output.path}`] })
|
|
1046
958
|
await config.storage.clear(resolve(config.root, config.output.path))
|
|
1047
959
|
}
|
|
1048
960
|
|
|
@@ -1059,10 +971,12 @@ export class Kubb {
|
|
|
1059
971
|
*/
|
|
1060
972
|
async build(): Promise<BuildOutput> {
|
|
1061
973
|
const out = await this.safeBuild()
|
|
1062
|
-
if (out.
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
974
|
+
if (Diagnostics.hasError(out.diagnostics)) {
|
|
975
|
+
const errors = out.diagnostics
|
|
976
|
+
.filter(isProblemDiagnostic)
|
|
977
|
+
.filter((diagnostic) => diagnostic.severity === 'error')
|
|
978
|
+
.map((diagnostic) => diagnostic.cause ?? new DiagnosticError(diagnostic))
|
|
979
|
+
throw new BuildError(`Build failed with ${errors.length} ${errors.length === 1 ? 'error' : 'errors'}`, { errors })
|
|
1066
980
|
}
|
|
1067
981
|
return out
|
|
1068
982
|
}
|
|
@@ -1076,8 +990,9 @@ export class Kubb {
|
|
|
1076
990
|
using cleanup = this
|
|
1077
991
|
const driver = cleanup.driver
|
|
1078
992
|
const storage = cleanup.storage
|
|
1079
|
-
const {
|
|
1080
|
-
|
|
993
|
+
const { diagnostics } = await driver.run({ storage })
|
|
994
|
+
|
|
995
|
+
return { diagnostics, files: driver.fileManager.files, driver, storage }
|
|
1081
996
|
}
|
|
1082
997
|
|
|
1083
998
|
dispose(): void {
|
|
@@ -1087,27 +1002,6 @@ export class Kubb {
|
|
|
1087
1002
|
[Symbol.dispose](): void {
|
|
1088
1003
|
this.dispose()
|
|
1089
1004
|
}
|
|
1090
|
-
|
|
1091
|
-
#configLogs(config: Config): Array<string> {
|
|
1092
|
-
const u = this.#userConfig
|
|
1093
|
-
const diag = getDiagnosticInfo()
|
|
1094
|
-
return [
|
|
1095
|
-
'Configuration:',
|
|
1096
|
-
` • Name: ${u.name || 'unnamed'}`,
|
|
1097
|
-
` • Root: ${u.root || process.cwd()}`,
|
|
1098
|
-
` • Output: ${u.output?.path || 'not specified'}`,
|
|
1099
|
-
` • Plugins: ${u.plugins?.length || 0}`,
|
|
1100
|
-
'Output Settings:',
|
|
1101
|
-
` • Storage: ${config.storage.name}`,
|
|
1102
|
-
` • Formatter: ${u.output?.format || 'none'}`,
|
|
1103
|
-
` • Linter: ${u.output?.lint || 'none'}`,
|
|
1104
|
-
`Running adapter: ${config.adapter?.name || 'none'}`,
|
|
1105
|
-
'Environment:',
|
|
1106
|
-
Object.entries(diag)
|
|
1107
|
-
.map(([key, value]) => ` • ${key}: ${value}`)
|
|
1108
|
-
.join('\n'),
|
|
1109
|
-
]
|
|
1110
|
-
}
|
|
1111
1005
|
}
|
|
1112
1006
|
|
|
1113
1007
|
/**
|
package/src/createRenderer.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type { FileNode } from '@kubb/ast'
|
|
|
11
11
|
export type Renderer<TElement = unknown> = {
|
|
12
12
|
/**
|
|
13
13
|
* Renders `element` and populates {@link files} with the resulting {@link FileNode} objects.
|
|
14
|
-
* Called once per render cycle
|
|
14
|
+
* Called once per render cycle. Must resolve before {@link files} is read.
|
|
15
15
|
*/
|
|
16
16
|
render(element: TElement): Promise<void>
|
|
17
17
|
/**
|
|
@@ -52,7 +52,7 @@ export type RendererFactory<TElement = unknown> = () => Renderer<TElement>
|
|
|
52
52
|
* (JSX, a template string, a tree of any shape) into `FileNode`s that get
|
|
53
53
|
* written to disk.
|
|
54
54
|
*
|
|
55
|
-
* Use this to support output formats beyond JSX
|
|
55
|
+
* Use this to support output formats beyond JSX, for instance, a Handlebars
|
|
56
56
|
* renderer, a string-template renderer, or a renderer that writes binary
|
|
57
57
|
* files. Plugins and generators pick the renderer to use via the `renderer`
|
|
58
58
|
* field on `defineGenerator`.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { logLevel } from './constants.ts'
|
|
2
|
+
import type { Config } from './createKubb.ts'
|
|
3
|
+
import type { Diagnostic } from './diagnostics.ts'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A built-in reporter that renders a run's output, independent of the live logger view.
|
|
7
|
+
*
|
|
8
|
+
* - `cli` renders the per-config summary to the terminal (the default).
|
|
9
|
+
* - `json` writes a machine-readable report to stdout, for CI.
|
|
10
|
+
* - `file` writes a config's diagnostics to `.kubb/kubb-<name>-<timestamp>.log`.
|
|
11
|
+
*/
|
|
12
|
+
export type ReporterName = 'cli' | 'json' | 'file'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* One config's outcome within a run, as handed to a {@link Reporter}.
|
|
16
|
+
*/
|
|
17
|
+
export type GenerationResult = {
|
|
18
|
+
config: Config
|
|
19
|
+
/**
|
|
20
|
+
* Diagnostics collected while generating this config.
|
|
21
|
+
*/
|
|
22
|
+
diagnostics: Array<Diagnostic>
|
|
23
|
+
/**
|
|
24
|
+
* Number of files written for this config.
|
|
25
|
+
*/
|
|
26
|
+
filesCreated: number
|
|
27
|
+
status: 'success' | 'failed'
|
|
28
|
+
/**
|
|
29
|
+
* `process.hrtime()` snapshot taken when this config started generating.
|
|
30
|
+
*/
|
|
31
|
+
hrStart: [number, number]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Render context passed alongside the {@link GenerationResult}, carrying knobs a reporter needs
|
|
36
|
+
* but that are not part of the run data (e.g. verbosity).
|
|
37
|
+
*/
|
|
38
|
+
export type ReporterContext = {
|
|
39
|
+
/**
|
|
40
|
+
* Output verbosity. Use the `logLevel` constants exported from `@kubb/core`
|
|
41
|
+
* (`silent`, `error`, `warn`, `info`, `verbose`, `debug`).
|
|
42
|
+
*/
|
|
43
|
+
logLevel: (typeof logLevel)[keyof typeof logLevel]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Reporter contract. Unlike a Logger (the live TUI view), a reporter never sees the event
|
|
48
|
+
* emitter. `report` is called once per config with its {@link GenerationResult} and produces
|
|
49
|
+
* output (a terminal summary, a JSON report, a log file).
|
|
50
|
+
*/
|
|
51
|
+
export type Reporter = {
|
|
52
|
+
/**
|
|
53
|
+
* Display name, matching a {@link ReporterName} for the built-ins.
|
|
54
|
+
*/
|
|
55
|
+
name: string
|
|
56
|
+
/**
|
|
57
|
+
* Called once per config with that config's result and the render context.
|
|
58
|
+
*/
|
|
59
|
+
report: (result: GenerationResult, context: ReporterContext) => void | Promise<void>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type UserReporter = Reporter
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Defines a reporter. Returns the reporter unchanged at runtime. It exists for type inference and
|
|
66
|
+
* to mark the value as a reporter, mirroring {@link defineLogger}. Wiring the reporter onto the
|
|
67
|
+
* run's events is the host's job, so the reporter only ever deals with a {@link GenerationResult}.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { createReporter, Diagnostics } from '@kubb/core'
|
|
72
|
+
*
|
|
73
|
+
* export const jsonReporter = createReporter({
|
|
74
|
+
* name: 'json',
|
|
75
|
+
* report(result) {
|
|
76
|
+
* const status = Diagnostics.hasError(result.diagnostics) ? 'failed' : 'success'
|
|
77
|
+
* process.stdout.write(`${JSON.stringify({ status, diagnostics: result.diagnostics }, null, 2)}\n`)
|
|
78
|
+
* },
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function createReporter(reporter: UserReporter): Reporter {
|
|
83
|
+
return reporter
|
|
84
|
+
}
|
package/src/createStorage.ts
CHANGED
|
@@ -43,7 +43,7 @@ export type Storage = {
|
|
|
43
43
|
/**
|
|
44
44
|
* Defines a custom storage backend. The builder receives user options and
|
|
45
45
|
* returns a `Storage` implementation. Kubb ships with filesystem and
|
|
46
|
-
* in-memory storages
|
|
46
|
+
* in-memory storages, reach for this when you need to write generated files
|
|
47
47
|
* elsewhere (cloud storage, a database, a remote API).
|
|
48
48
|
*
|
|
49
49
|
* @example In-memory storage (the built-in implementation)
|