snakey
Version:
An Obeserver-based web microframework for Node.js
69 lines (62 loc) • 2.19 kB
text/typescript
import pathToRegexp = require('path-to-regexp');
export type PathPattern = string | RegExp;
/**
* Matches the pathname against the provided RegExp.
*
* Returns a match object on success. Otherwise return null.
* @param {string} pathname
* @param {RegExp} regex
* @return {RegExpMatchArray?}
*/
export function matchRegex(pathname: string, regex: RegExp): RegExpMatchArray | null {
if (!(regex instanceof RegExp)) {
throw new TypeError('regex should be a Regex object.');
}
return pathname.match(regex);
}
/**
* The type returned by matchPathPattern.
*
* The params object normally maps strings to strings. However, in the case of repeatable
* parameters, the value will be an array of strings. Optiional parameters may be
* `undefined`. Finally, regex groups are assigned numeric names.
*
* @typedef {Object} PathMatch
* @property {string} path - The pathname matched against
* @property {string} fullMatch - The full match against the pathname
* @property {Object} params - A map of parameter names to the values.
*/
export interface PathMatch {
path: string;
fullMatch: string;
params: Map<string, string[] | string | undefined>;
}
/**
* Matches the URL pathname against a string pattern using path-to-regexp.
*
* @param {string} pathname
* @param {string} pattern
* @return {PathMatch?}
*/
export function matchPathPattern(pathname: string, pattern: string) : PathMatch | null {
const keys = [];
const regex = pathToRegexp(pattern, keys);
const execResult = regex.exec(pathname);
if (execResult === null) {
return null;
}
return {
path: pathname,
fullMatch: execResult.shift().replace(/^\/+|\/+$/g, ''),
params: keys
.map((v, i) => ({...v, 'group': execResult[i]}))
.map((v) => v.group ? {...v, 'paramValue': v.group.split(v.delimiter)} : v)
.reduce((acc, cur) => {
if (cur.paramValue && !cur.repeat && cur.paramValue.length == 1) {
acc[cur.name] = cur.paramValue[0];
} else {
acc[cur.name] = cur.paramValue;
}
return acc;
}, {})};
}