Skip to content

feat(router-core): pass the param key to search parse/stringify callbacks#7568

Open
icholy wants to merge 1 commit into
TanStack:mainfrom
icholy:search-param-key
Open

feat(router-core): pass the param key to search parse/stringify callbacks#7568
icholy wants to merge 1 commit into
TanStack:mainfrom
icholy:search-param-key

Conversation

@icholy
Copy link
Copy Markdown

@icholy icholy commented Jun 6, 2026

Update parseSearchWith and stringifySearchWith to pass the param's key as a second argument to the parsing callbacks. This allows individual params to be serialized differently.

The problem

I have a numeric org param in my code which I didn't want to be escaped, so ?org=1 rather than the default's JSON-quoted ?org=%221%22. This was my first pass:

import { defaultParseSearch, defaultStringifySearch } from '@tanstack/react-router'

const router = createRouter({
  // ...
  parseSearch: (searchStr) => {
    const parsed = defaultParseSearch(searchStr)
    if ('org' in parsed) {
      parsed.org = String(parsed.org)
    }
    return parsed
  },
  stringifySearch: (search) => {
    const { org, ...rest } = search
    const base = defaultStringifySearch(rest)
    if (org == null) {
      return base
    }
    return `${base}${base ? '&' : '?'}org=${encodeURIComponent(String(org))}`
  },
})

With this change

I figured it would make more sense for this to be directly supported.

import {
  createRouter,
  parseSearchWith,
  stringifySearchWith,
} from '@tanstack/react-router'

const router = createRouter({
  // ...
  parseSearch: parseSearchWith((value, key) =>
    key === 'org' ? value : JSON.parse(value),
  ),
  stringifySearch: stringifySearchWith(
    (value, key) => (key === 'org' ? String(value) : JSON.stringify(value)),
    (value) => JSON.parse(value),
  ),
})

Summary by CodeRabbit

  • New Features

    • Search parameter serialization now supports per-parameter customization so different keys can use different parsing/encoding behavior.
  • Documentation

    • Guides updated with examples showing how to handle custom parsing/stringifying per search parameter.
  • Tests

    • New tests added to verify per-key parsing/serialization behavior and key-aware encoding.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 6, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9002756-525f-417e-8590-011b56ce8d99

📥 Commits

Reviewing files that changed from the base of the PR and between c3a2398 and 3b4a42c.

📒 Files selected for processing (6)
  • .changeset/search-param-key.md
  • docs/router/guide/custom-search-param-serialization.md
  • packages/router-core/src/qss.ts
  • packages/router-core/src/searchParams.ts
  • packages/router-core/tests/qss.test.ts
  • packages/router-core/tests/searchParams.test.ts
✅ Files skipped from review due to trivial changes (2)
  • .changeset/search-param-key.md
  • packages/router-core/tests/qss.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/router-core/src/qss.ts
  • packages/router-core/tests/searchParams.test.ts
  • docs/router/guide/custom-search-param-serialization.md
  • packages/router-core/src/searchParams.ts

📝 Walkthrough

Walkthrough

Query string encoding and search parameter parsing/stringification now pass the parameter key to callbacks. qss.encode and parseSearchWith/stringifySearchWith signatures were updated, tests verify per-key behavior and round-trip correctness, and docs/examples were updated to show key-aware usage.

Changes

Key-Aware Search Parameter Callbacks

Layer / File(s) Summary
Query String Encoder Key Support
packages/router-core/src/qss.ts, packages/router-core/tests/qss.test.ts
The encode function's stringify callback signature changes to (value, key) => string; URLSearchParams population passes the key. Test verifies the key is received by the callback.
Search Parameters API Key Support
packages/router-core/src/searchParams.ts, packages/router-core/tests/searchParams.test.ts
parseSearchWith and stringifySearchWith callbacks now receive (str, key) and (search, key) respectively. defaultParseSearch and defaultStringifySearch were updated to use the new callback shapes. Tests validate key-special-casing (e.g., q) and round-trip parsing/stringifying.
Docs and Changeset
docs/router/guide/custom-search-param-serialization.md, .changeset/search-param-key.md
Documentation examples (React and Solid) updated to show key-aware parse/stringify callbacks that treat q as a literal string while JSON-handling other keys. Changeset notes the callback signature change.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

package: router-core, documentation

Suggested reviewers

  • chorobin

Poem

🐰 I hop through keys with gentle cheer,
Each param told its name so clear.
q stays plain, the others play,
Parse and stringify the TanStack way —
A tiny rabbit clap! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: updating search param callbacks to receive the parameter key as an argument for per-key serialization control.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/router-core/tests/searchParams.test.ts (1)

107-121: 💤 Low value

Minor inconsistency in parameter naming.

On Line 114, the parser callback in stringifySearchWith uses a single-parameter signature (value) => JSON.parse(value), while the stringify callback above uses the new two-parameter signature. This is functionally correct (TypeScript allows this), but for clarity and consistency with the new API, consider using (value, key) => JSON.parse(value) to make it explicit that the key is available but ignored.

✨ Optional consistency improvement
     const stringify = stringifySearchWith(
       (value, key) => (key === 'q' ? String(value) : JSON.stringify(value)),
-      (value) => JSON.parse(value),
+      (value, key) => JSON.parse(value),
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/tests/searchParams.test.ts` around lines 107 - 121, The
two callbacks passed to stringifySearchWith should use the same two-parameter
signature for consistency: change the second parser callback from a single-arg
form to a two-arg form so it matches the first callback and the new API (i.e.,
update the second argument passed to stringifySearchWith to a function with
parameters (value, key) that calls JSON.parse(value)); this keeps
parseSearchWith and stringifySearchWith usage consistent and makes the unused
key explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/router-core/tests/searchParams.test.ts`:
- Around line 107-121: The two callbacks passed to stringifySearchWith should
use the same two-parameter signature for consistency: change the second parser
callback from a single-arg form to a two-arg form so it matches the first
callback and the new API (i.e., update the second argument passed to
stringifySearchWith to a function with parameters (value, key) that calls
JSON.parse(value)); this keeps parseSearchWith and stringifySearchWith usage
consistent and makes the unused key explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a0179c9a-4569-4a8a-abce-4f356865c85a

📥 Commits

Reviewing files that changed from the base of the PR and between 757d433 and c3a2398.

📒 Files selected for processing (5)
  • docs/router/guide/custom-search-param-serialization.md
  • packages/router-core/src/qss.ts
  • packages/router-core/src/searchParams.ts
  • packages/router-core/tests/qss.test.ts
  • packages/router-core/tests/searchParams.test.ts

@icholy icholy changed the title feat(router-core): pass the param key to search parse/stringify callacks feat(router-core): pass the param key to search parse/stringify callbacks Jun 6, 2026
@icholy icholy force-pushed the search-param-key branch from c3a2398 to 3b4a42c Compare June 6, 2026 23:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant