@depup/sentry__react 10.48.0-depup.0 → 10.67.0-depup.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/README.md +9 -3
- 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 +14 -77
- 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/index.js +6 -0
- package/build/cjs/index.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 +236 -692
- 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 +18 -96
- package/build/cjs/reactrouter-compat-utils/route-manifest.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/utils.js +82 -193
- package/build/cjs/reactrouter-compat-utils/utils.js.map +1 -1
- package/build/cjs/reactrouter.compat.js +29 -0
- package/build/cjs/reactrouter.compat.js.map +1 -0
- package/build/cjs/reactrouter.js +34 -111
- package/build/cjs/reactrouter.js.map +1 -1
- package/build/cjs/reactrouterv3.js +31 -60
- package/build/cjs/reactrouterv3.js.map +1 -1
- package/build/cjs/reactrouterv6.js +10 -42
- package/build/cjs/reactrouterv6.js.map +1 -1
- package/build/cjs/reactrouterv7.js +10 -42
- package/build/cjs/reactrouterv7.js.map +1 -1
- package/build/cjs/redux.js +61 -90
- package/build/cjs/redux.js.map +1 -1
- package/build/cjs/sdk.js +15 -10
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/tanstackrouter.js +90 -92
- 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 +13 -76
- 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/index.js +1 -0
- package/build/esm/index.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 +237 -693
- 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 +18 -96
- package/build/esm/reactrouter-compat-utils/route-manifest.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/utils.js +80 -191
- package/build/esm/reactrouter-compat-utils/utils.js.map +1 -1
- package/build/esm/reactrouter.compat.js +23 -0
- package/build/esm/reactrouter.compat.js.map +1 -0
- package/build/esm/reactrouter.js +34 -111
- package/build/esm/reactrouter.js.map +1 -1
- package/build/esm/reactrouterv3.js +29 -58
- package/build/esm/reactrouterv3.js.map +1 -1
- package/build/esm/reactrouterv6.js +10 -42
- package/build/esm/reactrouterv6.js.map +1 -1
- package/build/esm/reactrouterv7.js +10 -42
- package/build/esm/reactrouterv7.js.map +1 -1
- package/build/esm/redux.js +61 -90
- 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 +91 -93
- package/build/esm/tanstackrouter.js.map +1 -1
- package/build/types/error.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/isSyntheticEvent.d.ts +10 -0
- package/build/types/isSyntheticEvent.d.ts.map +1 -0
- package/build/types/reactrouter-compat-utils/instrumentation.d.ts +1 -1
- package/build/types/reactrouter-compat-utils/instrumentation.d.ts.map +1 -1
- package/build/types/reactrouter-compat-utils/utils.d.ts +1 -1
- package/build/types/reactrouter-compat-utils/utils.d.ts.map +1 -1
- package/build/types/reactrouter.compat.d.ts +42 -0
- package/build/types/reactrouter.compat.d.ts.map +1 -0
- package/build/types/reactrouter.d.ts.map +1 -1
- package/build/types/reactrouterv3.d.ts +1 -1
- package/build/types/reactrouterv3.d.ts.map +1 -1
- package/build/types/reactrouterv6.d.ts +10 -0
- package/build/types/reactrouterv6.d.ts.map +1 -1
- package/build/types/reactrouterv7.d.ts +10 -0
- package/build/types/reactrouterv7.d.ts.map +1 -1
- package/build/types/redux.d.ts +1 -1
- package/build/types/redux.d.ts.map +1 -1
- package/build/types/sdk.d.ts +1 -1
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types/tanstackrouter.d.ts +1 -1
- package/build/types/tanstackrouter.d.ts.map +1 -1
- package/build/types/vendor/tanstackrouter-types.d.ts +2 -1
- package/build/types/vendor/tanstackrouter-types.d.ts.map +1 -1
- package/build/types-ts3.8/index.d.ts +1 -0
- package/build/types-ts3.8/isSyntheticEvent.d.ts +10 -0
- package/build/types-ts3.8/reactrouter-compat-utils/instrumentation.d.ts +1 -1
- package/build/types-ts3.8/reactrouter-compat-utils/utils.d.ts +1 -1
- package/build/types-ts3.8/reactrouter.compat.d.ts +42 -0
- package/build/types-ts3.8/reactrouterv3.d.ts +1 -1
- package/build/types-ts3.8/reactrouterv6.d.ts +10 -0
- package/build/types-ts3.8/reactrouterv7.d.ts +10 -0
- package/build/types-ts3.8/redux.d.ts +1 -1
- package/build/types-ts3.8/sdk.d.ts +1 -1
- package/build/types-ts3.8/tanstackrouter.d.ts +1 -1
- package/build/types-ts3.8/vendor/tanstackrouter-types.d.ts +2 -1
- package/changes.json +8 -3
- package/package.json +18 -8
|
@@ -1,82 +1,49 @@
|
|
|
1
|
-
import { debug } from '@sentry/core';
|
|
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';\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":"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"}
|
|
@@ -1,184 +1,130 @@
|
|
|
1
|
-
import { getActiveSpan, getRootSpan, spanToJSON, debug } from '@sentry/core';
|
|
1
|
+
import { getActiveSpan, getRootSpan, spanToJSON, debug } from '@sentry/core/browser';
|
|
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
|
-
|
|
97
|
+
return "";
|
|
98
|
+
}
|
|
99
|
+
function reconstructNameFromDescendantParent(location, allRoutes, currentName) {
|
|
100
|
+
const descendantParents = allRoutes.filter(routeIsDescendant);
|
|
101
|
+
if (!descendantParents.length) {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
const matchedParents = _matchRoutes(descendantParents, location);
|
|
105
|
+
const parentMatch = matchedParents?.[matchedParents.length - 1];
|
|
106
|
+
if (!parentMatch || !pickSplat(parentMatch)) {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
const parentTemplate = trimSlash(trimWildcard(parentMatch.route.path || ""));
|
|
110
|
+
if (!parentTemplate) {
|
|
111
|
+
return void 0;
|
|
112
|
+
}
|
|
113
|
+
const expectedPrefix = prefixWithSlash(parentTemplate);
|
|
114
|
+
const firstElement = parentTemplate.split("/")[0];
|
|
115
|
+
const hasDynamicLead = firstElement?.startsWith(":") && currentName?.split("/").includes(firstElement);
|
|
116
|
+
if (currentName === expectedPrefix || currentName?.startsWith(`${expectedPrefix}/`) || hasDynamicLead) {
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
const remainingPathname = stripBasenameFromPathname(location.pathname, prefixWithSlash(parentMatch.pathnameBase)) || "/";
|
|
120
|
+
const remainingName = rebuildRoutePathFromAllRoutes(
|
|
121
|
+
allRoutes.filter((route) => route !== parentMatch.route),
|
|
122
|
+
{ pathname: remainingPathname }
|
|
123
|
+
);
|
|
124
|
+
return remainingName ? prefixWithSlash(`${parentTemplate}${prefixWithSlash(remainingName)}`) : void 0;
|
|
174
125
|
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Checks if the current location is inside a descendant route (route with splat parameter).
|
|
178
|
-
*/
|
|
179
126
|
function locationIsInsideDescendantRoute(location, routes) {
|
|
180
|
-
const matchedRoutes = _matchRoutes(routes, location)
|
|
181
|
-
|
|
127
|
+
const matchedRoutes = _matchRoutes(routes, location);
|
|
182
128
|
if (matchedRoutes) {
|
|
183
129
|
for (const match of matchedRoutes) {
|
|
184
130
|
if (routeIsDescendant(match.route) && pickSplat(match)) {
|
|
@@ -186,134 +132,77 @@ function locationIsInsideDescendantRoute(location, routes) {
|
|
|
186
132
|
}
|
|
187
133
|
}
|
|
188
134
|
}
|
|
189
|
-
|
|
190
135
|
return false;
|
|
191
136
|
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Returns a fallback transaction name from location pathname.
|
|
195
|
-
*/
|
|
196
137
|
function getFallbackTransactionName(location, basename) {
|
|
197
|
-
return _stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname ||
|
|
138
|
+
return _stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname || "";
|
|
198
139
|
}
|
|
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
|
-
) {
|
|
140
|
+
function getNormalizedName(routes, location, branches, basename = "") {
|
|
209
141
|
if (!routes || routes.length === 0) {
|
|
210
|
-
return [_stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname,
|
|
142
|
+
return [_stripBasename ? stripBasenameFromPathname(location.pathname, basename) : location.pathname, "url"];
|
|
211
143
|
}
|
|
212
|
-
|
|
213
144
|
if (!branches) {
|
|
214
|
-
return [getFallbackTransactionName(location, basename),
|
|
145
|
+
return [getFallbackTransactionName(location, basename), "url"];
|
|
215
146
|
}
|
|
216
|
-
|
|
217
|
-
let pathBuilder = '';
|
|
218
|
-
|
|
147
|
+
let pathBuilder = "";
|
|
219
148
|
for (const branch of branches) {
|
|
220
149
|
const route = branch.route;
|
|
221
150
|
if (!route) {
|
|
222
151
|
continue;
|
|
223
152
|
}
|
|
224
|
-
|
|
225
|
-
// Early return for index routes
|
|
226
153
|
if (route.index) {
|
|
227
154
|
return sendIndexPath(pathBuilder, branch.pathname, basename);
|
|
228
155
|
}
|
|
229
|
-
|
|
230
156
|
const path = route.path;
|
|
231
157
|
if (!path || pathIsWildcardAndHasChildren(path, branch)) {
|
|
232
158
|
continue;
|
|
233
159
|
}
|
|
234
|
-
|
|
235
|
-
// Build the route path
|
|
236
|
-
const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`;
|
|
160
|
+
const newPath = path[0] === "/" || pathBuilder[pathBuilder.length - 1] === "/" ? path : `/${path}`;
|
|
237
161
|
pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath);
|
|
238
|
-
|
|
239
|
-
// Check if this path matches the current location
|
|
240
162
|
if (trimSlash(location.pathname) !== trimSlash(basename + branch.pathname)) {
|
|
241
163
|
continue;
|
|
242
164
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) &&
|
|
247
|
-
!pathEndsWithWildcard(pathBuilder)
|
|
248
|
-
) {
|
|
249
|
-
return [(_stripBasename ? '' : basename) + newPath, 'route'];
|
|
165
|
+
if (getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) && !pathEndsWithWildcard(pathBuilder)) {
|
|
166
|
+
return [(_stripBasename ? "" : basename) + newPath, "route"];
|
|
250
167
|
}
|
|
251
|
-
|
|
252
|
-
// Handle wildcard routes with children - strip trailing wildcard
|
|
253
168
|
if (pathIsWildcardAndHasChildren(pathBuilder, branch)) {
|
|
254
169
|
pathBuilder = pathBuilder.slice(0, -1);
|
|
255
170
|
}
|
|
256
|
-
|
|
257
|
-
return [(_stripBasename ? '' : basename) + pathBuilder, 'route'];
|
|
171
|
+
return [(_stripBasename ? "" : basename) + pathBuilder, "route"];
|
|
258
172
|
}
|
|
259
|
-
|
|
260
|
-
// Fallback when no matching route found
|
|
261
|
-
return [getFallbackTransactionName(location, basename), 'url'];
|
|
173
|
+
return [getFallbackTransactionName(location, basename), "url"];
|
|
262
174
|
}
|
|
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
|
|
175
|
+
function resolveRouteNameAndSource(location, routes, allRoutes, branches, basename = "", lazyRouteManifest, enableAsyncRouteHandlers) {
|
|
277
176
|
if (enableAsyncRouteHandlers && lazyRouteManifest && lazyRouteManifest.length > 0) {
|
|
278
177
|
const manifestMatch = matchRouteManifest(location.pathname, lazyRouteManifest, basename);
|
|
279
178
|
if (manifestMatch) {
|
|
280
|
-
return [(_stripBasename ?
|
|
179
|
+
return [(_stripBasename ? "" : basename) + manifestMatch, "route"];
|
|
281
180
|
}
|
|
282
181
|
}
|
|
283
|
-
|
|
284
|
-
// Fall back to React Router route matching
|
|
285
182
|
let name;
|
|
286
|
-
let source =
|
|
287
|
-
|
|
183
|
+
let source = "url";
|
|
288
184
|
const isInDescendantRoute = locationIsInsideDescendantRoute(location, allRoutes);
|
|
289
|
-
|
|
290
185
|
if (isInDescendantRoute) {
|
|
291
186
|
name = prefixWithSlash(rebuildRoutePathFromAllRoutes(allRoutes, location));
|
|
292
|
-
source =
|
|
187
|
+
source = "route";
|
|
293
188
|
}
|
|
294
|
-
|
|
295
189
|
if (!isInDescendantRoute || !name) {
|
|
296
190
|
[name, source] = getNormalizedName(routes, location, branches, basename);
|
|
297
191
|
}
|
|
298
|
-
|
|
192
|
+
const anchoredName = reconstructNameFromDescendantParent(location, allRoutes, name);
|
|
193
|
+
if (anchoredName) {
|
|
194
|
+
return [anchoredName, "route"];
|
|
195
|
+
}
|
|
299
196
|
return [name || location.pathname, source];
|
|
300
197
|
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Gets the active root span if it's a pageload or navigation span.
|
|
304
|
-
*/
|
|
305
198
|
function getActiveRootSpan() {
|
|
306
199
|
const span = getActiveSpan();
|
|
307
|
-
const rootSpan = span ? getRootSpan(span) :
|
|
308
|
-
|
|
200
|
+
const rootSpan = span ? getRootSpan(span) : void 0;
|
|
309
201
|
if (!rootSpan) {
|
|
310
|
-
return
|
|
202
|
+
return void 0;
|
|
311
203
|
}
|
|
312
|
-
|
|
313
204
|
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;
|
|
205
|
+
return op === "navigation" || op === "pageload" ? rootSpan : void 0;
|
|
317
206
|
}
|
|
318
207
|
|
|
319
208
|
export { clearNavigationContext, getActiveRootSpan, getNavigationContext, getNormalizedName, getNumberOfUrlSegments, initializeRouterUtils, locationIsInsideDescendantRoute, pathEndsWithWildcard, pathIsWildcardAndHasChildren, prefixWithSlash, rebuildRoutePathFromAllRoutes, resolveRouteNameAndSource, routeIsDescendant, setNavigationContext, transactionNameHasWildcard };
|