import { BrowseState, SET_BROWSE_STATE_QUERY_PARAM } from "../browseStateProvider"; export const HIGHLIGHT_RANGE_QUERY_PARAM = 'highlightRange'; export type BrowseHighlightRange = { start: { lineNumber: number; column: number; }; end: { lineNumber: number; column: number; }; } | { start: { lineNumber: number; }; end: { lineNumber: number; }; } export interface GetBrowsePathProps { repoName: string; revisionName?: string; path: string; pathType: 'blob' | 'tree'; highlightRange?: BrowseHighlightRange; setBrowseState?: Partial; domain: string; } export const getBrowseParamsFromPathParam = (pathParam: string) => { const sentinelIndex = pathParam.search(/\/-\/(tree|blob)/); if (sentinelIndex === -1) { throw new Error(`Invalid browse pathname: "${pathParam}" - expected to contain "/-/(tree|blob)/" pattern`); } const repoAndRevisionPart = decodeURIComponent(pathParam.substring(0, sentinelIndex)); const lastAtIndex = repoAndRevisionPart.lastIndexOf('@'); const repoName = lastAtIndex === -1 ? repoAndRevisionPart : repoAndRevisionPart.substring(0, lastAtIndex); const revisionName = lastAtIndex === -1 ? undefined : repoAndRevisionPart.substring(lastAtIndex + 1); const { path, pathType } = ((): { path: string, pathType: 'tree' | 'blob' } => { const path = pathParam.substring(sentinelIndex + '/-/'.length); const pathType = path.startsWith('tree') ? 'tree' : 'blob'; // @note: decodedURIComponent is needed here incase the path contains a space. switch (pathType) { case 'tree': return { path: decodeURIComponent(path.startsWith('tree/') ? path.substring('tree/'.length) : path.substring('tree'.length)), pathType, }; case 'blob': return { path: decodeURIComponent(path.startsWith('blob/') ? path.substring('blob/'.length) : path.substring('blob'.length)), pathType, }; } })(); if (pathType === 'blob' && path === '') { throw new Error(`Invalid browse pathname: "${pathParam}" - expected to contain a path for blob type`); } return { repoName, revisionName, path, pathType, } }; export const getBrowsePath = ({ repoName, revisionName = 'HEAD', path, pathType, highlightRange, setBrowseState, domain, }: GetBrowsePathProps) => { const params = new URLSearchParams(); if (highlightRange) { const { start, end } = highlightRange; if ('column' in start && 'column' in end) { params.set(HIGHLIGHT_RANGE_QUERY_PARAM, `${start.lineNumber}:${start.column},${end.lineNumber}:${end.column}`); } else { params.set(HIGHLIGHT_RANGE_QUERY_PARAM, `${start.lineNumber},${end.lineNumber}`); } } if (setBrowseState) { params.set(SET_BROWSE_STATE_QUERY_PARAM, JSON.stringify(setBrowseState)); } const encodedPath = encodeURIComponent(path); const browsePath = `/${domain}/browse/${repoName}@${revisionName}/-/${pathType}/${encodedPath}${params.size > 0 ? `?${params.toString()}` : ''}`; return browsePath; };