UNPKG

static-path

Version:

Static-path uses TypeScript to prevent 404s and other path generation mistakes at compile time

77 lines 3.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.path = void 0; /* Build a new path. * * This function also does some runtime validity checks on the paths. Path * objects should be built at app boot time, so the validity checks here are * safe: the app won't even boot if the checks fail. */ function path(pattern) { const parts = patternParts(pattern); const paramsToPath = (params) => { return ('/' + parts .map((part) => { if (part.kind === 'param') { return paramValue(params, part.paramName); } else { return part.value; } }) .filter((value) => value !== '') .join('/')); }; /* Ideally, we'd normalize the pattern, then extract the path parts from that * normalized form. Unfortunately, that doesn't work because so much of this * code needs to know the exact literal type of `Pattern`, but normalizing * the pattern turns it into some other string type. So there's some subtle * duplication here, where multiple parts of the code know how to handle * slashes. */ paramsToPath.pattern = normalizePattern(pattern); paramsToPath.parts = parts; paramsToPath.path = (subpattern) => { return path(`${pattern}/${subpattern}`); }; if (!paramsToPath.pattern.startsWith('/')) { throw new Error(`Paths must begin with slashes, but ${JSON.stringify(paramsToPath.pattern)} doesn't.`); } return paramsToPath; } exports.path = path; /* Turn a Pattern literal string type into an array of the path's parts. */ function patternParts(pattern) { return pattern.split('/').map((part) => { if (part.startsWith(':')) { return { kind: 'param', paramName: part.replace(/^:/, '') }; } else { return { kind: 'constant', value: part }; } }); } /* Normalize patterns. E.g., '/courses//:courseId/' becomes * '/courses/:courseId' * * This function needs to exactly match what the `NormalizePattern` type does. * The type system can't see what we're doing here, so we have to verify the * match manually. */ function normalizePattern(pattern) { // Case 1: we're looking at the root path, '/'. We don't want to change it. if (pattern === '/') { return pattern; } return pattern // Case 2: Replace repeated slashes with one slash. .replace(/\/+/g, '/') // Case 3: Remove trailing slashes. .replace(/^(.+)\/$/, (match, patternWithoutTrailingSlash) => patternWithoutTrailingSlash); } function paramValue(params, paramName) { const value = params[paramName]; if (typeof value !== 'string') { throw new Error(`When generating a path, the path param ${JSON.stringify(paramName)} didn't exist on params object ${JSON.stringify(params)}. The types should have prevented this, so either you defeated them (e.g., with \`as\`) or this is a bug!`); } return value; } //# sourceMappingURL=index.js.map