@kubb/plugin-ts 5.0.0-alpha.3 → 5.0.0-alpha.5
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/{components-CRjwjdyE.js → components-Cwn1rflQ.js} +9 -3
- package/dist/components-Cwn1rflQ.js.map +1 -0
- package/dist/{components-DI0aTIBg.cjs → components-CxTvawXI.cjs} +9 -3
- package/dist/components-CxTvawXI.cjs.map +1 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +1 -1
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.ts +24 -47
- package/dist/generators.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{plugin-DmwgRHK8.js → plugin-kdQ5D2cW.js} +302 -96
- package/dist/plugin-kdQ5D2cW.js.map +1 -0
- package/dist/{plugin-D5rCK1zO.cjs → plugin-meWNDVe7.cjs} +298 -92
- package/dist/plugin-meWNDVe7.cjs.map +1 -0
- package/dist/{types-BpeKGgCn.d.ts → types-eWhVEVgF.d.ts} +13 -3
- package/package.json +8 -8
- package/src/components/v2/Type.tsx +15 -2
- package/src/factory.ts +12 -16
- package/src/generators/typeGenerator.tsx +1 -2
- package/src/generators/v2/typeGenerator.tsx +77 -110
- package/src/generators/v2/utils.ts +145 -0
- package/src/plugin.ts +28 -4
- package/src/printer.ts +15 -1
- package/src/types.ts +10 -0
- package/dist/components-CRjwjdyE.js.map +0 -1
- package/dist/components-DI0aTIBg.cjs.map +0 -1
- package/dist/plugin-D5rCK1zO.cjs.map +0 -1
- package/dist/plugin-DmwgRHK8.js.map +0 -1
|
@@ -1,45 +1,46 @@
|
|
|
1
|
+
import { applyParamsCasing } from '@kubb/ast'
|
|
1
2
|
import type { SchemaNode } from '@kubb/ast/types'
|
|
3
|
+
import { defineGenerator } from '@kubb/core'
|
|
2
4
|
import { useKubb } from '@kubb/core/hooks'
|
|
3
|
-
import { createReactGenerator } from '@kubb/plugin-oas/generators'
|
|
4
5
|
import { File } from '@kubb/react-fabric'
|
|
5
6
|
import { Type } from '../../components/v2/Type.tsx'
|
|
6
7
|
import type { PluginTs } from '../../types'
|
|
8
|
+
import { buildDataSchemaNode, buildResponsesSchemaNode, buildResponseUnionSchemaNode } from './utils.ts'
|
|
7
9
|
|
|
8
|
-
export const typeGenerator =
|
|
10
|
+
export const typeGenerator = defineGenerator<PluginTs>({
|
|
9
11
|
name: 'typescript',
|
|
10
|
-
|
|
12
|
+
type: 'react',
|
|
11
13
|
Operation({ node, adapter, options }) {
|
|
12
|
-
const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType } = options
|
|
14
|
+
const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, mapper } = options
|
|
15
|
+
const { mode, getFile, resolveName } = useKubb<PluginTs>()
|
|
13
16
|
|
|
14
|
-
const {
|
|
17
|
+
const file = getFile({ name: node.operationId, extname: '.ts', mode })
|
|
18
|
+
const params = applyParamsCasing(node.parameters, paramsCasing)
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
20
|
+
function renderSchemaType({
|
|
21
|
+
node: schemaNode,
|
|
22
|
+
name,
|
|
23
|
+
typedName,
|
|
24
|
+
description,
|
|
25
|
+
}: {
|
|
26
|
+
node: SchemaNode | null
|
|
27
|
+
name: string
|
|
28
|
+
typedName: string
|
|
29
|
+
description?: string
|
|
30
|
+
}) {
|
|
31
|
+
if (!schemaNode) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
22
34
|
|
|
23
|
-
function renderSchemaType({ node: schemaNode, name, typedName, description }: { node: SchemaNode; name: string; typedName: string; description?: string }) {
|
|
24
35
|
const imports = adapter.getImports(schemaNode, (schemaName) => ({
|
|
25
|
-
name: resolveName({
|
|
26
|
-
|
|
27
|
-
pluginName: plugin.name,
|
|
28
|
-
type: 'type',
|
|
29
|
-
}),
|
|
30
|
-
path: getFile({
|
|
31
|
-
name: schemaName,
|
|
32
|
-
pluginName: plugin.name,
|
|
33
|
-
extname: '.ts',
|
|
34
|
-
mode,
|
|
35
|
-
}).path,
|
|
36
|
+
name: resolveName({ name: schemaName, type: 'type' }),
|
|
37
|
+
path: getFile({ name: schemaName, extname: '.ts', mode }).path,
|
|
36
38
|
}))
|
|
37
39
|
|
|
38
40
|
return (
|
|
39
41
|
<>
|
|
40
42
|
{mode === 'split' &&
|
|
41
43
|
imports.map((imp) => <File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} isTypeOnly />)}
|
|
42
|
-
|
|
43
44
|
<Type
|
|
44
45
|
name={name}
|
|
45
46
|
typedName={typedName}
|
|
@@ -50,127 +51,93 @@ export const typeGenerator = createReactGenerator<PluginTs, '2'>({
|
|
|
50
51
|
optionalType={optionalType}
|
|
51
52
|
arrayType={arrayType}
|
|
52
53
|
syntaxType={syntaxType}
|
|
54
|
+
mapper={mapper}
|
|
53
55
|
/>
|
|
54
56
|
</>
|
|
55
57
|
)
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
name: `${node.operationId} ${param.name}`,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const typedName = resolveName({
|
|
66
|
-
name: `${node.operationId} ${param.name}`,
|
|
67
|
-
pluginName: plugin.name,
|
|
68
|
-
type: 'type',
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
return renderSchemaType({ node: param.schema, name, typedName })
|
|
72
|
-
})
|
|
60
|
+
const paramTypes = params.map((param) =>
|
|
61
|
+
renderSchemaType({
|
|
62
|
+
node: param.schema,
|
|
63
|
+
name: resolveName({ name: `${node.operationId} ${param.name}`, type: 'function' }),
|
|
64
|
+
typedName: resolveName({ name: `${node.operationId} ${param.name}`, type: 'type' }),
|
|
65
|
+
}),
|
|
66
|
+
)
|
|
73
67
|
|
|
74
|
-
// Response types
|
|
75
68
|
const responseTypes = node.responses
|
|
76
69
|
.filter((res) => res.schema)
|
|
77
|
-
.map((res) =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
name:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const typedName = resolveName({
|
|
86
|
-
name: responseName,
|
|
87
|
-
pluginName: plugin.name,
|
|
88
|
-
type: 'type',
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
return renderSchemaType({ node: schemaNode, name: resolvedName, typedName, description: res.description })
|
|
92
|
-
})
|
|
70
|
+
.map((res) =>
|
|
71
|
+
renderSchemaType({
|
|
72
|
+
node: res.schema!,
|
|
73
|
+
name: resolveName({ name: `${node.operationId} ${res.statusCode}`, type: 'function' }),
|
|
74
|
+
typedName: resolveName({ name: `${node.operationId} ${res.statusCode}`, type: 'type' }),
|
|
75
|
+
description: res.description,
|
|
76
|
+
}),
|
|
77
|
+
)
|
|
93
78
|
|
|
94
|
-
// Request body type
|
|
95
79
|
const requestType = node.requestBody
|
|
96
|
-
? (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
})
|
|
103
|
-
const typedName = resolveName({
|
|
104
|
-
name: requestName,
|
|
105
|
-
pluginName: plugin.name,
|
|
106
|
-
type: 'type',
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
return renderSchemaType({ node: node.requestBody, name: resolvedName, typedName, description: node.requestBody.description })
|
|
110
|
-
})()
|
|
80
|
+
? renderSchemaType({
|
|
81
|
+
node: node.requestBody,
|
|
82
|
+
name: resolveName({ name: `${node.operationId} MutationRequest`, type: 'function' }),
|
|
83
|
+
typedName: resolveName({ name: `${node.operationId} MutationRequest`, type: 'type' }),
|
|
84
|
+
description: node.requestBody.description,
|
|
85
|
+
})
|
|
111
86
|
: null
|
|
112
87
|
|
|
88
|
+
const dataType = renderSchemaType({
|
|
89
|
+
node: buildDataSchemaNode({ node: { ...node, parameters: params }, resolveName }),
|
|
90
|
+
name: resolveName({ name: `${node.operationId} Data`, type: 'function' }),
|
|
91
|
+
typedName: resolveName({ name: `${node.operationId} Data`, type: 'type' }),
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const responsesType = renderSchemaType({
|
|
95
|
+
node: buildResponsesSchemaNode({ node, resolveName }),
|
|
96
|
+
name: resolveName({ name: `${node.operationId} Responses`, type: 'function' }),
|
|
97
|
+
typedName: resolveName({ name: `${node.operationId} Responses`, type: 'type' }),
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const responseType = renderSchemaType({
|
|
101
|
+
node: buildResponseUnionSchemaNode({ node, resolveName }),
|
|
102
|
+
name: resolveName({ name: `${node.operationId} Response`, type: 'function' }),
|
|
103
|
+
typedName: resolveName({ name: `${node.operationId} Response`, type: 'type' }),
|
|
104
|
+
})
|
|
105
|
+
|
|
113
106
|
return (
|
|
114
107
|
<File baseName={file.baseName} path={file.path} meta={file.meta}>
|
|
115
108
|
{paramTypes}
|
|
116
109
|
{responseTypes}
|
|
117
110
|
{requestType}
|
|
111
|
+
{dataType}
|
|
112
|
+
{responsesType}
|
|
113
|
+
{responseType}
|
|
118
114
|
</File>
|
|
119
115
|
)
|
|
120
116
|
},
|
|
121
117
|
Schema({ node, adapter, options }) {
|
|
122
|
-
const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType } = options
|
|
123
|
-
const {
|
|
118
|
+
const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, mapper } = options
|
|
119
|
+
const { mode, resolveName, getFile } = useKubb<PluginTs>()
|
|
124
120
|
|
|
125
121
|
if (!node.name) {
|
|
126
122
|
return
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
const imports = adapter.getImports(node, (schemaName) => ({
|
|
130
|
-
name: resolveName({
|
|
131
|
-
|
|
132
|
-
pluginName: plugin.name,
|
|
133
|
-
type: 'type',
|
|
134
|
-
}),
|
|
135
|
-
path: getFile({
|
|
136
|
-
name: schemaName,
|
|
137
|
-
pluginName: plugin.name,
|
|
138
|
-
extname: '.ts',
|
|
139
|
-
mode,
|
|
140
|
-
// options: {
|
|
141
|
-
// group
|
|
142
|
-
// },
|
|
143
|
-
}).path,
|
|
126
|
+
name: resolveName({ name: schemaName, type: 'type' }),
|
|
127
|
+
path: getFile({ name: schemaName, extname: '.ts', mode }).path,
|
|
144
128
|
}))
|
|
145
129
|
|
|
146
130
|
const isEnumSchema = node.type === 'enum'
|
|
147
131
|
|
|
148
|
-
let typedName = resolveName({
|
|
149
|
-
name: node.name,
|
|
150
|
-
pluginName: plugin.name,
|
|
151
|
-
type: 'type',
|
|
152
|
-
})
|
|
153
|
-
|
|
132
|
+
let typedName = resolveName({ name: node.name, type: 'type' })
|
|
154
133
|
if (['asConst', 'asPascalConst'].includes(enumType) && isEnumSchema) {
|
|
155
|
-
typedName
|
|
134
|
+
typedName += 'Key'
|
|
156
135
|
}
|
|
157
136
|
|
|
158
137
|
const type = {
|
|
159
|
-
name: resolveName({
|
|
160
|
-
name: node.name,
|
|
161
|
-
pluginName: plugin.name,
|
|
162
|
-
type: 'function',
|
|
163
|
-
}),
|
|
138
|
+
name: resolveName({ name: node.name, type: 'function' }),
|
|
164
139
|
typedName,
|
|
165
|
-
file: getFile({
|
|
166
|
-
name: node.name,
|
|
167
|
-
pluginName: plugin.name,
|
|
168
|
-
extname: '.ts',
|
|
169
|
-
mode,
|
|
170
|
-
// options: {
|
|
171
|
-
// group
|
|
172
|
-
// },
|
|
173
|
-
}),
|
|
140
|
+
file: getFile({ name: node.name, extname: '.ts', mode }),
|
|
174
141
|
} as const
|
|
175
142
|
|
|
176
143
|
return (
|
|
@@ -179,7 +146,6 @@ export const typeGenerator = createReactGenerator<PluginTs, '2'>({
|
|
|
179
146
|
imports.map((imp) => (
|
|
180
147
|
<File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
|
|
181
148
|
))}
|
|
182
|
-
|
|
183
149
|
<Type
|
|
184
150
|
name={type.name}
|
|
185
151
|
typedName={type.typedName}
|
|
@@ -189,6 +155,7 @@ export const typeGenerator = createReactGenerator<PluginTs, '2'>({
|
|
|
189
155
|
optionalType={optionalType}
|
|
190
156
|
arrayType={arrayType}
|
|
191
157
|
syntaxType={syntaxType}
|
|
158
|
+
mapper={mapper}
|
|
192
159
|
/>
|
|
193
160
|
</File>
|
|
194
161
|
)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { createProperty, createSchema } from '@kubb/ast'
|
|
2
|
+
import type { OperationNode, ParameterNode, SchemaNode } from '@kubb/ast/types'
|
|
3
|
+
|
|
4
|
+
type ResolveName = (opts: { name: string; type: 'type' | 'function' }) => string
|
|
5
|
+
|
|
6
|
+
type BuildParamsSchemaOptions = {
|
|
7
|
+
params: Array<ParameterNode>
|
|
8
|
+
operationId: string
|
|
9
|
+
resolveName: ResolveName
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Builds an `ObjectSchemaNode` for a group of parameters (path/query/header).
|
|
14
|
+
* Each property is a `ref` schema pointing to the individually-resolved parameter type.
|
|
15
|
+
*/
|
|
16
|
+
export function buildParamsSchema({ params, operationId, resolveName }: BuildParamsSchemaOptions): SchemaNode {
|
|
17
|
+
return createSchema({
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: params.map((param) =>
|
|
20
|
+
createProperty({
|
|
21
|
+
name: param.name,
|
|
22
|
+
schema: createSchema({
|
|
23
|
+
type: 'ref',
|
|
24
|
+
name: resolveName({ name: `${operationId} ${param.name}`, type: 'function' }),
|
|
25
|
+
optional: !param.required,
|
|
26
|
+
}),
|
|
27
|
+
}),
|
|
28
|
+
),
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type BuildOperationSchemaOptions = {
|
|
33
|
+
node: OperationNode
|
|
34
|
+
resolveName: ResolveName
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds an `ObjectSchemaNode` representing the `<OperationId>Data` type:
|
|
39
|
+
* - `data` → request body ref (optional) or `never`
|
|
40
|
+
* - `pathParams` → inline object of path param refs, or `never`
|
|
41
|
+
* - `queryParams` → inline object of query param refs (optional), or `never`
|
|
42
|
+
* - `headerParams` → inline object of header param refs (optional), or `never`
|
|
43
|
+
* - `url` → Express-style template literal (plugin-ts extension, handled by printer)
|
|
44
|
+
*/
|
|
45
|
+
export function buildDataSchemaNode({ node, resolveName }: BuildOperationSchemaOptions): SchemaNode {
|
|
46
|
+
const pathParams = node.parameters.filter((p) => p.in === 'path')
|
|
47
|
+
const queryParams = node.parameters.filter((p) => p.in === 'query')
|
|
48
|
+
const headerParams = node.parameters.filter((p) => p.in === 'header')
|
|
49
|
+
|
|
50
|
+
return createSchema({
|
|
51
|
+
type: 'object',
|
|
52
|
+
properties: [
|
|
53
|
+
createProperty({
|
|
54
|
+
name: 'data',
|
|
55
|
+
schema: node.requestBody
|
|
56
|
+
? createSchema({
|
|
57
|
+
type: 'ref',
|
|
58
|
+
name: resolveName({ name: `${node.operationId} MutationRequest`, type: 'function' }),
|
|
59
|
+
optional: true,
|
|
60
|
+
})
|
|
61
|
+
: createSchema({ type: 'never', optional: true }),
|
|
62
|
+
}),
|
|
63
|
+
createProperty({
|
|
64
|
+
name: 'pathParams',
|
|
65
|
+
schema:
|
|
66
|
+
pathParams.length > 0
|
|
67
|
+
? buildParamsSchema({ params: pathParams, operationId: node.operationId, resolveName })
|
|
68
|
+
: createSchema({ type: 'never', optional: true }),
|
|
69
|
+
}),
|
|
70
|
+
createProperty({
|
|
71
|
+
name: 'queryParams',
|
|
72
|
+
schema:
|
|
73
|
+
queryParams.length > 0
|
|
74
|
+
? createSchema({ ...buildParamsSchema({ params: queryParams, operationId: node.operationId, resolveName }), optional: true })
|
|
75
|
+
: createSchema({ type: 'never', optional: true }),
|
|
76
|
+
}),
|
|
77
|
+
createProperty({
|
|
78
|
+
name: 'headerParams',
|
|
79
|
+
schema:
|
|
80
|
+
headerParams.length > 0
|
|
81
|
+
? createSchema({ ...buildParamsSchema({ params: headerParams, operationId: node.operationId, resolveName }), optional: true })
|
|
82
|
+
: createSchema({ type: 'never', optional: true }),
|
|
83
|
+
}),
|
|
84
|
+
createProperty({
|
|
85
|
+
name: 'url',
|
|
86
|
+
schema: createSchema({ type: 'url', path: node.path }),
|
|
87
|
+
}),
|
|
88
|
+
],
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Builds an `ObjectSchemaNode` representing `<OperationId>Responses` — keyed by HTTP status code.
|
|
94
|
+
*
|
|
95
|
+
* Example output:
|
|
96
|
+
* ```ts
|
|
97
|
+
* export type PlaceOrderPatchResponses = { 200: PlaceOrderPatch200; 405: PlaceOrderPatch405 }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function buildResponsesSchemaNode({ node, resolveName }: BuildOperationSchemaOptions): SchemaNode | null {
|
|
101
|
+
const responsesWithSchema = node.responses.filter((res) => res.schema)
|
|
102
|
+
|
|
103
|
+
if (responsesWithSchema.length === 0) {
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return createSchema({
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: responsesWithSchema.map((res) =>
|
|
110
|
+
createProperty({
|
|
111
|
+
name: String(res.statusCode),
|
|
112
|
+
schema: createSchema({
|
|
113
|
+
type: 'ref',
|
|
114
|
+
name: resolveName({ name: `${node.operationId} ${res.statusCode}`, type: 'function' }),
|
|
115
|
+
}),
|
|
116
|
+
}),
|
|
117
|
+
),
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Builds a `UnionSchemaNode` representing `<OperationId>Response` — all response types in union format.
|
|
123
|
+
*
|
|
124
|
+
* Example output:
|
|
125
|
+
* ```ts
|
|
126
|
+
* export type PlaceOrderPatchResponse = PlaceOrderPatch200 | PlaceOrderPatch405
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export function buildResponseUnionSchemaNode({ node, resolveName }: BuildOperationSchemaOptions): SchemaNode | null {
|
|
130
|
+
const responsesWithSchema = node.responses.filter((res) => res.schema)
|
|
131
|
+
|
|
132
|
+
if (responsesWithSchema.length === 0) {
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return createSchema({
|
|
137
|
+
type: 'union',
|
|
138
|
+
members: responsesWithSchema.map((res) =>
|
|
139
|
+
createSchema({
|
|
140
|
+
type: 'ref',
|
|
141
|
+
name: resolveName({ name: `${node.operationId} ${res.statusCode}`, type: 'function' }),
|
|
142
|
+
}),
|
|
143
|
+
),
|
|
144
|
+
})
|
|
145
|
+
}
|
package/src/plugin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { camelCase, pascalCase } from '@internals/utils'
|
|
3
3
|
import { walk } from '@kubb/ast'
|
|
4
|
-
import { definePlugin, type Group, getBarrelFiles, getMode } from '@kubb/core'
|
|
4
|
+
import { definePlugin, type Group, getBarrelFiles, getMode, resolveOptions } from '@kubb/core'
|
|
5
5
|
import { buildOperation, buildSchema, OperationGenerator, pluginOasName, SchemaGenerator } from '@kubb/plugin-oas'
|
|
6
6
|
import { typeGenerator, typeGeneratorV2 } from './generators'
|
|
7
7
|
import type { PluginTs } from './types.ts'
|
|
@@ -58,7 +58,6 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
58
58
|
usedEnumNames,
|
|
59
59
|
},
|
|
60
60
|
pre: [pluginOasName],
|
|
61
|
-
//resolveOptions(operation|schema): ResolvedOptions
|
|
62
61
|
resolvePath(baseName, pathMode, options) {
|
|
63
62
|
const root = path.resolve(this.config.root, this.config.output.path)
|
|
64
63
|
const mode = pathMode ?? getMode(path.resolve(root, output.path))
|
|
@@ -117,7 +116,14 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
117
116
|
async schema(schemaNode) {
|
|
118
117
|
const writeTasks = generators.map(async (generator) => {
|
|
119
118
|
if (generator.type === 'react' && generator.version === '2') {
|
|
119
|
+
const options = resolveOptions(schemaNode, { options: plugin.options, exclude, include, override })
|
|
120
|
+
|
|
121
|
+
if (options === null) {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
120
125
|
await buildSchema(schemaNode, {
|
|
126
|
+
options,
|
|
121
127
|
adapter,
|
|
122
128
|
config,
|
|
123
129
|
fabric,
|
|
@@ -130,12 +136,19 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
130
136
|
}
|
|
131
137
|
})
|
|
132
138
|
|
|
133
|
-
await writeTasks
|
|
139
|
+
await Promise.all(writeTasks)
|
|
134
140
|
},
|
|
135
141
|
async operation(operationNode) {
|
|
136
142
|
const writeTasks = generators.map(async (generator) => {
|
|
137
143
|
if (generator.type === 'react' && generator.version === '2') {
|
|
144
|
+
const options = resolveOptions(operationNode, { options: plugin.options, exclude, include, override })
|
|
145
|
+
|
|
146
|
+
if (options === null) {
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
138
150
|
await buildOperation(operationNode, {
|
|
151
|
+
options,
|
|
139
152
|
adapter,
|
|
140
153
|
config,
|
|
141
154
|
fabric,
|
|
@@ -148,12 +161,23 @@ export const pluginTs = definePlugin<PluginTs>((options) => {
|
|
|
148
161
|
}
|
|
149
162
|
})
|
|
150
163
|
|
|
151
|
-
await writeTasks
|
|
164
|
+
await Promise.all(writeTasks)
|
|
152
165
|
},
|
|
153
166
|
},
|
|
154
167
|
{ depth: 'shallow' },
|
|
155
168
|
)
|
|
156
169
|
|
|
170
|
+
const barrelFiles = await getBarrelFiles(this.fabric.files, {
|
|
171
|
+
type: output.barrelType ?? 'named',
|
|
172
|
+
root,
|
|
173
|
+
output,
|
|
174
|
+
meta: {
|
|
175
|
+
pluginName: this.plugin.name,
|
|
176
|
+
},
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
await this.upsertFile(...barrelFiles)
|
|
180
|
+
|
|
157
181
|
return
|
|
158
182
|
}
|
|
159
183
|
|
package/src/printer.ts
CHANGED
|
@@ -19,6 +19,10 @@ type TsOptions = {
|
|
|
19
19
|
* @default `'inlineLiteral'`
|
|
20
20
|
*/
|
|
21
21
|
enumType: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal' | 'inlineLiteral'
|
|
22
|
+
/**
|
|
23
|
+
* Custom property signatures that override specific object properties by name.
|
|
24
|
+
*/
|
|
25
|
+
mapper?: Record<string, ts.PropertySignature>
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
type TsPrinter = PrinterFactoryOptions<'typescript', TsOptions, ts.TypeNode>
|
|
@@ -143,13 +147,19 @@ export const printerTs = definePrinter<TsPrinter>((options) => ({
|
|
|
143
147
|
any: () => factory.keywordTypeNodes.any,
|
|
144
148
|
unknown: () => factory.keywordTypeNodes.unknown,
|
|
145
149
|
void: () => factory.keywordTypeNodes.void,
|
|
150
|
+
never: () => factory.keywordTypeNodes.never,
|
|
146
151
|
boolean: () => factory.keywordTypeNodes.boolean,
|
|
147
152
|
null: () => factory.keywordTypeNodes.null,
|
|
148
153
|
blob: () => factory.createTypeReferenceNode('Blob', []),
|
|
149
154
|
string: () => factory.keywordTypeNodes.string,
|
|
150
155
|
uuid: () => factory.keywordTypeNodes.string,
|
|
151
156
|
email: () => factory.keywordTypeNodes.string,
|
|
152
|
-
url: () =>
|
|
157
|
+
url: (node) => {
|
|
158
|
+
if (node.path) {
|
|
159
|
+
return factory.createUrlTemplateType(node.path)
|
|
160
|
+
}
|
|
161
|
+
return factory.keywordTypeNodes.string
|
|
162
|
+
},
|
|
153
163
|
datetime: () => factory.keywordTypeNodes.string,
|
|
154
164
|
number: () => factory.keywordTypeNodes.number,
|
|
155
165
|
integer: () => factory.keywordTypeNodes.number,
|
|
@@ -219,6 +229,10 @@ export const printerTs = definePrinter<TsPrinter>((options) => ({
|
|
|
219
229
|
const { print } = this
|
|
220
230
|
|
|
221
231
|
const propertyNodes: Array<ts.TypeElement> = node.properties.map((prop) => {
|
|
232
|
+
if (this.options.mapper && Object.hasOwn(this.options.mapper, prop.name)) {
|
|
233
|
+
return this.options.mapper[prop.name]!
|
|
234
|
+
}
|
|
235
|
+
|
|
222
236
|
const baseType = (print(prop.schema) ?? factory.keywordTypeNodes.unknown) as ts.TypeNode
|
|
223
237
|
const type = buildPropertyType(prop.schema, baseType, this.options.optionalType)
|
|
224
238
|
|
package/src/types.ts
CHANGED
|
@@ -63,6 +63,8 @@ export type Options = {
|
|
|
63
63
|
/**
|
|
64
64
|
* Set a suffix for the generated enums.
|
|
65
65
|
* @default 'enum'
|
|
66
|
+
* @deprecated Set `enumSuffix` on the adapter (`adapterOas({ enumSuffix })`) instead.
|
|
67
|
+
* In v5, the adapter owns this decision at parse time; the plugin option is ignored.
|
|
66
68
|
*/
|
|
67
69
|
enumSuffix?: string
|
|
68
70
|
/**
|
|
@@ -70,6 +72,8 @@ export type Options = {
|
|
|
70
72
|
* - 'string' represents dates as string values.
|
|
71
73
|
* - 'date' represents dates as JavaScript Date objects.
|
|
72
74
|
* @default 'string'
|
|
75
|
+
* @deprecated Set `dateType` on the adapter (`adapterOas({ dateType })`) instead.
|
|
76
|
+
* In v5, the adapter owns this decision at parse time; the plugin option is ignored.
|
|
73
77
|
*/
|
|
74
78
|
dateType?: 'string' | 'date'
|
|
75
79
|
/**
|
|
@@ -78,6 +82,8 @@ export type Options = {
|
|
|
78
82
|
* - 'bigint' uses the TypeScript `bigint` type (accurate for values exceeding Number.MAX_SAFE_INTEGER).
|
|
79
83
|
* @note in v5 of Kubb 'bigint' will become the default to better align with OpenAPI's int64 specification.
|
|
80
84
|
* @default 'number'
|
|
85
|
+
* @deprecated Set `integerType` on the adapter (`adapterOas({ integerType })`) instead.
|
|
86
|
+
* In v5, the adapter owns this decision at parse time; the plugin option is ignored.
|
|
81
87
|
*/
|
|
82
88
|
integerType?: 'number' | 'bigint'
|
|
83
89
|
/**
|
|
@@ -86,6 +92,8 @@ export type Options = {
|
|
|
86
92
|
* - 'unknown' requires type narrowing before use.
|
|
87
93
|
* - 'void' represents no value.
|
|
88
94
|
* @default 'any'
|
|
95
|
+
* @deprecated Set `unknownType` on the adapter (`adapterOas({ unknownType })`) instead.
|
|
96
|
+
* In v5, the adapter owns this decision at parse time; the plugin option is ignored.
|
|
89
97
|
*/
|
|
90
98
|
unknownType?: 'any' | 'unknown' | 'void'
|
|
91
99
|
/**
|
|
@@ -94,6 +102,8 @@ export type Options = {
|
|
|
94
102
|
* - 'unknown' requires type narrowing before use.
|
|
95
103
|
* - 'void' represents no value.
|
|
96
104
|
* @default `unknownType`
|
|
105
|
+
* @deprecated Set `emptySchemaType` on the adapter (`adapterOas({ emptySchemaType })`) instead.
|
|
106
|
+
* In v5, the adapter owns this decision at parse time; the plugin option is ignored.
|
|
97
107
|
*/
|
|
98
108
|
emptySchemaType?: 'any' | 'unknown' | 'void'
|
|
99
109
|
/**
|