@@ -71,7 +71,86 @@ export class RedirectsMiddleware extends MiddlewareBase {
71
71
} ;
72
72
}
73
73
74
- private handler = async ( req : NextRequest , res ?: NextResponse ) : Promise < NextResponse > => {
74
+ /**
75
+ * Method returns RedirectInfo when matches
76
+ * @param {NextRequest } req request
77
+ * @param {string } siteName site name
78
+ * @returns Promise<RedirectInfo | undefined> The redirect info or undefined if no redirect is found
79
+ * @protected
80
+ */
81
+ protected async getExistsRedirect (
82
+ req : NextRequest ,
83
+ siteName : string
84
+ ) : Promise < RedirectResult | undefined > {
85
+ const { pathname : targetURL , search : targetQS = '' , locale } = this . normalizeUrl (
86
+ req . nextUrl . clone ( )
87
+ ) ;
88
+ const normalizedPath = targetURL . replace ( / \/ * $ / gi, '' ) ;
89
+ const redirects = await this . redirectsService . fetchRedirects ( siteName ) ;
90
+ const language = this . getLanguage ( req ) ;
91
+ const modifyRedirects = structuredClone ( redirects ) ;
92
+ let matchedQueryString : string | undefined ;
93
+
94
+ return modifyRedirects . length
95
+ ? modifyRedirects . find ( ( redirect : RedirectResult ) => {
96
+ if ( isRegexOrUrl ( redirect . pattern ) === 'url' ) {
97
+ const parseUrlPattern = redirect . pattern . endsWith ( '/' )
98
+ ? redirect . pattern . slice ( 0 , - 1 ) . split ( '?' )
99
+ : redirect . pattern . split ( '?' ) ;
100
+
101
+ return (
102
+ ( parseUrlPattern [ 0 ] === normalizedPath ||
103
+ parseUrlPattern [ 0 ] === `/${ locale } ${ normalizedPath } ` ) &&
104
+ areURLSearchParamsEqual (
105
+ new URLSearchParams ( parseUrlPattern [ 1 ] ?? '' ) ,
106
+ new URLSearchParams ( targetQS )
107
+ )
108
+ ) ;
109
+ }
110
+
111
+ // Modify the redirect pattern to ignore the language prefix in the path
112
+ // And escapes non-special "?" characters in a string or regex.
113
+ redirect . pattern = escapeNonSpecialQuestionMarks (
114
+ redirect . pattern . replace ( new RegExp ( `^[^]?/${ language } /` , 'gi' ) , '' )
115
+ ) ;
116
+
117
+ // Prepare the redirect pattern as a regular expression, making it more flexible for matching URLs
118
+ redirect . pattern = `/^\/${ redirect . pattern
119
+ . replace ( / ^ \/ | \/ $ / g, '' ) // Removes leading and trailing slashes
120
+ . replace ( / ^ \^ \/ | \/ \$ $ / g, '' ) // Removes unnecessary start (^) and end ($) anchors
121
+ . replace ( / ^ \^ | \$ $ / g, '' ) // Further cleans up anchors
122
+ . replace ( / \$ \/ g i $ / g, '' ) } [\/]?$/i`; // Ensures the pattern allows an optional trailing slash
123
+
124
+ matchedQueryString = [
125
+ regexParser ( redirect . pattern ) . test ( `${ normalizedPath } ${ targetQS } ` ) ,
126
+ regexParser ( redirect . pattern ) . test ( `/${ locale } ${ normalizedPath } ${ targetQS } ` ) ,
127
+ ] . some ( Boolean )
128
+ ? targetQS
129
+ : undefined ;
130
+
131
+ // Save the matched query string (if found) into the redirect object
132
+ redirect . matchedQueryString = matchedQueryString || '' ;
133
+
134
+ return (
135
+ ! ! (
136
+ regexParser ( redirect . pattern ) . test ( targetURL ) ||
137
+ regexParser ( redirect . pattern ) . test ( `/${ req . nextUrl . locale } ${ targetURL } ` ) ||
138
+ matchedQueryString
139
+ ) && ( redirect . locale ? redirect . locale . toLowerCase ( ) === locale . toLowerCase ( ) : true )
140
+ ) ;
141
+ } )
142
+ : undefined ;
143
+ }
144
+
145
+ /**
146
+ * @param {NextRequest } req request
147
+ * @param {Response } res response
148
+ * @returns {Promise<NextResponse> } The redirect response.
149
+ */
150
+ protected async processRedirectRequest (
151
+ req : NextRequest ,
152
+ res ?: NextResponse
153
+ ) : Promise < NextResponse > {
75
154
const pathname = req . nextUrl . pathname ;
76
155
const language = this . getLanguage ( req ) ;
77
156
const hostname = this . getHostHeader ( req ) || this . defaultHostname ;
@@ -201,79 +280,12 @@ export class RedirectsMiddleware extends MiddlewareBase {
201
280
} ) ;
202
281
203
282
return response ;
204
- } ;
205
-
206
- /**
207
- * Method returns RedirectInfo when matches
208
- * @param {NextRequest } req request
209
- * @param {string } siteName site name
210
- * @returns Promise<RedirectInfo | undefined>
211
- * @private
212
- */
213
- private async getExistsRedirect (
214
- req : NextRequest ,
215
- siteName : string
216
- ) : Promise < RedirectResult | undefined > {
217
- const { pathname : targetURL , search : targetQS = '' , locale } = this . normalizeUrl (
218
- req . nextUrl . clone ( )
219
- ) ;
220
- const normalizedPath = targetURL . replace ( / \/ * $ / gi, '' ) ;
221
- const redirects = await this . redirectsService . fetchRedirects ( siteName ) ;
222
- const language = this . getLanguage ( req ) ;
223
- const modifyRedirects = structuredClone ( redirects ) ;
224
- let matchedQueryString : string | undefined ;
225
-
226
- return modifyRedirects . length
227
- ? modifyRedirects . find ( ( redirect : RedirectResult ) => {
228
- if ( isRegexOrUrl ( redirect . pattern ) === 'url' ) {
229
- const parseUrlPattern = redirect . pattern . endsWith ( '/' )
230
- ? redirect . pattern . slice ( 0 , - 1 ) . split ( '?' )
231
- : redirect . pattern . split ( '?' ) ;
232
-
233
- return (
234
- ( parseUrlPattern [ 0 ] === normalizedPath ||
235
- parseUrlPattern [ 0 ] === `/${ locale } ${ normalizedPath } ` ) &&
236
- areURLSearchParamsEqual (
237
- new URLSearchParams ( parseUrlPattern [ 1 ] ?? '' ) ,
238
- new URLSearchParams ( targetQS )
239
- )
240
- ) ;
241
- }
242
-
243
- // Modify the redirect pattern to ignore the language prefix in the path
244
- // And escapes non-special "?" characters in a string or regex.
245
- redirect . pattern = escapeNonSpecialQuestionMarks (
246
- redirect . pattern . replace ( new RegExp ( `^[^]?/${ language } /` , 'gi' ) , '' )
247
- ) ;
248
-
249
- // Prepare the redirect pattern as a regular expression, making it more flexible for matching URLs
250
- redirect . pattern = `/^\/${ redirect . pattern
251
- . replace ( / ^ \/ | \/ $ / g, '' ) // Removes leading and trailing slashes
252
- . replace ( / ^ \^ \/ | \/ \$ $ / g, '' ) // Removes unnecessary start (^) and end ($) anchors
253
- . replace ( / ^ \^ | \$ $ / g, '' ) // Further cleans up anchors
254
- . replace ( / \$ \/ g i $ / g, '' ) } [\/]?$/i`; // Ensures the pattern allows an optional trailing slash
255
-
256
- matchedQueryString = [
257
- regexParser ( redirect . pattern ) . test ( `${ normalizedPath } ${ targetQS } ` ) ,
258
- regexParser ( redirect . pattern ) . test ( `/${ locale } ${ normalizedPath } ${ targetQS } ` ) ,
259
- ] . some ( Boolean )
260
- ? targetQS
261
- : undefined ;
262
-
263
- // Save the matched query string (if found) into the redirect object
264
- redirect . matchedQueryString = matchedQueryString || '' ;
265
-
266
- return (
267
- ! ! (
268
- regexParser ( redirect . pattern ) . test ( targetURL ) ||
269
- regexParser ( redirect . pattern ) . test ( `/${ req . nextUrl . locale } ${ targetURL } ` ) ||
270
- matchedQueryString
271
- ) && ( redirect . locale ? redirect . locale . toLowerCase ( ) === locale . toLowerCase ( ) : true )
272
- ) ;
273
- } )
274
- : undefined ;
275
283
}
276
284
285
+ private handler = async ( req : NextRequest , res ?: NextResponse ) : Promise < NextResponse > => {
286
+ return this . processRedirectRequest ( req , res ) ;
287
+ } ;
288
+
277
289
/**
278
290
* When a user clicks on a link generated by the Link component from next/link,
279
291
* Next.js adds special parameters in the route called path.
0 commit comments