@devp0nt/route0 1.0.0-next.6 → 1.0.0-next.7

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.
@@ -1,6 +1,6 @@
1
1
  declare class Route0<TPathOriginalDefinition extends string, TPathDefinition extends Route0._PathDefinition<TPathOriginalDefinition>, TParamsDefinition extends Route0._ParamsDefinition<TPathOriginalDefinition>, TQueryDefinition extends Route0._QueryDefinition<TPathOriginalDefinition>> {
2
2
  pathOriginalDefinition: TPathOriginalDefinition;
3
- private pathDefinition;
3
+ private readonly pathDefinition;
4
4
  paramsDefinition: TParamsDefinition;
5
5
  queryDefinition: TQueryDefinition;
6
6
  baseUrl: string;
@@ -69,7 +69,7 @@ declare namespace Route0 {
69
69
  type _ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}` ? Tail extends `${infer _Param}/${infer Rest}` ? _ReplacePathParams<`${Head}${string}/${Rest}`> : `${Head}${string}` : S;
70
70
  type _DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? _DedupeSlashes<`${A}/${B}`> : S;
71
71
  type _EmptyRecord = Record<never, never>;
72
- type _JoinPath<Parent extends string, Suffix extends string> = _DedupeSlashes<Route0._PathDefinition<Parent> extends infer A extends string ? _PathDefinition<Suffix> extends infer B extends string ? A extends '' ? B extends '' ? '' : B extends `/${string}` ? B : `/${B}` : B extends '' ? A : A extends `${string}/` ? `${A}${B}` : B extends `/${string}` ? `${A}${B}` : `${A}/${B}` : never : never>;
72
+ type _JoinPath<Parent extends string, Suffix extends string> = _DedupeSlashes<_PathDefinition<Parent> extends infer A extends string ? _PathDefinition<Suffix> extends infer B extends string ? A extends '' ? B extends '' ? '' : B extends `/${string}` ? B : `/${B}` : B extends '' ? A : A extends `${string}/` ? `${A}${B}` : B extends `/${string}` ? `${A}${B}` : `${A}/${B}` : never : never>;
73
73
  type _OnlyIfNoParams<TParams extends object, Yes, No = never> = keyof TParams extends never ? Yes : No;
74
74
  type _OnlyIfHasParams<TParams extends object, Yes, No = never> = keyof TParams extends never ? No : Yes;
75
75
  type _PathDefinition<TPathOriginalDefinition extends string> = _TrimQueryTailDefinition<TPathOriginalDefinition>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["\n\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 pathDefinition: TPathDefinition\n paramsDefinition: TParamsDefinition\n queryDefinition: TQueryDefinition\n baseUrl: string\n\n private constructor(definition: TPathOriginalDefinition, config: Route0.RouteConfigInput = {}) {\n this.pathOriginalDefinition = definition as TPathOriginalDefinition\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 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 let url = String(this.pathDefinition)\n // replace params\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 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 ? 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 Route0._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> = _ExtractPathParams<\n _PathDefinition<TPathOriginalDefinition>\n > 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> = _NonEmpty<\n _QueryTailDefinitionWithoutFirstAmp<TPathOriginalDefinition>\n > 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: 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,6 +1,6 @@
1
1
  declare class Route0<TPathOriginalDefinition extends string, TPathDefinition extends Route0._PathDefinition<TPathOriginalDefinition>, TParamsDefinition extends Route0._ParamsDefinition<TPathOriginalDefinition>, TQueryDefinition extends Route0._QueryDefinition<TPathOriginalDefinition>> {
2
2
  pathOriginalDefinition: TPathOriginalDefinition;
3
- private pathDefinition;
3
+ private readonly pathDefinition;
4
4
  paramsDefinition: TParamsDefinition;
5
5
  queryDefinition: TQueryDefinition;
6
6
  baseUrl: string;
@@ -69,7 +69,7 @@ declare namespace Route0 {
69
69
  type _ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}` ? Tail extends `${infer _Param}/${infer Rest}` ? _ReplacePathParams<`${Head}${string}/${Rest}`> : `${Head}${string}` : S;
70
70
  type _DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? _DedupeSlashes<`${A}/${B}`> : S;
71
71
  type _EmptyRecord = Record<never, never>;
72
- type _JoinPath<Parent extends string, Suffix extends string> = _DedupeSlashes<Route0._PathDefinition<Parent> extends infer A extends string ? _PathDefinition<Suffix> extends infer B extends string ? A extends '' ? B extends '' ? '' : B extends `/${string}` ? B : `/${B}` : B extends '' ? A : A extends `${string}/` ? `${A}${B}` : B extends `/${string}` ? `${A}${B}` : `${A}/${B}` : never : never>;
72
+ type _JoinPath<Parent extends string, Suffix extends string> = _DedupeSlashes<_PathDefinition<Parent> extends infer A extends string ? _PathDefinition<Suffix> extends infer B extends string ? A extends '' ? B extends '' ? '' : B extends `/${string}` ? B : `/${B}` : B extends '' ? A : A extends `${string}/` ? `${A}${B}` : B extends `/${string}` ? `${A}${B}` : `${A}/${B}` : never : never>;
73
73
  type _OnlyIfNoParams<TParams extends object, Yes, No = never> = keyof TParams extends never ? Yes : No;
74
74
  type _OnlyIfHasParams<TParams extends object, Yes, No = never> = keyof TParams extends never ? No : Yes;
75
75
  type _PathDefinition<TPathOriginalDefinition extends string> = _TrimQueryTailDefinition<TPathOriginalDefinition>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["\n\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 pathDefinition: TPathDefinition\n paramsDefinition: TParamsDefinition\n queryDefinition: TQueryDefinition\n baseUrl: string\n\n private constructor(definition: TPathOriginalDefinition, config: Route0.RouteConfigInput = {}) {\n this.pathOriginalDefinition = definition as TPathOriginalDefinition\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 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 let url = String(this.pathDefinition)\n // replace params\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 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 ? 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 Route0._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> = _ExtractPathParams<\n _PathDefinition<TPathOriginalDefinition>\n > 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> = _NonEmpty<\n _QueryTailDefinitionWithoutFirstAmp<TPathOriginalDefinition>\n > 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":"AAsBO,MAAM,OAKX;AAAA,EACA;AAAA,EACQ;AAAA,EACR;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;AACV,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;AAGA,QAAI,MAAM,OAAO,KAAK,cAAc;AAEpC,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":[]}
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":[]}
package/package.json CHANGED
@@ -57,16 +57,21 @@
57
57
  "test:all:watch": "bun run test:watch & bun run test:dist:watch",
58
58
  "test:all:build": "bun run build:all && bun run test:all",
59
59
  "test:all:build:watch": "bun run build:all:watch & bun run test:all:watch",
60
- "lint": "biome check --write",
60
+ "lint": "bun run lint:base .",
61
+ "lint:base": "eslint --cache --cache-location node_modules/.cache/eslint/.eslintcache",
62
+ "lint:fix": "bun run lint --fix",
63
+ "format": "bun run format:base .",
64
+ "format:base": "prettier --cache --cache-location node_modules/.cache/prettier/.prettiercache --ignore-path .gitignore",
65
+ "format:fix": "bun run format:base --write",
61
66
  "types:build": "tsc --noEmit --project tsconfig.build.json",
62
67
  "types:dev": "tsc --noEmit",
63
68
  "types": "bun run types:dev",
64
69
  "pack:dry": "npm pack --dry-run",
65
- "prepare": "husky"
70
+ "prepare": "husky",
71
+ "clean": "rimraf dist && rimraf dist-test && rimraf node_modules/.cache"
66
72
  },
