@tanstack/router-core 1.120.3 → 1.120.4-alpha.1
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/fileRoute.d.cts +6 -2
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +5 -5
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/link.d.cts +5 -0
- package/dist/cjs/path.cjs +130 -16
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +17 -0
- package/dist/cjs/redirect.cjs +19 -14
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/redirect.d.cts +10 -7
- package/dist/cjs/route.cjs +12 -1
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +7 -8
- package/dist/cjs/router.cjs +227 -155
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +45 -3
- package/dist/cjs/typePrimitives.d.cts +2 -2
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +2 -0
- package/dist/esm/fileRoute.d.ts +6 -2
- package/dist/esm/index.d.ts +5 -5
- package/dist/esm/index.js +7 -3
- package/dist/esm/link.d.ts +5 -0
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/path.d.ts +17 -0
- package/dist/esm/path.js +130 -16
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/redirect.d.ts +10 -7
- package/dist/esm/redirect.js +20 -15
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/route.d.ts +7 -8
- package/dist/esm/route.js +12 -1
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +45 -3
- package/dist/esm/router.js +230 -158
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/typePrimitives.d.ts +2 -2
- package/dist/esm/utils.d.ts +2 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/fileRoute.ts +90 -1
- package/src/index.ts +13 -3
- package/src/link.ts +5 -0
- package/src/path.ts +181 -16
- package/src/redirect.ts +37 -22
- package/src/route.ts +92 -20
- package/src/router.ts +326 -209
- package/src/typePrimitives.ts +2 -2
- package/src/utils.ts +14 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FromPathOption, NavigateOptions, PathParamOptions, SearchParamOptions, ToPathOption } from './link.js';
|
|
2
|
-
import {
|
|
2
|
+
import { RedirectOptions } from './redirect.js';
|
|
3
3
|
import { RouteIds } from './routeInfo.js';
|
|
4
4
|
import { AnyRouter, RegisteredRouter } from './router.js';
|
|
5
5
|
import { UseParamsResult } from './useParams.js';
|
|
@@ -38,7 +38,7 @@ export type ValidateNavigateOptions<TRouter extends AnyRouter = RegisteredRouter
|
|
|
38
38
|
export type ValidateNavigateOptionsArray<TRouter extends AnyRouter = RegisteredRouter, TOptions extends ReadonlyArray<any> = ReadonlyArray<unknown>, TDefaultFrom extends string = string> = {
|
|
39
39
|
[K in keyof TOptions]: ValidateNavigateOptions<TRouter, TOptions[K], TDefaultFrom>;
|
|
40
40
|
};
|
|
41
|
-
export type ValidateRedirectOptions<TRouter extends AnyRouter = RegisteredRouter, TOptions = unknown, TDefaultFrom extends string = string> = Constrain<TOptions,
|
|
41
|
+
export type ValidateRedirectOptions<TRouter extends AnyRouter = RegisteredRouter, TOptions = unknown, TDefaultFrom extends string = string> = Constrain<TOptions, RedirectOptions<TRouter, InferFrom<TOptions, TDefaultFrom>, InferTo<TOptions>, InferMaskFrom<TOptions>, InferMaskTo<TOptions>>>;
|
|
42
42
|
export type ValidateRedirectOptionsArray<TRouter extends AnyRouter = RegisteredRouter, TOptions extends ReadonlyArray<any> = ReadonlyArray<unknown>, TDefaultFrom extends string = string> = {
|
|
43
43
|
[K in keyof TOptions]: ValidateRedirectOptions<TRouter, TOptions[K], TDefaultFrom>;
|
|
44
44
|
};
|
package/dist/esm/utils.d.ts
CHANGED
|
@@ -50,6 +50,8 @@ export type MergeAll<TUnion> = MergeAllObjects<TUnion> | ExtractPrimitives<TUnio
|
|
|
50
50
|
export type ValidateJSON<T> = ((...args: Array<any>) => any) extends T ? unknown extends T ? never : 'Function is not serializable' : {
|
|
51
51
|
[K in keyof T]: ValidateJSON<T[K]>;
|
|
52
52
|
};
|
|
53
|
+
export type LooseReturnType<T> = T extends (...args: Array<any>) => infer TReturn ? TReturn : never;
|
|
54
|
+
export type LooseAsyncReturnType<T> = T extends (...args: Array<any>) => infer TReturn ? TReturn extends Promise<infer TReturn> ? TReturn : TReturn : never;
|
|
53
55
|
export declare function last<T>(arr: Array<T>): T | undefined;
|
|
54
56
|
export declare function functionalUpdate<TPrevious, TResult = TPrevious>(updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>, previous: TPrevious): TResult;
|
|
55
57
|
export declare function pick<TValue, TKey extends keyof TValue>(parent: TValue, keys: Array<TKey>): Pick<TValue, TKey>;
|
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type { RouteIds } from './routeInfo'\nimport type { AnyRouter } from './router'\n\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\n\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\nexport type PickOptional<T> = {\n [K in keyof T as undefined extends T[K] ? K : never]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &\n keyof TRight extends never\n ? TRight\n : Omit<TRight, keyof TLeft & keyof TRight> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n }\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type IsNonEmptyObject<T> = T extends object\n ? keyof T extends never\n ? false\n : true\n : false\n\nexport type Assign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n : never\n : never\n\nexport type IntersectAssign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : TRight & TLeft\n : never\n : never\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive\n ? never\n : TUnion\n\nexport type PartialMergeAllObject<TUnion> =\n ExtractObjects<TUnion> extends infer TObj\n ? [TObj] extends [never]\n ? never\n : {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeAllPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n | undefined\n | null\n\nexport type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type PartialMergeAll<TUnion> =\n | ExtractPrimitives<TUnion>\n | PartialMergeAllObject<TUnion>\n\nexport type Constrain<T, TConstraint, TDefault = TConstraint> =\n | (T extends TConstraint ? T : never)\n | TDefault\n\nexport type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> =\n | (T & TConstraint)\n | TDefault\n\n/**\n * To be added to router types\n */\nexport type UnionToIntersection<T> = (\n T extends any ? (arg: T) => any : never\n) extends (arg: infer T) => any\n ? T\n : never\n\n/**\n * Merges everything in a union into one object.\n * This mapped type is homomorphic which means it preserves stuff! :)\n */\nexport type MergeAllObjects<\n TUnion,\n TIntersected = UnionToIntersection<ExtractObjects<TUnion>>,\n> = [keyof TIntersected] extends [never]\n ? never\n : {\n [TKey in keyof TIntersected]: TUnion extends any\n ? TUnion[TKey & keyof TUnion]\n : never\n }\n\nexport type MergeAll<TUnion> =\n | MergeAllObjects<TUnion>\n | ExtractPrimitives<TUnion>\n\nexport type ValidateJSON<T> = ((...args: Array<any>) => any) extends T\n ? unknown extends T\n ? never\n : 'Function is not serializable'\n : { [K in keyof T]: ValidateJSON<T[K]> }\n\nexport function last<T>(arr: Array<T>) {\n return arr[arr.length - 1]\n}\n\nfunction isFunction(d: any): d is Function {\n return typeof d === 'function'\n}\n\nexport function functionalUpdate<TPrevious, TResult = TPrevious>(\n updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,\n previous: TPrevious,\n): TResult {\n if (isFunction(updater)) {\n return updater(previous)\n }\n\n return updater\n}\n\nexport function pick<TValue, TKey extends keyof TValue>(\n parent: TValue,\n keys: Array<TKey>,\n): Pick<TValue, TKey> {\n return keys.reduce((obj: any, key: TKey) => {\n obj[key] = parent[key]\n return obj\n }, {} as any)\n}\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(prev: any, _next: T): T {\n if (prev === _next) {\n return prev\n }\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (array || (isPlainObject(prev) && isPlainObject(next))) {\n const prevItems = array ? prev : Object.keys(prev)\n const prevSize = prevItems.length\n const nextItems = array ? next : Object.keys(next)\n const nextSize = nextItems.length\n const copy: any = array ? [] : {}\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n if (\n ((!array && prevItems.includes(key)) || array) &&\n prev[key] === undefined &&\n next[key] === undefined\n ) {\n copy[key] = undefined\n equalItems++\n } else {\n copy[key] = replaceEqualDeep(prev[key], next[key])\n if (copy[key] === prev[key] && prev[key] !== undefined) {\n equalItems++\n }\n }\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n }\n\n return next\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\nfunction getObjectKeys(obj: any, ignoreUndefined: boolean) {\n let keys = Object.keys(obj)\n if (ignoreUndefined) {\n keys = keys.filter((key) => obj[key] !== undefined)\n }\n return keys\n}\n\nexport function deepEqual(\n a: any,\n b: any,\n opts?: { partial?: boolean; ignoreUndefined?: boolean },\n): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const ignoreUndefined = opts?.ignoreUndefined ?? true\n const aKeys = getObjectKeys(a, ignoreUndefined)\n const bKeys = getObjectKeys(b, ignoreUndefined)\n\n if (!opts?.partial && aKeys.length !== bKeys.length) {\n return false\n }\n\n return bKeys.every((key) => deepEqual(a[key], b[key], opts))\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) {\n return false\n }\n return !a.some((item, index) => !deepEqual(item, b[index], opts))\n }\n\n return false\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true\n ? T\n : T | undefined\n\nexport type StrictOrFrom<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>\n strict?: TStrict\n }\n\nexport type ThrowConstraint<\n TStrict extends boolean,\n TThrow extends boolean,\n> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n *\n * @deprecated use `jsesc` instead\n */\nexport function escapeJSON(jsonString: string) {\n return jsonString\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/'/g, \"\\\\'\") // Escape single quotes\n .replace(/\"/g, '\\\\\"') // Escape double quotes\n}\n\nexport function shallow<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n const keysA = Object.keys(objA)\n if (keysA.length !== Object.keys(objB).length) {\n return false\n }\n\n for (const item of keysA) {\n if (\n !Object.prototype.hasOwnProperty.call(objB, item) ||\n !Object.is(objA[item as keyof T], objB[item as keyof T])\n ) {\n return false\n }\n }\n return true\n}\n\n/**\n * Checks if a string contains URI-encoded special characters (e.g., %3F, %20).\n *\n * @param {string} inputString The string to check.\n * @returns {boolean} True if the string contains URI-encoded characters, false otherwise.\n * @example\n * ```typescript\n * const str1 = \"foo%3Fbar\";\n * const hasEncodedChars = hasUriEncodedChars(str1); // returns true\n * ```\n */\nexport function hasUriEncodedChars(inputString: string): boolean {\n // This regex looks for a percent sign followed by two hexadecimal digits\n const pattern = /%[0-9A-Fa-f]{2}/\n return pattern.test(inputString)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type { RouteIds } from './routeInfo'\nimport type { AnyRouter } from './router'\n\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\n\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\nexport type PickOptional<T> = {\n [K in keyof T as undefined extends T[K] ? K : never]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &\n keyof TRight extends never\n ? TRight\n : Omit<TRight, keyof TLeft & keyof TRight> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n }\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type IsNonEmptyObject<T> = T extends object\n ? keyof T extends never\n ? false\n : true\n : false\n\nexport type Assign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n : never\n : never\n\nexport type IntersectAssign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : TRight & TLeft\n : never\n : never\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive\n ? never\n : TUnion\n\nexport type PartialMergeAllObject<TUnion> =\n ExtractObjects<TUnion> extends infer TObj\n ? [TObj] extends [never]\n ? never\n : {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeAllPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n | undefined\n | null\n\nexport type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type PartialMergeAll<TUnion> =\n | ExtractPrimitives<TUnion>\n | PartialMergeAllObject<TUnion>\n\nexport type Constrain<T, TConstraint, TDefault = TConstraint> =\n | (T extends TConstraint ? T : never)\n | TDefault\n\nexport type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> =\n | (T & TConstraint)\n | TDefault\n\n/**\n * To be added to router types\n */\nexport type UnionToIntersection<T> = (\n T extends any ? (arg: T) => any : never\n) extends (arg: infer T) => any\n ? T\n : never\n\n/**\n * Merges everything in a union into one object.\n * This mapped type is homomorphic which means it preserves stuff! :)\n */\nexport type MergeAllObjects<\n TUnion,\n TIntersected = UnionToIntersection<ExtractObjects<TUnion>>,\n> = [keyof TIntersected] extends [never]\n ? never\n : {\n [TKey in keyof TIntersected]: TUnion extends any\n ? TUnion[TKey & keyof TUnion]\n : never\n }\n\nexport type MergeAll<TUnion> =\n | MergeAllObjects<TUnion>\n | ExtractPrimitives<TUnion>\n\nexport type ValidateJSON<T> = ((...args: Array<any>) => any) extends T\n ? unknown extends T\n ? never\n : 'Function is not serializable'\n : { [K in keyof T]: ValidateJSON<T[K]> }\n\nexport type LooseReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\nexport type LooseAsyncReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn extends Promise<infer TReturn>\n ? TReturn\n : TReturn\n : never\n\nexport function last<T>(arr: Array<T>) {\n return arr[arr.length - 1]\n}\n\nfunction isFunction(d: any): d is Function {\n return typeof d === 'function'\n}\n\nexport function functionalUpdate<TPrevious, TResult = TPrevious>(\n updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,\n previous: TPrevious,\n): TResult {\n if (isFunction(updater)) {\n return updater(previous)\n }\n\n return updater\n}\n\nexport function pick<TValue, TKey extends keyof TValue>(\n parent: TValue,\n keys: Array<TKey>,\n): Pick<TValue, TKey> {\n return keys.reduce((obj: any, key: TKey) => {\n obj[key] = parent[key]\n return obj\n }, {} as any)\n}\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(prev: any, _next: T): T {\n if (prev === _next) {\n return prev\n }\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (array || (isPlainObject(prev) && isPlainObject(next))) {\n const prevItems = array ? prev : Object.keys(prev)\n const prevSize = prevItems.length\n const nextItems = array ? next : Object.keys(next)\n const nextSize = nextItems.length\n const copy: any = array ? [] : {}\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n if (\n ((!array && prevItems.includes(key)) || array) &&\n prev[key] === undefined &&\n next[key] === undefined\n ) {\n copy[key] = undefined\n equalItems++\n } else {\n copy[key] = replaceEqualDeep(prev[key], next[key])\n if (copy[key] === prev[key] && prev[key] !== undefined) {\n equalItems++\n }\n }\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n }\n\n return next\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\nfunction getObjectKeys(obj: any, ignoreUndefined: boolean) {\n let keys = Object.keys(obj)\n if (ignoreUndefined) {\n keys = keys.filter((key) => obj[key] !== undefined)\n }\n return keys\n}\n\nexport function deepEqual(\n a: any,\n b: any,\n opts?: { partial?: boolean; ignoreUndefined?: boolean },\n): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const ignoreUndefined = opts?.ignoreUndefined ?? true\n const aKeys = getObjectKeys(a, ignoreUndefined)\n const bKeys = getObjectKeys(b, ignoreUndefined)\n\n if (!opts?.partial && aKeys.length !== bKeys.length) {\n return false\n }\n\n return bKeys.every((key) => deepEqual(a[key], b[key], opts))\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) {\n return false\n }\n return !a.some((item, index) => !deepEqual(item, b[index], opts))\n }\n\n return false\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true\n ? T\n : T | undefined\n\nexport type StrictOrFrom<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>\n strict?: TStrict\n }\n\nexport type ThrowConstraint<\n TStrict extends boolean,\n TThrow extends boolean,\n> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n *\n * @deprecated use `jsesc` instead\n */\nexport function escapeJSON(jsonString: string) {\n return jsonString\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/'/g, \"\\\\'\") // Escape single quotes\n .replace(/\"/g, '\\\\\"') // Escape double quotes\n}\n\nexport function shallow<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n const keysA = Object.keys(objA)\n if (keysA.length !== Object.keys(objB).length) {\n return false\n }\n\n for (const item of keysA) {\n if (\n !Object.prototype.hasOwnProperty.call(objB, item) ||\n !Object.is(objA[item as keyof T], objB[item as keyof T])\n ) {\n return false\n }\n }\n return true\n}\n\n/**\n * Checks if a string contains URI-encoded special characters (e.g., %3F, %20).\n *\n * @param {string} inputString The string to check.\n * @returns {boolean} True if the string contains URI-encoded characters, false otherwise.\n * @example\n * ```typescript\n * const str1 = \"foo%3Fbar\";\n * const hasEncodedChars = hasUriEncodedChars(str1); // returns true\n * ```\n */\nexport function hasUriEncodedChars(inputString: string): boolean {\n // This regex looks for a percent sign followed by two hexadecimal digits\n const pattern = /%[0-9A-Fa-f]{2}/\n return pattern.test(inputString)\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-core",
|
|
3
|
-
"version": "1.120.
|
|
3
|
+
"version": "1.120.4-alpha.1",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@tanstack/store": "^0.7.0",
|
|
48
48
|
"tiny-invariant": "^1.3.3",
|
|
49
|
-
"@tanstack/history": "1.
|
|
49
|
+
"@tanstack/history": "1.120.4-alpha.1"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {}
|
|
52
52
|
}
|
package/src/fileRoute.ts
CHANGED
|
@@ -2,6 +2,10 @@ import type {
|
|
|
2
2
|
AnyContext,
|
|
3
3
|
AnyPathParams,
|
|
4
4
|
AnyRoute,
|
|
5
|
+
FileBaseRouteOptions,
|
|
6
|
+
ResolveParams,
|
|
7
|
+
Route,
|
|
8
|
+
RouteConstraints,
|
|
5
9
|
UpdatableRouteOptions,
|
|
6
10
|
} from './route'
|
|
7
11
|
import type { AnyValidator } from './validators'
|
|
@@ -28,6 +32,87 @@ export interface FileRoutesByPath {
|
|
|
28
32
|
// }
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
export interface FileRouteOptions<
|
|
36
|
+
TFilePath extends string,
|
|
37
|
+
TParentRoute extends AnyRoute,
|
|
38
|
+
TId extends RouteConstraints['TId'],
|
|
39
|
+
TPath extends RouteConstraints['TPath'],
|
|
40
|
+
TFullPath extends RouteConstraints['TFullPath'],
|
|
41
|
+
TSearchValidator = undefined,
|
|
42
|
+
TParams = ResolveParams<TPath>,
|
|
43
|
+
TRouteContextFn = AnyContext,
|
|
44
|
+
TBeforeLoadFn = AnyContext,
|
|
45
|
+
TLoaderDeps extends Record<string, any> = {},
|
|
46
|
+
TLoaderFn = undefined,
|
|
47
|
+
> extends FileBaseRouteOptions<
|
|
48
|
+
TParentRoute,
|
|
49
|
+
TId,
|
|
50
|
+
TPath,
|
|
51
|
+
TSearchValidator,
|
|
52
|
+
TParams,
|
|
53
|
+
TLoaderDeps,
|
|
54
|
+
TLoaderFn,
|
|
55
|
+
AnyContext,
|
|
56
|
+
TRouteContextFn,
|
|
57
|
+
TBeforeLoadFn
|
|
58
|
+
>,
|
|
59
|
+
UpdatableRouteOptions<
|
|
60
|
+
TParentRoute,
|
|
61
|
+
TId,
|
|
62
|
+
TFullPath,
|
|
63
|
+
TParams,
|
|
64
|
+
TSearchValidator,
|
|
65
|
+
TLoaderFn,
|
|
66
|
+
TLoaderDeps,
|
|
67
|
+
AnyContext,
|
|
68
|
+
TRouteContextFn,
|
|
69
|
+
TBeforeLoadFn
|
|
70
|
+
> {}
|
|
71
|
+
|
|
72
|
+
export type CreateFileRoute<
|
|
73
|
+
TFilePath extends string,
|
|
74
|
+
TParentRoute extends AnyRoute,
|
|
75
|
+
TId extends RouteConstraints['TId'],
|
|
76
|
+
TPath extends RouteConstraints['TPath'],
|
|
77
|
+
TFullPath extends RouteConstraints['TFullPath'],
|
|
78
|
+
> = <
|
|
79
|
+
TSearchValidator = undefined,
|
|
80
|
+
TParams = ResolveParams<TPath>,
|
|
81
|
+
TRouteContextFn = AnyContext,
|
|
82
|
+
TBeforeLoadFn = AnyContext,
|
|
83
|
+
TLoaderDeps extends Record<string, any> = {},
|
|
84
|
+
TLoaderFn = undefined,
|
|
85
|
+
>(
|
|
86
|
+
options?: FileRouteOptions<
|
|
87
|
+
TFilePath,
|
|
88
|
+
TParentRoute,
|
|
89
|
+
TId,
|
|
90
|
+
TPath,
|
|
91
|
+
TFullPath,
|
|
92
|
+
TSearchValidator,
|
|
93
|
+
TParams,
|
|
94
|
+
TRouteContextFn,
|
|
95
|
+
TBeforeLoadFn,
|
|
96
|
+
TLoaderDeps,
|
|
97
|
+
TLoaderFn
|
|
98
|
+
>,
|
|
99
|
+
) => Route<
|
|
100
|
+
TParentRoute,
|
|
101
|
+
TPath,
|
|
102
|
+
TFullPath,
|
|
103
|
+
TFilePath,
|
|
104
|
+
TId,
|
|
105
|
+
TSearchValidator,
|
|
106
|
+
TParams,
|
|
107
|
+
AnyContext,
|
|
108
|
+
TRouteContextFn,
|
|
109
|
+
TBeforeLoadFn,
|
|
110
|
+
TLoaderDeps,
|
|
111
|
+
TLoaderFn,
|
|
112
|
+
unknown,
|
|
113
|
+
unknown
|
|
114
|
+
>
|
|
115
|
+
|
|
31
116
|
export type LazyRouteOptions = Pick<
|
|
32
117
|
UpdatableRouteOptions<
|
|
33
118
|
AnyRoute,
|
|
@@ -44,8 +129,12 @@ export type LazyRouteOptions = Pick<
|
|
|
44
129
|
'component' | 'errorComponent' | 'pendingComponent' | 'notFoundComponent'
|
|
45
130
|
>
|
|
46
131
|
|
|
47
|
-
export interface LazyRoute {
|
|
132
|
+
export interface LazyRoute<in out TRoute extends AnyRoute> {
|
|
48
133
|
options: {
|
|
49
134
|
id: string
|
|
50
135
|
} & LazyRouteOptions
|
|
51
136
|
}
|
|
137
|
+
|
|
138
|
+
export type CreateLazyFileRoute<TRoute extends AnyRoute> = (
|
|
139
|
+
opts: LazyRouteOptions,
|
|
140
|
+
) => LazyRoute<TRoute>
|
package/src/index.ts
CHANGED
|
@@ -60,8 +60,10 @@ export type {
|
|
|
60
60
|
InferFileRouteTypes,
|
|
61
61
|
FileRouteTypes,
|
|
62
62
|
FileRoutesByPath,
|
|
63
|
+
CreateFileRoute,
|
|
63
64
|
LazyRoute,
|
|
64
65
|
LazyRouteOptions,
|
|
66
|
+
CreateLazyFileRoute,
|
|
65
67
|
} from './fileRoute'
|
|
66
68
|
|
|
67
69
|
export type {
|
|
@@ -149,8 +151,6 @@ export type {
|
|
|
149
151
|
StringifyParamsFn,
|
|
150
152
|
ParamsOptions,
|
|
151
153
|
UpdatableStaticRouteOption,
|
|
152
|
-
LooseReturnType,
|
|
153
|
-
LooseAsyncReturnType,
|
|
154
154
|
ContextReturnType,
|
|
155
155
|
ContextAsyncReturnType,
|
|
156
156
|
ResolveRouteContext,
|
|
@@ -209,6 +209,8 @@ export {
|
|
|
209
209
|
SearchParamError,
|
|
210
210
|
PathParamError,
|
|
211
211
|
getInitialRouterState,
|
|
212
|
+
processRouteTree,
|
|
213
|
+
getMatchedRoutes,
|
|
212
214
|
} from './router'
|
|
213
215
|
export type {
|
|
214
216
|
ViewTransitionOptions,
|
|
@@ -322,6 +324,8 @@ export type {
|
|
|
322
324
|
MergeAll,
|
|
323
325
|
ValidateJSON,
|
|
324
326
|
StrictOrFrom,
|
|
327
|
+
LooseReturnType,
|
|
328
|
+
LooseAsyncReturnType,
|
|
325
329
|
} from './utils'
|
|
326
330
|
|
|
327
331
|
export type {
|
|
@@ -370,7 +374,13 @@ export type { UseLoaderDataResult, ResolveUseLoaderData } from './useLoaderData'
|
|
|
370
374
|
|
|
371
375
|
export type { Redirect, ResolvedRedirect, AnyRedirect } from './redirect'
|
|
372
376
|
|
|
373
|
-
export {
|
|
377
|
+
export {
|
|
378
|
+
redirect,
|
|
379
|
+
isRedirect,
|
|
380
|
+
isResolvedRedirect,
|
|
381
|
+
tsrRedirectHeaderKey,
|
|
382
|
+
parseRedirect,
|
|
383
|
+
} from './redirect'
|
|
374
384
|
|
|
375
385
|
export type { NotFoundError } from './not-found'
|
|
376
386
|
export { isNotFound, notFound } from './not-found'
|
package/src/link.ts
CHANGED
|
@@ -591,6 +591,11 @@ export interface LinkOptionsProps {
|
|
|
591
591
|
* @default false
|
|
592
592
|
*/
|
|
593
593
|
disabled?: boolean
|
|
594
|
+
/**
|
|
595
|
+
* When the preload strategy is set to `intent`, this controls the proximity of the link to the cursor before it is preloaded.
|
|
596
|
+
* If the user exits this proximity before this delay, the preload will be cancelled.
|
|
597
|
+
*/
|
|
598
|
+
preloadIntentProximity?: number
|
|
594
599
|
}
|
|
595
600
|
|
|
596
601
|
export type LinkOptions<
|
package/src/path.ts
CHANGED
|
@@ -5,6 +5,9 @@ import type { AnyPathParams } from './route'
|
|
|
5
5
|
export interface Segment {
|
|
6
6
|
type: 'pathname' | 'param' | 'wildcard'
|
|
7
7
|
value: string
|
|
8
|
+
// Add a new property to store the static segment if present
|
|
9
|
+
prefixSegment?: string
|
|
10
|
+
suffixSegment?: string
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
export function joinPaths(paths: Array<string | undefined>) {
|
|
@@ -137,10 +140,52 @@ export function resolvePath({
|
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
|
|
140
|
-
const
|
|
143
|
+
const segmentValues = baseSegments.map((segment) => {
|
|
144
|
+
if (segment.type === 'param') {
|
|
145
|
+
const param = segment.value.substring(1)
|
|
146
|
+
if (segment.prefixSegment && segment.suffixSegment) {
|
|
147
|
+
return `${segment.prefixSegment}{$${param}}${segment.suffixSegment}`
|
|
148
|
+
} else if (segment.prefixSegment) {
|
|
149
|
+
return `${segment.prefixSegment}{$${param}}`
|
|
150
|
+
} else if (segment.suffixSegment) {
|
|
151
|
+
return `{$${param}}${segment.suffixSegment}`
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (segment.type === 'wildcard') {
|
|
155
|
+
if (segment.prefixSegment && segment.suffixSegment) {
|
|
156
|
+
return `${segment.prefixSegment}{$}${segment.suffixSegment}`
|
|
157
|
+
} else if (segment.prefixSegment) {
|
|
158
|
+
return `${segment.prefixSegment}{$}`
|
|
159
|
+
} else if (segment.suffixSegment) {
|
|
160
|
+
return `{$}${segment.suffixSegment}`
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return segment.value
|
|
164
|
+
})
|
|
165
|
+
const joined = joinPaths([basepath, ...segmentValues])
|
|
141
166
|
return cleanPath(joined)
|
|
142
167
|
}
|
|
143
168
|
|
|
169
|
+
const PARAM_RE = /^\$.{1,}$/ // $paramName
|
|
170
|
+
const PARAM_W_CURLY_BRACES_RE = /^(.*?)\{(\$[a-zA-Z_$][a-zA-Z0-9_$]*)\}(.*)$/ // prefix{$paramName}suffix
|
|
171
|
+
const WILDCARD_RE = /^\$$/ // $
|
|
172
|
+
const WILDCARD_W_CURLY_BRACES_RE = /^(.*?)\{\$\}(.*)$/ // prefix{$}suffix
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Required: `/foo/$bar` ✅
|
|
176
|
+
* Prefix and Suffix: `/foo/prefix${bar}suffix` ✅
|
|
177
|
+
* Wildcard: `/foo/$` ✅
|
|
178
|
+
* Wildcard with Prefix and Suffix: `/foo/prefix{$}suffix` ✅
|
|
179
|
+
*
|
|
180
|
+
* Future:
|
|
181
|
+
* Optional: `/foo/{-bar}`
|
|
182
|
+
* Optional named segment: `/foo/{bar}`
|
|
183
|
+
* Optional named segment with Prefix and Suffix: `/foo/prefix{-bar}suffix`
|
|
184
|
+
* Escape special characters:
|
|
185
|
+
* - `/foo/[$]` - Static route
|
|
186
|
+
* - `/foo/[$]{$foo} - Dynamic route with a static prefix of `$`
|
|
187
|
+
* - `/foo/{$foo}[$]` - Dynamic route with a static suffix of `$`
|
|
188
|
+
*/
|
|
144
189
|
export function parsePathname(pathname?: string): Array<Segment> {
|
|
145
190
|
if (!pathname) {
|
|
146
191
|
return []
|
|
@@ -167,20 +212,55 @@ export function parsePathname(pathname?: string): Array<Segment> {
|
|
|
167
212
|
|
|
168
213
|
segments.push(
|
|
169
214
|
...split.map((part): Segment => {
|
|
170
|
-
|
|
215
|
+
// Check for wildcard with curly braces: prefix{$}suffix
|
|
216
|
+
const wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE)
|
|
217
|
+
if (wildcardBracesMatch) {
|
|
218
|
+
const prefix = wildcardBracesMatch[1]
|
|
219
|
+
const suffix = wildcardBracesMatch[2]
|
|
171
220
|
return {
|
|
172
221
|
type: 'wildcard',
|
|
173
|
-
value:
|
|
222
|
+
value: '$',
|
|
223
|
+
prefixSegment: prefix || undefined,
|
|
224
|
+
suffixSegment: suffix || undefined,
|
|
174
225
|
}
|
|
175
226
|
}
|
|
176
227
|
|
|
177
|
-
|
|
228
|
+
// Check for the new parameter format: prefix{$paramName}suffix
|
|
229
|
+
const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE)
|
|
230
|
+
if (paramBracesMatch) {
|
|
231
|
+
const prefix = paramBracesMatch[1]
|
|
232
|
+
const paramName = paramBracesMatch[2]
|
|
233
|
+
const suffix = paramBracesMatch[3]
|
|
178
234
|
return {
|
|
179
235
|
type: 'param',
|
|
180
|
-
value:
|
|
236
|
+
value: '' + paramName,
|
|
237
|
+
prefixSegment: prefix || undefined,
|
|
238
|
+
suffixSegment: suffix || undefined,
|
|
181
239
|
}
|
|
182
240
|
}
|
|
183
241
|
|
|
242
|
+
// Check for bare parameter format: $paramName (without curly braces)
|
|
243
|
+
if (PARAM_RE.test(part)) {
|
|
244
|
+
const paramName = part.substring(1)
|
|
245
|
+
return {
|
|
246
|
+
type: 'param',
|
|
247
|
+
value: '$' + paramName,
|
|
248
|
+
prefixSegment: undefined,
|
|
249
|
+
suffixSegment: undefined,
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Check for bare wildcard: $ (without curly braces)
|
|
254
|
+
if (WILDCARD_RE.test(part)) {
|
|
255
|
+
return {
|
|
256
|
+
type: 'wildcard',
|
|
257
|
+
value: '$',
|
|
258
|
+
prefixSegment: undefined,
|
|
259
|
+
suffixSegment: undefined,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Handle regular pathname segment
|
|
184
264
|
return {
|
|
185
265
|
type: 'pathname',
|
|
186
266
|
value: part.includes('%25')
|
|
@@ -248,9 +328,13 @@ export function interpolatePath({
|
|
|
248
328
|
interpolatedPathSegments.map((segment) => {
|
|
249
329
|
if (segment.type === 'wildcard') {
|
|
250
330
|
usedParams._splat = params._splat
|
|
331
|
+
const segmentPrefix = segment.prefixSegment || ''
|
|
332
|
+
const segmentSuffix = segment.suffixSegment || ''
|
|
251
333
|
const value = encodeParam('_splat')
|
|
252
|
-
if (leaveWildcards)
|
|
253
|
-
|
|
334
|
+
if (leaveWildcards) {
|
|
335
|
+
return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}`
|
|
336
|
+
}
|
|
337
|
+
return `${segmentPrefix}${value}${segmentSuffix}`
|
|
254
338
|
}
|
|
255
339
|
|
|
256
340
|
if (segment.type === 'param') {
|
|
@@ -259,11 +343,14 @@ export function interpolatePath({
|
|
|
259
343
|
isMissingParams = true
|
|
260
344
|
}
|
|
261
345
|
usedParams[key] = params[key]
|
|
346
|
+
|
|
347
|
+
const segmentPrefix = segment.prefixSegment || ''
|
|
348
|
+
const segmentSuffix = segment.suffixSegment || ''
|
|
262
349
|
if (leaveParams) {
|
|
263
350
|
const value = encodeParam(segment.value)
|
|
264
|
-
return `${segment.value}${value ?? ''}`
|
|
351
|
+
return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}`
|
|
265
352
|
}
|
|
266
|
-
return encodeParam(key) ?? 'undefined'
|
|
353
|
+
return `${segmentPrefix}${encodeParam(key) ?? 'undefined'}${segmentSuffix}`
|
|
267
354
|
}
|
|
268
355
|
|
|
269
356
|
return segment.value
|
|
@@ -390,9 +477,57 @@ export function matchByPath(
|
|
|
390
477
|
|
|
391
478
|
if (routeSegment) {
|
|
392
479
|
if (routeSegment.type === 'wildcard') {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
480
|
+
// Capture all remaining segments for a wildcard
|
|
481
|
+
const remainingBaseSegments = baseSegments.slice(i)
|
|
482
|
+
|
|
483
|
+
let _splat: string
|
|
484
|
+
|
|
485
|
+
// If this is a wildcard with prefix/suffix, we need to handle the first segment specially
|
|
486
|
+
if (routeSegment.prefixSegment || routeSegment.suffixSegment) {
|
|
487
|
+
if (!baseSegment) return false
|
|
488
|
+
|
|
489
|
+
const prefix = routeSegment.prefixSegment || ''
|
|
490
|
+
const suffix = routeSegment.suffixSegment || ''
|
|
491
|
+
|
|
492
|
+
// Check if the base segment starts with prefix and ends with suffix
|
|
493
|
+
const baseValue = baseSegment.value
|
|
494
|
+
if ('prefixSegment' in routeSegment) {
|
|
495
|
+
if (!baseValue.startsWith(prefix)) {
|
|
496
|
+
return false
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if ('suffixSegment' in routeSegment) {
|
|
500
|
+
if (
|
|
501
|
+
!baseSegments[baseSegments.length - 1]?.value.endsWith(suffix)
|
|
502
|
+
) {
|
|
503
|
+
return false
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
let rejoinedSplat = decodeURI(
|
|
508
|
+
joinPaths(remainingBaseSegments.map((d) => d.value)),
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
// Remove the prefix and suffix from the rejoined splat
|
|
512
|
+
if (prefix && rejoinedSplat.startsWith(prefix)) {
|
|
513
|
+
rejoinedSplat = rejoinedSplat.slice(prefix.length)
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (suffix && rejoinedSplat.endsWith(suffix)) {
|
|
517
|
+
rejoinedSplat = rejoinedSplat.slice(
|
|
518
|
+
0,
|
|
519
|
+
rejoinedSplat.length - suffix.length,
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
_splat = rejoinedSplat
|
|
524
|
+
} else {
|
|
525
|
+
// If no prefix/suffix, just rejoin the remaining segments
|
|
526
|
+
_splat = decodeURI(
|
|
527
|
+
joinPaths(remainingBaseSegments.map((d) => d.value)),
|
|
528
|
+
)
|
|
529
|
+
}
|
|
530
|
+
|
|
396
531
|
// TODO: Deprecate *
|
|
397
532
|
params['*'] = _splat
|
|
398
533
|
params['_splat'] = _splat
|
|
@@ -426,11 +561,41 @@ export function matchByPath(
|
|
|
426
561
|
if (baseSegment.value === '/') {
|
|
427
562
|
return false
|
|
428
563
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
564
|
+
|
|
565
|
+
let _paramValue: string
|
|
566
|
+
|
|
567
|
+
// If this param has prefix/suffix, we need to extract the actual parameter value
|
|
568
|
+
if (routeSegment.prefixSegment || routeSegment.suffixSegment) {
|
|
569
|
+
const prefix = routeSegment.prefixSegment || ''
|
|
570
|
+
const suffix = routeSegment.suffixSegment || ''
|
|
571
|
+
|
|
572
|
+
// Check if the base segment starts with prefix and ends with suffix
|
|
573
|
+
const baseValue = baseSegment.value
|
|
574
|
+
if (prefix && !baseValue.startsWith(prefix)) {
|
|
575
|
+
return false
|
|
576
|
+
}
|
|
577
|
+
if (suffix && !baseValue.endsWith(suffix)) {
|
|
578
|
+
return false
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
let paramValue = baseValue
|
|
582
|
+
if (prefix && paramValue.startsWith(prefix)) {
|
|
583
|
+
paramValue = paramValue.slice(prefix.length)
|
|
584
|
+
}
|
|
585
|
+
if (suffix && paramValue.endsWith(suffix)) {
|
|
586
|
+
paramValue = paramValue.slice(
|
|
587
|
+
0,
|
|
588
|
+
paramValue.length - suffix.length,
|
|
589
|
+
)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
_paramValue = decodeURIComponent(paramValue)
|
|
593
|
+
} else {
|
|
594
|
+
// If no prefix/suffix, just decode the base segment value
|
|
595
|
+
_paramValue = decodeURIComponent(baseSegment.value)
|
|
433
596
|
}
|
|
597
|
+
|
|
598
|
+
params[routeSegment.value.substring(1)] = _paramValue
|
|
434
599
|
}
|
|
435
600
|
}
|
|
436
601
|
|
package/src/redirect.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { NavigateOptions } from './link'
|
|
2
2
|
import type { AnyRouter, RegisteredRouter } from './router'
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
export const tsrRedirectHeaderKey = 'X-Tanstack-Router-Redirect-Options'
|
|
4
5
|
|
|
5
6
|
export type AnyRedirect = Redirect<any, any, any, any, any>
|
|
6
7
|
|
|
@@ -13,6 +14,17 @@ export type Redirect<
|
|
|
13
14
|
TTo extends string | undefined = undefined,
|
|
14
15
|
TMaskFrom extends string = TFrom,
|
|
15
16
|
TMaskTo extends string = '.',
|
|
17
|
+
> = Response & {
|
|
18
|
+
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
19
|
+
redirectHandled?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type RedirectOptions<
|
|
23
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
24
|
+
TFrom extends string = string,
|
|
25
|
+
TTo extends string | undefined = undefined,
|
|
26
|
+
TMaskFrom extends string = TFrom,
|
|
27
|
+
TMaskTo extends string = '.',
|
|
16
28
|
> = {
|
|
17
29
|
href?: string
|
|
18
30
|
/**
|
|
@@ -42,12 +54,7 @@ export type ResolvedRedirect<
|
|
|
42
54
|
TTo extends string = '',
|
|
43
55
|
TMaskFrom extends string = TFrom,
|
|
44
56
|
TMaskTo extends string = '',
|
|
45
|
-
> =
|
|
46
|
-
Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
47
|
-
'code' | 'statusCode' | 'headers'
|
|
48
|
-
> & {
|
|
49
|
-
href: string
|
|
50
|
-
}
|
|
57
|
+
> = Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
51
58
|
|
|
52
59
|
export function redirect<
|
|
53
60
|
TRouter extends AnyRouter = RegisteredRouter,
|
|
@@ -56,30 +63,38 @@ export function redirect<
|
|
|
56
63
|
const TMaskFrom extends string = TFrom,
|
|
57
64
|
const TMaskTo extends string = '',
|
|
58
65
|
>(
|
|
59
|
-
opts:
|
|
66
|
+
opts: RedirectOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
60
67
|
): Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> {
|
|
61
|
-
;(opts as any).isRedirect = true
|
|
62
68
|
opts.statusCode = opts.statusCode || opts.code || 307
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
const headers = new Headers(opts.headers || {})
|
|
70
|
+
|
|
71
|
+
const response = new Response(null, {
|
|
72
|
+
status: opts.statusCode,
|
|
73
|
+
headers,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
;(response as Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>).options =
|
|
77
|
+
opts
|
|
71
78
|
|
|
72
79
|
if (opts.throw) {
|
|
73
|
-
throw
|
|
80
|
+
throw response
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
return
|
|
83
|
+
return response as Redirect<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
export function isRedirect(obj: any): obj is AnyRedirect {
|
|
80
|
-
return !!obj
|
|
87
|
+
return obj instanceof Response && !!(obj as any).options
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
export function isResolvedRedirect(obj: any): obj is
|
|
84
|
-
return
|
|
90
|
+
export function isResolvedRedirect(obj: any): obj is AnyRedirect {
|
|
91
|
+
return isRedirect(obj) && !!obj.options.href
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function parseRedirect(obj: any) {
|
|
95
|
+
if (typeof obj === 'object' && obj.isSerializedRedirect) {
|
|
96
|
+
return redirect(obj)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return undefined
|
|
85
100
|
}
|