Files
klz-cables.com/.pnpm-store/v10/files/95/5cf8b124df0da122e6fc74cb9795cfe7b8f911a335a0111c3c29112a7b536f94525b1ed68f5f56e33e129163b4b3dd45b1945f6486d105bf3cb54c5bd5223c
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

337 lines
10 KiB
Plaintext

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const core = require('@sentry/core');
const debugBuild = require('../debug-build.js');
const routeManifest = require('./route-manifest.js');
// Global variables that these utilities depend on
let _matchRoutes;
let _stripBasename = false;
// Navigation context stack for nested/concurrent patchRoutesOnNavigation calls.
// Required because window.location hasn't updated yet when handlers are invoked.
const _navigationContextStack = [];
const MAX_CONTEXT_STACK_SIZE = 10;
/**
* Pushes a navigation context and returns a unique token for cleanup.
* The token uses object identity for uniqueness (no counter needed).
*/
function setNavigationContext(targetPath, span) {
const token = {};
// Prevent unbounded stack growth - oldest (likely stale) contexts are evicted first
if (_navigationContextStack.length >= MAX_CONTEXT_STACK_SIZE) {
debugBuild.DEBUG_BUILD && core.debug.warn('[React Router] Navigation context stack overflow - removing oldest context');
_navigationContextStack.shift();
}
_navigationContextStack.push({ token, targetPath, span });
return token;
}
/**
* Clears the navigation context if it's on top of the stack (LIFO).
* If our context is not on top (out-of-order completion), we leave it -
* it will be cleaned up by overflow protection when the stack fills up.
*/
function clearNavigationContext(token) {
const top = _navigationContextStack[_navigationContextStack.length - 1];
if (top?.token === token) {
_navigationContextStack.pop();
}
}
/** Gets the current (most recent) navigation context if inside a patchRoutesOnNavigation call. */
function getNavigationContext() {
const length = _navigationContextStack.length;
// The `?? null` converts undefined (from array access) to null to match return type
return length > 0 ? (_navigationContextStack[length - 1] ?? null) : null;
}
/**
* Initialize function to set dependencies that the router utilities need.
* Must be called before using any of the exported utility functions.
*/
function initializeRouterUtils(matchRoutes, stripBasename = false) {
_matchRoutes = matchRoutes;
_stripBasename = stripBasename;
}
// Helper functions
function pickPath(match) {
return trimWildcard(match.route.path || '');
}
function pickSplat(match) {
return match.params['*'] || '';
}
function trimWildcard(path) {
return path[path.length - 1] === '*' ? path.slice(0, -1) : path;
}
function trimSlash(path) {
return path[path.length - 1] === '/' ? path.slice(0, -1) : path;
}
/**
* Checks if a path ends with a wildcard character (*).
*/
function pathEndsWithWildcard(path) {
return path.endsWith('*');
}
/** Checks if transaction name has wildcard (/* or ends with *). */
function transactionNameHasWildcard(name) {
return name.includes('/*') || name.endsWith('*');
}
/**
* Checks if a path is a wildcard and has child routes.
*/
function pathIsWildcardAndHasChildren(path, branch) {
return (pathEndsWithWildcard(path) && !!branch.route.children?.length) || false;
}
/** Check if route is in descendant route (<Routes> within <Routes>) */
function routeIsDescendant(route) {
return !!(!route.children && route.element && route.path?.endsWith('/*'));
}
function sendIndexPath(pathBuilder, pathname, basename) {
const reconstructedPath =
pathBuilder && pathBuilder.length > 0
? pathBuilder
: _stripBasename
? routeManifest.stripBasenameFromPathname(pathname, basename)
: pathname;
let formattedPath =
// If the path ends with a wildcard suffix, remove both the slash and the asterisk
reconstructedPath.slice(-2) === '/*' ? reconstructedPath.slice(0, -2) : reconstructedPath;
// If the path ends with a slash, remove it (but keep single '/')
if (formattedPath.length > 1 && formattedPath[formattedPath.length - 1] === '/') {
formattedPath = formattedPath.slice(0, -1);
}
return [formattedPath, 'route'];
}
/**
* Returns the number of URL segments in the given URL string.
* Splits at '/' or '\/' to handle regex URLs correctly.
*
* @param url - The URL string to segment.
* @returns The number of segments in the URL.
*/
function getNumberOfUrlSegments(url) {
// split at '/' or at '\/' to split regex urls correctly
return url.split(/\\?\//).filter(s => s.length > 0 && s !== ',').length;
}
// Exported utility functions
/**
* Ensures a path string starts with a forward slash.
*/
function prefixWithSlash(path) {
return path[0] === '/' ? path : `/${path}`;
}
/**
* Rebuilds the route path from all available routes by matching against the current location.
*/
function rebuildRoutePathFromAllRoutes(allRoutes, location) {
const matchedRoutes = _matchRoutes(allRoutes, location) ;
if (!matchedRoutes || matchedRoutes.length === 0) {
return '';
}
for (const match of matchedRoutes) {
if (match.route.path && match.route.path !== '*') {
const path = pickPath(match);
const strippedPath = routeManifest.stripBasenameFromPathname(location.pathname, prefixWithSlash(match.pathnameBase));
if (location.pathname === strippedPath) {
return trimSlash(strippedPath);
}
return trimSlash(
trimSlash(path || '') +
prefixWithSlash(
rebuildRoutePathFromAllRoutes(
allRoutes.filter(route => route !== match.route),
{
pathname: strippedPath,
},
),
),
);
}
}
return '';
}
/**
* Checks if the current location is inside a descendant route (route with splat parameter).
*/
function locationIsInsideDescendantRoute(location, routes) {
const matchedRoutes = _matchRoutes(routes, location) ;
if (matchedRoutes) {
for (const match of matchedRoutes) {
if (routeIsDescendant(match.route) && pickSplat(match)) {
return true;
}
}
}
return false;
}
/**
* Returns a fallback transaction name from location pathname.
*/
function getFallbackTransactionName(location, basename) {
return _stripBasename ? routeManifest.stripBasenameFromPathname(location.pathname, basename) : location.pathname || '';
}
/**
* Gets a normalized route name and transaction source from the current routes and location.
*/
function getNormalizedName(
routes,
location,
branches,
basename = '',
) {
if (!routes || routes.length === 0) {
return [_stripBasename ? routeManifest.stripBasenameFromPathname(location.pathname, basename) : location.pathname, 'url'];
}
if (!branches) {
return [getFallbackTransactionName(location, basename), 'url'];
}
let pathBuilder = '';
for (const branch of branches) {
const route = branch.route;
if (!route) {
continue;
}
// Early return for index routes
if (route.index) {
return sendIndexPath(pathBuilder, branch.pathname, basename);
}
const path = route.path;
if (!path || pathIsWildcardAndHasChildren(path, branch)) {
continue;
}
// Build the route path
const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`;
pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath);
// Check if this path matches the current location
if (trimSlash(location.pathname) !== trimSlash(basename + branch.pathname)) {
continue;
}
// Check if this is a parameterized route like /stores/:storeId/products/:productId
if (
getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) &&
!pathEndsWithWildcard(pathBuilder)
) {
return [(_stripBasename ? '' : basename) + newPath, 'route'];
}
// Handle wildcard routes with children - strip trailing wildcard
if (pathIsWildcardAndHasChildren(pathBuilder, branch)) {
pathBuilder = pathBuilder.slice(0, -1);
}
return [(_stripBasename ? '' : basename) + pathBuilder, 'route'];
}
// Fallback when no matching route found
return [getFallbackTransactionName(location, basename), 'url'];
}
/**
* Shared helper function to resolve route name and source
*/
function resolveRouteNameAndSource(
location,
routes,
allRoutes,
branches,
basename = '',
lazyRouteManifest,
enableAsyncRouteHandlers,
) {
// When lazy route manifest is provided, use it as the primary source for transaction names
if (enableAsyncRouteHandlers && lazyRouteManifest && lazyRouteManifest.length > 0) {
const manifestMatch = routeManifest.matchRouteManifest(location.pathname, lazyRouteManifest, basename);
if (manifestMatch) {
return [(_stripBasename ? '' : basename) + manifestMatch, 'route'];
}
}
// Fall back to React Router route matching
let name;
let source = 'url';
const isInDescendantRoute = locationIsInsideDescendantRoute(location, allRoutes);
if (isInDescendantRoute) {
name = prefixWithSlash(rebuildRoutePathFromAllRoutes(allRoutes, location));
source = 'route';
}
if (!isInDescendantRoute || !name) {
[name, source] = getNormalizedName(routes, location, branches, basename);
}
return [name || location.pathname, source];
}
/**
* Gets the active root span if it's a pageload or navigation span.
*/
function getActiveRootSpan() {
const span = core.getActiveSpan();
const rootSpan = span ? core.getRootSpan(span) : undefined;
if (!rootSpan) {
return undefined;
}
const op = core.spanToJSON(rootSpan).op;
// Only use this root span if it is a pageload or navigation span
return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;
}
exports.clearNavigationContext = clearNavigationContext;
exports.getActiveRootSpan = getActiveRootSpan;
exports.getNavigationContext = getNavigationContext;
exports.getNormalizedName = getNormalizedName;
exports.getNumberOfUrlSegments = getNumberOfUrlSegments;
exports.initializeRouterUtils = initializeRouterUtils;
exports.locationIsInsideDescendantRoute = locationIsInsideDescendantRoute;
exports.pathEndsWithWildcard = pathEndsWithWildcard;
exports.pathIsWildcardAndHasChildren = pathIsWildcardAndHasChildren;
exports.prefixWithSlash = prefixWithSlash;
exports.rebuildRoutePathFromAllRoutes = rebuildRoutePathFromAllRoutes;
exports.resolveRouteNameAndSource = resolveRouteNameAndSource;
exports.routeIsDescendant = routeIsDescendant;
exports.setNavigationContext = setNavigationContext;
exports.transactionNameHasWildcard = transactionNameHasWildcard;
//# sourceMappingURL=utils.js.map