@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
package/src/utils.ts ADDED
@@ -0,0 +1,180 @@
1
+ import { URLPath } from '@internals/utils'
2
+ import type { ast } from '@kubb/core'
3
+ import type { ResolverTs } from '@kubb/plugin-ts'
4
+ import type { ResolverZod } from '@kubb/plugin-zod'
5
+ import { createFunctionParams } from './functionParams.ts'
6
+ import type { PluginClient } from './types.ts'
7
+
8
+ /**
9
+ * Extracts documentation comments from an operation node.
10
+ * Includes description, summary, link, and deprecation information.
11
+ */
12
+ export function getComments(node: ast.OperationNode): Array<string> {
13
+ return [
14
+ node.description && `@description ${node.description}`,
15
+ node.summary && `@summary ${node.summary}`,
16
+ node.path && `{@link ${new URLPath(node.path).URL}}`,
17
+ node.deprecated && '@deprecated',
18
+ ]
19
+ .filter((x): x is string => Boolean(x))
20
+ .flatMap((text) => text.split(/\r?\n/).map((line) => line.trim()))
21
+ .filter((x): x is string => Boolean(x))
22
+ }
23
+
24
+ /**
25
+ * Builds a mapping of original parameter names to their transformed (cased) names.
26
+ * Returns undefined if no names have changed.
27
+ */
28
+ export function buildParamsMapping(originalParams: Array<ast.ParameterNode>, casedParams: Array<ast.ParameterNode>): Record<string, string> | undefined {
29
+ const mapping: Record<string, string> = {}
30
+ let hasChanged = false
31
+ originalParams.forEach((param, i) => {
32
+ const casedName = casedParams[i]?.name ?? param.name
33
+ mapping[param.name] = casedName
34
+ if (param.name !== casedName) {
35
+ hasChanged = true
36
+ }
37
+ })
38
+ return hasChanged ? mapping : undefined
39
+ }
40
+
41
+ /**
42
+ * Builds HTTP headers array for a client request.
43
+ * Includes Content-Type (if not default) and spreads header parameters if present.
44
+ */
45
+ export function buildHeaders(contentType: string, hasHeaderParams: boolean): Array<string> {
46
+ return [
47
+ contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : undefined,
48
+ hasHeaderParams ? '...headers' : undefined,
49
+ ].filter(Boolean) as Array<string>
50
+ }
51
+
52
+ /**
53
+ * Builds TypeScript generic parameters for a client method.
54
+ * Includes response type, error type, and optional request type.
55
+ */
56
+ export function buildGenerics(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
57
+ const responseName = tsResolver.resolveResponseName(node)
58
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined
59
+ const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
60
+ const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
61
+ return [responseName, TError, requestName || 'unknown'].filter(Boolean)
62
+ }
63
+
64
+ /**
65
+ * Builds the parameters object for a class-based client method.
66
+ * Includes URL, method, base URL, headers, and request/response data.
67
+ */
68
+ export function buildClassClientParams({
69
+ node,
70
+ path,
71
+ baseURL,
72
+ tsResolver,
73
+ isFormData,
74
+ headers,
75
+ }: {
76
+ node: ast.OperationNode
77
+ path: URLPath
78
+ baseURL: string | undefined
79
+ tsResolver: ResolverTs
80
+ isFormData: boolean
81
+ headers: Array<string>
82
+ }) {
83
+ const queryParamsName =
84
+ node.parameters.filter((p) => p.in === 'query').length > 0
85
+ ? tsResolver.resolveQueryParamsName(node, node.parameters.filter((p) => p.in === 'query')[0]!)
86
+ : undefined
87
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined
88
+
89
+ return createFunctionParams({
90
+ config: {
91
+ mode: 'object',
92
+ children: {
93
+ requestConfig: {
94
+ mode: 'inlineSpread',
95
+ },
96
+ method: {
97
+ value: JSON.stringify(node.method.toUpperCase()),
98
+ },
99
+ url: {
100
+ value: path.template,
101
+ },
102
+ baseURL: baseURL
103
+ ? {
104
+ value: JSON.stringify(baseURL),
105
+ }
106
+ : undefined,
107
+ params: queryParamsName ? {} : undefined,
108
+ data: requestName
109
+ ? {
110
+ value: isFormData ? 'formData as FormData' : 'requestData',
111
+ }
112
+ : undefined,
113
+ headers: headers.length
114
+ ? {
115
+ value: `{ ${headers.join(', ')}, ...requestConfig.headers }`,
116
+ }
117
+ : undefined,
118
+ },
119
+ },
120
+ })
121
+ }
122
+
123
+ /**
124
+ * Builds the request data parsing line for client methods.
125
+ * Applies Zod validation if configured, otherwise uses data directly.
126
+ */
127
+ export function buildRequestDataLine({
128
+ parser,
129
+ node,
130
+ zodResolver,
131
+ }: {
132
+ parser: PluginClient['resolvedOptions']['parser'] | undefined
133
+ node: ast.OperationNode
134
+ zodResolver?: ResolverZod
135
+ }): string {
136
+ const zodRequestName = zodResolver && parser === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined
137
+ if (parser === 'zod' && zodRequestName) {
138
+ return `const requestData = ${zodRequestName}.parse(data)`
139
+ }
140
+ if (node.requestBody?.content?.[0]?.schema) {
141
+ return 'const requestData = data'
142
+ }
143
+ return ''
144
+ }
145
+
146
+ /**
147
+ * Builds the form data conversion line for file upload requests.
148
+ * Returns empty string if not applicable.
149
+ */
150
+ export function buildFormDataLine(isFormData: boolean, hasRequest: boolean): string {
151
+ return isFormData && hasRequest ? 'const formData = buildFormData(requestData)' : ''
152
+ }
153
+
154
+ /**
155
+ * Builds the return statement for a client method.
156
+ * Applies Zod validation to response data if configured, otherwise returns raw response.
157
+ */
158
+ export function buildReturnStatement({
159
+ dataReturnType,
160
+ parser,
161
+ node,
162
+ zodResolver,
163
+ }: {
164
+ dataReturnType: PluginClient['resolvedOptions']['dataReturnType']
165
+ parser: PluginClient['resolvedOptions']['parser'] | undefined
166
+ node: ast.OperationNode
167
+ zodResolver?: ResolverZod
168
+ }): string {
169
+ const zodResponseName = zodResolver && parser === 'zod' ? zodResolver.resolveResponseName?.(node) : undefined
170
+ if (dataReturnType === 'full' && parser === 'zod' && zodResponseName) {
171
+ return `return {...res, data: ${zodResponseName}.parse(res.data)}`
172
+ }
173
+ if (dataReturnType === 'data' && parser === 'zod' && zodResponseName) {
174
+ return `return ${zodResponseName}.parse(res.data)`
175
+ }
176
+ if (dataReturnType === 'full' && parser === 'client') {
177
+ return 'return res'
178
+ }
179
+ return 'return res.data'
180
+ }
@@ -31,7 +31,7 @@ export type ResponseConfig<TData = unknown> = {
31
31
 
32
32
  export type ResponseErrorConfig<TError = unknown> = AxiosError<TError>
33
33
 
34
- export type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>) => Promise<ResponseConfig<TData>>
34
+ export type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>
35
35
 
