Skip to content

perf: use slice for proven ordered bounds - #7977

Open
Sheraff wants to merge 5 commits into
mainfrom
codex/shorter-string-operations
Open

perf: use slice for proven ordered bounds#7977
Sheraff wants to merge 5 commits into
mainfrom
codex/shorter-string-operations

Conversation

@Sheraff

@Sheraff Sheraff commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Replace 24 internal substring calls with shorter slice calls only where both bounds are proven non-negative and ordered.

The five extraction sites whose bounds can reverse remain substring; focused tests cover overlapping named, optional, and wildcard affixes plus Unicode lowercase expansion. No public API or browser-support floor changes.

Bundle impact

Measured from clean commit ae8b0397cf0a6813ea380fae4903371fd5d83ae5 against exact main base 697ebb6ddbd433d052b6b4707938a5c595865d58:

  • all 17 scenarios improve total gzip by 2–23 bytes
  • raw size improves by 84–88 bytes in every scenario
  • one initial-gzip metric regresses by 3 bytes; mixed Brotli results are disclosed in the checked-in report
  • no imports, helpers, exports, or tree-shaking boundaries change

A nearby indexOfincludes group was dropped after its isolated performance result was not confidently neutral.

Performance and validation

  • direct ordered-bound benchmark: slice averages 10.34% faster than substring across four final runs
  • real API benchmarks are flat to positive except a noisy search-prefix case with alternating paired direction
  • router-core path suite: 361/361 passed with no type errors
  • package unit, type, and lint validation passed for history, router-core, React Router, and Solid Router
  • five independent semantic, compatibility, performance, tree-shaking, test, and measurement reviews approved the clean final diff

Full attribution, matrix, performance results, and rejected variants are in RESULT-optimization-shorter-string-operations.md.

Summary by CodeRabbit

  • Performance

    • Improved efficiency of route and URL string processing without changing routing behavior or public APIs.
  • Bug Fixes

    • Improved handling of overlapping wildcard and named route parameters, including optional parameters.
    • Fixed edge cases involving suffixes whose lowercase conversion changes string length.
    • Preserved correct captured values for required and optional parameters.
  • Documentation

    • Added performance benchmarks and validation results for route, path, and search parsing operations.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change replaces 24 safe substring calls with slice across history and router-core code. It adds routing regression tests, focused benchmarks, and a report covering bundle sizes, semantic safeguards, validation, and rejected alternatives.

Changes

String slicing optimization

Layer / File(s) Summary
Safe slice replacements
packages/history/src/index.ts, packages/router-core/src/{new-process-route-tree.ts,path.ts,searchParams.ts}
Replaces safe string extraction calls with slice without changing public APIs or routing behavior.
Routing validation and benchmarks
packages/router-core/tests/path.test.ts, packages/router-core/tests/path-string-operations.bench.ts
Adds overlap and Unicode regression cases, equivalent-operation assertions, and benchmarks for routing and string workloads.
Optimization results report
RESULT-optimization-shorter-string-operations.md
Records replacement constraints, bundle measurements across 17 scenarios, validation results, benchmark comparisons, and rejected includes changes.

Estimated code review effort: 2 (Simple) | ~15 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main performance change: replacing safe ordered-bound substring calls with slice.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/shorter-string-operations

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

❤️ Share

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

@nx-cloud

nx-cloud Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 95bacef

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

☁️ Nx Cloud last updated this comment at 2026-08-08 06:29:57 UTC

@pkg-pr-new

pkg-pr-new Bot commented Aug 6, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7977

@tanstack/eslint-plugin-router

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

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@7977

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7977

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7977

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7977

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@7977

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7977

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7977

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7977

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7977

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7977

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7977

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7977

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7977

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7977

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7977

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7977

@tanstack/vue-router

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

@tanstack/vue-router-devtools

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

@tanstack/vue-router-ssr-query

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

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7977

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7977

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7977

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7977

commit: 95bacef

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Benchmarks

  • Commit: dee7f54e8e34
  • Measured at: 2026-08-08T06:18:36.671Z
  • Baseline source: history:4fa1df75402c
  • Dashboard: bundle-size history

The following scenarios have bundle-size changes compared with the baseline:

Scenario Current (gzip) Delta vs baseline Initial gzip Raw Brotli Trend
react-router.minimal 83.90 KiB -9 B (-0.01%) 83.76 KiB 262.54 KiB 72.96 KiB ██████████▁▁
react-router.full 87.39 KiB -3 B (-0.00%) 87.26 KiB 274.26 KiB 75.98 KiB ██████████▁▁
solid-router.minimal 33.21 KiB -8 B (-0.02%) 33.09 KiB 96.38 KiB 29.99 KiB █▇▇▇▇▇▇▇▇▇▁▁
solid-router.full 38.04 KiB -9 B (-0.02%) 37.91 KiB 111.02 KiB 34.23 KiB █▇▇▇▇▇▇▇▇▇▁▁
vue-router.minimal 49.49 KiB -11 B (-0.02%) 49.36 KiB 138.13 KiB 44.67 KiB █▇▇▇▇▇▇▇▇▇▁▁
vue-router.full 55.06 KiB -11 B (-0.02%) 54.94 KiB 156.30 KiB 49.57 KiB █▇▇▇▇▇▇▇▇▇▁▁
react-start.deferred-hydration 97.38 KiB -5 B (-0.01%) 96.54 KiB 306.08 KiB 84.41 KiB ██████████▁▁
react-start.full 99.83 KiB -7 B (-0.01%) 99.69 KiB 314.43 KiB 86.50 KiB ██████████▁▁
react-start.rsbuild.minimal 99.99 KiB -8 B (-0.01%) 99.81 KiB 315.26 KiB 86.26 KiB █▁▁▁▂▂▂▂▂▂▂▂
react-start.rsbuild.minimal-iife 100.39 KiB -10 B (-0.01%) 100.23 KiB 316.19 KiB 86.60 KiB █▁▁▁▂▂▂▂▂▂▂▂
react-start.rsbuild.full 103.30 KiB -8 B (-0.01%) 103.13 KiB 325.35 KiB 88.96 KiB █▁▁▁▂▂▂▂▃▃▃▂
solid-start.minimal 45.93 KiB -11 B (-0.02%) 45.81 KiB 137.39 KiB 40.80 KiB █▇▇▇▇▇▇▇▇▇▁▁
solid-start.deferred-hydration 49.00 KiB -6 B (-0.01%) 45.86 KiB 144.85 KiB 43.63 KiB █▇▇▇▇▇▇▇▇▇▁▁
solid-start.full 51.01 KiB -9 B (-0.02%) 50.88 KiB 152.77 KiB 45.25 KiB █▇▇▇▇▇▇▇▇▇▁▁
vue-start.minimal 65.48 KiB -9 B (-0.01%) 65.35 KiB 188.90 KiB 58.30 KiB █▇▇▇▇▇▇▇▇▇▁▁
vue-start.full 69.28 KiB -4 B (-0.01%) 69.16 KiB 201.17 KiB 61.55 KiB █▇▇▇▇▇▇▇▇▇▁▁

Current gzip tracks all emitted client JS chunks. Initial gzip tracks only the entry/import graph. Trend sparkline is historical current gzip ending with this PR measurement; lower is better.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

No changeset entries found. Merging this PR will not cause a version bump for any packages.

@codspeed-hq

codspeed-hq Bot commented Aug 6, 2026

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 4 improved benchmarks
❌ 1 regressed benchmark
✅ 175 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory mem server error-paths unmatched (react) 273.1 KB 1,660.6 KB -83.55%
Memory mem server server-fn-churn (vue) 3,927.3 KB 263.2 KB ×15
Memory mem server peak-large-page (react) 2,064 KB 953.1 KB ×2.2
Simulation ssr request loop (solid) 152.3 ms 145.5 ms +4.67%
Memory mem server error-paths not-found (vue) 333 KB 319.7 KB +4.19%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing codex/shorter-string-operations (95bacef) with main (4fa1df7)

Open in CodSpeed

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud has identified a possible root cause for your failed CI:

We classified this failure as an environment issue unrelated to the PR. The error originates in a stale e2e-utils dist artifact missing the toRuntimePath export — a build environment problem entirely outside the scope of the substringslice optimization changes in @tanstack/router-core. No changes to this PR are needed to resolve it.

No code changes were suggested for this issue.

Trigger a rerun:

Rerun CI

Nx Cloud View detailed reasoning on Nx Cloud ↗


🎓 Learn more about Self-Healing CI on nx.dev

@Sheraff
Sheraff marked this pull request as ready for review August 8, 2026 07:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (1)
RESULT-optimization-shorter-string-operations.md (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Retain reproducible measurement artifacts.

The report stores the full bundle matrix in /tmp/native-slice-only-full.json. That path is transient and unavailable to later reviewers. Commit the measurement input or document a reproducible command, environment, and artifact location for the reported validation and benchmark results.

Also applies to: 54-74

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@RESULT-optimization-shorter-string-operations.md` at line 17, Make the
benchmark results reproducible by committing the measurement input artifact or
documenting the exact command, environment, and durable artifact location used
to generate the reported validation and benchmark results. Replace the transient
/tmp/native-slice-only-full.json reference in the report and apply the same
change to the related content covering lines 54–74.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/router-core/src/path.ts`:
- Around line 380-390: In the optional-parameter handling branch, update the
guard for missing or undefined valueRaw to use a braced if block while
preserving its continue behavior; leave the surrounding usedParams and
prefix/suffix logic unchanged.

---

Nitpick comments:
In `@RESULT-optimization-shorter-string-operations.md`:
- Line 17: Make the benchmark results reproducible by committing the measurement
input artifact or documenting the exact command, environment, and durable
artifact location used to generate the reported validation and benchmark
results. Replace the transient /tmp/native-slice-only-full.json reference in the
report and apply the same change to the related content covering lines 54–74.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d17e760b-2f63-4977-a555-131f1ad9187b

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa1df7 and 95bacef.

📒 Files selected for processing (7)
  • RESULT-optimization-shorter-string-operations.md
  • packages/history/src/index.ts
  • packages/router-core/src/new-process-route-tree.ts
  • packages/router-core/src/path.ts
  • packages/router-core/src/searchParams.ts
  • packages/router-core/tests/path-string-operations.bench.ts
  • packages/router-core/tests/path.test.ts

Comment on lines 380 to +390
if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
const key = path.substring(segment[2], segment[3])
const key = path.slice(segment[2], segment[3])
const valueRaw = params[key]

// Check if optional parameter is missing or undefined
if (valueRaw == null) continue

usedParams[key] = valueRaw

const prefix = path.substring(start, segment[1])
const suffix = path.substring(segment[4], end)
const prefix = path.slice(start, segment[1])
const suffix = path.slice(segment[4], end)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add braces to the optional-parameter guard.

Line 385 uses a one-line if body. Add braces to meet the TypeScript control-statement rule.

Proposed fix
-      if (valueRaw == null) continue
+      if (valueRaw == null) {
+        continue
+      }

As per coding guidelines, “Always use curly braces for if, else, loops, and similar control statements.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
const key = path.substring(segment[2], segment[3])
const key = path.slice(segment[2], segment[3])
const valueRaw = params[key]
// Check if optional parameter is missing or undefined
if (valueRaw == null) continue
usedParams[key] = valueRaw
const prefix = path.substring(start, segment[1])
const suffix = path.substring(segment[4], end)
const prefix = path.slice(start, segment[1])
const suffix = path.slice(segment[4], end)
if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
const key = path.slice(segment[2], segment[3])
const valueRaw = params[key]
// Check if optional parameter is missing or undefined
if (valueRaw == null) {
continue
}
usedParams[key] = valueRaw
const prefix = path.slice(start, segment[1])
const suffix = path.slice(segment[4], end)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/src/path.ts` around lines 380 - 390, In the
optional-parameter handling branch, update the guard for missing or undefined
valueRaw to use a braced if block while preserving its continue behavior; leave
the surrounding usedParams and prefix/suffix logic unchanged.

Source: Coding guidelines

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