mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Rewrite getHighlighterExpressionsFromQuery to use Loki parser (#53316)
* refactor(loki): use Loki parser in getHighlighterExpressionsFromQuery * fix(highlighter): update regex to properly identify term quotes * refactor(highlighter): determine quote type by string comparison * Chore: remove empty line
This commit is contained in:
parent
d638cd4fd7
commit
27e2953951
@ -98,6 +98,15 @@ describe('getHighlighterExpressionsFromQuery', () => {
|
|||||||
it('does not remove backslash escaping if regex filter operator and backticks are used', () => {
|
it('does not remove backslash escaping if regex filter operator and backticks are used', () => {
|
||||||
expect(getHighlighterExpressionsFromQuery('{foo="bar"} |~ `\\w+`')).toEqual(['\\w+']);
|
expect(getHighlighterExpressionsFromQuery('{foo="bar"} |~ `\\w+`')).toEqual(['\\w+']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
input | expected
|
||||||
|
${'`"test"`'} | ${'"test"'}
|
||||||
|
${'"`test`"'} | ${'`test`'}
|
||||||
|
${'`"test"a`'} | ${'"test"a'}
|
||||||
|
`('should correctly identify the type of quote used in the term', ({ input, expected }) => {
|
||||||
|
expect(getHighlighterExpressionsFromQuery(`{foo="bar"} |= ${input}`)).toEqual([expected]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getNormalizedLokiQuery', () => {
|
describe('getNormalizedLokiQuery', () => {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
import { SyntaxNode } from '@lezer/common';
|
||||||
import { escapeRegExp } from 'lodash';
|
import { escapeRegExp } from 'lodash';
|
||||||
|
|
||||||
import { parser } from '@grafana/lezer-logql';
|
import { parser, LineFilter, PipeExact, PipeMatch, Filter, String } from '@grafana/lezer-logql';
|
||||||
|
|
||||||
import { ErrorName } from '../prometheus/querybuilder/shared/parsingUtils';
|
import { ErrorName } from '../prometheus/querybuilder/shared/parsingUtils';
|
||||||
|
|
||||||
@ -15,45 +16,39 @@ export function formatQuery(selector: string | undefined): string {
|
|||||||
* E.g., `{} |= foo |=bar != baz` returns `['foo', 'bar']`.
|
* E.g., `{} |= foo |=bar != baz` returns `['foo', 'bar']`.
|
||||||
*/
|
*/
|
||||||
export function getHighlighterExpressionsFromQuery(input: string): string[] {
|
export function getHighlighterExpressionsFromQuery(input: string): string[] {
|
||||||
let expression = input;
|
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
// Consume filter expression from left to right
|
const tree = parser.parse(input);
|
||||||
while (expression) {
|
const filters: SyntaxNode[] = [];
|
||||||
const filterStart = expression.search(/\|=|\|~|!=|!~/);
|
tree.iterate({
|
||||||
// Nothing more to search
|
enter: (type, from, to, get): void => {
|
||||||
if (filterStart === -1) {
|
if (type.id === LineFilter) {
|
||||||
break;
|
filters.push(get());
|
||||||
}
|
}
|
||||||
// Drop terms for negative filters
|
},
|
||||||
const filterOperator = expression.slice(filterStart, filterStart + 2);
|
});
|
||||||
const skip = expression.slice(filterStart).search(/!=|!~/) === 0;
|
|
||||||
expression = expression.slice(filterStart + 2);
|
for (let filter of filters) {
|
||||||
if (skip) {
|
const pipeExact = filter.getChild(Filter)?.getChild(PipeExact);
|
||||||
|
const pipeMatch = filter.getChild(Filter)?.getChild(PipeMatch);
|
||||||
|
const string = filter.getChild(String);
|
||||||
|
|
||||||
|
if ((!pipeExact && !pipeMatch) || !string) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Check if there is more chained, by just looking for the next pipe-operator
|
|
||||||
const filterEnd = expression.search(/\|/);
|
const filterTerm = input.substring(string.from, string.to).trim();
|
||||||
let filterTerm;
|
const backtickedTerm = filterTerm[0] === '`';
|
||||||
if (filterEnd === -1) {
|
const unwrappedFilterTerm = filterTerm.substring(1, filterTerm.length - 1);
|
||||||
filterTerm = expression.trim();
|
|
||||||
} else {
|
if (!unwrappedFilterTerm) {
|
||||||
filterTerm = expression.slice(0, filterEnd).trim();
|
continue;
|
||||||
expression = expression.slice(filterEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const quotedTerm = filterTerm.match(/"(.*?)"/);
|
|
||||||
const backtickedTerm = filterTerm.match(/`(.*?)`/);
|
|
||||||
const term = quotedTerm || backtickedTerm;
|
|
||||||
|
|
||||||
if (term) {
|
|
||||||
const unwrappedFilterTerm = term[1];
|
|
||||||
const regexOperator = filterOperator === '|~';
|
|
||||||
|
|
||||||
let resultTerm = '';
|
let resultTerm = '';
|
||||||
|
|
||||||
// Only filter expressions with |~ operator are treated as regular expressions
|
// Only filter expressions with |~ operator are treated as regular expressions
|
||||||
if (regexOperator) {
|
if (pipeMatch) {
|
||||||
// When using backticks, Loki doesn't require to escape special characters and we can just push regular expression to highlights array
|
// When using backticks, Loki doesn't require to escape special characters and we can just push regular expression to highlights array
|
||||||
// When using quotes, we have extra backslash escaping and we need to replace \\ with \
|
// When using quotes, we have extra backslash escaping and we need to replace \\ with \
|
||||||
resultTerm = backtickedTerm ? unwrappedFilterTerm : unwrappedFilterTerm.replace(/\\\\/g, '\\');
|
resultTerm = backtickedTerm ? unwrappedFilterTerm : unwrappedFilterTerm.replace(/\\\\/g, '\\');
|
||||||
@ -65,11 +60,7 @@ export function getHighlighterExpressionsFromQuery(input: string): string[] {
|
|||||||
if (resultTerm) {
|
if (resultTerm) {
|
||||||
results.push(resultTerm);
|
results.push(resultTerm);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user