From 96d8a89c710b7237141185abef1e1642ce1305d3 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 15 Aug 2025 14:29:38 +0200 Subject: [PATCH] fix: handle subsegments --- .../matchers/matcher-pattern.spec.ts | 22 +++++++++++ .../matchers/matcher-pattern.ts | 39 ++++++++++++++----- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.spec.ts b/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.spec.ts index 0a4c8b04..6381c13c 100644 --- a/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.spec.ts +++ b/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.spec.ts @@ -217,4 +217,26 @@ describe('MatcherPatternPathCustom', () => { '/teams/123/456' ) }) + + it('sub segments (params + static)', () => { + const pattern = new MatcherPatternPathCustomParams( + /^\/teams\/([^/]+?)-b-([^/]+?)$/i, + { + teamId: {}, + otherId: {}, + }, + ['teams', [0, '-b-', 0]] + ) + + expect(pattern.match('/teams/123-b-456')).toEqual({ + teamId: '123', + otherId: '456', + }) + expect(() => pattern.match('/teams/123-b')).toThrow() + expect(() => pattern.match('/teams/123-b-456/c')).toThrow() + expect(() => pattern.match('/teams/')).toThrow() + expect(pattern.build({ teamId: '123', otherId: '456' })).toBe( + '/teams/123-b-456' + ) + }) }) diff --git a/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.ts b/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.ts index eb38aad5..d16a51ae 100644 --- a/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.ts +++ b/packages/router/src/experimental/route-resolver/matchers/matcher-pattern.ts @@ -291,7 +291,7 @@ export class MatcherPatternPathCustomParams< // A better version could be using all the parts to join them // .e.g ['users', 0, 'profile', 1] -> /users/123/profile/456 // numbers are indexes of the params in the params object keys - readonly pathParts: Array + readonly pathParts: Array> ) { this.paramsKeys = Object.keys(this.params) as Array } @@ -335,16 +335,35 @@ export class MatcherPatternPathCustomParams< .map(part => { if (typeof part === 'string') { return part + } else if (typeof part === 'number') { + const paramName = this.paramsKeys[paramIndex++] + const paramOptions = this.params[paramName] + const value: ReturnType> = ( + paramOptions.set || identityFn + )(params[paramName]) + + return Array.isArray(value) + ? value.map(encodeParam).join('/') + : encodeParam(value) + } else { + return part + .map(subPart => { + if (typeof subPart === 'string') { + return subPart + } + + const paramName = this.paramsKeys[paramIndex++] + const paramOptions = this.params[paramName] + const value: ReturnType> = ( + paramOptions.set || identityFn + )(params[paramName]) + + return Array.isArray(value) + ? value.map(encodeParam).join('/') + : encodeParam(value) + }) + .join('') } - const paramName = this.paramsKeys[paramIndex++] - const paramOptions = this.params[paramName] - const value: ReturnType> = ( - paramOptions.set || identityFn - )(params[paramName]) - - return Array.isArray(value) - ? value.map(encodeParam).join('/') - : encodeParam(value) }) .filter(identityFn) // filter out empty values .join('/') -- 2.47.3