@kubb/adapter-oas 5.0.0-alpha.7 → 5.0.0-alpha.9

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-alpha.7",
3
+ "version": "5.0.0-alpha.9",
4
4
  "description": "OpenAPI / Swagger adapter for Kubb — converts OAS input into a @kubb/ast RootNode.",
5
5
  "keywords": [
6
6
  "openapi",
@@ -46,8 +46,8 @@
46
46
  "openapi-types": "^12.1.3",
47
47
  "remeda": "^2.33.6",
48
48
  "swagger2openapi": "^7.0.8",
49
- "@kubb/ast": "5.0.0-alpha.7",
50
- "@kubb/core": "5.0.0-alpha.7"
49
+ "@kubb/ast": "5.0.0-alpha.9",
50
+ "@kubb/core": "5.0.0-alpha.9"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/swagger2openapi": "^7.0.4",
package/src/adapter.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path'
2
2
  import { createRoot } from '@kubb/ast'
3
3
  import type { AdapterSource } from '@kubb/core'
4
- import { defineAdapter } from '@kubb/core'
4
+ import { createAdapter } from '@kubb/core'
5
5
  import { resolveServerUrl } from './oas/resolveServerUrl.ts'
6
6
  import { parseFromConfig } from './oas/utils.ts'
7
7
  import { createOasParser } from './parser.ts'
@@ -28,7 +28,7 @@ export const adapterOasName = 'oas' satisfies OasAdapter['name']
28
28
  * })
