@kubb/adapter-oas 5.0.0-beta.6 → 5.0.0-beta.60
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/LICENSE +17 -10
- package/README.md +100 -0
- package/dist/index.cjs +1451 -614
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +821 -63
- package/dist/index.js +1453 -611
- package/dist/index.js.map +1 -1
- package/package.json +12 -8
- package/src/adapter.bench.ts +60 -0
- package/src/adapter.ts +133 -56
- package/src/bundler.ts +71 -0
- package/src/constants.ts +17 -3
- package/src/dialect.ts +38 -0
- package/src/discriminator.ts +68 -44
- package/src/factory.ts +63 -48
- package/src/index.ts +0 -3
- package/src/mime.ts +22 -0
- package/src/operation.ts +194 -0
- package/src/parser.ts +321 -203
- package/src/refs.ts +31 -5
- package/src/resolvers.ts +86 -48
- package/src/schemaDiagnostics.ts +76 -0
- package/src/stream.ts +283 -0
- package/src/types.ts +82 -53
- package/extension.yaml +0 -344
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/src/stream.ts
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { containsCircularRef, findCircularSchemas } from '@kubb/ast/utils'
|
|
2
|
+
import { ast } from '@kubb/core'
|
|
3
|
+
import { SCHEMA_REF_PREFIX } from './constants.ts'
|
|
4
|
+
import { buildDiscriminatorChildMap, patchDiscriminatorNode } from './discriminator.ts'
|
|
5
|
+
import { getOperations } from './operation.ts'
|
|
6
|
+
import type { SchemaParser } from './parser.ts'
|
|
7
|
+
import { resolveServerUrl } from './resolvers.ts'
|
|
8
|
+
import { reportSchemaDiagnostics } from './schemaDiagnostics.ts'
|
|
9
|
+
import type { DiscriminatorTarget } from './discriminator.ts'
|
|
10
|
+
import type { AdapterOas, Document, SchemaObject } from './types.ts'
|
|
11
|
+
|
|
12
|
+
export type PreScanResult = {
|
|
13
|
+
refAliasMap: Map<string, ast.SchemaNode>
|
|
14
|
+
enumNames: Array<string>
|
|
15
|
+
circularNames: Array<string>
|
|
16
|
+
discriminatorChildMap: Map<string, DiscriminatorTarget> | null
|
|
17
|
+
dedupePlan: ast.DedupePlan | null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builds the deduplication plan from the already-parsed top-level schema nodes plus a
|
|
22
|
+
* single extra parse pass over operations (so duplicates in request/response bodies are seen).
|
|
23
|
+
*
|
|
24
|
+
* Only enums and objects are candidates, and object shapes that reference a circular schema are
|
|
25
|
+
* rejected to avoid hoisting recursive structures. Inline shapes reuse their context-derived
|
|
26
|
+
* name (collision-resolved against existing component names). Shapes without a name stay inline.
|
|
27
|
+
*/
|
|
28
|
+
function createDedupePlan({
|
|
29
|
+
schemaNodes,
|
|
30
|
+
operationNodes,
|
|
31
|
+
schemaNames,
|
|
32
|
+
circularNames,
|
|
33
|
+
}: {
|
|
34
|
+
schemaNodes: Array<ast.SchemaNode>
|
|
35
|
+
operationNodes: Array<ast.OperationNode>
|
|
36
|
+
schemaNames: Array<string>
|
|
37
|
+
circularNames: Array<string>
|
|
38
|
+
}): ast.DedupePlan {
|
|
39
|
+
const circularSchemas = new Set(circularNames)
|
|
40
|
+
const usedNames = new Set(schemaNames)
|
|
41
|
+
|
|
42
|
+
return ast.buildDedupePlan([...schemaNodes, ...operationNodes], {
|
|
43
|
+
isCandidate: (node) => {
|
|
44
|
+
if (node.type === 'enum') return true
|
|
45
|
+
if (node.type !== 'object') return false
|
|
46
|
+
// Skip object shapes that are part of a circular chain, hoisting them would break the cycle.
|
|
47
|
+
if (node.name && circularSchemas.has(node.name)) return false
|
|
48
|
+
return !containsCircularRef(node, { circularSchemas })
|
|
49
|
+
},
|
|
50
|
+
nameFor: (node) => {
|
|
51
|
+
const base = node.name
|
|
52
|
+
if (!base) return null
|
|
53
|
+
|
|
54
|
+
let name = base
|
|
55
|
+
let counter = 2
|
|
56
|
+
while (usedNames.has(name)) {
|
|
57
|
+
name = `${base}${counter++}`
|
|
58
|
+
}
|
|
59
|
+
usedNames.add(name)
|
|
60
|
+
return name
|
|
61
|
+
},
|
|
62
|
+
refFor: (name) => `${SCHEMA_REF_PREFIX}${name}`,
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Reads the server URL from the document's `servers` array at `serverIndex`,
|
|
68
|
+
* interpolating any `serverVariables` into the URL template.
|
|
69
|
+
*
|
|
70
|
+
* Returns `null` when `serverIndex` is omitted or out of range.
|
|
71
|
+
*
|
|
72
|
+
* @example Resolve the first server
|
|
73
|
+
* `resolveBaseUrl({ document, serverIndex: 0 })`
|
|
74
|
+
*
|
|
75
|
+
* @example Override a path variable
|
|
76
|
+
* `resolveBaseUrl({ document, serverIndex: 0, serverVariables: { version: 'v2' } })`
|
|
77
|
+
*/
|
|
78
|
+
export function resolveBaseUrl({
|
|
79
|
+
document,
|
|
80
|
+
serverIndex,
|
|
81
|
+
serverVariables,
|
|
82
|
+
}: {
|
|
83
|
+
document: Document
|
|
84
|
+
serverIndex?: number
|
|
85
|
+
serverVariables?: Record<string, string>
|
|
86
|
+
}): string | null {
|
|
87
|
+
const server = serverIndex !== undefined ? document.servers?.at(serverIndex) : undefined
|
|
88
|
+
return server?.url ? resolveServerUrl(server, serverVariables) : null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Parses every schema once to build the lookup structures that streaming needs upfront.
|
|
93
|
+
*
|
|
94
|
+
* Three things happen in this single pass:
|
|
95
|
+
* - `refAliasMap` records schemas that are pure `$ref` aliases so the streaming pass can inline them.
|
|
96
|
+
* - `enumNames` collects the names of every enum schema so plugins skip re-scanning the stream.
|
|
97
|
+
* - `circularNames` runs cycle detection, which requires all nodes in memory simultaneously.
|
|
98
|
+
* The `allNodes` array is local and drops out of scope as soon as this function returns.
|
|
99
|
+
*
|
|
100
|
+
* After this call, only `refAliasMap` and `discriminatorChildMap` stay alive in the adapter closure.
|
|
101
|
+
* Both are proportional to the number of aliases or discriminator parents, not total schema count.
|
|
102
|
+
*
|
|
103
|
+
* Each schema is parsed again during the streaming pass. This is intentional.
|
|
104
|
+
* Holding the parsed nodes in memory here would defeat the streaming memory benefit.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* const { refAliasMap, enumNames, circularNames } = preScan({
|
|
109
|
+
* schemas,
|
|
110
|
+
* parseSchema,
|
|
111
|
+
* parserOptions,
|
|
112
|
+
* discriminator: 'strict',
|
|
113
|
+
* })
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function preScan({
|
|
117
|
+
schemas,
|
|
118
|
+
parseSchema,
|
|
119
|
+
parseOperation,
|
|
120
|
+
document,
|
|
121
|
+
parserOptions,
|
|
122
|
+
discriminator,
|
|
123
|
+
dedupe,
|
|
124
|
+
}: {
|
|
125
|
+
schemas: Record<string, SchemaObject>
|
|
126
|
+
parseSchema: (entry: { schema: SchemaObject; name: string }, options: ast.ParserOptions) => ast.SchemaNode
|
|
127
|
+
parseOperation: SchemaParser['parseOperation']
|
|
128
|
+
document: Document
|
|
129
|
+
parserOptions: ast.ParserOptions
|
|
130
|
+
discriminator: AdapterOas['options']['discriminator']
|
|
131
|
+
dedupe: boolean
|
|
132
|
+
}): PreScanResult {
|
|
133
|
+
const allNodes: Array<ast.SchemaNode> = []
|
|
134
|
+
const refAliasMap = new Map<string, ast.SchemaNode>()
|
|
135
|
+
const enumNames: Array<string> = []
|
|
136
|
+
const discriminatorParentNodes: Array<ast.SchemaNode> = []
|
|
137
|
+
|
|
138
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
139
|
+
const node = parseSchema({ schema, name }, parserOptions)
|
|
140
|
+
allNodes.push(node)
|
|
141
|
+
reportSchemaDiagnostics({ node, name })
|
|
142
|
+
if (node.type === 'ref' && node.name && node.name !== name) {
|
|
143
|
+
refAliasMap.set(name, node)
|
|
144
|
+
}
|
|
145
|
+
if (ast.narrowSchema(node, ast.schemaTypes.enum) && node.name) {
|
|
146
|
+
enumNames.push(node.name)
|
|
147
|
+
}
|
|
148
|
+
if (discriminator === 'inherit' && (schema.oneOf ?? schema.anyOf) && schema.discriminator?.propertyName) {
|
|
149
|
+
discriminatorParentNodes.push(node)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const circularNames = [...findCircularSchemas(allNodes)]
|
|
154
|
+
const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null
|
|
155
|
+
|
|
156
|
+
let dedupePlan: ast.DedupePlan | null = null
|
|
157
|
+
if (dedupe) {
|
|
158
|
+
// One extra parse pass over operations so duplicates in request/response bodies are seen.
|
|
159
|
+
// Reuses the already-parsed `allNodes` for schemas, no second schema parse.
|
|
160
|
+
const operationNodes: Array<ast.OperationNode> = []
|
|
161
|
+
for (const operation of getOperations(document)) {
|
|
162
|
+
const operationNode = parseOperation(parserOptions, operation)
|
|
163
|
+
if (operationNode) operationNodes.push(operationNode)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
dedupePlan = createDedupePlan({ schemaNodes: allNodes, operationNodes, schemaNames: Object.keys(schemas), circularNames })
|
|
167
|
+
|
|
168
|
+
for (const definition of dedupePlan.hoisted) {
|
|
169
|
+
if (definition.type === 'enum' && definition.name) enumNames.push(definition.name)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Enum names that duplicate an earlier schema's content are never emitted, so they are not
|
|
174
|
+
// advertised to plugins either.
|
|
175
|
+
const aliasNames = dedupePlan?.aliasNames
|
|
176
|
+
const emittedEnumNames = aliasNames && aliasNames.size > 0 ? enumNames.filter((name) => !aliasNames.has(name)) : enumNames
|
|
177
|
+
|
|
178
|
+
return { refAliasMap, enumNames: emittedEnumNames, circularNames, discriminatorChildMap, dedupePlan }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Creates a lazy `InputNode<true>` from already-resolved adapter state.
|
|
183
|
+
*
|
|
184
|
+
* The schema and operation iterables each start a fresh parse pass on every
|
|
185
|
+
* `[Symbol.asyncIterator]()` call. This lets multiple plugins consume the same
|
|
186
|
+
* stream object independently without sharing a cursor or holding all nodes in memory.
|
|
187
|
+
*
|
|
188
|
+
* Ref aliases in `refAliasMap` are inlined during iteration: an alias entry is replaced
|
|
189
|
+
* with its target's parsed node (but keeps the alias name) so plugins never receive bare `ref` nodes.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* const streamNode = createInputStream({ schemas, parseSchema, parseOperation, document, parserOptions, refAliasMap, discriminatorChildMap, meta })
|
|
194
|
+
* for await (const schema of streamNode.schemas) {
|
|
195
|
+
* // each call to for-await restarts from the first schema
|
|
196
|
+
* }
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function createInputStream({
|
|
200
|
+
schemas,
|
|
201
|
+
parseSchema,
|
|
202
|
+
parseOperation,
|
|
203
|
+
document,
|
|
204
|
+
parserOptions,
|
|
205
|
+
refAliasMap,
|
|
206
|
+
discriminatorChildMap,
|
|
207
|
+
dedupePlan,
|
|
208
|
+
meta,
|
|
209
|
+
}: {
|
|
210
|
+
schemas: Record<string, SchemaObject>
|
|
211
|
+
parseSchema: SchemaParser['parseSchema']
|
|
212
|
+
parseOperation: SchemaParser['parseOperation']
|
|
213
|
+
document: Document
|
|
214
|
+
parserOptions: ast.ParserOptions
|
|
215
|
+
refAliasMap: Map<string, ast.SchemaNode>
|
|
216
|
+
discriminatorChildMap: Map<string, DiscriminatorTarget> | null
|
|
217
|
+
dedupePlan: ast.DedupePlan | null
|
|
218
|
+
meta: ast.InputMeta
|
|
219
|
+
}): ast.InputNode<true> {
|
|
220
|
+
// Rewrites a top-level schema against the dedupe plan: a structurally identical sibling
|
|
221
|
+
// becomes a `ref` alias to the canonical one (keeping its own name). Otherwise nested
|
|
222
|
+
// duplicates are collapsed while the schema's own root is preserved.
|
|
223
|
+
const rewriteTopLevelSchema = (node: ast.SchemaNode): ast.SchemaNode => {
|
|
224
|
+
if (!dedupePlan) return node
|
|
225
|
+
|
|
226
|
+
const canonical = dedupePlan.canonicalBySignature.get(ast.signatureOf(node))
|
|
227
|
+
if (canonical && canonical.name !== node.name) {
|
|
228
|
+
return ast.factory.createSchema({
|
|
229
|
+
type: 'ref',
|
|
230
|
+
name: node.name ?? null,
|
|
231
|
+
ref: canonical.ref,
|
|
232
|
+
description: node.description,
|
|
233
|
+
deprecated: node.deprecated,
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return ast.applyDedupe(node, dedupePlan, true)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const schemasIterable: AsyncIterable<ast.SchemaNode> = {
|
|
241
|
+
[Symbol.asyncIterator]() {
|
|
242
|
+
return (async function* () {
|
|
243
|
+
// Hoisted canonical definitions are emitted first so the schema list owns the shared shapes.
|
|
244
|
+
if (dedupePlan) {
|
|
245
|
+
for (const definition of dedupePlan.hoisted) yield definition
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
249
|
+
// A top-level schema whose content duplicates an earlier one is not emitted: every
|
|
250
|
+
// ref to it is repointed at the first schema with that content, so its model would
|
|
251
|
+
// be dead code.
|
|
252
|
+
if (dedupePlan?.aliasNames.has(name)) continue
|
|
253
|
+
|
|
254
|
+
// Inline ref aliases: replace the alias entry with its target's parsed node
|
|
255
|
+
// (keeping the alias name). Skip the first parse entirely for alias entries
|
|
256
|
+
// since that result is never used.
|
|
257
|
+
const alias = refAliasMap.get(name)
|
|
258
|
+
if (alias?.name && schemas[alias.name]) {
|
|
259
|
+
yield rewriteTopLevelSchema({ ...parseSchema({ schema: schemas[alias.name]!, name: alias.name }, parserOptions), name })
|
|
260
|
+
continue
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const parsed = parseSchema({ schema, name }, parserOptions)
|
|
264
|
+
const node = discriminatorChildMap?.get(name) ? patchDiscriminatorNode(parsed, discriminatorChildMap.get(name)!) : parsed
|
|
265
|
+
yield rewriteTopLevelSchema(node)
|
|
266
|
+
}
|
|
267
|
+
})()
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const operationsIterable: AsyncIterable<ast.OperationNode> = {
|
|
272
|
+
[Symbol.asyncIterator]() {
|
|
273
|
+
return (async function* () {
|
|
274
|
+
for (const operation of getOperations(document)) {
|
|
275
|
+
const node = parseOperation(parserOptions, operation)
|
|
276
|
+
if (node) yield dedupePlan ? ast.applyDedupe(node, dedupePlan) : node
|
|
277
|
+
}
|
|
278
|
+
})()
|
|
279
|
+
},
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return ast.factory.createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta })
|
|
283
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
// external packages
|
|
2
|
-
|
|
3
1
|
import type { AdapterFactoryOptions } from '@kubb/core'
|
|
4
|
-
import { ast } from '@kubb/core'
|
|
5
|
-
import type {
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
OASDocument,
|
|
9
|
-
MediaTypeObject as OASMediaTypeObject,
|
|
10
|
-
ResponseObject as OASResponseObject,
|
|
11
|
-
SchemaObject as OASSchemaObject,
|
|
12
|
-
} from 'oas/types'
|
|
13
|
-
import type { OpenAPIV3 } from 'openapi-types'
|
|
2
|
+
import type { ast } from '@kubb/core'
|
|
3
|
+
import type { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema'
|
|
4
|
+
import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'
|
|
5
|
+
import type { Operation } from './operation.ts'
|
|
14
6
|
|
|
15
|
-
|
|
16
|
-
* Re-exports of `openapi-types` for use by adapter consumers.
|
|
17
|
-
*/
|
|
18
|
-
export type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'
|
|
7
|
+
export type { Operation }
|
|
19
8
|
|
|
20
9
|
/**
|
|
21
|
-
*
|
|
22
|
-
* Supports `'application/json'` or any other media type.
|
|
10
|
+
* Media type used to pick a schema from an operation's request or response.
|
|
23
11
|
*
|
|
24
12
|
* @example
|
|
25
13
|
* ```ts
|
|
@@ -41,7 +29,18 @@ export type ContentType = 'application/json' | (string & {})
|
|
|
41
29
|
* }
|
|
42
30
|
* ```
|
|
43
31
|
*/
|
|
44
|
-
export type SchemaObject =
|
|
32
|
+
export type SchemaObject = {
|
|
33
|
+
externalDocs?: unknown
|
|
34
|
+
xml?: unknown
|
|
35
|
+
$schema?: string
|
|
36
|
+
deprecated?: boolean
|
|
37
|
+
example?: unknown
|
|
38
|
+
examples?: Array<unknown>
|
|
39
|
+
nullable?: boolean
|
|
40
|
+
readOnly?: boolean
|
|
41
|
+
writeOnly?: boolean
|
|
42
|
+
discriminator?: DiscriminatorObject
|
|
43
|
+
'x-readme-ref-name'?: string
|
|
45
44
|
/**
|
|
46
45
|
* OAS 3.0 vendor extension: marks a schema as nullable without using `type: ['null', ...]`.
|
|
47
46
|
*/
|
|
@@ -68,44 +67,35 @@ export type SchemaObject = OASSchemaObject & {
|
|
|
68
67
|
*/
|
|
69
68
|
items?: SchemaObject | ReferenceObject
|
|
70
69
|
/**
|
|
71
|
-
*
|
|
70
|
+
* Allowed values for this schema.
|
|
72
71
|
*/
|
|
73
72
|
enum?: Array<string | number | boolean | null>
|
|
74
|
-
}
|
|
73
|
+
} & (OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject | JSONSchema4 | JSONSchema6 | JSONSchema7)
|
|
75
74
|
|
|
76
75
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* HttpMethods['GET'] // 'get'
|
|
82
|
-
* HttpMethods['POST'] // 'post'
|
|
83
|
-
* ```
|
|
76
|
+
* HTTP method in the lowercase form an OpenAPI path item uses for its keys.
|
|
84
77
|
*/
|
|
85
|
-
export
|
|
86
|
-
Uppercase<ast.HttpMethod>,
|
|
87
|
-
Lowercase<ast.HttpMethod>
|
|
88
|
-
>
|
|
78
|
+
export type HttpMethod = Lowercase<ast.HttpMethod>
|
|
89
79
|
|
|
90
80
|
/**
|
|
91
|
-
*
|
|
81
|
+
* Normalized OpenAPI document after parsing.
|
|
92
82
|
*/
|
|
93
|
-
export type
|
|
83
|
+
export type Document = (OpenAPIV3.Document | OpenAPIV3_1.Document) & Record<string, unknown>
|
|
94
84
|
|
|
95
85
|
/**
|
|
96
|
-
*
|
|
86
|
+
* Single operation object (the `get`/`post`/… entry on a path item) plus any vendor extensions.
|
|
97
87
|
*/
|
|
98
|
-
export type
|
|
88
|
+
export type OperationObject = (OpenAPIV3.OperationObject | OpenAPIV3_1.OperationObject) & Record<string, unknown>
|
|
99
89
|
|
|
100
90
|
/**
|
|
101
|
-
*
|
|
91
|
+
* Path item object holding the operations and shared parameters for a single URL path.
|
|
102
92
|
*/
|
|
103
|
-
export type
|
|
93
|
+
export type PathItemObject = OpenAPIV3.PathItemObject | OpenAPIV3_1.PathItemObject
|
|
104
94
|
|
|
105
95
|
/**
|
|
106
96
|
* Discriminator object for `oneOf`/`anyOf` schemas in OpenAPI.
|
|
107
97
|
*/
|
|
108
|
-
export type DiscriminatorObject =
|
|
98
|
+
export type DiscriminatorObject = OpenAPIV3.DiscriminatorObject | OpenAPIV3_1.DiscriminatorObject
|
|
109
99
|
|
|
110
100
|
/**
|
|
111
101
|
* OpenAPI reference object pointing to a schema definition via `$ref`.
|
|
@@ -113,18 +103,35 @@ export type DiscriminatorObject = OASDiscriminatorObject
|
|
|
113
103
|
export type ReferenceObject = OpenAPIV3.ReferenceObject
|
|
114
104
|
|
|
115
105
|
/**
|
|
116
|
-
* OpenAPI response object
|
|
106
|
+
* OpenAPI response object holding the content and headers for one status code.
|
|
107
|
+
*/
|
|
108
|
+
export type ResponseObject = OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* OpenAPI request body object that maps content types to their media type objects.
|
|
117
112
|
*/
|
|
118
|
-
export type
|
|
113
|
+
export type RequestBodyObject = OpenAPIV3.RequestBodyObject | OpenAPIV3_1.RequestBodyObject
|
|
119
114
|
|
|
120
115
|
/**
|
|
121
116
|
* OpenAPI media type object that maps a content-type string to its schema.
|
|
122
117
|
*/
|
|
123
|
-
export type MediaTypeObject =
|
|
118
|
+
export type MediaTypeObject = OpenAPIV3.MediaTypeObject | OpenAPIV3_1.MediaTypeObject
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* OpenAPI parameter object, narrowed so `in` is always one of the four valid locations.
|
|
122
|
+
*/
|
|
123
|
+
export type ParameterObject = {
|
|
124
|
+
in: 'cookie' | 'header' | 'path' | 'query'
|
|
125
|
+
} & (OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject)
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* OpenAPI server object describing a base URL and its `{variable}` substitutions.
|
|
129
|
+
*/
|
|
130
|
+
export type ServerObject = OpenAPIV3.ServerObject | OpenAPIV3_1.ServerObject
|
|
124
131
|
|
|
125
132
|
/**
|
|
126
|
-
* Configuration
|
|
127
|
-
*
|
|
133
|
+
* Configuration for the OpenAPI adapter: spec validation, content-type selection,
|
|
134
|
+
* server URL resolution, and how schema types are derived.
|
|
128
135
|
*
|
|
129
136
|
* @example
|
|
130
137
|
* ```ts
|
|
@@ -138,23 +145,28 @@ export type MediaTypeObject = OASMediaTypeObject
|
|
|
138
145
|
*/
|
|
139
146
|
export type AdapterOasOptions = {
|
|
140
147
|
/**
|
|
141
|
-
* Validate the OpenAPI spec before parsing.
|
|
148
|
+
* Validate the OpenAPI spec with `@readme/openapi-parser` before parsing.
|
|
149
|
+
* Set to `false` only when you have a known-invalid spec you still want to
|
|
150
|
+
* generate from.
|
|
151
|
+
*
|
|
142
152
|
* @default true
|
|
143
153
|
*/
|
|
144
154
|
validate?: boolean
|
|
145
155
|
/**
|
|
146
|
-
* Preferred
|
|
147
|
-
*
|
|
156
|
+
* Preferred media type when an operation defines several. Defaults to the
|
|
157
|
+
* first JSON-compatible media type found in the spec.
|
|
148
158
|
*/
|
|
149
159
|
contentType?: ContentType
|
|
150
160
|
/**
|
|
151
|
-
* Index into `
|
|
152
|
-
*
|
|
161
|
+
* Index into the `servers` array from your OpenAPI spec. Used to compute the
|
|
162
|
+
* base URL for plugins that need it. Most projects pick `0` for the primary
|
|
163
|
+
* server. Omit to leave `baseURL` undefined.
|
|
153
164
|
*/
|
|
154
165
|
serverIndex?: number
|
|
155
166
|
/**
|
|
156
167
|
* Override values for `{variable}` placeholders in the selected server URL.
|
|
157
|
-
* Only used when `serverIndex` is set.
|
|
168
|
+
* Only used when `serverIndex` is set. Variables you do not provide use
|
|
169
|
+
* their `default` value from the spec.
|
|
158
170
|
*
|
|
159
171
|
* @example
|
|
160
172
|
* ```ts
|
|
@@ -165,12 +177,28 @@ export type AdapterOasOptions = {
|
|
|
165
177
|
*/
|
|
166
178
|
serverVariables?: Record<string, string>
|
|
167
179
|
/**
|
|
168
|
-
* How the discriminator field is interpreted.
|
|
169
|
-
* - `'strict'`
|
|
170
|
-
*
|
|
180
|
+
* How the `discriminator` field on `oneOf`/`anyOf` schemas is interpreted.
|
|
181
|
+
* - `'strict'` child schemas stay exactly as written. The discriminator
|
|
182
|
+
* narrows types at the call site but child shapes are not modified.
|
|
183
|
+
* - `'inherit'` Kubb propagates the discriminator property as a literal
|
|
184
|
+
* value into each child schema, so each branch's discriminator field is
|
|
185
|
+
* precisely typed.
|
|
186
|
+
*
|
|
171
187
|
* @default 'strict'
|
|
172
188
|
*/
|
|
173
189
|
discriminator?: 'strict' | 'inherit'
|
|
190
|
+
/**
|
|
191
|
+
* Collapse structurally identical schemas and enums into a single shared definition.
|
|
192
|
+
*
|
|
193
|
+
* Duplicated inline shapes (especially enums repeated across many properties) are hoisted
|
|
194
|
+
* into one named schema. Every other occurrence, and any structurally identical top-level
|
|
195
|
+
* component, becomes a `ref` to it. Equality is shape-only, so documentation such as
|
|
196
|
+
* `description` and `example` is ignored. Set to `false` to keep every occurrence inline
|
|
197
|
+
* and produce byte-for-byte identical output to earlier versions.
|
|
198
|
+
*
|
|
199
|
+
* @default true
|
|
200
|
+
*/
|
|
201
|
+
dedupe?: boolean
|
|
174
202
|
} & Partial<ast.ParserOptions>
|
|
175
203
|
|
|
176
204
|
/**
|
|
@@ -182,6 +210,7 @@ export type AdapterOasResolvedOptions = {
|
|
|
182
210
|
serverIndex: AdapterOasOptions['serverIndex']
|
|
183
211
|
serverVariables: AdapterOasOptions['serverVariables']
|
|
184
212
|
discriminator: NonNullable<AdapterOasOptions['discriminator']>
|
|
213
|
+
dedupe: NonNullable<AdapterOasOptions['dedupe']>
|
|
185
214
|
dateType: NonNullable<AdapterOasOptions['dateType']>
|
|
186
215
|
integerType: NonNullable<AdapterOasOptions['integerType']>
|
|
187
216
|
unknownType: NonNullable<AdapterOasOptions['unknownType']>
|