Skip to content

Conversation

nlynzaad
Copy link
Contributor

@nlynzaad nlynzaad commented Oct 7, 2025

This PR reverts the work done in #5165, #5182 and #5169. These changes, although solving the original issue in #5164 introduced a slew of other problems related to trailing underscores, especially in code-based routing solutions. See #5296 and #5313.

The original problem was caused by route matching failing in the case of named params being used in conjunction with non-nested routes. This in turn was due to the trailing underscore being retained in the routeId but removed in the route path and when used with named params this would cause the match to fail.

The original attempt in resolving the issue was to resolve it at runtime and not affect the way users have been using and referencing non-nested paths. Unfortunately, this was not the right way to resolve the issue and didn't address the root cause. The root of the problem was how the non-nested indicator was being processed in the generation of the routes when using file-based routing.

A side effect of how we have been resolving non-nested paths in the generator till now was that we removed any trailing underscores from the route path and hence escaping trailing underscores was not possible.

This PR introduces changes to the generator to better deal with the non-nested indicating trailing underscores. Primarily this is done by identifying a route as a non-nested route as early as possible and then removing the trailing underscore at that point before the route is processed further. This allows us to align the routeId with the path.

By doing this ahead of escaping the required characters, we now also do not need to remove any trailing underscores that appear further in the process, which has the benefit of enabling the use of escaped trailing underscores.

Unfortunately, this change does result in a change of how non-nested paths are referenced in functions that take the routeId as an input, for example, useParams, useNavigate, getRouteApi, etc. Previously this would look like useParams({ from: '/posts_/$postId/edit' }) and now, with the removal of the trailing underscore in the routeId, this looks like: useParams({ from: '/posts/$postId/edit' }).

This change in the referencing, although being more correct and more closely aligned to the actual path, does bring a change users might regard as breaking. Hence, we have opted to put this behind a feature flag in the router plugin under the experimental section:

tanstackRouter({
	experimental: {
		nonNestedRoutes: true,
	},
})

Since this is behind a feature flag tests have been updated to reflect and test the expected behavior in both cases, where this is enabled and where it is not. This means we are testing for the expected errors where we know they now exist and the correct handling with the applied fix. This was done for router-generator, react-router/basic-file-based, solid-router/basic-file-based.

It also adds two notes to the documentation to communicate the new feature flag and escape functionality.

Summary by CodeRabbit

  • New Features

    • Experimental Non‑Nested Routes mode (config flag + env toggle) with generator and runtime opt‑in.
  • Documentation

    • Added migration guidance and clarified escaping trailing underscores in file‑naming docs.
  • Refactor

    • Centralized path parsing in core to unify route parsing behavior.
  • Tests / Chores

    • E2E and test workflows updated to run both default and non‑nested modes; test assertions and dev scripts adapted for conditional mode.

Copy link

nx-cloud bot commented Oct 7, 2025

View your CI Pipeline Execution ↗ for commit 43220cf

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

☁️ Nx Cloud last updated this comment at 2025-10-08 08:10:05 UTC

@nlynzaad nlynzaad changed the title fix(route-core): resolve non-nested routes correctly in generator fix(route-core, router-generator): resolve non-nested routes correctly in generator Oct 7, 2025
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Walkthrough

Enables an experimental nonNestedRoutes flow across docs, e2e harnesses (React/Solid), router-generator, and router-core: adds docs and test-mode flags, threads an experimental flag through generator APIs and snapshots, refactors router-core path parsing to centralize via parsePathname, and adds many non-nested snapshots/tests and helper utilities.

Changes

