feat(plugin-react-query): add pathParamsAsGetters option#139
Open
efpatti wants to merge 6 commits into
Open
Conversation
Both plugin-vue-query and plugin-react-query need to walk a FunctionParametersNode and rewrite parameter types with an outer wrapper. The two operations are framework-agnostic at the AST level — only the wrapper string and the per-param predicate differ. Lifts them into @internals/tanstack-query so future plugins (and the existing ones, in follow-up commits) can share the primitive. No consumers updated in this commit.
Drops five local printType copies and three local wrapOperationParamsWithMaybeRef variants across Query, QueryOptions, InfiniteQuery, QueryKey, and Mutation in favour of a single transformParamTypes call from @internals/tanstack-query. The hardcoded "skip 'options' / 'config'" branch is now expressed as the shouldWrap predicate. Net: 173 lines removed, 24 added. All snapshots remain byte-identical — pure refactor with zero behavior change.
Widens generated useQuery path-param signatures to \`T | (() => T) | undefined\` so callers can pass either the value or a zero-arg getter. Inside the hook body, each path param is unwrapped once via \`typeof v === 'function' ? v() : v\` before it is forwarded to queryKey() and queryOptions(). Reactive frameworks (Svelte 5 \$state, Solid signals, MobX observables) compile-warn when a reactive value is captured into a closure that reads it only at init. The getter form keeps the read inside a closure that re-evaluates on each access. Implementation uses the transformParamTypes helper introduced in @internals/tanstack-query (same primitive plugin-vue-query uses). Defaults to false; output is byte-identical to before when omitted. Scope: useQuery only — suspense, infinite, and mutation are untouched.
… harden coverage Addresses review feedback before opening the upstream PR: - Make `pathParamNames` optional in the `getParams` options object (defaults to an empty set). The previous required field broke external consumers of the public `Query.getParams` export when they upgraded without supplying the new field. - Add a snapshot case for `pathParamsAsGetters: true` on an operation with no path params (`findByTags`). Verified byte-identical to the baseline `findByTags` snapshot, pinning the no-op short-circuit. - Add a snapshot case for `pathParamsAsGetters: true` paired with `paramsType: 'object'` (everything-in-one-object form). Exercises the rewriter against shorthand inside the unified-object call expression. - Add a changeset entry for `@kubb/plugin-vue-query` (patch) so the internal refactor that drops the local `wrapOperationParamsWithMaybeRef` and `printType` copies in favour of the shared helper is visible in the release notes.
…rewriter
Three optional follow-ups to the original feature:
- Add a snapshot case for an operation with two path params
(\`GET /user/{userId}/pet/{petId}\`). Exercises the prelude emitting
multiple unwrap lines and the rewriter substituting both names in
the queryKey/queryOptions call expressions.
- Fix a latent bug in \`buildArgRewriter\`'s shorthand expansion: the
previous regex matched on top-level commas as well, which made the
multi-path-param inline call \`(userId, petId, config)\` produce the
syntactically invalid \`(userId_, petId: petId_, config)\`. Step 1
is now scoped to occurrences inside \`{...}\` blocks, so function
argument commas no longer trigger shorthand expansion.
- Defensive coding: escape regex metacharacters in path-param names
before interpolating them into the rewriter's regexes. Today path
param names come through \`ast.caseParams\` and are always valid
identifiers, but the escape guards against future shape changes.
- Add direct unit tests for \`printType\` and \`transformParamTypes\` in
\`@internals/tanstack-query\`. Previously these helpers were only
covered transitively via the Vue and React plugin snapshots; the
new tests let the helpers be evolved or refactored in isolation
without waiting on plugin-level test runs.
🦋 Changeset detectedLatest commit: 209c97d The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
|
@copilot resolve the merge conflicts in this pull request |
Author
Hi buddy! I’ll resolve them manually to avoid breaking snapshots/shared generator logic, then rerun tests before pushing. |
- Adopt upstream's queryKeyTransformer / buildQueryKeyParams API - Migrate generator destructuring to ctx.inputNode - Drop vue-query transformParamTypes refactor (upstream kept local helper) - Preserve pathParamsAsGetters option, helpers, and test cases
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tracks #140
🎯 Changes
Adds an opt-in
pathParamsAsGetters: booleanoption to@kubb/plugin-react-querythat widens generateduseQuerypath-param signatures so callers can pass either a value or a zero-arg getter (T | (() => T) | undefined). Inside the hook body, each path param is unwrapped once viatypeof v === 'function' ? v() : vbefore it is forwarded toqueryKey(...)andqueryOptions(...).Motivation: reactive frameworks where reading a value at hook-call time captures only the initial snapshot warn or silently break with the current path-param-by-value shape — Svelte 5
$state(which emitsstate_referenced_locally), Solid signals, MobX observables, Preact signals, and similar. The getter form keeps the read inside a closure that re-evaluates on each access.plugin-react-query)pathParamsAsGetters?: boolean(defaultfalse, non-breaking).typeofcheck per hook call.useQueryonly. Suspense, infinite, and mutation hooks are intentionally untouched (happy to extend in a follow-up).@internals/tanstack-query)printTypeandtransformParamTypes. The two operations are framework-agnostic at the AST level — only the wrapper string and the per-param predicate differ between plugins.plugin-vue-query)printTypeand 3 variants ofwrapOperationParamsWithMaybeRefacrossQuery,QueryOptions,InfiniteQuery,QueryKey, andMutationin favour of the sharedtransformParamTypeshelper.queryGenerator.test.tsx: inline path-param,pathParamsType: 'object',paramsType: 'object', multi-path-param (GET /user/{userId}/pet/{petId}), and one byte-identical guard for an operation with no path params.printTypeandtransformParamTypesin@internals/tanstack-queryso the shared helpers are covered independently of the consuming plugins.Query.getParamssignature:pathParamNamesis optional with a default of an empty set.queryKey/queryOptionscall expressions scopes shorthand expansion to{...}blocks so it does not misfire on function-argument commas (caught by the multi-path-param snapshot).## pathParamsAsGetterssection inpackages/plugin-react-query/README.mdwith before/after example, motivation, and scope notes.pnpm formatclean (oxfmt).pnpm lint0/0 (oxlint).pnpm typecheck13 packages green.pnpm test849 passed / 54 files (840 existing + 9 new).pnpm changeset statusrecognises both entries.✅ Checklist
pnpm run test.🚀 Release Impact