sourcebot/packages/web/src/features/search/fileSourceApi.ts
Brendan Kellam 92578881df
Some checks are pending
Publish to ghcr / build (linux/amd64, blacksmith-4vcpu-ubuntu-2404) (push) Waiting to run
Publish to ghcr / build (linux/arm64, blacksmith-8vcpu-ubuntu-2204-arm) (push) Waiting to run
Publish to ghcr / merge (push) Blocked by required conditions
Update Roadmap Released / update (push) Waiting to run
chore(web): Scope code nav to current repository by default (#647)
2025-11-30 18:53:09 -08:00

84 lines
2.8 KiB
TypeScript

import 'server-only';
import { fileNotFound, ServiceError, unexpectedError } from "../../lib/serviceError";
import { FileSourceRequest, FileSourceResponse } from "./types";
import { isServiceError } from "../../lib/utils";
import { search } from "./searchApi";
import { sew } from "@/actions";
import { withOptionalAuthV2 } from "@/withAuthV2";
import { QueryIR } from './ir';
import escapeStringRegexp from "escape-string-regexp";
// @todo (bkellam) #574 : We should really be using `git show <hash>:<path>` to fetch file contents here.
// This will allow us to support permalinks to files at a specific revision that may not be indexed
// by zoekt. We should also refactor this out of the /search folder.
export const getFileSource = async ({ fileName, repository, branch }: FileSourceRequest): Promise<FileSourceResponse | ServiceError> => sew(() =>
withOptionalAuthV2(async () => {
const query: QueryIR = {
and: {
children: [
{
repo: {
regexp: `^${escapeStringRegexp(repository)}$`,
},
},
{
substring: {
pattern: fileName,
case_sensitive: true,
file_name: true,
content: false,
}
},
...(branch ? [{
branch: {
pattern: branch,
exact: true,
},
}]: [])
]
}
}
const searchResponse = await search({
queryType: 'ir',
query,
options: {
matches: 1,
whole: true,
}
});
if (isServiceError(searchResponse)) {
return searchResponse;
}
const files = searchResponse.files;
if (!files || files.length === 0) {
return fileNotFound(fileName, repository);
}
const file = files[0];
const source = file.content ?? '';
const language = file.language;
const repoInfo = searchResponse.repositoryInfo.find((repo) => repo.id === file.repositoryId);
if (!repoInfo) {
// This should never happen.
return unexpectedError("Repository info not found");
}
return {
source,
language,
path: fileName,
repository,
repositoryCodeHostType: repoInfo.codeHostType,
repositoryDisplayName: repoInfo.displayName,
repositoryWebUrl: repoInfo.webUrl,
branch,
webUrl: file.webUrl,
} satisfies FileSourceResponse;
}));