@kubb/plugin-vue-query 5.0.0-alpha.8 → 5.0.0-beta.3

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