From ab62098b4f47b910ad89b8f08b882bf0d38c973f Mon Sep 17 00:00:00 2001 From: skirtle <65301168+skirtles-code@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:23:28 +0000 Subject: [PATCH] fix: combining 'end' and 'strict' (#2154) --- .../__tests__/matcher/pathParser.spec.ts | 72 ++++++++++++++++++- .../router/src/matcher/pathParserRanker.ts | 2 +- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/packages/router/__tests__/matcher/pathParser.spec.ts b/packages/router/__tests__/matcher/pathParser.spec.ts index 5ed7ed406..b7b9969b1 100644 --- a/packages/router/__tests__/matcher/pathParser.spec.ts +++ b/packages/router/__tests__/matcher/pathParser.spec.ts @@ -619,9 +619,77 @@ describe('Path parser', () => { matchParams('/home', '/other/home', {}, { start: false }) }) + it('defaults to matching the end', () => { + // The default should behave like `end: true` + const optionSets = [{}, { end: true }] + + for (const options of optionSets) { + matchParams('/home', '/home', {}, options) + matchParams('/home', '/home/', {}, options) + matchParams('/home', '/home/other', null, options) + matchParams('/home', '/homepage', null, options) + + matchParams('/home/', '/home', {}, options) + matchParams('/home/', '/home/', {}, options) + matchParams('/home/', '/home/other', null, options) + matchParams('/home/', '/homepage', null, options) + } + }) + it('can not match the end', () => { - matchParams('/home', '/home/other', null, { end: true }) - matchParams('/home', '/home/other', {}, { end: false }) + const options = { end: false } + + matchParams('/home', '/home', {}, options) + matchParams('/home', '/home/', {}, options) + matchParams('/home', '/home/other', {}, options) + matchParams('/home', '/homepage', {}, options) + + matchParams('/home/:p', '/home', null, options) + matchParams('/home/:p', '/home/', null, options) + matchParams('/home/:p', '/home/a', { p: 'a' }, options) + matchParams('/home/:p', '/home/a/', { p: 'a' }, options) + matchParams('/home/:p', '/home/a/b', { p: 'a' }, options) + matchParams('/home/:p', '/homepage', null, options) + + matchParams('/home/', '/home', {}, options) + matchParams('/home/', '/home/', {}, options) + matchParams('/home/', '/home/other', {}, options) + matchParams('/home/', '/homepage', {}, options) + + matchParams('/home/:p/', '/home', null, options) + matchParams('/home/:p/', '/home/', null, options) + matchParams('/home/:p/', '/home/a', { p: 'a' }, options) + matchParams('/home/:p/', '/home/a/', { p: 'a' }, options) + matchParams('/home/:p/', '/home/a/b', { p: 'a' }, options) + matchParams('/home/:p/', '/homepage', null, options) + }) + + it('can not match the end when strict', () => { + const options = { end: false, strict: true } + + matchParams('/home', '/home', {}, options) + matchParams('/home', '/home/', {}, options) + matchParams('/home', '/home/other', {}, options) + matchParams('/home', '/homepage', null, options) + + matchParams('/home/:p', '/home', null, options) + matchParams('/home/:p', '/home/', null, options) + matchParams('/home/:p', '/home/a', { p: 'a' }, options) + matchParams('/home/:p', '/home/a/', { p: 'a' }, options) + matchParams('/home/:p', '/home/a/b', { p: 'a' }, options) + matchParams('/home/:p', '/homepage', null, options) + + matchParams('/home/', '/home', null, options) + matchParams('/home/', '/home/', {}, options) + matchParams('/home/', '/home/other', {}, options) + matchParams('/home/', '/homepage', null, options) + + matchParams('/home/:p/', '/home', null, options) + matchParams('/home/:p/', '/home/', null, options) + matchParams('/home/:p/', '/home/a', null, options) + matchParams('/home/:p/', '/home/a/', { p: 'a' }, options) + matchParams('/home/:p/', '/home/a/b', { p: 'a' }, options) + matchParams('/home/:p/', '/homepage', null, options) }) it('should not match optional params + static without leading slash', () => { diff --git a/packages/router/src/matcher/pathParserRanker.ts b/packages/router/src/matcher/pathParserRanker.ts index 670013794..81b077642 100644 --- a/packages/router/src/matcher/pathParserRanker.ts +++ b/packages/router/src/matcher/pathParserRanker.ts @@ -217,7 +217,7 @@ export function tokensToParser( if (options.end) pattern += '$' // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else - else if (options.strict) pattern += '(?:/|$)' + else if (options.strict && !pattern.endsWith('/')) pattern += '(?:/|$)' const re = new RegExp(pattern, options.sensitive ? '' : 'i')