@kubb/plugin-client 5.0.0-beta.42 → 5.0.0-beta.64

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 (39) hide show
  1. package/dist/clients/axios.cjs.map +1 -1
  2. package/dist/clients/axios.js.map +1 -1
  3. package/dist/clients/fetch.cjs.map +1 -1
  4. package/dist/clients/fetch.js.map +1 -1
  5. package/dist/index.cjs +439 -383
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.ts +60 -25
  8. package/dist/index.js +435 -383
  9. package/dist/index.js.map +1 -1
  10. package/dist/templates/clients/axios.source.cjs.map +1 -1
  11. package/dist/templates/clients/axios.source.js.map +1 -1
  12. package/dist/templates/clients/fetch.source.cjs.map +1 -1
  13. package/dist/templates/clients/fetch.source.js.map +1 -1
  14. package/dist/templates/config.source.cjs.map +1 -1
  15. package/dist/templates/config.source.js.map +1 -1
  16. package/package.json +10 -18
  17. package/extension.yaml +0 -1267
  18. package/src/clients/axios.ts +0 -113
  19. package/src/clients/fetch.ts +0 -201
  20. package/src/components/ClassClient.tsx +0 -137
  21. package/src/components/Client.tsx +0 -273
  22. package/src/components/Operations.tsx +0 -29
  23. package/src/components/StaticClassClient.tsx +0 -129
  24. package/src/components/Url.tsx +0 -91
  25. package/src/components/WrapperClient.tsx +0 -33
  26. package/src/functionParams.ts +0 -118
  27. package/src/generators/classClientGenerator.tsx +0 -253
  28. package/src/generators/clientGenerator.tsx +0 -127
  29. package/src/generators/groupedClientGenerator.tsx +0 -82
  30. package/src/generators/operationsGenerator.tsx +0 -34
  31. package/src/generators/staticClassClientGenerator.tsx +0 -232
  32. package/src/index.ts +0 -9
  33. package/src/plugin.ts +0 -160
  34. package/src/resolvers/resolverClient.ts +0 -45
  35. package/src/templates/clients/axios.source.ts +0 -4
  36. package/src/templates/clients/fetch.source.ts +0 -4
  37. package/src/templates/config.source.ts +0 -4
  38. package/src/types.ts +0 -268
  39. package/src/utils.ts +0 -159
