@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,203 +1,204 @@
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, QueryOptions, SuspenseQuery } from '../components'
13
9
  import type { PluginReactQuery } from '../types'
10
+ import { transformName } from '../utils.ts'
14
11
 
15
- export const suspenseQueryGenerator = createReactGenerator<PluginReactQuery>({
12
+ export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
16
13
  name: 'react-suspense-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
+ suspense,
22
+ paramsCasing,
23
+ paramsType,
24
+ pathParamsType,
25
+ parser,
26
+ client: clientOptions,
27
+ group,
28
+ transformers,
29
+ customOptions,
30
+ } = ctx.options
23
31
 
24
- const oas = useOas()
25
- const { getSchemas, getName, getFile } = useOperationManager(generator)
32
+ const pluginTs = driver.getPlugin(pluginTsName)
33
+ if (!pluginTs) return null
34
+ const tsResolver = driver.getResolver(pluginTsName)
26
35
 
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
- )
36
+ // query: false means "this IS a query op" (suspense hooks still generate)
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
31
43
 
32
- const isSuspense = !!options.suspense
44
+ if (!isQuery || isMutation || !isSuspense) return null
33
45
 
34
- const importPath = options.query ? options.query.importPath : '@tanstack/react-query'
46
+ const importPath = query ? query.importPath : '@tanstack/react-query'
35
47
 
36
- const query = {
37
- name: getName(operation, {
38
- type: 'function',
39
- prefix: 'use',
40
- suffix: 'suspense',
41
- }),
42
- typeName: getName(operation, { type: 'type' }),
43
- file: getFile(operation, { prefix: 'use', suffix: 'suspense' }),
44
- }
48
+ const baseName = resolver.resolveName(node.operationId)
49
+ const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
50
+ const queryName = transformName(`use${capitalize(baseName)}Suspense`, 'function', transformers)
51
+ const queryOptionsName = transformName(`${baseName}SuspenseQueryOptions`, 'function', transformers)
52
+ const queryKeyName = transformName(`${baseName}SuspenseQueryKey`, 'const', transformers)
53
+ const queryKeyTypeName = transformName(`${capitalize(baseName)}SuspenseQueryKey`, 'type', transformers)
54
+ const clientName = transformName(`${baseName}Suspense`, 'function', transformers)
45
55
 
46
- const hasClientPlugin = !!driver.getPluginByName(pluginClientName)
47
- // Class-based clients are not compatible with query hooks, so we generate inline clients
48
- const shouldUseClientPlugin = hasClientPlugin && options.client.clientType !== 'class'
49
- const client = {
50
- name: shouldUseClientPlugin
51
- ? getName(operation, {
52
- type: 'function',
53
- pluginName: pluginClientName,
54
- })
55
- : getName(operation, {
56
- type: 'function',
57
- suffix: 'suspense',
58
- }),
59
- file: getFile(operation, { pluginName: pluginClientName }),
56
+ const meta = {
57
+ file: resolver.resolveFile({ name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
58
+ fileTs: tsResolver.resolveFile(
59
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
60
+ { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
61
+ ),
60
62
  }
61
63
 
62
- const queryOptions = {
63
- name: getName(operation, {
64
- type: 'function',
65
- suffix: 'SuspenseQueryOptions',
66
- }),
67
- }
64
+ const casedParams = ast.caseParams(node.parameters, paramsCasing)
65
+ const pathParams = casedParams.filter((p) => p.in === 'path')
66
+ const queryParams = casedParams.filter((p) => p.in === 'query')
67
+ const headerParams = casedParams.filter((p) => p.in === 'header')
68
68
 
69
- const queryKey = {
70
- name: getName(operation, { type: 'const', suffix: 'SuspenseQueryKey' }),
71
- typeName: getName(operation, {
72
- type: 'type',
73
- suffix: 'SuspenseQueryKey',
74
- }),
75
- }
69
+ const importedTypeNames = [
70
+ node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined,
71
+ tsResolver.resolveResponseName(node),
72
+ ...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
73
+ ...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
74
+ ...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
75
+ ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
76
+ ].filter((name): name is string => !!name && name !== queryKeyTypeName)
76
77
 
77
- const type = {
78
- file: getFile(operation, { pluginName: pluginTsName }),
79
- //todo remove type?
80
- schemas: getSchemas(operation, {
81
- pluginName: pluginTsName,
82
- type: 'type',
83
- }),
84
- }
78
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
79
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
80
+ const fileZod = zodResolver
81
+ ? zodResolver.resolveFile(
82
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
83
+ { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
84
+ )
85
+ : undefined
86
+ const zodSchemaNames =
87
+ zodResolver && parser === 'zod'
88
+ ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined].filter(Boolean)
89
+ : []
85
90
 
86
- const zod = {
87
- file: getFile(operation, { pluginName: pluginZodName }),
88
- schemas: getSchemas(operation, {
89
- pluginName: pluginZodName,
90
- type: 'function',
91
- }),
92
- }
91
+ const clientPlugin = driver.getPlugin(pluginClientName)
92
+ const hasClientPlugin = clientPlugin?.name === pluginClientName
93
+ const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
94
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : undefined
93
95
 
94
- if (!isQuery || isMutation || !isSuspense) {
95
- return null
96
- }
96
+ const clientFile = shouldUseClientPlugin
97
+ ? clientResolver?.resolveFile(
98
+ { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
99
+ {
100
+ root,
101
+ output: clientPlugin?.options?.output ?? output,
102
+ group: clientPlugin?.options?.group,
103
+ },
104
+ )
105
+ : undefined
106
+
107
+ const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientName) : clientName
97
108
 
98
109
  return (
99
110
  <File
100
- baseName={query.file.baseName}
101
- path={query.file.path}
102
- meta={query.file.meta}
103
- banner={getBanner({ oas, output, config: driver.config })}
104
- footer={getFooter({ oas, output })}
111
+ baseName={meta.file.baseName}
112
+ path={meta.file.path}
113
+ meta={meta.file.meta}
114
+ banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
115
+ footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
105
116
  >
106
- {options.parser === 'zod' && (
107
- <File.Import name={[zod.schemas.response.name, zod.schemas.request?.name].filter(Boolean)} root={query.file.path} path={zod.file.path} />
117
+ {parser === 'zod' && fileZod && zodSchemaNames.length > 0 && (
118
+ <File.Import name={zodSchemaNames as string[]} root={meta.file.path} path={fileZod.path} />
108
119
  )}
109
- {options.client.importPath ? (
120
+ {clientOptions.importPath ? (
110
121
  <>
111
- {!shouldUseClientPlugin && <File.Import name={'fetch'} path={options.client.importPath} />}
112
- <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={options.client.importPath} isTypeOnly />
113
- {options.client.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={options.client.importPath} isTypeOnly />}
122
+ {!shouldUseClientPlugin && <File.Import name={'fetch'} path={clientOptions.importPath} />}
123
+ <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
124
+ {clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
114
125
  </>
115
126
  ) : (
116
127
  <>
117
- {!shouldUseClientPlugin && (
118
- <File.Import name={['fetch']} root={query.file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} />
119
- )}
128
+ {!shouldUseClientPlugin && <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />}
120
129
  <File.Import
121
130
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
122
- root={query.file.path}
123
- path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')}
131
+ root={meta.file.path}
132
+ path={path.resolve(root, '.kubb/fetch.ts')}
124
133
  isTypeOnly
125
134
  />
126
- {options.client.dataReturnType === 'full' && (
127
- <File.Import name={['ResponseConfig']} root={query.file.path} path={path.resolve(config.root, config.output.path, '.kubb/fetch.ts')} isTypeOnly />
135
+ {clientOptions.dataReturnType === 'full' && (
136
+ <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
128
137
  )}
129
138
  </>
130
139
  )}
131
- {shouldUseClientPlugin && <File.Import name={[client.name]} root={query.file.path} path={client.file.path} />}
132
- {!shouldUseClientPlugin && (
133
- <File.Import name={['buildFormData']} root={query.file.path} path={path.resolve(config.root, config.output.path, '.kubb/config.ts')} />
140
+ {shouldUseClientPlugin && clientFile && <File.Import name={[resolvedClientName]} root={meta.file.path} path={clientFile.path} />}
141
+ {!shouldUseClientPlugin && <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />}
142
+ {customOptions && <File.Import name={[customOptions.name]} path={customOptions.importPath} />}
143
+ {meta.fileTs && importedTypeNames.length > 0 && (
144
+ <File.Import name={Array.from(new Set(importedTypeNames))} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
134
145
  )}
135
- {options.customOptions && <File.Import name={[options.customOptions.name]} path={options.customOptions.importPath} />}
136
- <File.Import
137
- name={[
138
- type.schemas.request?.name,
139
- type.schemas.response.name,
140
- type.schemas.pathParams?.name,
141
- type.schemas.queryParams?.name,
142
- type.schemas.headerParams?.name,
143
- ...(type.schemas.statusCodes?.map((item) => item.name) || []),
144
- ].filter(Boolean)}
145
- root={query.file.path}
146
- path={type.file.path}
147
- isTypeOnly
148
- />
146
+
149
147
  <QueryKey
150
- name={queryKey.name}
151
- typeName={queryKey.typeName}
152
- operation={operation}
153
- paramsCasing={options.paramsCasing}
154
- pathParamsType={options.pathParamsType}
155
- typeSchemas={type.schemas}
156
- transformer={options.queryKey}
148
+ name={queryKeyName}
149
+ typeName={queryKeyTypeName}
150
+ node={node}
151
+ tsResolver={tsResolver}
152
+ pathParamsType={pathParamsType}
153
+ paramsCasing={paramsCasing}
154
+ transformer={ctx.options.queryKey}
157
155
  />
158
156
 
159
157
  {!shouldUseClientPlugin && (
160
158
  <Client
161
- name={client.name}
162
- baseURL={options.client.baseURL}
163
- operation={operation}
164
- typeSchemas={type.schemas}
165
- zodSchemas={zod.schemas}
166
- dataReturnType={options.client.dataReturnType || 'data'}
167
- paramsCasing={options.client?.paramsCasing || options.paramsCasing}
168
- paramsType={options.paramsType}
169
- pathParamsType={options.pathParamsType}
170
- parser={options.parser}
159
+ name={resolvedClientName}
160
+ baseURL={clientOptions.baseURL}
161
+ dataReturnType={clientOptions.dataReturnType || 'data'}
162
+ paramsCasing={clientOptions.paramsCasing || paramsCasing}
163
+ paramsType={paramsType}
164
+ pathParamsType={pathParamsType}
165
+ parser={parser}
166
+ node={node}
167
+ tsResolver={tsResolver}
168
+ zodResolver={zodResolver}
171
169
  />
172
170
  )}
171
+
173
172
  <File.Import name={['queryOptions']} path={importPath} />
173
+
174
174
  <QueryOptions
175
- name={queryOptions.name}
176
- clientName={client.name}
177
- queryKeyName={queryKey.name}
178
- typeSchemas={type.schemas}
179
- paramsCasing={options.paramsCasing}
180
- paramsType={options.paramsType}
181
- pathParamsType={options.pathParamsType}
182
- dataReturnType={options.client.dataReturnType}
175
+ name={queryOptionsName}
176
+ clientName={resolvedClientName}
177
+ queryKeyName={queryKeyName}
178
+ node={node}
179
+ tsResolver={tsResolver}
180
+ paramsCasing={paramsCasing}
181
+ paramsType={paramsType}
182
+ pathParamsType={pathParamsType}
183
+ dataReturnType={clientOptions.dataReturnType || 'data'}
183
184
  />
184
- {options.suspense && (
185
+
186
+ {suspense && (
185
187
  <>
186
188
  <File.Import name={['useSuspenseQuery']} path={importPath} />
187
189
  <File.Import name={['QueryKey', 'QueryClient', 'UseSuspenseQueryOptions', 'UseSuspenseQueryResult']} path={importPath} isTypeOnly />
188
-
189
190
  <SuspenseQuery
190
- name={query.name}
191
- queryOptionsName={queryOptions.name}
192
- typeSchemas={type.schemas}
193
- paramsType={options.paramsType}
194
- paramsCasing={options.paramsCasing}
195
- pathParamsType={options.pathParamsType}
196
- operation={operation}
197
- dataReturnType={options.client.dataReturnType || 'data'}
198
- queryKeyName={queryKey.name}
199
- queryKeyTypeName={queryKey.typeName}
200
- customOptions={options.customOptions}
191
+ name={queryName}
192
+ queryOptionsName={queryOptionsName}
193
+ queryKeyName={queryKeyName}
194
+ queryKeyTypeName={queryKeyTypeName}
195
+ node={node}
196
+ tsResolver={tsResolver}
197
+ paramsCasing={paramsCasing}
198
+ paramsType={paramsType}
199
+ pathParamsType={pathParamsType}
200
+ dataReturnType={clientOptions.dataReturnType || 'data'}
201
+ customOptions={customOptions}
201
202
  />
202
203
  </>
203
204
  )}
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { pluginReactQuery, pluginReactQueryName } from './plugin.ts'
1
+ export { default, pluginReactQuery, pluginReactQueryName } from './plugin.ts'
2
2
  export type { PluginReactQuery } from './types.ts'