UNPKG

@exlinep/router

Version:
121 lines (103 loc) 3.09 kB
/** * @ignore * @packageDocumentation */ import * as ptr from 'path-to-regexp'; const cache: Map<string, [ptr.PathFunction, ptr.Token[]]> = new Map<string, [ptr.PathFunction, ptr.Token[]]>(); const cacheLimit = 10000; let cacheCount = 0; function parsePath(pageId: string): [ptr.PathFunction, ptr.Token[]] { const cached = cache.get(pageId); if (cached) { return cached; } const tokens = ptr.parse(pageId); const generator = ptr.tokensToFunction(tokens); if (cacheCount < cacheLimit) { cache.set(pageId, [generator, tokens]); cacheCount++; } return [generator, tokens]; } interface CachedPath { regexp: RegExp; keys: ptr.Token[]; } const convertCache = new Map<string, CachedPath>(); function convertPath(path: string, options?: ptr.TokensToRegexpOptions & ptr.ParseOptions): CachedPath { const cacheKey = `${options?.end ? '1' : '0'}${options?.strict}${options?.sensitive}${path}`; const pathCache = convertCache.get(cacheKey); if (pathCache) { return pathCache; } const keys: ptr.Key[] = []; const regexp = ptr.pathToRegexp(path, keys); const result = { regexp, keys }; if (cacheCount < cacheLimit) { convertCache.set(cacheKey, result); cacheCount++; } return result; } /** * Создание пути из шаблона * @param pageId /user/:id * @param params {id:5,name:Ivan} * @return {string} /user/5?name=Ivan * @ignore */ export function generatePath(pageId: string, params?: {}): string { if (!params) { params = {}; } params = { ...params }; const [generatePath, tokens] = parsePath(pageId); const path = generatePath(params); const restParams: { [key: string]: any } = { ...params }; tokens.forEach((t) => { if (typeof t === 'object') { delete restParams[t.name.toString()]; } }); const result = `${path}?${new URLSearchParams(restParams).toString()}`; return result.replace(/\?$/gmu, ''); } /** * @ignore */ export interface MatchInterface { isExact: boolean; path: string; url: string; params: { [key: string]: string }; } /** * Проверка что строка удовлетворяет шаблону * @param location /user/5 * @param pageId /user/:id([0-9]+) * @ignore */ export function matchPath(location: string, pageId: string): null | MatchInterface { const { regexp, keys } = convertPath(pageId, { end: false, strict: false, sensitive: false, }); let match = regexp.exec(location); if (!match) { return null; } const [url, ...values] = match; const isExact = location === url; return { path: pageId, // the path used to match url: pageId === '/' && url === '' ? '/' : url, // the matched portion of the URL isExact, // whether or not we matched exactly params: keys.reduce<{ [key: string]: string }>((memo, key, index) => { if (typeof key === 'object') { memo[key.name] = values[index]; } return memo; }, {}), }; }