-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
dev-router.ts
112 lines (97 loc) · 2.7 KB
/
dev-router.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import url from 'url';
import PCRE from 'pcre-to-regexp';
import isURL from './is-url';
import DevServer from './dev-server';
import { BuilderInputs, RouteConfig, RouteResult } from './types';
export function resolveRouteParameters(
str: string,
match: string[],
keys: string[]
): string {
return str.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];
});
}
export default async function(
reqPath = '',
routes?: RouteConfig[],
devServer?: DevServer
): Promise<RouteResult> {
let found: RouteResult | undefined;
const { pathname: reqPathname = '/', query } = url.parse(reqPath, true);
// try route match
if (routes) {
let idx = -1;
for (const routeConfig of routes) {
idx++;
let { src, headers, handle } = routeConfig;
if (handle) {
if (handle === 'filesystem' && devServer) {
if (await devServer.hasFilesystem(reqPathname)) {
break;
}
}
continue;
}
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 = resolveRouteParameters(routeConfig.dest, match, keys);
}
if (headers) {
// Create a clone of the `headers` object to not mutate the original one
headers = { ...headers };
for (const key of Object.keys(headers)) {
headers[key] = resolveRouteParameters(headers[key], match, keys);
}
}
if (isURL(destPath)) {
found = {
dest: destPath,
status: routeConfig.status,
headers,
uri_args: {},
matched_route: routeConfig,
matched_route_idx: idx
};
} else {
const { pathname, query } = url.parse(destPath, true);
found = {
dest: pathname || '/',
status: routeConfig.status,
headers,
uri_args: query,
matched_route: routeConfig,
matched_route_idx: idx
};
}
break;
}
}
}
if (!found) {
found = {
dest: reqPathname,
uri_args: query
};
}
return found;
}