| Server IP : 159.203.156.69 / Your IP : 216.73.217.172 Web Server : nginx/1.24.0 System : Linux main-ubuntu 6.8.0-71-generic #71-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 22 16:52:38 UTC 2025 x86_64 User : root ( 0) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/tanviranik.com/node_modules/vinext/dist/routing/ |
Upload File : |
import { removeTrailingSlash } from "../utils/base-path.js";
//#region src/routing/route-validation.ts
/**
* Dynamic route validation adapted from Next.js' sorted-routes implementation.
* Source:
* https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/sorted-routes.ts
*/
var UrlNode = class UrlNode {
placeholder = true;
children = /* @__PURE__ */ new Map();
slugName = null;
restSlugName = null;
optionalRestSlugName = null;
insert(urlPath) {
this.insertSegments(urlPath.split("/").filter(Boolean), [], false);
}
insertSegments(urlPaths, slugNames, isCatchAll) {
if (urlPaths.length === 0) {
this.placeholder = false;
return;
}
if (isCatchAll) throw new Error("Catch-all must be the last part of the URL.");
let nextSegment = urlPaths[0];
if (nextSegment.startsWith("[") && nextSegment.endsWith("]")) {
let segmentName = nextSegment.slice(1, -1);
let isOptional = false;
if (segmentName.startsWith("[") && segmentName.endsWith("]")) {
segmentName = segmentName.slice(1, -1);
isOptional = true;
}
if (segmentName.startsWith("…")) throw new Error(`Detected a three-dot character ('…') at ('${segmentName}'). Did you mean ('...')?`);
if (segmentName.startsWith("...")) {
segmentName = segmentName.substring(3);
isCatchAll = true;
}
if (segmentName.startsWith("[") || segmentName.endsWith("]")) throw new Error(`Segment names may not start or end with extra brackets ('${segmentName}').`);
if (segmentName.startsWith(".")) throw new Error(`Segment names may not start with erroneous periods ('${segmentName}').`);
const handleSlug = (previousSlug, nextSlug) => {
if (previousSlug !== null && previousSlug !== nextSlug) throw new Error(`You cannot use different slug names for the same dynamic path ('${previousSlug}' !== '${nextSlug}').`);
for (const slug of slugNames) {
if (slug === nextSlug) throw new Error(`You cannot have the same slug name "${nextSlug}" repeat within a single dynamic path`);
if (slug.replace(/\W/g, "") === nextSegment.replace(/\W/g, "")) throw new Error(`You cannot have the slug names "${slug}" and "${nextSlug}" differ only by non-word symbols within a single dynamic path`);
}
slugNames.push(nextSlug);
};
if (isCatchAll) if (isOptional) {
if (this.restSlugName !== null) throw new Error(`You cannot use both an required and optional catch-all route at the same level ("[...${this.restSlugName}]" and "${urlPaths[0]}" ).`);
handleSlug(this.optionalRestSlugName, segmentName);
this.optionalRestSlugName = segmentName;
nextSegment = "[[...]]";
} else {
if (this.optionalRestSlugName !== null) throw new Error(`You cannot use both an optional and required catch-all route at the same level ("[[...${this.optionalRestSlugName}]]" and "${urlPaths[0]}").`);
handleSlug(this.restSlugName, segmentName);
this.restSlugName = segmentName;
nextSegment = "[...]";
}
else {
if (isOptional) throw new Error(`Optional route parameters are not yet supported ("${urlPaths[0]}").`);
handleSlug(this.slugName, segmentName);
this.slugName = segmentName;
nextSegment = "[]";
}
}
let child = this.children.get(nextSegment);
if (!child) {
child = new UrlNode();
this.children.set(nextSegment, child);
}
child.insertSegments(urlPaths.slice(1), slugNames, isCatchAll);
}
assertOptionalCatchAllSpecificity(prefix = "/") {
if (!this.placeholder && this.optionalRestSlugName !== null) {
const route = prefix === "/" ? "/" : prefix.slice(0, -1);
throw new Error(`You cannot define a route with the same specificity as a optional catch-all route ("${route}" and "${route}[[...${this.optionalRestSlugName}]]").`);
}
for (const [segment, child] of this.children) {
const nextPrefixSegment = segment === "[]" ? `[${this.slugName}]` : segment === "[...]" ? `[...${this.restSlugName}]` : segment === "[[...]]" ? `[[...${this.optionalRestSlugName}]]` : segment;
child.assertOptionalCatchAllSpecificity(`${prefix}${nextPrefixSegment}/`);
}
}
};
function patternToNextFormat(pattern) {
if (pattern === "/") return "/";
return pattern.replace(/:([^/]+?)\+(?=\/|$)/g, "[...$1]").replace(/:([^/]+?)\*(?=\/|$)/g, "[[...$1]]").replace(/:([^/]+?)(?=\/|$)/g, "[$1]");
}
function normalizeRoutePattern(pattern) {
return removeTrailingSlash(pattern);
}
function validateRoutePatterns(patterns) {
const root = new UrlNode();
const seenPatterns = /* @__PURE__ */ new Set();
for (const pattern of patterns) {
const normalizedPattern = normalizeRoutePattern(pattern);
if (seenPatterns.has(normalizedPattern)) throw new Error(`You cannot have two routes that resolve to the same path ("${normalizedPattern}").`);
seenPatterns.add(normalizedPattern);
root.insert(patternToNextFormat(normalizedPattern));
}
root.assertOptionalCatchAllSpecificity();
}
//#endregion
export { patternToNextFormat, validateRoutePatterns };
//# sourceMappingURL=route-validation.js.map