@kubb/plugin-react-query 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 (53) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +1 -3
  3. package/dist/components-DTGLu4UV.js +1451 -0
  4. package/dist/components-DTGLu4UV.js.map +1 -0
  5. package/dist/components-dAKJEn9b.cjs +1571 -0
  6. package/dist/components-dAKJEn9b.cjs.map +1 -0
  7. package/dist/components.cjs +1 -1
  8. package/dist/components.d.ts +105 -161
  9. package/dist/components.js +1 -1
  10. package/dist/generators-CWEQsdO9.cjs +1502 -0
  11. package/dist/generators-CWEQsdO9.cjs.map +1 -0
  12. package/dist/generators-C_fbcjpG.js +1460 -0
  13. package/dist/generators-C_fbcjpG.js.map +1 -0
  14. package/dist/generators.cjs +1 -1
  15. package/dist/generators.d.ts +9 -505
  16. package/dist/generators.js +1 -1
  17. package/dist/index.cjs +114 -126
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +4 -4
  20. package/dist/index.js +110 -126
  21. package/dist/index.js.map +1 -1
  22. package/dist/{types-D5S7Ny9r.d.ts → types-DfaFRSBf.d.ts} +100 -86
  23. package/extension.yaml +938 -0
  24. package/package.json +59 -62
  25. package/src/components/InfiniteQuery.tsx +75 -139
  26. package/src/components/InfiniteQueryOptions.tsx +62 -164
  27. package/src/components/Mutation.tsx +58 -113
  28. package/src/components/MutationOptions.tsx +61 -80
  29. package/src/components/Query.tsx +67 -140
  30. package/src/components/QueryOptions.tsx +75 -135
  31. package/src/components/SuspenseInfiniteQuery.tsx +75 -139
  32. package/src/components/SuspenseInfiniteQueryOptions.tsx +62 -164
  33. package/src/components/SuspenseQuery.tsx +67 -150
  34. package/src/generators/customHookOptionsFileGenerator.tsx +33 -45
  35. package/src/generators/hookOptionsGenerator.tsx +115 -175
  36. package/src/generators/infiniteQueryGenerator.tsx +183 -176
  37. package/src/generators/mutationGenerator.tsx +127 -138
  38. package/src/generators/queryGenerator.tsx +141 -141
  39. package/src/generators/suspenseInfiniteQueryGenerator.tsx +175 -155
  40. package/src/generators/suspenseQueryGenerator.tsx +149 -148
  41. package/src/index.ts +1 -1
  42. package/src/plugin.ts +133 -183
  43. package/src/resolvers/resolverReactQuery.ts +22 -0
  44. package/src/types.ts +67 -45
  45. package/src/utils.ts +40 -0
  46. package/dist/components-BHQT9ZLc.cjs +0 -1634
  47. package/dist/components-BHQT9ZLc.cjs.map +0 -1
  48. package/dist/components-CpyHYGOw.js +0 -1520
  49. package/dist/components-CpyHYGOw.js.map +0 -1
  50. package/dist/generators-DP07m3rH.cjs +0 -1469
  51. package/dist/generators-DP07m3rH.cjs.map +0 -1
  52. package/dist/generators-DkQwKTc2.js +0 -1427
  53. package/dist/generators-DkQwKTc2.js.map +0 -1
@@ -1,201 +1,221 @@
1
1
  import path from 'node:path'
2
- import { usePluginDriver } from '@kubb/core/hooks'
3
- import { pluginClientName } from '@kubb/plugin-client'
4
- import { Client } from '@kubb/plugin-client/components'
5
- import { createReactGenerator } from '@kubb/plugin-oas/generators'
6
- import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
7
- import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
2
+ import { ast, defineGenerator } from '@kubb/core'
3
+ import { Client, pluginClientName } from '@kubb/plugin-client'
8
4
  import { pluginTsName } from '@kubb/plugin-ts'
9
5
  import { pluginZodName } from '@kubb/plugin-zod'
10
- import { File } from '@kubb/react-fabric'
6
+ import { File, jsxRenderer } from '@kubb/renderer-jsx'
11
7
  import { difference } from 'remeda'
12
8
  import { QueryKey, SuspenseInfiniteQuery, SuspenseInfiniteQueryOptions } from '../components'
13
9
  import type { PluginReactQuery } from '../types'
10
+ import { transformName } from '../utils.ts'
14
11
 
15
- export const suspenseInfiniteQueryGenerator = createReactGenerator<PluginReactQuery>({
12
+ export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>({
16
13
  name: 'react-suspense-infinite-query',
17
- Operation({ config, operation, generator, plugin }) {
14
+ renderer: jsxRenderer,
15
+ operation(node, ctx) {
16
+ const { adapter, config, driver, resolver, root } = ctx
18
17
  const {
19
- options,
20
- options: { output },
21
- } = plugin
22
- const driver = usePluginDriver()
18
+ output,
19
+ query,
20
+ mutation,
21
+ infinite,
22
+ suspense,
23
+ paramsCasing,
24
+ paramsType,
25
+ pathParamsType,
26
+ parser,
27
+ client: clientOptions,
28
+ group,
29
+ transformers,
30
+ customOptions,
31
+ } = ctx.options
23
32
 
24
- const oas = useOas()
25
- const { getSchemas, getName, getFile } = useOperationManager(generator)
33
+ const pluginTs = driver.getPlugin(pluginTsName)
34
+ if (!pluginTs) return null
35
+ const tsResolver = driver.getResolver(pluginTsName)
26
36
 
27
- const isQuery = typeof options.query === 'boolean' ? true : options.query?.methods.some((method) => operation.method === method)
28
- const isMutation = difference(options.mutation ? options.mutation.methods : [], options.query ? options.query.methods : []).some(
29
- (method) => operation.method === method,
30
- )
31
- const isSuspense = !!options.suspense
32
- const infiniteOptions = options.infinite && typeof options.infinite === 'object' ? options.infinite : undefined
37
+ const isQuery = query === false || (!!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase()))
38
+ const isMutation =
39
+ mutation !== false &&
40
+ !isQuery &&
41
+ difference(mutation ? mutation.methods : [], query ? query.methods : []).some((method) => node.method.toLowerCase() === method.toLowerCase())
42
+ const isSuspense = !!suspense
43
+ const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : undefined
33
44
 
34
- const importPath = options.query ? options.query.importPath : '@tanstack/react-query'
45
+ if (!isQuery || isMutation || !isSuspense || !infiniteOptions) return null
35
46
 
36
- const query = {
37
- name: getName(operation, { type: 'function', prefix: 'use', suffix: 'suspenseInfinite' }),
38
- typeName: getName(operation, { type: 'type' }),
39
- file: getFile(operation, { prefix: 'use', suffix: 'suspenseInfinite' }),
40
- }
47
+ // Validate queryParam exists in operation's query parameters
48
+ const normalizeKey = (key: string) => key.replace(/\?$/, '')
49
+ const queryParamKeys = node.parameters.filter((p) => p.in === 'query').map((p) => p.name)
50
+ const hasQueryParam = infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false
51
+ const hasCursorParam = !infiniteOptions.cursorParam || true
41
52
 
42
- const hasClientPlugin = !!driver.getPluginByName(pluginClientName)
43
- // Class-based clients are not compatible with query hooks, so we generate inline clients
44
- const shouldUseClientPlugin = hasClientPlugin && options.client.clientType !== 'class'
45
- const client = {
46
- name: shouldUseClientPlugin
47
- ? getName(operation, {
48
- type: 'function',
49
- pluginName: pluginClientName,
50
- })
51
- : getName(operation, {
52
- type: 'function',
53
- suffix: 'suspenseInfinite',
54
- }),
55
- file: getFile(operation, { pluginName: pluginClientName }),
56
- }
53
+ if (!hasQueryParam || !hasCursorParam) return null
57
54
 
58
- const queryOptions = {
59
- name: getName(operation, { type: 'function', suffix: 'SuspenseInfiniteQueryOptions' }),
60
- }
55
+ const importPath = query ? query.importPath : '@tanstack/react-query'
61
56
 
62
- const queryKey = {
63
- name: getName(operation, { type: 'const', suffix: 'SuspenseInfiniteQueryKey' }),
64
- typeName: getName(operation, { type: 'type', suffix: 'SuspenseInfiniteQueryKey' }),
65
- }
57
+ const baseName = resolver.resolveName(node.operationId)
58
+ const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
59
+ const queryName = transformName(`use${capitalize(baseName)}SuspenseInfinite`, 'function', transformers)
60
+ const queryOptionsName = transformName(`${baseName}SuspenseInfiniteQueryOptions`, 'function', transformers)
61
+ const queryKeyName = transformName(`${baseName}SuspenseInfiniteQueryKey`, 'const', transformers)
62
+ const queryKeyTypeName = transformName(`${capitalize(baseName)}SuspenseInfiniteQueryKey`, 'type', transformers)
63
+ const clientBaseName = transformName(`${baseName}SuspenseInfinite`, 'function', transformers)
66
64
 
67
- const type = {
68
- file: getFile(operation, { pluginName: pluginTsName }),
69
- //todo remove type?
70
- schemas: getSchemas(operation, { pluginName: pluginTsName, type: 'type' }),
65
+ const meta = {
66
+ file: resolver.resolveFile({ name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
67
+ fileTs: tsResolver.resolveFile(
68
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
69
+ { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
70
+ ),
71
71
  }
72
72
 
73
- const zod = {
74
- file: getFile(operation, { pluginName: pluginZodName }),
75
- schemas: getSchemas(operation, { pluginName: pluginZodName, type: 'function' }),
76
- }
73
+ const casedParams = ast.caseParams(node.parameters, paramsCasing)
74
+ const pathParams = casedParams.filter((p) => p.in === 'path')
75
+ const queryParams = casedParams.filter((p) => p.in === 'query')
76
+ const headerParams = casedParams.filter((p) => p.in === 'header')
77
77
 
78
- if (!isQuery || isMutation || !isSuspense || !infiniteOptions) {
79
- return null
80
- }
78
+ const importedTypeNames = [
79
+ node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined,
80
+ tsResolver.resolveResponseName(node),
81
+ ...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
82
+ ...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
83
+ ...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
84
+ ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
85
+ ].filter(Boolean)
86
+
87
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
88
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
89
+ const fileZod = zodResolver
90
+ ? zodResolver.resolveFile(
91
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
92
+ { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
93
+ )
94
+ : undefined
95
+ const zodSchemaNames =
96
+ zodResolver && parser === 'zod'
97
+ ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined].filter(Boolean)
98
+ : []
99
+
100
+ const clientPlugin = driver.getPlugin(pluginClientName)
101
+ const hasClientPlugin = clientPlugin?.name === pluginClientName
102
+ const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
103
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : undefined
104
+
105
+ const clientFile = shouldUseClientPlugin
106
+ ? clientResolver?.resolveFile(
107
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
108
+ {
109
+ root,
110
+ output: clientPlugin?.options?.output ?? output,
111
+ group: clientPlugin?.options?.group,
112
+ },
113
+ )
114
+ : undefined
115
+
116
+ const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientBaseName) : clientBaseName
81
117
 
82
118
  return (
83
119
  <File
84
- baseName={query.file.baseName}
85
- path={query.file.path}
86
- meta={query.file.meta}
87
- banner={getBanner({ oas, output, config: driver.config })}
88
- footer={getFooter({ oas, output })}
120
+ baseName={meta.file.baseName}
121
+ path={meta.file.path}
122
+ meta={meta.file.meta}
123
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
124
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
89
125
  >
90
- {options.parser === 'zod' && (
91
- <File.Import name={[zod.schemas.response.name, zod.schemas.request?.name].filter(Boolean)} root={query.file.path} path={zod.file.path} />
126
+ {parser === 'zod' && fileZod && zodSchemaNames.length > 0 && (
127
+ <File.Import name={zodSchemaNames as string[]} root={meta.file.path} path={fileZod.path} />
92
128
  )}
93
- {options.client.importPath ? (
129
+ {clientOptions.importPath ? (
94
130
  <>
95
- {!shouldUseClientPlugin && <File.Import name={'fetch'} path={options.client.importPath} />}
96
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={options.client.importPath} isTypeOnly />
97
- {options.client.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={options.client.importPath} isTypeOnly />}
131
+ {!shouldUseClientPlugin && <File.Import name={'fetch'} path={clientOptions.importPath} />}
132
+ <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
133
+ {clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
98
134
  </>
99
135
  ) : (
100
136
  <>
101
- {!shouldUseClientPlugin && (
102
- <File.Import name={['fetch']} root={query.file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
103
- )}
137
+ {!shouldUseClientPlugin && <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />}
104
138
  <File.Import
105
139
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
106
- root={query.file.path}
107
- path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
140
+ root={meta.file.path}
141
+ path={path.resolve(root, '.kubb/fetch.ts')}
108
142
  isTypeOnly
109
143
  />
110
- {options.client.dataReturnType === 'full' && (
111
- <File.Import name={['ResponseConfig']} root={query.file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} isTypeOnly />
144
+ {clientOptions.dataReturnType === 'full' && (
145
+ <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
112
146
  )}
113
147
  </>
114
148
  )}
115
-
116
- {shouldUseClientPlugin && <File.Import name={[client.name]} root={query.file.path} path={client.file.path} />}
117
- {!shouldUseClientPlugin && (
118
- <File.Import name={['buildFormData']} root={query.file.path} path={path.resolve(config.root, config.output.path, '.kubb/config.ts')} />
149
+ {shouldUseClientPlugin && clientFile && <File.Import name={[resolvedClientName]} root={meta.file.path} path={clientFile.path} />}
150
+ {!shouldUseClientPlugin && <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />}
151
+ {customOptions && <File.Import name={[customOptions.name]} path={customOptions.importPath} />}
152
+ {meta.fileTs && importedTypeNames.length > 0 && (
153
+ <File.Import name={Array.from(new Set(importedTypeNames))} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
119
154
  )}
120
- {options.customOptions && <File.Import name={[options.customOptions.name]} path={options.customOptions.importPath} />}
121
- <File.Import
122
- name={[
123
- type.schemas.request?.name,
124
- type.schemas.response.name,
125
- type.schemas.pathParams?.name,
126
- type.schemas.queryParams?.name,
127
- type.schemas.headerParams?.name,
128
- ...(type.schemas.statusCodes?.map((item) => item.name) || []),
129
- ].filter(Boolean)}
130
- root={query.file.path}
131
- path={type.file.path}
132
- isTypeOnly
133
- />
155
+
134
156
  <QueryKey
135
- name={queryKey.name}
136
- typeName={queryKey.typeName}
137
- operation={operation}
138
- paramsCasing={options.paramsCasing}
139
- pathParamsType={options.pathParamsType}
140
- typeSchemas={type.schemas}
141
- transformer={options.queryKey}
157
+ name={queryKeyName}
158
+ typeName={queryKeyTypeName}
159
+ node={node}
160
+ tsResolver={tsResolver}
161
+ pathParamsType={pathParamsType}
162
+ paramsCasing={paramsCasing}
163
+ transformer={ctx.options.queryKey}
142
164
  />
165
+
143
166
  {!shouldUseClientPlugin && (
144
167
  <Client
145
- name={client.name}
146
- baseURL={options.client.baseURL}
147
- operation={operation}
148
- typeSchemas={type.schemas}
149
- zodSchemas={zod.schemas}
150
- dataReturnType={options.client.dataReturnType || 'data'}
151
- paramsCasing={options.client?.paramsCasing || options.paramsCasing}
152
- paramsType={options.paramsType}
153
- pathParamsType={options.pathParamsType}
154
- parser={options.parser}
168
+ name={resolvedClientName}
169
+ baseURL={clientOptions.baseURL}
170
+ dataReturnType={clientOptions.dataReturnType || 'data'}
171
+ paramsCasing={clientOptions.paramsCasing || paramsCasing}
172
+ paramsType={paramsType}
173
+ pathParamsType={pathParamsType}
174
+ parser={parser}
175
+ node={node}
176
+ tsResolver={tsResolver}
177
+ zodResolver={zodResolver}
155
178
  />
156
179
  )}
157
- {infiniteOptions && (
158
- <>
159
- <File.Import name={['InfiniteData']} isTypeOnly path={importPath} />
160
- <File.Import name={['infiniteQueryOptions']} path={importPath} />
161
- <SuspenseInfiniteQueryOptions
162
- name={queryOptions.name}
163
- clientName={client.name}
164
- queryKeyName={queryKey.name}
165
- typeSchemas={type.schemas}
166
- paramsCasing={options.paramsCasing}
167
- paramsType={options.paramsType}
168
- pathParamsType={options.pathParamsType}
169
- dataReturnType={options.client.dataReturnType || 'data'}
170
- cursorParam={infiniteOptions.cursorParam}
171
- nextParam={infiniteOptions.nextParam}
172
- previousParam={infiniteOptions.previousParam}
173
- initialPageParam={infiniteOptions.initialPageParam}
174
- queryParam={infiniteOptions.queryParam}
175
- />
176
- </>
177
- )}
178
- {infiniteOptions && (
179
- <>
180
- <File.Import name={['useSuspenseInfiniteQuery']} path={importPath} />
181
- <File.Import name={['QueryKey', 'QueryClient', 'UseSuspenseInfiniteQueryOptions', 'UseSuspenseInfiniteQueryResult']} path={importPath} isTypeOnly />
182
- <SuspenseInfiniteQuery
183
- name={query.name}
184
- queryOptionsName={queryOptions.name}
185
- typeSchemas={type.schemas}
186
- paramsCasing={options.paramsCasing}
187
- paramsType={options.paramsType}
188
- pathParamsType={options.pathParamsType}
189
- operation={operation}
190
- dataReturnType={options.client.dataReturnType || 'data'}
191
- queryKeyName={queryKey.name}
192
- queryKeyTypeName={queryKey.typeName}
193
- customOptions={options.customOptions}
194
- initialPageParam={infiniteOptions.initialPageParam}
195
- queryParam={infiniteOptions.queryParam}
196
- />
197
- </>
198
- )}
180
+
181
+ <File.Import name={['InfiniteData']} isTypeOnly path={importPath} />
182
+ <File.Import name={['infiniteQueryOptions']} path={importPath} />
183
+
184
+ <SuspenseInfiniteQueryOptions
185
+ name={queryOptionsName}
186
+ clientName={resolvedClientName}
187
+ queryKeyName={queryKeyName}
188
+ node={node}
189
+ tsResolver={tsResolver}
190
+ paramsCasing={paramsCasing}
191
+ paramsType={paramsType}
192
+ pathParamsType={pathParamsType}
193
+ dataReturnType={clientOptions.dataReturnType || 'data'}
194
+ cursorParam={infiniteOptions.cursorParam}
195
+ nextParam={infiniteOptions.nextParam}
196
+ previousParam={infiniteOptions.previousParam}
197
+ initialPageParam={infiniteOptions.initialPageParam}
198
+ queryParam={infiniteOptions.queryParam}
199
+ />
200
+
201
+ <File.Import name={['useSuspenseInfiniteQuery']} path={importPath} />
202
+ <File.Import name={['QueryKey', 'QueryClient', 'UseSuspenseInfiniteQueryOptions', 'UseSuspenseInfiniteQueryResult']} path={importPath} isTypeOnly />
203
+
204
+ <SuspenseInfiniteQuery
205
+ name={queryName}
206
+ queryOptionsName={queryOptionsName}
207
+ queryKeyName={queryKeyName}
208
+ queryKeyTypeName={queryKeyTypeName}
209
+ node={node}
210
+ tsResolver={tsResolver}
211
+ paramsCasing={paramsCasing}
212
+ paramsType={paramsType}
213
+ pathParamsType={pathParamsType}
214
+ dataReturnType={clientOptions.dataReturnType || 'data'}
215
+ initialPageParam={infiniteOptions.initialPageParam}
216
+ queryParam={infiniteOptions.queryParam}
217
+ customOptions={customOptions}
218
+ />
199
219
  </File>
200
220
  )
201
221
  },