@kubb/adapter-oas 4.36.1 → 5.0.0-alpha.10

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": "4.36.1",
3
+ "version": "5.0.0-alpha.10",
4
4
  "description": "OpenAPI / Swagger adapter for Kubb — converts OAS input into a @kubb/ast RootNode.",
5
5
  "keywords": [
6
6
  "openapi",
@@ -36,8 +36,8 @@
36
36
  "!/**/__snapshots__/**"
37
37
  ],
38
38
  "dependencies": {
39
- "@kubb/fabric-core": "0.13.3",
40
- "@redocly/openapi-core": "^2.21.1",
39
+ "@kubb/fabric-core": "0.14.0",
40
+ "@redocly/openapi-core": "^2.24.0",
41
41
  "@stoplight/yaml": "^4.3.0",
42
42
  "fflate": "^0.8.2",
43
43
  "jsonpointer": "^5.0.1",
@@ -46,15 +46,15 @@
46
46
  "openapi-types": "^12.1.3",
47
47
  "remeda": "^2.33.6",
48
48
  "swagger2openapi": "^7.0.8",
49
- "@kubb/ast": "4.36.1",
50
- "@kubb/core": "4.36.1"
49
+ "@kubb/ast": "5.0.0-alpha.10",
50
+ "@kubb/core": "5.0.0-alpha.10"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/swagger2openapi": "^7.0.4",
54
54
  "@internals/utils": "0.0.0"
55
55
  },
56
56
  "engines": {
57
- "node": ">=20"
57
+ "node": ">=22"
58
58
  },
59
59
  "publishConfig": {
60
60
  "access": "public",
package/src/adapter.ts CHANGED
@@ -1,11 +1,12 @@
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'
8
8
  import type { OasAdapter } from './types.ts'
9
+ import { getImports } from './utils.ts'
9
10
 
10
11
  export const adapterOasName = 'oas' satisfies OasAdapter['name']
11
12
 
@@ -27,7 +28,7 @@ export const adapterOasName = 'oas' satisfies OasAdapter['name']
27
28
  * })
28
29
  * ```
29
30
  */
30
- export const adapterOas = defineAdapter<OasAdapter>((options) => {
31
+ export const adapterOas = createAdapter<OasAdapter>((options) => {
31
32
  const {
32
33
  validate = true,
33
34
  oasClass,
@@ -42,6 +43,10 @@ export const adapterOas = defineAdapter<OasAdapter>((options) => {
42
43
  emptySchemaType = unknownType,
43
44
  } = options
44
45
 
46
+ // Mutable Map shared between `options` and each `parse()` call.
47
+ // Populated (and replaced) on every parse so consumers always see the latest state.
48
+ const nameMapping = new Map<string, string>()
49
+
45
50
  return {
46
51
  name: adapterOasName,
47
52
  options: {
@@ -56,6 +61,10 @@ export const adapterOas = defineAdapter<OasAdapter>((options) => {
56
61
  integerType,
57
62
  unknownType,
58
63
  emptySchemaType,
64
+ nameMapping,
65
+ },
66
+ getImports(node, resolve) {
67
+ return getImports({ node, nameMapping, resolve })
59
68
  },
60
69
  async parse(source) {
61
70
  const fakeConfig = sourceToFakeConfig(source)
@@ -75,12 +84,20 @@ export const adapterOas = defineAdapter<OasAdapter>((options) => {
75
84
  const baseURL = server?.url ? resolveServerUrl(server, serverVariables) : undefined
76
85
 
77
86
  const parser = createOasParser(oas, { contentType, collisionDetection })
87
+
88
+ // Sync the adapter's shared nameMapping with the one computed by the parser.
89
+ nameMapping.clear()
90
+ for (const [key, value] of parser.nameMapping) {
91
+ nameMapping.set(key, value)
92
+ }
93
+
78
94
  const root = parser.parse({ dateType, integerType, unknownType, emptySchemaType })
79
95
 
80
96
  return createRoot({
81
97
  ...root,
82
98
  meta: {
83
99
  title: oas.api.info?.title,
100
+ description: oas.api.info?.description,
84
101
  version: oas.api.info?.version,
85
102
  baseURL,
86
103
  },
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/types.ts CHANGED
@@ -30,6 +30,25 @@ export type SchemaObject = OASSchemaObject & {
30
30
  */
31
31
  contentMediaType?: string
32
32
  $ref?: string
33
+ /**
34
+ * OAS 3.1 / JSON Schema: positional items in a tuple schema.
35
+ * Replaces the OAS 3.0 multi-item `items` array syntax.
36
+ */
37
+ prefixItems?: Array<SchemaObject | ReferenceObject>
38
+ /**
39
+ * JSON Schema: maps regex patterns to sub-schemas for additional property validation.
40
+ */
41
+ patternProperties?: Record<string, SchemaObject | boolean>
42
+ /**
43
+ * OAS 3.0 / JSON Schema: single-schema form.
44
+ * The OAS base type already includes this, but we re-declare it here to ensure
45
+ * the single-schema overload takes precedence over the multi-schema tuple form.
46
+ */
47
+ items?: SchemaObject | ReferenceObject
48
+ /**
49
+ * Enum values for this schema (narrowed from `unknown[]` in the base type).
50
+ */
51
+ enum?: Array<string | number | boolean | null>
33
52
  }
34
53
 
35
54
  /**
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 }