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

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 (61) 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/extension.yaml +776 -0
  23. package/package.json +67 -84
  24. package/src/clients/axios.ts +5 -1
  25. package/src/clients/fetch.ts +5 -1
  26. package/src/components/ClassClient.tsx +45 -142
  27. package/src/components/Client.tsx +90 -129
  28. package/src/components/Operations.tsx +10 -10
  29. package/src/components/StaticClassClient.tsx +44 -138
  30. package/src/components/Url.tsx +38 -48
  31. package/src/components/WrapperClient.tsx +3 -3
  32. package/src/functionParams.ts +118 -0
  33. package/src/generators/classClientGenerator.tsx +148 -171
  34. package/src/generators/clientGenerator.tsx +95 -82
  35. package/src/generators/groupedClientGenerator.tsx +50 -52
  36. package/src/generators/operationsGenerator.tsx +11 -18
  37. package/src/generators/staticClassClientGenerator.tsx +178 -183
  38. package/src/index.ts +9 -2
  39. package/src/plugin.ts +115 -145
  40. package/src/resolvers/resolverClient.ts +22 -0
  41. package/src/types.ts +104 -44
  42. package/src/utils.ts +180 -0
  43. package/templates/clients/axios.ts +5 -2
  44. package/templates/clients/fetch.ts +5 -2
  45. package/dist/StaticClassClient-By-aMAe4.cjs +0 -677
  46. package/dist/StaticClassClient-By-aMAe4.cjs.map +0 -1
  47. package/dist/StaticClassClient-CCn9g9eF.js +0 -636
  48. package/dist/StaticClassClient-CCn9g9eF.js.map +0 -1
  49. package/dist/components.cjs +0 -7
  50. package/dist/components.d.ts +0 -216
  51. package/dist/components.js +0 -2
  52. package/dist/generators-BYUJaeZP.js +0 -723
  53. package/dist/generators-BYUJaeZP.js.map +0 -1
  54. package/dist/generators-DTxD9FDY.cjs +0 -753
  55. package/dist/generators-DTxD9FDY.cjs.map +0 -1
  56. package/dist/generators.cjs +0 -7
  57. package/dist/generators.d.ts +0 -517
  58. package/dist/generators.js +0 -2
  59. package/dist/types-DBQdg-BV.d.ts +0 -169
  60. package/src/components/index.ts +0 -5
  61. 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)