-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrouter.ts
119 lines (98 loc) · 3.15 KB
/
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
113
114
115
116
117
118
119
export default class Router {
private GetRoot;
constructor() {
this.GetRoot = new RouterNode({ path: "/" });
}
getRoot() {
return this.GetRoot;
}
// Insert new GET Path handler
Get(path: string, handler: Function): void {
if (path === "/") {
if (this.GetRoot.handler) {
throw new Error("/ route already exists");
}
this.GetRoot.handler = handler;
}
// Remove leading and trailing slashes
if (path[0] === "/") {
path = path.slice(1);
}
if (path[path.length-1] === "/") {
path = path.slice(0, -1);
}
let segments: string[] = path.split("/");
segments.unshift("/");
if (this.GetRoot === undefined) {
this.GetRoot = new RouterNode({ path: segments[0], handler });
segments.shift();
}
let curr = this.GetRoot;
let parent = curr;
while (segments.length) {
const pathSegment = segments.shift()
if (!curr || curr.path !== pathSegment) {
// Only add handler if it's the end of the path
if (segments.length) {
parent = parent.insert(pathSegment, undefined);
} else {
parent = parent.insert(pathSegment, handler);
}
curr = null;
} else {
parent = curr;
curr = this.getChild(curr, segments[0]);
}
}
}
getChild(node: RouterNode, path: string): RouterNode|null {
if (node.children?.length) {
for (let i = 0; i < node.children.length; i++) {
if (node.children[i].path === path) {
return node.children[i];
}
}
}
return null;
}
getMatch(path: string): RouterNode|null {
path = this.trimSlashes(path);
let segments: string[] = path.split("/");
segments.unshift("/");
let curr = this.GetRoot;
while (segments.length) {
const pathSegment = segments.shift();
if (!curr || curr.path !== pathSegment) return null;
// Return curr if reached end of path
if (segments.length <= 0) return curr;
curr = this.getChild(curr, segments[0]);
}
return curr;
}
trimSlashes(path: string): string {
if (path[0] === "/") {
path = path.slice(1);
}
if (path[path.length-1] === "/") {
path = path.slice(0, -1);
}
return path;
}
}
export class RouterNode {
path: string;
handler?: Function;
children?: RouterNode[];
constructor({ path, handler }: { path: string, handler?: Function}) {
this.path = path;
this.handler = handler;
}
insert(path: string, handler: Function): RouterNode {
if (this.children === undefined) {
this.children = [];
}
const node = new RouterNode({ path, handler });
this.children.push(node);
return node;
}
}