@devp0nt/route0 1.0.0-next.2 → 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.
@@ -0,0 +1,345 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var index_exports = {};
20
+ __export(index_exports, {
21
+ Route0: () => Route0,
22
+ Routes: () => Routes
23
+ });
24
+ module.exports = __toCommonJS(index_exports);
25
+ class Route0 {
26
+ pathOriginal;
27
+ pathDefinition;
28
+ paramsDefinition;
29
+ searchDefinition;
30
+ baseUrl;
31
+ constructor(definition, config = {}) {
32
+ this.pathOriginal = definition;
33
+ this.pathDefinition = Route0._getPathDefinitionByPathOriginal(definition);
34
+ this.paramsDefinition = Route0._getParamsDefinitionByPathOriginal(definition);
35
+ this.searchDefinition = Route0._getSearchDefinitionByPathOriginal(definition);
36
+ const { baseUrl } = config;
37
+ if (baseUrl && typeof baseUrl === "string" && baseUrl.length) {
38
+ this.baseUrl = baseUrl;
39
+ } else {
40
+ const g = globalThis;
41
+ if (typeof g?.location?.origin === "string" && g.location.origin.length > 0) {
42
+ this.baseUrl = g.location.origin;
43
+ } else {
44
+ this.baseUrl = "https://example.com";
45
+ }
46
+ }
47
+ }
48
+ static create(definition, config) {
49
+ const original = new Route0(definition, config);
50
+ const callable = original.get.bind(original);
51
+ Object.setPrototypeOf(callable, original);
52
+ Object.defineProperty(callable, Symbol.toStringTag, {
53
+ value: original.pathOriginal
54
+ });
55
+ return callable;
56
+ }
57
+ static _splitPathDefinitionAndSearchTailDefinition(pathOriginal) {
58
+ const i = pathOriginal.indexOf("&");
59
+ if (i === -1) return { pathDefinition: pathOriginal, searchTailDefinition: "" };
60
+ return {
61
+ pathDefinition: pathOriginal.slice(0, i),
62
+ searchTailDefinition: pathOriginal.slice(i)
63
+ };
64
+ }
65
+ static _getAbsPath(baseUrl, pathWithSearch) {
66
+ return new URL(pathWithSearch, baseUrl).toString().replace(/\/$/, "");
67
+ }
68
+ static _getPathDefinitionByPathOriginal(pathOriginal) {
69
+ const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal);
70
+ return pathDefinition;
71
+ }
72
+ static _getParamsDefinitionByPathOriginal(pathOriginal) {
73
+ const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal);
74
+ const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g));
75
+ const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]));
76
+ return paramsDefinition;
77
+ }
78
+ static _getSearchDefinitionByPathOriginal(pathOriginal) {
79
+ const { searchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(pathOriginal);
80
+ if (!searchTailDefinition) {
81
+ return {};
82
+ }
83
+ const keys = searchTailDefinition.split("&").map(Boolean);
84
+ const searchDefinition = Object.fromEntries(keys.map((k) => [k, true]));
85
+ return searchDefinition;
86
+ }
87
+ extend(suffixDefinition) {
88
+ const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(
89
+ this.pathOriginal
90
+ );
91
+ const { pathDefinition: suffixPathDefinition, searchTailDefinition: suffixSearchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(suffixDefinition);
92
+ const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\/{2,}/g, "/");
93
+ const pathOriginal = `${pathDefinition}${suffixSearchTailDefinition}`;
94
+ return Route0.create(pathOriginal, { baseUrl: this.baseUrl });
95
+ }
96
+ // implementation
97
+ get(...args) {
98
+ const { searchInput, paramsInput, absInput } = (() => {
99
+ if (args.length === 0) {
100
+ return { searchInput: {}, paramsInput: {}, absInput: false };
101
+ }
102
+ const input = args[0];
103
+ if (typeof input !== "object" || input === null) {
104
+ return { searchInput: {}, paramsInput: {}, absInput: false };
105
+ }
106
+ const { search, abs, ...params } = input;
107
+ return { searchInput: search || {}, paramsInput: params, absInput: abs ?? false };
108
+ })();
109
+ const neededParamsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : [];
110
+ const providedParamsKeys = Object.keys(paramsInput);
111
+ const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k));
112
+ if (notProvidedKeys.length) {
113
+ Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, "undefined"])));
114
+ }
115
+ let url = this.pathDefinition;
116
+ url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? "")));
117
+ const searchInputStringified = Object.fromEntries(Object.entries(searchInput).map(([k, v]) => [k, String(v)]));
118
+ url = [url, new URLSearchParams(searchInputStringified).toString()].filter(Boolean).join("?");
119
+ url = url.replace(/\/{2,}/g, "/");
120
+ url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url;
121
+ return url;
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
+ }
148
+ getDefinition() {
149
+ return this.pathDefinition;
150
+ }
151
+ clone(config) {
152
+ return new Route0(this.pathOriginal, config);
153
+ }
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);
159
+ const base = abs ? void 0 : "http://example.com";
160
+ const url = new URL(hrefOrHrefRelOrLocation, base);
161
+ const searchParams = Object.fromEntries(url.searchParams.entries());
162
+ let pathname = url.pathname;
163
+ if (pathname.length > 1 && pathname.endsWith("/")) {
164
+ pathname = pathname.slice(0, -1);
165
+ }
166
+ const hrefRel = pathname + url.search + url.hash;
167
+ const location = {
168
+ pathname,
169
+ search: url.search,
170
+ hash: url.hash,
171
+ origin: abs ? url.origin : void 0,
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
186
+ };
187
+ return location;
188
+ }
189
+ getLocation(hrefOrHrefRelOrLocation) {
190
+ const location = Route0.getLocation(hrefOrHrefRelOrLocation);
191
+ location.route = this.pathOriginal;
192
+ location.params = {};
193
+ const escapeRegex = (s) => s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
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;
196
+ const paramNames = [];
197
+ const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m, name) => {
198
+ paramNames.push(String(name));
199
+ return "([^/]+)";
200
+ });
201
+ const exactRe = new RegExp(`^${pattern}$`);
202
+ const parentRe = new RegExp(`^${pattern}(?:/.*)?$`);
203
+ const exactMatch = pathname.match(exactRe);
204
+ if (exactMatch) {
205
+ const values = exactMatch.slice(1);
206
+ const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? "")]));
207
+ location.params = params;
208
+ } else {
209
+ location.params = {};
210
+ }
211
+ const exact = !!exactMatch;
212
+ const parent = !exact && parentRe.test(pathname);
213
+ const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def);
214
+ return {
215
+ ...location,
216
+ exact,
217
+ parent,
218
+ children
219
+ };
220
+ }
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);
338
+ }
339
+ }
340
+ // Annotate the CommonJS export names for ESM import in node:
341
+ 0 && (module.exports = {
342
+ Route0,
343
+ Routes
344
+ });
345
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
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"]}