67
73
  "dependencies": {},
68
74
  "devDependencies": {
69
- "@biomejs/biome": "^2.2.4",
70
75
  "@commitlint/cli": "^19.8.1",
71
76
  "@commitlint/config-conventional": "^19.8.1",
72
77
  "@semantic-release/changelog": "^6.0.3",
@@ -76,7 +81,13 @@
76
81
  "@types/bun": "^1.2.22",
77
82
  "@types/node": "^20.0.0",
78
83
  "cross-env": "^10.0.0",
84
+ "eslint": "^9.36.0",
85
+ "eslint-config-love": "^130.0.0",
86
+ "eslint-config-prettier": "^10.1.8",
79
87
  "husky": "^9.1.7",
88
+ "lint-staged": "^16.2.1",
89
+ "prettier": "^3.6.2",
90
+ "rimraf": "^6.0.1",
80
91
  "semantic-release": "^24.2.8",
81
92
  "tsup": "^8.0.0",
82
93
  "typescript": "^5.0.0"
@@ -88,5 +99,5 @@
88
99
  "publishConfig": {
89
100
  "access": "public"
90
101
  },
91
- "version": "1.0.0-next.6"
102
+ "version": "1.0.0-next.7"
92
103
  }
package/src/index.ts CHANGED
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  // TODO: use splats in param definition "*"
4
2
  // TODO: ? check extend for query only .extend('&x&z')
5
3
  // TODO: .create(route, {useQuery, useParams})
@@ -27,13 +25,13 @@ export class Route0<
27
25
  TQueryDefinition extends Route0._QueryDefinition<TPathOriginalDefinition>,
