@kubb/adapter-oas 5.0.0-beta.28 → 5.0.0-beta.29

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/adapter-oas",
3
- "version": "5.0.0-beta.28",
3
+ "version": "5.0.0-beta.29",
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",
@@ -47,7 +47,7 @@
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.28"
50
+ "@kubb/core": "5.0.0-beta.29"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/swagger2openapi": "^7.0.4",
package/src/parser.ts CHANGED
@@ -8,11 +8,11 @@ import {
8
8
  buildSchemaNode,
9
9
  flattenSchema,
10
10
  getDateType,
11
- getMediaType,
12
11
  getParameters,
13
12
  getPrimitiveType,
14
13
  getRequestBodyContentTypes,
15
14
  getRequestSchema,
15
+ getResponseBodyContentTypes,
16
16
  getResponseSchema,
17
17
  getSchemas,
18
18
  getSchemaType,
@@ -931,28 +931,37 @@ export function createSchemaParser(ctx: OasParserContext) {
931
931
 
932
932
  const responses: Array<ast.ResponseNode> = operation.getResponseStatusCodes().map((statusCode) => {
933
933
  const responseObj = operation.getResponseByStatusCode(statusCode)
934
- const responseSchema = getResponseSchema(document, operation, statusCode, { contentType: ctx.contentType })
935
934
 
936
935
  // Use `Status<code>` (matching plugin-ts's resolveResponseStatusName convention) so the
937
936
  // qualified names for nested enums don't collide with top-level component schemas that
938
937
  // happen to be named `<operation><statusCode>` (e.g. `GetMaintenance200`).
939
938
  const responseName = operationName ? `${operationName}Status${statusCode}` : undefined
940
- const schema =
941
- responseSchema && Object.keys(responseSchema).length > 0
942
- ? parseSchema({ schema: responseSchema, name: responseName }, options)
943
- : ast.createSchema({
944
- type: typeOptionMap.get(options.emptySchemaType)!,
945
- })
939
+ const { description } = getResponseMeta(responseObj)
940
+
941
+ const parseEntrySchema = (contentType?: string) => {
942
+ const raw = getResponseSchema(document, operation, statusCode, { contentType })
943
+ const node =
944
+ raw && Object.keys(raw).length > 0
945
+ ? parseSchema({ schema: raw, name: responseName }, options)
946
+ : ast.createSchema({ type: typeOptionMap.get(options.emptySchemaType)! })
947
+ return { schema: node, keysToOmit: collectPropertyKeysByFlag(raw, 'writeOnly') }
948
+ }
946
949
 
947
- const { description, content } = getResponseMeta(responseObj)
948
- const mediaType = content ? getMediaType(Object.keys(content)[0] ?? '') : getMediaType(operation.contentType ?? '')
950
+ // Build one entry per declared response content type so plugins can union the variants.
951
+ // When a global contentType is configured, restrict to that single type (mirrors requestBody).
952
+ const responseContentTypes = ctx.contentType ? [ctx.contentType] : getResponseBodyContentTypes(document, operation, statusCode)
953
+ const content = responseContentTypes.map((contentType) => ({ contentType, ...parseEntrySchema(contentType) }))
954
+
955
+ // Body-less responses keep a single fallback entry so the response still resolves to a
956
+ // (void/any) schema, matching how `requestBody` only carries schemas inside `content`.
957
+ if (content.length === 0) {
958
+ content.push({ contentType: operation.contentType || 'application/json', ...parseEntrySchema(ctx.contentType) })
959
+ }
949
960
 
950
961
  return ast.createResponse({
951
962
  statusCode: statusCode as ast.StatusCode,
952
963
  description,
953
- schema,
954
- mediaType,
955
- keysToOmit: collectPropertyKeysByFlag(responseSchema, 'writeOnly'),
964
+ content,
956
965
  })
957
966
  })
958
967
 
package/src/resolvers.ts CHANGED
@@ -541,3 +541,33 @@ export function getRequestBodyContentTypes(document: Document, operation: Operat
541
541
  // Do not bail out on isReference — the content is already present on the merged object.
542
542
  return body.content ? Object.keys(body.content) : []
543
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
+ }