frontitygit
Version:
A Frontity source package for the REST API of self-hosted and WordPress.com sites
126 lines (113 loc) • 3.21 kB
text/typescript
import { Pattern } from "../../types";
import pathToRegexp, { Key } from "path-to-regexp";
/**
* Extract the parameters of the `path-to-regexp` pattern from the link.
*
* @param link - The link that was matched.
* @param regexp - The regexp from `path-to-regexp` that will be used.
* @param keys - The array with keys generated by `path-to-regexp`.
*
* @returns An object with the parameter names and its corresponding values
* from the link.
*/
const extractParameters = (
link: string,
regexp: RegExp,
keys: Key[]
): Record<string, string> =>
link
// First remove the query and hash part.
// These parameters are extracted from the pathname.
.replace(/\?.*/, "")
.match(regexp)
.slice(1)
.reduce((result, value, index) => {
result[keys[index].name] = value;
return result;
}, {});
/**
* The return object for the {@link getMatch} function.
*/
interface GetMatchReturn<
Func extends (...args: any) => any,
Patt extends Pattern<Func>
> {
/**
* The params extracted from the `path-to-regexp` pattern or the named capture
* groups of the regular expresion.
*/
params: Record<string, string>;
/**
* The handler/redirection function that was matched.
*/
func: Patt["func"];
/**
* The name of the handler/redirection function that was matched.
*/
name: string;
/**
* The pattern of the handler/redirection function that was matched.
*/
pattern: string;
}
/**
* The `source` object that contains a link and a route.
*/
interface Source {
/**
* The full link with `queryString`.
*/
link?: string;
/**
* The link without the query and pagination part.
*/
route?: string;
}
/**
* The regular expression flag.
*/
const REGULAR_EXPRESSION = "RegExp:";
/**
* Match a link with a list of handler/redirection objects.
*
* @param source - The source to be matched.
* @param list - The list of handler/redirection objects.
*
* @returns An object containing the matched handler/redirection. Defined in
* {@link GetMatchReturn}.
*/
export const getMatch = <
Func extends (...args: any) => any,
Patt extends Pattern<Func>
>(
source: Source,
list: Patt[]
): GetMatchReturn<Func, Patt> | null => {
const result = list
.sort(({ priority: p1 }, { priority: p2 }) => p1 - p2)
.map(({ name, priority, pattern, func }) => {
let url: string;
const keys = [];
// Otherwise, we need to pick the value based on the pattern
if (pattern.startsWith(REGULAR_EXPRESSION)) {
url = source.link;
} else {
url = source.route;
}
const regexp = pattern.startsWith(REGULAR_EXPRESSION)
? new RegExp(pattern.replace(REGULAR_EXPRESSION, ""))
: pathToRegexp(pattern, keys);
return { name, priority, pattern, regexp, keys, url, func };
})
.find(({ regexp, url }) => regexp.test(url));
return result
? {
func: result.func,
params: result.pattern.startsWith(REGULAR_EXPRESSION)
? result.regexp.exec(result.url).groups
: extractParameters(result.url, result.regexp, result.keys),
name: result.name,
pattern: result.pattern,
}
: null;
};