@beignet/core
Version:
Core framework primitives for Beignet
56 lines • 2.56 kB
JavaScript
const PARAM_NAME = "[A-Za-z0-9_-]+";
const COLON_PARAM = new RegExp(`^:(${PARAM_NAME})$`);
const BRACKET_PARAM = new RegExp(`^\\[(${PARAM_NAME})\\]$`);
function createPathTemplateError(path, segment) {
return new Error(`Unsupported path template segment "${segment}" in "${path}". ` +
"Use single-segment params like :id or [id]. Contract catch-all params such as [...path] and partial-segment params are not supported. Expose a platform catch-all route to the Beignet server, but keep individual contracts on concrete paths.");
}
function parsePathSegment(path, segment) {
const colonMatch = segment.match(COLON_PARAM);
if (colonMatch) {
return { kind: "dynamic", name: colonMatch[1], raw: segment };
}
const bracketMatch = segment.match(BRACKET_PARAM);
if (bracketMatch) {
return { kind: "dynamic", name: bracketMatch[1], raw: segment };
}
if (segment.startsWith(":") ||
segment.startsWith("[") ||
segment.endsWith("]")) {
throw createPathTemplateError(path, segment);
}
return { kind: "static", value: segment };
}
/**
* Parse a Beignet route path template.
*
* Paths must start with `/`. Dynamic segments may use `:id` or `[id]`.
* Contract catch-all segments and partial dynamic segments are intentionally rejected.
*/
export function parsePathTemplate(path) {
if (!path.startsWith("/")) {
throw new Error(`Invalid path template "${path}". Paths must start with "/".`);
}
const segments = path
.split("/")
.filter(Boolean)
.map((segment) => parsePathSegment(path, segment));
const keys = segments
.filter((segment) => segment.kind === "dynamic")
.map((segment) => segment.name);
const duplicateKeys = keys.filter((key, index) => keys.indexOf(key) !== index);
if (duplicateKeys.length) {
throw new Error(`Invalid path template "${path}". Path parameter names must be unique; duplicate parameter "${duplicateKeys[0]}" was found.`);
}
const normalizedPath = `/${segments
.map((segment) => segment.kind === "static" ? segment.value : `:${segment.name}`)
.join("/")}`;
const shapeKey = `/${segments
.map((segment) => (segment.kind === "static" ? segment.value : ":"))
.join("/")}`;
const openApiPath = `/${segments
.map((segment) => segment.kind === "static" ? segment.value : `{${segment.name}}`)
.join("/")}`;
return { keys, segments, normalizedPath, shapeKey, openApiPath };
}
//# sourceMappingURL=path-template.js.map