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

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 (41) hide show
  1. package/README.md +26 -5
  2. package/dist/{components-qfOFRSoM.cjs → components-B6lPYyOP.cjs} +367 -381
  3. package/dist/components-B6lPYyOP.cjs.map +1 -0
  4. package/dist/{components-D1UhYFgY.js → components-BZqujNQv.js} +336 -380
  5. package/dist/components-BZqujNQv.js.map +1 -0
  6. package/dist/components.cjs +1 -1
  7. package/dist/components.d.ts +3 -67
  8. package/dist/components.js +1 -1
  9. package/dist/{generators-CbnIVBgY.js → generators-C-3isXzW.js} +158 -203
  10. package/dist/generators-C-3isXzW.js.map +1 -0
  11. package/dist/{generators-C4gs_P1i.cjs → generators-QHQkbNnm.cjs} +157 -202
  12. package/dist/generators-QHQkbNnm.cjs.map +1 -0
  13. package/dist/generators.cjs +1 -1
  14. package/dist/generators.d.ts +17 -1
  15. package/dist/generators.js +1 -1
  16. package/dist/index.cjs +136 -23
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +29 -1
  19. package/dist/index.js +136 -23
  20. package/dist/index.js.map +1 -1
  21. package/dist/types-D-LjzI_Q.d.ts +270 -0
  22. package/extension.yaml +1273 -0
  23. package/package.json +16 -18
  24. package/src/components/InfiniteQuery.tsx +16 -48
  25. package/src/components/InfiniteQueryOptions.tsx +43 -58
  26. package/src/components/Mutation.tsx +33 -42
  27. package/src/components/Query.tsx +16 -49
  28. package/src/components/QueryKey.tsx +9 -61
  29. package/src/components/QueryOptions.tsx +20 -76
  30. package/src/generators/infiniteQueryGenerator.tsx +55 -63
  31. package/src/generators/mutationGenerator.tsx +50 -61
  32. package/src/generators/queryGenerator.tsx +52 -61
  33. package/src/plugin.ts +46 -30
  34. package/src/resolvers/resolverVueQuery.ts +61 -4
  35. package/src/types.ts +129 -53
  36. package/src/utils.ts +44 -25
  37. package/dist/components-D1UhYFgY.js.map +0 -1
  38. package/dist/components-qfOFRSoM.cjs.map +0 -1
  39. package/dist/generators-C4gs_P1i.cjs.map +0 -1
  40. package/dist/generators-CbnIVBgY.js.map +0 -1
  41. package/dist/types-nVDTfuS1.d.ts +0 -194
