1
- // Copied from serverless-next.js (v1.8.0 )
1
+ // Copied from serverless-next.js (v1.9.10 )
2
2
// https://github.com/danielcondemarin/serverless-next.js/blob/master/packages/serverless-nextjs-component/lib/sortedRoutes.js
3
3
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
6
6
7
7
class UrlNode {
8
8
constructor ( ) {
9
9
this . placeholder = true ;
10
10
this . children = new Map ( ) ;
11
11
this . slugName = null ;
12
+ this . restSlugName = null ;
12
13
}
13
- hasSlug ( ) {
14
- return this . slugName != null ;
15
- }
14
+
16
15
insert ( urlPath ) {
17
- this . _insert ( urlPath . split ( "/" ) . filter ( Boolean ) ) ;
16
+ this . _insert ( urlPath . split ( "/" ) . filter ( Boolean ) , [ ] , false ) ;
18
17
}
18
+
19
19
smoosh ( ) {
20
20
return this . _smoosh ( ) ;
21
21
}
22
+
22
23
_smoosh ( prefix = "/" ) {
23
24
const childrenPaths = [ ...this . children . keys ( ) ] . sort ( ) ;
24
- if ( this . hasSlug ( ) ) {
25
+ if ( this . slugName !== null ) {
25
26
childrenPaths . splice ( childrenPaths . indexOf ( "[]" ) , 1 ) ;
26
27
}
28
+ if ( this . restSlugName !== null ) {
29
+ childrenPaths . splice ( childrenPaths . indexOf ( "[...]" ) , 1 ) ;
30
+ }
31
+
27
32
const routes = childrenPaths
28
33
. map ( c => this . children . get ( c ) . _smoosh ( `${ prefix } ${ c } /` ) )
29
34
. reduce ( ( prev , curr ) => [ ...prev , ...curr ] , [ ] ) ;
30
- if ( this . hasSlug ( ) ) {
35
+
36
+ if ( this . slugName !== null ) {
31
37
routes . push (
32
38
...this . children . get ( "[]" ) . _smoosh ( `${ prefix } [${ this . slugName } ]/` )
33
39
) ;
34
40
}
41
+
35
42
if ( ! this . placeholder ) {
36
43
routes . unshift ( prefix === "/" ? "/" : prefix . slice ( 0 , - 1 ) ) ;
37
44
}
45
+
46
+ if ( this . restSlugName !== null ) {
47
+ routes . push (
48
+ ...this . children
49
+ . get ( "[...]" )
50
+ . _smoosh ( `${ prefix } [...${ this . restSlugName } ]/` )
51
+ ) ;
52
+ }
53
+
38
54
return routes ;
39
55
}
40
- _insert ( urlPaths , slugNames = [ ] ) {
56
+
57
+ _insert ( urlPaths , slugNames , isCatchAll ) {
41
58
if ( urlPaths . length === 0 ) {
42
59
this . placeholder = false ;
43
60
return ;
44
61
}
62
+
63
+ if ( isCatchAll ) {
64
+ throw new Error ( `Catch-all must be the last part of the URL.` ) ;
65
+ }
66
+
45
67
// The next segment in the urlPaths list
46
68
let nextSegment = urlPaths [ 0 ] ;
69
+
47
70
// Check if the segment matches `[something]`
48
71
if ( nextSegment . startsWith ( "[" ) && nextSegment . endsWith ( "]" ) ) {
49
72
// 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 ;
61
77
}
62
- if ( slugNames . indexOf ( slugName ) !== - 1 ) {
78
+
79
+ if ( segmentName . startsWith ( "." ) ) {
63
80
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 } '). `
65
82
) ;
66
83
}
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
+ }
72
122
}
123
+
73
124
// If this UrlNode doesn't have the nextSegment yet we create a new child UrlNode
74
125
if ( ! this . children . has ( nextSegment ) ) {
75
126
this . children . set ( nextSegment , new UrlNode ( ) ) ;
76
127
}
77
- this . children . get ( nextSegment ) . _insert ( urlPaths . slice ( 1 ) , slugNames ) ;
128
+
129
+ this . children
130
+ . get ( nextSegment )
131
+ . _insert ( urlPaths . slice ( 1 ) , slugNames , isCatchAll ) ;
78
132
}
79
133
}
80
134
81
135
module . exports = function getSortedRoutes ( normalizedPages ) {
82
136
// First the UrlNode is created, and every UrlNode can have only 1 dynamic segment
83
137
// Eg you can't have pages/[post]/abc.js and pages/[hello]/something-else.js
84
138
// Only 1 dynamic segment per nesting level
139
+
85
140
// So in the case that is test/integration/dynamic-routing it'll be this:
86
141
// pages/[post]/comments.js
87
142
// pages/blog/[post]/comment/[id].js
@@ -90,6 +145,7 @@ module.exports = function getSortedRoutes(normalizedPages) {
90
145
// And since your PR passed through `slugName` as an array basically it'd including it in too many possibilities
91
146
// Instead what has to be passed through is the upwards path's dynamic names
92
147
const root = new UrlNode ( ) ;
148
+
93
149
// Here the `root` gets injected multiple paths, and insert will break them up into sublevels
94
150
normalizedPages . forEach ( pagePath => root . insert ( pagePath ) ) ;
95
151
// Smoosh will then sort those sublevels up to the point where you get the correct route definition priority
0 commit comments