@kubb/plugin-client 5.0.0-alpha.9 → 5.0.0-beta.3

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 (60) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +4 -4
  3. package/dist/clients/axios.cjs +2 -2
  4. package/dist/clients/axios.cjs.map +1 -1
  5. package/dist/clients/axios.d.ts +4 -4
  6. package/dist/clients/axios.js +1 -1
  7. package/dist/clients/axios.js.map +1 -1
  8. package/dist/clients/fetch.cjs +1 -1
  9. package/dist/clients/fetch.cjs.map +1 -1
  10. package/dist/clients/fetch.d.ts +2 -2
  11. package/dist/clients/fetch.js +1 -1
  12. package/dist/clients/fetch.js.map +1 -1
  13. package/dist/index.cjs +1739 -97
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +324 -4
  16. package/dist/index.js +1725 -95
  17. package/dist/index.js.map +1 -1
  18. package/dist/templates/clients/axios.source.cjs +1 -1
  19. package/dist/templates/clients/axios.source.js +1 -1
  20. package/dist/templates/clients/fetch.source.cjs +1 -1
  21. package/dist/templates/clients/fetch.source.js +1 -1
  22. package/package.json +67 -84
  23. package/src/clients/axios.ts +5 -1
  24. package/src/clients/fetch.ts +5 -1
  25. package/src/components/ClassClient.tsx +45 -142
  26. package/src/components/Client.tsx +90 -129
  27. package/src/components/Operations.tsx +10 -10
  28. package/src/components/StaticClassClient.tsx +44 -138
  29. package/src/components/Url.tsx +38 -48
  30. package/src/components/WrapperClient.tsx +3 -3
  31. package/src/functionParams.ts +118 -0
  32. package/src/generators/classClientGenerator.tsx +148 -171
  33. package/src/generators/clientGenerator.tsx +95 -82
  34. package/src/generators/groupedClientGenerator.tsx +50 -52
  35. package/src/generators/operationsGenerator.tsx +11 -18
  36. package/src/generators/staticClassClientGenerator.tsx +178 -183
  37. package/src/index.ts +9 -2
  38. package/src/plugin.ts +115 -145
  39. package/src/resolvers/resolverClient.ts +22 -0
  40. package/src/types.ts +104 -44
  41. package/src/utils.ts +180 -0
  42. package/templates/clients/axios.ts +5 -2
  43. package/templates/clients/fetch.ts +5 -2
  44. package/dist/StaticClassClient-By-aMAe4.cjs +0 -677
  45. package/dist/StaticClassClient-By-aMAe4.cjs.map +0 -1
  46. package/dist/StaticClassClient-CCn9g9eF.js +0 -636
  47. package/dist/StaticClassClient-CCn9g9eF.js.map +0 -1
  48. package/dist/components.cjs +0 -7
  49. package/dist/components.d.ts +0 -216
  50. package/dist/components.js +0 -2
  51. package/dist/generators-BYUJaeZP.js +0 -723
  52. package/dist/generators-BYUJaeZP.js.map +0 -1
  53. package/dist/generators-DTxD9FDY.cjs +0 -753
  54. package/dist/generators-DTxD9FDY.cjs.map +0 -1
  55. package/dist/generators.cjs +0 -7
  56. package/dist/generators.d.ts +0 -517
  57. package/dist/generators.js +0 -2
  58. package/dist/types-DBQdg-BV.d.ts +0 -169
  59. package/src/components/index.ts +0 -5
  60. package/src/generators/index.ts +0 -5
@@ -1,47 +1,41 @@
1
1
  import { camelCase } from '@internals/utils'
2
- import { usePluginDriver } from '@kubb/core/hooks'
3
- import type { KubbFile } from '@kubb/fabric-core/types'
4
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
5
- import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
6
- import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
7
- import { File, Function } from '@kubb/react-fabric'
2
+ import type { ast } from '@kubb/core'
3
+ import { defineGenerator } from '@kubb/core'
4
+ import { File, Function, jsxRenderer } from '@kubb/renderer-jsx'
8
5
  import type { PluginClient } from '../types'
