-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRouter.ts
101 lines (79 loc) · 2.71 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
import type { RouteParametersWithQuery } from "@/types/Route.types";
import {
type RouterConfiguration, RouterConfigurationFromJson, RouterConfigurationFromJsonSchema
} from "@/types/Router.types";
import { ensureNoTrailingSlash, isString } from "@/helpers/utils";
import { Route } from "@/classes/Route";
import { stringify } from "qs";
const defaultQsConfig = () => ({
addQueryPrefix: true,
encoder: (value: unknown, defaultEncoder: CallableFunction, _charset: string, type: string) => {
if ((type === 'value') && typeof value === 'boolean')
return value ? 1 : 0;
return defaultEncoder(value);
},
encodeValuesOnly: true,
skipNulls: true,
});
export const defaultConfig = () => ({
absolute: false,
strict: false,
qsConfig: defaultQsConfig(),
base: '/',
defaults: {},
routes: {},
});
const parseRouterConfig = (config: string): RouterConfigurationFromJson => {
return RouterConfigurationFromJsonSchema.parse(JSON.parse(config));
};
/**
* @classdesc Routing helper.
*/
export class Router {
#config: RouterConfiguration = defaultConfig();
constructor(config?: string | Partial<RouterConfiguration>) {
this.config = config ?? {};
}
get config(): RouterConfiguration {
return this.#config;
}
set config(value: string | Partial<RouterConfiguration>) {
value = isString(value) ? parseRouterConfig(value) : value;
this.#config = {
...this.#config,
...value,
qsConfig: {
...defaultQsConfig(),
... (value?.qsConfig ?? {}),
},
};
}
get base(): string {
return ensureNoTrailingSlash(this.#config.base);
}
get origin(): string {
return this.#config.absolute ? this.base : '';
}
has(name: string): boolean {
return Object.hasOwn(this.#config.routes, name);
}
compile(name: string, params: RouteParametersWithQuery): string {
const route = this.getRoute(name);
const { substituted, url } = route.compile(params);
const query = params._query ?? {};
delete params._query;
for (const key of Object.keys(params)) {
if (substituted.includes(key))
continue;
if (Object.hasOwn(query, key))
console.warn(`Duplicate "${key}" in params and params.query may cause issues`);
query[key] = params[key];
}
return url + stringify(query, this.#config.qsConfig);
}
getRoute(name: string): Route {
if (!this.has(name))
throw new Error(`No such route "${name}" in the route list`);
return new Route(name, this.#config.routes[name], this)
}
}