28
26
  > {
29
27
  pathOriginalDefinition: TPathOriginalDefinition
30
- private pathDefinition: TPathDefinition
28
+ private readonly pathDefinition: TPathDefinition
31
29
  paramsDefinition: TParamsDefinition
32
30
  queryDefinition: TQueryDefinition
33
31
  baseUrl: string
34
32
 
35
33
  private constructor(definition: TPathOriginalDefinition, config: Route0.RouteConfigInput = {}) {
36
- this.pathOriginalDefinition = definition as TPathOriginalDefinition
34
+ this.pathOriginalDefinition = definition
37
35
  this.pathDefinition = Route0._getPathDefinitionByOriginalDefinition(definition) as TPathDefinition
38
36
  this.paramsDefinition = Route0._getParamsDefinitionByRouteDefinition(definition) as TParamsDefinition
39
37
  this.queryDefinition = Route0._getQueryDefinitionByRouteDefinition(definition) as TQueryDefinition
@@ -43,6 +41,7 @@ export class Route0<
43
41
  this.baseUrl = baseUrl
44
42
  } else {
45
43
  const g = globalThis as unknown as { location?: { origin?: string } }
44
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
46
45
  if (g?.location?.origin) {
47
46
  this.baseUrl = g.location.origin
48
47
  } else {
@@ -238,8 +237,10 @@ export class Route0<
238
237
  }
239
238
 
240
239
  // create url
240
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
241
241
  let url = String(this.pathDefinition)
242
242
  // replace params
243
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
243
244
  url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? '')))
244
245
  // query params
245
246
  const queryInputStringified = Object.fromEntries(Object.entries(queryInput).map(([k, v]) => [k, String(v)]))
@@ -279,6 +280,7 @@ export namespace Route0 {
279
280
  export type _QueryTailDefinitionWithoutFirstAmp<S extends string> = S extends `${string}&${infer T}` ? T : ''
280
281
  export type _QueryTailDefinitionWithFirstAmp<S extends string> = S extends `${string}&${infer T}` ? `&${T}` : ''
281
282
  export type _AmpSplit<S extends string> = S extends `${infer A}&${infer B}` ? A | _AmpSplit<B> : S
283
+ // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
282
284
  export type _NonEmpty<T> = [T] extends ['' | never] ? never : T
283
285
  export type _ExtractPathParams<S extends string> = S extends `${string}:${infer After}`
284
286
  ? After extends `${infer Name}/${infer Rest}`
@@ -286,14 +288,15 @@ export namespace Route0 {
286
288
  : After
287
289
  : never
288
290
  export type _ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}`
289
- ? Tail extends `${infer _Param}/${infer Rest}`
291
+ ? // eslint-disable-next-line @typescript-eslint/no-unused-vars
292
+ Tail extends `${infer _Param}/${infer Rest}`
290
293
  ? _ReplacePathParams<`${Head}${string}/${Rest}`>
291
294
  : `${Head}${string}`
292
295
  : S
293
296
  export type _DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? _DedupeSlashes<`${A}/${B}`> : S
294
297
  export type _EmptyRecord = Record<never, never>
295
298
  export type _JoinPath<Parent extends string, Suffix extends string> = _DedupeSlashes<
296
- Route0._PathDefinition<Parent> extends infer A extends string
299
+ _PathDefinition<Parent> extends infer A extends string
297
300
  ? _PathDefinition<Suffix> extends infer B extends string
298
301
  ? A extends ''
299
302
  ? B extends ''
@@ -317,22 +320,20 @@ export namespace Route0 {
317
320
 
318
321
  export type _PathDefinition<TPathOriginalDefinition extends string> =
319
322
  _TrimQueryTailDefinition<TPathOriginalDefinition>
320
- export type _ParamsDefinition<TPathOriginalDefinition extends string> = _ExtractPathParams<
321
- _PathDefinition<TPathOriginalDefinition>
322
- > extends infer U
323
- ? [U] extends [never]
324
- ? _EmptyRecord
325
- : { [K in Extract<U, string>]: true }
326
- : _EmptyRecord
327
- export type _QueryDefinition<TPathOriginalDefinition extends string> = _NonEmpty<
328
- _QueryTailDefinitionWithoutFirstAmp<TPathOriginalDefinition>
329
- > extends infer Tail extends string
330
- ? _AmpSplit<Tail> extends infer U
323
+ export type _ParamsDefinition<TPathOriginalDefinition extends string> =
324
+ _ExtractPathParams<_PathDefinition<TPathOriginalDefinition>> extends infer U
331
325
  ? [U] extends [never]
332
326
  ? _EmptyRecord
333
327
  : { [K in Extract<U, string>]: true }
334
328
  : _EmptyRecord
335
- : _EmptyRecord
329
+ export type _QueryDefinition<TPathOriginalDefinition extends string> =
330
+ _NonEmpty<_QueryTailDefinitionWithoutFirstAmp<TPathOriginalDefinition>> extends infer Tail extends string
331
+ ? _AmpSplit<Tail> extends infer U
332
+ ? [U] extends [never]
333
+ ? _EmptyRecord
334
+ : { [K in Extract<U, string>]: true }
335
+ : _EmptyRecord
336
+ : _EmptyRecord
336
337
  export type _RoutePathOriginalDefinitionExtended<
337
338
  TSourcePathOriginalDefinition extends string,
338
339
  TSuffixPathOriginalDefinition extends string,