mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
Escape regex when searching for a specific filepath + some error handling / schema adjustments
This commit is contained in:
parent
17bf94fc5f
commit
4e5deb22a1
6 changed files with 33 additions and 8 deletions
|
|
@ -26,6 +26,7 @@
|
|||
"@uiw/react-codemirror": "^4.23.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"http-status-codes": "^2.3.0",
|
||||
"lucide-react": "^0.435.0",
|
||||
"next": "14.2.6",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
export enum ErrorCode {
|
||||
UNEXPECTED_ERROR = 'UNEXPECTED_ERROR',
|
||||
MISSING_REQUIRED_QUERY_PARAMETER = 'MISSING_REQUIRED_QUERY_PARAMETER',
|
||||
REPOSITORY_NOT_FOUND = 'REPOSITORY_NOT_FOUND',
|
||||
FILE_NOT_FOUND = 'FILE_NOT_FOUND',
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ export type SearchRequest = z.infer<typeof searchRequestSchema>;
|
|||
export const searchRequestSchema = z.object({
|
||||
query: z.string(),
|
||||
numResults: z.number(),
|
||||
whole: z.optional(z.boolean()),
|
||||
whole: z.boolean().optional(),
|
||||
});
|
||||
|
||||
|
||||
export type SearchResponse = z.infer<typeof searchResponseSchema>;
|
||||
export type SearchResult = SearchResponse["Result"];
|
||||
export type SearchResultFile = SearchResult["Files"][number];
|
||||
export type SearchResultFile = NonNullable<SearchResult["Files"]>[number];
|
||||
export type SearchResultFileMatch = SearchResultFile["ChunkMatches"][number];
|
||||
export type SearchResultRange = z.infer<typeof rangeSchema>;
|
||||
export type SearchResultLocation = z.infer<typeof locationSchema>;
|
||||
|
|
@ -50,8 +50,8 @@ export const searchResponseSchema = z.object({
|
|||
Checksum: z.string(),
|
||||
Score: z.number(),
|
||||
// Set if `whole` is true.
|
||||
Content: z.optional(z.string()),
|
||||
})),
|
||||
Content: z.string().optional(),
|
||||
})).nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { SHARD_MAX_MATCH_COUNT, TOTAL_MAX_MATCH_COUNT } from "../environment";
|
||||
import { FileSourceRequest, FileSourceResponse, SearchRequest, SearchResponse, searchResponseSchema } from "../schemas";
|
||||
import { fileNotFound, invalidZoektResponse, ServiceError } from "../serviceError";
|
||||
import { fileNotFound, invalidZoektResponse, schemaValidationError, ServiceError, unexpectedError } from "../serviceError";
|
||||
import { isServiceError } from "../utils";
|
||||
import { zoektFetch } from "./zoektClient";
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
|
||||
export const search = async ({ query, numResults, whole }: SearchRequest): Promise<SearchResponse | ServiceError> => {
|
||||
const body = JSON.stringify({
|
||||
|
|
@ -29,12 +30,21 @@ export const search = async ({ query, numResults, whole }: SearchRequest): Promi
|
|||
}
|
||||
|
||||
const searchBody = await searchResponse.json();
|
||||
return searchResponseSchema.parse(searchBody);
|
||||
const parsedSearchResponse = searchResponseSchema.safeParse(searchBody);
|
||||
if (!parsedSearchResponse.success) {
|
||||
console.error(`Failed to parse zoekt response. Error: ${parsedSearchResponse.error}`);
|
||||
return unexpectedError(`Something went wrong while parsing the response from zoekt`);
|
||||
}
|
||||
|
||||
return parsedSearchResponse.data;
|
||||
}
|
||||
|
||||
export const getFileSource = async ({ fileName, repository }: FileSourceRequest): Promise<FileSourceResponse | ServiceError> => {
|
||||
const escapedFileName = escapeStringRegexp(fileName);
|
||||
const escapedRepository = escapeStringRegexp(repository);
|
||||
|
||||
const searchResponse = await search({
|
||||
query: `${fileName} repo:${repository}`,
|
||||
query: `${escapedFileName} repo:^${escapedRepository}$`,
|
||||
numResults: 1,
|
||||
whole: true,
|
||||
});
|
||||
|
|
@ -45,7 +55,7 @@ export const getFileSource = async ({ fileName, repository }: FileSourceRequest)
|
|||
|
||||
const files = searchResponse.Result.Files;
|
||||
|
||||
if (files.length === 0) {
|
||||
if (!files || files.length === 0) {
|
||||
return fileNotFound(fileName, repository);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,4 +59,12 @@ export const fileNotFound = async (fileName: string, repository: string): Promis
|
|||
errorCode: ErrorCode.FILE_NOT_FOUND,
|
||||
message: `File "${fileName}" not found in repository "${repository}"`,
|
||||
};
|
||||
}
|
||||
|
||||
export const unexpectedError = (message: string): ServiceError => {
|
||||
return {
|
||||
statusCode: StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
errorCode: ErrorCode.UNEXPECTED_ERROR,
|
||||
message: `Unexpected error: ${message}`,
|
||||
};
|
||||
}
|
||||
|
|
@ -1607,6 +1607,11 @@ escape-string-regexp@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
escape-string-regexp@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
|
||||
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
|
||||
|
||||
eslint-config-next@14.2.6:
|
||||
version "14.2.6"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.2.6.tgz#43623683155540feff830b08956a57ece8148d8f"
|
||||
|
|
|
|||
Loading…
Reference in a new issue