1
+ /* eslint-disable complexity */
1
2
/* eslint-disable max-lines */
2
3
// Inspired from Donnie McNeal's solution:
3
4
// https://gist.github.com/wontondon/e8c4bdf2888875e4c755712e99279536
@@ -157,24 +158,49 @@ function sendIndexPath(pathBuilder: string, pathname: string, basename: string):
157
158
return [ formattedPath , 'route' ] ;
158
159
}
159
160
160
- function pathEndsWithWildcard ( path : string , branch : RouteMatch < string > ) : boolean {
161
- return ( path . slice ( - 2 ) === '/*' && branch . route . children && branch . route . children . length > 0 ) || false ;
161
+ function pathEndsWithWildcard ( path : string ) : boolean {
162
+ return path . endsWith ( '*' ) ;
162
163
}
163
164
164
165
function pathIsWildcardAndHasChildren ( path : string , branch : RouteMatch < string > ) : boolean {
165
- return ( path === '*' && branch . route . children && branch . route . children . length > 0 ) || false ;
166
+ return ( pathEndsWithWildcard ( path ) && branch . route . children && branch . route . children . length > 0 ) || false ;
167
+ }
168
+
169
+ function pathIsWildcardWithNoChildren ( path : string , branch : RouteMatch < string > ) : boolean {
170
+ return ( pathEndsWithWildcard ( path ) && ( ! branch . route . children || branch . route . children . length === 0 ) ) || false ;
166
171
}
167
172
168
173
function getNormalizedName (
169
174
routes : RouteObject [ ] ,
170
175
location : Location ,
171
176
branches : RouteMatch [ ] ,
172
177
basename : string = '' ,
178
+ allRoutes : RouteObject [ ] = routes ,
173
179
) : [ string , TransactionSource ] {
174
180
if ( ! routes || routes . length === 0 ) {
175
181
return [ _stripBasename ? stripBasenameFromPathname ( location . pathname , basename ) : location . pathname , 'url' ] ;
176
182
}
177
183
184
+ const matchedRoutes = _matchRoutes ( routes , location ) ;
185
+
186
+ if ( matchedRoutes ) {
187
+ const wildCardRoutes : RouteMatch [ ] = matchedRoutes . filter (
188
+ ( match : RouteMatch ) => match . route . path && pathIsWildcardWithNoChildren ( match . route . path , match ) ,
189
+ ) ;
190
+
191
+ for ( const wildCardRoute of wildCardRoutes ) {
192
+ const wildCardRouteMatch = _matchRoutes ( allRoutes , location , wildCardRoute . pathnameBase ) ;
193
+
194
+ if ( wildCardRouteMatch ) {
195
+ const [ name , source ] = getNormalizedName ( wildCardRoutes , location , wildCardRouteMatch , basename , allRoutes ) ;
196
+
197
+ if ( wildCardRoute . pathnameBase && name ) {
198
+ return [ wildCardRoute . pathnameBase + name , source ] ;
199
+ }
200
+ }
201
+ }
202
+ }
203
+
178
204
let pathBuilder = '' ;
179
205
if ( branches ) {
180
206
for ( const branch of branches ) {
@@ -192,20 +218,23 @@ function getNormalizedName(
192
218
pathBuilder += newPath ;
193
219
194
220
// If the path matches the current location, return the path
195
- if ( basename + branch . pathname === location . pathname ) {
221
+ if (
222
+ location . pathname . endsWith ( basename + branch . pathname ) ||
223
+ location . pathname . endsWith ( `${ basename } ${ branch . pathname } /` )
224
+ ) {
196
225
if (
197
226
// If the route defined on the element is something like
198
227
// <Route path="/stores/:storeId/products/:productId" element={<div>Product</div>} />
199
228
// We should check against the branch.pathname for the number of / separators
200
229
getNumberOfUrlSegments ( pathBuilder ) !== getNumberOfUrlSegments ( branch . pathname ) &&
201
230
// We should not count wildcard operators in the url segments calculation
202
- pathBuilder . slice ( - 2 ) !== '/*'
231
+ ! pathEndsWithWildcard ( pathBuilder )
203
232
) {
204
233
return [ ( _stripBasename ? '' : basename ) + newPath , 'route' ] ;
205
234
}
206
235
207
236
// if the last character of the pathbuilder is a wildcard and there are children, remove the wildcard
208
- if ( pathEndsWithWildcard ( pathBuilder , branch ) ) {
237
+ if ( pathIsWildcardAndHasChildren ( pathBuilder , branch ) ) {
209
238
pathBuilder = pathBuilder . slice ( 0 , - 1 ) ;
210
239
}
211
240
@@ -225,13 +254,14 @@ function updatePageloadTransaction(
225
254
routes : RouteObject [ ] ,
226
255
matches ?: AgnosticDataRouteMatch ,
227
256
basename ?: string ,
257
+ allRoutes ?: RouteObject [ ] ,
228
258
) : void {
229
259
const branches = Array . isArray ( matches )
230
260
? matches
231
261
: ( _matchRoutes ( routes , location , basename ) as unknown as RouteMatch [ ] ) ;
232
262
233
263
if ( branches ) {
234
- const [ name , source ] = getNormalizedName ( routes , location , branches , basename ) ;
264
+ const [ name , source ] = getNormalizedName ( routes , location , branches , basename , allRoutes ) ;
235
265
236
266
getCurrentScope ( ) . setTransactionName ( name ) ;
237
267
@@ -248,6 +278,7 @@ function handleNavigation(
248
278
navigationType : Action ,
249
279
matches ?: AgnosticDataRouteMatch ,
250
280
basename ?: string ,
281
+ allRoutes ?: RouteObject [ ] ,
251
282
) : void {
252
283
const branches = Array . isArray ( matches ) ? matches : _matchRoutes ( routes , location , basename ) ;
253
284
@@ -257,7 +288,7 @@ function handleNavigation(
257
288
}
258
289
259
290
if ( ( navigationType === 'PUSH' || navigationType === 'POP' ) && branches ) {
260
- const [ name , source ] = getNormalizedName ( routes , location , branches , basename ) ;
291
+ const [ name , source ] = getNormalizedName ( routes , location , branches , basename , allRoutes ) ;
261
292
262
293
startBrowserTracingNavigationSpan ( client , {
263
294
name,
@@ -270,6 +301,20 @@ function handleNavigation(
270
301
}
271
302
}
272
303
304
+ const getChildRoutesRecursively = ( route : RouteObject ) : RouteObject [ ] => {
305
+ const routes : RouteObject [ ] = [ ] ;
306
+
307
+ if ( route . children ) {
308
+ route . children . forEach ( child => {
309
+ routes . push ( ...getChildRoutesRecursively ( child ) ) ;
310
+ } ) ;
311
+ }
312
+
313
+ routes . push ( route ) ;
314
+
315
+ return routes ;
316
+ } ;
317
+
273
318
// eslint-disable-next-line @typescript-eslint/no-explicit-any
274
319
export function withSentryReactRouterV6Routing < P extends Record < string , any > , R extends React . FC < P > > ( Routes : R ) : R {
275
320
if ( ! _useEffect || ! _useLocation || ! _useNavigationType || ! _createRoutesFromChildren || ! _matchRoutes ) {
@@ -281,6 +326,7 @@ export function withSentryReactRouterV6Routing<P extends Record<string, any>, R
281
326
return Routes ;
282
327
}
283
328
329
+ const allRoutes : RouteObject [ ] = [ ] ;
284
330
let isMountRenderPass : boolean = true ;
285
331
286
332
const SentryRoutes : React . FC < P > = ( props : P ) => {
@@ -291,11 +337,15 @@ export function withSentryReactRouterV6Routing<P extends Record<string, any>, R
291
337
( ) => {
292
338
const routes = _createRoutesFromChildren ( props . children ) as RouteObject [ ] ;
293
339
340
+ routes . forEach ( route => {
341
+ allRoutes . push ( ...getChildRoutesRecursively ( route ) ) ;
342
+ } ) ;
343
+
294
344
if ( isMountRenderPass ) {
295
- updatePageloadTransaction ( getActiveRootSpan ( ) , location , routes ) ;
345
+ updatePageloadTransaction ( getActiveRootSpan ( ) , location , routes , undefined , undefined , allRoutes ) ;
296
346
isMountRenderPass = false ;
297
347
} else {
298
- handleNavigation ( location , routes , navigationType ) ;
348
+ handleNavigation ( location , routes , navigationType , undefined , undefined , allRoutes ) ;
299
349
}
300
350
} ,
301
351
// `props.children` is purposely not included in the dependency array, because we do not want to re-run this effect
@@ -326,6 +376,7 @@ export function wrapUseRoutes(origUseRoutes: UseRoutes): UseRoutes {
326
376
}
327
377
328
378
let isMountRenderPass : boolean = true ;
379
+ const allRoutes : RouteObject [ ] = [ ] ;
329
380
330
381
const SentryRoutes : React . FC < {
331
382
children ?: React . ReactNode ;
@@ -349,11 +400,15 @@ export function wrapUseRoutes(origUseRoutes: UseRoutes): UseRoutes {
349
400
const normalizedLocation =
350
401
typeof stableLocationParam === 'string' ? { pathname : stableLocationParam } : stableLocationParam ;
351
402
403
+ routes . forEach ( route => {
404
+ allRoutes . push ( ...getChildRoutesRecursively ( route ) ) ;
405
+ } ) ;
406
+
352
407
if ( isMountRenderPass ) {
353
- updatePageloadTransaction ( getActiveRootSpan ( ) , normalizedLocation , routes ) ;
408
+ updatePageloadTransaction ( getActiveRootSpan ( ) , normalizedLocation , routes , undefined , undefined , allRoutes ) ;
354
409
isMountRenderPass = false ;
355
410
} else {
356
- handleNavigation ( normalizedLocation , routes , navigationType ) ;
411
+ handleNavigation ( normalizedLocation , routes , navigationType , undefined , undefined , allRoutes ) ;
357
412
}
358
413
} , [ navigationType , stableLocationParam ] ) ;
359
414
0 commit comments