@devp0nt/route0 1.0.0-next.13 → 1.0.0-next.15
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.js → index.cjs} +53 -1
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +30 -4
- package/dist/esm/index.d.ts +30 -4
- package/dist/esm/index.js +52 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +13 -5
- package/src/index.test.ts +50 -0
- package/src/index.ts +115 -7
- package/dist/cjs/index.js.map +0 -1
|
@@ -150,9 +150,61 @@ class Route0 {
|
|
|
150
150
|
clone(config) {
|
|
151
151
|
return new Route0(this.pathOriginalDefinition, config);
|
|
152
152
|
}
|
|
153
|
+
static getLocation(urlOrPath) {
|
|
154
|
+
const abs = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(urlOrPath);
|
|
155
|
+
const base = abs ? void 0 : "http://example.com";
|
|
156
|
+
const url = new URL(urlOrPath, base);
|
|
157
|
+
const query = Object.fromEntries(url.searchParams.entries());
|
|
158
|
+
let pathname = url.pathname;
|
|
159
|
+
if (pathname.length > 1 && pathname.endsWith("/")) {
|
|
160
|
+
pathname = pathname.slice(0, -1);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
query,
|
|
164
|
+
params: {},
|
|
165
|
+
// filled later by .parse()
|
|
166
|
+
pathname,
|
|
167
|
+
search: url.search,
|
|
168
|
+
hash: url.hash,
|
|
169
|
+
origin: abs ? url.origin : void 0,
|
|
170
|
+
href: abs ? url.href : pathname + url.search + url.hash,
|
|
171
|
+
abs
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
match(url) {
|
|
175
|
+
const location = Route0.getLocation(url);
|
|
176
|
+
const escapeRegex = (s) => s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
177
|
+
const def = this.pathDefinition.length > 1 && this.pathDefinition.endsWith("/") ? this.pathDefinition.slice(0, -1) : this.pathDefinition;
|
|
178
|
+
const pathname = location.pathname.length > 1 && location.pathname.endsWith("/") ? location.pathname.slice(0, -1) : location.pathname;
|
|
179
|
+
const paramNames = [];
|
|
180
|
+
const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m, name) => {
|
|
181
|
+
paramNames.push(String(name));
|
|
182
|
+
return "([^/]+)";
|
|
183
|
+
});
|
|
184
|
+
const exactRe = new RegExp(`^${pattern}$`);
|
|
185
|
+
const parentRe = new RegExp(`^${pattern}(?:/.*)?$`);
|
|
186
|
+
const exactMatch = pathname.match(exactRe);
|
|
187
|
+
if (exactMatch) {
|
|
188
|
+
const values = exactMatch.slice(1);
|
|
189
|
+
const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? "")]));
|
|
190
|
+
location.params = params;
|
|
191
|
+
} else {
|
|
192
|
+
;
|
|
193
|
+
location.params = {};
|
|
194
|
+
}
|
|
195
|
+
const exact = !!exactMatch;
|
|
196
|
+
const parent = !exact && parentRe.test(pathname);
|
|
197
|
+
const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def);
|
|
198
|
+
return {
|
|
199
|
+
exact,
|
|
200
|
+
parent,
|
|
201
|
+
children,
|
|
202
|
+
location
|
|
203
|
+
};
|
|
204
|
+
}
|
|
153
205
|
}
|
|
154
206
|
// Annotate the CommonJS export names for ESM import in node:
|
|
155
207
|
0 && (module.exports = {
|
|
156
208
|
Route0
|
|
157
209
|
});
|
|
158
|
-
//# sourceMappingURL=index.
|
|
210
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// 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\n// page0\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 match(url: string): Route0.MatchResult<this> {\n const location = Route0.getLocation(url)\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, name) => {\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 as any).params = params\n } else {\n ;(location as any).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,\n } as never\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 Location<TRoute0 extends AnyRoute = AnyRoute> = {\n query: _QueryInput<TRoute0['queryDefinition']>\n params: _ParamsInput<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}\n"],"mappings":"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","names":[]}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -11,7 +11,7 @@ declare class Route0<TPathOriginalDefinition extends string, TPathDefinition ext
|
|
|
11
11
|
private static _getPathDefinitionByOriginalDefinition;
|
|
12
12
|
private static _getParamsDefinitionByRouteDefinition;
|
|
13
13
|
private static _getQueryDefinitionByRouteDefinition;
|
|
14
|
-
static overrideMany<T extends Record<string, Route0
|
|
14
|
+
static overrideMany<T extends Record<string, Route0.AnyRoute>>(routes: T, config: Route0.RouteConfigInput): T;
|
|
15
15
|
extend<TSuffixDefinition extends string>(suffixDefinition: TSuffixDefinition): Route0.Callable<Route0<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>, Route0._PathDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>, Route0._ParamsDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>, Route0._QueryDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>>>;
|
|
16
16
|
get(input: Route0._OnlyIfHasParams<TParamsDefinition, Route0._WithParamsInput<TParamsDefinition, {
|
|
17
17
|
query?: undefined;
|
|
@@ -48,16 +48,21 @@ declare class Route0<TPathOriginalDefinition extends string, TPathDefinition ext
|
|
|
48
48
|
}>): Route0._OnlyIfNoParams<TParamsDefinition, Route0._AbsoluteWithQueryRouteValue<TPathOriginalDefinition>>;
|
|
49
49
|
getDefinition(): TPathDefinition;
|
|
50
50
|
clone(config?: Route0.RouteConfigInput): Route0<TPathOriginalDefinition, Route0._TrimQueryTailDefinition<TPathOriginalDefinition>, Route0._ParamsDefinition<TPathOriginalDefinition>, Route0._QueryDefinition<TPathOriginalDefinition>>;
|
|
51
|
+
static getLocation(url: `${string}://${string}`): Route0.Location;
|
|
52
|
+
static getLocation(path: `/${string}`): Route0.Location;
|
|
53
|
+
static getLocation(urlOrPath: string): Route0.Location;
|
|
54
|
+
match(url: string): Route0.MatchResult<this>;
|
|
51
55
|
}
|
|
52
56
|
declare namespace Route0 {
|
|
53
|
-
type
|
|
57
|
+
type AnyRoute = Route0<any, any, any, any>;
|
|
58
|
+
type Callable<T extends AnyRoute> = T & T['get'];
|
|
54
59
|
type RouteConfigInput = {
|
|
55
60
|
baseUrl?: string;
|
|
56
61
|
};
|
|
57
|
-
type Params<TRoute0 extends
|
|
62
|
+
type Params<TRoute0 extends AnyRoute> = {
|
|
58
63
|
[K in keyof TRoute0['paramsDefinition']]: string;
|
|
59
64
|
};
|
|
60
|
-
type Query<TRoute0 extends
|
|
65
|
+
type Query<TRoute0 extends AnyRoute> = Partial<{
|
|
61
66
|
[K in keyof TRoute0['queryDefinition']]: string | undefined;
|
|
62
67
|
} & Record<string, string | undefined>>;
|
|
63
68
|
type _TrimQueryTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S;
|
|
@@ -94,6 +99,27 @@ declare namespace Route0 {
|
|
|
94
99
|
type _WithQueryRouteValue<TPathOriginalDefinition extends string> = `${_ReplacePathParams<_PathDefinition<TPathOriginalDefinition>>}?${string}`;
|
|
95
100
|
type _AbsolutePathOnlyRouteValue<TPathOriginalDefinition extends string> = `${string}${_PathOnlyRouteValue<TPathOriginalDefinition>}`;
|
|
96
101
|
type _AbsoluteWithQueryRouteValue<TPathOriginalDefinition extends string> = `${string}${_WithQueryRouteValue<TPathOriginalDefinition>}`;
|
|
102
|
+
type Location<TRoute0 extends AnyRoute = AnyRoute> = {
|
|
103
|
+
query: _QueryInput<TRoute0['queryDefinition']>;
|
|
104
|
+
params: _ParamsInput<TRoute0['paramsDefinition']>;
|
|
105
|
+
pathname: string;
|
|
106
|
+
search: string;
|
|
107
|
+
hash: string;
|
|
108
|
+
origin?: string;
|
|
109
|
+
href: string;
|
|
110
|
+
abs: boolean;
|
|
111
|
+
};
|
|
112
|
+
type MatchResult<TRoute0 extends AnyRoute, TExact extends boolean = boolean> = TExact extends true ? {
|
|
113
|
+
exact: true;
|
|
114
|
+
parent: false;
|
|
115
|
+
children: false;
|
|
116
|
+
location: Location<TRoute0>;
|
|
117
|
+
} : TExact extends false ? {
|
|
118
|
+
exact: false;
|
|
119
|
+
parent: boolean;
|
|
120
|
+
children: boolean;
|
|
121
|
+
location: Location;
|
|
122
|
+
} : never;
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
export { Route0 };
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ declare class Route0<TPathOriginalDefinition extends string, TPathDefinition ext
|
|
|
11
11
|
private static _getPathDefinitionByOriginalDefinition;
|
|
12
12
|
private static _getParamsDefinitionByRouteDefinition;
|
|
13
13
|
private static _getQueryDefinitionByRouteDefinition;
|
|
14
|
-
static overrideMany<T extends Record<string, Route0
|
|
14
|
+
static overrideMany<T extends Record<string, Route0.AnyRoute>>(routes: T, config: Route0.RouteConfigInput): T;
|
|
15
15
|
extend<TSuffixDefinition extends string>(suffixDefinition: TSuffixDefinition): Route0.Callable<Route0<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>, Route0._PathDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>, Route0._ParamsDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>, Route0._QueryDefinition<Route0._RoutePathOriginalDefinitionExtended<TPathOriginalDefinition, TSuffixDefinition>>>>;
|
|
16
16
|
get(input: Route0._OnlyIfHasParams<TParamsDefinition, Route0._WithParamsInput<TParamsDefinition, {
|
|
17
17
|
query?: undefined;
|
|
@@ -48,16 +48,21 @@ declare class Route0<TPathOriginalDefinition extends string, TPathDefinition ext
|
|
|
48
48
|
}>): Route0._OnlyIfNoParams<TParamsDefinition, Route0._AbsoluteWithQueryRouteValue<TPathOriginalDefinition>>;
|
|
49
49
|
getDefinition(): TPathDefinition;
|
|
50
50
|
clone(config?: Route0.RouteConfigInput): Route0<TPathOriginalDefinition, Route0._TrimQueryTailDefinition<TPathOriginalDefinition>, Route0._ParamsDefinition<TPathOriginalDefinition>, Route0._QueryDefinition<TPathOriginalDefinition>>;
|
|
51
|
+
static getLocation(url: `${string}://${string}`): Route0.Location;
|
|
52
|
+
static getLocation(path: `/${string}`): Route0.Location;
|
|
53
|
+
static getLocation(urlOrPath: string): Route0.Location;
|
|
54
|
+
match(url: string): Route0.MatchResult<this>;
|
|
51
55
|
}
|
|
52
56
|
declare namespace Route0 {
|
|
53
|
-
type
|
|
57
|
+
type AnyRoute = Route0<any, any, any, any>;
|
|
58
|
+
type Callable<T extends AnyRoute> = T & T['get'];
|
|
54
59
|
type RouteConfigInput = {
|
|
55
60
|
baseUrl?: string;
|
|
56
61
|
};
|
|
57
|
-
type Params<TRoute0 extends
|
|
62
|
+
type Params<TRoute0 extends AnyRoute> = {
|
|
58
63
|
[K in keyof TRoute0['paramsDefinition']]: string;
|
|
59
64
|
};
|
|
60
|
-
type Query<TRoute0 extends
|
|
65
|
+
type Query<TRoute0 extends AnyRoute> = Partial<{
|
|
61
66
|
[K in keyof TRoute0['queryDefinition']]: string | undefined;
|
|
62
67
|
} & Record<string, string | undefined>>;
|
|
63
68
|
type _TrimQueryTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S;
|
|
@@ -94,6 +99,27 @@ declare namespace Route0 {
|
|
|
94
99
|
type _WithQueryRouteValue<TPathOriginalDefinition extends string> = `${_ReplacePathParams<_PathDefinition<TPathOriginalDefinition>>}?${string}`;
|
|
95
100
|
type _AbsolutePathOnlyRouteValue<TPathOriginalDefinition extends string> = `${string}${_PathOnlyRouteValue<TPathOriginalDefinition>}`;
|
|
96
101
|
type _AbsoluteWithQueryRouteValue<TPathOriginalDefinition extends string> = `${string}${_WithQueryRouteValue<TPathOriginalDefinition>}`;
|
|
102
|
+
type Location<TRoute0 extends AnyRoute = AnyRoute> = {
|
|
103
|
+
query: _QueryInput<TRoute0['queryDefinition']>;
|
|
104
|
+
params: _ParamsInput<TRoute0['paramsDefinition']>;
|
|
105
|
+
pathname: string;
|
|
106
|
+
search: string;
|
|
107
|
+
hash: string;
|
|
108
|
+
origin?: string;
|
|
109
|
+
href: string;
|
|
110
|
+
abs: boolean;
|
|
111
|
+
};
|
|
112
|
+
type MatchResult<TRoute0 extends AnyRoute, TExact extends boolean = boolean> = TExact extends true ? {
|
|
113
|
+
exact: true;
|
|
114
|
+
parent: false;
|
|
115
|
+
children: false;
|
|
116
|
+
location: Location<TRoute0>;
|
|
117
|
+
} : TExact extends false ? {
|
|
118
|
+
exact: false;
|
|
119
|
+
parent: boolean;
|
|
120
|
+
children: boolean;
|
|
121
|
+
location: Location;
|
|
122
|
+
} : never;
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
export { Route0 };
|
package/dist/esm/index.js
CHANGED
|
@@ -127,6 +127,58 @@ class Route0 {
|
|
|
127
127
|
clone(config) {
|
|
128
128
|
return new Route0(this.pathOriginalDefinition, config);
|
|
129
129
|
}
|
|
130
|
+
static getLocation(urlOrPath) {
|
|
131
|
+
const abs = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(urlOrPath);
|
|
132
|
+
const base = abs ? void 0 : "http://example.com";
|
|
133
|
+
const url = new URL(urlOrPath, base);
|
|
134
|
+
const query = Object.fromEntries(url.searchParams.entries());
|
|
135
|
+
let pathname = url.pathname;
|
|
136
|
+
if (pathname.length > 1 && pathname.endsWith("/")) {
|
|
137
|
+
pathname = pathname.slice(0, -1);
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
query,
|
|
141
|
+
params: {},
|
|
142
|
+
// filled later by .parse()
|
|
143
|
+
pathname,
|
|
144
|
+
search: url.search,
|
|
145
|
+
hash: url.hash,
|
|
146
|
+
origin: abs ? url.origin : void 0,
|
|
147
|
+
href: abs ? url.href : pathname + url.search + url.hash,
|
|
148
|
+
abs
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
match(url) {
|
|
152
|
+
const location = Route0.getLocation(url);
|
|
153
|
+
const escapeRegex = (s) => s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
154
|
+
const def = this.pathDefinition.length > 1 && this.pathDefinition.endsWith("/") ? this.pathDefinition.slice(0, -1) : this.pathDefinition;
|
|
155
|
+
const pathname = location.pathname.length > 1 && location.pathname.endsWith("/") ? location.pathname.slice(0, -1) : location.pathname;
|
|
156
|
+
const paramNames = [];
|
|
157
|
+
const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m, name) => {
|
|
158
|
+
paramNames.push(String(name));
|
|
159
|
+
return "([^/]+)";
|
|
160
|
+
});
|
|
161
|
+
const exactRe = new RegExp(`^${pattern}$`);
|
|
162
|
+
const parentRe = new RegExp(`^${pattern}(?:/.*)?$`);
|
|
163
|
+
const exactMatch = pathname.match(exactRe);
|
|
164
|
+
if (exactMatch) {
|
|
165
|
+
const values = exactMatch.slice(1);
|
|
166
|
+
const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? "")]));
|
|
167
|
+
location.params = params;
|
|
168
|
+
} else {
|
|
169
|
+
;
|
|
170
|
+
location.params = {};
|
|
171
|
+
}
|
|
172
|
+
const exact = !!exactMatch;
|
|
173
|
+
const parent = !exact && parentRe.test(pathname);
|
|
174
|
+
const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def);
|
|
175
|
+
return {
|
|
176
|
+
exact,
|
|
177
|
+
parent,
|
|
178
|
+
children,
|
|
179
|
+
location
|
|
180
|
+
};
|
|
181
|
+
}
|
|
130
182
|
}
|
|
131
183
|
export {
|
|
132
184
|
Route0
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// 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\n// page0\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<any, any, any, any>>>(\n routes: T,\n config: Route0.RouteConfigInput,\n ): 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\nexport namespace Route0 {\n export type Callable<T extends Route0<any, any, any, any>> = T & T['get']\n export type RouteConfigInput = {\n baseUrl?: string\n }\n export type Params<TRoute0 extends Route0<any, any, any, any>> = {\n [K in keyof TRoute0['paramsDefinition']]: string\n }\n export type Query<TRoute0 extends Route0<any, any, any, any>> = 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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// 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\n// page0\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 match(url: string): Route0.MatchResult<this> {\n const location = Route0.getLocation(url)\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, name) => {\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 as any).params = params\n } else {\n ;(location as any).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,\n } as never\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 Location<TRoute0 extends AnyRoute = AnyRoute> = {\n query: _QueryInput<TRoute0['queryDefinition']>\n params: _ParamsInput<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}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devp0nt/route0",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.15",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Sergei Dmitriev",
|
|
@@ -15,14 +15,21 @@
|
|
|
15
15
|
"url": "https://github.com/devp0nt/route0/issues"
|
|
16
16
|
},
|
|
17
17
|
"type": "module",
|
|
18
|
-
"main": "./dist/cjs/index.js",
|
|
19
|
-
"module": "./dist/esm/index.js",
|
|
20
18
|
"types": "./dist/esm/index.d.ts",
|
|
19
|
+
"main": "./dist/cjs/index.cjs",
|
|
20
|
+
"module": "./dist/esm/index.js",
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./dist/esm/index.d.ts",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"require": "./dist/cjs/index.cjs",
|
|
25
|
+
"import": "./dist/esm/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"typesVersions": {
|
|
29
|
+
"*": {
|
|
30
|
+
"": [
|
|
31
|
+
"./dist/esm/index.d.ts"
|
|
32
|
+
]
|
|
26
33
|
}
|
|
27
34
|
},
|
|
28
35
|
"files": [
|
|
@@ -85,6 +92,7 @@
|
|
|
85
92
|
"@types/bun": "^1.2.22",
|
|
86
93
|
"@types/node": "^20.0.0",
|
|
87
94
|
"cross-env": "^10.0.0",
|
|
95
|
+
"esbuild-fix-imports-plugin": "^1.0.22",
|
|
88
96
|
"eslint": "^9.36.0",
|
|
89
97
|
"eslint-config-love": "^130.0.0",
|
|
90
98
|
"eslint-config-prettier": "^10.1.8",
|
package/src/index.test.ts
CHANGED
|
@@ -203,4 +203,54 @@ describe('route0', () => {
|
|
|
203
203
|
// @ts-expect-error no path params allowed for this route (shorthand)
|
|
204
204
|
expect(rNo.get({ id: '1' })).toBe('/b')
|
|
205
205
|
})
|
|
206
|
+
|
|
207
|
+
it('getLocation location of url', () => {
|
|
208
|
+
let location = Route0.getLocation('/prefix/some/suffix')
|
|
209
|
+
expect(location).toMatchObject({
|
|
210
|
+
hash: '',
|
|
211
|
+
href: '/prefix/some/suffix',
|
|
212
|
+
abs: false,
|
|
213
|
+
origin: undefined,
|
|
214
|
+
params: {},
|
|
215
|
+
pathname: '/prefix/some/suffix',
|
|
216
|
+
query: {},
|
|
217
|
+
search: '',
|
|
218
|
+
})
|
|
219
|
+
location = Route0.getLocation('/prefix/some/suffix?x=1&z=2')
|
|
220
|
+
expect(location).toMatchObject({
|
|
221
|
+
hash: '',
|
|
222
|
+
href: '/prefix/some/suffix?x=1&z=2',
|
|
223
|
+
abs: false,
|
|
224
|
+
origin: undefined,
|
|
225
|
+
params: {},
|
|
226
|
+
pathname: '/prefix/some/suffix',
|
|
227
|
+
query: { x: '1', z: '2' },
|
|
228
|
+
search: '?x=1&z=2',
|
|
229
|
+
})
|
|
230
|
+
location = Route0.getLocation('https://example.com/prefix/some/suffix?x=1&z=2')
|
|
231
|
+
expect(location).toMatchObject({
|
|
232
|
+
hash: '',
|
|
233
|
+
href: 'https://example.com/prefix/some/suffix?x=1&z=2',
|
|
234
|
+
abs: true,
|
|
235
|
+
origin: 'https://example.com',
|
|
236
|
+
params: {},
|
|
237
|
+
pathname: '/prefix/some/suffix',
|
|
238
|
+
query: { x: '1', z: '2' },
|
|
239
|
+
search: '?x=1&z=2',
|
|
240
|
+
})
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
it('match', () => {
|
|
244
|
+
const route0 = Route0.create('/prefix/:x/some/:y/:z/suffix')
|
|
245
|
+
let match = route0.match('/prefix/some/suffix')
|
|
246
|
+
expect(match.exact).toBe(false)
|
|
247
|
+
expect(match.parent).toBe(false)
|
|
248
|
+
expect(match.children).toBe(false)
|
|
249
|
+
expect(match.location.params).toMatchObject({})
|
|
250
|
+
match = route0.match('/prefix/xxx/some/yyy/zzz/suffix')
|
|
251
|
+
expect(match.exact).toBe(true)
|
|
252
|
+
expect(match.parent).toBe(false)
|
|
253
|
+
expect(match.children).toBe(false)
|
|
254
|
+
expect(match.location.params).toMatchObject({ x: 'xxx', y: 'yyy', z: 'zzz' })
|
|
255
|
+
})
|
|
206
256
|
})
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// TODO: Роут0 три пусть три тоже сам генерится вероятно
|
|
2
|
+
// TODO: Роут0 три мод, тогда там все ноуты кончаются на .селф
|
|
1
3
|
// TODO: use splats in param definition "*"
|
|
2
4
|
// TODO: ? check extend for query only .extend('&x&z')
|
|
3
5
|
// TODO: .create(route, {useQuery, useParams})
|
|
@@ -125,10 +127,7 @@ export class Route0<
|
|
|
125
127
|
return queryDefinition as Route0._QueryDefinition<TPathOriginalDefinition>
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
static overrideMany<T extends Record<string, Route0
|
|
129
|
-
routes: T,
|
|
130
|
-
config: Route0.RouteConfigInput,
|
|
131
|
-
): T {
|
|
130
|
+
static overrideMany<T extends Record<string, Route0.AnyRoute>>(routes: T, config: Route0.RouteConfigInput): T {
|
|
132
131
|
const result = {} as T
|
|
133
132
|
for (const [key, value] of Object.entries(routes)) {
|
|
134
133
|
;(result as any)[key] = value.clone(config)
|
|
@@ -260,17 +259,100 @@ export class Route0<
|
|
|
260
259
|
clone(config?: Route0.RouteConfigInput) {
|
|
261
260
|
return new Route0(this.pathOriginalDefinition, config)
|
|
262
261
|
}
|
|
262
|
+
|
|
263
|
+
static getLocation(url: `${string}://${string}`): Route0.Location
|
|
264
|
+
static getLocation(path: `/${string}`): Route0.Location
|
|
265
|
+
static getLocation(urlOrPath: string): Route0.Location
|
|
266
|
+
static getLocation(urlOrPath: string): Route0.Location {
|
|
267
|
+
// Allow both relative and absolute inputs
|
|
268
|
+
const abs = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(urlOrPath)
|
|
269
|
+
const base = abs ? undefined : 'http://example.com' // dummy base for relative URLs
|
|
270
|
+
|
|
271
|
+
const url = new URL(urlOrPath, base)
|
|
272
|
+
|
|
273
|
+
// Extract query and params (params left empty for now — parsed separately)
|
|
274
|
+
const query = Object.fromEntries(url.searchParams.entries())
|
|
275
|
+
|
|
276
|
+
// Normalize pathname (remove trailing slash except for root)
|
|
277
|
+
let pathname = url.pathname
|
|
278
|
+
if (pathname.length > 1 && pathname.endsWith('/')) {
|
|
279
|
+
pathname = pathname.slice(0, -1)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Build the location object similar to browser location
|
|
283
|
+
return {
|
|
284
|
+
query,
|
|
285
|
+
params: {}, // filled later by .parse()
|
|
286
|
+
pathname,
|
|
287
|
+
search: url.search,
|
|
288
|
+
hash: url.hash,
|
|
289
|
+
origin: abs ? url.origin : undefined,
|
|
290
|
+
href: abs ? url.href : pathname + url.search + url.hash,
|
|
291
|
+
abs,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
match(url: string): Route0.MatchResult<this> {
|
|
296
|
+
const location = Route0.getLocation(url)
|
|
297
|
+
|
|
298
|
+
const escapeRegex = (s: string) => s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
299
|
+
|
|
300
|
+
// Normalize both sides (no trailing slash except root)
|
|
301
|
+
const def =
|
|
302
|
+
this.pathDefinition.length > 1 && this.pathDefinition.endsWith('/')
|
|
303
|
+
? this.pathDefinition.slice(0, -1)
|
|
304
|
+
: this.pathDefinition
|
|
305
|
+
const pathname =
|
|
306
|
+
location.pathname.length > 1 && location.pathname.endsWith('/')
|
|
307
|
+
? location.pathname.slice(0, -1)
|
|
308
|
+
: location.pathname
|
|
309
|
+
|
|
310
|
+
// Build a regex from the route definition: /a/:x/b/:y -> ^/a/([^/]+)/b/([^/]+)$
|
|
311
|
+
const paramNames: string[] = []
|
|
312
|
+
const pattern = def.replace(/:([A-Za-z0-9_]+)/g, (_m, name) => {
|
|
313
|
+
paramNames.push(String(name))
|
|
314
|
+
return '([^/]+)'
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
const exactRe = new RegExp(`^${pattern}$`)
|
|
318
|
+
const parentRe = new RegExp(`^${pattern}(?:/.*)?$`) // route matches the beginning of the URL (may have more)
|
|
319
|
+
const exactMatch = pathname.match(exactRe)
|
|
320
|
+
|
|
321
|
+
// Fill params only for exact match (keeps behavior predictable)
|
|
322
|
+
if (exactMatch) {
|
|
323
|
+
const values = exactMatch.slice(1)
|
|
324
|
+
const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? '')]))
|
|
325
|
+
;(location as any).params = params
|
|
326
|
+
} else {
|
|
327
|
+
;(location as any).params = {}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const exact = !!exactMatch
|
|
331
|
+
const parent = !exact && parentRe.test(pathname)
|
|
332
|
+
|
|
333
|
+
// "children": the URL is a prefix of the route definition (ignoring params’ concrete values)
|
|
334
|
+
// We check if the definition starts with the URL path boundary-wise.
|
|
335
|
+
const children = !exact && new RegExp(`^${escapeRegex(pathname)}(?:/|$)`).test(def)
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
exact,
|
|
339
|
+
parent,
|
|
340
|
+
children,
|
|
341
|
+
location,
|
|
342
|
+
} as never
|
|
343
|
+
}
|
|
263
344
|
}
|
|
264
345
|
|
|
265
346
|
export namespace Route0 {
|
|
266
|
-
export type
|
|
347
|
+
export type AnyRoute = Route0<any, any, any, any>
|
|
348
|
+
export type Callable<T extends AnyRoute> = T & T['get']
|
|
267
349
|
export type RouteConfigInput = {
|
|
268
350
|
baseUrl?: string
|
|
269
351
|
}
|
|
270
|
-
export type Params<TRoute0 extends
|
|
352
|
+
export type Params<TRoute0 extends AnyRoute> = {
|
|
271
353
|
[K in keyof TRoute0['paramsDefinition']]: string
|
|
272
354
|
}
|
|
273
|
-
export type Query<TRoute0 extends
|
|
355
|
+
export type Query<TRoute0 extends AnyRoute> = Partial<
|
|
274
356
|
{
|
|
275
357
|
[K in keyof TRoute0['queryDefinition']]: string | undefined
|
|
276
358
|
} & Record<string, string | undefined>
|
|
@@ -362,4 +444,30 @@ export namespace Route0 {
|
|
|
362
444
|
`${string}${_PathOnlyRouteValue<TPathOriginalDefinition>}`
|
|
363
445
|
export type _AbsoluteWithQueryRouteValue<TPathOriginalDefinition extends string> =
|
|
364
446
|
`${string}${_WithQueryRouteValue<TPathOriginalDefinition>}`
|
|
447
|
+
|
|
448
|
+
export type Location<TRoute0 extends AnyRoute = AnyRoute> = {
|
|
449
|
+
query: _QueryInput<TRoute0['queryDefinition']>
|
|
450
|
+
params: _ParamsInput<TRoute0['paramsDefinition']>
|
|
451
|
+
pathname: string
|
|
452
|
+
search: string
|
|
453
|
+
hash: string
|
|
454
|
+
origin?: string
|
|
455
|
+
href: string
|
|
456
|
+
abs: boolean
|
|
457
|
+
}
|
|
458
|
+
export type MatchResult<TRoute0 extends AnyRoute, TExact extends boolean = boolean> = TExact extends true
|
|
459
|
+
? {
|
|
460
|
+
exact: true
|
|
461
|
+
parent: false
|
|
462
|
+
children: false
|
|
463
|
+
location: Location<TRoute0>
|
|
464
|
+
}
|
|
465
|
+
: TExact extends false
|
|
466
|
+
? {
|
|
467
|
+
exact: false
|
|
468
|
+
parent: boolean
|
|
469
|
+
children: boolean
|
|
470
|
+
location: Location
|
|
471
|
+
}
|
|
472
|
+
: never
|
|
365
473
|
}
|
package/dist/cjs/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// 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\n// page0\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<any, any, any, any>>>(\n routes: T,\n config: Route0.RouteConfigInput,\n ): 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\nexport namespace Route0 {\n export type Callable<T extends Route0<any, any, any, any>> = T & T['get']\n export type RouteConfigInput = {\n baseUrl?: string\n }\n export type Params<TRoute0 extends Route0<any, any, any, any>> = {\n [K in keyof TRoute0['paramsDefinition']]: string\n }\n export type Query<TRoute0 extends Route0<any, any, any, any>> = 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"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBO,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,aACL,QACA,QACG;AACH,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;AACF;","names":[]}
|