compare-path
Version:
An easy-to-use package to detect if two URLs match each other by comparing their abstract paths
92 lines • 3.65 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.comparePath = comparePath;
const clean_path_1 = require("./clean-path");
/**
* Compares a given URL path to a defined shape and extracts matching parameters.
*
* Supports:
*
* - Dynamic segments via `:param` or `[param]`
* - Catch-all segments via `**`
*
* @example
* comparePath('/users/:id', '/users/123') // [true, { id: '123' }]
* comparePath('/docs/**', '/docs/foo/bar') // [true, { rest: ['foo', 'bar'] }]
*
* @template T - Route shape string (e.g., '/users/:id' or '/users/[id]')
* @template U - Actual URL path string to compare
* @param shape - The route definition with dynamic/wildcard segments
* @param path - The current URL path to match against the shape
* @returns A tuple:
*
* - [true, params] if the path matches, with extracted parameters
* - [false, null] if the path does not match
*/
function comparePath(shape, path) {
const cleanedShape = (0, clean_path_1.cleanPath)(shape);
const cleanedPath = (0, clean_path_1.cleanPath)(path);
const shapeParts = cleanedShape.split('/');
const pathParts = cleanedPath.split('/');
let params = {};
const wildcardIndex = shapeParts.indexOf('**');
/** Checks if a segment is a dynamic param (either :param or [param]) */
const isParam = (segment) => segment.startsWith(':') || (segment.startsWith('[') && segment.endsWith(']'));
/**
* Extracts the param name from a segment
*
* @example
* ':id' -> 'id', '[id]' -> 'id'
*/
const extractParamName = (segment) => segment.startsWith(':') ? segment.slice(1) : segment.slice(1, -1);
if (wildcardIndex === -1) {
if (shapeParts.length !== pathParts.length)
return [false, null];
for (let i = 0; i < shapeParts.length; i++) {
const shapeSegment = shapeParts[i];
const pathSegment = pathParts[i];
if (isParam(shapeSegment)) {
const paramName = extractParamName(shapeSegment);
params[paramName] = pathSegment;
}
else if (shapeSegment !== pathSegment) {
return [false, null];
}
}
return [true, params];
}
else {
const preParts = shapeParts.slice(0, wildcardIndex);
const postParts = shapeParts.slice(wildcardIndex + 1);
if (pathParts.length < preParts.length + postParts.length) {
return [false, null];
}
for (let i = 0; i < preParts.length; i++) {
const shapeSegment = preParts[i];
const pathSegment = pathParts[i];
if (isParam(shapeSegment)) {
const paramName = extractParamName(shapeSegment);
params[paramName] = pathSegment;
}
else if (shapeSegment !== pathSegment) {
return [false, null];
}
}
for (let i = 0; i < postParts.length; i++) {
const shapeSegment = postParts[postParts.length - 1 - i];
const pathSegment = pathParts[pathParts.length - 1 - i];
if (isParam(shapeSegment)) {
const paramName = extractParamName(shapeSegment);
params[paramName] = pathSegment;
}
else if (shapeSegment !== pathSegment) {
return [false, null];
}
}
const restStart = preParts.length;
const restEnd = pathParts.length - postParts.length;
params['rest'] = pathParts.slice(restStart, restEnd);
return [true, params];
}
}
//# sourceMappingURL=compare-path.js.map