1- // Copied from serverless-next.js (v1.8.0 )
1+ // Copied from serverless-next.js (v1.9.10 )
22// https://github.com/danielcondemarin/serverless-next.js/blob/master/packages/serverless-nextjs-component/lib/sortedRoutes.js
33
4- // This file Taken was from next.js repo
5- // https://github.com/zeit/next.js/blob/820a9790baafd36f14a79cf416162e3263cb00c4 /packages/next/next-server/lib/router/utils/sorted-routes.ts#L89
4+ /// This file taken was from next.js repo and converted to JS.
5+ // https://github.com/zeit/next.js/blob/canary /packages/next/next-server/lib/router/utils/sorted-routes.ts
66
77class UrlNode {
88 constructor ( ) {
99 this . placeholder = true ;
1010 this . children = new Map ( ) ;
1111 this . slugName = null ;
12+ this . restSlugName = null ;
1213 }
13- hasSlug ( ) {
14- return this . slugName != null ;
15- }
14+
1615 insert ( urlPath ) {
17- this . _insert ( urlPath . split ( "/" ) . filter ( Boolean ) ) ;
16+ this . _insert ( urlPath . split ( "/" ) . filter ( Boolean ) , [ ] , false ) ;
1817 }
18+
1919 smoosh ( ) {
2020 return this . _smoosh ( ) ;
2121 }
22+
2223 _smoosh ( prefix = "/" ) {
2324 const childrenPaths = [ ...this . children . keys ( ) ] . sort ( ) ;
24- if ( this . hasSlug ( ) ) {
25+ if ( this . slugName !== null ) {
2526 childrenPaths . splice ( childrenPaths . indexOf ( "[]" ) , 1 ) ;
2627 }
28+ if ( this . restSlugName !== null ) {
29+ childrenPaths . splice ( childrenPaths . indexOf ( "[...]" ) , 1 ) ;
30+ }
31+
2732 const routes = childrenPaths
2833 . map ( c => this . children . get ( c ) . _smoosh ( `${ prefix } ${ c } /` ) )
2934 . reduce ( ( prev , curr ) => [ ...prev , ...curr ] , [ ] ) ;
30- if ( this . hasSlug ( ) ) {
35+
36+ if ( this . slugName !== null ) {
3137 routes . push (
3238 ...this . children . get ( "[]" ) . _smoosh ( `${ prefix } [${ this . slugName } ]/` )
3339 ) ;
3440 }
41+
3542 if ( ! this . placeholder ) {
3643 routes . unshift ( prefix === "/" ? "/" : prefix . slice ( 0 , - 1 ) ) ;
3744 }
45+
46+ if ( this . restSlugName !== null ) {
47+ routes . push (
48+ ...this . children
49+ . get ( "[...]" )
50+ . _smoosh ( `${ prefix } [...${ this . restSlugName } ]/` )
51+ ) ;
52+ }
53+
3854 return routes ;
3955 }
40- _insert ( urlPaths , slugNames = [ ] ) {
56+
57+ _insert ( urlPaths , slugNames , isCatchAll ) {
4158 if ( urlPaths . length === 0 ) {
4259 this . placeholder = false ;
4360 return ;
4461 }
62+
63+ if ( isCatchAll ) {
64+ throw new Error ( `Catch-all must be the last part of the URL.` ) ;
65+ }
66+
4567 // The next segment in the urlPaths list
4668 let nextSegment = urlPaths [ 0 ] ;
69+
4770 // Check if the segment matches `[something]`
4871 if ( nextSegment . startsWith ( "[" ) && nextSegment . endsWith ( "]" ) ) {
4972 // Strip `[` and `]`, leaving only `something`
50- const slugName = nextSegment . slice ( 1 , - 1 ) ;
51- // If the specific segment already has a slug but the slug is not `something`
52- // This prevents collisions like:
53- // pages/[post]/index.js
54- // pages/[id]/index.js
55- // Because currently multiple dynamic params on the same segment level are not supported
56- if ( this . hasSlug ( ) && slugName !== this . slugName ) {
57- // TODO: This error seems to be confusing for users, needs an err.sh link, the description can be based on above comment.
58- throw new Error (
59- "You cannot use different slug names for the same dynamic path."
60- ) ;
73+ let segmentName = nextSegment . slice ( 1 , - 1 ) ;
74+ if ( segmentName . startsWith ( "..." ) ) {
75+ segmentName = segmentName . substring ( 3 ) ;
76+ isCatchAll = true ;
6177 }
62- if ( slugNames . indexOf ( slugName ) !== - 1 ) {
78+
79+ if ( segmentName . startsWith ( "." ) ) {
6380 throw new Error (
64- `You cannot have the same slug name " ${ slugName } " repeat within a single dynamic path `
81+ `Segment names may not start with erroneous periods (' ${ segmentName } '). `
6582 ) ;
6683 }
67- slugNames . push ( slugName ) ;
68- // slugName is kept as it can only be one particular slugName
69- this . slugName = slugName ;
70- // nextSegment is overwritten to [] so that it can later be sorted specifically
71- nextSegment = "[]" ;
84+
85+ function handleSlug ( previousSlug , nextSlug ) {
86+ if ( previousSlug !== null ) {
87+ // If the specific segment already has a slug but the slug is not `something`
88+ // This prevents collisions like:
89+ // pages/[post]/index.js
90+ // pages/[id]/index.js
91+ // Because currently multiple dynamic params on the same segment level are not supported
92+ if ( previousSlug !== nextSlug ) {
93+ // TODO: This error seems to be confusing for users, needs an err.sh link, the description can be based on above comment.
94+ throw new Error (
95+ `You cannot use different slug names for the same dynamic path ('${ previousSlug } ' !== '${ nextSlug } ').`
96+ ) ;
97+ }
98+ }
99+
100+ if ( slugNames . indexOf ( nextSlug ) !== - 1 ) {
101+ throw new Error (
102+ `You cannot have the same slug name "${ nextSlug } " repeat within a single dynamic path`
103+ ) ;
104+ }
105+
106+ slugNames . push ( nextSlug ) ;
107+ }
108+
109+ if ( isCatchAll ) {
110+ handleSlug ( this . restSlugName , segmentName ) ;
111+ // slugName is kept as it can only be one particular slugName
112+ this . restSlugName = segmentName ;
113+ // nextSegment is overwritten to [] so that it can later be sorted specifically
114+ nextSegment = "[...]" ;
115+ } else {
116+ handleSlug ( this . slugName , segmentName ) ;
117+ // slugName is kept as it can only be one particular slugName
118+ this . slugName = segmentName ;
119+ // nextSegment is overwritten to [] so that it can later be sorted specifically
120+ nextSegment = "[]" ;
121+ }
72122 }
123+
73124 // If this UrlNode doesn't have the nextSegment yet we create a new child UrlNode
74125 if ( ! this . children . has ( nextSegment ) ) {
75126 this . children . set ( nextSegment , new UrlNode ( ) ) ;
76127 }
77- this . children . get ( nextSegment ) . _insert ( urlPaths . slice ( 1 ) , slugNames ) ;
128+
129+ this . children
130+ . get ( nextSegment )
131+ . _insert ( urlPaths . slice ( 1 ) , slugNames , isCatchAll ) ;
78132 }
79133}
80134
81135module . exports = function getSortedRoutes ( normalizedPages ) {
82136 // First the UrlNode is created, and every UrlNode can have only 1 dynamic segment
83137 // Eg you can't have pages/[post]/abc.js and pages/[hello]/something-else.js
84138 // Only 1 dynamic segment per nesting level
139+
85140 // So in the case that is test/integration/dynamic-routing it'll be this:
86141 // pages/[post]/comments.js
87142 // pages/blog/[post]/comment/[id].js
@@ -90,6 +145,7 @@ module.exports = function getSortedRoutes(normalizedPages) {
90145 // And since your PR passed through `slugName` as an array basically it'd including it in too many possibilities
91146 // Instead what has to be passed through is the upwards path's dynamic names
92147 const root = new UrlNode ( ) ;
148+
93149 // Here the `root` gets injected multiple paths, and insert will break them up into sublevels
94150 normalizedPages . forEach ( pagePath => root . insert ( pagePath ) ) ;
95151 // Smoosh will then sort those sublevels up to the point where you get the correct route definition priority
0 commit comments