From 588f2140030060ad460f8cba83dca18233824cdf Mon Sep 17 00:00:00 2001 From: Linpeng Zhang <44171495+linpengzhang@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:26:28 +0000 Subject: [PATCH] Catch path-to-regexp errors and fall through to minimatch The `sourceMatches` function tries path-to-regexp first and falls back to minimatch. However, if the source pattern uses syntax that path-to-regexp cannot parse (e.g. extglob negation like `**/!(*.css|*.js)`), path-to-regexp throws an exception instead of returning null. This prevents the minimatch fallback from ever running. Wrap the path-to-regexp block in a try/catch so that incompatible patterns gracefully fall through to minimatch, which does support them. Made-with: Cursor --- src/index.js | 21 ++++++++++++++------- test/integration.test.js | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/index.js b/src/index.js index 564f012..4906a73 100644 --- a/src/index.js +++ b/src/index.js @@ -43,15 +43,22 @@ const sourceMatches = (source, requestPath, allowSegments) => { let results = null; if (allowSegments) { - const normalized = slashed.replace('*', '(.*)'); - const expression = pathToRegExp(normalized, keys); + try { + const normalized = slashed.replace('*', '(.*)'); + const expression = pathToRegExp(normalized, keys); - results = expression.exec(resolvedPath); + results = expression.exec(resolvedPath); - if (!results) { - // clear keys so that they are not used - // later with empty results. this may - // happen if minimatch returns true + if (!results) { + // clear keys so that they are not used + // later with empty results. this may + // happen if minimatch returns true + keys.length = 0; + } + } catch (_) { + // If path-to-regexp cannot parse the source pattern (e.g. + // extglob negation like `!(*.css|*.js)`), fall through to + // the minimatch check below. keys.length = 0; } } diff --git a/test/integration.test.js b/test/integration.test.js index cebc479..cc12a8d 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -362,6 +362,25 @@ test('set `rewrites` config property to path segment', async () => { expect(json).toEqual(content); }); +test('set `rewrites` config property with extglob negation pattern', async () => { + const destination = '.dotfile'; + const related = path.join(fixturesFull, destination); + const content = await fs.readFile(related, 'utf8'); + + const url = await getUrl({ + rewrites: [{ + source: '**/!(*.js|*.css)', + destination + }] + }); + + const response = await fetch(`${url}/face/delete`); + const text = await response.text(); + + expect(response.status).toBe(200); + expect(text).toBe(content); +}); + test('set `redirects` config property to wildcard path', async () => { const destination = 'testing';