package/package.json CHANGED
@@ -1,26 +1,23 @@
1
1
  {
2
2
  "name": "@kubb/plugin-vue-query",
3
- "version": "5.0.0-beta.3",
4
- "description": "Vue Query hooks generator plugin for Kubb, creating type-safe API client hooks from OpenAPI specifications for Vue.js applications.",
3
+ "version": "5.0.0-beta.31",
4
+ "description": "Generate type-safe TanStack Query (Vue Query) composables from your OpenAPI specification. Covers useQuery, useMutation, useInfiniteQuery, and queryOptions with Vue 3 Composition API support.",
5
5
  "keywords": [
6
- "api-client",
7
- "code-generator",
6
+ "code-generation",
8
7
  "codegen",
9
8
  "composables",
9
+ "composition-api",
10
10
  "data-fetching",
11
- "hooks",
12
11
  "kubb",
13
- "oas",
14
12
  "openapi",
15
- "plugins",
16
- "sdk-generator",
17
13
  "swagger",
14
+ "tanstack",
18
15
  "tanstack-query",
19
- "type-safe",
20
16
  "typescript",
17
+ "use-mutation",
18
+ "use-query",
21
19
  "vue",
22
20
  "vue-query",
23
- "vue.js",
24
21
  "vue3"
25
22
  ],
26
23
  "license": "MIT",
@@ -33,7 +30,7 @@
33
30
  "files": [
34
31
  "src",
35
32
  "dist",
36
- "plugin.json",
33
+ "extension.yaml",
37
34
  "!/**/**.test.**",
38
35
  "!/**/__tests__/**",
39
36
  "!/**/__snapshots__/**"
@@ -73,19 +70,20 @@
73
70
  "registry": "https://registry.npmjs.org/"
74
71
  },
75
72
  "dependencies": {
76
- "@kubb/core": "5.0.0-beta.3",
77
- "@kubb/renderer-jsx": "5.0.0-beta.3",
78
- "remeda": "^2.34.0",
79
- "@kubb/plugin-client": "5.0.0-beta.3",
80
- "@kubb/plugin-ts": "5.0.0-beta.3",
81
- "@kubb/plugin-zod": "5.0.0-beta.3"
73
+ "@kubb/core": "5.0.0-beta.31",
74
+ "@kubb/renderer-jsx": "5.0.0-beta.31",
75
+ "remeda": "^2.34.1",
76
+ "@kubb/plugin-client": "5.0.0-beta.31",
77
+ "@kubb/plugin-ts": "5.0.0-beta.31",
78
+ "@kubb/plugin-zod": "5.0.0-beta.31"
82
79
  },
83
80
  "devDependencies": {
81
+ "@internals/shared": "0.0.0",
84
82
  "@internals/tanstack-query": "0.0.0",
85
83
  "@internals/utils": "0.0.0"
86
84
  },
87
85
  "peerDependencies": {
88
- "@kubb/renderer-jsx": "5.0.0-beta.3"
86
+ "@kubb/renderer-jsx": "5.0.0-beta.31"
89
87
  },
90
88
  "size-limit": [
91
89
  {
@@ -4,8 +4,9 @@ import { functionPrinter } from '@kubb/plugin-ts'
4
4
  import { File, Function } from '@kubb/renderer-jsx'
5
5
  import type { KubbReactNode } from '@kubb/renderer-jsx/types'
6
6
  import type { Infinite, PluginVueQuery } from '../types.ts'
7
- import { getComments, resolveErrorNames } from '../utils.ts'
8
- import { QueryKey } from './QueryKey.tsx'
7
+ import { getEnabledParamNames, markParamsOptional } from '@internals/tanstack-query'
8
+ import { getComments, resolveErrorNames, resolveSuccessNames, wrapWithMaybeRefOrGetter } from '../utils.ts'
9
+ import { buildQueryKeyParamsNode } from './QueryKey.tsx'
9
10
  import { getQueryOptionsParams } from './QueryOptions.tsx'
10
11
 
11
12
  type Props = {
@@ -26,7 +27,7 @@ type Props = {
26
27
  const declarationPrinter = functionPrinter({ mode: 'declaration' })
27
28
  const callPrinter = functionPrinter({ mode: 'call' })
28
29
 
29
- function getParams(
30
+ function buildInfiniteQueryParamsNode(
30
31
  node: ast.OperationNode,
31
32
  options: {
32
33
  paramsType: PluginVueQuery['resolvedOptions']['paramsType']
@@ -37,8 +38,9 @@ function getParams(
37
38
  },
38
39
  ): ast.FunctionParametersNode {
39
40
  const { paramsType, paramsCasing, pathParamsType, dataReturnType, resolver } = options
40
- const responseName = resolver.resolveResponseName(node)
41
- const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined
41
+ const successNames = resolveSuccessNames(node, resolver)
42
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : resolver.resolveResponseName(node)
43
+ const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null
42
44
  const errorNames = resolveErrorNames(node, resolver)
43
45
 
44
46
  const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
@@ -64,44 +66,7 @@ function getParams(
64
66
  extraParams: [optionsParam],
65
67
  })
66
68
 
67
- return wrapOperationParamsWithMaybeRef(baseParams)
68
- }
69
-
70
- function wrapOperationParamsWithMaybeRef(paramsNode: ast.FunctionParametersNode): ast.FunctionParametersNode {
71
- const wrappedParams = paramsNode.params.map((param) => {
72
- if ('kind' in param && (param as ast.ParameterGroupNode).kind === 'ParameterGroup') {
73
- const group = param as ast.ParameterGroupNode
74
- return {
75
- ...group,
76
- properties: group.properties.map((p) => ({
77
- ...p,
78
- type: p.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(p.type)}>` }) : p.type,
79
- })),
80
- }
81
- }
82
- const fp = param as ast.FunctionParameterNode
83
- if (fp.name === 'options') return fp
84
- return {
85
- ...fp,
86
- type: fp.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(fp.type)}>` }) : fp.type,
87
- }
88
- })
89
- return ast.createFunctionParameters({ params: wrappedParams })
90
- }
91
-
92
- function printType(typeNode: ast.ParamsTypeNode | undefined): string {
93
- if (!typeNode) return 'unknown'
94
- if (typeNode.variant === 'reference') return typeNode.name
95
- if (typeNode.variant === 'member') return `${typeNode.base}['${typeNode.key}']`
96
- if (typeNode.variant === 'struct') {
97
- const parts = typeNode.properties.map((p) => {
98
- const typeStr = printType(p.type)
99
- const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name)
100
- return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`
101
- })
102
- return `{ ${parts.join('; ')} }`
103
- }
104
- return 'unknown'
69
+ return wrapWithMaybeRefOrGetter(baseParams, (name) => name === 'options')
105
70
  }
106
71
 
107
72
  export function InfiniteQuery({
@@ -116,7 +81,8 @@ export function InfiniteQuery({
116
81
  node,
117
82
  tsResolver,
118
83
  }: Props): KubbReactNode {
119
- const responseName = tsResolver.resolveResponseName(node)
84
+ const successNames = resolveSuccessNames(node, tsResolver)
85
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
120
86
  const errorNames = resolveErrorNames(node, tsResolver)
121
87
 
122
88
  const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
@@ -124,13 +90,17 @@ export function InfiniteQuery({
124
90
  const returnType = `UseInfiniteQueryReturnType<${['TData', TError].join(', ')}> & { queryKey: TQueryKey }`
125
91
  const generics = [`TData = InfiniteData<${TData}>`, `TQueryData = ${TData}`, `TQueryKey extends QueryKey = ${queryKeyTypeName}`]
126
92
 
127
- const queryKeyParamsNode = QueryKey.getParams(node, { pathParamsType, paramsCasing, resolver: tsResolver })
93
+ const queryKeyParamsNode = buildQueryKeyParamsNode(node, { pathParamsType, paramsCasing, resolver: tsResolver })
128
94
  const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? ''
95
+ const enabledNames = getEnabledParamNames(queryKeyParamsNode)
129
96
 
130
97
  const queryOptionsParamsNode = getQueryOptionsParams(node, { paramsType, paramsCasing, pathParamsType, resolver: tsResolver })
131
98
  const queryOptionsParamsCall = callPrinter.print(queryOptionsParamsNode) ?? ''
132
99
 
133
- const paramsNode = getParams(node, { paramsType, paramsCasing, pathParamsType, dataReturnType, resolver: tsResolver })
100
+ const paramsNode = markParamsOptional(
101
+ buildInfiniteQueryParamsNode(node, { paramsType, paramsCasing, pathParamsType, dataReturnType, resolver: tsResolver }),
102
+ enabledNames,
103
+ )
134
104
  const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
135
105
 
136
106
  return (
@@ -155,5 +125,3 @@ export function InfiniteQuery({
155
125
  </File.Source>
156
126
  )
157
127
  }
158
-
159
- InfiniteQuery.getParams = getParams
@@ -1,3 +1,4 @@
1
+ import { getOperationParameters } from '@internals/shared'
1
2
  import { getNestedAccessor } from '@internals/utils'
2
3
  import type { ast } from '@kubb/core'
3
4
  import type { ResolverTs } from '@kubb/plugin-ts'
@@ -5,9 +6,10 @@ import { functionPrinter } from '@kubb/plugin-ts'
5
6
  import { File, Function } from '@kubb/renderer-jsx'
6
7
  import type { KubbReactNode } from '@kubb/renderer-jsx/types'
7
8
  import type { Infinite, PluginVueQuery } from '../types.ts'
8
- import { resolveErrorNames } from '../utils.ts'
9
- import { QueryKey } from './QueryKey.tsx'
10
- import { buildEnabledCheck, getQueryOptionsParams } from './QueryOptions.tsx'
9
+ import { resolveErrorNames, resolveSuccessNames } from '../utils.ts'
10
+ import { buildQueryKeyParamsNode } from './QueryKey.tsx'
11
+ import { getEnabledParamNames, markParamsOptional } from '@internals/tanstack-query'
12
+ import { getQueryOptionsParams } from './QueryOptions.tsx'
11
13
 
12
14
  type Props = {
13
15
  name: string
@@ -45,7 +47,8 @@ export function InfiniteQueryOptions({
45
47
  queryParam,
46
48
  queryKeyName,
47
49
  }: Props): KubbReactNode {
48
- const responseName = tsResolver.resolveResponseName(node)
50
+ const successNames = resolveSuccessNames(node, tsResolver)
51
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
49
52
  const queryFnDataType = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
50
53
  const errorNames = resolveErrorNames(node, tsResolver)
51
54
  const errorType = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
@@ -65,61 +68,51 @@ export function InfiniteQueryOptions({
65
68
  ? 'boolean'
66
69
  : 'unknown'
67
70
 
68
- const rawQueryParams = node.parameters.filter((p) => p.in === 'query')
71
+ const rawQueryParams = getOperationParameters(node).query
69
72
  const queryParamsTypeName =
70
73
  rawQueryParams.length > 0
71
74
  ? (() => {
72
75
  const groupName = tsResolver.resolveQueryParamsName(node, rawQueryParams[0]!)
73
76
  const individualName = tsResolver.resolveParamName(node, rawQueryParams[0]!)
74
- return groupName !== individualName ? groupName : undefined
77
+ return groupName !== individualName ? groupName : null
75
78
  })()
76
- : undefined
79
+ : null
77
80
 
78
- const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : undefined
81
+ const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null
79
82
  const pageParamType = queryParamType ? (isInitialPageParamDefined ? `NonNullable<${queryParamType}>` : queryParamType) : fallbackPageParamType
80
83
 
81
- const paramsNode = getQueryOptionsParams(node, { paramsType, paramsCasing, pathParamsType, resolver: tsResolver })
82
- const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
83
- const rawParamsCall = callPrinter.print(paramsNode) ?? ''
84
- const clientCallStr = rawParamsCall.replace(/\bconfig\b(?=[^,]*$)/, '{ ...config, signal: config.signal ?? signal }')
85
-
86
- const queryKeyParamsNode = QueryKey.getParams(node, { pathParamsType, paramsCasing, resolver: tsResolver })
84
+ const queryKeyParamsNode = buildQueryKeyParamsNode(node, { pathParamsType, paramsCasing, resolver: tsResolver })
87
85
  const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? ''
88
86
 
89
- const enabledSource = buildEnabledCheck(queryKeyParamsNode)
90
- const enabledText = enabledSource ? `enabled: () => !!(${enabledSource}),` : ''
87
+ const enabledNames = getEnabledParamNames(queryKeyParamsNode)
88
+ const enabledText = enabledNames.length ? `enabled: () => ${enabledNames.map((n) => `!!toValue(${n})`).join(' && ')},` : ''
91
89
 
92
- const hasNewParams = nextParam !== undefined || previousParam !== undefined
90
+ const paramsNode = markParamsOptional(getQueryOptionsParams(node, { paramsType, paramsCasing, pathParamsType, resolver: tsResolver }), enabledNames)
91
+ const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
92
+ const rawParamsCall = callPrinter.print(paramsNode) ?? ''
93
+ const clientCallStr = rawParamsCall.replace(/\bconfig\b(?=[^,]*$)/, '{ ...config, signal: config.signal ?? signal }')
93
94
 
94
- let getNextPageParamExpr: string | undefined
95
- let getPreviousPageParamExpr: string | undefined
95
+ const hasNewParams = nextParam != null || previousParam != null
96
96
 
97
- if (hasNewParams) {
98
- if (nextParam) {
99
- const accessor = getNestedAccessor(nextParam, 'lastPage')
100
- if (accessor) {
101
- getNextPageParamExpr = `getNextPageParam: (lastPage) => ${accessor}`
102
- }
103
- }
104
- if (previousParam) {
105
- const accessor = getNestedAccessor(previousParam, 'firstPage')
106
- if (accessor) {
107
- getPreviousPageParamExpr = `getPreviousPageParam: (firstPage) => ${accessor}`
108
- }
97
+ const [getNextPageParamExpr, getPreviousPageParamExpr] = (() => {
98
+ if (hasNewParams) {
99
+ const nextAccessor = nextParam ? getNestedAccessor(nextParam, 'lastPage') : null
100
+ const prevAccessor = previousParam ? getNestedAccessor(previousParam, 'firstPage') : null
101
+ return [
102
+ nextAccessor ? `getNextPageParam: (lastPage) => ${nextAccessor}` : null,
103
+ prevAccessor ? `getPreviousPageParam: (firstPage) => ${prevAccessor}` : null,
104
+ ] as const
109
105
  }
110
- } else if (cursorParam) {
111
- getNextPageParamExpr = `getNextPageParam: (lastPage) => lastPage['${cursorParam}']`
112
- getPreviousPageParamExpr = `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`
113
- } else {
114
- if (dataReturnType === 'full') {
115
- getNextPageParamExpr =
116
- 'getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage.data) && lastPage.data.length === 0 ? undefined : lastPageParam + 1'
117
- } else {
118
- getNextPageParamExpr =
119
- 'getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1'
106
+ if (cursorParam) {
107
+ return [`getNextPageParam: (lastPage) => lastPage['${cursorParam}']`, `getPreviousPageParam: (firstPage) => firstPage['${cursorParam}']`] as const
120
108
  }
121
- getPreviousPageParamExpr = 'getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= 1 ? undefined : firstPageParam - 1'
122
- }
109
+ return [
110
+ dataReturnType === 'full'
111
+ ? 'getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage.data) && lastPage.data.length === 0 ? undefined : lastPageParam + 1'
112
+ : 'getNextPageParam: (lastPage, _allPages, lastPageParam) => Array.isArray(lastPage) && lastPage.length === 0 ? undefined : lastPageParam + 1',
113
+ 'getPreviousPageParam: (_firstPage, _allPages, firstPageParam) => firstPageParam <= 1 ? undefined : firstPageParam - 1',
114
+ ] as const
115
+ })()
123
116
 
124
117
  const queryOptionsArr = [
125
118
  `initialPageParam: ${typeof initialPageParam === 'string' ? JSON.stringify(initialPageParam) : initialPageParam}`,
@@ -147,7 +140,7 @@ export function InfiniteQueryOptions({
147
140
  queryKey,
148
141
  queryFn: async ({ signal, pageParam }) => {
149
142
  ${infiniteOverrideParams}
150
- return ${clientName}(${addToValueCalls(clientCallStr)})
143
+ return ${clientName}(${addToValueCalls(clientCallStr, enabledNames)})
151
144
  },
152
145
  ${queryOptionsArr.join(',\n')}
153
146
  })
@@ -166,7 +159,7 @@ export function InfiniteQueryOptions({
166
159
  ${enabledText}
167
160
  queryKey,
168
161
  queryFn: async ({ signal }) => {
169
- return ${clientName}(${addToValueCalls(clientCallStr)})
162
+ return ${clientName}(${addToValueCalls(clientCallStr, enabledNames)})
170
163
  },
171
164
  ${queryOptionsArr.join(',\n')}
172
165
  })
@@ -176,15 +169,17 @@ export function InfiniteQueryOptions({
176
169
  )
177
170
  }
178
171
 
179
- function addToValueCalls(callStr: string): string {
172
+ function addToValueCalls(callStr: string, enabledNames: ReadonlyArray<string> = []): string {
173
+ const optional = new Set(enabledNames)
180
174
  // Step 1: Transform shorthand object params like { petId } → { petId: toValue(petId) }
175
+ // Params that drive the `enabled` guard are optional, so assert non-null: toValue(petId!)
181
176
  let result = callStr.replace(/\{\s*([\w,\s]+)\s*\}(?=\s*,)/g, (match, inner: string) => {
182
177
  if (inner.includes(':') || inner.includes('...')) return match
183
178
  const keys = inner
184
179
  .split(',')
185
180
  .map((k: string) => k.trim())
186
181
  .filter(Boolean)
187
- const wrapped = keys.map((k: string) => `${k}: toValue(${k})`).join(', ')
182
+ const wrapped = keys.map((k: string) => `${k}: toValue(${optional.has(k) ? `${k}!` : k})`).join(', ')
188
183
  return `{ ${wrapped} }`
189
184
  })
190
185
 
@@ -192,18 +187,8 @@ function addToValueCalls(callStr: string): string {
192
187
  result = result.replace(/(?<![{.:?])\b(\w+)\b(?=\s*,)/g, (match, name: string) => {
193
188
  if (name === 'config' || name === 'signal' || name === 'undefined') return match
194
189
  if (match.includes('toValue(')) return match
195
- return `toValue(${name})`
190
+ return `toValue(${optional.has(name) ? `${name}!` : name})`
196
191
  })
197
192
 
198
193
  return result
199
194
  }
200
-
201
- InfiniteQueryOptions.getParams = (
202
- node: ast.OperationNode,
203
- options: {
204
- paramsType: PluginVueQuery['resolvedOptions']['paramsType']
205
- paramsCasing: PluginVueQuery['resolvedOptions']['paramsCasing']
206
- pathParamsType: PluginVueQuery['resolvedOptions']['pathParamsType']
207
- resolver: ResolverTs
208
- },
209
- ) => getQueryOptionsParams(node, options)
@@ -4,8 +4,7 @@ import { functionPrinter } from '@kubb/plugin-ts'
4
4
  import { File, Function } from '@kubb/renderer-jsx'
5
5
  import type { KubbReactNode } from '@kubb/renderer-jsx/types'
6
6
  import type { PluginVueQuery } from '../types.ts'
7
- import { buildMutationArgParams, getComments, resolveErrorNames } from '../utils.ts'
8
- import { MutationKey } from './MutationKey.tsx'
7
+ import { buildRequestConfigType, getComments, resolveErrorNames, resolveSuccessNames, wrapWithMaybeRefOrGetter } from '../utils.ts'
9
8
 
10
9
  type Props = {
11
10
  name: string
@@ -24,7 +23,22 @@ const declarationPrinter = functionPrinter({ mode: 'declaration' })
24
23
  const callPrinter = functionPrinter({ mode: 'call' })
25
24
  const keysPrinter = functionPrinter({ mode: 'keys' })
26
25
 
27
- function getParams(
26
+ function createMutationArgParams(
27
+ node: ast.OperationNode,
28
+ options: {
29
+ paramsCasing: PluginVueQuery['resolvedOptions']['paramsCasing']
30
+ resolver: ResolverTs
31
+ },
32
+ ): ast.FunctionParametersNode {
33
+ return ast.createOperationParams(node, {
34
+ paramsType: 'inline',
35
+ pathParamsType: 'inline',
36
+ paramsCasing: options.paramsCasing,
37
+ resolver: options.resolver,
38
+ })
39
+ }
40
+
41
+ function buildMutationParamsNode(
28
42
  node: ast.OperationNode,
29
43
  options: {
30
44
  paramsCasing: PluginVueQuery['resolvedOptions']['paramsCasing']
@@ -33,24 +47,16 @@ function getParams(
33
47
  },
34
48
  ): ast.FunctionParametersNode {
35
49
  const { paramsCasing, dataReturnType, resolver } = options
36
- const responseName = resolver.resolveResponseName(node)
37
- const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined
50
+ const successNames = resolveSuccessNames(node, resolver)
51
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : resolver.resolveResponseName(node)
38
52
  const errorNames = resolveErrorNames(node, resolver)
39
53
 
40
54
  const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
41
55
  const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
42
56
 
43
- const mutationArgParamsNode = buildMutationArgParams(node, { paramsCasing, resolver })
57
+ const mutationArgParamsNode = createMutationArgParams(node, { paramsCasing, resolver })
44
58
 
45
- // Vue-query uses MutationObserverOptions instead of UseMutationOptions, and wraps params with MaybeRefOrGetter
46
- const mutationArgWrapped = mutationArgParamsNode.params.map((param) => {
47
- const fp = param as ast.FunctionParameterNode
48
- return {
49
- ...fp,
50
- type: fp.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(fp.type)}>` }) : fp.type,
51
- }
52
- })
53
- const wrappedParamsNode = ast.createFunctionParameters({ params: mutationArgWrapped })
59
+ const wrappedParamsNode = wrapWithMaybeRefOrGetter(mutationArgParamsNode)
54
60
  const TRequestWrapped = wrappedParamsNode.params.length > 0 ? (declarationPrinter.print(wrappedParamsNode) ?? '') : ''
55
61
 
56
62
  return ast.createFunctionParameters({
@@ -60,8 +66,8 @@ function getParams(
60
66
  type: ast.createParamsType({
61
67
  variant: 'reference',
62
68
  name: `{
63
- mutation?: MutationObserverOptions<${[TData, TError, TRequestWrapped ? `{${TRequestWrapped}}` : 'void', 'TContext'].join(', ')}> & { client?: QueryClient },
64
- client?: ${requestName ? `Partial<RequestConfig<${requestName}>> & { client?: Client }` : 'Partial<RequestConfig> & { client?: Client }'},
69
+ mutation?: MutationObserverOptions<${[TData, TError, TRequestWrapped ? `{${TRequestWrapped}}` : 'undefined', 'TContext'].join(', ')}> & { client?: QueryClient },
70
+ client?: ${buildRequestConfigType(node, resolver)},
65
71
  }`,
66
72
  }),
67
73
  default: '{}',
@@ -70,21 +76,6 @@ function getParams(
70
76
  })
71
77
  }
72
78
 
73
- function printType(typeNode: ast.ParamsTypeNode | undefined): string {
74
- if (!typeNode) return 'unknown'
75
- if (typeNode.variant === 'reference') return typeNode.name
76
- if (typeNode.variant === 'member') return `${typeNode.base}['${typeNode.key}']`
77
- if (typeNode.variant === 'struct') {
78
- const parts = typeNode.properties.map((p) => {
79
- const typeStr = printType(p.type)
80
- const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name)
81
- return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`
82
- })
83
- return `{ ${parts.join('; ')} }`
84
- }
85
- return 'unknown'
86
- }
87
-
88
79
  export function Mutation({
89
80
  name,
90
81
  clientName,
@@ -96,20 +87,24 @@ export function Mutation({
96
87
  tsResolver,
97
88
  mutationKeyName,
98
89
  }: Props): KubbReactNode {
99
- const responseName = tsResolver.resolveResponseName(node)
90
+ const successNames = resolveSuccessNames(node, tsResolver)
91
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
100
92
  const errorNames = resolveErrorNames(node, tsResolver)
101
93
 
102
94
  const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
103
95
  const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
104
96
 
105
- const mutationArgParamsNode = buildMutationArgParams(node, { paramsCasing, resolver: tsResolver })
97
+ const mutationArgParamsNode = createMutationArgParams(node, {
98
+ paramsCasing,
99
+ resolver: tsResolver,
100
+ })
106
101
  const hasMutationParams = mutationArgParamsNode.params.length > 0
107
102
  const TRequest = hasMutationParams ? (declarationPrinter.print(mutationArgParamsNode) ?? '') : ''
108
103
  const argKeysStr = hasMutationParams ? (keysPrinter.print(mutationArgParamsNode) ?? '') : ''
109
104
 
110
- const generics = [TData, TError, TRequest ? `{${TRequest}}` : 'void', 'TContext'].join(', ')
105
+ const generics = [TData, TError, TRequest ? `{${TRequest}}` : 'undefined', 'TContext'].join(', ')
111
106
 
112
- const mutationKeyParamsNode = MutationKey.getParams()
107
+ const mutationKeyParamsNode = ast.createFunctionParameters({ params: [] })
113
108
  const mutationKeyParamsCall = callPrinter.print(mutationKeyParamsNode) ?? ''
114
109
 
115
110
  const clientCallParamsNode = ast.createOperationParams(node, {
@@ -122,9 +117,7 @@ export function Mutation({
122
117
  name: 'config',
123
118
  type: ast.createParamsType({
124
119
  variant: 'reference',
125
- name: node.requestBody?.content?.[0]?.schema
126
- ? `Partial<RequestConfig<${tsResolver.resolveDataName(node)}>> & { client?: Client }`
127
- : 'Partial<RequestConfig> & { client?: Client }',
120
+ name: buildRequestConfigType(node, tsResolver),
128
121
  }),
129
122
  default: '{}',
130
123
  }),
@@ -132,7 +125,7 @@ export function Mutation({
132
125
  })
133
126
  const clientCallStr = callPrinter.print(clientCallParamsNode) ?? ''
134
127
 
135
- const paramsNode = getParams(node, { paramsCasing, dataReturnType, resolver: tsResolver })
128
+ const paramsNode = buildMutationParamsNode(node, { paramsCasing, dataReturnType, resolver: tsResolver })
136
129
  const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
137
130
 
138
131
  return (
@@ -155,5 +148,3 @@ export function Mutation({
155
148
  </File.Source>
156
149
  )
157
150
  }
158
-
159
- Mutation.getParams = getParams
@@ -4,8 +4,9 @@ import { functionPrinter } from '@kubb/plugin-ts'
4
4
  import { File, Function } from '@kubb/renderer-jsx'
5
5
  import type { KubbReactNode } from '@kubb/renderer-jsx/types'
6
6
  import type { PluginVueQuery } from '../types.ts'
7
- import { getComments, resolveErrorNames } from '../utils.ts'
8
- import { QueryKey } from './QueryKey.tsx'
7
+ import { getEnabledParamNames, markParamsOptional } from '@internals/tanstack-query'
8
+ import { getComments, resolveErrorNames, resolveSuccessNames, wrapWithMaybeRefOrGetter } from '../utils.ts'
9
+ import { buildQueryKeyParamsNode } from './QueryKey.tsx'
9
10
  import { getQueryOptionsParams } from './QueryOptions.tsx'
10
11
 
11
12
  type Props = {
@@ -24,7 +25,7 @@ type Props = {
24
25
  const declarationPrinter = functionPrinter({ mode: 'declaration' })
25
26
  const callPrinter = functionPrinter({ mode: 'call' })
26
27
 
27
- function getParams(
28
+ function buildQueryParamsNode(
28
29
  node: ast.OperationNode,
29
30
  options: {
30
31
  paramsType: PluginVueQuery['resolvedOptions']['paramsType']
@@ -35,8 +36,9 @@ function getParams(
35
36
  },
36
37
  ): ast.FunctionParametersNode {
37
38
  const { paramsType, paramsCasing, pathParamsType, dataReturnType, resolver } = options
38
- const responseName = resolver.resolveResponseName(node)
39
- const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined
39
+ const successNames = resolveSuccessNames(node, resolver)
40
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : resolver.resolveResponseName(node)
41
+ const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null
40
42
  const errorNames = resolveErrorNames(node, resolver)
41
43
 
42
44
  const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
@@ -63,45 +65,7 @@ function getParams(
63
65
  extraParams: [optionsParam],
64
66
  })
65
67
 
66
- return wrapOperationParamsWithMaybeRef(baseParams)
67
- }
68
-
69
- function wrapOperationParamsWithMaybeRef(paramsNode: ast.FunctionParametersNode): ast.FunctionParametersNode {
70
- const wrappedParams = paramsNode.params.map((param) => {
71
- if ('kind' in param && (param as ast.ParameterGroupNode).kind === 'ParameterGroup') {
72
- const group = param as ast.ParameterGroupNode
73
- return {
74
- ...group,
75
- properties: group.properties.map((p) => ({
76
- ...p,
77
- type: p.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(p.type)}>` }) : p.type,
78
- })),
79
- }
80
- }
81
- const fp = param as ast.FunctionParameterNode
82
- // Don't wrap 'options' param — it's not a reactive value
83
- if (fp.name === 'options') return fp
84
- return {
85
- ...fp,
86
- type: fp.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(fp.type)}>` }) : fp.type,
87
- }
88
- })
89
- return ast.createFunctionParameters({ params: wrappedParams })
90
- }
91
-
92
- function printType(typeNode: ast.ParamsTypeNode | undefined): string {
93
- if (!typeNode) return 'unknown'
94
- if (typeNode.variant === 'reference') return typeNode.name
95
- if (typeNode.variant === 'member') return `${typeNode.base}['${typeNode.key}']`
96
- if (typeNode.variant === 'struct') {
97
- const parts = typeNode.properties.map((p) => {
98
- const typeStr = printType(p.type)
99
- const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name)
100
- return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`
101
- })
102
- return `{ ${parts.join('; ')} }`
103
- }
104
- return 'unknown'
68
+ return wrapWithMaybeRefOrGetter(baseParams, (name) => name === 'options')
105
69
  }
