Skip to content

Conversation

@schiller-manuel
Copy link
Contributor

@schiller-manuel schiller-manuel commented Dec 20, 2025

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

Summary by CodeRabbit

  • New Features
    • Support for escaping special tokens so bracketed/underscored segments are treated as literal path parts; custom token names supported and reflected in generated route metadata.
  • Bug Fixes
    • Path normalization, index detection and pathless/layout resolution now respect escaped segments; related error messaging updated.
  • Tests
    • New unit tests, snapshots and e2e suite validating escaped-special-string routing and custom-token scenarios; generated route trees updated.

✏️ Tip: You can customize this high-level summary in your review settings.

…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
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 20, 2025

Walkthrough

Propagates 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

Cohort / File(s) Change Summary
Utils — escape-aware path helpers
packages/router-generator/src/utils.ts
Added top-level DISALLOWED_ESCAPE_CHARS and helpers: isFullyEscapedSegment, hasEscapedLeadingUnderscore, hasEscapedTrailingUnderscore, removeUnderscoresWithEscape, removeLayoutSegmentsWithEscape, isSegmentPathless. Updated inferFullPath to use escape-aware processing.
Filesystem route meta / pathless layout validation
packages/router-generator/src/filesystem/physical/getRouteNodes.ts
Import hasEscapedLeadingUnderscore; updated getRouteMeta(routePath, originalRoutePath, config) and isValidPathlessLayoutRoute(normalizedRoutePath, originalRoutePath, routeType, config) signatures; logic now uses originalRoutePath to detect escaped suffixes and adjust route-type/index normalization.
Generator — propagate original paths & use escape-aware cleaning
packages/router-generator/src/generator.ts
Replaced removeLayoutSegments/removeUnderscores with removeLayoutSegmentsWithEscape/removeUnderscoresWithEscape; track originalRoutePath, trimmedOriginalPath, originalSplit, lastOriginalSegment; integrate isSegmentPathless into non-path detection and compute original-relative paths.
Utils public API (exports changed)
packages/router-generator/src/utils.ts, packages/router-generator/src/generator.ts
Renamed/introduced exports: removeLayoutSegmentsWithEscape, removeUnderscoresWithEscape, added isSegmentPathless (public).
Tests — folder mapping and fixtures
packages/router-generator/tests/generator.test.ts
Recognize escaped-custom-tokens in rewriteConfigByFolderName, set custom indexToken/routeToken for that fixture.
Tests — escaped-custom-tokens fixture
packages/router-generator/tests/generator/escaped-custom-tokens/*
New test routes and generated routeTree.snapshot.ts exercising custom escaped tokens (_1nd3x, _r0ut3_) and literal-path behavior.
Tests — escaped-special-strings fixture
packages/router-generator/tests/generator/escaped-special-strings/*
New test routes and generated snapshot covering escaped special strings/reserved tokens (e.g., [_]layout, [index], api[_]v2[_]users, etc.) and resulting typed route tree snapshot.
Tests — utils unit tests
packages/router-generator/tests/utils.test.ts
Added tests for new escape-aware utilities: hasEscapedLeadingUnderscore, hasEscapedTrailingUnderscore, isSegmentPathless, removeLayoutSegmentsWithEscape, removeUnderscoresWithEscape.
E2E — escaped-special-strings app & tests
e2e/react-router/escaped-special-strings/...
New e2e app, route tree gen, routes, Playwright config, tests, and supporting files exercising escaped-literal routes and client navigation.

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)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review focus:
    • utils escape-detection edge cases (double-escaping, nested brackets, empty segments)
    • propagation and correctness of originalRoutePath through generator → getRouteMeta → isValidPathlessLayoutRoute
    • public API rename impact and updated imports across codebase and tests
    • e2e and snapshot generation correctness

Possibly related PRs

Suggested reviewers

  • nlynzaad
  • Sheraff

Poem

🐇 I nudged an underscore aside,

escaped tokens now hop in stride.
Literal paths find daylight clear,
no magic trims or sneaky tiers.
Tiny hops, big route cheer. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.78% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: enabling escaping of any special string in file-based routing using square-bracket syntax. It is clear, specific, and directly related to the primary objective.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch generator-escaping

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

@nx-cloud
Copy link

nx-cloud bot commented Dec 20, 2025

View your CI Pipeline Execution ↗ for commit f1256b3

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 47s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 3s View ↗

☁️ Nx Cloud last updated this comment at 2025-12-20 13:20:51 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 20, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6156

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@6156

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6156

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6156

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6156

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6156

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6156

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6156

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6156

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6156

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6156

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6156

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6156

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6156

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6156

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6156

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6156

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6156

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6156

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6156

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@6156

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6156

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6156

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6156

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6156

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6156

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6156

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6156

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6156

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6156

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6156

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6156

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6156

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6156

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6156

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6156

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6156

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6156

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6156

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6156

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6156

commit: f1256b3

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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-nocheck directive 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 .ts and .tsx files.

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-nocheck to 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 escaping config.indexToken in the regex patterns.

While the static analysis ReDoS warnings are likely false positives for typical usage (since indexToken is usually a simple string like "index"), user-provided configuration values are used directly in new RegExp(). If a user sets an unusual indexToken containing regex metacharacters, it could cause unexpected behavior.

The escapeRegExp utility already exists in this file (used for routeToken elsewhere). 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 escapeRegExp from utils or define it locally if not already available in scope.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c5fdb1 and ea9a657.

📒 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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/__root.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/src/generator.ts
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/src/generator.ts
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/src/utils.ts
  • packages/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[_].tsx
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/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[_].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/nested.[index].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]prefix[_]middle[_]suffix.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[lazy].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]layout.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/foo[_]bar.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/api[_]v2[_]users.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/nested.[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[index].tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/[_1nd3x].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[route].tsx
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/blog._r0ut3_.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/[_]auth.route.tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routeTree.snapshot.ts
  • packages/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].tsx
  • packages/router-generator/tests/generator/escaped-special-strings/routes/index.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routes/_1nd3x.tsx
  • packages/router-generator/tests/generator/escaped-custom-tokens/routeTree.snapshot.ts
  • packages/router-generator/tests/generator/escaped-special-strings/routes/__root.tsx
  • packages/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].tsx which 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 in posts.[_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/_1nd3x path instead of treating _1nd3x as an index route indicator.

packages/router-generator/tests/generator.test.ts (1)

78-81: LGTM!

The configuration correctly mirrors the custom-tokens case to test escaped token behavior. Both cases use the same custom token values (_1nd3x and _r0ut3_), but the test fixtures in the escaped-custom-tokens folder 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_bar path 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 .route suffix 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 /lazy path 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 for createRootRoute.

The file references createRootRoute without importing it, which will cause a ReferenceError at 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 router
packages/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 for createRootRoute.

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 router
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: 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_CHARS constant 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 isSegmentEscaped function correctly handles three escape patterns:

  1. Fully escaped segments: [index]index
  2. Leading underscore escape: [_]foo_foo
  3. Trailing underscore escape: foo[_]foo_

The documentation is clear with good examples.


252-302: LGTM!

Both hasEscapedLeadingUnderscore and hasEscapedTrailingUnderscore correctly detect:

  1. Partial escape patterns ([_]layout, blog[_])
  2. 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 removeUnderscoresWithEscape function correctly preserves underscores that were escaped while removing non-escaped leading/trailing underscores. The segment-by-segment processing with index alignment to originalSegments is the right approach.


418-452: LGTM!

The removeLayoutSegmentsWithEscape function correctly filters out layout segments (those starting with _) while preserving segments where the underscore was escaped. The index-based lookup to originalSegments during filtering is correct.


454-468: LGTM!

The isSegmentPathless function provides a clean abstraction for determining if a segment should be treated as pathless, delegating to hasEscapedLeadingUnderscore for escape detection.


692-704: LGTM!

The inferFullPath function now correctly uses the escape-aware variants, passing routeNode.originalRoutePath to both removeLayoutSegmentsWithEscape and removeUnderscoresWithEscape. 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 hasEscapedLeadingUnderscore from 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 originalRoutePath and only strips special suffixes when they are not escaped (wrapped in brackets). This enables files like [lazy].tsx to produce literal /lazy paths.


309-383: LGTM!

The getRouteMeta function is cleanly updated to:

  1. Accept originalRoutePath parameter
  2. Extract the last segment for escape checking
  3. Use isSuffixEscaped helper to verify each suffix before assigning route types

This 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 isValidPathlessLayoutRoute function correctly integrates escape awareness:

  • Uses hasEscapedLeadingUnderscore to check both the last and second-to-last original segments
  • Returns false for 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:

  1. trimmedOriginalPath correctly computes the original path relative to the parent
  2. lastOriginalSegment extraction enables escape detection for the final segment
  3. isNonPath now correctly uses isSegmentPathless to check if the underscore is escaped
  4. cleanedPath uses the escape-aware variants to preserve literal underscores

This ensures files like [_]layout.tsx produce /_layout paths instead of being treated as pathless layouts.


1449-1481: LGTM!

The pathless layout special handling correctly mirrors the main path processing:

  • immediateParentOriginalPath is computed for escape-aware ancestor lookup
  • originalPathRelativeToParent is derived when finding the nearest real parent
  • The cleanedPath computation uses escape-aware functions with the proper original path context

This 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 in packages/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 in packages/router-generator/tests/generator/**/routeTree*.snapshot.ts are fixtures used to verify generator output and are intentionally preserved as-is.

Comment on lines +1 to +2
import { createFileRoute } from '@tanstack/react-router'
// @ts-nocheck
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

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.

Suggested change
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.

Comment on lines +1 to +4
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')()
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

@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.

Suggested change
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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 removeLayoutSegmentsWithEscape filters out pathless segments, the returned path has fewer segments than originalRoutePath. When this modified path is passed to removeUnderscoresWithEscape along with the unchanged originalRoutePath, 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 removeLayoutSegmentsWithEscape to return both the filtered routePath and filtered originalPath:

-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

📥 Commits

Reviewing files that changed from the base of the PR and between ea9a657 and 0612d58.

📒 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_CHARS is the key change that enables this PR's functionality, allowing paths like [_]layout to 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 routePath while originalPath remains 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 inferFullPath for 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 false for segments that don't start with underscore or have escaped underscores.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 .tsx files.

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-testid attributes. 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 hasEscapedLeadingUnderscore and hasEscapedTrailingUnderscore are 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

📥 Commits

Reviewing files that changed from the base of the PR and between 3faae7e and f1256b3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is 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.ts
  • e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx
  • e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • e2e/react-router/escaped-special-strings/src/routes/[route].tsx
  • e2e/react-router/escaped-special-strings/playwright.config.ts
  • e2e/react-router/escaped-special-strings/src/main.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[index].tsx
  • packages/router-generator/tests/utils.test.ts
  • e2e/react-router/escaped-special-strings/tests/setup/global.teardown.ts
  • e2e/react-router/escaped-special-strings/src/routeTree.gen.ts
  • e2e/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.ts
  • e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx
  • e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • e2e/react-router/escaped-special-strings/src/routes/[route].tsx
  • e2e/react-router/escaped-special-strings/playwright.config.ts
  • e2e/react-router/escaped-special-strings/src/main.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[index].tsx
  • packages/router-generator/tests/utils.test.ts
  • e2e/react-router/escaped-special-strings/tests/setup/global.teardown.ts
  • e2e/react-router/escaped-special-strings/vite.config.js
  • e2e/react-router/escaped-special-strings/src/routeTree.gen.ts
  • e2e/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.ts
  • e2e/react-router/escaped-special-strings/src/routes/[_]layout.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx
  • e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • e2e/react-router/escaped-special-strings/package.json
  • e2e/react-router/escaped-special-strings/src/routes/[route].tsx
  • e2e/react-router/escaped-special-strings/src/main.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[index].tsx
  • packages/router-generator/tests/utils.test.ts
  • e2e/react-router/escaped-special-strings/tests/setup/global.teardown.ts
  • e2e/react-router/escaped-special-strings/src/routeTree.gen.ts
  • e2e/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.ts
  • e2e/react-router/escaped-special-strings/tsconfig.json
  • e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx
  • e2e/react-router/escaped-special-strings/package.json
  • e2e/react-router/escaped-special-strings/src/main.tsx
  • e2e/react-router/escaped-special-strings/tests/setup/global.teardown.ts
  • e2e/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.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx
  • e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • e2e/react-router/escaped-special-strings/src/routes/[route].tsx
  • e2e/react-router/escaped-special-strings/src/routes/[index].tsx
  • packages/router-generator/tests/utils.test.ts
  • e2e/react-router/escaped-special-strings/src/routeTree.gen.ts
  • e2e/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.tsx
  • e2e/react-router/escaped-special-strings/tsconfig.json
  • e2e/react-router/escaped-special-strings/src/routes/[lazy].tsx
  • e2e/react-router/escaped-special-strings/tests/escaped-routes.spec.ts
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • e2e/react-router/escaped-special-strings/package.json
  • e2e/react-router/escaped-special-strings/src/routes/[route].tsx
  • e2e/react-router/escaped-special-strings/src/main.tsx
  • e2e/react-router/escaped-special-strings/src/routes/[index].tsx
  • packages/router-generator/tests/utils.test.ts
  • e2e/react-router/escaped-special-strings/vite.config.js
  • e2e/react-router/escaped-special-strings/src/routeTree.gen.ts
  • e2e/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.tsx
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • 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: 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].tsx
  • e2e/react-router/escaped-special-strings/src/routes/blog[_].tsx
  • e2e/react-router/escaped-special-strings/package.json
  • e2e/react-router/escaped-special-strings/src/routes/[route].tsx
  • e2e/react-router/escaped-special-strings/src/main.tsx
  • e2e/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.ts
  • e2e/react-router/escaped-special-strings/package.json
  • packages/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.ts
  • e2e/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[_].tsx
  • 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: 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 /lazy path, correctly demonstrating the escaped special string feature where [lazy].tsx produces 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 /index path, 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[_].tsx with 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-testid attributes 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 /route path, 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.ts file 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.tsx produces a literal /_layout path 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-testid attributes 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 notFoundComponent with navigation back to a known route. The data-testid attribute 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 proper data-testid attributes for e2e testing. The Outlet placement 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, and removeLayoutSegmentsWithEscape thoroughly 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.

@schiller-manuel schiller-manuel merged commit c9a19a2 into main Dec 20, 2025
6 checks passed
@schiller-manuel schiller-manuel deleted the generator-escaping branch December 20, 2025 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants