@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/dist/index.cjs +164 -404
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -17
- package/dist/index.js +158 -402
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/adapter.ts +3 -5
- package/src/constants.ts +0 -49
- package/src/discriminator.ts +25 -0
- package/src/infer.ts +85 -0
- package/src/naming.ts +25 -0
- package/src/oas/Oas.ts +2 -10
- package/src/oas/types.ts +10 -4
- package/src/parser.ts +123 -340
- package/src/refResolver.ts +65 -0
- package/src/types.ts +0 -11
- package/src/utils.ts +0 -168
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/adapter-oas",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
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.
|
|
50
|
-
"@kubb/core": "5.0.0-alpha.
|
|
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
|
|
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
|
|
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'
|
|
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
|
-
|
|
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
|
-
*
|
|
57
|
+
* Canonical uppercase->lowercase HTTP method map.
|
|
58
|
+
* Re-exported for backwards compatibility with previous adapter-oas API.
|
|
56
59
|
*/
|
|
57
|
-
export
|
|
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 =
|
|
65
|
+
export type HttpMethod = Lowercase<AstHttpMethod>
|
|
60
66
|
|
|
61
67
|
export type Document = OASDocument
|
|
62
68
|
|