@kubb/adapter-oas 5.0.0-alpha.14 → 5.0.0-alpha.16

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.14",
3
+ "version": "5.0.0-alpha.16",
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.14",
50
- "@kubb/core": "5.0.0-alpha.14"
49
+ "@kubb/ast": "5.0.0-alpha.16",
50
+ "@kubb/core": "5.0.0-alpha.16"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/swagger2openapi": "^7.0.4",
package/src/adapter.ts CHANGED
@@ -6,8 +6,8 @@ import { DEFAULT_PARSER_OPTIONS } from './constants.ts'
6
6
  import { resolveServerUrl } from './oas/resolveServerUrl.ts'
7
7
  import { parseFromConfig } from './oas/utils.ts'
8
8
  import { createOasParser } from './parser.ts'
9
+ import { getImports } from './refResolver.ts'
9
10
  import type { OasAdapter } from './types.ts'
10
- import { getImports } from './utils.ts'
11
11
 
12
12
  export const adapterOasName = 'oas' satisfies OasAdapter['name']
13
13
 
@@ -37,7 +37,6 @@ export const adapterOas = createAdapter<OasAdapter>((options) => {
37
37
  serverIndex,
38
38
  serverVariables,
39
39
  discriminator = 'strict',
40
- collisionDetection = true,
41
40
  dateType = DEFAULT_PARSER_OPTIONS.dateType,
42
41
  integerType = DEFAULT_PARSER_OPTIONS.integerType,
43
42
  unknownType = DEFAULT_PARSER_OPTIONS.unknownType,
@@ -58,7 +57,6 @@ export const adapterOas = createAdapter<OasAdapter>((options) => {
58
57
  serverIndex,
59
58
  serverVariables,
60
59
  discriminator,
61
- collisionDetection,
62
60
  dateType,
63
61
  integerType,
64
62
  unknownType,
@@ -73,7 +71,7 @@ export const adapterOas = createAdapter<OasAdapter>((options) => {
73
71
  const fakeConfig = sourceToFakeConfig(source)
74
72
  const oas = await parseFromConfig(fakeConfig, oasClass)
75
73
 
76
- oas.setOptions({ contentType, discriminator, collisionDetection })
74
+ oas.setOptions({ contentType, discriminator })
77
75
 
78
76
  if (validate) {
79
77
  try {
@@ -86,7 +84,7 @@ export const adapterOas = createAdapter<OasAdapter>((options) => {
86
84
  const server = serverIndex !== undefined ? oas.api.servers?.at(serverIndex) : undefined
87
85
  const baseURL = server?.url ? resolveServerUrl(server, serverVariables) : undefined
88
86
 
89
- const parser = createOasParser(oas, { contentType, collisionDetection })
87
+ const parser = createOasParser(oas, { contentType })
90
88
  const root = parser.parse({ dateType, integerType, unknownType, emptySchemaType, enumSuffix })
91
89
 
92
90
  // This must happen after parse() because legacy enum remapping is finalized there.
package/src/constants.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { SchemaType } from '@kubb/ast/types'
2
- import type { HttpMethods as OASHttpMethods } from 'oas/types'
3
2
  import type { ParserOptions } from './types.ts'
4
3
 
5
4
  /**
@@ -65,56 +64,8 @@ export const formatMap = {
65
64
  double: 'number',
66
65
  } as const satisfies Record<string, SchemaType>
67
66
 
68
- /**
69
- * Exhaustive list of media types that Kubb recognizes.
70
- */
71
- export const knownMediaTypes = new Set([
72
- 'application/json',
73
- 'application/xml',
74
- 'application/x-www-form-urlencoded',
75
- 'application/octet-stream',
76
- 'application/pdf',
77
- 'application/zip',
78
- 'application/graphql',
79
- 'multipart/form-data',
80
- 'text/plain',
81
- 'text/html',
82
- 'text/csv',
83
- 'text/xml',
84
- 'image/png',
85
- 'image/jpeg',
86
- 'image/gif',
87
- 'image/webp',
88
- 'image/svg+xml',
89
- 'audio/mpeg',
90
- 'video/mp4',
91
- ] as const)
92
-
93
67
  /**
94
68
  * Vendor extension keys used to attach human-readable labels to enum values.
95
69
  * Checked in priority order: the first key found wins.
96
70
  */
97
71
  export const enumExtensionKeys = ['x-enumNames', 'x-enum-varnames'] as const
98
-
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)
103
-
104
- /**
105
- * Canonical HTTP method names for the Kubb OAS layer.
106
- * Keys are uppercase (used in generated code); values are the lowercase strings
107
- * that the `oas` library uses internally.
108
- *
109
- * TODO(v5): remove — use `httpMethods` from `@kubb/ast`
110
- */
111
- export const httpMethods = {
112
- GET: 'get',
113
- POST: 'post',
114
- PUT: 'put',
115
- PATCH: 'patch',
116
- DELETE: 'delete',
117
- HEAD: 'head',
118
- OPTIONS: 'options',
119
- TRACE: 'trace',
120
- } as const satisfies Record<Uppercase<OASHttpMethods>, OASHttpMethods>
@@ -0,0 +1,25 @@
1
+ import { createProperty, createSchema } from '@kubb/ast'
2
+ import type { SchemaNode } from '@kubb/ast/types'
3
+
4
+ export function resolveDiscriminatorValue(mapping: Record<string, string> | undefined, ref: string | undefined): string | undefined {
5
+ if (!mapping || !ref) return undefined
6
+ return Object.entries(mapping).find(([, value]) => value === ref)?.[0]
7
+ }
8
+
9
+ export function createDiscriminantNode(propertyName: string, value: string): SchemaNode {
10
+ return createSchema({
11
+ type: 'object',
12
+ primitive: 'object',
13
+ properties: [
14
+ createProperty({
15
+ name: propertyName,
16
+ schema: createSchema({
17
+ type: 'enum',
18
+ primitive: 'string',
19
+ enumValues: [value],
20
+ }),
21
+ required: true,
22
+ }),
23
+ ],
24
+ })
25
+ }
package/src/infer.ts ADDED
@@ -0,0 +1,85 @@
1
+ import type {
2
+ ArraySchemaNode,
3
+ DateSchemaNode,
4
+ DatetimeSchemaNode,
5
+ EnumSchemaNode,
6
+ IntersectionSchemaNode,
7
+ NumberSchemaNode,
8
+ ObjectSchemaNode,
9
+ RefSchemaNode,
10
+ ScalarSchemaNode,
11
+ SchemaNode,
12
+ StringSchemaNode,
13
+ TimeSchemaNode,
14
+ UnionSchemaNode,
15
+ } from '@kubb/ast/types'
16
+ import type { SchemaObject } from './oas/types.ts'
17
+ import type { ParserOptions } from './types.ts'
18
+
19
+ /**
20
+ * Maps each `dateType` option value to the AST node produced by `format: 'date-time'`.
21
+ */
22
+ type DateTimeNodeByDateType = {
23
+ date: DateSchemaNode
24
+ string: DatetimeSchemaNode
25
+ stringOffset: DatetimeSchemaNode
26
+ stringLocal: DatetimeSchemaNode
27
+ false: StringSchemaNode
28
+ }
29
+
30
+ /**
31
+ * Resolves the AST node produced by `format: 'date-time'` based on the `dateType` option.
32
+ */
33
+ type ResolveDateTimeNode<TDateType extends ParserOptions['dateType']> = DateTimeNodeByDateType[TDateType extends keyof DateTimeNodeByDateType
34
+ ? TDateType
35
+ : 'string']
36
+
37
+ /**
38
+ * Single source of truth: ordered list of `[shape, SchemaNode]` pairs.
39
+ * `InferSchemaNode` walks this tuple in order and returns the node type of the first matching entry.
40
+ * Parameterized over `TDateType` so `format: 'date-time'` resolves to the correct node based on the option.
41
+ */
42
+ type SchemaNodeMap<TDateType extends ParserOptions['dateType'] = 'string'> = [
43
+ [{ $ref: string }, RefSchemaNode],
44
+ [{ allOf: ReadonlyArray<unknown>; properties: object }, IntersectionSchemaNode],
45
+ [{ allOf: readonly [unknown, unknown, ...unknown[]] }, IntersectionSchemaNode],
46
+ [{ allOf: ReadonlyArray<unknown> }, SchemaNode],
47
+ [{ oneOf: ReadonlyArray<unknown> }, UnionSchemaNode],
48
+ [{ anyOf: ReadonlyArray<unknown> }, UnionSchemaNode],
49
+ [{ const: null }, ScalarSchemaNode],
50
+ [{ const: string | number | boolean }, EnumSchemaNode],
51
+ [{ type: ReadonlyArray<string> }, UnionSchemaNode],
52
+ [{ type: 'array'; enum: ReadonlyArray<unknown> }, ArraySchemaNode],
53
+ [{ enum: ReadonlyArray<unknown> }, EnumSchemaNode],
54
+ [{ type: 'object' }, ObjectSchemaNode],
55
+ [{ additionalProperties: boolean | {} }, ObjectSchemaNode],
56
+ [{ type: 'array' }, ArraySchemaNode],
57
+ [{ items: object }, ArraySchemaNode],
58
+ [{ prefixItems: ReadonlyArray<unknown> }, ArraySchemaNode],
59
+ [{ type: string; format: 'date-time' }, ResolveDateTimeNode<TDateType>],
60
+ [{ type: string; format: 'date' }, DateSchemaNode],
61
+ [{ type: string; format: 'time' }, TimeSchemaNode],
62
+ [{ format: 'date-time' }, ResolveDateTimeNode<TDateType>],
63
+ [{ format: 'date' }, DateSchemaNode],
64
+ [{ format: 'time' }, TimeSchemaNode],
65
+ [{ type: 'string' }, StringSchemaNode],
66
+ [{ type: 'number' }, NumberSchemaNode],
67
+ [{ type: 'integer' }, NumberSchemaNode],
68
+ [{ type: 'bigint' }, NumberSchemaNode],
69
+ [{ type: string }, ScalarSchemaNode],
70
+ [{ minLength: number }, StringSchemaNode],
71
+ [{ maxLength: number }, StringSchemaNode],
72
+ [{ pattern: string }, StringSchemaNode],
73
+ [{ minimum: number }, NumberSchemaNode],
74
+ [{ maximum: number }, NumberSchemaNode],
75
+ ]
76
+
77
+ export type InferSchemaNode<
78
+ TSchema extends SchemaObject,
79
+ TDateType extends ParserOptions['dateType'] = 'string',
80
+ TEntries extends ReadonlyArray<[object, SchemaNode]> = SchemaNodeMap<TDateType>,
81
+ > = TEntries extends [infer TEntry extends [object, SchemaNode], ...infer TRest extends ReadonlyArray<[object, SchemaNode]>]
82
+ ? TSchema extends TEntry[0]
83
+ ? TEntry[1]
84
+ : InferSchemaNode<TSchema, TDateType, TRest>
85
+ : SchemaNode
package/src/naming.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { pascalCase } from '@internals/utils'
2
+ import { narrowSchema } from '@kubb/ast'
3
+ import type { SchemaNode } from '@kubb/ast/types'
4
+
5
+ export function resolveChildName(parentName: string | undefined, propName: string): string | undefined {
6
+ return parentName ? pascalCase([parentName, propName].join(' ')) : undefined
7
+ }
8
+
9
+ export function resolveEnumPropName(parentName: string | undefined, propName: string, enumSuffix: string): string {
10
+ return pascalCase([parentName, propName, enumSuffix].filter(Boolean).join(' '))
11
+ }
12
+
13
+ export function applyEnumName(propNode: SchemaNode, parentName: string | undefined, propName: string, enumSuffix: string): SchemaNode {
14
+ const enumNode = narrowSchema(propNode, 'enum')
15
+
16
+ if (enumNode?.primitive === 'boolean') {
17
+ return { ...propNode, name: undefined }
18
+ }
19
+
20
+ if (enumNode) {
21
+ return { ...propNode, name: resolveEnumPropName(parentName, propName, enumSuffix) }
22
+ }
23
+
24
+ return propNode
25
+ }
package/src/oas/Oas.ts CHANGED
@@ -8,7 +8,6 @@ import {
8
8
  flattenSchema,
9
9
  isDiscriminator,
10
10
  isReference,
11
- legacyResolve,
12
11
  resolveCollisions,
13
12
  type SchemaWithMetadata,
14
13
  sortSchemas,
@@ -25,11 +24,6 @@ const KUBB_INLINE_REF_PREFIX = '#kubb-inline-'
25
24
  type OasOptions = {
26
25
  contentType?: contentType
27
26
  discriminator?: 'strict' | 'inherit'
28
- /**
29
- * Resolve name collisions when schemas from different components share the same name (case-insensitive).
30
- * @default false
31
- */
32
- collisionDetection?: boolean
33
27
  }
34
28
 
35
29
  export class Oas extends BaseOas {
@@ -541,13 +535,12 @@ export class Oas extends BaseOas {
541
535
  * Get schemas from OpenAPI components (schemas, responses, requestBodies).
542
536
  * Returns schemas in dependency order along with name mapping for collision resolution.
543
537
  */
544
- getSchemas(options: { contentType?: contentType; includes?: Array<'schemas' | 'responses' | 'requestBodies'>; collisionDetection?: boolean } = {}): {
538
+ getSchemas(options: { contentType?: contentType; includes?: Array<'schemas' | 'responses' | 'requestBodies'> } = {}): {
545
539
  schemas: Record<string, SchemaObject>
546
540
  nameMapping: Map<string, string>
547
541
  } {
548
542
  const contentType = options.contentType ?? this.#options.contentType
549
543
  const includes = options.includes ?? ['schemas', 'requestBodies', 'responses']
550
- const shouldResolveCollisions = options.collisionDetection ?? this.#options.collisionDetection ?? false
551
544
 
552
545
  const components = this.getDefinition().components
553
546
  const schemasWithMeta: SchemaWithMetadata[] = []
@@ -612,8 +605,7 @@ export class Oas extends BaseOas {
612
605
  }
613
606
  }
614
607
 
615
- // Apply collision resolution only if enabled
616
- const { schemas, nameMapping } = shouldResolveCollisions ? resolveCollisions(schemasWithMeta) : legacyResolve(schemasWithMeta)
608
+ const { schemas, nameMapping } = resolveCollisions(schemasWithMeta)
617
609
 
618
610
  return {
619
611
  schemas: sortSchemas(schemas),
package/src/oas/types.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  // external packages
2
+
3
+ import { httpMethods } from '@kubb/ast'
4
+ import type { HttpMethod as AstHttpMethod } from '@kubb/ast/types'
2
5
  import type { Operation as OASOperation } from 'oas/operation'
3
6
  import type {
4
7
  DiscriminatorObject as OASDiscriminatorObject,
5
8
  OASDocument,
6
- HttpMethods as OASHttpMethods,
7
9
  MediaTypeObject as OASMediaTypeObject,
8
10
  ResponseObject as OASResponseObject,
9
11
  SchemaObject as OASSchemaObject,
@@ -52,11 +54,15 @@ export type SchemaObject = OASSchemaObject & {
52
54
  }
53
55
 
54
56
  /**
55
- * Re-exported from `constants.ts` for backwards compatibility.
57
+ * Canonical uppercase->lowercase HTTP method map.
58
+ * Re-exported for backwards compatibility with previous adapter-oas API.
56
59
  */
57
- export { httpMethods as HttpMethods } from '../constants.ts'
60
+ export const HttpMethods = Object.fromEntries(Object.entries(httpMethods).map(([lower, upper]) => [upper, lower])) as Record<
61
+ Uppercase<AstHttpMethod>,
62
+ Lowercase<AstHttpMethod>
63
+ >
58
64
 
59
- export type HttpMethod = OASHttpMethods
65
+ export type HttpMethod = Lowercase<AstHttpMethod>
60
66
 
61
67
  export type Document = OASDocument
62
68