@esportsplus/routing 0.0.42 → 0.0.43
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/.editorconfig +9 -9
- package/.gitattributes +2 -2
- package/.github/dependabot.yml +23 -0
- package/.github/workflows/bump.yml +7 -0
- package/.github/workflows/publish.yml +14 -0
- package/build/browser.d.ts +2 -2
- package/build/browser.js +11 -16
- package/build/constants.js +1 -6
- package/build/index.js +5 -27
- package/build/router/index.js +8 -12
- package/build/router/node.js +9 -12
- package/build/router/route.js +3 -9
- package/build/slugify.js +1 -3
- package/build/types.js +2 -6
- package/package.json +22 -22
- package/src/browser.ts +163 -163
- package/src/constants.ts +7 -7
- package/src/index.ts +7 -7
- package/src/router/index.ts +218 -218
- package/src/router/node.ts +140 -140
- package/src/router/route.ts +27 -27
- package/src/slugify.ts +3 -3
- package/src/types.ts +30 -30
- package/tsconfig.json +10 -9
package/src/router/index.ts
CHANGED
|
@@ -1,219 +1,219 @@
|
|
|
1
|
-
import { STATIC } from '~/constants';
|
|
2
|
-
import { Options } from '~/types';
|
|
3
|
-
import { Node } from './node';
|
|
4
|
-
import { Route } from './route';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let { isArray } = Array;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function normalize(path: string) {
|
|
11
|
-
if (path[0] !== '/') {
|
|
12
|
-
path = '/' + path;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (path[path.length - 1] === '/') {
|
|
16
|
-
path = path.slice(0, -1);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return path || '/';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function radixkey(method: string, path: string, subdomain?: string | null) {
|
|
23
|
-
return ((subdomain ? subdomain + ' ' : '') + method).toUpperCase() + ' ' + normalize(path);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function set<T>(route: Route<T>, key: keyof Route<T>, value?: unknown) {
|
|
27
|
-
if (!value) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!route[key]) {
|
|
32
|
-
(route[key] as unknown) = value;
|
|
33
|
-
}
|
|
34
|
-
else if (typeof value === 'string') {
|
|
35
|
-
if (typeof route[key] === 'string') {
|
|
36
|
-
(route[key] as string) += value;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
else if (isArray(value)) {
|
|
40
|
-
if (isArray(route[key])) {
|
|
41
|
-
(route[key] as unknown[]).push( ...value );
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class Router<T> {
|
|
48
|
-
groups: Omit<Options<T>, 'responder'>[] = [];
|
|
49
|
-
root: Node<T>;
|
|
50
|
-
routes: Record<string, Route<T>> = {};
|
|
51
|
-
static: Record<string, Route<T>> = {};
|
|
52
|
-
subdomains: string[] | null = null;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
constructor() {
|
|
56
|
-
this.root = new Node();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
private add(radixkey: string, route: Route<T>) {
|
|
61
|
-
if (radixkey.indexOf(':') === -1 || this.root.add(radixkey, route).type === STATIC) {
|
|
62
|
-
if (this.static[radixkey]) {
|
|
63
|
-
throw new Error(`Routing: static path '${radixkey}' is already in use`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
this.static[radixkey] = route;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return this;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private route({ middleware, name, path, responder, subdomain }: Options<T>) {
|
|
73
|
-
let route = new Route(responder);
|
|
74
|
-
|
|
75
|
-
for (let i = 0, n = this.groups.length; i < n; i++) {
|
|
76
|
-
let { middleware, name, path, subdomain } = this.groups[i];
|
|
77
|
-
|
|
78
|
-
set(route, 'name', name);
|
|
79
|
-
set(route, 'middleware', middleware);
|
|
80
|
-
set(route, 'path', path);
|
|
81
|
-
set(route, 'subdomain', subdomain);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
set(route, 'name', name);
|
|
85
|
-
set(route, 'middleware', middleware);
|
|
86
|
-
set(route, 'path', path);
|
|
87
|
-
set(route, 'subdomain', subdomain);
|
|
88
|
-
|
|
89
|
-
if (route.path) {
|
|
90
|
-
route.path = normalize(route.path);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (route.subdomain === 'www') {
|
|
94
|
-
route.subdomain = '';
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return route;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
delete(options: Options<T>) {
|
|
102
|
-
return this.on(['DELETE'], options);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
get(options: Options<T>) {
|
|
106
|
-
return this.on(['GET'], options);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
group(options: Router<T>['groups'][0]) {
|
|
110
|
-
return {
|
|
111
|
-
routes: (fn: (router: Router<T>) => void) => {
|
|
112
|
-
this.groups.push(options);
|
|
113
|
-
fn(this);
|
|
114
|
-
this.groups.pop();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
match(method: string, path: string, subdomain?: string | null): ReturnType<Node<T>['find']> {
|
|
120
|
-
let key = radixkey(method, path, subdomain);
|
|
121
|
-
|
|
122
|
-
if (key in this.static) {
|
|
123
|
-
return {
|
|
124
|
-
route: this.static[key]
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return this.root.find(key);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
on(methods: string[], options: Options<T>) {
|
|
132
|
-
let route = this.route(options);
|
|
133
|
-
|
|
134
|
-
if (route.name) {
|
|
135
|
-
if (this.routes[route.name]) {
|
|
136
|
-
throw new Error(`Routing: '${route.name}' is already in use`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
this.routes[route.name] = route;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (route.path) {
|
|
143
|
-
for (let i = 0, n = methods.length; i < n; i++) {
|
|
144
|
-
let key = radixkey(methods[i], route.path, route.subdomain);
|
|
145
|
-
|
|
146
|
-
if (key.indexOf('?:') !== -1) {
|
|
147
|
-
let segments = key.split('?:'),
|
|
148
|
-
url = '';
|
|
149
|
-
|
|
150
|
-
for (let i = 0, n = segments.length; i < n; i++) {
|
|
151
|
-
this.add((url += (i > 0 ? '/:' : '/') + segments[i]), route);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
this.add(key, route);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (route.subdomain) {
|
|
161
|
-
if (!this.subdomains) {
|
|
162
|
-
this.subdomains = [route.subdomain];
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
this.subdomains.push(route.subdomain);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return this;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
post(options: Options<T>) {
|
|
173
|
-
return this.on(['POST'], options);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
put(options: Options<T>) {
|
|
177
|
-
return this.on(['PUT'], options);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
uri(name: string, values: unknown[] = []) {
|
|
181
|
-
let path = this.routes[name]?.path;
|
|
182
|
-
|
|
183
|
-
if (!path) {
|
|
184
|
-
throw new Error(`Routing: route name '${name}' does not exist or it does not provide a path`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
let resolved = [] as typeof values,
|
|
188
|
-
segments = path.split('/');
|
|
189
|
-
|
|
190
|
-
for (let i = 0, n = segments.length; i < n; i++) {
|
|
191
|
-
let segment = segments[i],
|
|
192
|
-
symbol = segment[0];
|
|
193
|
-
|
|
194
|
-
if (symbol === ':') {
|
|
195
|
-
resolved.push(values[i]);
|
|
196
|
-
}
|
|
197
|
-
else if (symbol === '?') {
|
|
198
|
-
if (values[i] === undefined) {
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
resolved.push(values[i]);
|
|
203
|
-
}
|
|
204
|
-
else if (symbol === '*') {
|
|
205
|
-
resolved.push( ...values.slice(i) );
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
resolved.push(segment);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return resolved.join('/');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
export default <T>() => new Router<T>();
|
|
1
|
+
import { STATIC } from '~/constants';
|
|
2
|
+
import { Options } from '~/types';
|
|
3
|
+
import { Node } from './node';
|
|
4
|
+
import { Route } from './route';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
let { isArray } = Array;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function normalize(path: string) {
|
|
11
|
+
if (path[0] !== '/') {
|
|
12
|
+
path = '/' + path;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (path[path.length - 1] === '/') {
|
|
16
|
+
path = path.slice(0, -1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return path || '/';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function radixkey(method: string, path: string, subdomain?: string | null) {
|
|
23
|
+
return ((subdomain ? subdomain + ' ' : '') + method).toUpperCase() + ' ' + normalize(path);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function set<T>(route: Route<T>, key: keyof Route<T>, value?: unknown) {
|
|
27
|
+
if (!value) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!route[key]) {
|
|
32
|
+
(route[key] as unknown) = value;
|
|
33
|
+
}
|
|
34
|
+
else if (typeof value === 'string') {
|
|
35
|
+
if (typeof route[key] === 'string') {
|
|
36
|
+
(route[key] as string) += value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (isArray(value)) {
|
|
40
|
+
if (isArray(route[key])) {
|
|
41
|
+
(route[key] as unknown[]).push( ...value );
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Router<T> {
|
|
48
|
+
groups: Omit<Options<T>, 'responder'>[] = [];
|
|
49
|
+
root: Node<T>;
|
|
50
|
+
routes: Record<string, Route<T>> = {};
|
|
51
|
+
static: Record<string, Route<T>> = {};
|
|
52
|
+
subdomains: string[] | null = null;
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
constructor() {
|
|
56
|
+
this.root = new Node();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
private add(radixkey: string, route: Route<T>) {
|
|
61
|
+
if (radixkey.indexOf(':') === -1 || this.root.add(radixkey, route).type === STATIC) {
|
|
62
|
+
if (this.static[radixkey]) {
|
|
63
|
+
throw new Error(`Routing: static path '${radixkey}' is already in use`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.static[radixkey] = route;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private route({ middleware, name, path, responder, subdomain }: Options<T>) {
|
|
73
|
+
let route = new Route(responder);
|
|
74
|
+
|
|
75
|
+
for (let i = 0, n = this.groups.length; i < n; i++) {
|
|
76
|
+
let { middleware, name, path, subdomain } = this.groups[i];
|
|
77
|
+
|
|
78
|
+
set(route, 'name', name);
|
|
79
|
+
set(route, 'middleware', middleware);
|
|
80
|
+
set(route, 'path', path);
|
|
81
|
+
set(route, 'subdomain', subdomain);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
set(route, 'name', name);
|
|
85
|
+
set(route, 'middleware', middleware);
|
|
86
|
+
set(route, 'path', path);
|
|
87
|
+
set(route, 'subdomain', subdomain);
|
|
88
|
+
|
|
89
|
+
if (route.path) {
|
|
90
|
+
route.path = normalize(route.path);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (route.subdomain === 'www') {
|
|
94
|
+
route.subdomain = '';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return route;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
delete(options: Options<T>) {
|
|
102
|
+
return this.on(['DELETE'], options);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get(options: Options<T>) {
|
|
106
|
+
return this.on(['GET'], options);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
group(options: Router<T>['groups'][0]) {
|
|
110
|
+
return {
|
|
111
|
+
routes: (fn: (router: Router<T>) => void) => {
|
|
112
|
+
this.groups.push(options);
|
|
113
|
+
fn(this);
|
|
114
|
+
this.groups.pop();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
match(method: string, path: string, subdomain?: string | null): ReturnType<Node<T>['find']> {
|
|
120
|
+
let key = radixkey(method, path, subdomain);
|
|
121
|
+
|
|
122
|
+
if (key in this.static) {
|
|
123
|
+
return {
|
|
124
|
+
route: this.static[key]
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this.root.find(key);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
on(methods: string[], options: Options<T>) {
|
|
132
|
+
let route = this.route(options);
|
|
133
|
+
|
|
134
|
+
if (route.name) {
|
|
135
|
+
if (this.routes[route.name]) {
|
|
136
|
+
throw new Error(`Routing: '${route.name}' is already in use`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.routes[route.name] = route;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (route.path) {
|
|
143
|
+
for (let i = 0, n = methods.length; i < n; i++) {
|
|
144
|
+
let key = radixkey(methods[i], route.path, route.subdomain);
|
|
145
|
+
|
|
146
|
+
if (key.indexOf('?:') !== -1) {
|
|
147
|
+
let segments = key.split('?:'),
|
|
148
|
+
url = '';
|
|
149
|
+
|
|
150
|
+
for (let i = 0, n = segments.length; i < n; i++) {
|
|
151
|
+
this.add((url += (i > 0 ? '/:' : '/') + segments[i]), route);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.add(key, route);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (route.subdomain) {
|
|
161
|
+
if (!this.subdomains) {
|
|
162
|
+
this.subdomains = [route.subdomain];
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
this.subdomains.push(route.subdomain);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
post(options: Options<T>) {
|
|
173
|
+
return this.on(['POST'], options);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
put(options: Options<T>) {
|
|
177
|
+
return this.on(['PUT'], options);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
uri(name: string, values: unknown[] = []) {
|
|
181
|
+
let path = this.routes[name]?.path;
|
|
182
|
+
|
|
183
|
+
if (!path) {
|
|
184
|
+
throw new Error(`Routing: route name '${name}' does not exist or it does not provide a path`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let resolved = [] as typeof values,
|
|
188
|
+
segments = path.split('/');
|
|
189
|
+
|
|
190
|
+
for (let i = 0, n = segments.length; i < n; i++) {
|
|
191
|
+
let segment = segments[i],
|
|
192
|
+
symbol = segment[0];
|
|
193
|
+
|
|
194
|
+
if (symbol === ':') {
|
|
195
|
+
resolved.push(values[i]);
|
|
196
|
+
}
|
|
197
|
+
else if (symbol === '?') {
|
|
198
|
+
if (values[i] === undefined) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
resolved.push(values[i]);
|
|
203
|
+
}
|
|
204
|
+
else if (symbol === '*') {
|
|
205
|
+
resolved.push( ...values.slice(i) );
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
resolved.push(segment);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return resolved.join('/');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
export default <T>() => new Router<T>();
|
|
219
219
|
export { Router, Route };
|