@kubb/adapter-oas 5.0.0-beta.25 → 5.0.0-beta.27
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/index.cjs +43 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -16
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter.ts +2 -2
- package/src/discriminator.ts +1 -1
- package/src/parser.ts +29 -16
- package/src/resolvers.ts +8 -8
- package/src/stream.ts +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/adapter-oas",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.27",
|
|
4
4
|
"description": "OpenAPI and Swagger adapter for Kubb. Parses and validates OAS 2.0/3.x specifications into a @kubb/ast RootNode for downstream code generation plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"registry": "https://registry.npmjs.org/"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@redocly/openapi-core": "^2.
|
|
46
|
+
"@redocly/openapi-core": "^2.31.2",
|
|
47
47
|
"oas": "^32.1.18",
|
|
48
48
|
"oas-normalize": "^16.0.4",
|
|
49
49
|
"swagger2openapi": "^7.0.8",
|
|
50
|
-
"@kubb/core": "5.0.0-beta.
|
|
50
|
+
"@kubb/core": "5.0.0-beta.27"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/swagger2openapi": "^7.0.4",
|
package/src/adapter.ts
CHANGED
|
@@ -153,8 +153,8 @@ export const adapterOas = createAdapter<AdapterOas>((options) => {
|
|
|
153
153
|
async parse(source) {
|
|
154
154
|
const streamNode = await createStream(source)
|
|
155
155
|
|
|
156
|
-
const collect = async <T>(iter: AsyncIterable<T>): Promise<T
|
|
157
|
-
const out: T
|
|
156
|
+
const collect = async <T>(iter: AsyncIterable<T>): Promise<Array<T>> => {
|
|
157
|
+
const out: Array<T> = []
|
|
158
158
|
for await (const item of iter) out.push(item)
|
|
159
159
|
return out
|
|
160
160
|
}
|
package/src/discriminator.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type DiscriminatorTarget = {
|
|
|
14
14
|
* small pre-parsed subset of schemas (only the discriminator parents) rather than on all
|
|
15
15
|
* schemas at once.
|
|
16
16
|
*/
|
|
17
|
-
export function buildDiscriminatorChildMap(schemas: ast.SchemaNode
|
|
17
|
+
export function buildDiscriminatorChildMap(schemas: Array<ast.SchemaNode>): Map<string, DiscriminatorTarget> {
|
|
18
18
|
const childMap = new Map<string, DiscriminatorTarget>()
|
|
19
19
|
|
|
20
20
|
for (const schema of schemas) {
|
package/src/parser.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { URLPath } from '@internals/utils'
|
|
1
|
+
import { pascalCase, URLPath } from '@internals/utils'
|
|
2
2
|
import { ast } from '@kubb/core'
|
|
3
3
|
import BaseOas from 'oas'
|
|
4
4
|
import { DEFAULT_PARSER_OPTIONS, enumExtensionKeys, SCHEMA_REF_PREFIX, typeOptionMap } from './constants.ts'
|
|
@@ -161,7 +161,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
161
161
|
schema.additionalProperties === undefined
|
|
162
162
|
) {
|
|
163
163
|
const [memberSchema] = schema.allOf as Array<SchemaObject | ReferenceObject>
|
|
164
|
-
const memberNode = parseSchema({ schema: memberSchema! as SchemaObject, name
|
|
164
|
+
const memberNode = parseSchema({ schema: memberSchema! as SchemaObject, name }, rawOptions)
|
|
165
165
|
const { kind: _kind, ...memberNodeProps } = memberNode
|
|
166
166
|
const mergedNullable = nullable || memberNode.nullable || undefined
|
|
167
167
|
const mergedDefault = schema.default === null && mergedNullable ? undefined : (schema.default ?? memberNode.default)
|
|
@@ -208,7 +208,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
208
208
|
}
|
|
209
209
|
return true
|
|
210
210
|
})
|
|
211
|
-
.map((s) => parseSchema({ schema: s as SchemaObject }, rawOptions))
|
|
211
|
+
.map((s) => parseSchema({ schema: s as SchemaObject, name }, rawOptions))
|
|
212
212
|
|
|
213
213
|
const syntheticStart = allOfMembers.length
|
|
214
214
|
|
|
@@ -233,6 +233,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
233
233
|
properties: { [key]: resolved.properties[key] },
|
|
234
234
|
required: [key],
|
|
235
235
|
} as SchemaObject,
|
|
236
|
+
name,
|
|
236
237
|
},
|
|
237
238
|
rawOptions,
|
|
238
239
|
),
|
|
@@ -246,6 +247,9 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
246
247
|
|
|
247
248
|
if (schema.properties) {
|
|
248
249
|
const { allOf: _allOf, ...schemaWithoutAllOf } = schema
|
|
250
|
+
// Don't pass `name` here — the result must stay anonymous so it can be merged with the
|
|
251
|
+
// adjacent synthetic object in `mergeAdjacentObjectsLazy`. Nested enum qualification
|
|
252
|
+
// happens upstream via `convertObject`'s `setEnumName` propagation.
|
|
249
253
|
allOfMembers.push(parseSchema({ schema: schemaWithoutAllOf }, rawOptions))
|
|
250
254
|
}
|
|
251
255
|
|
|
@@ -301,7 +305,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
301
305
|
const members = unionMembers.map((s) => {
|
|
302
306
|
const ref = isReference(s) ? s.$ref : undefined
|
|
303
307
|
const discriminatorValue = ast.findDiscriminator(discriminator?.mapping, ref)
|
|
304
|
-
const memberNode = parseSchema({ schema: s as SchemaObject }, rawOptions)
|
|
308
|
+
const memberNode = parseSchema({ schema: s as SchemaObject, name }, rawOptions)
|
|
305
309
|
|
|
306
310
|
if (!discriminatorValue || !discriminator) {
|
|
307
311
|
return memberNode
|
|
@@ -351,7 +355,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
351
355
|
return ast.createSchema({
|
|
352
356
|
type: 'union',
|
|
353
357
|
...unionBase,
|
|
354
|
-
members: ast.simplifyUnion(unionMembers.map((s) => parseSchema({ schema: s as SchemaObject }, rawOptions))),
|
|
358
|
+
members: ast.simplifyUnion(unionMembers.map((s) => parseSchema({ schema: s as SchemaObject, name }, rawOptions))),
|
|
355
359
|
})
|
|
356
360
|
}
|
|
357
361
|
|
|
@@ -646,7 +650,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
646
650
|
*/
|
|
647
651
|
function convertArray({ schema, name, nullable, defaultValue, rawOptions, options }: SchemaContext): ast.SchemaNode {
|
|
648
652
|
const rawItems = schema.items as SchemaObject | undefined
|
|
649
|
-
const itemName = rawItems?.enum?.length && name ? ast.enumPropName(null, name, options.enumSuffix) :
|
|
653
|
+
const itemName = rawItems?.enum?.length && name ? ast.enumPropName(null, name, options.enumSuffix) : name
|
|
650
654
|
const items = rawItems ? [parseSchema({ schema: rawItems, name: itemName }, rawOptions)] : []
|
|
651
655
|
|
|
652
656
|
return ast.createSchema({
|
|
@@ -770,7 +774,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
770
774
|
}
|
|
771
775
|
|
|
772
776
|
if (Array.isArray(schema.type) && schema.type.length > 1) {
|
|
773
|
-
const nonNullTypes = schema.type.filter((t) => t !== 'null') as string
|
|
777
|
+
const nonNullTypes = schema.type.filter((t) => t !== 'null') as Array<string>
|
|
774
778
|
const arrayNullable = schema.type.includes('null') || nullable || undefined
|
|
775
779
|
|
|
776
780
|
if (nonNullTypes.length > 1) {
|
|
@@ -814,15 +818,17 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
814
818
|
/**
|
|
815
819
|
* Converts a dereferenced OAS parameter object into a `ParameterNode`.
|
|
816
820
|
*/
|
|
817
|
-
function parseParameter(options: ast.ParserOptions, param: Record<string, unknown
|
|
821
|
+
function parseParameter(options: ast.ParserOptions, param: Record<string, unknown>, parentName?: string): ast.ParameterNode {
|
|
818
822
|
const required = (param['required'] as boolean | undefined) ?? false
|
|
823
|
+
const paramName = param['name'] as string
|
|
824
|
+
const schemaName = parentName && paramName ? pascalCase(`${parentName} ${paramName}`) : undefined
|
|
819
825
|
|
|
820
826
|
const schema: ast.SchemaNode = param['schema']
|
|
821
|
-
? parseSchema({ schema: param['schema'] as SchemaObject }, options)
|
|
827
|
+
? parseSchema({ schema: param['schema'] as SchemaObject, name: schemaName }, options)
|
|
822
828
|
: ast.createSchema({ type: typeOptionMap.get(options.unknownType)! })
|
|
823
829
|
|
|
824
830
|
return ast.createParameter({
|
|
825
|
-
name:
|
|
831
|
+
name: paramName,
|
|
826
832
|
in: param['in'] as ast.ParameterLocation,
|
|
827
833
|
schema: {
|
|
828
834
|
...schema,
|
|
@@ -871,10 +877,10 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
871
877
|
* Collects property names whose schema has a truthy boolean flag (`readOnly` or `writeOnly`).
|
|
872
878
|
* `$ref` entries are skipped since their flags live on the dereferenced target.
|
|
873
879
|
*/
|
|
874
|
-
function collectPropertyKeysByFlag(schema: SchemaObject | null, flag: 'readOnly' | 'writeOnly'): string
|
|
880
|
+
function collectPropertyKeysByFlag(schema: SchemaObject | null, flag: 'readOnly' | 'writeOnly'): Array<string> | null {
|
|
875
881
|
if (!schema?.properties) return null
|
|
876
882
|
|
|
877
|
-
const keys: string
|
|
883
|
+
const keys: Array<string> = []
|
|
878
884
|
for (const key in schema.properties) {
|
|
879
885
|
const prop = schema.properties[key]
|
|
880
886
|
if (prop && !isReference(prop) && (prop as Record<string, unknown>)[flag]) {
|
|
@@ -888,8 +894,10 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
888
894
|
* Converts an OAS `Operation` into an `OperationNode`.
|
|
889
895
|
*/
|
|
890
896
|
function parseOperation(options: ast.ParserOptions, operation: Operation): ast.OperationNode {
|
|
897
|
+
const operationId = operation.getOperationId()
|
|
898
|
+
const operationName = operationId ? pascalCase(operationId) : undefined
|
|
891
899
|
const parameters: Array<ast.ParameterNode> = getParameters(document, operation).map((param) =>
|
|
892
|
-
parseParameter(options, param as unknown as Record<string, unknown
|
|
900
|
+
parseParameter(options, param as unknown as Record<string, unknown>, operationName),
|
|
893
901
|
)
|
|
894
902
|
|
|
895
903
|
// Determine which content types to include in requestBody.content.
|
|
@@ -898,6 +906,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
898
906
|
const allContentTypes = ctx.contentType ? [ctx.contentType] : getRequestBodyContentTypes(document, operation)
|
|
899
907
|
|
|
900
908
|
const requestBodyMeta = getRequestBodyMeta(operation)
|
|
909
|
+
const requestBodyName = operationName ? `${operationName}Request` : undefined
|
|
901
910
|
|
|
902
911
|
const content = allContentTypes.flatMap((ct) => {
|
|
903
912
|
const schema = getRequestSchema(document, operation, { contentType: ct })
|
|
@@ -905,7 +914,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
905
914
|
return [
|
|
906
915
|
{
|
|
907
916
|
contentType: ct,
|
|
908
|
-
schema: ast.syncOptionality(parseSchema({ schema }, options), requestBodyMeta.required),
|
|
917
|
+
schema: ast.syncOptionality(parseSchema({ schema, name: requestBodyName }, options), requestBodyMeta.required),
|
|
909
918
|
keysToOmit: collectPropertyKeysByFlag(schema, 'readOnly'),
|
|
910
919
|
},
|
|
911
920
|
]
|
|
@@ -924,9 +933,13 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
924
933
|
const responseObj = operation.getResponseByStatusCode(statusCode)
|
|
925
934
|
const responseSchema = getResponseSchema(document, operation, statusCode, { contentType: ctx.contentType })
|
|
926
935
|
|
|
936
|
+
// Use `Status<code>` (matching plugin-ts's resolveResponseStatusName convention) so the
|
|
937
|
+
// qualified names for nested enums don't collide with top-level component schemas that
|
|
938
|
+
// happen to be named `<operation><statusCode>` (e.g. `GetMaintenance200`).
|
|
939
|
+
const responseName = operationName ? `${operationName}Status${statusCode}` : undefined
|
|
927
940
|
const schema =
|
|
928
941
|
responseSchema && Object.keys(responseSchema).length > 0
|
|
929
|
-
? parseSchema({ schema: responseSchema }, options)
|
|
942
|
+
? parseSchema({ schema: responseSchema, name: responseName }, options)
|
|
930
943
|
: ast.createSchema({
|
|
931
944
|
type: typeOptionMap.get(options.emptySchemaType)!,
|
|
932
945
|
})
|
|
@@ -946,7 +959,7 @@ export function createSchemaParser(ctx: OasParserContext) {
|
|
|
946
959
|
const urlPath = new URLPath(operation.path)
|
|
947
960
|
|
|
948
961
|
return ast.createOperation({
|
|
949
|
-
operationId
|
|
962
|
+
operationId,
|
|
950
963
|
method: operation.method.toUpperCase() as ast.HttpMethod,
|
|
951
964
|
path: urlPath.path,
|
|
952
965
|
tags: operation.getTags().map((tag) => tag.name),
|
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
|
|
|
@@ -339,13 +339,13 @@ function* collectRefs(schema: unknown): Generator<string, void, undefined> {
|
|
|
339
339
|
* ```
|
|
340
340
|
*/
|
|
341
341
|
export function sortSchemas(schemas: Record<string, SchemaObject>): Record<string, SchemaObject> {
|
|
342
|
-
const deps = new Map<string, string
|
|
342
|
+
const deps = new Map<string, Array<string>>()
|
|
343
343
|
|
|
344
344
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
345
345
|
deps.set(name, [...new Set(collectRefs(schema))])
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
const sorted: string
|
|
348
|
+
const sorted: Array<string> = []
|
|
349
349
|
const visited = new Set<string>()
|
|
350
350
|
|
|
351
351
|
function visit(name: string, stack: Set<string>) {
|
|
@@ -402,7 +402,7 @@ function resolveSchemaRef(document: Document, schema: SchemaObject): SchemaObjec
|
|
|
402
402
|
export function getSchemas(document: Document, { contentType }: GetSchemasOptions): GetSchemasResult {
|
|
403
403
|
const components = document.components
|
|
404
404
|
|
|
405
|
-
const candidates: SchemaWithMetadata
|
|
405
|
+
const candidates: Array<SchemaWithMetadata> = [
|
|
406
406
|
...Object.entries((components?.schemas as Record<string, SchemaObject>) ?? {}).map(([name, schema]) => ({
|
|
407
407
|
schema: resolveSchemaRef(document, schema),
|
|
408
408
|
source: 'schemas' as const,
|
|
@@ -424,7 +424,7 @@ export function getSchemas(document: Document, { contentType }: GetSchemasOption
|
|
|
424
424
|
),
|
|
425
425
|
]
|
|
426
426
|
|
|
427
|
-
const normalizedNames = new Map<string, SchemaWithMetadata
|
|
427
|
+
const normalizedNames = new Map<string, Array<SchemaWithMetadata>>()
|
|
428
428
|
for (const item of candidates) {
|
|
429
429
|
const key = pascalCase(item.originalName)
|
|
430
430
|
const bucket = normalizedNames.get(key) ?? []
|
|
@@ -529,7 +529,7 @@ export function buildSchemaNode(schema: SchemaObject, name: string | null | unde
|
|
|
529
529
|
* // ['application/json', 'multipart/form-data']
|
|
530
530
|
* ```
|
|
531
531
|
*/
|
|
532
|
-
export function getRequestBodyContentTypes(document: Document, operation: Operation): string
|
|
532
|
+
export function getRequestBodyContentTypes(document: Document, operation: Operation): Array<string> {
|
|
533
533
|
if (operation.schema.requestBody) {
|
|
534
534
|
operation.schema.requestBody = dereferenceWithRef(document, operation.schema.requestBody)
|
|
535
535
|
}
|
package/src/stream.ts
CHANGED
|
@@ -8,8 +8,8 @@ import type { AdapterOas, Document, SchemaObject } from './types.ts'
|
|
|
8
8
|
|
|
9
9
|
export type PreScanResult = {
|
|
10
10
|
refAliasMap: Map<string, ast.SchemaNode>
|
|
11
|
-
enumNames: string
|
|
12
|
-
circularNames: string
|
|
11
|
+
enumNames: Array<string>
|
|
12
|
+
circularNames: Array<string>
|
|
13
13
|
discriminatorChildMap: Map<string, DiscriminatorTarget> | null
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -74,10 +74,10 @@ export function preScan({
|
|
|
74
74
|
parserOptions: ast.ParserOptions
|
|
75
75
|
discriminator: AdapterOas['options']['discriminator']
|
|
76
76
|
}): PreScanResult {
|
|
77
|
-
const allNodes: ast.SchemaNode
|
|
77
|
+
const allNodes: Array<ast.SchemaNode> = []
|
|
78
78
|
const refAliasMap = new Map<string, ast.SchemaNode>()
|
|
79
|
-
const enumNames: string
|
|
80
|
-
const discriminatorParentNodes: ast.SchemaNode
|
|
79
|
+
const enumNames: Array<string> = []
|
|
80
|
+
const discriminatorParentNodes: Array<ast.SchemaNode> = []
|
|
81
81
|
|
|
82
82
|
for (const [name, schema] of Object.entries(schemas)) {
|
|
83
83
|
const node = parseSchema({ schema, name }, parserOptions)
|