@esportsplus/routing 0.0.49 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/browser.d.ts +2 -3
- package/build/browser.js +8 -9
- package/build/constants.d.ts +5 -1
- package/build/constants.js +5 -1
- package/build/index.d.ts +3 -5
- package/build/index.js +3 -5
- package/build/router/index.d.ts +15 -13
- package/build/router/index.js +33 -36
- package/build/router/node.d.ts +2 -2
- package/build/router/node.js +1 -1
- package/build/types.d.ts +13 -3
- package/build/types.js +2 -2
- package/package.json +2 -2
- package/src/browser.ts +9 -11
- package/src/constants.ts +10 -1
- package/src/index.ts +3 -7
- package/src/router/index.ts +47 -51
- package/src/router/node.ts +3 -3
- package/src/types.ts +16 -3
- package/build/router/route.d.ts +0 -11
- package/build/router/route.js +0 -18
- package/build/router2/constants.d.ts +0 -3
- package/build/router2/constants.js +0 -3
- package/build/router2/index.d.ts +0 -11
- package/build/router2/index.js +0 -226
- package/build/router2/node.d.ts +0 -10
- package/build/router2/node.js +0 -117
- package/build/router2/trie.d.ts +0 -11
- package/build/router2/trie.js +0 -53
- package/build/router2/types.d.ts +0 -11
- package/build/router2/types.js +0 -1
- package/src/router/route.ts +0 -28
- package/src/router2/constants.ts +0 -6
- package/src/router2/index.ts +0 -330
- package/src/router2/node.ts +0 -184
- package/src/router2/trie.ts +0 -88
- package/src/router2/types.ts +0 -59
package/src/router2/index.ts
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
import { METHOD_NAME_ALL, PATH_ERROR } from './constants';
|
|
2
|
-
import { Trie } from './trie';
|
|
3
|
-
import { HandlerMap, HandlerMetadata, Matcher, Method, ParameterMap, ParameterMetadata, Path, Result, StaticMap } from './types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const NULL_MATCHER = [/^$/, [], Object.create(null)] as Matcher<any>;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let empty: any[] = [],
|
|
10
|
-
wildcardCache: Record<Path, RegExp> = Object.create(null);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function buildMatcherFromPreprocessedRoutes<T>(routes: [Path, HandlerMap<T>[]][]): Matcher<T> {
|
|
14
|
-
if (routes.length === 0) {
|
|
15
|
-
return NULL_MATCHER;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
let handlerMetadata: HandlerMetadata<T>[] = [],
|
|
19
|
-
routesWithStaticPathFlag = routes
|
|
20
|
-
.map(
|
|
21
|
-
(route) => [!/\*|\/:/.test(route[0]), ...route] as [boolean, Path, HandlerMap<T>[]]
|
|
22
|
-
)
|
|
23
|
-
.sort(([isStaticA, pathA], [isStaticB, pathB]) =>
|
|
24
|
-
isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
|
|
25
|
-
),
|
|
26
|
-
staticMap: StaticMap<T> = Object.create(null),
|
|
27
|
-
trie = new Trie();
|
|
28
|
-
|
|
29
|
-
for (let i = 0, j = -1, n = routesWithStaticPathFlag.length; i < n; i++) {
|
|
30
|
-
let [ validatePathOnly, path, handlers ] = routesWithStaticPathFlag[i];
|
|
31
|
-
|
|
32
|
-
if (validatePathOnly) {
|
|
33
|
-
staticMap[path] = [ handlers.map(([h]) => [h, Object.create(null)]), empty ]
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
j++
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let parameterMetadata: ParameterMetadata;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
parameterMetadata = trie.insert(path, j, validatePathOnly)
|
|
43
|
-
}
|
|
44
|
-
catch (e) {
|
|
45
|
-
throw e === PATH_ERROR ? new Error(`Routing: '${path}' is not supported`) : e
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (validatePathOnly) {
|
|
49
|
-
continue
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
handlerMetadata[j] = handlers.map(([h, i]) => {
|
|
53
|
-
let paramIndexMap: ParameterMap = Object.create(null);
|
|
54
|
-
|
|
55
|
-
i -= 1;
|
|
56
|
-
|
|
57
|
-
for (; i >= 0; i--) {
|
|
58
|
-
let [key, value] = parameterMetadata[i];
|
|
59
|
-
|
|
60
|
-
paramIndexMap[key] = value;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return [h, paramIndexMap];
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let [regexp, handlerReplacementMap, parameterReplacementMap] = trie.build();
|
|
68
|
-
|
|
69
|
-
for (let i = 0, n = handlerMetadata.length; i < n; i++) {
|
|
70
|
-
let metadata = handlerMetadata[i];
|
|
71
|
-
|
|
72
|
-
for (let j = 0, n = metadata.length; j < n; j++) {
|
|
73
|
-
let map = metadata[j]?.[1];
|
|
74
|
-
|
|
75
|
-
if (!map) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
for (let key in map) {
|
|
80
|
-
map[key] = parameterReplacementMap[ map[key] ];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let handlerMap: HandlerMetadata<T>[] = [];
|
|
86
|
-
|
|
87
|
-
for (let i = 0, n = handlerReplacementMap.length; i < n; i++) {
|
|
88
|
-
handlerMap[i] = handlerMetadata[handlerReplacementMap[i]];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return [regexp, handlerMap, staticMap] as Matcher<T>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function buildWildcardRegExp(path: Path): RegExp {
|
|
95
|
-
return (wildcardCache[path] ??= new RegExp(
|
|
96
|
-
path === '*'
|
|
97
|
-
? ''
|
|
98
|
-
: `^${path.replace(/\/\*$|([.\\+*[^\]$()])/g, (_, char) =>
|
|
99
|
-
char ? `\\${char}` : '(?:|/.*)'
|
|
100
|
-
)}$`
|
|
101
|
-
))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function clearWildcardCache() {
|
|
105
|
-
wildcardCache = Object.create(null);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function findMiddleware<T>(middleware: Record<string, T[]> | undefined, path: Path): T[] | undefined {
|
|
109
|
-
if (!middleware) {
|
|
110
|
-
return undefined;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let keys = Object.keys(middleware).sort((a, b) => b.length - a.length);
|
|
114
|
-
|
|
115
|
-
for (let i = 0, n = keys.length; i < n; i++) {
|
|
116
|
-
if (buildWildcardRegExp(keys[i]).test(path)) {
|
|
117
|
-
return [...middleware[keys[i]]];
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return undefined;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// If path is `/api/animals/:type?` [`/api/animals`, `/api/animals/:type`] else null
|
|
125
|
-
function findOptionalParameters(path: Path): string[] | null {
|
|
126
|
-
if (!path.match(/\:.+\?$/)) {
|
|
127
|
-
return null
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
let base = '',
|
|
131
|
-
results: string[] = [],
|
|
132
|
-
segments = path.split('/');
|
|
133
|
-
|
|
134
|
-
for (let i = 0, n = segments.length; i < n; i++) {
|
|
135
|
-
let segment = segments[i];
|
|
136
|
-
|
|
137
|
-
if (segment !== '' && !/\:/.test(segment)) {
|
|
138
|
-
base += '/' + segment;
|
|
139
|
-
}
|
|
140
|
-
else if (/\:/.test(segment)) {
|
|
141
|
-
if (/\?/.test(segment)) {
|
|
142
|
-
if (results.length === 0 && base === '') {
|
|
143
|
-
results.push('/');
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
results.push(base);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
base += '/' + segment.replace('?', '');
|
|
150
|
-
results.push(base);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
base += '/' + segment;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return results.filter((v, i, a) => a.indexOf(v) === i);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
class Router<T> {
|
|
163
|
-
middleware?: Record<Method, Record<Path, HandlerMap<T>[]>>
|
|
164
|
-
routes?: Record<Method, Record<Path, HandlerMap<T>[]>>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
constructor() {
|
|
168
|
-
this.middleware = {
|
|
169
|
-
[METHOD_NAME_ALL]: Object.create(null)
|
|
170
|
-
};
|
|
171
|
-
this.routes = {
|
|
172
|
-
[METHOD_NAME_ALL]: Object.create(null)
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
private buildAllMatchers(): Record<Method, Matcher<T> | null> {
|
|
178
|
-
let matchers: Record<Method, Matcher<T> | null> = Object.create(null);
|
|
179
|
-
|
|
180
|
-
for (let method in this.middleware) {
|
|
181
|
-
matchers[method] ||= this.buildMatcher(method);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
for (let method in this.routes) {
|
|
185
|
-
matchers[method] ||= this.buildMatcher(method);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
this.middleware = this.routes = undefined;
|
|
189
|
-
|
|
190
|
-
return matchers;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private buildMatcher(method: Method): Matcher<T> | null {
|
|
194
|
-
let isAll = method === METHOD_NAME_ALL,
|
|
195
|
-
properties = [this.middleware, this.routes],
|
|
196
|
-
property,
|
|
197
|
-
routes: [Path, HandlerMap<T>[]][] = [];
|
|
198
|
-
|
|
199
|
-
while (property = properties.pop()) {
|
|
200
|
-
let values = property[method]
|
|
201
|
-
? Object.keys(property[method]).map((path) => [path, property![method][path]])
|
|
202
|
-
: [];
|
|
203
|
-
|
|
204
|
-
if (values.length !== 0) {
|
|
205
|
-
isAll ||= true;
|
|
206
|
-
routes.push(...(values as typeof routes));
|
|
207
|
-
}
|
|
208
|
-
else if (method !== METHOD_NAME_ALL) {
|
|
209
|
-
routes.push(
|
|
210
|
-
...(Object.keys(property[METHOD_NAME_ALL]).map((path) => [path, property![METHOD_NAME_ALL][path]]) as typeof routes)
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return isAll === true ? buildMatcherFromPreprocessedRoutes(routes) : null;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
add(method: Method, path: Path, handler: T) {
|
|
219
|
-
let { middleware, routes } = this;
|
|
220
|
-
|
|
221
|
-
if (!middleware || !routes) {
|
|
222
|
-
throw new Error('Routing: Cannot add route after matcher has been built.');
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (!middleware[method]) {
|
|
226
|
-
let properties = [middleware, routes],
|
|
227
|
-
property;
|
|
228
|
-
|
|
229
|
-
while (property = properties.pop()) {
|
|
230
|
-
let copy = property[METHOD_NAME_ALL],
|
|
231
|
-
into = property[method];
|
|
232
|
-
|
|
233
|
-
property[method] = Object.create(null);
|
|
234
|
-
|
|
235
|
-
for (let path in copy) {
|
|
236
|
-
into[path] = [ ...copy[path] ];
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (path === '/*') {
|
|
242
|
-
path = '*';
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
let parameters = (path.match(/\/:/g) || []).length;
|
|
246
|
-
|
|
247
|
-
if (/\*$/.test(path)) {
|
|
248
|
-
let regex = buildWildcardRegExp(path);
|
|
249
|
-
|
|
250
|
-
if (method === METHOD_NAME_ALL) {
|
|
251
|
-
for (let m in middleware) {
|
|
252
|
-
middleware[m][path] ||=
|
|
253
|
-
findMiddleware(middleware[m], path) ||
|
|
254
|
-
findMiddleware(middleware[METHOD_NAME_ALL], path) ||
|
|
255
|
-
[];
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
middleware[method][path] ||=
|
|
260
|
-
findMiddleware(middleware[method], path) ||
|
|
261
|
-
findMiddleware(middleware[METHOD_NAME_ALL], path) ||
|
|
262
|
-
[];
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
let properties = [middleware, routes],
|
|
266
|
-
property;
|
|
267
|
-
|
|
268
|
-
while (property = properties.pop()) {
|
|
269
|
-
for (let m in property) {
|
|
270
|
-
if (method === METHOD_NAME_ALL || method === m) {
|
|
271
|
-
let routes = property[m];
|
|
272
|
-
|
|
273
|
-
for (let path in routes) {
|
|
274
|
-
regex.test(path) && routes[path].push([handler, parameters]);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
let paths = findOptionalParameters(path) || [path];
|
|
284
|
-
|
|
285
|
-
for (let i = 0, n = paths.length; i < n; i++) {
|
|
286
|
-
let path = paths[i];
|
|
287
|
-
|
|
288
|
-
for (let m in routes) {
|
|
289
|
-
if (method === METHOD_NAME_ALL || method === m) {
|
|
290
|
-
let r = routes[m];
|
|
291
|
-
|
|
292
|
-
r[path] ||= [
|
|
293
|
-
...(findMiddleware(middleware[m], path) ||
|
|
294
|
-
findMiddleware(middleware[METHOD_NAME_ALL], path) ||
|
|
295
|
-
[]),
|
|
296
|
-
];
|
|
297
|
-
r[path].push([handler, parameters - n + i + 1]);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
match(method: Method, path: Path): Result<T> {
|
|
304
|
-
clearWildcardCache();
|
|
305
|
-
|
|
306
|
-
let matchers = this.buildAllMatchers();
|
|
307
|
-
|
|
308
|
-
this.match = (method, path) => {
|
|
309
|
-
let matcher = (matchers[method] || matchers[METHOD_NAME_ALL]) as Matcher<T>,
|
|
310
|
-
staticMatch = matcher[2][path];
|
|
311
|
-
|
|
312
|
-
if (staticMatch) {
|
|
313
|
-
return staticMatch;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
let match = path.match(matcher[0]);
|
|
317
|
-
|
|
318
|
-
if (!match) {
|
|
319
|
-
return [[], empty];
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return [matcher[1][match.indexOf('', 1)], match];
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return this.match(method, path);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
export { Router };
|
package/src/router2/node.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { PATH_ERROR } from './constants';
|
|
2
|
-
import type { Trie } from './trie';
|
|
3
|
-
import { ParameterMetadata, Path } from './types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const LABEL_REGEXP = '[^/]+';
|
|
7
|
-
|
|
8
|
-
const REGEXP_CHARACTERS = new Set('.\\+*[^]$()');
|
|
9
|
-
|
|
10
|
-
const WILDCARD_ONLY_REGEXP = '.*';
|
|
11
|
-
|
|
12
|
-
const WILDCARD_TAIL_REGEXP = '(?:|/.*)';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// '*' matches to all the trailing paths
|
|
16
|
-
const MATCH_WILDCARD_ONLY = ['', '', WILDCARD_ONLY_REGEXP];
|
|
17
|
-
|
|
18
|
-
const MATCH_LABEL = ['', '', LABEL_REGEXP];
|
|
19
|
-
|
|
20
|
-
// '/path/to/*' is /\/path\/to(?:|/.*)$
|
|
21
|
-
const MATCH_WILDCARD_TAIL = ['', '', WILDCARD_TAIL_REGEXP];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Sort order:
|
|
26
|
-
* 1. literal
|
|
27
|
-
* 2. special pattern (e.g. :label{[0-9]+})
|
|
28
|
-
* 3. common label pattern (e.g. :label)
|
|
29
|
-
* 4. wildcard
|
|
30
|
-
*/
|
|
31
|
-
function sort(a: Path, b: Path): number {
|
|
32
|
-
if (a.length === 1) {
|
|
33
|
-
return b.length === 1 ? (a < b ? -1 : 1) : -1;
|
|
34
|
-
}
|
|
35
|
-
else if (b.length === 1) {
|
|
36
|
-
return 1;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (a === WILDCARD_ONLY_REGEXP || a === WILDCARD_TAIL_REGEXP) {
|
|
40
|
-
return 1;
|
|
41
|
-
}
|
|
42
|
-
else if (b === WILDCARD_ONLY_REGEXP || b === WILDCARD_TAIL_REGEXP) {
|
|
43
|
-
return -1;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (a === LABEL_REGEXP) {
|
|
47
|
-
return 1;
|
|
48
|
-
}
|
|
49
|
-
else if (b === LABEL_REGEXP) {
|
|
50
|
-
return -1;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return a.length === b.length ? (a < b ? -1 : 1) : b.length - a.length;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class Node {
|
|
58
|
-
children: Record<Path, Node> = Object.create(null);
|
|
59
|
-
index?: number;
|
|
60
|
-
slot?: number;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
buildRegexString(): Path {
|
|
64
|
-
let children = this.children,
|
|
65
|
-
path,
|
|
66
|
-
paths: Path[] = Object.keys(children).sort(sort);
|
|
67
|
-
|
|
68
|
-
for (let i = 0, n = paths.length; i < n; i++) {
|
|
69
|
-
let child = children[ path = paths[i] ];
|
|
70
|
-
|
|
71
|
-
paths[i] = (
|
|
72
|
-
typeof child.slot === 'number'
|
|
73
|
-
? `(${path})@${child.slot}`
|
|
74
|
-
: REGEXP_CHARACTERS.has(path)
|
|
75
|
-
? `\\${path}`
|
|
76
|
-
: path
|
|
77
|
-
) + child.buildRegexString();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (typeof this.index === 'number') {
|
|
81
|
-
paths.unshift(`#${this.index}`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (paths.length === 0) {
|
|
85
|
-
return '';
|
|
86
|
-
}
|
|
87
|
-
else if (paths.length === 1) {
|
|
88
|
-
return paths[0];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return '(?:' + paths.join('|') + ')';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
insert(
|
|
95
|
-
tokens: readonly Path[],
|
|
96
|
-
index: number,
|
|
97
|
-
parameters: ParameterMetadata,
|
|
98
|
-
context: Trie['context'],
|
|
99
|
-
validatePathOnly: boolean
|
|
100
|
-
): void {
|
|
101
|
-
if (tokens.length === 0) {
|
|
102
|
-
if (this.index !== undefined) {
|
|
103
|
-
throw PATH_ERROR;
|
|
104
|
-
}
|
|
105
|
-
else if (validatePathOnly) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
this.index = index;
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let [token, ...remainingTokens] = tokens,
|
|
114
|
-
node,
|
|
115
|
-
pattern = token === '*'
|
|
116
|
-
? remainingTokens.length === 0
|
|
117
|
-
? MATCH_WILDCARD_ONLY
|
|
118
|
-
: MATCH_LABEL
|
|
119
|
-
: token === '/*'
|
|
120
|
-
? MATCH_WILDCARD_TAIL
|
|
121
|
-
: token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
122
|
-
|
|
123
|
-
if (pattern) {
|
|
124
|
-
let name = pattern[1],
|
|
125
|
-
path = pattern[2] || LABEL_REGEXP;
|
|
126
|
-
|
|
127
|
-
if (name && pattern[2]) {
|
|
128
|
-
// (a|b) => (?:a|b)
|
|
129
|
-
path = path.replace(/^\((?!\?:)(?=[^)]+\)$)/, '(?:');
|
|
130
|
-
|
|
131
|
-
// prefix(?:a|b) is allowed, but prefix(a|b) is not
|
|
132
|
-
if (/\((?!\?:)/.test(path)) {
|
|
133
|
-
throw PATH_ERROR;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
node = this.children[path];
|
|
138
|
-
|
|
139
|
-
if (!node) {
|
|
140
|
-
for (let key in this.children) {
|
|
141
|
-
if (key !== WILDCARD_ONLY_REGEXP && key !== WILDCARD_TAIL_REGEXP) {
|
|
142
|
-
throw PATH_ERROR;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (validatePathOnly) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
node = this.children[path] = new Node();
|
|
151
|
-
|
|
152
|
-
if (name !== '') {
|
|
153
|
-
node.slot = context.slot++;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (name !== '' && validatePathOnly === false) {
|
|
158
|
-
parameters.push([name, node.slot as number]);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
node = this.children[token];
|
|
163
|
-
|
|
164
|
-
if (!node) {
|
|
165
|
-
for (let key in this.children) {
|
|
166
|
-
if (key.length > 1 && key !== WILDCARD_ONLY_REGEXP && key !== WILDCARD_TAIL_REGEXP) {
|
|
167
|
-
throw PATH_ERROR;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (validatePathOnly) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
node = this.children[token] = new Node();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
node.insert(remainingTokens, index, parameters, context, validatePathOnly);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
export { Node };
|
package/src/router2/trie.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { Node } from './node'
|
|
2
|
-
import { Indexes, ParameterMetadata, Path } from './types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const NEVER_MATCH = [/^$/, [], []] as [RegExp, Indexes, Indexes];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Trie {
|
|
9
|
-
context = { slot: 0 };
|
|
10
|
-
root = new Node();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
build(): [RegExp, Indexes, Indexes] {
|
|
14
|
-
let regex = this.root.buildRegexString();
|
|
15
|
-
|
|
16
|
-
if (regex === '') {
|
|
17
|
-
return NEVER_MATCH;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let handlers: Indexes = [],
|
|
21
|
-
i = 0,
|
|
22
|
-
parameters: Indexes = [];
|
|
23
|
-
|
|
24
|
-
regex = regex.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handler, parameter) => {
|
|
25
|
-
if (typeof handler !== 'undefined') {
|
|
26
|
-
handlers[++i] = Number(handler);
|
|
27
|
-
return '$()';
|
|
28
|
-
}
|
|
29
|
-
else if (typeof parameter !== 'undefined') {
|
|
30
|
-
parameters[Number(parameter)] = ++i;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return '';
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
return [new RegExp(`^${regex}`), handlers, parameters];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
insert(path: Path, index: number, pathErrorCheckOnly: boolean): ParameterMetadata {
|
|
40
|
-
let groups: [string, string][] = [],
|
|
41
|
-
parameters: ParameterMetadata = [];
|
|
42
|
-
|
|
43
|
-
for (let i = 0; ;) {
|
|
44
|
-
let replaced = false;
|
|
45
|
-
|
|
46
|
-
path = path.replace(/\{[^}]+\}/g, (m) => {
|
|
47
|
-
let mark = `@\\${i}`;
|
|
48
|
-
|
|
49
|
-
groups[i++] = [mark, m];
|
|
50
|
-
replaced = true;
|
|
51
|
-
|
|
52
|
-
return mark;
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
if (!replaced) {
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* - pattern (:label, :label{0-9]+}, ...)
|
|
62
|
-
* - /* wildcard
|
|
63
|
-
* - character
|
|
64
|
-
*/
|
|
65
|
-
let tokens = path.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
66
|
-
|
|
67
|
-
for (let i = groups.length - 1; i >= 0; i--) {
|
|
68
|
-
let [ mark, replacement ] = groups[i],
|
|
69
|
-
token;
|
|
70
|
-
|
|
71
|
-
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
72
|
-
token = tokens[j];
|
|
73
|
-
|
|
74
|
-
if (token.indexOf(mark) !== -1) {
|
|
75
|
-
token = token.replace(mark, replacement);
|
|
76
|
-
break
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
this.root.insert(tokens, index, parameters, this.context, pathErrorCheckOnly);
|
|
82
|
-
|
|
83
|
-
return parameters;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
export { Trie };
|
package/src/router2/types.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
type HandlerMap<T> = [T, number];
|
|
2
|
-
|
|
3
|
-
type HandlerMetadata<T> = [T, ParameterMap][];
|
|
4
|
-
|
|
5
|
-
type Indexes = number[];
|
|
6
|
-
|
|
7
|
-
type Matcher<T> = [RegExp, HandlerMetadata<T>[], StaticMap<T>];
|
|
8
|
-
|
|
9
|
-
type Method = string;
|
|
10
|
-
|
|
11
|
-
type ParameterMap = Record<string, number>;
|
|
12
|
-
|
|
13
|
-
type ParameterMetadata = [string, number][];
|
|
14
|
-
|
|
15
|
-
type Path = string;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The result can be in one of two formats:
|
|
19
|
-
* 1. An array of handlers with their corresponding parameter index maps, followed by a parameter stash.
|
|
20
|
-
* 2. An array of handlers with their corresponding parameter maps.
|
|
21
|
-
*
|
|
22
|
-
* Example:
|
|
23
|
-
*
|
|
24
|
-
* [[handler, paramIndexMap][], paramArray]
|
|
25
|
-
* ```typescript
|
|
26
|
-
* [
|
|
27
|
-
* [
|
|
28
|
-
* [middlewareA, {}], // '*'
|
|
29
|
-
* [funcA, {'id': 0}], // '/user/:id/*'
|
|
30
|
-
* [funcB, {'id': 0, 'action': 1}], // '/user/:id/:action'
|
|
31
|
-
* ],
|
|
32
|
-
* ['123', 'abc']
|
|
33
|
-
* ]
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* [[handler, params][]]
|
|
37
|
-
* ```typescript
|
|
38
|
-
* [
|
|
39
|
-
* [
|
|
40
|
-
* [middlewareA, {}], // '*'
|
|
41
|
-
* [funcA, {'id': '123'}], // '/user/:id/*'
|
|
42
|
-
* [funcB, {'id': '123', 'action': 'abc'}], // '/user/:id/:action'
|
|
43
|
-
* ]
|
|
44
|
-
* ]
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
type Result<T> = [ [T, ParameterMap][], string[] ] | [ [T, Record<string, string>][] ];
|
|
48
|
-
|
|
49
|
-
type StaticMap<T> = Record<Path, Result<T>>;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export {
|
|
53
|
-
HandlerMap, HandlerMetadata,
|
|
54
|
-
Indexes,
|
|
55
|
-
Matcher, Method,
|
|
56
|
-
ParameterMap, ParameterMetadata, Path,
|
|
57
|
-
Result,
|
|
58
|
-
StaticMap
|
|
59
|
-
};
|