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

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-D1UhYFgY.js → components-B4IlVmNa.js} +244 -353
  3. package/dist/components-B4IlVmNa.js.map +1 -0
  4. package/dist/{components-qfOFRSoM.cjs → components-CIedagno.cjs} +269 -354
  5. package/dist/components-CIedagno.cjs.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-ClYptnDj.js} +144 -132
  10. package/dist/generators-ClYptnDj.js.map +1 -0
  11. package/dist/{generators-C4gs_P1i.cjs → generators-D7kNtBBo.cjs} +142 -130
  12. package/dist/generators-D7kNtBBo.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 +100 -17
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +29 -1
  19. package/dist/index.js +100 -17
  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 +11 -48
  25. package/src/components/InfiniteQueryOptions.tsx +38 -50
  26. package/src/components/Mutation.tsx +33 -42
  27. package/src/components/Query.tsx +11 -49
  28. package/src/components/QueryKey.tsx +8 -61
  29. package/src/components/QueryOptions.tsx +14 -67
  30. package/src/generators/infiniteQueryGenerator.tsx +46 -51
  31. package/src/generators/mutationGenerator.tsx +41 -49
  32. package/src/generators/queryGenerator.tsx +43 -49
  33. package/src/plugin.ts +43 -15
  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
@@ -1,20 +1,26 @@
1
1
  import path from 'node:path'
2
- import { ast, defineGenerator } from '@kubb/core'
2
+ import { resolveOperationTypeNames } from '@internals/shared'
3
+ import { resolveZodSchemaNames } from '@internals/tanstack-query'
4
+ import { 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, jsxRenderer } from '@kubb/renderer-jsx'
8
+ import { File, jsxRendererSync } from '@kubb/renderer-jsx'
7
9
  import { difference } from 'remeda'
8
10
  import { Query, QueryKey, QueryOptions } from '../components'
9
11
  import type { PluginVueQuery } from '../types'
10
- import { transformName } from '../utils.ts'
11
12
 
