Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/react-query-match-predicate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kubb/plugin-react-query': patch
---

Give each of the five hook generators (`query`, `suspenseQuery`, `infiniteQuery`, `suspenseInfiniteQuery`, `mutation`) a `match` predicate instead of classifying and bailing out inside `operation()`. This replaces the `createOperationDispatcher` workaround from #728, now that `@kubb/core`'s `Generator` supports `match` natively (kubb-labs/kubb#3828, released in `kubb@5.0.0-beta.104`). Generated output is unchanged.
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,31 @@ import type { PluginReactQuery } from '../types'
export const infiniteQueryGenerator = defineGenerator<PluginReactQuery>({
name: 'react-infinite-query',
renderer: jsxRenderer,
match(node, ctx) {
const operationNode = node as ast.OperationNode
if (!ast.isHttpOperationNode(operationNode)) return false
const { query, mutation, infinite, hooks } = ctx.options

const { isQuery, isMutation } = classifyOperation(operationNode, { query, mutation })
const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : null
if (!isQuery || isMutation || !infiniteOptions || !hooks) return false

// Validate queryParam exists in operation's query parameters, optional or not. cursorParam
// validation against response schema keys is skipped in v5 (complex schema inspection).
const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name)
return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false
},
operation(node, ctx) {
if (!ast.isHttpOperationNode(node)) return null
const { config, driver, resolver, root } = ctx
const { output, query, mutation, infinite, client, group, customOptions, hooks } = ctx.options
const { output, query, infinite, client, group, customOptions } = ctx.options

const pluginTs = driver.getPlugin(pluginTsName)
if (!pluginTs) return null
const tsResolver = driver.getResolver(pluginTsName)

const { isQuery, isMutation } = classifyOperation(node, { query, mutation })
const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : null

if (!isQuery || isMutation || !infiniteOptions || !hooks) return null

// Validate queryParam exists in operation's query parameters
const normalizeKey = (key: string) => key.replace(/\?$/, '')
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name)
const hasQueryParam = infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false
// cursorParam validation against response schema keys is skipped in v5 (complex schema inspection)
if (!hasQueryParam) return null
if (!infiniteOptions) return null

const importPath = query ? query.importPath : '@tanstack/react-query'

Expand Down
12 changes: 7 additions & 5 deletions packages/plugin-react-query/src/generators/mutationGenerator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,21 @@ import type { PluginReactQuery } from '../types'
export const mutationGenerator = defineGenerator<PluginReactQuery>({
name: 'react-query-mutation',
renderer: jsxRenderer,
match(node, ctx) {
const operationNode = node as ast.OperationNode
if (!ast.isHttpOperationNode(operationNode)) return false
const { query, mutation } = ctx.options
return classifyOperation(operationNode, { query, mutation }).isMutation
},
operation(node, ctx) {
if (!ast.isHttpOperationNode(node)) return null
const { config, driver, resolver, root } = ctx
const { output, query, mutation, client, group, customOptions, hooks } = ctx.options
const { output, mutation, client, group, customOptions, hooks } = ctx.options

const pluginTs = driver.getPlugin(pluginTsName)
if (!pluginTs) return null
const tsResolver = driver.getResolver(pluginTsName)

const { isMutation } = classifyOperation(node, { query, mutation })

if (!isMutation) return null

const importPath = mutation ? mutation.importPath : '@tanstack/react-query'

// The registered contract client plugin owns the `<op>` the hook imports and calls.
Expand Down
13 changes: 8 additions & 5 deletions packages/plugin-react-query/src/generators/queryGenerator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@ import type { PluginReactQuery } from '../types'
export const queryGenerator = defineGenerator<PluginReactQuery>({
name: 'react-query',
renderer: jsxRenderer,
match(node, ctx) {
const operationNode = node as ast.OperationNode
if (!ast.isHttpOperationNode(operationNode)) return false
const { query, mutation } = ctx.options
const { isQuery, isMutation } = classifyOperation(operationNode, { query, mutation })
return isQuery && !isMutation
},
operation(node, ctx) {
if (!ast.isHttpOperationNode(node)) return null
const { config, driver, resolver, root } = ctx
const { output, query, mutation, client, group, customOptions, hooks } = ctx.options
const { output, query, client, group, customOptions, hooks } = ctx.options

const pluginTs = driver.getPlugin(pluginTsName)
if (!pluginTs) return null
const tsResolver = driver.getResolver(pluginTsName)

const { isQuery, isMutation } = classifyOperation(node, { query, mutation })

if (!isQuery || isMutation) return null

const importPath = query ? query.importPath : '@tanstack/react-query'

// The registered contract client plugin owns the `<op>` the hook imports and calls.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,30 @@ import type { PluginReactQuery } from '../types'
export const suspenseInfiniteQueryGenerator = defineGenerator<PluginReactQuery>({
name: 'react-suspense-infinite-query',
renderer: jsxRenderer,
match(node, ctx) {
const operationNode = node as ast.OperationNode
if (!ast.isHttpOperationNode(operationNode)) return false
const { query, mutation, infinite, suspense, hooks } = ctx.options

const { isQuery, isMutation } = classifyOperation(operationNode, { query, mutation })
const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : null
if (!isQuery || isMutation || !suspense || !infiniteOptions || !hooks) return false

// Validate queryParam exists in operation's query parameters, optional or not
const queryParamKeys = getOperationParameters(operationNode).query.map((p) => p.name)
return infiniteOptions.queryParam ? queryParamKeys.includes(infiniteOptions.queryParam) || queryParamKeys.includes(`${infiniteOptions.queryParam}?`) : false
},
operation(node, ctx) {
if (!ast.isHttpOperationNode(node)) return null
const { config, driver, resolver, root } = ctx
const { output, query, mutation, infinite, suspense, client, group, customOptions, hooks } = ctx.options
const { output, query, infinite, client, group, customOptions } = ctx.options

const pluginTs = driver.getPlugin(pluginTsName)
if (!pluginTs) return null
const tsResolver = driver.getResolver(pluginTsName)

const { isQuery, isMutation } = classifyOperation(node, { query, mutation })
const isSuspense = !!suspense
const infiniteOptions = infinite && typeof infinite === 'object' ? infinite : null

if (!isQuery || isMutation || !isSuspense || !infiniteOptions || !hooks) return null

// Validate queryParam exists in operation's query parameters
const normalizeKey = (key: string) => key.replace(/\?$/, '')
const queryParamKeys = getOperationParameters(node).query.map((p) => p.name)
const hasQueryParam = infiniteOptions.queryParam ? queryParamKeys.some((k) => normalizeKey(k) === infiniteOptions.queryParam) : false
if (!hasQueryParam) return null
if (!infiniteOptions) return null

const importPath = query ? query.importPath : '@tanstack/react-query'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,22 @@ import type { PluginReactQuery } from '../types'
export const suspenseQueryGenerator = defineGenerator<PluginReactQuery>({
name: 'react-suspense-query',
renderer: jsxRenderer,
match(node, ctx) {
const operationNode = node as ast.OperationNode
if (!ast.isHttpOperationNode(operationNode)) return false
const { query, mutation, suspense, hooks } = ctx.options
const { isQuery, isMutation } = classifyOperation(operationNode, { query, mutation })
return isQuery && !isMutation && !!suspense && hooks
},
operation(node, ctx) {
if (!ast.isHttpOperationNode(node)) return null
const { config, driver, resolver, root } = ctx
const { output, query, mutation, suspense, client, group, customOptions, hooks } = ctx.options
const { output, query, client, group, customOptions } = ctx.options

const pluginTs = driver.getPlugin(pluginTsName)
if (!pluginTs) return null
const tsResolver = driver.getResolver(pluginTsName)

const { isQuery, isMutation } = classifyOperation(node, { query, mutation })
const isSuspense = !!suspense

if (!isQuery || isMutation || !isSuspense || !hooks) return null

const importPath = query ? query.importPath : '@tanstack/react-query'

// The registered contract client plugin owns the `<op>` the hook imports and calls.
Expand Down
Loading
Loading