@sentry/react 10.53.1 → 10.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/constants.js +3 -5
- package/build/cjs/constants.js.map +1 -1
- package/build/cjs/debug-build.js +0 -5
- package/build/cjs/debug-build.js.map +1 -1
- package/build/cjs/error.js +12 -72
- package/build/cjs/error.js.map +1 -1
- package/build/cjs/errorboundary.js +22 -77
- package/build/cjs/errorboundary.js.map +1 -1
- package/build/cjs/hoist-non-react-statics.js +16 -84
- package/build/cjs/hoist-non-react-statics.js.map +1 -1
- package/build/cjs/isSyntheticEvent.js +10 -0
- package/build/cjs/isSyntheticEvent.js.map +1 -0
- package/build/cjs/profiler.js +35 -110
- package/build/cjs/profiler.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/instrumentation.js +219 -690
- package/build/cjs/reactrouter-compat-utils/instrumentation.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/lazy-routes.js +24 -85
- package/build/cjs/reactrouter-compat-utils/lazy-routes.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/route-manifest.js +17 -95
- package/build/cjs/reactrouter-compat-utils/route-manifest.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/utils.js +48 -190
- package/build/cjs/reactrouter-compat-utils/utils.js.map +1 -1
- package/build/cjs/reactrouter.js +33 -113
- package/build/cjs/reactrouter.js.map +1 -1
- package/build/cjs/reactrouterv3.js +27 -59
- package/build/cjs/reactrouterv3.js.map +1 -1
- package/build/cjs/reactrouterv6.js +8 -41
- package/build/cjs/reactrouterv6.js.map +1 -1
- package/build/cjs/reactrouterv7.js +8 -41
- package/build/cjs/reactrouterv7.js.map +1 -1
- package/build/cjs/redux.js +60 -88
- package/build/cjs/redux.js.map +1 -1
- package/build/cjs/sdk.js +13 -8
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/tanstackrouter.js +24 -64
- package/build/cjs/tanstackrouter.js.map +1 -1
- package/build/esm/constants.js +3 -5
- package/build/esm/constants.js.map +1 -1
- package/build/esm/debug-build.js +0 -5
- package/build/esm/debug-build.js.map +1 -1
- package/build/esm/error.js +12 -72
- package/build/esm/error.js.map +1 -1
- package/build/esm/errorboundary.js +22 -77
- package/build/esm/errorboundary.js.map +1 -1
- package/build/esm/hoist-non-react-statics.js +16 -84
- package/build/esm/hoist-non-react-statics.js.map +1 -1
- package/build/esm/isSyntheticEvent.js +8 -0
- package/build/esm/isSyntheticEvent.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/profiler.js +35 -110
- package/build/esm/profiler.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/instrumentation.js +219 -690
- package/build/esm/reactrouter-compat-utils/instrumentation.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/lazy-routes.js +24 -85
- package/build/esm/reactrouter-compat-utils/lazy-routes.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/route-manifest.js +17 -95
- package/build/esm/reactrouter-compat-utils/route-manifest.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/utils.js +48 -190
- package/build/esm/reactrouter-compat-utils/utils.js.map +1 -1
- package/build/esm/reactrouter.js +33 -113
- package/build/esm/reactrouter.js.map +1 -1
- package/build/esm/reactrouterv3.js +27 -59
- package/build/esm/reactrouterv3.js.map +1 -1
- package/build/esm/reactrouterv6.js +8 -41
- package/build/esm/reactrouterv6.js.map +1 -1
- package/build/esm/reactrouterv7.js +8 -41
- package/build/esm/reactrouterv7.js.map +1 -1
- package/build/esm/redux.js +60 -88
- package/build/esm/redux.js.map +1 -1
- package/build/esm/sdk.js +15 -10
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/tanstackrouter.js +24 -64
- package/build/esm/tanstackrouter.js.map +1 -1
- package/build/types/isSyntheticEvent.d.ts +10 -0
- package/build/types/isSyntheticEvent.d.ts.map +1 -0
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types-ts3.8/isSyntheticEvent.d.ts +10 -0
- package/package.json +3 -3
|
@@ -1,82 +1,49 @@
|
|
|
1
1
|
import { debug } from '@sentry/core/browser';
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Strip the basename from a pathname if exists.
|
|
6
|
-
*
|
|
7
|
-
* Vendored and modified from `react-router`
|
|
8
|
-
* https://github.com/remix-run/react-router/blob/462bb712156a3f739d6139a0f14810b76b002df6/packages/router/utils.ts#L1038
|
|
9
|
-
*/
|
|
10
4
|
function stripBasenameFromPathname(pathname, basename) {
|
|
11
|
-
if (!basename || basename ===
|
|
5
|
+
if (!basename || basename === "/") {
|
|
12
6
|
return pathname;
|
|
13
7
|
}
|
|
14
|
-
|
|
15
8
|
if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
|
|
16
9
|
return pathname;
|
|
17
10
|
}
|
|
18
|
-
|
|
19
|
-
// We want to leave trailing slash behavior in the user's control, so if they
|
|
20
|
-
// specify a basename with a trailing slash, we should support it
|
|
21
|
-
const startIndex = basename.endsWith('/') ? basename.length - 1 : basename.length;
|
|
11
|
+
const startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
|
|
22
12
|
const nextChar = pathname.charAt(startIndex);
|
|
23
|
-
if (nextChar && nextChar !==
|
|
24
|
-
// pathname does not start with basename/
|
|
13
|
+
if (nextChar && nextChar !== "/") {
|
|
25
14
|
return pathname;
|
|
26
15
|
}
|
|
27
|
-
|
|
28
|
-
return pathname.slice(startIndex) || '/';
|
|
16
|
+
return pathname.slice(startIndex) || "/";
|
|
29
17
|
}
|
|
30
|
-
|
|
31
|
-
// Cache for sorted manifests - keyed by manifest array reference
|
|
32
|
-
const SORTED_MANIFEST_CACHE = new WeakMap();
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Matches a pathname against a route manifest and returns the matching pattern.
|
|
36
|
-
* Optionally strips a basename prefix before matching.
|
|
37
|
-
*/
|
|
18
|
+
const SORTED_MANIFEST_CACHE = /* @__PURE__ */ new WeakMap();
|
|
38
19
|
function matchRouteManifest(pathname, manifest, basename) {
|
|
39
20
|
if (!pathname || !manifest?.length) {
|
|
40
21
|
return null;
|
|
41
22
|
}
|
|
42
|
-
|
|
43
23
|
const normalizedPathname = basename ? stripBasenameFromPathname(pathname, basename) : pathname;
|
|
44
|
-
|
|
45
24
|
let sorted = SORTED_MANIFEST_CACHE.get(manifest);
|
|
46
25
|
if (!sorted) {
|
|
47
26
|
sorted = sortBySpecificity(manifest);
|
|
48
27
|
SORTED_MANIFEST_CACHE.set(manifest, sorted);
|
|
49
|
-
DEBUG_BUILD && debug.log(
|
|
28
|
+
DEBUG_BUILD && debug.log("[React Router] Sorted route manifest by specificity:", sorted.length, "patterns");
|
|
50
29
|
}
|
|
51
|
-
|
|
52
30
|
for (const pattern of sorted) {
|
|
53
31
|
if (matchesPattern(normalizedPathname, pattern)) {
|
|
54
|
-
DEBUG_BUILD && debug.log(
|
|
32
|
+
DEBUG_BUILD && debug.log("[React Router] Matched pathname", normalizedPathname, "to pattern", pattern);
|
|
55
33
|
return pattern;
|
|
56
34
|
}
|
|
57
35
|
}
|
|
58
|
-
|
|
59
|
-
DEBUG_BUILD && debug.log('[React Router] No manifest match found for pathname:', normalizedPathname);
|
|
36
|
+
DEBUG_BUILD && debug.log("[React Router] No manifest match found for pathname:", normalizedPathname);
|
|
60
37
|
return null;
|
|
61
38
|
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Checks if a pathname matches a route pattern.
|
|
65
|
-
*/
|
|
66
39
|
function matchesPattern(pathname, pattern) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return pathname === '/' || pathname === '';
|
|
40
|
+
if (pattern === "/") {
|
|
41
|
+
return pathname === "/" || pathname === "";
|
|
70
42
|
}
|
|
71
|
-
|
|
72
43
|
const pathSegments = splitPath(pathname);
|
|
73
44
|
const patternSegments = splitPath(pattern);
|
|
74
|
-
|
|
75
|
-
// Handle wildcard at end
|
|
76
|
-
const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === '*';
|
|
77
|
-
|
|
45
|
+
const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === "*";
|
|
78
46
|
if (hasWildcard) {
|
|
79
|
-
// Pattern with wildcard: path must have at least as many segments as pattern (minus wildcard)
|
|
80
47
|
const patternSegmentsWithoutWildcard = patternSegments.slice(0, -1);
|
|
81
48
|
if (pathSegments.length < patternSegmentsWithoutWildcard.length) {
|
|
82
49
|
return false;
|
|
@@ -88,101 +55,56 @@ function matchesPattern(pathname, pattern) {
|
|
|
88
55
|
}
|
|
89
56
|
return true;
|
|
90
57
|
}
|
|
91
|
-
|
|
92
|
-
// Exact segment count match required
|
|
93
58
|
if (pathSegments.length !== patternSegments.length) {
|
|
94
59
|
return false;
|
|
95
60
|
}
|
|
96
|
-
|
|
97
61
|
for (const [i, patternSegment] of patternSegments.entries()) {
|
|
98
62
|
if (!segmentMatches(pathSegments[i], patternSegment)) {
|
|
99
63
|
return false;
|
|
100
64
|
}
|
|
101
65
|
}
|
|
102
|
-
|
|
103
66
|
return true;
|
|
104
67
|
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Checks if a path segment matches a pattern segment.
|
|
108
|
-
*/
|
|
109
68
|
function segmentMatches(pathSegment, patternSegment) {
|
|
110
|
-
if (pathSegment ===
|
|
69
|
+
if (pathSegment === void 0 || patternSegment === void 0) {
|
|
111
70
|
return false;
|
|
112
71
|
}
|
|
113
|
-
// Parameter matches anything
|
|
114
72
|
if (PARAM_RE.test(patternSegment)) {
|
|
115
73
|
return true;
|
|
116
74
|
}
|
|
117
|
-
// Literal must match exactly
|
|
118
75
|
return pathSegment === patternSegment;
|
|
119
76
|
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Splits a path into segments, filtering out empty strings.
|
|
123
|
-
*/
|
|
124
77
|
function splitPath(path) {
|
|
125
|
-
return path.split(
|
|
78
|
+
return path.split("/").filter(Boolean);
|
|
126
79
|
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* React Router scoring weights and param detection.
|
|
130
|
-
* https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts
|
|
131
|
-
*/
|
|
132
80
|
const PARAM_RE = /^:[\w-]+$/;
|
|
133
81
|
const STATIC_SEGMENT_SCORE = 10;
|
|
134
82
|
const DYNAMIC_SEGMENT_SCORE = 3;
|
|
135
83
|
const EMPTY_SEGMENT_SCORE = 1;
|
|
136
84
|
const SPLAT_PENALTY = -2;
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Computes a specificity score for a route pattern.
|
|
140
|
-
* Matches React Router's computeScore() algorithm exactly.
|
|
141
|
-
*/
|
|
142
85
|
function computeScore(pattern) {
|
|
143
|
-
const segments = pattern.split(
|
|
144
|
-
|
|
145
|
-
// Base score is segment count (including empty segment from leading slash)
|
|
86
|
+
const segments = pattern.split("/");
|
|
146
87
|
let score = segments.length;
|
|
147
|
-
|
|
148
|
-
// Apply splat penalty once if pattern contains wildcard
|
|
149
|
-
if (segments.includes('*')) {
|
|
88
|
+
if (segments.includes("*")) {
|
|
150
89
|
score += SPLAT_PENALTY;
|
|
151
90
|
}
|
|
152
|
-
|
|
153
91
|
for (const segment of segments) {
|
|
154
|
-
if (segment ===
|
|
155
|
-
// Splat penalty already applied globally above
|
|
92
|
+
if (segment === "*") {
|
|
156
93
|
continue;
|
|
157
94
|
} else if (PARAM_RE.test(segment)) {
|
|
158
95
|
score += DYNAMIC_SEGMENT_SCORE;
|
|
159
|
-
} else if (segment ===
|
|
96
|
+
} else if (segment === "") {
|
|
160
97
|
score += EMPTY_SEGMENT_SCORE;
|
|
161
98
|
} else {
|
|
162
99
|
score += STATIC_SEGMENT_SCORE;
|
|
163
100
|
}
|
|
164
101
|
}
|
|
165
|
-
|
|
166
102
|
return score;
|
|
167
103
|
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Sorts route patterns by specificity (most specific first).
|
|
171
|
-
* Implements React Router's ranking algorithm from computeScore():
|
|
172
|
-
* https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts
|
|
173
|
-
*
|
|
174
|
-
* React Router scoring: base=segments.length, static=+10, dynamic=+3, empty=+1, splat=-2 (once)
|
|
175
|
-
* Higher score = more specific pattern.
|
|
176
|
-
* Equal scores preserve manifest order (same as React Router).
|
|
177
|
-
*
|
|
178
|
-
* Note: Users should order their manifest from most specific to least specific
|
|
179
|
-
* when patterns have equal specificity (e.g., `/users/:id/settings` and `/:type/123/settings`).
|
|
180
|
-
*/
|
|
181
104
|
function sortBySpecificity(manifest) {
|
|
182
105
|
return [...manifest].sort((a, b) => {
|
|
183
106
|
const aScore = computeScore(a);
|
|
184
107
|
const bScore = computeScore(b);
|
|
185
|
-
|
|
186
108
|
return bScore - aScore;
|
|
187
109
|
});
|
|
188
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-manifest.js","sources":["../../../src/reactrouter-compat-utils/route-manifest.ts"],"sourcesContent":["import { debug } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Strip the basename from a pathname if exists.\n *\n * Vendored and modified from `react-router`\n * https://github.com/remix-run/react-router/blob/462bb712156a3f739d6139a0f14810b76b002df6/packages/router/utils.ts#L1038\n */\nexport function stripBasenameFromPathname(pathname: string, basename: string): string {\n if (!basename || basename === '/') {\n return pathname;\n }\n\n if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {\n return pathname;\n }\n\n // We want to leave trailing slash behavior in the user's control, so if they\n // specify a basename with a trailing slash, we should support it\n const startIndex = basename.endsWith('/') ? basename.length - 1 : basename.length;\n const nextChar = pathname.charAt(startIndex);\n if (nextChar && nextChar !== '/') {\n // pathname does not start with basename/\n return pathname;\n }\n\n return pathname.slice(startIndex) || '/';\n}\n\n// Cache for sorted manifests - keyed by manifest array reference\nconst SORTED_MANIFEST_CACHE = new WeakMap<string[], string[]>();\n\n/**\n * Matches a pathname against a route manifest and returns the matching pattern.\n * Optionally strips a basename prefix before matching.\n */\nexport function matchRouteManifest(pathname: string, manifest: string[], basename?: string): string | null {\n if (!pathname || !manifest?.length) {\n return null;\n }\n\n const normalizedPathname = basename ? stripBasenameFromPathname(pathname, basename) : pathname;\n\n let sorted = SORTED_MANIFEST_CACHE.get(manifest);\n if (!sorted) {\n sorted = sortBySpecificity(manifest);\n SORTED_MANIFEST_CACHE.set(manifest, sorted);\n DEBUG_BUILD && debug.log('[React Router] Sorted route manifest by specificity:', sorted.length, 'patterns');\n }\n\n for (const pattern of sorted) {\n if (matchesPattern(normalizedPathname, pattern)) {\n DEBUG_BUILD && debug.log('[React Router] Matched pathname', normalizedPathname, 'to pattern', pattern);\n return pattern;\n }\n }\n\n DEBUG_BUILD && debug.log('[React Router] No manifest match found for pathname:', normalizedPathname);\n return null;\n}\n\n/**\n * Checks if a pathname matches a route pattern.\n */\nfunction matchesPattern(pathname: string, pattern: string): boolean {\n // Handle root path special case\n if (pattern === '/') {\n return pathname === '/' || pathname === '';\n }\n\n const pathSegments = splitPath(pathname);\n const patternSegments = splitPath(pattern);\n\n // Handle wildcard at end\n const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === '*';\n\n if (hasWildcard) {\n // Pattern with wildcard: path must have at least as many segments as pattern (minus wildcard)\n const patternSegmentsWithoutWildcard = patternSegments.slice(0, -1);\n if (pathSegments.length < patternSegmentsWithoutWildcard.length) {\n return false;\n }\n for (const [i, patternSegment] of patternSegmentsWithoutWildcard.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n return true;\n }\n\n // Exact segment count match required\n if (pathSegments.length !== patternSegments.length) {\n return false;\n }\n\n for (const [i, patternSegment] of patternSegments.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Checks if a path segment matches a pattern segment.\n */\nfunction segmentMatches(pathSegment: string | undefined, patternSegment: string | undefined): boolean {\n if (pathSegment === undefined || patternSegment === undefined) {\n return false;\n }\n // Parameter matches anything\n if (PARAM_RE.test(patternSegment)) {\n return true;\n }\n // Literal must match exactly\n return pathSegment === patternSegment;\n}\n\n/**\n * Splits a path into segments, filtering out empty strings.\n */\nfunction splitPath(path: string): string[] {\n return path.split('/').filter(Boolean);\n}\n\n/**\n * React Router scoring weights and param detection.\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n */\nconst PARAM_RE = /^:[\\w-]+$/;\nconst STATIC_SEGMENT_SCORE = 10;\nconst DYNAMIC_SEGMENT_SCORE = 3;\nconst EMPTY_SEGMENT_SCORE = 1;\nconst SPLAT_PENALTY = -2;\n\n/**\n * Computes a specificity score for a route pattern.\n * Matches React Router's computeScore() algorithm exactly.\n */\nfunction computeScore(pattern: string): number {\n const segments = pattern.split('/');\n\n // Base score is segment count (including empty segment from leading slash)\n let score = segments.length;\n\n // Apply splat penalty once if pattern contains wildcard\n if (segments.includes('*')) {\n score += SPLAT_PENALTY;\n }\n\n for (const segment of segments) {\n if (segment === '*') {\n // Splat penalty already applied globally above\n continue;\n } else if (PARAM_RE.test(segment)) {\n score += DYNAMIC_SEGMENT_SCORE;\n } else if (segment === '') {\n score += EMPTY_SEGMENT_SCORE;\n } else {\n score += STATIC_SEGMENT_SCORE;\n }\n }\n\n return score;\n}\n\n/**\n * Sorts route patterns by specificity (most specific first).\n * Implements React Router's ranking algorithm from computeScore():\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n *\n * React Router scoring: base=segments.length, static=+10, dynamic=+3, empty=+1, splat=-2 (once)\n * Higher score = more specific pattern.\n * Equal scores preserve manifest order (same as React Router).\n *\n * Note: Users should order their manifest from most specific to least specific\n * when patterns have equal specificity (e.g., `/users/:id/settings` and `/:type/123/settings`).\n */\nfunction sortBySpecificity(manifest: string[]): string[] {\n return [...manifest].sort((a, b) => {\n const aScore = computeScore(a);\n const bScore = computeScore(b);\n\n return bScore - aScore;\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"route-manifest.js","sources":["../../../src/reactrouter-compat-utils/route-manifest.ts"],"sourcesContent":["import { debug } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Strip the basename from a pathname if exists.\n *\n * Vendored and modified from `react-router`\n * https://github.com/remix-run/react-router/blob/462bb712156a3f739d6139a0f14810b76b002df6/packages/router/utils.ts#L1038\n */\nexport function stripBasenameFromPathname(pathname: string, basename: string): string {\n if (!basename || basename === '/') {\n return pathname;\n }\n\n if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {\n return pathname;\n }\n\n // We want to leave trailing slash behavior in the user's control, so if they\n // specify a basename with a trailing slash, we should support it\n const startIndex = basename.endsWith('/') ? basename.length - 1 : basename.length;\n const nextChar = pathname.charAt(startIndex);\n if (nextChar && nextChar !== '/') {\n // pathname does not start with basename/\n return pathname;\n }\n\n return pathname.slice(startIndex) || '/';\n}\n\n// Cache for sorted manifests - keyed by manifest array reference\nconst SORTED_MANIFEST_CACHE = new WeakMap<string[], string[]>();\n\n/**\n * Matches a pathname against a route manifest and returns the matching pattern.\n * Optionally strips a basename prefix before matching.\n */\nexport function matchRouteManifest(pathname: string, manifest: string[], basename?: string): string | null {\n if (!pathname || !manifest?.length) {\n return null;\n }\n\n const normalizedPathname = basename ? stripBasenameFromPathname(pathname, basename) : pathname;\n\n let sorted = SORTED_MANIFEST_CACHE.get(manifest);\n if (!sorted) {\n sorted = sortBySpecificity(manifest);\n SORTED_MANIFEST_CACHE.set(manifest, sorted);\n DEBUG_BUILD && debug.log('[React Router] Sorted route manifest by specificity:', sorted.length, 'patterns');\n }\n\n for (const pattern of sorted) {\n if (matchesPattern(normalizedPathname, pattern)) {\n DEBUG_BUILD && debug.log('[React Router] Matched pathname', normalizedPathname, 'to pattern', pattern);\n return pattern;\n }\n }\n\n DEBUG_BUILD && debug.log('[React Router] No manifest match found for pathname:', normalizedPathname);\n return null;\n}\n\n/**\n * Checks if a pathname matches a route pattern.\n */\nfunction matchesPattern(pathname: string, pattern: string): boolean {\n // Handle root path special case\n if (pattern === '/') {\n return pathname === '/' || pathname === '';\n }\n\n const pathSegments = splitPath(pathname);\n const patternSegments = splitPath(pattern);\n\n // Handle wildcard at end\n const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === '*';\n\n if (hasWildcard) {\n // Pattern with wildcard: path must have at least as many segments as pattern (minus wildcard)\n const patternSegmentsWithoutWildcard = patternSegments.slice(0, -1);\n if (pathSegments.length < patternSegmentsWithoutWildcard.length) {\n return false;\n }\n for (const [i, patternSegment] of patternSegmentsWithoutWildcard.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n return true;\n }\n\n // Exact segment count match required\n if (pathSegments.length !== patternSegments.length) {\n return false;\n }\n\n for (const [i, patternSegment] of patternSegments.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Checks if a path segment matches a pattern segment.\n */\nfunction segmentMatches(pathSegment: string | undefined, patternSegment: string | undefined): boolean {\n if (pathSegment === undefined || patternSegment === undefined) {\n return false;\n }\n // Parameter matches anything\n if (PARAM_RE.test(patternSegment)) {\n return true;\n }\n // Literal must match exactly\n return pathSegment === patternSegment;\n}\n\n/**\n * Splits a path into segments, filtering out empty strings.\n */\nfunction splitPath(path: string): string[] {\n return path.split('/').filter(Boolean);\n}\n\n/**\n * React Router scoring weights and param detection.\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n */\nconst PARAM_RE = /^:[\\w-]+$/;\nconst STATIC_SEGMENT_SCORE = 10;\nconst DYNAMIC_SEGMENT_SCORE = 3;\nconst EMPTY_SEGMENT_SCORE = 1;\nconst SPLAT_PENALTY = -2;\n\n/**\n * Computes a specificity score for a route pattern.\n * Matches React Router's computeScore() algorithm exactly.\n */\nfunction computeScore(pattern: string): number {\n const segments = pattern.split('/');\n\n // Base score is segment count (including empty segment from leading slash)\n let score = segments.length;\n\n // Apply splat penalty once if pattern contains wildcard\n if (segments.includes('*')) {\n score += SPLAT_PENALTY;\n }\n\n for (const segment of segments) {\n if (segment === '*') {\n // Splat penalty already applied globally above\n continue;\n } else if (PARAM_RE.test(segment)) {\n score += DYNAMIC_SEGMENT_SCORE;\n } else if (segment === '') {\n score += EMPTY_SEGMENT_SCORE;\n } else {\n score += STATIC_SEGMENT_SCORE;\n }\n }\n\n return score;\n}\n\n/**\n * Sorts route patterns by specificity (most specific first).\n * Implements React Router's ranking algorithm from computeScore():\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n *\n * React Router scoring: base=segments.length, static=+10, dynamic=+3, empty=+1, splat=-2 (once)\n * Higher score = more specific pattern.\n * Equal scores preserve manifest order (same as React Router).\n *\n * Note: Users should order their manifest from most specific to least specific\n * when patterns have equal specificity (e.g., `/users/:id/settings` and `/:type/123/settings`).\n */\nfunction sortBySpecificity(manifest: string[]): string[] {\n return [...manifest].sort((a, b) => {\n const aScore = computeScore(a);\n const bScore = computeScore(b);\n\n return bScore - aScore;\n });\n}\n"],"names":[],"mappings":";;;AASO,SAAS,yBAAA,CAA0B,UAAkB,QAAA,EAA0B;AACpF,EAAA,IAAI,CAAC,QAAA,IAAY,QAAA,KAAa,GAAA,EAAK;AACjC,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,SAAS,WAAA,EAAY,CAAE,WAAW,QAAA,CAAS,WAAA,EAAa,CAAA,EAAG;AAC9D,IAAA,OAAO,QAAA;AAAA,EACT;AAIA,EAAA,MAAM,UAAA,GAAa,SAAS,QAAA,CAAS,GAAG,IAAI,QAAA,CAAS,MAAA,GAAS,IAAI,QAAA,CAAS,MAAA;AAC3E,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,MAAA,CAAO,UAAU,CAAA;AAC3C,EAAA,IAAI,QAAA,IAAY,aAAa,GAAA,EAAK;AAEhC,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,OAAO,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA,IAAK,GAAA;AACvC;AAGA,MAAM,qBAAA,uBAA4B,OAAA,EAA4B;AAMvD,SAAS,kBAAA,CAAmB,QAAA,EAAkB,QAAA,EAAoB,QAAA,EAAkC;AACzG,EAAA,IAAI,CAAC,QAAA,IAAY,CAAC,QAAA,EAAU,MAAA,EAAQ;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,kBAAA,GAAqB,QAAA,GAAW,yBAAA,CAA0B,QAAA,EAAU,QAAQ,CAAA,GAAI,QAAA;AAEtF,EAAA,IAAI,MAAA,GAAS,qBAAA,CAAsB,GAAA,CAAI,QAAQ,CAAA;AAC/C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAA,GAAS,kBAAkB,QAAQ,CAAA;AACnC,IAAA,qBAAA,CAAsB,GAAA,CAAI,UAAU,MAAM,CAAA;AAC1C,IAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,sDAAA,EAAwD,MAAA,CAAO,QAAQ,UAAU,CAAA;AAAA,EAC5G;AAEA,EAAA,KAAA,MAAW,WAAW,MAAA,EAAQ;AAC5B,IAAA,IAAI,cAAA,CAAe,kBAAA,EAAoB,OAAO,CAAA,EAAG;AAC/C,MAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,iCAAA,EAAmC,kBAAA,EAAoB,cAAc,OAAO,CAAA;AACrG,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,sDAAA,EAAwD,kBAAkB,CAAA;AACnG,EAAA,OAAO,IAAA;AACT;AAKA,SAAS,cAAA,CAAe,UAAkB,OAAA,EAA0B;AAElE,EAAA,IAAI,YAAY,GAAA,EAAK;AACnB,IAAA,OAAO,QAAA,KAAa,OAAO,QAAA,KAAa,EAAA;AAAA,EAC1C;AAEA,EAAA,MAAM,YAAA,GAAe,UAAU,QAAQ,CAAA;AACvC,EAAA,MAAM,eAAA,GAAkB,UAAU,OAAO,CAAA;AAGzC,EAAA,MAAM,WAAA,GAAc,gBAAgB,MAAA,GAAS,CAAA,IAAK,gBAAgB,eAAA,CAAgB,MAAA,GAAS,CAAC,CAAA,KAAM,GAAA;AAElG,EAAA,IAAI,WAAA,EAAa;AAEf,IAAA,MAAM,8BAAA,GAAiC,eAAA,CAAgB,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAClE,IAAA,IAAI,YAAA,CAAa,MAAA,GAAS,8BAAA,CAA+B,MAAA,EAAQ;AAC/D,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,cAAc,CAAA,IAAK,8BAAA,CAA+B,SAAQ,EAAG;AAC1E,MAAA,IAAI,CAAC,cAAA,CAAe,YAAA,CAAa,CAAC,CAAA,EAAG,cAAc,CAAA,EAAG;AACpD,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,IAAI,YAAA,CAAa,MAAA,KAAW,eAAA,CAAgB,MAAA,EAAQ;AAClD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,cAAc,CAAA,IAAK,eAAA,CAAgB,SAAQ,EAAG;AAC3D,IAAA,IAAI,CAAC,cAAA,CAAe,YAAA,CAAa,CAAC,CAAA,EAAG,cAAc,CAAA,EAAG;AACpD,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAKA,SAAS,cAAA,CAAe,aAAiC,cAAA,EAA6C;AACpG,EAAA,IAAI,WAAA,KAAgB,MAAA,IAAa,cAAA,KAAmB,MAAA,EAAW;AAC7D,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAA,CAAS,IAAA,CAAK,cAAc,CAAA,EAAG;AACjC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,WAAA,KAAgB,cAAA;AACzB;AAKA,SAAS,UAAU,IAAA,EAAwB;AACzC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AACvC;AAMA,MAAM,QAAA,GAAW,WAAA;AACjB,MAAM,oBAAA,GAAuB,EAAA;AAC7B,MAAM,qBAAA,GAAwB,CAAA;AAC9B,MAAM,mBAAA,GAAsB,CAAA;AAC5B,MAAM,aAAA,GAAgB,EAAA;AAMtB,SAAS,aAAa,OAAA,EAAyB;AAC7C,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA;AAGlC,EAAA,IAAI,QAAQ,QAAA,CAAS,MAAA;AAGrB,EAAA,IAAI,QAAA,CAAS,QAAA,CAAS,GAAG,CAAA,EAAG;AAC1B,IAAA,KAAA,IAAS,aAAA;AAAA,EACX;AAEA,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAI,YAAY,GAAA,EAAK;AAEnB,MAAA;AAAA,IACF,CAAA,MAAA,IAAW,QAAA,CAAS,IAAA,CAAK,OAAO,CAAA,EAAG;AACjC,MAAA,KAAA,IAAS,qBAAA;AAAA,IACX,CAAA,MAAA,IAAW,YAAY,EAAA,EAAI;AACzB,MAAA,KAAA,IAAS,mBAAA;AAAA,IACX,CAAA,MAAO;AACL,MAAA,KAAA,IAAS,oBAAA;AAAA,IACX;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAcA,SAAS,kBAAkB,QAAA,EAA8B;AACvD,EAAA,OAAO,CAAC,GAAG,QAAQ,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AAClC,IAAA,MAAM,MAAA,GAAS,aAAa,CAAC,CAAA;AAC7B,IAAA,MAAM,MAAA,GAAS,aAAa,CAAC,CAAA;AAE7B,IAAA,OAAO,MAAA,GAAS,MAAA;AAAA,EAClB,CAAC,CAAA;AACH;;;;"}
|
|
@@ -2,183 +2,102 @@ import { getActiveSpan, getRootSpan, spanToJSON, debug } from '@sentry/core/brow
|
|
|
2
2
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
3
|
import { matchRouteManifest, stripBasenameFromPathname } from './route-manifest.js';
|
|
4
4
|
|
|
5
|
-
// Global variables that these utilities depend on
|
|
6
5
|
let _matchRoutes;
|
|
7
6
|
let _stripBasename = false;
|
|
8
|
-
|
|
9
|
-
// Navigation context stack for nested/concurrent patchRoutesOnNavigation calls.
|
|
10
|
-
// Required because window.location hasn't updated yet when handlers are invoked.
|
|
11
|
-
|
|
12
7
|
const _navigationContextStack = [];
|
|
13
8
|
const MAX_CONTEXT_STACK_SIZE = 10;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Pushes a navigation context and returns a unique token for cleanup.
|
|
17
|
-
* The token uses object identity for uniqueness (no counter needed).
|
|
18
|
-
*/
|
|
19
9
|
function setNavigationContext(targetPath, span) {
|
|
20
10
|
const token = {};
|
|
21
|
-
// Prevent unbounded stack growth - oldest (likely stale) contexts are evicted first
|
|
22
11
|
if (_navigationContextStack.length >= MAX_CONTEXT_STACK_SIZE) {
|
|
23
|
-
DEBUG_BUILD && debug.warn(
|
|
12
|
+
DEBUG_BUILD && debug.warn("[React Router] Navigation context stack overflow - removing oldest context");
|
|
24
13
|
_navigationContextStack.shift();
|
|
25
14
|
}
|
|
26
15
|
_navigationContextStack.push({ token, targetPath, span });
|
|
27
16
|
return token;
|
|
28
17
|
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Clears the navigation context if it's on top of the stack (LIFO).
|
|
32
|
-
* If our context is not on top (out-of-order completion), we leave it -
|
|
33
|
-
* it will be cleaned up by overflow protection when the stack fills up.
|
|
34
|
-
*/
|
|
35
18
|
function clearNavigationContext(token) {
|
|
36
19
|
const top = _navigationContextStack[_navigationContextStack.length - 1];
|
|
37
20
|
if (top?.token === token) {
|
|
38
21
|
_navigationContextStack.pop();
|
|
39
22
|
}
|
|
40
23
|
}
|
|
41
|
-
|
|
42
|
-
/** Gets the current (most recent) navigation context if inside a patchRoutesOnNavigation call. */
|
|
43
24
|
function getNavigationContext() {
|
|
44
25
|
const length = _navigationContextStack.length;
|
|
45
|
-
|
|
46
|
-
return length > 0 ? (_navigationContextStack[length - 1] ?? null) : null;
|
|
26
|
+
return length > 0 ? _navigationContextStack[length - 1] ?? null : null;
|
|
47
27
|
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Initialize function to set dependencies that the router utilities need.
|
|
51
|
-
* Must be called before using any of the exported utility functions.
|
|
52
|
-
*/
|
|
53
28
|
function initializeRouterUtils(matchRoutes, stripBasename = false) {
|
|
54
29
|
_matchRoutes = matchRoutes;
|
|
55
30
|
_stripBasename = stripBasename;
|
|
56
31
|
}
|
|
57
|
-
|
|
58
|
-
// Helper functions
|
|
59
32
|
function pickPath(match) {
|
|
60
|
-
return trimWildcard(match.route.path ||
|
|
33
|
+
return trimWildcard(match.route.path || "");
|
|
61
34
|
}
|
|
62
|
-
|
|
63
35
|
function pickSplat(match) {
|
|
64
|
-
return match.params[
|
|
36
|
+
return match.params["*"] || "";
|
|
65
37
|
}
|
|
66
|
-
|
|
67
38
|
function trimWildcard(path) {
|
|
68
|
-
return path[path.length - 1] ===
|
|
39
|
+
return path[path.length - 1] === "*" ? path.slice(0, -1) : path;
|
|
69
40
|
}
|
|
70
|
-
|
|
71
41
|
function trimSlash(path) {
|
|
72
|
-
return path[path.length - 1] ===
|
|
42
|
+
return path[path.length - 1] === "/" ? path.slice(0, -1) : path;
|
|
73
43
|
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Checks if a path ends with a wildcard character (*).
|
|
77
|
-
*/
|
|
78
44
|
function pathEndsWithWildcard(path) {
|
|
79
|
-
return path.endsWith(
|
|
45
|
+
return path.endsWith("*");
|
|
80
46
|
}
|
|
81
|
-
|
|
82
|
-
/** Checks if transaction name has wildcard (/* or ends with *). */
|
|
83
47
|
function transactionNameHasWildcard(name) {
|
|
84
|
-
return name.includes(
|
|
48
|
+
return name.includes("/*") || name.endsWith("*");
|
|
85
49
|
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Checks if a path is a wildcard and has child routes.
|
|
89
|
-
*/
|
|
90
50
|
function pathIsWildcardAndHasChildren(path, branch) {
|
|
91
|
-
return
|
|
51
|
+
return pathEndsWithWildcard(path) && !!branch.route.children?.length || false;
|
|
92
52
|
}
|
|
93
|
-
|
|
94
|
-
/** Check if route is in descendant route (<Routes> within <Routes>) */
|
|
95
53
|
function routeIsDescendant(route) {
|
|
96
|
-
return !!(!route.children && route.element && route.path?.endsWith(
|
|
54
|
+
return !!(!route.children && route.element && route.path?.endsWith("/*"));
|
|
97
55
|
}
|
|
98
|
-
|
|
99
56
|
function sendIndexPath(pathBuilder, pathname, basename) {
|
|
100
|
-
const reconstructedPath =
|
|
101
|
-
|
|
102
|
-
? pathBuilder
|
|
103
|
-
: _stripBasename
|
|
104
|
-
? stripBasenameFromPathname(pathname, basename)
|
|
105
|
-
: pathname;
|
|
106
|
-
|
|
107
|
-
let formattedPath =
|
|
57
|
+
const reconstructedPath = pathBuilder && pathBuilder.length > 0 ? pathBuilder : _stripBasename ? stripBasenameFromPathname(pathname, basename) : pathname;
|
|
58
|
+
let formattedPath = (
|
|
108
59
|
// If the path ends with a wildcard suffix, remove both the slash and the asterisk
|
|
109
|
-
reconstructedPath.slice(-2) ===
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (formattedPath.length > 1 && formattedPath[formattedPath.length - 1] === '/') {
|
|
60
|
+
reconstructedPath.slice(-2) === "/*" ? reconstructedPath.slice(0, -2) : reconstructedPath
|
|
61
|
+
);
|
|
62
|
+
if (formattedPath.length > 1 && formattedPath[formattedPath.length - 1] === "/") {
|
|
113
63
|
formattedPath = formattedPath.slice(0, -1);
|
|
114
64
|
}
|
|
115
|
-
|
|
116
|
-
return [formattedPath, 'route'];
|
|
65
|
+
return [formattedPath, "route"];
|
|
117
66
|
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Returns the number of URL segments in the given URL string.
|
|
121
|
-
* Splits at '/' or '\/' to handle regex URLs correctly.
|
|
122
|
-
*
|
|
123
|
-
* @param url - The URL string to segment.
|
|
124
|
-
* @returns The number of segments in the URL.
|
|
125
|
-
*/
|
|
126
67
|
function getNumberOfUrlSegments(url) {
|
|
127
|
-
|
|
128
|
-
return url.split(/\\?\//).filter(s => s.length > 0 && s !== ',').length;
|
|
68
|
+
return url.split(/\\?\//).filter((s) => s.length > 0 && s !== ",").length;
|
|
129
69
|
}
|
|
130
|
-
|
|
131
|
-
// Exported utility functions
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Ensures a path string starts with a forward slash.
|
|
135
|
-
*/
|
|
136
70
|
function prefixWithSlash(path) {
|
|
137
|
-
return path[0] ===
|
|
71
|
+
return path[0] === "/" ? path : `/${path}`;
|
|
138
72
|
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Rebuilds the route path from all available routes by matching against the current location.
|
|
142
|
-
*/
|
|
143
73
|
function rebuildRoutePathFromAllRoutes(allRoutes, location) {
|
|
144
|
-
const matchedRoutes = _matchRoutes(allRoutes, location)
|
|
145
|
-
|
|
74
|
+
const matchedRoutes = _matchRoutes(allRoutes, location);
|
|
146
75
|
if (!matchedRoutes || matchedRoutes.length === 0) {
|
|
147
|
-
return
|
|
76
|
+
return "";
|
|
148
77
|
}
|
|
149
|
-
|
|
150
78
|
for (const match of matchedRoutes) {
|
|
151
|
-
if (match.route.path && match.route.path !==
|
|
79
|
+
if (match.route.path && match.route.path !== "*") {
|
|
152
80
|
const path = pickPath(match);
|
|
153
81
|
const strippedPath = stripBasenameFromPathname(location.pathname, prefixWithSlash(match.pathnameBase));
|
|
154
|
-
|
|
155
82
|
if (location.pathname === strippedPath) {
|
|
156
83
|
return trimSlash(strippedPath);
|
|
157
84
|
}
|
|
158
|
-
|
|
159
85
|
return trimSlash(
|
|
160
|
-
trimSlash(path ||
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
),
|
|
86
|
+
trimSlash(path || "") + prefixWithSlash(
|
|
87
|
+
rebuildRoutePathFromAllRoutes(
|
|
88
|
+
allRoutes.filter((route) => route !== match.route),
|
|
89
|
+
{
|
|
90
|
+
pathname: strippedPath
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
)
|
|
169
94
|
);
|
|
170
95
|
}
|
|
171
96
|
}
|
|
172
|
-
|
|
173
|
-
return '';
|
|
97
|
+
return "";
|
|
174
98
|
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Checks if the current location is inside a descendant route (route with splat parameter).
|
|
178
|
-
*/
|
|
179
99
|
function locationIsInsideDescendantRoute(location, routes) {
|
|
180
|
-
const matchedRoutes = _matchRoutes(routes, location)
|
|
181
|
-
|
|
100
|
+
const matchedRoutes = _matchRoutes(routes, location);
|
|
182
101
|
if (matchedRoutes) {
|
|
183
102
|
for (const match of matchedRoutes) {
|
|
184
103
|
if (routeIsDescendant(match.route) && pickSplat(match)) {
|
|
@@ -186,134 +105,73 @@ function locationIsInsideDescendantRoute(location, routes) {
|
|
|
186
105
|
}
|
|
187
106
|
}
|
|
188
107
|
}
|
|
189
|
-
|
|
190
108
|
return false;
|
|
191
109
|
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Returns a fallback transaction name from location pathname.
|
|
195
|
-
*/
|
|
196
110
|
function getFallbackTransactionName(location, basename) {
|
|
197
|
-
return _stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname ||
|
|
111
|
+
return _stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname || "";
|
|
198
112
|
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Gets a normalized route name and transaction source from the current routes and location.
|
|
202
|
-
*/
|
|
203
|
-
function getNormalizedName(
|
|
204
|
-
routes,
|
|
205
|
-
location,
|
|
206
|
-
branches,
|
|
207
|
-
basename = '',
|
|
208
|
-
) {
|
|
113
|
+
function getNormalizedName(routes, location, branches, basename = "") {
|
|
209
114
|
if (!routes || routes.length === 0) {
|
|
210
|
-
return [_stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname,
|
|
115
|
+
return [_stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname, "url"];
|
|
211
116
|
}
|
|
212
|
-
|
|
213
117
|
if (!branches) {
|
|
214
|
-
return [getFallbackTransactionName(location, basename),
|
|
118
|
+
return [getFallbackTransactionName(location, basename), "url"];
|
|
215
119
|
}
|
|
216
|
-
|
|
217
|
-
let pathBuilder = '';
|
|
218
|
-
|
|
120
|
+
let pathBuilder = "";
|
|
219
121
|
for (const branch of branches) {
|
|
220
122
|
const route = branch.route;
|
|
221
123
|
if (!route) {
|
|
222
124
|
continue;
|
|
223
125
|
}
|
|
224
|
-
|
|
225
|
-
// Early return for index routes
|
|
226
126
|
if (route.index) {
|
|
227
127
|
return sendIndexPath(pathBuilder, branch.pathname, basename);
|
|
228
128
|
}
|
|
229
|
-
|
|
230
129
|
const path = route.path;
|
|
231
130
|
if (!path || pathIsWildcardAndHasChildren(path, branch)) {
|
|
232
131
|
continue;
|
|
233
132
|
}
|
|
234
|
-
|
|
235
|
-
// Build the route path
|
|
236
|
-
const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`;
|
|
133
|
+
const newPath = path[0] === "/" || pathBuilder[pathBuilder.length - 1] === "/" ? path : `/${path}`;
|
|
237
134
|
pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath);
|
|
238
|
-
|
|
239
|
-
// Check if this path matches the current location
|
|
240
135
|
if (trimSlash(location.pathname) !== trimSlash(basename + branch.pathname)) {
|
|
241
136
|
continue;
|
|
242
137
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) &&
|
|
247
|
-
!pathEndsWithWildcard(pathBuilder)
|
|
248
|
-
) {
|
|
249
|
-
return [(_stripBasename ? '' : basename) + newPath, 'route'];
|
|
138
|
+
if (getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) && !pathEndsWithWildcard(pathBuilder)) {
|
|
139
|
+
return [(_stripBasename ? "" : basename) + newPath, "route"];
|
|
250
140
|
}
|
|
251
|
-
|
|
252
|
-
// Handle wildcard routes with children - strip trailing wildcard
|
|
253
141
|
if (pathIsWildcardAndHasChildren(pathBuilder, branch)) {
|
|
254
142
|
pathBuilder = pathBuilder.slice(0, -1);
|
|
255
143
|
}
|
|
256
|
-
|
|
257
|
-
return [(_stripBasename ? '' : basename) + pathBuilder, 'route'];
|
|
144
|
+
return [(_stripBasename ? "" : basename) + pathBuilder, "route"];
|
|
258
145
|
}
|
|
259
|
-
|
|
260
|
-
// Fallback when no matching route found
|
|
261
|
-
return [getFallbackTransactionName(location, basename), 'url'];
|
|
146
|
+
return [getFallbackTransactionName(location, basename), "url"];
|
|
262
147
|
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Shared helper function to resolve route name and source
|
|
266
|
-
*/
|
|
267
|
-
function resolveRouteNameAndSource(
|
|
268
|
-
location,
|
|
269
|
-
routes,
|
|
270
|
-
allRoutes,
|
|
271
|
-
branches,
|
|
272
|
-
basename = '',
|
|
273
|
-
lazyRouteManifest,
|
|
274
|
-
enableAsyncRouteHandlers,
|
|
275
|
-
) {
|
|
276
|
-
// When lazy route manifest is provided, use it as the primary source for transaction names
|
|
148
|
+
function resolveRouteNameAndSource(location, routes, allRoutes, branches, basename = "", lazyRouteManifest, enableAsyncRouteHandlers) {
|
|
277
149
|
if (enableAsyncRouteHandlers && lazyRouteManifest && lazyRouteManifest.length > 0) {
|
|
278
150
|
const manifestMatch = matchRouteManifest(location.pathname, lazyRouteManifest, basename);
|
|
279
151
|
if (manifestMatch) {
|
|
280
|
-
return [(_stripBasename ?
|
|
152
|
+
return [(_stripBasename ? "" : basename) + manifestMatch, "route"];
|
|
281
153
|
}
|
|
282
154
|
}
|
|
283
|
-
|
|
284
|
-
// Fall back to React Router route matching
|
|
285
155
|
let name;
|
|
286
|
-
let source =
|
|
287
|
-
|
|
156
|
+
let source = "url";
|
|
288
157
|
const isInDescendantRoute = locationIsInsideDescendantRoute(location, allRoutes);
|
|
289
|
-
|
|
290
158
|
if (isInDescendantRoute) {
|
|
291
159
|
name = prefixWithSlash(rebuildRoutePathFromAllRoutes(allRoutes, location));
|
|
292
|
-
source =
|
|
160
|
+
source = "route";
|
|
293
161
|
}
|
|
294
|
-
|
|
295
162
|
if (!isInDescendantRoute || !name) {
|
|
296
163
|
[name, source] = getNormalizedName(routes, location, branches, basename);
|
|
297
164
|
}
|
|
298
|
-
|
|
299
165
|
return [name || location.pathname, source];
|
|
300
166
|
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Gets the active root span if it's a pageload or navigation span.
|
|
304
|
-
*/
|
|
305
167
|
function getActiveRootSpan() {
|
|
306
168
|
const span = getActiveSpan();
|
|
307
|
-
const rootSpan = span ? getRootSpan(span) :
|
|
308
|
-
|
|
169
|
+
const rootSpan = span ? getRootSpan(span) : void 0;
|
|
309
170
|
if (!rootSpan) {
|
|
310
|
-
return
|
|
171
|
+
return void 0;
|
|
311
172
|
}
|
|
312
|
-
|
|
313
173
|
const op = spanToJSON(rootSpan).op;
|
|
314
|
-
|
|
315
|
-
// Only use this root span if it is a pageload or navigation span
|
|
316
|
-
return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;
|
|
174
|
+
return op === "navigation" || op === "pageload" ? rootSpan : void 0;
|
|
317
175
|
}
|
|
318
176
|
|
|
319
177
|
export { clearNavigationContext, getActiveRootSpan, getNavigationContext, getNormalizedName, getNumberOfUrlSegments, initializeRouterUtils, locationIsInsideDescendantRoute, pathEndsWithWildcard, pathIsWildcardAndHasChildren, prefixWithSlash, rebuildRoutePathFromAllRoutes, resolveRouteNameAndSource, routeIsDescendant, setNavigationContext, transactionNameHasWildcard };
|