36
36
  let _config: Partial<RequestConfig> = {
37
37
  baseURL: typeof AXIOS_BASE !== 'undefined' ? AXIOS_BASE : undefined,
@@ -60,7 +60,10 @@ export const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T
60
60
 
61
61
  export const axiosInstance = axios.create(getConfig())
62
62
 
63
- export const fetch = async <TData, TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>): Promise<ResponseConfig<TData>> => {
63
+ export const fetch = async <TData, TError = unknown, TVariables = unknown>(
64
+ config: RequestConfig<TVariables>,
65
+ _request?: unknown,
66
+ ): Promise<ResponseConfig<TData>> => {
64
67
  return axiosInstance.request<TData, ResponseConfig<TData>>(mergeConfig(getConfig(), config)).catch((e: AxiosError<TError>) => {
65
68
  throw e
66
69
  })
@@ -52,9 +52,12 @@ export const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T
52
52
 
53
53
  export type ResponseErrorConfig<TError = unknown> = TError
54
54
 
55
- export type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>) => Promise<ResponseConfig<TData>>
55
+ export type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>
56
56
 
57
- export const fetch = async <TData, _TError = unknown, TVariables = unknown>(paramsConfig: RequestConfig<TVariables>): Promise<ResponseConfig<TData>> => {
57
+ export const fetch = async <TData, _TError = unknown, TVariables = unknown>(
58
+ paramsConfig: RequestConfig<TVariables>,
59
+ _request?: unknown,
60
+ ): Promise<ResponseConfig<TData>> => {
58
61
  const normalizedParams = new URLSearchParams()
59
62
 
60
63
  const config = mergeConfig(getConfig(), paramsConfig)