@kubb/plugin-client 5.0.0-alpha.3 → 5.0.0-alpha.31
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.d.ts +2 -2
- package/dist/index.cjs +1893 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +480 -4
- package/dist/index.js +1885 -77
- package/dist/index.js.map +1 -1
- package/package.json +10 -25
- package/src/components/ClassClient.tsx +42 -138
- package/src/components/Client.tsx +85 -124
- package/src/components/ClientLegacy.tsx +501 -0
- package/src/components/Operations.tsx +8 -8
- package/src/components/StaticClassClient.tsx +41 -135
- package/src/components/Url.tsx +37 -46
- package/src/generators/classClientGenerator.tsx +125 -148
- package/src/generators/clientGenerator.tsx +93 -82
- package/src/generators/groupedClientGenerator.tsx +47 -50
- package/src/generators/operationsGenerator.tsx +9 -17
- package/src/generators/staticClassClientGenerator.tsx +159 -164
- package/src/index.ts +11 -1
- package/src/plugin.ts +115 -108
- package/src/presets.ts +25 -0
- package/src/resolvers/resolverClient.ts +26 -0
- package/src/resolvers/resolverClientLegacy.ts +26 -0
- package/src/types.ts +105 -40
- package/src/utils.ts +148 -0
- package/dist/StaticClassClient-By-aMAe4.cjs +0 -677
- package/dist/StaticClassClient-By-aMAe4.cjs.map +0 -1
- package/dist/StaticClassClient-CCn9g9eF.js +0 -636
- package/dist/StaticClassClient-CCn9g9eF.js.map +0 -1
- package/dist/components.cjs +0 -7
- package/dist/components.d.ts +0 -216
- package/dist/components.js +0 -2
- package/dist/generators-C2jT7XCH.js +0 -723
- package/dist/generators-C2jT7XCH.js.map +0 -1
- package/dist/generators-qkDW17Hf.cjs +0 -753
- package/dist/generators-qkDW17Hf.cjs.map +0 -1
- package/dist/generators.cjs +0 -7
- package/dist/generators.d.ts +0 -512
- package/dist/generators.js +0 -2
- package/dist/types-CdM4DK1M.d.ts +0 -169
- package/src/components/index.ts +0 -5
- package/src/generators/index.ts +0 -5
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { camelCase, pascalCase } from '@internals/utils'
|
|
3
|
-
import {
|
|
4
|
-
import type { KubbFile } from '@kubb/
|
|
5
|
-
import
|
|
6
|
-
import type {
|
|
7
|
-
import { createReactGenerator } from '@kubb/plugin-oas/generators'
|
|
8
|
-
import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
|
|
9
|
-
import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
|
|
3
|
+
import type { OperationNode } from '@kubb/ast/types'
|
|
4
|
+
import type { KubbFile } from '@kubb/core'
|
|
5
|
+
import { defineGenerator } from '@kubb/core'
|
|
6
|
+
import type { PluginTs } from '@kubb/plugin-ts'
|
|
10
7
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
8
|
+
import type { PluginZod } from '@kubb/plugin-zod'
|
|
11
9
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
12
10
|
import { File } from '@kubb/react-fabric'
|
|
13
11
|
import { ClassClient } from '../components/ClassClient'
|
|
@@ -15,12 +13,12 @@ import { WrapperClient } from '../components/WrapperClient'
|
|
|
15
13
|
import type { PluginClient } from '../types'
|
|
16
14
|
|
|
17
15
|
type OperationData = {
|
|
18
|
-
|
|
16
|
+
node: OperationNode
|
|
19
17
|
name: string
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
tsResolver: PluginTs['resolver']
|
|
19
|
+
zodResolver: PluginZod['resolver'] | undefined
|
|
22
20
|
typeFile: KubbFile.File
|
|
23
|
-
zodFile: KubbFile.File
|
|
21
|
+
zodFile: KubbFile.File | undefined
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
type Controller = {
|
|
@@ -29,74 +27,85 @@ type Controller = {
|
|
|
29
27
|
operations: Array<OperationData>
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
function resolveTypeImportNames(node: OperationNode, tsResolver: PluginTs['resolver']): Array<string> {
|
|
31
|
+
const names: Array<string | undefined> = [
|
|
32
|
+
node.requestBody?.schema ? tsResolver.resolveDataName(node) : undefined,
|
|
33
|
+
tsResolver.resolveResponseName(node),
|
|
34
|
+
...node.parameters.filter((p) => p.in === 'path').map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
35
|
+
...node.parameters.filter((p) => p.in === 'query').map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
36
|
+
...node.parameters.filter((p) => p.in === 'header').map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
37
|
+
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
|
|
38
|
+
]
|
|
39
|
+
return names.filter((n): n is string => Boolean(n))
|
|
40
|
+
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
42
|
+
function resolveZodImportNames(node: OperationNode, zodResolver: PluginZod['resolver']): Array<string> {
|
|
43
|
+
const names: Array<string | undefined> = [zodResolver.resolveResponseName?.(node), node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : undefined]
|
|
44
|
+
return names.filter((n): n is string => Boolean(n))
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
export const classClientGenerator = defineGenerator<PluginClient>({
|
|
48
|
+
name: 'classClient',
|
|
49
|
+
operations(nodes, options) {
|
|
50
|
+
const { adapter, config, driver, resolver, root } = this
|
|
51
|
+
const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, wrapper } = options
|
|
52
|
+
const baseURL = options.baseURL ?? adapter.rootNode?.meta?.baseURL
|
|
53
|
+
|
|
54
|
+
const pluginTs = driver.getPlugin(pluginTsName)
|
|
55
|
+
if (!pluginTs?.resolver) return null
|
|
56
|
+
|
|
57
|
+
const tsResolver = pluginTs.resolver
|
|
58
|
+
const tsPluginOptions = pluginTs.options
|
|
59
|
+
const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
|
|
60
|
+
const zodResolver = pluginZod?.resolver
|
|
61
|
+
|
|
62
|
+
function buildOperationData(node: OperationNode): OperationData {
|
|
63
|
+
const typeFile = tsResolver.resolveFile(
|
|
64
|
+
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
65
|
+
{ root, output: tsPluginOptions?.output ?? output, group: tsPluginOptions?.group },
|
|
66
|
+
)
|
|
67
|
+
const zodFile =
|
|
68
|
+
zodResolver && pluginZod?.options
|
|
69
|
+
? zodResolver.resolveFile(
|
|
70
|
+
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
71
|
+
{ root, output: pluginZod.options.output ?? output, group: pluginZod.options.group },
|
|
72
|
+
)
|
|
73
|
+
: undefined
|
|
51
74
|
|
|
52
75
|
return {
|
|
53
|
-
|
|
54
|
-
name:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
typeFile
|
|
58
|
-
zodFile
|
|
76
|
+
node: node,
|
|
77
|
+
name: resolver.resolveName(node.operationId),
|
|
78
|
+
tsResolver,
|
|
79
|
+
zodResolver,
|
|
80
|
+
typeFile,
|
|
81
|
+
zodFile,
|
|
59
82
|
}
|
|
60
83
|
}
|
|
61
84
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
const groupName = group?.tag ? (options.group?.name?.({ group: camelCase(group.tag) }) ?? pascalCase(group.tag)) : 'Client'
|
|
85
|
+
const controllers = nodes.reduce(
|
|
86
|
+
(acc, operationNode) => {
|
|
87
|
+
const tag = operationNode.tags[0]
|
|
88
|
+
const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? pascalCase(tag)) : 'Client'
|
|
67
89
|
|
|
68
|
-
if (!
|
|
69
|
-
// If no grouping, put all operations in a single class
|
|
90
|
+
if (!tag && !group) {
|
|
70
91
|
const name = 'ApiClient'
|
|
71
|
-
const file =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
pluginName,
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
const operationData = buildOperationData(operation)
|
|
78
|
-
const previousFile = acc.find((item) => item.file.path === file.path)
|
|
92
|
+
const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group })
|
|
93
|
+
const operationData = buildOperationData(operationNode)
|
|
94
|
+
const previous = acc.find((item) => item.file.path === file.path)
|
|
79
95
|
|
|
80
|
-
if (
|
|
81
|
-
|
|
96
|
+
if (previous) {
|
|
97
|
+
previous.operations.push(operationData)
|
|
82
98
|
} else {
|
|
83
99
|
acc.push({ name, file, operations: [operationData] })
|
|
84
100
|
}
|
|
85
|
-
} else if (
|
|
86
|
-
// Group by tag
|
|
101
|
+
} else if (tag) {
|
|
87
102
|
const name = groupName
|
|
88
|
-
const file =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
pluginName,
|
|
92
|
-
options: { group },
|
|
93
|
-
})
|
|
103
|
+
const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group })
|
|
104
|
+
const operationData = buildOperationData(operationNode)
|
|
105
|
+
const previous = acc.find((item) => item.file.path === file.path)
|
|
94
106
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (previousFile) {
|
|
99
|
-
previousFile.operations.push(operationData)
|
|
107
|
+
if (previous) {
|
|
108
|
+
previous.operations.push(operationData)
|
|
100
109
|
} else {
|
|
101
110
|
acc.push({ name, file, operations: [operationData] })
|
|
102
111
|
}
|
|
@@ -112,22 +121,15 @@ export const classClientGenerator = createReactGenerator<PluginClient>({
|
|
|
112
121
|
const typeFilesByPath = new Map<string, KubbFile.File>()
|
|
113
122
|
|
|
114
123
|
ops.forEach((op) => {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
typeImportsByFile.set(typeFile.path, new Set())
|
|
124
|
+
const names = resolveTypeImportNames(op.node, tsResolver)
|
|
125
|
+
if (!typeImportsByFile.has(op.typeFile.path)) {
|
|
126
|
+
typeImportsByFile.set(op.typeFile.path, new Set())
|
|
119
127
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (typeSchemas.response?.name) typeImports.add(typeSchemas.response.name)
|
|
124
|
-
if (typeSchemas.pathParams?.name) typeImports.add(typeSchemas.pathParams.name)
|
|
125
|
-
if (typeSchemas.queryParams?.name) typeImports.add(typeSchemas.queryParams.name)
|
|
126
|
-
if (typeSchemas.headerParams?.name) typeImports.add(typeSchemas.headerParams.name)
|
|
127
|
-
typeSchemas.statusCodes?.forEach((item) => {
|
|
128
|
-
if (item?.name) typeImports.add(item.name)
|
|
128
|
+
const imports = typeImportsByFile.get(op.typeFile.path)!
|
|
129
|
+
names.forEach((n) => {
|
|
130
|
+
imports.add(n)
|
|
129
131
|
})
|
|
130
|
-
typeFilesByPath.set(typeFile.path, typeFile)
|
|
132
|
+
typeFilesByPath.set(op.typeFile.path, op.typeFile)
|
|
131
133
|
})
|
|
132
134
|
|
|
133
135
|
return { typeImportsByFile, typeFilesByPath }
|
|
@@ -138,16 +140,16 @@ export const classClientGenerator = createReactGenerator<PluginClient>({
|
|
|
138
140
|
const zodFilesByPath = new Map<string, KubbFile.File>()
|
|
139
141
|
|
|
140
142
|
ops.forEach((op) => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (!zodImportsByFile.has(zodFile.path)) {
|
|
144
|
-
zodImportsByFile.set(zodFile.path, new Set())
|
|
143
|
+
if (!op.zodFile || !zodResolver) return
|
|
144
|
+
const names = resolveZodImportNames(op.node, zodResolver)
|
|
145
|
+
if (!zodImportsByFile.has(op.zodFile.path)) {
|
|
146
|
+
zodImportsByFile.set(op.zodFile.path, new Set())
|
|
145
147
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
zodFilesByPath.set(zodFile.path, zodFile)
|
|
148
|
+
const imports = zodImportsByFile.get(op.zodFile.path)!
|
|
149
|
+
names.forEach((n) => {
|
|
150
|
+
imports.add(n)
|
|
151
|
+
})
|
|
152
|
+
zodFilesByPath.set(op.zodFile.path, op.zodFile)
|
|
151
153
|
})
|
|
152
154
|
|
|
153
155
|
return { zodImportsByFile, zodFilesByPath }
|
|
@@ -156,10 +158,8 @@ export const classClientGenerator = createReactGenerator<PluginClient>({
|
|
|
156
158
|
const files = controllers.map(({ name, file, operations: ops }) => {
|
|
157
159
|
const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
|
|
158
160
|
const { zodImportsByFile, zodFilesByPath } =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
: { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, KubbFile.File>() }
|
|
162
|
-
const hasFormData = ops.some((op) => op.operation.getContentType() === 'multipart/form-data')
|
|
161
|
+
parser === 'zod' ? collectZodImports(ops) : { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, KubbFile.File>() }
|
|
162
|
+
const hasFormData = ops.some((op) => op.node.requestBody?.contentType === 'multipart/form-data')
|
|
163
163
|
|
|
164
164
|
return (
|
|
165
165
|
<File
|
|
@@ -167,76 +167,58 @@ export const classClientGenerator = createReactGenerator<PluginClient>({
|
|
|
167
167
|
baseName={file.baseName}
|
|
168
168
|
path={file.path}
|
|
169
169
|
meta={file.meta}
|
|
170
|
-
banner={
|
|
171
|
-
footer={
|
|
170
|
+
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
171
|
+
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
172
172
|
>
|
|
173
|
-
{
|
|
173
|
+
{importPath ? (
|
|
174
174
|
<>
|
|
175
|
-
<File.Import name={'fetch'} path={
|
|
176
|
-
<File.Import name={['mergeConfig']} path={
|
|
177
|
-
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={
|
|
175
|
+
<File.Import name={'fetch'} path={importPath} />
|
|
176
|
+
<File.Import name={['mergeConfig']} path={importPath} />
|
|
177
|
+
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
|
|
178
178
|
</>
|
|
179
179
|
) : (
|
|
180
180
|
<>
|
|
181
|
-
<File.Import name={['fetch']} root={file.path} path={path.resolve(
|
|
182
|
-
<File.Import name={['mergeConfig']} root={file.path} path={path.resolve(
|
|
183
|
-
<File.Import
|
|
184
|
-
name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
|
|
185
|
-
root={file.path}
|
|
186
|
-
path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
|
|
187
|
-
isTypeOnly
|
|
188
|
-
/>
|
|
181
|
+
<File.Import name={['fetch']} root={file.path} path={path.resolve(root, '.kubb/fetch.ts')} />
|
|
182
|
+
<File.Import name={['mergeConfig']} root={file.path} path={path.resolve(root, '.kubb/fetch.ts')} />
|
|
183
|
+
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} root={file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
|
|
189
184
|
</>
|
|
190
185
|
)}
|
|
191
186
|
|
|
192
|
-
{hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(
|
|
187
|
+
{hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(root, '.kubb/config.ts')} />}
|
|
193
188
|
|
|
194
|
-
{Array.from(typeImportsByFile.entries()).map(([filePath,
|
|
189
|
+
{Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
195
190
|
const typeFile = typeFilesByPath.get(filePath)
|
|
196
|
-
if (!typeFile)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const importNames = Array.from(imports).filter(Boolean)
|
|
200
|
-
if (importNames.length === 0) {
|
|
201
|
-
return null
|
|
202
|
-
}
|
|
191
|
+
if (!typeFile) return null
|
|
192
|
+
const importNames = Array.from(importSet).filter(Boolean)
|
|
193
|
+
if (importNames.length === 0) return null
|
|
203
194
|
return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
|
|
204
195
|
})}
|
|
205
196
|
|
|
206
|
-
{
|
|
207
|
-
Array.from(zodImportsByFile.entries()).map(([filePath,
|
|
197
|
+
{parser === 'zod' &&
|
|
198
|
+
Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
|
|
208
199
|
const zodFile = zodFilesByPath.get(filePath)
|
|
209
|
-
if (!zodFile)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const importNames = Array.from(imports).filter(Boolean)
|
|
213
|
-
if (importNames.length === 0) {
|
|
214
|
-
return null
|
|
215
|
-
}
|
|
216
|
-
|
|
200
|
+
if (!zodFile) return null
|
|
201
|
+
const importNames = Array.from(importSet).filter(Boolean)
|
|
202
|
+
if (importNames.length === 0) return null
|
|
217
203
|
return <File.Import key={filePath} name={importNames} root={file.path} path={zodFile.path} />
|
|
218
204
|
})}
|
|
219
205
|
|
|
220
206
|
<ClassClient
|
|
221
207
|
name={name}
|
|
222
208
|
operations={ops}
|
|
223
|
-
baseURL={
|
|
224
|
-
dataReturnType={
|
|
225
|
-
pathParamsType={
|
|
226
|
-
paramsCasing={
|
|
227
|
-
paramsType={
|
|
228
|
-
parser={
|
|
209
|
+
baseURL={baseURL}
|
|
210
|
+
dataReturnType={dataReturnType}
|
|
211
|
+
pathParamsType={pathParamsType}
|
|
212
|
+
paramsCasing={paramsCasing}
|
|
213
|
+
paramsType={paramsType}
|
|
214
|
+
parser={parser}
|
|
229
215
|
/>
|
|
230
216
|
</File>
|
|
231
217
|
)
|
|
232
218
|
})
|
|
233
219
|
|
|
234
|
-
if (
|
|
235
|
-
const wrapperFile =
|
|
236
|
-
name: options.wrapper.className,
|
|
237
|
-
extname: '.ts',
|
|
238
|
-
pluginName,
|
|
239
|
-
})
|
|
220
|
+
if (wrapper) {
|
|
221
|
+
const wrapperFile = resolver.resolveFile({ name: wrapper.className, extname: '.ts' }, { root, output, group })
|
|
240
222
|
|
|
241
223
|
files.push(
|
|
242
224
|
<File
|
|
@@ -244,29 +226,24 @@ export const classClientGenerator = createReactGenerator<PluginClient>({
|
|
|
244
226
|
baseName={wrapperFile.baseName}
|
|
245
227
|
path={wrapperFile.path}
|
|
246
228
|
meta={wrapperFile.meta}
|
|
247
|
-
banner={
|
|
248
|
-
footer={
|
|
229
|
+
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
230
|
+
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
249
231
|
>
|
|
250
|
-
{
|
|
251
|
-
<File.Import name={['Client', 'RequestConfig']} path={
|
|
232
|
+
{importPath ? (
|
|
233
|
+
<File.Import name={['Client', 'RequestConfig']} path={importPath} isTypeOnly />
|
|
252
234
|
) : (
|
|
253
|
-
<File.Import
|
|
254
|
-
name={['Client', 'RequestConfig']}
|
|
255
|
-
root={wrapperFile.path}
|
|
256
|
-
path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
|
|
257
|
-
isTypeOnly
|
|
258
|
-
/>
|
|
235
|
+
<File.Import name={['Client', 'RequestConfig']} root={wrapperFile.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
|
|
259
236
|
)}
|
|
260
237
|
|
|
261
238
|
{controllers.map(({ name, file }) => (
|
|
262
239
|
<File.Import key={name} name={[name]} root={wrapperFile.path} path={file.path} />
|
|
263
240
|
))}
|
|
264
241
|
|
|
265
|
-
<WrapperClient name={
|
|
242
|
+
<WrapperClient name={wrapper.className} classNames={controllers.map(({ name }) => name)} />
|
|
266
243
|
</File>,
|
|
267
244
|
)
|
|
268
245
|
}
|
|
269
246
|
|
|
270
|
-
return files
|
|
247
|
+
return <>{files}</>
|
|
271
248
|
},
|
|
272
249
|
})
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
|
|
5
|
-
import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
|
|
2
|
+
import { caseParams } from '@kubb/ast'
|
|
3
|
+
import { defineGenerator } from '@kubb/core'
|
|
6
4
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
7
5
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
8
6
|
import { File } from '@kubb/react-fabric'
|
|
@@ -10,114 +8,127 @@ import { Client } from '../components/Client'
|
|
|
10
8
|
import { Url } from '../components/Url.tsx'
|
|
11
9
|
import type { PluginClient } from '../types'
|
|
12
10
|
|
|
13
|
-
export const clientGenerator =
|
|
11
|
+
export const clientGenerator = defineGenerator<PluginClient>({
|
|
14
12
|
name: 'client',
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const {
|
|
18
|
-
|
|
19
|
-
options: { output, urlType },
|
|
20
|
-
} = plugin
|
|
21
|
-
|
|
22
|
-
const oas = useOas()
|
|
23
|
-
const { getSchemas, getName, getFile } = useOperationManager(generator)
|
|
24
|
-
|
|
25
|
-
const client = {
|
|
26
|
-
name: getName(operation, { type: 'function' }),
|
|
27
|
-
file: getFile(operation),
|
|
28
|
-
}
|
|
13
|
+
operation(node, options) {
|
|
14
|
+
const { adapter, config, driver, resolver, root } = this
|
|
15
|
+
const { output, urlType, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, group } = options
|
|
16
|
+
const baseURL = options.baseURL ?? adapter.rootNode?.meta?.baseURL
|
|
29
17
|
|
|
30
|
-
const
|
|
31
|
-
name: getName(operation, { type: 'function', suffix: 'url', prefix: 'get' }),
|
|
32
|
-
file: getFile(operation),
|
|
33
|
-
}
|
|
18
|
+
const pluginTs = driver.getPlugin(pluginTsName)
|
|
34
19
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
schemas: getSchemas(operation, { pluginName: pluginTsName, type: 'type' }),
|
|
20
|
+
if (!pluginTs?.resolver) {
|
|
21
|
+
return null
|
|
38
22
|
}
|
|
39
23
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
24
|
+
const tsResolver = pluginTs.resolver
|
|
25
|
+
|
|
26
|
+
const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
|
|
27
|
+
const zodResolver = pluginZod?.resolver
|
|
28
|
+
|
|
29
|
+
const casedParams = caseParams(node.parameters, paramsCasing)
|
|
30
|
+
const pathParams = casedParams.filter((p) => p.in === 'path')
|
|
31
|
+
const queryParams = casedParams.filter((p) => p.in === 'query')
|
|
32
|
+
const headerParams = casedParams.filter((p) => p.in === 'header')
|
|
33
|
+
|
|
34
|
+
const importedTypeNames = [
|
|
35
|
+
...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
36
|
+
...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
37
|
+
...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
38
|
+
node.requestBody?.schema ? tsResolver.resolveDataName(node) : undefined,
|
|
39
|
+
tsResolver.resolveResponseName(node),
|
|
40
|
+
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
|
|
41
|
+
].filter(Boolean)
|
|
44
42
|
|
|
45
|
-
const
|
|
43
|
+
const importedZodNames =
|
|
44
|
+
zodResolver && parser === 'zod'
|
|
45
|
+
? [zodResolver.resolveResponseName?.(node), node.requestBody?.schema ? zodResolver.resolveDataName?.(node) : undefined].filter(Boolean)
|
|
46
|
+
: []
|
|
47
|
+
|
|
48
|
+
const meta = {
|
|
49
|
+
name: resolver.resolveName(node.operationId),
|
|
50
|
+
urlName: `get${resolver.resolveName(node.operationId).charAt(0).toUpperCase()}${resolver.resolveName(node.operationId).slice(1)}Url`,
|
|
51
|
+
file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
|
|
52
|
+
fileTs: tsResolver.resolveFile(
|
|
53
|
+
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
54
|
+
{
|
|
55
|
+
root,
|
|
56
|
+
output: pluginTs.options?.output ?? output,
|
|
57
|
+
group: pluginTs.options?.group,
|
|
58
|
+
},
|
|
59
|
+
),
|
|
60
|
+
fileZod:
|
|
61
|
+
zodResolver && pluginZod?.options
|
|
62
|
+
? zodResolver.resolveFile(
|
|
63
|
+
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
64
|
+
{
|
|
65
|
+
root,
|
|
66
|
+
output: pluginZod.options.output ?? output,
|
|
67
|
+
group: pluginZod.options.group,
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
: undefined,
|
|
71
|
+
} as const
|
|
72
|
+
|
|
73
|
+
const isFormData = node.requestBody?.contentType === 'multipart/form-data'
|
|
46
74
|
|
|
47
75
|
return (
|
|
48
76
|
<File
|
|
49
|
-
baseName={
|
|
50
|
-
path={
|
|
51
|
-
meta={
|
|
52
|
-
banner={
|
|
53
|
-
footer={
|
|
77
|
+
baseName={meta.file.baseName}
|
|
78
|
+
path={meta.file.path}
|
|
79
|
+
meta={meta.file.meta}
|
|
80
|
+
banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
|
|
81
|
+
footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
|
|
54
82
|
>
|
|
55
|
-
{
|
|
83
|
+
{importPath ? (
|
|
56
84
|
<>
|
|
57
|
-
<File.Import name={'fetch'} path={
|
|
58
|
-
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={
|
|
85
|
+
<File.Import name={'fetch'} path={importPath} />
|
|
86
|
+
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
|
|
59
87
|
</>
|
|
60
88
|
) : (
|
|
61
89
|
<>
|
|
62
|
-
<File.Import name={['fetch']} root={
|
|
90
|
+
<File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />
|
|
63
91
|
<File.Import
|
|
64
92
|
name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
|
|
65
|
-
root={
|
|
66
|
-
path={path.resolve(
|
|
93
|
+
root={meta.file.path}
|
|
94
|
+
path={path.resolve(root, '.kubb/fetch.ts')}
|
|
67
95
|
isTypeOnly
|
|
68
96
|
/>
|
|
69
97
|
</>
|
|
70
98
|
)}
|
|
71
99
|
|
|
72
|
-
{isFormData &&
|
|
73
|
-
<File.Import name={['buildFormData']} root={client.file.path} path={path.resolve(config.root, config.output.path, '.kubb/config.ts')} />
|
|
74
|
-
)}
|
|
100
|
+
{isFormData && node.requestBody?.schema && <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />}
|
|
75
101
|
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
path={zod.file.path}
|
|
81
|
-
/>
|
|
102
|
+
{meta.fileZod && importedZodNames.length > 0 && <File.Import name={importedZodNames as string[]} root={meta.file.path} path={meta.fileZod.path} />}
|
|
103
|
+
|
|
104
|
+
{meta.fileTs && importedTypeNames.length > 0 && (
|
|
105
|
+
<File.Import name={Array.from(new Set(importedTypeNames))} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
|
|
82
106
|
)}
|
|
83
|
-
<File.Import
|
|
84
|
-
name={[
|
|
85
|
-
type.schemas.request?.name,
|
|
86
|
-
type.schemas.response.name,
|
|
87
|
-
type.schemas.pathParams?.name,
|
|
88
|
-
type.schemas.queryParams?.name,
|
|
89
|
-
type.schemas.headerParams?.name,
|
|
90
|
-
...(type.schemas.statusCodes?.map((item) => item.name) || []),
|
|
91
|
-
].filter((x): x is string => Boolean(x))}
|
|
92
|
-
root={client.file.path}
|
|
93
|
-
path={type.file.path}
|
|
94
|
-
isTypeOnly
|
|
95
|
-
/>
|
|
96
107
|
|
|
97
108
|
<Url
|
|
98
|
-
name={
|
|
99
|
-
baseURL={
|
|
100
|
-
pathParamsType={
|
|
101
|
-
paramsCasing={
|
|
102
|
-
paramsType={
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
name={meta.urlName}
|
|
110
|
+
baseURL={baseURL}
|
|
111
|
+
pathParamsType={pathParamsType}
|
|
112
|
+
paramsCasing={paramsCasing}
|
|
113
|
+
paramsType={paramsType}
|
|
114
|
+
node={node}
|
|
115
|
+
tsResolver={tsResolver}
|
|
105
116
|
isIndexable={urlType === 'export'}
|
|
106
117
|
isExportable={urlType === 'export'}
|
|
107
118
|
/>
|
|
108
119
|
|
|
109
120
|
<Client
|
|
110
|
-
name={
|
|
111
|
-
urlName={
|
|
112
|
-
baseURL={
|
|
113
|
-
dataReturnType={
|
|
114
|
-
pathParamsType={
|
|
115
|
-
paramsCasing={
|
|
116
|
-
paramsType={
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
name={meta.name}
|
|
122
|
+
urlName={meta.urlName}
|
|
123
|
+
baseURL={baseURL}
|
|
124
|
+
dataReturnType={dataReturnType}
|
|
125
|
+
pathParamsType={pathParamsType}
|
|
126
|
+
paramsCasing={paramsCasing}
|
|
127
|
+
paramsType={paramsType}
|
|
128
|
+
node={node}
|
|
129
|
+
tsResolver={tsResolver}
|
|
130
|
+
zodResolver={zodResolver}
|
|
131
|
+
parser={parser}
|
|
121
132
|
/>
|
|
122
133
|
</File>
|
|
123
134
|
)
|