@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.
- package/README.md +26 -5
- package/dist/{components-qfOFRSoM.cjs → components-B6lPYyOP.cjs} +367 -381
- package/dist/components-B6lPYyOP.cjs.map +1 -0
- package/dist/{components-D1UhYFgY.js → components-BZqujNQv.js} +336 -380
- package/dist/components-BZqujNQv.js.map +1 -0
- package/dist/components.cjs +1 -1
- package/dist/components.d.ts +3 -67
- package/dist/components.js +1 -1
- package/dist/{generators-CbnIVBgY.js → generators-C-3isXzW.js} +158 -203
- package/dist/generators-C-3isXzW.js.map +1 -0
- package/dist/{generators-C4gs_P1i.cjs → generators-QHQkbNnm.cjs} +157 -202
- package/dist/generators-QHQkbNnm.cjs.map +1 -0
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.ts +17 -1
- package/dist/generators.js +1 -1
- package/dist/index.cjs +136 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +136 -23
- package/dist/index.js.map +1 -1
- package/dist/types-D-LjzI_Q.d.ts +270 -0
- package/extension.yaml +1273 -0
- package/package.json +16 -18
- package/src/components/InfiniteQuery.tsx +16 -48
- package/src/components/InfiniteQueryOptions.tsx +43 -58
- package/src/components/Mutation.tsx +33 -42
- package/src/components/Query.tsx +16 -49
- package/src/components/QueryKey.tsx +9 -61
- package/src/components/QueryOptions.tsx +20 -76
- package/src/generators/infiniteQueryGenerator.tsx +55 -63
- package/src/generators/mutationGenerator.tsx +50 -61
- package/src/generators/queryGenerator.tsx +52 -61
- package/src/plugin.ts +46 -30
- package/src/resolvers/resolverVueQuery.ts +61 -4
- package/src/types.ts +129 -53
- package/src/utils.ts +44 -25
- package/dist/components-D1UhYFgY.js.map +0 -1
- package/dist/components-qfOFRSoM.cjs.map +0 -1
- package/dist/generators-C4gs_P1i.cjs.map +0 -1
- package/dist/generators-CbnIVBgY.js.map +0 -1
- package/dist/types-nVDTfuS1.d.ts +0 -194
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ast } from '@kubb/core'
|
|
1
|
+
import type { ast } from '@kubb/core'
|
|
3
2
|
import type { ResolverTs } from '@kubb/plugin-ts'
|
|
4
3
|
import { functionPrinter } from '@kubb/plugin-ts'
|
|
5
4
|
import { File, Function, Type } from '@kubb/renderer-jsx'
|
|
6
5
|
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
6
|
+
import { getEnabledParamNames, markParamsOptional, queryKeyTransformer } from '@internals/tanstack-query'
|
|
7
7
|
import type { Transformer } from '../types.ts'
|
|
8
|
-
import { buildQueryKeyParams } from '../utils.ts'
|
|
8
|
+
import { buildQueryKeyParams, wrapWithMaybeRefOrGetter } from '../utils.ts'
|
|
9
9
|
|
|
10
10
|
type Props = {
|
|
11
11
|
name: string
|
|
@@ -14,71 +14,23 @@ type Props = {
|
|
|
14
14
|
tsResolver: ResolverTs
|
|
15
15
|
paramsCasing: 'camelcase' | undefined
|
|
16
16
|
pathParamsType: 'object' | 'inline'
|
|
17
|
-
transformer: Transformer | undefined
|
|
17
|
+
transformer: Transformer | null | undefined
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const declarationPrinter = functionPrinter({ mode: 'declaration' })
|
|
21
|
-
const callPrinter = functionPrinter({ mode: 'call' })
|
|
22
21
|
|
|
23
|
-
function
|
|
24
|
-
const wrappedParams = paramsNode.params.map((param) => {
|
|
25
|
-
if ('kind' in param && (param as ast.ParameterGroupNode).kind === 'ParameterGroup') {
|
|
26
|
-
const group = param as ast.ParameterGroupNode
|
|
27
|
-
return {
|
|
28
|
-
...group,
|
|
29
|
-
properties: group.properties.map((p) => ({
|
|
30
|
-
...p,
|
|
31
|
-
type: p.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(p.type)}>` }) : p.type,
|
|
32
|
-
})),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const fp = param as ast.FunctionParameterNode
|
|
36
|
-
return {
|
|
37
|
-
...fp,
|
|
38
|
-
type: fp.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(fp.type)}>` }) : fp.type,
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
return ast.createFunctionParameters({ params: wrappedParams })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function printType(typeNode: ast.ParamsTypeNode | undefined): string {
|
|
45
|
-
if (!typeNode) return 'unknown'
|
|
46
|
-
if (typeNode.variant === 'reference') return typeNode.name
|
|
47
|
-
if (typeNode.variant === 'member') return `${typeNode.base}['${typeNode.key}']`
|
|
48
|
-
if (typeNode.variant === 'struct') {
|
|
49
|
-
const parts = typeNode.properties.map((p) => {
|
|
50
|
-
const typeStr = printType(p.type)
|
|
51
|
-
const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name)
|
|
52
|
-
return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`
|
|
53
|
-
})
|
|
54
|
-
return `{ ${parts.join('; ')} }`
|
|
55
|
-
}
|
|
56
|
-
return 'unknown'
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function getParams(
|
|
22
|
+
export function buildQueryKeyParamsNode(
|
|
60
23
|
node: ast.OperationNode,
|
|
61
24
|
options: { pathParamsType: 'object' | 'inline'; paramsCasing: 'camelcase' | undefined; resolver: ResolverTs },
|
|
62
25
|
): ast.FunctionParametersNode {
|
|
63
26
|
return wrapWithMaybeRefOrGetter(buildQueryKeyParams(node, options))
|
|
64
27
|
}
|
|
65
28
|
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const hasRequestBody = !!node.requestBody?.content?.[0]?.schema
|
|
70
|
-
|
|
71
|
-
return [
|
|
72
|
-
path.toObject({ type: 'path', stringify: true }),
|
|
73
|
-
hasQueryParams ? '...(params ? [params] : [])' : undefined,
|
|
74
|
-
hasRequestBody ? '...(data ? [data] : [])' : undefined,
|
|
75
|
-
].filter(Boolean) as string[]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function QueryKey({ name, node, tsResolver, paramsCasing, pathParamsType, typeName, transformer = getTransformer }: Props): KubbReactNode {
|
|
79
|
-
const paramsNode = getParams(node, { pathParamsType, paramsCasing, resolver: tsResolver })
|
|
29
|
+
export function QueryKey({ name, node, tsResolver, paramsCasing, pathParamsType, typeName, transformer }: Props): KubbReactNode {
|
|
30
|
+
const baseParamsNode = buildQueryKeyParamsNode(node, { pathParamsType, paramsCasing, resolver: tsResolver })
|
|
31
|
+
const paramsNode = markParamsOptional(baseParamsNode, getEnabledParamNames(baseParamsNode))
|
|
80
32
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
81
|
-
const keys = transformer({
|
|
33
|
+
const keys = (transformer ?? queryKeyTransformer)({
|
|
82
34
|
node,
|
|
83
35
|
casing: paramsCasing,
|
|
84
36
|
})
|
|
@@ -98,7 +50,3 @@ export function QueryKey({ name, node, tsResolver, paramsCasing, pathParamsType,
|
|
|
98
50
|
</>
|
|
99
51
|
)
|
|
100
52
|
}
|
|
101
|
-
|
|
102
|
-
QueryKey.getParams = getParams
|
|
103
|
-
QueryKey.getTransformer = getTransformer
|
|
104
|
-
QueryKey.callPrinter = callPrinter
|
|
@@ -3,9 +3,10 @@ import type { ResolverTs } from '@kubb/plugin-ts'
|
|
|
3
3
|
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
|
+
import { getEnabledParamNames, markParamsOptional } from '@internals/tanstack-query'
|
|
6
7
|
import type { PluginVueQuery } from '../types.ts'
|
|
7
|
-
import { resolveErrorNames } from '../utils.ts'
|
|
8
|
-
import {
|
|
8
|
+
import { resolveErrorNames, resolveSuccessNames, wrapWithMaybeRefOrGetter } from '../utils.ts'
|
|
9
|
+
import { buildQueryKeyParamsNode } from './QueryKey.tsx'
|
|
9
10
|
|
|
10
11
|
type Props = {
|
|
11
12
|
name: string
|
|
@@ -32,7 +33,7 @@ export function getQueryOptionsParams(
|
|
|
32
33
|
},
|
|
33
34
|
): ast.FunctionParametersNode {
|
|
34
35
|
const { paramsType, paramsCasing, pathParamsType, resolver } = options
|
|
35
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) :
|
|
36
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null
|
|
36
37
|
|
|
37
38
|
const baseParams = ast.createOperationParams(node, {
|
|
38
39
|
paramsType,
|
|
@@ -51,65 +52,7 @@ export function getQueryOptionsParams(
|
|
|
51
52
|
],
|
|
52
53
|
})
|
|
53
54
|
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function wrapOperationParamsWithMaybeRef(paramsNode: ast.FunctionParametersNode): ast.FunctionParametersNode {
|
|
58
|
-
const wrappedParams = paramsNode.params.map((param) => {
|
|
59
|
-
if ('kind' in param && (param as ast.ParameterGroupNode).kind === 'ParameterGroup') {
|
|
60
|
-
const group = param as ast.ParameterGroupNode
|
|
61
|
-
return {
|
|
62
|
-
...group,
|
|
63
|
-
properties: group.properties.map((p) => ({
|
|
64
|
-
...p,
|
|
65
|
-
type: p.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(p.type)}>` }) : p.type,
|
|
66
|
-
})),
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const fp = param as ast.FunctionParameterNode
|
|
70
|
-
// Don't wrap 'config' param — it's not reactive
|
|
71
|
-
if (fp.name === 'config') return fp
|
|
72
|
-
return {
|
|
73
|
-
...fp,
|
|
74
|
-
type: fp.type ? ast.createParamsType({ variant: 'reference', name: `MaybeRefOrGetter<${printType(fp.type)}>` }) : fp.type,
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
return ast.createFunctionParameters({ params: wrappedParams })
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function printType(typeNode: ast.ParamsTypeNode | undefined): string {
|
|
81
|
-
if (!typeNode) return 'unknown'
|
|
82
|
-
if (typeNode.variant === 'reference') return typeNode.name
|
|
83
|
-
if (typeNode.variant === 'member') return `${typeNode.base}['${typeNode.key}']`
|
|
84
|
-
if (typeNode.variant === 'struct') {
|
|
85
|
-
const parts = typeNode.properties.map((p) => {
|
|
86
|
-
const typeStr = printType(p.type)
|
|
87
|
-
const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name)
|
|
88
|
-
return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`
|
|
89
|
-
})
|
|
90
|
-
return `{ ${parts.join('; ')} }`
|
|
91
|
-
}
|
|
92
|
-
return 'unknown'
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function buildEnabledCheck(paramsNode: ast.FunctionParametersNode): string {
|
|
96
|
-
const required: string[] = []
|
|
97
|
-
for (const param of paramsNode.params) {
|
|
98
|
-
if ('kind' in param && (param as ast.ParameterGroupNode).kind === 'ParameterGroup') {
|
|
99
|
-
const group = param as ast.ParameterGroupNode
|
|
100
|
-
for (const child of group.properties) {
|
|
101
|
-
if (!child.optional && child.default === undefined) {
|
|
102
|
-
required.push(child.name)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
const fp = param as ast.FunctionParameterNode
|
|
107
|
-
if (!fp.optional && fp.default === undefined) {
|
|
108
|
-
required.push(fp.name)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return required.join(' && ')
|
|
55
|
+
return wrapWithMaybeRefOrGetter(baseParams, (name) => name === 'config')
|
|
113
56
|
}
|
|
114
57
|
|
|
115
58
|
export function QueryOptions({
|
|
@@ -123,25 +66,26 @@ export function QueryOptions({
|
|
|
123
66
|
pathParamsType,
|
|
124
67
|
queryKeyName,
|
|
125
68
|
}: Props): KubbReactNode {
|
|
126
|
-
const
|
|
69
|
+
const successNames = resolveSuccessNames(node, tsResolver)
|
|
70
|
+
const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
|
|
127
71
|
const errorNames = resolveErrorNames(node, tsResolver)
|
|
128
72
|
|
|
129
73
|
const TData = dataReturnType === 'data' ? responseName : `ResponseConfig<${responseName}>`
|
|
130
74
|
const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`
|
|
131
75
|
|
|
132
|
-
const
|
|
76
|
+
const queryKeyParamsNode = buildQueryKeyParamsNode(node, { pathParamsType, paramsCasing, resolver: tsResolver })
|
|
77
|
+
const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? ''
|
|
78
|
+
|
|
79
|
+
const enabledNames = getEnabledParamNames(queryKeyParamsNode)
|
|
80
|
+
const enabledText = enabledNames.length ? `enabled: () => ${enabledNames.map((n) => `!!toValue(${n})`).join(' && ')},` : ''
|
|
81
|
+
|
|
82
|
+
const paramsNode = markParamsOptional(getQueryOptionsParams(node, { paramsType, paramsCasing, pathParamsType, resolver: tsResolver }), enabledNames)
|
|
133
83
|
const paramsSignature = declarationPrinter.print(paramsNode) ?? ''
|
|
134
84
|
const rawParamsCall = callPrinter.print(paramsNode) ?? ''
|
|
135
85
|
|
|
136
86
|
// Transform: wrap non-config params with toValue(), add signal to config
|
|
137
87
|
const clientCallStr = rawParamsCall.replace(/\bconfig\b(?=[^,]*$)/, '{ ...config, signal: config.signal ?? signal }')
|
|
138
88
|
|
|
139
|
-
const queryKeyParamsNode = QueryKey.getParams(node, { pathParamsType, paramsCasing, resolver: tsResolver })
|
|
140
|
-
const queryKeyParamsCall = callPrinter.print(queryKeyParamsNode) ?? ''
|
|
141
|
-
|
|
142
|
-
const enabledSource = buildEnabledCheck(queryKeyParamsNode)
|
|
143
|
-
const enabledText = enabledSource ? `enabled: () => !!(${enabledSource}),` : ''
|
|
144
|
-
|
|
145
89
|
return (
|
|
146
90
|
<File.Source name={name} isExportable isIndexable>
|
|
147
91
|
<Function name={name} export params={paramsSignature}>
|
|
@@ -151,7 +95,7 @@ export function QueryOptions({
|
|
|
151
95
|
${enabledText}
|
|
152
96
|
queryKey,
|
|
153
97
|
queryFn: async ({ signal }) => {
|
|
154
|
-
return ${clientName}(${addToValueCalls(clientCallStr)})
|
|
98
|
+
return ${clientName}(${addToValueCalls(clientCallStr, enabledNames)})
|
|
155
99
|
},
|
|
156
100
|
})
|
|
157
101
|
`}
|
|
@@ -167,8 +111,10 @@ export function QueryOptions({
|
|
|
167
111
|
* Handles both inline params (`petId, config`) and object shorthand
|
|
168
112
|
* params (`{ petId }, config`) by expanding to `{ petId: toValue(petId) }`.
|
|
169
113
|
*/
|
|
170
|
-
function addToValueCalls(callStr: string): string {
|
|
114
|
+
function addToValueCalls(callStr: string, enabledNames: ReadonlyArray<string> = []): string {
|
|
115
|
+
const optional = new Set(enabledNames)
|
|
171
116
|
// Step 1: Transform shorthand object params like { petId } → { petId: toValue(petId) }
|
|
117
|
+
// Params that drive the `enabled` guard are optional, so assert non-null: toValue(petId!)
|
|
172
118
|
let result = callStr.replace(/\{\s*([\w,\s]+)\s*\}(?=\s*,)/g, (match, inner: string) => {
|
|
173
119
|
// Only transform simple shorthand (no colons, no spread)
|
|
174
120
|
if (inner.includes(':') || inner.includes('...')) return match
|
|
@@ -176,7 +122,7 @@ function addToValueCalls(callStr: string): string {
|
|
|
176
122
|
.split(',')
|
|
177
123
|
.map((k: string) => k.trim())
|
|
178
124
|
.filter(Boolean)
|
|
179
|
-
const wrapped = keys.map((k: string) => `${k}: toValue(${k})`).join(', ')
|
|
125
|
+
const wrapped = keys.map((k: string) => `${k}: toValue(${optional.has(k) ? `${k}!` : k})`).join(', ')
|
|
180
126
|
return `{ ${wrapped} }`
|
|
181
127
|
})
|
|
182
128
|
|
|
@@ -184,10 +130,8 @@ function addToValueCalls(callStr: string): string {
|
|
|
184
130
|
result = result.replace(/(?<![{.:?])\b(\w+)\b(?=\s*,)/g, (match, name: string) => {
|
|
185
131
|
if (name === 'config' || name === 'signal' || name === 'undefined') return match
|
|
186
132
|
if (match.includes('toValue(')) return match
|
|
187
|
-
return `toValue(${name})`
|
|
133
|
+
return `toValue(${optional.has(name) ? `${name}!` : name})`
|
|
188
134
|
})
|
|
189
135
|
|
|
190
136
|
return result
|
|
191
137
|
}
|
|
192
|
-
|
|
193
|
-
QueryOptions.getParams = getQueryOptionsParams
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
+
import { getOperationParameters, operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
3
|
+
import { resolveZodSchemaNames } from '@internals/tanstack-query'
|
|
2
4
|
import { ast, defineGenerator } from '@kubb/core'
|
|
3
5
|
import { Client, pluginClientName } from '@kubb/plugin-client'
|
|
4
6
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
5
7
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
6
|
-
import { File,
|
|
8
|
+
import { File, jsxRendererSync } from '@kubb/renderer-jsx'
|
|
7
9
|
import { difference } from 'remeda'
|
|
8
10
|
import { InfiniteQuery, InfiniteQueryOptions, QueryKey } from '../components'
|
|
9
11
|
import type { PluginVueQuery } from '../types'
|
|
10
|
-
import { transformName } from '../utils.ts'
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Built-in generator for `useInfiniteQuery` composables. Enabled when
|
|
15
|
+
* `pluginVueQuery({ infinite: { ... } })`. Emits one `useFooInfiniteQuery`
|
|
16
|
+
* composable per query operation, wiring the configured cursor path into
|
|
17
|
+
* TanStack Query's cursor-based pagination.
|
|
18
|
+
*/
|
|
12
19
|
export const infiniteQueryGenerator = defineGenerator<PluginVueQuery>({
|
|
13
20
|
name: 'vue-query-infinite',
|
|
14
|
-
renderer:
|
|
21
|
+
renderer: jsxRendererSync,
|
|
15
22
|
operation(node, ctx) {
|
|
16
|
-
|
|
17
|
-
const {
|
|
23
|
+
if (!ast.isHttpOperationNode(node)) return null
|
|
24
|
+
const { config, driver, resolver, root } = ctx
|
|
25
|
+
const { output, query, mutation, infinite, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group } = ctx.options
|
|
18
26
|
|
|
19
27
|
const pluginTs = driver.getPlugin(pluginTsName)
|
|
20
28
|
if (!pluginTs) return null
|
|
@@ -25,13 +33,13 @@ export const infiniteQueryGenerator = defineGenerator<PluginVueQuery>({
|
|
|
25
33
|
mutation !== false &&
|
|
26
34
|
!isQuery &&
|
|
27
35
|
difference(mutation ? mutation.methods : [], query ? query.methods : []).some((method) => node.method.toLowerCase() === method.toLowerCase())
|
|
28
|
-
const infiniteOptions = infinite && typeof infinite === 'object' ? infinite :
|
|
36
|
+
const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : null
|
|
29
37
|
|
|
30
38
|
if (!isQuery || isMutation || !infiniteOptions) return null
|
|
31
39
|
|
|
32
40
|
// Validate queryParam exists in operation's query parameters
|
|
33
41
|
const normalizeKey = (key: string) => key.replace(/\?$/, '')
|
|
34
|
-
const queryParamKeys = node
|
|
42
|
+
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name)
|
|
35
43
|
const hasQueryParam = infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false
|
|
36
44
|
// cursorParam validation against response schema keys is skipped in v5 (complex schema inspection)
|
|
37
45
|
const hasCursorParam = !infiniteOptions.cursorParam || true
|
|
@@ -40,64 +48,50 @@ export const infiniteQueryGenerator = defineGenerator<PluginVueQuery>({
|
|
|
40
48
|
|
|
41
49
|
const importPath = query ? query.importPath : '@tanstack/vue-query'
|
|
42
50
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const queryKeyTypeName = transformName(`${capitalize(baseName)}InfiniteQueryKey`, 'type', transformers)
|
|
49
|
-
const clientBaseName = transformName(`${baseName}Infinite`, 'function', transformers)
|
|
51
|
+
const queryName = resolver.resolveInfiniteQueryName(node)
|
|
52
|
+
const queryOptionsName = resolver.resolveInfiniteQueryOptionsName(node)
|
|
53
|
+
const queryKeyName = resolver.resolveInfiniteQueryKeyName(node)
|
|
54
|
+
const queryKeyTypeName = resolver.resolveInfiniteQueryKeyTypeName(node)
|
|
55
|
+
const clientBaseName = resolver.resolveInfiniteClientName(node)
|
|
50
56
|
|
|
51
57
|
const meta = {
|
|
52
|
-
file: resolver.resolveFile(
|
|
53
|
-
fileTs: tsResolver.resolveFile(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
file: resolver.resolveFile(operationFileEntry(node, queryName), { root, output, group: group ?? undefined }),
|
|
59
|
+
fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
60
|
+
root,
|
|
61
|
+
output: pluginTs.options?.output ?? output,
|
|
62
|
+
group: pluginTs.options?.group ?? undefined,
|
|
63
|
+
}),
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
66
|
+
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, {
|
|
67
|
+
paramsCasing,
|
|
68
|
+
exclude: [queryKeyTypeName],
|
|
69
|
+
order: 'body-response-first',
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
|
|
73
|
+
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
|
|
75
74
|
const fileZod = zodResolver
|
|
76
|
-
? zodResolver.resolveFile(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined].filter(Boolean)
|
|
84
|
-
: []
|
|
75
|
+
? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
76
|
+
root,
|
|
77
|
+
output: pluginZod?.options?.output ?? output,
|
|
78
|
+
group: pluginZod?.options?.group ?? undefined,
|
|
79
|
+
})
|
|
80
|
+
: null
|
|
81
|
+
const zodSchemaNames = resolveZodSchemaNames(node, zodResolver)
|
|
85
82
|
|
|
86
83
|
const clientPlugin = driver.getPlugin(pluginClientName)
|
|
87
84
|
const hasClientPlugin = clientPlugin?.name === pluginClientName
|
|
88
85
|
const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
|
|
89
|
-
const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) :
|
|
86
|
+
const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
|
|
90
87
|
|
|
91
88
|
const clientFile = shouldUseClientPlugin
|
|
92
|
-
? clientResolver?.resolveFile(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
: undefined
|
|
89
|
+
? clientResolver?.resolveFile(operationFileEntry(node, node.operationId), {
|
|
90
|
+
root,
|
|
91
|
+
output: clientPlugin?.options?.output ?? output,
|
|
92
|
+
group: clientPlugin?.options?.group ?? undefined,
|
|
93
|
+
})
|
|
94
|
+
: null
|
|
101
95
|
|
|
102
96
|
const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientBaseName) : clientBaseName
|
|
103
97
|
|
|
@@ -106,29 +100,27 @@ export const infiniteQueryGenerator = defineGenerator<PluginVueQuery>({
|
|
|
106
100
|
baseName={meta.file.baseName}
|
|
107
101
|
path={meta.file.path}
|
|
108
102
|
meta={meta.file.meta}
|
|
109
|
-
banner={resolver.resolveBanner(
|
|
110
|
-
footer={resolver.resolveFooter(
|
|
103
|
+
banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
104
|
+
footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
111
105
|
>
|
|
112
|
-
{
|
|
113
|
-
<File.Import name={zodSchemaNames as string[]} root={meta.file.path} path={fileZod.path} />
|
|
114
|
-
)}
|
|
106
|
+
{fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
|
|
115
107
|
{clientOptions.importPath ? (
|
|
116
108
|
<>
|
|
117
|
-
{!shouldUseClientPlugin && <File.Import name={'
|
|
109
|
+
{!shouldUseClientPlugin && <File.Import name={'client'} path={clientOptions.importPath} />}
|
|
118
110
|
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
|
|
119
111
|
{clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
|
|
120
112
|
</>
|
|
121
113
|
) : (
|
|
122
114
|
<>
|
|
123
|
-
{!shouldUseClientPlugin && <File.Import name={['
|
|
115
|
+
{!shouldUseClientPlugin && <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />}
|
|
124
116
|
<File.Import
|
|
125
117
|
name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
|
|
126
118
|
root={meta.file.path}
|
|
127
|
-
path={path.resolve(root, '.kubb/
|
|
119
|
+
path={path.resolve(root, '.kubb/client.ts')}
|
|
128
120
|
isTypeOnly
|
|
129
121
|
/>
|
|
130
122
|
{clientOptions.dataReturnType === 'full' && (
|
|
131
|
-
<File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/
|
|
123
|
+
<File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
|
|
132
124
|
)}
|
|
133
125
|
</>
|
|
134
126
|
)}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
+
import { operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
|
|
3
|
+
import { resolveZodSchemaNames } from '@internals/tanstack-query'
|
|
2
4
|
import { ast, defineGenerator } from '@kubb/core'
|
|
3
5
|
import { Client, pluginClientName } from '@kubb/plugin-client'
|
|
4
6
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
5
7
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
6
|
-
import { File,
|
|
8
|
+
import { File, jsxRendererSync } from '@kubb/renderer-jsx'
|
|
7
9
|
import { difference } from 'remeda'
|
|
8
10
|
import { Mutation, MutationKey } from '../components'
|
|
9
11
|
import type { PluginVueQuery } from '../types'
|
|
10
|
-
import { transformName } from '../utils.ts'
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Built-in generator for `useMutation` composables. Emits one
|
|
15
|
+
* `useFooMutation` composable per POST/PUT/DELETE operation (configurable
|
|
16
|
+
* via `mutation.methods`) plus the matching `fooMutationKey` helper.
|
|
17
|
+
*/
|
|
12
18
|
export const mutationGenerator = defineGenerator<PluginVueQuery>({
|
|
13
19
|
name: 'vue-query-mutation',
|
|
14
|
-
renderer:
|
|
20
|
+
renderer: jsxRendererSync,
|
|
15
21
|
operation(node, ctx) {
|
|
16
|
-
|
|
17
|
-
const {
|
|
22
|
+
if (!ast.isHttpOperationNode(node)) return null
|
|
23
|
+
const { config, driver, resolver, root } = ctx
|
|
24
|
+
const { output, query, mutation, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group } = ctx.options
|
|
18
25
|
|
|
19
26
|
const pluginTs = driver.getPlugin(pluginTsName)
|
|
20
27
|
if (!pluginTs) return null
|
|
@@ -30,63 +37,45 @@ export const mutationGenerator = defineGenerator<PluginVueQuery>({
|
|
|
30
37
|
|
|
31
38
|
const importPath = mutation ? mutation.importPath : '@tanstack/vue-query'
|
|
32
39
|
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const mutationKeyName = transformName(`${baseName}MutationKey`, 'const', transformers)
|
|
38
|
-
const clientName = transformName(baseName, 'function', transformers)
|
|
40
|
+
const mutationHookName = resolver.resolveMutationName(node)
|
|
41
|
+
const mutationTypeName = resolver.resolveMutationTypeName(node)
|
|
42
|
+
const mutationKeyName = resolver.resolveMutationKeyName(node)
|
|
43
|
+
const clientName = resolver.resolveClientName(node)
|
|
39
44
|
|
|
40
45
|
const meta = {
|
|
41
|
-
file: resolver.resolveFile(
|
|
42
|
-
fileTs: tsResolver.resolveFile(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
file: resolver.resolveFile(operationFileEntry(node, mutationHookName), { root, output, group: group ?? undefined }),
|
|
47
|
+
fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
48
|
+
root,
|
|
49
|
+
output: pluginTs.options?.output ?? output,
|
|
50
|
+
group: pluginTs.options?.group ?? undefined,
|
|
51
|
+
}),
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const importedTypeNames = [
|
|
54
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined,
|
|
55
|
-
tsResolver.resolveResponseName(node),
|
|
56
|
-
...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
57
|
-
...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
58
|
-
...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
59
|
-
...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
|
|
60
|
-
].filter((name): name is string => !!name)
|
|
61
|
-
|
|
62
|
-
const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
|
|
63
|
-
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
|
|
54
|
+
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing, order: 'body-response-first' })
|
|
55
|
+
|
|
56
|
+
const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
|
|
57
|
+
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
|
|
64
58
|
const fileZod = zodResolver
|
|
65
|
-
? zodResolver.resolveFile(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined].filter(Boolean)
|
|
73
|
-
: []
|
|
59
|
+
? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
|
|
60
|
+
root,
|
|
61
|
+
output: pluginZod?.options?.output ?? output,
|
|
62
|
+
group: pluginZod?.options?.group ?? undefined,
|
|
63
|
+
})
|
|
64
|
+
: null
|
|
65
|
+
const zodSchemaNames = resolveZodSchemaNames(node, zodResolver)
|
|
74
66
|
|
|
75
67
|
const clientPlugin = driver.getPlugin(pluginClientName)
|
|
76
68
|
const hasClientPlugin = clientPlugin?.name === pluginClientName
|
|
77
69
|
const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
|
|
78
|
-
const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) :
|
|
70
|
+
const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
|
|
79
71
|
|
|
80
72
|
const clientFile = shouldUseClientPlugin
|
|
81
|
-
? clientResolver?.resolveFile(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
},
|
|
88
|
-
)
|
|
89
|
-
: undefined
|
|
73
|
+
? clientResolver?.resolveFile(operationFileEntry(node, node.operationId), {
|
|
74
|
+
root,
|
|
75
|
+
output: clientPlugin?.options?.output ?? output,
|
|
76
|
+
group: clientPlugin?.options?.group ?? undefined,
|
|
77
|
+
})
|
|
78
|
+
: null
|
|
90
79
|
|
|
91
80
|
const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientName) : clientName
|
|
92
81
|
|
|
@@ -95,35 +84,35 @@ export const mutationGenerator = defineGenerator<PluginVueQuery>({
|
|
|
95
84
|
baseName={meta.file.baseName}
|
|
96
85
|
path={meta.file.path}
|
|
97
86
|
meta={meta.file.meta}
|
|
98
|
-
banner={resolver.resolveBanner(
|
|
99
|
-
footer={resolver.resolveFooter(
|
|
87
|
+
banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
88
|
+
footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
|
|
100
89
|
>
|
|
101
|
-
{
|
|
102
|
-
<File.Import name={zodSchemaNames as string[]} root={meta.file.path} path={fileZod.path} />
|
|
103
|
-
)}
|
|
90
|
+
{fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
|
|
104
91
|
{clientOptions.importPath ? (
|
|
105
92
|
<>
|
|
106
|
-
{!shouldUseClientPlugin && <File.Import name={'
|
|
93
|
+
{!shouldUseClientPlugin && <File.Import name={'client'} path={clientOptions.importPath} />}
|
|
107
94
|
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
|
|
108
95
|
{clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
|
|
109
96
|
</>
|
|
110
97
|
) : (
|
|
111
98
|
<>
|
|
112
|
-
{!shouldUseClientPlugin && <File.Import name={['
|
|
99
|
+
{!shouldUseClientPlugin && <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />}
|
|
113
100
|
<File.Import
|
|
114
101
|
name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
|
|
115
102
|
root={meta.file.path}
|
|
116
|
-
path={path.resolve(root, '.kubb/
|
|
103
|
+
path={path.resolve(root, '.kubb/client.ts')}
|
|
117
104
|
isTypeOnly
|
|
118
105
|
/>
|
|
119
106
|
{clientOptions.dataReturnType === 'full' && (
|
|
120
|
-
<File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/
|
|
107
|
+
<File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
|
|
121
108
|
)}
|
|
122
109
|
</>
|
|
123
110
|
)}
|
|
124
111
|
<File.Import name={['MaybeRefOrGetter']} path="vue" isTypeOnly />
|
|
125
112
|
{shouldUseClientPlugin && clientFile && <File.Import name={[resolvedClientName]} root={meta.file.path} path={clientFile.path} />}
|
|
126
|
-
{!shouldUseClientPlugin &&
|
|
113
|
+
{!shouldUseClientPlugin && node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') && (
|
|
114
|
+
<File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />
|
|
115
|
+
)}
|
|
127
116
|
{meta.fileTs && importedTypeNames.length > 0 && (
|
|
128
117
|
<File.Import name={Array.from(new Set(importedTypeNames))} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
|
|
129
118
|
)}
|