@carno.js/core 1.0.2 → 1.0.3
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/LICENSE +21 -674
- package/README.md +188 -188
- package/dist/Carno.js +466 -269
- package/dist/bun/index.js +6 -19
- package/dist/bun/index.js.map +27 -28
- package/package.json +3 -2
- package/src/Carno.ts +605 -605
- package/src/DefaultRoutes.ts +34 -34
- package/src/cache/CacheDriver.ts +50 -50
- package/src/cache/CacheService.ts +139 -139
- package/src/cache/MemoryDriver.ts +104 -104
- package/src/cache/RedisDriver.ts +116 -116
- package/src/compiler/JITCompiler.ts +167 -167
- package/src/container/Container.ts +168 -168
- package/src/context/Context.ts +128 -128
- package/src/cors/CorsHandler.ts +145 -145
- package/src/decorators/Controller.ts +63 -63
- package/src/decorators/Inject.ts +16 -16
- package/src/decorators/Middleware.ts +22 -22
- package/src/decorators/Service.ts +18 -18
- package/src/decorators/methods.ts +58 -58
- package/src/decorators/params.ts +47 -47
- package/src/events/Lifecycle.ts +97 -97
- package/src/exceptions/HttpException.ts +99 -99
- package/src/index.ts +92 -92
- package/src/metadata.ts +46 -46
- package/src/middleware/CarnoMiddleware.ts +14 -14
- package/src/router/RadixRouter.ts +225 -225
- package/src/testing/TestHarness.ts +177 -177
- package/src/utils/Metadata.ts +43 -43
- package/src/validation/ValibotAdapter.ts +95 -95
- package/src/validation/ValidatorAdapter.ts +69 -69
- package/src/validation/ZodAdapter.ts +102 -102
package/src/metadata.ts
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { Scope } from './container/Container';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Controller options for the @Controller decorator.
|
|
5
|
-
*/
|
|
6
|
-
export interface ControllerOptions {
|
|
7
|
-
path?: string;
|
|
8
|
-
scope?: Scope;
|
|
9
|
-
children?: any[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Controller metadata stored on controller classes.
|
|
14
|
-
*/
|
|
15
|
-
export interface ControllerMeta {
|
|
16
|
-
path: string;
|
|
17
|
-
scope?: Scope;
|
|
18
|
-
children?: any[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Route metadata stored on controllers.
|
|
23
|
-
*/
|
|
24
|
-
export interface RouteInfo {
|
|
25
|
-
method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options';
|
|
26
|
-
path: string;
|
|
27
|
-
handlerName: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Middleware metadata.
|
|
32
|
-
*/
|
|
33
|
-
export interface MiddlewareInfo {
|
|
34
|
-
handler: Function;
|
|
35
|
-
target?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Metadata keys.
|
|
40
|
-
*/
|
|
41
|
-
export const CONTROLLER_META = Symbol('turbo:controller');
|
|
42
|
-
export const ROUTES_META = Symbol('turbo:routes');
|
|
43
|
-
export const PARAMS_META = Symbol('turbo:params');
|
|
44
|
-
export const MIDDLEWARE_META = Symbol('turbo:middleware');
|
|
45
|
-
export const SERVICE_META = Symbol('turbo:service');
|
|
46
|
-
export const INJECT_META = Symbol('turbo:inject');
|
|
1
|
+
import { Scope } from './container/Container';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Controller options for the @Controller decorator.
|
|
5
|
+
*/
|
|
6
|
+
export interface ControllerOptions {
|
|
7
|
+
path?: string;
|
|
8
|
+
scope?: Scope;
|
|
9
|
+
children?: any[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Controller metadata stored on controller classes.
|
|
14
|
+
*/
|
|
15
|
+
export interface ControllerMeta {
|
|
16
|
+
path: string;
|
|
17
|
+
scope?: Scope;
|
|
18
|
+
children?: any[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Route metadata stored on controllers.
|
|
23
|
+
*/
|
|
24
|
+
export interface RouteInfo {
|
|
25
|
+
method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options';
|
|
26
|
+
path: string;
|
|
27
|
+
handlerName: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Middleware metadata.
|
|
32
|
+
*/
|
|
33
|
+
export interface MiddlewareInfo {
|
|
34
|
+
handler: Function;
|
|
35
|
+
target?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Metadata keys.
|
|
40
|
+
*/
|
|
41
|
+
export const CONTROLLER_META = Symbol('turbo:controller');
|
|
42
|
+
export const ROUTES_META = Symbol('turbo:routes');
|
|
43
|
+
export const PARAMS_META = Symbol('turbo:params');
|
|
44
|
+
export const MIDDLEWARE_META = Symbol('turbo:middleware');
|
|
45
|
+
export const SERVICE_META = Symbol('turbo:service');
|
|
46
|
+
export const INJECT_META = Symbol('turbo:inject');
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { Context } from '../context/Context';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Closure function to call the next middleware in the chain.
|
|
5
|
-
*/
|
|
6
|
-
export type CarnoClosure = () => void | Promise<void>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Interface for onion-style middleware.
|
|
10
|
-
* Middleware must call next() to continue the chain.
|
|
11
|
-
*/
|
|
12
|
-
export interface CarnoMiddleware {
|
|
13
|
-
handle(ctx: Context, next: CarnoClosure): void | Promise<void>;
|
|
14
|
-
}
|
|
1
|
+
import type { Context } from '../context/Context';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Closure function to call the next middleware in the chain.
|
|
5
|
+
*/
|
|
6
|
+
export type CarnoClosure = () => void | Promise<void>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Interface for onion-style middleware.
|
|
10
|
+
* Middleware must call next() to continue the chain.
|
|
11
|
+
*/
|
|
12
|
+
export interface CarnoMiddleware {
|
|
13
|
+
handle(ctx: Context, next: CarnoClosure): void | Promise<void>;
|
|
14
|
+
}
|
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ultra-fast Radix Router for Turbo.
|
|
3
|
-
*
|
|
4
|
-
* Optimizations:
|
|
5
|
-
* - Char code comparisons (no string allocations)
|
|
6
|
-
* - Frozen empty params object
|
|
7
|
-
* - O(1) method lookup via char code index
|
|
8
|
-
* - Minimal allocations in hot path
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const EMPTY_PARAMS: Readonly<Record<string, string>> = Object.freeze({});
|
|
12
|
-
|
|
13
|
-
interface Node<T> {
|
|
14
|
-
part: string;
|
|
15
|
-
store: T | null;
|
|
16
|
-
children: Map<number, Node<T>> | null;
|
|
17
|
-
paramChild: ParamNode<T> | null;
|
|
18
|
-
wildcardStore: T | null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface ParamNode<T> {
|
|
22
|
-
name: string;
|
|
23
|
-
store: T | null;
|
|
24
|
-
child: Node<T> | null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface RouteMatch<T> {
|
|
28
|
-
store: T;
|
|
29
|
-
params: Record<string, string>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function createNode<T>(part: string): Node<T> {
|
|
33
|
-
return {
|
|
34
|
-
part,
|
|
35
|
-
store: null,
|
|
36
|
-
children: null,
|
|
37
|
-
paramChild: null,
|
|
38
|
-
wildcardStore: null
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export class RadixRouter<T> {
|
|
43
|
-
private roots: Record<string, Node<T>> = {};
|
|
44
|
-
|
|
45
|
-
add(method: string, path: string, store: T): void {
|
|
46
|
-
if (path === '') path = '/';
|
|
47
|
-
if (path[0] !== '/') path = '/' + path;
|
|
48
|
-
|
|
49
|
-
const isWildcard = path.endsWith('*');
|
|
50
|
-
|
|
51
|
-
if (isWildcard) path = path.slice(0, -1);
|
|
52
|
-
|
|
53
|
-
let node = this.roots[method];
|
|
54
|
-
|
|
55
|
-
if (!node) {
|
|
56
|
-
node = this.roots[method] = createNode('/');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let i = 0;
|
|
60
|
-
const len = path.length;
|
|
61
|
-
|
|
62
|
-
while (i < len) {
|
|
63
|
-
const char = path.charCodeAt(i);
|
|
64
|
-
|
|
65
|
-
if (char === 58) {
|
|
66
|
-
const paramStart = i + 1;
|
|
67
|
-
let paramEnd = paramStart;
|
|
68
|
-
|
|
69
|
-
while (paramEnd < len && path.charCodeAt(paramEnd) !== 47) {
|
|
70
|
-
paramEnd++;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const paramName = path.slice(paramStart, paramEnd);
|
|
74
|
-
|
|
75
|
-
if (!node.paramChild) {
|
|
76
|
-
node.paramChild = { name: paramName, store: null, child: null };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (paramEnd >= len) {
|
|
80
|
-
node.paramChild.store = store;
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!node.paramChild.child) {
|
|
85
|
-
node.paramChild.child = createNode(path.slice(paramEnd));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
node = node.paramChild.child;
|
|
89
|
-
i = paramEnd;
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
let segmentEnd = i;
|
|
94
|
-
|
|
95
|
-
while (segmentEnd < len && path.charCodeAt(segmentEnd) !== 47 && path.charCodeAt(segmentEnd) !== 58) {
|
|
96
|
-
segmentEnd++;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (segmentEnd < len && path.charCodeAt(segmentEnd) === 47) {
|
|
100
|
-
segmentEnd++;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const segment = path.slice(i, segmentEnd);
|
|
104
|
-
|
|
105
|
-
if (segment === node.part) {
|
|
106
|
-
i = segmentEnd;
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!node.children) {
|
|
111
|
-
node.children = new Map();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const firstChar = segment.charCodeAt(0);
|
|
115
|
-
let child = node.children.get(firstChar);
|
|
116
|
-
|
|
117
|
-
if (!child) {
|
|
118
|
-
child = createNode(segment);
|
|
119
|
-
node.children.set(firstChar, child);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
node = child;
|
|
123
|
-
i = segmentEnd;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (isWildcard) {
|
|
127
|
-
node.wildcardStore = store;
|
|
128
|
-
} else {
|
|
129
|
-
node.store = store;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
find(method: string, path: string): RouteMatch<T> | null {
|
|
134
|
-
const root = this.roots[method];
|
|
135
|
-
|
|
136
|
-
if (!root) return null;
|
|
137
|
-
|
|
138
|
-
return this.matchPath(root, path, 0, path.length);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private matchPath(
|
|
142
|
-
node: Node<T>,
|
|
143
|
-
path: string,
|
|
144
|
-
start: number,
|
|
145
|
-
len: number
|
|
146
|
-
): RouteMatch<T> | null {
|
|
147
|
-
const partLen = node.part.length;
|
|
148
|
-
const end = start + partLen;
|
|
149
|
-
|
|
150
|
-
if (partLen > 1) {
|
|
151
|
-
if (end > len) return null;
|
|
152
|
-
|
|
153
|
-
for (let i = 1, j = start + 1; i < partLen; i++, j++) {
|
|
154
|
-
if (node.part.charCodeAt(i) !== path.charCodeAt(j)) {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (end === len) {
|
|
161
|
-
if (node.store !== null) {
|
|
162
|
-
return { store: node.store, params: EMPTY_PARAMS };
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (node.wildcardStore !== null) {
|
|
166
|
-
return { store: node.wildcardStore, params: { '*': '' } };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (node.children) {
|
|
173
|
-
const child = node.children.get(path.charCodeAt(end));
|
|
174
|
-
|
|
175
|
-
if (child) {
|
|
176
|
-
const result = this.matchPath(child, path, end, len);
|
|
177
|
-
|
|
178
|
-
if (result) return result;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (node.paramChild) {
|
|
183
|
-
const param = node.paramChild;
|
|
184
|
-
let paramEnd = end;
|
|
185
|
-
|
|
186
|
-
while (paramEnd < len && path.charCodeAt(paramEnd) !== 47) {
|
|
187
|
-
paramEnd++;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (paramEnd === end) return null;
|
|
191
|
-
|
|
192
|
-
const paramValue = path.slice(end, paramEnd);
|
|
193
|
-
|
|
194
|
-
if (paramEnd >= len) {
|
|
195
|
-
if (param.store !== null) {
|
|
196
|
-
return {
|
|
197
|
-
store: param.store,
|
|
198
|
-
params: { [param.name]: paramValue }
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
} else if (param.child) {
|
|
202
|
-
const result = this.matchPath(param.child, path, paramEnd, len);
|
|
203
|
-
|
|
204
|
-
if (result) {
|
|
205
|
-
if (result.params === EMPTY_PARAMS) {
|
|
206
|
-
result.params = { [param.name]: paramValue };
|
|
207
|
-
} else {
|
|
208
|
-
result.params[param.name] = paramValue;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return result;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (node.wildcardStore !== null) {
|
|
217
|
-
return {
|
|
218
|
-
store: node.wildcardStore,
|
|
219
|
-
params: { '*': path.slice(end) }
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Ultra-fast Radix Router for Turbo.
|
|
3
|
+
*
|
|
4
|
+
* Optimizations:
|
|
5
|
+
* - Char code comparisons (no string allocations)
|
|
6
|
+
* - Frozen empty params object
|
|
7
|
+
* - O(1) method lookup via char code index
|
|
8
|
+
* - Minimal allocations in hot path
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const EMPTY_PARAMS: Readonly<Record<string, string>> = Object.freeze({});
|
|
12
|
+
|
|
13
|
+
interface Node<T> {
|
|
14
|
+
part: string;
|
|
15
|
+
store: T | null;
|
|
16
|
+
children: Map<number, Node<T>> | null;
|
|
17
|
+
paramChild: ParamNode<T> | null;
|
|
18
|
+
wildcardStore: T | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ParamNode<T> {
|
|
22
|
+
name: string;
|
|
23
|
+
store: T | null;
|
|
24
|
+
child: Node<T> | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface RouteMatch<T> {
|
|
28
|
+
store: T;
|
|
29
|
+
params: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createNode<T>(part: string): Node<T> {
|
|
33
|
+
return {
|
|
34
|
+
part,
|
|
35
|
+
store: null,
|
|
36
|
+
children: null,
|
|
37
|
+
paramChild: null,
|
|
38
|
+
wildcardStore: null
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class RadixRouter<T> {
|
|
43
|
+
private roots: Record<string, Node<T>> = {};
|
|
44
|
+
|
|
45
|
+
add(method: string, path: string, store: T): void {
|
|
46
|
+
if (path === '') path = '/';
|
|
47
|
+
if (path[0] !== '/') path = '/' + path;
|
|
48
|
+
|
|
49
|
+
const isWildcard = path.endsWith('*');
|
|
50
|
+
|
|
51
|
+
if (isWildcard) path = path.slice(0, -1);
|
|
52
|
+
|
|
53
|
+
let node = this.roots[method];
|
|
54
|
+
|
|
55
|
+
if (!node) {
|
|
56
|
+
node = this.roots[method] = createNode('/');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let i = 0;
|
|
60
|
+
const len = path.length;
|
|
61
|
+
|
|
62
|
+
while (i < len) {
|
|
63
|
+
const char = path.charCodeAt(i);
|
|
64
|
+
|
|
65
|
+
if (char === 58) {
|
|
66
|
+
const paramStart = i + 1;
|
|
67
|
+
let paramEnd = paramStart;
|
|
68
|
+
|
|
69
|
+
while (paramEnd < len && path.charCodeAt(paramEnd) !== 47) {
|
|
70
|
+
paramEnd++;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const paramName = path.slice(paramStart, paramEnd);
|
|
74
|
+
|
|
75
|
+
if (!node.paramChild) {
|
|
76
|
+
node.paramChild = { name: paramName, store: null, child: null };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (paramEnd >= len) {
|
|
80
|
+
node.paramChild.store = store;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!node.paramChild.child) {
|
|
85
|
+
node.paramChild.child = createNode(path.slice(paramEnd));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
node = node.paramChild.child;
|
|
89
|
+
i = paramEnd;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let segmentEnd = i;
|
|
94
|
+
|
|
95
|
+
while (segmentEnd < len && path.charCodeAt(segmentEnd) !== 47 && path.charCodeAt(segmentEnd) !== 58) {
|
|
96
|
+
segmentEnd++;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (segmentEnd < len && path.charCodeAt(segmentEnd) === 47) {
|
|
100
|
+
segmentEnd++;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const segment = path.slice(i, segmentEnd);
|
|
104
|
+
|
|
105
|
+
if (segment === node.part) {
|
|
106
|
+
i = segmentEnd;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!node.children) {
|
|
111
|
+
node.children = new Map();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const firstChar = segment.charCodeAt(0);
|
|
115
|
+
let child = node.children.get(firstChar);
|
|
116
|
+
|
|
117
|
+
if (!child) {
|
|
118
|
+
child = createNode(segment);
|
|
119
|
+
node.children.set(firstChar, child);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
node = child;
|
|
123
|
+
i = segmentEnd;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (isWildcard) {
|
|
127
|
+
node.wildcardStore = store;
|
|
128
|
+
} else {
|
|
129
|
+
node.store = store;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
find(method: string, path: string): RouteMatch<T> | null {
|
|
134
|
+
const root = this.roots[method];
|
|
135
|
+
|
|
136
|
+
if (!root) return null;
|
|
137
|
+
|
|
138
|
+
return this.matchPath(root, path, 0, path.length);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private matchPath(
|
|
142
|
+
node: Node<T>,
|
|
143
|
+
path: string,
|
|
144
|
+
start: number,
|
|
145
|
+
len: number
|
|
146
|
+
): RouteMatch<T> | null {
|
|
147
|
+
const partLen = node.part.length;
|
|
148
|
+
const end = start + partLen;
|
|
149
|
+
|
|
150
|
+
if (partLen > 1) {
|
|
151
|
+
if (end > len) return null;
|
|
152
|
+
|
|
153
|
+
for (let i = 1, j = start + 1; i < partLen; i++, j++) {
|
|
154
|
+
if (node.part.charCodeAt(i) !== path.charCodeAt(j)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (end === len) {
|
|
161
|
+
if (node.store !== null) {
|
|
162
|
+
return { store: node.store, params: EMPTY_PARAMS };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (node.wildcardStore !== null) {
|
|
166
|
+
return { store: node.wildcardStore, params: { '*': '' } };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (node.children) {
|
|
173
|
+
const child = node.children.get(path.charCodeAt(end));
|
|
174
|
+
|
|
175
|
+
if (child) {
|
|
176
|
+
const result = this.matchPath(child, path, end, len);
|
|
177
|
+
|
|
178
|
+
if (result) return result;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (node.paramChild) {
|
|
183
|
+
const param = node.paramChild;
|
|
184
|
+
let paramEnd = end;
|
|
185
|
+
|
|
186
|
+
while (paramEnd < len && path.charCodeAt(paramEnd) !== 47) {
|
|
187
|
+
paramEnd++;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (paramEnd === end) return null;
|
|
191
|
+
|
|
192
|
+
const paramValue = path.slice(end, paramEnd);
|
|
193
|
+
|
|
194
|
+
if (paramEnd >= len) {
|
|
195
|
+
if (param.store !== null) {
|
|
196
|
+
return {
|
|
197
|
+
store: param.store,
|
|
198
|
+
params: { [param.name]: paramValue }
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
} else if (param.child) {
|
|
202
|
+
const result = this.matchPath(param.child, path, paramEnd, len);
|
|
203
|
+
|
|
204
|
+
if (result) {
|
|
205
|
+
if (result.params === EMPTY_PARAMS) {
|
|
206
|
+
result.params = { [param.name]: paramValue };
|
|
207
|
+
} else {
|
|
208
|
+
result.params[param.name] = paramValue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (node.wildcardStore !== null) {
|
|
217
|
+
return {
|
|
218
|
+
store: node.wildcardStore,
|
|
219
|
+
params: { '*': path.slice(end) }
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|