@@ -275,33 +275,39 @@ export function compile<P extends ParamData = ParamData>(
275275 const fn = tokensToFunction ( data . tokens , delimiter , encode ) ;
276276
277277 return function path ( params : P = { } as P ) {
278- const [ path , ...missing ] = fn ( params ) ;
278+ const missing : string [ ] = [ ] ;
279+ const path = fn ( params , missing ) ;
280+
279281 if ( missing . length ) {
280282 throw new TypeError ( `Missing parameters: ${ missing . join ( ", " ) } ` ) ;
281283 }
284+
282285 return path ;
283286 } ;
284287}
285288
286289export type ParamData = Partial < Record < string , string | string [ ] > > ;
287290export type PathFunction < P extends ParamData > = ( data ?: P ) => string ;
288291
292+ /**
293+ * Internal path builder function.
294+ */
295+ type TokenEncoder = ( data : ParamData , missing : string [ ] ) => string ;
296+
289297function tokensToFunction (
290298 tokens : Token [ ] ,
291299 delimiter : string ,
292300 encode : Encode | false ,
293- ) {
301+ ) : TokenEncoder {
294302 const encoders = tokens . map ( ( token ) =>
295303 tokenToFunction ( token , delimiter , encode ) ,
296304 ) ;
297305
298- return ( data : ParamData ) => {
299- const result : string [ ] = [ "" ] ;
306+ return ( data : ParamData , missing : string [ ] ) => {
307+ let result = "" ;
300308
301309 for ( const encoder of encoders ) {
302- const [ value , ...extras ] = encoder ( data ) ;
303- result [ 0 ] += value ;
304- result . push ( ...extras ) ;
310+ result += encoder ( data , missing ) ;
305311 }
306312
307313 return result ;
@@ -315,55 +321,62 @@ function tokenToFunction(
315321 token : Token ,
316322 delimiter : string ,
317323 encode : Encode | false ,
318- ) : ( data : ParamData ) => string [ ] {
319- if ( token . type === "text" ) return ( ) => [ token . value ] ;
324+ ) : TokenEncoder {
325+ if ( token . type === "text" ) return ( ) => token . value ;
320326
321327 if ( token . type === "group" ) {
322328 const fn = tokensToFunction ( token . tokens , delimiter , encode ) ;
323329
324- return ( data ) => {
325- const [ value , ...missing ] = fn ( data ) ;
326- if ( ! missing . length ) return [ value ] ;
327- return [ "" ] ;
330+ return ( data , missing ) => {
331+ const len = missing . length ;
332+ const value = fn ( data , missing ) ;
333+ if ( missing . length === len ) return value ;
334+
335+ missing . length = len ; // Reset optional group.
336+ return "" ;
328337 } ;
329338 }
330339
331340 const encodeValue = encode || NOOP_VALUE ;
332341
333342 if ( token . type === "wildcard" && encode !== false ) {
334- return ( data ) => {
343+ return ( data , missing ) => {
335344 const value = data [ token . name ] ;
336- if ( value == null ) return [ "" , token . name ] ;
345+ if ( value == null ) {
346+ missing . push ( token . name ) ;
347+ return "" ;
348+ }
337349
338350 if ( ! Array . isArray ( value ) || value . length === 0 ) {
339351 throw new TypeError ( `Expected "${ token . name } " to be a non-empty array` ) ;
340352 }
341353
342- return [
343- value
344- . map ( ( value , index ) => {
345- if ( typeof value !== "string" ) {
346- throw new TypeError (
347- `Expected "${ token . name } /${ index } " to be a string` ,
348- ) ;
349- }
354+ return value
355+ . map ( ( value , index ) => {
356+ if ( typeof value !== "string" ) {
357+ throw new TypeError (
358+ `Expected "${ token . name } /${ index } " to be a string` ,
359+ ) ;
360+ }
350361
351- return encodeValue ( value ) ;
352- } )
353- . join ( delimiter ) ,
354- ] ;
362+ return encodeValue ( value ) ;
363+ } )
364+ . join ( delimiter ) ;
355365 } ;
356366 }
357367
358- return ( data ) => {
368+ return ( data , missing ) => {
359369 const value = data [ token . name ] ;
360- if ( value == null ) return [ "" , token . name ] ;
370+ if ( value == null ) {
371+ missing . push ( token . name ) ;
372+ return "" ;
373+ }
361374
362375 if ( typeof value !== "string" ) {
363376 throw new TypeError ( `Expected "${ token . name } " to be a string` ) ;
364377 }
365378
366- return [ encodeValue ( value ) ] ;
379+ return encodeValue ( value ) ;
367380 } ;
368381}
369382
0 commit comments