Skip to content

Commit 2146eb4

Browse files
committed
fix: Detect raw-to-parameterized route upgrades in cross-usage scenarios
- Add isParameterizedRoute() helper to detect if route has parameters (:id) or wildcards (*) - Update shouldSkipNavigation() to detect raw path to parameterized route upgrades - Enables proper updateName() calls in cross-usage scenarios - Fixes 3 failing cross-usage navigation tests In cross-usage scenarios (e.g., wrapCreateBrowserRouter + wrapUseRoutes), the first wrapper may create a span with the raw URL path (e.g., /second-level/321/third-level/123) if nested routes aren't fully resolved yet. The second wrapper should then upgrade it to the parameterized form (e.g., /second-level/:id/third-level/:id). Previously, this upgrade wasn't detected because we only checked for wildcard-to-parameterized and length-based specificity. Now we also detect raw-to-parameterized upgrades.
1 parent c29e60f commit 2146eb4

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

packages/react/src/reactrouter-compat-utils/instrumentation.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ export function computeLocationKey(location: Location): string {
9696
return `${location.pathname}${location.search || ''}${location.hash || ''}`;
9797
}
9898

99+
/**
100+
* Checks if a route name is parameterized (contains route parameters like :id or wildcards like *)
101+
* vs a raw URL path.
102+
*/
103+
function isParameterizedRoute(routeName: string): boolean {
104+
return routeName.includes(':') || routeName.includes('*');
105+
}
106+
99107
/**
100108
* Determines if a navigation should be skipped as a duplicate, and if an existing span should be updated.
101109
* Exported for testing.
@@ -122,14 +130,17 @@ export function shouldSkipNavigation(
122130
// This allows cross-usage scenarios where the second wrapper has more complete route info
123131
const currentHasWildcard = !!trackedNav.routeName && transactionNameHasWildcard(trackedNav.routeName);
124132
const proposedHasWildcard = transactionNameHasWildcard(proposedName);
133+
const currentIsParameterized = !!trackedNav.routeName && isParameterizedRoute(trackedNav.routeName);
134+
const proposedIsParameterized = isParameterizedRoute(proposedName);
125135

126136
const isWildcardUpgrade = currentHasWildcard && !proposedHasWildcard;
137+
const isRawToParameterized = !currentIsParameterized && proposedIsParameterized;
127138
const isMoreSpecific =
128139
proposedName !== trackedNav.routeName &&
129140
proposedName.length > (trackedNav.routeName?.length || 0) &&
130141
!proposedHasWildcard;
131142

132-
const shouldUpdate = !!(trackedNav.routeName && (isWildcardUpgrade || isMoreSpecific));
143+
const shouldUpdate = !!(trackedNav.routeName && (isWildcardUpgrade || isRawToParameterized || isMoreSpecific));
133144

134145
return { skip: true, shouldUpdate };
135146
}
@@ -141,17 +152,21 @@ export function shouldSkipNavigation(
141152
// Check if we should update the span name with a better route
142153
// Allow updates if:
143154
// 1. Current has wildcard and new doesn't (wildcard → parameterized upgrade)
144-
// 2. New name is different and more specific (longer, indicating nested routes resolved)
155+
// 2. Current is raw path and new is parameterized (raw → parameterized upgrade)
156+
// 3. New name is different and more specific (longer, indicating nested routes resolved)
145157
const currentHasWildcard = !!trackedNav.routeName && transactionNameHasWildcard(trackedNav.routeName);
146158
const proposedHasWildcard = transactionNameHasWildcard(proposedName);
159+
const currentIsParameterized = !!trackedNav.routeName && isParameterizedRoute(trackedNav.routeName);
160+
const proposedIsParameterized = isParameterizedRoute(proposedName);
147161

148162
const isWildcardUpgrade = currentHasWildcard && !proposedHasWildcard;
163+
const isRawToParameterized = !currentIsParameterized && proposedIsParameterized;
149164
const isMoreSpecific =
150165
proposedName !== trackedNav.routeName &&
151166
proposedName.length > (trackedNav.routeName?.length || 0) &&
152167
!proposedHasWildcard;
153168

154-
const shouldUpdate = !!(trackedNav.routeName && (isWildcardUpgrade || isMoreSpecific));
169+
const shouldUpdate = !!(trackedNav.routeName && (isWildcardUpgrade || isRawToParameterized || isMoreSpecific));
155170

156171
return { skip: true, shouldUpdate };
157172
}
@@ -802,7 +817,9 @@ export function handleNavigation(opts: {
802817
// Update placeholder's route name - the real span will be created with this name
803818
trackedNav.routeName = name;
804819
DEBUG_BUILD &&
805-
debug.log(`[Tracing] Updated placeholder navigation name from "${oldName}" to "${name}" (will apply to real span)`);
820+
debug.log(
821+
`[Tracing] Updated placeholder navigation name from "${oldName}" to "${name}" (will apply to real span)`,
822+
);
806823
} else {
807824
// Update existing real span from wildcard to parameterized route name
808825
trackedNav.span.updateName(name);

0 commit comments

Comments
 (0)