@tanstack/router-core 1.136.3 → 1.136.5
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/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +2 -0
- package/dist/cjs/index.cjs +0 -5
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -4
- package/dist/cjs/lru-cache.cjs +5 -0
- package/dist/cjs/lru-cache.cjs.map +1 -1
- package/dist/cjs/lru-cache.d.cts +1 -0
- package/dist/cjs/new-process-route-tree.cjs +655 -0
- package/dist/cjs/new-process-route-tree.cjs.map +1 -0
- package/dist/cjs/new-process-route-tree.d.cts +177 -0
- package/dist/cjs/path.cjs +133 -434
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +3 -39
- package/dist/cjs/router.cjs +47 -98
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +7 -11
- package/dist/cjs/ssr/constants.cjs.map +1 -1
- package/dist/cjs/ssr/constants.d.cts +1 -0
- package/dist/cjs/ssr/ssr-client.cjs +2 -0
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-client.d.cts +4 -1
- package/dist/cjs/ssr/ssr-server.cjs +64 -12
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/tsrScript.cjs +1 -1
- package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
- package/dist/esm/Matches.d.ts +2 -0
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/index.d.ts +1 -4
- package/dist/esm/index.js +1 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lru-cache.d.ts +1 -0
- package/dist/esm/lru-cache.js +5 -0
- package/dist/esm/lru-cache.js.map +1 -1
- package/dist/esm/new-process-route-tree.d.ts +177 -0
- package/dist/esm/new-process-route-tree.js +655 -0
- package/dist/esm/new-process-route-tree.js.map +1 -0
- package/dist/esm/path.d.ts +3 -39
- package/dist/esm/path.js +133 -434
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/router.d.ts +7 -11
- package/dist/esm/router.js +48 -99
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/ssr/constants.d.ts +1 -0
- package/dist/esm/ssr/constants.js.map +1 -1
- package/dist/esm/ssr/ssr-client.d.ts +4 -1
- package/dist/esm/ssr/ssr-client.js +2 -0
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.js +64 -12
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/tsrScript.js +1 -1
- package/dist/esm/ssr/tsrScript.js.map +1 -1
- package/package.json +1 -1
- package/src/Matches.ts +2 -0
- package/src/index.ts +0 -6
- package/src/lru-cache.ts +6 -0
- package/src/new-process-route-tree.ts +1036 -0
- package/src/path.ts +168 -639
- package/src/router.ts +58 -126
- package/src/ssr/constants.ts +1 -0
- package/src/ssr/ssr-client.ts +10 -1
- package/src/ssr/ssr-server.ts +69 -12
- package/src/ssr/tsrScript.ts +4 -0
- package/dist/cjs/process-route-tree.cjs +0 -144
- package/dist/cjs/process-route-tree.cjs.map +0 -1
- package/dist/cjs/process-route-tree.d.cts +0 -18
- package/dist/esm/process-route-tree.d.ts +0 -18
- package/dist/esm/process-route-tree.js +0 -144
- package/dist/esm/process-route-tree.js.map +0 -1
- package/src/process-route-tree.ts +0 -241
package/dist/cjs/path.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.cjs","sources":["../../src/path.ts"],"sourcesContent":["import { last } from './utils'\nimport type { LRUCache } from './lru-cache'\nimport type { MatchLocation } from './RouterProvider'\nimport type { AnyPathParams } from './route'\n\nexport const SEGMENT_TYPE_PATHNAME = 0\nexport const SEGMENT_TYPE_PARAM = 1\nexport const SEGMENT_TYPE_WILDCARD = 2\nexport const SEGMENT_TYPE_OPTIONAL_PARAM = 3\n\nexport interface Segment {\n readonly type:\n | typeof SEGMENT_TYPE_PATHNAME\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM\n readonly value: string\n readonly prefixSegment?: string\n readonly suffixSegment?: string\n // Indicates if there is a static segment after this required/optional param\n readonly hasStaticAfter?: boolean\n}\n\n/** Join path segments, cleaning duplicate slashes between parts. */\n/** Join path segments, cleaning duplicate slashes between parts. */\nexport function joinPaths(paths: Array<string | undefined>) {\n return cleanPath(\n paths\n .filter((val) => {\n return val !== undefined\n })\n .join('/'),\n )\n}\n\n/** Remove repeated slashes from a path string. */\n/** Remove repeated slashes from a path string. */\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\n/** Trim leading slashes (except preserving root '/'). */\n/** Trim leading slashes (except preserving root '/'). */\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\n/** Trim trailing slashes (except preserving root '/'). */\n/** Trim trailing slashes (except preserving root '/'). */\nexport function trimPathRight(path: string) {\n return path === '/' ? path : path.replace(/\\/{1,}$/, '')\n}\n\n/** Trim both leading and trailing slashes. */\n/** Trim both leading and trailing slashes. */\nexport function trimPath(path: string) {\n return trimPathRight(trimPathLeft(path))\n}\n\n/** Remove a trailing slash from value when appropriate for comparisons. */\nexport function removeTrailingSlash(value: string, basepath: string): string {\n if (value?.endsWith('/') && value !== '/' && value !== `${basepath}/`) {\n return value.slice(0, -1)\n }\n return value\n}\n\n// intended to only compare path name\n// see the usage in the isActive under useLinkProps\n// /sample/path1 = /sample/path1/\n// /sample/path1/some <> /sample/path1\n/**\n * Compare two pathnames for exact equality after normalizing trailing slashes\n * relative to the provided `basepath`.\n */\n/**\n * Compare two pathnames for exact equality after normalizing trailing slashes\n * relative to the provided `basepath`.\n */\nexport function exactPathTest(\n pathName1: string,\n pathName2: string,\n basepath: string,\n): boolean {\n return (\n removeTrailingSlash(pathName1, basepath) ===\n removeTrailingSlash(pathName2, basepath)\n )\n}\n\n// When resolving relative paths, we treat all paths as if they are trailing slash\n// documents. All trailing slashes are removed after the path is resolved.\n// Here are a few examples:\n//\n// /a/b/c + ./d = /a/b/c/d\n// /a/b/c + ../d = /a/b/d\n// /a/b/c + ./d/ = /a/b/c/d\n// /a/b/c + ../d/ = /a/b/d\n// /a/b/c + ./ = /a/b/c\n//\n// Absolute paths that start with `/` short circuit the resolution process to the root\n// path.\n//\n// Here are some examples:\n//\n// /a/b/c + /d = /d\n// /a/b/c + /d/ = /d\n// /a/b/c + / = /\n//\n// Non-.-prefixed paths are still treated as relative paths, resolved like `./`\n//\n// Here are some examples:\n//\n// /a/b/c + d = /a/b/c/d\n// /a/b/c + d/ = /a/b/c/d\n// /a/b/c + d/e = /a/b/c/d/e\ninterface ResolvePathOptions {\n base: string\n to: string\n trailingSlash?: 'always' | 'never' | 'preserve'\n parseCache?: ParsePathnameCache\n}\n\nfunction segmentToString(segment: Segment): string {\n const { type, value } = segment\n if (type === SEGMENT_TYPE_PATHNAME) {\n return value\n }\n\n const { prefixSegment, suffixSegment } = segment\n\n if (type === SEGMENT_TYPE_PARAM) {\n const param = value.substring(1)\n if (prefixSegment && suffixSegment) {\n return `${prefixSegment}{$${param}}${suffixSegment}`\n } else if (prefixSegment) {\n return `${prefixSegment}{$${param}}`\n } else if (suffixSegment) {\n return `{$${param}}${suffixSegment}`\n }\n }\n\n if (type === SEGMENT_TYPE_OPTIONAL_PARAM) {\n const param = value.substring(1)\n if (prefixSegment && suffixSegment) {\n return `${prefixSegment}{-$${param}}${suffixSegment}`\n } else if (prefixSegment) {\n return `${prefixSegment}{-$${param}}`\n } else if (suffixSegment) {\n return `{-$${param}}${suffixSegment}`\n }\n return `{-$${param}}`\n }\n\n if (type === SEGMENT_TYPE_WILDCARD) {\n if (prefixSegment && suffixSegment) {\n return `${prefixSegment}{$}${suffixSegment}`\n } else if (prefixSegment) {\n return `${prefixSegment}{$}`\n } else if (suffixSegment) {\n return `{$}${suffixSegment}`\n }\n }\n\n // This case should never happen, should we throw instead?\n return value\n}\n\n/**\n * Resolve a destination path against a base, honoring trailing-slash policy\n * and supporting relative segments (`.`/`..`) and absolute `to` values.\n */\nexport function resolvePath({\n base,\n to,\n trailingSlash = 'never',\n parseCache,\n}: ResolvePathOptions) {\n let baseSegments = parsePathname(base, parseCache).slice()\n const toSegments = parsePathname(to, parseCache)\n\n if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {\n baseSegments.pop()\n }\n\n for (let index = 0, length = toSegments.length; index < length; index++) {\n const toSegment = toSegments[index]!\n const value = toSegment.value\n if (value === '/') {\n if (!index) {\n // Leading slash\n baseSegments = [toSegment]\n } else if (index === length - 1) {\n // Trailing Slash\n baseSegments.push(toSegment)\n } else {\n // ignore inter-slashes\n }\n } else if (value === '..') {\n baseSegments.pop()\n } else if (value === '.') {\n // ignore\n } else {\n baseSegments.push(toSegment)\n }\n }\n\n if (baseSegments.length > 1) {\n if (last(baseSegments)!.value === '/') {\n if (trailingSlash === 'never') {\n baseSegments.pop()\n }\n } else if (trailingSlash === 'always') {\n baseSegments.push({ type: SEGMENT_TYPE_PATHNAME, value: '/' })\n }\n }\n\n const segmentValues = baseSegments.map(segmentToString)\n // const joined = joinPaths([basepath, ...segmentValues])\n const joined = joinPaths(segmentValues)\n return joined\n}\n\nexport type ParsePathnameCache = LRUCache<string, ReadonlyArray<Segment>>\n\n/**\n * Parse a pathname into an array of typed segments used by the router's\n * matcher. Results are optionally cached via an LRU cache.\n */\n/**\n * Parse a pathname into an array of typed segments used by the router's\n * matcher. Results are optionally cached via an LRU cache.\n */\nexport const parsePathname = (\n pathname?: string,\n cache?: ParsePathnameCache,\n): ReadonlyArray<Segment> => {\n if (!pathname) return []\n const cached = cache?.get(pathname)\n if (cached) return cached\n const parsed = baseParsePathname(pathname)\n cache?.set(pathname, parsed)\n return parsed\n}\n\nconst PARAM_RE = /^\\$.{1,}$/ // $paramName\nconst PARAM_W_CURLY_BRACES_RE = /^(.*?)\\{(\\$[a-zA-Z_$][a-zA-Z0-9_$]*)\\}(.*)$/ // prefix{$paramName}suffix\nconst OPTIONAL_PARAM_W_CURLY_BRACES_RE =\n /^(.*?)\\{-(\\$[a-zA-Z_$][a-zA-Z0-9_$]*)\\}(.*)$/ // prefix{-$paramName}suffix\n\nconst WILDCARD_RE = /^\\$$/ // $\nconst WILDCARD_W_CURLY_BRACES_RE = /^(.*?)\\{\\$\\}(.*)$/ // prefix{$}suffix\n\n/**\n * Required: `/foo/$bar` ✅\n * Prefix and Suffix: `/foo/prefix${bar}suffix` ✅\n * Wildcard: `/foo/$` ✅\n * Wildcard with Prefix and Suffix: `/foo/prefix{$}suffix` ✅\n *\n * Optional param: `/foo/{-$bar}`\n * Optional param with Prefix and Suffix: `/foo/prefix{-$bar}suffix`\n\n * Future:\n * Optional named segment: `/foo/{bar}`\n * Optional named segment with Prefix and Suffix: `/foo/prefix{-bar}suffix`\n * Escape special characters:\n * - `/foo/[$]` - Static route\n * - `/foo/[$]{$foo} - Dynamic route with a static prefix of `$`\n * - `/foo/{$foo}[$]` - Dynamic route with a static suffix of `$`\n */\nfunction baseParsePathname(pathname: string): ReadonlyArray<Segment> {\n pathname = cleanPath(pathname)\n\n const segments: Array<Segment> = []\n\n if (pathname.slice(0, 1) === '/') {\n pathname = pathname.substring(1)\n segments.push({\n type: SEGMENT_TYPE_PATHNAME,\n value: '/',\n })\n }\n\n if (!pathname) {\n return segments\n }\n\n // Remove empty segments and '.' segments\n const split = pathname.split('/').filter(Boolean)\n\n segments.push(\n ...split.map((part): Segment => {\n // Check for wildcard with curly braces: prefix{$}suffix\n const wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE)\n if (wildcardBracesMatch) {\n const prefix = wildcardBracesMatch[1]\n const suffix = wildcardBracesMatch[2]\n return {\n type: SEGMENT_TYPE_WILDCARD,\n value: '$',\n prefixSegment: prefix || undefined,\n suffixSegment: suffix || undefined,\n }\n }\n\n // Check for optional parameter format: prefix{-$paramName}suffix\n const optionalParamBracesMatch = part.match(\n OPTIONAL_PARAM_W_CURLY_BRACES_RE,\n )\n if (optionalParamBracesMatch) {\n const prefix = optionalParamBracesMatch[1]\n const paramName = optionalParamBracesMatch[2]!\n const suffix = optionalParamBracesMatch[3]\n return {\n type: SEGMENT_TYPE_OPTIONAL_PARAM,\n value: paramName, // Now just $paramName (no prefix)\n prefixSegment: prefix || undefined,\n suffixSegment: suffix || undefined,\n }\n }\n\n // Check for the new parameter format: prefix{$paramName}suffix\n const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE)\n if (paramBracesMatch) {\n const prefix = paramBracesMatch[1]\n const paramName = paramBracesMatch[2]\n const suffix = paramBracesMatch[3]\n return {\n type: SEGMENT_TYPE_PARAM,\n value: '' + paramName,\n prefixSegment: prefix || undefined,\n suffixSegment: suffix || undefined,\n }\n }\n\n // Check for bare parameter format: $paramName (without curly braces)\n if (PARAM_RE.test(part)) {\n const paramName = part.substring(1)\n return {\n type: SEGMENT_TYPE_PARAM,\n value: '$' + paramName,\n prefixSegment: undefined,\n suffixSegment: undefined,\n }\n }\n\n // Check for bare wildcard: $ (without curly braces)\n if (WILDCARD_RE.test(part)) {\n return {\n type: SEGMENT_TYPE_WILDCARD,\n value: '$',\n prefixSegment: undefined,\n suffixSegment: undefined,\n }\n }\n\n // Handle regular pathname segment\n return {\n type: SEGMENT_TYPE_PATHNAME,\n value: part,\n }\n }),\n )\n\n if (pathname.slice(-1) === '/') {\n pathname = pathname.substring(1)\n segments.push({\n type: SEGMENT_TYPE_PATHNAME,\n value: '/',\n })\n }\n\n return segments\n}\n\ninterface InterpolatePathOptions {\n path?: string\n params: Record<string, unknown>\n // Map of encoded chars to decoded chars (e.g. '%40' -> '@') that should remain decoded in path params\n decodeCharMap?: Map<string, string>\n parseCache?: ParsePathnameCache\n}\n\ntype InterPolatePathResult = {\n interpolatedPath: string\n usedParams: Record<string, unknown>\n isMissingParams: boolean // true if any params were not available when being looked up in the params object\n}\n/**\n * Interpolate params and wildcards into a route path template.\n *\n * - Encodes params safely (configurable allowed characters)\n * - Supports `{-$optional}` segments, `{prefix{$id}suffix}` and `{$}` wildcards\n */\n/**\n * Interpolate params and wildcards into a route path template.\n * Encodes safely and supports optional params and custom decode char maps.\n */\nexport function interpolatePath({\n path,\n params,\n decodeCharMap,\n parseCache,\n}: InterpolatePathOptions): InterPolatePathResult {\n const interpolatedPathSegments = parsePathname(path, parseCache)\n\n function encodeParam(key: string): any {\n const value = params[key]\n const isValueString = typeof value === 'string'\n\n if (key === '*' || key === '_splat') {\n // the splat/catch-all routes shouldn't have the '/' encoded out\n return isValueString ? encodeURI(value) : value\n } else {\n return isValueString ? encodePathParam(value, decodeCharMap) : value\n }\n }\n\n // Tracking if any params are missing in the `params` object\n // when interpolating the path\n let isMissingParams = false\n\n const usedParams: Record<string, unknown> = {}\n const interpolatedPath = joinPaths(\n interpolatedPathSegments.map((segment) => {\n if (segment.type === SEGMENT_TYPE_PATHNAME) {\n return segment.value\n }\n\n if (segment.type === SEGMENT_TYPE_WILDCARD) {\n usedParams._splat = params._splat\n\n // TODO: Deprecate *\n usedParams['*'] = params._splat\n\n const segmentPrefix = segment.prefixSegment || ''\n const segmentSuffix = segment.suffixSegment || ''\n\n // Check if _splat parameter is missing. _splat could be missing if undefined or an empty string or some other falsy value.\n if (!params._splat) {\n isMissingParams = true\n // For missing splat parameters, just return the prefix and suffix without the wildcard\n // If there is a prefix or suffix, return them joined, otherwise omit the segment\n if (segmentPrefix || segmentSuffix) {\n return `${segmentPrefix}${segmentSuffix}`\n }\n return undefined\n }\n\n const value = encodeParam('_splat')\n\n return `${segmentPrefix}${value}${segmentSuffix}`\n }\n\n if (segment.type === SEGMENT_TYPE_PARAM) {\n const key = segment.value.substring(1)\n if (!isMissingParams && !(key in params)) {\n isMissingParams = true\n }\n usedParams[key] = params[key]\n\n const segmentPrefix = segment.prefixSegment || ''\n const segmentSuffix = segment.suffixSegment || ''\n\n return `${segmentPrefix}${encodeParam(key) ?? 'undefined'}${segmentSuffix}`\n }\n\n if (segment.type === SEGMENT_TYPE_OPTIONAL_PARAM) {\n const key = segment.value.substring(1)\n\n const segmentPrefix = segment.prefixSegment || ''\n const segmentSuffix = segment.suffixSegment || ''\n\n // Check if optional parameter is missing or undefined\n if (!(key in params) || params[key] == null) {\n // For optional params with prefix/suffix, keep the prefix/suffix but omit the param\n if (segmentPrefix || segmentSuffix) {\n return `${segmentPrefix}${segmentSuffix}`\n }\n // If no prefix/suffix, omit the entire segment\n return undefined\n }\n\n usedParams[key] = params[key]\n\n return `${segmentPrefix}${encodeParam(key) ?? ''}${segmentSuffix}`\n }\n\n return segment.value\n }),\n )\n return { usedParams, interpolatedPath, isMissingParams }\n}\n\nfunction encodePathParam(value: string, decodeCharMap?: Map<string, string>) {\n let encoded = encodeURIComponent(value)\n if (decodeCharMap) {\n for (const [encodedChar, char] of decodeCharMap) {\n encoded = encoded.replaceAll(encodedChar, char)\n }\n }\n return encoded\n}\n\n/**\n * Match a pathname against a route destination and return extracted params\n * or `undefined`. Uses the same parsing as the router for consistency.\n */\n/**\n * Match a pathname against a route destination and return extracted params\n * or `undefined`. Uses the same parsing as the router for consistency.\n */\nexport function matchPathname(\n currentPathname: string,\n matchLocation: Pick<MatchLocation, 'to' | 'fuzzy' | 'caseSensitive'>,\n parseCache?: ParsePathnameCache,\n): AnyPathParams | undefined {\n const pathParams = matchByPath(currentPathname, matchLocation, parseCache)\n // const searchMatched = matchBySearch(location.search, matchLocation)\n\n if (matchLocation.to && !pathParams) {\n return\n }\n\n return pathParams ?? {}\n}\n\n/** Low-level matcher that compares two path strings and extracts params. */\n/** Low-level matcher that compares two path strings and extracts params. */\nexport function matchByPath(\n from: string,\n {\n to,\n fuzzy,\n caseSensitive,\n }: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>,\n parseCache?: ParsePathnameCache,\n): Record<string, string> | undefined {\n const stringTo = to as string\n\n // Parse the from and to\n const baseSegments = parsePathname(\n from.startsWith('/') ? from : `/${from}`,\n parseCache,\n )\n const routeSegments = parsePathname(\n stringTo.startsWith('/') ? stringTo : `/${stringTo}`,\n parseCache,\n )\n\n const params: Record<string, string> = {}\n\n const result = isMatch(\n baseSegments,\n routeSegments,\n params,\n fuzzy,\n caseSensitive,\n )\n\n return result ? params : undefined\n}\n\nfunction isMatch(\n baseSegments: ReadonlyArray<Segment>,\n routeSegments: ReadonlyArray<Segment>,\n params: Record<string, string>,\n fuzzy?: boolean,\n caseSensitive?: boolean,\n): boolean {\n let baseIndex = 0\n let routeIndex = 0\n\n while (baseIndex < baseSegments.length || routeIndex < routeSegments.length) {\n const baseSegment = baseSegments[baseIndex]\n const routeSegment = routeSegments[routeIndex]\n\n if (routeSegment) {\n if (routeSegment.type === SEGMENT_TYPE_WILDCARD) {\n // Capture all remaining segments for a wildcard\n const remainingBaseSegments = baseSegments.slice(baseIndex)\n\n let _splat: string\n\n // If this is a wildcard with prefix/suffix, we need to handle the first segment specially\n if (routeSegment.prefixSegment || routeSegment.suffixSegment) {\n if (!baseSegment) return false\n\n const prefix = routeSegment.prefixSegment || ''\n const suffix = routeSegment.suffixSegment || ''\n\n // Check if the base segment starts with prefix and ends with suffix\n const baseValue = baseSegment.value\n if ('prefixSegment' in routeSegment) {\n if (!baseValue.startsWith(prefix)) {\n return false\n }\n }\n if ('suffixSegment' in routeSegment) {\n if (\n !baseSegments[baseSegments.length - 1]?.value.endsWith(suffix)\n ) {\n return false\n }\n }\n\n let rejoinedSplat = decodeURI(\n joinPaths(remainingBaseSegments.map((d) => d.value)),\n )\n\n // Remove the prefix and suffix from the rejoined splat\n if (prefix && rejoinedSplat.startsWith(prefix)) {\n rejoinedSplat = rejoinedSplat.slice(prefix.length)\n }\n\n if (suffix && rejoinedSplat.endsWith(suffix)) {\n rejoinedSplat = rejoinedSplat.slice(\n 0,\n rejoinedSplat.length - suffix.length,\n )\n }\n\n _splat = rejoinedSplat\n } else {\n // If no prefix/suffix, just rejoin the remaining segments\n _splat = decodeURI(\n joinPaths(remainingBaseSegments.map((d) => d.value)),\n )\n }\n\n // TODO: Deprecate *\n params['*'] = _splat\n params['_splat'] = _splat\n return true\n }\n\n if (routeSegment.type === SEGMENT_TYPE_PATHNAME) {\n if (routeSegment.value === '/' && !baseSegment?.value) {\n routeIndex++\n continue\n }\n\n if (baseSegment) {\n if (caseSensitive) {\n if (routeSegment.value !== baseSegment.value) {\n return false\n }\n } else if (\n routeSegment.value.toLowerCase() !== baseSegment.value.toLowerCase()\n ) {\n return false\n }\n baseIndex++\n routeIndex++\n continue\n } else {\n return false\n }\n }\n\n if (routeSegment.type === SEGMENT_TYPE_PARAM) {\n if (!baseSegment) {\n return false\n }\n\n if (baseSegment.value === '/') {\n return false\n }\n\n let _paramValue = ''\n let matched = false\n\n // If this param has prefix/suffix, we need to extract the actual parameter value\n if (routeSegment.prefixSegment || routeSegment.suffixSegment) {\n const prefix = routeSegment.prefixSegment || ''\n const suffix = routeSegment.suffixSegment || ''\n\n // Check if the base segment starts with prefix and ends with suffix\n const baseValue = baseSegment.value\n if (prefix && !baseValue.startsWith(prefix)) {\n return false\n }\n if (suffix && !baseValue.endsWith(suffix)) {\n return false\n }\n\n let paramValue = baseValue\n if (prefix && paramValue.startsWith(prefix)) {\n paramValue = paramValue.slice(prefix.length)\n }\n if (suffix && paramValue.endsWith(suffix)) {\n paramValue = paramValue.slice(0, paramValue.length - suffix.length)\n }\n\n _paramValue = decodeURIComponent(paramValue)\n matched = true\n } else {\n // If no prefix/suffix, just decode the base segment value\n _paramValue = decodeURIComponent(baseSegment.value)\n matched = true\n }\n\n if (matched) {\n params[routeSegment.value.substring(1)] = _paramValue\n baseIndex++\n }\n\n routeIndex++\n continue\n }\n\n if (routeSegment.type === SEGMENT_TYPE_OPTIONAL_PARAM) {\n // Optional parameters can be missing - don't fail the match\n if (!baseSegment) {\n // No base segment for optional param - skip this route segment\n routeIndex++\n continue\n }\n\n if (baseSegment.value === '/') {\n // Skip slash segments for optional params\n routeIndex++\n continue\n }\n\n let _paramValue = ''\n let matched = false\n\n // If this optional param has prefix/suffix, we need to extract the actual parameter value\n if (routeSegment.prefixSegment || routeSegment.suffixSegment) {\n const prefix = routeSegment.prefixSegment || ''\n const suffix = routeSegment.suffixSegment || ''\n\n // Check if the base segment starts with prefix and ends with suffix\n const baseValue = baseSegment.value\n if (\n (!prefix || baseValue.startsWith(prefix)) &&\n (!suffix || baseValue.endsWith(suffix))\n ) {\n let paramValue = baseValue\n if (prefix && paramValue.startsWith(prefix)) {\n paramValue = paramValue.slice(prefix.length)\n }\n if (suffix && paramValue.endsWith(suffix)) {\n paramValue = paramValue.slice(\n 0,\n paramValue.length - suffix.length,\n )\n }\n\n _paramValue = decodeURIComponent(paramValue)\n matched = true\n }\n } else {\n // For optional params without prefix/suffix, we need to check if the current\n // base segment should match this optional param or a later route segment\n\n // Look ahead to see if there's a later route segment that matches the current base segment\n let shouldMatchOptional = true\n for (\n let lookAhead = routeIndex + 1;\n lookAhead < routeSegments.length;\n lookAhead++\n ) {\n const futureRouteSegment = routeSegments[lookAhead]\n if (\n futureRouteSegment?.type === SEGMENT_TYPE_PATHNAME &&\n futureRouteSegment.value === baseSegment.value\n ) {\n // The current base segment matches a future pathname segment,\n // so we should skip this optional parameter\n shouldMatchOptional = false\n break\n }\n\n // If we encounter a required param or wildcard, stop looking ahead\n if (\n futureRouteSegment?.type === SEGMENT_TYPE_PARAM ||\n futureRouteSegment?.type === SEGMENT_TYPE_WILDCARD\n ) {\n if (baseSegments.length < routeSegments.length) {\n shouldMatchOptional = false\n }\n break\n }\n }\n\n if (shouldMatchOptional) {\n // If no prefix/suffix, just decode the base segment value\n _paramValue = decodeURIComponent(baseSegment.value)\n matched = true\n }\n }\n\n if (matched) {\n params[routeSegment.value.substring(1)] = _paramValue\n baseIndex++\n }\n\n routeIndex++\n continue\n }\n }\n\n // If we have base segments left but no route segments, it's a fuzzy match\n if (baseIndex < baseSegments.length && routeIndex >= routeSegments.length) {\n params['**'] = joinPaths(\n baseSegments.slice(baseIndex).map((d) => d.value),\n )\n return !!fuzzy && routeSegments[routeSegments.length - 1]?.value !== '/'\n }\n\n // If we have route segments left but no base segments, check if remaining are optional\n if (routeIndex < routeSegments.length && baseIndex >= baseSegments.length) {\n // Check if all remaining route segments are optional\n for (let i = routeIndex; i < routeSegments.length; i++) {\n if (routeSegments[i]?.type !== SEGMENT_TYPE_OPTIONAL_PARAM) {\n return false\n }\n }\n // All remaining are optional, so we can finish\n break\n }\n\n break\n }\n\n return true\n}\n"],"names":["last"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"path.cjs","sources":["../../src/path.ts"],"sourcesContent":["import { last } from './utils'\nimport {\n SEGMENT_TYPE_OPTIONAL_PARAM,\n SEGMENT_TYPE_PARAM,\n SEGMENT_TYPE_PATHNAME,\n SEGMENT_TYPE_WILDCARD,\n parseSegment,\n} from './new-process-route-tree'\nimport type { LRUCache } from './lru-cache'\n\n/** Join path segments, cleaning duplicate slashes between parts. */\n/** Join path segments, cleaning duplicate slashes between parts. */\nexport function joinPaths(paths: Array<string | undefined>) {\n return cleanPath(\n paths\n .filter((val) => {\n return val !== undefined\n })\n .join('/'),\n )\n}\n\n/** Remove repeated slashes from a path string. */\n/** Remove repeated slashes from a path string. */\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\n/** Trim leading slashes (except preserving root '/'). */\n/** Trim leading slashes (except preserving root '/'). */\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\n/** Trim trailing slashes (except preserving root '/'). */\n/** Trim trailing slashes (except preserving root '/'). */\nexport function trimPathRight(path: string) {\n return path === '/' ? path : path.replace(/\\/{1,}$/, '')\n}\n\n/** Trim both leading and trailing slashes. */\n/** Trim both leading and trailing slashes. */\nexport function trimPath(path: string) {\n return trimPathRight(trimPathLeft(path))\n}\n\n/** Remove a trailing slash from value when appropriate for comparisons. */\nexport function removeTrailingSlash(value: string, basepath: string): string {\n if (value?.endsWith('/') && value !== '/' && value !== `${basepath}/`) {\n return value.slice(0, -1)\n }\n return value\n}\n\n// intended to only compare path name\n// see the usage in the isActive under useLinkProps\n// /sample/path1 = /sample/path1/\n// /sample/path1/some <> /sample/path1\n/**\n * Compare two pathnames for exact equality after normalizing trailing slashes\n * relative to the provided `basepath`.\n */\n/**\n * Compare two pathnames for exact equality after normalizing trailing slashes\n * relative to the provided `basepath`.\n */\nexport function exactPathTest(\n pathName1: string,\n pathName2: string,\n basepath: string,\n): boolean {\n return (\n removeTrailingSlash(pathName1, basepath) ===\n removeTrailingSlash(pathName2, basepath)\n )\n}\n\n// When resolving relative paths, we treat all paths as if they are trailing slash\n// documents. All trailing slashes are removed after the path is resolved.\n// Here are a few examples:\n//\n// /a/b/c + ./d = /a/b/c/d\n// /a/b/c + ../d = /a/b/d\n// /a/b/c + ./d/ = /a/b/c/d\n// /a/b/c + ../d/ = /a/b/d\n// /a/b/c + ./ = /a/b/c\n//\n// Absolute paths that start with `/` short circuit the resolution process to the root\n// path.\n//\n// Here are some examples:\n//\n// /a/b/c + /d = /d\n// /a/b/c + /d/ = /d\n// /a/b/c + / = /\n//\n// Non-.-prefixed paths are still treated as relative paths, resolved like `./`\n//\n// Here are some examples:\n//\n// /a/b/c + d = /a/b/c/d\n// /a/b/c + d/ = /a/b/c/d\n// /a/b/c + d/e = /a/b/c/d/e\ninterface ResolvePathOptions {\n base: string\n to: string\n trailingSlash?: 'always' | 'never' | 'preserve'\n cache?: LRUCache<string, string>\n}\n\n/**\n * Resolve a destination path against a base, honoring trailing-slash policy\n * and supporting relative segments (`.`/`..`) and absolute `to` values.\n */\nexport function resolvePath({\n base,\n to,\n trailingSlash = 'never',\n cache,\n}: ResolvePathOptions) {\n const isAbsolute = to.startsWith('/')\n const isBase = !isAbsolute && to === '.'\n\n let key\n if (cache) {\n // `trailingSlash` is static per router, so it doesn't need to be part of the cache key\n key = isAbsolute ? to : isBase ? base : base + '\\0' + to\n const cached = cache.get(key)\n if (cached) return cached\n }\n\n let baseSegments: Array<string>\n if (isBase) {\n baseSegments = base.split('/')\n } else if (isAbsolute) {\n baseSegments = to.split('/')\n } else {\n baseSegments = base.split('/')\n while (baseSegments.length > 1 && last(baseSegments) === '') {\n baseSegments.pop()\n }\n\n const toSegments = to.split('/')\n for (let index = 0, length = toSegments.length; index < length; index++) {\n const value = toSegments[index]!\n if (value === '') {\n if (!index) {\n // Leading slash\n baseSegments = [value]\n } else if (index === length - 1) {\n // Trailing Slash\n baseSegments.push(value)\n } else {\n // ignore inter-slashes\n }\n } else if (value === '..') {\n baseSegments.pop()\n } else if (value === '.') {\n // ignore\n } else {\n baseSegments.push(value)\n }\n }\n }\n\n if (baseSegments.length > 1) {\n if (last(baseSegments) === '') {\n if (trailingSlash === 'never') {\n baseSegments.pop()\n }\n } else if (trailingSlash === 'always') {\n baseSegments.push('')\n }\n }\n\n let segment\n let joined = ''\n for (let i = 0; i < baseSegments.length; i++) {\n if (i > 0) joined += '/'\n const part = baseSegments[i]!\n if (!part) continue\n segment = parseSegment(part, 0, segment)\n const kind = segment[0]\n if (kind === SEGMENT_TYPE_PATHNAME) {\n joined += part\n continue\n }\n const end = segment[5]\n const prefix = part.substring(0, segment[1])\n const suffix = part.substring(segment[4], end)\n const value = part.substring(segment[2], segment[3])\n if (kind === SEGMENT_TYPE_PARAM) {\n joined += prefix || suffix ? `${prefix}{$${value}}${suffix}` : `$${value}`\n } else if (kind === SEGMENT_TYPE_WILDCARD) {\n joined += prefix || suffix ? `${prefix}{$}${suffix}` : '$'\n } else {\n // SEGMENT_TYPE_OPTIONAL_PARAM\n joined += `${prefix}{-$${value}}${suffix}`\n }\n }\n joined = cleanPath(joined)\n const result = joined || '/'\n if (key && cache) cache.set(key, result)\n return result\n}\n\ninterface InterpolatePathOptions {\n path?: string\n params: Record<string, unknown>\n // Map of encoded chars to decoded chars (e.g. '%40' -> '@') that should remain decoded in path params\n decodeCharMap?: Map<string, string>\n}\n\ntype InterPolatePathResult = {\n interpolatedPath: string\n usedParams: Record<string, unknown>\n isMissingParams: boolean // true if any params were not available when being looked up in the params object\n}\n\nfunction encodeParam(\n key: string,\n params: InterpolatePathOptions['params'],\n decodeCharMap: InterpolatePathOptions['decodeCharMap'],\n): any {\n const value = params[key]\n if (typeof value !== 'string') return value\n\n if (key === '_splat') {\n // the splat/catch-all routes shouldn't have the '/' encoded out\n return encodeURI(value)\n } else {\n return encodePathParam(value, decodeCharMap)\n }\n}\n\n/**\n * Interpolate params and wildcards into a route path template.\n *\n * - Encodes params safely (configurable allowed characters)\n * - Supports `{-$optional}` segments, `{prefix{$id}suffix}` and `{$}` wildcards\n */\n/**\n * Interpolate params and wildcards into a route path template.\n * Encodes safely and supports optional params and custom decode char maps.\n */\nexport function interpolatePath({\n path,\n params,\n decodeCharMap,\n}: InterpolatePathOptions): InterPolatePathResult {\n // Tracking if any params are missing in the `params` object\n // when interpolating the path\n let isMissingParams = false\n const usedParams: Record<string, unknown> = {}\n\n if (!path || path === '/')\n return { interpolatedPath: '/', usedParams, isMissingParams }\n if (!path.includes('$'))\n return { interpolatedPath: path, usedParams, isMissingParams }\n\n const length = path.length\n let cursor = 0\n let segment\n let joined = ''\n while (cursor < length) {\n const start = cursor\n segment = parseSegment(path, start, segment)\n const end = segment[5]\n cursor = end + 1\n\n if (start === end) continue\n\n const kind = segment[0]\n\n if (kind === SEGMENT_TYPE_PATHNAME) {\n joined += '/' + path.substring(start, end)\n continue\n }\n\n if (kind === SEGMENT_TYPE_WILDCARD) {\n const splat = params._splat\n usedParams._splat = splat\n // TODO: Deprecate *\n usedParams['*'] = splat\n\n const prefix = path.substring(start, segment[1])\n const suffix = path.substring(segment[4], end)\n\n // Check if _splat parameter is missing. _splat could be missing if undefined or an empty string or some other falsy value.\n if (!splat) {\n isMissingParams = true\n // For missing splat parameters, just return the prefix and suffix without the wildcard\n // If there is a prefix or suffix, return them joined, otherwise omit the segment\n if (prefix || suffix) {\n joined += '/' + prefix + suffix\n }\n continue\n }\n\n const value = encodeParam('_splat', params, decodeCharMap)\n joined += '/' + prefix + value + suffix\n continue\n }\n\n if (kind === SEGMENT_TYPE_PARAM) {\n const key = path.substring(segment[2], segment[3])\n if (!isMissingParams && !(key in params)) {\n isMissingParams = true\n }\n usedParams[key] = params[key]\n\n const prefix = path.substring(start, segment[1])\n const suffix = path.substring(segment[4], end)\n const value = encodeParam(key, params, decodeCharMap) ?? 'undefined'\n joined += '/' + prefix + value + suffix\n continue\n }\n\n if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n const key = path.substring(segment[2], segment[3])\n const prefix = path.substring(start, segment[1])\n const suffix = path.substring(segment[4], end)\n const valueRaw = params[key]\n\n // Check if optional parameter is missing or undefined\n if (valueRaw == null) {\n if (prefix || suffix) {\n // For optional params with prefix/suffix, keep the prefix/suffix but omit the param\n joined += '/' + prefix + suffix\n }\n // If no prefix/suffix, omit the entire segment\n continue\n }\n\n usedParams[key] = valueRaw\n\n const value = encodeParam(key, params, decodeCharMap) ?? ''\n joined += '/' + prefix + value + suffix\n continue\n }\n }\n\n if (path.endsWith('/')) joined += '/'\n\n const interpolatedPath = joined || '/'\n\n return { usedParams, interpolatedPath, isMissingParams }\n}\n\nfunction encodePathParam(value: string, decodeCharMap?: Map<string, string>) {\n let encoded = encodeURIComponent(value)\n if (decodeCharMap) {\n for (const [encodedChar, char] of decodeCharMap) {\n encoded = encoded.replaceAll(encodedChar, char)\n }\n }\n return encoded\n}\n"],"names":["last","parseSegment","SEGMENT_TYPE_PATHNAME","SEGMENT_TYPE_PARAM","SEGMENT_TYPE_WILDCARD","SEGMENT_TYPE_OPTIONAL_PARAM"],"mappings":"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"}
|
package/dist/cjs/path.d.cts
CHANGED
|
@@ -1,17 +1,4 @@
|
|
|
1
1
|
import { LRUCache } from './lru-cache.cjs';
|
|
2
|
-
import { MatchLocation } from './RouterProvider.cjs';
|
|
3
|
-
import { AnyPathParams } from './route.cjs';
|
|
4
|
-
export declare const SEGMENT_TYPE_PATHNAME = 0;
|
|
5
|
-
export declare const SEGMENT_TYPE_PARAM = 1;
|
|
6
|
-
export declare const SEGMENT_TYPE_WILDCARD = 2;
|
|
7
|
-
export declare const SEGMENT_TYPE_OPTIONAL_PARAM = 3;
|
|
8
|
-
export interface Segment {
|
|
9
|
-
readonly type: typeof SEGMENT_TYPE_PATHNAME | typeof SEGMENT_TYPE_PARAM | typeof SEGMENT_TYPE_WILDCARD | typeof SEGMENT_TYPE_OPTIONAL_PARAM;
|
|
10
|
-
readonly value: string;
|
|
11
|
-
readonly prefixSegment?: string;
|
|
12
|
-
readonly suffixSegment?: string;
|
|
13
|
-
readonly hasStaticAfter?: boolean;
|
|
14
|
-
}
|
|
15
2
|
/** Join path segments, cleaning duplicate slashes between parts. */
|
|
16
3
|
/** Join path segments, cleaning duplicate slashes between parts. */
|
|
17
4
|
export declare function joinPaths(paths: Array<string | undefined>): string;
|
|
@@ -42,28 +29,17 @@ interface ResolvePathOptions {
|
|
|
42
29
|
base: string;
|
|
43
30
|
to: string;
|
|
44
31
|
trailingSlash?: 'always' | 'never' | 'preserve';
|
|
45
|
-
|
|
32
|
+
cache?: LRUCache<string, string>;
|
|
46
33
|
}
|
|
47
34
|
/**
|
|
48
35
|
* Resolve a destination path against a base, honoring trailing-slash policy
|
|
49
36
|
* and supporting relative segments (`.`/`..`) and absolute `to` values.
|
|
50
37
|
*/
|
|
51
|
-
export declare function resolvePath({ base, to, trailingSlash,
|
|
52
|
-
export type ParsePathnameCache = LRUCache<string, ReadonlyArray<Segment>>;
|
|
53
|
-
/**
|
|
54
|
-
* Parse a pathname into an array of typed segments used by the router's
|
|
55
|
-
* matcher. Results are optionally cached via an LRU cache.
|
|
56
|
-
*/
|
|
57
|
-
/**
|
|
58
|
-
* Parse a pathname into an array of typed segments used by the router's
|
|
59
|
-
* matcher. Results are optionally cached via an LRU cache.
|
|
60
|
-
*/
|
|
61
|
-
export declare const parsePathname: (pathname?: string, cache?: ParsePathnameCache) => ReadonlyArray<Segment>;
|
|
38
|
+
export declare function resolvePath({ base, to, trailingSlash, cache, }: ResolvePathOptions): string;
|
|
62
39
|
interface InterpolatePathOptions {
|
|
63
40
|
path?: string;
|
|
64
41
|
params: Record<string, unknown>;
|
|
65
42
|
decodeCharMap?: Map<string, string>;
|
|
66
|
-
parseCache?: ParsePathnameCache;
|
|
67
43
|
}
|
|
68
44
|
type InterPolatePathResult = {
|
|
69
45
|
interpolatedPath: string;
|
|
@@ -80,17 +56,5 @@ type InterPolatePathResult = {
|
|
|
80
56
|
* Interpolate params and wildcards into a route path template.
|
|
81
57
|
* Encodes safely and supports optional params and custom decode char maps.
|
|
82
58
|
*/
|
|
83
|
-
export declare function interpolatePath({ path, params, decodeCharMap,
|
|
84
|
-
/**
|
|
85
|
-
* Match a pathname against a route destination and return extracted params
|
|
86
|
-
* or `undefined`. Uses the same parsing as the router for consistency.
|
|
87
|
-
*/
|
|
88
|
-
/**
|
|
89
|
-
* Match a pathname against a route destination and return extracted params
|
|
90
|
-
* or `undefined`. Uses the same parsing as the router for consistency.
|
|
91
|
-
*/
|
|
92
|
-
export declare function matchPathname(currentPathname: string, matchLocation: Pick<MatchLocation, 'to' | 'fuzzy' | 'caseSensitive'>, parseCache?: ParsePathnameCache): AnyPathParams | undefined;
|
|
93
|
-
/** Low-level matcher that compares two path strings and extracts params. */
|
|
94
|
-
/** Low-level matcher that compares two path strings and extracts params. */
|
|
95
|
-
export declare function matchByPath(from: string, { to, fuzzy, caseSensitive, }: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>, parseCache?: ParsePathnameCache): Record<string, string> | undefined;
|
|
59
|
+
export declare function interpolatePath({ path, params, decodeCharMap, }: InterpolatePathOptions): InterPolatePathResult;
|
|
96
60
|
export {};
|
package/dist/cjs/router.cjs
CHANGED
|
@@ -3,14 +3,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const store = require("@tanstack/store");
|
|
4
4
|
const history = require("@tanstack/history");
|
|
5
5
|
const utils = require("./utils.cjs");
|
|
6
|
-
const
|
|
6
|
+
const newProcessRouteTree = require("./new-process-route-tree.cjs");
|
|
7
7
|
const path = require("./path.cjs");
|
|
8
|
+
const lruCache = require("./lru-cache.cjs");
|
|
8
9
|
const notFound = require("./not-found.cjs");
|
|
9
10
|
const scrollRestoration = require("./scroll-restoration.cjs");
|
|
10
11
|
const searchParams = require("./searchParams.cjs");
|
|
11
12
|
const root = require("./root.cjs");
|
|
12
13
|
const redirect = require("./redirect.cjs");
|
|
13
|
-
const lruCache = require("./lru-cache.cjs");
|
|
14
14
|
const loadMatches = require("./load-matches.cjs");
|
|
15
15
|
const rewrite = require("./rewrite.cjs");
|
|
16
16
|
function defaultSerializeError(err) {
|
|
@@ -157,17 +157,21 @@ class RouterCore {
|
|
|
157
157
|
);
|
|
158
158
|
};
|
|
159
159
|
this.buildRouteTree = () => {
|
|
160
|
-
const { routesById, routesByPath,
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
const { routesById, routesByPath, processedTree } = newProcessRouteTree.processRouteTree(
|
|
161
|
+
this.routeTree,
|
|
162
|
+
this.options.caseSensitive,
|
|
163
|
+
(route, i) => {
|
|
163
164
|
route.init({
|
|
164
165
|
originalIndex: i
|
|
165
166
|
});
|
|
166
167
|
}
|
|
167
|
-
|
|
168
|
+
);
|
|
169
|
+
if (this.options.routeMasks) {
|
|
170
|
+
newProcessRouteTree.processRouteMasks(this.options.routeMasks, processedTree);
|
|
171
|
+
}
|
|
168
172
|
this.routesById = routesById;
|
|
169
173
|
this.routesByPath = routesByPath;
|
|
170
|
-
this.
|
|
174
|
+
this.processedTree = processedTree;
|
|
171
175
|
const notFoundRoute = this.options.notFoundRoute;
|
|
172
176
|
if (notFoundRoute) {
|
|
173
177
|
notFoundRoute.init({
|
|
@@ -230,12 +234,13 @@ class RouterCore {
|
|
|
230
234
|
}
|
|
231
235
|
return location;
|
|
232
236
|
};
|
|
237
|
+
this.resolvePathCache = lruCache.createLRUCache(1e3);
|
|
233
238
|
this.resolvePathWithBase = (from, path$1) => {
|
|
234
239
|
const resolvedPath = path.resolvePath({
|
|
235
240
|
base: from,
|
|
236
241
|
to: path.cleanPath(path$1),
|
|
237
242
|
trailingSlash: this.options.trailingSlash,
|
|
238
|
-
|
|
243
|
+
cache: this.resolvePathCache
|
|
239
244
|
});
|
|
240
245
|
return resolvedPath;
|
|
241
246
|
};
|
|
@@ -251,16 +256,11 @@ class RouterCore {
|
|
|
251
256
|
}
|
|
252
257
|
return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
|
|
253
258
|
};
|
|
254
|
-
this.
|
|
255
|
-
this.getMatchedRoutes = (pathname, routePathname) => {
|
|
259
|
+
this.getMatchedRoutes = (pathname) => {
|
|
256
260
|
return getMatchedRoutes({
|
|
257
261
|
pathname,
|
|
258
|
-
routePathname,
|
|
259
|
-
caseSensitive: this.options.caseSensitive,
|
|
260
|
-
routesByPath: this.routesByPath,
|
|
261
262
|
routesById: this.routesById,
|
|
262
|
-
|
|
263
|
-
parseCache: this.parsePathnameCache
|
|
263
|
+
processedTree: this.processedTree
|
|
264
264
|
});
|
|
265
265
|
};
|
|
266
266
|
this.cancelMatch = (id) => {
|
|
@@ -294,10 +294,7 @@ class RouterCore {
|
|
|
294
294
|
});
|
|
295
295
|
const lastMatch = utils.last(allCurrentLocationMatches);
|
|
296
296
|
if (dest.from && process.env.NODE_ENV !== "production" && dest._isNavigate) {
|
|
297
|
-
const allFromMatches = this.getMatchedRoutes(
|
|
298
|
-
dest.from,
|
|
299
|
-
void 0
|
|
300
|
-
).matchedRoutes;
|
|
297
|
+
const allFromMatches = this.getMatchedRoutes(dest.from).matchedRoutes;
|
|
301
298
|
const matchedFrom = utils.findLast(allCurrentLocationMatches, (d) => {
|
|
302
299
|
return comparePaths(d.fullPath, dest.from);
|
|
303
300
|
});
|
|
@@ -319,8 +316,7 @@ class RouterCore {
|
|
|
319
316
|
);
|
|
320
317
|
const interpolatedNextTo = path.interpolatePath({
|
|
321
318
|
path: nextTo,
|
|
322
|
-
params: nextParams
|
|
323
|
-
parseCache: this.parsePathnameCache
|
|
319
|
+
params: nextParams
|
|
324
320
|
}).interpolatedPath;
|
|
325
321
|
const destRoutes = this.matchRoutes(interpolatedNextTo, void 0, {
|
|
326
322
|
_buildLocation: true
|
|
@@ -341,8 +337,7 @@ class RouterCore {
|
|
|
341
337
|
path.interpolatePath({
|
|
342
338
|
path: nextTo,
|
|
343
339
|
params: nextParams,
|
|
344
|
-
decodeCharMap: this.pathParamsDecodeCharMap
|
|
345
|
-
parseCache: this.parsePathnameCache
|
|
340
|
+
decodeCharMap: this.pathParamsDecodeCharMap
|
|
346
341
|
}).interpolatedPath
|
|
347
342
|
);
|
|
348
343
|
let nextSearch = fromSearch;
|
|
@@ -395,31 +390,22 @@ class RouterCore {
|
|
|
395
390
|
const next = build(dest);
|
|
396
391
|
let maskedNext = maskedDest ? build(maskedDest) : void 0;
|
|
397
392
|
if (!maskedNext) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
const match =
|
|
393
|
+
const params = {};
|
|
394
|
+
if (this.options.routeMasks) {
|
|
395
|
+
const match = newProcessRouteTree.findFlatMatch(
|
|
401
396
|
next.pathname,
|
|
402
|
-
|
|
403
|
-
to: d.from,
|
|
404
|
-
caseSensitive: false,
|
|
405
|
-
fuzzy: false
|
|
406
|
-
},
|
|
407
|
-
this.parsePathnameCache
|
|
397
|
+
this.processedTree
|
|
408
398
|
);
|
|
409
399
|
if (match) {
|
|
410
|
-
params
|
|
411
|
-
|
|
400
|
+
Object.assign(params, match.params);
|
|
401
|
+
const { from: _from, ...maskProps } = match.route;
|
|
402
|
+
maskedDest = {
|
|
403
|
+
from: opts.from,
|
|
404
|
+
...maskProps,
|
|
405
|
+
params
|
|
406
|
+
};
|
|
407
|
+
maskedNext = build(maskedDest);
|
|
412
408
|
}
|
|
413
|
-
return false;
|
|
414
|
-
});
|
|
415
|
-
if (foundMask) {
|
|
416
|
-
const { from: _from, ...maskProps } = foundMask;
|
|
417
|
-
maskedDest = {
|
|
418
|
-
from: opts.from,
|
|
419
|
-
...maskProps,
|
|
420
|
-
params
|
|
421
|
-
};
|
|
422
|
-
maskedNext = build(maskedDest);
|
|
423
409
|
}
|
|
424
410
|
}
|
|
425
411
|
if (maskedNext) {
|
|
@@ -926,26 +912,25 @@ class RouterCore {
|
|
|
926
912
|
}
|
|
927
913
|
const pending = opts?.pending === void 0 ? !this.state.isLoading : opts.pending;
|
|
928
914
|
const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location;
|
|
929
|
-
const match =
|
|
915
|
+
const match = newProcessRouteTree.findSingleMatch(
|
|
916
|
+
next.pathname,
|
|
917
|
+
opts?.caseSensitive ?? false,
|
|
918
|
+
opts?.fuzzy ?? false,
|
|
930
919
|
baseLocation.pathname,
|
|
931
|
-
|
|
932
|
-
...opts,
|
|
933
|
-
to: next.pathname
|
|
934
|
-
},
|
|
935
|
-
this.parsePathnameCache
|
|
920
|
+
this.processedTree
|
|
936
921
|
);
|
|
937
922
|
if (!match) {
|
|
938
923
|
return false;
|
|
939
924
|
}
|
|
940
925
|
if (location.params) {
|
|
941
|
-
if (!utils.deepEqual(match, location.params, { partial: true })) {
|
|
926
|
+
if (!utils.deepEqual(match.params, location.params, { partial: true })) {
|
|
942
927
|
return false;
|
|
943
928
|
}
|
|
944
929
|
}
|
|
945
|
-
if (
|
|
946
|
-
return utils.deepEqual(baseLocation.search, next.search, { partial: true }) ? match : false;
|
|
930
|
+
if (opts?.includeSearch ?? true) {
|
|
931
|
+
return utils.deepEqual(baseLocation.search, next.search, { partial: true }) ? match.params : false;
|
|
947
932
|
}
|
|
948
|
-
return match;
|
|
933
|
+
return match.params;
|
|
949
934
|
};
|
|
950
935
|
this.hasNotFoundMatch = () => {
|
|
951
936
|
return this.__store.state.matches.some(
|
|
@@ -981,8 +966,7 @@ class RouterCore {
|
|
|
981
966
|
}
|
|
982
967
|
matchRoutesInternal(next, opts) {
|
|
983
968
|
const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes(
|
|
984
|
-
next.pathname
|
|
985
|
-
opts?.dest?.to
|
|
969
|
+
next.pathname
|
|
986
970
|
);
|
|
987
971
|
let isGlobalNotFound = false;
|
|
988
972
|
if (
|
|
@@ -1227,51 +1211,16 @@ function validateSearch(validateSearch2, input) {
|
|
|
1227
1211
|
}
|
|
1228
1212
|
function getMatchedRoutes({
|
|
1229
1213
|
pathname,
|
|
1230
|
-
routePathname,
|
|
1231
|
-
caseSensitive,
|
|
1232
|
-
routesByPath,
|
|
1233
1214
|
routesById,
|
|
1234
|
-
|
|
1235
|
-
parseCache
|
|
1215
|
+
processedTree
|
|
1236
1216
|
}) {
|
|
1237
|
-
|
|
1217
|
+
const routeParams = {};
|
|
1238
1218
|
const trimmedPath = path.trimPathRight(pathname);
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
caseSensitive: route.options?.caseSensitive ?? caseSensitive,
|
|
1245
|
-
// we need fuzzy matching for `notFoundMode: 'fuzzy'`
|
|
1246
|
-
fuzzy: true
|
|
1247
|
-
},
|
|
1248
|
-
parseCache
|
|
1249
|
-
);
|
|
1250
|
-
return result;
|
|
1251
|
-
};
|
|
1252
|
-
let foundRoute = routePathname !== void 0 ? routesByPath[routePathname] : void 0;
|
|
1253
|
-
if (foundRoute) {
|
|
1254
|
-
routeParams = getMatchedParams(foundRoute);
|
|
1255
|
-
} else {
|
|
1256
|
-
let fuzzyMatch = void 0;
|
|
1257
|
-
for (const route of flatRoutes) {
|
|
1258
|
-
const matchedParams = getMatchedParams(route);
|
|
1259
|
-
if (matchedParams) {
|
|
1260
|
-
if (route.path !== "/" && matchedParams["**"]) {
|
|
1261
|
-
if (!fuzzyMatch) {
|
|
1262
|
-
fuzzyMatch = { foundRoute: route, routeParams: matchedParams };
|
|
1263
|
-
}
|
|
1264
|
-
} else {
|
|
1265
|
-
foundRoute = route;
|
|
1266
|
-
routeParams = matchedParams;
|
|
1267
|
-
break;
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
if (!foundRoute && fuzzyMatch) {
|
|
1272
|
-
foundRoute = fuzzyMatch.foundRoute;
|
|
1273
|
-
routeParams = fuzzyMatch.routeParams;
|
|
1274
|
-
}
|
|
1219
|
+
let foundRoute = void 0;
|
|
1220
|
+
const match = newProcessRouteTree.findRouteMatch(trimmedPath, processedTree, true);
|
|
1221
|
+
if (match) {
|
|
1222
|
+
foundRoute = match.route;
|
|
1223
|
+
Object.assign(routeParams, match.params);
|
|
1275
1224
|
}
|
|
1276
1225
|
let routeCursor = foundRoute || routesById[root.rootRouteId];
|
|
1277
1226
|
const matchedRoutes = [routeCursor];
|