@kubb/core 5.0.0-beta.62 → 5.0.0-beta.64

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 (43) hide show
  1. package/dist/{diagnostics-D0G07LHG.d.ts → diagnostics-BqiNAWVS.d.ts} +47 -40
  2. package/dist/index.cjs +47 -52
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +7 -8
  5. package/dist/index.js +49 -54
  6. package/dist/index.js.map +1 -1
  7. package/dist/{memoryStorage-CWFzAz4o.js → memoryStorage-DWnhqUf2.js} +3 -3
  8. package/dist/memoryStorage-DWnhqUf2.js.map +1 -0
  9. package/dist/{memoryStorage-CUj1hrxa.cjs → memoryStorage-mojU6pbA.cjs} +2 -2
  10. package/dist/memoryStorage-mojU6pbA.cjs.map +1 -0
  11. package/dist/mocks.cjs +2 -2
  12. package/dist/mocks.cjs.map +1 -1
  13. package/dist/mocks.d.ts +3 -3
  14. package/dist/mocks.js +3 -3
  15. package/dist/mocks.js.map +1 -1
  16. package/package.json +4 -5
  17. package/dist/memoryStorage-CUj1hrxa.cjs.map +0 -1
  18. package/dist/memoryStorage-CWFzAz4o.js.map +0 -1
  19. package/src/FileManager.ts +0 -137
  20. package/src/FileProcessor.ts +0 -212
  21. package/src/KubbDriver.ts +0 -893
  22. package/src/Transform.ts +0 -105
  23. package/src/constants.ts +0 -126
  24. package/src/createAdapter.ts +0 -127
  25. package/src/createKubb.ts +0 -196
  26. package/src/createRenderer.ts +0 -72
  27. package/src/createReporter.ts +0 -134
  28. package/src/createStorage.ts +0 -83
  29. package/src/defineGenerator.ts +0 -210
  30. package/src/defineParser.ts +0 -62
  31. package/src/definePlugin.ts +0 -437
  32. package/src/defineResolver.ts +0 -711
  33. package/src/diagnostics.ts +0 -662
  34. package/src/index.ts +0 -20
  35. package/src/mocks.ts +0 -249
  36. package/src/reporters/cliReporter.ts +0 -89
  37. package/src/reporters/fileReporter.ts +0 -103
  38. package/src/reporters/jsonReporter.ts +0 -20
  39. package/src/reporters/report.ts +0 -85
  40. package/src/storages/fsStorage.ts +0 -82
  41. package/src/storages/memoryStorage.ts +0 -55
  42. package/src/types.ts +0 -829
  43. /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
