@devp0nt/route0 1.0.0-next.3 → 1.0.0-next.31
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/dist/cjs/index.cjs +509 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +239 -83
- package/dist/esm/index.d.ts +239 -83
- package/dist/esm/index.js +421 -71
- package/dist/esm/index.js.map +1 -1
- package/package.json +42 -16
- package/src/index.test.ts +1496 -35
- package/src/index.ts +979 -244
- package/dist/cjs/index.js +0 -158
- package/dist/cjs/index.js.map +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
class Route0 {
|
|
2
|
-
|
|
2
|
+
definition;
|
|
3
3
|
pathDefinition;
|
|
4
4
|
paramsDefinition;
|
|
5
|
-
|
|
5
|
+
searchDefinition;
|
|
6
6
|
baseUrl;
|
|
7
7
|
constructor(definition, config = {}) {
|
|
8
|
-
this.
|
|
9
|
-
this.pathDefinition = Route0.
|
|
10
|
-
this.paramsDefinition = Route0.
|
|
11
|
-
this.
|
|
8
|
+
this.definition = definition;
|
|
9
|
+
this.pathDefinition = Route0._getPathDefinitionBydefinition(definition);
|
|
10
|
+
this.paramsDefinition = Route0._getParamsDefinitionBydefinition(definition);
|
|
11
|
+
this.searchDefinition = Route0._getSearchDefinitionBydefinition(definition);
|
|
12
12
|
const { baseUrl } = config;
|
|
13
13
|
if (baseUrl && typeof baseUrl === "string" && baseUrl.length) {
|
|
14
14
|
this.baseUrl = baseUrl;
|
|
15
15
|
} else {
|
|
16
16
|
const g = globalThis;
|
|
17
|
-
if (g?.location?.origin) {
|
|
17
|
+
if (typeof g?.location?.origin === "string" && g.location.origin.length > 0) {
|
|
18
18
|
this.baseUrl = g.location.origin;
|
|
19
19
|
} else {
|
|
20
20
|
this.baseUrl = "https://example.com";
|
|
@@ -22,113 +22,463 @@ class Route0 {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
static create(definition, config) {
|
|
25
|
-
|
|
26
|
-
definition
|
|
27
|
-
|
|
28
|
-
);
|
|
25
|
+
if (typeof definition === "function") {
|
|
26
|
+
return definition;
|
|
27
|
+
}
|
|
28
|
+
const original = typeof definition === "object" ? definition : new Route0(definition, config);
|
|
29
29
|
const callable = original.get.bind(original);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (typeof value === "function") {
|
|
34
|
-
return value.bind(original);
|
|
35
|
-
}
|
|
36
|
-
return value;
|
|
37
|
-
},
|
|
38
|
-
set(_target, prop, value, receiver) {
|
|
39
|
-
;
|
|
40
|
-
original[prop] = value;
|
|
41
|
-
return true;
|
|
42
|
-
},
|
|
43
|
-
has(_target, prop) {
|
|
44
|
-
return prop in original;
|
|
45
|
-
}
|
|
30
|
+
Object.setPrototypeOf(callable, original);
|
|
31
|
+
Object.defineProperty(callable, Symbol.toStringTag, {
|
|
32
|
+
value: original.definition
|
|
46
33
|
});
|
|
47
|
-
|
|
48
|
-
return proxy;
|
|
34
|
+
return callable;
|
|
49
35
|
}
|
|
50
|
-
static
|
|
51
|
-
const i =
|
|
52
|
-
if (i === -1) return { pathDefinition:
|
|
36
|
+
static _splitPathDefinitionAndSearchTailDefinition(definition) {
|
|
37
|
+
const i = definition.indexOf("&");
|
|
38
|
+
if (i === -1) return { pathDefinition: definition, searchTailDefinition: "" };
|
|
53
39
|
return {
|
|
54
|
-
pathDefinition:
|
|
55
|
-
|
|
40
|
+
pathDefinition: definition.slice(0, i),
|
|
41
|
+
searchTailDefinition: definition.slice(i)
|
|
56
42
|
};
|
|
57
43
|
}
|
|
58
|
-
static _getAbsPath(baseUrl,
|
|
59
|
-
return new URL(
|
|
44
|
+
static _getAbsPath(baseUrl, pathWithSearch) {
|
|
45
|
+
return new URL(pathWithSearch, baseUrl).toString().replace(/\/$/, "");
|
|
60
46
|
}
|
|
61
|
-
static
|
|
62
|
-
const { pathDefinition } = Route0.
|
|
47
|
+
static _getPathDefinitionBydefinition(definition) {
|
|
48
|
+
const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition);
|
|
63
49
|
return pathDefinition;
|
|
64
50
|
}
|
|
65
|
-
static
|
|
66
|
-
const { pathDefinition } = Route0.
|
|
51
|
+
static _getParamsDefinitionBydefinition(definition) {
|
|
52
|
+
const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition);
|
|
67
53
|
const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g));
|
|
68
54
|
const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]));
|
|
55
|
+
const keysCount = Object.keys(paramsDefinition).length;
|
|
56
|
+
if (keysCount === 0) {
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
69
59
|
return paramsDefinition;
|
|
70
60
|
}
|
|
71
|
-
static
|
|
72
|
-
const {
|
|
73
|
-
if (!
|
|
74
|
-
return
|
|
61
|
+
static _getSearchDefinitionBydefinition(definition) {
|
|
62
|
+
const { searchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition);
|
|
63
|
+
if (!searchTailDefinition) {
|
|
64
|
+
return void 0;
|
|
75
65
|
}
|
|
76
|
-
const keys =
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const result = {};
|
|
82
|
-
for (const [key, value] of Object.entries(routes)) {
|
|
83
|
-
;
|
|
84
|
-
result[key] = value.clone(config);
|
|
66
|
+
const keys = searchTailDefinition.split("&").filter(Boolean);
|
|
67
|
+
const searchDefinition = Object.fromEntries(keys.map((k) => [k, true]));
|
|
68
|
+
const keysCount = Object.keys(searchDefinition).length;
|
|
69
|
+
if (keysCount === 0) {
|
|
70
|
+
return void 0;
|
|
85
71
|
}
|
|
86
|
-
return
|
|
72
|
+
return searchDefinition;
|
|
87
73
|
}
|
|
88
74
|
extend(suffixDefinition) {
|
|
89
|
-
const { pathDefinition: parentPathDefinition } = Route0.
|
|
90
|
-
|
|
91
|
-
);
|
|
92
|
-
const { pathDefinition: suffixPathDefinition, queryTailDefinition: suffixQueryTailDefinition } = Route0._splitPathDefinitionAndQueryTailDefinition(suffixDefinition);
|
|
75
|
+
const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(this.definition);
|
|
76
|
+
const { pathDefinition: suffixPathDefinition, searchTailDefinition: suffixSearchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(suffixDefinition);
|
|
93
77
|
const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\/{2,}/g, "/");
|
|
94
|
-
const
|
|
95
|
-
return Route0.create(
|
|
78
|
+
const definition = `${pathDefinition}${suffixSearchTailDefinition}`;
|
|
79
|
+
return Route0.create(definition, { baseUrl: this.baseUrl });
|
|
96
80
|
}
|
|
97
81
|
// implementation
|
|
98
82
|
get(...args) {
|
|
99
|
-
const {
|
|
83
|
+
const { searchInput, paramsInput, absInput } = (() => {
|
|
100
84
|
if (args.length === 0) {
|
|
101
|
-
return {
|
|
85
|
+
return { searchInput: {}, paramsInput: {}, absInput: false };
|
|
102
86
|
}
|
|
103
87
|
const input = args[0];
|
|
104
88
|
if (typeof input !== "object" || input === null) {
|
|
105
|
-
return {
|
|
89
|
+
return { searchInput: {}, paramsInput: {}, absInput: false };
|
|
106
90
|
}
|
|
107
|
-
const {
|
|
108
|
-
return {
|
|
91
|
+
const { search, abs, ...params } = input;
|
|
92
|
+
return { searchInput: search || {}, paramsInput: params, absInput: abs ?? false };
|
|
109
93
|
})();
|
|
110
|
-
const neededParamsKeys = Object.keys(this.paramsDefinition);
|
|
94
|
+
const neededParamsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : [];
|
|
111
95
|
const providedParamsKeys = Object.keys(paramsInput);
|
|
112
96
|
const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k));
|
|
113
97
|
if (notProvidedKeys.length) {
|
|
114
98
|
Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, "undefined"])));
|
|
115
99
|
}
|
|
116
|
-
let url =
|
|
100
|
+
let url = this.pathDefinition;
|
|
117
101
|
url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? "")));
|
|
118
|
-
const
|
|
119
|
-
url = [url, new URLSearchParams(
|
|
102
|
+
const searchInputStringified = Object.fromEntries(Object.entries(searchInput).map(([k, v]) => [k, String(v)]));
|
|
103
|
+
url = [url, new URLSearchParams(searchInputStringified).toString()].filter(Boolean).join("?");
|
|
120
104
|
url = url.replace(/\/{2,}/g, "/");
|
|
121
105
|
url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url;
|
|
122
106
|
return url;
|
|
123
107
|
}
|
|
108
|
+
// implementation
|
|
109
|
+
flat(...args) {
|
|
110
|
+
const { searchInput, paramsInput, absInput } = (() => {
|
|
111
|
+
if (args.length === 0) {
|
|
112
|
+
return { searchInput: {}, paramsInput: {}, absInput: false };
|
|
113
|
+
}
|
|
114
|
+
const input = args[0];
|
|
115
|
+
if (typeof input !== "object" || input === null) {
|
|
116
|
+
return { searchInput: {}, paramsInput: {}, absInput: args[1] ?? false };
|
|
117
|
+
}
|
|
118
|
+
const paramsKeys = this.getParamsKeys();
|
|
119
|
+
const paramsInput2 = paramsKeys.reduce((acc, key) => {
|
|
120
|
+
if (input[key] !== void 0) {
|
|
121
|
+
acc[key] = input[key];
|
|
122
|
+
}
|
|
123
|
+
return acc;
|
|
124
|
+
}, {});
|
|
125
|
+
const searchKeys = this.getSearchKeys();
|
|
126
|
+
const searchInput2 = Object.keys(input).filter((k) => {
|
|
127
|
+
if (searchKeys.includes(k)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (paramsKeys.includes(k)) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}).reduce((acc, key) => {
|
|
135
|
+
acc[key] = input[key];
|
|
136
|
+
return acc;
|
|
137
|
+
}, {});
|
|
138
|
+
return { searchInput: searchInput2, paramsInput: paramsInput2, absInput: args[1] ?? false };
|
|
139
|
+
})();
|
|
140
|
+
return this.get({ ...paramsInput, search: searchInput, abs: absInput });
|
|
141
|
+
}
|
|
142
|
+
getParamsKeys() {
|
|
143
|
+
return Object.keys(this.paramsDefinition || {});
|
|
144
|
+
}
|
|
145
|
+
getSearchKeys() {
|
|
146
|
+
return Object.keys(this.searchDefinition || {});
|
|
147
|
+
}
|
|
148
|
+
getFlatKeys() {
|
|
149
|
+
return [...this.getSearchKeys(), ...this.getParamsKeys()];
|
|
150
|
+
}
|
|
124
151
|
getDefinition() {
|
|
125
152
|
return this.pathDefinition;
|
|
126
153
|
}
|
|
127
154
|
clone(config) {
|
|
128
|
-
return new Route0(this.
|
|
155
|
+
return new Route0(this.definition, config);
|
|
156
|
+
}
|
|
157
|
+
getRegexString() {
|
|
158
|
+
const pattern = this.pathDefinition.replace(/\/+$/, "").replace(/:(\w+)/g, "___PARAM___").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/___PARAM___/g, "([^/]+)");
|
|
159
|
+
return pattern || "/";
|
|
160
|
+
}
|
|
161
|
+
getRegex() {
|
|
162
|
+
const inner = this.getRegexString();
|
|
163
|
+
if (inner === "/") return /^\/?$/;
|
|
164
|
+
return new RegExp(`^${inner}/?$`);
|
|
165
|
+
}
|
|
166
|
+
static getRegexStringGroup(routes) {
|
|
167
|
+
return routes.map((route) => route.getRegexString()).join("|");
|
|
168
|
+
}
|
|
169
|
+
static getRegexGroup(routes) {
|
|
170
|
+
const patterns = routes.map((route) => {
|
|
171
|
+
const inner = route.getRegexString();
|
|
172
|
+
if (inner === "/") return "/?";
|
|
173
|
+
return `${inner}/?`;
|
|
174
|
+
});
|
|
175
|
+
return new RegExp(`^(${patterns.join("|")})$`);
|
|
176
|
+
}
|
|
177
|
+
static getLocation(hrefOrHrefRelOrLocation) {
|
|
178
|
+
if (hrefOrHrefRelOrLocation instanceof URL) {
|
|
179
|
+
return Route0.getLocation(hrefOrHrefRelOrLocation.href);
|
|
180
|
+
}
|
|
181
|
+
if (typeof hrefOrHrefRelOrLocation !== "string") {
|
|
182
|
+
hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel;
|
|
183
|
+
}
|
|
184
|
+
const abs = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(hrefOrHrefRelOrLocation);
|
|
185
|
+
const base = abs ? void 0 : "http://example.com";
|
|
186
|
+
const url = new URL(hrefOrHrefRelOrLocation, base);
|
|
187
|
+
const searchParams = Object.fromEntries(url.searchParams.entries());
|
|
188
|
+
let pathname = url.pathname;
|
|
189
|
+
if (pathname.length > 1 && pathname.endsWith("/")) {
|
|
190
|
+
pathname = pathname.slice(0, -1);
|
|
191
|
+
}
|
|
192
|
+
const hrefRel = pathname + url.search + url.hash;
|
|
193
|
+
const location = {
|
|
194
|
+
pathname,
|
|
195
|
+
search: url.search,
|
|
196
|
+
hash: url.hash,
|
|
197
|
+
origin: abs ? url.origin : void 0,
|
|
198
|
+
href: abs ? url.href : void 0,
|
|
199
|
+
hrefRel,
|
|
200
|
+
abs,
|
|
201
|
+
// extra host-related fields (available even for relative with dummy base)
|
|
202
|
+
host: abs ? url.host : void 0,
|
|
203
|
+
hostname: abs ? url.hostname : void 0,
|
|
204
|
+
port: abs ? url.port || void 0 : void 0,
|
|
205
|
+
// specific to UnknownLocation
|
|
206
|
+
searchParams,
|
|
207
|
+
params: void 0,
|
|
208
|
+
route: void 0,
|
|
209
|
+
exact: false,
|
|
210
|
+
parent: false,
|
|
211
|
+
children: false
|
|
212
|
+
};
|
|
213
|
+
return location;
|
|
214
|
+
}
|
|
215
|
+
getLocation(hrefOrHrefRelOrLocation) {
|
|
216
|
+
if (hrefOrHrefRelOrLocation instanceof URL) {
|
|
217
|
+
return this.getLocation(hrefOrHrefRelOrLocation.href);
|
|
218
|
+
}
|
|
219
|
+
if (typeof hrefOrHrefRelOrLocation !== "string") {
|
|
220
|
+
hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel;
|
|
221
|
+
}
|
|
222
|
+
const location = Route0.getLocation(hrefOrHrefRelOrLocation);
|
|
223
|
+
location.route = this.definition;
|
|
224
|
+
location.params = {};
|
|
225
|
+
const pathname = location.pathname.length > 1 && location.pathname.endsWith("/") ? location.pathname.slice(0, -1) : location.pathname;
|
|
226
|
+
const pattern = this.getRegexString();
|
|
227
|
+
const paramNames = [];
|
|
228
|
+
const def = this.pathDefinition.length > 1 && this.pathDefinition.endsWith("/") ? this.pathDefinition.slice(0, -1) : this.pathDefinition;
|
|
229
|
+
def.replace(/:([A-Za-z0-9_]+)/g, (_m, name) => {
|
|
230
|
+
paramNames.push(String(name));
|
|
231
|
+
return "";
|
|
232
|
+
});
|
|
233
|
+
const exactRe = new RegExp(`^${pattern}$`);
|
|
234
|
+
const parentRe = new RegExp(`^${pattern}(?:/.*)?$`);
|
|
235
|
+
const exactMatch = pathname.match(exactRe);
|
|
236
|
+
if (exactMatch) {
|
|
237
|
+
const values = exactMatch.slice(1);
|
|
238
|
+
const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? "")]));
|
|
239
|
+
location.params = params;
|
|
240
|
+
} else {
|
|
241
|
+
location.params = {};
|
|
242
|
+
}
|
|
243
|
+
const exact = !!exactMatch;
|
|
244
|
+
const parent = !exact && parentRe.test(pathname);
|
|
245
|
+
const getParts = (path) => path === "/" ? ["/"] : path.split("/").filter(Boolean);
|
|
246
|
+
const defParts = getParts(def);
|
|
247
|
+
const pathParts = getParts(pathname);
|
|
248
|
+
let isPrefix = true;
|
|
249
|
+
if (pathParts.length > defParts.length) {
|
|
250
|
+
isPrefix = false;
|
|
251
|
+
} else {
|
|
252
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
253
|
+
const defPart = defParts[i];
|
|
254
|
+
const pathPart = pathParts[i];
|
|
255
|
+
if (!defPart) {
|
|
256
|
+
isPrefix = false;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
if (defPart.startsWith(":")) continue;
|
|
260
|
+
if (defPart !== pathPart) {
|
|
261
|
+
isPrefix = false;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const children = !exact && isPrefix;
|
|
267
|
+
return {
|
|
268
|
+
...location,
|
|
269
|
+
exact,
|
|
270
|
+
parent,
|
|
271
|
+
children
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
isSame(other) {
|
|
275
|
+
return this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "__PARAM__") === other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "__PARAM__");
|
|
276
|
+
}
|
|
277
|
+
static isSame(a, b) {
|
|
278
|
+
if (!a) {
|
|
279
|
+
if (!b) return true;
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (!b) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
return Route0.create(a).isSame(Route0.create(b));
|
|
286
|
+
}
|
|
287
|
+
isChildren(other) {
|
|
288
|
+
if (!other) return false;
|
|
289
|
+
other = Route0.create(other);
|
|
290
|
+
const getParts = (path) => path === "/" ? ["/"] : path.split("/").filter(Boolean);
|
|
291
|
+
if (other.pathDefinition === "/" && this.pathDefinition !== "/") {
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
const thisParts = getParts(this.pathDefinition);
|
|
295
|
+
const otherParts = getParts(other.pathDefinition);
|
|
296
|
+
if (thisParts.length <= otherParts.length) return false;
|
|
297
|
+
for (let i = 0; i < otherParts.length; i++) {
|
|
298
|
+
const otherPart = otherParts[i];
|
|
299
|
+
const thisPart = thisParts[i];
|
|
300
|
+
if (otherPart.startsWith(":")) continue;
|
|
301
|
+
if (otherPart !== thisPart) return false;
|
|
302
|
+
}
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
isParent(other) {
|
|
306
|
+
if (!other) return false;
|
|
307
|
+
other = Route0.create(other);
|
|
308
|
+
const getParts = (path) => path === "/" ? ["/"] : path.split("/").filter(Boolean);
|
|
309
|
+
if (this.pathDefinition === "/" && other.pathDefinition !== "/") {
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
const thisParts = getParts(this.pathDefinition);
|
|
313
|
+
const otherParts = getParts(other.pathDefinition);
|
|
314
|
+
if (thisParts.length >= otherParts.length) return false;
|
|
315
|
+
for (let i = 0; i < thisParts.length; i++) {
|
|
316
|
+
const thisPart = thisParts[i];
|
|
317
|
+
const otherPart = otherParts[i];
|
|
318
|
+
if (thisPart.startsWith(":")) continue;
|
|
319
|
+
if (thisPart !== otherPart) return false;
|
|
320
|
+
}
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
isConflict(other) {
|
|
324
|
+
if (!other) return false;
|
|
325
|
+
other = Route0.create(other);
|
|
326
|
+
const getParts = (path) => {
|
|
327
|
+
if (path === "/") return ["/"];
|
|
328
|
+
return path.split("/").filter(Boolean);
|
|
329
|
+
};
|
|
330
|
+
const thisParts = getParts(this.pathDefinition);
|
|
331
|
+
const otherParts = getParts(other.pathDefinition);
|
|
332
|
+
if (thisParts.length !== otherParts.length) {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
for (let i = 0; i < thisParts.length; i++) {
|
|
336
|
+
const thisPart = thisParts[i];
|
|
337
|
+
const otherPart = otherParts[i];
|
|
338
|
+
if (thisPart.startsWith(":") && otherPart.startsWith(":")) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (thisPart.startsWith(":") || otherPart.startsWith(":")) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (thisPart !== otherPart) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
isMoreSpecificThan(other) {
|
|
351
|
+
if (!other) return false;
|
|
352
|
+
other = Route0.create(other);
|
|
353
|
+
const getParts = (path) => {
|
|
354
|
+
if (path === "/") return ["/"];
|
|
355
|
+
return path.split("/").filter(Boolean);
|
|
356
|
+
};
|
|
357
|
+
const thisParts = getParts(this.pathDefinition);
|
|
358
|
+
const otherParts = getParts(other.pathDefinition);
|
|
359
|
+
for (let i = 0; i < Math.min(thisParts.length, otherParts.length); i++) {
|
|
360
|
+
const thisIsStatic = !thisParts[i].startsWith(":");
|
|
361
|
+
const otherIsStatic = !otherParts[i].startsWith(":");
|
|
362
|
+
if (thisIsStatic && !otherIsStatic) return true;
|
|
363
|
+
if (!thisIsStatic && otherIsStatic) return false;
|
|
364
|
+
}
|
|
365
|
+
return this.pathDefinition < other.pathDefinition;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
class Routes {
|
|
369
|
+
routes;
|
|
370
|
+
pathsOrdering;
|
|
371
|
+
keysOrdering;
|
|
372
|
+
ordered;
|
|
373
|
+
_;
|
|
374
|
+
constructor({
|
|
375
|
+
routes,
|
|
376
|
+
isHydrated = false,
|
|
377
|
+
pathsOrdering,
|
|
378
|
+
keysOrdering,
|
|
379
|
+
ordered
|
|
380
|
+
}) {
|
|
381
|
+
this.routes = isHydrated ? routes : Routes.hydrate(routes);
|
|
382
|
+
if (!pathsOrdering || !keysOrdering || !ordered) {
|
|
383
|
+
const ordering = Routes.makeOrdering(this.routes);
|
|
384
|
+
this.pathsOrdering = ordering.pathsOrdering;
|
|
385
|
+
this.keysOrdering = ordering.keysOrdering;
|
|
386
|
+
this.ordered = this.keysOrdering.map((key) => this.routes[key]);
|
|
387
|
+
} else {
|
|
388
|
+
this.pathsOrdering = pathsOrdering;
|
|
389
|
+
this.keysOrdering = keysOrdering;
|
|
390
|
+
this.ordered = ordered;
|
|
391
|
+
}
|
|
392
|
+
this._ = {
|
|
393
|
+
getLocation: this.getLocation.bind(this),
|
|
394
|
+
override: this.override.bind(this),
|
|
395
|
+
pathsOrdering: this.pathsOrdering,
|
|
396
|
+
keysOrdering: this.keysOrdering,
|
|
397
|
+
ordered: this.ordered
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
static create(routes) {
|
|
401
|
+
const instance = new Routes({ routes });
|
|
402
|
+
return Routes.prettify(instance);
|
|
403
|
+
}
|
|
404
|
+
static prettify(instance) {
|
|
405
|
+
Object.setPrototypeOf(instance, Routes.prototype);
|
|
406
|
+
Object.defineProperty(instance, Symbol.toStringTag, {
|
|
407
|
+
value: "Routes"
|
|
408
|
+
});
|
|
409
|
+
Object.assign(instance, {
|
|
410
|
+
override: instance.override.bind(instance)
|
|
411
|
+
});
|
|
412
|
+
Object.assign(instance, instance.routes);
|
|
413
|
+
return instance;
|
|
414
|
+
}
|
|
415
|
+
static hydrate(routes) {
|
|
416
|
+
const result = {};
|
|
417
|
+
for (const key in routes) {
|
|
418
|
+
if (Object.prototype.hasOwnProperty.call(routes, key)) {
|
|
419
|
+
const value = routes[key];
|
|
420
|
+
result[key] = typeof value === "string" ? Route0.create(value) : value;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
getLocation(hrefOrHrefRelOrLocation) {
|
|
426
|
+
const input = hrefOrHrefRelOrLocation;
|
|
427
|
+
for (const route of this.ordered) {
|
|
428
|
+
const loc = route.getLocation(hrefOrHrefRelOrLocation);
|
|
429
|
+
if (loc.exact) {
|
|
430
|
+
return loc;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return typeof input === "string" ? Route0.getLocation(input) : Route0.getLocation(input);
|
|
434
|
+
}
|
|
435
|
+
static makeOrdering(routes) {
|
|
436
|
+
const hydrated = Routes.hydrate(routes);
|
|
437
|
+
const entries = Object.entries(hydrated);
|
|
438
|
+
const getParts = (path) => {
|
|
439
|
+
if (path === "/") return ["/"];
|
|
440
|
+
return path.split("/").filter(Boolean);
|
|
441
|
+
};
|
|
442
|
+
entries.sort(([_keyA, routeA], [_keyB, routeB]) => {
|
|
443
|
+
const partsA = getParts(routeA.pathDefinition);
|
|
444
|
+
const partsB = getParts(routeB.pathDefinition);
|
|
445
|
+
if (partsA.length !== partsB.length) {
|
|
446
|
+
return partsA.length - partsB.length;
|
|
447
|
+
}
|
|
448
|
+
if (routeA.isConflict(routeB)) {
|
|
449
|
+
if (routeA.isMoreSpecificThan(routeB)) return -1;
|
|
450
|
+
if (routeB.isMoreSpecificThan(routeA)) return 1;
|
|
451
|
+
}
|
|
452
|
+
return routeA.pathDefinition.localeCompare(routeB.pathDefinition);
|
|
453
|
+
});
|
|
454
|
+
const pathsOrdering = entries.map(([_key, route]) => route.definition);
|
|
455
|
+
const keysOrdering = entries.map(([_key, route]) => _key);
|
|
456
|
+
return { pathsOrdering, keysOrdering };
|
|
457
|
+
}
|
|
458
|
+
override(config) {
|
|
459
|
+
const newRoutes = {};
|
|
460
|
+
for (const key in this.routes) {
|
|
461
|
+
if (Object.prototype.hasOwnProperty.call(this.routes, key)) {
|
|
462
|
+
newRoutes[key] = this.routes[key].clone(config);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const instance = new Routes({
|
|
466
|
+
routes: newRoutes,
|
|
467
|
+
isHydrated: true,
|
|
468
|
+
pathsOrdering: this.pathsOrdering,
|
|
469
|
+
keysOrdering: this.keysOrdering,
|
|
470
|
+
ordered: this.keysOrdering.map((key) => newRoutes[key])
|
|
471
|
+
});
|
|
472
|
+
return Routes.prettify(instance);
|
|
129
473
|
}
|
|
474
|
+
static _ = {
|
|
475
|
+
prettify: Routes.prettify.bind(Routes),
|
|
476
|
+
hydrate: Routes.hydrate.bind(Routes),
|
|
477
|
+
makeOrdering: Routes.makeOrdering.bind(Routes)
|
|
478
|
+
};
|
|
130
479
|
}
|
|
131
480
|
export {
|
|
132
|
-
Route0
|
|
481
|
+
Route0,
|
|
482
|
+
Routes
|
|
133
483
|
};
|
|
134
484
|
//# sourceMappingURL=index.js.map
|