mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 20:35:24 +00:00
support search contexts
This commit is contained in:
parent
e6859cbf5c
commit
307e17e8d6
7 changed files with 92 additions and 27 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
||||
export const
|
||||
negate = 21,
|
||||
negate = 22,
|
||||
Program = 1,
|
||||
OrExpr = 2,
|
||||
AndExpr = 3,
|
||||
|
|
@ -9,12 +9,13 @@ export const
|
|||
ArchivedExpr = 6,
|
||||
RevisionExpr = 7,
|
||||
ContentExpr = 8,
|
||||
FileExpr = 9,
|
||||
ForkExpr = 10,
|
||||
VisibilityExpr = 11,
|
||||
RepoExpr = 12,
|
||||
LangExpr = 13,
|
||||
SymExpr = 14,
|
||||
RepoSetExpr = 15,
|
||||
ParenExpr = 16,
|
||||
Term = 17
|
||||
ContextExpr = 9,
|
||||
FileExpr = 10,
|
||||
ForkExpr = 11,
|
||||
VisibilityExpr = 12,
|
||||
RepoExpr = 13,
|
||||
LangExpr = 14,
|
||||
SymExpr = 15,
|
||||
RepoSetExpr = 16,
|
||||
ParenExpr = 17,
|
||||
Term = 18
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -35,6 +35,7 @@ PrefixExpr {
|
|||
ArchivedExpr |
|
||||
RevisionExpr |
|
||||
ContentExpr |
|
||||
ContextExpr |
|
||||
FileExpr |
|
||||
ForkExpr |
|
||||
VisibilityExpr |
|
||||
|
|
@ -46,6 +47,7 @@ PrefixExpr {
|
|||
|
||||
RevisionExpr { revisionKw value }
|
||||
ContentExpr { contentKw value }
|
||||
ContextExpr { contextKw value }
|
||||
FileExpr { fileKw value }
|
||||
RepoExpr { repoKw value }
|
||||
LangExpr { langKw value }
|
||||
|
|
@ -71,6 +73,7 @@ value { quotedString | word }
|
|||
archivedKw { "archived:" }
|
||||
revisionKw { "rev:" }
|
||||
contentKw { "content:" | "c:" }
|
||||
contextKw { "context:" }
|
||||
fileKw { "file:" | "f:" }
|
||||
forkKw { "fork:" }
|
||||
visibilityKw { "visibility:" }
|
||||
|
|
@ -91,7 +94,7 @@ value { quotedString | word }
|
|||
|
||||
@precedence {
|
||||
quotedString,
|
||||
archivedKw, revisionKw, contentKw, fileKw,
|
||||
archivedKw, revisionKw, contentKw, contextKw, fileKw,
|
||||
forkKw, visibilityKw, repoKw, langKw,
|
||||
symKw, reposetKw, or,
|
||||
word
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@ Program(NegateExpr(PrefixExpr(ForkExpr)))
|
|||
|
||||
Program(NegateExpr(PrefixExpr(VisibilityExpr)))
|
||||
|
||||
# Negate context prefix
|
||||
|
||||
-context:backend
|
||||
|
||||
==>
|
||||
|
||||
Program(NegateExpr(PrefixExpr(ContextExpr)))
|
||||
|
||||
# Negate symbol prefix
|
||||
|
||||
-sym:OldClass
|
||||
|
|
|
|||
|
|
@ -102,6 +102,14 @@ visibility:public
|
|||
|
||||
Program(PrefixExpr(VisibilityExpr))
|
||||
|
||||
# Context prefix
|
||||
|
||||
context:web
|
||||
|
||||
==>
|
||||
|
||||
Program(PrefixExpr(ContextExpr))
|
||||
|
||||
# Symbol prefix
|
||||
|
||||
sym:MyClass
|
||||
|
|
@ -302,6 +310,14 @@ content:@Component
|
|||
|
||||
Program(PrefixExpr(ContentExpr))
|
||||
|
||||
# Context with underscores
|
||||
|
||||
context:data_engineering
|
||||
|
||||
==>
|
||||
|
||||
Program(PrefixExpr(ContextExpr))
|
||||
|
||||
# Prefix in parentheses
|
||||
|
||||
(file:test.js)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { NextRequest } from 'next/server';
|
|||
import * as path from 'path';
|
||||
import { parser as _parser } from '@sourcebot/query-language';
|
||||
import { transformToZoektQuery } from './transformer';
|
||||
import { SINGLE_TENANT_ORG_ID } from '@/lib/constants';
|
||||
|
||||
const logger = createLogger('streamSearchApi');
|
||||
|
||||
|
|
@ -78,14 +79,33 @@ export const POST = async (request: NextRequest) => {
|
|||
|
||||
const parser = _parser.configure({
|
||||
strict: true,
|
||||
})
|
||||
});
|
||||
|
||||
const tree = parser.parse(query);
|
||||
const zoektQuery = transformToZoektQuery({
|
||||
const zoektQuery = await transformToZoektQuery({
|
||||
tree,
|
||||
input: query,
|
||||
isCaseSensitivityEnabled,
|
||||
isRegexEnabled,
|
||||
onExpandSearchContext: async (contextName: string) => {
|
||||
const context = await prisma.searchContext.findUnique({
|
||||
where: {
|
||||
name_orgId: {
|
||||
name: contextName,
|
||||
orgId: SINGLE_TENANT_ORG_ID,
|
||||
}
|
||||
},
|
||||
include: {
|
||||
repos: true,
|
||||
}
|
||||
});
|
||||
|
||||
if (!context) {
|
||||
throw new Error(`Search context "${contextName}" not found`);
|
||||
}
|
||||
|
||||
return context.repos.map((repo) => repo.name);
|
||||
},
|
||||
});
|
||||
|
||||
console.log(JSON.stringify(zoektQuery, null, 2));
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
RepoExpr,
|
||||
RevisionExpr,
|
||||
ContentExpr,
|
||||
ContextExpr,
|
||||
LangExpr,
|
||||
SymExpr,
|
||||
ArchivedExpr,
|
||||
|
|
@ -44,14 +45,16 @@ export const transformToZoektQuery = ({
|
|||
input,
|
||||
isCaseSensitivityEnabled,
|
||||
isRegexEnabled,
|
||||
onExpandSearchContext,
|
||||
}: {
|
||||
tree: Tree;
|
||||
input: string;
|
||||
isCaseSensitivityEnabled: boolean;
|
||||
isRegexEnabled: boolean;
|
||||
}): Q => {
|
||||
onExpandSearchContext: (contextName: string) => Promise<string[]>;
|
||||
}): Promise<Q> => {
|
||||
|
||||
const transformNode = (node: SyntaxNode): Q => {
|
||||
const transformNode = async (node: SyntaxNode): Promise<Q> => {
|
||||
switch (node.type.id) {
|
||||
case Program: {
|
||||
// Program wraps the actual query - transform its child
|
||||
|
|
@ -65,7 +68,7 @@ export const transformToZoektQuery = ({
|
|||
case AndExpr:
|
||||
return {
|
||||
and: {
|
||||
children: getChildren(node).map(c => transformNode(c))
|
||||
children: await Promise.all(getChildren(node).map(c => transformNode(c)))
|
||||
},
|
||||
query: "and"
|
||||
}
|
||||
|
|
@ -73,7 +76,7 @@ export const transformToZoektQuery = ({
|
|||
case OrExpr:
|
||||
return {
|
||||
or: {
|
||||
children: getChildren(node).map(c => transformNode(c))
|
||||
children: await Promise.all(getChildren(node).map(c => transformNode(c)))
|
||||
},
|
||||
query: "or"
|
||||
};
|
||||
|
|
@ -86,7 +89,7 @@ export const transformToZoektQuery = ({
|
|||
}
|
||||
return {
|
||||
not: {
|
||||
child: transformNode(negateChild)
|
||||
child: await transformNode(negateChild)
|
||||
},
|
||||
query: "not"
|
||||
};
|
||||
|
|
@ -130,7 +133,7 @@ export const transformToZoektQuery = ({
|
|||
}
|
||||
}
|
||||
|
||||
const transformPrefixExpr = (node: SyntaxNode): Q => {
|
||||
const transformPrefixExpr = async (node: SyntaxNode): Promise<Q> => {
|
||||
// Find which specific prefix type this is
|
||||
const prefixNode = node.firstChild;
|
||||
if (!prefixNode) {
|
||||
|
|
@ -189,6 +192,7 @@ export const transformToZoektQuery = ({
|
|||
query: "substring"
|
||||
};
|
||||
|
||||
|
||||
case LangExpr:
|
||||
return {
|
||||
language: {
|
||||
|
|
@ -287,6 +291,19 @@ export const transformToZoektQuery = ({
|
|||
};
|
||||
}
|
||||
|
||||
case ContextExpr: {
|
||||
const repoNames = await onExpandSearchContext(value);
|
||||
return {
|
||||
repo_set: {
|
||||
set: repoNames.reduce((acc, s) => {
|
||||
acc[s.trim()] = true;
|
||||
return acc;
|
||||
}, {} as Record<string, boolean>)
|
||||
},
|
||||
query: "repo_set"
|
||||
};
|
||||
}
|
||||
|
||||
case RepoSetExpr: {
|
||||
return {
|
||||
repo_set: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue