@esportsplus/routing 0.0.16 → 0.0.17
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/middleware/dispatch.d.ts +2 -2
- package/build/middleware/index.d.ts +2 -4
- package/build/middleware/match.d.ts +2 -4
- package/build/middleware/match.js +7 -7
- package/build/router/index.d.ts +14 -14
- package/build/router/index.js +17 -7
- package/build/router/node.d.ts +8 -8
- package/build/router/node.js +10 -10
- package/build/router/route.d.ts +7 -8
- package/build/router/route.js +1 -1
- package/build/spa.d.ts +7 -9
- package/build/spa.js +22 -28
- package/build/types.d.ts +9 -7
- package/package.json +1 -1
- package/src/middleware/dispatch.ts +3 -3
- package/src/middleware/match.ts +9 -9
- package/src/router/index.ts +38 -24
- package/src/router/node.ts +26 -26
- package/src/router/route.ts +8 -8
- package/src/spa.ts +25 -43
- package/src/types.ts +11 -7
- package/src/router/path.ts +0 -28
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const _default: <R>(request: Request) =>
|
|
1
|
+
import { Request, Responder } from '../types';
|
|
2
|
+
declare const _default: <R>(request: Request<R>) => R | Promise<R>;
|
|
3
3
|
export default _default;
|
|
@@ -2,11 +2,9 @@ import factory from '@esportsplus/middleware';
|
|
|
2
2
|
import dispatch from './dispatch';
|
|
3
3
|
import match from './match';
|
|
4
4
|
declare const _default: {
|
|
5
|
-
dispatch: <R>(request: import("../types").Request) =>
|
|
5
|
+
dispatch: <R>(request: import("../types").Request<R>) => R | Promise<R>;
|
|
6
6
|
factory: <I, R_1>(...middleware: import("@esportsplus/middleware/build/types").Middleware<I, R_1>[]) => import("@esportsplus/middleware/build/types").Next<I, R_1>;
|
|
7
|
-
match: <R_2>(router: import("../router").Router
|
|
8
|
-
spa?: boolean | undefined;
|
|
9
|
-
}) => import("@esportsplus/middleware/build/types").Middleware<import("../types").Request, R_2>;
|
|
7
|
+
match: <R_2>(router: import("../router").Router<R_2>, subdomain?: string | undefined) => import("../types").Middleware<R_2>;
|
|
10
8
|
};
|
|
11
9
|
export default _default;
|
|
12
10
|
export { dispatch, factory, match };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Middleware,
|
|
2
|
-
declare const _default: <R>(router: Router
|
|
3
|
-
spa?: boolean | undefined;
|
|
4
|
-
}) => Middleware<Request, R>;
|
|
1
|
+
import { Middleware, Router } from '../types';
|
|
2
|
+
declare const _default: <R>(router: Router<R>, subdomain?: string) => Middleware<R>;
|
|
5
3
|
export default _default;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
export default (router,
|
|
2
|
-
let subdomain = null;
|
|
1
|
+
export default (router, subdomain) => {
|
|
3
2
|
return (request, next) => {
|
|
4
|
-
|
|
3
|
+
let match = subdomain || request.subdomain;
|
|
4
|
+
if (match === undefined) {
|
|
5
5
|
if (router.subdomains) {
|
|
6
6
|
for (let i = 0, n = router.subdomains.length; i < n; i++) {
|
|
7
7
|
if (!request.hostname.startsWith(router.subdomains[i])) {
|
|
8
8
|
continue;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
match = router.subdomains[i];
|
|
11
11
|
break;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
if (
|
|
15
|
-
|
|
14
|
+
if (match === undefined) {
|
|
15
|
+
match = '';
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
let { parameters, route } = router.match(request.method, request.path,
|
|
18
|
+
let { parameters, route } = router.match(request.method, request.path, match);
|
|
19
19
|
request.data.parameters = parameters;
|
|
20
20
|
request.data.route = route;
|
|
21
21
|
return next(request);
|
package/build/router/index.d.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { Options } from '../types';
|
|
2
2
|
import { Node } from './node';
|
|
3
3
|
import { Route } from './route';
|
|
4
|
-
declare class Router {
|
|
5
|
-
groups: Omit<Options
|
|
6
|
-
root: Node
|
|
7
|
-
routes: Record<string, Route
|
|
8
|
-
static: Record<string, Route
|
|
4
|
+
declare class Router<R> {
|
|
5
|
+
groups: Omit<Options<R>, 'responder'>[];
|
|
6
|
+
root: Node<R>;
|
|
7
|
+
routes: Record<string, Route<R>>;
|
|
8
|
+
static: Record<string, Route<R>>;
|
|
9
9
|
subdomains: string[] | null;
|
|
10
10
|
constructor();
|
|
11
11
|
private add;
|
|
12
12
|
private route;
|
|
13
|
-
delete(options: Options): this;
|
|
14
|
-
get(options: Options): this;
|
|
15
|
-
group(options: Router['groups'][0]): {
|
|
16
|
-
routes: (fn: (router: Router) => void) => void;
|
|
13
|
+
delete(options: Options<R>): this;
|
|
14
|
+
get(options: Options<R>): this;
|
|
15
|
+
group(options: Router<R>['groups'][0]): {
|
|
16
|
+
routes: (fn: (router: Router<R>) => void) => void;
|
|
17
17
|
};
|
|
18
|
-
match(method: string, path: string, subdomain?: string | null): ReturnType<Node['find']>;
|
|
19
|
-
on(methods: string[], options: Options): this;
|
|
20
|
-
post(options: Options): this;
|
|
21
|
-
put(options: Options): this;
|
|
18
|
+
match(method: string, path: string, subdomain?: string | null): ReturnType<Node<R>['find']>;
|
|
19
|
+
on(methods: string[], options: Options<R>): this;
|
|
20
|
+
post(options: Options<R>): this;
|
|
21
|
+
put(options: Options<R>): this;
|
|
22
22
|
uri(name: string, values?: unknown[]): string;
|
|
23
23
|
}
|
|
24
|
-
declare const _default: () => Router
|
|
24
|
+
declare const _default: <R>() => Router<R>;
|
|
25
25
|
export default _default;
|
|
26
26
|
export { Router, Route };
|
package/build/router/index.js
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { STATIC } from '../constants';
|
|
2
2
|
import { Node } from './node';
|
|
3
|
-
import { normalize, radixkey } from './path';
|
|
4
3
|
import { Route } from './route';
|
|
5
4
|
let { isArray } = Array;
|
|
5
|
+
function normalize(path) {
|
|
6
|
+
if (path[0] !== '/') {
|
|
7
|
+
path = '/' + path;
|
|
8
|
+
}
|
|
9
|
+
if (path[path.length - 1] === '/') {
|
|
10
|
+
path = path.slice(0, -1);
|
|
11
|
+
}
|
|
12
|
+
return path || '/';
|
|
13
|
+
}
|
|
14
|
+
function radixkey(method, path, subdomain) {
|
|
15
|
+
return ((subdomain ? subdomain + ' ' : '') + method).toUpperCase() + ' ' + normalize(path);
|
|
16
|
+
}
|
|
6
17
|
function set(route, key, value) {
|
|
7
18
|
if (!value) {
|
|
8
19
|
return;
|
|
@@ -78,9 +89,11 @@ class Router {
|
|
|
78
89
|
};
|
|
79
90
|
}
|
|
80
91
|
match(method, path, subdomain) {
|
|
81
|
-
let key = radixkey(
|
|
92
|
+
let key = radixkey(method, path, subdomain);
|
|
82
93
|
if (key in this.static) {
|
|
83
|
-
return {
|
|
94
|
+
return {
|
|
95
|
+
route: this.static[key]
|
|
96
|
+
};
|
|
84
97
|
}
|
|
85
98
|
return this.root.find(key);
|
|
86
99
|
}
|
|
@@ -94,10 +107,7 @@ class Router {
|
|
|
94
107
|
}
|
|
95
108
|
if (route.path) {
|
|
96
109
|
for (let i = 0, n = methods.length; i < n; i++) {
|
|
97
|
-
let key = radixkey(route.path,
|
|
98
|
-
method: methods[i],
|
|
99
|
-
subdomain: route.subdomain
|
|
100
|
-
});
|
|
110
|
+
let key = radixkey(methods[i], route.path, route.subdomain);
|
|
101
111
|
if (key.indexOf('?:') !== -1) {
|
|
102
112
|
let segments = key.split('?:'), url = '';
|
|
103
113
|
for (let i = 0, n = segments.length; i < n; i++) {
|
package/build/router/node.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Route } from './index';
|
|
2
|
-
declare class Node {
|
|
3
|
-
children: Map<string | number, Node
|
|
4
|
-
parent: Node | null;
|
|
2
|
+
declare class Node<R> {
|
|
3
|
+
children: Map<string | number, Node<R>> | null;
|
|
4
|
+
parent: Node<R> | null;
|
|
5
5
|
path: string | null;
|
|
6
6
|
property: string | null;
|
|
7
|
-
route: Route | null;
|
|
7
|
+
route: Route<R> | null;
|
|
8
8
|
type: number | null;
|
|
9
|
-
constructor(parent?: Node['parent']);
|
|
10
|
-
add(path: string, route: Route): Node
|
|
9
|
+
constructor(parent?: Node<R>['parent']);
|
|
10
|
+
add(path: string, route: Route<R>): Node<R>;
|
|
11
11
|
find(path: string): {
|
|
12
12
|
parameters?: Record<PropertyKey, unknown>;
|
|
13
|
-
route?: Route
|
|
13
|
+
route?: Route<R>;
|
|
14
14
|
};
|
|
15
|
-
remove(path: string):
|
|
15
|
+
remove(path: string): void;
|
|
16
16
|
}
|
|
17
17
|
export { Node };
|
package/build/router/node.js
CHANGED
|
@@ -20,12 +20,12 @@ class Node {
|
|
|
20
20
|
}
|
|
21
21
|
node.children.set(segment, (child = new Node(node)));
|
|
22
22
|
if (symbol === ':') {
|
|
23
|
-
child.property = segment.slice(1) ||
|
|
23
|
+
child.property = (segment.slice(1) || unnamed++).toString();
|
|
24
24
|
node.children.set(PLACEHOLDER, child);
|
|
25
25
|
type = null;
|
|
26
26
|
}
|
|
27
27
|
else if (symbol === '*') {
|
|
28
|
-
child.property = segment.slice(2) ||
|
|
28
|
+
child.property = (segment.slice(2) || unnamed++).toString();
|
|
29
29
|
node.children.set(WILDCARD, child);
|
|
30
30
|
type = null;
|
|
31
31
|
}
|
|
@@ -79,15 +79,15 @@ class Node {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
if (node.children?.size) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
let parent = node.parent;
|
|
86
|
+
if (parent && parent.children) {
|
|
87
|
+
parent.children.delete(segments[segments.length - 1]);
|
|
88
|
+
parent.children.delete(WILDCARD);
|
|
89
|
+
parent.children.delete(PLACEHOLDER);
|
|
89
90
|
}
|
|
90
|
-
return node;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
export { Node };
|
package/build/router/route.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { Middleware, Responder } from '../types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
dispatch: ReturnType<typeof factory> | null;
|
|
1
|
+
import { Middleware, Next, Responder } from '../types';
|
|
2
|
+
declare class Route<R> {
|
|
3
|
+
dispatch: Next<R> | null;
|
|
5
4
|
name: string | null;
|
|
6
5
|
path: string | null;
|
|
7
|
-
responder: Responder
|
|
8
|
-
stack: Middleware<
|
|
6
|
+
responder: Responder<R>;
|
|
7
|
+
stack: Middleware<R>[] | null;
|
|
9
8
|
subdomain: string | null;
|
|
10
|
-
constructor(responder: Responder);
|
|
11
|
-
get dispatcher():
|
|
9
|
+
constructor(responder: Responder<R>);
|
|
10
|
+
get dispatcher(): Next<R>;
|
|
12
11
|
}
|
|
13
12
|
export { Route };
|
package/build/router/route.js
CHANGED
package/build/spa.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { Router } from './types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
back: () => void;
|
|
8
|
-
forward: () => void;
|
|
1
|
+
import { Request, Router } from './types';
|
|
2
|
+
declare function back(): void;
|
|
3
|
+
declare function forward(): void;
|
|
4
|
+
declare const _default: <R>(router: Router<R>) => {
|
|
5
|
+
back: typeof back;
|
|
6
|
+
forward: typeof forward;
|
|
9
7
|
redirect: (path: string, { state, values }: {
|
|
10
8
|
state?: Record<PropertyKey, unknown> | undefined;
|
|
11
9
|
values?: unknown[] | undefined;
|
|
12
10
|
}) => void;
|
|
13
|
-
request:
|
|
11
|
+
request: Request<unknown>;
|
|
14
12
|
uri: (path: string, values?: unknown[]) => string;
|
|
15
13
|
};
|
|
16
14
|
export default _default;
|
package/build/spa.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
let
|
|
2
|
-
function
|
|
3
|
-
|
|
1
|
+
let state = request();
|
|
2
|
+
function back() {
|
|
3
|
+
window.history.back();
|
|
4
|
+
}
|
|
5
|
+
function forward() {
|
|
6
|
+
window.history.forward();
|
|
7
|
+
}
|
|
8
|
+
function normalize(uri) {
|
|
9
|
+
if (uri[0] === '/') {
|
|
10
|
+
return '#' + uri;
|
|
11
|
+
}
|
|
12
|
+
return uri;
|
|
13
|
+
}
|
|
14
|
+
function request() {
|
|
15
|
+
let { hash, hostname, href, origin, port, protocol } = new URL(window?.location?.href || ''), path = hash?.replace('#/', '/')?.split('?') || ['/', ''];
|
|
4
16
|
return {
|
|
5
17
|
data: {},
|
|
6
18
|
href,
|
|
@@ -14,43 +26,25 @@ function request(url = window?.location?.href || '') {
|
|
|
14
26
|
};
|
|
15
27
|
}
|
|
16
28
|
function update() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
state[key] = values[key];
|
|
21
|
-
}
|
|
29
|
+
let values = request();
|
|
30
|
+
for (let key in values) {
|
|
31
|
+
state[key] = values[key];
|
|
22
32
|
}
|
|
23
33
|
}
|
|
24
|
-
|
|
25
|
-
const forward = () => window.history.forward();
|
|
26
|
-
export default (router, fn = request) => {
|
|
27
|
-
let state = {};
|
|
28
|
-
cache.push({
|
|
29
|
-
factory: fn,
|
|
30
|
-
state
|
|
31
|
-
});
|
|
32
|
-
update();
|
|
34
|
+
export default (router) => {
|
|
33
35
|
window.addEventListener('popstate', update);
|
|
34
36
|
return {
|
|
35
37
|
back,
|
|
36
38
|
forward,
|
|
37
39
|
redirect: (path, { state, values }) => {
|
|
38
|
-
if (path.startsWith('
|
|
40
|
+
if (path.startsWith('https://') || path.startsWith('http://')) {
|
|
39
41
|
return window.location.replace(path);
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
if (uri[0] === '/') {
|
|
43
|
-
uri = '#' + uri;
|
|
44
|
-
}
|
|
45
|
-
window.history.pushState(state || {}, '', uri);
|
|
43
|
+
window.history.pushState((state || {}), '', normalize(router.uri(path, values || [])));
|
|
46
44
|
},
|
|
47
45
|
request: state,
|
|
48
46
|
uri: (path, values = []) => {
|
|
49
|
-
|
|
50
|
-
if (uri[0] === '/') {
|
|
51
|
-
uri = '#' + uri;
|
|
52
|
-
}
|
|
53
|
-
return uri;
|
|
47
|
+
return normalize(router.uri(path, values || []));
|
|
54
48
|
}
|
|
55
49
|
};
|
|
56
50
|
};
|
package/build/types.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { Middleware, Next } from '@esportsplus/middleware';
|
|
1
|
+
import { Middleware as M, Next as N } from '@esportsplus/middleware';
|
|
2
2
|
import { Route, Router } from './router';
|
|
3
|
-
type
|
|
4
|
-
|
|
3
|
+
type Middleware<R> = M<Request<R>, ReturnType<Responder<R>>>;
|
|
4
|
+
type Next<R> = N<Request<R>, ReturnType<Responder<R>>>;
|
|
5
|
+
type Options<R> = {
|
|
6
|
+
middleware?: Middleware<R>[];
|
|
5
7
|
name?: string;
|
|
6
8
|
path?: string;
|
|
7
|
-
responder: Responder
|
|
9
|
+
responder: Responder<R>;
|
|
8
10
|
subdomain?: string;
|
|
9
11
|
};
|
|
10
|
-
type Request = {
|
|
11
|
-
data: ReturnType<Router['match']> & Record<PropertyKey, unknown>;
|
|
12
|
+
type Request<R> = {
|
|
13
|
+
data: ReturnType<Router<R>['match']> & Record<PropertyKey, unknown>;
|
|
12
14
|
href: string;
|
|
13
15
|
hostname: string;
|
|
14
16
|
method: string;
|
|
@@ -19,5 +21,5 @@ type Request = {
|
|
|
19
21
|
query: Record<string, unknown>;
|
|
20
22
|
subdomain?: string;
|
|
21
23
|
};
|
|
22
|
-
type Responder =
|
|
24
|
+
type Responder<R> = (request: Request<R>) => Promise<R> | R;
|
|
23
25
|
export { Middleware, Next, Options, Request, Responder, Route, Router };
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Request, Responder } from '~/types';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
export default <R>(request: Request) => {
|
|
4
|
+
export default <R>(request: Request<R>): ReturnType<Responder<R>> => {
|
|
5
5
|
let { route } = request.data;
|
|
6
6
|
|
|
7
7
|
if (!route) {
|
|
8
8
|
throw new Error(`Routing: route dispatching failed, route is undefined!`);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
return route.dispatcher(request)
|
|
11
|
+
return route.dispatcher(request);
|
|
12
12
|
};
|
package/src/middleware/match.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { Middleware,
|
|
1
|
+
import { Middleware, Router } from '~/types';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
export default <R>(router: Router
|
|
5
|
-
let subdomain: string | null = null;
|
|
6
|
-
|
|
4
|
+
export default <R>(router: Router<R>, subdomain?: string): Middleware<R> => {
|
|
7
5
|
return (request, next) => {
|
|
8
|
-
|
|
6
|
+
let match = subdomain || request.subdomain;
|
|
7
|
+
|
|
8
|
+
if (match === undefined) {
|
|
9
9
|
if (router.subdomains) {
|
|
10
10
|
for (let i = 0, n = router.subdomains.length; i < n; i++) {
|
|
11
11
|
if (!request.hostname.startsWith(router.subdomains[i])) {
|
|
12
12
|
continue;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
match = router.subdomains[i];
|
|
16
16
|
break;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
if (
|
|
21
|
-
|
|
20
|
+
if (match === undefined) {
|
|
21
|
+
match = '';
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
let { parameters, route } = router.match(request.method, request.path,
|
|
25
|
+
let { parameters, route } = router.match(request.method, request.path, match);
|
|
26
26
|
|
|
27
27
|
request.data.parameters = parameters;
|
|
28
28
|
request.data.route = route;
|
package/src/router/index.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { STATIC } from '~/constants';
|
|
2
2
|
import { Options } from '~/types';
|
|
3
3
|
import { Node } from './node';
|
|
4
|
-
import { normalize, radixkey } from './path';
|
|
5
4
|
import { Route } from './route';
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
let { isArray } = Array;
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
function
|
|
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<R>(route: Route<R>, key: keyof Route<R>, value?: unknown) {
|
|
12
27
|
if (!value) {
|
|
13
28
|
return;
|
|
14
29
|
}
|
|
@@ -29,11 +44,11 @@ function set(route: Route, key: keyof Route, value?: unknown) {
|
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
|
|
32
|
-
class Router {
|
|
33
|
-
groups: Omit<Options
|
|
34
|
-
root: Node
|
|
35
|
-
routes: Record<string, Route
|
|
36
|
-
static: Record<string, Route
|
|
47
|
+
class Router<R> {
|
|
48
|
+
groups: Omit<Options<R>, 'responder'>[] = [];
|
|
49
|
+
root: Node<R>;
|
|
50
|
+
routes: Record<string, Route<R>> = {};
|
|
51
|
+
static: Record<string, Route<R>> = {};
|
|
37
52
|
subdomains: string[] | null = null;
|
|
38
53
|
|
|
39
54
|
|
|
@@ -42,7 +57,7 @@ class Router {
|
|
|
42
57
|
}
|
|
43
58
|
|
|
44
59
|
|
|
45
|
-
private add(radixkey: string, route: Route) {
|
|
60
|
+
private add(radixkey: string, route: Route<R>) {
|
|
46
61
|
if (radixkey.indexOf(':') === -1 || this.root.add(radixkey, route).type === STATIC) {
|
|
47
62
|
if (this.static[radixkey]) {
|
|
48
63
|
throw new Error(`Routing: static path '${radixkey}' is already in use`);
|
|
@@ -54,7 +69,7 @@ class Router {
|
|
|
54
69
|
return this;
|
|
55
70
|
}
|
|
56
71
|
|
|
57
|
-
private route({ middleware, name, path, responder, subdomain }: Options) {
|
|
72
|
+
private route({ middleware, name, path, responder, subdomain }: Options<R>) {
|
|
58
73
|
let route = new Route(responder);
|
|
59
74
|
|
|
60
75
|
for (let i = 0, n = this.groups.length; i < n; i++) {
|
|
@@ -83,19 +98,19 @@ class Router {
|
|
|
83
98
|
}
|
|
84
99
|
|
|
85
100
|
|
|
86
|
-
delete(options: Options) {
|
|
101
|
+
delete(options: Options<R>) {
|
|
87
102
|
this.on(['DELETE'], options);
|
|
88
103
|
return this;
|
|
89
104
|
}
|
|
90
105
|
|
|
91
|
-
get(options: Options) {
|
|
106
|
+
get(options: Options<R>) {
|
|
92
107
|
this.on(['GET'], options);
|
|
93
108
|
return this;
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
group(options: Router['groups'][0]) {
|
|
111
|
+
group(options: Router<R>['groups'][0]) {
|
|
97
112
|
return {
|
|
98
|
-
routes: (fn: (router: Router) => void) => {
|
|
113
|
+
routes: (fn: (router: Router<R>) => void) => {
|
|
99
114
|
this.groups.push(options);
|
|
100
115
|
fn(this);
|
|
101
116
|
this.groups.pop();
|
|
@@ -103,17 +118,19 @@ class Router {
|
|
|
103
118
|
}
|
|
104
119
|
}
|
|
105
120
|
|
|
106
|
-
match(method: string, path: string, subdomain?: string | null): ReturnType<Node['find']> {
|
|
107
|
-
let key = radixkey(
|
|
121
|
+
match(method: string, path: string, subdomain?: string | null): ReturnType<Node<R>['find']> {
|
|
122
|
+
let key = radixkey(method, path, subdomain);
|
|
108
123
|
|
|
109
124
|
if (key in this.static) {
|
|
110
|
-
return {
|
|
125
|
+
return {
|
|
126
|
+
route: this.static[key]
|
|
127
|
+
};
|
|
111
128
|
}
|
|
112
129
|
|
|
113
130
|
return this.root.find(key);
|
|
114
131
|
}
|
|
115
132
|
|
|
116
|
-
on(methods: string[], options: Options) {
|
|
133
|
+
on(methods: string[], options: Options<R>) {
|
|
117
134
|
let route = this.route(options);
|
|
118
135
|
|
|
119
136
|
if (route.name) {
|
|
@@ -126,10 +143,7 @@ class Router {
|
|
|
126
143
|
|
|
127
144
|
if (route.path) {
|
|
128
145
|
for (let i = 0, n = methods.length; i < n; i++) {
|
|
129
|
-
let key = radixkey(route.path,
|
|
130
|
-
method: methods[i],
|
|
131
|
-
subdomain: route.subdomain
|
|
132
|
-
});
|
|
146
|
+
let key = radixkey(methods[i], route.path, route.subdomain);
|
|
133
147
|
|
|
134
148
|
if (key.indexOf('?:') !== -1) {
|
|
135
149
|
let segments = key.split('?:'),
|
|
@@ -157,12 +171,12 @@ class Router {
|
|
|
157
171
|
return this;
|
|
158
172
|
}
|
|
159
173
|
|
|
160
|
-
post(options: Options) {
|
|
174
|
+
post(options: Options<R>) {
|
|
161
175
|
this.on(['POST'], options);
|
|
162
176
|
return this;
|
|
163
177
|
}
|
|
164
178
|
|
|
165
|
-
put(options: Options) {
|
|
179
|
+
put(options: Options<R>) {
|
|
166
180
|
this.on(['PUT'], options);
|
|
167
181
|
return this;
|
|
168
182
|
}
|
|
@@ -205,5 +219,5 @@ class Router {
|
|
|
205
219
|
}
|
|
206
220
|
|
|
207
221
|
|
|
208
|
-
export default () => new Router();
|
|
222
|
+
export default <R>() => new Router<R>();
|
|
209
223
|
export { Router, Route };
|
package/src/router/node.ts
CHANGED
|
@@ -2,28 +2,28 @@ import { PLACEHOLDER, STATIC, WILDCARD } from '~/constants';
|
|
|
2
2
|
import { Route } from './index';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class Node {
|
|
6
|
-
children: Map<string | number, Node
|
|
7
|
-
parent: Node | null = null;
|
|
5
|
+
class Node<R> {
|
|
6
|
+
children: Map<string | number, Node<R>> | null = null;
|
|
7
|
+
parent: Node<R> | null = null;
|
|
8
8
|
path: string | null = null;
|
|
9
9
|
property: string | null = null;
|
|
10
|
-
route: Route | null = null;
|
|
10
|
+
route: Route<R> | null = null;
|
|
11
11
|
type: number | null = null;
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
constructor(parent: Node['parent'] = null) {
|
|
14
|
+
constructor(parent: Node<R>['parent'] = null) {
|
|
15
15
|
this.parent = parent;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
add(path: string, route: Route) {
|
|
20
|
-
let node: Node | undefined = this,
|
|
19
|
+
add(path: string, route: Route<R>) {
|
|
20
|
+
let node: Node<R> | undefined = this,
|
|
21
21
|
segments = path.split('/'),
|
|
22
|
-
type: Node['type'] = STATIC,
|
|
22
|
+
type: Node<R>['type'] = STATIC,
|
|
23
23
|
unnamed = 0;
|
|
24
24
|
|
|
25
25
|
for (let i = 0, n = segments.length; i < n; i++) {
|
|
26
|
-
let child: Node | undefined = node.children?.get(segments[i]);
|
|
26
|
+
let child: Node<R> | undefined = node.children?.get(segments[i]);
|
|
27
27
|
|
|
28
28
|
if (!child) {
|
|
29
29
|
let segment = segments[i],
|
|
@@ -33,17 +33,17 @@ class Node {
|
|
|
33
33
|
node.children = new Map();
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
node.children.set(segment, (child = new Node(node)));
|
|
36
|
+
node.children.set(segment, (child = new Node<R>(node)));
|
|
37
37
|
|
|
38
38
|
// Named property
|
|
39
39
|
if (symbol === ':') {
|
|
40
|
-
child.property = segment.slice(1) ||
|
|
40
|
+
child.property = (segment.slice(1) || unnamed++).toString();
|
|
41
41
|
node.children.set(PLACEHOLDER, child);
|
|
42
42
|
type = null;
|
|
43
43
|
}
|
|
44
44
|
// "*:" Wildcard property
|
|
45
45
|
else if (symbol === '*') {
|
|
46
|
-
child.property = segment.slice(2) ||
|
|
46
|
+
child.property = (segment.slice(2) || unnamed++).toString();
|
|
47
47
|
node.children.set(WILDCARD, child);
|
|
48
48
|
type = null;
|
|
49
49
|
}
|
|
@@ -61,12 +61,12 @@ class Node {
|
|
|
61
61
|
|
|
62
62
|
find(path: string): {
|
|
63
63
|
parameters?: Record<PropertyKey, unknown>;
|
|
64
|
-
route?: Route
|
|
64
|
+
route?: Route<R>;
|
|
65
65
|
} {
|
|
66
|
-
let node: Node | undefined = this,
|
|
66
|
+
let node: Node<R> | undefined = this,
|
|
67
67
|
parameters: Record<PropertyKey, unknown> = {},
|
|
68
68
|
segments = path.split('/'),
|
|
69
|
-
wildcard: { node: Node
|
|
69
|
+
wildcard: { node: Node<R>, value: string } | null = null;
|
|
70
70
|
|
|
71
71
|
for (let i = 0, n = segments.length; i < n; i++) {
|
|
72
72
|
let segment = segments[i],
|
|
@@ -80,7 +80,7 @@ class Node {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
// Exact matches take precedence over placeholders
|
|
83
|
-
let next: Node | undefined = node.children?.get(segment);
|
|
83
|
+
let next: Node<R> | undefined = node.children?.get(segment);
|
|
84
84
|
|
|
85
85
|
if (next) {
|
|
86
86
|
node = next;
|
|
@@ -112,7 +112,7 @@ class Node {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
remove(path: string) {
|
|
115
|
-
let node: Node | undefined = this,
|
|
115
|
+
let node: Node<R> | undefined = this,
|
|
116
116
|
segments = path.split('/');
|
|
117
117
|
|
|
118
118
|
for (let i = 0, n = segments.length; i < n; i++) {
|
|
@@ -123,17 +123,17 @@ class Node {
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (parent && parent.children) {
|
|
130
|
-
parent.children.delete( segments[segments.length - 1] );
|
|
131
|
-
parent.children.delete(WILDCARD);
|
|
132
|
-
parent.children.delete(PLACEHOLDER);
|
|
133
|
-
}
|
|
126
|
+
if (node.children?.size) {
|
|
127
|
+
return;
|
|
134
128
|
}
|
|
135
129
|
|
|
136
|
-
|
|
130
|
+
let parent = node.parent;
|
|
131
|
+
|
|
132
|
+
if (parent && parent.children) {
|
|
133
|
+
parent.children.delete( segments[segments.length - 1] );
|
|
134
|
+
parent.children.delete(WILDCARD);
|
|
135
|
+
parent.children.delete(PLACEHOLDER);
|
|
136
|
+
}
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
package/src/router/route.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { Middleware, Responder } from '~/types';
|
|
1
|
+
import { Middleware, Next, Responder } from '~/types';
|
|
2
2
|
import { factory } from '~/middleware';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class Route {
|
|
6
|
-
dispatch:
|
|
5
|
+
class Route<R> {
|
|
6
|
+
dispatch: Next<R> | null = null;
|
|
7
7
|
name: string | null = null;
|
|
8
8
|
path: string | null = null;
|
|
9
|
-
responder: Responder
|
|
10
|
-
stack: Middleware<
|
|
9
|
+
responder: Responder<R>;
|
|
10
|
+
stack: Middleware<R>[] | null = null;
|
|
11
11
|
subdomain: string | null = null;
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
constructor(responder: Responder) {
|
|
14
|
+
constructor(responder: Responder<R>) {
|
|
15
15
|
this.responder = responder;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
get dispatcher() {
|
|
20
20
|
if (this.dispatch === null) {
|
|
21
|
-
if (
|
|
22
|
-
this.dispatch =
|
|
21
|
+
if (this.stack === null) {
|
|
22
|
+
this.dispatch = (request) => this.responder(request);
|
|
23
23
|
}
|
|
24
24
|
else {
|
|
25
25
|
this.dispatch = factory(...this.stack, (request => this.responder(request)));
|
package/src/spa.ts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { Request, Router } from './types';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
factory: () => T;
|
|
6
|
-
state: T;
|
|
7
|
-
};
|
|
4
|
+
let state = request();
|
|
8
5
|
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
function back() {
|
|
8
|
+
window.history.back();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function forward() {
|
|
12
|
+
window.history.forward();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalize(uri: string) {
|
|
16
|
+
if (uri[0] === '/') {
|
|
17
|
+
return '#' + uri;
|
|
18
|
+
}
|
|
11
19
|
|
|
20
|
+
return uri;
|
|
21
|
+
}
|
|
12
22
|
|
|
13
|
-
function request(
|
|
14
|
-
let { hash, hostname, href, origin, port, protocol } = new URL(
|
|
23
|
+
function request<R>(): Request<R> {
|
|
24
|
+
let { hash, hostname, href, origin, port, protocol } = new URL( window?.location?.href || '' ),
|
|
15
25
|
path = hash?.replace('#/', '/')?.split('?') || ['/', ''];
|
|
16
26
|
|
|
17
27
|
return {
|
|
@@ -28,59 +38,31 @@ function request(url: string = window?.location?.href || ''): Request {
|
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
function update() {
|
|
31
|
-
|
|
32
|
-
let { factory, state } = cache[i],
|
|
33
|
-
values = factory();
|
|
41
|
+
let values = request();
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
for (let key in values) {
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
state[key] = values[key];
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const forward = () => window.history.forward();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
export default (router: Router, fn: Cache['factory'] = request) => {
|
|
48
|
-
let state = {} as ReturnType< typeof fn >;
|
|
49
|
-
|
|
50
|
-
cache.push({
|
|
51
|
-
factory: fn,
|
|
52
|
-
state
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
update();
|
|
56
|
-
|
|
50
|
+
export default <R>(router: Router<R>) => {
|
|
57
51
|
window.addEventListener('popstate', update);
|
|
58
52
|
|
|
59
53
|
return {
|
|
60
54
|
back,
|
|
61
55
|
forward,
|
|
62
56
|
redirect: (path: string, { state, values }: { state?: Record<PropertyKey, unknown>; values?: unknown[] }) => {
|
|
63
|
-
if (path.startsWith('
|
|
57
|
+
if (path.startsWith('https://') || path.startsWith('http://')) {
|
|
64
58
|
return window.location.replace(path);
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (uri[0] === '/') {
|
|
70
|
-
uri = '#' + uri;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
window.history.pushState(state || {}, '', uri);
|
|
61
|
+
window.history.pushState( (state || {}), '', normalize(router.uri(path, values || [])) );
|
|
74
62
|
},
|
|
75
63
|
request: state,
|
|
76
64
|
uri: (path: string, values: unknown[] = []) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (uri[0] === '/') {
|
|
80
|
-
uri = '#' + uri;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return uri;
|
|
65
|
+
return normalize( router.uri(path, values || []) );
|
|
84
66
|
}
|
|
85
67
|
};
|
|
86
68
|
};
|
package/src/types.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import { Middleware, Next } from '@esportsplus/middleware';
|
|
1
|
+
import { Middleware as M, Next as N } from '@esportsplus/middleware';
|
|
2
2
|
import { Route, Router } from './router';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
type
|
|
6
|
-
|
|
5
|
+
type Middleware<R> = M<Request<R>, ReturnType<Responder<R>>>;
|
|
6
|
+
|
|
7
|
+
type Next<R> = N<Request<R>, ReturnType<Responder<R>>>;
|
|
8
|
+
|
|
9
|
+
type Options<R> = {
|
|
10
|
+
middleware?: Middleware<R>[];
|
|
7
11
|
name?: string;
|
|
8
12
|
path?: string;
|
|
9
|
-
responder: Responder
|
|
13
|
+
responder: Responder<R>;
|
|
10
14
|
subdomain?: string;
|
|
11
15
|
};
|
|
12
16
|
|
|
13
|
-
type Request = {
|
|
14
|
-
data: ReturnType<Router['match']> & Record<PropertyKey, unknown>;
|
|
17
|
+
type Request<R> = {
|
|
18
|
+
data: ReturnType<Router<R>['match']> & Record<PropertyKey, unknown>;
|
|
15
19
|
href: string;
|
|
16
20
|
hostname: string;
|
|
17
21
|
method: string;
|
|
@@ -23,7 +27,7 @@ type Request = {
|
|
|
23
27
|
subdomain?: string;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
|
-
type Responder =
|
|
30
|
+
type Responder<R> = (request: Request<R>) => Promise<R> | R;
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
export { Middleware, Next, Options, Request, Responder, Route, Router };
|
package/src/router/path.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const normalize = (path: string) => {
|
|
2
|
-
if (path[0] !== '/') {
|
|
3
|
-
path = '/' + path;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
if (path.endsWith('/')) {
|
|
7
|
-
path = path.slice(0, -1);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return path || '/';
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const radixkey = (path: string, { method, subdomain }: { method?: string | null; subdomain?: string | null; } = {}) => {
|
|
14
|
-
let prefix = '';
|
|
15
|
-
|
|
16
|
-
if (subdomain) {
|
|
17
|
-
prefix = subdomain + ' ';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (method) {
|
|
21
|
-
prefix += method + ' ';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return prefix.toUpperCase() + normalize(path);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export { normalize, radixkey };
|