106
70
 
107
71
  export function Query({
@@ -116,7 +80,8 @@ export function Query({
116
80
  node,
117
81
  tsResolver,
118
82
  }: Props): KubbReactNode {
119
- const responseName = tsResolver.resolveResponseName(node)
83
+ const successNames = resolveSuccessNames(node, tsResolver)
84
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
120
85
  const errorNames = resolveErrorNames(node, tsResolver)
121
86
 
122
87
  const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
@@ -124,13 +89,17 @@ export function Query({
124
89
  const returnType = `UseQueryReturnType<${['TData', TError].join(', ')}> & { queryKey: TQueryKey }`
125
90
  const generics = [`TData = ${TData}`, `TQueryData = ${TData}`, `TQueryKey extends QueryKey = ${queryKeyTypeName}`]
126
91
 
127
- const queryKeyParamsNode = QueryKey.getParams(node, { pathParamsType, paramsCasing, resolver: tsResolver })
92
+ const queryKeyParamsNode = buildQueryKeyParamsNode(node, { pathParamsType, paramsCasing, resolver: tsResolver })
128
93
  const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? ''
94
+ const enabledNames = getEnabledParamNames(queryKeyParamsNode)
129
95
 
130
96
  const queryOptionsParamsNode = getQueryOptionsParams(node, { paramsType, paramsCasing, pathParamsType, resolver: tsResolver })
131
97
  const queryOptionsParamsCall = callPrinter.print(queryOptionsParamsNode) ?? ''
132
98
 
133
- const paramsNode = getParams(node, { paramsType, paramsCasing, pathParamsType, dataReturnType, resolver: tsResolver })
99
+ const paramsNode = markParamsOptional(
100
+ buildQueryParamsNode(node, { paramsType, paramsCasing, pathParamsType, dataReturnType, resolver: tsResolver }),
101
+ enabledNames,
102
+ )
134
103
  const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
135
104
 
136
105
  return (
@@ -155,5 +124,3 @@ export function Query({
155
124
  </File.Source>
156
125
  )
157
126
  }
158
-
159
- Query.getParams = getParams