@kubb/plugin-ts 5.0.0-alpha.20 → 5.0.0-alpha.21
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/Type-B6fo0gSk.js +120 -0
- package/dist/Type-B6fo0gSk.js.map +1 -0
- package/dist/Type-oFwUfkZv.cjs +131 -0
- package/dist/Type-oFwUfkZv.cjs.map +1 -0
- package/dist/builderTs-Cd3juc2G.cjs +120 -0
- package/dist/builderTs-Cd3juc2G.cjs.map +1 -0
- package/dist/builderTs-DausqHpc.js +116 -0
- package/dist/builderTs-DausqHpc.js.map +1 -0
- package/dist/builders.cjs +3 -0
- package/dist/builders.d.ts +8 -0
- package/dist/builders.js +2 -0
- package/dist/{casing-Cp-jbC_k.js → casing-BJHFg-zZ.js} +1 -1
- package/dist/{casing-Cp-jbC_k.js.map → casing-BJHFg-zZ.js.map} +1 -1
- package/dist/{casing-D2uQKLWS.cjs → casing-DHfdqpLi.cjs} +2 -39
- package/dist/{casing-D2uQKLWS.cjs.map → casing-DHfdqpLi.cjs.map} +1 -1
- package/dist/chunk-ByKO4r7w.cjs +38 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.ts +1 -2
- package/dist/components.js +1 -1
- package/dist/generators-ByK18qUn.js +551 -0
- package/dist/generators-ByK18qUn.js.map +1 -0
- package/dist/{generators-xHWQCNd9.cjs → generators-aSsiTfUO.cjs} +296 -293
- package/dist/generators-aSsiTfUO.cjs.map +1 -0
- package/dist/generators.cjs +2 -1
- package/dist/generators.d.ts +5 -2
- package/dist/generators.js +2 -2
- package/dist/index.cjs +38 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +36 -35
- package/dist/index.js.map +1 -1
- package/dist/{Type-CMC7L-38.js → printerTs-BgZucv4T.js} +18 -130
- package/dist/printerTs-BgZucv4T.js.map +1 -0
- package/dist/{Type-B70QnSzH.cjs → printerTs-CFXc_LpP.cjs} +40 -133
- package/dist/printerTs-CFXc_LpP.cjs.map +1 -0
- package/dist/printers.cjs +3 -0
- package/dist/printers.d.ts +75 -0
- package/dist/printers.js +2 -0
- package/dist/{resolvers-DsKabI0F.js → resolverTsLegacy-DLl854-P.js} +8 -7
- package/dist/resolverTsLegacy-DLl854-P.js.map +1 -0
- package/dist/{resolvers-YIpeP5YD.cjs → resolverTsLegacy-sJ16Iqrl.cjs} +9 -7
- package/dist/resolverTsLegacy-sJ16Iqrl.cjs.map +1 -0
- package/dist/resolvers.cjs +3 -3
- package/dist/resolvers.d.ts +1 -1
- package/dist/resolvers.js +1 -1
- package/dist/{types-zqLMbIqZ.d.ts → types-BcyuFDn9.d.ts} +26 -22
- package/package.json +17 -5
- package/src/builders/builderTs.ts +92 -0
- package/src/builders/index.ts +1 -0
- package/src/components/Type.tsx +4 -6
- package/src/factory.ts +0 -32
- package/src/generators/index.ts +1 -0
- package/src/generators/typeGenerator.tsx +49 -140
- package/src/generators/typeGeneratorLegacy.tsx +345 -0
- package/src/index.ts +1 -1
- package/src/plugin.ts +15 -44
- package/src/presets.ts +10 -7
- package/src/printers/index.ts +1 -0
- package/src/{printer.ts → printers/printerTs.ts} +20 -16
- package/src/resolvers/resolverTs.ts +7 -4
- package/src/resolvers/resolverTsLegacy.ts +1 -1
- package/src/types.ts +39 -21
- package/dist/Type-B70QnSzH.cjs.map +0 -1
- package/dist/Type-CMC7L-38.js.map +0 -1
- package/dist/generators-BFkr7ecU.js +0 -556
- package/dist/generators-BFkr7ecU.js.map +0 -1
- package/dist/generators-xHWQCNd9.cjs.map +0 -1
- package/dist/resolvers-DsKabI0F.js.map +0 -1
- package/dist/resolvers-YIpeP5YD.cjs.map +0 -1
- package/src/generators/utils.ts +0 -308
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { pascalCase } from '@internals/utils'
|
|
3
|
+
import { caseParams, composeTransformers, createProperty, createSchema, narrowSchema, schemaTypes, transform } from '@kubb/ast'
|
|
4
|
+
import type { OperationNode, ParameterNode, SchemaNode } from '@kubb/ast/types'
|
|
5
|
+
import { defineGenerator, getMode } from '@kubb/core'
|
|
6
|
+
import { File } from '@kubb/react-fabric'
|
|
7
|
+
import { Type } from '../components/Type.tsx'
|
|
8
|
+
import { ENUM_TYPES_WITH_KEY_SUFFIX } from '../constants.ts'
|
|
9
|
+
import { resolverTsLegacy } from '../resolvers/resolverTsLegacy.ts'
|
|
10
|
+
import type { PluginTs, ResolverTs } from '../types'
|
|
11
|
+
|
|
12
|
+
type BuildGroupedParamsSchemaOptions = {
|
|
13
|
+
params: Array<ParameterNode>
|
|
14
|
+
parentName?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function buildGroupedParamsSchema({ params, parentName }: BuildGroupedParamsSchemaOptions): SchemaNode {
|
|
18
|
+
return createSchema({
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: params.map((param) => {
|
|
21
|
+
let schema = param.schema
|
|
22
|
+
if (narrowSchema(schema, 'enum') && !schema.name && parentName) {
|
|
23
|
+
schema = { ...schema, name: pascalCase([parentName, param.name, 'enum'].join(' ')) }
|
|
24
|
+
}
|
|
25
|
+
return createProperty({
|
|
26
|
+
name: param.name,
|
|
27
|
+
required: param.required,
|
|
28
|
+
schema,
|
|
29
|
+
})
|
|
30
|
+
}),
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type BuildOperationSchemaOptions = {
|
|
35
|
+
node: OperationNode
|
|
36
|
+
resolver: ResolverTs
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildLegacyResponsesSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode | null {
|
|
40
|
+
const isGet = node.method.toLowerCase() === 'get'
|
|
41
|
+
const successResponses = node.responses.filter((res) => {
|
|
42
|
+
const code = Number(res.statusCode)
|
|
43
|
+
return !Number.isNaN(code) && code >= 200 && code < 300
|
|
44
|
+
})
|
|
45
|
+
const errorResponses = node.responses.filter((res) => res.statusCode === 'default' || Number(res.statusCode) >= 400)
|
|
46
|
+
|
|
47
|
+
const responseSchema =
|
|
48
|
+
successResponses.length > 0
|
|
49
|
+
? successResponses.length === 1
|
|
50
|
+
? createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, successResponses[0]!.statusCode) })
|
|
51
|
+
: createSchema({
|
|
52
|
+
type: 'union',
|
|
53
|
+
members: successResponses.map((res) => createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, res.statusCode) })),
|
|
54
|
+
})
|
|
55
|
+
: createSchema({ type: 'any' })
|
|
56
|
+
|
|
57
|
+
const errorsSchema =
|
|
58
|
+
errorResponses.length > 0
|
|
59
|
+
? errorResponses.length === 1
|
|
60
|
+
? createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, errorResponses[0]!.statusCode) })
|
|
61
|
+
: createSchema({
|
|
62
|
+
type: 'union',
|
|
63
|
+
members: errorResponses.map((res) => createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, res.statusCode) })),
|
|
64
|
+
})
|
|
65
|
+
: createSchema({ type: 'any' })
|
|
66
|
+
|
|
67
|
+
const properties = [createProperty({ name: 'Response', required: true, schema: responseSchema })]
|
|
68
|
+
|
|
69
|
+
if (!isGet && node.requestBody?.schema) {
|
|
70
|
+
properties.push(
|
|
71
|
+
createProperty({
|
|
72
|
+
name: 'Request',
|
|
73
|
+
required: true,
|
|
74
|
+
schema: createSchema({ type: 'ref', name: resolver.resolveDataTypedName(node) }),
|
|
75
|
+
}),
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (node.parameters.some((p) => p.in === 'query') && resolver.resolveQueryParamsTypedName) {
|
|
80
|
+
properties.push(
|
|
81
|
+
createProperty({
|
|
82
|
+
name: 'QueryParams',
|
|
83
|
+
required: true,
|
|
84
|
+
schema: createSchema({ type: 'ref', name: resolver.resolveQueryParamsTypedName(node) }),
|
|
85
|
+
}),
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (node.parameters.some((p) => p.in === 'path') && resolver.resolvePathParamsTypedName) {
|
|
90
|
+
properties.push(
|
|
91
|
+
createProperty({
|
|
92
|
+
name: 'PathParams',
|
|
93
|
+
required: true,
|
|
94
|
+
schema: createSchema({ type: 'ref', name: resolver.resolvePathParamsTypedName(node) }),
|
|
95
|
+
}),
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (node.parameters.some((p) => p.in === 'header') && resolver.resolveHeaderParamsTypedName) {
|
|
100
|
+
properties.push(
|
|
101
|
+
createProperty({
|
|
102
|
+
name: 'HeaderParams',
|
|
103
|
+
required: true,
|
|
104
|
+
schema: createSchema({ type: 'ref', name: resolver.resolveHeaderParamsTypedName(node) }),
|
|
105
|
+
}),
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
properties.push(createProperty({ name: 'Errors', required: true, schema: errorsSchema }))
|
|
110
|
+
|
|
111
|
+
return createSchema({ type: 'object', properties })
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildLegacyResponseUnionSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode {
|
|
115
|
+
const successResponses = node.responses.filter((res) => {
|
|
116
|
+
const code = Number(res.statusCode)
|
|
117
|
+
return !Number.isNaN(code) && code >= 200 && code < 300
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
if (successResponses.length === 0) {
|
|
121
|
+
return createSchema({ type: 'any' })
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (successResponses.length === 1) {
|
|
125
|
+
return createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, successResponses[0]!.statusCode) })
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return createSchema({
|
|
129
|
+
type: 'union',
|
|
130
|
+
members: successResponses.map((res) => createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, res.statusCode) })),
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function nameUnnamedEnums(node: SchemaNode, parentName: string): SchemaNode {
|
|
135
|
+
return transform(node, {
|
|
136
|
+
schema(n) {
|
|
137
|
+
const enumNode = narrowSchema(n, 'enum')
|
|
138
|
+
if (enumNode && !enumNode.name) {
|
|
139
|
+
return { ...enumNode, name: pascalCase([parentName, 'enum'].join(' ')) }
|
|
140
|
+
}
|
|
141
|
+
return undefined
|
|
142
|
+
},
|
|
143
|
+
property(p) {
|
|
144
|
+
const enumNode = narrowSchema(p.schema, 'enum')
|
|
145
|
+
if (enumNode && !enumNode.name) {
|
|
146
|
+
return {
|
|
147
|
+
...p,
|
|
148
|
+
schema: { ...enumNode, name: pascalCase([parentName, p.name, 'enum'].join(' ')) },
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return undefined
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const typeGeneratorLegacy = defineGenerator<PluginTs>({
|
|
157
|
+
name: 'typescript-legacy',
|
|
158
|
+
type: 'react',
|
|
159
|
+
Operation({ node, adapter, options, config }) {
|
|
160
|
+
const { enumType, enumKeyCasing, optionalType, arrayType, syntaxType, paramsCasing, group, output, resolver, transformers = [] } = options
|
|
161
|
+
|
|
162
|
+
const root = path.resolve(config.root, config.output.path)
|
|
163
|
+
const mode = getMode(path.resolve(root, output.path))
|
|
164
|
+
|
|
165
|
+
const file = resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group })
|
|
166
|
+
const params = caseParams(node.parameters, paramsCasing)
|
|
167
|
+
|
|
168
|
+
function renderSchemaType({
|
|
169
|
+
node: schemaNode,
|
|
170
|
+
name,
|
|
171
|
+
typedName,
|
|
172
|
+
description,
|
|
173
|
+
keysToOmit,
|
|
174
|
+
}: {
|
|
175
|
+
node: SchemaNode | null
|
|
176
|
+
name: string
|
|
177
|
+
typedName: string
|
|
178
|
+
description?: string
|
|
179
|
+
keysToOmit?: Array<string>
|
|
180
|
+
}) {
|
|
181
|
+
if (!schemaNode) {
|
|
182
|
+
return null
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const transformedNode = transform(schemaNode, composeTransformers(...transformers))
|
|
186
|
+
|
|
187
|
+
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
188
|
+
name: resolver.default(schemaName, 'type'),
|
|
189
|
+
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
190
|
+
}))
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<>
|
|
194
|
+
{mode === 'split' &&
|
|
195
|
+
imports.map((imp) => <File.Import key={[name, imp.path, imp.isTypeOnly].join('-')} root={file.path} path={imp.path} name={imp.name} isTypeOnly />)}
|
|
196
|
+
<Type
|
|
197
|
+
name={name}
|
|
198
|
+
typedName={typedName}
|
|
199
|
+
node={transformedNode}
|
|
200
|
+
description={description}
|
|
201
|
+
enumType={enumType}
|
|
202
|
+
enumKeyCasing={enumKeyCasing}
|
|
203
|
+
optionalType={optionalType}
|
|
204
|
+
arrayType={arrayType}
|
|
205
|
+
syntaxType={syntaxType}
|
|
206
|
+
resolver={resolver}
|
|
207
|
+
keysToOmit={keysToOmit}
|
|
208
|
+
/>
|
|
209
|
+
</>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const pathParams = params.filter((p) => p.in === 'path')
|
|
214
|
+
const queryParams = params.filter((p) => p.in === 'query')
|
|
215
|
+
const headerParams = params.filter((p) => p.in === 'header')
|
|
216
|
+
|
|
217
|
+
const responseTypes = node.responses.map((res) => {
|
|
218
|
+
const responseName = resolver.resolveResponseStatusName(node, res.statusCode)
|
|
219
|
+
const baseResponseName = resolverTsLegacy.resolveResponseStatusName(node, res.statusCode)
|
|
220
|
+
|
|
221
|
+
return renderSchemaType({
|
|
222
|
+
node: res.schema ? nameUnnamedEnums(res.schema, baseResponseName) : res.schema,
|
|
223
|
+
name: responseName,
|
|
224
|
+
typedName: resolver.resolveResponseStatusTypedName(node, res.statusCode),
|
|
225
|
+
description: res.description,
|
|
226
|
+
keysToOmit: res.keysToOmit,
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
const requestType = node.requestBody?.schema
|
|
231
|
+
? renderSchemaType({
|
|
232
|
+
node: nameUnnamedEnums(node.requestBody.schema, resolverTsLegacy.resolveDataName(node)),
|
|
233
|
+
name: resolver.resolveDataName(node),
|
|
234
|
+
typedName: resolver.resolveDataTypedName(node),
|
|
235
|
+
description: node.requestBody.description ?? node.requestBody.schema.description,
|
|
236
|
+
keysToOmit: node.requestBody.keysToOmit,
|
|
237
|
+
})
|
|
238
|
+
: null
|
|
239
|
+
|
|
240
|
+
const legacyParamTypes = [
|
|
241
|
+
pathParams.length > 0
|
|
242
|
+
? renderSchemaType({
|
|
243
|
+
node: buildGroupedParamsSchema({ params: pathParams, parentName: resolverTsLegacy.resolvePathParamsName!(node) }),
|
|
244
|
+
name: resolver.resolvePathParamsName!(node),
|
|
245
|
+
typedName: resolver.resolvePathParamsTypedName!(node),
|
|
246
|
+
})
|
|
247
|
+
: null,
|
|
248
|
+
queryParams.length > 0
|
|
249
|
+
? renderSchemaType({
|
|
250
|
+
node: buildGroupedParamsSchema({ params: queryParams, parentName: resolverTsLegacy.resolveQueryParamsName!(node) }),
|
|
251
|
+
name: resolver.resolveQueryParamsName!(node),
|
|
252
|
+
typedName: resolver.resolveQueryParamsTypedName!(node),
|
|
253
|
+
})
|
|
254
|
+
: null,
|
|
255
|
+
headerParams.length > 0
|
|
256
|
+
? renderSchemaType({
|
|
257
|
+
node: buildGroupedParamsSchema({ params: headerParams, parentName: resolverTsLegacy.resolveHeaderParamsName!(node) }),
|
|
258
|
+
name: resolver.resolveHeaderParamsName!(node),
|
|
259
|
+
typedName: resolver.resolveHeaderParamsTypedName!(node),
|
|
260
|
+
})
|
|
261
|
+
: null,
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
const legacyResponsesType = renderSchemaType({
|
|
265
|
+
node: buildLegacyResponsesSchemaNode({ node, resolver }),
|
|
266
|
+
name: resolver.resolveResponsesName(node),
|
|
267
|
+
typedName: resolver.resolveResponsesTypedName(node),
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
const legacyResponseType = renderSchemaType({
|
|
271
|
+
node: buildLegacyResponseUnionSchemaNode({ node, resolver }),
|
|
272
|
+
name: resolver.resolveResponseName(node),
|
|
273
|
+
typedName: resolver.resolveResponseTypedName(node),
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<File
|
|
278
|
+
baseName={file.baseName}
|
|
279
|
+
path={file.path}
|
|
280
|
+
meta={file.meta}
|
|
281
|
+
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
282
|
+
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
283
|
+
>
|
|
284
|
+
{legacyParamTypes}
|
|
285
|
+
{responseTypes}
|
|
286
|
+
{requestType}
|
|
287
|
+
{legacyResponseType}
|
|
288
|
+
{legacyResponsesType}
|
|
289
|
+
</File>
|
|
290
|
+
)
|
|
291
|
+
},
|
|
292
|
+
Schema({ node, adapter, options, config }) {
|
|
293
|
+
const { enumType, enumKeyCasing, syntaxType, optionalType, arrayType, output, group, resolver, transformers = [] } = options
|
|
294
|
+
|
|
295
|
+
const root = path.resolve(config.root, config.output.path)
|
|
296
|
+
const mode = getMode(path.resolve(root, output.path))
|
|
297
|
+
|
|
298
|
+
if (!node.name) {
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const transformedNode = transform(node, composeTransformers(...transformers))
|
|
303
|
+
|
|
304
|
+
const imports = adapter.getImports(transformedNode, (schemaName) => ({
|
|
305
|
+
name: resolver.default(schemaName, 'type'),
|
|
306
|
+
path: resolver.resolveFile({ name: schemaName, extname: '.ts' }, { root, output, group }).path,
|
|
307
|
+
}))
|
|
308
|
+
|
|
309
|
+
const isEnumSchema = !!narrowSchema(node, schemaTypes.enum)
|
|
310
|
+
|
|
311
|
+
const typedName = ENUM_TYPES_WITH_KEY_SUFFIX.has(enumType) && isEnumSchema ? resolver.resolveEnumKeyTypedName(node) : resolver.resolveTypedName(node.name)
|
|
312
|
+
|
|
313
|
+
const type = {
|
|
314
|
+
name: resolver.resolveName(node.name),
|
|
315
|
+
typedName,
|
|
316
|
+
file: resolver.resolveFile({ name: node.name, extname: '.ts' }, { root, output, group }),
|
|
317
|
+
} as const
|
|
318
|
+
|
|
319
|
+
return (
|
|
320
|
+
<File
|
|
321
|
+
baseName={type.file.baseName}
|
|
322
|
+
path={type.file.path}
|
|
323
|
+
meta={type.file.meta}
|
|
324
|
+
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
325
|
+
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
326
|
+
>
|
|
327
|
+
{mode === 'split' &&
|
|
328
|
+
imports.map((imp) => (
|
|
329
|
+
<File.Import key={[node.name, imp.path, imp.isTypeOnly].join('-')} root={type.file.path} path={imp.path} name={imp.name} isTypeOnly />
|
|
330
|
+
))}
|
|
331
|
+
<Type
|
|
332
|
+
name={type.name}
|
|
333
|
+
typedName={type.typedName}
|
|
334
|
+
node={transformedNode}
|
|
335
|
+
enumType={enumType}
|
|
336
|
+
enumKeyCasing={enumKeyCasing}
|
|
337
|
+
optionalType={optionalType}
|
|
338
|
+
arrayType={arrayType}
|
|
339
|
+
syntaxType={syntaxType}
|
|
340
|
+
resolver={resolver}
|
|
341
|
+
/>
|
|
342
|
+
</File>
|
|
343
|
+
)
|
|
344
|
+
},
|
|
345
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { pluginTs, pluginTsName } from './plugin.ts'
|
|
2
|
-
export type { PluginTs
|
|
2
|
+
export type { PluginTs } from './types.ts'
|
package/src/plugin.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { camelCase } from '@internals/utils'
|
|
3
2
|
import { walk } from '@kubb/ast'
|
|
4
|
-
import { createPlugin,
|
|
5
|
-
import { typeGenerator } from './generators/index.ts'
|
|
3
|
+
import { createPlugin, getBarrelFiles, renderOperation, renderSchema } from '@kubb/core'
|
|
6
4
|
import { getPreset } from './presets.ts'
|
|
7
5
|
import type { PluginTs } from './types.ts'
|
|
8
6
|
|
|
@@ -21,73 +19,49 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
21
19
|
arrayType = 'array',
|
|
22
20
|
syntaxType = 'type',
|
|
23
21
|
paramsCasing,
|
|
24
|
-
generators = [typeGenerator].filter(Boolean),
|
|
25
22
|
compatibilityPreset = 'default',
|
|
26
|
-
resolvers: userResolvers,
|
|
23
|
+
resolvers: userResolvers = [],
|
|
27
24
|
transformers: userTransformers = [],
|
|
25
|
+
generators: userGenerators = [],
|
|
28
26
|
} = options
|
|
29
27
|
|
|
30
|
-
const {
|
|
28
|
+
const { resolver, transformers, generators } = getPreset(compatibilityPreset, {
|
|
31
29
|
resolvers: userResolvers,
|
|
32
30
|
transformers: userTransformers,
|
|
31
|
+
generators: userGenerators,
|
|
33
32
|
})
|
|
34
33
|
|
|
35
34
|
let resolveNameWarning = false
|
|
35
|
+
let resolvePathWarning = false
|
|
36
36
|
|
|
37
37
|
return {
|
|
38
38
|
name: pluginTsName,
|
|
39
39
|
options: {
|
|
40
40
|
output,
|
|
41
41
|
optionalType,
|
|
42
|
+
group,
|
|
42
43
|
arrayType,
|
|
43
44
|
enumType,
|
|
44
45
|
enumKeyCasing,
|
|
45
46
|
syntaxType,
|
|
46
|
-
group,
|
|
47
|
-
override,
|
|
48
47
|
paramsCasing,
|
|
49
|
-
compatibilityPreset,
|
|
50
|
-
baseResolver,
|
|
51
48
|
resolver,
|
|
52
49
|
transformers,
|
|
53
50
|
},
|
|
54
51
|
resolvePath(baseName, pathMode, options) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (mode === 'single') {
|
|
59
|
-
/**
|
|
60
|
-
* when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
|
|
61
|
-
* Other plugins then need to call addOrAppend instead of just add from the fileManager class
|
|
62
|
-
*/
|
|
63
|
-
return path.resolve(root, output.path)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (group && (options?.group?.path || options?.group?.tag)) {
|
|
67
|
-
const groupName: Group['name'] = group?.name
|
|
68
|
-
? group.name
|
|
69
|
-
: (ctx) => {
|
|
70
|
-
if (group?.type === 'path') {
|
|
71
|
-
return `${ctx.group.split('/')[1]}`
|
|
72
|
-
}
|
|
73
|
-
return `${camelCase(ctx.group)}Controller`
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return path.resolve(
|
|
77
|
-
root,
|
|
78
|
-
output.path,
|
|
79
|
-
groupName({
|
|
80
|
-
group: group.type === 'path' ? options.group.path! : options.group.tag!,
|
|
81
|
-
}),
|
|
82
|
-
baseName,
|
|
83
|
-
)
|
|
52
|
+
if (!resolvePathWarning) {
|
|
53
|
+
this.driver.events.emit('warn', 'Do not use resolvePath for pluginTs, use resolverTs.resolvePath instead')
|
|
54
|
+
resolvePathWarning = true
|
|
84
55
|
}
|
|
85
56
|
|
|
86
|
-
return
|
|
57
|
+
return resolver.resolvePath(
|
|
58
|
+
{ baseName, pathMode, tag: options?.group?.tag, path: options?.group?.path },
|
|
59
|
+
{ root: path.resolve(this.config.root, this.config.output.path), output, group },
|
|
60
|
+
)
|
|
87
61
|
},
|
|
88
62
|
resolveName(name, type) {
|
|
89
63
|
if (!resolveNameWarning) {
|
|
90
|
-
this.driver.events.emit('warn', 'Do not use resolveName for pluginTs, use resolverTs instead')
|
|
64
|
+
this.driver.events.emit('warn', 'Do not use resolveName for pluginTs, use resolverTs.default instead')
|
|
91
65
|
resolveNameWarning = true
|
|
92
66
|
}
|
|
93
67
|
|
|
@@ -97,7 +71,6 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
97
71
|
const { config, fabric, plugin, adapter, rootNode, driver, openInStudio } = this
|
|
98
72
|
|
|
99
73
|
const root = path.resolve(config.root, config.output.path)
|
|
100
|
-
const mode = getMode(path.resolve(root, output.path))
|
|
101
74
|
|
|
102
75
|
if (!adapter) {
|
|
103
76
|
throw new Error('Plugin cannot work without adapter being set')
|
|
@@ -124,7 +97,6 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
124
97
|
Component: generator.Schema,
|
|
125
98
|
plugin,
|
|
126
99
|
driver,
|
|
127
|
-
mode,
|
|
128
100
|
})
|
|
129
101
|
}
|
|
130
102
|
})
|
|
@@ -148,7 +120,6 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
148
120
|
Component: generator.Operation,
|
|
149
121
|
plugin,
|
|
150
122
|
driver,
|
|
151
|
-
mode,
|
|
152
123
|
})
|
|
153
124
|
}
|
|
154
125
|
})
|
package/src/presets.ts
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import type { Visitor } from '@kubb/ast/types'
|
|
2
|
-
import { type CompatibilityPreset, definePreset, definePresets, getPreset as getCorePreset } from '@kubb/core'
|
|
2
|
+
import { type CompatibilityPreset, definePreset, definePresets, type Generator, getPreset as getCorePreset } from '@kubb/core'
|
|
3
|
+
import { typeGenerator, typeGeneratorLegacy } from './generators/index.ts'
|
|
3
4
|
import { resolverTs, resolverTsLegacy } from './resolvers/index.ts'
|
|
4
|
-
import type { ResolverTs } from './types.ts'
|
|
5
|
+
import type { PluginTs, ResolverTs } from './types.ts'
|
|
5
6
|
|
|
6
7
|
export const presets = definePresets<ResolverTs>({
|
|
7
|
-
default: definePreset('default', { resolvers: [resolverTs] }),
|
|
8
|
-
kubbV4: definePreset('kubbV4', { resolvers: [resolverTsLegacy] }),
|
|
8
|
+
default: definePreset('default', { resolvers: [resolverTs], generators: [typeGenerator] }),
|
|
9
|
+
kubbV4: definePreset('kubbV4', { resolvers: [resolverTsLegacy], generators: [typeGeneratorLegacy] }),
|
|
9
10
|
})
|
|
10
11
|
|
|
11
12
|
type GetPresetOptions = {
|
|
12
|
-
resolvers
|
|
13
|
-
transformers
|
|
13
|
+
resolvers: Array<ResolverTs>
|
|
14
|
+
transformers: Array<Visitor>
|
|
15
|
+
generators: Array<Generator<PluginTs>>
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
export function getPreset(preset: CompatibilityPreset, { resolvers, transformers }: GetPresetOptions
|
|
18
|
+
export function getPreset(preset: CompatibilityPreset, { resolvers, transformers, generators }: GetPresetOptions) {
|
|
17
19
|
return getCorePreset({
|
|
18
20
|
preset,
|
|
19
21
|
presets,
|
|
20
22
|
resolvers: [resolverTs, ...(resolvers ?? [])],
|
|
21
23
|
transformers,
|
|
24
|
+
generators,
|
|
22
25
|
})
|
|
23
26
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { printerTs } from './printerTs.ts'
|
|
@@ -3,10 +3,11 @@ import { isStringType, narrowSchema, schemaTypes } from '@kubb/ast'
|
|
|
3
3
|
import type { ArraySchemaNode, SchemaNode } from '@kubb/ast/types'
|
|
4
4
|
import type { PrinterFactoryOptions } from '@kubb/core'
|
|
5
5
|
import { definePrinter } from '@kubb/core'
|
|
6
|
+
import { safePrint } from '@kubb/fabric-core/parsers/typescript'
|
|
6
7
|
import type ts from 'typescript'
|
|
7
|
-
import { ENUM_TYPES_WITH_KEY_SUFFIX, OPTIONAL_ADDS_QUESTION_TOKEN, OPTIONAL_ADDS_UNDEFINED } from '
|
|
8
|
-
import * as factory from '
|
|
9
|
-
import type { PluginTs, ResolverTs } from '
|
|
8
|
+
import { ENUM_TYPES_WITH_KEY_SUFFIX, OPTIONAL_ADDS_QUESTION_TOKEN, OPTIONAL_ADDS_UNDEFINED } from '../constants.ts'
|
|
9
|
+
import * as factory from '../factory.ts'
|
|
10
|
+
import type { PluginTs, ResolverTs } from '../types.ts'
|
|
10
11
|
|
|
11
12
|
type TsOptions = {
|
|
12
13
|
/**
|
|
@@ -50,7 +51,7 @@ type TsOptions = {
|
|
|
50
51
|
/**
|
|
51
52
|
* TypeScript printer factory options: maps `SchemaNode` → `ts.TypeNode` (raw) or `ts.Node` (full declaration).
|
|
52
53
|
*/
|
|
53
|
-
type TsPrinter = PrinterFactoryOptions<'typescript', TsOptions, ts.TypeNode,
|
|
54
|
+
type TsPrinter = PrinterFactoryOptions<'typescript', TsOptions, ts.TypeNode, string>
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
57
|
* Converts a primitive const value to a TypeScript literal type node.
|
|
@@ -287,32 +288,33 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
287
288
|
})
|
|
288
289
|
}
|
|
289
290
|
|
|
290
|
-
return this.
|
|
291
|
+
return this.transform(m)
|
|
291
292
|
})
|
|
292
293
|
.filter(Boolean)
|
|
293
294
|
|
|
294
295
|
return factory.createUnionDeclaration({ withParentheses: true, nodes: memberNodes }) ?? undefined
|
|
295
296
|
}
|
|
296
297
|
|
|
297
|
-
return factory.createUnionDeclaration({ withParentheses: true, nodes: buildMemberNodes(members, this.
|
|
298
|
+
return factory.createUnionDeclaration({ withParentheses: true, nodes: buildMemberNodes(members, this.transform) }) ?? undefined
|
|
298
299
|
},
|
|
299
300
|
intersection(node) {
|
|
300
|
-
return factory.createIntersectionDeclaration({ withParentheses: true, nodes: buildMemberNodes(node.members, this.
|
|
301
|
+
return factory.createIntersectionDeclaration({ withParentheses: true, nodes: buildMemberNodes(node.members, this.transform) }) ?? undefined
|
|
301
302
|
},
|
|
302
303
|
array(node) {
|
|
303
|
-
const itemNodes = (node.items ?? []).map((item) => this.
|
|
304
|
+
const itemNodes = (node.items ?? []).map((item) => this.transform(item)).filter(Boolean)
|
|
304
305
|
|
|
305
306
|
return factory.createArrayDeclaration({ nodes: itemNodes, arrayType: this.options.arrayType }) ?? undefined
|
|
306
307
|
},
|
|
307
308
|
tuple(node) {
|
|
308
|
-
return buildTupleNode(node, this.
|
|
309
|
+
return buildTupleNode(node, this.transform)
|
|
309
310
|
},
|
|
310
311
|
object(node) {
|
|
311
|
-
const {
|
|
312
|
+
const { transform, options } = this
|
|
313
|
+
|
|
312
314
|
const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType)
|
|
313
315
|
|
|
314
316
|
const propertyNodes: Array<ts.TypeElement> = node.properties.map((prop) => {
|
|
315
|
-
const baseType =
|
|
317
|
+
const baseType = transform(prop.schema) ?? factory.keywordTypeNodes.unknown
|
|
316
318
|
const type = buildPropertyType(prop.schema, baseType, options.optionalType)
|
|
317
319
|
|
|
318
320
|
const propertyNode = factory.createPropertySignature({
|
|
@@ -325,7 +327,7 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
325
327
|
return factory.appendJSDocToNode({ node: propertyNode, comments: buildPropertyJSDocComments(prop.schema) })
|
|
326
328
|
})
|
|
327
329
|
|
|
328
|
-
const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length,
|
|
330
|
+
const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, transform)]
|
|
329
331
|
|
|
330
332
|
if (!allElements.length) {
|
|
331
333
|
return factory.keywordTypeNodes.object
|
|
@@ -335,10 +337,10 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
335
337
|
},
|
|
336
338
|
},
|
|
337
339
|
print(node) {
|
|
338
|
-
let type = this.
|
|
340
|
+
let type = this.transform(node)
|
|
339
341
|
|
|
340
342
|
if (!type) {
|
|
341
|
-
return
|
|
343
|
+
return null
|
|
342
344
|
}
|
|
343
345
|
|
|
344
346
|
// Apply top-level nullable / optional union modifiers.
|
|
@@ -353,12 +355,12 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
353
355
|
// Without typeName, return the type node as-is (no declaration wrapping).
|
|
354
356
|
const { typeName, syntaxType = 'type', description, keysToOmit } = this.options
|
|
355
357
|
if (!typeName) {
|
|
356
|
-
return type
|
|
358
|
+
return safePrint(type)
|
|
357
359
|
}
|
|
358
360
|
|
|
359
361
|
const useTypeGeneration = syntaxType === 'type' || type.kind === factory.syntaxKind.union || !!keysToOmit?.length
|
|
360
362
|
|
|
361
|
-
|
|
363
|
+
const typeNode = factory.createTypeDeclaration({
|
|
362
364
|
name: typeName,
|
|
363
365
|
isExportable: true,
|
|
364
366
|
type: keysToOmit?.length
|
|
@@ -380,6 +382,8 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
380
382
|
node?.example ? `@example ${node.example}` : undefined,
|
|
381
383
|
],
|
|
382
384
|
})
|
|
385
|
+
|
|
386
|
+
return safePrint(typeNode)
|
|
383
387
|
},
|
|
384
388
|
}
|
|
385
389
|
})
|
|
@@ -27,6 +27,7 @@ function resolveName(name: string, type?: 'file' | 'function' | 'type' | 'const'
|
|
|
27
27
|
export const resolverTs = defineResolver<PluginTs>(() => {
|
|
28
28
|
return {
|
|
29
29
|
name: 'default',
|
|
30
|
+
pluginName: 'plugin-ts',
|
|
30
31
|
default(name, type) {
|
|
31
32
|
return resolveName(name, type)
|
|
32
33
|
},
|
|
@@ -86,11 +87,13 @@ export const resolverTs = defineResolver<PluginTs>(() => {
|
|
|
86
87
|
"resolvePathParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
|
|
87
88
|
)
|
|
88
89
|
},
|
|
89
|
-
resolveQueryParamsName(
|
|
90
|
-
|
|
90
|
+
resolveQueryParamsName(_node) {
|
|
91
|
+
throw new Error("resolveQueryParamsName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamName per individual parameter instead.")
|
|
91
92
|
},
|
|
92
|
-
resolveQueryParamsTypedName(
|
|
93
|
-
|
|
93
|
+
resolveQueryParamsTypedName(_node) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
"resolveQueryParamsTypedName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamTypedName per individual parameter instead.",
|
|
96
|
+
)
|
|
94
97
|
},
|
|
95
98
|
resolveHeaderParamsName(_node) {
|
|
96
99
|
throw new Error("resolveHeaderParamsName is only available with compatibilityPreset: 'kubbV4'. Use resolveParamName per individual parameter instead.")
|
|
@@ -28,7 +28,7 @@ import { resolverTs } from './resolverTs.ts'
|
|
|
28
28
|
export const resolverTsLegacy = defineResolver<PluginTs>(() => {
|
|
29
29
|
return {
|
|
30
30
|
...resolverTs,
|
|
31
|
-
|
|
31
|
+
pluginName: 'plugin-ts',
|
|
32
32
|
resolveResponseStatusName(node, statusCode) {
|
|
33
33
|
if (statusCode === 'default') {
|
|
34
34
|
return this.resolveName(`${node.operationId} Error`)
|