/
githubmirror
/
ionic
Обзор
Документация
Войти
/
githubmirror
/
ionic
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
core/src/components/router/utils/path.ts
138 строк
4 KB
Shane
fix(router): support anchor fragments in href (#31172)
28 май 2026, 23:04
Не верифицирован
28 май 2026, 23:04
a982516
Код
Авторство
О чём код?
import { ROUTER_INTENT_FORWARD } from './constants'; import type { ParsedRoute, RouteChain, RouterDirection } from './interface'; /** Join the non empty segments with "/". */ export const generatePath = (segments: string[]): string => { const path = segments.filter((s) => s.length > 0).join('/'); return '/' + path; }; const generateUrl = (segments: string[], useHash: boolean, queryString?: string, fragment?: string) => { let url = generatePath(segments); if (useHash) { url = '#' + url; } if (queryString !== undefined) { url += '?' + queryString; } if (fragment !== undefined) { url += '#' + fragment; } return url; }; export const writeSegments = ( history: History, root: string, useHash: boolean, segments: string[], direction: RouterDirection, state: number, queryString?: string, fragment?: string ) => { const url = generateUrl([...parsePath(root).segments, ...segments], useHash, queryString, fragment); if (direction === ROUTER_INTENT_FORWARD) { history.pushState(state, '', url); } else { history.replaceState(state, '', url); } }; /** * Transforms a chain to a list of segments. * * Notes: * - parameter segments of the form :param are replaced with their value, * - null is returned when a value is missing for any parameter segment. */ export const chainToSegments = (chain: RouteChain): string[] | null => { const segments = []; for (const route of chain) { for (const segment of route.segments) { if (segment[0] === ':') { // eslint-disable-next-line @typescript-eslint/prefer-optional-chain const param = route.params && route.params[segment.slice(1)]; if (!param) { return null; } segments.push(param); } else if (segment !== '') { segments.push(segment); } } } return segments; }; /** * Removes the prefix segments from the path segments. * * Return: * - null when the path segments do not start with the passed prefix, * - the path segments after the prefix otherwise. */ const removePrefix = (prefix: string[], segments: string[]): string[] | null => { if (prefix.length > segments.length) { return null; } if (prefix.length <= 1 && prefix[0] === '') { return segments; } for (let i = 0; i < prefix.length; i++) { if (prefix[i] !== segments[i]) { return null; } } if (segments.length === prefix.length) { return ['']; } return segments.slice(prefix.length); }; export const readSegments = (loc: Location, root: string, useHash: boolean): string[] | null => { const prefix = parsePath(root).segments; const pathname = useHash ? loc.hash.slice(1) : loc.pathname; const segments = parsePath(pathname).segments; return removePrefix(prefix, segments); }; /** * Parses the path to: * - segments an array of '/' separated parts, * - queryString (undefined when no query string), * - fragment (undefined when no `#`). */ export const parsePath = (path: string | undefined | null): ParsedRoute => { let segments = ['']; let queryString; let fragment; if (path != null) { // The fragment ("#") starts a section that runs to the end of the URL. // Anything inside it (including "?") is part of the fragment per RFC 3986. const fragStart = path.indexOf('#'); if (fragStart > -1) { fragment = path.substring(fragStart + 1); path = path.substring(0, fragStart); } const qsStart = path.indexOf('?'); if (qsStart > -1) { queryString = path.substring(qsStart + 1); path = path.substring(0, qsStart); } segments = path .split('/') .map((s) => s.trim()) .filter((s) => s.length > 0); if (segments.length === 0) { segments = ['']; } } return { segments, queryString, fragment }; };