@kubb/plugin-client 5.0.0-alpha.27 → 5.0.0-alpha.29

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