@beignet/core
Version:
Core framework primitives for Beignet
65 lines (56 loc) • 1.61 kB
text/typescript
import { parsePathTemplate } from "../contracts/index.js";
export type CompiledPath = {
keys: string[];
pattern: RegExp;
segments: ReturnType<typeof parsePathTemplate>["segments"];
normalizedPath: string;
shapeKey: string;
};
export class PathDecodeError extends Error {
constructor() {
super("Malformed URL path");
this.name = "PathDecodeError";
}
}
export function compilePath(path: string): CompiledPath {
const parsed = parsePathTemplate(path);
const regexParts = parsed.segments.map((segment) =>
segment.kind === "dynamic"
? "([^/]+)"
: segment.value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
);
const pattern = new RegExp(`^/${regexParts.join("/")}$`);
return { ...parsed, pattern };
}
export function decodeMatchedParams(
keys: string[],
match: RegExpExecArray,
): Record<string, string> {
const params: Record<string, string> = {};
try {
keys.forEach((key, index) => {
params[key] = decodeURIComponent(match[index + 1]);
});
} catch (error) {
if (error instanceof URIError) {
throw new PathDecodeError();
}
throw error;
}
return params;
}
export function compareRouteSpecificity(
a: CompiledPath,
b: CompiledPath,
): number {
const maxLength = Math.max(a.segments.length, b.segments.length);
for (let index = 0; index < maxLength; index++) {
const aSegment = a.segments[index];
const bSegment = b.segments[index];
if (!aSegment) return 1;
if (!bSegment) return -1;
if (aSegment.kind === bSegment.kind) continue;
return aSegment.kind === "static" ? -1 : 1;
}
return 0;
}