@kubb/adapter-oas 5.0.0-alpha.1 → 5.0.0-alpha.11

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.1",
3
+ "version": "5.0.0-alpha.11",
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.22.1",
39
+ "@kubb/fabric-core": "0.14.0",
40
+ "@redocly/openapi-core": "^2.24.1",
41
41
  "@stoplight/yaml": "^4.3.0",
42
42
  "fflate": "^0.8.2",
43
43
  "jsonpointer": "^5.0.1",
@@ -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.1",
50
- "@kubb/core": "5.0.0-alpha.1"
49
+ "@kubb/ast": "5.0.0-alpha.11",
50
+ "@kubb/core": "5.0.0-alpha.11"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/swagger2openapi": "^7.0.4",
package/src/adapter.ts CHANGED
@@ -1,11 +1,13 @@
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
+ import { DEFAULT_PARSER_OPTIONS } from './constants.ts'
5
6
  import { resolveServerUrl } from './oas/resolveServerUrl.ts'
6
7
  import { parseFromConfig } from './oas/utils.ts'
7
8
  import { createOasParser } from './parser.ts'
8
9
  import type { OasAdapter } from './types.ts'
10
+ import { getImports } from './utils.ts'
9
11
 
10
12
  export const adapterOasName = 'oas' satisfies OasAdapter['name']
11
13
 
@@ -27,7 +29,7 @@ export const adapterOasName = 'oas' satisfies OasAdapter['name']
27
29
  * })
28
30
  * ```
29
31
  */
30
- export const adapterOas = defineAdapter<OasAdapter>((options) => {
32
+ export const adapterOas = createAdapter<OasAdapter>((options) => {
31
33
  const {
32
34
  validate = true,
33
35
  oasClass,
@@ -35,13 +37,18 @@ export const adapterOas = defineAdapter<OasAdapter>((options) => {
35
37
  serverIndex,
36
38
  serverVariables,
37
39
  discriminator = 'strict',
38
- collisionDetection = false,
39
- dateType = 'string',
40
- integerType = 'number',
41
- unknownType = 'any',
42
- emptySchemaType = unknownType,
40
+ collisionDetection = true,
41
+ dateType = DEFAULT_PARSER_OPTIONS.dateType,
42
+ integerType = DEFAULT_PARSER_OPTIONS.integerType,
43
+ unknownType = DEFAULT_PARSER_OPTIONS.unknownType,
44
+ enumSuffix = DEFAULT_PARSER_OPTIONS.enumSuffix,
45
+ emptySchemaType = unknownType || DEFAULT_PARSER_OPTIONS.emptySchemaType,
43
46
  } = options
44
47
 
48
+ // Mutable Map shared between `options` and each `parse()` call.
49
+ // Populated (and replaced) on every parse so consumers always see the latest state.
50
+ const nameMapping = new Map<string, string>()
51
+
45
52
  return {
46
53
  name: adapterOasName,
47
54
  options: {
@@ -56,6 +63,11 @@ export const adapterOas = defineAdapter<OasAdapter>((options) => {
56
63
  integerType,
57
64
  unknownType,
58
65
  emptySchemaType,
66
+ enumSuffix,
67
+ nameMapping,
68
+ },
69
+ getImports(node, resolve) {
70
+ return getImports({ node, nameMapping, resolve })
59
71
  },
60
72
  async parse(source) {
61
73
  const fakeConfig = sourceToFakeConfig(source)
@@ -75,12 +87,20 @@ export const adapterOas = defineAdapter<OasAdapter>((options) => {
75
87
  const baseURL = server?.url ? resolveServerUrl(server, serverVariables) : undefined
76
88
 
77
89
  const parser = createOasParser(oas, { contentType, collisionDetection })
78
- const root = parser.parse({ dateType, integerType, unknownType, emptySchemaType })
90
+
91
+ // Sync the adapter's shared nameMapping with the one computed by the parser.
92
+ nameMapping.clear()
93
+ for (const [key, value] of parser.nameMapping) {
94
+ nameMapping.set(key, value)
95
+ }
96
+
97
+ const root = parser.parse({ dateType, integerType, unknownType, emptySchemaType, enumSuffix })
79
98
 
80
99
  return createRoot({
81
100
  ...root,
82
101
  meta: {
83
102
  title: oas.api.info?.title,
103
+ description: oas.api.info?.description,
84
104
  version: oas.api.info?.version,
85
105
  baseURL,
86
106
  },
package/src/constants.ts CHANGED
@@ -1,7 +1,17 @@
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
+ import type { ParserOptions } from './types.ts'
3
4
 
4
- // ─── Merge defaults ────────────────────────────────────────────────────────────
5
+ /**
6
+ * Default values for all `Options` fields.
7
+ */
8
+ export const DEFAULT_PARSER_OPTIONS = {
9
+ dateType: 'string',
10
+ integerType: 'number',
11
+ unknownType: 'any',
12
+ emptySchemaType: 'any',
13
+ enumSuffix: 'enum',
14
+ } as const satisfies ParserOptions
5
15
 
6
16
  /**
7
17
  * OpenAPI version string written into merged document stubs.
@@ -18,14 +28,12 @@ export const MERGE_DEFAULT_TITLE = 'Merged API' as const
18
28
  */
19
29
  export const MERGE_DEFAULT_VERSION = '1.0.0' as const
20
30
 
21
- // ─── Schema analysis ───────────────────────────────────────────────────────────
22
-
23
31
  /**
24
32
  * JSON Schema keywords that indicate structural composition.
25
33
  * A schema fragment containing any of these keys must not be inlined into its
26
34
  * parent during `allOf` flattening — it carries semantic meaning of its own.
27
35
  */
28
- export const structuralKeys = new Set<string>(['properties', 'items', 'additionalProperties', 'oneOf', 'anyOf', 'allOf', 'not'])
36
+ export const structuralKeys = new Set(['properties', 'items', 'additionalProperties', 'oneOf', 'anyOf', 'allOf', 'not'] as const)
29
37
 
30
38
  /**
31
39
  * Maps OAS/JSON Schema `format` strings to their Kubb `SchemaType` equivalents.
@@ -59,9 +67,8 @@ export const formatMap = {
59
67
 
60
68
  /**
61
69
  * 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
70
  */
64
- export const knownMediaTypes = [
71
+ export const knownMediaTypes = new Set([
65
72
  'application/json',
66
73
  'application/xml',
67
74
  'application/x-www-form-urlencoded',
@@ -81,7 +88,7 @@ export const knownMediaTypes = [
81
88
  'image/svg+xml',
82
89
  'audio/mpeg',
83
90
  'video/mp4',
84
- ] as const satisfies ReadonlyArray<MediaType>
91
+ ] as const)
85
92
 
86
93
  /**
87
94
  * Vendor extension keys used to attach human-readable labels to enum values.
@@ -89,7 +96,10 @@ export const knownMediaTypes = [
89
96
  */
90
97
  export const enumExtensionKeys = ['x-enumNames', 'x-enum-varnames'] as const
91
98
 
92
- // ─── HTTP ──────────────────────────────────────────────────────────────────────
99
+ /**
100
+ * Scalar primitive schema types used for union member simplification.
101
+ */
102
+ export const SCALAR_PRIMITIVE_TYPES = new Set(['string', 'number', 'integer', 'bigint', 'boolean'] as const)
93
103
 
94
104
  /**
95
105
  * Canonical HTTP method names for the Kubb OAS layer.
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 }