1- import type { ParsedPath } from './parse'
21import escapeStringRegexp from 'escape-string-regexp'
32
43import { encodePath , joinURL } from 'ufo'
4+ import type { ParsedPathSegment } from './parse'
55import { parsePath } from './parse'
66
77/**
@@ -17,12 +17,15 @@ import { parsePath } from './parse'
1717/**
1818 * TODO: need to implement protection logging + fall back to what radix3 supports.
1919 */
20- export function toRadix3 ( filePath : string | ParsedPath ) {
21- const segments = typeof filePath === 'string' ? parsePath ( filePath ) : filePath
20+ export function toRadix3 ( filePath : string | ParsedPathSegment [ ] ) {
21+ const segments = typeof filePath === 'string' ? parsePath ( filePath ) . segments : filePath
2222
2323 let route = '/'
2424
2525 for ( const segment of segments ) {
26+ if ( segment . every ( token => token . type === 'group' ) )
27+ continue
28+
2629 let radixSegment = ''
2730 for ( const token of segment ) {
2831 if ( token . type === 'static' )
@@ -39,36 +42,52 @@ export function toRadix3(filePath: string | ParsedPath) {
3942 }
4043
4144 // If a segment has value '' we skip adding it entirely
42- if ( route )
45+ if ( radixSegment )
4346 route = joinURL ( route , radixSegment )
4447 }
4548
4649 return route
4750}
4851
49- export function toVueRouter4 ( filePath : string | ParsedPath ) {
50- const segments = typeof filePath === 'string' ? parsePath ( filePath ) : filePath
52+ export function toVueRouter4 ( filePath : string | ParsedPathSegment [ ] ) {
53+ const segments = typeof filePath === 'string' ? parsePath ( filePath ) . segments : filePath
5154
5255 let path = '/'
5356
54- for ( const segment of segments ) {
57+ for ( let i = 0 ; i < segments . length ; i ++ ) {
58+ const segment = segments [ i ]
59+
60+ // Skip group-only segments as they don't contribute to the URL path
61+ if ( segment . every ( token => token . type === 'group' ) )
62+ continue
63+
64+ const hasSucceedingSegment = i < segments . length - 1
65+
5566 let pathSegment = ''
5667 for ( const token of segment ) {
68+ if ( token . type === 'group' )
69+ continue
5770 if ( token . type === 'static' ) {
5871 pathSegment += encodePath ( token . value ) . replace ( / : / g, '\\:' )
5972 continue
6073 }
61- if ( token . type === 'dynamic' )
74+ if ( token . type === 'dynamic' ) {
6275 pathSegment += `:${ token . value } ()`
63-
64- if ( token . type === 'optional' )
76+ continue
77+ }
78+ if ( token . type === 'optional' ) {
6579 pathSegment += `:${ token . value } ?`
66-
67- if ( token . type === 'catchall' )
68- pathSegment += `:${ token . value } (.*)*`
80+ continue
81+ }
82+ if ( token . type === 'catchall' ) {
83+ pathSegment += hasSucceedingSegment ? `:${ token . value } ([^/]*)*` : `:${ token . value } (.*)*`
84+ continue
85+ }
6986 }
7087
71- path = joinURL ( path , pathSegment )
88+ // Only join if pathSegment is not empty
89+ if ( pathSegment )
90+ path = joinURL ( path , pathSegment )
7291 }
7392
7493 return {
@@ -79,28 +98,41 @@ export function toVueRouter4(filePath: string | ParsedPath) {
7998function sanitizeCaptureGroup ( captureGroup : string ) {
8099 return captureGroup . replace ( / ^ ( \d ) / , '_$1' ) . replace ( / \. / g, '' )
81100}
82- export function toRegExp ( filePath : string | ParsedPath ) {
83- const segments = typeof filePath === 'string' ? parsePath ( filePath ) : filePath
101+ export function toRegExp ( filePath : string | ParsedPathSegment [ ] ) {
102+ const segments = typeof filePath === 'string' ? parsePath ( filePath ) . segments : filePath
84103
104+ const keys : string [ ] = [ ]
85105 let sourceRE = '\\/'
86106
87107 for ( const segment of segments ) {
108+ if ( segment . every ( token => token . type === 'group' ) )
109+ continue
110+
88111 let reSegment = ''
89112 for ( const token of segment ) {
90113 if ( token . type === 'static' )
91114 reSegment += escapeStringRegexp ( token . value )
92115
93- if ( token . type === 'dynamic' )
94- reSegment += `(?<${ sanitizeCaptureGroup ( token . value ) } >[^/]+)`
116+ if ( token . type === 'dynamic' ) {
117+ const key = sanitizeCaptureGroup ( token . value )
118+ keys . push ( key )
119+ reSegment += `(?<${ key } >[^/]+)`
120+ }
95121
96- if ( token . type === 'optional' )
97- reSegment += `(?<${ sanitizeCaptureGroup ( token . value ) } >[^/]*)`
122+ if ( token . type === 'optional' ) {
123+ const key = sanitizeCaptureGroup ( token . value )
124+ keys . push ( key )
125+ reSegment += `(?<${ key } >[^/]*)`
126+ }
98127
99- if ( token . type === 'catchall' )
100- reSegment += `(?<${ sanitizeCaptureGroup ( token . value ) } >.*)`
128+ if ( token . type === 'catchall' ) {
129+ const key = sanitizeCaptureGroup ( token . value )
130+ keys . push ( key )
131+ reSegment += `(?<${ key } >.*)`
132+ }
101133 }
102134
103- if ( segment . every ( token => token . type === 'optional' || token . type === 'catchall' ) ) {
135+ if ( segment . every ( token => token . type === 'optional' || token . type === 'catchall' || token . type === 'group' ) ) {
104136 sourceRE += `(?:${ reSegment } \\/?)`
105137 }
106138 else if ( reSegment ) {
@@ -112,5 +144,8 @@ export function toRegExp(filePath: string | ParsedPath) {
112144 // make final slash optional
113145 sourceRE += '?'
114146
115- return new RegExp ( sourceRE )
147+ return {
148+ pattern : new RegExp ( sourceRE ) ,
149+ keys,
150+ }
116151}
0 commit comments