@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
@@ -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, 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
+ 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,64 +37,50 @@ export const queryGenerator = defineGenerator<PluginVueQuery>({
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 = parser === 'zod' ? 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)
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,29 +89,27 @@ 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
100
  {clientOptions.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={clientOptions.importPath} isTypeOnly />}
110
101
  </>
111
102
  ) : (
112
103
  <>
113
- {!shouldUseClientPlugin && <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />}
104
+ {!shouldUseClientPlugin && <File.Import name={['client']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} />}
114
105
  <File.Import
115
106
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
116
107
  root={meta.file.path}
117
- path={path.resolve(root, '.kubb/fetch.ts')}
108
+ path={path.resolve(root, '.kubb/client.ts')}
118
109
  isTypeOnly
119
110
  />
120
111
  {clientOptions.dataReturnType === 'full' && (
121
- <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
112
+ <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/client.ts')} isTypeOnly />
122
113
  )}
123
114
  </>
124
115
  )}
package/src/plugin.ts CHANGED
@@ -1,20 +1,48 @@
1
1
  import path from 'node:path'
2
- import { camelCase } from '@internals/utils'
3
- import { ast, definePlugin, type Group } from '@kubb/core'
2
+ import { createGroupConfig } from '@internals/shared'
3
+ import { ast, definePlugin } from '@kubb/core'
4
4
  import { 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
48
  output = { path: 'hooks', barrelType: 'named' },
@@ -22,15 +50,14 @@ export const pluginVueQuery = definePlugin<PluginVueQuery>((options) => {
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, { suffix: 'Controller', honorName: true })
59
76
 
60
77
  return {
61
78
  name: pluginVueQueryName,
62
79
  options,
63
- dependencies: [pluginTsName, parser === 'zod' ? pluginZodName : undefined].filter(Boolean),
80
+ dependencies: [pluginTsName, parser === 'zod' ? 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,
@@ -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
  }))