@kubb/plugin-client 5.0.0-beta.4 → 5.0.0-beta.56
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/README.md +39 -24
- package/dist/clients/axios.cjs +26 -4
- package/dist/clients/axios.cjs.map +1 -1
- package/dist/clients/axios.d.ts +11 -5
- package/dist/clients/axios.js +26 -4
- package/dist/clients/axios.js.map +1 -1
- package/dist/clients/fetch.cjs +77 -9
- package/dist/clients/fetch.cjs.map +1 -1
- package/dist/clients/fetch.d.ts +10 -3
- package/dist/clients/fetch.js +77 -9
- package/dist/clients/fetch.js.map +1 -1
- package/dist/index.cjs +836 -514
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +206 -105
- package/dist/index.js +833 -515
- package/dist/index.js.map +1 -1
- package/dist/templates/clients/axios.source.cjs +1 -1
- package/dist/templates/clients/axios.source.cjs.map +1 -1
- package/dist/templates/clients/axios.source.d.ts +1 -1
- package/dist/templates/clients/axios.source.js +1 -1
- package/dist/templates/clients/axios.source.js.map +1 -1
- package/dist/templates/clients/fetch.source.cjs +1 -1
- package/dist/templates/clients/fetch.source.cjs.map +1 -1
- package/dist/templates/clients/fetch.source.d.ts +1 -1
- package/dist/templates/clients/fetch.source.js +1 -1
- package/dist/templates/clients/fetch.source.js.map +1 -1
- package/dist/templates/config.source.cjs.map +1 -1
- package/dist/templates/config.source.d.ts +1 -1
- package/dist/templates/config.source.js.map +1 -1
- package/package.json +14 -26
- package/src/clients/axios.ts +41 -7
- package/src/clients/fetch.ts +106 -6
- package/src/components/ClassClient.tsx +47 -24
- package/src/components/Client.tsx +100 -71
- package/src/components/StaticClassClient.tsx +47 -24
- package/src/components/Url.tsx +10 -12
- package/src/components/WrapperClient.tsx +9 -5
- package/src/functionParams.ts +8 -8
- package/src/generators/classClientGenerator.tsx +63 -51
- package/src/generators/clientGenerator.tsx +45 -48
- package/src/generators/groupedClientGenerator.tsx +12 -6
- package/src/generators/operationsGenerator.ts +47 -0
- package/src/generators/staticClassClientGenerator.tsx +57 -45
- package/src/index.ts +2 -1
- package/src/plugin.ts +30 -28
- package/src/resolvers/resolverClient.ts +32 -8
- package/src/types.ts +111 -65
- package/src/utils.ts +142 -63
- package/extension.yaml +0 -776
- package/src/components/Operations.tsx +0 -28
- package/src/generators/operationsGenerator.tsx +0 -28
- package/templates/clients/axios.ts +0 -73
- package/templates/clients/fetch.ts +0 -96
- package/templates/config.ts +0 -43
- /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildOperationComments,
|
|
3
|
+
buildParamsMapping,
|
|
4
|
+
buildRequestConfigType,
|
|
5
|
+
getContentTypeInfo,
|
|
6
|
+
getOperationParameters,
|
|
7
|
+
getResponseType,
|
|
8
|
+
resolveSuccessNames,
|
|
9
|
+
} from '@internals/shared'
|
|
10
|
+
import { isValidVarName, Url } from '@internals/utils'
|
|
11
|
+
import { stringify } from '@kubb/ast/utils'
|
|
2
12
|
import { ast } from '@kubb/core'
|
|
3
13
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
4
14
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
@@ -7,8 +17,8 @@ import { File, Function } from '@kubb/renderer-jsx'
|
|
|
7
17
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
8
18
|
import { createFunctionParams } from '../functionParams.ts'
|
|
9
19
|
import type { PluginClient } from '../types.ts'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
20
|
+
import { buildStatusUnionType, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
|
|
21
|
+
import { buildUrlParamsNode } from './Url.tsx'
|
|
12
22
|
|
|
13
23
|
type Props = {
|
|
14
24
|
name: string
|
|
@@ -18,7 +28,7 @@ type Props = {
|
|
|
18
28
|
isConfigurable?: boolean
|
|
19
29
|
returnType?: string
|
|
20
30
|
|
|
21
|
-
baseURL: string | undefined
|
|
31
|
+
baseURL: string | null | undefined
|
|
22
32
|
dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
|
|
23
33
|
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
24
34
|
paramsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
@@ -26,7 +36,7 @@ type Props = {
|
|
|
26
36
|
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
27
37
|
node: ast.OperationNode
|
|
28
38
|
tsResolver: ResolverTs
|
|
29
|
-
zodResolver?: ResolverZod
|
|
39
|
+
zodResolver?: ResolverZod | null
|
|
30
40
|
children?: KubbReactNode
|
|
31
41
|
}
|
|
32
42
|
|
|
@@ -41,26 +51,33 @@ type GetParamsProps = {
|
|
|
41
51
|
|
|
42
52
|
const declarationPrinter = functionPrinter({ mode: 'declaration' })
|
|
43
53
|
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
export function buildClientParamsNode({
|
|
55
|
+
paramsType,
|
|
56
|
+
paramsCasing,
|
|
57
|
+
pathParamsType,
|
|
58
|
+
node,
|
|
59
|
+
tsResolver,
|
|
60
|
+
isConfigurable,
|
|
61
|
+
}: GetParamsProps): ast.FunctionParametersNode {
|
|
47
62
|
return ast.createOperationParams(node, {
|
|
48
63
|
paramsType,
|
|
49
64
|
pathParamsType: paramsType === 'object' ? 'object' : pathParamsType === 'object' ? 'object' : 'inline',
|
|
50
65
|
paramsCasing,
|
|
51
66
|
resolver: tsResolver,
|
|
52
|
-
extraParams:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
extraParams: [
|
|
68
|
+
...(isConfigurable
|
|
69
|
+
? [
|
|
70
|
+
ast.createFunctionParameter({
|
|
71
|
+
name: 'config',
|
|
72
|
+
type: ast.createParamsType({
|
|
73
|
+
variant: 'reference',
|
|
74
|
+
name: buildRequestConfigType(node, tsResolver),
|
|
75
|
+
}),
|
|
76
|
+
default: '{}',
|
|
59
77
|
}),
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
: [],
|
|
78
|
+
]
|
|
79
|
+
: []),
|
|
80
|
+
],
|
|
64
81
|
})
|
|
65
82
|
}
|
|
66
83
|
|
|
@@ -82,28 +99,31 @@ export function Client({
|
|
|
82
99
|
children,
|
|
83
100
|
isConfigurable = true,
|
|
84
101
|
}: Props): KubbReactNode {
|
|
85
|
-
|
|
86
|
-
const contentType = node
|
|
87
|
-
const isFormData = contentType === 'multipart/form-data'
|
|
102
|
+
if (!ast.isHttpOperationNode(node)) return null
|
|
103
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
|
|
104
|
+
const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
|
|
105
|
+
const responseType = getResponseType(node)
|
|
88
106
|
|
|
89
|
-
const originalPathParams
|
|
90
|
-
const casedPathParams =
|
|
91
|
-
const originalQueryParams = node.parameters.filter((p) => p.in === 'query')
|
|
92
|
-
const casedQueryParams = ast.caseParams(originalQueryParams, paramsCasing)
|
|
93
|
-
const originalHeaderParams = node.parameters.filter((p) => p.in === 'header')
|
|
94
|
-
const casedHeaderParams = ast.caseParams(originalHeaderParams, paramsCasing)
|
|
107
|
+
const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node)
|
|
108
|
+
const { path: casedPathParams, query: casedQueryParams, header: casedHeaderParams } = getOperationParameters(node, { paramsCasing })
|
|
95
109
|
|
|
96
|
-
const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) :
|
|
97
|
-
const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) :
|
|
98
|
-
const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) :
|
|
110
|
+
const pathParamsMapping = paramsCasing && !urlName ? buildParamsMapping(originalPathParams, casedPathParams) : null
|
|
111
|
+
const queryParamsMapping = paramsCasing ? buildParamsMapping(originalQueryParams, casedQueryParams) : null
|
|
112
|
+
const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : null
|
|
99
113
|
|
|
100
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) :
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
const
|
|
114
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
|
|
115
|
+
const successNames = resolveSuccessNames(node, tsResolver)
|
|
116
|
+
const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
|
|
117
|
+
const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]!) : null
|
|
118
|
+
const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]!) : null
|
|
104
119
|
|
|
105
|
-
const
|
|
106
|
-
const
|
|
120
|
+
const requestParser = resolveRequestParser(parser)
|
|
121
|
+
const responseParser = resolveResponseParser(parser)
|
|
122
|
+
const zodResponseName = zodResolver && responseParser === 'zod' ? zodResolver.resolveResponseName?.(node) : null
|
|
123
|
+
const zodRequestName = zodResolver && requestParser === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null
|
|
124
|
+
const queryParamsParser = resolveQueryParamsParser(parser)
|
|
125
|
+
const zodQueryParamsName =
|
|
126
|
+
zodResolver && queryParamsParser === 'zod' && originalQueryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, originalQueryParams[0]!) : null
|
|
107
127
|
|
|
108
128
|
const errorNames = node.responses
|
|
109
129
|
.filter((r) => {
|
|
@@ -113,14 +133,18 @@ export function Client({
|
|
|
113
133
|
.map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
|
|
114
134
|
|
|
115
135
|
const headers = [
|
|
116
|
-
contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` :
|
|
117
|
-
headerParamsName ? (headerParamsMapping ? '...mappedHeaders' : '...headers') :
|
|
136
|
+
!isMultipleContentTypes && contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : null,
|
|
137
|
+
headerParamsName ? (headerParamsMapping ? '...mappedHeaders' : '...headers') : null,
|
|
118
138
|
].filter(Boolean)
|
|
119
139
|
|
|
120
140
|
const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
|
|
121
141
|
|
|
122
|
-
const
|
|
123
|
-
const
|
|
142
|
+
const allStatusNames = node.responses.map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
|
|
143
|
+
const genericsResponseName = dataReturnType === 'full' ? (allStatusNames.length > 0 ? allStatusNames.join(' | ') : responseName) : responseName
|
|
144
|
+
// z.output<> reflects the post-transform type (e.g. date coercion turns Date → string), avoiding a compile error on the generated call
|
|
145
|
+
const requestGenericType = parser === 'zod' && zodRequestName ? `z.output<typeof ${zodRequestName}>` : requestName || 'unknown'
|
|
146
|
+
const generics = [genericsResponseName, TError, requestGenericType].filter(Boolean)
|
|
147
|
+
const paramsNode = buildClientParamsNode({
|
|
124
148
|
paramsType,
|
|
125
149
|
paramsCasing,
|
|
126
150
|
pathParamsType,
|
|
@@ -130,7 +154,7 @@ export function Client({
|
|
|
130
154
|
})
|
|
131
155
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
132
156
|
|
|
133
|
-
const urlParamsNode =
|
|
157
|
+
const urlParamsNode = buildUrlParamsNode({
|
|
134
158
|
paramsType,
|
|
135
159
|
paramsCasing,
|
|
136
160
|
pathParamsType,
|
|
@@ -145,45 +169,58 @@ export function Client({
|
|
|
145
169
|
mode: 'object',
|
|
146
170
|
children: {
|
|
147
171
|
method: {
|
|
148
|
-
value:
|
|
172
|
+
value: stringify(node.method.toUpperCase()),
|
|
149
173
|
},
|
|
150
174
|
url: {
|
|
151
|
-
value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : path
|
|
175
|
+
value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : Url.toTemplateString(node.path),
|
|
152
176
|
},
|
|
153
177
|
baseURL:
|
|
154
178
|
baseURL && !urlName
|
|
155
179
|
? {
|
|
156
180
|
value: `\`${baseURL}\``,
|
|
157
181
|
}
|
|
158
|
-
:
|
|
159
|
-
params: queryParamsName ? (queryParamsMapping ? { value: 'mappedParams' } : {}) :
|
|
182
|
+
: null,
|
|
183
|
+
params: queryParamsName ? (zodQueryParamsName ? { value: 'requestParams' } : queryParamsMapping ? { value: 'mappedParams' } : {}) : null,
|
|
160
184
|
data: requestName
|
|
161
185
|
? {
|
|
162
|
-
value:
|
|
186
|
+
value:
|
|
187
|
+
isMultipleContentTypes && hasFormData
|
|
188
|
+
? "contentType === 'multipart/form-data' ? formData as FormData : requestData"
|
|
189
|
+
: isFormData
|
|
190
|
+
? 'formData as FormData'
|
|
191
|
+
: 'requestData',
|
|
163
192
|
}
|
|
164
|
-
:
|
|
193
|
+
: null,
|
|
194
|
+
contentType: isConfigurable && isMultipleContentTypes ? {} : null,
|
|
195
|
+
responseType: responseType ? { value: stringify(responseType) } : null,
|
|
165
196
|
requestConfig: isConfigurable
|
|
166
197
|
? {
|
|
167
198
|
mode: 'inlineSpread',
|
|
168
199
|
}
|
|
169
|
-
:
|
|
200
|
+
: null,
|
|
170
201
|
headers: headers.length
|
|
171
202
|
? {
|
|
172
203
|
value: isConfigurable ? `{ ${headers.join(', ')}, ...requestConfig.headers }` : `{ ${headers.join(', ')} }`,
|
|
173
204
|
}
|
|
174
|
-
:
|
|
205
|
+
: null,
|
|
175
206
|
},
|
|
176
207
|
},
|
|
177
208
|
})
|
|
178
209
|
|
|
210
|
+
const statusUnionType = dataReturnType === 'full' ? buildStatusUnionType(node, tsResolver) : null
|
|
211
|
+
|
|
179
212
|
const childrenElement = children ? (
|
|
180
213
|
children
|
|
181
214
|
) : (
|
|
182
215
|
<>
|
|
183
|
-
{dataReturnType === 'full' &&
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
216
|
+
{dataReturnType === 'full' &&
|
|
217
|
+
responseParser === 'zod' &&
|
|
218
|
+
zodResponseName &&
|
|
219
|
+
statusUnionType &&
|
|
220
|
+
`return {...res, data: ${zodResponseName}.parse(res.data)} as ${statusUnionType}`}
|
|
221
|
+
{dataReturnType === 'full' && responseParser !== 'zod' && statusUnionType && `return res as ${statusUnionType}`}
|
|
222
|
+
{dataReturnType === 'data' && responseParser === 'zod' && zodResponseName && `return ${zodResponseName}.parse(res.data)`}
|
|
223
|
+
{dataReturnType === 'data' && responseParser !== 'zod' && 'return res.data'}
|
|
187
224
|
</>
|
|
188
225
|
)
|
|
189
226
|
|
|
@@ -198,31 +235,26 @@ export function Client({
|
|
|
198
235
|
export={isExportable}
|
|
199
236
|
params={paramsSignature}
|
|
200
237
|
JSDoc={{
|
|
201
|
-
comments:
|
|
238
|
+
comments: buildOperationComments(node, { link: 'urlPath', linkPosition: 'beforeDeprecated', splitLines: true }),
|
|
202
239
|
}}
|
|
203
240
|
returnType={returnType}
|
|
204
241
|
>
|
|
205
|
-
{isConfigurable
|
|
206
|
-
|
|
242
|
+
{isConfigurable
|
|
243
|
+
? `const { client: request = client, ${isMultipleContentTypes ? `contentType = ${stringify(contentType)}, ` : ''}...requestConfig } = config`
|
|
244
|
+
: ''}
|
|
207
245
|
<br />
|
|
208
246
|
{pathParamsMapping &&
|
|
209
247
|
Object.entries(pathParamsMapping)
|
|
210
248
|
.filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName)
|
|
211
249
|
.map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
|
|
212
250
|
.join('\n')}
|
|
213
|
-
{pathParamsMapping &&
|
|
214
|
-
<>
|
|
215
|
-
<br />
|
|
216
|
-
<br />
|
|
217
|
-
</>
|
|
218
|
-
)}
|
|
251
|
+
{pathParamsMapping && <br />}
|
|
219
252
|
{queryParamsMapping && queryParamsName && (
|
|
220
253
|
<>
|
|
221
254
|
{`const mappedParams = params ? { ${Object.entries(queryParamsMapping)
|
|
222
255
|
.map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`)
|
|
223
256
|
.join(', ')} } : undefined`}
|
|
224
257
|
<br />
|
|
225
|
-
<br />
|
|
226
258
|
</>
|
|
227
259
|
)}
|
|
228
260
|
{headerParamsMapping && headerParamsName && (
|
|
@@ -231,16 +263,15 @@ export function Client({
|
|
|
231
263
|
.map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`)
|
|
232
264
|
.join(', ')} } : undefined`}
|
|
233
265
|
<br />
|
|
234
|
-
<br />
|
|
235
266
|
</>
|
|
236
267
|
)}
|
|
237
|
-
{
|
|
238
|
-
|
|
239
|
-
{isFormData && requestName && 'const formData = buildFormData(requestData)'}
|
|
268
|
+
{requestParser === 'zod' && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && 'const requestData = data'}
|
|
269
|
+
{zodQueryParamsName && `const requestParams = ${zodQueryParamsName}.parse(params)`}
|
|
270
|
+
{(isFormData || (isMultipleContentTypes && hasFormData)) && requestName && 'const formData = buildFormData(requestData)'}
|
|
240
271
|
<br />
|
|
241
272
|
{isConfigurable
|
|
242
273
|
? `const res = await request<${generics.join(', ')}>(${clientParams.toCall()})`
|
|
243
|
-
: `const res = await
|
|
274
|
+
: `const res = await client<${generics.join(', ')}>(${clientParams.toCall()})`}
|
|
244
275
|
<br />
|
|
245
276
|
{childrenElement}
|
|
246
277
|
</Function>
|
|
@@ -248,5 +279,3 @@ export function Client({
|
|
|
248
279
|
</>
|
|
249
280
|
)
|
|
250
281
|
}
|
|
251
|
-
|
|
252
|
-
Client.getParams = getParams
|
|
@@ -1,19 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { buildOperationComments, getContentTypeInfo, getOperationParameters } from '@internals/shared'
|
|
2
|
+
import { Url } from '@internals/utils'
|
|
3
|
+
import { buildJSDoc, stringify } from '@kubb/ast/utils'
|
|
4
|
+
import { ast } from '@kubb/core'
|
|
3
5
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
4
6
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
5
7
|
import type { ResolverZod } from '@kubb/plugin-zod'
|
|
6
8
|
import { File } from '@kubb/renderer-jsx'
|
|
7
9
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
8
10
|
import type { PluginClient } from '../types.ts'
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
+
import {
|
|
12
|
+
buildClassClientParams,
|
|
13
|
+
buildFormDataLine,
|
|
14
|
+
buildGenerics,
|
|
15
|
+
buildHeaders,
|
|
16
|
+
buildQueryParamsLine,
|
|
17
|
+
buildRequestDataLine,
|
|
18
|
+
buildReturnStatement,
|
|
19
|
+
resolveQueryParamsParser,
|
|
20
|
+
} from '../utils.ts'
|
|
21
|
+
import { buildClientParamsNode } from './Client.tsx'
|
|
11
22
|
|
|
12
23
|
type OperationData = {
|
|
13
24
|
node: ast.OperationNode
|
|
14
25
|
name: string
|
|
15
26
|
tsResolver: ResolverTs
|
|
16
|
-
zodResolver?: ResolverZod
|
|
27
|
+
zodResolver?: ResolverZod | null
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
type Props = {
|
|
@@ -21,7 +32,7 @@ type Props = {
|
|
|
21
32
|
isExportable?: boolean
|
|
22
33
|
isIndexable?: boolean
|
|
23
34
|
operations: Array<OperationData>
|
|
24
|
-
baseURL: string | undefined
|
|
35
|
+
baseURL: string | null | undefined
|
|
25
36
|
dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
|
|
26
37
|
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
27
38
|
paramsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
@@ -34,8 +45,8 @@ type GenerateMethodProps = {
|
|
|
34
45
|
node: ast.OperationNode
|
|
35
46
|
name: string
|
|
36
47
|
tsResolver: ResolverTs
|
|
37
|
-
zodResolver?: ResolverZod
|
|
38
|
-
baseURL: string | undefined
|
|
48
|
+
zodResolver?: ResolverZod | null
|
|
49
|
+
baseURL: string | null | undefined
|
|
39
50
|
dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
|
|
40
51
|
parser: PluginClient['resolvedOptions']['parser'] | undefined
|
|
41
52
|
paramsType: PluginClient['resolvedOptions']['paramsType']
|
|
@@ -57,28 +68,41 @@ function generateMethod({
|
|
|
57
68
|
paramsCasing,
|
|
58
69
|
pathParamsType,
|
|
59
70
|
}: GenerateMethodProps): string {
|
|
60
|
-
|
|
61
|
-
const contentType = node
|
|
62
|
-
const isFormData = contentType === 'multipart/form-data'
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const generics = buildGenerics(node, tsResolver)
|
|
69
|
-
const paramsNode = Client.getParams({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable: true })
|
|
71
|
+
if (!ast.isHttpOperationNode(node)) return ''
|
|
72
|
+
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
|
|
73
|
+
const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
|
|
74
|
+
const { header: headerParams } = getOperationParameters(node)
|
|
75
|
+
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]!) : null
|
|
76
|
+
const headers = isMultipleContentTypes ? (headerParamsName ? ['...headers'] : []) : buildHeaders(contentType, !!headerParamsName)
|
|
77
|
+
const generics = buildGenerics(node, tsResolver, { dataReturnType, zodResolver, parser })
|
|
78
|
+
const paramsNode = buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable: true })
|
|
70
79
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
71
|
-
const
|
|
72
|
-
const
|
|
80
|
+
const { query: queryParams } = getOperationParameters(node)
|
|
81
|
+
const zodQueryParamsName =
|
|
82
|
+
zodResolver && resolveQueryParamsParser(parser) === 'zod' && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]!) : null
|
|
83
|
+
const clientParams = buildClassClientParams({
|
|
84
|
+
node,
|
|
85
|
+
url: Url.toTemplateString(node.path, { casing: paramsCasing }),
|
|
86
|
+
baseURL,
|
|
87
|
+
tsResolver,
|
|
88
|
+
isFormData,
|
|
89
|
+
isMultipleContentTypes,
|
|
90
|
+
hasFormData,
|
|
91
|
+
headers,
|
|
92
|
+
zodQueryParamsName,
|
|
93
|
+
})
|
|
94
|
+
const jsdoc = buildJSDoc(buildOperationComments(node, { link: 'urlPath', linkPosition: 'beforeDeprecated', splitLines: true }))
|
|
73
95
|
|
|
74
96
|
const requestDataLine = buildRequestDataLine({ parser, node, zodResolver })
|
|
75
|
-
const
|
|
76
|
-
const
|
|
97
|
+
const queryParamsLine = buildQueryParamsLine({ parser, node, zodResolver })
|
|
98
|
+
const formDataLine = buildFormDataLine(isFormData || (isMultipleContentTypes && hasFormData), !!node.requestBody?.content?.[0]?.schema)
|
|
99
|
+
const returnStatement = buildReturnStatement({ dataReturnType, parser, node, zodResolver, tsResolver })
|
|
77
100
|
|
|
78
101
|
const methodBody = [
|
|
79
|
-
|
|
102
|
+
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${stringify(contentType)}, ` : ''}...requestConfig } = mergeConfig(this.#config, config)`,
|
|
80
103
|
'',
|
|
81
104
|
requestDataLine,
|
|
105
|
+
queryParamsLine,
|
|
82
106
|
formDataLine,
|
|
83
107
|
`const res = await request<${generics.join(', ')}>(${clientParams.toCall()})`,
|
|
84
108
|
returnStatement,
|
|
@@ -127,4 +151,3 @@ export function StaticClassClient({
|
|
|
127
151
|
</File.Source>
|
|
128
152
|
)
|
|
129
153
|
}
|
|
130
|
-
StaticClassClient.getParams = Client.getParams
|
package/src/components/Url.tsx
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildParamsMapping, getOperationParameters } from '@internals/shared'
|
|
2
|
+
import { isValidVarName, Url as UrlHelper } from '@internals/utils'
|
|
2
3
|
import { ast } from '@kubb/core'
|
|
3
4
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
4
5
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
5
6
|
import { Const, File, Function } from '@kubb/renderer-jsx'
|
|
6
7
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
7
8
|
import type { PluginClient } from '../types.ts'
|
|
8
|
-
import { buildParamsMapping } from '../utils.ts'
|
|
9
9
|
|
|
10
10
|
type Props = {
|
|
11
11
|
name: string
|
|
12
12
|
isExportable?: boolean
|
|
13
13
|
isIndexable?: boolean
|
|
14
14
|
|
|
15
|
-
baseURL: string | undefined
|
|
15
|
+
baseURL: string | null | undefined
|
|
16
16
|
paramsCasing: PluginClient['resolvedOptions']['paramsCasing']
|
|
17
17
|
paramsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
18
18
|
pathParamsType: PluginClient['resolvedOptions']['pathParamsType']
|
|
@@ -30,7 +30,7 @@ type GetParamsProps = {
|
|
|
30
30
|
|
|
31
31
|
const declarationPrinter = functionPrinter({ mode: 'declaration' })
|
|
32
32
|
|
|
33
|
-
function
|
|
33
|
+
export function buildUrlParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver }: GetParamsProps): ast.FunctionParametersNode {
|
|
34
34
|
// Build a URL-only node with only path params (no body, query, header)
|
|
35
35
|
const urlNode: ast.OperationNode = {
|
|
36
36
|
...node,
|
|
@@ -57,9 +57,9 @@ export function Url({
|
|
|
57
57
|
node,
|
|
58
58
|
tsResolver,
|
|
59
59
|
}: Props): KubbReactNode {
|
|
60
|
-
|
|
60
|
+
if (!ast.isHttpOperationNode(node)) return null
|
|
61
61
|
|
|
62
|
-
const paramsNode =
|
|
62
|
+
const paramsNode = buildUrlParamsNode({
|
|
63
63
|
paramsType,
|
|
64
64
|
paramsCasing,
|
|
65
65
|
pathParamsType,
|
|
@@ -68,9 +68,9 @@ export function Url({
|
|
|
68
68
|
})
|
|
69
69
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
70
70
|
|
|
71
|
-
const originalPathParams = node
|
|
72
|
-
const casedPathParams =
|
|
73
|
-
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) :
|
|
71
|
+
const { path: originalPathParams } = getOperationParameters(node)
|
|
72
|
+
const { path: casedPathParams } = getOperationParameters(node, { paramsCasing })
|
|
73
|
+
const pathParamsMapping = paramsCasing ? buildParamsMapping(originalPathParams, casedPathParams) : null
|
|
74
74
|
|
|
75
75
|
return (
|
|
76
76
|
<File.Source name={name} isExportable={isExportable} isIndexable={isIndexable}>
|
|
@@ -81,12 +81,10 @@ export function Url({
|
|
|
81
81
|
.map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
|
|
82
82
|
.join('\n')}
|
|
83
83
|
{pathParamsMapping && Object.keys(pathParamsMapping).length > 0 && <br />}
|
|
84
|
-
<Const name={'res'}>{`{ method: '${node.method.toUpperCase()}', url: ${
|
|
84
|
+
<Const name={'res'}>{`{ method: '${node.method.toUpperCase()}', url: ${UrlHelper.toTemplateString(node.path, { prefix: baseURL })} as const }`}</Const>
|
|
85
85
|
<br />
|
|
86
86
|
return res
|
|
87
87
|
</Function>
|
|
88
88
|
</File.Source>
|
|
89
89
|
)
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
Url.getParams = getParams
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import { camelCase } from '@internals/utils'
|
|
2
1
|
import { File } from '@kubb/renderer-jsx'
|
|
3
2
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
4
3
|
|
|
4
|
+
type ClientController = {
|
|
5
|
+
className: string
|
|
6
|
+
propertyName: string
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
type Props = {
|
|
6
10
|
name: string
|
|
7
|
-
|
|
11
|
+
controllers: Array<ClientController>
|
|
8
12
|
isExportable?: boolean
|
|
9
13
|
isIndexable?: boolean
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
export function WrapperClient({ name,
|
|
13
|
-
const properties =
|
|
14
|
-
const assignments =
|
|
16
|
+
export function WrapperClient({ name, controllers, isExportable = true, isIndexable = true }: Props): KubbReactNode {
|
|
17
|
+
const properties = controllers.map(({ className, propertyName }) => ` readonly ${propertyName}: ${className}`).join('\n')
|
|
18
|
+
const assignments = controllers.map(({ className, propertyName }) => ` this.${propertyName} = new ${className}(config)`).join('\n')
|
|
15
19
|
|
|
16
20
|
const classCode = `export class ${name} {
|
|
17
21
|
${properties}
|
package/src/functionParams.ts
CHANGED
|
@@ -11,7 +11,7 @@ type ParamLeaf = {
|
|
|
11
11
|
|
|
12
12
|
type ParamGroup = {
|
|
13
13
|
mode: 'object' | 'inlineSpread'
|
|
14
|
-
children: Record<string, ParamLeaf | undefined>
|
|
14
|
+
children: Record<string, ParamLeaf | null | undefined>
|
|
15
15
|
default?: string
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -25,14 +25,14 @@ function isGroup(spec: ParamSpec): spec is ParamGroup {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function createType(type?: string) {
|
|
28
|
-
return type ? ast.createParamsType({ variant: 'reference', name: type }) :
|
|
28
|
+
return type ? ast.createParamsType({ variant: 'reference', name: type }) : null
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function createDeclarationLeaf(name: string, spec: ParamLeaf): ast.FunctionParameterNode {
|
|
32
32
|
if (spec.default !== undefined) {
|
|
33
33
|
return ast.createFunctionParameter({
|
|
34
34
|
name,
|
|
35
|
-
type: createType(spec.type),
|
|
35
|
+
type: createType(spec.type) ?? undefined,
|
|
36
36
|
default: spec.default,
|
|
37
37
|
rest: spec.mode === 'inlineSpread',
|
|
38
38
|
})
|
|
@@ -40,7 +40,7 @@ function createDeclarationLeaf(name: string, spec: ParamLeaf): ast.FunctionParam
|
|
|
40
40
|
|
|
41
41
|
return ast.createFunctionParameter({
|
|
42
42
|
name,
|
|
43
|
-
type: createType(spec.type),
|
|
43
|
+
type: createType(spec.type) ?? undefined,
|
|
44
44
|
optional: !!spec.optional,
|
|
45
45
|
rest: spec.mode === 'inlineSpread',
|
|
46
46
|
})
|
|
@@ -52,7 +52,7 @@ function createDeclarationParam(name: string, spec: ParamSpec): ast.FunctionPara
|
|
|
52
52
|
inline: spec.mode === 'inlineSpread',
|
|
53
53
|
default: spec.default,
|
|
54
54
|
properties: Object.entries(spec.children)
|
|
55
|
-
.filter(([, child]) => child
|
|
55
|
+
.filter(([, child]) => child != null)
|
|
56
56
|
.map(([childName, child]) => createDeclarationLeaf(childName, child!)),
|
|
57
57
|
})
|
|
58
58
|
}
|
|
@@ -65,7 +65,7 @@ function createCallParam(name: string, spec: ParamSpec): ast.FunctionParameterNo
|
|
|
65
65
|
return ast.createParameterGroup({
|
|
66
66
|
inline: spec.mode === 'inlineSpread',
|
|
67
67
|
properties: Object.entries(spec.children)
|
|
68
|
-
.filter(([, child]) => child
|
|
68
|
+
.filter(([, child]) => child != null)
|
|
69
69
|
.map(([childName, child]) =>
|
|
70
70
|
ast.createFunctionParameter({
|
|
71
71
|
name:
|
|
@@ -92,8 +92,8 @@ function createCallParam(name: string, spec: ParamSpec): ast.FunctionParameterNo
|
|
|
92
92
|
* Creates function parameter builders for generating function signatures and calls.
|
|
93
93
|
* Returns utilities to output constructor signatures (`toConstructor()`) or call expressions (`toCall()`).
|
|
94
94
|
*/
|
|
95
|
-
export function createFunctionParams(params: Record<string, ParamSpec | undefined>) {
|
|
96
|
-
const entries = Object.entries(params).filter(([, spec]) => spec
|
|
95
|
+
export function createFunctionParams(params: Record<string, ParamSpec | null | undefined>) {
|
|
96
|
+
const entries = Object.entries(params).filter(([, spec]) => spec != null) as Array<[string, ParamSpec]>
|
|
97
97
|
|
|
98
98
|
return {
|
|
99
99
|
toConstructor() {
|