@chubbyts/chubbyts-framework-router-path-to-regexp
Version:
Path-to-regex routing implementation for chubbyts-framework.
84 lines (83 loc) • 3.91 kB
JavaScript
import { compile, match } from 'path-to-regexp';
import { createMethodNotAllowed, createNotFound } from '@chubbyts/chubbyts-http-error/dist/http-error';
import { stringify } from 'qs';
/**
* ```ts
* import type { Match } from '@chubbyts/chubbyts-framework/dist/router/route-matcher';
* import type { RoutesByName } from '@chubbyts/chubbyts-framework/dist/router/routes-by-name';
* import { createPathToRegexpRouteMatcher } from '@chubbyts/chubbyts-framework-router-path-to-regexp/dist/path-to-regexp-router';
*
* const routesByName: RoutesByName = ...;
*
* const pathToRegexpRouteMatcher: Match = createPathToRegexpRouteMatcher(routesByName);
* ```
*/
export const createPathToRegexpRouteMatcher = (routesByName) => {
const matchersByName = new Map(Array.from(routesByName.entries()).map(([name, route]) => [name, match(route.path)]));
return (request) => {
const method = request.method;
const path = decodeURI(request.uri.path);
const matchWithMethods = [];
for (const [name, route] of routesByName.entries()) {
const matcherByName = matchersByName.get(name);
const matchedPath = matcherByName(path);
if (!matchedPath) {
continue;
}
const routeMethod = route.method;
if (routeMethod === method) {
return { ...route, attributes: matchedPath.params };
}
// eslint-disable-next-line functional/immutable-data
matchWithMethods.push(routeMethod);
}
if (matchWithMethods.length > 0) {
throw createMethodNotAllowed({
detail: `Method "${method}" at path "${path}" is not allowed. Must be one of: "${matchWithMethods.join('", "')}".`,
});
}
throw createNotFound({
detail: `The page "${path}" you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly.`,
});
};
};
/**
* ```ts
* import type { GeneratePath } from '@chubbyts/chubbyts-framework/dist/router/url-generator';
* import type { RoutesByName } from '@chubbyts/chubbyts-framework/dist/router/routes-by-name';
* import { createPathToRegexpPathGenerator } from '@chubbyts/chubbyts-framework-router-path-to-regexp/dist/path-to-regexp-router';
*
* const routesByName: RoutesByName = ...;
*
* const pathToRegexpPathGenerator: GeneratePath = createPathToRegexpPathGenerator(routesByName);
* ```
*/
export const createPathToRegexpPathGenerator = (routesByName) => {
const compilesByName = new Map(Array.from(routesByName.entries()).map(([name, route]) => [name, compile(route.path)]));
return (name, attributes, query) => {
const route = routesByName.get(name);
if (undefined === route) {
throw new Error(`Missing route: "${name}"`);
}
const compileByName = compilesByName.get(name);
return compileByName(attributes) + (undefined !== query ? '?' + stringify(query, { encodeValuesOnly: true }) : '');
};
};
/**
* ```ts
* import type { GeneratePath, GenerateUrl } from '@chubbyts/chubbyts-framework/dist/router/url-generator';
* import type { RoutesByName } from '@chubbyts/chubbyts-framework/dist/router/routes-by-name';
* import { createPathToRegexpUrlGenerator } from '@chubbyts/chubbyts-framework-router-path-to-regexp/dist/path-to-regexp-router';
*
* const generatePath: GeneratePath = ...;
*
* const pathToRegexpUrlGenerator: GenerateUrl = createPathToRegexpUrlGenerator(generatePath);
* ```
*/
export const createPathToRegexpUrlGenerator = (generatePath) => {
return (request, name, attributes, query) => {
const { schema, userInfo, host, port } = request.uri;
const path = generatePath(name, attributes, query);
return schema + '://' + (userInfo ? userInfo + '@' : '') + host + (port ? ':' + port : '') + path;
};
};