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.
|
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
||||||
export const
|
export const
|
||||||
negate = 21,
|
negate = 22,
|
||||||
Program = 1,
|
Program = 1,
|
||||||
OrExpr = 2,
|
OrExpr = 2,
|
||||||
AndExpr = 3,
|
AndExpr = 3,
|
||||||
|
|
@ -9,12 +9,13 @@ export const
|
||||||
ArchivedExpr = 6,
|
ArchivedExpr = 6,
|
||||||
RevisionExpr = 7,
|
RevisionExpr = 7,
|
||||||
ContentExpr = 8,
|
ContentExpr = 8,
|
||||||
FileExpr = 9,
|
ContextExpr = 9,
|
||||||
ForkExpr = 10,
|
FileExpr = 10,
|
||||||
VisibilityExpr = 11,
|
ForkExpr = 11,
|
||||||
RepoExpr = 12,
|
VisibilityExpr = 12,
|
||||||
LangExpr = 13,
|
RepoExpr = 13,
|
||||||
SymExpr = 14,
|
LangExpr = 14,
|
||||||
RepoSetExpr = 15,
|
SymExpr = 15,
|
||||||
ParenExpr = 16,
|
RepoSetExpr = 16,
|
||||||
Term = 17
|
ParenExpr = 17,
|
||||||
|
Term = 18
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -35,6 +35,7 @@ PrefixExpr {
|
||||||
ArchivedExpr |
|
ArchivedExpr |
|
||||||
RevisionExpr |
|
RevisionExpr |
|
||||||
ContentExpr |
|
ContentExpr |
|
||||||
|
ContextExpr |
|
||||||
FileExpr |
|
FileExpr |
|
||||||
ForkExpr |
|
ForkExpr |
|
||||||
VisibilityExpr |
|
VisibilityExpr |
|
||||||
|
|
@ -46,6 +47,7 @@ PrefixExpr {
|
||||||
|
|
||||||
RevisionExpr { revisionKw value }
|
RevisionExpr { revisionKw value }
|
||||||
ContentExpr { contentKw value }
|
ContentExpr { contentKw value }
|
||||||
|
ContextExpr { contextKw value }
|
||||||
FileExpr { fileKw value }
|
FileExpr { fileKw value }
|
||||||
RepoExpr { repoKw value }
|
RepoExpr { repoKw value }
|
||||||
LangExpr { langKw value }
|
LangExpr { langKw value }
|
||||||
|
|
@ -71,6 +73,7 @@ value { quotedString | word }
|
||||||
archivedKw { "archived:" }
|
archivedKw { "archived:" }
|
||||||
revisionKw { "rev:" }
|
revisionKw { "rev:" }
|
||||||
contentKw { "content:" | "c:" }
|
contentKw { "content:" | "c:" }
|
||||||
|
contextKw { "context:" }
|
||||||
fileKw { "file:" | "f:" }
|
fileKw { "file:" | "f:" }
|
||||||
forkKw { "fork:" }
|
forkKw { "fork:" }
|
||||||
visibilityKw { "visibility:" }
|
visibilityKw { "visibility:" }
|
||||||
|
|
@ -91,7 +94,7 @@ value { quotedString | word }
|
||||||
|
|
||||||
@precedence {
|
@precedence {
|
||||||
quotedString,
|
quotedString,
|
||||||
archivedKw, revisionKw, contentKw, fileKw,
|
archivedKw, revisionKw, contentKw, contextKw, fileKw,
|
||||||
forkKw, visibilityKw, repoKw, langKw,
|
forkKw, visibilityKw, repoKw, langKw,
|
||||||
symKw, reposetKw, or,
|
symKw, reposetKw, or,
|
||||||
word
|
word
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,14 @@ Program(NegateExpr(PrefixExpr(ForkExpr)))
|
||||||
|
|
||||||
Program(NegateExpr(PrefixExpr(VisibilityExpr)))
|
Program(NegateExpr(PrefixExpr(VisibilityExpr)))
|
||||||
|
|
||||||
|
# Negate context prefix
|
||||||
|
|
||||||
|
-context:backend
|
||||||
|
|
||||||
|
==>
|
||||||
|
|
||||||
|
Program(NegateExpr(PrefixExpr(ContextExpr)))
|
||||||
|
|
||||||
# Negate symbol prefix
|
# Negate symbol prefix
|
||||||
|
|
||||||
-sym:OldClass
|
-sym:OldClass
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,14 @@ visibility:public
|
||||||
|
|
||||||
Program(PrefixExpr(VisibilityExpr))
|
Program(PrefixExpr(VisibilityExpr))
|
||||||
|
|
||||||
|
# Context prefix
|
||||||
|
|
||||||
|
context:web
|
||||||
|
|
||||||
|
==>
|
||||||
|
|
||||||
|
Program(PrefixExpr(ContextExpr))
|
||||||
|
|
||||||
# Symbol prefix
|
# Symbol prefix
|
||||||
|
|
||||||
sym:MyClass
|
sym:MyClass
|
||||||
|
|
@ -302,6 +310,14 @@ content:@Component
|
||||||
|
|
||||||
Program(PrefixExpr(ContentExpr))
|
Program(PrefixExpr(ContentExpr))
|
||||||
|
|
||||||
|
# Context with underscores
|
||||||
|
|
||||||
|
context:data_engineering
|
||||||
|
|
||||||
|
==>
|
||||||
|
|
||||||
|
Program(PrefixExpr(ContextExpr))
|
||||||
|
|
||||||
# Prefix in parentheses
|
# Prefix in parentheses
|
||||||
|
|
||||||
(file:test.js)
|
(file:test.js)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { NextRequest } from 'next/server';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { parser as _parser } from '@sourcebot/query-language';
|
import { parser as _parser } from '@sourcebot/query-language';
|
||||||
import { transformToZoektQuery } from './transformer';
|
import { transformToZoektQuery } from './transformer';
|
||||||
|
import { SINGLE_TENANT_ORG_ID } from '@/lib/constants';
|
||||||
|
|
||||||
const logger = createLogger('streamSearchApi');
|
const logger = createLogger('streamSearchApi');
|
||||||
|
|
||||||
|
|
@ -78,14 +79,33 @@ export const POST = async (request: NextRequest) => {
|
||||||
|
|
||||||
const parser = _parser.configure({
|
const parser = _parser.configure({
|
||||||
strict: true,
|
strict: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
const tree = parser.parse(query);
|
const tree = parser.parse(query);
|
||||||
const zoektQuery = transformToZoektQuery({
|
const zoektQuery = await transformToZoektQuery({
|
||||||
tree,
|
tree,
|
||||||
input: query,
|
input: query,
|
||||||
isCaseSensitivityEnabled,
|
isCaseSensitivityEnabled,
|
||||||
isRegexEnabled,
|
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));
|
console.log(JSON.stringify(zoektQuery, null, 2));
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
RepoExpr,
|
RepoExpr,
|
||||||
RevisionExpr,
|
RevisionExpr,
|
||||||
ContentExpr,
|
ContentExpr,
|
||||||
|
ContextExpr,
|
||||||
LangExpr,
|
LangExpr,
|
||||||
SymExpr,
|
SymExpr,
|
||||||
ArchivedExpr,
|
ArchivedExpr,
|
||||||
|
|
@ -44,14 +45,16 @@ export const transformToZoektQuery = ({
|
||||||
input,
|
input,
|
||||||
isCaseSensitivityEnabled,
|
isCaseSensitivityEnabled,
|
||||||
isRegexEnabled,
|
isRegexEnabled,
|
||||||
|
onExpandSearchContext,
|
||||||
}: {
|
}: {
|
||||||
tree: Tree;
|
tree: Tree;
|
||||||
input: string;
|
input: string;
|
||||||
isCaseSensitivityEnabled: boolean;
|
isCaseSensitivityEnabled: boolean;
|
||||||
isRegexEnabled: 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) {
|
switch (node.type.id) {
|
||||||
case Program: {
|
case Program: {
|
||||||
// Program wraps the actual query - transform its child
|
// Program wraps the actual query - transform its child
|
||||||
|
|
@ -65,7 +68,7 @@ export const transformToZoektQuery = ({
|
||||||
case AndExpr:
|
case AndExpr:
|
||||||
return {
|
return {
|
||||||
and: {
|
and: {
|
||||||
children: getChildren(node).map(c => transformNode(c))
|
children: await Promise.all(getChildren(node).map(c => transformNode(c)))
|
||||||
},
|
},
|
||||||
query: "and"
|
query: "and"
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +76,7 @@ export const transformToZoektQuery = ({
|
||||||
case OrExpr:
|
case OrExpr:
|
||||||
return {
|
return {
|
||||||
or: {
|
or: {
|
||||||
children: getChildren(node).map(c => transformNode(c))
|
children: await Promise.all(getChildren(node).map(c => transformNode(c)))
|
||||||
},
|
},
|
||||||
query: "or"
|
query: "or"
|
||||||
};
|
};
|
||||||
|
|
@ -86,7 +89,7 @@ export const transformToZoektQuery = ({
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
not: {
|
not: {
|
||||||
child: transformNode(negateChild)
|
child: await transformNode(negateChild)
|
||||||
},
|
},
|
||||||
query: "not"
|
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
|
// Find which specific prefix type this is
|
||||||
const prefixNode = node.firstChild;
|
const prefixNode = node.firstChild;
|
||||||
if (!prefixNode) {
|
if (!prefixNode) {
|
||||||
|
|
@ -189,6 +192,7 @@ export const transformToZoektQuery = ({
|
||||||
query: "substring"
|
query: "substring"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
case LangExpr:
|
case LangExpr:
|
||||||
return {
|
return {
|
||||||
language: {
|
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: {
|
case RepoSetExpr: {
|
||||||
return {
|
return {
|
||||||
repo_set: {
|
repo_set: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue