[PR #1080] [MERGED] refactor(config): dedupe regex cache and destination param chain #1077

Closed
opened 2026-05-06 13:11:52 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/1080
Author: @james-elicx
Created: 5/5/2026
Status: Merged
Merged: 5/5/2026
Merged by: @james-elicx

Base: mainHead: refactor/dedupe-config-matchers-internals


📝 Commits (1)

  • 20c404e refactor(config): dedupe regex cache and destination param chain

📊 Changes

1 file changed (+49 additions, -29 deletions)

View changed files

📝 packages/vinext/src/config/config-matchers.ts (+49 -29)

📄 Description

Summary

Two related cleanups inside packages/vinext/src/config/config-matchers.ts. Pure refactor — no behavior change. Follow-up to #1058.

A. getCachedRegex helper (collapses 3 near-identical caches)

The file had three separate Map-based regex compilation caches, each repeating the same if (cache.get(key) === undefined) { compile + safeRegExp; cache.set(...) } pattern:

  • _compiledPatternCache (in matchConfigPattern)
  • _compiledHeaderSourceCache (in matchHeaders)
  • _compiledConditionCache (in _cachedConditionRegex)

These are now consumed via a single generic helper:

function getCachedRegex<K, V>(cache: Map<K, V | null>, key: K, compile: () => V | null): V | null

The helper is generic over the cached value type (the pattern cache stores { re, paramNames } | null while the others store RegExp | null), and only handles caching — compile() is still responsible for invoking safeRegExp(), so the ReDoS-rejection path is untouched. null continues to mark "seen and rejected" so we never re-run isSafeRegex on a known-bad pattern.

The per-cache documentation comments at the declaration sites (explaining why each cache exists) are preserved verbatim.

B. substituteAndSanitizeDestination wrapper (collapses 4 call sites)

substituteDestinationParams(dest, params) followed immediately by sanitizeDestination(...) appeared in four places — locale-static redirect, locale-prefix redirect, linear redirect fallback, and rewrite. All four sites passed exactly the same arguments and used the result the same way (assign to dest, then return / store on a localeMatch). They are now wrapped in a single file-private helper.

The "collapse protocol-relative URLs" comment is kept at the redirect-fallback and rewrite call sites.

Files changed

  • packages/vinext/src/config/config-matchers.ts (+49 / -29)

Test plan

  • pnpm vp test run tests/app-router.test.ts tests/pages-router.test.ts — 508/508 pass; one unrelated allowedDevOrigins afterAll teardown timeout in pages-router (pre-existing flake, no production code path touched by this PR)
  • pnpm vp test run tests/next-config.test.ts tests/features.test.ts tests/pages-i18n.test.ts — 379/379 pass (covers redirects, rewrites, headers, has/missing conditions)
  • pnpm fmt --write
  • pnpm knip — clean

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/1080 **Author:** [@james-elicx](https://github.com/james-elicx) **Created:** 5/5/2026 **Status:** ✅ Merged **Merged:** 5/5/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `refactor/dedupe-config-matchers-internals` --- ### 📝 Commits (1) - [`20c404e`](https://github.com/cloudflare/vinext/commit/20c404efd50b71cff5f2485bd3c4f6e01c4f0f52) refactor(config): dedupe regex cache and destination param chain ### 📊 Changes **1 file changed** (+49 additions, -29 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/config/config-matchers.ts` (+49 -29) </details> ### 📄 Description ## Summary Two related cleanups inside `packages/vinext/src/config/config-matchers.ts`. Pure refactor — no behavior change. Follow-up to #1058. ### A. `getCachedRegex` helper (collapses 3 near-identical caches) The file had three separate `Map`-based regex compilation caches, each repeating the same `if (cache.get(key) === undefined) { compile + safeRegExp; cache.set(...) }` pattern: - `_compiledPatternCache` (in `matchConfigPattern`) - `_compiledHeaderSourceCache` (in `matchHeaders`) - `_compiledConditionCache` (in `_cachedConditionRegex`) These are now consumed via a single generic helper: ```ts function getCachedRegex<K, V>(cache: Map<K, V | null>, key: K, compile: () => V | null): V | null ``` The helper is generic over the cached value type (the pattern cache stores `{ re, paramNames } | null` while the others store `RegExp | null`), and only handles caching — `compile()` is still responsible for invoking `safeRegExp()`, so the ReDoS-rejection path is untouched. `null` continues to mark "seen and rejected" so we never re-run `isSafeRegex` on a known-bad pattern. The per-cache documentation comments at the declaration sites (explaining *why* each cache exists) are preserved verbatim. ### B. `substituteAndSanitizeDestination` wrapper (collapses 4 call sites) `substituteDestinationParams(dest, params)` followed immediately by `sanitizeDestination(...)` appeared in four places — locale-static redirect, locale-prefix redirect, linear redirect fallback, and rewrite. All four sites passed exactly the same arguments and used the result the same way (assign to `dest`, then return / store on a `localeMatch`). They are now wrapped in a single file-private helper. The "collapse protocol-relative URLs" comment is kept at the redirect-fallback and rewrite call sites. ## Files changed - `packages/vinext/src/config/config-matchers.ts` (+49 / -29) ## Test plan - [x] `pnpm vp test run tests/app-router.test.ts tests/pages-router.test.ts` — 508/508 pass; one unrelated `allowedDevOrigins` `afterAll` teardown timeout in pages-router (pre-existing flake, no production code path touched by this PR) - [x] `pnpm vp test run tests/next-config.test.ts tests/features.test.ts tests/pages-i18n.test.ts` — 379/379 pass (covers redirects, rewrites, headers, has/missing conditions) - [x] `pnpm fmt --write` - [x] `pnpm knip` — clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:11:52 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#1077
No description provided.