@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.
Files changed (42) hide show
  1. package/dist/clients/axios.d.ts +2 -2
  2. package/dist/index.cjs +1893 -74
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +480 -4
  5. package/dist/index.js +1885 -77
  6. package/dist/index.js.map +1 -1
  7. package/package.json +10 -25
  8. package/src/components/ClassClient.tsx +42 -138
  9. package/src/components/Client.tsx +85 -124
  10. package/src/components/ClientLegacy.tsx +501 -0
  11. package/src/components/Operations.tsx +8 -8
  12. package/src/components/StaticClassClient.tsx +41 -135
  13. package/src/components/Url.tsx +37 -46
  14. package/src/generators/classClientGenerator.tsx +125 -148
  15. package/src/generators/clientGenerator.tsx +93 -82
  16. package/src/generators/groupedClientGenerator.tsx +47 -50
  17. package/src/generators/operationsGenerator.tsx +9 -17
  18. package/src/generators/staticClassClientGenerator.tsx +159 -164
  19. package/src/index.ts +11 -1
  20. package/src/plugin.ts +115 -108
  21. package/src/presets.ts +25 -0
  22. package/src/resolvers/resolverClient.ts +26 -0
  23. package/src/resolvers/resolverClientLegacy.ts +26 -0
  24. package/src/types.ts +105 -40
  25. package/src/utils.ts +148 -0
  26. package/dist/StaticClassClient-By-aMAe4.cjs +0 -677
  27. package/dist/StaticClassClient-By-aMAe4.cjs.map +0 -1
  28. package/dist/StaticClassClient-CCn9g9eF.js +0 -636
  29. package/dist/StaticClassClient-CCn9g9eF.js.map +0 -1
  30. package/dist/components.cjs +0 -7
  31. package/dist/components.d.ts +0 -216
  32. package/dist/components.js +0 -2
  33. package/dist/generators-C2jT7XCH.js +0 -723
  34. package/dist/generators-C2jT7XCH.js.map +0 -1
  35. package/dist/generators-qkDW17Hf.cjs +0 -753
  36. package/dist/generators-qkDW17Hf.cjs.map +0 -1
  37. package/dist/generators.cjs +0 -7
  38. package/dist/generators.d.ts +0 -512
  39. package/dist/generators.js +0 -2
  40. package/dist/types-CdM4DK1M.d.ts +0 -169
  41. package/src/components/index.ts +0 -5
  42. 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 { usePluginManager } from '@kubb/core/hooks'
4
- import type { KubbFile } from '@kubb/fabric-core/types'
5
- import type { Operation } from '@kubb/oas'
6
- import type { OperationSchemas } from '@kubb/plugin-oas'
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
- operation: Operation
16
+ node: OperationNode
19
17
  name: string
20
- typeSchemas: OperationSchemas
21
- zodSchemas: OperationSchemas | undefined
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
- export const classClientGenerator = createReactGenerator<PluginClient>({
33
- name: 'classClient',
34
- Operations({ operations, generator, plugin, config }) {
35
- const { options, name: pluginName } = plugin
36
- const pluginManager = usePluginManager()
37
-
38
- const oas = useOas()
39
- const { getName, getFile, getGroup, getSchemas } = useOperationManager(generator)
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
- function buildOperationData(operation: Operation): OperationData {
42
- const type = {
43
- file: getFile(operation, { pluginName: pluginTsName }),
44
- schemas: getSchemas(operation, { pluginName: pluginTsName, type: 'type' }),
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
- const zod = {
48
- file: getFile(operation, { pluginName: pluginZodName }),
49
- schemas: getSchemas(operation, { pluginName: pluginZodName, type: 'function' }),
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
- operation,
54
- name: getName(operation, { type: 'function' }),
55
- typeSchemas: type.schemas,
56
- zodSchemas: zod.schemas,
57
- typeFile: type.file,
58
- zodFile: zod.file,
76
+ node: node,
77
+ name: resolver.resolveName(node.operationId),
78
+ tsResolver,
79
+ zodResolver,
80
+ typeFile,
81
+ zodFile,
59
82
  }
60
83
  }
61
84
 
62
- // Group operations by tag
63
- const controllers = operations.reduce(
64
- (acc, operation) => {
65
- const group = getGroup(operation)
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 (!group?.tag && !options.group) {
69
- // If no grouping, put all operations in a single class
90
+ if (!tag && !group) {
70
91
  const name = 'ApiClient'
71
- const file = pluginManager.getFile({
72
- name,
73
- extname: '.ts',
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 (previousFile) {
81
- previousFile.operations.push(operationData)
96
+ if (previous) {
97
+ previous.operations.push(operationData)
82
98
  } else {
83
99
  acc.push({ name, file, operations: [operationData] })
84
100
  }
85
- } else if (group?.tag) {
86
- // Group by tag
101
+ } else if (tag) {
87
102
  const name = groupName
88
- const file = pluginManager.getFile({
89
- name,
90
- extname: '.ts',
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
- const operationData = buildOperationData(operation)
96
- const previousFile = acc.find((item) => item.file.path === file.path)
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 { typeSchemas, typeFile } = op
116
-
117
- if (!typeImportsByFile.has(typeFile.path)) {
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 typeImports = typeImportsByFile.get(typeFile.path)!
121
-
122
- if (typeSchemas.request?.name) typeImports.add(typeSchemas.request.name)
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
- const { zodSchemas, zodFile } = op
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 zodImports = zodImportsByFile.get(zodFile.path)!
147
-
148
- if (zodSchemas?.response?.name) zodImports.add(zodSchemas.response.name)
149
- if (zodSchemas?.request?.name) zodImports.add(zodSchemas.request.name)
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
- options.parser === 'zod'
160
- ? collectZodImports(ops)
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={getBanner({ oas, output: options.output, config: pluginManager.config })}
171
- footer={getFooter({ oas, output: options.output })}
170
+ banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
171
+ footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
172
172
  >
173
- {options.importPath ? (
173
+ {importPath ? (
174
174
  <>
175
- <File.Import name={'fetch'} path={options.importPath} />
176
- <File.Import name={['mergeConfig']} path={options.importPath} />
177
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={options.importPath} isTypeOnly />
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(config.root, config.output.path, '.kubb/fetch.ts')} />
182
- <File.Import name={['mergeConfig']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
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(config.root, config.output.path, '.kubb/config.ts')} />}
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, imports]) => {
189
+ {Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
195
190
  const typeFile = typeFilesByPath.get(filePath)
196
- if (!typeFile) {
197
- return null
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
- {options.parser === 'zod' &&
207
- Array.from(zodImportsByFile.entries()).map(([filePath, imports]) => {
197
+ {parser === 'zod' &&
198
+ Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
208
199
  const zodFile = zodFilesByPath.get(filePath)
209
- if (!zodFile) {
210
- return null
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={options.baseURL}
224
- dataReturnType={options.dataReturnType}
225
- pathParamsType={options.pathParamsType}
226
- paramsCasing={options.paramsCasing}
227
- paramsType={options.paramsType}
228
- parser={options.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 (options.wrapper) {
235
- const wrapperFile = pluginManager.getFile({
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={getBanner({ oas, output: options.output, config: pluginManager.config })}
248
- footer={getFooter({ oas, output: options.output })}
229
+ banner={resolver.resolveBanner(adapter.rootNode, { output, config })}
230
+ footer={resolver.resolveFooter(adapter.rootNode, { output, config })}
249
231
  >
250
- {options.importPath ? (
251
- <File.Import name={['Client', 'RequestConfig']} path={options.importPath} isTypeOnly />
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={options.wrapper.className} classNames={controllers.map(({ name }) => 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 { usePluginManager } from '@kubb/core/hooks'
3
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
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 = createReactGenerator<PluginClient>({
11
+ export const clientGenerator = defineGenerator<PluginClient>({
14
12
  name: 'client',
15
- Operation({ config, plugin, operation, generator }) {
16
- const pluginManager = usePluginManager()
17
- const {
18
- options,
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 url = {
31
- name: getName(operation, { type: 'function', suffix: 'url', prefix: 'get' }),
32
- file: getFile(operation),
33
- }
18
+ const pluginTs = driver.getPlugin(pluginTsName)
34
19
 
35
- const type = {
36
- file: getFile(operation, { pluginName: pluginTsName }),
37
- schemas: getSchemas(operation, { pluginName: pluginTsName, type: 'type' }),
20
+ if (!pluginTs?.resolver) {
21
+ return null
38
22
  }
39
23
 
40
- const zod = {
41
- file: getFile(operation, { pluginName: pluginZodName }),
42
- schemas: getSchemas(operation, { pluginName: pluginZodName, type: 'function' }),
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 isFormData = operation.getContentType() === 'multipart/form-data'
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={client.file.baseName}
50
- path={client.file.path}
51
- meta={client.file.meta}
52
- banner={getBanner({ oas, output, config: pluginManager.config })}
53
- footer={getFooter({ oas, output })}
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
- {options.importPath ? (
83
+ {importPath ? (
56
84
  <>
57
- <File.Import name={'fetch'} path={options.importPath} />
58
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={options.importPath} isTypeOnly />
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={client.file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
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={client.file.path}
66
- path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
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 && type.schemas.request?.name && (
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
- {options.parser === 'zod' && (
77
- <File.Import
78
- name={[zod.schemas.response.name, zod.schemas.request?.name].filter((x): x is string => Boolean(x))}
79
- root={client.file.path}
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={url.name}
99
- baseURL={options.baseURL}
100
- pathParamsType={options.pathParamsType}
101
- paramsCasing={options.paramsCasing}
102
- paramsType={options.paramsType}
103
- typeSchemas={type.schemas}
104
- operation={operation}
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={client.name}
111
- urlName={url.name}
112
- baseURL={options.baseURL}
113
- dataReturnType={options.dataReturnType}
114
- pathParamsType={options.pathParamsType}
115
- paramsCasing={options.paramsCasing}
116
- paramsType={options.paramsType}
117
- typeSchemas={type.schemas}
118
- operation={operation}
119
- parser={options.parser}
120
- zodSchemas={zod.schemas}
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
  )