@kubb/plugin-react-query 5.0.0-beta.15 → 5.0.0-beta.25

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 (45) hide show
  1. package/dist/{components-BZ3a2O0G.cjs → components-C1_zAoAO.cjs} +65 -84
  2. package/dist/components-C1_zAoAO.cjs.map +1 -0
  3. package/dist/{components-DJqIUiZW.js → components-C91DnOOV.js} +65 -84
  4. package/dist/components-C91DnOOV.js.map +1 -0
  5. package/dist/components.cjs +1 -1
  6. package/dist/components.d.ts +1 -1
  7. package/dist/components.js +1 -1
  8. package/dist/{generators-BQ_vEksc.js → generators-9srJC_zb.js} +115 -75
  9. package/dist/generators-9srJC_zb.js.map +1 -0
  10. package/dist/{generators-DSjer1xY.cjs → generators-DS3JH1hR.cjs} +115 -75
  11. package/dist/generators-DS3JH1hR.cjs.map +1 -0
  12. package/dist/generators.cjs +1 -1
  13. package/dist/generators.d.ts +41 -1
  14. package/dist/generators.js +1 -1
  15. package/dist/index.cjs +51 -11
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.ts +30 -1
  18. package/dist/index.js +51 -11
  19. package/dist/index.js.map +1 -1
  20. package/dist/{types-DG_OxOym.d.ts → types-DiZPLTXl.d.ts} +92 -55
  21. package/extension.yaml +904 -325
  22. package/package.json +7 -7
  23. package/src/components/InfiniteQuery.tsx +4 -4
  24. package/src/components/InfiniteQueryOptions.tsx +21 -31
  25. package/src/components/Mutation.tsx +2 -2
  26. package/src/components/MutationOptions.tsx +1 -1
  27. package/src/components/Query.tsx +1 -1
  28. package/src/components/QueryOptions.tsx +1 -1
  29. package/src/components/SuspenseInfiniteQuery.tsx +4 -4
  30. package/src/components/SuspenseInfiniteQueryOptions.tsx +21 -31
  31. package/src/components/SuspenseQuery.tsx +1 -1
  32. package/src/generators/customHookOptionsFileGenerator.tsx +7 -1
  33. package/src/generators/hookOptionsGenerator.tsx +17 -11
  34. package/src/generators/infiniteQueryGenerator.tsx +22 -13
  35. package/src/generators/mutationGenerator.tsx +20 -12
  36. package/src/generators/queryGenerator.tsx +20 -12
  37. package/src/generators/suspenseInfiniteQueryGenerator.tsx +22 -13
  38. package/src/generators/suspenseQueryGenerator.tsx +21 -12
  39. package/src/plugin.ts +34 -5
  40. package/src/resolvers/resolverReactQuery.ts +15 -4
  41. package/src/types.ts +89 -52
  42. package/dist/components-BZ3a2O0G.cjs.map +0 -1
  43. package/dist/components-DJqIUiZW.js.map +0 -1
  44. package/dist/generators-BQ_vEksc.js.map +0 -1
  45. package/dist/generators-DSjer1xY.cjs.map +0 -1
@@ -10,11 +10,16 @@ import { difference } from 'remeda'
10
10
  import { Query, QueryKey, QueryOptions } from '../components'
11
11
  import type { PluginReactQuery } from '../types'
12
12
 
