@esportsplus/routing 0.6.0 → 0.6.2
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 +24 -24
- package/.github/workflows/bump.yml +8 -8
- package/.github/workflows/dependabot.yml +11 -11
- package/.github/workflows/publish.yml +16 -16
- package/README.md +217 -217
- package/build/client/index.d.ts +1 -1
- package/build/client/index.js +10 -10
- package/package.json +3 -3
- package/src/client/constants.ts +21 -21
- package/src/client/index.ts +195 -195
- package/src/client/router/index.ts +293 -293
- package/src/client/router/node.ts +121 -121
- package/src/client/types.ts +105 -105
- package/src/constants.ts +3 -3
- package/test/index.ts +648 -648
- package/tsconfig.json +8 -8
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
import { PARAMETER, STATIC, WILDCARD } from '../constants';
|
|
2
|
-
import { Route } from './index';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Node<T> {
|
|
6
|
-
parent: Node<T> | null = null;
|
|
7
|
-
path: string | null = null;
|
|
8
|
-
route: Route<T> | null = null;
|
|
9
|
-
static: Map<string | number, Node<T>> | null = null;
|
|
10
|
-
type: number | null = null;
|
|
11
|
-
|
|
12
|
-
// Parameter or Wildcard parameter name
|
|
13
|
-
name: string | null = null;
|
|
14
|
-
parameter: Node<T> | null = null;
|
|
15
|
-
wildcard: Node<T> | null = null;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
constructor(parent: Node<T>['parent'] = null) {
|
|
19
|
-
this.parent = parent;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
add(path: string, route: Route<T>) {
|
|
24
|
-
let node: Node<T> | undefined = this,
|
|
25
|
-
segments = path.split('/'),
|
|
26
|
-
type: Node<T>['type'] = STATIC,
|
|
27
|
-
unnamed = 0;
|
|
28
|
-
|
|
29
|
-
for (let i = 0, n = segments.length; i < n; i++) {
|
|
30
|
-
let segment = segments[i],
|
|
31
|
-
symbol = segment[0];
|
|
32
|
-
|
|
33
|
-
// Parameter
|
|
34
|
-
if (symbol === ':') {
|
|
35
|
-
if (!node.parameter) {
|
|
36
|
-
node.parameter = new Node<T>(node);
|
|
37
|
-
node.parameter.name = (segment.slice(1) || unnamed++).toString();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
node = node.parameter;
|
|
41
|
-
type = PARAMETER;
|
|
42
|
-
}
|
|
43
|
-
// "*:" Wildcard
|
|
44
|
-
else if (symbol === '*') {
|
|
45
|
-
if (!node.wildcard) {
|
|
46
|
-
node.wildcard = new Node<T>(node);
|
|
47
|
-
node.wildcard.name = (segment.slice(2) || unnamed++).toString();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
node = node.wildcard;
|
|
51
|
-
type = WILDCARD;
|
|
52
|
-
}
|
|
53
|
-
// Static name
|
|
54
|
-
else {
|
|
55
|
-
let next: Node<T> | undefined = node.static?.get(segment);
|
|
56
|
-
|
|
57
|
-
if (!next) {
|
|
58
|
-
next = new Node<T>(node);
|
|
59
|
-
(node.static ??= new Map()).set(segment, next);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
node = next;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
node.path = path;
|
|
67
|
-
node.route = route;
|
|
68
|
-
node.type = type;
|
|
69
|
-
|
|
70
|
-
return node;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
find(path: string): {
|
|
74
|
-
parameters?: Readonly<Record<PropertyKey, unknown>>;
|
|
75
|
-
route?: Readonly<Route<T>>;
|
|
76
|
-
} {
|
|
77
|
-
let node: Node<T> | undefined = this,
|
|
78
|
-
parameters: Record<PropertyKey, unknown> | undefined,
|
|
79
|
-
segments = path.split('/'),
|
|
80
|
-
wildcard: { node: Node<T>, start: number } | undefined;
|
|
81
|
-
|
|
82
|
-
for (let i = 0, n = segments.length; i < n; i++) {
|
|
83
|
-
let segment = segments[i];
|
|
84
|
-
|
|
85
|
-
if (node.wildcard) {
|
|
86
|
-
wildcard = {
|
|
87
|
-
node: node.wildcard,
|
|
88
|
-
start: i
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Exact matches take precedence over parameters
|
|
93
|
-
let next: Node<T> | undefined = node.static?.get(segment) as Node<T> | undefined;
|
|
94
|
-
|
|
95
|
-
if (next) {
|
|
96
|
-
node = next;
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!node.parameter) {
|
|
101
|
-
node = undefined;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
node = node.parameter;
|
|
106
|
-
(parameters ??= {})[node.name!] = segment;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if ((node === undefined || node.route === null) && wildcard) {
|
|
110
|
-
node = wildcard.node;
|
|
111
|
-
(parameters ??= {})[ node.name! ] = segments.slice(wildcard.start).join('/');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
parameters,
|
|
116
|
-
route: node?.route || undefined
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
1
|
+
import { PARAMETER, STATIC, WILDCARD } from '../constants';
|
|
2
|
+
import { Route } from './index';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Node<T> {
|
|
6
|
+
parent: Node<T> | null = null;
|
|
7
|
+
path: string | null = null;
|
|
8
|
+
route: Route<T> | null = null;
|
|
9
|
+
static: Map<string | number, Node<T>> | null = null;
|
|
10
|
+
type: number | null = null;
|
|
11
|
+
|
|
12
|
+
// Parameter or Wildcard parameter name
|
|
13
|
+
name: string | null = null;
|
|
14
|
+
parameter: Node<T> | null = null;
|
|
15
|
+
wildcard: Node<T> | null = null;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
constructor(parent: Node<T>['parent'] = null) {
|
|
19
|
+
this.parent = parent;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
add(path: string, route: Route<T>) {
|
|
24
|
+
let node: Node<T> | undefined = this,
|
|
25
|
+
segments = path.split('/'),
|
|
26
|
+
type: Node<T>['type'] = STATIC,
|
|
27
|
+
unnamed = 0;
|
|
28
|
+
|
|
29
|
+
for (let i = 0, n = segments.length; i < n; i++) {
|
|
30
|
+
let segment = segments[i],
|
|
31
|
+
symbol = segment[0];
|
|
32
|
+
|
|
33
|
+
// Parameter
|
|
34
|
+
if (symbol === ':') {
|
|
35
|
+
if (!node.parameter) {
|
|
36
|
+
node.parameter = new Node<T>(node);
|
|
37
|
+
node.parameter.name = (segment.slice(1) || unnamed++).toString();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
node = node.parameter;
|
|
41
|
+
type = PARAMETER;
|
|
42
|
+
}
|
|
43
|
+
// "*:" Wildcard
|
|
44
|
+
else if (symbol === '*') {
|
|
45
|
+
if (!node.wildcard) {
|
|
46
|
+
node.wildcard = new Node<T>(node);
|
|
47
|
+
node.wildcard.name = (segment.slice(2) || unnamed++).toString();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
node = node.wildcard;
|
|
51
|
+
type = WILDCARD;
|
|
52
|
+
}
|
|
53
|
+
// Static name
|
|
54
|
+
else {
|
|
55
|
+
let next: Node<T> | undefined = node.static?.get(segment);
|
|
56
|
+
|
|
57
|
+
if (!next) {
|
|
58
|
+
next = new Node<T>(node);
|
|
59
|
+
(node.static ??= new Map()).set(segment, next);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
node = next;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
node.path = path;
|
|
67
|
+
node.route = route;
|
|
68
|
+
node.type = type;
|
|
69
|
+
|
|
70
|
+
return node;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
find(path: string): {
|
|
74
|
+
parameters?: Readonly<Record<PropertyKey, unknown>>;
|
|
75
|
+
route?: Readonly<Route<T>>;
|
|
76
|
+
} {
|
|
77
|
+
let node: Node<T> | undefined = this,
|
|
78
|
+
parameters: Record<PropertyKey, unknown> | undefined,
|
|
79
|
+
segments = path.split('/'),
|
|
80
|
+
wildcard: { node: Node<T>, start: number } | undefined;
|
|
81
|
+
|
|
82
|
+
for (let i = 0, n = segments.length; i < n; i++) {
|
|
83
|
+
let segment = segments[i];
|
|
84
|
+
|
|
85
|
+
if (node.wildcard) {
|
|
86
|
+
wildcard = {
|
|
87
|
+
node: node.wildcard,
|
|
88
|
+
start: i
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Exact matches take precedence over parameters
|
|
93
|
+
let next: Node<T> | undefined = node.static?.get(segment) as Node<T> | undefined;
|
|
94
|
+
|
|
95
|
+
if (next) {
|
|
96
|
+
node = next;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!node.parameter) {
|
|
101
|
+
node = undefined;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
node = node.parameter;
|
|
106
|
+
(parameters ??= {})[node.name!] = segment;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if ((node === undefined || node.route === null) && wildcard) {
|
|
110
|
+
node = wildcard.node;
|
|
111
|
+
(parameters ??= {})[ node.name! ] = segments.slice(wildcard.start).join('/');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
parameters,
|
|
116
|
+
route: node?.route || undefined
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
122
|
export { Node };
|
package/src/client/types.ts
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import { NeverAsync } from '@esportsplus/utilities';
|
|
2
|
-
import { Router } from './router';
|
|
3
|
-
import pipeline from '@esportsplus/pipeline';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
type AccumulateRoutes<T extends readonly RouteFactory<any>[]> =
|
|
7
|
-
T extends readonly [infer F extends RouteFactory<any>, ...infer Rest extends readonly RouteFactory<any>[]]
|
|
8
|
-
? ExtractRoutes<F> & AccumulateRoutes<Rest>
|
|
9
|
-
: {};
|
|
10
|
-
|
|
11
|
-
type ExtractOptionalParams<Path extends string> =
|
|
12
|
-
Path extends `/${infer Segment}/${infer Rest}`
|
|
13
|
-
? (Segment extends `?:${infer Param}` ? Param : never) | ExtractOptionalParams<`/${Rest}`>
|
|
14
|
-
: Path extends `/${infer Segment}`
|
|
15
|
-
? (Segment extends `?:${infer Param}` ? Param : never)
|
|
16
|
-
: never;
|
|
17
|
-
|
|
18
|
-
type ExtractParamsTuple<Path extends string> =
|
|
19
|
-
Path extends `${infer _Start}:${infer Param}/${infer Rest}`
|
|
20
|
-
? [Param, ...ExtractParamsTuple<`/${Rest}`>]
|
|
21
|
-
: Path extends `${infer _Start}:${infer Param}`
|
|
22
|
-
? [Param]
|
|
23
|
-
: [];
|
|
24
|
-
|
|
25
|
-
type ExtractRequiredParams<Path extends string> =
|
|
26
|
-
Path extends `/${infer Segment}/${infer Rest}`
|
|
27
|
-
? (Segment extends `:${infer Param}` ? Param : never) | ExtractRequiredParams<`/${Rest}`>
|
|
28
|
-
: Path extends `/${infer Segment}`
|
|
29
|
-
? (Segment extends `:${infer Param}` ? Param : never)
|
|
30
|
-
: never;
|
|
31
|
-
|
|
32
|
-
type ExtractRoutes<F> =
|
|
33
|
-
F extends (r: Router<any, any>) => Router<any, infer Routes extends RouteRegistry>
|
|
34
|
-
? Routes
|
|
35
|
-
: never;
|
|
36
|
-
|
|
37
|
-
type InferOutput<F> = F extends RouteFactory<infer T> ? T : never;
|
|
38
|
-
|
|
39
|
-
type LabeledParamsTuple<Params extends string[]> =
|
|
40
|
-
Params extends [infer _First extends string, ...infer Rest extends string[]]
|
|
41
|
-
? [_First: string | number, ...LabeledParamsTuple<Rest>]
|
|
42
|
-
: [];
|
|
43
|
-
|
|
44
|
-
type Middleware<T> = NeverAsync<(input: Request<T>, next: Next<T>) => T>;
|
|
45
|
-
|
|
46
|
-
type Name = string;
|
|
47
|
-
|
|
48
|
-
type Next<T> = NeverAsync<(input: Request<T>) => T>;
|
|
49
|
-
|
|
50
|
-
type Options<T> = {
|
|
51
|
-
middleware?: Middleware<T>[];
|
|
52
|
-
name?: string;
|
|
53
|
-
path?: string;
|
|
54
|
-
subdomain?: string;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
type PathParamsObject<Path extends string> =
|
|
58
|
-
{ [K in ExtractRequiredParams<Path>]: string | number } &
|
|
59
|
-
{ [K in ExtractOptionalParams<Path>]?: string | number };
|
|
60
|
-
|
|
61
|
-
type PathParamsTuple<Path extends string> =
|
|
62
|
-
LabeledParamsTuple<ExtractParamsTuple<Path>>;
|
|
63
|
-
|
|
64
|
-
type Request<T> = {
|
|
65
|
-
data: Record<PropertyKey, unknown> & ReturnType<Router<T>['match']>;
|
|
66
|
-
hostname: string;
|
|
67
|
-
href: string;
|
|
68
|
-
method: string;
|
|
69
|
-
origin: string;
|
|
70
|
-
path: string;
|
|
71
|
-
port: string;
|
|
72
|
-
protocol: string;
|
|
73
|
-
query: Record<string, unknown>;
|
|
74
|
-
subdomain?: string;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
type Route<T> = {
|
|
78
|
-
name: Name | null;
|
|
79
|
-
path: string | null;
|
|
80
|
-
pipeline: ReturnType<typeof pipeline<Request<T>, T>>,
|
|
81
|
-
subdomain: string | null;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
type RouteFactory<T> = (router: Router<T, any>) => Router<T, RouteRegistry>;
|
|
85
|
-
|
|
86
|
-
type RouteOptions<T> = Options<T> & {
|
|
87
|
-
responder: Next<T>;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
type RoutePath<Routes, K extends keyof Routes> =
|
|
91
|
-
Routes[K] extends { path: infer P extends string } ? P : string;
|
|
92
|
-
|
|
93
|
-
type RouteRegistry = Record<string, { path: string }>;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
export type {
|
|
97
|
-
AccumulateRoutes,
|
|
98
|
-
ExtractOptionalParams, ExtractRequiredParams,
|
|
99
|
-
InferOutput,
|
|
100
|
-
Middleware,
|
|
101
|
-
Name, Next,
|
|
102
|
-
Options,
|
|
103
|
-
PathParamsObject, PathParamsTuple,
|
|
104
|
-
Request, Router, Route, RouteFactory, RouteOptions, RoutePath, RouteRegistry
|
|
105
|
-
};
|
|
1
|
+
import { NeverAsync } from '@esportsplus/utilities';
|
|
2
|
+
import { Router } from './router';
|
|
3
|
+
import pipeline from '@esportsplus/pipeline';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type AccumulateRoutes<T extends readonly RouteFactory<any>[]> =
|
|
7
|
+
T extends readonly [infer F extends RouteFactory<any>, ...infer Rest extends readonly RouteFactory<any>[]]
|
|
8
|
+
? ExtractRoutes<F> & AccumulateRoutes<Rest>
|
|
9
|
+
: {};
|
|
10
|
+
|
|
11
|
+
type ExtractOptionalParams<Path extends string> =
|
|
12
|
+
Path extends `/${infer Segment}/${infer Rest}`
|
|
13
|
+
? (Segment extends `?:${infer Param}` ? Param : never) | ExtractOptionalParams<`/${Rest}`>
|
|
14
|
+
: Path extends `/${infer Segment}`
|
|
15
|
+
? (Segment extends `?:${infer Param}` ? Param : never)
|
|
16
|
+
: never;
|
|
17
|
+
|
|
18
|
+
type ExtractParamsTuple<Path extends string> =
|
|
19
|
+
Path extends `${infer _Start}:${infer Param}/${infer Rest}`
|
|
20
|
+
? [Param, ...ExtractParamsTuple<`/${Rest}`>]
|
|
21
|
+
: Path extends `${infer _Start}:${infer Param}`
|
|
22
|
+
? [Param]
|
|
23
|
+
: [];
|
|
24
|
+
|
|
25
|
+
type ExtractRequiredParams<Path extends string> =
|
|
26
|
+
Path extends `/${infer Segment}/${infer Rest}`
|
|
27
|
+
? (Segment extends `:${infer Param}` ? Param : never) | ExtractRequiredParams<`/${Rest}`>
|
|
28
|
+
: Path extends `/${infer Segment}`
|
|
29
|
+
? (Segment extends `:${infer Param}` ? Param : never)
|
|
30
|
+
: never;
|
|
31
|
+
|
|
32
|
+
type ExtractRoutes<F> =
|
|
33
|
+
F extends (r: Router<any, any>) => Router<any, infer Routes extends RouteRegistry>
|
|
34
|
+
? Routes
|
|
35
|
+
: never;
|
|
36
|
+
|
|
37
|
+
type InferOutput<F> = F extends RouteFactory<infer T> ? T : never;
|
|
38
|
+
|
|
39
|
+
type LabeledParamsTuple<Params extends string[]> =
|
|
40
|
+
Params extends [infer _First extends string, ...infer Rest extends string[]]
|
|
41
|
+
? [_First: string | number, ...LabeledParamsTuple<Rest>]
|
|
42
|
+
: [];
|
|
43
|
+
|
|
44
|
+
type Middleware<T> = NeverAsync<(input: Request<T>, next: Next<T>) => T>;
|
|
45
|
+
|
|
46
|
+
type Name = string;
|
|
47
|
+
|
|
48
|
+
type Next<T> = NeverAsync<(input: Request<T>) => T>;
|
|
49
|
+
|
|
50
|
+
type Options<T> = {
|
|
51
|
+
middleware?: Middleware<T>[];
|
|
52
|
+
name?: string;
|
|
53
|
+
path?: string;
|
|
54
|
+
subdomain?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type PathParamsObject<Path extends string> =
|
|
58
|
+
{ [K in ExtractRequiredParams<Path>]: string | number } &
|
|
59
|
+
{ [K in ExtractOptionalParams<Path>]?: string | number };
|
|
60
|
+
|
|
61
|
+
type PathParamsTuple<Path extends string> =
|
|
62
|
+
LabeledParamsTuple<ExtractParamsTuple<Path>>;
|
|
63
|
+
|
|
64
|
+
type Request<T> = {
|
|
65
|
+
data: Record<PropertyKey, unknown> & ReturnType<Router<T>['match']>;
|
|
66
|
+
hostname: string;
|
|
67
|
+
href: string;
|
|
68
|
+
method: string;
|
|
69
|
+
origin: string;
|
|
70
|
+
path: string;
|
|
71
|
+
port: string;
|
|
72
|
+
protocol: string;
|
|
73
|
+
query: Record<string, unknown>;
|
|
74
|
+
subdomain?: string;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
type Route<T> = {
|
|
78
|
+
name: Name | null;
|
|
79
|
+
path: string | null;
|
|
80
|
+
pipeline: ReturnType<typeof pipeline<Request<T>, T>>,
|
|
81
|
+
subdomain: string | null;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type RouteFactory<T> = (router: Router<T, any>) => Router<T, RouteRegistry>;
|
|
85
|
+
|
|
86
|
+
type RouteOptions<T> = Options<T> & {
|
|
87
|
+
responder: Next<T>;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
type RoutePath<Routes, K extends keyof Routes> =
|
|
91
|
+
Routes[K] extends { path: infer P extends string } ? P : string;
|
|
92
|
+
|
|
93
|
+
type RouteRegistry = Record<string, { path: string }>;
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
export type {
|
|
97
|
+
AccumulateRoutes,
|
|
98
|
+
ExtractOptionalParams, ExtractRequiredParams,
|
|
99
|
+
InferOutput,
|
|
100
|
+
Middleware,
|
|
101
|
+
Name, Next,
|
|
102
|
+
Options,
|
|
103
|
+
PathParamsObject, PathParamsTuple,
|
|
104
|
+
Request, Router, Route, RouteFactory, RouteOptions, RoutePath, RouteRegistry
|
|
105
|
+
};
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const PACKAGE_NAME = '@esportsplus/routing';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const PACKAGE_NAME = '@esportsplus/routing';
|
|
2
|
+
|
|
3
|
+
|
|
4
4
|
export { PACKAGE_NAME };
|