@kubb/plugin-swr 3.0.0-alpha.0

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.
@@ -0,0 +1,290 @@
1
+ import { FunctionParams, URLPath } from '@kubb/core/utils'
2
+ import { Parser, File, Function, useApp } from '@kubb/react'
3
+ import { pluginTsName } from '@kubb/plugin-ts'
4
+ import { useOperation, useOperationManager } from '@kubb/plugin-oas/hooks'
5
+ import { getASTParams, getComments } from '@kubb/plugin-oas/utils'
6
+ import { pluginZodName } from '@kubb/plugin-zod'
7
+
8
+ import { QueryOptions } from './QueryOptions.tsx'
9
+ import { SchemaType } from './SchemaType.tsx'
10
+
11
+ import type { ReactNode } from 'react'
12
+ import type { FileMeta, PluginSwr } from '../types.ts'
13
+
14
+ type TemplateProps = {
15
+ /**
16
+ * Name of the function
17
+ */
18
+ name: string
19
+ /**
20
+ * Parameters/options/props that need to be used
21
+ */
22
+ params: string
23
+ /**
24
+ * Generics that needs to be added for TypeScript
25
+ */
26
+ generics?: string
27
+ /**
28
+ * ReturnType(see async for adding Promise type)
29
+ */
30
+ returnType?: string
31
+ /**
32
+ * Options for JSdocs
33
+ */
34
+ JSDoc?: {
35
+ comments: string[]
36
+ }
37
+ hook: {
38
+ name: string
39
+ generics?: string
40
+ queryOptions: string
41
+ }
42
+ client: {
43
+ path: URLPath
44
+ withQueryParams: boolean
45
+ }
46
+ }
47
+
48
+ function Template({ name, generics, returnType, params, JSDoc, hook, client }: TemplateProps): ReactNode {
49
+ if (client.withQueryParams) {
50
+ return (
51
+ <>
52
+ <Function name={name} export generics={generics} returnType={returnType} params={params} JSDoc={JSDoc}>
53
+ {`
54
+ const { query: queryOptions, client: clientOptions = {}, shouldFetch = true } = options ?? {}
55
+
56
+ const url = ${client.path.template}
57
+ const query = ${hook.name}<${hook.generics}>(
58
+ shouldFetch ? [url, params]: null,
59
+ {
60
+ ...${hook.queryOptions},
61
+ ...queryOptions
62
+ }
63
+ )
64
+
65
+ return query
66
+ `}
67
+ </Function>
68
+ </>
69
+ )
70
+ }
71
+
72
+ return (
73
+ <>
74
+ <Function name={name} export generics={generics} returnType={returnType} params={params} JSDoc={JSDoc}>
75
+ {`
76
+ const { query: queryOptions, client: clientOptions = {}, shouldFetch = true } = options ?? {}
77
+
78
+ const url = ${client.path.template}
79
+ const query = ${hook.name}<${hook.generics}>(
80
+ shouldFetch ? url : null,
81
+ {
82
+ ...${hook.queryOptions},
83
+ ...queryOptions
84
+ }
85
+ )
86
+
87
+ return query
88
+ `}
89
+ </Function>
90
+ </>
91
+ )
92
+ }
93
+
94
+ const defaultTemplates = {
95
+ default: Template,
96
+ } as const
97
+
98
+ type Props = {
99
+ factory: {
100
+ name: string
101
+ }
102
+ /**
103
+ * This will make it possible to override the default behaviour.
104
+ */
105
+ Template?: React.ComponentType<TemplateProps>
106
+ /**
107
+ * This will make it possible to override the default behaviour.
108
+ */
109
+ QueryOptionsTemplate?: React.ComponentType<React.ComponentProps<typeof QueryOptions.templates.default>>
110
+ }
111
+
112
+ export function Query({ factory, Template = defaultTemplates.default, QueryOptionsTemplate = QueryOptions.templates.default }: Props): ReactNode {
113
+ const {
114
+ pluginManager,
115
+ plugin: {
116
+ key: pluginKey,
117
+ options: { dataReturnType },
118
+ },
119
+ } = useApp<PluginSwr>()
120
+
121
+ const operation = useOperation()
122
+ const { getSchemas, getName } = useOperationManager()
123
+
124
+ const schemas = getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' })
125
+ const zodSchemas = getSchemas(operation, { pluginKey: [pluginZodName], type: 'function' })
126
+
127
+ const name = getName(operation, { type: 'function' })
128
+
129
+ const queryOptionsName = pluginManager.resolveName({
130
+ name: `${factory.name}QueryOptions`,
131
+ pluginKey,
132
+ })
133
+ const generics = new FunctionParams()
134
+ const params = new FunctionParams()
135
+ const queryParams = new FunctionParams()
136
+ const client = {
137
+ method: operation.method,
138
+ path: new URLPath(operation.path),
139
+ withQueryParams: !!schemas.queryParams?.name,
140
+ withData: !!schemas.request?.name,
141
+ withPathParams: !!schemas.pathParams?.name,
142
+ withHeaders: !!schemas.headerParams?.name,
143
+ }
144
+
145
+ const resultGenerics = ['TData', `${factory.name}["error"]`]
146
+
147
+ generics.add([{ type: 'TData', default: `${factory.name}["response"]` }])
148
+
149
+ const queryOptionsGenerics = ['TData']
150
+
151
+ params.add([
152
+ ...getASTParams(schemas.pathParams, { typed: true }),
153
+ {
154
+ name: 'params',
155
+ type: `${factory.name}['queryParams']`,
156
+ enabled: client.withQueryParams,
157
+ required: false,
158
+ },
159
+ {
160
+ name: 'headers',
161
+ type: `${factory.name}['headerParams']`,
162
+ enabled: client.withHeaders,
163
+ required: false,
164
+ },
165
+ {
166
+ name: 'options',
167
+ required: false,
168
+ type: `{
169
+ query?: SWRConfiguration<${resultGenerics.join(', ')}>,
170
+ client?: ${factory.name}['client']['parameters'],
171
+ shouldFetch?: boolean,
172
+ }`,
173
+ default: '{}',
174
+ },
175
+ ])
176
+
177
+ queryParams.add([
178
+ ...getASTParams(schemas.pathParams, { typed: false }),
179
+ {
180
+ name: 'params',
181
+ enabled: client.withQueryParams,
182
+ required: false,
183
+ },
184
+ {
185
+ name: 'headers',
186
+ enabled: client.withHeaders,
187
+ required: false,
188
+ },
189
+ {
190
+ name: 'clientOptions',
191
+ required: false,
192
+ },
193
+ ])
194
+
195
+ const hook = {
196
+ name: 'useSWR',
197
+ generics: [...resultGenerics, client.withQueryParams ? '[typeof url, typeof params] | null' : 'typeof url | null'].join(', '),
198
+ queryOptions: `${queryOptionsName}<${queryOptionsGenerics.join(', ')}>(${queryParams.toString()})`,
199
+ }
200
+
201
+ return (
202
+ <>
203
+ <QueryOptions factory={factory} Template={QueryOptionsTemplate} dataReturnType={dataReturnType} />
204
+
205
+ <Template
206
+ name={name}
207
+ generics={generics.toString()}
208
+ JSDoc={{ comments: getComments(operation) }}
209
+ client={client}
210
+ hook={hook}
211
+ params={params.toString()}
212
+ returnType={`SWRResponse<${resultGenerics.join(', ')}>`}
213
+ />
214
+ </>
215
+ )
216
+ }
217
+
218
+ type FileProps = {
219
+ /**
220
+ * This will make it possible to override the default behaviour.
221
+ */
222
+ templates?: {
223
+ query: typeof defaultTemplates
224
+ queryOptions: typeof QueryOptions.templates
225
+ }
226
+ }
227
+
228
+ Query.File = function ({ templates }: FileProps): ReactNode {
229
+ const {
230
+ pluginManager,
231
+ plugin: {
232
+ options: {
233
+ extName,
234
+ client: { importPath },
235
+ parser,
236
+ },
237
+ },
238
+ } = useApp<PluginSwr>()
239
+ const { getSchemas, getFile, getName } = useOperationManager()
240
+ const operation = useOperation()
241
+
242
+ const file = getFile(operation)
243
+ const schemas = getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' })
244
+ const zodSchemas = getSchemas(operation, { pluginKey: [pluginZodName], type: 'function' })
245
+ const fileType = getFile(operation, { pluginKey: [pluginTsName] })
246
+ const fileZodSchemas = getFile(operation, {
247
+ pluginKey: [pluginZodName],
248
+ })
249
+
250
+ const factoryName = getName(operation, { type: 'type' })
251
+
252
+ const Template = templates?.query.default || defaultTemplates.default
253
+ const QueryOptionsTemplate = templates?.queryOptions.default || QueryOptions.templates.default
254
+ const factory = {
255
+ name: factoryName,
256
+ }
257
+
258
+ return (
259
+ <Parser language="typescript">
260
+ <File<FileMeta> baseName={file.baseName} path={file.path} meta={file.meta}>
261
+ {parser === 'zod' && <File.Import extName={extName} name={[zodSchemas.response.name]} root={file.path} path={fileZodSchemas.path} />}
262
+ <File.Import name="useSWR" path="swr" />
263
+ <File.Import name={['SWRConfiguration', 'SWRResponse']} path="swr" isTypeOnly />
264
+ <File.Import name={'client'} path={importPath} />
265
+ <File.Import name={['ResponseConfig']} path={importPath} isTypeOnly />
266
+ <File.Import
267
+ extName={extName}
268
+ name={[
269
+ schemas.request?.name,
270
+ schemas.response.name,
271
+ schemas.pathParams?.name,
272
+ schemas.queryParams?.name,
273
+ schemas.headerParams?.name,
274
+ ...(schemas.statusCodes?.map((item) => item.name) || []),
275
+ ].filter(Boolean)}
276
+ root={file.path}
277
+ path={fileType.path}
278
+ isTypeOnly
279
+ />
280
+
281
+ <File.Source>
282
+ <SchemaType factory={factory} />
283
+ <Query factory={factory} Template={Template} QueryOptionsTemplate={QueryOptionsTemplate} />
284
+ </File.Source>
285
+ </File>
286
+ </Parser>
287
+ )
288
+ }
289
+
290
+ Query.templates = defaultTemplates
@@ -0,0 +1,197 @@
1
+ import transformers from '@kubb/core/transformers'
2
+ import { FunctionParams, URLPath } from '@kubb/core/utils'
3
+ import { useOperation, useOperationManager } from '@kubb/plugin-oas/hooks'
4
+ import { getASTParams } from '@kubb/plugin-oas/utils'
5
+ import { Function, useApp } from '@kubb/react'
6
+ import { pluginZodName } from '@kubb/plugin-zod'
7
+
8
+ import type { HttpMethod } from '@kubb/oas'
9
+ import type { ReactNode } from 'react'
10
+ import type { PluginSwr } from '../types.ts'
11
+ import { pluginTsName } from '@kubb/plugin-ts'
12
+
13
+ type TemplateProps = {
14
+ /**
15
+ * Name of the function
16
+ */
17
+ name: string
18
+ /**
19
+ * Parameters/options/props that need to be used
20
+ */
21
+ params: string
22
+ /**
23
+ * Generics that needs to be added for TypeScript
24
+ */
25
+ generics?: string
26
+ /**
27
+ * ReturnType(see async for adding Promise type)
28
+ */
29
+ returnType?: string
30
+ /**
31
+ * Options for JSdocs
32
+ */
33
+ JSDoc?: {
34
+ comments: string[]
35
+ }
36
+ client: {
37
+ generics: string
38
+ method: HttpMethod
39
+ path: URLPath
40
+ withQueryParams: boolean
41
+ withPathParams: boolean
42
+ withData: boolean
43
+ withHeaders: boolean
44
+ contentType: string
45
+ }
46
+ dataReturnType: NonNullable<PluginSwr['options']['dataReturnType']>
47
+ parser: string | undefined
48
+ }
49
+
50
+ function Template({ name, params, generics, returnType, JSDoc, client, dataReturnType, parser }: TemplateProps): ReactNode {
51
+ const isFormData = client.contentType === 'multipart/form-data'
52
+ const headers = [
53
+ client.contentType !== 'application/json' ? `'Content-Type': '${client.contentType}'` : undefined,
54
+ client.withHeaders ? '...headers' : undefined,
55
+ ]
56
+ .filter(Boolean)
57
+ .join(', ')
58
+
59
+ const clientOptions = [
60
+ `method: "${client.method}"`,
61
+ `url: ${client.path.template}`,
62
+ client.withQueryParams ? 'params' : undefined,
63
+ client.withData && !isFormData ? 'data' : undefined,
64
+ client.withData && isFormData ? 'data: formData' : undefined,
65
+ headers.length ? `headers: { ${headers}, ...options.headers }` : undefined,
66
+ '...options',
67
+ ].filter(Boolean)
68
+
69
+ const resolvedClientOptions = `${transformers.createIndent(4)}${clientOptions.join(`,\n${transformers.createIndent(4)}`)}`
70
+
71
+ let returnRes = parser ? `return ${parser}(res.data)` : 'return res.data'
72
+
73
+ if (dataReturnType === 'full') {
74
+ returnRes = parser ? `return {...res, data: ${parser}(res.data)}` : 'return res'
75
+ }
76
+
77
+ const formData = isFormData
78
+ ? `
79
+ const formData = new FormData()
80
+ if(data) {
81
+ Object.keys(data).forEach((key) => {
82
+ const value = data[key];
83
+ if (typeof key === "string" && (typeof value === "string" || value instanceof Blob)) {
84
+ formData.append(key, value);
85
+ }
86
+ })
87
+ }
88
+ `
89
+ : undefined
90
+
91
+ return (
92
+ <Function name={name} export generics={generics} returnType={returnType} params={params} JSDoc={JSDoc}>
93
+ {`
94
+ return {
95
+ fetcher: async () => {
96
+ ${formData || ''}
97
+ const res = await client<${client.generics}>({
98
+ ${resolvedClientOptions}
99
+ })
100
+
101
+ ${returnRes}
102
+ },
103
+ }
104
+
105
+ `}
106
+ </Function>
107
+ )
108
+ }
109
+
110
+ const defaultTemplates = {
111
+ default: Template,
112
+ } as const
113
+
114
+ type Props = {
115
+ factory: {
116
+ name: string
117
+ }
118
+ dataReturnType: NonNullable<PluginSwr['options']['dataReturnType']>
119
+ /**
120
+ * This will make it possible to override the default behaviour.
121
+ */
122
+ Template?: React.ComponentType<TemplateProps>
123
+ }
124
+
125
+ export function QueryOptions({ factory, dataReturnType, Template = defaultTemplates.default }: Props): ReactNode {
126
+ const {
127
+ pluginManager,
128
+ plugin: {
129
+ key: pluginKey,
130
+ options: { parser },
131
+ },
132
+ } = useApp<PluginSwr>()
133
+ const { getSchemas } = useOperationManager()
134
+ const operation = useOperation()
135
+
136
+ const schemas = getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' })
137
+ const zodSchemas = getSchemas(operation, { pluginKey: [pluginZodName], type: 'function' })
138
+ const name = pluginManager.resolveName({
139
+ name: `${factory.name}QueryOptions`,
140
+ pluginKey,
141
+ })
142
+ const contentType = operation.getContentType()
143
+
144
+ const generics = new FunctionParams()
145
+ const params = new FunctionParams()
146
+
147
+ const clientGenerics = ['TData', `${factory.name}['error']`]
148
+ const resultGenerics = ['TData', `${factory.name}['error']`]
149
+
150
+ generics.add([{ type: 'TData', default: `${factory.name}['response']` }])
151
+
152
+ params.add([
153
+ ...getASTParams(schemas.pathParams, { typed: true }),
154
+ {
155
+ name: 'params',
156
+ type: `${factory.name}['queryParams']`,
157
+ enabled: !!schemas.queryParams?.name,
158
+ required: false,
159
+ },
160
+ {
161
+ name: 'headers',
162
+ type: `${factory.name}['headerParams']`,
163
+ enabled: !!schemas.headerParams?.name,
164
+ required: false,
165
+ },
166
+ {
167
+ name: 'options',
168
+ type: `${factory.name}['client']['parameters']`,
169
+ default: '{}',
170
+ },
171
+ ])
172
+
173
+ const client = {
174
+ withQueryParams: !!schemas.queryParams?.name,
175
+ withData: !!schemas.request?.name,
176
+ withPathParams: !!schemas.pathParams?.name,
177
+ withHeaders: !!schemas.headerParams?.name,
178
+ method: operation.method,
179
+ path: new URLPath(operation.path),
180
+ generics: clientGenerics.join(', '),
181
+ contentType,
182
+ }
183
+
184
+ return (
185
+ <Template
186
+ name={name}
187
+ params={params.toString()}
188
+ generics={generics.toString()}
189
+ returnType={`SWRConfiguration<${resultGenerics.join(', ')}>`}
190
+ client={client}
191
+ dataReturnType={dataReturnType}
192
+ parser={parser === 'zod' ? `${zodSchemas.response.name}.parse` : undefined}
193
+ />
194
+ )
195
+ }
196
+
197
+ QueryOptions.templates = defaultTemplates
@@ -0,0 +1,59 @@
1
+ import { Type, useApp } from '@kubb/react'
2
+
3
+ import { useOperation, useOperationManager } from '@kubb/plugin-oas/hooks'
4
+ import type { ReactNode } from 'react'
5
+ import type { PluginSwr } from '../types.ts'
6
+ import { pluginTsName } from '@kubb/plugin-ts'
7
+
8
+ type Props = {
9
+ factory: {
10
+ name: string
11
+ }
12
+ }
13
+
14
+ export function SchemaType({ factory }: Props): ReactNode {
15
+ const {
16
+ plugin: {
17
+ options: { dataReturnType },
18
+ },
19
+ } = useApp<PluginSwr>()
20
+ const { getSchemas } = useOperationManager()
21
+ const operation = useOperation()
22
+
23
+ const schemas = getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' })
24
+
25
+ const [TData, TError, TRequest, TPathParams, TQueryParams, THeaderParams, TResponse] = [
26
+ schemas.response.name,
27
+ schemas.errors?.map((item) => item.name).join(' | ') || 'never',
28
+ schemas.request?.name || 'never',
29
+ schemas.pathParams?.name || 'never',
30
+ schemas.queryParams?.name || 'never',
31
+ schemas.headerParams?.name || 'never',
32
+ schemas.response.name,
33
+ ]
34
+
35
+ const clientType = `${factory.name}Client`
36
+
37
+ return (
38
+ <>
39
+ <Type name={clientType}>{`typeof client<${TResponse}, ${TError}, ${TRequest}>`}</Type>
40
+ <Type name={factory.name}>
41
+ {`
42
+ {
43
+ data: ${TData}
44
+ error: ${TError}
45
+ request: ${TRequest}
46
+ pathParams: ${TPathParams}
47
+ queryParams: ${TQueryParams}
48
+ headerParams: ${THeaderParams}
49
+ response: ${dataReturnType === 'data' ? TData : `Awaited<ReturnType<${clientType}>>`}
50
+ client: {
51
+ parameters: Partial<Parameters<${clientType}>[0]>
52
+ return: Awaited<ReturnType<${clientType}>>
53
+ }
54
+ }
55
+ `}
56
+ </Type>
57
+ </>
58
+ )
59
+ }
@@ -0,0 +1,42 @@
1
+ type CreatePetsClient = typeof client<CreatePetsMutationResponse, never, CreatePetsMutationRequest>
2
+ type CreatePets = {
3
+ data: CreatePetsMutationResponse
4
+ error: never
5
+ request: CreatePetsMutationRequest
6
+ pathParams: never
7
+ queryParams: never
8
+ headerParams: never
9
+ response: CreatePetsMutationResponse
10
+ client: {
11
+ parameters: Partial<Parameters<CreatePetsClient>[0]>
12
+ return: Awaited<ReturnType<CreatePetsClient>>
13
+ }
14
+ }
15
+
16
+ /**
17
+ * @summary Create a pet
18
+ * @link /pets
19
+ */
20
+ export function useCreatePets(options?: {
21
+ mutation?: SWRMutationConfiguration<CreatePets['response'], CreatePets['error']>
22
+ client?: CreatePets['client']['parameters']
23
+ shouldFetch?: boolean
24
+ }): SWRMutationResponse<CreatePets['response'], CreatePets['error']> {
25
+ const { mutation: mutationOptions, client: clientOptions = {}, shouldFetch = true } = options ?? {}
26
+
27
+ const url = `/pets` as const
28
+ return useSWRMutation<CreatePets['response'], CreatePets['error'], typeof url | null>(
29
+ shouldFetch ? url : null,
30
+ async (_url, { arg: data }) => {
31
+ const res = await client<CreatePets['data'], CreatePets['error'], CreatePets['request']>({
32
+ method: 'post',
33
+ url,
34
+ data,
35
+ ...clientOptions,
36
+ })
37
+
38
+ return res.data
39
+ },
40
+ mutationOptions,
41
+ )
42
+ }
@@ -0,0 +1,55 @@
1
+ type ShowPetByIdClient = typeof client<ShowPetByIdQueryResponse, never, never>
2
+ type ShowPetById = {
3
+ data: ShowPetByIdQueryResponse
4
+ error: never
5
+ request: never
6
+ pathParams: ShowPetByIdPathParams
7
+ queryParams: never
8
+ headerParams: never
9
+ response: ShowPetByIdQueryResponse
10
+ client: {
11
+ parameters: Partial<Parameters<ShowPetByIdClient>[0]>
12
+ return: Awaited<ReturnType<ShowPetByIdClient>>
13
+ }
14
+ }
15
+
16
+ export function ShowPetByIdQueryOptions<TData = ShowPetById['response']>(
17
+ petId: ShowPetByIdPathParams['petId'],
18
+ testId: ShowPetByIdPathParams['testId'],
19
+ options: ShowPetById['client']['parameters'] = {},
20
+ ): SWRConfiguration<TData, ShowPetById['error']> {
21
+ return {
22
+ fetcher: async () => {
23
+ const res = await client<TData, ShowPetById['error']>({
24
+ method: 'get',
25
+ url: `/pets/${petId}`,
26
+ ...options,
27
+ })
28
+
29
+ return res.data
30
+ },
31
+ }
32
+ }
33
+ /**
34
+ * @summary Info for a specific pet
35
+ * @link /pets/:petId
36
+ */
37
+ export function useShowPetById<TData = ShowPetById['response']>(
38
+ petId: ShowPetByIdPathParams['petId'],
39
+ testId: ShowPetByIdPathParams['testId'],
40
+ options?: {
41
+ query?: SWRConfiguration<TData, ShowPetById['error']>
42
+ client?: ShowPetById['client']['parameters']
43
+ shouldFetch?: boolean
44
+ },
45
+ ): SWRResponse<TData, ShowPetById['error']> {
46
+ const { query: queryOptions, client: clientOptions = {}, shouldFetch = true } = options ?? {}
47
+
48
+ const url = `/pets/${petId}`
49
+ const query = useSWR<TData, ShowPetById['error'], typeof url | null>(shouldFetch ? url : null, {
50
+ ...ShowPetByIdQueryOptions<TData>(petId, testId, clientOptions),
51
+ ...queryOptions,
52
+ })
53
+
54
+ return query
55
+ }
@@ -0,0 +1,3 @@
1
+ export { Mutation } from './Mutation.tsx'
2
+ export { Query } from './Query.tsx'
3
+ export { QueryOptions } from './QueryOptions.tsx'
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { pluginSwr } from './plugin.ts'
2
+
3
+ export { pluginSwr, pluginSwrName } from './plugin.ts'
4
+ export type { PluginSwr } from './types.ts'
5
+
6
+ /**
7
+ * @deprecated Use `import { pluginSwr } from '@kubb/plugin-swr'` instead
8
+ */
9
+ const definePluginDefault = pluginSwr
10
+ /**
11
+ * @deprecated Use `import { pluginSwr } from '@kubb/plugin-swr'` instead
12
+ */
13
+ export const definePlugin = pluginSwr
14
+
15
+ export default definePluginDefault