@kubb/adapter-oas 5.0.0-beta.3 → 5.0.0-beta.30
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/README.md +98 -0
- package/dist/index.cjs +778 -417
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +37 -66
- package/dist/index.js +778 -414
- package/dist/index.js.map +1 -1
- package/extension.yaml +431 -0
- package/package.json +6 -4
- package/src/adapter.bench.ts +64 -0
- package/src/adapter.ts +90 -48
- package/src/dialect.ts +38 -0
- package/src/discriminator.ts +57 -40
- package/src/factory.ts +1 -4
- package/src/index.ts +2 -2
- package/src/parser.ts +219 -134
- package/src/refs.ts +16 -4
- package/src/resolvers.ts +50 -21
- package/src/stream.ts +175 -0
- package/src/types.ts +21 -11
package/src/refs.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isReference } from './guards.ts'
|
|
2
2
|
import type { Document } from './types.ts'
|
|
3
3
|
|
|
4
|
+
const _refCache = new WeakMap<Document, Map<string, unknown>>()
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Resolves a local JSON pointer reference from a document.
|
|
6
8
|
*
|
|
@@ -18,11 +20,19 @@ export function resolveRef<T = unknown>(document: Document, $ref: string): T | n
|
|
|
18
20
|
if ($ref === '') {
|
|
19
21
|
return null
|
|
20
22
|
}
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
if (!$ref.startsWith('#')) return null
|
|
24
|
+
$ref = globalThis.decodeURIComponent($ref.substring(1))
|
|
25
|
+
|
|
26
|
+
let docCache = _refCache.get(document)
|
|
27
|
+
if (!docCache) {
|
|
28
|
+
docCache = new Map()
|
|
29
|
+
_refCache.set(document, docCache)
|
|
25
30
|
}
|
|
31
|
+
|
|
32
|
+
if (docCache.has($ref)) {
|
|
33
|
+
return docCache.get($ref) as T
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
const current = $ref
|
|
27
37
|
.split('/')
|
|
28
38
|
.filter(Boolean)
|
|
@@ -31,6 +41,8 @@ export function resolveRef<T = unknown>(document: Document, $ref: string): T | n
|
|
|
31
41
|
if (!current) {
|
|
32
42
|
throw new Error(`Could not find a definition for ${origRef}.`)
|
|
33
43
|
}
|
|
44
|
+
|
|
45
|
+
docCache.set($ref, current)
|
|
34
46
|
return current as T
|
|
35
47
|
}
|
|
36
48
|
|
package/src/resolvers.ts
CHANGED
|
@@ -86,7 +86,7 @@ export type OperationsOptions = {
|
|
|
86
86
|
* ```
|
|
87
87
|
*/
|
|
88
88
|
export function getParameters(document: Document, operation: Operation): Array<ParameterObject> {
|
|
89
|
-
const resolveParams = (params: unknown
|
|
89
|
+
const resolveParams = (params: Array<unknown>): Array<ParameterObject> =>
|
|
90
90
|
params.map((p) => dereferenceWithRef(document, p)).filter((p): p is ParameterObject => !!p && typeof p === 'object' && 'in' in p && 'name' in p)
|
|
91
91
|
|
|
92
92
|
const operationParams = resolveParams(operation.schema?.parameters || [])
|
|
@@ -108,7 +108,7 @@ export function getParameters(document: Document, operation: Operation): Array<P
|
|
|
108
108
|
return Array.from(paramMap.values())
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
function getResponseBody(responseBody: boolean | ResponseObject, contentType?: string): MediaTypeObject | false | [string, MediaTypeObject, ...string
|
|
111
|
+
function getResponseBody(responseBody: boolean | ResponseObject, contentType?: string): MediaTypeObject | false | [string, MediaTypeObject, ...Array<string>] {
|
|
112
112
|
if (!responseBody) return false
|
|
113
113
|
if (isReference(responseBody)) return false
|
|
114
114
|
|
|
@@ -260,7 +260,7 @@ function hasStructuralKeywords(fragment: SchemaObject): boolean {
|
|
|
260
260
|
export function flattenSchema(schema: SchemaObject | null): SchemaObject | null {
|
|
261
261
|
if (!schema?.allOf || schema.allOf.length === 0) return schema ?? null
|
|
262
262
|
|
|
263
|
-
const allOfFragments = schema.allOf as SchemaObject
|
|
263
|
+
const allOfFragments = schema.allOf as Array<SchemaObject>
|
|
264
264
|
if (allOfFragments.some((item) => isRef(item))) return schema
|
|
265
265
|
if (allOfFragments.some(hasStructuralKeywords)) return schema
|
|
266
266
|
|
|
@@ -305,27 +305,25 @@ export function extractSchemaFromContent(content: Record<string, unknown> | unde
|
|
|
305
305
|
/**
|
|
306
306
|
* Walks a schema tree and collects the names of all `#/components/schemas/<name>` `$ref`s.
|
|
307
307
|
*/
|
|
308
|
-
function collectRefs(schema: unknown
|
|
308
|
+
function* collectRefs(schema: unknown): Generator<string, void, undefined> {
|
|
309
309
|
if (Array.isArray(schema)) {
|
|
310
|
-
for (const item of schema) collectRefs(item
|
|
311
|
-
return
|
|
310
|
+
for (const item of schema) yield* collectRefs(item)
|
|
311
|
+
return
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
if (schema && typeof schema === 'object') {
|
|
315
315
|
for (const key in schema) {
|
|
316
316
|
const value = (schema as Record<string, unknown>)[key]
|
|
317
|
-
if (key === '$ref' && typeof value === 'string') {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
317
|
+
if (!(key === '$ref' && typeof value === 'string')) {
|
|
318
|
+
yield* collectRefs(value)
|
|
319
|
+
continue
|
|
320
|
+
}
|
|
321
|
+
if (value.startsWith(SCHEMA_REF_PREFIX)) {
|
|
322
|
+
const name = value.slice(SCHEMA_REF_PREFIX.length)
|
|
323
|
+
if (name) yield name
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
|
-
|
|
328
|
-
return refs
|
|
329
327
|
}
|
|
330
328
|
|
|
331
329
|
/**
|
|
@@ -341,13 +339,13 @@ function collectRefs(schema: unknown, refs = new Set<string>()): Set<string> {
|
|
|
341
339
|
* ```
|
|
342
340
|
*/
|
|
343
341
|
export function sortSchemas(schemas: Record<string, SchemaObject>): Record<string, SchemaObject> {
|
|
344
|
-
const deps = new Map<string, string
|
|
342
|
+
const deps = new Map<string, Array<string>>()
|
|
345
343
|
|
|
346
344
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
347
|
-
deps.set(name,
|
|
345
|
+
deps.set(name, [...new Set(collectRefs(schema))])
|
|
348
346
|
}
|
|
349
347
|
|
|
350
|
-
const sorted: string
|
|
348
|
+
const sorted: Array<string> = []
|
|
351
349
|
const visited = new Set<string>()
|
|
352
350
|
|
|
353
351
|
function visit(name: string, stack: Set<string>) {
|
|
@@ -404,7 +402,7 @@ function resolveSchemaRef(document: Document, schema: SchemaObject): SchemaObjec
|
|
|
404
402
|
export function getSchemas(document: Document, { contentType }: GetSchemasOptions): GetSchemasResult {
|
|
405
403
|
const components = document.components
|
|
406
404
|
|
|
407
|
-
const candidates: SchemaWithMetadata
|
|
405
|
+
const candidates: Array<SchemaWithMetadata> = [
|
|
408
406
|
...Object.entries((components?.schemas as Record<string, SchemaObject>) ?? {}).map(([name, schema]) => ({
|
|
409
407
|
schema: resolveSchemaRef(document, schema),
|
|
410
408
|
source: 'schemas' as const,
|
|
@@ -426,7 +424,7 @@ export function getSchemas(document: Document, { contentType }: GetSchemasOption
|
|
|
426
424
|
),
|
|
427
425
|
]
|
|
428
426
|
|
|
429
|
-
const normalizedNames = new Map<string, SchemaWithMetadata
|
|
427
|
+
const normalizedNames = new Map<string, Array<SchemaWithMetadata>>()
|
|
430
428
|
for (const item of candidates) {
|
|
431
429
|
const key = pascalCase(item.originalName)
|
|
432
430
|
const bucket = normalizedNames.get(key) ?? []
|
|
@@ -514,6 +512,7 @@ export function buildSchemaNode(schema: SchemaObject, name: string | null | unde
|
|
|
514
512
|
writeOnly: schema.writeOnly,
|
|
515
513
|
default: defaultValue,
|
|
516
514
|
example: schema.example,
|
|
515
|
+
format: schema.format,
|
|
517
516
|
} as const
|
|
518
517
|
}
|
|
519
518
|
|
|
@@ -530,7 +529,7 @@ export function buildSchemaNode(schema: SchemaObject, name: string | null | unde
|
|
|
530
529
|
* // ['application/json', 'multipart/form-data']
|
|
531
530
|
* ```
|
|
532
531
|
*/
|
|
533
|
-
export function getRequestBodyContentTypes(document: Document, operation: Operation): string
|
|
532
|
+
export function getRequestBodyContentTypes(document: Document, operation: Operation): Array<string> {
|
|
534
533
|
if (operation.schema.requestBody) {
|
|
535
534
|
operation.schema.requestBody = dereferenceWithRef(document, operation.schema.requestBody)
|
|
536
535
|
}
|
|
@@ -542,3 +541,33 @@ export function getRequestBodyContentTypes(document: Document, operation: Operat
|
|
|
542
541
|
// Do not bail out on isReference — the content is already present on the merged object.
|
|
543
542
|
return body.content ? Object.keys(body.content) : []
|
|
544
543
|
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Returns all response content type keys for an operation at a given status code.
|
|
547
|
+
*
|
|
548
|
+
* Response `$ref`s are resolved in-place first — the same mutation `getResponseSchema` performs —
|
|
549
|
+
* so the returned list reflects the available content types even for referenced responses.
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* ```ts
|
|
553
|
+
* getResponseBodyContentTypes(document, operation, 200)
|
|
554
|
+
* // ['application/json', 'application/xml']
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
export function getResponseBodyContentTypes(document: Document, operation: Operation, statusCode: string | number): Array<string> {
|
|
558
|
+
if (operation.schema.responses) {
|
|
559
|
+
const responses = operation.schema.responses
|
|
560
|
+
for (const key in responses) {
|
|
561
|
+
const schema = responses[key]
|
|
562
|
+
if (schema && isReference(schema)) {
|
|
563
|
+
responses[key] = resolveRef<any>(document, schema.$ref)
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const responseObj = operation.getResponseByStatusCode(statusCode)
|
|
569
|
+
if (!responseObj || typeof responseObj !== 'object' || isReference(responseObj)) return []
|
|
570
|
+
|
|
571
|
+
const body = responseObj as { content?: Record<string, unknown> }
|
|
572
|
+
return body.content ? Object.keys(body.content) : []
|
|
573
|
+
}
|
package/src/stream.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { ast } from '@kubb/core'
|
|
2
|
+
import type BaseOas from 'oas'
|
|
3
|
+
import { buildDiscriminatorChildMap, patchDiscriminatorNode } from './discriminator.ts'
|
|
4
|
+
import type { SchemaParser } from './parser.ts'
|
|
5
|
+
import { resolveServerUrl } from './resolvers.ts'
|
|
6
|
+
import type { DiscriminatorTarget } from './discriminator.ts'
|
|
7
|
+
import type { AdapterOas, Document, SchemaObject } from './types.ts'
|
|
8
|
+
|
|
9
|
+
export type PreScanResult = {
|
|
10
|
+
refAliasMap: Map<string, ast.SchemaNode>
|
|
11
|
+
enumNames: Array<string>
|
|
12
|
+
circularNames: Array<string>
|
|
13
|
+
discriminatorChildMap: Map<string, DiscriminatorTarget> | null
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Reads the server URL from the document's `servers` array at `serverIndex`,
|
|
18
|
+
* interpolating any `serverVariables` into the URL template.
|
|
19
|
+
*
|
|
20
|
+
* Returns `null` when `serverIndex` is omitted or out of range.
|
|
21
|
+
*
|
|
22
|
+
* @example Resolve the first server
|
|
23
|
+
* `resolveBaseUrl({ document, serverIndex: 0 })`
|
|
24
|
+
*
|
|
25
|
+
* @example Override a path variable
|
|
26
|
+
* `resolveBaseUrl({ document, serverIndex: 0, serverVariables: { version: 'v2' } })`
|
|
27
|
+
*/
|
|
28
|
+
export function resolveBaseUrl({
|
|
29
|
+
document,
|
|
30
|
+
serverIndex,
|
|
31
|
+
serverVariables,
|
|
32
|
+
}: {
|
|
33
|
+
document: Document
|
|
34
|
+
serverIndex?: number
|
|
35
|
+
serverVariables?: Record<string, string>
|
|
36
|
+
}): string | null {
|
|
37
|
+
const server = serverIndex !== undefined ? document.servers?.at(serverIndex) : undefined
|
|
38
|
+
return server?.url ? resolveServerUrl(server, serverVariables) : null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Parses every schema once to build the lookup structures that streaming needs upfront.
|
|
43
|
+
*
|
|
44
|
+
* Three things happen in this single pass:
|
|
45
|
+
* - `refAliasMap` records schemas that are pure `$ref` aliases so the streaming pass can inline them.
|
|
46
|
+
* - `enumNames` collects the names of every enum schema so plugins skip re-scanning the stream.
|
|
47
|
+
* - `circularNames` runs cycle detection, which requires all nodes in memory simultaneously.
|
|
48
|
+
* The `allNodes` array is local and drops out of scope as soon as this function returns.
|
|
49
|
+
*
|
|
50
|
+
* After this call, only `refAliasMap` and `discriminatorChildMap` stay alive in the adapter closure.
|
|
51
|
+
* Both are proportional to the number of aliases or discriminator parents, not total schema count.
|
|
52
|
+
*
|
|
53
|
+
* Each schema is parsed again during the streaming pass — this is intentional.
|
|
54
|
+
* Holding the parsed nodes in memory here would defeat the streaming memory benefit.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const { refAliasMap, enumNames, circularNames } = preScan({
|
|
59
|
+
* schemas,
|
|
60
|
+
* parseSchema,
|
|
61
|
+
* parserOptions,
|
|
62
|
+
* discriminator: 'strict',
|
|
63
|
+
* })
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export function preScan({
|
|
67
|
+
schemas,
|
|
68
|
+
parseSchema,
|
|
69
|
+
parserOptions,
|
|
70
|
+
discriminator,
|
|
71
|
+
}: {
|
|
72
|
+
schemas: Record<string, SchemaObject>
|
|
73
|
+
parseSchema: (entry: { schema: SchemaObject; name: string }, options: ast.ParserOptions) => ast.SchemaNode
|
|
74
|
+
parserOptions: ast.ParserOptions
|
|
75
|
+
discriminator: AdapterOas['options']['discriminator']
|
|
76
|
+
}): PreScanResult {
|
|
77
|
+
const allNodes: Array<ast.SchemaNode> = []
|
|
78
|
+
const refAliasMap = new Map<string, ast.SchemaNode>()
|
|
79
|
+
const enumNames: Array<string> = []
|
|
80
|
+
const discriminatorParentNodes: Array<ast.SchemaNode> = []
|
|
81
|
+
|
|
82
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
83
|
+
const node = parseSchema({ schema, name }, parserOptions)
|
|
84
|
+
allNodes.push(node)
|
|
85
|
+
if (node.type === 'ref' && node.name && node.name !== name) {
|
|
86
|
+
refAliasMap.set(name, node)
|
|
87
|
+
}
|
|
88
|
+
if (ast.narrowSchema(node, ast.schemaTypes.enum) && node.name) {
|
|
89
|
+
enumNames.push(node.name)
|
|
90
|
+
}
|
|
91
|
+
if (discriminator === 'inherit' && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) {
|
|
92
|
+
discriminatorParentNodes.push(node)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const circularNames = [...ast.findCircularSchemas(allNodes)]
|
|
97
|
+
const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null
|
|
98
|
+
|
|
99
|
+
return { refAliasMap, enumNames, circularNames, discriminatorChildMap }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Creates a lazy `InputStreamNode` from already-resolved adapter state.
|
|
104
|
+
*
|
|
105
|
+
* The schema and operation iterables each start a fresh parse pass on every
|
|
106
|
+
* `[Symbol.asyncIterator]()` call. This lets multiple plugins consume the same
|
|
107
|
+
* stream object independently without sharing a cursor or holding all nodes in memory.
|
|
108
|
+
*
|
|
109
|
+
* Ref aliases in `refAliasMap` are inlined during iteration: an alias entry is replaced
|
|
110
|
+
* with its target's parsed node (but keeps the alias name) so plugins never receive bare `ref` nodes.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const streamNode = createInputStream({ schemas, parseSchema, parseOperation, baseOas, parserOptions, refAliasMap, discriminatorChildMap, meta })
|
|
115
|
+
* for await (const schema of streamNode.schemas) {
|
|
116
|
+
* // each call to for-await restarts from the first schema
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export function createInputStream({
|
|
121
|
+
schemas,
|
|
122
|
+
parseSchema,
|
|
123
|
+
parseOperation,
|
|
124
|
+
baseOas,
|
|
125
|
+
parserOptions,
|
|
126
|
+
refAliasMap,
|
|
127
|
+
discriminatorChildMap,
|
|
128
|
+
meta,
|
|
129
|
+
}: {
|
|
130
|
+
schemas: Record<string, SchemaObject>
|
|
131
|
+
parseSchema: SchemaParser['parseSchema']
|
|
132
|
+
parseOperation: SchemaParser['parseOperation']
|
|
133
|
+
baseOas: BaseOas
|
|
134
|
+
parserOptions: ast.ParserOptions
|
|
135
|
+
refAliasMap: Map<string, ast.SchemaNode>
|
|
136
|
+
discriminatorChildMap: Map<string, DiscriminatorTarget> | null
|
|
137
|
+
meta: ast.InputMeta
|
|
138
|
+
}): ast.InputStreamNode {
|
|
139
|
+
const schemasIterable: AsyncIterable<ast.SchemaNode> = {
|
|
140
|
+
[Symbol.asyncIterator]() {
|
|
141
|
+
return (async function* () {
|
|
142
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
143
|
+
// Inline ref aliases: replace the alias entry with its target's parsed node
|
|
144
|
+
// (keeping the alias name). Skip the first parse entirely for alias entries
|
|
145
|
+
// since that result is never used.
|
|
146
|
+
const alias = refAliasMap.get(name)
|
|
147
|
+
if (alias?.name && schemas[alias.name]) {
|
|
148
|
+
yield { ...parseSchema({ schema: schemas[alias.name]!, name: alias.name }, parserOptions), name }
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const parsed = parseSchema({ schema, name }, parserOptions)
|
|
153
|
+
const node = discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)!) : parsed
|
|
154
|
+
yield node
|
|
155
|
+
}
|
|
156
|
+
})()
|
|
157
|
+
},
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const operationsIterable: AsyncIterable<ast.OperationNode> = {
|
|
161
|
+
[Symbol.asyncIterator]() {
|
|
162
|
+
return (async function* () {
|
|
163
|
+
for (const methods of Object.values(baseOas.getPaths())) {
|
|
164
|
+
for (const operation of Object.values(methods)) {
|
|
165
|
+
if (!operation) continue
|
|
166
|
+
const node = parseOperation(parserOptions, operation)
|
|
167
|
+
if (node) yield node
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
})()
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return ast.createStreamInput(schemasIterable, operationsIterable, meta)
|
|
175
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -123,8 +123,9 @@ export type ResponseObject = OASResponseObject
|
|
|
123
123
|
export type MediaTypeObject = OASMediaTypeObject
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* Configuration options for the OpenAPI adapter.
|
|
127
|
-
*
|
|
126
|
+
* Configuration options for the OpenAPI adapter. Controls spec validation,
|
|
127
|
+
* content-type selection, server URL resolution, and how types are derived
|
|
128
|
+
* from the spec.
|
|
128
129
|
*
|
|
129
130
|
* @example
|
|
130
131
|
* ```ts
|
|
@@ -138,23 +139,28 @@ export type MediaTypeObject = OASMediaTypeObject
|
|
|
138
139
|
*/
|
|
139
140
|
export type AdapterOasOptions = {
|
|
140
141
|
/**
|
|
141
|
-
* Validate the OpenAPI spec before parsing.
|
|
142
|
+
* Validate the OpenAPI spec with `@readme/openapi-parser` before parsing.
|
|
143
|
+
* Set to `false` only when you have a known-invalid spec you still want to
|
|
144
|
+
* generate from.
|
|
145
|
+
*
|
|
142
146
|
* @default true
|
|
143
147
|
*/
|
|
144
148
|
validate?: boolean
|
|
145
149
|
/**
|
|
146
|
-
* Preferred
|
|
147
|
-
*
|
|
150
|
+
* Preferred media type when an operation defines several. Defaults to the
|
|
151
|
+
* first JSON-compatible media type found in the spec.
|
|
148
152
|
*/
|
|
149
153
|
contentType?: ContentType
|
|
150
154
|
/**
|
|
151
|
-
* Index into `
|
|
152
|
-
*
|
|
155
|
+
* Index into the `servers` array from your OpenAPI spec. Used to compute the
|
|
156
|
+
* base URL for plugins that need it. Most projects pick `0` for the primary
|
|
157
|
+
* server. Omit to leave `baseURL` undefined.
|
|
153
158
|
*/
|
|
154
159
|
serverIndex?: number
|
|
155
160
|
/**
|
|
156
161
|
* Override values for `{variable}` placeholders in the selected server URL.
|
|
157
|
-
* Only used when `serverIndex` is set.
|
|
162
|
+
* Only used when `serverIndex` is set. Variables you do not provide use
|
|
163
|
+
* their `default` value from the spec.
|
|
158
164
|
*
|
|
159
165
|
* @example
|
|
160
166
|
* ```ts
|
|
@@ -165,9 +171,13 @@ export type AdapterOasOptions = {
|
|
|
165
171
|
*/
|
|
166
172
|
serverVariables?: Record<string, string>
|
|
167
173
|
/**
|
|
168
|
-
* How the discriminator field is interpreted.
|
|
169
|
-
* - `'strict'`
|
|
170
|
-
*
|
|
174
|
+
* How the `discriminator` field on `oneOf`/`anyOf` schemas is interpreted.
|
|
175
|
+
* - `'strict'` — child schemas stay exactly as written; the discriminator
|
|
176
|
+
* narrows types at the call site but child shapes are not modified.
|
|
177
|
+
* - `'inherit'` — Kubb propagates the discriminator property as a literal
|
|
178
|
+
* value into each child schema, so each branch's discriminator field is
|
|
179
|
+
* precisely typed.
|
|
180
|
+
*
|
|
171
181
|
* @default 'strict'
|
|
172
182
|
*/
|
|
173
183
|
discriminator?: 'strict' | 'inherit'
|