[now dev] Use pcre-to-regexp to match routes (#2027)

* [now dev] Use `pcre-to-regexp` to match `routes`

The now.json `routes` support PCRE syntax like named captures,
so use the `pcre-to-regexp` module to match the routes.

Fixes #2023.

* Pass the resolved router `dest` and query params to the Lambda
This commit is contained in:
Nathan Rajlich
2019-03-27 18:37:43 -07:00
committed by Leo Lamprecht
parent 6c8dc90267
commit fd3c110c02
6 changed files with 48 additions and 7 deletions

3
@types/pcre-to-regexp/index.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
declare module 'pcre-to-regexp' {
export default function (pattern: string, keys?: string[]): RegExp
}

View File

@@ -208,6 +208,7 @@
"npm-package-arg": "6.1.0",
"nyc": "13.2.0",
"ora": "1.3.0",
"pcre-to-regexp": "0.0.4",
"pkg": "4.3.7",
"pluralize": "7.0.0",
"pre-commit": "1.2.2",

View File

@@ -1,5 +1,6 @@
import url from 'url';
import qs from 'querystring';
import PCRE from 'pcre-to-regexp';
import isURL from './is-url';
@@ -12,12 +13,39 @@ export default function(reqPath = '', routes?: RouteConfig[]): RouteResult {
// try route match
if (routes) {
routes.find((routeConfig: RouteConfig, idx: number) => {
const matcher = new RegExp('^' + routeConfig.src + '$');
let { src } = routeConfig;
if (matcher.test(reqPathname)) {
const destPath = routeConfig.dest
? reqPathname.replace(matcher, routeConfig.dest)
: reqPathname;
if (!src.startsWith('^')) {
src = `^${src}`;
}
if (!src.endsWith('$')) {
src = `${src}$`;
}
const keys: string[] = [];
const matcher = PCRE(`%${src}%i`, keys);
const match = matcher.exec(reqPathname);
if (match) {
let destPath: string = reqPathname;
if (routeConfig.dest) {
destPath = routeConfig.dest.replace(
/\$([1-9a-zA-Z]+)/g,
(_, param) => {
let matchIndex: number = keys.indexOf(param);
if (matchIndex === -1) {
// It's a number match, not a named capture
matchIndex = parseInt(param, 10);
} else {
// For named captures, add one to the `keys` index to
// match up with the RegExp group matches
matchIndex++;
}
return match[matchIndex];
}
);
}
if (isURL(destPath)) {
found = {

View File

@@ -316,10 +316,14 @@ export default class DevServer {
}
const body = await rawBody(req);
let path: string = dest;
if (Object.keys(uri_args || {}).length > 0) {
path += `?${qs.stringify(uri_args)}`;
}
const payload: InvokePayload = {
method: req.method || 'GET',
path: req.url || '/',
path,
headers: req.headers,
encoding: 'base64',
body: body.toString('base64')

View File

@@ -36,7 +36,7 @@ test('[dev-router] captured groups', t => {
test('[dev-router] named groups', t => {
const routesConfig = [
{ src: '/user/(?<id>.+)', dest: '/user.js?id=$<id>' }
{ src: '/user/(?<id>.+)', dest: '/user.js?id=$id' }
];
const result = devRouter('/user/123', routesConfig);

View File

@@ -5448,6 +5448,11 @@ path-type@^3.0.0:
dependencies:
pify "^3.0.0"
pcre-to-regexp@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/pcre-to-regexp/-/pcre-to-regexp-0.0.4.tgz#a19c3fc6af540349f915367a4776c75c651dae05"
integrity sha1-oZw/xq9UA0n5FTZ6R3bHXGUdrgU=
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"