@kubb/plugin-client 5.0.0-beta.42 → 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/dist/clients/axios.cjs.map +1 -1
- package/dist/clients/axios.js.map +1 -1
- package/dist/clients/fetch.cjs.map +1 -1
- package/dist/clients/fetch.js.map +1 -1
- package/dist/index.cjs +393 -342
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +57 -22
- package/dist/index.js +389 -342
- package/dist/index.js.map +1 -1
- package/dist/templates/clients/axios.source.cjs.map +1 -1
- package/dist/templates/clients/axios.source.js.map +1 -1
- package/dist/templates/clients/fetch.source.cjs.map +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.js.map +1 -1
- package/package.json +10 -17
- package/src/components/ClassClient.tsx +31 -7
- package/src/components/Client.tsx +33 -25
- package/src/components/StaticClassClient.tsx +31 -7
- package/src/components/Url.tsx +2 -3
- package/src/generators/classClientGenerator.tsx +20 -12
- package/src/generators/clientGenerator.tsx +18 -10
- package/src/generators/groupedClientGenerator.tsx +2 -2
- package/src/generators/operationsGenerator.ts +47 -0
- package/src/generators/staticClassClientGenerator.tsx +20 -12
- package/src/index.ts +2 -1
- package/src/plugin.ts +5 -4
- package/src/resolvers/resolverClient.ts +5 -4
- package/src/types.ts +29 -21
- package/src/utils.ts +122 -22
- package/extension.yaml +0 -1267
- package/src/components/Operations.tsx +0 -29
- package/src/generators/operationsGenerator.tsx +0 -34
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"axios.source.cjs","names":[],"sources":[
|
|
1
|
+
{"version":3,"file":"axios.source.cjs","names":[],"sources":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"axios.source.js","names":[],"sources":[
|
|
1
|
+
{"version":3,"file":"axios.source.js","names":[],"sources":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.source.cjs","names":[],"sources":[
|
|
1
|
+
{"version":3,"file":"fetch.source.cjs","names":[],"sources":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.source.js","names":[],"sources":[
|
|
1
|
+
{"version":3,"file":"fetch.source.js","names":[],"sources":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.source.cjs","names":[],"sources":[
|
|
1
|
+
{"version":3,"file":"config.source.cjs","names":[],"sources":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.source.js","names":[],"sources":[
|
|
1
|
+
{"version":3,"file":"config.source.js","names":[],"sources":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-client",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.56",
|
|
4
4
|
"description": "Generate type-safe HTTP clients from your OpenAPI specification. Supports Axios, Fetch, and custom client adapters with full TypeScript inference and zero boilerplate.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"files": [
|
|
25
25
|
"src",
|
|
26
26
|
"dist",
|
|
27
|
-
"extension.yaml",
|
|
28
27
|
"*.d.ts",
|
|
29
28
|
"*.d.cts",
|
|
30
29
|
"!/**/**.test.**",
|
|
@@ -87,18 +86,19 @@
|
|
|
87
86
|
"registry": "https://registry.npmjs.org/"
|
|
88
87
|
},
|
|
89
88
|
"dependencies": {
|
|
90
|
-
"@kubb/
|
|
91
|
-
"@kubb/
|
|
92
|
-
"@kubb/
|
|
93
|
-
"@kubb/plugin-
|
|
89
|
+
"@kubb/ast": "5.0.0-beta.55",
|
|
90
|
+
"@kubb/core": "5.0.0-beta.55",
|
|
91
|
+
"@kubb/renderer-jsx": "5.0.0-beta.55",
|
|
92
|
+
"@kubb/plugin-ts": "5.0.0-beta.56",
|
|
93
|
+
"@kubb/plugin-zod": "5.0.0-beta.56"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
|
-
"axios": "^1.
|
|
96
|
+
"axios": "^1.17.0",
|
|
97
97
|
"@internals/shared": "0.0.0",
|
|
98
98
|
"@internals/utils": "0.0.0"
|
|
99
99
|
},
|
|
100
100
|
"peerDependencies": {
|
|
101
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
101
|
+
"@kubb/renderer-jsx": "5.0.0-beta.55",
|
|
102
102
|
"axios": "^1.7.2"
|
|
103
103
|
},
|
|
104
104
|
"peerDependenciesMeta": {
|
|
@@ -106,19 +106,12 @@
|
|
|
106
106
|
"optional": true
|
|
107
107
|
}
|
|
108
108
|
},
|
|
109
|
-
"size-limit": [
|
|
110
|
-
{
|
|
111
|
-
"path": "./dist/*.js",
|
|
112
|
-
"limit": "510 KiB",
|
|
113
|
-
"gzip": true
|
|
114
|
-
}
|
|
115
|
-
],
|
|
116
109
|
"engines": {
|
|
117
110
|
"node": ">=22"
|
|
118
111
|
},
|
|
119
112
|
"scripts": {
|
|
120
|
-
"build": "tsdown
|
|
121
|
-
"clean": "
|
|
113
|
+
"build": "tsdown",
|
|
114
|
+
"clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
|
|
122
115
|
"lint": "oxlint .",
|
|
123
116
|
"lint:fix": "oxlint --fix .",
|
|
124
117
|
"release": "pnpm publish --no-git-check",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildOperationComments, getContentTypeInfo, getOperationParameters } from '@internals/shared'
|
|
2
|
-
import {
|
|
2
|
+
import { Url } from '@internals/utils'
|
|
3
|
+
import { buildJSDoc, stringify } from '@kubb/ast/utils'
|
|
3
4
|
import { ast } from '@kubb/core'
|
|
4
5
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
5
6
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
@@ -7,7 +8,16 @@ import type { ResolverZod } from '@kubb/plugin-zod'
|
|
|
7
8
|
import { File } from '@kubb/renderer-jsx'
|
|
8
9
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
9
10
|
import type { PluginClient } from '../types.ts'
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
buildClassClientParams,
|
|
13
|
+
buildFormDataLine,
|
|
14
|
+
buildGenerics,
|
|
15
|
+
buildHeaders,
|
|
16
|
+
buildQueryParamsLine,
|
|
17
|
+
buildRequestDataLine,
|
|
18
|
+
buildReturnStatement,
|
|
19
|
+
resolveQueryParamsParser,
|
|
20
|
+
} from '../utils.ts'
|
|
11
21
|
import { buildClientParamsNode } from './Client.tsx'
|
|
12
22
|
|
|
13
23
|
type OperationData = {
|
|
@@ -59,26 +69,40 @@ function generateMethod({
|
|
|
59
69
|
pathParamsType,
|
|
60
70
|
}: GenerateMethodProps): string {
|
|
61
71
|
if (!ast.isHttpOperationNode(node)) return ''
|
|
62
|
-
const path = new URLPath(node.path, { casing: paramsCasing })
|
|
63
72
|
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
|
|
64
73
|
const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
|
|
65
74
|
const { header: headerParams } = getOperationParameters(node)
|
|
66
75
|
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]!) : null
|
|
67
76
|
const headers = isMultipleContentTypes ? (headerParamsName ? ['...headers'] : []) : buildHeaders(contentType, !!headerParamsName)
|
|
68
|
-
const generics = buildGenerics(node, tsResolver)
|
|
77
|
+
const generics = buildGenerics(node, tsResolver, { dataReturnType, zodResolver, parser })
|
|
69
78
|
const paramsNode = buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable: true })
|
|
70
79
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
71
|
-
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
|
+
})
|
|
72
94
|
const jsdoc = buildJSDoc(buildOperationComments(node, { link: 'urlPath', linkPosition: 'beforeDeprecated', splitLines: true }))
|
|
73
95
|
|
|
74
96
|
const requestDataLine = buildRequestDataLine({ parser, node, zodResolver })
|
|
97
|
+
const queryParamsLine = buildQueryParamsLine({ parser, node, zodResolver })
|
|
75
98
|
const formDataLine = buildFormDataLine(isFormData || (isMultipleContentTypes && hasFormData), !!node.requestBody?.content?.[0]?.schema)
|
|
76
|
-
const returnStatement = buildReturnStatement({ dataReturnType, parser, node, zodResolver })
|
|
99
|
+
const returnStatement = buildReturnStatement({ dataReturnType, parser, node, zodResolver, tsResolver })
|
|
77
100
|
|
|
78
101
|
const methodBody = [
|
|
79
|
-
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${
|
|
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,
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
getResponseType,
|
|
8
8
|
resolveSuccessNames,
|
|
9
9
|
} from '@internals/shared'
|
|
10
|
-
import { isValidVarName,
|
|
10
|
+
import { isValidVarName, Url } from '@internals/utils'
|
|
11
|
+
import { stringify } from '@kubb/ast/utils'
|
|
11
12
|
import { ast } from '@kubb/core'
|
|
12
13
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
13
14
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
@@ -16,6 +17,7 @@ import { File, Function } from '@kubb/renderer-jsx'
|
|
|
16
17
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
17
18
|
import { createFunctionParams } from '../functionParams.ts'
|
|
18
19
|
import type { PluginClient } from '../types.ts'
|
|
20
|
+
import { buildStatusUnionType, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
|
|
19
21
|
import { buildUrlParamsNode } from './Url.tsx'
|
|
20
22
|
|
|
21
23
|
type Props = {
|
|
@@ -98,7 +100,6 @@ export function Client({
|
|
|
98
100
|
isConfigurable = true,
|
|
99
101
|
}: Props): KubbReactNode {
|
|
100
102
|
if (!ast.isHttpOperationNode(node)) return null
|
|
101
|
-
const path = new URLPath(node.path)
|
|
102
103
|
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
|
|
103
104
|
const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
|
|
104
105
|
const responseType = getResponseType(node)
|
|
@@ -116,8 +117,13 @@ export function Client({
|
|
|
116
117
|
const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]!) : null
|
|
117
118
|
const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]!) : null
|
|
118
119
|
|
|
119
|
-
const
|
|
120
|
-
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
|
|
121
127
|
|
|
122
128
|
const errorNames = node.responses
|
|
123
129
|
.filter((r) => {
|
|
@@ -133,7 +139,11 @@ export function Client({
|
|
|
133
139
|
|
|
134
140
|
const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
|
|
135
141
|
|
|
136
|
-
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)
|
|
137
147
|
const paramsNode = buildClientParamsNode({
|
|
138
148
|
paramsType,
|
|
139
149
|
paramsCasing,
|
|
@@ -159,10 +169,10 @@ export function Client({
|
|
|
159
169
|
mode: 'object',
|
|
160
170
|
children: {
|
|
161
171
|
method: {
|
|
162
|
-
value:
|
|
172
|
+
value: stringify(node.method.toUpperCase()),
|
|
163
173
|
},
|
|
164
174
|
url: {
|
|
165
|
-
value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : path
|
|
175
|
+
value: urlName ? `${urlName}(${urlParamsCall}).url.toString()` : Url.toTemplateString(node.path),
|
|
166
176
|
},
|
|
167
177
|
baseURL:
|
|
168
178
|
baseURL && !urlName
|
|
@@ -170,7 +180,7 @@ export function Client({
|
|
|
170
180
|
value: `\`${baseURL}\``,
|
|
171
181
|
}
|
|
172
182
|
: null,
|
|
173
|
-
params: queryParamsName ? (queryParamsMapping ? { value: 'mappedParams' } : {}) : null,
|
|
183
|
+
params: queryParamsName ? (zodQueryParamsName ? { value: 'requestParams' } : queryParamsMapping ? { value: 'mappedParams' } : {}) : null,
|
|
174
184
|
data: requestName
|
|
175
185
|
? {
|
|
176
186
|
value:
|
|
@@ -182,7 +192,7 @@ export function Client({
|
|
|
182
192
|
}
|
|
183
193
|
: null,
|
|
184
194
|
contentType: isConfigurable && isMultipleContentTypes ? {} : null,
|
|
185
|
-
responseType: responseType ? { value:
|
|
195
|
+
responseType: responseType ? { value: stringify(responseType) } : null,
|
|
186
196
|
requestConfig: isConfigurable
|
|
187
197
|
? {
|
|
188
198
|
mode: 'inlineSpread',
|
|
@@ -197,14 +207,20 @@ export function Client({
|
|
|
197
207
|
},
|
|
198
208
|
})
|
|
199
209
|
|
|
210
|
+
const statusUnionType = dataReturnType === 'full' ? buildStatusUnionType(node, tsResolver) : null
|
|
211
|
+
|
|
200
212
|
const childrenElement = children ? (
|
|
201
213
|
children
|
|
202
214
|
) : (
|
|
203
215
|
<>
|
|
204
|
-
{dataReturnType === 'full' &&
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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'}
|
|
208
224
|
</>
|
|
209
225
|
)
|
|
210
226
|
|
|
@@ -224,28 +240,21 @@ export function Client({
|
|
|
224
240
|
returnType={returnType}
|
|
225
241
|
>
|
|
226
242
|
{isConfigurable
|
|
227
|
-
? `const { client: request = client, ${isMultipleContentTypes ? `contentType = ${
|
|
243
|
+
? `const { client: request = client, ${isMultipleContentTypes ? `contentType = ${stringify(contentType)}, ` : ''}...requestConfig } = config`
|
|
228
244
|
: ''}
|
|
229
245
|
<br />
|
|
230
|
-
<br />
|
|
231
246
|
{pathParamsMapping &&
|
|
232
247
|
Object.entries(pathParamsMapping)
|
|
233
248
|
.filter(([originalName, camelCaseName]) => isValidVarName(originalName) && originalName !== camelCaseName)
|
|
234
249
|
.map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
|
|
235
250
|
.join('\n')}
|
|
236
|
-
{pathParamsMapping &&
|
|
237
|
-
<>
|
|
238
|
-
<br />
|
|
239
|
-
<br />
|
|
240
|
-
</>
|
|
241
|
-
)}
|
|
251
|
+
{pathParamsMapping && <br />}
|
|
242
252
|
{queryParamsMapping && queryParamsName && (
|
|
243
253
|
<>
|
|
244
254
|
{`const mappedParams = params ? { ${Object.entries(queryParamsMapping)
|
|
245
255
|
.map(([originalName, camelCaseName]) => `"${originalName}": params.${camelCaseName}`)
|
|
246
256
|
.join(', ')} } : undefined`}
|
|
247
257
|
<br />
|
|
248
|
-
<br />
|
|
249
258
|
</>
|
|
250
259
|
)}
|
|
251
260
|
{headerParamsMapping && headerParamsName && (
|
|
@@ -254,11 +263,10 @@ export function Client({
|
|
|
254
263
|
.map(([originalName, camelCaseName]) => `"${originalName}": headers.${camelCaseName}`)
|
|
255
264
|
.join(', ')} } : undefined`}
|
|
256
265
|
<br />
|
|
257
|
-
<br />
|
|
258
266
|
</>
|
|
259
267
|
)}
|
|
260
|
-
{
|
|
261
|
-
|
|
268
|
+
{requestParser === 'zod' && zodRequestName ? `const requestData = ${zodRequestName}.parse(data)` : requestName && 'const requestData = data'}
|
|
269
|
+
{zodQueryParamsName && `const requestParams = ${zodQueryParamsName}.parse(params)`}
|
|
262
270
|
{(isFormData || (isMultipleContentTypes && hasFormData)) && requestName && 'const formData = buildFormData(requestData)'}
|
|
263
271
|
<br />
|
|
264
272
|
{isConfigurable
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildOperationComments, getContentTypeInfo, getOperationParameters } from '@internals/shared'
|
|
2
|
-
import {
|
|
2
|
+
import { Url } from '@internals/utils'
|
|
3
|
+
import { buildJSDoc, stringify } from '@kubb/ast/utils'
|
|
3
4
|
import { ast } from '@kubb/core'
|
|
4
5
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
5
6
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
@@ -7,7 +8,16 @@ import type { ResolverZod } from '@kubb/plugin-zod'
|
|
|
7
8
|
import { File } from '@kubb/renderer-jsx'
|
|
8
9
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
9
10
|
import type { PluginClient } from '../types.ts'
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
buildClassClientParams,
|
|
13
|
+
buildFormDataLine,
|
|
14
|
+
buildGenerics,
|
|
15
|
+
buildHeaders,
|
|
16
|
+
buildQueryParamsLine,
|
|
17
|
+
buildRequestDataLine,
|
|
18
|
+
buildReturnStatement,
|
|
19
|
+
resolveQueryParamsParser,
|
|
20
|
+
} from '../utils.ts'
|
|
11
21
|
import { buildClientParamsNode } from './Client.tsx'
|
|
12
22
|
|
|
13
23
|
type OperationData = {
|
|
@@ -59,26 +69,40 @@ function generateMethod({
|
|
|
59
69
|
pathParamsType,
|
|
60
70
|
}: GenerateMethodProps): string {
|
|
61
71
|
if (!ast.isHttpOperationNode(node)) return ''
|
|
62
|
-
const path = new URLPath(node.path, { casing: paramsCasing })
|
|
63
72
|
const { defaultContentType: contentType, isMultipleContentTypes, hasFormData } = getContentTypeInfo(node)
|
|
64
73
|
const isFormData = !isMultipleContentTypes && contentType === 'multipart/form-data'
|
|
65
74
|
const { header: headerParams } = getOperationParameters(node)
|
|
66
75
|
const headerParamsName = headerParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, headerParams[0]!) : null
|
|
67
76
|
const headers = isMultipleContentTypes ? (headerParamsName ? ['...headers'] : []) : buildHeaders(contentType, !!headerParamsName)
|
|
68
|
-
const generics = buildGenerics(node, tsResolver)
|
|
77
|
+
const generics = buildGenerics(node, tsResolver, { dataReturnType, zodResolver, parser })
|
|
69
78
|
const paramsNode = buildClientParamsNode({ paramsType, paramsCasing, pathParamsType, node, tsResolver, isConfigurable: true })
|
|
70
79
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
71
|
-
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
|
+
})
|
|
72
94
|
const jsdoc = buildJSDoc(buildOperationComments(node, { link: 'urlPath', linkPosition: 'beforeDeprecated', splitLines: true }))
|
|
73
95
|
|
|
74
96
|
const requestDataLine = buildRequestDataLine({ parser, node, zodResolver })
|
|
97
|
+
const queryParamsLine = buildQueryParamsLine({ parser, node, zodResolver })
|
|
75
98
|
const formDataLine = buildFormDataLine(isFormData || (isMultipleContentTypes && hasFormData), !!node.requestBody?.content?.[0]?.schema)
|
|
76
|
-
const returnStatement = buildReturnStatement({ dataReturnType, parser, node, zodResolver })
|
|
99
|
+
const returnStatement = buildReturnStatement({ dataReturnType, parser, node, zodResolver, tsResolver })
|
|
77
100
|
|
|
78
101
|
const methodBody = [
|
|
79
|
-
`const { client: request = client, ${isMultipleContentTypes ? `contentType = ${
|
|
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,
|
package/src/components/Url.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildParamsMapping, getOperationParameters } from '@internals/shared'
|
|
2
|
-
import { isValidVarName,
|
|
2
|
+
import { isValidVarName, Url as UrlHelper } from '@internals/utils'
|
|
3
3
|
import { ast } from '@kubb/core'
|
|
4
4
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
5
5
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
@@ -58,7 +58,6 @@ export function Url({
|
|
|
58
58
|
tsResolver,
|
|
59
59
|
}: Props): KubbReactNode {
|
|
60
60
|
if (!ast.isHttpOperationNode(node)) return null
|
|
61
|
-
const path = new URLPath(node.path)
|
|
62
61
|
|
|
63
62
|
const paramsNode = buildUrlParamsNode({
|
|
64
63
|
paramsType,
|
|
@@ -82,7 +81,7 @@ export function Url({
|
|
|
82
81
|
.map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)
|
|
83
82
|
.join('\n')}
|
|
84
83
|
{pathParamsMapping && Object.keys(pathParamsMapping).length > 0 && <br />}
|
|
85
|
-
<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>
|
|
86
85
|
<br />
|
|
87
86
|
return res
|
|
88
87
|
</Function>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
2
|
+
import { getOperationParameters, operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
3
3
|
import { camelCase } from '@internals/utils'
|
|
4
4
|
import { ast, defineGenerator } from '@kubb/core'
|
|
5
5
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
6
6
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
7
7
|
import type { ResolverZod } from '@kubb/plugin-zod'
|
|
8
8
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
9
|
-
import { File,
|
|
9
|
+
import { File, jsxRenderer } from '@kubb/renderer-jsx'
|
|
10
10
|
import { ClassClient } from '../components/ClassClient'
|
|
11
11
|
import { WrapperClient } from '../components/WrapperClient'
|
|
12
12
|
import type { PluginClient } from '../types'
|
|
13
|
+
import { isParserEnabled, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
|
|
13
14
|
|
|
14
15
|
type OperationData = {
|
|
15
16
|
node: ast.OperationNode
|
|
@@ -31,10 +32,12 @@ function resolveTypeImportNames(node: ast.OperationNode, tsResolver: ResolverTs)
|
|
|
31
32
|
return resolveOperationTypeNames(node, tsResolver, { order: 'body-response-first' })
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod): Array<string> {
|
|
35
|
+
function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod, parser: PluginClient['resolvedOptions']['parser']): Array<string> {
|
|
36
|
+
const { query: queryParams } = getOperationParameters(node)
|
|
35
37
|
const names: Array<string | null | undefined> = [
|
|
36
|
-
zodResolver.resolveResponseName?.(node),
|
|
37
|
-
node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
38
|
+
resolveResponseParser(parser) === 'zod' ? zodResolver.resolveResponseName?.(node) : null,
|
|
39
|
+
resolveRequestParser(parser) === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
40
|
+
resolveQueryParamsParser(parser) === 'zod' && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]!) : null,
|
|
38
41
|
]
|
|
39
42
|
return names.filter((n): n is string => Boolean(n))
|
|
40
43
|
}
|
|
@@ -46,7 +49,7 @@ function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod
|
|
|
46
49
|
*/
|
|
47
50
|
export const classClientGenerator = defineGenerator<PluginClient>({
|
|
48
51
|
name: 'classClient',
|
|
49
|
-
renderer:
|
|
52
|
+
renderer: jsxRenderer,
|
|
50
53
|
operations(nodes, ctx) {
|
|
51
54
|
const { config, driver, resolver, root } = ctx
|
|
52
55
|
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, sdk } = ctx.options
|
|
@@ -57,7 +60,7 @@ export const classClientGenerator = defineGenerator<PluginClient>({
|
|
|
57
60
|
|
|
58
61
|
const tsResolver = driver.getResolver(pluginTsName)
|
|
59
62
|
const tsPluginOptions = pluginTs.options
|
|
60
|
-
const pluginZod = parser
|
|
63
|
+
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null
|
|
61
64
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
|
|
62
65
|
|
|
63
66
|
function buildOperationData(node: ast.OperationNode): OperationData {
|
|
@@ -88,7 +91,7 @@ export const classClientGenerator = defineGenerator<PluginClient>({
|
|
|
88
91
|
const controllers = nodes.reduce((acc, operationNode) => {
|
|
89
92
|
if (!ast.isHttpOperationNode(operationNode)) return acc
|
|
90
93
|
const tag = operationNode.tags[0]
|
|
91
|
-
const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag)) : resolver.
|
|
94
|
+
const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag)) : resolver.resolveClassName('Client')
|
|
92
95
|
|
|
93
96
|
if (!tag && !group) {
|
|
94
97
|
const name = resolver.resolveClassName('ApiClient')
|
|
@@ -145,7 +148,7 @@ export const classClientGenerator = defineGenerator<PluginClient>({
|
|
|
145
148
|
|
|
146
149
|
ops.forEach((op) => {
|
|
147
150
|
if (!op.zodFile || !zodResolver) return
|
|
148
|
-
const names = resolveZodImportNames(op.node, zodResolver)
|
|
151
|
+
const names = resolveZodImportNames(op.node, zodResolver, parser)
|
|
149
152
|
if (!zodImportsByFile.has(op.zodFile.path)) {
|
|
150
153
|
zodImportsByFile.set(op.zodFile.path, new Set())
|
|
151
154
|
}
|
|
@@ -161,8 +164,9 @@ export const classClientGenerator = defineGenerator<PluginClient>({
|
|
|
161
164
|
|
|
162
165
|
const files = controllers.map(({ name, file, operations: ops }) => {
|
|
163
166
|
const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
|
|
164
|
-
const { zodImportsByFile, zodFilesByPath } =
|
|
165
|
-
|
|
167
|
+
const { zodImportsByFile, zodFilesByPath } = isParserEnabled(parser)
|
|
168
|
+
? collectZodImports(ops)
|
|
169
|
+
: { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, ast.FileNode>() }
|
|
166
170
|
const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') ?? false)
|
|
167
171
|
|
|
168
172
|
return (
|
|
@@ -190,6 +194,10 @@ export const classClientGenerator = defineGenerator<PluginClient>({
|
|
|
190
194
|
|
|
191
195
|
{hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(root, '.kubb/config.ts')} />}
|
|
192
196
|
|
|
197
|
+
{parser === 'zod' && zodResolver && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && (
|
|
198
|
+
<File.Import name={['z']} path="zod" isTypeOnly />
|
|
199
|
+
)}
|
|
200
|
+
|
|
193
201
|
{Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
194
202
|
const typeFile = typeFilesByPath.get(filePath)
|
|
195
203
|
if (!typeFile) return null
|
|
@@ -198,7 +206,7 @@ export const classClientGenerator = defineGenerator<PluginClient>({
|
|
|
198
206
|
return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
|
|
199
207
|
})}
|
|
200
208
|
|
|
201
|
-
{parser
|
|
209
|
+
{isParserEnabled(parser) &&
|
|
202
210
|
Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
203
211
|
const zodFile = zodFilesByPath.get(filePath)
|
|
204
212
|
if (!zodFile) return null
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
2
|
+
import { getOperationParameters, operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
3
3
|
import { ast, defineGenerator } from '@kubb/core'
|
|
4
4
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
5
5
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
6
|
-
import { File,
|
|
6
|
+
import { File, jsxRenderer } from '@kubb/renderer-jsx'
|
|
7
7
|
import { Client } from '../components/Client'
|
|
8
8
|
import { Url } from '../components/Url.tsx'
|
|
9
9
|
import type { PluginClient } from '../types'
|
|
10
|
+
import { isParserEnabled, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Built-in operation generator for `@kubb/plugin-client`. Emits one async
|
|
@@ -15,7 +16,7 @@ import type { PluginClient } from '../types'
|
|
|
15
16
|
*/
|
|
16
17
|
export const clientGenerator = defineGenerator<PluginClient>({
|
|
17
18
|
name: 'client',
|
|
18
|
-
renderer:
|
|
19
|
+
renderer: jsxRenderer,
|
|
19
20
|
operation(node, ctx) {
|
|
20
21
|
if (!ast.isHttpOperationNode(node)) return null
|
|
21
22
|
const { config, driver, resolver, root } = ctx
|
|
@@ -30,17 +31,22 @@ export const clientGenerator = defineGenerator<PluginClient>({
|
|
|
30
31
|
|
|
31
32
|
const tsResolver = driver.getResolver(pluginTsName)
|
|
32
33
|
|
|
33
|
-
const pluginZod = parser
|
|
34
|
+
const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null
|
|
34
35
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
|
|
35
36
|
|
|
36
37
|
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing })
|
|
37
38
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
39
|
+
const { query: queryParams } = getOperationParameters(node)
|
|
40
|
+
|
|
41
|
+
const importedZodNames = zodResolver
|
|
42
|
+
? [
|
|
43
|
+
resolveResponseParser(parser) === 'zod' ? zodResolver.resolveResponseName?.(node) : null,
|
|
44
|
+
resolveRequestParser(parser) === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
|
|
45
|
+
resolveQueryParamsParser(parser) === 'zod' && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]!) : null,
|
|
46
|
+
].filter((name): name is string => Boolean(name))
|
|
47
|
+
: []
|
|
48
|
+
|
|
49
|
+
const zodRequestName = zodResolver && parser === 'zod' && node.requestBody?.content?.[0]?.schema ? (zodResolver.resolveDataName?.(node) ?? null) : null
|
|
44
50
|
|
|
45
51
|
const meta = {
|
|
46
52
|
name: resolver.resolveName(node.operationId),
|
|
@@ -90,6 +96,8 @@ export const clientGenerator = defineGenerator<PluginClient>({
|
|
|
90
96
|
|
|
91
97
|
{hasFormData && <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />}
|
|
92
98
|
|
|
99
|
+
{zodRequestName && <File.Import name={['z']} path="zod" isTypeOnly />}
|
|
100
|
+
|
|
93
101
|
{meta.fileZod && importedZodNames.length > 0 && <File.Import name={importedZodNames as Array<string>} root={meta.file.path} path={meta.fileZod.path} />}
|
|
94
102
|
|
|
95
103
|
{meta.fileTs && importedTypeNames.length > 0 && (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { camelCase } from '@internals/utils'
|
|
2
2
|
import type { ast } from '@kubb/core'
|
|
3
3
|
import { defineGenerator } from '@kubb/core'
|
|
4
|
-
import { File, Function,
|
|
4
|
+
import { File, Function, jsxRenderer } from '@kubb/renderer-jsx'
|
|
5
5
|
import type { PluginClient } from '../types'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -12,7 +12,7 @@ import type { PluginClient } from '../types'
|
|
|
12
12
|
*/
|
|
13
13
|
export const groupedClientGenerator = defineGenerator<PluginClient>({
|
|
14
14
|
name: 'groupedClient',
|
|
15
|
-
renderer:
|
|
15
|
+
renderer: jsxRenderer,
|
|
16
16
|
operations(nodes, ctx) {
|
|
17
17
|
const { config, resolver, root } = ctx
|
|
18
18
|
const { output, group } = ctx.options
|