@@ -1,253 +0,0 @@
1
- import path from 'node:path'
2
- import { operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
3
- import { camelCase } from '@internals/utils'
4
- import { ast, defineGenerator } from '@kubb/core'
5
- import type { ResolverTs } from '@kubb/plugin-ts'
6
- import { pluginTsName } from '@kubb/plugin-ts'
7
- import type { ResolverZod } from '@kubb/plugin-zod'
8
- import { pluginZodName } from '@kubb/plugin-zod'
9
- import { File, jsxRendererSync } from '@kubb/renderer-jsx'
10
- import { ClassClient } from '../components/ClassClient'
11
- import { WrapperClient } from '../components/WrapperClient'
12
- import type { PluginClient } from '../types'
13
-
14
- type OperationData = {
15
- node: ast.OperationNode
16
- name: string
17
- tsResolver: ResolverTs
18
- zodResolver: ResolverZod | null
19
- typeFile: ast.FileNode
20
- zodFile: ast.FileNode | null
21
- }
22
-
23
- type Controller = {
24
- name: string
25
- propertyName: string
26
- file: ast.FileNode
27
- operations: Array<OperationData>
28
- }
29
-
30
- function resolveTypeImportNames(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
31
- return resolveOperationTypeNames(node, tsResolver, { order: 'body-response-first' })
32
- }
33
-
34
- function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod): Array<string> {
35
- const names: Array<string | null | undefined> = [
36
- zodResolver.resolveResponseName?.(node),
37
- node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
38
- ]
39
- return names.filter((n): n is string => Boolean(n))
40
- }
41
-
42
- /**
43
- * Built-in `operations` generator for `@kubb/plugin-client` when
44
- * `clientType: 'class'`. Emits one class per tag, with one instance method
45
- * per operation and a shared constructor for request configuration.
46
- */
47
- export const classClientGenerator = defineGenerator<PluginClient>({
48
- name: 'classClient',
49
- renderer: jsxRendererSync,
50
- operations(nodes, ctx) {
51
- const { config, driver, resolver, root } = ctx
52
- const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, sdk } = ctx.options
53
- const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL
54
-
55
- const pluginTs = driver.getPlugin(pluginTsName)
56
- if (!pluginTs) return null
57
-
58
- const tsResolver = driver.getResolver(pluginTsName)
59
- const tsPluginOptions = pluginTs.options
60
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
61
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
62
-
63
- function buildOperationData(node: ast.OperationNode): OperationData {
64
- const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
65
- root,
66
- output: tsPluginOptions?.output ?? output,
67
- group: tsPluginOptions?.group,
68
- })
69
- const zodFile =
70
- zodResolver && pluginZod?.options
71
- ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
72
- root,
73
- output: pluginZod.options?.output ?? output,
74
- group: pluginZod.options?.group ?? undefined,
75
- })
76
- : null
77
-
78
- return {
79
- node: node,
80
- name: resolver.resolveName(node.operationId),
81
- tsResolver,
82
- zodResolver,
83
- typeFile,
84
- zodFile,
85
- }
86
- }
87
-
88
- const controllers = nodes.reduce((acc, operationNode) => {
89
- if (!ast.isHttpOperationNode(operationNode)) return acc
90
- const tag = operationNode.tags[0]
91
- const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag)) : resolver.resolveGroupName('Client')
92
-
93
- if (!tag && !group) {
94
- const name = resolver.resolveClassName('ApiClient')
95
- const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group: group ?? undefined })
96
- const operationData = buildOperationData(operationNode)
97
- const previous = acc.find((item) => item.file.path === file.path)
98
-
99
- if (previous) {
100
- previous.operations.push(operationData)
101
- } else {
102
- acc.push({ name, propertyName: resolver.resolveClientPropertyName(name), file, operations: [operationData] })
103
- }
104
- return acc
105
- }
106
-
107
- if (tag) {
108
- const name = groupName
109
- const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group: group ?? undefined })
110
- const operationData = buildOperationData(operationNode)
111
- const previous = acc.find((item) => item.file.path === file.path)
112
-
113
- if (previous) {
114
- previous.operations.push(operationData)
115
- } else {
116
- acc.push({ name, propertyName: resolver.resolveClientPropertyName(name), file, operations: [operationData] })
117
- }
118
- }
119
-
120
- return acc
121
- }, [] as Array<Controller>)
122
-
123
- function collectTypeImports(ops: Array<OperationData>) {
124
- const typeImportsByFile = new Map<string, Set<string>>()
125
- const typeFilesByPath = new Map<string, ast.FileNode>()
126
-
127
- ops.forEach((op) => {
128
- const names = resolveTypeImportNames(op.node, tsResolver)
129
- if (!typeImportsByFile.has(op.typeFile.path)) {
130
- typeImportsByFile.set(op.typeFile.path, new Set())
131
- }
132
- const imports = typeImportsByFile.get(op.typeFile.path)!
133
- names.forEach((n) => {
134
- imports.add(n)
135
- })
136
- typeFilesByPath.set(op.typeFile.path, op.typeFile)
137
- })
138
-
139
- return { typeImportsByFile, typeFilesByPath }
140
- }
141
-
142
- function collectZodImports(ops: Array<OperationData>) {
143
- const zodImportsByFile = new Map<string, Set<string>>()
144
- const zodFilesByPath = new Map<string, ast.FileNode>()
145
-
146
- ops.forEach((op) => {
147
- if (!op.zodFile || !zodResolver) return
148
- const names = resolveZodImportNames(op.node, zodResolver)
149
- if (!zodImportsByFile.has(op.zodFile.path)) {
150
- zodImportsByFile.set(op.zodFile.path, new Set())
151
- }
152
- const imports = zodImportsByFile.get(op.zodFile.path)!
153
- names.forEach((n) => {
154
- imports.add(n)
155
- })
156
- zodFilesByPath.set(op.zodFile.path, op.zodFile)
157
- })
158
-
159
- return { zodImportsByFile, zodFilesByPath }
160
- }
161
-
162
- const files = controllers.map(({ name, file, operations: ops }) => {
163
- const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
164
- const { zodImportsByFile, zodFilesByPath } =
165
- parser === 'zod' ? collectZodImports(ops) : { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, ast.FileNode>() }
166
- const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') ?? false)
167
-
168
- return (
169
- <File
170
- key={file.path}
171
- baseName={file.baseName}
172
- path={file.path}
173
- meta={file.meta}
174
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
175
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
176
- >
177
- {importPath ? (
178
- <>
179
- <File.Import name={'client'} path={importPath} />
180
- <File.Import name={['mergeConfig']} path={importPath} />
181
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
182
- </>
183
- ) : (
184
- <>
185
- <File.Import name={['client']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
186
- <File.Import name={['mergeConfig']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
187
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
188
- </>
189
- )}
190
-
191
- {hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(root, '.kubb/config.ts')} />}
192
-
193
- {Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
194
- const typeFile = typeFilesByPath.get(filePath)
195
- if (!typeFile) return null
196
- const importNames = Array.from(importSet).filter(Boolean)
197
- if (importNames.length === 0) return null
198
- return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
199
- })}
200
-
201
- {parser === 'zod' &&
202
- Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
203
- const zodFile = zodFilesByPath.get(filePath)
204
- if (!zodFile) return null
205
- const importNames = Array.from(importSet).filter(Boolean)
206
- if (importNames.length === 0) return null
207
- return <File.Import key={filePath} name={importNames} root={file.path} path={zodFile.path} />
208
- })}
209
-
210
- <ClassClient
211
- name={name}
212
- operations={ops}
213
- baseURL={baseURL}
214
- dataReturnType={dataReturnType}
215
- pathParamsType={pathParamsType}
216
- paramsCasing={paramsCasing}
217
- paramsType={paramsType}
218
- parser={parser}
219
- />
220
- </File>
221
- )
222
- })
223
-
224
- if (sdk) {
225
- const sdkFile = resolver.resolveFile({ name: sdk.className, extname: '.ts' }, { root, output, group: group ?? undefined })
226
-
227
- files.push(
228
- <File
229
- key={sdkFile.path}
230
- baseName={sdkFile.baseName}
231
- path={sdkFile.path}
232
- meta={sdkFile.meta}
233
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: sdkFile.path, baseName: sdkFile.baseName } })}
234
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: sdkFile.path, baseName: sdkFile.baseName } })}
235
- >
236
- {importPath ? (
237
- <File.Import name={['Client', 'RequestConfig']} path={importPath} isTypeOnly />
238
- ) : (
239
- <File.Import name={['Client', 'RequestConfig']} root={sdkFile.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
240
- )}
241
-
242
- {controllers.map(({ name, file }) => (
243
- <File.Import key={name} name={[name]} root={sdkFile.path} path={file.path} />
244
- ))}
245
-
246
- <WrapperClient name={sdk.className} controllers={controllers.map(({ name, propertyName }) => ({ className: name, propertyName }))} />
247
- </File>,
248
- )
249
- }
250
-
251
- return <>{files}</>
252
- },
253
- })
@@ -1,127 +0,0 @@
1
- import path from 'node:path'
2
- import { operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
3
- import { ast, defineGenerator } from '@kubb/core'
4
- import { pluginTsName } from '@kubb/plugin-ts'
5
- import { pluginZodName } from '@kubb/plugin-zod'
6
- import { File, jsxRendererSync } from '@kubb/renderer-jsx'
7
- import { Client } from '../components/Client'
8
- import { Url } from '../components/Url.tsx'
9
- import type { PluginClient } from '../types'
10
-
11
- /**
12
- * Built-in operation generator for `@kubb/plugin-client`. Emits one async
13
- * function per OpenAPI operation, plus the matching URL helper. Used when
14
- * `clientType: 'function'` (the default).
15
- */
16
- export const clientGenerator = defineGenerator<PluginClient>({
17
- name: 'client',
18
- renderer: jsxRendererSync,
19
- operation(node, ctx) {
20
- if (!ast.isHttpOperationNode(node)) return null
21
- const { config, driver, resolver, root } = ctx
22
- const { output, urlType, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath, group } = ctx.options
23
- const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL
24
-
25
- const pluginTs = driver.getPlugin(pluginTsName)
26
-
27
- if (!pluginTs) {
28
- return null
29
- }
30
-
31
- const tsResolver = driver.getResolver(pluginTsName)
32
-
33
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
34
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
35
-
36
- const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing })
37
-
38
- const importedZodNames =
39
- zodResolver && parser === 'zod'
40
- ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null].filter(
41
- (name): name is string => Boolean(name),
42
- )
43
- : []
44
-
45
- const meta = {
46
- name: resolver.resolveName(node.operationId),
47
- urlName: resolver.resolveUrlName(node),
48
- file: resolver.resolveFile(operationFileEntry(node, node.operationId), { root, output, group: group ?? undefined }),
49
- fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
50
- root,
51
- output: pluginTs.options?.output ?? output,
52
- group: pluginTs.options?.group ?? undefined,
53
- }),
54
- fileZod:
55
- zodResolver && pluginZod?.options
56
- ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
57
- root,
58
- output: pluginZod.options.output ?? output,
59
- group: pluginZod.options?.group ?? undefined,
60
- })
61
- : null,
62
- } as const
63
-
64
- const hasFormData = node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') ?? false
65
-
66
- return (
67
- <File
68
- baseName={meta.file.baseName}
69
- path={meta.file.path}
70
- meta={meta.file.meta}
71
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
72
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
73
- >
74
- {importPath ? (
75
- <>
76
- <File.Import name={'client'} path={importPath} />
77
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
78
- </>
79
- ) : (
80
- <>
81
- <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />
82
- <File.Import
83
- name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
84
- root={meta.file.path}
85
- path={path.resolve(root, '.kubb/client.ts')}
86
- isTypeOnly
87
- />
88
- </>
89
- )}
90
-
91
- {hasFormData && <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />}
92
-
93
- {meta.fileZod && importedZodNames.length > 0 && <File.Import name={importedZodNames as Array<string>} root={meta.file.path} path={meta.fileZod.path} />}
94
-
95
- {meta.fileTs && importedTypeNames.length > 0 && (
96
- <File.Import name={Array.from(new Set(importedTypeNames))} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
97
- )}
98
-
99
- <Url
100
- name={meta.urlName}
101
- baseURL={baseURL}
102
- pathParamsType={pathParamsType}
103
- paramsCasing={paramsCasing}
104
- paramsType={paramsType}
105
- node={node}
106
- tsResolver={tsResolver}
107
- isIndexable={urlType === 'export'}
108
- isExportable={urlType === 'export'}
109
- />
110
-
111
- <Client
112
- name={meta.name}
113
- urlName={meta.urlName}
114
- baseURL={baseURL}
115
- dataReturnType={dataReturnType}
116
- pathParamsType={pathParamsType}
117
- paramsCasing={paramsCasing}
118
- paramsType={paramsType}
119
- node={node}
120
- tsResolver={tsResolver}
121
- zodResolver={zodResolver}
122
- parser={parser}
123
- />
124
- </File>
125
- )
126
- },
127
- })
@@ -1,82 +0,0 @@
1
- import { camelCase } from '@internals/utils'
2
- import type { ast } from '@kubb/core'
3
- import { defineGenerator } from '@kubb/core'
4
- import { File, Function, jsxRendererSync } from '@kubb/renderer-jsx'
5
- import type { PluginClient } from '../types'
6
-
7
- /**
8
- * Emits one aggregate file per tag/group when `group` is configured. Each
9
- * file re-exports every client function for that group, so callers can
10
- * `import { petController } from './gen/clients'` instead of importing
11
- * each operation individually.
12
- */
13
- export const groupedClientGenerator = defineGenerator<PluginClient>({
14
- name: 'groupedClient',
15
- renderer: jsxRendererSync,
16
- operations(nodes, ctx) {
17
- const { config, resolver, root } = ctx
18
- const { output, group } = ctx.options
19
-
20
- const controllers = nodes.reduce(
21
- (acc, operationNode) => {
22
- if (group?.type === 'tag') {
23
- const tag = operationNode.tags[0]
24
- const name = tag ? group?.name?.({ group: camelCase(tag) }) : null
25
-
26
- if (!tag || !name) {
27
- return acc
28
- }
29
-
30
- const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group: group ?? undefined })
31
- const clientFile = resolver.resolveFile(
32
- { name: operationNode.operationId, extname: '.ts', tag: operationNode.tags[0] ?? 'default', path: operationNode.path },
33
- { root, output, group: group ?? undefined },
34
- )
35
-
36
- const client = {
37
- name: resolver.resolveName(operationNode.operationId),
38
- file: clientFile,
39
- }
40
-
41
- const previous = acc.find((item) => item.file.path === file.path)
42
-
43
- if (previous) {
44
- previous.clients.push(client)
45
- } else {
46
- acc.push({ name, file, clients: [client] })
47
- }
48
- }
49
-
50
- return acc
51
- },
52
- [] as Array<{ name: string; file: ast.FileNode; clients: Array<{ name: string; file: ast.FileNode }> }>,
53
- )
54
-
55
- return (
56
- <>
57
- {controllers.map(({ name, file, clients }) => {
58
- return (
59
- <File
60
- key={file.path}
61
- baseName={file.baseName}
62
- path={file.path}
63
- meta={file.meta}
64
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName, isAggregation: true } })}
65
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName, isAggregation: true } })}
66
- >
67
- {clients.map((client) => (
68
- <File.Import key={client.name} name={[client.name]} root={file.path} path={client.file.path} />
69
- ))}
70
-
71
- <File.Source name={name} isExportable isIndexable>
72
- <Function export name={name}>
73
- {`return { ${clients.map((client) => client.name).join(', ')} }`}
74
- </Function>
75
- </File.Source>
76
- </File>
77
- )
78
- })}
79
- </>
80
- )
81
- },
82
- })
@@ -1,34 +0,0 @@
1
- import { ast, defineGenerator } from '@kubb/core'
2
- import { File, jsxRendererSync } from '@kubb/renderer-jsx'
3
- import { Operations } from '../components/Operations'
4
- import type { PluginClient } from '../types'
5
-
6
- /**
7
- * Generates an `operations.ts` file that re-exports every operation grouped
8
- * by HTTP method. Enabled when `pluginClient({ operations: true })`. Useful
9
- * for building meta-tooling on top of the generated client (route
10
- * registries, API explorers).
11
- */
12
- export const operationsGenerator = defineGenerator<PluginClient>({
13
- name: 'client',
14
- renderer: jsxRendererSync,
15
- operations(nodes, ctx) {
16
- const { config, resolver, root } = ctx
17
- const { output, group } = ctx.options
18
-
19
- const name = 'operations'
20
- const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group: group ?? undefined })
21
-
22
- return (
23
- <File
24
- baseName={file.baseName}
25
- path={file.path}
26
- meta={file.meta}
27
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
28
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
29
- >
30
- <Operations name={name} nodes={nodes.filter(ast.isHttpOperationNode)} />
31
- </File>
32
- )
33
- },
34
- })