13
+ /**
14
+ * Built-in generator for `useQuery` hooks. Emits one `useFooQuery` hook per
15
+ * GET operation (configurable via `query.methods`) plus the matching
16
+ * `fooQueryKey` / `fooQueryOptions` helpers.
17
+ */
13
18
  export const queryGenerator = defineGenerator<PluginReactQuery>({
14
19
  name: 'react-query',
15
20
  renderer: jsxRendererSync,
16
21
  operation(node, ctx) {
17
- const { config, driver, resolver, root, inputNode } = ctx
22
+ const { config, driver, resolver, root } = ctx
18
23
  const { output, query, mutation, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group, customOptions } = ctx.options
19
24
 
20
25
  const pluginTs = driver.getPlugin(pluginTsName)
@@ -39,10 +44,13 @@ export const queryGenerator = defineGenerator<PluginReactQuery>({
39
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 }),
47
+ file: resolver.resolveFile(
48
+ { name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
49
+ { root, output, group: group ?? undefined },
50
+ ),
43
51
  fileTs: tsResolver.resolveFile(
44
52
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
45
- { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
53
+ { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },
46
54
  ),
47
55
  }
48
56
 
@@ -52,20 +60,20 @@ export const queryGenerator = defineGenerator<PluginReactQuery>({
52
60
  order: 'body-response-first',
53
61
  })
54
62
 
55
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
56
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
63
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
64
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
57
65
  const fileZod = zodResolver
58
66
  ? zodResolver.resolveFile(
59
67
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
60
- { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
68
+ { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group ?? undefined },
61
69
  )
62
- : undefined
70
+ : null
63
71
  const zodSchemaNames = resolveZodSchemaNames(node, zodResolver)
64
72
 
65
73
  const clientPlugin = driver.getPlugin(pluginClientName)
66
74
  const hasClientPlugin = clientPlugin?.name === pluginClientName
67
75
  const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
68
- const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : undefined
76
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
69
77
 
70
78
  const clientFile = shouldUseClientPlugin
71
79
  ? clientResolver?.resolveFile(
@@ -73,10 +81,10 @@ export const queryGenerator = defineGenerator<PluginReactQuery>({
73
81
  {
74
82
  root,
75
83
  output: clientPlugin?.options?.output ?? output,
76
- group: clientPlugin?.options?.group,
84
+ group: clientPlugin?.options?.group ?? undefined,
77
85
  },
78
86
  )
79
- : undefined
87
+ : null
80
88
 
81
89
  const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientName) : clientName
82
90
 
@@ -85,8 +93,8 @@ export const queryGenerator = defineGenerator<PluginReactQuery>({
85
93
  baseName={meta.file.baseName}
86
94
  path={meta.file.path}
87
95
  meta={meta.file.meta}
88
- banner={resolver.resolveBanner(inputNode, { output, config })}
89
- footer={resolver.resolveFooter(inputNode, { output, config })}
96
+ banner={resolver.resolveBanner(ctx.meta, { output, config })}
97
+ footer={resolver.resolveFooter(ctx.meta, { output, config })}
90
98
  >
91
99
  {fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
92
100
  {clientOptions.importPath ? (
@@ -10,11 +10,17 @@ import { difference } from 'remeda'
10
10
  import { QueryKey, SuspenseInfiniteQuery, SuspenseInfiniteQueryOptions } from '../components'
11
11
  import type { PluginReactQuery } from '../types'
12
12
 
13
+ /**
14
+ * Built-in generator for `useSuspenseInfiniteQuery` hooks. Enabled when both
15
+ * `suspense` and `infinite` are configured. Combines suspense semantics with
16
+ * cursor-based pagination — handlers throw promises while loading and pull
17
+ * additional pages on demand.
18
+ */
13
19
  export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>({
14
20
  name: 'react-suspense-infinite-query',
15
21
  renderer: jsxRendererSync,
16
22
  operation(node, ctx) {
17
- const { config, driver, resolver, root, inputNode } = ctx
23
+ const { config, driver, resolver, root } = ctx
18
24
  const {
19
25
  output,
20
26
  query,
@@ -40,7 +46,7 @@ export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>(
40
46
  !isQuery &&
41
47
  difference(mutation ? mutation.methods : [], query ? query.methods : []).some((method) => node.method.toLowerCase() === method.toLowerCase())
42
48
  const isSuspense = !!suspense
43
- const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : undefined
49
+ const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : null
44
50
 
45
51
  if (!isQuery || isMutation || !isSuspense || !infiniteOptions) return null
46
52
 
@@ -61,29 +67,32 @@ export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>(
61
67
  const clientBaseName = resolver.resolveSuspenseInfiniteClientName(node)
62
68
 
63
69
  const meta = {
64
- file: resolver.resolveFile({ name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
70
+ file: resolver.resolveFile(
71
+ { name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
72
+ { root, output, group: group ?? undefined },
73
+ ),
65
74
  fileTs: tsResolver.resolveFile(
66
75
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
67
- { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
76
+ { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },
68
77
  ),
69
78
  }
70
79
 
71
80
  const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing, order: 'body-response-first' })
72
81
 
73
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
74
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
82
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
83
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
75
84
  const fileZod = zodResolver
76
85
  ? zodResolver.resolveFile(
77
86
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
78
- { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
87
+ { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group ?? undefined },
79
88
  )
80
- : undefined
89
+ : null
81
90
  const zodSchemaNames = resolveZodSchemaNames(node, zodResolver)
82
91
 
83
92
  const clientPlugin = driver.getPlugin(pluginClientName)
84
93
  const hasClientPlugin = clientPlugin?.name === pluginClientName
85
94
  const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
86
- const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : undefined
95
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
87
96
 
88
97
  const clientFile = shouldUseClientPlugin
89
98
  ? clientResolver?.resolveFile(
@@ -91,10 +100,10 @@ export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>(
91
100
  {
92
101
  root,
93
102
  output: clientPlugin?.options?.output ?? output,
94
- group: clientPlugin?.options?.group,
103
+ group: clientPlugin?.options?.group ?? undefined,
95
104
  },
96
105
  )
97
- : undefined
106
+ : null
98
107
 
99
108
  const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientBaseName) : clientBaseName
100
109
 
@@ -103,8 +112,8 @@ export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>(
103
112
  baseName={meta.file.baseName}
104
113
  path={meta.file.path}
105
114
  meta={meta.file.meta}
106
- banner={resolver.resolveBanner(inputNode, { output, config })}
107
- footer={resolver.resolveFooter(inputNode, { output, config })}
115
+ banner={resolver.resolveBanner(ctx.meta, { output, config })}
116
+ footer={resolver.resolveFooter(ctx.meta, { output, config })}
108
117
  >
109
118
  {fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
110
119
  {clientOptions.importPath ? (
@@ -10,11 +10,17 @@ import { difference } from 'remeda'
10
10
  import { QueryKey, QueryOptions, SuspenseQuery } from '../components'
11
11
  import type { PluginReactQuery } from '../types'
12
12
 
13
+ /**
14
+ * Built-in generator for `useSuspenseQuery` hooks. Enabled when
15
+ * `pluginReactQuery({ suspense: {} })`. Emits one `useFooSuspenseQuery` hook
16
+ * per query operation. Suspense queries throw promises while loading and
17
+ * require a `<Suspense>` boundary in the React tree. TanStack Query v5+ only.
18
+ */
13
19
  export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
14
20
  name: 'react-suspense-query',
15
21
  renderer: jsxRendererSync,
16
22
  operation(node, ctx) {
17
- const { config, driver, resolver, root, inputNode } = ctx
23
+ const { config, driver, resolver, root } = ctx
18
24
  const { output, query, mutation, suspense, paramsCasing, paramsType, pathParamsType, parser, client: clientOptions, group, customOptions } = ctx.options
19
25
 
20
26
  const pluginTs = driver.getPlugin(pluginTsName)
@@ -40,10 +46,13 @@ export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
40
46
  const clientName = resolver.resolveSuspenseClientName(node)
41
47
 
42
48
  const meta = {
43
- file: resolver.resolveFile({ name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
49
+ file: resolver.resolveFile(
50
+ { name: queryName, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
51
+ { root, output, group: group ?? undefined },
52
+ ),
44
53
  fileTs: tsResolver.resolveFile(
45
54
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
46
- { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group },
55
+ { root, output: pluginTs.options?.output ?? output, group: pluginTs.options?.group ?? undefined },
47
56
  ),
48
57
  }
49
58
 
@@ -53,20 +62,20 @@ export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
53
62
  order: 'body-response-first',
54
63
  })
55
64
 
56
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
57
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
65
+ const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : null
66
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
58
67
  const fileZod = zodResolver
59
68
  ? zodResolver.resolveFile(
60
69
  { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
61
- { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group },
70
+ { root, output: pluginZod?.options?.output ?? output, group: pluginZod?.options?.group ?? undefined },
62
71
  )
63
- : undefined
72
+ : null
64
73
  const zodSchemaNames = resolveZodSchemaNames(node, zodResolver)
65
74
 
66
75
  const clientPlugin = driver.getPlugin(pluginClientName)
67
76
  const hasClientPlugin = clientPlugin?.name === pluginClientName
68
77
  const shouldUseClientPlugin = hasClientPlugin && clientOptions.clientType !== 'class'
69
- const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : undefined
78
+ const clientResolver = shouldUseClientPlugin ? driver.getResolver(pluginClientName) : null
70
79
 
71
80
  const clientFile = shouldUseClientPlugin
72
81
  ? clientResolver?.resolveFile(
@@ -74,10 +83,10 @@ export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
74
83
  {
75
84
  root,
76
85
  output: clientPlugin?.options?.output ?? output,
77
- group: clientPlugin?.options?.group,
86
+ group: clientPlugin?.options?.group ?? undefined,
78
87
  },
79
88
  )
80
- : undefined
89
+ : null
81
90
 
82
91
  const resolvedClientName = shouldUseClientPlugin ? (clientResolver?.resolveName(node.operationId) ?? clientName) : clientName
83
92
 
@@ -86,8 +95,8 @@ export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
86
95
  baseName={meta.file.baseName}
87
96
  path={meta.file.path}
88
97
  meta={meta.file.meta}
89
- banner={resolver.resolveBanner(inputNode, { output, config })}
90
- footer={resolver.resolveFooter(inputNode, { output, config })}
98
+ banner={resolver.resolveBanner(ctx.meta, { output, config })}
99
+ footer={resolver.resolveFooter(ctx.meta, { output, config })}
91
100
  >
92
101
  {fileZod && zodSchemaNames.length > 0 && <File.Import name={zodSchemaNames} root={meta.file.path} path={fileZod.path} />}
93
102
  {clientOptions.importPath ? (
package/src/plugin.ts CHANGED
@@ -20,8 +20,37 @@ import {
20
20
  import { resolverReactQuery } from './resolvers/resolverReactQuery.ts'
21
21
  import type { PluginReactQuery } from './types.ts'
22
22
 
23
+ /**
24
+ * Canonical plugin name for `@kubb/plugin-react-query`. Used for driver lookups
25
+ * and cross-plugin dependency references.
26
+ */
23
27
  export const pluginReactQueryName = 'plugin-react-query' satisfies PluginReactQuery['name']
24
28
 
29
+ /**
30
+ * Generates one TanStack Query hook per OpenAPI operation for React. Queries
31
+ * become `useFooQuery`/`useFooSuspenseQuery`/`useFooInfiniteQuery`; mutations
32
+ * become `useFooMutation`. Each hook is fully typed: query keys, input
33
+ * variables, response data, and error shape all come from the spec.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { defineConfig } from 'kubb'
38
+ * import { pluginTs } from '@kubb/plugin-ts'
39
+ * import { pluginReactQuery } from '@kubb/plugin-react-query'
40
+ *
41
+ * export default defineConfig({
42
+ * input: { path: './petStore.yaml' },
43
+ * output: { path: './src/gen' },
44
+ * plugins: [
45
+ * pluginTs(),
46
+ * pluginReactQuery({
47
+ * output: { path: './hooks' },
48
+ * suspense: {},
49
+ * }),
50
+ * ],
51
+ * })
52
+ * ```
53
+ */
25
54
  export const pluginReactQuery = definePlugin<PluginReactQuery>((options) => {
26
55
  const {
27
56
  output = { path: 'hooks', barrelType: 'named' },
@@ -73,7 +102,7 @@ export const pluginReactQuery = definePlugin<PluginReactQuery>((options) => {
73
102
  return `${camelCase(ctx.group)}Controller`
74
103
  },
75
104
  } satisfies Group)
76
- : undefined
105
+ : null
77
106
 
78
107
  return {
79
108
  name: pluginReactQueryName,
@@ -116,14 +145,14 @@ export const pluginReactQuery = definePlugin<PluginReactQuery>((options) => {
116
145
  ? {
117
146
  queryParam: 'id',
118
147
  initialPageParam: 0,
119
- cursorParam: undefined,
120
- nextParam: undefined,
121
- previousParam: undefined,
148
+ cursorParam: null,
149
+ nextParam: null,
150
+ previousParam: null,
122
151
  ...infinite,
123
152
  }
124
153
  : false,
125
154
  suspense,
126
- customOptions: customOptions ? { name: 'useCustomHookOptions', ...customOptions } : undefined,
155
+ customOptions: customOptions ? { name: 'useCustomHookOptions', ...customOptions } : null,
127
156
  parser,
128
157
  paramsType,
129
158
  pathParamsType,
@@ -7,12 +7,23 @@ function capitalize(name: string): string {
7
7
  }
8
8
 
9
9
  /**
10
- * Naming convention resolver for React Query plugin.
10
+ * Default resolver used by `@kubb/plugin-react-query`. Decides the names and
11
+ * file paths for every generated TanStack Query hook (`useFooQuery`,
12
+ * `useFooMutation`, `useFooInfiniteQuery`, ...) and its companion helpers
13
+ * (`fooQueryKey`, `fooQueryOptions`).
11
14
  *
12
- * Provides default naming helpers using camelCase for functions and file paths.
15
+ * Functions and files use camelCase; hooks get the `use` prefix; suspense and
16
+ * infinite variants are suffixed with `Suspense`/`Infinite`.
13
17
  *
14
- * @example
15
- * `resolverReactQuery.default('list pets', 'function') // → 'listPets'`
18
+ * @example Resolve hook and helper names
19
+ * ```ts
20
+ * import { resolverReactQuery } from '@kubb/plugin-react-query'
21
+ *
22
+ * resolverReactQuery.resolveQueryName(operationNode) // 'useGetPetById'
23
+ * resolverReactQuery.resolveMutationName(operationNode) // 'useUpdatePet'
24
+ * resolverReactQuery.resolveQueryKeyName(operationNode) // 'getPetByIdQueryKey'
25
+ * resolverReactQuery.resolveQueryOptionsName(operationNode) // 'getPetByIdQueryOptions'
26
+ * ```
16
27
  */
17
28
  export const resolverReactQuery = defineResolver<PluginReactQuery>(() => ({
18
29
  name: 'default',
package/src/types.ts CHANGED
@@ -128,27 +128,34 @@ export type ResolverReactQuery = Resolver & {
128
128
  type Suspense = object
129
129
 
130
130
  /**
131
- * Customize the queryKey.
131
+ * Builds the `queryKey` used by each generated query hook.
132
+ *
133
+ * @note String values are inlined verbatim into generated code. Wrap literal
134
+ * strings in `JSON.stringify(...)`.
132
135
  */
133
136
  type QueryKey = Transformer
134
137
 
135
138
  /**
136
- * Customize the mutationKey.
139
+ * Builds the `mutationKey` used by each generated mutation hook.
140
+ *
141
+ * @note String values are inlined verbatim into generated code. Wrap literal
142
+ * strings in `JSON.stringify(...)`.
137
143
  */
138
144
  type MutationKey = Transformer
139
145
 
140
146
  type Query = {
141
147
  /**
142
- * HTTP methods to use for queries.
148
+ * HTTP methods treated as queries. Operations using these methods produce
149
+ * `useQuery`-style hooks.
143
150
  *
144
151
  * @default ['get']
145
152
  */
146
153
  methods?: Array<string>
147
154
  /**
148
- * Path to the useQuery hook for useQuery functionality.
149
- * Used as `import { useQuery } from '${importPath}'`.
150
- * Accepts relative and absolute paths.
151
- * Path is used as-is; relative paths are based on the generated file location.
155
+ * Module specifier used in the `import { useQuery } from '...'` statement at
156
+ * the top of every generated hook file. Useful for routing through a wrapper
157
+ * that injects a default `queryClient`.
158
+ *
152
159
  * @default '@tanstack/react-query'
153
160
  */
154
161
  importPath?: string
@@ -156,16 +163,16 @@ type Query = {
156
163
 
157
164
  type Mutation = {
158
165
  /**
159
- * HTTP methods to use for mutations.
166
+ * HTTP methods treated as mutations. Operations using these methods produce
167
+ * `useMutation`-style hooks.
160
168
  *
161
169
  * @default ['post', 'put', 'delete']
162
170
  */
163
171
  methods?: Array<string>
164
172
  /**
165
- * Path to the useMutation hook for useMutation functionality.
166
- * Used as `import { useMutation } from '${importPath}'`.
167
- * Accepts relative and absolute paths.
168
- * Path is used as-is; relative paths are based on the generated file location.
173
+ * Module specifier used in the `import { useMutation } from '...'` statement
174
+ * at the top of every generated hook file.
175
+ *
169
176
  * @default '@tanstack/react-query'
170
177
  */
171
178
  importPath?: string
@@ -173,42 +180,45 @@ type Mutation = {
173
180
 
174
181
  export type Infinite = {
175
182
  /**
176
- * Specify the params key used for `pageParam`.
183
+ * Name of the query parameter that holds the page cursor.
184
+ *
177
185
  * @default 'id'
178
186
  */
179
- queryParam: string
187
+ queryParam?: string
180
188
  /**
181
- * Which field of the data is used, set it to undefined when no cursor is known.
182
- * @deprecated Use `nextParam` and `previousParam` instead for more flexible pagination handling.
189
+ * Path to the cursor field on the response. Leave undefined when the cursor
190
+ * is not known.
191
+ *
192
+ * @deprecated Use `nextParam` and `previousParam` for richer pagination control.
183
193
  */
184
- cursorParam?: string | undefined
194
+ cursorParam?: string | null
185
195
  /**
186
- * Which field of the data is used to get the cursor for the next page.
187
- * Supports dot notation (e.g. 'pagination.next.id') or array path (e.g. ['pagination', 'next', 'id']) to access nested fields.
196
+ * Path to the next-page cursor on the response. Supports dot notation
197
+ * (`'pagination.next.id'`) or array form (`['pagination', 'next', 'id']`).
188
198
  */
189
- nextParam?: string | string[] | undefined
199
+ nextParam?: string | Array<string> | null
190
200
  /**
191
- * Which field of the data is used to get the cursor for the previous page.
192
- * Supports dot notation (e.g. 'pagination.prev.id') or array path (e.g. ['pagination', 'prev', 'id']) to access nested fields.
201
+ * Path to the previous-page cursor on the response. Supports dot notation
202
+ * or array form.
193
203
  */
194
- previousParam?: string | string[] | undefined
204
+ previousParam?: string | Array<string> | null
195
205
  /**
196
- * The initial value, the value of the first page.
206
+ * Initial value for `pageParam` on the first fetch.
207
+ *
197
208
  * @default 0
198
209
  */
199
- initialPageParam: unknown
210
+ initialPageParam?: unknown
200
211
  }
201
212
 
202
213
  type CustomOptions = {
203
214
  /**
204
- * Path to the hook that is used to customize the hook options.
205
- * It used as `import ${customOptions.name} from '${customOptions.importPath}'`.
206
- * It allows both relative and absolute paths but be aware that we will not change the path.
215
+ * Module specifier of your custom-options hook. Imported as
216
+ * `import ${name} from '${importPath}'`.
207
217
  */
208
218
  importPath: string
209
219
  /**
210
- * Name of the exported hook that is used to customize the hook options.
211
- * It used as `import ${customOptions.name} from '${customOptions.importPath}'`.
220
+ * Exported function name of your custom-options hook.
221
+ *
212
222
  * @default 'useCustomHookOptions'
213
223
  */
214
224
  name?: string
@@ -216,86 +226,113 @@ type CustomOptions = {
216
226
 
217
227
  export type Options = {
218
228
  /**
219
- * Specify the export location for the files and define the behavior of the output
220
- * @default { path: 'hooks', barrelType: 'named' }
229
+ * Where the generated hooks are written and how they are exported.
230
+ *
231
+ * @default { path: 'hooks', barrel: { type: 'named' } }
221
232
  */
222
233
  output?: Output
223
234
  /**
224
- * Group the @tanstack/query hooks based on the provided name.
235
+ * Split generated files into subfolders based on the operation's tag.
225
236
  */
226
237
  group?: Group
238
+ /**
239
+ * HTTP client used inside every generated hook. Mirrors a subset of
240
+ * `pluginClient` options.
241
+ */
227
242
  client?: ClientImportPath & Pick<PluginClient['options'], 'clientType' | 'dataReturnType' | 'baseURL' | 'bundle' | 'paramsCasing'>
228
243
  /**
229
- * Tags, operations, or paths to exclude from generation.
244
+ * Skip operations matching at least one entry in the list.
230
245
  */
231
246
  exclude?: Array<Exclude>
232
247
  /**
233
- * Tags, operations, or paths to include in generation.
248
+ * Restrict generation to operations matching at least one entry in the list.
234
249
  */
235
250
  include?: Array<Include>
236
251
  /**
237
- * Override options for specific tags, operations, or paths.
252
+ * Apply a different options object to operations matching a pattern.
238
253
  */
239
254
  override?: Array<Override<ResolvedOptions>>
240
255
  /**
241
- * Apply casing to parameter names.
256
+ * Rename parameter properties in the generated hooks.
257
+ *
258
+ * @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
242
259
  */
243
260
  paramsCasing?: 'camelcase'
244
261
  /**
245
- * How parameters are passed: grouped in an object or spread inline.
262
+ * How operation parameters appear in the generated hook signature.
263
+ * - `'inline'` — positional arguments.
264
+ * - `'object'` — single destructured object argument.
246
265
  *
247
266
  * @default 'inline'
248
267
  */
249
268
  paramsType?: 'object' | 'inline'
250
269
  /**
251
- * How path parameters are passed: grouped in an object or spread inline.
270
+ * How URL path parameters are arranged inside the inline argument list.
252
271
  *
253
272
  * @default 'inline'
254
273
  */
255
274
  pathParamsType?: PluginClient['options']['pathParamsType']
256
275
  /**
257
- * Add infinite query hooks.
276
+ * Enables `useInfiniteQuery` hooks for cursor- or page-based pagination.
277
+ * Pass an object to configure how the cursor is read; pass `false` to skip.
278
+ *
279
+ * @default false
258
280
  */
259
281
  infinite?: Partial<Infinite> | false
260
282
  /**
261
- * Add suspense query hooks.
283
+ * Adds `useSuspenseQuery` hooks alongside the regular `useQuery` ones.
284
+ * Pass an empty object (`{}`) to enable. TanStack Query v5+ only.
262
285
  */
263
286
  suspense?: Partial<Suspense> | false
287
+ /**
288
+ * Custom `queryKey` builder. Use to add a version namespace, swap to
289
+ * operation IDs, or shape keys to match an existing invalidation strategy.
290
+ */
264
291
  queryKey?: QueryKey
265
292
  /**
266
- * Configure useQuery behavior.
293
+ * Configures query hooks. Set to `false` to skip generating hooks entirely
294
+ * and emit only `queryOptions(...)` helpers.
267
295
  */
268
296
  query?: Partial<Query> | false
297
+ /**
298
+ * Custom `mutationKey` builder. Useful when you batch invalidations or read
299
+ * mutation state via `useMutationState`.
300
+ */
269
301
  mutationKey?: MutationKey
270
302
  /**
271
- * Configure useMutation behavior.
303
+ * Configures mutation hooks. Set to `false` to skip mutation generation.
272
304
  */
273
305
  mutation?: Partial<Mutation> | false
274
306
  /**
275
- * Use a custom hook to customize hook options and generate a HookOptions type.
307
+ * Wires every generated hook through a user-supplied function that returns
308
+ * extra options (`onSuccess`, `onError`, `select`, ...). Also emits a
309
+ * `HookOptions` type so the wrapper stays in sync with generated hooks.
276
310
  */
277
311
  customOptions?: CustomOptions
278
312
  /**
279
- * Parser to use for validating response data.
313
+ * Validator applied to response bodies before they reach the caller.
314
+ * - `'client'` — no validation. Trusts the API.
315
+ * - `'zod'` — pipes responses through schemas from `@kubb/plugin-zod`.
280
316
  */
281
317
  parser?: PluginClient['options']['parser']
282
318
  /**
283
- * Override naming conventions for function names and types.
319
+ * Override how hook names and file paths are built. Methods you omit fall
320
+ * back to the default `resolverReactQuery`.
284
321
  */
285
322
  resolver?: Partial<ResolverReactQuery> & ThisType<ResolverReactQuery>
286
323
  /**
287
- * AST visitor to transform generated nodes.
324
+ * AST visitor applied to each operation node before printing.
288
325
  */
289
326
  transformer?: ast.Visitor
290
327
  /**
291
- * Additional generators alongside the default generators.
328
+ * Custom generators that run alongside the built-in React Query generators.
292
329
  */
293
330
  generators?: Array<Generator<PluginReactQuery>>
294
331
  }
295
332
 
296
333
  type ResolvedOptions = {
297
334
  output: Output
298
- group: Group | undefined
335
+ group: Group | null
299
336
  exclude: NonNullable<Options['exclude']>
300
337
  include: Options['include']
301
338
  override: NonNullable<Options['override']>
@@ -309,11 +346,11 @@ type ResolvedOptions = {
309
346
  */
310
347
  infinite: NonNullable<Infinite> | false
311
348
  suspense: Suspense | false
312
- queryKey: QueryKey | undefined
349
+ queryKey: QueryKey | null
313
350
  query: NonNullable<Required<Query>> | false
314
- mutationKey: MutationKey | undefined
351
+ mutationKey: MutationKey | null
315
352
  mutation: NonNullable<Required<Mutation>> | false
316
- customOptions: NonNullable<Required<CustomOptions>> | undefined
353
+ customOptions: NonNullable<Required<CustomOptions>> | null
317
354
  resolver: ResolverReactQuery
318
355
  }
319
356