Cohort / File(s) Summary
Docs: Non‑Nested Routes
docs/router/framework/react/routing/file-naming-conventions.md, docs/router/framework/react/routing/routing-concepts.md
Added advisory notes and an experimental nonNestedRoutes section with migration/config examples.
E2E (React) infra & scripts
e2e/react-router/basic-file-based/package.json, e2e/react-router/basic-file-based/playwright.config.ts, e2e/react-router/basic-file-based/vite.config.js
Adds nonnested scripts; dynamic Playwright webServer.command based on mode; Vite plugin toggles experimental.nonNestedRoutes; env propagation.
E2E (React) routes & tests
e2e/react-router/basic-file-based/src/routes/.../*, e2e/react-router/basic-file-based/tests/*.spec.ts, e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts
Adds useExperimentalNonNestedRoutes util; conditionally composes paths/from values in route files; tests branch assertions based on the flag.
E2E (Solid) infra & scripts
e2e/solid-router/basic-file-based/package.json, e2e/solid-router/basic-file-based/playwright.config.ts, e2e/solid-router/basic-file-based/vite.config.js
Mirrors React e2e changes: nonnested scripts, dynamic Playwright command/env, Vite plugin experimental toggle.
E2E (Solid) routes & tests
e2e/solid-router/basic-file-based/src/routes/.../*, e2e/solid-router/basic-file-based/tests/*.spec.ts, e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts
Adds useExperimentalNonNestedRoutes util; conditional path/from composition in routes; tests branch expectations for non-nested mode.
router-core: parsing refactor
packages/router-core/src/path.ts, packages/router-core/src/process-route-tree.ts
Centralizes parsing via parsePathname (signature extended), removes exported helpers (parseBasePathSegments/parseRoutePathSegments), updates callers and decoding/wildcard logic.
router-core: tests
packages/router-core/tests/path.test.ts, packages/router-core/tests/match-by-path.test.ts
Removes large non-nested path test blocks/suites.
router-generator: config & types
packages/router-generator/src/config.ts, packages/router-generator/src/types.ts
Adds experimental.nonNestedRoutes to config schema; extends RouteNode with originalRoutePath and _isExperimentalNonNestedRoute.
router-generator: filesystem & node emission
packages/router-generator/src/filesystem/physical/getRouteNodes.ts
determineInitialRoutePath receives config; emitted RouteNode now includes _isExperimentalNonNestedRoute and originalRoutePath.
router-generator: utils & inference
packages/router-generator/src/utils.ts
determineInitialRoutePath now returns structured object; adds isValidNonNestedRoute, removeLeadingUnderscores, removeTrailingUnderscores; makes infer/hasParentRoute config-aware and threads config through inferFullPath/inferTo/createRouteNodes helpers.
router-generator: generator plumbing
packages/router-generator/src/generator.ts
Threads config into handleNode/createRouteNodesBy*; uses removeLeadingUnderscores conditionally; passes originalRoutePath into parent resolution.
router-generator: tests & snapshots
packages/router-generator/tests/**/routeTree.nonnested.snapshot.ts, packages/router-generator/tests/**/tests.nonnested.test-d.ts, packages/router-generator/tests/utils.test.ts, plus many generator test updates
Adds many non-nested generated snapshots; updates generator tests to run both nonNested modes; adds tests for new utils and determineInitialRoutePath behavior.
types-disabled fixtures
packages/router-generator/tests/generator/types-disabled/**
Adds top-of-file ts-nocheck/ESLint suppression comments and minor fixture exports to support tests.
Misc: tooling
packages/router-generator/.prettierignore
Adds ignore pattern for routeTree.*.snapshot.ts.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev
  participant PW as Playwright
  participant Vite as Vite
  participant Plugin as tanstackRouter plugin
  participant App

  Dev->>PW: run test:e2e(:nonnested|:default)
  PW->>PW: resolve mode via env/useExperimentalNonNestedRoutes
  PW->>Vite: start server with MODE/VITE_MODE/PORT env
  Vite->>Plugin: initialize plugin with experimental.nonNestedRoutes=(MODE==='nonnested')
  Plugin->>App: build/serve routes honoring nonNested flag
  Dev->>App: execute e2e tests (assertions branch on flag)
Loading
sequenceDiagram
  autonumber
  participant Gen as Generator
  participant FS as getRouteNodes
  participant Util as utils.determineInitialRoutePath
  participant Node as RouteNode

  Gen->>FS: read files (pass config.experimental.nonNestedRoutes)
  FS->>Util: determineInitialRoutePath(filePathNoExt, config)
  Util-->>FS: { routePath, originalRoutePath, isExperimentalNonNestedRoute }
  FS->>Node: emit RouteNode with originalRoutePath & _isExperimentalNonNestedRoute
  Gen->>Util: hasParentRoute(routes, node, routePath, originalRoutePath)
  Util-->>Gen: resolved parent (non-nested aware)
  Gen->>Gen: generate snapshots/types using config-driven underscore handling
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • schiller-manuel
  • Sheraff

Poem

"I hopped through code with eager paws,
Trimmed underscores and tuned the laws.
MODE flipped to 'nonnested', tests take wing,
Snapshots sprout and e2e sings.
A rabbit's cheer — routes leap and spring! 🐇"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the primary change, specifying a fix for non-nested route resolution within the generator and indicating the affected packages (route-core and router-generator), which aligns with the pull request’s objectives.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ 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 non-nested-paths

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

Copy link

pkg-pr-new bot commented Oct 7, 2025

More templates

@tanstack/arktype-adapter

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

@tanstack/directive-functions-plugin

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

@tanstack/eslint-plugin-router

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

@tanstack/history

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

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

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

@tanstack/react-start-client

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

@tanstack/react-start-server

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

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/server-functions-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-start

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

@tanstack/solid-start-client

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

@tanstack/solid-start-server

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

@tanstack/start-client-core

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

@tanstack/start-plugin-core

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

@tanstack/start-server-core

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

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

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

@tanstack/valibot-adapter

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

@tanstack/virtual-file-routes

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

@tanstack/zod-adapter

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

commit: 43220cf

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/router-generator/src/generator.ts (1)

1203-1224: Propagate originalRoutePath and flag to nested hasParentRoute call.

The second hasParentRoute invocation omits experimental context and originalRoutePath, risking incorrect parent resolution for experimental non-nested routes.

Apply this diff:

-      const possibleParentRoute = hasParentRoute(
-        parentRoute.children,
-        node,
-        node.routePath,
-      )
+      const possibleParentRoute = hasParentRoute(
+        parentRoute.children,
+        node,
+        node.routePath,
+        useExperimentalNonNestedRoutes,
+        node.originalRoutePath,
+      )
packages/router-core/src/path.ts (2)

344-350: Trailing-slash handling assigns the wrong substring (harmless now, but brittle).

pathname = pathname.substring(1) removes the first char, not the trailing slash. Since pathname isn’t used after this, it doesn’t break today, but it’s incorrect. Simplify by removing the assignment or fix it.

-  if (pathname.slice(-1) === '/') {
-    pathname = pathname.substring(1)
-    segments.push({
+  if (pathname.slice(-1) === '/') {
+    segments.push({
       type: SEGMENT_TYPE_PATHNAME,
       value: '/',
     })
   }

441-447: leaveParams uses the wrong key; values will never append.

encodeParam(segment.value) looks up params['$foo'] instead of params['foo'].

-        if (leaveParams) {
-          const value = encodeParam(segment.value)
-          return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}`
-        }
-        return `${segmentPrefix}${encodeParam(key) ?? 'undefined'}${segmentSuffix}`
+        if (leaveParams) {
+          const value = encodeParam(key)
+          return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}`
+        }
+        return `${segmentPrefix}${encodeParam(key) ?? 'undefined'}${segmentSuffix}`
🧹 Nitpick comments (20)
packages/router-generator/tests/generator.test.ts (1)

249-264: Consider flatMap for clarity.

The reduce logic is correct but a flatMap or simple loop might be more readable:

-const testCases = folderNames.reduce(
-  (accum: Array<{ folderName: string; nonNested: boolean }>, folderName) => {
-    accum.push({
-      folderName,
-      nonNested: true,
-    })
-
-    accum.push({
-      folderName,
-      nonNested: false,
-    })
-
-    return accum
-  },
-  [],
-)
+const testCases = folderNames.flatMap(folderName => [
+  { folderName, nonNested: true },
+  { folderName, nonNested: false },
+])
e2e/react-router/basic-file-based/vite.config.js (1)

7-15: Harden the flag check to also read VITE_MODE (and optionally use Vite’s mode).

Your gating works; consider also checking VITE_MODE to align with the test env and make it more robust. Optional: switch to defineConfig(({ mode }) => ...) and compare mode directly.

Apply this minimal change:

       experimental: {
-        nonNestedRoutes: process.env.MODE === 'nonnested',
+        nonNestedRoutes:
+          process.env.MODE === 'nonnested' ||
+          process.env.VITE_MODE === 'nonnested',
       },

Alternative (optional) using Vite’s mode:

export default defineConfig(({ mode }) => ({
  plugins: [
    tanstackRouter({
      target: 'react',
      experimental: { nonNestedRoutes: mode === 'nonnested' },
    }),
    react(),
  ],
}))
e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (1)

8-11: Gate both getRouteApi and useParams ‘from’ with the same routeId.

Right now, getRouteApi toggles the id, but useParams({ from }) below stays at '/posts_/$postId/edit'. In non-nested mode, that likely mismatches. Define one routeId and reuse it for both.

-const api = getRouteApi(
-  // @ts-expect-error path is updated with new Experimental Non Nested Paths to not include the trailing underscore
-  `/${useExperimentalNonNestedRoutes ? 'posts' : 'posts_'}/$postId/edit`,
-)
+const routeId =
+  `/${useExperimentalNonNestedRoutes ? 'posts' : 'posts_'}/$postId/edit`
+// @ts-expect-error routeId differs under experimental non-nested paths
+const api = getRouteApi(routeId)

Also update the hook (outside this hunk) to match:

// @ts-expect-error routeId differs under experimental non-nested paths
const paramsViaHook = useParams({ from: routeId })
e2e/react-router/basic-file-based/package.json (1)

7-17: Make scripts cross‑platform (env vars and cleanup).

Current scripts use POSIX env and rm; these break on Windows shells. Prefer cross-env and rimraf.

- "dev:nonnested": "MODE=nonnested VITE_MODE=nonnested vite --port 3000",
+ "dev:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite --port 3000",
- "build:nonnested": "MODE=nonnested VITE_MODE=nonnested vite build && tsc --noEmit",
+ "build:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite build && tsc --noEmit",
- "serve:nonnested": "MODE=nonnested VITE_MODE=nonnested vite preview",
+ "serve:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite preview",
- "start:nonnested": "MODE=nonnested VITE_MODE=nonnested vite",
+ "start:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite",
- "test:e2e:default": "rm -rf port*.txt; playwright test --project=chromium",
+ "test:e2e:default": "rimraf port*.txt && playwright test --project=chromium",
- "test:e2e:nonnested": "rm -rf port*.txt; MODE=nonnested playwright test --project=chromium"
+ "test:e2e:nonnested": "rimraf port*.txt && cross-env MODE=nonnested playwright test --project=chromium"

Add devDependencies:

  • cross-env
  • rimraf
packages/router-generator/src/types.ts (1)

7-7: Document new fields’ intent and stability.

Add brief JSDoc to signal usage and experimental status to downstream consumers.

-  originalRoutePath?: string
+  /** Unmodified path as discovered from the filesystem before normalization/escaping */
+  originalRoutePath?: string
...
-  _isExperimentalNonNestedRoute?: boolean
+  /** @experimental Marker for routes detected as non-nested (subject to change) */
+  _isExperimentalNonNestedRoute?: boolean

Also applies to: 17-17

packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.nonnested.test-d.ts (1)

1-539: Deduplicate repeated string literals in unions to reduce noise

Several unions contain duplicates (e.g., '/posts/$postId' listed twice). It’s harmless but increases churn in snapshots and cognitive load. If these are generated, consider deduping before emit.

e2e/solid-router/basic-file-based/tests/params.spec.ts (1)

170-177: Stabilize after navigation to reduce flakes

After clicking foo2Bar2Link and waiting for URL, add a networkidle wait before reading DOM.

   await foo2Bar2Link.click()
   await page.waitForURL('/params-ps/non-nested/foo2/bar2')
+  await page.waitForLoadState('networkidle')
   const pagePathname2 = new URL(page.url()).pathname
packages/router-generator/tests/deny-route-group-config.test.ts (2)

26-31: Preserve other experimental flags when setting nonNestedRoutes

Deep-merge experimental to avoid clobbering other flags passed via inlineConfig.

-    experimental: {
-      nonNestedRoutes: nonNested,
-    },
+    experimental: {
+      ...(rest as any)?.experimental,
+      nonNestedRoutes: nonNested,
+    },

16-20: Use path utilities instead of string concatenation for generatedRouteTree

String concat works but path.join is safer and clearer.

-  const {
-    generatedRouteTree = `/routeTree.${nonNested ? 'nonnested.' : ''}gen.ts`,
-    ...rest
-  } = inlineConfig
+  const {
+    generatedRouteTree = `routeTree.${nonNested ? 'nonnested.' : ''}gen.ts`,
+    ...rest
+  } = inlineConfig
   const dir = makeFolderDir(folder)
 
   const config = getConfig({
     disableLogging: true,
     routesDirectory: dir,
-    generatedRouteTree: dir + generatedRouteTree,
+    generatedRouteTree: join(dir, generatedRouteTree),

Also applies to: 23-26

e2e/solid-router/basic-file-based/package.json (2)

15-18: Ensure Vite sees the non-nested mode during e2e tests

Also set VITE_MODE for the Playwright run, so any Vite web server or plugin config keyed off VITE_MODE receives it.

-    "test:e2e": "pnpm run test:e2e:nonnested && pnpm run test:e2e:default",
+    "test:e2e": "pnpm run test:e2e:nonnested && pnpm run test:e2e:default",
     "test:e2e:default": "rm -rf port*.txt; playwright test --project=chromium",
-    "test:e2e:nonnested": "rm -rf port*.txt; MODE=nonnested playwright test --project=chromium"
+    "test:e2e:nonnested": "rm -rf port*.txt; MODE=nonnested VITE_MODE=nonnested playwright test --project=chromium"

7-8: Optional: use cross-env for cross‑platform env vars in scripts

Setting env vars inline isn’t portable on Windows shells. Consider cross-env for dev/build/serve/start/test scripts.

-    "dev:nonnested": "MODE=nonnested VITE_MODE=nonnested vite --port 3000",
+    "dev:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite --port 3000",
-    "build:nonnested": "MODE=nonnested VITE_MODE=nonnested vite build && tsc --noEmit",
+    "build:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite build && tsc --noEmit",
-    "serve:nonnested": "MODE=nonnested VITE_MODE=nonnested vite preview",
+    "serve:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite preview",
-    "start:nonnested": "MODE=nonnested VITE_MODE=nonnested vite",
+    "start:nonnested": "cross-env MODE=nonnested VITE_MODE=nonnested vite",
-    "test:e2e:nonnested": "rm -rf port*.txt; MODE=nonnested VITE_MODE=nonnested playwright test --project=chromium"
+    "test:e2e:nonnested": "rm -rf port*.txt; cross-env MODE=nonnested VITE_MODE=nonnested playwright test --project=chromium"

Add devDependency:

   "devDependencies": {
+    "cross-env": "^7.0.3",

Also applies to: 10-15

packages/router-generator/src/generator.ts (1)

677-737: Use the locally merged config instead of this.config for inference helpers.

buildRouteTree merges config into a local variable but passes this.config to:

  • createRouteNodesByFullPath
  • createRouteNodesByTo
  • buildFileRoutesByPathInterface
  • unions (fullPaths/to) derived from the above

This can desync behavior when opts.config is provided and is also inconsistent with surrounding code using the local config.

Apply this diff:

-${[...createRouteNodesByFullPath(acc.routeNodes, this.config).entries()]
+${[...createRouteNodesByFullPath(acc.routeNodes, config).entries()]
-${[...createRouteNodesByTo(acc.routeNodes, this.config).entries()]
+${[...createRouteNodesByTo(acc.routeNodes, config).entries()]
-                ...createRouteNodesByFullPath(
-                  acc.routeNodes,
-                  this.config,
-                ).keys(),
+                ...createRouteNodesByFullPath(
+                  acc.routeNodes,
+                  config,
+                ).keys(),
-            ? [...createRouteNodesByTo(acc.routeNodes, this.config).keys()]
+            ? [...createRouteNodesByTo(acc.routeNodes, config).keys()]
-        config: this.config,
+        config,
packages/router-generator/src/filesystem/physical/getRouteNodes.ts (1)

234-237: Optional: drop unused experimental from getRouteMeta signature.

experimental isn’t used in getRouteMeta. Consider removing it (and corresponding calls) to reduce noise, unless reserved for near-term use.

packages/router-core/src/path.ts (2)

204-215: parsePathname cache ignores basePathValues; future divergence could return stale segments.

If basePathValues later alters parsing, caching solely by pathname will mix results across modes.

  • Either incorporate basePathValues into the cache key, or maintain separate caches per mode.
  • If basePathValues is guaranteed no-op, add a comment asserting that to prevent misuse.

Example (conceptual):

-  const cached = cache?.get(pathname)
+  const cacheKey = basePathValues ? `${pathname}::base` : pathname
+  const cached = cache?.get(cacheKey)
   if (cached) return cached
-  const parsed = baseParsePathname(pathname, basePathValues)
-  cache?.set(pathname, parsed)
+  const parsed = baseParsePathname(pathname, basePathValues)
+  cache?.set(cacheKey, parsed)

567-586: Simplify prefix/suffix checks for wildcard with braces.

Using the 'in' operator is redundant here and can be misleading. Just check truthiness of the prefix/suffix strings.

-          if ('prefixSegment' in routeSegment) {
-            if (!baseValue.startsWith(prefix)) {
-              return false
-            }
-          }
-          if ('suffixSegment' in routeSegment) {
-            if (
-              !baseSegments[baseSegments.length - 1]?.value.endsWith(suffix)
-            ) {
-              return false
-            }
-          }
+          if (prefix && !baseValue.startsWith(prefix)) {
+            return false
+          }
+          if (suffix && !baseSegments[baseSegments.length - 1]?.value.endsWith(suffix)) {
+            return false
+          }
packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts (1)

13-15: Empty interfaces flagged by Biome; prefer type aliases or ignore via Biome.

To satisfy lint/suspicious/noEmptyInterface, switch to type aliases (no behavior change for snapshots).

-export interface FileRoutesByFullPath {}
-export interface FileRoutesByTo {}
+export type FileRoutesByFullPath = {}
+export type FileRoutesByTo = {}
@@
-export interface RootRouteChildren {}
+export type RootRouteChildren = {}

Alternatively, annotate the file to ignore Biome for generated snapshots:

/* biome-ignore file: generated snapshot */

Also applies to: 26-26

packages/router-generator/src/utils.ts (4)

196-210: Escape routeToken in dynamic regex and remove dead code in underscore helpers

  • Prevent unintended regex behavior by escaping routeToken-derived fragments.
  • Remove unused variables and fix ineffective early-return checks.

Apply this diff:

 export function removeLeadingUnderscores(s: string, routeToken: string) {
-  const parts = s.split('/')
-
-  if (parts.length === 0) return s
+  if (!s) return s
-
-  const routeTokenToExclude =
-    routeToken[0] === '_' ? routeToken.slice(1) : routeToken
-
-  const leadingUnderscoreRegex =
-    routeToken[0] === '_'
-      ? new RegExp(`(?<=^|\\/)_(?!${routeTokenToExclude})`, 'g')
-      : new RegExp(`(?<=^|\\/)_`, 'g')
-
-  return s.replaceAll(leadingUnderscoreRegex, '')
+  const tokenStartsWithUnderscore = routeToken.startsWith('_')
+  const routeTokenToExclude = tokenStartsWithUnderscore
+    ? routeToken.slice(1)
+    : routeToken
+  const safe = escapeRegExp(routeTokenToExclude)
+  const leadingUnderscoreRegex = tokenStartsWithUnderscore
+    ? new RegExp(`(?<=^|\\/)_(?!${safe})`, 'g')
+    : /(?<=^|\/)_/g
+  return s.replace(leadingUnderscoreRegex, '')
 }
 
 export function removeTrailingUnderscores(s: string, routeToken: string) {
-  const parts = s.split('/')
-
-  if (parts.length === 0) return s
-
-  const routeTokenToExclude =
-    routeToken.slice(-1) === '_' ? routeToken.slice(0, -1) : routeToken
-
-  const trailingUnderscoreRegex =
-    routeToken[0] === '_'
-      ? new RegExp(`(?<!${routeTokenToExclude})_(?=\\/|$)`, 'g')
-      : new RegExp(`_(?=\\/)|_$`, 'g')
-
-  return s.replaceAll(trailingUnderscoreRegex, '')
+  if (!s) return s
+  const tokenStartsWithUnderscore = routeToken.startsWith('_')
+  const routeTokenToExclude = routeToken.endsWith('_')
+    ? routeToken.slice(0, -1)
+    : routeToken
+  const safe = escapeRegExp(routeTokenToExclude)
+  const trailingUnderscoreRegex = tokenStartsWithUnderscore
+    ? new RegExp(`(?<!${safe})_(?=\\/|$)`, 'g')
+    : /_(?=\/)|_$/g
+  return s.replace(trailingUnderscoreRegex, '')
 }

Add this helper once in the module:

function escapeRegExp(s: string): string {
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

Note: Addresses static analysis warnings on dynamic RegExp construction.

Also applies to: 212-226


356-362: Unused parameter in hasParentRoute signature

useExperimentalNonNestedRoutes is never read. Remove or mark deprecated to avoid confusion; callers already rely on node._isExperimentalNonNestedRoute.


491-497: Potentially redundant cleanup step

removeLayoutSegments strips underscore-prefixed segments already; removeLeadingUnderscores may be redundant here. Consider dropping it for clarity unless you have a case it still affects.


797-803: Fix stale JSDoc wording

Comment says “pathless layout route” but function validates non-nested routes. Update wording to match behavior.

-/**
- * Used to validate if a route is a pathless layout route
+/**
+ * Validates whether a normalized route path represents a non‑nested (pathless) route
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5fdf29 and 1365c21.

📒 Files selected for processing (65)
  • docs/router/framework/react/routing/file-naming-conventions.md (1 hunks)
  • docs/router/framework/react/routing/routing-concepts.md (1 hunks)
  • e2e/react-router/basic-file-based/package.json (1 hunks)
  • e2e/react-router/basic-file-based/playwright.config.ts (2 hunks)
  • e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (1 hunks)
  • e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (1 hunks)
  • e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts (2 hunks)
  • e2e/react-router/basic-file-based/tests/params.spec.ts (3 hunks)
  • e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1 hunks)
  • e2e/react-router/basic-file-based/vite.config.js (1 hunks)
  • e2e/solid-router/basic-file-based/package.json (1 hunks)
  • e2e/solid-router/basic-file-based/playwright.config.ts (2 hunks)
  • e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (1 hunks)
  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (1 hunks)
  • e2e/solid-router/basic-file-based/tests/non-nested-paths.spec.ts (2 hunks)
  • e2e/solid-router/basic-file-based/tests/params.spec.ts (3 hunks)
  • e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1 hunks)
  • e2e/solid-router/basic-file-based/vite.config.js (1 hunks)
  • packages/router-core/src/path.ts (9 hunks)
  • packages/router-core/src/process-route-tree.ts (2 hunks)
  • packages/router-core/tests/match-by-path.test.ts (0 hunks)
  • packages/router-core/tests/path.test.ts (0 hunks)
  • packages/router-generator/src/config.ts (1 hunks)
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts (4 hunks)
  • packages/router-generator/src/generator.ts (10 hunks)
  • packages/router-generator/src/types.ts (2 hunks)
  • packages/router-generator/src/utils.ts (15 hunks)
  • packages/router-generator/tests/deny-route-group-config.test.ts (3 hunks)
  • packages/router-generator/tests/generator.test.ts (5 hunks)
  • packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/custom-scaffolding/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/custom-tokens/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/dot-escaped/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/export-variations/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.nonnested.test-d.ts (1 hunks)
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.nonnested.test-d.ts (1 hunks)
  • packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/numbers-in-path/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/path-above-route-in-group/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/prefix-suffix/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/routeFileIgnore/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/routeFilePrefix/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/single-level/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (1 hunks)
  • packages/router-generator/tests/generator/types-disabled/routes/__root.tsx (1 hunks)
  • packages/router-generator/tests/generator/types-disabled/routes/index.tsx (1 hunks)
  • packages/router-generator/tests/generator/types-disabled/routes/posts.tsx (1 hunks)
  • packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx (1 hunks)
  • packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx (1 hunks)
  • packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/virtual-inside-nested/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/generator/virtual/routeTree.nonnested.snapshot.ts (1 hunks)
  • packages/router-generator/tests/utils.test.ts (8 hunks)
💤 Files with no reviewable changes (2)
  • packages/router-core/tests/match-by-path.test.ts
  • packages/router-core/tests/path.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts
  • e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts
  • e2e/react-router/basic-file-based/playwright.config.ts
  • e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
  • e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts
  • e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx
  • e2e/solid-router/basic-file-based/playwright.config.ts
  • packages/router-generator/src/types.ts
  • packages/router-generator/tests/generator/routeFileIgnore/routeTree.nonnested.snapshot.ts
  • e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx
  • e2e/solid-router/basic-file-based/tests/non-nested-paths.spec.ts
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/__root.tsx
  • packages/router-core/src/path.ts
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.nonnested.snapshot.ts
  • packages/router-generator/src/config.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.nonnested.test-d.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.nonnested.test-d.ts
  • packages/router-generator/tests/generator/routeFilePrefix/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/virtual/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/export-variations/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/path-above-route-in-group/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/single-level/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/custom-tokens/routeTree.nonnested.snapshot.ts
  • e2e/solid-router/basic-file-based/tests/params.spec.ts
  • packages/router-generator/tests/generator/numbers-in-path/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/deny-route-group-config.test.ts
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/tests/generator/types-disabled/routes/posts.tsx
  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
  • e2e/react-router/basic-file-based/tests/params.spec.ts
  • packages/router-generator/tests/generator/virtual-inside-nested/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx
  • packages/router-generator/tests/generator/prefix-suffix/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/custom-scaffolding/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/index.tsx
  • packages/router-core/src/process-route-tree.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/dot-escaped/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx
  • packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/utils.test.ts
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts
  • e2e/react-router/basic-file-based/vite.config.js
  • e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts
  • e2e/react-router/basic-file-based/playwright.config.ts
  • e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
  • e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts
  • e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx
  • e2e/solid-router/basic-file-based/playwright.config.ts
  • e2e/solid-router/basic-file-based/package.json
  • e2e/react-router/basic-file-based/package.json
  • e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx
  • e2e/solid-router/basic-file-based/tests/non-nested-paths.spec.ts
  • e2e/solid-router/basic-file-based/tests/params.spec.ts
  • e2e/solid-router/basic-file-based/vite.config.js
  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
  • e2e/react-router/basic-file-based/tests/params.spec.ts
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

Use internal docs links relative to the docs/ folder (e.g., ./guide/data-loading)

Files:

  • docs/router/framework/react/routing/routing-concepts.md
  • docs/router/framework/react/routing/file-naming-conventions.md
docs/{router,start}/**

📄 CodeRabbit inference engine (AGENTS.md)

Place router docs under docs/router/ and start framework docs under docs/start/

Files:

  • docs/router/framework/react/routing/routing-concepts.md
  • docs/router/framework/react/routing/file-naming-conventions.md
**/src/routes/**

📄 CodeRabbit inference engine (AGENTS.md)

Place file-based routes under src/routes/ directories

Files:

  • e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
  • e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx
  • e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx
  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Files:

  • packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js
  • packages/router-generator/src/types.ts
  • packages/router-generator/tests/generator/routeFileIgnore/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/__root.tsx
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.nonnested.snapshot.ts
  • packages/router-generator/src/config.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.nonnested.test-d.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.nonnested.test-d.ts
  • packages/router-generator/tests/generator/routeFilePrefix/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/virtual/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/export-variations/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/path-above-route-in-group/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/single-level/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/custom-tokens/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/numbers-in-path/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/deny-route-group-config.test.ts
  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/tests/generator/types-disabled/routes/posts.tsx
  • packages/router-generator/tests/generator/virtual-inside-nested/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/users.$userId.tsx
  • packages/router-generator/tests/generator/prefix-suffix/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/custom-scaffolding/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/index.tsx
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/dot-escaped/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/types-disabled/routes/posts/$postId.tsx
  • packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/tests/utils.test.ts
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

Use workspace:* protocol for internal dependencies in package.json files

Files:

  • e2e/solid-router/basic-file-based/package.json
  • e2e/react-router/basic-file-based/package.json
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/path.ts
  • packages/router-core/src/process-route-tree.ts
🧠 Learnings (1)
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
PR: TanStack/router#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/types-disabled/routeTree.nonnested.snapshot.js
  • packages/router-generator/tests/generator/routeFileIgnore/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/routeFilePrefix/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/virtual/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/path-above-route-in-group/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/single-level/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/custom-tokens/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/custom-scaffolding/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/only-root/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/route-groups/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.nonnested.snapshot.ts
  • packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts
🧬 Code graph analysis (42)
e2e/react-router/basic-file-based/playwright.config.ts (2)
e2e/e2e-utils/src/derivePort.ts (2)
  • getTestServerPort (25-27)
  • getDummyServerPort (21-23)
e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (3)
e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (1)
  • Route (4-6)
e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx (1)
  • Route (3-5)
e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts (1)
e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (3)
e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/route.tsx (1)
  • Route (3-5)
e2e/react-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/route.tsx (1)
  • Route (3-3)
e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (1)
  • routeTree (93-95)
e2e/solid-router/basic-file-based/playwright.config.ts (2)
e2e/e2e-utils/src/derivePort.ts (2)
  • getTestServerPort (25-27)
  • getDummyServerPort (21-23)
e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
packages/router-generator/tests/generator/routeFileIgnore/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (18-20)
  • FileRoutesByTo (21-23)
  • FileRoutesById (24-27)
  • FileRouteTypes (28-35)
  • RootRouteChildren (36-38)
  • routeTree (55-57)
packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (68-78)
  • FileRoutesByTo (79-87)
  • FileRoutesById (88-99)
  • FileRouteTypes (100-133)
  • RootRouteChildren (134-139)
  • routeTree (245-247)
e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (1)
e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
e2e/solid-router/basic-file-based/tests/non-nested-paths.spec.ts (1)
e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (53-59)
  • FileRoutesByTo (60-66)
  • FileRoutesById (67-74)
  • FileRouteTypes (75-88)
  • RootRouteChildren (89-94)
  • routeTree (153-155)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.snapshot.ts (1)
  • FileRoutesByPath (97-133)
packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/nested-route-groups-with-layouts-before-physical/routeTree.snapshot.ts (1)
  • FileRouteTypes (96-114)
packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts (2)
  • FileRoutesByFullPath (68-78)
  • routeTree (245-247)
packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts (2)
  • FileRoutesByFullPath (70-80)
  • routeTree (329-331)
packages/router-generator/tests/generator/routeFilePrefix/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/export-variations/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (27-30)
  • FileRoutesByTo (31-34)
  • FileRoutesById (35-39)
  • FileRouteTypes (40-47)
  • RootRouteChildren (48-51)
  • routeTree (76-78)
packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (1)
  • IndexRoute (22-26)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (58-64)
  • FileRoutesByTo (65-71)
  • FileRoutesById (72-79)
  • FileRouteTypes (80-93)
  • RootRouteChildren (94-99)
  • routeTree (205-207)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.snapshot.ts (1)
  • FileRoutesByPath (97-133)
packages/router-generator/tests/generator/virtual/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (5)
  • FileRoutesByFullPath (32-36)
  • FileRoutesByTo (37-41)
  • FileRoutesById (42-47)
  • FileRouteTypes (48-55)
  • routeTree (93-95)
packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts (5)
  • FileRoutesByFullPath (13-13)
  • FileRoutesByTo (14-14)
  • FileRoutesById (15-17)
  • FileRouteTypes (18-25)
  • routeTree (33-35)
packages/router-generator/tests/generator/nested-layouts/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (5)
  • FileRoutesByFullPath (32-36)
  • FileRoutesByTo (37-41)
  • FileRoutesById (42-47)
  • FileRouteTypes (48-55)
  • routeTree (93-95)
packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (32-36)
  • FileRoutesByTo (37-41)
  • FileRoutesById (42-47)
  • FileRouteTypes (48-55)
  • RootRouteChildren (56-60)
  • routeTree (93-95)
packages/router-generator/tests/generator/export-variations/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/export-variations/routeTree.snapshot.ts (1)
  • FileRouteTypes (40-47)
packages/router-generator/tests/generator/no-duplicate-route-segment/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (32-36)
  • FileRoutesByTo (37-41)
  • FileRoutesById (42-47)
  • FileRouteTypes (48-55)
  • RootRouteChildren (56-60)
  • routeTree (93-95)
packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (18-20)
  • FileRoutesByTo (21-23)
  • FileRoutesById (24-27)
  • FileRouteTypes (28-35)
  • RootRouteChildren (36-38)
  • routeTree (55-57)
packages/router-generator/src/filesystem/physical/getRouteNodes.ts (1)
packages/router-generator/src/utils.ts (1)
  • determineInitialRoutePath (57-144)
packages/router-generator/src/utils.ts (3)
packages/router-generator/src/config.ts (1)
  • Config (66-66)
packages/router-generator/src/index.ts (1)
  • rootPathId (45-45)
packages/router-generator/src/types.ts (1)
  • RouteNode (1-18)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts (1)
  • FileRouteTypes (36-43)
packages/router-generator/tests/generator/path-above-route-in-group/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (68-78)
  • FileRoutesByTo (79-87)
  • FileRoutesById (88-99)
  • FileRouteTypes (100-133)
  • RootRouteChildren (134-139)
  • routeTree (245-247)
packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts (6)
  • FileRoutesByFullPath (13-13)
  • FileRoutesByTo (14-14)
  • FileRoutesById (15-17)
  • FileRouteTypes (18-25)
  • RootRouteChildren (26-26)
  • routeTree (33-35)
packages/router-generator/tests/generator/single-level/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (3)
  • PostsRoute (17-21)
  • IndexRoute (22-26)
  • rootRouteChildren (44-48)
packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (18-20)
  • FileRoutesByTo (21-23)
  • FileRoutesById (24-27)
  • FileRouteTypes (28-35)
  • RootRouteChildren (36-38)
  • routeTree (55-57)
packages/router-generator/tests/generator/custom-tokens/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (68-78)
  • FileRoutesByTo (79-87)
  • FileRoutesById (88-99)
  • FileRouteTypes (100-133)
  • RootRouteChildren (134-139)
  • routeTree (245-247)
e2e/solid-router/basic-file-based/tests/params.spec.ts (1)
e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
packages/router-generator/tests/generator/numbers-in-path/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts (3)
  • FileRoutesByPath (83-119)
  • FileRouteTypes (66-73)
  • FileRoutesByFullPath (44-50)
packages/router-generator/tests/deny-route-group-config.test.ts (1)
packages/router-generator/src/config.ts (2)
  • Config (66-66)
  • getConfig (76-151)
packages/router-generator/tests/generator.test.ts (1)
packages/router-generator/src/config.ts (2)
  • Config (66-66)
  • getConfig (76-151)
e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (2)
e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (1)
  • Route (4-6)
e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
e2e/react-router/basic-file-based/tests/params.spec.ts (1)
e2e/react-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
packages/router-generator/tests/generator/virtual-inside-nested/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (3)
  • FileRouteTypes (48-55)
  • RootRouteChildren (56-60)
  • routeTree (93-95)
packages/router-generator/tests/generator/file-modification-verboseFileRoutes-true/routeTree.snapshot.ts (1)
  • FileRoutesByPath (97-133)
packages/router-generator/tests/generator/prefix-suffix/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (32-36)
  • FileRoutesByTo (37-41)
  • FileRoutesById (42-47)
  • FileRouteTypes (48-55)
  • RootRouteChildren (56-60)
  • routeTree (93-95)
packages/router-generator/tests/generator/custom-scaffolding/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (1)
  • IndexRoute (22-26)
packages/router-core/src/process-route-tree.ts (2)
packages/router-core/src/path.ts (1)
  • parsePathname (204-215)
packages/router-core/src/index.ts (1)
  • parsePathname (103-103)
packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.nonnested.snapshot.ts (1)
e2e/react-router/js-only-file-based/src/routeTree.gen.js (4)
  • PostsRouteRoute (25-29)
  • PostsIndexRoute (35-39)
  • PostsRouteRouteWithChildren (68-70)
  • PostsRouteRouteChildren (63-66)
packages/router-generator/tests/generator/dot-escaped/routeTree.nonnested.snapshot.ts (1)
packages/router-generator/tests/generator/export-variations/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (27-30)
  • FileRoutesByTo (31-34)
  • FileRoutesById (35-39)
  • FileRouteTypes (40-47)
  • RootRouteChildren (48-51)
  • routeTree (76-78)
packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.nonnested.snapshot.ts (3)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (32-36)
  • FileRoutesByTo (37-41)
  • FileRoutesById (42-47)
  • FileRouteTypes (48-55)
  • RootRouteChildren (56-60)
  • routeTree (93-95)
packages/router-generator/tests/generator/append-and-prepend/routeTree.nonnested.snapshot.ts (6)
  • FileRoutesByFullPath (18-20)
  • FileRoutesByTo (21-23)
  • FileRoutesById (24-27)
  • FileRouteTypes (28-35)
  • RootRouteChildren (36-38)
  • routeTree (55-57)
packages/router-generator/tests/generator/only-root/routeTree.nonnested.generated.snapshot.ts (6)
  • FileRoutesByFullPath (13-13)
  • FileRoutesByTo (14-14)
  • FileRoutesById (15-17)
  • FileRouteTypes (18-25)
  • RootRouteChildren (26-26)
  • routeTree (33-35)
packages/router-generator/tests/generator/flat/routeTree.nonnested.snapshot.ts (1)
e2e/react-router/js-only-file-based/src/routeTree.gen.js (4)
  • PostsRouteRoute (25-29)
  • PostsIndexRoute (35-39)
  • PostsRouteRouteWithChildren (68-70)
  • PostsRouteRouteChildren (63-66)
packages/router-generator/src/generator.ts (3)
packages/router-generator/src/utils.ts (8)
  • createRouteNodesByFullPath (505-515)
  • createRouteNodesByTo (520-530)
  • resetRegex (291-294)
  • hasParentRoute (356-443)
  • removeGroups (312-314)
  • removeLeadingUnderscores (196-210)
  • removeLayoutSegments (324-328)
  • removeUnderscores (192-194)
packages/router-generator/src/types.ts (2)
  • RouteNode (1-18)
  • HandleNodeAccumulator (55-59)
packages/router-generator/src/config.ts (1)
  • Config (66-66)
packages/router-generator/tests/utils.test.ts (2)
packages/router-generator/src/utils.ts (5)
  • determineInitialRoutePath (57-144)
  • removeLeadingUnderscores (196-210)
  • removeTrailingUnderscores (212-226)
  • routePathToVariable (150-190)
  • isValidNonNestedRoute (803-843)
packages/router-generator/src/types.ts (1)
  • ImportDeclaration (49-53)
🪛 ast-grep (0.39.5)
packages/router-generator/src/utils.ts

[warning] 205-205: 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((?<=^|\\/)_(?!${routeTokenToExclude}), 'g')
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] 221-221: 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((?<!${routeTokenToExclude})_(?=\\/|$), 'g')
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/only-root/routeTree.nonnested.generated.snapshot.ts

[error] 13-13: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 14-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 26-26: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

packages/router-generator/tests/generator/only-root/routeTree.nonnested.snapshot.ts

[error] 13-13: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 14-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 26-26: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

⏰ 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: Preview
  • GitHub Check: Test

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: 1

🧹 Nitpick comments (3)
e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (1)

2-2: Consider renaming the imported constant.

The useExperimentalNonNestedRoutes identifier follows React/Solid hook naming conventions (prefixed with "use"), but it's actually a boolean constant, not a function or hook. Consider renaming it to something like isExperimentalNonNestedRoutesEnabled or EXPERIMENTAL_NON_NESTED_ROUTES to avoid confusion.

packages/router-generator/src/utils.ts (2)

196-212: Consider the regex complexity and potential alternatives.

The removeLeadingUnderscores function constructs regexes dynamically from routeToken. While escapeRegExp mitigates ReDoS risks, the regex logic is complex with negative lookahead/lookbehind assertions:

  • Line 208: (?<=^|\\/)_(?!${escapeRegExp(routeTokenToExclude)})

For maintainability and potential performance improvements, consider whether a simpler string-based approach could achieve the same result (e.g., split, filter, and rejoin based on position and routeToken context). However, if the current regex approach is well-tested and performs adequately, it may be acceptable to defer this optimization.

Note: The static analysis warning about ReDoS at line 207 is likely a false positive given the escapeRegExp call, but the complexity warrants attention.


214-226: Consider the regex complexity and potential alternatives.

The removeTrailingUnderscores function has similar complexity to removeLeadingUnderscores, using dynamic regex construction with negative lookbehind:

  • Line 222: (?<!${escapeRegExp(routeTokenToExclude)})_(?=\\/|$)

The same maintainability and performance considerations apply. While escapeRegExp mitigates ReDoS risks, the regex complexity could be reduced with a string-based approach if performance or maintainability becomes a concern.

Note: The static analysis warning about ReDoS at line 221 is likely a false positive given the escapeRegExp call, but warrants monitoring.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1365c21 and 638c0db.

📒 Files selected for processing (5)
  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (1 hunks)
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts (3 hunks)
  • packages/router-generator/src/generator.ts (11 hunks)
  • packages/router-generator/src/utils.ts (15 hunks)
  • packages/router-generator/tests/generator.test.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/utils.ts
  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
  • packages/router-generator/src/generator.ts
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Files:

  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/utils.ts
  • packages/router-generator/src/generator.ts
  • packages/router-generator/src/filesystem/physical/getRouteNodes.ts
**/src/routes/**

📄 CodeRabbit inference engine (AGENTS.md)

Place file-based routes under src/routes/ directories

Files:

  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx
🧬 Code graph analysis (5)
packages/router-generator/tests/generator.test.ts (1)
packages/router-generator/src/config.ts (2)
  • Config (66-66)
  • getConfig (76-151)
packages/router-generator/src/utils.ts (3)
packages/router-generator/src/config.ts (1)
  • Config (66-66)
packages/router-generator/src/index.ts (1)
  • rootPathId (45-45)
packages/router-generator/src/types.ts (1)
  • RouteNode (1-18)
e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (2)
e2e/solid-router/basic-file-based/src/routes/params-ps/non-nested/$foo_/$bar.tsx (1)
  • Route (4-6)
e2e/solid-router/basic-file-based/tests/utils/useExperimentalNonNestedRoutes.ts (1)
  • useExperimentalNonNestedRoutes (1-6)
packages/router-generator/src/generator.ts (3)
packages/router-generator/src/utils.ts (8)
  • createRouteNodesByFullPath (495-505)
  • createRouteNodesByTo (510-520)
  • resetRegex (291-294)
  • hasParentRoute (356-436)
  • removeGroups (312-314)
  • removeLeadingUnderscores (200-212)
  • removeLayoutSegments (324-328)
  • removeUnderscores (192-194)
packages/router-generator/src/types.ts (2)
  • RouteNode (1-18)
  • HandleNodeAccumulator (55-59)
packages/router-generator/src/config.ts (1)
  • Config (66-66)
packages/router-generator/src/filesystem/physical/getRouteNodes.ts (1)
packages/router-generator/src/utils.ts (1)
  • determineInitialRoutePath (57-144)
🪛 ast-grep (0.39.5)
packages/router-generator/src/utils.ts

[warning] 207-207: 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((?<=^|\\/)_(?!${escapeRegExp(routeTokenToExclude)}), 'g')
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] 221-221: 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((?<!${escapeRegExp(routeTokenToExclude)})_(?=\\/|$), 'g')
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)

⏰ 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). (1)
  • GitHub Check: Test
🔇 Additional comments (18)
e2e/solid-router/basic-file-based/src/routes/posts_.$postId.edit.tsx (2)

1-2: LGTM! Imports are clean and properly consolidated.

The addition of useExperimentalNonNestedRoutes is appropriate for testing both feature-flag modes in this e2e test file.


8-11: Runtime-conditional routes are test-only
Confirmed that conditional getRouteApi and useParams patterns appear only under e2e/, not in production code.

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

43-64: LGTM!

The nonNested parameter is correctly threaded through the configuration and properly controls both the generated route tree filename and the experimental flag.


249-252: LGTM!

The test case generation using flatMap to run each test with both nonNested: true and nonNested: false is a clean approach for comprehensive coverage.


254-287: LGTM!

The test orchestration correctly passes the nonNested flag through the configuration pipeline and adjusts snapshot paths accordingly.


289-343: LGTM!

The directory creation test correctly handles both nonNested modes and properly constructs file paths and snapshot references.

packages/router-generator/src/filesystem/physical/getRouteNodes.ts (3)

37-37: LGTM!

The addition of 'experimental' to the config type correctly enables access to the experimental feature flags.


135-141: LGTM!

The call to determineInitialRoutePath correctly handles the updated return type, destructuring all three fields (routePath, originalRoutePath, isExperimentalNonNestedRoute) from the result.


196-204: LGTM!

The addition of _isExperimentalNonNestedRoute and originalRoutePath to the RouteNode correctly preserves experimental non-nested route metadata for downstream processing.

packages/router-generator/src/generator.ts (3)

678-732: LGTM!

The config is correctly threaded through createRouteNodesByFullPath, createRouteNodesByTo, and buildFileRoutesByPathInterface to enable config-driven path generation for the TypeScript interface types.


1190-1246: LGTM!

The handleNode method correctly implements the experimental non-nested routes behavior by conditionally applying removeLeadingUnderscores instead of removeUnderscores. The logic properly:

  1. Derives the experimental flag from config
  2. Passes originalRoutePath to hasParentRoute for accurate parent resolution
  3. Applies the appropriate path cleaning based on the feature flag

The TODO comments appropriately document the intended breaking change in a future major version.


1280-1288: LGTM!

The recursive handleNode calls correctly pass the config parameter through, ensuring consistent behavior for virtual nodes and parent nodes.

Also applies to: 1327-1335

packages/router-generator/src/utils.ts (6)

57-144: LGTM!

The updated determineInitialRoutePath correctly implements the experimental non-nested routes feature by:

  1. Preserving the originalRoutePath before transformations for downstream use
  2. Determining whether the route qualifies as experimental non-nested via isValidNonNestedRoute
  3. Conditionally removing trailing underscores only when the feature flag is enabled and the route is not the root path
  4. Maintaining the existing escaping logic for bracket content

The change from returning a string to returning an object is a necessary breaking change to support the feature, and all call sites have been updated accordingly.


356-436: LGTM with note on complexity.

The hasParentRoute function correctly implements the experimental non-nested routes feature with custom parent resolution logic. The key changes:

  1. Adds originalRoutePathToCheck parameter to track the original path before transformations
  2. Introduces getNonNestedSegments to identify non-nested route boundaries
  3. Implements special filtering for experimental non-nested routes to exclude conflicting routes and include only layout/root routes that aren't marked as non-nested

The logic is complex but appears intentional for the feature's requirements. The bracket-matching filter in getNonNestedSegments (lines 366-371) correctly handles escaped characters in route paths.


477-490: LGTM!

The inferFullPath function correctly implements the experimental behavior by:

  • Preserving trailing underscores when the experimental flag is enabled (using removeLayoutSegments only)
  • Maintaining backward compatibility with the existing behavior (using removeUnderscores) when the flag is off

The TODO comment appropriately documents the intended breaking change in a future major version.


495-548: LGTM!

The functions createRouteNodesByFullPath, createRouteNodesByTo, and inferTo correctly thread the optional config parameter through the path inference pipeline, enabling config-driven path generation.


715-741: LGTM!

The buildFileRoutesByPathInterface function correctly accepts the optional config parameter and passes it to inferFullPath (line 733) for accurate type generation.


787-833: LGTM!

The isValidNonNestedRoute function correctly implements the validation logic for experimental non-nested routes by:

  1. Returning false early when the feature flag is not enabled
  2. Checking if the last segment ends with an underscore (excluding indexToken and routeToken)
  3. Iterating through intermediate segments in reverse to find trailing underscores
  4. Excluding the rootPathId from being considered non-nested

The logic correctly identifies non-nested routes based on trailing underscore markers while respecting the configuration tokens.

@nlynzaad
Copy link
Contributor Author

nlynzaad commented Oct 7, 2025

test failure is due to the ci: automated fixes changing layout of test snapshot resulting in failure when matching formatting.

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: 1

♻️ Duplicate comments (1)
packages/router-generator/tests/generator.test.ts (1)

117-118: Fix the path construction to match line 49.

Line 118 is missing a dot after routeTree, causing inconsistent naming. When nonNested is true, the path becomes /routeTreenonnested..gen.js (missing separator dot, double dot before gen), while line 49 correctly produces /routeTree.nonnested.gen.ts.

Apply this diff to fix the path construction:

       config.generatedRouteTree =
         makeFolderDir(folderName) +
-        `/routeTree${nonNested ? 'nonnested.' : ''}.gen.js`
+        `/routeTree.${nonNested ? 'nonnested.' : ''}gen.js`
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 638c0db and f4a5975.

📒 Files selected for processing (2)
  • packages/router-generator/src/utils.ts (15 hunks)
  • packages/router-generator/tests/generator.test.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/utils.ts
packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Files:

  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/utils.ts
🧬 Code graph analysis (2)
packages/router-generator/tests/generator.test.ts (1)
packages/router-generator/src/config.ts (2)
  • Config (66-66)
  • getConfig (76-151)
packages/router-generator/src/utils.ts (3)
packages/router-generator/src/config.ts (1)
  • Config (66-66)
packages/router-generator/src/index.ts (1)
  • rootPathId (45-45)
packages/router-generator/src/types.ts (1)
  • RouteNode (1-18)
🪛 ast-grep (0.39.5)
packages/router-generator/src/utils.ts

[warning] 209-209: 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((?<=^|\\/)_(?!${escapedRouteToken}), 'g')
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((?<!${escapedRouteToken})_(?=\\/|$), 'g')
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)

🔇 Additional comments (7)
packages/router-generator/tests/generator.test.ts (2)

249-287: LGTM! Comprehensive test coverage for both modes.

The test structure correctly generates test cases for both nonNested: true and nonNested: false scenarios across all folders. The snapshot path construction consistently uses the correct pattern, and the nonNested parameter is properly threaded through setupConfig and rewriteConfigByFolderName.


289-343: LGTM! Directory creation test properly covers both modes.

The directory creation test correctly handles both nonNested scenarios with proper cleanup logic and snapshot path construction matching the pattern established in the main test.

packages/router-generator/src/utils.ts (5)

57-144: LGTM! Well-structured refactoring with backward compatibility.

The function correctly:

  1. Returns a structured object with routePath, isExperimentalNonNestedRoute, and originalRoutePath
  2. Gates the non-nested route handling behind config?.experimental?.nonNestedRoutes
  3. Removes trailing underscores early (before escaping) to preserve escaped trailing underscores
  4. Maintains backward compatibility when the feature flag is disabled

The comment at lines 82-83 notes the TODO for renaming when no longer experimental, which is appropriate.


196-214: LGTM! Standard regex escaping with proper safeguards.

The escapeRegExp function provides standard protection against regex injection. removeLeadingUnderscores correctly handles the edge case where routeToken itself starts with an underscore by excluding it from the removal pattern.

Note: The static analysis tool flags line 209 as a potential ReDoS risk. However, this is a false positive since routeToken comes from the developer-controlled Config object (not runtime user input) and is properly escaped.


481-552: LGTM! Consistent config propagation pattern.

The config parameter is correctly threaded through:

  • inferFullPath → uses config to determine underscore removal strategy
  • createRouteNodesByFullPath → passes config to inferFullPath
  • createRouteNodesByTo → passes config to inferTo
  • inferTo → delegates to inferFullPath with config

The optional parameter approach maintains backward compatibility while enabling the new experimental feature.


791-837: LGTM! Clear validation logic for non-nested routes.

The isValidNonNestedRoute function correctly:

  1. Gates the check behind the experimental feature flag
  2. Excludes special cases (root route, empty paths)
  3. Identifies non-nested routes by checking for trailing underscores in segments
  4. Excludes indexToken and routeToken from the trailing underscore check
  5. Properly handles multi-segment paths by walking backwards

The logic aligns with the file-based routing convention where trailing underscores denote pathless routes.


360-440: Add unit tests for non-nested parent route resolution.

No existing tests cover the _isExperimentalNonNestedRoute branch in hasParentRoute. Add tests for:

  • Multiple levels of non-nested routes
  • Mixed nested and non-nested routes
  • Segments with 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: 1

♻️ Duplicate comments (2)
packages/router-generator/tests/generator.test.ts (1)

43-64: LGTM! Clean parameter addition.

The nonNested parameter is properly threaded through the config setup, with correct destructuring and default value handling.

packages/router-generator/src/utils.ts (1)

218-234: LGTM! Correct implementation of removeTrailingUnderscores.

The function correctly checks if the route token ends with an underscore using routeToken.slice(-1) === '_' at line 221 (the past review comment flagging line 225 is outdated). The regex construction with negative lookbehind properly excludes the route token from removal.

Note: The static analysis warning about ReDoS at line 230 is a false positive since routeToken is developer-controlled configuration.

🧹 Nitpick comments (1)
packages/router-generator/src/utils.ts (1)

76-76: Consider extracting splitRegex to module level.

The splitRegex pattern /(?<!\[)\.(?!\])/g is defined identically at both lines 76 and 106 (after variable assignment). Since this regex is used consistently throughout the function, consider extracting it to a module-level constant for maintainability.

Apply this diff to extract the regex:

 const BRACKET_CONTENT_RE = /\[(.*?)\]/g
+const SPLIT_REGEX = /(?<!\[)\.(?!\])/g

 export function determineInitialRoutePath(
   routePath: string,
   config?: Pick<Config, 'experimental' | 'routeToken' | 'indexToken'>,
 ) {
   ...
-  const splitRegex = /(?<!\[)\.(?!\])/g
-
   const originalRoutePath =
-    cleanPath(`/${(cleanPath(routePath) || '').split(splitRegex).join('/')}`) ||
+    cleanPath(`/${(cleanPath(routePath) || '').split(SPLIT_REGEX).join('/')}`) ||
     ''
   ...
-  const parts = cleanedRoutePath.split(splitRegex)
+  const parts = cleanedRoutePath.split(SPLIT_REGEX)

Also applies to: 106-106

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4a5975 and 16db1a5.

📒 Files selected for processing (3)
  • packages/router-generator/src/utils.ts (15 hunks)
  • packages/router-generator/tests/generator.test.ts (5 hunks)
  • packages/router-generator/tests/utils.test.ts (8 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/utils.test.ts
packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Files:

  • packages/router-generator/tests/generator.test.ts
  • packages/router-generator/src/utils.ts
  • packages/router-generator/tests/utils.test.ts
🧬 Code graph analysis (3)
packages/router-generator/tests/generator.test.ts (1)
packages/router-generator/src/config.ts (2)
  • Config (66-66)
  • getConfig (76-151)
packages/router-generator/src/utils.ts (3)
packages/router-generator/src/config.ts (1)
  • Config (66-66)
packages/router-generator/src/index.ts (1)
  • rootPathId (45-45)
packages/router-generator/src/types.ts (1)
  • RouteNode (1-18)
packages/router-generator/tests/utils.test.ts (2)
packages/router-generator/src/utils.ts (5)
  • determineInitialRoutePath (57-144)
  • removeLeadingUnderscores (200-216)
  • removeTrailingUnderscores (218-234)
  • routePathToVariable (150-190)
  • isValidNonNestedRoute (801-841)
packages/router-generator/src/types.ts (1)
  • ImportDeclaration (49-53)
🪛 ast-grep (0.39.5)
packages/router-generator/src/utils.ts

[warning] 211-211: 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((?<=^|\\/)_(?!${escapedRouteToken}), 'g')
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] 229-229: 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((?<!${escapedRouteToken})_(?=\\/|$), 'g')
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)

⏰ 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 (11)
packages/router-generator/tests/utils.test.ts (4)

22-32: LGTM! Excellent use of parameterized tests.

The describe.each pattern effectively tests both experimental non-nested and default modes, ensuring consistent behavior across configurations.


90-102: LGTM! Proper error handling test pattern.

The test correctly uses vi.spyOn to verify error messages and properly restores the console spy afterward.


118-173: LGTM! Comprehensive trailing underscore test coverage.

The tests thoroughly cover various edge cases including route tokens with leading/trailing underscores, escaped underscores, and different path structures.


373-405: LGTM! Good coverage of non-nested route validation.

The tests verify both valid and invalid non-nested routes, and confirm that the feature is properly gated behind the experimental flag.

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

72-160: LGTM! Consistent non-nested handling across test cases.

The rewriteConfigByFolderName function correctly propagates the nonNested parameter and updates file paths accordingly for each test case.


246-287: LGTM! Effective test parameterization.

The flatMap pattern creates comprehensive test coverage by running each folder test with both nonNested: true and nonNested: false, ensuring backward compatibility while testing the new feature.

packages/router-generator/src/utils.ts (5)

57-144: LGTM! Well-structured refactor of determineInitialRoutePath.

The function now returns an object with routePath, isExperimentalNonNestedRoute, and originalRoutePath, which provides callers with complete context about the path transformation. The early detection and removal of trailing underscores (lines 91-104) before escaping is the correct approach to preserve escaped underscores.


196-216: LGTM! Correct implementation of removeLeadingUnderscores.

The function properly handles route tokens that start with underscores by excluding them from removal. The regex construction with negative lookahead is correct.

Note: The static analysis warning about ReDoS at line 212 is a false positive since routeToken is developer-controlled configuration.


364-444: Complex but correct non-nested route parent resolution.

The hasParentRoute function handles non-nested routes by:

  1. Bypassing standard parent lookup when _isExperimentalNonNestedRoute is true (lines 393-395)
  2. Using getNonNestedSegments helper to identify non-nested segments (lines 370-382)
  3. Special logic to find parents among other non-nested routes or layout/pathless routes (lines 397-426)

The logic is intricate but appears correct for the feature requirements.


485-498: LGTM! Config-driven path inference.

The inferFullPath function now conditionally applies removeLayoutSegments or removeUnderscores + removeLayoutSegments based on the experimental flag, properly supporting both modes.


801-841: LGTM! Clear non-nested route validation logic.

The isValidNonNestedRoute function correctly:

  1. Guards against disabled feature (lines 805-807)
  2. Validates segment structure (lines 809-813)
  3. Excludes __root (lines 818-820)
  4. Checks for trailing underscores in the last segment (lines 822-828)
  5. Traverses parent segments checking for non-nested patterns (lines 830-838)

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d692497 and 43220cf.

📒 Files selected for processing (2)
  • packages/router-generator/.prettierignore (1 hunks)
  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/router-generator/.prettierignore
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts
packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Files:

  • packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts
🧠 Learnings (1)
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
PR: TanStack/router#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/no-formatted-route-tree/routeTree.nonnested.snapshot.ts
🧬 Code graph analysis (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (2)
packages/router-generator/tests/generator/types-disabled/routeTree.nonnested.snapshot.js (1)
  • IndexRoute (22-26)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts (1)
  • FileRouteTypes (36-43)
⏰ 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 (1)
packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts (1)

11-77: Non-nested routing structure is correctly implemented.

The snapshot correctly demonstrates non-nested routing behavior where all routes (IndexRoute, NestedIndexRoute, NestedChildRoute) are direct children of the root route rather than being nested. The type interfaces, module augmentation, and route tree assembly follow the expected pattern for generated route trees.

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.

1 participant