@kubb/plugin-react-query 5.0.0-alpha.8 → 5.0.0-beta.10

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