prometheus/web/ui/module/codemirror-promql/src/parser/matcher.ts
Neeraj Gartia 99f9d32499
UTF-8: updates UI parser to support UTF-8 characters (#13590)
Signed-off-by: Neeraj Gartia <neerajgartia211002@gmail.com>
2024-04-29 11:14:01 +02:00

131 lines
3.8 KiB
TypeScript

// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { SyntaxNode } from '@lezer/common';
import {
EqlRegex,
EqlSingle,
LabelName,
MatchOp,
Neq,
NeqRegex,
StringLiteral,
UnquotedLabelMatcher,
QuotedLabelMatcher,
QuotedLabelName,
} from '@prometheus-io/lezer-promql';
import { EditorState } from '@codemirror/state';
import { Matcher } from '../types';
function createMatcher(labelMatcher: SyntaxNode, state: EditorState): Matcher {
const matcher = new Matcher(0, '', '');
const cursor = labelMatcher.cursor();
switch (cursor.type.id) {
case QuotedLabelMatcher:
if (!cursor.next()) {
// weird case, that would mean the QuotedLabelMatcher doesn't have any child.
return matcher;
}
do {
switch (cursor.type.id) {
case QuotedLabelName:
matcher.name = state.sliceDoc(cursor.from, cursor.to).slice(1, -1);
break;
case MatchOp:
const ope = cursor.node.firstChild;
if (ope) {
matcher.type = ope.type.id;
}
break;
case StringLiteral:
matcher.value = state.sliceDoc(cursor.from, cursor.to).slice(1, -1);
break;
}
} while (cursor.nextSibling());
break;
case UnquotedLabelMatcher:
if (!cursor.next()) {
// weird case, that would mean the UnquotedLabelMatcher doesn't have any child.
return matcher;
}
do {
switch (cursor.type.id) {
case LabelName:
matcher.name = state.sliceDoc(cursor.from, cursor.to);
break;
case MatchOp:
const ope = cursor.node.firstChild;
if (ope) {
matcher.type = ope.type.id;
}
break;
case StringLiteral:
matcher.value = state.sliceDoc(cursor.from, cursor.to).slice(1, -1);
break;
}
} while (cursor.nextSibling());
break;
case QuotedLabelName:
matcher.name = '__name__';
matcher.value = state.sliceDoc(cursor.from, cursor.to).slice(1, -1);
matcher.type = EqlSingle;
break;
}
return matcher;
}
export function buildLabelMatchers(labelMatchers: SyntaxNode[], state: EditorState): Matcher[] {
const matchers: Matcher[] = [];
labelMatchers.forEach((value) => {
matchers.push(createMatcher(value, state));
});
return matchers;
}
export function labelMatchersToString(metricName: string, matchers?: Matcher[], labelName?: string): string {
if (!matchers || matchers.length === 0) {
return metricName;
}
let matchersAsString = '';
for (const matcher of matchers) {
if (matcher.name === labelName || matcher.value === '') {
continue;
}
let type = '';
switch (matcher.type) {
case EqlSingle:
type = '=';
break;
case Neq:
type = '!=';
break;
case NeqRegex:
type = '!~';
break;
case EqlRegex:
type = '=~';
break;
default:
type = '=';
}
const m = `${matcher.name}${type}"${matcher.value}"`;
if (matchersAsString === '') {
matchersAsString = m;
} else {
matchersAsString = `${matchersAsString},${m}`;
}
}
return `${metricName}{${matchersAsString}}`;
}