From e3532516a6af04e518029aa18ad6a022519349e7 Mon Sep 17 00:00:00 2001 From: devteamaegis Date: Thu, 11 Jun 2026 02:09:19 -0400 Subject: [PATCH] fix(query-language): don't treat a dash before a non-prefix colon word as negation A query like `-foo:bar` or `-http://example.com` raised a SyntaxError. The negate tokenizer accepted `-` as negation whenever any colon appeared in the following word, but the grammar only allows a NegateExpr to wrap a known PrefixExpr. With no matching prefix, the strict parser used in search failed the whole query. Now negation is only emitted when the dash is immediately followed by a known prefix keyword; other colon-bearing words parse as a single Term. --- packages/queryLanguage/src/tokens.ts | 27 ++++++------------------ packages/queryLanguage/test/negation.txt | 24 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/queryLanguage/src/tokens.ts b/packages/queryLanguage/src/tokens.ts index 1bb69f531..043462200 100644 --- a/packages/queryLanguage/src/tokens.ts +++ b/packages/queryLanguage/src/tokens.ts @@ -673,27 +673,12 @@ export const negateToken = new ExternalTokenizer((input, stack) => { } } - // Check if followed by a prefix keyword (by checking for keyword followed by colon) - let foundColon = false; - let peekOffset = offset; - - while (true) { - const ch = input.peek(peekOffset); - if (ch === EOF) break; - - if (ch === COLON) { - foundColon = true; - break; - } - // Hit a delimiter (whitespace, paren, or quote) - not a prefix keyword - if (isWhitespace(ch) || ch === OPEN_PAREN || ch === CLOSE_PAREN || ch === QUOTE) { - break; - } - peekOffset++; - } - - if (foundColon) { - // It's a prefix keyword, accept as negate + // Only accept as negate when the dash is immediately followed by a known + // prefix keyword (e.g. `-file:`). A bare word that merely contains a colon + // (e.g. `-foo:bar`, `-http://x`) is not a prefix and must be left for + // wordToken; otherwise the grammar has no PrefixExpr to follow the negate + // token and the (strict) parser throws a SyntaxError. + if (startsWithPrefixAt(input, offset)) { input.advance(); input.acceptToken(negate); return; diff --git a/packages/queryLanguage/test/negation.txt b/packages/queryLanguage/test/negation.txt index 105c96347..b1d8755aa 100644 --- a/packages/queryLanguage/test/negation.txt +++ b/packages/queryLanguage/test/negation.txt @@ -277,3 +277,27 @@ chat lang:TypeScript -file:(test|spec) ==> Program(AndExpr(Term,PrefixExpr(LangExpr),NegateExpr(PrefixExpr(FileExpr)))) + +# Dash term with non-prefix colon word (e.g. a URL) stays a single Term + +-http://example.com + +==> + +Program(Term) + +# Dash term with unknown colon key stays a single Term + +-time:12 + +==> + +Program(Term) + +# Prefix combined with a negated non-prefix colon word + +repo:x -foo:bar + +==> + +Program(AndExpr(PrefixExpr(RepoExpr),Term))