9
6
 
10
- export const groupedClientGenerator = createReactGenerator<PluginClient>({
7
+ export const groupedClientGenerator = defineGenerator<PluginClient>({
11
8
  name: 'groupedClient',
12
- Operations({ operations, generator, plugin }) {
13
- const { options, name: pluginName } = plugin
14
- const driver = usePluginDriver()
9
+ renderer: jsxRenderer,
10
+ operations(nodes, ctx) {
11
+ const { config, resolver, adapter, root } = ctx
12
+ const { output, group } = ctx.options
15
13
 
16
- const oas = useOas()
17
- const { getName, getFile, getGroup } = useOperationManager(generator)
14
+ const controllers = nodes.reduce(
15
+ (acc, operationNode) => {
16
+ if (group?.type === 'tag') {
17
+ const tag = operationNode.tags[0]
18
+ const name = tag ? group?.name?.({ group: camelCase(tag) }) : undefined
18
19
 
19
- const controllers = operations.reduce(
20
- (acc, operation) => {
21
- if (options.group?.type === 'tag') {
22
- const group = getGroup(operation)
23
- const name = group?.tag ? options.group?.name?.({ group: camelCase(group.tag) }) : undefined
24
-
25
- if (!group?.tag || !name) {
20
+ if (!tag || !name) {
26
21
  return acc
27
22
  }
28
23
 
29
- const file = driver.getFile({
30
- name,
31
- extname: '.ts',
32
- pluginName,
33
- options: { group },
34
- })
24
+ const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group })
25
+ const clientFile = resolver.resolveFile(
26
+ { name: operationNode.operationId, extname: '.ts', tag: operationNode.tags[0] ?? 'default', path: operationNode.path },
27
+ { root, output, group },
28
+ )
35
29
 
36
30
  const client = {
37
- name: getName(operation, { type: 'function' }),
38
- file: getFile(operation),
31
+ name: resolver.resolveName(operationNode.operationId),
32
+ file: clientFile,
39
33
  }
40
34
 
41
- const previousFile = acc.find((item) => item.file.path === file.path)
35
+ const previous = acc.find((item) => item.file.path === file.path)
42
36
 
43
- if (previousFile) {
44
- previousFile.clients.push(client)
37
+ if (previous) {
38
+ previous.clients.push(client)
45
39
  } else {
46
40
  acc.push({ name, file, clients: [client] })
47
41
  }
@@ -49,30 +43,34 @@ export const groupedClientGenerator = createReactGenerator<PluginClient>({
49
43
 
50
44
  return acc
51
45
  },
52
- [] as Array<{ name: string; file: KubbFile.File; clients: Array<{ name: string; file: KubbFile.File }> }>,
46
+ [] as Array<{ name: string; file: ast.FileNode; clients: Array<{ name: string; file: ast.FileNode }> }>,
53
47
  )
54
48
 
55
- return controllers.map(({ name, file, clients }) => {
56
- return (
57
- <File
58
- key={file.path}
59
- baseName={file.baseName}
60
- path={file.path}
61
- meta={file.meta}
62
- banner={getBanner({ oas, output: options.output, config: driver.config })}
63
- footer={getFooter({ oas, output: options.output })}
64
- >
65
- {clients.map((client) => (
66
- <File.Import key={client.name} name={[client.name]} root={file.path} path={client.file.path} />
67
- ))}
49
+ return (
50
+ <>
51
+ {controllers.map(({ name, file, clients }) => {
52
+ return (
53
+ <File
54
+ key={file.path}
55
+ baseName={file.baseName}
56
+ path={file.path}
57
+ meta={file.meta}
58
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
59
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
60
+ >
61
+ {clients.map((client) => (
62
+ <File.Import key={client.name} name={[client.name]} root={file.path} path={client.file.path} />
63
+ ))}
68
64
 
69
- <File.Source name={name} isExportable isIndexable>
70
- <Function export name={name}>
71
- {`return { ${clients.map((client) => client.name).join(', ')} }`}
72
- </Function>
73
- </File.Source>
74
- </File>
75
- )
76
- })
65
+ <File.Source name={name} isExportable isIndexable>
66
+ <Function export name={name}>
67
+ {`return { ${clients.map((client) => client.name).join(', ')} }`}
68
+ </Function>
69
+ </File.Source>
70
+ </File>
71
+ )
72
+ })}
73
+ </>
74
+ )
77
75
  },
78
76
  })
@@ -1,34 +1,27 @@
1
- import { usePluginDriver } from '@kubb/core/hooks'
2
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
3
- import { useOas } from '@kubb/plugin-oas/hooks'
4
- import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
5
- import { File } from '@kubb/react-fabric'
1
+ import { defineGenerator } from '@kubb/core'
2
+ import { File, jsxRenderer } from '@kubb/renderer-jsx'
6
3
  import { Operations } from '../components/Operations'
7
4
  import type { PluginClient } from '../types'
8
5
 
9
- export const operationsGenerator = createReactGenerator<PluginClient>({
6
+ export const operationsGenerator = defineGenerator<PluginClient>({
10
7
  name: 'client',
11
- Operations({ operations, plugin }) {
12
- const {
13
- name: pluginName,
14
- options: { output },
15
- } = plugin
16
- const driver = usePluginDriver()
17
-
18
- const oas = useOas()
8
+ renderer: jsxRenderer,
9
+ operations(nodes, ctx) {
10
+ const { config, resolver, adapter, root } = ctx
11
+ const { output, group } = ctx.options
19
12
 
20
13
  const name = 'operations'
21
- const file = driver.getFile({ name, extname: '.ts', pluginName })
14
+ const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group })
22
15
 
23
16
  return (
24
17
  <File
25
18
  baseName={file.baseName}
26
19
  path={file.path}
27
20
  meta={file.meta}
28
- banner={getBanner({ oas, output, config: driver.config })}
29
- footer={getFooter({ oas, output })}
21
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
22
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
30
23
  >
31
- <Operations name={name} operations={operations} />
24
+ <Operations name={name} nodes={nodes} />
32
25
  </File>
33
26
  )
34
27
  },
@@ -1,132 +1,134 @@
1
1
  import path from 'node:path'
2
2
  import { camelCase, pascalCase } from '@internals/utils'
3
- import { usePluginDriver } 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 { ast } from '@kubb/core'
4
+ import { defineGenerator } from '@kubb/core'
5
+ import type { ResolverTs } from '@kubb/plugin-ts'
10
6
  import { pluginTsName } from '@kubb/plugin-ts'
7
+ import type { ResolverZod } from '@kubb/plugin-zod'
11
8
  import { pluginZodName } from '@kubb/plugin-zod'
12
- import { File } from '@kubb/react-fabric'
9
+ import { File, jsxRenderer } from '@kubb/renderer-jsx'
13
10
  import { StaticClassClient } from '../components/StaticClassClient'
14
11
  import type { PluginClient } from '../types'
15
12
 
16
13
  type OperationData = {
17
- operation: Operation
14
+ node: ast.OperationNode
18
15
  name: string
19
- typeSchemas: OperationSchemas
20
- zodSchemas: OperationSchemas | undefined
21
- typeFile: KubbFile.File
22
- zodFile: KubbFile.File
16
+ tsResolver: ResolverTs
17
+ zodResolver: ResolverZod | undefined
18
+ typeFile: ast.FileNode
19
+ zodFile: ast.FileNode | undefined
23
20
  }
24
21
 
25
22
  type Controller = {
26
23
  name: string
27
- file: KubbFile.File
24
+ file: ast.FileNode
28
25
  operations: Array<OperationData>
29
26
  }
30
27
 
31
- export const staticClassClientGenerator = createReactGenerator<PluginClient>({
32
- name: 'staticClassClient',
33
- Operations({ operations, generator, plugin, config }) {
34
- const { options, name: pluginName } = plugin
35
- const driver = usePluginDriver()
36
-
37
- const oas = useOas()
38
- const { getName, getFile, getGroup, getSchemas } = useOperationManager(generator)
28
+ function resolveTypeImportNames(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
29
+ const names: Array<string | undefined> = [
30
+ node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined,
31
+ tsResolver.resolveResponseName(node),
32
+ ...node.parameters.filter((p) => p.in === 'path').map((p) => tsResolver.resolvePathParamsName(node, p)),
33
+ ...node.parameters.filter((p) => p.in === 'query').map((p) => tsResolver.resolveQueryParamsName(node, p)),
34
+ ...node.parameters.filter((p) => p.in === 'header').map((p) => tsResolver.resolveHeaderParamsName(node, p)),
35
+ ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
36
+ ]
37
+ return names.filter((n): n is string => Boolean(n))
38
+ }
39
39
 
40
- function buildOperationData(operation: Operation): OperationData {
41
- const type = {
42
- file: getFile(operation, { pluginName: pluginTsName }),
43
- schemas: getSchemas(operation, { pluginName: pluginTsName, type: 'type' }),
44
- }
40
+ function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod): Array<string> {
41
+ const names: Array<string | undefined> = [
42
+ zodResolver.resolveResponseName?.(node),
43
+ node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined,
44
+ ]
45
+ return names.filter((n): n is string => Boolean(n))
46
+ }
45
47
 
46
- const zod = {
47
- file: getFile(operation, { pluginName: pluginZodName }),
48
- schemas: getSchemas(operation, { pluginName: pluginZodName, type: 'function' }),
49
- }
48
+ export const staticClassClientGenerator = defineGenerator<PluginClient>({
49
+ name: 'staticClassClient',
50
+ renderer: jsxRenderer,
51
+ operations(nodes, ctx) {
52
+ const { adapter, config, driver, resolver, root } = ctx
53
+ const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath } = ctx.options
54
+ const baseURL = ctx.options.baseURL ?? adapter.inputNode?.meta?.baseURL
55
+
56
+ const pluginTs = driver.getPlugin(pluginTsName)
57
+ if (!pluginTs) return null
58
+
59
+ const tsResolver = driver.getResolver(pluginTsName)
60
+ const tsPluginOptions = pluginTs.options
61
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
62
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
63
+
64
+ function buildOperationData(node: ast.OperationNode): OperationData {
65
+ const typeFile = tsResolver.resolveFile(
66
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
67
+ { root, output: tsPluginOptions?.output ?? output, group: tsPluginOptions?.group },
68
+ )
69
+ const zodFile =
70
+ zodResolver && pluginZod?.options
71
+ ? zodResolver.resolveFile(
72
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
73
+ { root, output: pluginZod.options?.output ?? output, group: pluginZod.options?.group },
74
+ )
75
+ : undefined
50
76
 
51
77
  return {
52
- operation,
53
- name: getName(operation, { type: 'function' }),
54
- typeSchemas: type.schemas,
55
- zodSchemas: zod.schemas,
56
- typeFile: type.file,
57
- zodFile: zod.file,
78
+ node: node,
79
+ name: resolver.resolveName(node.operationId),
80
+ tsResolver,
81
+ zodResolver,
82
+ typeFile,
83
+ zodFile,
58
84
  }
59
85
  }
60
86
 
61
- // Group operations by tag
62
- const controllers = operations.reduce(
63
- (acc, operation) => {
64
- const group = getGroup(operation)
65
- const groupName = group?.tag ? (options.group?.name?.({ group: camelCase(group.tag) }) ?? pascalCase(group.tag)) : 'Client'
66
-
67
- if (!group?.tag && !options.group) {
68
- // If no grouping, put all operations in a single class
69
- const name = 'ApiClient'
70
- const file = driver.getFile({
71
- name,
72
- extname: '.ts',
73
- pluginName,
74
- })
75
-
76
- const operationData = buildOperationData(operation)
77
- const previousFile = acc.find((item) => item.file.path === file.path)
78
-
79
- if (previousFile) {
80
- previousFile.operations.push(operationData)
81
- } else {
82
- acc.push({ name, file, operations: [operationData] })
83
- }
84
- } else if (group?.tag) {
85
- // Group by tag
86
- const name = groupName
87
- const file = driver.getFile({
88
- name,
89
- extname: '.ts',
90
- pluginName,
91
- options: { group },
92
- })
93
-
94
- const operationData = buildOperationData(operation)
95
- const previousFile = acc.find((item) => item.file.path === file.path)
96
-
97
- if (previousFile) {
98
- previousFile.operations.push(operationData)
99
- } else {
100
- acc.push({ name, file, operations: [operationData] })
101
- }
87
+ const controllers = nodes.reduce((acc, operationNode) => {
88
+ const tag = operationNode.tags[0]
89
+ const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? pascalCase(tag)) : 'Client'
90
+
91
+ if (!tag && !group) {
92
+ const name = 'ApiClient'
93
+ const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group })
94
+ const operationData = buildOperationData(operationNode)
95
+ const previous = acc.find((item) => item.file.path === file.path)
96
+
97
+ if (previous) {
98
+ previous.operations.push(operationData)
99
+ } else {
100
+ acc.push({ name, file, operations: [operationData] })
102
101
  }
102
+ } else if (tag) {
103
+ const name = groupName
104
+ const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group })
105
+ const operationData = buildOperationData(operationNode)
106
+ const previous = acc.find((item) => item.file.path === file.path)
107
+
108
+ if (previous) {
109
+ previous.operations.push(operationData)
110
+ } else {
111
+ acc.push({ name, file, operations: [operationData] })
112
+ }
113
+ }
103
114
 
104
- return acc
105
- },
106
- [] as Array<Controller>,
107
- )
115
+ return acc
116
+ }, [] as Array<Controller>)
108
117
 
109
118
  function collectTypeImports(ops: Array<OperationData>) {
110
119
  const typeImportsByFile = new Map<string, Set<string>>()
111
- const typeFilesByPath = new Map<string, KubbFile.File>()
120
+ const typeFilesByPath = new Map<string, ast.FileNode>()
112
121
 
113
122
  ops.forEach((op) => {
114
- const { typeSchemas, typeFile } = op
115
-
116
- if (!typeImportsByFile.has(typeFile.path)) {
117
- typeImportsByFile.set(typeFile.path, new Set())
123
+ const names = resolveTypeImportNames(op.node, tsResolver)
124
+ if (!typeImportsByFile.has(op.typeFile.path)) {
125
+ typeImportsByFile.set(op.typeFile.path, new Set())
118
126
  }
119
- const typeImports = typeImportsByFile.get(typeFile.path)!
120
-
121
- if (typeSchemas.request?.name) typeImports.add(typeSchemas.request.name)
122
- if (typeSchemas.response?.name) typeImports.add(typeSchemas.response.name)
123
- if (typeSchemas.pathParams?.name) typeImports.add(typeSchemas.pathParams.name)
124
- if (typeSchemas.queryParams?.name) typeImports.add(typeSchemas.queryParams.name)
125
- if (typeSchemas.headerParams?.name) typeImports.add(typeSchemas.headerParams.name)
126
- typeSchemas.statusCodes?.forEach((item) => {
127
- if (item?.name) typeImports.add(item.name)
127
+ const imports = typeImportsByFile.get(op.typeFile.path)!
128
+ names.forEach((n) => {
129
+ imports.add(n)
128
130
  })
129
- typeFilesByPath.set(typeFile.path, typeFile)
131
+ typeFilesByPath.set(op.typeFile.path, op.typeFile)
130
132
  })
131
133
 
132
134
  return { typeImportsByFile, typeFilesByPath }
@@ -134,100 +136,93 @@ export const staticClassClientGenerator = createReactGenerator<PluginClient>({
134
136
 
135
137
  function collectZodImports(ops: Array<OperationData>) {
136
138
  const zodImportsByFile = new Map<string, Set<string>>()
137
- const zodFilesByPath = new Map<string, KubbFile.File>()
139
+ const zodFilesByPath = new Map<string, ast.FileNode>()
138
140
 
139
141
  ops.forEach((op) => {
140
- const { zodSchemas, zodFile } = op
141
-
142
- if (!zodImportsByFile.has(zodFile.path)) {
143
- zodImportsByFile.set(zodFile.path, new Set())
142
+ if (!op.zodFile || !zodResolver) return
143
+ const names = resolveZodImportNames(op.node, zodResolver)
144
+ if (!zodImportsByFile.has(op.zodFile.path)) {
145
+ zodImportsByFile.set(op.zodFile.path, new Set())
144
146
  }
145
- const zodImports = zodImportsByFile.get(zodFile.path)!
146
-
147
- if (zodSchemas?.response?.name) zodImports.add(zodSchemas.response.name)
148
- if (zodSchemas?.request?.name) zodImports.add(zodSchemas.request.name)
149
- zodFilesByPath.set(zodFile.path, zodFile)
147
+ const imports = zodImportsByFile.get(op.zodFile.path)!
148
+ names.forEach((n) => {
149
+ imports.add(n)
150
+ })
151
+ zodFilesByPath.set(op.zodFile.path, op.zodFile)
150
152
  })
151
153
 
152
154
  return { zodImportsByFile, zodFilesByPath }
153
155
  }
154
156
 
155
- return controllers.map(({ name, file, operations: ops }) => {
156
- const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
157
- const { zodImportsByFile, zodFilesByPath } =
158
- options.parser === 'zod'
159
- ? collectZodImports(ops)
160
- : { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, KubbFile.File>() }
161
- const hasFormData = ops.some((op) => op.operation.getContentType() === 'multipart/form-data')
162
-
163
- return (
164
- <File
165
- key={file.path}
166
- baseName={file.baseName}
167
- path={file.path}
168
- meta={file.meta}
169
- banner={getBanner({ oas, output: options.output, config: driver.config })}
170
- footer={getFooter({ oas, output: options.output })}
171
- >
172
- {options.importPath ? (
173
- <>
174
- <File.Import name={'fetch'} path={options.importPath} />
175
- <File.Import name={['mergeConfig']} path={options.importPath} />
176
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={options.importPath} isTypeOnly />
177
- </>
178
- ) : (
179
- <>
180
- <File.Import name={['fetch']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
181
- <File.Import name={['mergeConfig']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
182
- <File.Import
183
- name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
184
- root={file.path}
185
- path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
186
- isTypeOnly
157
+ return (
158
+ <>
159
+ {controllers.map(({ name, file, operations: ops }) => {
160
+ const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
161
+ const { zodImportsByFile, zodFilesByPath } =
162
+ parser === 'zod' ? collectZodImports(ops) : { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, ast.FileNode>() }
163
+ const hasFormData = ops.some((op) => op.node.requestBody?.content?.[0]?.contentType === 'multipart/form-data')
164
+
165
+ return (
166
+ <File
167
+ key={file.path}
168
+ baseName={file.baseName}
169
+ path={file.path}
170
+ meta={file.meta}
171
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
172
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
173
+ >
174
+ {importPath ? (
175
+ <>
176
+ <File.Import name={'fetch'} path={importPath} />
177
+ <File.Import name={['mergeConfig']} path={importPath} />
178
+ <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
179
+ </>
180
+ ) : (
181
+ <>
182
+ <File.Import name={['fetch']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
183
+ <File.Import name={['mergeConfig']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
184
+ <File.Import
185
+ name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
186
+ root={file.path}
187
+ path={path.resolve(root, '.kubb/client.ts')}
188
+ isTypeOnly
189
+ />
190
+ </>
191
+ )}
192
+
193
+ {hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(root, '.kubb/config.ts')} />}
194
+
195
+ {Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
196
+ const typeFile = typeFilesByPath.get(filePath)
197
+ if (!typeFile) return null
198
+ const importNames = Array.from(importSet).filter(Boolean)
199
+ if (importNames.length === 0) return null
200
+ return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
201
+ })}
202
+
203
+ {parser === 'zod' &&
204
+ Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
205
+ const zodFile = zodFilesByPath.get(filePath)
206
+ if (!zodFile) return null
207
+ const importNames = Array.from(importSet).filter(Boolean)
208
+ if (importNames.length === 0) return null
209
+ return <File.Import key={filePath} name={importNames} root={file.path} path={zodFile.path} />
210
+ })}
211
+
212
+ <StaticClassClient
213
+ name={name}
214
+ operations={ops}
215
+ baseURL={baseURL}
216
+ dataReturnType={dataReturnType}
217
+ pathParamsType={pathParamsType}
218
+ paramsCasing={paramsCasing}
219
+ paramsType={paramsType}
220
+ parser={parser}
187
221
  />
188
- </>
189
- )}
190
-
191
- {hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/config.ts')} />}
192
-
193
- {Array.from(typeImportsByFile.entries()).map(([filePath, imports]) => {
194
- const typeFile = typeFilesByPath.get(filePath)
195
- if (!typeFile) {
196
- return null
197
- }
198
- const importNames = Array.from(imports).filter(Boolean)
199
- if (importNames.length === 0) {
200
- return null
201
- }
202
- return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
203
- })}
204
-
205
- {options.parser === 'zod' &&
206
- Array.from(zodImportsByFile.entries()).map(([filePath, imports]) => {
207
- const zodFile = zodFilesByPath.get(filePath)
208
- if (!zodFile) {
209
- return null
210
- }
211
- const importNames = Array.from(imports).filter(Boolean)
212
- if (importNames.length === 0) {
213
- return null
214
- }
215
-
216
- return <File.Import key={filePath} name={importNames} root={file.path} path={zodFile.path} />
217
- })}
218
-
219
- <StaticClassClient
220
- name={name}
221
- operations={ops}
222
- baseURL={options.baseURL}
223
- dataReturnType={options.dataReturnType}
224
- pathParamsType={options.pathParamsType}
225
- paramsCasing={options.paramsCasing}
226
- paramsType={options.paramsType}
227
- parser={options.parser}
228
- />
229
- </File>
230
- )
231
- })
222
+ </File>
223
+ )
224
+ })}
225
+ </>
226
+ )
232
227
  },
233
228
  })
package/src/index.ts CHANGED
@@ -1,2 +1,9 @@
1
- export { pluginClient, pluginClientName } from './plugin.ts'
2
- export type { ClientImportPath, PluginClient } from './types.ts'
1
+ export { Client } from './components/Client.tsx'
2
+ export { classClientGenerator } from './generators/classClientGenerator.tsx'
3
+ export { clientGenerator } from './generators/clientGenerator.tsx'
4
+ export { groupedClientGenerator } from './generators/groupedClientGenerator.tsx'
5
+ export { operationsGenerator } from './generators/operationsGenerator.tsx'
6
+ export { staticClassClientGenerator } from './generators/staticClassClientGenerator.tsx'
7
+ export { default, pluginClient, pluginClientName } from './plugin.ts'
8
+ export { resolverClient } from './resolvers/resolverClient.ts'
9
+ export type { ClientImportPath, PluginClient, ResolverClient } from './types.ts'