@sentry/nextjs
Version:
Official Sentry SDK for Next.js
168 lines (165 loc) • 5.94 kB
JavaScript
import * as fs from 'fs';
import * as path from 'path';
import { getBuildLogger } from '../buildLogger.js';
const DEFAULT_LOCALE_PARAM_NAMES = ["locale", "lang", "language", "lng"];
let manifestCache = null;
let lastAppDirPath = null;
let lastIncludeRouteGroups = void 0;
let lastLocaleParamNames = void 0;
function isPageFile(filename) {
return filename === "page.tsx" || filename === "page.jsx" || filename === "page.ts" || filename === "page.js";
}
function isRouteGroup(name) {
return name.startsWith("(") && name.endsWith(")");
}
function normalizeRouteGroupPath(routePath) {
return routePath.replace(/\/\((?=[^)/]*\))[^)/]+\)/g, "");
}
function getDynamicRouteSegment(name) {
if (name.startsWith("[[...") && name.endsWith("]]")) {
const paramName = name.slice(5, -2);
return `:${paramName}*?`;
} else if (name.startsWith("[...") && name.endsWith("]")) {
const paramName = name.slice(4, -1);
return `:${paramName}*`;
}
return `:${name.slice(1, -1)}`;
}
function buildRegexForDynamicRoute(routePath, localeParamNames) {
const segments = routePath.split("/").filter(Boolean);
const regexSegments = [];
const paramNames = [];
let hasOptionalCatchall = false;
for (const segment of segments) {
if (segment.startsWith(":")) {
const paramName = segment.substring(1);
if (paramName.endsWith("*?")) {
const cleanParamName = paramName.slice(0, -2);
paramNames.push(cleanParamName);
hasOptionalCatchall = true;
} else if (paramName.endsWith("*")) {
const cleanParamName = paramName.slice(0, -1);
paramNames.push(cleanParamName);
regexSegments.push("(.+)");
} else {
paramNames.push(paramName);
regexSegments.push("([^/]+)");
}
} else {
regexSegments.push(segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
}
}
let pattern;
if (hasOptionalCatchall) {
if (regexSegments.length === 0) {
pattern = "^/(.*)$";
} else {
const staticParts = regexSegments.join("/");
pattern = `^/${staticParts}(?:/(.*))?$`;
}
} else {
pattern = `^/${regexSegments.join("/")}$`;
}
return { regex: pattern, paramNames, hasOptionalPrefix: hasOptionalPrefix(paramNames, localeParamNames) };
}
function hasOptionalPrefix(paramNames, localeParamNames) {
const firstParam = paramNames[0];
if (firstParam === void 0) {
return false;
}
return localeParamNames.includes(firstParam);
}
function scanAppDirectory(dir, basePath = "", includeRouteGroups = false, localeParamNames = DEFAULT_LOCALE_PARAM_NAMES, silent) {
const dynamicRoutes = [];
const staticRoutes = [];
try {
const entries = fs.readdirSync(dir, { withFileTypes: true });
const pageFile = entries.find((entry) => isPageFile(entry.name));
if (pageFile) {
const routePath = includeRouteGroups ? basePath || "/" : normalizeRouteGroupPath(basePath || "/");
const isDynamic = routePath.includes(":");
if (isDynamic) {
const { regex, paramNames, hasOptionalPrefix: hasOptionalPrefix2 } = buildRegexForDynamicRoute(routePath, localeParamNames);
dynamicRoutes.push({
path: routePath,
regex,
paramNames,
hasOptionalPrefix: hasOptionalPrefix2
});
} else {
staticRoutes.push({
path: routePath
});
}
}
for (const entry of entries) {
if (entry.isDirectory()) {
const fullPath = path.join(dir, entry.name);
let routeSegment;
const isDynamic = entry.name.startsWith("[") && entry.name.endsWith("]");
const isRouteGroupDir = isRouteGroup(entry.name);
if (isRouteGroupDir) {
if (includeRouteGroups) {
routeSegment = entry.name;
} else {
routeSegment = "";
}
} else if (isDynamic) {
routeSegment = getDynamicRouteSegment(entry.name);
} else {
routeSegment = entry.name;
}
const newBasePath = routeSegment ? `${basePath}/${routeSegment}` : basePath;
const subRoutes = scanAppDirectory(fullPath, newBasePath, includeRouteGroups, localeParamNames, silent);
dynamicRoutes.push(...subRoutes.dynamicRoutes);
staticRoutes.push(...subRoutes.staticRoutes);
}
}
} catch (error) {
getBuildLogger(silent).warn("[@sentry/nextjs] Error building route manifest:", error);
}
return { dynamicRoutes, staticRoutes };
}
function createRouteManifest(options) {
let targetDir;
if (options?.appDirPath) {
targetDir = options.appDirPath;
} else {
const projectDir = process.cwd();
const maybeAppDirPath = path.join(projectDir, "app");
const maybeSrcAppDirPath = path.join(projectDir, "src", "app");
if (fs.existsSync(maybeAppDirPath) && fs.lstatSync(maybeAppDirPath).isDirectory()) {
targetDir = maybeAppDirPath;
} else if (fs.existsSync(maybeSrcAppDirPath) && fs.lstatSync(maybeSrcAppDirPath).isDirectory()) {
targetDir = maybeSrcAppDirPath;
}
}
if (!targetDir) {
return {
dynamicRoutes: [],
staticRoutes: []
};
}
const localeParamNames = options?.localeParamNames ?? DEFAULT_LOCALE_PARAM_NAMES;
if (manifestCache && lastAppDirPath === targetDir && lastIncludeRouteGroups === options?.includeRouteGroups && lastLocaleParamNames?.join(",") === localeParamNames.join(",")) {
return manifestCache;
}
const { dynamicRoutes, staticRoutes } = scanAppDirectory(
targetDir,
options?.basePath,
options?.includeRouteGroups,
localeParamNames,
options?.silent
);
const manifest = {
dynamicRoutes,
staticRoutes
};
manifestCache = manifest;
lastAppDirPath = targetDir;
lastIncludeRouteGroups = options?.includeRouteGroups;
lastLocaleParamNames = localeParamNames;
return manifest;
}
export { DEFAULT_LOCALE_PARAM_NAMES, createRouteManifest };
//# sourceMappingURL=createRouteManifest.js.map