@kubb/core 5.0.0-beta.38 → 5.0.0-beta.39
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/{diagnostics-CYfKPtbU.d.ts → diagnostics-DhfW8YpT.d.ts} +289 -347
- package/dist/index.cjs +553 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +164 -119
- package/dist/index.js +532 -149
- package/dist/index.js.map +1 -1
- package/dist/{KubbDriver-CyNF-NIb.js → memoryStorage-CNQTs-YG.js} +240 -157
- package/dist/memoryStorage-CNQTs-YG.js.map +1 -0
- package/dist/{KubbDriver-BYBUfOZ8.cjs → memoryStorage-DHi1d0To.cjs} +255 -196
- package/dist/memoryStorage-DHi1d0To.cjs.map +1 -0
- package/dist/mocks.cjs +36 -6
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.ts +30 -3
- package/dist/mocks.js +33 -5
- package/dist/mocks.js.map +1 -1
- package/package.json +4 -4
- package/src/KubbDriver.ts +21 -65
- package/src/Telemetry.ts +278 -0
- package/src/constants.ts +14 -21
- package/src/createKubb.ts +22 -50
- package/src/createReporter.ts +43 -13
- package/src/defineGenerator.ts +2 -6
- package/src/defineLogger.ts +13 -1
- package/src/defineResolver.ts +3 -4
- package/src/diagnostics.ts +130 -61
- package/src/index.ts +8 -16
- package/src/mocks.ts +57 -2
- package/src/reporters/cliReporter.ts +90 -0
- package/src/reporters/fileReporter.ts +103 -0
- package/src/reporters/jsonReporter.ts +20 -0
- package/src/reporters/report.ts +85 -0
- package/src/types.ts +0 -1
- package/dist/KubbDriver-BYBUfOZ8.cjs.map +0 -1
- package/dist/KubbDriver-CyNF-NIb.js.map +0 -1
- package/src/devtools.ts +0 -53
package/src/constants.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Number of file writes to batch in parallel during `flushPendingFiles`.
|
|
3
3
|
*/
|
|
4
|
-
export const
|
|
4
|
+
export const STREAM_FLUSH_EVERY = 50
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* OpenTelemetry ingestion endpoint for anonymous usage telemetry.
|
|
8
8
|
*/
|
|
9
|
-
export const
|
|
9
|
+
export const OTLP_ENDPOINT = 'https://otlp.kubb.dev' as const
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Maximum number of █ characters in a plugin timing bar.
|
|
13
|
+
*/
|
|
14
|
+
export const SUMMARY_MAX_BAR_LENGTH = 10 as const
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Divides elapsed milliseconds into bar-length units (1 block per 100 ms).
|
|
18
|
+
*/
|
|
19
|
+
export const SUMMARY_TIME_SCALE_DIVISOR = 100 as const
|
|
10
20
|
|
|
11
21
|
/**
|
|
12
22
|
* Number of schema/operation nodes to dispatch concurrently during generation.
|
|
@@ -27,19 +37,6 @@ export const HOOK_LISTENERS_PER_PLUGIN = 4
|
|
|
27
37
|
*/
|
|
28
38
|
export const OPERATION_FILTER_TYPES: ReadonlySet<string> = new Set(['tag', 'operationId', 'path', 'method', 'contentType'])
|
|
29
39
|
|
|
30
|
-
/**
|
|
31
|
-
* Numeric log-level thresholds used internally to compare verbosity.
|
|
32
|
-
*
|
|
33
|
-
* Higher numbers are more verbose.
|
|
34
|
-
*/
|
|
35
|
-
export const logLevel = {
|
|
36
|
-
silent: Number.NEGATIVE_INFINITY,
|
|
37
|
-
error: 0,
|
|
38
|
-
warn: 1,
|
|
39
|
-
info: 3,
|
|
40
|
-
verbose: 4,
|
|
41
|
-
} as const
|
|
42
|
-
|
|
43
40
|
/**
|
|
44
41
|
* Stable codes Kubb attaches to a `Diagnostic`. Each maps to a known failure mode
|
|
45
42
|
* and stays stable so it can be referenced in tooling and (later) docs. Reference
|
|
@@ -97,10 +94,6 @@ export const diagnosticCode = {
|
|
|
97
94
|
* without one.
|
|
98
95
|
*/
|
|
99
96
|
adapterRequired: 'KUBB_ADAPTER_REQUIRED',
|
|
100
|
-
/**
|
|
101
|
-
* The `devtools` config is set to something other than an object.
|
|
102
|
-
*/
|
|
103
|
-
devtoolsInvalid: 'KUBB_DEVTOOLS_INVALID',
|
|
104
97
|
/**
|
|
105
98
|
* A resolved output path escapes the output directory, which can stem from a path
|
|
106
99
|
* traversal in the spec or a misconfigured `group.name`.
|
package/src/createKubb.ts
CHANGED
|
@@ -2,15 +2,15 @@ import { resolve } from 'node:path'
|
|
|
2
2
|
import type { PossiblePromise } from '@internals/utils'
|
|
3
3
|
import { AsyncEventEmitter, BuildError } from '@internals/utils'
|
|
4
4
|
import type { FileNode, InputMeta, OperationNode, SchemaNode } from '@kubb/ast'
|
|
5
|
-
import {
|
|
5
|
+
import { HOOK_LISTENERS_PER_PLUGIN } from './constants.ts'
|
|
6
6
|
import type { Adapter } from './createAdapter.ts'
|
|
7
|
-
import { type Diagnostic,
|
|
7
|
+
import { type Diagnostic, Diagnostics, type ProblemDiagnostic, type UpdateDiagnostic } from './diagnostics.ts'
|
|
8
8
|
import { createStorage, type Storage } from './createStorage.ts'
|
|
9
9
|
import type { GeneratorContext } from './defineGenerator.ts'
|
|
10
10
|
import type { Middleware } from './defineMiddleware.ts'
|
|
11
11
|
import type { Parser } from './defineParser.ts'
|
|
12
12
|
import type { KubbPluginEndContext, KubbPluginSetupContext, KubbPluginStartContext, Plugin } from './definePlugin.ts'
|
|
13
|
-
import type { ReporterName } from './createReporter.ts'
|
|
13
|
+
import type { Reporter, ReporterName } from './createReporter.ts'
|
|
14
14
|
|
|
15
15
|
import { KubbDriver } from './KubbDriver.ts'
|
|
16
16
|
import { fsStorage } from './storages/fsStorage.ts'
|
|
@@ -269,28 +269,6 @@ export type Config<TInput = Input> = {
|
|
|
269
269
|
* @see {@link defineMiddleware} to create custom middleware.
|
|
270
270
|
*/
|
|
271
271
|
middleware?: Array<Middleware>
|
|
272
|
-
/**
|
|
273
|
-
* Kubb Studio cloud integration settings.
|
|
274
|
-
*
|
|
275
|
-
* Kubb Studio (https://kubb.studio) is a web-based IDE for managing API specs and generated code.
|
|
276
|
-
* Set to `true` to enable with default settings, or pass an object to customize the Studio URL.
|
|
277
|
-
*
|
|
278
|
-
* @default false // disabled by default
|
|
279
|
-
* @example
|
|
280
|
-
* ```ts
|
|
281
|
-
* devtools: true // use default Kubb Studio
|
|
282
|
-
* devtools: { studioUrl: 'https://my-studio.dev' } // custom Studio instance
|
|
283
|
-
* ```
|
|
284
|
-
*/
|
|
285
|
-
devtools?:
|
|
286
|
-
| true
|
|
287
|
-
| {
|
|
288
|
-
/**
|
|
289
|
-
* Override the Kubb Studio base URL.
|
|
290
|
-
* @default 'https://kubb.studio'
|
|
291
|
-
*/
|
|
292
|
-
studioUrl?: typeof DEFAULT_STUDIO_URL | (string & {})
|
|
293
|
-
}
|
|
294
272
|
/**
|
|
295
273
|
* Lifecycle hooks that execute during or after the build process.
|
|
296
274
|
*
|
|
@@ -323,21 +301,23 @@ export type Config<TInput = Input> = {
|
|
|
323
301
|
done?: string | Array<string>
|
|
324
302
|
}
|
|
325
303
|
/**
|
|
326
|
-
*
|
|
327
|
-
* the CLI `--reporter`
|
|
304
|
+
* The reporters available to the run, registered as instances. The host
|
|
305
|
+
* (the CLI via `--reporter`) selects which ones to trigger by `name` with {@link selectReporters}.
|
|
306
|
+
* `defineConfig` from the `kubb` package registers the built-in `cli`, `json`, and `file`
|
|
307
|
+
* reporters by default.
|
|
328
308
|
*
|
|
329
309
|
* - `cli` writes the end-of-run summary to the terminal.
|
|
330
310
|
* - `json` writes a machine-readable report to stdout, for CI.
|
|
331
311
|
* - `file` writes a debug log to `.kubb/<name>-<timestamp>.log`.
|
|
332
312
|
*
|
|
333
|
-
* @default ['cli']
|
|
334
|
-
*
|
|
335
313
|
* @example
|
|
336
314
|
* ```ts
|
|
337
|
-
*
|
|
315
|
+
* import { cliReporter, jsonReporter } from '@kubb/core'
|
|
316
|
+
*
|
|
317
|
+
* reporters: [cliReporter, jsonReporter, myReporter]
|
|
338
318
|
* ```
|
|
339
319
|
*/
|
|
340
|
-
reporters
|
|
320
|
+
reporters: Array<Reporter>
|
|
341
321
|
}
|
|
342
322
|
|
|
343
323
|
/**
|
|
@@ -345,7 +325,7 @@ export type Config<TInput = Input> = {
|
|
|
345
325
|
*
|
|
346
326
|
* `UserConfig` is what you pass to `defineConfig()`. It has optional `root`, `plugins`, `parsers`, and `adapter`
|
|
347
327
|
* fields (which fall back to sensible defaults). All other Config options are available, including `output`, `input`,
|
|
348
|
-
* `storage`, `middleware`,
|
|
328
|
+
* `storage`, `middleware`, and `hooks`.
|
|
349
329
|
*
|
|
350
330
|
* @example
|
|
351
331
|
* ```ts
|
|
@@ -356,7 +336,7 @@ export type Config<TInput = Input> = {
|
|
|
356
336
|
* })
|
|
357
337
|
* ```
|
|
358
338
|
*/
|
|
359
|
-
export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins' | 'parsers' | 'adapter' | 'storage'> & {
|
|
339
|
+
export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins' | 'parsers' | 'adapter' | 'storage' | 'reporters'> & {
|
|
360
340
|
/**
|
|
361
341
|
* Project root directory, absolute or relative to the config file location.
|
|
362
342
|
* @default process.cwd()
|
|
@@ -382,6 +362,12 @@ export type UserConfig<TInput = Input> = Omit<Config<TInput>, 'root' | 'plugins'
|
|
|
382
362
|
* @default fsStorage()
|
|
383
363
|
*/
|
|
384
364
|
storage?: Storage
|
|
365
|
+
/**
|
|
366
|
+
* Reporters available to the run. `defineConfig` registers the built-in `cli`, `json`, and
|
|
367
|
+
* `file` reporters when omitted.
|
|
368
|
+
* @default [cliReporter, jsonReporter, fileReporter] // applied by `defineConfig` from the `kubb` package
|
|
369
|
+
*/
|
|
370
|
+
reporters?: Array<Reporter>
|
|
385
371
|
}
|
|
386
372
|
|
|
387
373
|
declare global {
|
|
@@ -877,25 +863,11 @@ function resolveConfig(userConfig: UserConfig): Config {
|
|
|
877
863
|
...userConfig.output,
|
|
878
864
|
},
|
|
879
865
|
storage: userConfig.storage ?? fsStorage(),
|
|
880
|
-
|
|
881
|
-
? {
|
|
882
|
-
studioUrl: DEFAULT_STUDIO_URL,
|
|
883
|
-
...(typeof userConfig.devtools === 'boolean' ? {} : userConfig.devtools),
|
|
884
|
-
}
|
|
885
|
-
: undefined,
|
|
866
|
+
reporters: userConfig.reporters ?? [],
|
|
886
867
|
plugins: userConfig.plugins ?? [],
|
|
887
868
|
}
|
|
888
869
|
}
|
|
889
870
|
|
|
890
|
-
/**
|
|
891
|
-
* Type guard to check if a given config has an `input.path`.
|
|
892
|
-
*/
|
|
893
|
-
export function isInputPath(config: UserConfig | undefined): config is UserConfig<InputPath> & { input: InputPath }
|
|
894
|
-
export function isInputPath(config: Config | undefined): config is Config<InputPath> & { input: InputPath }
|
|
895
|
-
export function isInputPath(config: Config | UserConfig | undefined): config is (Config<InputPath> | UserConfig<InputPath>) & { input: InputPath } {
|
|
896
|
-
return typeof config?.input === 'object' && config.input !== null && 'path' in config.input
|
|
897
|
-
}
|
|
898
|
-
|
|
899
871
|
type CreateKubbOptions = {
|
|
900
872
|
hooks?: AsyncEventEmitter<KubbHooks>
|
|
901
873
|
}
|
|
@@ -973,9 +945,9 @@ export class Kubb {
|
|
|
973
945
|
const out = await this.safeBuild()
|
|
974
946
|
if (Diagnostics.hasError(out.diagnostics)) {
|
|
975
947
|
const errors = out.diagnostics
|
|
976
|
-
.filter(
|
|
948
|
+
.filter(Diagnostics.isProblem)
|
|
977
949
|
.filter((diagnostic) => diagnostic.severity === 'error')
|
|
978
|
-
.map((diagnostic) => diagnostic.cause ?? new
|
|
950
|
+
.map((diagnostic) => diagnostic.cause ?? new Diagnostics.Error(diagnostic))
|
|
979
951
|
throw new BuildError(`Build failed with ${errors.length} ${errors.length === 1 ? 'error' : 'errors'}`, { errors })
|
|
980
952
|
}
|
|
981
953
|
return out
|
package/src/createReporter.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { logLevel } from './
|
|
1
|
+
import type { logLevel } from './defineLogger.ts'
|
|
2
2
|
import type { Config } from './createKubb.ts'
|
|
3
3
|
import type { Diagnostic } from './diagnostics.ts'
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ export type ReporterContext = {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Host-facing reporter, as installed onto a run. Unlike a Logger (the live TUI view), a reporter
|
|
48
|
-
* never sees the event emitter. `report` runs once per config; `
|
|
48
|
+
* never sees the event emitter. `report` runs once per config; `drain`, when present, runs once
|
|
49
49
|
* after the last config.
|
|
50
50
|
*/
|
|
51
51
|
export type Reporter = {
|
|
@@ -61,23 +61,23 @@ export type Reporter = {
|
|
|
61
61
|
* Optional finalizer called once after the run's last config. The host wires it to
|
|
62
62
|
* `kubb:lifecycle:end`. {@link createReporter} closes it over the reports `report` returned.
|
|
63
63
|
*/
|
|
64
|
-
|
|
64
|
+
drain?: (context: ReporterContext) => void | Promise<void>
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Reporter definition passed to {@link createReporter}. `report` returns the value to collect for
|
|
69
|
-
* this config (e.g. a built report), and the optional `
|
|
69
|
+
* this config (e.g. a built report), and the optional `drain` receives the collected reports to
|
|
70
70
|
* emit as one document. `T` is inferred from `report`'s return type.
|
|
71
71
|
*/
|
|
72
72
|
export type UserReporter<T = void> = {
|
|
73
73
|
name: string
|
|
74
74
|
report: (result: GenerationResult, context: ReporterContext) => T | Promise<T>
|
|
75
|
-
|
|
75
|
+
drain?: (context: ReporterContext, reports: Array<T>) => void | Promise<void>
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* Defines a reporter. When the definition has a `
|
|
80
|
-
* `report` returns and hands the array to `
|
|
79
|
+
* Defines a reporter. When the definition has a `drain`, the returned reporter buffers each value
|
|
80
|
+
* `report` returns and hands the array to `drain` once, then clears it. Without a `drain`, nothing
|
|
81
81
|
* is buffered. Wiring the reporter onto the run's events is the host's job, so the reporter only
|
|
82
82
|
* ever deals with a {@link GenerationResult}.
|
|
83
83
|
*
|
|
@@ -90,16 +90,21 @@ export type UserReporter<T = void> = {
|
|
|
90
90
|
* report(result) {
|
|
91
91
|
* return { status: Diagnostics.hasError(result.diagnostics) ? 'failed' : 'success', diagnostics: result.diagnostics }
|
|
92
92
|
* },
|
|
93
|
-
*
|
|
93
|
+
* drain(context, reports) {
|
|
94
94
|
* process.stdout.write(`${JSON.stringify(reports, null, 2)}\n`)
|
|
95
95
|
* },
|
|
96
96
|
* })
|
|
97
97
|
* ```
|
|
98
98
|
*/
|
|
99
99
|
export function createReporter<T = void>(reporter: UserReporter<T>): Reporter {
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
102
|
-
return {
|
|
100
|
+
const drain = reporter.drain
|
|
101
|
+
if (!drain) {
|
|
102
|
+
return {
|
|
103
|
+
name: reporter.name,
|
|
104
|
+
async report(result, context) {
|
|
105
|
+
await reporter.report(result, context)
|
|
106
|
+
},
|
|
107
|
+
}
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
const reports: Array<T> = []
|
|
@@ -109,9 +114,34 @@ export function createReporter<T = void>(reporter: UserReporter<T>): Reporter {
|
|
|
109
114
|
async report(result, context) {
|
|
110
115
|
reports.push(await reporter.report(result, context))
|
|
111
116
|
},
|
|
112
|
-
async
|
|
113
|
-
await
|
|
117
|
+
async drain(context) {
|
|
118
|
+
await drain(context, reports)
|
|
114
119
|
reports.length = 0
|
|
115
120
|
},
|
|
116
121
|
}
|
|
117
122
|
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Picks the reporters whose `name` matches one of `names`, in the order the names are given.
|
|
126
|
+
* The config carries every available reporter, and the host selects which to activate by name
|
|
127
|
+
* (the CLI maps `--reporter` to this). Duplicate names and names without a matching reporter are
|
|
128
|
+
* skipped.
|
|
129
|
+
*/
|
|
130
|
+
export function selectReporters(reporters: ReadonlyArray<Reporter>, names: ReadonlyArray<string>): Array<Reporter> {
|
|
131
|
+
const seen = new Set<string>()
|
|
132
|
+
const selected: Array<Reporter> = []
|
|
133
|
+
|
|
134
|
+
for (const name of names) {
|
|
135
|
+
if (seen.has(name)) {
|
|
136
|
+
continue
|
|
137
|
+
}
|
|
138
|
+
seen.add(name)
|
|
139
|
+
|
|
140
|
+
const reporter = reporters.find((candidate) => candidate.name === name)
|
|
141
|
+
if (reporter) {
|
|
142
|
+
selected.push(reporter)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return selected
|
|
147
|
+
}
|
package/src/defineGenerator.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { KubbHooks } from './types.ts'
|
|
|
6
6
|
import type { KubbDriver } from './KubbDriver.ts'
|
|
7
7
|
import type { Plugin, PluginFactoryOptions } from './definePlugin.ts'
|
|
8
8
|
import type { Resolver } from './defineResolver.ts'
|
|
9
|
-
import type { Config
|
|
9
|
+
import type { Config } from './types.ts'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Context object passed to generator `schema`, `operation`, and `operations` methods.
|
|
@@ -67,7 +67,7 @@ export type GeneratorContext<TOptions extends PluginFactoryOptions = PluginFacto
|
|
|
67
67
|
* Report a warning. Collected as a `warning` diagnostic attributed to the current
|
|
68
68
|
* plugin. It surfaces in the run summary but does not fail the build. For a structured
|
|
69
69
|
* diagnostic with a code and source location, use `Diagnostics.report` or throw a
|
|
70
|
-
* `
|
|
70
|
+
* `Diagnostics.Error` directly.
|
|
71
71
|
*/
|
|
72
72
|
warn: (message: string) => void
|
|
73
73
|
/**
|
|
@@ -80,10 +80,6 @@ export type GeneratorContext<TOptions extends PluginFactoryOptions = PluginFacto
|
|
|
80
80
|
* the current plugin.
|
|
81
81
|
*/
|
|
82
82
|
info: (message: string) => void
|
|
83
|
-
/**
|
|
84
|
-
* Open the current input node in Kubb Studio.
|
|
85
|
-
*/
|
|
86
|
-
openInStudio: (options?: DevtoolsOptions) => Promise<void>
|
|
87
83
|
/**
|
|
88
84
|
* The configured adapter instance.
|
|
89
85
|
*/
|
package/src/defineLogger.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import type { AsyncEventEmitter } from '@internals/utils'
|
|
2
|
-
import type { logLevel } from './constants.ts'
|
|
3
2
|
import type { KubbHooks } from './types.ts'
|
|
4
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Numeric log-level thresholds used internally to compare verbosity.
|
|
6
|
+
*
|
|
7
|
+
* Higher numbers are more verbose.
|
|
8
|
+
*/
|
|
9
|
+
export const logLevel = {
|
|
10
|
+
silent: Number.NEGATIVE_INFINITY,
|
|
11
|
+
error: 0,
|
|
12
|
+
warn: 1,
|
|
13
|
+
info: 3,
|
|
14
|
+
verbose: 4,
|
|
15
|
+
} as const
|
|
16
|
+
|
|
5
17
|
/**
|
|
6
18
|
* Options accepted by a logger's `install` callback.
|
|
7
19
|
*/
|
package/src/defineResolver.ts
CHANGED
|
@@ -2,8 +2,7 @@ import path from 'node:path'
|
|
|
2
2
|
import { camelCase, pascalCase } from '@internals/utils'
|
|
3
3
|
import type { FileNode, InputMeta, Node, OperationNode, SchemaNode } from '@kubb/ast'
|
|
4
4
|
import { createFile, isOperationNode, isSchemaNode } from '@kubb/ast'
|
|
5
|
-
import {
|
|
6
|
-
import { DiagnosticError } from './diagnostics.ts'
|
|
5
|
+
import { Diagnostics } from './diagnostics.ts'
|
|
7
6
|
import type { PluginFactoryOptions } from './definePlugin.ts'
|
|
8
7
|
import { getMode } from './definePlugin.ts'
|
|
9
8
|
import type { Config, Group, Output } from './types.ts'
|
|
@@ -456,8 +455,8 @@ export function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }:
|
|
|
456
455
|
const outputDir = path.resolve(root, output.path)
|
|
457
456
|
const outputDirWithSep = outputDir.endsWith(path.sep) ? outputDir : `${outputDir}${path.sep}`
|
|
458
457
|
if (result !== outputDir && !result.startsWith(outputDirWithSep)) {
|
|
459
|
-
throw new
|
|
460
|
-
code:
|
|
458
|
+
throw new Diagnostics.Error({
|
|
459
|
+
code: Diagnostics.code.pathTraversal,
|
|
461
460
|
severity: 'error',
|
|
462
461
|
message: `Resolved path "${result}" is outside the output directory "${outputDir}".`,
|
|
463
462
|
help: 'This can stem from a path traversal in the OpenAPI specification or a misconfigured `group.name` function. Keep generated paths within the output directory.',
|