@@ -1,662 +0,0 @@
1
- import { AsyncLocalStorage } from 'node:async_hooks'
2
- import { styleText } from 'node:util'
3
- import type { AsyncEventEmitter } from '@internals/utils'
4
- import { getErrorMessage } from '@internals/utils'
5
- import { version } from '../package.json'
6
- import { type DiagnosticCode, diagnosticCode } from './constants.ts'
7
- import type { KubbHooks } from './types.ts'
8
-
9
- /**
10
- * Docs major version, derived from the package version so the link tracks the published major.
11
- */
12
- const docsMajor = version.split('.')[0] ?? '5'
13
-
14
- /**
15
- * How serious a diagnostic is. `error` fails the build, `warning` and `info`
16
- * are reported but do not.
17
- */
18
- export type DiagnosticSeverity = 'error' | 'warning' | 'info'
19
-
20
- /**
21
- * A human-readable explanation of a diagnostic code: a short title, what triggers it, and how
22
- * to resolve it. This is the source of truth the kubb.dev `/diagnostics/<slug>` pages mirror, so
23
- * every code stays documented in one place. Adding a code without documenting it fails the build.
24
- */
25
- export type DiagnosticDoc = {
26
- /**
27
- * Short title shown as the docs heading.
28
- */
29
- title: string
30
- /**
31
- * What triggers the diagnostic.
32
- */
33
- cause: string
34
- /**
35
- * The action that resolves it.
36
- */
37
- fix: string
38
- }
39
-
40
- /**
41
- * Points a diagnostic back into the source document. Inputs are parsed into an
42
- * object model with no line/column, so locations carry a JSON pointer the adapter
43
- * builds (the OAS adapter emits `#/components/schemas/Pet`). A `config` diagnostic
44
- * points at the Kubb config itself and so has no pointer.
45
- */
46
- export type DiagnosticLocation =
47
- | {
48
- kind: 'schema'
49
- /**
50
- * RFC 6901 JSON pointer into the source document.
51
- */
52
- pointer: string
53
- /**
54
- * The original reference when the diagnostic stems from an unresolved one.
55
- */
56
- ref?: string
57
- }
58
- | {
59
- kind: 'operation' | 'document'
60
- /**
61
- * RFC 6901 JSON pointer into the source document.
62
- */
63
- pointer: string
64
- }
65
- | {
66
- kind: 'config'
67
- }
68
-
69
- /**
70
- * What a diagnostic carries.
71
- * - `problem` is a build issue shown to the user, and the only kind rendered as a problem.
72
- * - `performance` records a plugin's elapsed time.
73
- * - `update` is a version notice.
74
- */
75
- export type DiagnosticKind = 'problem' | 'performance' | 'update'
76
-
77
- /**
78
- * Codes that describe a build problem: every {@link DiagnosticCode} except the
79
- * `performance` and `updateAvailable` codes, which ride on their own variants.
80
- */
81
- export type ProblemCode = Exclude<DiagnosticCode, typeof diagnosticCode.performance | typeof diagnosticCode.updateAvailable>
82
-
83
- /**
84
- * A build problem collected during a run, gathered into the result instead of
85
- * aborting on the first failure.
86
- */
87
- export type ProblemDiagnostic = {
88
- /**
89
- * @default 'problem'
90
- */
91
- kind?: 'problem'
92
- /**
93
- * Stable identifier for the problem, from the {@link diagnosticCode} catalog.
94
- */
95
- code: ProblemCode
96
- severity: DiagnosticSeverity
97
- message: string
98
- location?: DiagnosticLocation
99
- /**
100
- * A suggested fix, phrased as an action the user can take.
101
- */
102
- help?: string
103
- /**
104
- * Name of the plugin or subsystem that produced the diagnostic.
105
- */
106
- plugin?: string
107
- /**
108
- * The underlying error, when the diagnostic wraps a thrown one.
109
- */
110
- cause?: Error
111
- }
112
-
113
- /**
114
- * A per-plugin performance record, built with {@link Diagnostics.performance}. The `performance`
115
- * kind keeps it out of the problem list. It feeds the per-plugin timing bars, and reporters sum
116
- * these into the run total.
117
- */
118
- export type PerformanceDiagnostic = {
119
- kind: 'performance'
120
- code: typeof diagnosticCode.performance
121
- severity: 'info'
122
- message: string
123
- /**
124
- * The plugin this measurement belongs to.
125
- */
126
- plugin: string
127
- /**
128
- * Elapsed milliseconds.
129
- */
130
- duration: number
131
- }
132
-
133
- /**
134
- * A notice that a newer Kubb version is available on npm, built with {@link Diagnostics.update}.
135
- * It renders like any info diagnostic.
136
- */
137
- export type UpdateDiagnostic = {
138
- kind: 'update'
139
- code: typeof diagnosticCode.updateAvailable
140
- severity: 'info'
141
- message: string
142
- /**
143
- * The running Kubb version.
144
- */
145
- currentVersion: string
146
- /**
147
- * The newest version published on npm.
148
- */
149
- latestVersion: string
150
- }
151
-
152
- /**
153
- * A structured record collected during a build, discriminated on `kind`: a
154
- * {@link ProblemDiagnostic} for an issue, a {@link PerformanceDiagnostic} for a per-plugin
155
- * timing, or an {@link UpdateDiagnostic} for a version notice.
156
- */
157
- export type Diagnostic = ProblemDiagnostic | PerformanceDiagnostic | UpdateDiagnostic
158
-
159
- /**
160
- * Maps each {@link DiagnosticCode} to the variant it selects, for {@link narrow}.
161
- * Every {@link ProblemCode} selects a {@link ProblemDiagnostic}, and the two bookkeeping codes
162
- * select their own variant.
163
- */
164
- export type DiagnosticByCode = Record<ProblemCode, ProblemDiagnostic> &
165
- Record<typeof diagnosticCode.performance, PerformanceDiagnostic> &
166
- Record<typeof diagnosticCode.updateAvailable, UpdateDiagnostic>
167
-
168
- /**
169
- * Narrows a {@link Diagnostic} to the variant for `code`, or `null` when it does not match.
170
- *
171
- * @example
172
- * ```ts
173
- * const update = narrow(diagnostic, diagnosticCode.updateAvailable)
174
- * if (update) {
175
- * console.log(update.latestVersion)
176
- * }
177
- * ```
178
- */
179
- function narrow<C extends DiagnosticCode>(diagnostic: Diagnostic, code: C): DiagnosticByCode[C] | null {
180
- return diagnostic.code === code ? (diagnostic as DiagnosticByCode[C]) : null
181
- }
182
-
183
- /**
184
- * Builds a type guard that narrows a {@link Diagnostic} to the variant for `kind`. A diagnostic
185
- * with no `kind` is treated as a `problem`.
186
- */
187
- function isKind<T extends Diagnostic>(kind: DiagnosticKind) {
188
- return (diagnostic: Diagnostic): diagnostic is T => (diagnostic.kind ?? 'problem') === kind
189
- }
190
-
191
- /**
192
- * Returns `true` when the diagnostic is a build {@link ProblemDiagnostic}.
193
- *
194
- * @example
195
- * ```ts
196
- * if (isProblem(diagnostic)) {
197
- * console.log(diagnostic.location)
198
- * }
199
- * ```
200
- */
201
- const isProblem = isKind<ProblemDiagnostic>('problem')
202
-
203
- /**
204
- * Returns `true` when the diagnostic is a per-plugin {@link PerformanceDiagnostic}.
205
- *
206
- * @example
207
- * ```ts
208
- * const timings = diagnostics.filter(isPerformance)
209
- * ```
210
- */
211
- const isPerformance = isKind<PerformanceDiagnostic>('performance')
212
-
213
- /**
214
- * Returns `true` when the diagnostic is a version-update {@link UpdateDiagnostic}.
215
- *
216
- * @example
217
- * ```ts
218
- * if (isUpdate(diagnostic)) {
219
- * console.log(diagnostic.latestVersion)
220
- * }
221
- * ```
222
- */
223
- const isUpdate = isKind<UpdateDiagnostic>('update')
224
-
225
- /**
226
- * Glyph and accent color per severity, matching the miette/oxlint convention
227
- * (`×` error, `⚠` warning, `ℹ` advice).
228
- */
229
- const severityStyle: Record<DiagnosticSeverity, { glyph: string; color: 'red' | 'yellow' | 'blue' }> = {
230
- error: { glyph: '×', color: 'red' },
231
- warning: { glyph: '⚠', color: 'yellow' },
232
- info: { glyph: 'ℹ', color: 'blue' },
233
- }
234
-
235
- /**
236
- * A {@link Diagnostic} reduced to its JSON-safe fields plus a `docsUrl`, for
237
- * machine-readable output (the `--reporter json` report, the MCP tools). Drops the
238
- * non-serializable `cause` and the `timing`/`duration` bookkeeping.
239
- */
240
- export type SerializedDiagnostic = {
241
- code: DiagnosticCode
242
- severity: DiagnosticSeverity
243
- message: string
244
- location?: DiagnosticLocation
245
- help?: string
246
- plugin?: string
247
- /**
248
- * The kubb.dev docs link for the code, omitted for the unknown fallback.
249
- */
250
- docsUrl?: string
251
- }
252
-
253
- /**
254
- * Explanation for every {@link diagnosticCode}. Use {@link Diagnostics.explain} to look one up
255
- * and `Diagnostics.docsUrl` for the matching kubb.dev page.
256
- */
257
- const diagnosticCatalog: Record<DiagnosticCode, DiagnosticDoc> = {
258
- [diagnosticCode.unknown]: {
259
- title: 'Unknown error',
260
- cause: 'An error was thrown without a stable Kubb code, so it is reported as-is.',
261
- fix: 'Read the underlying message and stack. If it comes from a plugin or adapter, check its configuration; otherwise report it as a possible Kubb bug.',
262
- },
263
- [diagnosticCode.inputNotFound]: {
264
- title: 'Input not found',
265
- cause: 'The file or URL set in `input.path` (or passed as `kubb generate PATH`) could not be read.',
266
- fix: 'Check that the path or URL exists and is readable, then set it in `input.path` or pass it on the CLI.',
267
- },
268
- [diagnosticCode.inputRequired]: {
269
- title: 'Input required',
270
- cause: 'An adapter is configured but no `input` was provided.',
271
- fix: 'Set `input.path` (a file or URL) or `input.data` (an inline spec) in your Kubb config.',
272
- },
273
- [diagnosticCode.refNotFound]: {
274
- title: 'Reference not found',
275
- cause: 'A `$ref` could not be resolved in the source document.',
276
- fix: 'Add the missing definition (for example under `components.schemas`) or fix the `$ref`. Run `kubb validate` to check the spec.',
277
- },
278
- [diagnosticCode.invalidServerVariable]: {
279
- title: 'Invalid server variable',
280
- cause: 'A server variable value is not allowed by its `enum`.',
281
- fix: 'Use one of the values listed in the server variable `enum`, or update the spec.',
282
- },
283
- [diagnosticCode.pluginNotFound]: {
284
- title: 'Plugin not found',
285
- cause: 'A plugin that another plugin depends on is missing from the config.',
286
- fix: 'Add the required plugin to the `plugins` array in kubb.config.ts, or remove the dependency on it.',
287
- },
288
- [diagnosticCode.pluginFailed]: {
289
- title: 'Plugin failed',
290
- cause: 'A plugin threw while generating, or reported an error through `ctx.error`.',
291
- fix: 'Read the underlying error and check the plugin options and the schema or operation it failed on.',
292
- },
293
- [diagnosticCode.pluginWarning]: {
294
- title: 'Plugin warning',
295
- cause: 'A plugin reported a non-fatal warning through `ctx.warn`.',
296
- fix: 'Review the message. It does not fail the build; adjust the plugin options or input if the warning is unwanted.',
297
- },
298
- [diagnosticCode.pluginInfo]: {
299
- title: 'Plugin info',
300
- cause: 'A plugin reported an informational message through `ctx.info`.',
301
- fix: 'Informational only. No action is required.',
302
- },
303
- [diagnosticCode.unsupportedFormat]: {
304
- title: 'Unsupported format',
305
- cause: 'A schema uses a `format` Kubb does not map to a specific type, so it falls back to the base type.',
306
- fix: 'Use a format Kubb supports, or handle the custom format with a parser or plugin.',
307
- },
308
- [diagnosticCode.deprecated]: {
309
- title: 'Deprecated',
310
- cause: 'A referenced schema or operation is marked `deprecated`.',
311
- fix: 'Migrate off the deprecated definition if the warning is unwanted.',
312
- },
313
- [diagnosticCode.adapterRequired]: {
314
- title: 'Adapter required',
315
- cause: 'An action needs an adapter but none is configured.',
316
- fix: 'Set `adapter` in kubb.config.ts, for example `adapterOas()`.',
317
- },
318
- [diagnosticCode.pathTraversal]: {
319
- title: 'Path traversal',
320
- cause: 'A resolved output path escaped the output directory, which can stem from a path traversal in the spec or a misconfigured `group.name`.',
321
- fix: 'Keep generated paths within the output directory. Review the `group.name` function and the names coming from the spec.',
322
- },
323
- [diagnosticCode.invalidPluginOptions]: {
324
- title: 'Invalid plugin options',
325
- cause: "A plugin was configured with options that cannot be honored, for example `output.mode: 'file'` paired with a `group` option.",
326
- fix: "Fix the plugin options. A single-file output has nothing to group, so remove the `group` option or use `output.mode: 'directory'`.",
327
- },
328
- [diagnosticCode.hookFailed]: {
329
- title: 'Hook failed',
330
- cause: 'A post-generate shell hook (`hooks.done`) exited with a non-zero status.',
331
- fix: 'Check the command is installed and correct, and run it manually to see the error.',
332
- },
333
- [diagnosticCode.formatFailed]: {
334
- title: 'Format failed',
335
- cause: 'The formatter pass over the generated files failed.',
336
- fix: 'Check the formatter (oxfmt, biome, or prettier) is installed and its config is valid, then run it manually on the output.',
337
- },
338
- [diagnosticCode.lintFailed]: {
339
- title: 'Lint failed',
340
- cause: 'The linter pass over the generated files failed.',
341
- fix: 'Check the linter (oxlint, biome, or eslint) is installed and its config is valid, then run it manually on the output.',
342
- },
343
- [diagnosticCode.performance]: {
344
- title: 'Performance',
345
- cause: 'Not a failure. Records a plugin’s elapsed time, summed into the run total.',
346
- fix: 'No action. This is an informational metric.',
347
- },
348
- [diagnosticCode.updateAvailable]: {
349
- title: 'Update available',
350
- cause: 'A newer Kubb version is published on npm than the one running.',
351
- fix: 'Update the `@kubb/*` packages, for example `npm install -g @kubb/cli`, to get the latest fixes.',
352
- },
353
- }
354
-
355
- /**
356
- * Static helpers for working with {@link Diagnostic}s, plus the run-scoped sink
357
- * that lets deep code report a diagnostic without threading a callback.
358
- *
359
- * The sink lives in a single `AsyncLocalStorage` in the `@kubb/core` bundle.
360
- * `Diagnostics.scope` activates it for a run, so anything inside that run (the
361
- * adapter parse, a lazily consumed stream, a generator) reports through
362
- * `Diagnostics.report` and lands in the same run.
363
- */
364
- export class Diagnostics {
365
- static #reporterStorage = new AsyncLocalStorage<(diagnostic: Diagnostic) => void>()
366
-
367
- /**
368
- * The diagnostic code catalog, exposed as `Diagnostics.code` (e.g. `Diagnostics.code.refNotFound`).
369
- */
370
- static code = diagnosticCode
371
-
372
- /**
373
- * Type guard for a build {@link ProblemDiagnostic}.
374
- */
375
- static isProblem = isProblem
376
-
377
- /**
378
- * Type guard for a version-update {@link UpdateDiagnostic}.
379
- */
380
- static isUpdate = isUpdate
381
-
382
- /**
383
- * Type guard for a per-plugin {@link PerformanceDiagnostic}.
384
- */
385
- static isPerformance = isPerformance
386
-
387
- /**
388
- * Narrows a {@link Diagnostic} to the variant for `code`, or `null` when it does not match.
389
- */
390
- static narrow = narrow
391
-
392
- /**
393
- * An `Error` that carries a {@link Diagnostic}, so structured problems can flow
394
- * through the existing throw/catch paths while keeping their code and location.
395
- *
396
- * @example
397
- * ```ts
398
- * throw new Diagnostics.Error({ code: diagnosticCode.refNotFound, severity: 'error', message: `Could not find ${ref}`, location: { kind: 'schema', pointer: ref, ref } })
399
- * ```
400
- */
401
- static Error = class DiagnosticError extends Error {
402
- diagnostic: ProblemDiagnostic
403
-
404
- constructor(diagnostic: ProblemDiagnostic) {
405
- super(diagnostic.message, { cause: diagnostic.cause })
406
- this.name = 'DiagnosticError'
407
- this.diagnostic = diagnostic
408
- }
409
- }
410
-
411
- /**
412
- * Structural check for a {@link Diagnostics.Error}, including one thrown from a duplicated
413
- * `@kubb/core` copy where `instanceof` fails. Matches on the `name` and a `diagnostic`
414
- * that carries a `code`.
415
- */
416
- static isError(error: unknown): error is InstanceType<typeof Diagnostics.Error> {
417
- if (error instanceof Diagnostics.Error) {
418
- return true
419
- }
420
- return (
421
- error instanceof Error &&
422
- error.name === 'DiagnosticError' &&
423
- 'diagnostic' in error &&
424
- typeof (error as { diagnostic?: unknown }).diagnostic === 'object' &&
425
- (error as { diagnostic?: Diagnostic }).diagnostic !== null &&
426
- typeof (error as { diagnostic?: { code?: unknown } }).diagnostic?.code === 'string'
427
- )
428
- }
429
-
430
- /**
431
- * Runs `fn` with `sink` as the active diagnostic sink for the whole async
432
- * subtree, so {@link Diagnostics.report} reaches it from anywhere inside.
433
- */
434
- static scope<T>(sink: (diagnostic: Diagnostic) => void, fn: () => T): T {
435
- return Diagnostics.#reporterStorage.run(sink, fn)
436
- }
437
-
438
- /**
439
- * Collects a diagnostic into the active build via the run-scoped sink, without throwing.
440
- * Returns `true` when a run consumed it, `false` when called outside a {@link Diagnostics.scope}
441
- * (so callers can fall back to throwing). Use a `warning`/`info` severity for non-fatal issues.
442
- * For rendering a diagnostic live on the hook bus, use {@link Diagnostics.emit} instead.
443
- */
444
- static report(diagnostic: Diagnostic): boolean {
445
- const sink = Diagnostics.#reporterStorage.getStore()
446
- if (!sink) {
447
- return false
448
- }
449
- sink(diagnostic)
450
- return true
451
- }
452
-
453
- /**
454
- * Emits a diagnostic on the run's `kubb:diagnostic` event so the loggers render it live.
455
- * Use it instead of calling `hooks.emit('kubb:diagnostic', ...)` directly. To collect a
456
- * diagnostic into the build result from deep in a run, use {@link Diagnostics.report} instead.
457
- */
458
- static async emit(hooks: AsyncEventEmitter<KubbHooks>, diagnostic: ProblemDiagnostic | UpdateDiagnostic): Promise<void> {
459
- await hooks.emit('kubb:diagnostic', { diagnostic })
460
- }
461
-
462
- /**
463
- * Coerces any thrown value into a {@link ProblemDiagnostic}. A {@link Diagnostics.Error}
464
- * keeps its structured data, and anything else becomes a `KUBB_UNKNOWN` error.
465
- */
466
- static from(error: unknown): ProblemDiagnostic {
467
- // The event emitter and BuildError wrap the original, so walk the cause chain to
468
- // recover a Diagnostics.Error thrown deeper down. `root` tracks the deepest error so
469
- // the unknown diagnostic reports the original message and stack, not the wrapper's.
470
- const seen = new Set<unknown>()
471
- let current: unknown = error
472
- let root: Error | undefined
473
- while (current instanceof Error && !seen.has(current)) {
474
- // Match structurally, not just by `instanceof`: a `Diagnostics.Error` thrown from a
475
- // duplicated `@kubb/core` copy (bundled into an adapter or plugin) is a different
476
- // class, but still carries the same `diagnostic`, so its code must survive.
477
- if (Diagnostics.isError(current)) {
478
- return current.diagnostic
479
- }
480
- seen.add(current)
481
- root = current
482
- current = current.cause
483
- }
484
-
485
- return {
486
- code: diagnosticCode.unknown,
487
- severity: 'error',
488
- message: root ? root.message : getErrorMessage(error),
489
- cause: root,
490
- }
491
- }
492
-
493
- /**
494
- * Builds a per-plugin performance record. Reporters sum these into the run total.
495
- */
496
- static performance({ plugin, duration }: { plugin: string; duration: number }): PerformanceDiagnostic {
497
- return {
498
- kind: 'performance',
499
- code: diagnosticCode.performance,
500
- severity: 'info',
501
- message: `${plugin} generated in ${Math.round(duration)}ms`,
502
- plugin,
503
- duration,
504
- }
505
- }
506
-
507
- /**
508
- * Builds the version-update notice shown when a newer Kubb is published on npm.
509
- */
510
- static update({ currentVersion, latestVersion }: { currentVersion: string; latestVersion: string }): UpdateDiagnostic {
511
- return {
512
- kind: 'update',
513
- code: diagnosticCode.updateAvailable,
514
- severity: 'info',
515
- message: `Update available: v${currentVersion} → v${latestVersion}. Run \`npm install -g @kubb/cli\` to update.`,
516
- currentVersion,
517
- latestVersion,
518
- }
519
- }
520
-
521
- /**
522
- * True when any diagnostic is an error, the severity that fails a build. Non-error
523
- * diagnostics are ignored.
524
- */
525
- static hasError(diagnostics: ReadonlyArray<Diagnostic>): boolean {
526
- return diagnostics.some((diagnostic) => diagnostic.severity === 'error')
527
- }
528
-
529
- /**
530
- * Names of the plugins that failed, deduped, derived from the error diagnostics
531
- * that carry a `plugin`.
532
- */
533
- static failedPlugins(diagnostics: ReadonlyArray<Diagnostic>): Array<string> {
534
- const names = new Set<string>()
535
- for (const diagnostic of diagnostics) {
536
- if (diagnostic.severity === 'error' && diagnostic.plugin) {
537
- names.add(diagnostic.plugin)
538
- }
539
- }
540
- return [...names]
541
- }
542
-
543
- /**
544
- * Counts `problem` diagnostics by severity for the run summary. `timing`
545
- * diagnostics are ignored.
546
- */
547
- static count(diagnostics: ReadonlyArray<Diagnostic>): { errors: number; warnings: number; infos: number } {
548
- let errors = 0
549
- let warnings = 0
550
- let infos = 0
551
- for (const diagnostic of diagnostics) {
552
- if (!isProblem(diagnostic)) {
553
- continue
554
- }
555
- if (diagnostic.severity === 'error') {
556
- errors += 1
557
- } else if (diagnostic.severity === 'warning') {
558
- warnings += 1
559
- } else {
560
- infos += 1
561
- }
562
- }
563
- return { errors, warnings, infos }
564
- }
565
-
566
- /**
567
- * Drops duplicate `problem` diagnostics that share a code, location pointer, and
568
- * plugin, so the same issue reported across several passes is shown once. Non-problem
569
- * diagnostics are always kept.
570
- */
571
- static dedupe(diagnostics: ReadonlyArray<Diagnostic>): Array<Diagnostic> {
572
- const seen = new Set<string>()
573
- const result: Array<Diagnostic> = []
574
- for (const diagnostic of diagnostics) {
575
- if (!isProblem(diagnostic)) {
576
- result.push(diagnostic)
577
- continue
578
- }
579
- const pointer = diagnostic.location && 'pointer' in diagnostic.location ? diagnostic.location.pointer : ''
580
- const key = `${diagnostic.code} ${pointer} ${diagnostic.plugin ?? ''}`
581
- if (seen.has(key)) {
582
- continue
583
- }
584
- seen.add(key)
585
- result.push(diagnostic)
586
- }
587
- return result
588
- }
589
-
590
- /**
591
- * Builds the kubb.dev docs URL for a diagnostic code, e.g.
592
- * `KUBB_REF_NOT_FOUND` → `https://kubb.dev/docs/5.x/reference/diagnostics/kubb-ref-not-found`.
593
- */
594
- static docsUrl(code: string): string {
595
- const slug = code.toLowerCase().replaceAll('_', '-')
596
- return `https://kubb.dev/docs/${docsMajor}.x/reference/diagnostics/${slug}`
597
- }
598
-
599
- /**
600
- * The catalog entry for a code: its title, cause, and fix. Mirrors the kubb.dev
601
- * `/diagnostics/<slug>` page.
602
- */
603
- static explain(code: DiagnosticCode): DiagnosticDoc {
604
- return diagnosticCatalog[code]
605
- }
606
-
607
- /**
608
- * Reduces a diagnostic to its JSON-safe fields plus a `docsUrl`, for machine-readable
609
- * consumers. The `cause`, `kind`, and `duration` are dropped, and absent optional
610
- * fields are omitted rather than set to `undefined`.
611
- */
612
- static serialize(diagnostic: Diagnostic): SerializedDiagnostic {
613
- const problem = isProblem(diagnostic) ? diagnostic : undefined
614
- return {
615
- code: diagnostic.code,
616
- severity: diagnostic.severity,
617
- message: diagnostic.message,
618
- ...(problem?.location ? { location: problem.location } : {}),
619
- ...(problem?.help ? { help: problem.help } : {}),
620
- ...(problem?.plugin ? { plugin: problem.plugin } : {}),
621
- ...(diagnostic.code === diagnosticCode.unknown ? {} : { docsUrl: Diagnostics.docsUrl(diagnostic.code) }),
622
- }
623
- }
624
-
625
- /**
626
- * Renders a {@link Diagnostic} for terminal output as its parts: the colored severity `symbol`
627
- * (the gutter glyph), the `plugin(CODE): message` `headline`, and the `details` lines (optional
628
- * `at <pointer>`, `help:`, and `docs:`).
629
- *
630
- * Hosts compose these to fit their gutter: a clack logger passes `symbol` as its own gutter and
631
- * `[headline, ...details]` as the message, while plain text outputs use {@link Diagnostics.formatLines}.
632
- */
633
- static format(diagnostic: Diagnostic): { symbol: string; headline: string; details: Array<string> } {
634
- const { code, severity, message } = diagnostic
635
- const { glyph, color } = severityStyle[severity]
636
- const problem = isProblem(diagnostic) ? diagnostic : undefined
637
-
638
- const rule = styleText(color, styleText('bold', problem?.plugin ? `${problem.plugin}(${code})` : code))
639
- const details: Array<string> = []
640
-
641
- if (problem?.location && 'pointer' in problem.location) {
642
- details.push(` ${styleText('dim', 'at')} ${styleText('cyan', problem.location.pointer)}`)
643
- }
644
- if (problem?.help) {
645
- details.push(` ${styleText('cyan', 'help:')} ${problem.help}`)
646
- }
647
- if (code !== diagnosticCode.unknown) {
648
- details.push(` ${styleText('dim', 'docs:')} ${styleText('cyan', Diagnostics.docsUrl(code))}`)
649
- }
650
-
651
- return { symbol: styleText(color, styleText('bold', glyph)), headline: `${rule}: ${message}`, details }
652
- }
653
-
654
- /**
655
- * The self-contained block form of {@link Diagnostics.format}: `${symbol} ${headline}` followed by
656
- * the detail lines. Used where there is no gutter to own the symbol (plain and file output).
657
- */
658
- static formatLines(diagnostic: Diagnostic): Array<string> {
659
- const { symbol, headline, details } = Diagnostics.format(diagnostic)
660
- return [`${symbol} ${headline}`, ...details]
661
- }
662
- }
package/src/index.ts DELETED
@@ -1,20 +0,0 @@
1
- export { AsyncEventEmitter, Url } from '@internals/utils'
2
- // `@kubb/ast` re-exported as the `ast` namespace. Node constructors are reached as `ast.factory.createX`.
3
- export * as ast from '@kubb/ast'
4
- export { createAdapter } from './createAdapter.ts'
5
- export { Diagnostics } from './diagnostics.ts'
6
- export { createKubb } from './createKubb.ts'
7
- export { createReporter, logLevel } from './createReporter.ts'
8
- export { cliReporter } from './reporters/cliReporter.ts'
9
- export { fileReporter } from './reporters/fileReporter.ts'
10
- export { jsonReporter } from './reporters/jsonReporter.ts'
11
- export { createRenderer } from './createRenderer.ts'
12
- export { createStorage } from './createStorage.ts'
13
- export { defineGenerator } from './defineGenerator.ts'
14
- export { defineParser } from './defineParser.ts'
15
- export { definePlugin } from './definePlugin.ts'
16
- export { defineResolver } from './defineResolver.ts'
17
- export { KubbDriver } from './KubbDriver.ts'
18
- export { fsStorage } from './storages/fsStorage.ts'
19
- export { memoryStorage } from './storages/memoryStorage.ts'
20
- export * from './types.ts'