@kubb/plugin-client 4.17.1 → 4.18.1

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 (54) hide show
  1. package/dist/{Operations-DNpUQb3J.cjs → StaticClassClient-Doy7nyLp.cjs} +138 -18
  2. package/dist/StaticClassClient-Doy7nyLp.cjs.map +1 -0
  3. package/dist/{Operations-CSMXl98_.js → StaticClassClient-yRrX6THy.js} +134 -19
  4. package/dist/StaticClassClient-yRrX6THy.js.map +1 -0
  5. package/dist/{chunk-CbDLau6x.cjs → chunk-C1_xRkKa.cjs} +10 -0
  6. package/dist/chunk-iVr_oF3V.js +9 -0
  7. package/dist/clients/axios.cjs +1 -1
  8. package/dist/clients/axios.cjs.map +1 -1
  9. package/dist/clients/axios.d.cts +1 -0
  10. package/dist/clients/axios.d.ts +1 -0
  11. package/dist/clients/axios.js +1 -0
  12. package/dist/clients/axios.js.map +1 -1
  13. package/dist/clients/fetch.cjs +1 -0
  14. package/dist/clients/fetch.cjs.map +1 -1
  15. package/dist/clients/fetch.d.cts +2 -0
  16. package/dist/clients/fetch.d.ts +2 -0
  17. package/dist/clients/fetch.js +2 -0
  18. package/dist/clients/fetch.js.map +1 -1
  19. package/dist/components.cjs +6 -5
  20. package/dist/components.d.cts +55 -6
  21. package/dist/components.d.ts +55 -6
  22. package/dist/components.js +2 -2
  23. package/dist/{generators-DPH1gCSf.cjs → generators-BPQFq13R.cjs} +203 -7
  24. package/dist/generators-BPQFq13R.cjs.map +1 -0
  25. package/dist/{generators-DPpE1g5P.js → generators-CtXa-3Fh.js} +194 -3
  26. package/dist/generators-CtXa-3Fh.js.map +1 -0
  27. package/dist/generators.cjs +3 -2
  28. package/dist/generators.d.cts +6 -2
  29. package/dist/generators.d.ts +6 -2
  30. package/dist/generators.js +2 -2
  31. package/dist/index.cjs +4 -4
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +2 -1
  34. package/dist/index.d.ts +2 -1
  35. package/dist/index.js +4 -3
  36. package/dist/index.js.map +1 -1
  37. package/dist/{types-CLOc9nuD.d.cts → types-Chp-emXk.d.cts} +4 -2
  38. package/dist/{types-Bw1u7Glb.d.ts → types-aqsuGVmg.d.ts} +4 -2
  39. package/package.json +8 -8
  40. package/src/components/Client.tsx +2 -2
  41. package/src/components/StaticClassClient.tsx +224 -0
  42. package/src/components/Url.tsx +2 -2
  43. package/src/components/index.ts +1 -0
  44. package/src/generators/__snapshots__/static/Pet.ts +186 -0
  45. package/src/generators/__snapshots__/static/Store.ts +105 -0
  46. package/src/generators/__snapshots__/static/User.ts +143 -0
  47. package/src/generators/index.ts +1 -0
  48. package/src/generators/staticClassClientGenerator.tsx +231 -0
  49. package/src/plugin.ts +4 -2
  50. package/src/types.ts +2 -1
  51. package/dist/Operations-CSMXl98_.js.map +0 -1
  52. package/dist/Operations-DNpUQb3J.cjs.map +0 -1
  53. package/dist/generators-DPH1gCSf.cjs.map +0 -1
  54. package/dist/generators-DPpE1g5P.js.map +0 -1
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Generated by Kubb (https://kubb.dev/).
3
+ * Do not edit manually.
4
+ */
5
+ import type { RequestConfig, ResponseErrorConfig } from './test/.kubb/fetch'
6
+ import type {
7
+ UpdatePetMutationRequest,
8
+ UpdatePetMutationResponse,
9
+ UpdatePet400,
10
+ UpdatePet404,
11
+ UpdatePet405,
12
+ AddPetMutationRequest,
13
+ AddPetMutationResponse,
14
+ AddPet405,
15
+ FindPetsByStatusQueryResponse,
16
+ FindPetsByStatusQueryParams,
17
+ FindPetsByStatus400,
18
+ FindPetsByTagsQueryResponse,
19
+ FindPetsByTagsQueryParams,
20
+ FindPetsByTags400,
21
+ GetPetByIdQueryResponse,
22
+ GetPetByIdPathParams,
23
+ GetPetById400,
24
+ GetPetById404,
25
+ UpdatePetWithFormMutationResponse,
26
+ UpdatePetWithFormPathParams,
27
+ UpdatePetWithFormQueryParams,
28
+ UpdatePetWithForm405,
29
+ DeletePetMutationResponse,
30
+ DeletePetPathParams,
31
+ DeletePetHeaderParams,
32
+ DeletePet400,
33
+ UploadFileMutationRequest,
34
+ UploadFileMutationResponse,
35
+ UploadFilePathParams,
36
+ UploadFileQueryParams,
37
+ } from './findByTags'
38
+ import { buildFormData } from './test/.kubb/config'
39
+ import { fetch } from './test/.kubb/fetch'
40
+
41
+ export class Pet {
42
+ static #client: typeof fetch = fetch
43
+
44
+ /**
45
+ * @description Update an existing pet by Id
46
+ * @summary Update an existing pet
47
+ * {@link /pet}
48
+ */
49
+ static async updatePet(data: UpdatePetMutationRequest, config: Partial<RequestConfig<UpdatePetMutationRequest>> & { client?: typeof fetch } = {}) {
50
+ const { client: request = this.#client, ...requestConfig } = config
51
+ const requestData = data
52
+ const res = await request<UpdatePetMutationResponse, ResponseErrorConfig<UpdatePet400 | UpdatePet404 | UpdatePet405>, UpdatePetMutationRequest>({
53
+ method: 'PUT',
54
+ url: `/pet`,
55
+ data: requestData,
56
+ ...requestConfig,
57
+ })
58
+ return res.data
59
+ }
60
+
61
+ /**
62
+ * @description Add a new pet to the store
63
+ * @summary Add a new pet to the store
64
+ * {@link /pet}
65
+ */
66
+ static async addPet(data: AddPetMutationRequest, config: Partial<RequestConfig<AddPetMutationRequest>> & { client?: typeof fetch } = {}) {
67
+ const { client: request = this.#client, ...requestConfig } = config
68
+ const requestData = data
69
+ const res = await request<AddPetMutationResponse, ResponseErrorConfig<AddPet405>, AddPetMutationRequest>({
70
+ method: 'POST',
71
+ url: `/pet`,
72
+ data: requestData,
73
+ ...requestConfig,
74
+ })
75
+ return res.data
76
+ }
77
+
78
+ /**
79
+ * @description Multiple status values can be provided with comma separated strings
80
+ * @summary Finds Pets by status
81
+ * {@link /pet/findByStatus}
82
+ */
83
+ static async findPetsByStatus(params?: FindPetsByStatusQueryParams, config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
84
+ const { client: request = this.#client, ...requestConfig } = config
85
+ const res = await request<FindPetsByStatusQueryResponse, ResponseErrorConfig<FindPetsByStatus400>, unknown>({
86
+ method: 'GET',
87
+ url: `/pet/findByStatus`,
88
+ params,
89
+ ...requestConfig,
90
+ })
91
+ return res.data
92
+ }
93
+
94
+ /**
95
+ * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
96
+ * @summary Finds Pets by tags
97
+ * {@link /pet/findByTags}
98
+ */
99
+ static async findPetsByTags(params?: FindPetsByTagsQueryParams, config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
100
+ const { client: request = this.#client, ...requestConfig } = config
101
+ const res = await request<FindPetsByTagsQueryResponse, ResponseErrorConfig<FindPetsByTags400>, unknown>({
102
+ method: 'GET',
103
+ url: `/pet/findByTags`,
104
+ params,
105
+ ...requestConfig,
106
+ })
107
+ return res.data
108
+ }
109
+
110
+ /**
111
+ * @description Returns a single pet
112
+ * @summary Find pet by ID
113
+ * {@link /pet/:petId}
114
+ */
115
+ static async getPetById(petId: GetPetByIdPathParams['petId'], config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
116
+ const { client: request = this.#client, ...requestConfig } = config
117
+ const res = await request<GetPetByIdQueryResponse, ResponseErrorConfig<GetPetById400 | GetPetById404>, unknown>({
118
+ method: 'GET',
119
+ url: `/pet/${petId}`,
120
+ ...requestConfig,
121
+ })
122
+ return res.data
123
+ }
124
+
125
+ /**
126
+ * @summary Updates a pet in the store with form data
127
+ * {@link /pet/:petId}
128
+ */
129
+ static async updatePetWithForm(
130
+ petId: UpdatePetWithFormPathParams['petId'],
131
+ params?: UpdatePetWithFormQueryParams,
132
+ config: Partial<RequestConfig> & { client?: typeof fetch } = {},
133
+ ) {
134
+ const { client: request = this.#client, ...requestConfig } = config
135
+ const res = await request<UpdatePetWithFormMutationResponse, ResponseErrorConfig<UpdatePetWithForm405>, unknown>({
136
+ method: 'POST',
137
+ url: `/pet/${petId}`,
138
+ params,
139
+ ...requestConfig,
140
+ })
141
+ return res.data
142
+ }
143
+
144
+ /**
145
+ * @description delete a pet
146
+ * @summary Deletes a pet
147
+ * {@link /pet/:petId}
148
+ */
149
+ static async deletePet(
150
+ petId: DeletePetPathParams['petId'],
151
+ headers?: DeletePetHeaderParams,
152
+ config: Partial<RequestConfig> & { client?: typeof fetch } = {},
153
+ ) {
154
+ const { client: request = this.#client, ...requestConfig } = config
155
+ const res = await request<DeletePetMutationResponse, ResponseErrorConfig<DeletePet400>, unknown>({
156
+ method: 'DELETE',
157
+ url: `/pet/${petId}`,
158
+ ...requestConfig,
159
+ headers: { ...headers, ...requestConfig.headers },
160
+ })
161
+ return res.data
162
+ }
163
+
164
+ /**
165
+ * @summary uploads an image
166
+ * {@link /pet/:petId/uploadImage}
167
+ */
168
+ static async uploadFile(
169
+ petId: UploadFilePathParams['petId'],
170
+ data: UploadFileMutationRequest,
171
+ params?: UploadFileQueryParams,
172
+ config: Partial<RequestConfig<UploadFileMutationRequest>> & { client?: typeof fetch } = {},
173
+ ) {
174
+ const { client: request = this.#client, ...requestConfig } = config
175
+ const requestData = data
176
+ const formData = buildFormData(requestData)
177
+ const res = await request<UploadFileMutationResponse, ResponseErrorConfig<Error>, UploadFileMutationRequest>({
178
+ method: 'POST',
179
+ url: `/pet/${petId}/uploadImage`,
180
+ params,
181
+ data: formData as FormData,
182
+ ...requestConfig,
183
+ })
184
+ return res.data
185
+ }
186
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Generated by Kubb (https://kubb.dev/).
3
+ * Do not edit manually.
4
+ */
5
+ import type { RequestConfig, ResponseErrorConfig } from './test/.kubb/fetch'
6
+ import type {
7
+ GetInventoryQueryResponse,
8
+ PlaceOrderMutationRequest,
9
+ PlaceOrderMutationResponse,
10
+ PlaceOrder405,
11
+ PlaceOrderPatchMutationRequest,
12
+ PlaceOrderPatchMutationResponse,
13
+ PlaceOrderPatch405,
14
+ GetOrderByIdQueryResponse,
15
+ GetOrderByIdPathParams,
16
+ GetOrderById400,
17
+ GetOrderById404,
18
+ DeleteOrderMutationResponse,
19
+ DeleteOrderPathParams,
20
+ DeleteOrder400,
21
+ DeleteOrder404,
22
+ } from './findByTags'
23
+ import { fetch } from './test/.kubb/fetch'
24
+
25
+ export class Store {
26
+ static #client: typeof fetch = fetch
27
+
28
+ /**
29
+ * @description Returns a map of status codes to quantities
30
+ * @summary Returns pet inventories by status
31
+ * {@link /store/inventory}
32
+ */
33
+ static async getInventory(config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
34
+ const { client: request = this.#client, ...requestConfig } = config
35
+ const res = await request<GetInventoryQueryResponse, ResponseErrorConfig<Error>, unknown>({ method: 'GET', url: `/store/inventory`, ...requestConfig })
36
+ return res.data
37
+ }
38
+
39
+ /**
40
+ * @description Place a new order in the store
41
+ * @summary Place an order for a pet
42
+ * {@link /store/order}
43
+ */
44
+ static async placeOrder(data?: PlaceOrderMutationRequest, config: Partial<RequestConfig<PlaceOrderMutationRequest>> & { client?: typeof fetch } = {}) {
45
+ const { client: request = this.#client, ...requestConfig } = config
46
+ const requestData = data
47
+ const res = await request<PlaceOrderMutationResponse, ResponseErrorConfig<PlaceOrder405>, PlaceOrderMutationRequest>({
48
+ method: 'POST',
49
+ url: `/store/order`,
50
+ data: requestData,
51
+ ...requestConfig,
52
+ })
53
+ return res.data
54
+ }
55
+
56
+ /**
57
+ * @description Place a new order in the store with patch
58
+ * @summary Place an order for a pet with patch
59
+ * {@link /store/order}
60
+ */
61
+ static async placeOrderPatch(
62
+ data?: PlaceOrderPatchMutationRequest,
63
+ config: Partial<RequestConfig<PlaceOrderPatchMutationRequest>> & { client?: typeof fetch } = {},
64
+ ) {
65
+ const { client: request = this.#client, ...requestConfig } = config
66
+ const requestData = data
67
+ const res = await request<PlaceOrderPatchMutationResponse, ResponseErrorConfig<PlaceOrderPatch405>, PlaceOrderPatchMutationRequest>({
68
+ method: 'PATCH',
69
+ url: `/store/order`,
70
+ data: requestData,
71
+ ...requestConfig,
72
+ })
73
+ return res.data
74
+ }
75
+
76
+ /**
77
+ * @description For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.
78
+ * @summary Find purchase order by ID
79
+ * {@link /store/order/:orderId}
80
+ */
81
+ static async getOrderById(orderId: GetOrderByIdPathParams['orderId'], config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
82
+ const { client: request = this.#client, ...requestConfig } = config
83
+ const res = await request<GetOrderByIdQueryResponse, ResponseErrorConfig<GetOrderById400 | GetOrderById404>, unknown>({
84
+ method: 'GET',
85
+ url: `/store/order/${orderId}`,
86
+ ...requestConfig,
87
+ })
88
+ return res.data
89
+ }
90
+
91
+ /**
92
+ * @description For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
93
+ * @summary Delete purchase order by ID
94
+ * {@link /store/order/:orderId}
95
+ */
96
+ static async deleteOrder(orderId: DeleteOrderPathParams['orderId'], config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
97
+ const { client: request = this.#client, ...requestConfig } = config
98
+ const res = await request<DeleteOrderMutationResponse, ResponseErrorConfig<DeleteOrder400 | DeleteOrder404>, unknown>({
99
+ method: 'DELETE',
100
+ url: `/store/order/${orderId}`,
101
+ ...requestConfig,
102
+ })
103
+ return res.data
104
+ }
105
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Generated by Kubb (https://kubb.dev/).
3
+ * Do not edit manually.
4
+ */
5
+ import type { RequestConfig, ResponseErrorConfig } from './test/.kubb/fetch'
6
+ import type {
7
+ CreateUserMutationRequest,
8
+ CreateUserMutationResponse,
9
+ CreateUsersWithListInputMutationRequest,
10
+ CreateUsersWithListInputMutationResponse,
11
+ LoginUserQueryResponse,
12
+ LoginUserQueryParams,
13
+ LoginUser400,
14
+ LogoutUserQueryResponse,
15
+ GetUserByNameQueryResponse,
16
+ GetUserByNamePathParams,
17
+ GetUserByName400,
18
+ GetUserByName404,
19
+ UpdateUserMutationRequest,
20
+ UpdateUserMutationResponse,
21
+ UpdateUserPathParams,
22
+ DeleteUserMutationResponse,
23
+ DeleteUserPathParams,
24
+ DeleteUser400,
25
+ DeleteUser404,
26
+ } from './findByTags'
27
+ import { fetch } from './test/.kubb/fetch'
28
+
29
+ export class User {
30
+ static #client: typeof fetch = fetch
31
+
32
+ /**
33
+ * @description This can only be done by the logged in user.
34
+ * @summary Create user
35
+ * {@link /user}
36
+ */
37
+ static async createUser(data?: CreateUserMutationRequest, config: Partial<RequestConfig<CreateUserMutationRequest>> & { client?: typeof fetch } = {}) {
38
+ const { client: request = this.#client, ...requestConfig } = config
39
+ const requestData = data
40
+ const res = await request<CreateUserMutationResponse, ResponseErrorConfig<Error>, CreateUserMutationRequest>({
41
+ method: 'POST',
42
+ url: `/user`,
43
+ data: requestData,
44
+ ...requestConfig,
45
+ })
46
+ return res.data
47
+ }
48
+
49
+ /**
50
+ * @description Creates list of users with given input array
51
+ * @summary Creates list of users with given input array
52
+ * {@link /user/createWithList}
53
+ */
54
+ static async createUsersWithListInput(
55
+ data?: CreateUsersWithListInputMutationRequest,
56
+ config: Partial<RequestConfig<CreateUsersWithListInputMutationRequest>> & { client?: typeof fetch } = {},
57
+ ) {
58
+ const { client: request = this.#client, ...requestConfig } = config
59
+ const requestData = data
60
+ const res = await request<CreateUsersWithListInputMutationResponse, ResponseErrorConfig<Error>, CreateUsersWithListInputMutationRequest>({
61
+ method: 'POST',
62
+ url: `/user/createWithList`,
63
+ data: requestData,
64
+ ...requestConfig,
65
+ })
66
+ return res.data
67
+ }
68
+
69
+ /**
70
+ * @summary Logs user into the system
71
+ * {@link /user/login}
72
+ */
73
+ static async loginUser(params?: LoginUserQueryParams, config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
74
+ const { client: request = this.#client, ...requestConfig } = config
75
+ const res = await request<LoginUserQueryResponse, ResponseErrorConfig<LoginUser400>, unknown>({
76
+ method: 'GET',
77
+ url: `/user/login`,
78
+ params,
79
+ ...requestConfig,
80
+ })
81
+ return res.data
82
+ }
83
+
84
+ /**
85
+ * @summary Logs out current logged in user session
86
+ * {@link /user/logout}
87
+ */
88
+ static async logoutUser(config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
89
+ const { client: request = this.#client, ...requestConfig } = config
90
+ const res = await request<LogoutUserQueryResponse, ResponseErrorConfig<Error>, unknown>({ method: 'GET', url: `/user/logout`, ...requestConfig })
91
+ return res.data
92
+ }
93
+
94
+ /**
95
+ * @summary Get user by user name
96
+ * {@link /user/:username}
97
+ */
98
+ static async getUserByName(username: GetUserByNamePathParams['username'], config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
99
+ const { client: request = this.#client, ...requestConfig } = config
100
+ const res = await request<GetUserByNameQueryResponse, ResponseErrorConfig<GetUserByName400 | GetUserByName404>, unknown>({
101
+ method: 'GET',
102
+ url: `/user/${username}`,
103
+ ...requestConfig,
104
+ })
105
+ return res.data
106
+ }
107
+
108
+ /**
109
+ * @description This can only be done by the logged in user.
110
+ * @summary Update user
111
+ * {@link /user/:username}
112
+ */
113
+ static async updateUser(
114
+ username: UpdateUserPathParams['username'],
115
+ data?: UpdateUserMutationRequest,
116
+ config: Partial<RequestConfig<UpdateUserMutationRequest>> & { client?: typeof fetch } = {},
117
+ ) {
118
+ const { client: request = this.#client, ...requestConfig } = config
119
+ const requestData = data
120
+ const res = await request<UpdateUserMutationResponse, ResponseErrorConfig<Error>, UpdateUserMutationRequest>({
121
+ method: 'PUT',
122
+ url: `/user/${username}`,
123
+ data: requestData,
124
+ ...requestConfig,
125
+ })
126
+ return res.data
127
+ }
128
+
129
+ /**
130
+ * @description This can only be done by the logged in user.
131
+ * @summary Delete user
132
+ * {@link /user/:username}
133
+ */
134
+ static async deleteUser(username: DeleteUserPathParams['username'], config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
135
+ const { client: request = this.#client, ...requestConfig } = config
136
+ const res = await request<DeleteUserMutationResponse, ResponseErrorConfig<DeleteUser400 | DeleteUser404>, unknown>({
137
+ method: 'DELETE',
138
+ url: `/user/${username}`,
139
+ ...requestConfig,
140
+ })
141
+ return res.data
142
+ }
143
+ }
@@ -2,3 +2,4 @@ export { classClientGenerator } from './classClientGenerator.tsx'
2
2
  export { clientGenerator } from './clientGenerator.tsx'
3
3
  export { groupedClientGenerator } from './groupedClientGenerator.tsx'
4
4
  export { operationsGenerator } from './operationsGenerator.tsx'
5
+ export { staticClassClientGenerator } from './staticClassClientGenerator.tsx'
@@ -0,0 +1,231 @@
1
+ import path from 'node:path'
2
+ import { usePluginManager } from '@kubb/core/hooks'
3
+ import { camelCase, pascalCase } from '@kubb/core/transformers'
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'
10
+ import { pluginTsName } from '@kubb/plugin-ts'
11
+ import { pluginZodName } from '@kubb/plugin-zod'
12
+ import { File } from '@kubb/react-fabric'
13
+ import { StaticClassClient } from '../components/StaticClassClient'
14
+ import type { PluginClient } from '../types'
15
+
16
+ type OperationData = {
17
+ operation: Operation
18
+ name: string
19
+ typeSchemas: OperationSchemas
20
+ zodSchemas: OperationSchemas | undefined
21
+ typeFile: KubbFile.File
22
+ zodFile: KubbFile.File
23
+ }
24
+
25
+ type Controller = {
26
+ name: string
27
+ file: KubbFile.File
28
+ operations: Array<OperationData>
29
+ }
30
+
31
+ export const staticClassClientGenerator = createReactGenerator<PluginClient>({
32
+ name: 'staticClassClient',
33
+ Operations({ operations, generator, plugin, config }) {
34
+ const { options, key: pluginKey } = plugin
35
+ const pluginManager = usePluginManager()
36
+
37
+ const oas = useOas()
38
+ const { getName, getFile, getGroup, getSchemas } = useOperationManager(generator)
39
+
40
+ function buildOperationData(operation: Operation): OperationData {
41
+ const type = {
42
+ file: getFile(operation, { pluginKey: [pluginTsName] }),
43
+ schemas: getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' }),
44
+ }
45
+
46
+ const zod = {
47
+ file: getFile(operation, { pluginKey: [pluginZodName] }),
48
+ schemas: getSchemas(operation, { pluginKey: [pluginZodName], type: 'function' }),
49
+ }
50
+
51
+ 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,
58
+ }
59
+ }
60
+
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 = pluginManager.getFile({
71
+ name,
72
+ extname: '.ts',
73
+ pluginKey,
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 = pluginManager.getFile({
88
+ name,
89
+ extname: '.ts',
90
+ pluginKey,
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
+ }
102
+ }
103
+
104
+ return acc
105
+ },
106
+ [] as Array<Controller>,
107
+ )
108
+
109
+ function collectTypeImports(ops: Array<OperationData>) {
110
+ const typeImportsByFile = new Map<string, Set<string>>()
111
+ const typeFilesByPath = new Map<string, KubbFile.File>()
112
+
113
+ ops.forEach((op) => {
114
+ const { typeSchemas, typeFile } = op
115
+
116
+ if (!typeImportsByFile.has(typeFile.path)) {
117
+ typeImportsByFile.set(typeFile.path, new Set())
118
+ }
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)
128
+ })
129
+ typeFilesByPath.set(typeFile.path, typeFile)
130
+ })
131
+
132
+ return { typeImportsByFile, typeFilesByPath }
133
+ }
134
+
135
+ function collectZodImports(ops: Array<OperationData>) {
136
+ const zodImportsByFile = new Map<string, Set<string>>()
137
+ const zodFilesByPath = new Map<string, KubbFile.File>()
138
+
139
+ ops.forEach((op) => {
140
+ const { zodSchemas, zodFile } = op
141
+
142
+ if (!zodImportsByFile.has(zodFile.path)) {
143
+ zodImportsByFile.set(zodFile.path, new Set())
144
+ }
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)
150
+ })
151
+
152
+ return { zodImportsByFile, zodFilesByPath }
153
+ }
154
+
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: pluginManager.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={['RequestConfig', 'ResponseErrorConfig']} path={options.importPath} isTypeOnly />
176
+ </>
177
+ ) : (
178
+ <>
179
+ <File.Import name={['fetch']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
180
+ <File.Import
181
+ name={['RequestConfig', 'ResponseErrorConfig']}
182
+ root={file.path}
183
+ path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
184
+ isTypeOnly
185
+ />
186
+ </>
187
+ )}
188
+
189
+ {hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(config.root, config.output.path, '.kubb/config.ts')} />}
190
+
191
+ {Array.from(typeImportsByFile.entries()).map(([filePath, imports]) => {
192
+ const typeFile = typeFilesByPath.get(filePath)
193
+ if (!typeFile) {
194
+ return null
195
+ }
196
+ const importNames = Array.from(imports).filter(Boolean)
197
+ if (importNames.length === 0) {
198
+ return null
199
+ }
200
+ return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
201
+ })}
202
+
203
+ {options.parser === 'zod' &&
204
+ Array.from(zodImportsByFile.entries()).map(([filePath, imports]) => {
205
+ const zodFile = zodFilesByPath.get(filePath)
206
+ if (!zodFile) {
207
+ return null
208
+ }
209
+ const importNames = Array.from(imports).filter(Boolean)
210
+ if (importNames.length === 0) {
211
+ return null
212
+ }
213
+
214
+ return <File.Import key={filePath} name={importNames} root={file.path} path={zodFile.path} />
215
+ })}
216
+
217
+ <StaticClassClient
218
+ name={name}
219
+ operations={ops}
220
+ baseURL={options.baseURL}
221
+ dataReturnType={options.dataReturnType}
222
+ pathParamsType={options.pathParamsType}
223
+ paramsCasing={options.paramsCasing}
224
+ paramsType={options.paramsType}
225
+ parser={options.parser}
226
+ />
227
+ </File>
228
+ )
229
+ })
230
+ },
231
+ })
package/src/plugin.ts CHANGED
@@ -7,6 +7,7 @@ import { pluginZodName } from '@kubb/plugin-zod'
7
7
  import { classClientGenerator, operationsGenerator } from './generators'
8
8
  import { clientGenerator } from './generators/clientGenerator.tsx'
9
9
  import { groupedClientGenerator } from './generators/groupedClientGenerator.tsx'
10
+ import { staticClassClientGenerator } from './generators/staticClassClientGenerator.tsx'
10
11
  import type { PluginClient } from './types.ts'
11
12
 
12
13
  export const pluginClientName = 'plugin-client' satisfies PluginClient['name']
@@ -35,9 +36,10 @@ export const pluginClient = definePlugin<PluginClient>((options) => {
35
36
  } = options
36
37
 
37
38
  const resolvedImportPath = importPath ?? (!bundle ? `@kubb/plugin-client/clients/${client}` : undefined)
39
+
38
40
  const defaultGenerators = [
39
- clientType === 'class' ? classClientGenerator : clientGenerator,
40
- group && clientType !== 'class' ? groupedClientGenerator : undefined,
41
+ clientType === 'staticClass' ? staticClassClientGenerator : clientType === 'class' ? classClientGenerator : clientGenerator,
42
+ group && clientType === 'function' ? groupedClientGenerator : undefined,
41
43
  operations ? operationsGenerator : undefined,
42
44
  ].filter(Boolean)
43
45