astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
117 lines (116 loc) • 3.68 kB
JavaScript
import { shouldAppendForwardSlash } from "../build/util.js";
import { originPathnameSymbol } from "../constants.js";
import { AstroError, AstroErrorData } from "../errors/index.js";
import {
appendForwardSlash,
joinPaths,
prependForwardSlash,
removeTrailingForwardSlash
} from "../path.js";
import { createRequest } from "../request.js";
import { DEFAULT_404_ROUTE } from "./astro-designed-error-pages.js";
function findRouteToRewrite({
payload,
routes,
request,
trailingSlash,
buildFormat,
base
}) {
let newUrl = void 0;
if (payload instanceof URL) {
newUrl = payload;
} else if (payload instanceof Request) {
newUrl = new URL(payload.url);
} else {
newUrl = new URL(payload, new URL(request.url).origin);
}
let pathname = newUrl.pathname;
const shouldAppendSlash = shouldAppendForwardSlash(trailingSlash, buildFormat);
if (base !== "/") {
const isBasePathRequest = newUrl.pathname === base || newUrl.pathname === removeTrailingForwardSlash(base);
if (isBasePathRequest) {
pathname = shouldAppendSlash ? "/" : "";
} else if (newUrl.pathname.startsWith(base)) {
pathname = shouldAppendSlash ? appendForwardSlash(newUrl.pathname) : removeTrailingForwardSlash(newUrl.pathname);
pathname = pathname.slice(base.length);
}
}
if (!pathname.startsWith("/") && shouldAppendSlash && newUrl.pathname.endsWith("/")) {
pathname = prependForwardSlash(pathname);
}
if (pathname === "/" && base !== "/" && !shouldAppendSlash) {
pathname = "";
}
if (base !== "/" && (pathname === "" || pathname === "/") && !shouldAppendSlash) {
newUrl.pathname = removeTrailingForwardSlash(base);
} else {
newUrl.pathname = joinPaths(...[base, pathname].filter(Boolean));
}
const decodedPathname = decodeURI(pathname);
let foundRoute;
for (const route of routes) {
if (route.pattern.test(decodedPathname)) {
foundRoute = route;
break;
}
}
if (foundRoute) {
return {
routeData: foundRoute,
newUrl,
pathname: decodedPathname
};
} else {
const custom404 = routes.find((route) => route.route === "/404");
if (custom404) {
return { routeData: custom404, newUrl, pathname };
} else {
return { routeData: DEFAULT_404_ROUTE, newUrl, pathname };
}
}
}
function copyRequest(newUrl, oldRequest, isPrerendered, logger, routePattern) {
if (oldRequest.bodyUsed) {
throw new AstroError(AstroErrorData.RewriteWithBodyUsed);
}
return createRequest({
url: newUrl,
method: oldRequest.method,
body: oldRequest.body,
isPrerendered,
logger,
headers: isPrerendered ? {} : oldRequest.headers,
routePattern,
init: {
referrer: oldRequest.referrer,
referrerPolicy: oldRequest.referrerPolicy,
mode: oldRequest.mode,
credentials: oldRequest.credentials,
cache: oldRequest.cache,
redirect: oldRequest.redirect,
integrity: oldRequest.integrity,
signal: oldRequest.signal,
keepalive: oldRequest.keepalive,
// https://fetch.spec.whatwg.org/#dom-request-duplex
// @ts-expect-error It isn't part of the types, but undici accepts it and it allows to carry over the body to a new request
duplex: "half"
}
});
}
function setOriginPathname(request, pathname) {
Reflect.set(request, originPathnameSymbol, encodeURIComponent(pathname));
}
function getOriginPathname(request) {
const origin = Reflect.get(request, originPathnameSymbol);
if (origin) {
return decodeURIComponent(origin);
}
return new URL(request.url).pathname;
}
export {
copyRequest,
findRouteToRewrite,
getOriginPathname,
setOriginPathname
};