13
+ /**
14
+ * Built-in generator for `useQuery` composables. Emits one `useFooQuery`
15
+ * composable per GET operation (configurable via `query.methods`) plus the
16
+ * matching `fooQueryKey` / `fooQueryOptions` helpers.
17
+ */
12
18
  export const queryGenerator = defineGenerator<PluginVueQuery>({
13
19
  name: 'vue-query',
14
- renderer: jsxRenderer,
20
+ renderer: jsxRendererSync,
15
21
  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
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
@@ -30,53 +36,43 @@ export const queryGenerator = defineGenerator<PluginVueQuery>({
30
36
 
31
37
  const importPath = query ? query.importPath : '@tanstack/vue-query'
32
38
 
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)
39
+ const queryName = resolver.resolveQueryName(node)
40
+ const queryOptionsName = resolver.resolveQueryOptionsName(node)
41
+ const queryKeyName = resolver.resolveQueryKeyName(node)
42
+ const queryKeyTypeName = resolver.resolveQueryKeyTypeName(node)
43
+ const clientName = resolver.resolveClientName(node)
40
44
 
41
45
  const meta = {
42
- file: resolver.resolveFile({ name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
46
+ file: resolver.resolveFile(
47
+ { name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
48
+ { root, output, group: group ?? undefined },
49
+ ),
43
50
  fileTs: tsResolver.resolveFile(
44
51
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
45
- { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
52
+ { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },
46
53
  ),
47
54
  }
48
55
 
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
56
+ const importedTypeNames = resolveOperationTypeNames(node, tsResolver, {
57
+ paramsCasing,
58
+ exclude: [queryKeyTypeName],
59
+ order: 'body-response-first',
60
+ })
61
+
62
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
63
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
65
64
  const fileZod = zodResolver
66
65
  ? zodResolver.resolveFile(
67
66
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
68
- { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
67
+ { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group ?? undefined },
69
68
  )
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
- : []
69
+ : null
70
+ const zodSchemaNames = resolveZodSchemaNames(node, zodResolver)
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
78
  ? clientResolver?.resolveFile(
@@ -84,10 +80,10 @@ export const queryGenerator = defineGenerator<PluginVueQuery>({
84
80
  {
85
81
  root,
86
82
  output: clientPlugin?.options?.output ?? output,
87
- group: clientPlugin?.options?.group,
83
+ group: clientPlugin?.options?.group ?? undefined,
88
84
  },
89
85
  )
90
- : undefined
86
+ : null
91
87
 
92
88
  const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientName) : clientName
93
89
 
@@ -96,29 +92,27 @@ export const queryGenerator = defineGenerator<PluginVueQuery>({
96
92
  baseName={meta.file.baseName}
97
93
  path={meta.file.path}
98
94
  meta={meta.file.meta}
99
- banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
100
- footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
95
+ banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
96
+ footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: meta.file.path, baseName: meta.file.baseName } })}
101
97
  >
102
- {parser === 'zod' && fileZod && zodSchemaNames.length > 0 && (
103
- <File.Import name={zodSchemaNames as string[]} root={meta.file.path} path={fileZod.path} />
104
- )}
98
+ {fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
105
99
  {clientOptions.importPath ? (
106
100
  <>
107
- {!shouldUseClientPlugin && <File.Import name={'fetch'} path={clientOptions.importPath} />}
101
+ {!shouldUseClientPlugin && <File.Import name={'client'} path={clientOptions.importPath} />}
108
102
  <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={clientOptions.importPath} isTypeOnly />
109
103
  {clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
110
104
  </>
111
105
  ) : (
112
106
  <>
113
- {!shouldUseClientPlugin && <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />}
107
+ {!shouldUseClientPlugin && <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />}
114
108
  <File.Import
115
109
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
116
110
  root={meta.file.path}
117
- path={path.resolve(root, '.kubb/fetch.ts')}
111
+ path={path.resolve(root, '.kubb/client.ts')}
118
112
  isTypeOnly
119
113
  />
120
114
  {clientOptions.dataReturnType === 'full' && (
121
- <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
115
+ <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
122
116
  )}
123
117
  </>
124
118
  )}
package/src/plugin.ts CHANGED
@@ -7,14 +7,42 @@ import { source as fetchClientSource } from '@kubb/plugin-client/templates/clien
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
48
  output = { path: 'hooks', barrelType: 'named' },
@@ -24,13 +52,12 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
24
52
  override = [],
25
53
  parser = 'client',
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,7 +68,9 @@ 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
75
  const groupConfig = group
47
76
  ? ({
@@ -55,19 +84,18 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
55
84
  return `${camelCase(ctx.group)}Controller`
56
85
  },
57
86
  } satisfies Group)
58
- : undefined
87
+ : null
59
88
 
60
89
  return {
61
90
  name: pluginVueQueryName,
62
91
  options,
63
- dependencies: [pluginTsName, parser === 'zod' ? pluginZodName : undefined].filter(Boolean),
92
+ dependencies: [pluginTsName, parser === 'zod' ? pluginZodName : undefined].filter((dependency): dependency is string => Boolean(dependency)),
64
93
  hooks: {
65
94
  'kubb:plugin:setup'(ctx) {
66
95
  const resolver = userResolver ? { ...resolverVueQuery, ...userResolver } : resolverVueQuery
67
96
 
68
97
  ctx.setOptions({
69
98
  output,
70
- transformers,
71
99
  client: {
72
100
  bundle: client?.bundle,
73
101
  baseURL: client?.baseURL,
@@ -99,9 +127,9 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
99
127
  ? {
100
128
  queryParam: 'id',
101
129
  initialPageParam: 0,
102
- cursorParam: undefined,
103
- nextParam: undefined,
104
- previousParam: undefined,
130
+ cursorParam: null,
131
+ nextParam: null,
132
+ previousParam: null,
105
133
  ...infinite,
106
134
  }
107
135
  : false,
@@ -132,11 +160,11 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
132
160
 
133
161
  if (client?.bundle && !hasClientPlugin && !clientImportPath) {
134
162
  ctx.injectFile({
135
- baseName: 'fetch.ts',
136
- path: path.resolve(root, '.kubb/fetch.ts'),
163
+ baseName: 'client.ts',
164
+ path: path.resolve(root, '.kubb/client.ts'),
137
165
  sources: [
138
166
  ast.createSource({
139
- name: 'fetch',
167
+ name: 'client',
140
168
  nodes: [ast.createText(clientName === 'fetch' ? fetchClientSource : axiosClientSource)],
141
169
  isExportable: true,
142
170
  isIndexable: true,
@@ -2,18 +2,75 @@ import { camelCase } 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
29
  return camelCase(name, { isFile: type === 'file' })
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
  }))