@devp0nt/route0 1.0.0-next.19 → 1.0.0-next.20
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 +224 -92
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +208 -119
- package/dist/esm/index.d.ts +208 -119
- package/dist/esm/index.js +222 -91
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.test.ts +705 -65
- package/src/index.ts +664 -320
package/dist/cjs/index.cjs
CHANGED
|
@@ -18,26 +18,27 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var index_exports = {};
|
|
20
20
|
__export(index_exports, {
|
|
21
|
-
Route0: () => Route0
|
|
21
|
+
Route0: () => Route0,
|
|
22
|
+
Routes: () => Routes
|
|
22
23
|
});
|
|
23
24
|
module.exports = __toCommonJS(index_exports);
|
|
24
25
|
class Route0 {
|
|
25
|
-
|
|
26
|
+
pathOriginal;
|
|
26
27
|
pathDefinition;
|
|
27
28
|
paramsDefinition;
|
|
28
|
-
|
|
29
|
+
searchDefinition;
|
|
29
30
|
baseUrl;
|
|
30
31
|
constructor(definition, config = {}) {
|
|
31
|
-
this.
|
|
32
|
-
this.pathDefinition = Route0.
|
|
33
|
-
this.paramsDefinition = Route0.
|
|
34
|
-
this.
|
|
32
|
+
this.pathOriginal = definition;
|
|
33
|
+
this.pathDefinition = Route0._getPathDefinitionByPathOriginal(definition);
|
|
34
|
+
this.paramsDefinition = Route0._getParamsDefinitionByPathOriginal(definition);
|
|
35
|
+
this.searchDefinition = Route0._getSearchDefinitionByPathOriginal(definition);
|
|
35
36
|
const { baseUrl } = config;
|
|
36
37
|
if (baseUrl && typeof baseUrl === "string" && baseUrl.length) {
|
|
37
38
|
this.baseUrl = baseUrl;
|
|
38
39
|
} else {
|
|
39
40
|
const g = globalThis;
|
|
40
|
-
if (g?.location?.origin) {
|
|
41
|
+
if (typeof g?.location?.origin === "string" && g.location.origin.length > 0) {
|
|
41
42
|
this.baseUrl = g.location.origin;
|
|
42
43
|
} else {
|
|
43
44
|
this.baseUrl = "https://example.com";
|
|
@@ -45,137 +46,153 @@ class Route0 {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
static create(definition, config) {
|
|
48
|
-
const original = new Route0(
|
|
49
|
-
definition,
|
|
50
|
-
config
|
|
51
|
-
);
|
|
49
|
+
const original = new Route0(definition, config);
|
|
52
50
|
const callable = original.get.bind(original);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (typeof value === "function") {
|
|
57
|
-
return value.bind(original);
|
|
58
|
-
}
|
|
59
|
-
return value;
|
|
60
|
-
},
|
|
61
|
-
set(_target, prop, value, receiver) {
|
|
62
|
-
;
|
|
63
|
-
original[prop] = value;
|
|
64
|
-
return true;
|
|
65
|
-
},
|
|
66
|
-
has(_target, prop) {
|
|
67
|
-
return prop in original;
|
|
68
|
-
}
|
|
51
|
+
Object.setPrototypeOf(callable, original);
|
|
52
|
+
Object.defineProperty(callable, Symbol.toStringTag, {
|
|
53
|
+
value: original.pathOriginal
|
|
69
54
|
});
|
|
70
|
-
|
|
71
|
-
return proxy;
|
|
55
|
+
return callable;
|
|
72
56
|
}
|
|
73
|
-
static
|
|
74
|
-
const i =
|
|
75
|
-
if (i === -1) return { pathDefinition:
|
|
57
|
+
static _splitPathDefinitionAndSearchTailDefinition(pathOriginal) {
|
|
58
|
+
const i = pathOriginal.indexOf("&");
|
|
59
|
+
if (i === -1) return { pathDefinition: pathOriginal, searchTailDefinition: "" };
|
|
76
60
|
return {
|
|
77
|
-
pathDefinition:
|
|
78
|
-
|
|
61
|
+
pathDefinition: pathOriginal.slice(0, i),
|
|
62
|
+
searchTailDefinition: pathOriginal.slice(i)
|
|
79
63
|
};
|
|
80
64
|
}
|
|
81
|
-
static _getAbsPath(baseUrl,
|
|
82
|
-
return new URL(
|
|
65
|
+
static _getAbsPath(baseUrl, pathWithSearch) {
|
|
66
|
+
return new URL(pathWithSearch, baseUrl).toString().replace(/\/$/, "");
|
|
83
67
|
}
|
|
84
|
-
static
|
|
85
|
-
const { pathDefinition } = Route0.
|
|
68
|
+
static _getPathDefinitionByPathOriginal(pathOriginal) {
|
|
69
|
+
const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal);
|
|
86
70
|
return pathDefinition;
|
|
87
71
|
}
|
|
88
|
-
static
|
|
89
|
-
const { pathDefinition } = Route0.
|
|
72
|
+
static _getParamsDefinitionByPathOriginal(pathOriginal) {
|
|
73
|
+
const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal);
|
|
90
74
|
const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g));
|
|
91
75
|
const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]));
|
|
92
76
|
return paramsDefinition;
|
|
93
77
|
}
|
|
94
|
-
static
|
|
95
|
-
const {
|
|
96
|
-
if (!
|
|
78
|
+
static _getSearchDefinitionByPathOriginal(pathOriginal) {
|
|
79
|
+
const { searchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal);
|
|
80
|
+
if (!searchTailDefinition) {
|
|
97
81
|
return {};
|
|
98
82
|
}
|
|
99
|
-
const keys =
|
|
100
|
-
const
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
static overrideMany(routes, config) {
|
|
104
|
-
const result = {};
|
|
105
|
-
for (const [key, value] of Object.entries(routes)) {
|
|
106
|
-
;
|
|
107
|
-
result[key] = value.clone(config);
|
|
108
|
-
}
|
|
109
|
-
return result;
|
|
83
|
+
const keys = searchTailDefinition.split("&").map(Boolean);
|
|
84
|
+
const searchDefinition = Object.fromEntries(keys.map((k) => [k, true]));
|
|
85
|
+
return searchDefinition;
|
|
110
86
|
}
|
|
111
87
|
extend(suffixDefinition) {
|
|
112
|
-
const { pathDefinition: parentPathDefinition } = Route0.
|
|
113
|
-
this.
|
|
88
|
+
const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(
|
|
89
|
+
this.pathOriginal
|
|
114
90
|
);
|
|
115
|
-
const { pathDefinition: suffixPathDefinition,
|
|
91
|
+
const { pathDefinition: suffixPathDefinition, searchTailDefinition: suffixSearchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(suffixDefinition);
|
|
116
92
|
const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\/{2,}/g, "/");
|
|
117
|
-
const
|
|
118
|
-
return Route0.create(
|
|
93
|
+
const pathOriginal = `${pathDefinition}${suffixSearchTailDefinition}`;
|
|
94
|
+
return Route0.create(pathOriginal, { baseUrl: this.baseUrl });
|
|
119
95
|
}
|
|
120
96
|
// implementation
|
|
121
97
|
get(...args) {
|
|
122
|
-
const {
|
|
98
|
+
const { searchInput, paramsInput, absInput } = (() => {
|
|
123
99
|
if (args.length === 0) {
|
|
124
|
-
return {
|
|
100
|
+
return { searchInput: {}, paramsInput: {}, absInput: false };
|
|
125
101
|
}
|
|
126
102
|
const input = args[0];
|
|
127
103
|
if (typeof input !== "object" || input === null) {
|
|
128
|
-
return {
|
|
104
|
+
return { searchInput: {}, paramsInput: {}, absInput: false };
|
|
129
105
|
}
|
|
130
|
-
const {
|
|
131
|
-
return {
|
|
106
|
+
const { search, abs, ...params } = input;
|
|
107
|
+
return { searchInput: search || {}, paramsInput: params, absInput: abs ?? false };
|
|
132
108
|
})();
|
|
133
|
-
const neededParamsKeys = Object.keys(this.paramsDefinition);
|
|
109
|
+
const neededParamsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : [];
|
|
134
110
|
const providedParamsKeys = Object.keys(paramsInput);
|
|
135
111
|
const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k));
|
|
136
112
|
if (notProvidedKeys.length) {
|
|
137
113
|
Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, "undefined"])));
|
|
138
114
|
}
|
|
139
|
-
let url =
|
|
115
|
+
let url = this.pathDefinition;
|
|
140
116
|
url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? "")));
|
|
141
|
-
const
|
|
142
|
-
url = [url, new URLSearchParams(
|
|
117
|
+
const searchInputStringified = Object.fromEntries(Object.entries(searchInput).map(([k, v]) => [k, String(v)]));
|
|
118
|
+
url = [url, new URLSearchParams(searchInputStringified).toString()].filter(Boolean).join("?");
|
|
143
119
|
url = url.replace(/\/{2,}/g, "/");
|
|
144
120
|
url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url;
|
|
145
121
|
return url;
|
|
146
122
|
}
|
|
123
|
+
// implementation
|
|
124
|
+
flat(...args) {
|
|
125
|
+
const { searchInput, paramsInput, absInput } = (() => {
|
|
126
|
+
if (args.length === 0) {
|
|
127
|
+
return { searchInput: {}, paramsInput: {}, absInput: false };
|
|
128
|
+
}
|
|
129
|
+
const input = args[0];
|
|
130
|
+
if (typeof input !== "object" || input === null) {
|
|
131
|
+
return { searchInput: {}, paramsInput: {}, absInput: args[1] ?? false };
|
|
132
|
+
}
|
|
133
|
+
const paramsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : [];
|
|
134
|
+
const paramsInput2 = paramsKeys.reduce((acc, key) => {
|
|
135
|
+
if (input[key] !== void 0) {
|
|
136
|
+
acc[key] = input[key];
|
|
137
|
+
}
|
|
138
|
+
return acc;
|
|
139
|
+
}, {});
|
|
140
|
+
const searchInput2 = Object.keys(input).filter((k) => !paramsKeys.includes(k)).reduce((acc, key) => {
|
|
141
|
+
acc[key] = input[key];
|
|
142
|
+
return acc;
|
|
143
|
+
}, {});
|
|
144
|
+
return { searchInput: searchInput2, paramsInput: paramsInput2, absInput: args[1] ?? false };
|
|
145
|
+
})();
|
|
146
|
+
return this.get({ ...paramsInput, search: searchInput, abs: absInput });
|
|
147
|
+
}
|
|
147
148
|
getDefinition() {
|
|
148
149
|
return this.pathDefinition;
|
|
149
150
|
}
|
|
150
151
|
clone(config) {
|
|
151
|
-
return new Route0(this.
|
|
152
|
+
return new Route0(this.pathOriginal, config);
|
|
152
153
|
}
|
|
153
|
-
static getLocation(
|
|
154
|
-
|
|
154
|
+
static getLocation(hrefOrHrefRelOrLocation) {
|
|
155
|
+
if (typeof hrefOrHrefRelOrLocation !== "string") {
|
|
156
|
+
hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel;
|
|
157
|
+
}
|
|
158
|
+
const abs = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(hrefOrHrefRelOrLocation);
|
|
155
159
|
const base = abs ? void 0 : "http://example.com";
|
|
156
|
-
const url = new URL(
|
|
157
|
-
const
|
|
160
|
+
const url = new URL(hrefOrHrefRelOrLocation, base);
|
|
161
|
+
const searchParams = Object.fromEntries(url.searchParams.entries());
|
|
158
162
|
let pathname = url.pathname;
|
|
159
163
|
if (pathname.length > 1 && pathname.endsWith("/")) {
|
|
160
164
|
pathname = pathname.slice(0, -1);
|
|
161
165
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
params: {},
|
|
165
|
-
// filled later by .parse()
|
|
166
|
+
const hrefRel = pathname + url.search + url.hash;
|
|
167
|
+
const location = {
|
|
166
168
|
pathname,
|
|
167
169
|
search: url.search,
|
|
168
170
|
hash: url.hash,
|
|
169
171
|
origin: abs ? url.origin : void 0,
|
|
170
|
-
href: abs ? url.href :
|
|
171
|
-
|
|
172
|
+
href: abs ? url.href : void 0,
|
|
173
|
+
hrefRel,
|
|
174
|
+
abs,
|
|
175
|
+
// extra host-related fields (available even for relative with dummy base)
|
|
176
|
+
host: abs ? url.host : void 0,
|
|
177
|
+
hostname: abs ? url.hostname : void 0,
|
|
178
|
+
port: abs ? url.port || void 0 : void 0,
|
|
179
|
+
// specific to LocationUnknown
|
|
180
|
+
searchParams,
|
|
181
|
+
params: void 0,
|
|
182
|
+
route: void 0,
|
|
183
|
+
exact: false,
|
|
184
|
+
parent: false,
|
|
185
|
+
children: false
|
|
172
186
|
};
|
|
187
|
+
return location;
|
|
173
188
|
}
|
|
174
|
-
|
|
175
|
-
const
|
|
189
|
+
getLocation(hrefOrHrefRelOrLocation) {
|
|
190
|
+
const location = Route0.getLocation(hrefOrHrefRelOrLocation);
|
|
191
|
+
location.route = this.pathOriginal;
|
|
192
|
+
location.params = {};
|
|
176
193
|
const escapeRegex = (s) => s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
177
|
-
const def =
|
|
178
|
-
const pathname =
|
|
194
|
+
const def = this.pathDefinition.length > 1 && this.pathDefinition.endsWith("/") ? this.pathDefinition.slice(0, -1) : this.pathDefinition;
|
|
195
|
+
const pathname = location.pathname.length > 1 && location.pathname.endsWith("/") ? location.pathname.slice(0, -1) : location.pathname;
|
|
179
196
|
const paramNames = [];
|
|
180
197
|
const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m, name) => {
|
|
181
198
|
paramNames.push(String(name));
|
|
@@ -187,27 +204,142 @@ class Route0 {
|
|
|
187
204
|
if (exactMatch) {
|
|
188
205
|
const values = exactMatch.slice(1);
|
|
189
206
|
const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? "")]));
|
|
190
|
-
|
|
207
|
+
location.params = params;
|
|
191
208
|
} else {
|
|
192
|
-
|
|
209
|
+
location.params = {};
|
|
193
210
|
}
|
|
194
211
|
const exact = !!exactMatch;
|
|
195
212
|
const parent = !exact && parentRe.test(pathname);
|
|
196
213
|
const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def);
|
|
197
214
|
return {
|
|
215
|
+
...location,
|
|
198
216
|
exact,
|
|
199
217
|
parent,
|
|
200
|
-
children
|
|
201
|
-
location: locationCloned
|
|
218
|
+
children
|
|
202
219
|
};
|
|
203
220
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
221
|
+
isSame(other) {
|
|
222
|
+
return this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "") === other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "");
|
|
223
|
+
}
|
|
224
|
+
isChildren(other) {
|
|
225
|
+
return this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "") === other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "");
|
|
226
|
+
}
|
|
227
|
+
isParent(other) {
|
|
228
|
+
return other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "") === this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "");
|
|
229
|
+
}
|
|
230
|
+
isConflict(other) {
|
|
231
|
+
const getParts = (path) => {
|
|
232
|
+
if (path === "/") return ["/"];
|
|
233
|
+
return path.split("/").filter(Boolean);
|
|
234
|
+
};
|
|
235
|
+
const thisParts = getParts(this.pathDefinition);
|
|
236
|
+
const otherParts = getParts(other.pathDefinition);
|
|
237
|
+
if (thisParts.length !== otherParts.length) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
for (let i = 0; i < thisParts.length; i++) {
|
|
241
|
+
const thisPart = thisParts[i];
|
|
242
|
+
const otherPart = otherParts[i];
|
|
243
|
+
if (thisPart.startsWith(":") && otherPart.startsWith(":")) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (thisPart.startsWith(":") || otherPart.startsWith(":")) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (thisPart !== otherPart) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
isMoreSpecificThan(other) {
|
|
256
|
+
const getParts = (path) => {
|
|
257
|
+
if (path === "/") return ["/"];
|
|
258
|
+
return path.split("/").filter(Boolean);
|
|
259
|
+
};
|
|
260
|
+
const thisParts = getParts(this.pathDefinition);
|
|
261
|
+
const otherParts = getParts(other.pathDefinition);
|
|
262
|
+
for (let i = 0; i < Math.min(thisParts.length, otherParts.length); i++) {
|
|
263
|
+
const thisIsStatic = !thisParts[i].startsWith(":");
|
|
264
|
+
const otherIsStatic = !otherParts[i].startsWith(":");
|
|
265
|
+
if (thisIsStatic && !otherIsStatic) return true;
|
|
266
|
+
if (!thisIsStatic && otherIsStatic) return false;
|
|
267
|
+
}
|
|
268
|
+
return this.pathDefinition < other.pathDefinition;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
class Routes {
|
|
272
|
+
routes;
|
|
273
|
+
ordering;
|
|
274
|
+
constructor(routes, ordering, isHydrated) {
|
|
275
|
+
if (isHydrated) {
|
|
276
|
+
this.routes = routes;
|
|
277
|
+
this.ordering = ordering ?? Routes._makeOrdering(routes);
|
|
278
|
+
} else {
|
|
279
|
+
this.ordering = ordering ?? Routes._makeOrdering(routes);
|
|
280
|
+
this.routes = Routes._hydrate(routes);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
static create(routes) {
|
|
284
|
+
const instance = new Routes(routes);
|
|
285
|
+
return Routes._prettify(instance);
|
|
286
|
+
}
|
|
287
|
+
static _prettify(instance) {
|
|
288
|
+
Object.setPrototypeOf(instance, Routes.prototype);
|
|
289
|
+
Object.defineProperty(instance, Symbol.toStringTag, {
|
|
290
|
+
value: "Routes"
|
|
291
|
+
});
|
|
292
|
+
Object.assign(instance, {
|
|
293
|
+
override: instance.override.bind(instance)
|
|
294
|
+
});
|
|
295
|
+
Object.assign(instance, instance.routes);
|
|
296
|
+
return instance;
|
|
297
|
+
}
|
|
298
|
+
static _hydrate(routes) {
|
|
299
|
+
const result = {};
|
|
300
|
+
for (const key in routes) {
|
|
301
|
+
if (Object.prototype.hasOwnProperty.call(routes, key)) {
|
|
302
|
+
const value = routes[key];
|
|
303
|
+
result[key] = typeof value === "string" ? Route0.create(value) : value;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
static _makeOrdering(routes) {
|
|
309
|
+
const hydrated = Routes._hydrate(routes);
|
|
310
|
+
const entries = Object.entries(hydrated);
|
|
311
|
+
const getParts = (path) => {
|
|
312
|
+
if (path === "/") return ["/"];
|
|
313
|
+
return path.split("/").filter(Boolean);
|
|
314
|
+
};
|
|
315
|
+
entries.sort(([_keyA, routeA], [_keyB, routeB]) => {
|
|
316
|
+
const partsA = getParts(routeA.pathDefinition);
|
|
317
|
+
const partsB = getParts(routeB.pathDefinition);
|
|
318
|
+
if (partsA.length !== partsB.length) {
|
|
319
|
+
return partsA.length - partsB.length;
|
|
320
|
+
}
|
|
321
|
+
if (routeA.isConflict(routeB)) {
|
|
322
|
+
if (routeA.isMoreSpecificThan(routeB)) return -1;
|
|
323
|
+
if (routeB.isMoreSpecificThan(routeA)) return 1;
|
|
324
|
+
}
|
|
325
|
+
return routeA.pathDefinition.localeCompare(routeB.pathDefinition);
|
|
326
|
+
});
|
|
327
|
+
return entries.map(([_key, route]) => route.pathOriginal);
|
|
328
|
+
}
|
|
329
|
+
override(config) {
|
|
330
|
+
const newRoutes = {};
|
|
331
|
+
for (const key in this.routes) {
|
|
332
|
+
if (Object.prototype.hasOwnProperty.call(this.routes, key)) {
|
|
333
|
+
newRoutes[key] = this.routes[key].clone(config);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const instance = new Routes(newRoutes, this.ordering, true);
|
|
337
|
+
return Routes._prettify(instance);
|
|
207
338
|
}
|
|
208
339
|
}
|
|
209
340
|
// Annotate the CommonJS export names for ESM import in node:
|
|
210
341
|
0 && (module.exports = {
|
|
211
|
-
Route0
|
|
342
|
+
Route0,
|
|
343
|
+
Routes
|
|
212
344
|
});
|
|
213
345
|
//# sourceMappingURL=index.cjs.map
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// TODO: getLocation by windows location\n// TODO: избавиться от жутких эни в роуте\n// TODO: .extension('.json') to not add additional / but just add some extension\n// TODO: query input can be boolean, or even object with qs\n// TODO: Роут0 три пусть три тоже сам генерится вероятно\n// TODO: Роут0 три мод, тогда там все ноуты кончаются на .селф\n// TODO: use splats in param definition \"*\"\n// TODO: ? check extend for query only .extend('&x&z')\n// TODO: .create(route, {useQuery, useParams})\n// TODO: Из пас экзакт, из пасвизквери экзает, из чилдрен, из парент, из экзактОр\n// TODO: isEqual, isChildren, isParent\n// TODO: extractParams, extractQuery\n// TODO: getPathDefinition respecting definitionParamPrefix, definitionQueryPrefix\n// TODO: prepend\n// TODO: Route0.createTree({base:{self: x, children: ...})\n// TODO: overrideTree\n// TODO: .create(route, {baseUrl, useLocation})\n// TODO: ? optional path params as @\n// TODO: prependMany, extendMany, overrideMany, with types\n// TODO: optional route params /x/:id?\n\n// point0\n// TODO: Сделать чисто фронтовую штуку, которая сама вызывает лоадер, сама вызывает нужные мета и title, и отдаёт в компонент нужные штуки\n\n// ssr0\n// TODO: ССР работает просто поверх любого роутера, который поддерживает асинхронную загрузку страниц\n\nexport class Route0<\n TPathOriginalDefinition extends string,\n TPathDefinition extends Route0._PathDefinition<TPathOriginalDefinition>,\n TParamsDefinition extends Route0._ParamsDefinition<TPathOriginalDefinition>,\n TQueryDefinition extends Route0._QueryDefinition<TPathOriginalDefinition>,\n> {\n pathOriginalDefinition: TPathOriginalDefinition\n private readonly pathDefinition: TPathDefinition\n paramsDefinition: TParamsDefinition\n queryDefinition: TQueryDefinition\n baseUrl: string\n\n private constructor(definition: TPathOriginalDefinition, config: Route0.RouteConfigInput = {}) {\n this.pathOriginalDefinition = definition\n this.pathDefinition = Route0._getPathDefinitionByOriginalDefinition(definition) as TPathDefinition\n this.paramsDefinition = Route0._getParamsDefinitionByRouteDefinition(definition) as TParamsDefinition\n this.queryDefinition = Route0._getQueryDefinitionByRouteDefinition(definition) as TQueryDefinition\n\n const { baseUrl } = config\n if (baseUrl && typeof baseUrl === 'string' && baseUrl.length) {\n this.baseUrl = baseUrl\n } else {\n const g = globalThis as unknown as { location?: { origin?: string } }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (g?.location?.origin) {\n this.baseUrl = g.location.origin\n } else {\n this.baseUrl = 'https://example.com'\n }\n }\n }\n\n static create<\n TPathOriginalDefinition extends string,\n TPathDefinition extends Route0._PathDefinition<TPathOriginalDefinition>,\n TParamsDefinition extends Route0._ParamsDefinition<TPathOriginalDefinition>,\n TQueryDefinition extends Route0._QueryDefinition<TPathOriginalDefinition>,\n >(\n definition: TPathOriginalDefinition,\n config?: Route0.RouteConfigInput,\n ): Route0.Callable<Route0<TPathOriginalDefinition, TPathDefinition, TParamsDefinition, TQueryDefinition>> {\n const original = new Route0<TPathOriginalDefinition, TPathDefinition, TParamsDefinition, TQueryDefinition>(\n definition,\n config,\n )\n const callable = original.get.bind(original)\n const proxy = new Proxy(callable, {\n get(_target, prop, receiver) {\n const value = (original as any)[prop]\n if (typeof value === 'function') {\n return value.bind(original)\n }\n return value\n },\n set(_target, prop, value, receiver) {\n ;(original as any)[prop] = value\n return true\n },\n has(_target, prop) {\n return prop in original\n },\n })\n Object.setPrototypeOf(proxy, Route0.prototype)\n return proxy as never\n }\n\n private static _splitPathDefinitionAndQueryTailDefinition(pathOriginalDefinition: string) {\n const i = pathOriginalDefinition.indexOf('&')\n if (i === -1) return { pathDefinition: pathOriginalDefinition, queryTailDefinition: '' }\n return {\n pathDefinition: pathOriginalDefinition.slice(0, i),\n queryTailDefinition: pathOriginalDefinition.slice(i),\n }\n }\n\n private static _getAbsPath(baseUrl: string, pathWithQuery: string) {\n return new URL(pathWithQuery, baseUrl).toString().replace(/\\/$/, '')\n }\n\n private static _getPathDefinitionByOriginalDefinition<TPathOriginalDefinition extends string>(\n pathOriginalDefinition: TPathOriginalDefinition,\n ) {\n const { pathDefinition } = Route0._splitPathDefinitionAndQueryTailDefinition(pathOriginalDefinition)\n return pathDefinition as Route0._PathDefinition<TPathOriginalDefinition>\n }\n\n private static _getParamsDefinitionByRouteDefinition<TPathOriginalDefinition extends string>(\n pathOriginalDefinition: TPathOriginalDefinition,\n ) {\n const { pathDefinition } = Route0._splitPathDefinitionAndQueryTailDefinition(pathOriginalDefinition)\n const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g))\n const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]))\n return paramsDefinition as Route0._ParamsDefinition<TPathOriginalDefinition>\n }\n\n private static _getQueryDefinitionByRouteDefinition<TPathOriginalDefinition extends string>(\n pathOriginalDefinition: TPathOriginalDefinition,\n ) {\n const { queryTailDefinition } = Route0._splitPathDefinitionAndQueryTailDefinition(pathOriginalDefinition)\n if (!queryTailDefinition) {\n return {} as Route0._QueryDefinition<TPathOriginalDefinition>\n }\n const keys = queryTailDefinition.split('&').map(Boolean)\n const queryDefinition = Object.fromEntries(keys.map((k) => [k, true]))\n return queryDefinition as Route0._QueryDefinition<TPathOriginalDefinition>\n }\n\n static overrideMany<T extends Record<string, Route0.AnyRoute>>(routes: T, config: Route0.RouteConfigInput): T {\n const result = {} as T\n for (const [key, value] of Object.entries(routes)) {\n ;(result as any)[key] = value.clone(config)\n }\n return result\n }\n\n extend<TSuffixDefinition extends string>(\n suffixDefinition: TSuffixDefinition,\n ): Route0.Callable<\n Route0<\n Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>,\n Route0._PathDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>,\n Route0._ParamsDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>,\n Route0._QueryDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>\n >\n > {\n const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndQueryTailDefinition(\n this.pathOriginalDefinition,\n )\n const { pathDefinition: suffixPathDefinition, queryTailDefinition: suffixQueryTailDefinition } =\n Route0._splitPathDefinitionAndQueryTailDefinition(suffixDefinition)\n const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\\/{2,}/g, '/')\n const pathOriginalDefinition =\n `${pathDefinition}${suffixQueryTailDefinition}` as Route0._RoutePathOriginalDefinitionExtended<\n TPathOriginalDefinition,\n TSuffixDefinition\n >\n return Route0.create<\n Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>,\n Route0._PathDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>,\n Route0._ParamsDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>,\n Route0._QueryDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>\n >(pathOriginalDefinition, { baseUrl: this.baseUrl })\n }\n\n // has params\n get(\n input: Route0._OnlyIfHasParams<\n TParamsDefinition,\n Route0._WithParamsInput<TParamsDefinition, { query?: undefined; abs?: false }>\n >,\n ): Route0._OnlyIfHasParams<TParamsDefinition, Route0._PathOnlyRouteValue<TPathOriginalDefinition>>\n get(\n input: Route0._OnlyIfHasParams<\n TParamsDefinition,\n Route0._WithParamsInput<TParamsDefinition, { query: Route0._QueryInput<TQueryDefinition>; abs?: false }>\n >,\n ): Route0._OnlyIfHasParams<TParamsDefinition, Route0._WithQueryRouteValue<TPathOriginalDefinition>>\n get(\n input: Route0._OnlyIfHasParams<\n TParamsDefinition,\n Route0._WithParamsInput<TParamsDefinition, { query?: undefined; abs: true }>\n >,\n ): Route0._OnlyIfHasParams<TParamsDefinition, Route0._AbsolutePathOnlyRouteValue<TPathOriginalDefinition>>\n get(\n input: Route0._OnlyIfHasParams<\n TParamsDefinition,\n Route0._WithParamsInput<TParamsDefinition, { query: Route0._QueryInput<TQueryDefinition>; abs: true }>\n >,\n ): Route0._OnlyIfHasParams<TParamsDefinition, Route0._AbsoluteWithQueryRouteValue<TPathOriginalDefinition>>\n\n // no params\n get(\n ...args: Route0._OnlyIfNoParams<TParamsDefinition, [], [never]>\n ): Route0._PathOnlyRouteValue<TPathOriginalDefinition>\n get(\n input: Route0._OnlyIfNoParams<TParamsDefinition, { query?: undefined; abs?: false }>,\n ): Route0._OnlyIfNoParams<TParamsDefinition, Route0._PathOnlyRouteValue<TPathOriginalDefinition>>\n get(\n input: Route0._OnlyIfNoParams<TParamsDefinition, { query: Route0._QueryInput<TQueryDefinition>; abs?: false }>,\n ): Route0._OnlyIfNoParams<TParamsDefinition, Route0._WithQueryRouteValue<TPathOriginalDefinition>>\n get(\n input: Route0._OnlyIfNoParams<TParamsDefinition, { query?: undefined; abs: true }>,\n ): Route0._OnlyIfNoParams<TParamsDefinition, Route0._AbsolutePathOnlyRouteValue<TPathOriginalDefinition>>\n get(\n input: Route0._OnlyIfNoParams<TParamsDefinition, { query: Route0._QueryInput<TQueryDefinition>; abs: true }>,\n ): Route0._OnlyIfNoParams<TParamsDefinition, Route0._AbsoluteWithQueryRouteValue<TPathOriginalDefinition>>\n\n // implementation\n get(...args: any[]): string {\n const { queryInput, paramsInput, absInput } = ((): {\n queryInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { queryInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { queryInput: {}, paramsInput: {}, absInput: false }\n }\n const { query, abs, ...params } = input\n return { queryInput: query || {}, paramsInput: params, absInput: abs ?? false }\n })()\n\n // validate params\n const neededParamsKeys = Object.keys(this.paramsDefinition)\n const providedParamsKeys = Object.keys(paramsInput)\n const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k))\n if (notProvidedKeys.length) {\n // throw new Error(`Missing params: not defined keys ${notProvidedKeys.map((k) => `\"${k}\"`).join(\", \")}.`)\n Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, 'undefined'])))\n }\n\n // create url\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n let url = String(this.pathDefinition)\n // replace params\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? '')))\n // query params\n const queryInputStringified = Object.fromEntries(Object.entries(queryInput).map(([k, v]) => [k, String(v)]))\n url = [url, new URLSearchParams(queryInputStringified).toString()].filter(Boolean).join('?')\n // dedupe slashes\n url = url.replace(/\\/{2,}/g, '/')\n // absolute\n url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url\n\n return url\n }\n\n getDefinition() {\n return this.pathDefinition\n }\n\n clone(config?: Route0.RouteConfigInput) {\n return new Route0(this.pathOriginalDefinition, config)\n }\n\n static getLocation(url: `${string}://${string}`): Route0.Location\n static getLocation(path: `/${string}`): Route0.Location\n static getLocation(urlOrPath: string): Route0.Location\n static getLocation(urlOrPath: string): Route0.Location {\n // Allow both relative and absolute inputs\n const abs = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(urlOrPath)\n const base = abs ? undefined : 'http://example.com' // dummy base for relative URLs\n\n const url = new URL(urlOrPath, base)\n\n // Extract query and params (params left empty for now — parsed separately)\n const query = Object.fromEntries(url.searchParams.entries())\n\n // Normalize pathname (remove trailing slash except for root)\n let pathname = url.pathname\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1)\n }\n\n // Build the location object similar to browser location\n return {\n query,\n params: {}, // filled later by .parse()\n pathname,\n search: url.search,\n hash: url.hash,\n origin: abs ? url.origin : undefined,\n href: abs ? url.href : pathname + url.search + url.hash,\n abs,\n }\n }\n\n static getMatch<TRoute0 extends Route0.AnyRoute>(\n route0: TRoute0,\n location: Route0.Location,\n ): Route0.MatchResult<TRoute0> {\n const locationCloned = { ...location, params: { ...location.params }, query: { ...location.query } }\n const escapeRegex = (s: string) => s.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&')\n\n // Normalize both sides (no trailing slash except root)\n const def =\n route0.pathDefinition.length > 1 && route0.pathDefinition.endsWith('/')\n ? route0.pathDefinition.slice(0, -1)\n : route0.pathDefinition\n const pathname =\n locationCloned.pathname.length > 1 && locationCloned.pathname.endsWith('/')\n ? locationCloned.pathname.slice(0, -1)\n : locationCloned.pathname\n\n // Build a regex from the route definition: /a/:x/b/:y -> ^/a/([^/]+)/b/([^/]+)$\n const paramNames: string[] = []\n const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m: string, name: string) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n paramNames.push(String(name))\n return '([^/]+)'\n })\n\n const exactRe = new RegExp(`^${pattern}$`)\n const parentRe = new RegExp(`^${pattern}(?:/.*)?$`) // route matches the beginning of the URL (may have more)\n const exactMatch = pathname.match(exactRe)\n\n // Fill params only for exact match (keeps behavior predictable)\n if (exactMatch) {\n const values = exactMatch.slice(1)\n const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? '')]))\n locationCloned.params = params\n } else {\n locationCloned.params = {}\n }\n\n const exact = !!exactMatch\n const parent = !exact && parentRe.test(pathname)\n\n // \"children\": the URL is a prefix of the route definition (ignoring params’ concrete values)\n // We check if the definition starts with the URL path boundary-wise.\n const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def)\n\n return {\n exact,\n parent,\n children,\n location: locationCloned,\n } as never\n }\n match(url: string): Route0.MatchResult<this> {\n const location = Route0.getLocation(url)\n return Route0.getMatch(this, location)\n }\n}\n\nexport namespace Route0 {\n export type AnyRoute = Route0<any, any, any, any>\n export type Callable<T extends AnyRoute> = T & T['get']\n export type RouteConfigInput = {\n baseUrl?: string\n }\n export type Params<TRoute0 extends AnyRoute> = {\n [K in keyof TRoute0['paramsDefinition']]: string\n }\n export type Query<TRoute0 extends AnyRoute> = Partial<\n {\n [K in keyof TRoute0['queryDefinition']]: string | undefined\n } & Record<string, string | undefined>\n >\n\n export type _TrimQueryTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S\n export type _QueryTailDefinitionWithoutFirstAmp<S extends string> = S extends `${string}&${infer T}` ? T : ''\n export type _QueryTailDefinitionWithFirstAmp<S extends string> = S extends `${string}&${infer T}` ? `&${T}` : ''\n export type _AmpSplit<S extends string> = S extends `${infer A}&${infer B}` ? A | _AmpSplit<B> : S\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n export type _NonEmpty<T> = [T] extends ['' | never] ? never : T\n export type _ExtractPathParams<S extends string> = S extends `${string}:${infer After}`\n ? After extends `${infer Name}/${infer Rest}`\n ? Name | _ExtractPathParams<`/${Rest}`>\n : After\n : never\n export type _ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}`\n ? // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Tail extends `${infer _Param}/${infer Rest}`\n ? _ReplacePathParams<`${Head}${string}/${Rest}`>\n : `${Head}${string}`\n : S\n export type _DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? _DedupeSlashes<`${A}/${B}`> : S\n export type _EmptyRecord = Record<never, never>\n export type _JoinPath<Parent extends string, Suffix extends string> = _DedupeSlashes<\n _PathDefinition<Parent> extends infer A extends string\n ? _PathDefinition<Suffix> extends infer B extends string\n ? A extends ''\n ? B extends ''\n ? ''\n : B extends `/${string}`\n ? B\n : `/${B}`\n : B extends ''\n ? A\n : A extends `${string}/`\n ? `${A}${B}`\n : B extends `/${string}`\n ? `${A}${B}`\n : `${A}/${B}`\n : never\n : never\n >\n\n export type _OnlyIfNoParams<TParams extends object, Yes, No = never> = keyof TParams extends never ? Yes : No\n export type _OnlyIfHasParams<TParams extends object, Yes, No = never> = keyof TParams extends never ? No : Yes\n\n export type _PathDefinition<TPathOriginalDefinition extends string> =\n _TrimQueryTailDefinition<TPathOriginalDefinition>\n export type _ParamsDefinition<TPathOriginalDefinition extends string> =\n _ExtractPathParams<_PathDefinition<TPathOriginalDefinition>> extends infer U\n ? [U] extends [never]\n ? _EmptyRecord\n : { [K in Extract<U, string>]: true }\n : _EmptyRecord\n export type _QueryDefinition<TPathOriginalDefinition extends string> =\n _NonEmpty<_QueryTailDefinitionWithoutFirstAmp<TPathOriginalDefinition>> extends infer Tail extends string\n ? _AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? _EmptyRecord\n : { [K in Extract<U, string>]: true }\n : _EmptyRecord\n : _EmptyRecord\n export type _RoutePathOriginalDefinitionExtended<\n TSourcePathOriginalDefinition extends string,\n TSuffixPathOriginalDefinition extends string,\n > = `${_JoinPath<TSourcePathOriginalDefinition, TSuffixPathOriginalDefinition>}${_QueryTailDefinitionWithFirstAmp<TSuffixPathOriginalDefinition>}`\n\n export type _ParamsInput<TParamsDefinition extends object> = {\n [K in keyof TParamsDefinition]: string | number\n }\n export type _QueryInput<TQueryDefinition extends object> = Partial<{\n [K in keyof TQueryDefinition]: string | number\n }> &\n Record<string, string | number>\n export type _WithParamsInput<\n TParamsDefinition extends object,\n T extends {\n query?: _QueryInput<any>\n abs?: boolean\n },\n > = _ParamsInput<TParamsDefinition> & T\n\n export type _PathOnlyRouteValue<TPathOriginalDefinition extends string> =\n `${_ReplacePathParams<_PathDefinition<TPathOriginalDefinition>>}`\n export type _WithQueryRouteValue<TPathOriginalDefinition extends string> =\n `${_ReplacePathParams<_PathDefinition<TPathOriginalDefinition>>}?${string}`\n export type _AbsolutePathOnlyRouteValue<TPathOriginalDefinition extends string> =\n `${string}${_PathOnlyRouteValue<TPathOriginalDefinition>}`\n export type _AbsoluteWithQueryRouteValue<TPathOriginalDefinition extends string> =\n `${string}${_WithQueryRouteValue<TPathOriginalDefinition>}`\n\n export type _LocationParams<TParamsDefinition extends object> = {\n [K in keyof TParamsDefinition]: string\n }\n export type _LocationQuery<TQueryDefinition extends object> = {\n [K in keyof TQueryDefinition]: string | undefined\n } & Record<string, string | undefined>\n export type Location<TRoute0 extends AnyRoute = AnyRoute> = {\n query: _LocationQuery<TRoute0['queryDefinition']>\n params: _LocationParams<TRoute0['paramsDefinition']>\n pathname: string\n search: string\n hash: string\n origin?: string\n href: string\n abs: boolean\n }\n export type MatchResult<TRoute0 extends AnyRoute, TExact extends boolean = boolean> = TExact extends true\n ? {\n exact: true\n parent: false\n children: false\n location: Location<TRoute0>\n }\n : TExact extends false\n ? {\n exact: false\n parent: boolean\n children: boolean\n location: Location\n }\n : never\n export type HasParams<TRoute0 extends AnyRoute> =\n _ExtractPathParams<_PathDefinition<TRoute0['pathOriginalDefinition']>> extends infer U\n ? [U] extends [never]\n ? false\n : true\n : false\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BO,MAAM,OAKX;AAAA,EACA;AAAA,EACiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EAEQ,YAAY,YAAqC,SAAkC,CAAC,GAAG;AAC7F,SAAK,yBAAyB;AAC9B,SAAK,iBAAiB,OAAO,uCAAuC,UAAU;AAC9E,SAAK,mBAAmB,OAAO,sCAAsC,UAAU;AAC/E,SAAK,kBAAkB,OAAO,qCAAqC,UAAU;AAE7E,UAAM,EAAE,QAAQ,IAAI;AACpB,QAAI,WAAW,OAAO,YAAY,YAAY,QAAQ,QAAQ;AAC5D,WAAK,UAAU;AAAA,IACjB,OAAO;AACL,YAAM,IAAI;AAEV,UAAI,GAAG,UAAU,QAAQ;AACvB,aAAK,UAAU,EAAE,SAAS;AAAA,MAC5B,OAAO;AACL,aAAK,UAAU;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,OAML,YACA,QACwG;AACxG,UAAM,WAAW,IAAI;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AACA,UAAM,WAAW,SAAS,IAAI,KAAK,QAAQ;AAC3C,UAAM,QAAQ,IAAI,MAAM,UAAU;AAAA,MAChC,IAAI,SAAS,MAAM,UAAU;AAC3B,cAAM,QAAS,SAAiB,IAAI;AACpC,YAAI,OAAO,UAAU,YAAY;AAC/B,iBAAO,MAAM,KAAK,QAAQ;AAAA,QAC5B;AACA,eAAO;AAAA,MACT;AAAA,MACA,IAAI,SAAS,MAAM,OAAO,UAAU;AAClC;AAAC,QAAC,SAAiB,IAAI,IAAI;AAC3B,eAAO;AAAA,MACT;AAAA,MACA,IAAI,SAAS,MAAM;AACjB,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF,CAAC;AACD,WAAO,eAAe,OAAO,OAAO,SAAS;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,2CAA2C,wBAAgC;AACxF,UAAM,IAAI,uBAAuB,QAAQ,GAAG;AAC5C,QAAI,MAAM,GAAI,QAAO,EAAE,gBAAgB,wBAAwB,qBAAqB,GAAG;AACvF,WAAO;AAAA,MACL,gBAAgB,uBAAuB,MAAM,GAAG,CAAC;AAAA,MACjD,qBAAqB,uBAAuB,MAAM,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,OAAe,YAAY,SAAiB,eAAuB;AACjE,WAAO,IAAI,IAAI,eAAe,OAAO,EAAE,SAAS,EAAE,QAAQ,OAAO,EAAE;AAAA,EACrE;AAAA,EAEA,OAAe,uCACb,wBACA;AACA,UAAM,EAAE,eAAe,IAAI,OAAO,2CAA2C,sBAAsB;AACnG,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,sCACb,wBACA;AACA,UAAM,EAAE,eAAe,IAAI,OAAO,2CAA2C,sBAAsB;AACnG,UAAM,UAAU,MAAM,KAAK,eAAe,SAAS,mBAAmB,CAAC;AACvE,UAAM,mBAAmB,OAAO,YAAY,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;AAC5E,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,qCACb,wBACA;AACA,UAAM,EAAE,oBAAoB,IAAI,OAAO,2CAA2C,sBAAsB;AACxG,QAAI,CAAC,qBAAqB;AACxB,aAAO,CAAC;AAAA,IACV;AACA,UAAM,OAAO,oBAAoB,MAAM,GAAG,EAAE,IAAI,OAAO;AACvD,UAAM,kBAAkB,OAAO,YAAY,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACrE,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,aAAwD,QAAW,QAAoC;AAC5G,UAAM,SAAS,CAAC;AAChB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD;AAAC,MAAC,OAAe,GAAG,IAAI,MAAM,MAAM,MAAM;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,OACE,kBAQA;AACA,UAAM,EAAE,gBAAgB,qBAAqB,IAAI,OAAO;AAAA,MACtD,KAAK;AAAA,IACP;AACA,UAAM,EAAE,gBAAgB,sBAAsB,qBAAqB,0BAA0B,IAC3F,OAAO,2CAA2C,gBAAgB;AACpE,UAAM,iBAAiB,GAAG,oBAAoB,IAAI,oBAAoB,GAAG,QAAQ,WAAW,GAAG;AAC/F,UAAM,yBACJ,GAAG,cAAc,GAAG,yBAAyB;AAI/C,WAAO,OAAO,OAKZ,wBAAwB,EAAE,SAAS,KAAK,QAAQ,CAAC;AAAA,EACrD;AAAA;AAAA,EA8CA,OAAO,MAAqB;AAC1B,UAAM,EAAE,YAAY,aAAa,SAAS,KAAK,MAI1C;AACH,UAAI,KAAK,WAAW,GAAG;AACrB,eAAO,EAAE,YAAY,CAAC,GAAG,aAAa,CAAC,GAAG,UAAU,MAAM;AAAA,MAC5D;AACA,YAAM,QAAQ,KAAK,CAAC;AACpB,UAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAE/C,eAAO,EAAE,YAAY,CAAC,GAAG,aAAa,CAAC,GAAG,UAAU,MAAM;AAAA,MAC5D;AACA,YAAM,EAAE,OAAO,KAAK,GAAG,OAAO,IAAI;AAClC,aAAO,EAAE,YAAY,SAAS,CAAC,GAAG,aAAa,QAAQ,UAAU,OAAO,MAAM;AAAA,IAChF,GAAG;AAGH,UAAM,mBAAmB,OAAO,KAAK,KAAK,gBAAgB;AAC1D,UAAM,qBAAqB,OAAO,KAAK,WAAW;AAClD,UAAM,kBAAkB,iBAAiB,OAAO,CAAC,MAAM,CAAC,mBAAmB,SAAS,CAAC,CAAC;AACtF,QAAI,gBAAgB,QAAQ;AAE1B,aAAO,OAAO,aAAa,OAAO,YAAY,gBAAgB,IAAI,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;AAAA,IAC7F;AAIA,QAAI,MAAM,OAAO,KAAK,cAAc;AAGpC,UAAM,IAAI,QAAQ,qBAAqB,CAAC,IAAI,MAAM,mBAAmB,OAAO,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;AAEpG,UAAM,wBAAwB,OAAO,YAAY,OAAO,QAAQ,UAAU,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3G,UAAM,CAAC,KAAK,IAAI,gBAAgB,qBAAqB,EAAE,SAAS,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE3F,UAAM,IAAI,QAAQ,WAAW,GAAG;AAEhC,UAAM,WAAW,OAAO,YAAY,KAAK,SAAS,GAAG,IAAI;AAEzD,WAAO;AAAA,EACT;AAAA,EAEA,gBAAgB;AACd,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAkC;AACtC,WAAO,IAAI,OAAO,KAAK,wBAAwB,MAAM;AAAA,EACvD;AAAA,EAKA,OAAO,YAAY,WAAoC;AAErD,UAAM,MAAM,gCAAgC,KAAK,SAAS;AAC1D,UAAM,OAAO,MAAM,SAAY;AAE/B,UAAM,MAAM,IAAI,IAAI,WAAW,IAAI;AAGnC,UAAM,QAAQ,OAAO,YAAY,IAAI,aAAa,QAAQ,CAAC;AAG3D,QAAI,WAAW,IAAI;AACnB,QAAI,SAAS,SAAS,KAAK,SAAS,SAAS,GAAG,GAAG;AACjD,iBAAW,SAAS,MAAM,GAAG,EAAE;AAAA,IACjC;AAGA,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,CAAC;AAAA;AAAA,MACT;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ,MAAM,IAAI;AAAA,MACV,QAAQ,MAAM,IAAI,SAAS;AAAA,MAC3B,MAAM,MAAM,IAAI,OAAO,WAAW,IAAI,SAAS,IAAI;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,SACL,QACA,UAC6B;AAC7B,UAAM,iBAAiB,EAAE,GAAG,UAAU,QAAQ,EAAE,GAAG,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,MAAM,EAAE;AACnG,UAAM,cAAc,CAAC,MAAc,EAAE,QAAQ,yBAAyB,MAAM;AAG5E,UAAM,MACJ,OAAO,eAAe,SAAS,KAAK,OAAO,eAAe,SAAS,GAAG,IAClE,OAAO,eAAe,MAAM,GAAG,EAAE,IACjC,OAAO;AACb,UAAM,WACJ,eAAe,SAAS,SAAS,KAAK,eAAe,SAAS,SAAS,GAAG,IACtE,eAAe,SAAS,MAAM,GAAG,EAAE,IACnC,eAAe;AAGrB,UAAM,aAAuB,CAAC;AAC9B,UAAM,UAAU,IAAI,QAAQ,qBAAqB,CAAC,IAAY,SAAiB;AAE7E,iBAAW,KAAK,OAAO,IAAI,CAAC;AAC5B,aAAO;AAAA,IACT,CAAC;AAED,UAAM,UAAU,IAAI,OAAO,IAAI,OAAO,GAAG;AACzC,UAAM,WAAW,IAAI,OAAO,IAAI,OAAO,WAAW;AAClD,UAAM,aAAa,SAAS,MAAM,OAAO;AAGzC,QAAI,YAAY;AACd,YAAM,SAAS,WAAW,MAAM,CAAC;AACjC,YAAM,SAAS,OAAO,YAAY,WAAW,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,mBAAmB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACpG,qBAAe,SAAS;AAAA,IAC1B,OAAO;AACL,qBAAe,SAAS,CAAC;AAAA,IAC3B;AAEA,UAAM,QAAQ,CAAC,CAAC;AAChB,UAAM,SAAS,CAAC,SAAS,SAAS,KAAK,QAAQ;AAI/C,UAAM,WAAW,CAAC,SAAS,IAAI,OAAO,IAAI,YAAY,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG;AAElF,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,MAAM,KAAuC;AAC3C,UAAM,WAAW,OAAO,YAAY,GAAG;AACvC,WAAO,OAAO,SAAS,MAAM,QAAQ;AAAA,EACvC;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// TODO: asterisk\n// TODO: optional params\n// TODO: required search\n\n// TODO: .extension('.json') to not add additional / but just add some extension\n// TODO: search input can be boolean, or even object with qs\n// TODO: Роут0 три пусть три тоже сам генерится вероятно\n// TODO: Роут0 три мод, тогда там все ноуты кончаются на .селф\n// TODO: use splats in param definition \"*\"\n// TODO: ? check extend for search only .extend('&x&z')\n// TODO: .create(route, {useSearch, useParams})\n// TODO: Из пас экзакт, из пасвизквери экзает, из чилдрен, из парент, из экзактОр\n// TODO: isEqual, isChildren, isParent\n// TODO: extractParams, extractSearch\n// TODO: getPathDefinition respecting definitionParamPrefix, definitionSearchPrefix\n// TODO: prepend\n// TODO: Route0.createTree({base:{self: x, children: ...})\n// TODO: overrideTree\n// TODO: .create(route, {baseUrl, useLocation})\n// TODO: ? optional path params as @\n// TODO: prependMany, extendMany, overrideMany, with types\n// TODO: optional route params /x/:id?\n\nexport class Route0<TPath extends string> {\n readonly pathOriginal: TPath\n readonly pathDefinition: _PathDefinition<TPath>\n readonly paramsDefinition: _ParamsDefinition<TPath>\n readonly searchDefinition: _SearchDefinition<TPath>\n baseUrl: string\n\n private constructor(definition: TPath, config: RouteConfigInput = {}) {\n this.pathOriginal = definition\n this.pathDefinition = Route0._getPathDefinitionByPathOriginal(definition)\n this.paramsDefinition = Route0._getParamsDefinitionByPathOriginal(definition)\n this.searchDefinition = Route0._getSearchDefinitionByPathOriginal(definition)\n\n const { baseUrl } = config\n if (baseUrl && typeof baseUrl === 'string' && baseUrl.length) {\n this.baseUrl = baseUrl\n } else {\n const g = globalThis as unknown as { location?: { origin?: string } }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof g?.location?.origin === 'string' && g.location.origin.length > 0) {\n this.baseUrl = g.location.origin\n } else {\n this.baseUrl = 'https://example.com'\n }\n }\n }\n\n static create<TPath extends string>(definition: TPath, config?: RouteConfigInput): CallabelRoute<TPath> {\n const original = new Route0<TPath>(definition, config)\n const callable = original.get.bind(original)\n Object.setPrototypeOf(callable, original)\n Object.defineProperty(callable, Symbol.toStringTag, {\n value: original.pathOriginal,\n })\n return callable as never\n }\n\n private static _splitPathDefinitionAndSearchTailDefinition(pathOriginal: string) {\n const i = pathOriginal.indexOf('&')\n if (i === -1) return { pathDefinition: pathOriginal, searchTailDefinition: '' }\n return {\n pathDefinition: pathOriginal.slice(0, i),\n searchTailDefinition: pathOriginal.slice(i),\n }\n }\n\n private static _getAbsPath(baseUrl: string, pathWithSearch: string) {\n return new URL(pathWithSearch, baseUrl).toString().replace(/\\/$/, '')\n }\n\n private static _getPathDefinitionByPathOriginal<TPath extends string>(pathOriginal: TPath) {\n const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal)\n return pathDefinition as _PathDefinition<TPath>\n }\n\n private static _getParamsDefinitionByPathOriginal<TPath extends string>(pathOriginal: TPath) {\n const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal)\n const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g))\n const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]))\n return paramsDefinition as _ParamsDefinition<TPath>\n }\n\n private static _getSearchDefinitionByPathOriginal<TPath extends string>(pathOriginal: TPath) {\n const { searchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal)\n if (!searchTailDefinition) {\n return {} as _SearchDefinition<TPath>\n }\n const keys = searchTailDefinition.split('&').map(Boolean)\n const searchDefinition = Object.fromEntries(keys.map((k) => [k, true]))\n return searchDefinition as _SearchDefinition<TPath>\n }\n\n extend<TSuffixDefinition extends string>(\n suffixDefinition: TSuffixDefinition,\n ): CallabelRoute<PathExtended<TPath, TSuffixDefinition>> {\n const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(\n this.pathOriginal,\n )\n const { pathDefinition: suffixPathDefinition, searchTailDefinition: suffixSearchTailDefinition } =\n Route0._splitPathDefinitionAndSearchTailDefinition(suffixDefinition)\n const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\\/{2,}/g, '/')\n const pathOriginal = `${pathDefinition}${suffixSearchTailDefinition}` as PathExtended<TPath, TSuffixDefinition>\n return Route0.create<PathExtended<TPath, TSuffixDefinition>>(pathOriginal, { baseUrl: this.baseUrl })\n }\n\n // has params\n get(\n input: OnlyIfHasParams<_ParamsDefinition<TPath>, WithParamsInput<TPath, { search?: undefined; abs?: false }>>,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, PathOnlyRouteValue<TPath>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TPath>,\n WithParamsInput<TPath, { search: _SearchInput<TPath>; abs?: false }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, WithSearchRouteValue<TPath>>\n get(\n input: OnlyIfHasParams<_ParamsDefinition<TPath>, WithParamsInput<TPath, { search?: undefined; abs: true }>>,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, AbsolutePathOnlyRouteValue<TPath>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TPath>,\n WithParamsInput<TPath, { search: _SearchInput<TPath>; abs: true }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, AbsoluteWithSearchRouteValue<TPath>>\n\n // no params\n get(...args: OnlyIfNoParams<_ParamsDefinition<TPath>, [], [never]>): PathOnlyRouteValue<TPath>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, { search?: undefined; abs?: false }>,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, PathOnlyRouteValue<TPath>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, { search: _SearchInput<TPath>; abs?: false }>,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, WithSearchRouteValue<TPath>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, { search?: undefined; abs: true }>,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, AbsolutePathOnlyRouteValue<TPath>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, { search: _SearchInput<TPath>; abs: true }>,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, AbsoluteWithSearchRouteValue<TPath>>\n\n // implementation\n get(...args: any[]): string {\n const { searchInput, paramsInput, absInput } = ((): {\n searchInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const { search, abs, ...params } = input\n return { searchInput: search || {}, paramsInput: params, absInput: abs ?? false }\n })()\n\n // validate params\n const neededParamsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : []\n const providedParamsKeys = Object.keys(paramsInput)\n const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k))\n if (notProvidedKeys.length) {\n // throw new Error(`Missing params: not defined keys ${notProvidedKeys.map((k) => `\"${k}\"`).join(\", \")}.`)\n Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, 'undefined'])))\n }\n\n // create url\n\n let url = this.pathDefinition as string\n // replace params\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? '')))\n // search params\n const searchInputStringified = Object.fromEntries(Object.entries(searchInput).map(([k, v]) => [k, String(v)]))\n url = [url, new URLSearchParams(searchInputStringified).toString()].filter(Boolean).join('?')\n // dedupe slashes\n url = url.replace(/\\/{2,}/g, '/')\n // absolute\n url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url\n\n return url\n }\n\n // has params\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TPath>, WithParamsInput<TPath>>,\n abs?: false,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, PathOnlyRouteValue<TPath>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TPath>, WithParamsInput<TPath, _SearchInput<TPath>>>,\n abs?: false,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, WithSearchRouteValue<TPath>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TPath>, WithParamsInput<TPath>>,\n abs: true,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, AbsolutePathOnlyRouteValue<TPath>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TPath>, WithParamsInput<TPath, _SearchInput<TPath>>>,\n abs: true,\n ): OnlyIfHasParams<_ParamsDefinition<TPath>, AbsoluteWithSearchRouteValue<TPath>>\n\n // no params\n flat(...args: OnlyIfNoParams<_ParamsDefinition<TPath>, [], [never]>): PathOnlyRouteValue<TPath>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, Record<never, never>>,\n abs?: false,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, PathOnlyRouteValue<TPath>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, _SearchInput<TPath>>,\n abs?: false,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, WithSearchRouteValue<TPath>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, Record<never, never>>,\n abs: true,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, AbsolutePathOnlyRouteValue<TPath>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TPath>, _SearchInput<TPath>>,\n abs: true,\n ): OnlyIfNoParams<_ParamsDefinition<TPath>, AbsoluteWithSearchRouteValue<TPath>>\n\n // implementation\n flat(...args: any[]): string {\n const { searchInput, paramsInput, absInput } = ((): {\n searchInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { searchInput: {}, paramsInput: {}, absInput: args[1] ?? false }\n }\n const paramsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : []\n const paramsInput = paramsKeys.reduce<Record<string, string | number>>((acc, key) => {\n if (input[key] !== undefined) {\n acc[key] = input[key]\n }\n return acc\n }, {})\n const searchInput = Object.keys(input)\n .filter((k) => !paramsKeys.includes(k))\n .reduce<Record<string, string | number>>((acc, key) => {\n acc[key] = input[key]\n return acc\n }, {})\n return { searchInput, paramsInput, absInput: args[1] ?? false }\n })()\n\n return this.get({ ...paramsInput, search: searchInput, abs: absInput } as never)\n }\n\n getDefinition(): string {\n return this.pathDefinition\n }\n\n clone(config?: RouteConfigInput): Route0<TPath> {\n return new Route0(this.pathOriginal, config)\n }\n\n static getLocation(href: `${string}://${string}`): LocationUnknown\n static getLocation(hrefRel: `/${string}`): LocationUnknown\n static getLocation(hrefOrHrefRel: string): LocationUnknown\n static getLocation(location: LocationAny): LocationUnknown\n static getLocation(hrefOrHrefRelOrLocation: string | LocationAny): LocationUnknown\n static getLocation(hrefOrHrefRelOrLocation: string | LocationAny): LocationUnknown {\n if (typeof hrefOrHrefRelOrLocation !== 'string') {\n hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel\n }\n // Check if it's an absolute URL (starts with scheme://)\n const abs = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(hrefOrHrefRelOrLocation)\n\n // Use dummy base only if relative\n const base = abs ? undefined : 'http://example.com'\n const url = new URL(hrefOrHrefRelOrLocation, base)\n\n // Extract search params\n const searchParams = Object.fromEntries(url.searchParams.entries())\n\n // Normalize pathname (remove trailing slash except for root)\n let pathname = url.pathname\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1)\n }\n\n // Common derived values\n const hrefRel = pathname + url.search + url.hash\n\n // Build the location object consistent with _LocationGeneral\n const location: LocationUnknown = {\n pathname,\n search: url.search,\n hash: url.hash,\n origin: abs ? url.origin : undefined,\n href: abs ? url.href : undefined,\n hrefRel,\n abs,\n\n // extra host-related fields (available even for relative with dummy base)\n host: abs ? url.host : undefined,\n hostname: abs ? url.hostname : undefined,\n port: abs ? url.port || undefined : undefined,\n\n // specific to LocationUnknown\n searchParams,\n params: undefined,\n route: undefined,\n exact: false,\n parent: false,\n children: false,\n }\n\n return location\n }\n\n getLocation(href: `${string}://${string}`): LocationKnown<TPath>\n getLocation(hrefRel: `/${string}`): LocationKnown<TPath>\n getLocation(hrefOrHrefRel: string): LocationKnown<TPath>\n getLocation(location: LocationAny): LocationKnown<TPath>\n getLocation(hrefOrHrefRelOrLocation: string | LocationAny): LocationKnown<TPath>\n getLocation(hrefOrHrefRelOrLocation: string | LocationAny): LocationKnown<TPath> {\n const location = Route0.getLocation(hrefOrHrefRelOrLocation) as never as LocationKnown<TPath>\n location.route = this.pathOriginal as PathOriginal<TPath>\n location.params = {}\n\n const escapeRegex = (s: string) => s.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&')\n\n // Normalize both sides (no trailing slash except root)\n const def =\n this.pathDefinition.length > 1 && this.pathDefinition.endsWith('/')\n ? this.pathDefinition.slice(0, -1)\n : this.pathDefinition\n const pathname =\n location.pathname.length > 1 && location.pathname.endsWith('/')\n ? location.pathname.slice(0, -1)\n : location.pathname\n\n // Build a regex from the route definition: /a/:x/b/:y -> ^/a/([^/]+)/b/([^/]+)$\n const paramNames: string[] = []\n const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m: string, name: string) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n paramNames.push(String(name))\n return '([^/]+)'\n })\n\n const exactRe = new RegExp(`^${pattern}$`)\n const parentRe = new RegExp(`^${pattern}(?:/.*)?$`) // route matches the beginning of the URL (may have more)\n const exactMatch = pathname.match(exactRe)\n\n // Fill params only for exact match (keeps behavior predictable)\n if (exactMatch) {\n const values = exactMatch.slice(1)\n const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? '')]))\n location.params = params\n } else {\n location.params = {}\n }\n\n const exact = !!exactMatch\n const parent = !exact && parentRe.test(pathname)\n\n // \"children\": the URL is a prefix of the route definition (ignoring params’ concrete values)\n // We check if the definition starts with the URL path boundary-wise.\n const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def)\n\n return {\n ...location,\n exact,\n parent,\n children,\n } as LocationKnown<TPath>\n }\n\n isSame(other: Route0<TPath>): boolean {\n return (\n this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '') === other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '')\n )\n }\n\n isChildren(other: Route0<TPath>): boolean {\n return (\n this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '') === other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '')\n )\n }\n\n isParent(other: Route0<TPath>): boolean {\n return (\n other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '') === this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '')\n )\n }\n\n isConflict(other: Route0<any>): boolean {\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // Different lengths = no conflict (one is deeper than the other)\n if (thisParts.length !== otherParts.length) {\n return false\n }\n\n // Check if all segments could match\n for (let i = 0; i < thisParts.length; i++) {\n const thisPart = thisParts[i]\n const otherPart = otherParts[i]\n\n // Both params = always match\n if (thisPart.startsWith(':') && otherPart.startsWith(':')) {\n continue\n }\n\n // One is param = can match\n if (thisPart.startsWith(':') || otherPart.startsWith(':')) {\n continue\n }\n\n // Both static = must be same\n if (thisPart !== otherPart) {\n return false\n }\n }\n\n return true\n }\n\n isMoreSpecificThan(other: Route0<any>): boolean {\n // More specific = should come earlier when conflicted\n // Static segments beat param segments at the same position\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // Compare segment by segment\n for (let i = 0; i < Math.min(thisParts.length, otherParts.length); i++) {\n const thisIsStatic = !thisParts[i].startsWith(':')\n const otherIsStatic = !otherParts[i].startsWith(':')\n\n if (thisIsStatic && !otherIsStatic) return true\n if (!thisIsStatic && otherIsStatic) return false\n }\n\n // All equal, use lexicographic\n return this.pathDefinition < other.pathDefinition\n }\n}\n\nexport class Routes<const T extends RoutesRecord = RoutesRecord> {\n readonly routes: RoutesRecordHydrated<T>\n readonly ordering: string[]\n\n private constructor(routes: T, ordering?: string[], isHydrated?: boolean) {\n if (isHydrated) {\n this.routes = routes as unknown as RoutesRecordHydrated<T>\n this.ordering = ordering ?? Routes._makeOrdering(routes)\n } else {\n this.ordering = ordering ?? Routes._makeOrdering(routes)\n this.routes = Routes._hydrate(routes)\n }\n }\n\n static create<const T extends RoutesRecord>(routes: T): RoutesPretty<T> {\n const instance = new Routes(routes)\n return Routes._prettify(instance)\n }\n\n static _prettify<const T extends RoutesRecord>(instance: Routes<T>): RoutesPretty<T> {\n Object.setPrototypeOf(instance, Routes.prototype)\n Object.defineProperty(instance, Symbol.toStringTag, {\n value: 'Routes',\n })\n Object.assign(instance, {\n override: instance.override.bind(instance),\n })\n Object.assign(instance, instance.routes)\n return instance as unknown as RoutesPretty<T>\n }\n\n static _hydrate<const T extends RoutesRecord>(routes: T): RoutesRecordHydrated<T> {\n const result = {} as RoutesRecordHydrated<T>\n for (const key in routes) {\n if (Object.prototype.hasOwnProperty.call(routes, key)) {\n const value = routes[key]\n result[key] = (typeof value === 'string' ? Route0.create(value) : value) as CallabelRoute<T[typeof key]>\n }\n }\n return result\n }\n\n static _makeOrdering(routes: RoutesRecord): string[] {\n const hydrated = Routes._hydrate(routes)\n const entries = Object.entries(hydrated)\n\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n // Sort: shorter paths first, then by specificity, then alphabetically\n entries.sort(([_keyA, routeA], [_keyB, routeB]) => {\n const partsA = getParts(routeA.pathDefinition)\n const partsB = getParts(routeB.pathDefinition)\n\n // 1. Shorter paths first (by segment count)\n if (partsA.length !== partsB.length) {\n return partsA.length - partsB.length\n }\n\n // 2. Same length: check if they conflict\n if (routeA.isConflict(routeB)) {\n // Conflicting routes: more specific first\n if (routeA.isMoreSpecificThan(routeB)) return -1\n if (routeB.isMoreSpecificThan(routeA)) return 1\n }\n\n // 3. Same length, not conflicting or equal specificity: alphabetically\n return routeA.pathDefinition.localeCompare(routeB.pathDefinition)\n })\n\n return entries.map(([_key, route]) => route.pathOriginal)\n }\n\n override(config: RouteConfigInput): RoutesPretty<T> {\n const newRoutes = {} as RoutesRecordHydrated<T>\n for (const key in this.routes) {\n if (Object.prototype.hasOwnProperty.call(this.routes, key)) {\n newRoutes[key] = this.routes[key].clone(config) as CallabelRoute<T[typeof key]>\n }\n }\n const instance = new Routes(newRoutes, this.ordering, true)\n return Routes._prettify(instance) as RoutesPretty<T>\n }\n}\n\n// main\n\nexport type AnyRoute<T extends Route0<string> | string = string> = T extends string ? Route0<T> : T\nexport type CallabelRoute<T extends Route0<string> | string = string> = AnyRoute<T> & AnyRoute<T>['get']\nexport type RouteConfigInput = {\n baseUrl?: string\n}\n\n// collection\n\nexport type RoutesRecord = Record<string, AnyRoute | string>\nexport type RoutesRecordHydrated<TRoutesRecord extends RoutesRecord = RoutesRecord> = {\n [K in keyof TRoutesRecord]: CallabelRoute<TRoutesRecord[K]>\n}\nexport type RoutesPretty<TRoutesRecord extends RoutesRecord = RoutesRecord> = RoutesRecordHydrated<TRoutesRecord> &\n Routes<TRoutesRecord>\nexport type ExtractRoutesKeys<TRoutes extends RoutesPretty | RoutesRecord> = TRoutes extends RoutesPretty\n ? keyof TRoutes['routes']\n : TRoutes extends RoutesRecord\n ? keyof TRoutes\n : never\nexport type ExtractRoute<\n TRoutes extends RoutesPretty | RoutesRecord,\n TKey extends keyof ExtractRoutesKeys<TRoutes>,\n> = TKey extends keyof TRoutes ? TRoutes[TKey] : never\n\n// public utils\n\nexport type PathOriginal<T extends AnyRoute | string> = T extends AnyRoute\n ? T['pathOriginal']\n : T extends string\n ? T\n : never\nexport type PathDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['pathDefinition']\n : T extends string\n ? _PathDefinition<T>\n : never\nexport type ParamsDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['paramsDefinition']\n : T extends string\n ? _ParamsDefinition<T>\n : undefined\nexport type SearchDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['searchDefinition']\n : T extends string\n ? _SearchDefinition<T>\n : undefined\n\nexport type Extended<T extends AnyRoute | string | undefined, TSuffixDefinition extends string> = T extends AnyRoute\n ? Route0<PathExtended<T['pathOriginal'], TSuffixDefinition>>\n : T extends string\n ? Route0<PathExtended<T, TSuffixDefinition>>\n : T extends undefined\n ? Route0<TSuffixDefinition>\n : never\n\nexport type IsParent<T extends AnyRoute | string, TParent extends AnyRoute | string> = _IsParent<\n PathDefinition<T>,\n PathDefinition<TParent>\n>\nexport type IsChildren<T extends AnyRoute | string, TChildren extends AnyRoute | string> = _IsChildren<\n PathDefinition<T>,\n PathDefinition<TChildren>\n>\nexport type IsSame<T extends AnyRoute | string, TExact extends AnyRoute | string> = _IsSame<\n PathDefinition<T>,\n PathDefinition<TExact>\n>\nexport type IsSameParams<T1 extends AnyRoute | string, T2 extends AnyRoute | string> = _IsSameParams<\n ParamsDefinition<T1>,\n ParamsDefinition<T2>\n>\n\nexport type HasParams<T extends AnyRoute | string> =\n ExtractPathParams<PathDefinition<T>> extends infer U ? ([U] extends [never] ? false : true) : false\nexport type HasSearch<T extends AnyRoute | string> =\n NonEmpty<SearchTailDefinitionWithoutFirstAmp<PathOriginal<T>>> extends infer Tail extends string\n ? AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? false\n : true\n : false\n : false\n\nexport type ParamsOutput<T extends AnyRoute | string> = {\n [K in keyof ParamsDefinition<T>]: string\n}\nexport type SearchOutput<T extends AnyRoute | string = string> = Partial<\n {\n [K in keyof SearchDefinition<T>]?: string\n } & Record<string, string | undefined>\n>\nexport type StrictSearchOutput<T extends AnyRoute | string> = Partial<{\n [K in keyof SearchDefinition<T>]?: string | undefined\n}>\nexport type ParamsInput<T extends AnyRoute | string = string> = _ParamsInput<PathDefinition<T>>\nexport type SearchInput<T extends AnyRoute | string = string> = _SearchInput<PathOriginal<T>>\nexport type StrictSearchInput<T extends AnyRoute | string> = _StrictSearchInput<PathOriginal<T>>\n\n// location\n\nexport type LocationParams<TPath extends string> = {\n [K in keyof _ParamsDefinition<TPath>]: string\n}\nexport type LocationSearch<TPath extends string = string> = {\n [K in keyof _SearchDefinition<TPath>]: string | undefined\n} & Record<string, string | undefined>\n\nexport type _LocationGeneral = {\n pathname: string\n search: string\n hash: string\n origin?: string\n href?: string\n hrefRel: string\n abs: boolean\n port?: string\n host?: string\n hostname?: string\n}\nexport type LocationUnknown = _LocationGeneral & {\n params: undefined\n searchParams: SearchOutput\n route: undefined\n exact: false\n parent: false\n children: false\n}\nexport type LocationUnmatched<TRoute extends AnyRoute | string = AnyRoute | string> = _LocationGeneral & {\n params: Record<never, never>\n searchParams: SearchOutput<TRoute>\n route: PathOriginal<TRoute>\n exact: false\n parent: false\n children: false\n}\nexport type LocationExact<TRoute extends AnyRoute | string = AnyRoute | string> = _LocationGeneral & {\n params: ParamsOutput<TRoute>\n searchParams: SearchOutput<TRoute>\n route: PathOriginal<TRoute>\n exact: true\n parent: false\n children: false\n}\nexport type LocationParent<TRoute extends AnyRoute | string = AnyRoute | string> = _LocationGeneral & {\n params: Partial<ParamsOutput<TRoute>> // in fact maybe there will be whole params object, but does not matter now\n searchParams: SearchOutput<TRoute>\n route: PathOriginal<TRoute>\n exact: false\n parent: true\n children: false\n}\nexport type LocationChildren<TRoute extends AnyRoute | string = AnyRoute | string> = _LocationGeneral & {\n params: ParamsOutput<TRoute>\n searchParams: SearchOutput<TRoute>\n route: PathOriginal<TRoute>\n exact: false\n parent: false\n children: true\n}\nexport type LocationKnown<TRoute extends AnyRoute | string = AnyRoute | string> =\n | LocationUnmatched<TRoute>\n | LocationExact<TRoute>\n | LocationParent<TRoute>\n | LocationChildren<TRoute>\nexport type LocationAny<TRoute extends AnyRoute = AnyRoute> = LocationUnknown | LocationKnown<TRoute>\n\n// internal utils\n\nexport type _PathDefinition<T extends string> = T extends string ? TrimSearchTailDefinition<T> : never\nexport type _ParamsDefinition<TPath extends string> =\n ExtractPathParams<PathDefinition<TPath>> extends infer U\n ? [U] extends [never]\n ? undefined\n : { [K in Extract<U, string>]: true }\n : undefined\nexport type _SearchDefinition<TPath extends string> =\n NonEmpty<SearchTailDefinitionWithoutFirstAmp<TPath>> extends infer Tail extends string\n ? AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? undefined\n : { [K in Extract<U, string>]: true }\n : undefined\n : undefined\n\nexport type _ParamsInput<TPath extends string> =\n _ParamsDefinition<TPath> extends undefined\n ? Record<never, never>\n : {\n [K in keyof _ParamsDefinition<TPath>]: string | number\n }\nexport type _SearchInput<TPath extends string> =\n _SearchDefinition<TPath> extends undefined\n ? Record<string, string | number>\n : Partial<{\n [K in keyof _SearchDefinition<TPath>]: string | number\n }> &\n Record<string, string | number>\nexport type _StrictSearchInput<TPath extends string> = Partial<{\n [K in keyof _SearchDefinition<TPath>]: string | number\n}>\n\nexport type TrimSearchTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S\nexport type SearchTailDefinitionWithoutFirstAmp<S extends string> = S extends `${string}&${infer T}` ? T : ''\nexport type SearchTailDefinitionWithFirstAmp<S extends string> = S extends `${string}&${infer T}` ? `&${T}` : ''\nexport type AmpSplit<S extends string> = S extends `${infer A}&${infer B}` ? A | AmpSplit<B> : S\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\nexport type NonEmpty<T> = [T] extends ['' | never] ? never : T\nexport type ExtractPathParams<S extends string> = S extends `${string}:${infer After}`\n ? After extends `${infer Name}/${infer Rest}`\n ? Name | ExtractPathParams<`/${Rest}`>\n : After\n : never\nexport type ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}`\n ? // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Tail extends `${infer _Param}/${infer Rest}`\n ? ReplacePathParams<`${Head}${string}/${Rest}`>\n : `${Head}${string}`\n : S\nexport type DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? DedupeSlashes<`${A}/${B}`> : S\nexport type EmptyRecord = Record<never, never>\nexport type JoinPath<Parent extends string, Suffix extends string> = DedupeSlashes<\n PathDefinition<Parent> extends infer A extends string\n ? PathDefinition<Suffix> extends infer B extends string\n ? A extends ''\n ? B extends ''\n ? ''\n : B extends `/${string}`\n ? B\n : `/${B}`\n : B extends ''\n ? A\n : A extends `${string}/`\n ? `${A}${B}`\n : B extends `/${string}`\n ? `${A}${B}`\n : `${A}/${B}`\n : never\n : never\n>\n\nexport type OnlyIfNoParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? Yes : No\nexport type OnlyIfHasParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? No : Yes\n\nexport type PathOnlyRouteValue<TPath extends string> = `${ReplacePathParams<PathDefinition<TPath>>}`\nexport type WithSearchRouteValue<TPath extends string> = `${ReplacePathParams<PathDefinition<TPath>>}?${string}`\nexport type AbsolutePathOnlyRouteValue<TPath extends string> =\n PathOnlyRouteValue<TPath> extends '/' ? string : `${string}${PathOnlyRouteValue<TPath>}`\nexport type AbsoluteWithSearchRouteValue<TPath extends string> = `${string}${WithSearchRouteValue<TPath>}`\n\nexport type PathExtended<\n TSourcePathOriginalDefinition extends string,\n TSuffixPathOriginalDefinition extends string,\n> = `${JoinPath<TSourcePathOriginalDefinition, TSuffixPathOriginalDefinition>}${SearchTailDefinitionWithFirstAmp<TSuffixPathOriginalDefinition>}`\n\nexport type WithParamsInput<\n TPath extends string,\n T extends\n | {\n search?: _SearchInput<any>\n abs?: boolean\n }\n | undefined = undefined,\n> = _ParamsInput<TPath> & (T extends undefined ? Record<never, never> : T)\n\nexport type _IsSameParams<T1 extends object | undefined, T2 extends object | undefined> = T1 extends undefined\n ? T2 extends undefined\n ? true\n : false\n : T2 extends undefined\n ? false\n : T1 extends T2\n ? T2 extends T1\n ? true\n : false\n : false\n\nexport type _IsParent<T extends string, TParent extends string> = T extends TParent\n ? false\n : T extends `${TParent}${string}`\n ? true\n : false\nexport type _IsChildren<T extends string, TChildren extends string> = TChildren extends T\n ? false\n : TChildren extends `${T}${string}`\n ? true\n : false\nexport type _IsSame<T extends string, TExact extends string> = T extends TExact\n ? TExact extends T\n ? true\n : false\n : false\n"],"mappings":"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","names":["paramsInput","searchInput"]}
|