29
29
  * ```
30
30
  */
31
- export const adapterOas = defineAdapter<OasAdapter>((options) => {
31
+ export const adapterOas = createAdapter<OasAdapter>((options) => {
32
32
  const {
33
33
  validate = true,
34
34
  oasClass,
package/src/constants.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MediaType, SchemaType } from '@kubb/ast/types'
1
+ import type { SchemaType } from '@kubb/ast/types'
2
2
  import type { HttpMethods as OASHttpMethods } from 'oas/types'
3
3
 
4
4
  // ─── Merge defaults ────────────────────────────────────────────────────────────
@@ -25,7 +25,7 @@ export const MERGE_DEFAULT_VERSION = '1.0.0' as const
25
25
  * A schema fragment containing any of these keys must not be inlined into its
26
26
  * parent during `allOf` flattening — it carries semantic meaning of its own.
27
27
  */
28
- export const structuralKeys = new Set<string>(['properties', 'items', 'additionalProperties', 'oneOf', 'anyOf', 'allOf', 'not'])
28
+ export const structuralKeys = new Set(['properties', 'items', 'additionalProperties', 'oneOf', 'anyOf', 'allOf', 'not'] as const)
29
29
 
30
30
  /**
31
31
  * Maps OAS/JSON Schema `format` strings to their Kubb `SchemaType` equivalents.
@@ -59,9 +59,8 @@ export const formatMap = {
59
59
 
60
60
  /**
61
61
  * Exhaustive list of media types that Kubb recognizes.
62
- * Kept as a module-level constant to avoid re-allocating the array on every call.
63
62
  */
64
- export const knownMediaTypes = [
63
+ export const knownMediaTypes = new Set([
65
64
  'application/json',
66
65
  'application/xml',
67
66
  'application/x-www-form-urlencoded',
@@ -81,7 +80,7 @@ export const knownMediaTypes = [
81
80
  'image/svg+xml',
82
81
  'audio/mpeg',
83
82
  'video/mp4',
84
- ] as const satisfies ReadonlyArray<MediaType>
83
+ ] as const)
85
84
 
86
85
  /**
87
86
  * Vendor extension keys used to attach human-readable labels to enum values.
@@ -89,6 +88,11 @@ export const knownMediaTypes = [
89
88
  */
90
89
  export const enumExtensionKeys = ['x-enumNames', 'x-enum-varnames'] as const
91
90
 
91
+ /**
92
+ * Scalar primitive schema types used for union member simplification.
93
+ */
94
+ export const SCALAR_PRIMITIVE_TYPES = new Set(['string', 'number', 'integer', 'bigint', 'boolean'] as const)
95
+
92
96
  // ─── HTTP ──────────────────────────────────────────────────────────────────────
93
97
 
94
98
  /**
package/src/oas/Oas.ts CHANGED
@@ -431,14 +431,15 @@ export class Oas extends BaseOas {
431
431
  return this.dereferenceWithRef(schema)
432
432
  }
433
433
 
434
- getParametersSchema(operation: Operation, inKey: 'path' | 'query' | 'header'): SchemaObject | null {
435
- const { contentType = operation.getContentType() } = this.#options
436
-
437
- // Collect parameters from both operation-level and path-level, resolving $ref pointers.
438
- // oas v31+ filters out $ref parameters in getParameters(), so we access raw parameters
439
- // directly and resolve refs ourselves to preserve backward compatibility.
440
- // Note: dereferenceWithRef preserves the $ref property on resolved objects, so we check
441
- // for 'in' and 'name' fields to validate successful resolution instead of !isReference().
434
+ /**
435
+ * Returns all resolved parameters for an operation, merging path-level and operation-level
436
+ * parameters and deduplicating by `in:name` (operation-level takes precedence).
437
+ *
438
+ * oas v31+ filters out `$ref` parameters in `getParameters()`, so this method accesses the
439
+ * raw `operation.schema.parameters` and path-item parameters directly and resolves `$ref`
440
+ * pointers via `dereferenceWithRef` to preserve backward compatibility.
441
+ */
442
+ getParameters(operation: Operation): Array<ParameterObject> {
442
443
  const resolveParams = (params: unknown[]): Array<ParameterObject> =>
443
444
  params.map((p) => this.dereferenceWithRef(p)).filter((p): p is ParameterObject => !!p && typeof p === 'object' && 'in' in p && 'name' in p)
444
445
 
@@ -459,7 +460,13 @@ export class Oas extends BaseOas {
459
460
  }
460
461
  }
461
462
 
462
- const params = Array.from(paramMap.values()).filter((v) => v.in === inKey)
463
+ return Array.from(paramMap.values())
464
+ }
465
+
466
+ getParametersSchema(operation: Operation, inKey: 'path' | 'query' | 'header'): SchemaObject | null {
467
+ const { contentType = operation.getContentType() } = this.#options
468
+
469
+ const params = this.getParameters(operation).filter((v) => v.in === inKey)
463
470
 
464
471
  if (!params.length) {
465
472
  return null
package/src/oas/utils.ts CHANGED
@@ -183,7 +183,7 @@ export function flattenSchema(schema: SchemaObject | null): SchemaObject | null
183
183
  if (!schema?.allOf || schema.allOf.length === 0) return schema ?? null
184
184
  if (schema.allOf.some((item) => isRef(item))) return schema
185
185
 
186
- const isPlainFragment = (item: SchemaObject) => !Object.keys(item).some((key) => structuralKeys.has(key))
186
+ const isPlainFragment = (item: SchemaObject) => !Object.keys(item).some((key) => structuralKeys.has(key as 'properties'))
187
187
  if (!schema.allOf.every((item) => isPlainFragment(item as SchemaObject))) return schema
188
188
 
189
189
  const merged: SchemaObject = { ...schema }
package/src/parser.ts CHANGED
@@ -183,7 +183,7 @@ function getPrimitiveType(type: string | undefined): PrimitiveSchemaType {
183
183
  * Returns `undefined` for content types not present in `KNOWN_MEDIA_TYPES`.
184
184
  */
185
185
  function toMediaType(contentType: string): MediaType | undefined {
186
- return knownMediaTypes.includes(contentType as MediaType) ? (contentType as MediaType) : undefined
186
+ return knownMediaTypes.has(contentType as MediaType) ? (contentType as MediaType) : undefined
187
187
  }
188
188
 
189
189
  /**
@@ -973,6 +973,7 @@ export function createOasParser(oas: Oas, { contentType, collisionDetection }: O
973
973
  in: param['in'] as ParameterLocation,
974
974
  schema: {
975
975
  ...schema,
976
+ description: (param['description'] as string | undefined) ?? schema.description,
976
977
  optional: !required || !!schema.optional ? true : undefined,
977
978
  },
978
979
  required,
@@ -984,11 +985,7 @@ export function createOasParser(oas: Oas, { contentType, collisionDetection }: O
984
985
  * request body, and all response codes into their AST node equivalents.
985
986
  */
986
987
  function parseOperation(options: Options, oas: Oas, operation: Operation): OperationNode {
987
- const parameters: Array<ParameterNode> = operation.getParameters().map((param) => {
988
- const dereferenced = oas.dereferenceWithRef(param) as unknown as Record<string, unknown>
989
-
990
- return parseParameter(options, dereferenced)
991
- })
988
+ const parameters: Array<ParameterNode> = oas.getParameters(operation).map((param) => parseParameter(options, param as unknown as Record<string, unknown>))
992
989
 
993
990
  const requestBodySchema = oas.getRequestSchema(operation)
994
991
  const requestBody = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : undefined
@@ -997,7 +994,10 @@ export function createOasParser(oas: Oas, { contentType, collisionDetection }: O
997
994
  const responseObj = operation.getResponseByStatusCode(statusCode)
998
995
  const responseSchema = oas.getResponseSchema(operation, statusCode)
999
996
 
1000
- const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) : undefined
997
+ const schema =
998
+ responseSchema && Object.keys(responseSchema).length > 0
999
+ ? convertSchema({ schema: responseSchema }, options)
1000
+ : createSchema({ type: resolveTypeOption(options.emptySchemaType) })
1001
1001
 
1002
1002
  const description = typeof responseObj === 'object' && responseObj !== null && !Array.isArray(responseObj) ? responseObj.description : undefined
1003
1003
 
package/src/utils.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { collect, createProperty, createSchema, narrowSchema } from '@kubb/ast'
2
2
  import type { SchemaNode } from '@kubb/ast/types'
3
3
  import type { KubbFile } from '@kubb/fabric-core/types'
4
+ import { SCALAR_PRIMITIVE_TYPES } from './constants.ts'
4
5
 
5
6
  /**
6
7
  * Extracts the schema name from a `$ref` string.
@@ -96,9 +97,13 @@ export function mergeAdjacentAnonymousObjects(members: Array<SchemaNode>): Array
96
97
  *
97
98
  * Only scalar primitives (`string`, `number`, `integer`, `bigint`, `boolean`) are
98
99
  * considered — object, array, and ref members are left untouched.
100
+ *
101
+ * Const-derived enums (those without an `enumType`, produced from an OpenAPI `const`
102
+ * keyword) are **never** removed — `'accepted' | string` must stay as-is because the
103
+ * literal is intentional.
99
104
  */
100
105
  export function simplifyUnionMembers(members: Array<SchemaNode>): Array<SchemaNode> {
101
- const scalarPrimitives = new Set(members.filter((m) => ['string', 'number', 'integer', 'bigint', 'boolean'].includes(m.type)).map((m) => m.type as string))
106
+ const scalarPrimitives = new Set(members.filter((m) => SCALAR_PRIMITIVE_TYPES.has(m.type as 'string')).map((m) => m.type as string))
102
107
  if (!scalarPrimitives.size) return members
103
108
 
104
109
  return members.filter((m) => {
@@ -106,6 +111,8 @@ export function simplifyUnionMembers(members: Array<SchemaNode>): Array<SchemaNo
106
111
  const prim = m.primitive
107
112
  // Keep the enum if its primitive isn't fully subsumed.
108
113
  if (!prim) return true
114
+ // Const-derived enums have no `enumType`; keep them as intentional literals.
115
+ if (!m.enumType) return true
109
116
  // `number` subsumes `integer` literals and vice-versa for our purposes.
110
117
  if (scalarPrimitives.has(prim)) return false
111
118
  if ((prim === 'integer' || prim === 'number') && (scalarPrimitives.has('integer') || scalarPrimitives.has('number'))) return false