sourcebot/packages/web/src/app/[domain]/browse/hooks/utils.ts
Brendan Kellam 4ebe4e0475
Some checks failed
Publish to ghcr / build (linux/amd64, blacksmith-4vcpu-ubuntu-2404) (push) Has been cancelled
Publish to ghcr / build (linux/arm64, blacksmith-8vcpu-ubuntu-2204-arm) (push) Has been cancelled
Publish to ghcr / merge (push) Has been cancelled
chore(worker,web): Repo indexing stability improvements + perf improvements to web (#563)
2025-10-18 16:31:22 -07:00

89 lines
3.2 KiB
TypeScript

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<BrowseState>;
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;
};