@kubb/plugin-ts 5.0.0-alpha.11 → 5.0.0-alpha.13
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-C8EHVKjc.js +663 -0
- package/dist/Type-C8EHVKjc.js.map +1 -0
- package/dist/Type-DrOq6-nh.cjs +680 -0
- package/dist/Type-DrOq6-nh.cjs.map +1 -0
- package/dist/casing-Cp-jbC_k.js +84 -0
- package/dist/casing-Cp-jbC_k.js.map +1 -0
- package/dist/casing-D2uQKLWS.cjs +144 -0
- package/dist/casing-D2uQKLWS.cjs.map +1 -0
- package/dist/components.cjs +3 -2
- package/dist/components.d.ts +41 -9
- package/dist/components.js +2 -2
- package/dist/generators-CX3cSSdF.cjs +551 -0
- package/dist/generators-CX3cSSdF.cjs.map +1 -0
- package/dist/generators-dCqW0ECC.js +547 -0
- package/dist/generators-dCqW0ECC.js.map +1 -0
- package/dist/generators.cjs +2 -3
- package/dist/generators.d.ts +3 -503
- package/dist/generators.js +2 -2
- package/dist/index.cjs +135 -4
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -41
- package/dist/index.js +134 -2
- package/dist/index.js.map +1 -0
- package/dist/resolvers-CH7hINyz.js +181 -0
- package/dist/resolvers-CH7hINyz.js.map +1 -0
- package/dist/resolvers-ebHaaCyw.cjs +191 -0
- package/dist/resolvers-ebHaaCyw.cjs.map +1 -0
- package/dist/resolvers.cjs +4 -0
- package/dist/resolvers.d.ts +51 -0
- package/dist/resolvers.js +2 -0
- package/dist/{types-mSXmB8WU.d.ts → types-BSRhtbGl.d.ts} +80 -57
- package/package.json +12 -5
- package/src/components/{v2/Enum.tsx → Enum.tsx} +27 -11
- package/src/components/Type.tsx +24 -141
- package/src/components/index.ts +1 -0
- package/src/generators/index.ts +0 -1
- package/src/generators/typeGenerator.tsx +204 -413
- package/src/generators/utils.ts +300 -0
- package/src/index.ts +0 -1
- package/src/plugin.ts +81 -126
- package/src/printer.ts +20 -6
- package/src/resolvers/index.ts +2 -0
- package/src/{resolverTs.ts → resolvers/resolverTs.ts} +26 -2
- package/src/resolvers/resolverTsLegacy.ts +85 -0
- package/src/types.ts +75 -52
- package/dist/components-CRu8IKY3.js +0 -729
- package/dist/components-CRu8IKY3.js.map +0 -1
- package/dist/components-DeNDKlzf.cjs +0 -982
- package/dist/components-DeNDKlzf.cjs.map +0 -1
- package/dist/plugin-CJ29AwE2.cjs +0 -1320
- package/dist/plugin-CJ29AwE2.cjs.map +0 -1
- package/dist/plugin-D60XNJSD.js +0 -1267
- package/dist/plugin-D60XNJSD.js.map +0 -1
- package/src/components/v2/Type.tsx +0 -59
- package/src/generators/v2/typeGenerator.tsx +0 -167
- package/src/generators/v2/utils.ts +0 -140
- package/src/parser.ts +0 -389
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { pascalCase } from '@internals/utils'
|
|
2
|
+
import { createProperty, createSchema, narrowSchema, transform } from '@kubb/ast'
|
|
3
|
+
import type { OperationNode, ParameterNode, SchemaNode } from '@kubb/ast/types'
|
|
4
|
+
import type { ResolverTs } from '../types.ts'
|
|
5
|
+
|
|
6
|
+
type BuildParamsSchemaOptions = {
|
|
7
|
+
params: Array<ParameterNode>
|
|
8
|
+
node: OperationNode
|
|
9
|
+
resolver: ResolverTs
|
|
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
|
+
* The ref name includes the parameter location so generated type names follow
|
|
16
|
+
* the `<OperationId><Location><ParamName>` convention.
|
|
17
|
+
*/
|
|
18
|
+
export function buildParamsSchema({ params, node, resolver }: BuildParamsSchemaOptions): SchemaNode {
|
|
19
|
+
return createSchema({
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: params.map((param) =>
|
|
22
|
+
createProperty({
|
|
23
|
+
name: param.name,
|
|
24
|
+
schema: createSchema({
|
|
25
|
+
type: 'ref',
|
|
26
|
+
name: resolver.resolveParamName(node, param),
|
|
27
|
+
optional: !param.required,
|
|
28
|
+
}),
|
|
29
|
+
}),
|
|
30
|
+
),
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type BuildOperationSchemaOptions = {
|
|
35
|
+
node: OperationNode
|
|
36
|
+
resolver: ResolverTs
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Builds an `ObjectSchemaNode` representing the `<OperationId>RequestConfig` type:
|
|
41
|
+
* - `data` → request body ref (optional) or `never`
|
|
42
|
+
* - `pathParams` → inline object of path param refs, or `never`
|
|
43
|
+
* - `queryParams` → inline object of query param refs (optional), or `never`
|
|
44
|
+
* - `headerParams` → inline object of header param refs (optional), or `never`
|
|
45
|
+
* - `url` → Express-style template literal (plugin-ts extension, handled by printer)
|
|
46
|
+
*/
|
|
47
|
+
export function buildDataSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode {
|
|
48
|
+
const pathParams = node.parameters.filter((p) => p.in === 'path')
|
|
49
|
+
const queryParams = node.parameters.filter((p) => p.in === 'query')
|
|
50
|
+
const headerParams = node.parameters.filter((p) => p.in === 'header')
|
|
51
|
+
|
|
52
|
+
return createSchema({
|
|
53
|
+
type: 'object',
|
|
54
|
+
deprecated: node.deprecated,
|
|
55
|
+
properties: [
|
|
56
|
+
createProperty({
|
|
57
|
+
name: 'data',
|
|
58
|
+
schema: node.requestBody?.schema
|
|
59
|
+
? createSchema({
|
|
60
|
+
type: 'ref',
|
|
61
|
+
name: resolver.resolveDataTypedName(node),
|
|
62
|
+
optional: true,
|
|
63
|
+
})
|
|
64
|
+
: createSchema({ type: 'never', optional: true }),
|
|
65
|
+
}),
|
|
66
|
+
createProperty({
|
|
67
|
+
name: 'pathParams',
|
|
68
|
+
schema: pathParams.length > 0 ? buildParamsSchema({ params: pathParams, node, resolver }) : createSchema({ type: 'never', optional: true }),
|
|
69
|
+
}),
|
|
70
|
+
createProperty({
|
|
71
|
+
name: 'queryParams',
|
|
72
|
+
schema:
|
|
73
|
+
queryParams.length > 0
|
|
74
|
+
? createSchema({ ...buildParamsSchema({ params: queryParams, node, resolver }), 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, node, resolver }), 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
|
+
* Numeric status codes produce unquoted numeric keys (e.g. `200:`).
|
|
95
|
+
* All responses are included; those without a schema are represented as a ref to a `never` type.
|
|
96
|
+
*/
|
|
97
|
+
export function buildResponsesSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode | null {
|
|
98
|
+
if (node.responses.length === 0) {
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return createSchema({
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: node.responses.map((res) =>
|
|
105
|
+
createProperty({
|
|
106
|
+
name: String(res.statusCode),
|
|
107
|
+
schema: createSchema({
|
|
108
|
+
type: 'ref',
|
|
109
|
+
name: resolver.resolveResponseStatusTypedName(node, res.statusCode),
|
|
110
|
+
}),
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Builds a `UnionSchemaNode` representing `<OperationId>Response` — all response types in union format.
|
|
118
|
+
* Returns `null` when the operation has no responses with schemas.
|
|
119
|
+
*/
|
|
120
|
+
export function buildResponseUnionSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode | null {
|
|
121
|
+
const responsesWithSchema = node.responses.filter((res) => res.schema)
|
|
122
|
+
|
|
123
|
+
if (responsesWithSchema.length === 0) {
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return createSchema({
|
|
128
|
+
type: 'union',
|
|
129
|
+
members: responsesWithSchema.map((res) =>
|
|
130
|
+
createSchema({
|
|
131
|
+
type: 'ref',
|
|
132
|
+
name: resolver.resolveResponseStatusTypedName(node, res.statusCode),
|
|
133
|
+
}),
|
|
134
|
+
),
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
type BuildGroupedParamsSchemaOptions = {
|
|
139
|
+
params: Array<ParameterNode>
|
|
140
|
+
/**
|
|
141
|
+
* Parent type name (e.g. `FindPetsByStatusQueryParams`) used to derive enum names
|
|
142
|
+
* for inline enum properties (e.g. `FindPetsByStatusQueryParamsStatusEnum`).
|
|
143
|
+
*/
|
|
144
|
+
parentName?: string
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Builds an `ObjectSchemaNode` for a grouped parameters type (path/query/header) in legacy mode.
|
|
149
|
+
* Each property directly embeds the parameter's schema inline (not a ref).
|
|
150
|
+
* Used to generate `<OperationId>PathParams`, `<OperationId>QueryParams`, `<OperationId>HeaderParams`.
|
|
151
|
+
* @deprecated Legacy only — will be removed in v6.
|
|
152
|
+
*/
|
|
153
|
+
export function buildGroupedParamsSchema({ params, parentName }: BuildGroupedParamsSchemaOptions): SchemaNode {
|
|
154
|
+
return createSchema({
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: params.map((param) => {
|
|
157
|
+
let schema = { ...param.schema, optional: !param.required } as SchemaNode
|
|
158
|
+
// Name unnamed enum properties so they are emitted as enum declarations
|
|
159
|
+
if (narrowSchema(schema, 'enum') && !schema.name && parentName) {
|
|
160
|
+
schema = { ...schema, name: pascalCase([parentName, param.name, 'enum'].join(' ')) }
|
|
161
|
+
}
|
|
162
|
+
return createProperty({
|
|
163
|
+
name: param.name,
|
|
164
|
+
schema,
|
|
165
|
+
})
|
|
166
|
+
}),
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Builds the legacy wrapper `ObjectSchemaNode` for `<OperationId>Mutation` / `<OperationId>Query`.
|
|
172
|
+
* Structure: `{ Response, Request?, QueryParams?, PathParams?, HeaderParams?, Errors }`.
|
|
173
|
+
* Mirrors the v4 naming convention where this type acts as a namespace for the operation's shapes.
|
|
174
|
+
*
|
|
175
|
+
* @deprecated Legacy only — will be removed in v6.
|
|
176
|
+
*/
|
|
177
|
+
export function buildLegacyResponsesSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode | null {
|
|
178
|
+
const isGet = node.method.toLowerCase() === 'get'
|
|
179
|
+
const successResponses = node.responses.filter((res) => {
|
|
180
|
+
const code = Number(res.statusCode)
|
|
181
|
+
return !Number.isNaN(code) && code >= 200 && code < 300
|
|
182
|
+
})
|
|
183
|
+
const errorResponses = node.responses.filter((res) => res.statusCode === 'default' || Number(res.statusCode) >= 400)
|
|
184
|
+
|
|
185
|
+
const responseSchema =
|
|
186
|
+
successResponses.length > 0
|
|
187
|
+
? successResponses.length === 1
|
|
188
|
+
? createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, successResponses[0]!.statusCode) })
|
|
189
|
+
: createSchema({
|
|
190
|
+
type: 'union',
|
|
191
|
+
members: successResponses.map((res) => createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, res.statusCode) })),
|
|
192
|
+
})
|
|
193
|
+
: createSchema({ type: 'any' })
|
|
194
|
+
|
|
195
|
+
const errorsSchema =
|
|
196
|
+
errorResponses.length > 0
|
|
197
|
+
? errorResponses.length === 1
|
|
198
|
+
? createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, errorResponses[0]!.statusCode) })
|
|
199
|
+
: createSchema({
|
|
200
|
+
type: 'union',
|
|
201
|
+
members: errorResponses.map((res) => createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, res.statusCode) })),
|
|
202
|
+
})
|
|
203
|
+
: createSchema({ type: 'any' })
|
|
204
|
+
|
|
205
|
+
const properties = [createProperty({ name: 'Response', schema: responseSchema })]
|
|
206
|
+
|
|
207
|
+
if (!isGet && node.requestBody?.schema) {
|
|
208
|
+
properties.push(
|
|
209
|
+
createProperty({
|
|
210
|
+
name: 'Request',
|
|
211
|
+
schema: createSchema({ type: 'ref', name: resolver.resolveDataTypedName(node) }),
|
|
212
|
+
}),
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (node.parameters.some((p) => p.in === 'query') && resolver.resolveQueryParamsTypedName) {
|
|
217
|
+
properties.push(
|
|
218
|
+
createProperty({
|
|
219
|
+
name: 'QueryParams',
|
|
220
|
+
schema: createSchema({ type: 'ref', name: resolver.resolveQueryParamsTypedName(node) }),
|
|
221
|
+
}),
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (node.parameters.some((p) => p.in === 'path') && resolver.resolvePathParamsTypedName) {
|
|
226
|
+
properties.push(
|
|
227
|
+
createProperty({
|
|
228
|
+
name: 'PathParams',
|
|
229
|
+
schema: createSchema({ type: 'ref', name: resolver.resolvePathParamsTypedName(node) }),
|
|
230
|
+
}),
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (node.parameters.some((p) => p.in === 'header') && resolver.resolveHeaderParamsTypedName) {
|
|
235
|
+
properties.push(
|
|
236
|
+
createProperty({
|
|
237
|
+
name: 'HeaderParams',
|
|
238
|
+
schema: createSchema({ type: 'ref', name: resolver.resolveHeaderParamsTypedName(node) }),
|
|
239
|
+
}),
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
properties.push(createProperty({ name: 'Errors', schema: errorsSchema }))
|
|
244
|
+
|
|
245
|
+
return createSchema({ type: 'object', properties })
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Builds the legacy response union for `<OperationId>MutationResponse` / `<OperationId>QueryResponse`.
|
|
250
|
+
* In legacy mode this is the **success** response only (not the full union including errors).
|
|
251
|
+
* Returns an `any` schema when there is no success response, matching v4 behavior.
|
|
252
|
+
* @deprecated Legacy only — will be removed in v6.
|
|
253
|
+
*/
|
|
254
|
+
export function buildLegacyResponseUnionSchemaNode({ node, resolver }: BuildOperationSchemaOptions): SchemaNode {
|
|
255
|
+
const successResponses = node.responses.filter((res) => {
|
|
256
|
+
const code = Number(res.statusCode)
|
|
257
|
+
return !Number.isNaN(code) && code >= 200 && code < 300
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
if (successResponses.length === 0) {
|
|
261
|
+
return createSchema({ type: 'any' })
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (successResponses.length === 1) {
|
|
265
|
+
return createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, successResponses[0]!.statusCode) })
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return createSchema({
|
|
269
|
+
type: 'union',
|
|
270
|
+
members: successResponses.map((res) => createSchema({ type: 'ref', name: resolver.resolveResponseStatusTypedName(node, res.statusCode) })),
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Names unnamed enum nodes within a schema tree based on the parent type name.
|
|
276
|
+
* Used in legacy mode to ensure inline enums in response/request schemas get
|
|
277
|
+
* extracted as named enum declarations (e.g. `DeletePet200Enum`).
|
|
278
|
+
*
|
|
279
|
+
* @deprecated Legacy only — will be removed in v6.
|
|
280
|
+
*/
|
|
281
|
+
export function nameUnnamedEnums(node: SchemaNode, parentName: string): SchemaNode {
|
|
282
|
+
return transform(node, {
|
|
283
|
+
schema(n) {
|
|
284
|
+
if (n.type === 'enum' && !n.name) {
|
|
285
|
+
return { ...n, name: pascalCase([parentName, 'enum'].join(' ')) }
|
|
286
|
+
}
|
|
287
|
+
return undefined
|
|
288
|
+
},
|
|
289
|
+
property(p) {
|
|
290
|
+
const enumNode = narrowSchema(p.schema, 'enum')
|
|
291
|
+
if (enumNode && !enumNode.name) {
|
|
292
|
+
return {
|
|
293
|
+
...p,
|
|
294
|
+
schema: { ...enumNode, name: pascalCase([parentName, p.name, 'enum'].join(' ')) },
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return undefined
|
|
298
|
+
},
|
|
299
|
+
})
|
|
300
|
+
}
|
package/src/index.ts
CHANGED
package/src/plugin.ts
CHANGED
|
@@ -2,9 +2,8 @@ import path from 'node:path'
|
|
|
2
2
|
import { camelCase } from '@internals/utils'
|
|
3
3
|
import { walk } from '@kubb/ast'
|
|
4
4
|
import { createPlugin, type Group, getBarrelFiles, getMode, renderOperation, renderSchema } from '@kubb/core'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { resolverTs } from './resolverTs.ts'
|
|
5
|
+
import { typeGenerator } from './generators/index.ts'
|
|
6
|
+
import { resolverTs, resolverTsLegacy } from './resolvers/index.ts'
|
|
8
7
|
import type { PluginTs } from './types.ts'
|
|
9
8
|
|
|
10
9
|
export const pluginTsName = 'plugin-ts' satisfies PluginTs['name']
|
|
@@ -18,45 +17,50 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
18
17
|
override = [],
|
|
19
18
|
enumType = 'asConst',
|
|
20
19
|
enumKeyCasing = 'none',
|
|
21
|
-
enumSuffix = 'enum',
|
|
22
|
-
dateType = 'string',
|
|
23
|
-
integerType = 'number',
|
|
24
|
-
unknownType = 'any',
|
|
25
20
|
optionalType = 'questionToken',
|
|
26
21
|
arrayType = 'array',
|
|
27
|
-
emptySchemaType = unknownType,
|
|
28
22
|
syntaxType = 'type',
|
|
29
23
|
transformers = {},
|
|
30
24
|
paramsCasing,
|
|
31
|
-
generators = [typeGenerator
|
|
32
|
-
|
|
33
|
-
UNSTABLE_NAMING,
|
|
25
|
+
generators = [typeGenerator].filter(Boolean),
|
|
26
|
+
legacy = false,
|
|
34
27
|
} = options
|
|
35
28
|
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const baseResolver = legacy ? resolverTsLegacy : resolverTs
|
|
30
|
+
|
|
31
|
+
// When a `transformers.name` callback is provided, wrap the resolver so that
|
|
32
|
+
// every name produced by `default()` (and therefore by every helper that calls
|
|
33
|
+
// `this.default(...)`) flows through the user's transformer.
|
|
34
|
+
const resolver: typeof baseResolver = transformers?.name
|
|
35
|
+
? {
|
|
36
|
+
...baseResolver,
|
|
37
|
+
default(name, type) {
|
|
38
|
+
const resolved = baseResolver.default(name, type)
|
|
39
|
+
|
|
40
|
+
return transformers.name!(resolved, type) || resolved
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
: baseResolver
|
|
44
|
+
|
|
45
|
+
let resolveNameWarning = false
|
|
38
46
|
|
|
39
47
|
return {
|
|
40
48
|
name: pluginTsName,
|
|
41
49
|
options: {
|
|
42
50
|
output,
|
|
43
51
|
transformers,
|
|
44
|
-
dateType,
|
|
45
|
-
integerType,
|
|
46
52
|
optionalType,
|
|
47
53
|
arrayType,
|
|
48
54
|
enumType,
|
|
49
55
|
enumKeyCasing,
|
|
50
|
-
enumSuffix,
|
|
51
|
-
unknownType,
|
|
52
|
-
emptySchemaType,
|
|
53
56
|
syntaxType,
|
|
54
57
|
group,
|
|
55
58
|
override,
|
|
56
59
|
paramsCasing,
|
|
57
|
-
|
|
60
|
+
legacy,
|
|
61
|
+
resolver,
|
|
62
|
+
baseResolver,
|
|
58
63
|
},
|
|
59
|
-
pre: [pluginOasName],
|
|
60
64
|
resolvePath(baseName, pathMode, options) {
|
|
61
65
|
const root = path.resolve(this.config.root, this.config.output.path)
|
|
62
66
|
const mode = pathMode ?? getMode(path.resolve(root, output.path))
|
|
@@ -92,13 +96,12 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
92
96
|
return path.resolve(root, output.path, baseName)
|
|
93
97
|
},
|
|
94
98
|
resolveName(name, type) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return transformers?.name?.(resolvedName, type) || resolvedName
|
|
99
|
+
if (!resolveNameWarning) {
|
|
100
|
+
this.driver.events.emit('warn', 'Do not use resolveName for pluginTs, use resolverTs instead')
|
|
101
|
+
resolveNameWarning = true
|
|
99
102
|
}
|
|
100
103
|
|
|
101
|
-
return
|
|
104
|
+
return resolver.default(name, type)
|
|
102
105
|
},
|
|
103
106
|
async install() {
|
|
104
107
|
const { config, fabric, plugin, adapter, rootNode, driver, openInStudio } = this
|
|
@@ -106,114 +109,66 @@ export const pluginTs = createPlugin<PluginTs>((options) => {
|
|
|
106
109
|
const root = path.resolve(config.root, config.output.path)
|
|
107
110
|
const mode = getMode(path.resolve(root, output.path))
|
|
108
111
|
|
|
109
|
-
if (adapter) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
await walk(
|
|
113
|
-
rootNode,
|
|
114
|
-
{
|
|
115
|
-
async schema(schemaNode) {
|
|
116
|
-
const writeTasks = generators.map(async (generator) => {
|
|
117
|
-
if (generator.type === 'react' && generator.version === '2') {
|
|
118
|
-
const options = resolverTs.resolveOptions(schemaNode, { options: plugin.options, exclude, include, override })
|
|
119
|
-
|
|
120
|
-
if (options === null) {
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
await renderSchema(schemaNode, {
|
|
125
|
-
options,
|
|
126
|
-
adapter,
|
|
127
|
-
config,
|
|
128
|
-
fabric,
|
|
129
|
-
Component: generator.Schema,
|
|
130
|
-
plugin,
|
|
131
|
-
driver,
|
|
132
|
-
mode,
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
await Promise.all(writeTasks)
|
|
138
|
-
},
|
|
139
|
-
async operation(operationNode) {
|
|
140
|
-
const writeTasks = generators.map(async (generator) => {
|
|
141
|
-
if (generator.type === 'react' && generator.version === '2') {
|
|
142
|
-
const options = resolverTs.resolveOptions(operationNode, { options: plugin.options, exclude, include, override })
|
|
143
|
-
|
|
144
|
-
if (options === null) {
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
await renderOperation(operationNode, {
|
|
149
|
-
options,
|
|
150
|
-
adapter,
|
|
151
|
-
config,
|
|
152
|
-
fabric,
|
|
153
|
-
Component: generator.Operation,
|
|
154
|
-
plugin,
|
|
155
|
-
driver,
|
|
156
|
-
mode,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
})
|
|
112
|
+
if (!adapter) {
|
|
113
|
+
throw new Error('Plugin cannot work without adapter being set')
|
|
114
|
+
}
|
|
160
115
|
|
|
161
|
-
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
{ depth: 'shallow' },
|
|
165
|
-
)
|
|
116
|
+
await openInStudio({ ast: true })
|
|
166
117
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
})
|
|
118
|
+
await walk(
|
|
119
|
+
rootNode,
|
|
120
|
+
{
|
|
121
|
+
async schema(schemaNode) {
|
|
122
|
+
const writeTasks = generators.map(async (generator) => {
|
|
123
|
+
if (generator.type === 'react' && generator.version === '2') {
|
|
124
|
+
const options = resolver.resolveOptions(schemaNode, { options: plugin.options, exclude, include, override })
|
|
175
125
|
|
|
176
|
-
|
|
126
|
+
if (options === null) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
177
129
|
|
|
178
|
-
|
|
179
|
-
|
|
130
|
+
await renderSchema(schemaNode, {
|
|
131
|
+
options,
|
|
132
|
+
adapter,
|
|
133
|
+
config,
|
|
134
|
+
fabric,
|
|
135
|
+
Component: generator.Schema,
|
|
136
|
+
plugin,
|
|
137
|
+
driver,
|
|
138
|
+
mode,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
})
|
|
180
142
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
oas,
|
|
188
|
-
driver: this.driver,
|
|
189
|
-
events: this.events,
|
|
190
|
-
plugin: this.plugin,
|
|
191
|
-
contentType,
|
|
192
|
-
include: undefined,
|
|
193
|
-
override,
|
|
194
|
-
mode,
|
|
195
|
-
output: output.path,
|
|
196
|
-
})
|
|
143
|
+
await Promise.all(writeTasks)
|
|
144
|
+
},
|
|
145
|
+
async operation(operationNode) {
|
|
146
|
+
const writeTasks = generators.map(async (generator) => {
|
|
147
|
+
if (generator.type === 'react' && generator.version === '2') {
|
|
148
|
+
const options = resolver.resolveOptions(operationNode, { options: plugin.options, exclude, include, override })
|
|
197
149
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
150
|
+
if (options === null) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
await renderOperation(operationNode, {
|
|
155
|
+
options,
|
|
156
|
+
adapter,
|
|
157
|
+
config,
|
|
158
|
+
fabric,
|
|
159
|
+
Component: generator.Operation,
|
|
160
|
+
plugin,
|
|
161
|
+
driver,
|
|
162
|
+
mode,
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
})
|
|
214
166
|
|
|
215
|
-
|
|
216
|
-
|
|
167
|
+
await Promise.all(writeTasks)
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{ depth: 'shallow' },
|
|
171
|
+
)
|
|
217
172
|
|
|
218
173
|
const barrelFiles = await getBarrelFiles(this.fabric.files, {
|
|
219
174
|
type: output.barrelType ?? 'named',
|
package/src/printer.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsStringEscape,
|
|
1
|
+
import { jsStringEscape, stringify } from '@internals/utils'
|
|
2
2
|
import { isPlainStringType } from '@kubb/ast'
|
|
3
3
|
import type { ArraySchemaNode, SchemaNode } from '@kubb/ast/types'
|
|
4
4
|
import type { PrinterFactoryOptions } from '@kubb/core'
|
|
@@ -6,7 +6,7 @@ import { definePrinter } from '@kubb/core'
|
|
|
6
6
|
import type ts from 'typescript'
|
|
7
7
|
import { ENUM_TYPES_WITH_KEY_SUFFIX, OPTIONAL_ADDS_QUESTION_TOKEN, OPTIONAL_ADDS_UNDEFINED } from './constants.ts'
|
|
8
8
|
import * as factory from './factory.ts'
|
|
9
|
-
import type { PluginTs } from './types.ts'
|
|
9
|
+
import type { PluginTs, ResolverTs } from './types.ts'
|
|
10
10
|
|
|
11
11
|
type TsOptions = {
|
|
12
12
|
/**
|
|
@@ -41,6 +41,10 @@ type TsOptions = {
|
|
|
41
41
|
* Forces type-alias syntax even when `syntaxType` is `'interface'`.
|
|
42
42
|
*/
|
|
43
43
|
keysToOmit?: Array<string>
|
|
44
|
+
/**
|
|
45
|
+
* Resolver used to transform raw schema names into valid TypeScript identifiers.
|
|
46
|
+
*/
|
|
47
|
+
resolver: ResolverTs
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/**
|
|
@@ -130,11 +134,14 @@ function buildPropertyType(schema: SchemaNode, baseType: ts.TypeNode, optionalTy
|
|
|
130
134
|
* Collects JSDoc annotation strings (description, deprecated, min/max, pattern, default, example, type) for a schema node.
|
|
131
135
|
*/
|
|
132
136
|
function buildPropertyJSDocComments(schema: SchemaNode): Array<string | undefined> {
|
|
137
|
+
const isArray = schema.type === 'array'
|
|
138
|
+
|
|
133
139
|
return [
|
|
134
140
|
'description' in schema && schema.description ? `@description ${jsStringEscape(schema.description)}` : undefined,
|
|
135
141
|
'deprecated' in schema && schema.deprecated ? '@deprecated' : undefined,
|
|
136
|
-
|
|
137
|
-
'
|
|
142
|
+
// minItems/maxItems on arrays should not be emitted as @minLength/@maxLength
|
|
143
|
+
!isArray && 'min' in schema && schema.min !== undefined ? `@minLength ${schema.min}` : undefined,
|
|
144
|
+
!isArray && 'max' in schema && schema.max !== undefined ? `@maxLength ${schema.max}` : undefined,
|
|
138
145
|
'pattern' in schema && schema.pattern ? `@pattern ${schema.pattern}` : undefined,
|
|
139
146
|
'default' in schema && schema.default !== undefined
|
|
140
147
|
? `@default ${'primitive' in schema && schema.primitive === 'string' ? stringify(schema.default as string) : schema.default}`
|
|
@@ -235,7 +242,14 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
235
242
|
if (!node.name) {
|
|
236
243
|
return undefined
|
|
237
244
|
}
|
|
238
|
-
|
|
245
|
+
// Parser-generated refs (with $ref) carry raw schema names that need resolving.
|
|
246
|
+
// Use the canonical name from the $ref path — node.name may have been overridden
|
|
247
|
+
// (e.g. by single-member allOf flatten using the property-derived child name).
|
|
248
|
+
// Inline refs (without $ref) from utils already carry resolved type names.
|
|
249
|
+
const refName = node.ref ? (node.ref.split('/').at(-1) ?? node.name) : node.name
|
|
250
|
+
const name = node.ref ? this.options.resolver.default(refName, 'type') : refName
|
|
251
|
+
|
|
252
|
+
return factory.createTypeReferenceNode(name, undefined)
|
|
239
253
|
},
|
|
240
254
|
enum(node) {
|
|
241
255
|
const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []
|
|
@@ -249,7 +263,7 @@ export const printerTs = definePrinter<TsPrinter>((options) => {
|
|
|
249
263
|
return factory.createUnionDeclaration({ withParentheses: true, nodes: literalNodes }) ?? undefined
|
|
250
264
|
}
|
|
251
265
|
|
|
252
|
-
const resolvedName =
|
|
266
|
+
const resolvedName = this.options.resolver.default(node.name, 'type')
|
|
253
267
|
const typeName = ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enumType) ? `${resolvedName}Key` : resolvedName
|
|
254
268
|
|
|
255
269
|
return factory.createTypeReferenceNode(typeName, undefined)
|