-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat(router-generator): allow escaping any special string in file-based routing #6156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ed routing
This change extends the router-generator's escaping mechanism to allow ANY
special string to be escaped using square bracket syntax, not just dots.
## Problem
Previously, the router-generator only supported escaping dots using [.]
syntax (e.g., script[.]js.tsx -> /script.js). However, special strings
like 'index', 'route', 'lazy', and underscores ('_') could not be escaped,
making it impossible to create routes with literal paths like /index,
/route, /lazy, or paths containing literal underscores.
## Solution
Extended the escaping mechanism to support:
1. **Escaped special suffixes**: [index], [route], [lazy], [component], etc.
- [index].tsx -> /index (literal path, NOT treated as index route)
- [route].tsx -> /route (literal path, NOT treated as layout config)
- [lazy].tsx -> /lazy (literal path, NOT treated as lazy-loaded route)
2. **Escaped underscores in any position**:
- Leading: [_]layout.tsx -> /_layout (literal, NOT pathless layout)
- Trailing: blog[_].tsx -> /blog_ (literal, NOT escaping parent layout)
- Middle: foo[_]bar.tsx -> /foo_bar (literal underscore preserved)
- Multiple: api[_]v2[_]users.tsx -> /api_v2_users
- Fully escaped: [_prefix_middle_suffix].tsx -> /_prefix_middle_suffix
3. **Custom token escaping**: Works with custom indexToken and routeToken
- [_1nd3x].tsx with indexToken='_1nd3x' -> /_1nd3x (literal path)
- posts.[_r0ut3_].tsx with routeToken='_r0ut3_' -> /posts/_r0ut3_
## Implementation Details
### src/utils.ts
- Removed '_' from DISALLOWED_ESCAPE_CHARS to allow underscore escaping
- Added isSegmentEscaped() to check if a segment was bracket-escaped
- Added hasEscapedLeadingUnderscore() to detect [_] prefix or [_...] patterns
- Added hasEscapedTrailingUnderscore() to detect [_] suffix or [..._] patterns
- Added removeUnderscoresWithEscape() to preserve escaped underscores
- Added removeLayoutSegmentsWithEscape() to preserve escaped layout segments
- Added isSegmentPathless() to check for non-escaped leading underscores
- Updated inferFullPath() to use escape-aware functions
### src/filesystem/physical/getRouteNodes.ts
- Added escape checking for special suffixes (route, lazy, component, etc.)
- Updated isValidPathlessLayoutRoute() to check for escaped underscores
- Updated getRouteMeta() to accept originalRoutePath and check escaping
### src/generator.ts
- Updated handleNode() to use escape-aware path processing functions
- Compute trimmedOriginalPath alongside trimmedPath for escape detection
## Tests Added
- escaped-special-strings: Tests escaping of index, route, lazy, and
underscores in various positions (leading, trailing, middle, multiple)
- escaped-custom-tokens: Tests escaping with custom indexToken and
routeToken configurations
WalkthroughPropagates original (pre-normalized) route paths and adds escape-aware utilities so escaped underscores/brackets are treated as literal segments during route-type detection and path normalization. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Gen as Generator
participant Utils as Utils
participant FS as getRouteNodes
Gen->>Utils: removeLayoutSegmentsWithEscape(routePath, originalRoutePath)
Gen->>Utils: removeUnderscoresWithEscape(cleanedPath, originalRoutePath)
Gen->>Utils: isSegmentPathless(segment, originalSegment)
Gen->>FS: build node(routePath, originalRoutePath, config)
FS->>Utils: hasEscapedLeadingUnderscore(originalSegment)
FS->>Utils: check escaped suffixes / isFullyEscapedSegment(originalSegment)
FS-->>Gen: node metadata (routeType, normalized paths)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
View your CI Pipeline Execution ↗ for commit f1256b3
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx (1)
1-4: Route definition correctly demonstrates escaped underscores.The route path
'/_prefix_middle_suffix'accurately reflects the expected behavior where[_]in the filename produces literal underscores in the generated path. The implementation aligns with the PR's escaped-special-strings feature.However, the
@ts-nocheckdirective on line 2 disables TypeScript checking for the entire file, which contradicts the coding guideline to use TypeScript strict mode with extensive type safety. As per coding guidelines, TypeScript strict mode should be used for all.tsand.tsxfiles.Consider removing @ts-nocheck if not required
If the directive is necessary for this test fixture, please add a comment explaining why. Otherwise, consider removing it:
import { createFileRoute } from '@tanstack/react-router' -// @ts-nocheck // This should be a literal /_prefix_middle_suffix path with underscores everywhere export const Route = createFileRoute('/_prefix_middle_suffix')()packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx (1)
2-2: Consider removing@ts-nocheckto maintain type safety.The code in this file appears straightforward and type-safe. Unless there's a specific reason requiring disabled type checking, removing this directive would align with the coding guidelines requiring TypeScript strict mode with extensive type safety.
As per coding guidelines, TypeScript files should use strict mode with extensive type safety.
packages/router-generator/src/filesystem/physical/getRouteNodes.ts (1)
231-256: Consider escapingconfig.indexTokenin the regex patterns.While the static analysis ReDoS warnings are likely false positives for typical usage (since
indexTokenis usually a simple string like"index"), user-provided configuration values are used directly innew RegExp(). If a user sets an unusualindexTokencontaining regex metacharacters, it could cause unexpected behavior.The
escapeRegExputility already exists in this file (used forrouteTokenelsewhere). Consider applying it here for consistency and defense-in-depth.🔎 Proposed fix
+ const escapedIndexToken = escapeRegExp(config.indexToken) + if (!isIndexEscaped) { if (routePath === config.indexToken) { routePath = '/' } if (originalRoutePath === config.indexToken) { originalRoutePath = '/' } routePath = - routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || + routePath.replace(new RegExp(`/${escapedIndexToken}$`), '/') || '/' originalRoutePath = originalRoutePath.replace( - new RegExp(`/${config.indexToken}$`), + new RegExp(`/${escapedIndexToken}$`), '/', ) || '/' }Note: You'll need to either import
escapeRegExpfrom utils or define it locally if not already available in scope.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (24)
packages/router-generator/src/filesystem/physical/getRouteNodes.ts(9 hunks)packages/router-generator/src/generator.ts(4 hunks)packages/router-generator/src/utils.ts(4 hunks)packages/router-generator/tests/generator.test.ts(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx(1 hunks)packages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx(1 hunks)packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/src/generator.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/src/generator.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
🧠 Learnings (13)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/src/generator.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-12-17T02:17:55.086Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/src/generator.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/src/generator.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-09-22T00:56:49.237Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/src/generator.tspackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-09-22T00:56:53.426Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/src/generator.tspackages/router-generator/src/filesystem/physical/getRouteNodes.tspackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/src/utils.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/src/generator.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/src/filesystem/physical/getRouteNodes.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
Repo: TanStack/router PR: 5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsxpackages/router-generator/tests/generator.test.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Applied to files:
packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsxpackages/router-generator/tests/generator/escaped-special-strings/routes/index.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsxpackages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.tspackages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsxpackages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
📚 Learning: 2025-12-17T02:17:47.423Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:47.423Z
Learning: In packages/router-generator/src/generator.ts, enforce that pathless_layout routes with a cleanedPath must have a path property. This is required because child routes inherit the parent's path; without a path property, the full path will not resolve correctly at runtime. Update the route type/validation to require path for such routes and add tests ensuring that a pathless_layout with cleanedPath provides a valid fullPath resolution.
Applied to files:
packages/router-generator/src/generator.ts
📚 Learning: 2025-12-16T02:59:11.506Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6104
File: packages/start-plugin-core/tests/split-exports-plugin/snapshots/exports/functionExports.ts:1-1
Timestamp: 2025-12-16T02:59:11.506Z
Learning: In transformation test snapshots (e.g., split-exports plugin), comments at the top of snapshot files often describe the original input scenario being tested (e.g., "Multiple function exports") rather than the transformed output in the snapshot itself. This helps document what transformation is being validated.
Applied to files:
packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
🧬 Code graph analysis (13)
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsx (7)
packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx (12)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx (1)
Route(3-3)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx (1)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx (2)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx (1)
packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx (1)
Route(2-2)
packages/router-generator/src/generator.ts (2)
packages/router-generator/src/utils.ts (6)
trimPathLeft(128-130)isSegmentPathless(462-468)removeGroups(594-596)removeUnderscoresWithEscape(382-416)removeLayoutSegmentsWithEscape(426-452)removeLastSegmentFromPath(632-636)packages/router-core/src/path.ts (1)
trimPathLeft(29-31)
packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx (1)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx (1)
Route(2-2)
packages/router-generator/src/filesystem/physical/getRouteNodes.ts (1)
packages/router-generator/src/utils.ts (1)
hasEscapedLeadingUnderscore(258-276)
packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx (8)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx (1)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx (9)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx (1)
Route(4-4)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx (2)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx (1)
Route(4-4)packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
Route(4-4)
🪛 ast-grep (0.40.0)
packages/router-generator/src/filesystem/physical/getRouteNodes.ts
[warning] 223-223: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(/${suffixToStrip}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 225-225: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(/${suffixToStrip}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 247-247: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(/${config.indexToken}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 252-252: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(/${config.indexToken}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🪛 Biome (2.1.2)
packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
[error] 129-129: This property is later overwritten by an object member with the same name.
Overwritten with this property.
If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property.
(lint/suspicious/noDuplicateObjectKeys)
[error] 14-14: Shouldn't redeclare 'R1nd3xRouteImport'. Consider to delete it or rename it.
'R1nd3xRouteImport' is defined here:
(lint/suspicious/noRedeclare)
[error] 28-28: Shouldn't redeclare 'R1nd3xRoute'. Consider to delete it or rename it.
'R1nd3xRoute' is defined here:
(lint/suspicious/noRedeclare)
packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
[error] 259-259: This property is later overwritten by an object member with the same name.
Overwritten with this property.
If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property.
(lint/suspicious/noDuplicateObjectKeys)
[error] 21-21: Shouldn't redeclare 'IndexRouteImport'. Consider to delete it or rename it.
'IndexRouteImport' is defined here:
(lint/suspicious/noRedeclare)
[error] 69-69: Shouldn't redeclare 'IndexRoute'. Consider to delete it or rename it.
'IndexRoute' is defined here:
(lint/suspicious/noRedeclare)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Test
- GitHub Check: Preview
🔇 Additional comments (33)
packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx (1)
3-4: LGTM! Test correctly validates custom indexToken behavior.The route definition correctly tests that
_1nd3x(without brackets) is treated as a custom indexToken and produces the root path/, contrasting with the escaped version[_1nd3x].tsxwhich produces the literal path/_1nd3x.packages/router-generator/tests/generator/escaped-custom-tokens/routes/posts.[_r0ut3_].tsx (1)
1-4: LGTM!The test fixture correctly demonstrates escaped custom routeToken behavior. The file produces a literal
/posts/_r0ut3_path segment instead of treating_r0ut3_as a layout configuration token.packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx (1)
1-4: LGTM!The test fixture correctly demonstrates non-escaped custom routeToken behavior. The unescaped
_r0ut3_suffix creates a pathless layout configuration for/blog, contrasting with the escaped version inposts.[_r0ut3_].tsx.packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx (1)
1-4: LGTM!The test fixture correctly demonstrates escaped custom indexToken behavior. The file produces a literal
/nested/_1nd3xpath instead of treating_1nd3xas an index route indicator.packages/router-generator/tests/generator.test.ts (1)
78-81: LGTM!The configuration correctly mirrors the
custom-tokenscase to test escaped token behavior. Both cases use the same custom token values (_1nd3xand_r0ut3_), but the test fixtures in theescaped-custom-tokensfolder use bracket-escaped filenames to verify that escaped tokens are treated as literal path segments.packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx (1)
1-4: LGTM!The test fixture correctly demonstrates escaped underscore behavior in the middle position. The file produces a literal
/foo_barpath with the underscore preserved, aligning with the PR's objective to support escaped underscores in any position.packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx (1)
1-4: LGTM!The test fixture correctly demonstrates the interaction between escaped underscores and special suffixes. The escaped
[_]produces a literal leading underscore in the path/_auth, while the.routesuffix is still honored as a layout configuration indicator.packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx (1)
1-4: LGTM!The test fixture correctly demonstrates escaped special suffix behavior. The escaped
[lazy]produces a literal/lazypath instead of being treated as a lazy-loading indicator, aligning with the PR's objective to allow escaping of any special string.packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx (1)
1-2: Critical: Missing import forcreateRootRoute.The file references
createRootRoutewithout importing it, which will cause aReferenceErrorat runtime. All other test fixture files in this suite include the necessary import statement.🔎 Proposed fix
+import { createRootRoute } from '@tanstack/react-router' // @ts-nocheck export const Route = createRootRoute()⛔ Skipped due to learnings
Learnt from: nlynzaad Repo: TanStack/router PR: 5402 File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21 Timestamp: 2025-10-08T08:11:47.088Z Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.Learnt from: nlynzaad Repo: TanStack/router PR: 5732 File: packages/start-client-core/src/client/hydrateStart.ts:6-9 Timestamp: 2025-11-02T16:16:24.898Z Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.Learnt from: schiller-manuel Repo: TanStack/router PR: 6120 File: packages/router-generator/src/generator.ts:654-657 Timestamp: 2025-12-17T02:17:55.086Z Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.Learnt from: schiller-manuel Repo: TanStack/router PR: 5330 File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61 Timestamp: 2025-10-01T18:31:35.420Z Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.Learnt from: CR Repo: TanStack/router PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T15:03:07.223Z Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin routerpackages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx (1)
1-4: Test fixture correctly demonstrates escaped index token behavior.The file properly imports the necessary function, includes an explanatory comment, and defines a route with the literal path '/index' rather than treating it as an index route. This aligns with the PR's goal of supporting escaped special strings.
packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx (1)
1-3: LGTM!This test fixture correctly represents the standard (non-escaped) index route with path '/'. It provides a useful contrast to the escaped [index].tsx file, helping verify the generator distinguishes between escaped and non-escaped tokens.
packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx (1)
1-4: LGTM!This test fixture correctly demonstrates escaped custom indexToken behavior. The literal path '/_1nd3x' will verify that the generator properly handles escaped custom tokens rather than treating them as special framework tokens.
packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx (1)
1-4: LGTM!This test fixture correctly verifies that an escaped leading underscore produces a literal '/_layout' path rather than being treated as a pathless layout. The clear comment helps document the expected behavior.
packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx (1)
1-4: LGTM!This test fixture correctly demonstrates that the escaped 'route' token produces a literal '/route' path rather than being treated as a layout configuration file. This aligns with the PR's goal of allowing any special string to be escaped.
packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx (1)
1-4: LGTM!This test fixture effectively demonstrates the handling of multiple escaped underscores within a path segment. The literal path '/api_v2_users' verifies that the generator preserves underscores in multiple middle positions, which is a key feature of this PR.
packages/router-generator/tests/generator/escaped-special-strings/routes/blog[_].tsx (1)
1-4: LGTM!This test fixture correctly demonstrates escaped trailing underscore behavior. The literal path '/blog_' verifies that the generator preserves trailing underscores when escaped, which aligns with the PR's goal of supporting escaped underscores in any position (leading, trailing, middle, and multiple).
Based on learnings, underscores have historically had special meaning in TanStack Router path handling, so this test is valuable for ensuring the escape mechanism works correctly.
packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx (1)
1-2: Missing import forcreateRootRoute.The file uses
createRootRoute()without importing it, which will cause a runtime error.🔎 Proposed fix
+import { createRootRoute } from '@tanstack/react-router' // @ts-nocheck export const Route = createRootRoute()⛔ Skipped due to learnings
Learnt from: nlynzaad Repo: TanStack/router PR: 5402 File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21 Timestamp: 2025-10-08T08:11:47.088Z Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.Learnt from: nlynzaad Repo: TanStack/router PR: 5732 File: packages/start-client-core/src/client/hydrateStart.ts:6-9 Timestamp: 2025-11-02T16:16:24.898Z Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.Learnt from: CR Repo: TanStack/router PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T15:03:07.223Z Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin routerLearnt from: schiller-manuel Repo: TanStack/router PR: 5330 File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61 Timestamp: 2025-10-01T18:31:35.420Z Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.Learnt from: schiller-manuel Repo: TanStack/router PR: 6120 File: packages/router-generator/src/generator.ts:654-657 Timestamp: 2025-12-17T02:17:55.086Z Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.packages/router-generator/src/utils.ts (7)
143-160: LGTM!The
DISALLOWED_ESCAPE_CHARSconstant is well-documented and includes all security-relevant characters that should not be allowed in bracket escapes (path separators, URL special chars, filesystem reserved chars).
207-250: LGTM!The
isSegmentEscapedfunction correctly handles three escape patterns:
- Fully escaped segments:
[index]→index- Leading underscore escape:
[_]foo→_foo- Trailing underscore escape:
foo[_]→foo_The documentation is clear with good examples.
252-302: LGTM!Both
hasEscapedLeadingUnderscoreandhasEscapedTrailingUnderscorecorrectly detect:
- Partial escape patterns (
[_]layout,blog[_])- Fully escaped segments that happen to start/end with underscore (
[_1nd3x],[_r0ut3_])The nested bracket check (
!slice(1, -1).includes('[')) prevents false positives from complex patterns.
374-416: LGTM!The
removeUnderscoresWithEscapefunction correctly preserves underscores that were escaped while removing non-escaped leading/trailing underscores. The segment-by-segment processing with index alignment tooriginalSegmentsis the right approach.
418-452: LGTM!The
removeLayoutSegmentsWithEscapefunction correctly filters out layout segments (those starting with_) while preserving segments where the underscore was escaped. The index-based lookup tooriginalSegmentsduring filtering is correct.
454-468: LGTM!The
isSegmentPathlessfunction provides a clean abstraction for determining if a segment should be treated as pathless, delegating tohasEscapedLeadingUnderscorefor escape detection.
692-704: LGTM!The
inferFullPathfunction now correctly uses the escape-aware variants, passingrouteNode.originalRoutePathto bothremoveLayoutSegmentsWithEscapeandremoveUnderscoresWithEscape. This ensures escaped underscores are preserved in the final path.packages/router-generator/src/filesystem/physical/getRouteNodes.ts (4)
5-5: LGTM!The import of
hasEscapedLeadingUnderscorefrom utils is correctly added to support escape-aware pathless layout detection.
200-229: LGTM!The escape-aware suffix handling correctly identifies the last segment from
originalRoutePathand only strips special suffixes when they are not escaped (wrapped in brackets). This enables files like[lazy].tsxto produce literal/lazypaths.
309-383: LGTM!The
getRouteMetafunction is cleanly updated to:
- Accept
originalRoutePathparameter- Extract the last segment for escape checking
- Use
isSuffixEscapedhelper to verify each suffix before assigning route typesThis ensures escaped special tokens (e.g.,
[lazy].tsx,[route].tsx) produce literal path segments instead of triggering special route type handling.
393-448: LGTM!The
isValidPathlessLayoutRoutefunction correctly integrates escape awareness:
- Uses
hasEscapedLeadingUnderscoreto check both the last and second-to-last original segments- Returns
falsefor escaped underscores, treating them as literal path segments- Maintains correct behavior for non-escaped pathless layout routes
packages/router-generator/src/generator.ts (3)
31-42: LGTM!The imports correctly add the new escape-aware utilities (
isSegmentPathless,removeLayoutSegmentsWithEscape,removeUnderscoresWithEscape) and remove the non-escape-aware versions from the import list.
1367-1391: LGTM!The escape-aware path processing is well-implemented:
trimmedOriginalPathcorrectly computes the original path relative to the parentlastOriginalSegmentextraction enables escape detection for the final segmentisNonPathnow correctly usesisSegmentPathlessto check if the underscore is escapedcleanedPathuses the escape-aware variants to preserve literal underscoresThis ensures files like
[_]layout.tsxproduce/_layoutpaths instead of being treated as pathless layouts.
1449-1481: LGTM!The pathless layout special handling correctly mirrors the main path processing:
immediateParentOriginalPathis computed for escape-aware ancestor lookuporiginalPathRelativeToParentis derived when finding the nearest real parent- The
cleanedPathcomputation uses escape-aware functions with the proper original path contextThis maintains consistency between the two code paths and ensures escaped underscores are preserved in all scenarios.
packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts (1)
12-14: This is a snapshot file that tests the router-generator's output. Per established guidelines, snapshot files inpackages/router-generator/tests/generator/are fixtures and should not be flagged for issues, as they intentionally preserve the generator's output exactly as produced for verification purposes.packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts (1)
12-21: This is a test snapshot fixture and should not be reviewed for code issues. Snapshot files inpackages/router-generator/tests/generator/**/routeTree*.snapshot.tsare fixtures used to verify generator output and are intentionally preserved as-is.
| import { createFileRoute } from '@tanstack/react-router' | ||
| // @ts-nocheck |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move @ts-nocheck directive to the top of the file.
The @ts-nocheck directive must be placed at the very top of the file, before any imports or statements, to be recognized by TypeScript.
🔎 Proposed fix
-import { createFileRoute } from '@tanstack/react-router'
// @ts-nocheck
+import { createFileRoute } from '@tanstack/react-router'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { createFileRoute } from '@tanstack/react-router' | |
| // @ts-nocheck | |
| // @ts-nocheck | |
| import { createFileRoute } from '@tanstack/react-router' |
🤖 Prompt for AI Agents
In
packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
around lines 1 to 2, the @ts-nocheck directive is placed after an import so
TypeScript will ignore it; move the comment to the very first line of the file
(before any imports or code) so it is effective, i.e., remove the current line
and add the same //@ts-nocheck at the top of the file.
| import { createFileRoute } from '@tanstack/react-router' | ||
| // @ts-nocheck | ||
| // This should be /nested/index (literal), NOT treated as the index of /nested | ||
| export const Route = createFileRoute('/nested/index')() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ts-nocheck directive should be placed before any imports.
The // @ts-nocheck comment on line 2 is placed after the import statement, which means TypeScript will not recognize it as a valid directive. Move it to line 1 for it to take effect.
🔎 Proposed fix
+// @ts-nocheck
import { createFileRoute } from '@tanstack/react-router'
-// @ts-nocheck
// This should be /nested/index (literal), NOT treated as the index of /nested
export const Route = createFileRoute('/nested/index')()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { createFileRoute } from '@tanstack/react-router' | |
| // @ts-nocheck | |
| // This should be /nested/index (literal), NOT treated as the index of /nested | |
| export const Route = createFileRoute('/nested/index')() | |
| // @ts-nocheck | |
| import { createFileRoute } from '@tanstack/react-router' | |
| // This should be /nested/index (literal), NOT treated as the index of /nested | |
| export const Route = createFileRoute('/nested/index')() |
🤖 Prompt for AI Agents
packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
lines 1-4: The TypeScript directive is currently after an import so it won't be
honored; move the `// @ts-nocheck` comment to the very first line (before any
imports) so it takes effect, keeping the rest of the file unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/router-generator/src/utils.ts (1)
626-638: Critical: Segment misalignment after layout removal causes incorrect path generation.After
removeLayoutSegmentsWithEscapefilters out pathless segments, the returned path has fewer segments thanoriginalRoutePath. When this modified path is passed toremoveUnderscoresWithEscapealong with the unchangedoriginalRoutePath, the segment indices no longer align, causing escaped underscores to be incorrectly removed.Example demonstrating the bug:
Input: - routePath: "/_layout/_auth/login" - originalRoutePath: "/_layout/[_]auth/login" After removeLayoutSegmentsWithEscape("/_layout/_auth/login", "/_layout/[_]auth/login"): - Returns: "/_auth/login" (segments: ["", "_auth", "login"]) Then removeUnderscoresWithEscape("/_auth/login", "/_layout/[_]auth/login"): - routePath segments[1] = "_auth" - originalPath segments[1] = "_layout" ❌ (should be "[_]auth") - hasEscapedLeadingUnderscore("_layout") = false - Leading "_" incorrectly removed from "_auth" - Result: "/auth/login" ❌ (expected: "/_auth/login")🔧 Recommended fix
Option 1: Modify
removeLayoutSegmentsWithEscapeto return both the filteredroutePathand filteredoriginalPath:-export function removeLayoutSegmentsWithEscape( +function removeLayoutSegmentsWithEscapeInternal( routePath: string = '/', originalPath?: string, -): string { +): { routePath: string; originalPath: string } { - if (!originalPath) return removeLayoutSegments(routePath) + if (!originalPath) { + return { routePath: removeLayoutSegments(routePath), originalPath: routePath } + } const routeSegments = routePath.split('/') const originalSegments = originalPath.split('/') - const newSegments = routeSegments.filter((segment, i) => { + const newRouteSegments: string[] = [] + const newOriginalSegments: string[] = [] + + for (let i = 0; i < routeSegments.length; i++) { + const segment = routeSegments[i]! const originalSegment = originalSegments[i] || '' - return !isSegmentPathless(segment, originalSegment) - }) + if (!isSegmentPathless(segment, originalSegment)) { + newRouteSegments.push(segment) + newOriginalSegments.push(originalSegment) + } + } - return newSegments.join('/') + return { + routePath: newRouteSegments.join('/'), + originalPath: newOriginalSegments.join('/') + } } +export function removeLayoutSegmentsWithEscape( + routePath: string = '/', + originalPath?: string, +): string { + return removeLayoutSegmentsWithEscapeInternal(routePath, originalPath).routePath +} export const inferFullPath = (routeNode: RouteNode): string => { + const afterLayoutRemoval = removeLayoutSegmentsWithEscapeInternal( + routeNode.routePath, + routeNode.originalRoutePath, + ) const fullPath = removeGroups( removeUnderscoresWithEscape( - removeLayoutSegmentsWithEscape( - routeNode.routePath, - routeNode.originalRoutePath, - ), - routeNode.originalRoutePath, + afterLayoutRemoval.routePath, + afterLayoutRemoval.originalPath, ), ) return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\/$/, '') }Option 2: Combine both operations into a single escape-aware transformation function that processes both removals in one pass while maintaining alignment.
🧹 Nitpick comments (1)
packages/router-generator/src/utils.ts (1)
207-218: Consider minor optimization for readability.The function correctly identifies fully escaped segments. A small optimization would store the sliced content once instead of computing it twice:
📝 Optional refactor
function isFullyEscapedSegment(originalSegment: string): boolean { - return ( - originalSegment.startsWith('[') && - originalSegment.endsWith(']') && - !originalSegment.slice(1, -1).includes('[') && - !originalSegment.slice(1, -1).includes(']') - ) + if (!originalSegment.startsWith('[') || !originalSegment.endsWith(']')) { + return false + } + const content = originalSegment.slice(1, -1) + return !content.includes('[') && !content.includes(']') }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/router-generator/src/utils.ts(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
packages/router-generator/src/utils.ts
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
packages/router-generator/src/utils.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
📚 Learning: 2025-12-17T02:17:55.086Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
Applied to files:
packages/router-generator/src/utils.ts
📚 Learning: 2025-09-22T00:56:49.237Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Applied to files:
packages/router-generator/src/utils.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
Applied to files:
packages/router-generator/src/utils.ts
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
packages/router-generator/src/utils.ts
📚 Learning: 2025-09-22T00:56:53.426Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Applied to files:
packages/router-generator/src/utils.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
packages/router-generator/src/utils.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Test
- GitHub Check: Preview
🔇 Additional comments (5)
packages/router-generator/src/utils.ts (5)
143-160: LGTM - underscore removal enables the new escaping feature.The removal of underscore from
DISALLOWED_ESCAPE_CHARSis the key change that enables this PR's functionality, allowing paths like[_]layoutto produce/_layout. The remaining characters are appropriately restricted to prevent filesystem and URL issues.
220-246: LGTM - escape detection logic is correct.Both functions correctly identify escaped underscores using the square-bracket patterns. The logic handles both inline escapes
[_]and fully-escaped segments like[_layout].
318-360: Function logic is sound for aligned segment arrays.The function correctly preserves escaped underscores by checking the original segment's escape status before removal. The
|| ''fallback handles missing segments defensively by treating them as non-escaped.
362-386: Function works correctly but creates segment misalignment.The function correctly filters out pathless layout segments. However, it only returns the modified
routePathwhileoriginalPathremains unchanged. This creates a segment index misalignment issue when the returned path is subsequently passed to other functions that expect aligned segment arrays.See the critical issue flagged in
inferFullPathfor the impact of this design.
388-402: LGTM - pathless detection logic is correct.The function correctly identifies pathless segments by checking for non-escaped leading underscores. The logic appropriately returns
falsefor segments that don't start with underscore or have escaped underscores.
3faae7e to
20cb3f0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx (1)
9-21: Consider adding explicit return type annotation.The component logic and test structure look good. For better alignment with TypeScript strict mode guidelines, consider adding an explicit return type annotation.
🔎 Proposed refactor
-function EscapedLazyComponent() { +function EscapedLazyComponent(): JSX.Element { return ( <div> <h2 data-testid="page-title">Escaped Lazy Page</h2>As per coding guidelines, TypeScript strict mode with extensive type safety is recommended for all
.tsxfiles.e2e/react-router/escaped-special-strings/src/routes/[index].tsx (1)
9-21: Consider adding a return type annotation for stricter type safety.The component is well-structured for e2e testing with appropriate
data-testidattributes. However, per the TypeScript strict mode guidelines, consider adding an explicit return type annotation.🔎 Suggested type annotation
-function EscapedIndexComponent() { +function EscapedIndexComponent(): JSX.Element { return (As per coding guidelines, TypeScript files should use extensive type safety.
packages/router-generator/tests/utils.test.ts (1)
304-364: Excellent test coverage with minor duplication.The test suites for
hasEscapedLeadingUnderscoreandhasEscapedTrailingUnderscoreare comprehensive, covering prefix/suffix patterns, fully escaped segments, non-escaped cases, and partial escapes with nested brackets.Minor observation: The test case
[_]appears in both the "prefix/suffix pattern" and "fully escaped segment" blocks for each function (lines 308 & 315, 340 & 347). While not incorrect, these are duplicate assertions that don't add additional validation value.🔎 Optional: Remove duplicate test cases
For
hasEscapedLeadingUnderscore:it('returns true for fully escaped segment starting with underscore', () => { expect(hasEscapedLeadingUnderscore('[_layout]')).toBe(true) expect(hasEscapedLeadingUnderscore('[_foo]')).toBe(true) expect(hasEscapedLeadingUnderscore('[_1nd3x]')).toBe(true) - expect(hasEscapedLeadingUnderscore('[_]')).toBe(true) })For
hasEscapedTrailingUnderscore:it('returns true for fully escaped segment ending with underscore', () => { expect(hasEscapedTrailingUnderscore('[blog_]')).toBe(true) expect(hasEscapedTrailingUnderscore('[foo_]')).toBe(true) expect(hasEscapedTrailingUnderscore('[_r0ut3_]')).toBe(true) - expect(hasEscapedTrailingUnderscore('[_]')).toBe(true) })
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
e2e/react-router/escaped-special-strings/.gitignore(1 hunks)e2e/react-router/escaped-special-strings/index.html(1 hunks)e2e/react-router/escaped-special-strings/package.json(1 hunks)e2e/react-router/escaped-special-strings/playwright.config.ts(1 hunks)e2e/react-router/escaped-special-strings/src/main.tsx(1 hunks)e2e/react-router/escaped-special-strings/src/routeTree.gen.ts(1 hunks)e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx(1 hunks)e2e/react-router/escaped-special-strings/src/routes/[index].tsx(1 hunks)e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx(1 hunks)e2e/react-router/escaped-special-strings/src/routes/[route].tsx(1 hunks)e2e/react-router/escaped-special-strings/src/routes/__root.tsx(1 hunks)e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx(1 hunks)e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts(1 hunks)e2e/react-router/escaped-special-strings/tests/setup/global.setup.ts(1 hunks)e2e/react-router/escaped-special-strings/tests/setup/global.teardown.ts(1 hunks)e2e/react-router/escaped-special-strings/tsconfig.json(1 hunks)e2e/react-router/escaped-special-strings/vite.config.js(1 hunks)packages/router-generator/tests/utils.test.ts(3 hunks)
✅ Files skipped from review due to trivial changes (2)
- e2e/react-router/escaped-special-strings/.gitignore
- e2e/react-router/escaped-special-strings/index.html
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
e2e/react-router/escaped-special-strings/tests/setup/global.setup.tse2e/react-router/escaped-special-strings/src/routes/[_]layout.tsxe2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/src/routes/blog[_].tsxe2e/react-router/escaped-special-strings/src/routes/[route].tsxe2e/react-router/escaped-special-strings/playwright.config.tse2e/react-router/escaped-special-strings/src/main.tsxe2e/react-router/escaped-special-strings/src/routes/[index].tsxpackages/router-generator/tests/utils.test.tse2e/react-router/escaped-special-strings/tests/setup/global.teardown.tse2e/react-router/escaped-special-strings/src/routeTree.gen.tse2e/react-router/escaped-special-strings/src/routes/__root.tsx
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
e2e/react-router/escaped-special-strings/tests/setup/global.setup.tse2e/react-router/escaped-special-strings/src/routes/[_]layout.tsxe2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/src/routes/blog[_].tsxe2e/react-router/escaped-special-strings/src/routes/[route].tsxe2e/react-router/escaped-special-strings/playwright.config.tse2e/react-router/escaped-special-strings/src/main.tsxe2e/react-router/escaped-special-strings/src/routes/[index].tsxpackages/router-generator/tests/utils.test.tse2e/react-router/escaped-special-strings/tests/setup/global.teardown.tse2e/react-router/escaped-special-strings/vite.config.jse2e/react-router/escaped-special-strings/src/routeTree.gen.tse2e/react-router/escaped-special-strings/src/routes/__root.tsx
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Use workspace protocol
workspace:*for internal dependencies in package.json files
Files:
e2e/react-router/escaped-special-strings/package.json
🧠 Learnings (15)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
e2e/react-router/escaped-special-strings/tests/setup/global.setup.tse2e/react-router/escaped-special-strings/src/routes/[_]layout.tsxe2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/src/routes/blog[_].tsxe2e/react-router/escaped-special-strings/package.jsone2e/react-router/escaped-special-strings/src/routes/[route].tsxe2e/react-router/escaped-special-strings/src/main.tsxe2e/react-router/escaped-special-strings/src/routes/[index].tsxpackages/router-generator/tests/utils.test.tse2e/react-router/escaped-special-strings/tests/setup/global.teardown.tse2e/react-router/escaped-special-strings/src/routeTree.gen.tse2e/react-router/escaped-special-strings/src/routes/__root.tsx
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Applied to files:
e2e/react-router/escaped-special-strings/tests/setup/global.setup.tse2e/react-router/escaped-special-strings/tsconfig.jsone2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/package.jsone2e/react-router/escaped-special-strings/src/main.tsxe2e/react-router/escaped-special-strings/tests/setup/global.teardown.tse2e/react-router/escaped-special-strings/src/routeTree.gen.ts
📚 Learning: 2025-12-17T02:17:55.086Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
Applied to files:
e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsxe2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/src/routes/blog[_].tsxe2e/react-router/escaped-special-strings/src/routes/[route].tsxe2e/react-router/escaped-special-strings/src/routes/[index].tsxpackages/router-generator/tests/utils.test.tse2e/react-router/escaped-special-strings/src/routeTree.gen.tse2e/react-router/escaped-special-strings/src/routes/__root.tsx
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsxe2e/react-router/escaped-special-strings/tsconfig.jsone2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/src/routes/blog[_].tsxe2e/react-router/escaped-special-strings/package.jsone2e/react-router/escaped-special-strings/src/routes/[route].tsxe2e/react-router/escaped-special-strings/src/main.tsxe2e/react-router/escaped-special-strings/src/routes/[index].tsxpackages/router-generator/tests/utils.test.tse2e/react-router/escaped-special-strings/vite.config.jse2e/react-router/escaped-special-strings/src/routeTree.gen.tse2e/react-router/escaped-special-strings/src/routes/__root.tsx
📚 Learning: 2025-09-22T00:56:53.426Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Applied to files:
e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsxe2e/react-router/escaped-special-strings/src/routes/blog[_].tsxpackages/router-generator/tests/utils.test.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript strict mode with extensive type safety for all code
Applied to files:
e2e/react-router/escaped-special-strings/tsconfig.json
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
Applied to files:
e2e/react-router/escaped-special-strings/src/routes/[lazy].tsxe2e/react-router/escaped-special-strings/src/routes/blog[_].tsxe2e/react-router/escaped-special-strings/package.jsone2e/react-router/escaped-special-strings/src/routes/[route].tsxe2e/react-router/escaped-special-strings/src/main.tsxe2e/react-router/escaped-special-strings/src/routeTree.gen.ts
📚 Learning: 2025-10-09T12:59:02.129Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/src/styles/app.css:19-21
Timestamp: 2025-10-09T12:59:02.129Z
Learning: In e2e test directories (paths containing `e2e/`), accessibility concerns like outline suppression patterns are less critical since the code is for testing purposes, not production use.
Applied to files:
e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
Repo: TanStack/router PR: 5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.
Applied to files:
e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/package.jsonpackages/router-generator/tests/utils.test.ts
📚 Learning: 2025-10-09T12:59:14.842Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/public/site.webmanifest:2-3
Timestamp: 2025-10-09T12:59:14.842Z
Learning: In e2e test fixtures (files under e2e directories), empty or placeholder values in configuration files like site.webmanifest are acceptable and should not be flagged unless the test specifically validates those fields.
Applied to files:
e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.tse2e/react-router/escaped-special-strings/playwright.config.ts
📚 Learning: 2025-09-22T00:56:49.237Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Applied to files:
e2e/react-router/escaped-special-strings/src/routes/blog[_].tsxpackages/router-generator/tests/utils.test.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/package.json : Use workspace protocol `workspace:*` for internal dependencies in package.json files
Applied to files:
e2e/react-router/escaped-special-strings/package.json
📚 Learning: 2025-09-28T21:41:45.233Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.
Applied to files:
packages/router-generator/tests/utils.test.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions
Applied to files:
e2e/react-router/escaped-special-strings/src/routeTree.gen.ts
🧬 Code graph analysis (5)
e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx (1)
e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx (1)
Route(5-7)
e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx (6)
e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/[index].tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/[route].tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/__root.tsx (1)
Route(3-13)packages/router-core/src/ssr/tsrScript.ts (1)
p(16-18)
e2e/react-router/escaped-special-strings/src/routes/[route].tsx (5)
e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/[index].tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx (1)
Route(5-7)e2e/react-router/escaped-special-strings/src/routes/__root.tsx (1)
Route(3-13)e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx (1)
Route(5-7)
e2e/react-router/escaped-special-strings/playwright.config.ts (1)
e2e/vue-router/basic-esbuild-file-based/src/esbuild.run.js (1)
command(9-9)
packages/router-generator/tests/utils.test.ts (1)
packages/router-generator/src/utils.ts (5)
hasEscapedLeadingUnderscore(226-232)hasEscapedTrailingUnderscore(240-246)isSegmentPathless(396-402)removeUnderscoresWithEscape(326-360)removeLayoutSegmentsWithEscape(370-386)
🔇 Additional comments (21)
e2e/react-router/escaped-special-strings/tsconfig.json (1)
1-15: LGTM! Well-configured TypeScript setup for the e2e test project.The configuration correctly enables strict mode (as required), uses modern React JSX transform, and includes appropriate Vite-specific settings. All essential compiler options are present and properly configured for a React+Vite e2e test environment.
e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx (1)
1-7: LGTM! Route definition correctly demonstrates escaped special string.The route properly uses
createFileRoute('/lazy')to create a literal/lazypath, correctly demonstrating the escaped special string feature where[lazy].tsxproduces a literal path instead of triggering lazy-loading semantics.e2e/react-router/escaped-special-strings/src/routes/[index].tsx (1)
1-7: LGTM! Correctly demonstrates the escaped index route feature.The route definition properly uses
createFileRoute('/index')to create a literal/indexpath, matching the expected behavior for an escaped[index]filename. The comments clearly document the escaping semantics.e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx (2)
1-7: LGTM! Correct demonstration of trailing underscore escaping.The route definition correctly demonstrates the new escaping functionality. The filename
blog[_].tsxwith the bracket-escaped trailing underscore properly generates a route at the literal path/blog_, preserving the underscore as intended by this PR. The implementation follows the same pattern as the other escaped route examples in this e2e suite.
9-21: LGTM! Clean test component with proper test identifiers.The component implementation is straightforward and well-suited for e2e testing. It includes appropriate
data-testidattributes for automated verification and clearly displays the expected path/blog_to validate that the trailing underscore escaping works correctly.e2e/react-router/escaped-special-strings/vite.config.js (1)
1-13: LGTM!Standard Vite configuration with TanStack Router and React plugins properly configured for the e2e test project.
e2e/react-router/escaped-special-strings/tests/setup/global.teardown.ts (1)
1-6: LGTM!Teardown script correctly stops the dummy e2e server using the package name identifier. Properly mirrors the setup script structure.
e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts (1)
1-124: LGTM!Comprehensive test coverage for the escaped special strings feature. Tests verify both direct navigation and client-side routing for all escaped route types, including special tokens (index, route, lazy) and underscores in various positions.
e2e/react-router/escaped-special-strings/tests/setup/global.setup.ts (1)
1-6: LGTM!Setup script correctly starts the dummy e2e server using the package name identifier. Properly mirrors the teardown script structure.
e2e/react-router/escaped-special-strings/src/routes/[route].tsx (1)
1-21: LGTM!Route file correctly demonstrates the new escaping feature. The
[route]filename syntax creates a literal/routepath, and the component provides appropriate test data for e2e verification.e2e/react-router/escaped-special-strings/src/main.tsx (1)
1-24: LGTM!Standard React Router entry point with proper type safety registration. The defensive check on Line 21 prevents duplicate mounting, which is appropriate for e2e testing scenarios.
e2e/react-router/escaped-special-strings/playwright.config.ts (1)
1-53: LGTM!Playwright configuration is properly set up for e2e testing with dynamic port allocation, appropriate environment variables, and global setup/teardown hooks. The web server command builds and previews the app, which is correct for testing the production build.
e2e/react-router/escaped-special-strings/package.json (1)
1-28: LGTM!Package manifest correctly uses the workspace protocol (
workspace:^) for all internal TanStack dependencies and properly configures the e2e test project as an ESM module. Scripts and dependencies are appropriate for testing the escaped special strings feature.e2e/react-router/escaped-special-strings/src/routeTree.gen.ts (1)
1-131: Skipping review of autogenerated test fixture.This
routeTree.gen.tsfile is autogenerated by TanStack Router (as indicated by the file header) and serves as a test fixture to verify the generator's correct output for escaped special strings. Based on learnings, these generated route tree files should not be reviewed or modified.e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx (2)
1-7: LGTM! Route definition correctly demonstrates escaped underscore behavior.The route path
'/_layout'accurately reflects the new escaping feature: the filename[_]layout.tsxproduces a literal/_layoutpath instead of being treated as a pathless layout. The explanatory comments effectively document the behavior.
9-21: LGTM! Component structure is appropriate for e2e testing.The component provides clear visual feedback about the escaped path and includes proper
data-testidattributes for automated testing. The implementation correctly demonstrates the feature behavior.e2e/react-router/escaped-special-strings/src/routes/__root.tsx (2)
1-13: LGTM! Root route configuration is well-structured.The root route properly sets up the component hierarchy and includes a helpful
notFoundComponentwith navigation back to a known route. Thedata-testidattribute enables automated testing of 404 behavior.
15-48: LGTM! Navigation comprehensively covers all escaped-path test cases.The navigation includes links to all the routes demonstrating the new escaping feature (
/index,/route,/lazy,/_layout,/blog_), and each link has properdata-testidattributes for e2e testing. TheOutletplacement correctly renders child routes.packages/router-generator/tests/utils.test.ts (3)
1-19: LGTM! Imports correctly updated for escape-aware utilities.The new imports and renamed functions align with the extended escaping mechanism introduced in this PR. All imported utilities are properly tested in the new test suites below.
77-89: LGTM! Error message correctly reflects underscore escaping support.The error message has been appropriately updated to exclude underscore from the disallowed characters list, consistent with the PR's goal of allowing underscores to be escaped using square-bracket syntax.
366-495: Excellent comprehensive test coverage for escape-aware utilities.The test suites for
isSegmentPathless,removeUnderscoresWithEscape, andremoveLayoutSegmentsWithEscapethoroughly validate the new escape-aware behavior introduced in this PR:
- isSegmentPathless: Correctly distinguishes between escaped and non-escaped leading underscores
- removeUnderscoresWithEscape: Comprehensively tests preservation of escaped underscores (leading, trailing, fully-escaped) while removing non-escaped ones, plus fallback and edge case handling
- removeLayoutSegmentsWithEscape: Validates that escaped layout segments are preserved while non-escaped ones are removed, including mixed scenarios and root path handling
All assertions align with the implementation and PR objectives. Based on learnings, this correctly extends TanStack Router's existing underscore-stripping behavior to respect escaping.
This change extends the router-generator's escaping mechanism to allow ANY special string to be escaped using square bracket syntax, not just dots.
Problem
Previously, the router-generator only supported escaping dots using [.] syntax (e.g., script[.]js.tsx -> /script.js). However, special strings like 'index', 'route', 'lazy', and underscores ('_') could not be escaped, making it impossible to create routes with literal paths like /index, /route, /lazy, or paths containing literal underscores.
Solution
Extended the escaping mechanism to support:
Escaped special suffixes: [index], [route], [lazy], [component], etc.
Escaped underscores in any position:
Custom token escaping: Works with custom indexToken and routeToken
Implementation Details
src/utils.ts
src/filesystem/physical/getRouteNodes.ts
src/generator.ts
Tests Added
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.