@kubb/plugin-vue-query 5.0.0-beta.4 → 5.0.0-beta.56

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 (43) hide show
  1. package/README.md +39 -22
  2. package/dist/{components-D1UhYFgY.js → components-B79Gljyl.js} +483 -565
  3. package/dist/components-B79Gljyl.js.map +1 -0
  4. package/dist/{components-qfOFRSoM.cjs → components-D3xIZ9FA.cjs} +513 -565
  5. package/dist/components-D3xIZ9FA.cjs.map +1 -0
  6. package/dist/components.cjs +1 -1
  7. package/dist/components.d.ts +4 -68
  8. package/dist/components.js +1 -1
  9. package/dist/{generators-C4gs_P1i.cjs → generators-BTtcGtUY.cjs} +225 -314
  10. package/dist/generators-BTtcGtUY.cjs.map +1 -0
  11. package/dist/generators-D95ddIFV.js +620 -0
  12. package/dist/generators-D95ddIFV.js.map +1 -0
  13. package/dist/generators.cjs +1 -1
  14. package/dist/generators.d.ts +21 -6
  15. package/dist/generators.js +1 -1
  16. package/dist/index.cjs +158 -25
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +31 -4
  19. package/dist/index.js +160 -27
  20. package/dist/index.js.map +1 -1
  21. package/dist/types-CwabLiFK.d.ts +266 -0
  22. package/package.json +18 -27
  23. package/src/components/InfiniteQuery.tsx +18 -50
  24. package/src/components/InfiniteQueryOptions.tsx +64 -82
  25. package/src/components/Mutation.tsx +35 -44
  26. package/src/components/Query.tsx +18 -51
  27. package/src/components/QueryKey.tsx +9 -61
  28. package/src/components/QueryOptions.tsx +22 -99
  29. package/src/generators/infiniteQueryGenerator.tsx +55 -67
  30. package/src/generators/mutationGenerator.tsx +53 -65
  31. package/src/generators/queryGenerator.tsx +52 -65
  32. package/src/plugin.ts +48 -32
  33. package/src/resolvers/resolverVueQuery.ts +63 -6
  34. package/src/types.ts +132 -60
  35. package/src/utils.ts +45 -25
  36. package/dist/components-D1UhYFgY.js.map +0 -1
  37. package/dist/components-qfOFRSoM.cjs.map +0 -1
  38. package/dist/generators-C4gs_P1i.cjs.map +0 -1
  39. package/dist/generators-CbnIVBgY.js +0 -709
  40. package/dist/generators-CbnIVBgY.js.map +0 -1
  41. package/dist/types-nVDTfuS1.d.ts +0 -194
  42. package/extension.yaml +0 -793
  43. /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
@@ -1,92 +1,81 @@
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
- import { Client, pluginClientName } from '@kubb/plugin-client'
5
+ import { Client, isParserEnabled, pluginClientName } from '@kubb/plugin-client'
4
6
  import { pluginTsName } from '@kubb/plugin-ts'
5
7
  import { pluginZodName } from '@kubb/plugin-zod'
6
8
  import { File, jsxRenderer } from '@kubb/renderer-jsx'
7
- import { difference } from 'remeda'
8
9
  import { Mutation, MutationKey } from '../components'
9
10
  import type { PluginVueQuery } from '../types'
10
- import { transformName } from '../utils.ts'
11
11
 
12
+ /**
13
+ * Built-in generator for `useMutation` composables. Emits one
14
+ * `useFooMutation` composable per POST/PUT/DELETE operation (configurable
15
+ * via `mutation.methods`) plus the matching `fooMutationKey` helper.
16
+ */
12
17
  export const mutationGenerator = defineGenerator<PluginVueQuery>({
13
18
  name: 'vue-query-mutation',
14
19
  renderer: jsxRenderer,
15
20
  operation(node, ctx) {
16
- const { adapter, config, driver, resolver, root } = ctx
17
- const { output, query, mutation, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group, transformers } = ctx.options
21
+ if (!ast.isHttpOperationNode(node)) return null
22
+ const { config, driver, resolver, root } = ctx
23
+ const { output, query, mutation, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group } = ctx.options
18
24
 
19
25
  const pluginTs = driver.getPlugin(pluginTsName)
20
26
  if (!pluginTs) return null
21
27
  const tsResolver = driver.getResolver(pluginTsName)
22
28
 
23
29
  const isQuery = query === false || (!!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase()))
30
+ const queryMethods = new Set(query ? query.methods : [])
24
31
  const isMutation =
25
32
  mutation !== false &&
26
33
  !isQuery &&
27
- difference(mutation ? mutation.methods : [], query ? query.methods : []).some((method) => node.method.toLowerCase() === method.toLowerCase())
34
+ (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
28
35
 
29
36
  if (!isMutation) return null
30
37
 
31
38
  const importPath = mutation ? mutation.importPath : '@tanstack/vue-query'
32
39
 
33
- const baseName = resolver.resolveName(node.operationId)
34
- const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
35
- const mutationHookName = transformName(`use${capitalize(baseName)}`, 'function', transformers)
36
- const mutationTypeName = transformName(`${capitalize(baseName)}`, 'type', transformers)
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({ name: mutationHookName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
42
- fileTs: tsResolver.resolveFile(
43
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
44
- { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
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 casedParams = ast.caseParams(node.parameters, paramsCasing)
49
- const pathParams = casedParams.filter((p) => p.in === 'path')
50
- const queryParams = casedParams.filter((p) => p.in === 'query')
51
- const headerParams = casedParams.filter((p) => p.in === 'header')
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 = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null
57
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
64
58
  const fileZod = zodResolver
65
- ? zodResolver.resolveFile(
66
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
67
- { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
68
- )
69
- : undefined
70
- const zodSchemaNames =
71
- zodResolver && parser === 'zod'
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, parser)
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) : undefined
70
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
79
71
 
80
72
  const clientFile = shouldUseClientPlugin
81
- ? clientResolver?.resolveFile(
82
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
83
- {
84
- root,
85
- output: clientPlugin?.options?.output ?? output,
86
- group: clientPlugin?.options?.group,
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,34 @@ 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(adapter.inputNode, { output, config })}
99
- footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
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
- {parser === 'zod' && fileZod && zodSchemaNames.length > 0 && (
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={'fetch'} path={clientOptions.importPath} />}
93
+ {!shouldUseClientPlugin && <File.Import name={'client'} path={clientOptions.importPath} />}
107
94
  <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
108
- {clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
109
95
  </>
110
96
  ) : (
111
97
  <>
112
- {!shouldUseClientPlugin && <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />}
98
+ {!shouldUseClientPlugin && <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />}
113
99
  <File.Import
114
100
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
115
101
  root={meta.file.path}
116
- path={path.resolve(root, '.kubb/fetch.ts')}
102
+ path={path.resolve(root, '.kubb/client.ts')}
117
103
  isTypeOnly
118
104
  />
119
- {clientOptions.dataReturnType === 'full' && (
120
- <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
121
- )}
122
105
  </>
123
106
  )}
124
107
  <File.Import name={['MaybeRefOrGetter']} path="vue" isTypeOnly />
125
108
  {shouldUseClientPlugin && clientFile && <File.Import name={[resolvedClientName]} root={meta.file.path} path={clientFile.path} />}
126
- {!shouldUseClientPlugin && <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />}
109
+ {!shouldUseClientPlugin && node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') && (
110
+ <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />
111
+ )}
112
+ {!shouldUseClientPlugin && parser === 'zod' && zodResolver && node.requestBody?.content?.[0]?.schema && (
113
+ <File.Import name={['z']} path="zod" isTypeOnly />
114
+ )}
127
115
  {meta.fileTs && importedTypeNames.length > 0 && (
128
116
  <File.Import name={Array.from(new Set(importedTypeNames))} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
129
117
  )}
@@ -1,93 +1,86 @@
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
- import { Client, pluginClientName } from '@kubb/plugin-client'
5
+ import { Client, isParserEnabled, pluginClientName } from '@kubb/plugin-client'
4
6
  import { pluginTsName } from '@kubb/plugin-ts'
5
7
  import { pluginZodName } from '@kubb/plugin-zod'
6
8
  import { File, jsxRenderer } from '@kubb/renderer-jsx'
7
- import { difference } from 'remeda'
8
9
  import { Query, QueryKey, QueryOptions } from '../components'
9
10
  import type { PluginVueQuery } from '../types'
10
- import { transformName } from '../utils.ts'
11
11
 
12
+ /**
13
+ * Built-in generator for `useQuery` composables. Emits one `useFooQuery`
14
+ * composable per GET operation (configurable via `query.methods`) plus the
15
+ * matching `fooQueryKey` / `fooQueryOptions` helpers.
16
+ */
12
17
  export const queryGenerator = defineGenerator<PluginVueQuery>({
13
18
  name: 'vue-query',
14
19
  renderer: jsxRenderer,
15
20
  operation(node, ctx) {
16
- const { adapter, config, driver, resolver, root } = ctx
17
- const { output, query, mutation, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group, transformers } = ctx.options
21
+ if (!ast.isHttpOperationNode(node)) return null
22
+ const { config, driver, resolver, root } = ctx
23
+ const { output, query, mutation, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group } = ctx.options
18
24
 
19
25
  const pluginTs = driver.getPlugin(pluginTsName)
20
26
  if (!pluginTs) return null
21
27
  const tsResolver = driver.getResolver(pluginTsName)
22
28
 
23
29
  const isQuery = query === false || (!!query && query.methods.some((method) => node.method.toLowerCase() === method.toLowerCase()))
30
+ const queryMethods = new Set(query ? query.methods : [])
24
31
  const isMutation =
25
32
  mutation !== false &&
26
33
  !isQuery &&
27
- difference(mutation ? mutation.methods : [], query ? query.methods : []).some((method) => node.method.toLowerCase() === method.toLowerCase())
34
+ (mutation ? mutation.methods : []).some((method) => !queryMethods.has(method) && node.method.toLowerCase() === method.toLowerCase())
28
35
 
29
36
  if (!isQuery || isMutation) return null
30
37
 
31
38
  const importPath = query ? query.importPath : '@tanstack/vue-query'
32
39
 
33
- const baseName = resolver.resolveName(node.operationId)
34
- const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
35
- const queryName = transformName(`use${capitalize(baseName)}`, 'function', transformers)
36
- const queryOptionsName = transformName(`${baseName}QueryOptions`, 'function', transformers)
37
- const queryKeyName = transformName(`${baseName}QueryKey`, 'const', transformers)
38
- const queryKeyTypeName = transformName(`${capitalize(baseName)}QueryKey`, 'type', transformers)
39
- const clientName = transformName(baseName, 'function', transformers)
40
+ const queryName = resolver.resolveQueryName(node)
41
+ const queryOptionsName = resolver.resolveQueryOptionsName(node)
42
+ const queryKeyName = resolver.resolveQueryKeyName(node)
43
+ const queryKeyTypeName = resolver.resolveQueryKeyTypeName(node)
44
+ const clientName = resolver.resolveClientName(node)
40
45
 
41
46
  const meta = {
42
- file: resolver.resolveFile({ name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
43
- fileTs: tsResolver.resolveFile(
44
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
45
- { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
46
- ),
47
+ file: resolver.resolveFile(operationFileEntry(node, queryName), { root, output, group: group ?? undefined }),
48
+ fileTs: tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
49
+ root,
50
+ output: pluginTs.options?.output ?? output,
51
+ group: pluginTs.options?.group ?? undefined,
52
+ }),
47
53
  }
48
54
 
49
- const casedParams = ast.caseParams(node.parameters, paramsCasing)
50
- const pathParams = casedParams.filter((p) => p.in === 'path')
51
- const queryParams = casedParams.filter((p) => p.in === 'query')
52
- const headerParams = casedParams.filter((p) => p.in === 'header')
53
-
54
- const importedTypeNames = [
55
- node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined,
56
- tsResolver.resolveResponseName(node),
57
- ...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
58
- ...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
59
- ...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
60
- ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
61
- ].filter((name): name is string => !!name && name !== queryKeyTypeName)
62
-
63
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
64
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
55
+ const importedTypeNames = resolveOperationTypeNames(node, tsResolver, {
56
+ paramsCasing,
57
+ exclude: [queryKeyTypeName],
58
+ order: 'body-response-first',
59
+ })
60
+
61
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null
62
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
65
63
  const fileZod = zodResolver
66
- ? zodResolver.resolveFile(
67
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
68
- { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
69
- )
70
- : undefined
71
- const zodSchemaNames =
72
- zodResolver && parser === 'zod'
73
- ? [zodResolver.resolveResponseName?.(node), node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined].filter(Boolean)
74
- : []
64
+ ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
65
+ root,
66
+ output: pluginZod?.options?.output ?? output,
67
+ group: pluginZod?.options?.group ?? undefined,
68
+ })
69
+ : null
70
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver, parser)
75
71
 
76
72
  const clientPlugin = driver.getPlugin(pluginClientName)
77
73
  const hasClientPlugin = clientPlugin?.name === pluginClientName
78
74
  const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
79
- const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : undefined
75
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
80
76
 
81
77
  const clientFile = shouldUseClientPlugin
82
- ? clientResolver?.resolveFile(
83
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
84
- {
85
- root,
86
- output: clientPlugin?.options?.output ?? output,
87
- group: clientPlugin?.options?.group,
88
- },
89
- )
90
- : undefined
78
+ ? clientResolver?.resolveFile(operationFileEntry(node, node.operationId), {
79
+ root,
80
+ output: clientPlugin?.options?.output ?? output,
81
+ group: clientPlugin?.options?.group ?? undefined,
82
+ })
83
+ : null
91
84
 
92
85
  const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientName) : clientName
93
86
 
@@ -96,30 +89,24 @@ export const queryGenerator = defineGenerator<PluginVueQuery>({
96
89
  baseName={meta.file.baseName}
97
90
  path={meta.file.path}
98
91
  meta={meta.file.meta}
99
- banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
100
- footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
92
+ banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
93
+ footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
101
94
  >
102
- {parser === 'zod' && fileZod && zodSchemaNames.length > 0 && (
103
- <File.Import name={zodSchemaNames as string[]} root={meta.file.path} path={fileZod.path} />
104
- )}
95
+ {fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
105
96
  {clientOptions.importPath ? (
106
97
  <>
107
- {!shouldUseClientPlugin && <File.Import name={'fetch'} path={clientOptions.importPath} />}
98
+ {!shouldUseClientPlugin && <File.Import name={'client'} path={clientOptions.importPath} />}
108
99
  <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
109
- {clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
110
100
  </>
111
101
  ) : (
112
102
  <>
113
- {!shouldUseClientPlugin && <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />}
103
+ {!shouldUseClientPlugin && <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />}
114
104
  <File.Import
115
105
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
116
106
  root={meta.file.path}
117
- path={path.resolve(root, '.kubb/fetch.ts')}
107
+ path={path.resolve(root, '.kubb/client.ts')}
118
108
  isTypeOnly
119
109
  />
120
- {clientOptions.dataReturnType === 'full' && (
121
- <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
122
- )}
123
110
  </>
124
111
  )}
125
112
  <File.Import name={['toValue']} path="vue" />
package/src/plugin.ts CHANGED
@@ -1,36 +1,63 @@
1
1
  import path from 'node:path'
2
- import { camelCase } from '@internals/utils'
3
- import { ast, definePlugin, type Group } from '@kubb/core'
4
- import { pluginClientName } from '@kubb/plugin-client'
2
+ import { createGroupConfig } from '@internals/shared'
3
+ import { ast, definePlugin } from '@kubb/core'
4
+ import { isParserEnabled, pluginClientName } from '@kubb/plugin-client'
5
5
  import { source as axiosClientSource } from '@kubb/plugin-client/templates/clients/axios.source'
6
6
  import { source as fetchClientSource } from '@kubb/plugin-client/templates/clients/fetch.source'
7
7
  import { source as configSource } from '@kubb/plugin-client/templates/config.source'
8
8
  import { pluginTsName } from '@kubb/plugin-ts'
9
9
  import { pluginZodName } from '@kubb/plugin-zod'
10
- import { MutationKey } from './components/MutationKey.tsx'
11
- import { QueryKey } from './components/QueryKey.tsx'
10
+ import { mutationKeyTransformer } from '@internals/tanstack-query'
11
+ import { queryKeyTransformer } from '@internals/tanstack-query'
12
12
  import { infiniteQueryGenerator, mutationGenerator, queryGenerator } from './generators'
13
13
  import { resolverVueQuery } from './resolvers/resolverVueQuery.ts'
14
14
  import type { PluginVueQuery } from './types.ts'
15
15
 
16
+ /**
17
+ * Canonical plugin name for `@kubb/plugin-vue-query`. Used for driver lookups
18
+ * and cross-plugin dependency references.
19
+ */
16
20
  export const pluginVueQueryName = 'plugin-vue-query' satisfies PluginVueQuery['name']
17
21
 
22
+ /**
23
+ * Generates one TanStack Query composable per OpenAPI operation for Vue's
24
+ * Composition API. Queries become `useFooQuery` (and optionally
25
+ * `useFooInfiniteQuery`); mutations become `useFooMutation`. Each composable
26
+ * is fully typed end to end.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { defineConfig } from 'kubb'
31
+ * import { pluginTs } from '@kubb/plugin-ts'
32
+ * import { pluginVueQuery } from '@kubb/plugin-vue-query'
33
+ *
34
+ * export default defineConfig({
35
+ * input: { path: './petStore.yaml' },
36
+ * output: { path: './src/gen' },
37
+ * plugins: [
38
+ * pluginTs(),
39
+ * pluginVueQuery({
40
+ * output: { path: './hooks' },
41
+ * }),
42
+ * ],
43
+ * })
44
+ * ```
45
+ */
18
46
  export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
19
47
  const {
20
- output = { path: 'hooks', barrelType: 'named' },
48
+ output = { path: 'hooks', barrel: { type: 'named' } },
21
49
  group,
22
50
  exclude = [],
23
51
  include,
24
52
  override = [],
25
- parser = 'client',
53
+ parser = false,
26
54
  infinite = false,
27
- transformers = {},
28
55
  paramsType = 'inline',
29
56
  pathParamsType = paramsType === 'object' ? 'object' : options.pathParamsType || 'inline',
30
57
  mutation = {},
31
58
  query = {},
32
- mutationKey = MutationKey.getTransformer,
33
- queryKey = QueryKey.getTransformer,
59
+ mutationKey = mutationKeyTransformer,
60
+ queryKey = queryKeyTransformer,
34
61
  paramsCasing,
35
62
  client,
36
63
  resolver: userResolver,
@@ -41,33 +68,22 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
41
68
  const clientName = client?.client ?? 'axios'
42
69
  const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : undefined)
43
70
 
44
- const selectedGenerators = options.generators ?? [queryGenerator, infiniteQueryGenerator, mutationGenerator].filter(Boolean)
71
+ const selectedGenerators =
72
+ options.generators ??
73
+ [queryGenerator, infiniteQueryGenerator, mutationGenerator].filter((generator): generator is NonNullable<typeof generator> => Boolean(generator))
45
74
 
46
- const groupConfig = group
47
- ? ({
48
- ...group,
49
- name: group.name
50
- ? group.name
51
- : (ctx: { group: string }) => {
52
- if (group.type === 'path') {
53
- return `${ctx.group.split('/')[1]}`
54
- }
55
- return `${camelCase(ctx.group)}Controller`
56
- },
57
- } satisfies Group)
58
- : undefined
75
+ const groupConfig = createGroupConfig(group)
59
76
 
60
77
  return {
61
78
  name: pluginVueQueryName,
62
79
  options,
63
- dependencies: [pluginTsName, parser === 'zod' ? pluginZodName : undefined].filter(Boolean),
80
+ dependencies: [pluginTsName, isParserEnabled(parser) ? pluginZodName : undefined].filter((dependency): dependency is string => Boolean(dependency)),
64
81
  hooks: {
65
82
  'kubb:plugin:setup'(ctx) {
66
83
  const resolver = userResolver ? { ...resolverVueQuery, ...userResolver } : resolverVueQuery
67
84
 
68
85
  ctx.setOptions({
69
86
  output,
70
- transformers,
71
87
  client: {
72
88
  bundle: client?.bundle,
73
89
  baseURL: client?.baseURL,
@@ -99,9 +115,9 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
99
115
  ? {
100
116
  queryParam: 'id',
101
117
  initialPageParam: 0,
102
- cursorParam: undefined,
103
- nextParam: undefined,
104
- previousParam: undefined,
118
+ cursorParam: null,
119
+ nextParam: null,
120
+ previousParam: null,
105
121
  ...infinite,
106
122
  }
107
123
  : false,
@@ -132,11 +148,11 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
132
148
 
133
149
  if (client?.bundle && !hasClientPlugin && !clientImportPath) {
134
150
  ctx.injectFile({
135
- baseName: 'fetch.ts',
136
- path: path.resolve(root, '.kubb/fetch.ts'),
151
+ baseName: 'client.ts',
152
+ path: path.resolve(root, '.kubb/client.ts'),
137
153
  sources: [
138
154
  ast.createSource({
139
- name: 'fetch',
155
+ name: 'client',
140
156
  nodes: [ast.createText(clientName === 'fetch' ? fetchClientSource : axiosClientSource)],
141
157
  isExportable: true,
142
158
  isIndexable: true,
@@ -1,19 +1,76 @@
1
- import { camelCase } from '@internals/utils'
1
+ import { camelCase, toFilePath } from '@internals/utils'
2
2
  import { defineResolver } from '@kubb/core'
3
3
  import type { PluginVueQuery } from '../types.ts'
4
4
 
5
+ function capitalize(name: string): string {
6
+ return `${name.charAt(0).toUpperCase()}${name.slice(1)}`
7
+ }
8
+
5
9
  /**
6
- * Naming convention resolver for Vue Query plugin.
10
+ * Default resolver used by `@kubb/plugin-vue-query`. Decides the names and
11
+ * file paths for every generated TanStack Query composable (`useFooQuery`,
12
+ * `useFooMutation`, `useFooInfiniteQuery`) and its companion helpers.
13
+ *
14
+ * Functions and files use camelCase; composables get the `use` prefix.
15
+ *
16
+ * @example Resolve composable and helper names
17
+ * ```ts
18
+ * import { resolverVueQuery } from '@kubb/plugin-vue-query'
7
19
  *
8
- * Provides default naming helpers using camelCase for functions and file paths.
20
+ * resolverVueQuery.resolveQueryName(operationNode) // 'useGetPetById'
21
+ * resolverVueQuery.resolveQueryKeyName(operationNode) // 'getPetByIdQueryKey'
22
+ * resolverVueQuery.resolveQueryOptionsName(operationNode) // 'getPetByIdQueryOptions'
23
+ * ```
9
24
  */
10
- export const resolverVueQuery = defineResolver<PluginVueQuery>((ctx) => ({
25
+ export const resolverVueQuery = defineResolver<PluginVueQuery>(() => ({
11
26
  name: 'default',
12
27
  pluginName: 'plugin-vue-query',
13
28
  default(name, type) {
14
- return camelCase(name, { isFile: type === 'file' })
29
+ return type === 'file' ? toFilePath(name) : camelCase(name)
15
30
  },
16
31
  resolveName(name) {
17
- return ctx.default(name, 'function')
32
+ return this.default(name, 'function')
33
+ },
34
+ resolvePathName(name, type) {
35
+ return this.default(name, type)
36
+ },
37
+ resolveQueryName(node) {
38
+ return `use${capitalize(this.resolveName(node.operationId))}`
39
+ },
40
+ resolveInfiniteQueryName(node) {
41
+ return `use${capitalize(this.resolveName(node.operationId))}Infinite`
42
+ },
43
+ resolveMutationName(node) {
44
+ return `use${capitalize(this.resolveName(node.operationId))}`
45
+ },
46
+ resolveQueryOptionsName(node) {
47
+ return `${this.resolveName(node.operationId)}QueryOptions`
48
+ },
49
+ resolveInfiniteQueryOptionsName(node) {
50
+ return `${this.resolveName(node.operationId)}InfiniteQueryOptions`
51
+ },
52
+ resolveQueryKeyName(node) {
53
+ return `${this.resolveName(node.operationId)}QueryKey`
54
+ },
55
+ resolveInfiniteQueryKeyName(node) {
56
+ return `${this.resolveName(node.operationId)}InfiniteQueryKey`
57
+ },
58
+ resolveMutationKeyName(node) {
59
+ return `${this.resolveName(node.operationId)}MutationKey`
60
+ },
61
+ resolveQueryKeyTypeName(node) {
62
+ return `${capitalize(this.resolveName(node.operationId))}QueryKey`
63
+ },
64
+ resolveInfiniteQueryKeyTypeName(node) {
65
+ return `${capitalize(this.resolveName(node.operationId))}InfiniteQueryKey`
66
+ },
67
+ resolveMutationTypeName(node) {
68
+ return capitalize(this.resolveName(node.operationId))
69
+ },
70
+ resolveClientName(node) {
71
+ return this.resolveName(node.operationId)
72
+ },
73
+ resolveInfiniteClientName(node) {
74
+ return `${this.resolveName(node.operationId)}Infinite`
18
75
  },
19
76
  }))