generated from sapphiredev/sapphire-template
/
RouteStore.ts
85 lines (65 loc) · 2.36 KB
/
RouteStore.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
import { Store } from '@sapphire/pieces';
import { Collection } from 'discord.js';
import { URLSearchParams } from 'url';
import type { ApiRequest } from './api/ApiRequest';
import type { ApiResponse } from './api/ApiResponse';
import { methodEntries, type Methods } from './http/HttpMethods';
import { Route } from './Route';
const slash = '/'.charCodeAt(0);
export interface MethodCallback {
(request: ApiRequest, response: ApiResponse): unknown;
}
export interface RouteMatch {
route: Route;
cb: MethodCallback;
}
/**
* @since 1.0.0
*/
export class RouteStore extends Store<Route, 'routes'> {
public readonly table = new Collection<Methods, Collection<Route, MethodCallback>>();
public constructor() {
super(Route, { name: 'routes' });
for (const [method] of methodEntries) this.table.set(method, new Collection());
}
public match(request: ApiRequest): RouteMatch | null {
const { method } = request;
// If there is no method, we can't match a route so return null
if (typeof method === 'undefined') {
return null;
}
// We get all the methods that are tied to the provided method to have a smaller list to filter through
const methodTable = this.table.get(method as Methods);
// If there are no methods of the provided type then we won't find any route so we return null
if (typeof methodTable === 'undefined') {
return null;
}
const { splits, querystring } = this.parseURL(request.url);
for (const [route, cb] of methodTable.entries()) {
const result = route.router.match(splits);
if (result === null) continue;
request.params = result;
request.query = Object.fromEntries(new URLSearchParams(querystring).entries());
return { route, cb };
}
return null;
}
private parseURL(url = '') {
const index = url.indexOf('?');
/* eslint-disable @typescript-eslint/init-declarations */
let pathname: string;
let querystring: string;
/* eslint-enable @typescript-eslint/init-declarations */
if (index === -1) {
pathname = url;
querystring = '';
} else {
pathname = url.substring(0, index);
querystring = url.substring(index + 1);
}
if (pathname.charCodeAt(0) === slash) pathname = pathname.substring(1);
if (pathname.length > 0 && pathname.charCodeAt(pathname.length - 1) === slash) pathname = pathname.substring(0, pathname.length - 1);
const splits = pathname.split('/');
return { splits, querystring };
}
}