🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more →

@grafana/lezer-logql

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@grafana/lezer-logql - npm Package Compare versions

Comparing version

to
0.2.5

@@ -38,4 +38,3 @@ import { LRParser } from '@lezer/lr';

Sort$1 = 34,
Sort_Desc$1 = 35,
MetricExpr$1 = 96;
Sort_Desc$1 = 35;

@@ -248,676 +247,2 @@ const keywordTokens = {

function getNodeFromQuery(query, nodeType) {
const nodes = [];
const tree = parser.parse(query);
tree.iterate({
enter: (node) => {
if (nodeType === undefined || nodeType === node.type.id) {
nodes.push(node.node);
}
},
});
return nodes[0];
}
function isLogsQuery(query) {
if (getNodeFromQuery(query, MetricExpr$1)) {
return false;
}
return true;
}
function indent(level) {
return ' '.repeat(level);
}
function indentMultiline(block, level) {
const lines = block.split('\n');
return lines.map((line) => indent(level) + line).join('\n');
}
function trimMultiline(block) {
const lines = block.split('\n');
return lines.map((line) => line.trimEnd()).join('\n');
}
function needsBrackets(node, queryType) {
const childNodeIsSame = node.firstChild?.type.id === queryType;
let addBrackets = false;
if (node.firstChild && childNodeIsSame) {
addBrackets = true;
node = node.firstChild;
}
return { addBrackets, newNode: node };
}
function iterateNode(node, lookingFor) {
const nodes = [];
let child = node.firstChild;
while (child) {
if (lookingFor.includes(child.type.id)) {
nodes.push(child);
}
nodes.push(...iterateNode(child, lookingFor));
child = child.nextSibling;
}
return nodes;
}
function buildResponse(pipelineType, lastPipelineType, formattedNode) {
if (lastPipelineType === pipelineType) {
return ` ${formattedNode}`;
}
return `\n${indent(1)}${formattedNode}`;
}
function trimEnd(input, charactersToTrim) {
let endIndex = input.length - 1;
while (endIndex >= 0 && charactersToTrim.includes(input[endIndex])) {
endIndex--;
}
return input.substring(0, endIndex + 1);
}
const formatLogExpr = (node, query) => {
const { addBrackets, newNode } = needsBrackets(node, LogExpr);
node = newNode;
const tree = parser.parse(query.substring(node.from, node.to));
let formatted = '';
tree.iterate({
enter: (ref) => {
const node = ref.node;
switch (node.type.id) {
case Selector:
formatted += formatSelector(node, query);
break;
case PipelineExpr:
node.parent?.type.id !== PipelineExpr && (formatted += formatPipelineExpr(node, query));
break;
}
},
});
return addBrackets ? '(' + formatted + ')' : formatted;
};
function formatSelector(node, query) {
const selector = query.substring(node.from, node.to);
const subtree = parser.parse(selector);
const labelNodes = [];
let response = '';
subtree.iterate({
enter: (ref) => {
const node = ref.node;
if (node.type.id === Matcher) {
labelNodes.push(node);
}
},
});
labelNodes.sort((a, b) => {
const labelNodeA = a.getChild(Identifier);
const labelNodeB = b.getChild(Identifier);
const labelValueA = labelNodeA && query.substring(labelNodeA.from, labelNodeA.to);
const labelValueB = labelNodeB && query.substring(labelNodeB.from, labelNodeB.to);
if (!labelValueA || !labelValueB) {
return 0;
}
if (labelValueA < labelValueB) {
return -1;
}
if (labelValueA > labelValueB) {
return 1;
}
return 0;
});
labelNodes.forEach((node) => {
const labelNode = node.getChild(Identifier);
const operatorNode = labelNode ? labelNode.nextSibling : null;
const valueNode = node.getChild(String);
const label = labelNode ? query.substring(labelNode.from, labelNode.to) : null;
const operator = operatorNode ? query.substring(operatorNode.from, operatorNode.to) : null;
const value = valueNode ? query.substring(valueNode.from, valueNode.to) : null;
response += `${label}${operator}${value}, `;
});
return '{' + trimEnd(response, ', ') + '}';
}
function formatPipelineExpr(node, query) {
const pipelineExprNodes = [
LineFilter,
LabelParser,
LogfmtParser,
LabelFilter,
JsonExpressionParser,
LineFormatExpr,
LabelFormatExpr,
DecolorizeExpr,
];
let lastPipelineType;
let response = '';
iterateNode(node, pipelineExprNodes).forEach((node) => {
switch (node.type.id) {
case LineFilter:
response += buildResponse(LineFilter, lastPipelineType, formatLineFilter(node, query));
lastPipelineType = LineFilter;
break;
case LabelParser:
response += buildResponse(LabelParser, lastPipelineType, formatLabelParser(node, query));
lastPipelineType = LabelParser;
break;
case LogfmtParser:
response += buildResponse(LogfmtParser, lastPipelineType, formatLabelParser(node, query));
lastPipelineType = LogfmtParser;
break;
case JsonExpressionParser:
response += buildResponse(JsonExpressionParser, lastPipelineType, formatJsonExpressionParser(node, query));
lastPipelineType = JsonExpressionParser;
break;
case LabelFilter:
response += buildResponse(LabelFilter, lastPipelineType, formatLabelFilter(node, query));
lastPipelineType = LabelFilter;
break;
case LineFormatExpr:
response += buildResponse(LineFormatExpr, lastPipelineType, formatLineFormatExpr(node, query));
lastPipelineType = LineFormatExpr;
break;
case LabelFormatExpr:
response += buildResponse(LabelFormatExpr, lastPipelineType, formatLabelFormatExpr(node, query));
lastPipelineType = LabelFormatExpr;
break;
case DecolorizeExpr:
response += buildResponse(DecolorizeExpr, lastPipelineType, formatDecolorizeExpr());
lastPipelineType = DecolorizeExpr;
break;
}
});
return response;
}
function formatLineFilter(node, query) {
const filterNode = node.getChild(Filter);
const filterOperationNode = node.getChild(FilterOp);
const stringNode = node.getChild(String);
const filter = filterNode && query.substring(filterNode.from, filterNode.to);
const string = stringNode && query.substring(stringNode.from, stringNode.to);
if (filterOperationNode) {
return `${filter} ip(${string})`;
}
return `${filter} ${string}`;
}
function formatLabelParser(node, query) {
const hasString = node.getChild(String);
if (hasString) {
const parserNode = node.getChild(Regexp) || node.getChild(Pattern);
const stringNode = node.getChild(String);
const parser = parserNode && query.substring(parserNode.from, parserNode.to);
const string = stringNode && query.substring(stringNode.from, stringNode.to);
return `| ${parser}${string}`;
}
const labelParser = query.substring(node.from, node.to);
return `| ${labelParser}`;
}
function formatJsonExpressionParser(node, query) {
const jsonExpressionNodes = iterateNode(node, [LabelExtractionExpression]);
let response = '';
jsonExpressionNodes.forEach((node) => {
const identifierNode = node.getChild(Identifier);
const valueNode = node.getChild(String);
const identifier = identifierNode && query.substring(identifierNode.from, identifierNode.to);
const value = valueNode && query.substring(valueNode.from, valueNode.to);
response += `${identifier}=${value}, `;
});
return `| json ${trimEnd(response, ', ')}`;
}
function formatLabelFilter(node, query) {
const selectedFilter =
node.getChild(Matcher) ||
node.getChild(IpLabelFilter) ||
node.getChild(NumberFilter) ||
node.getChild(UnitFilter)?.getChild(DurationFilter) ||
node.getChild(UnitFilter)?.getChild(BytesFilter);
if (!selectedFilter) {
return '';
}
const selectedFilterType = selectedFilter.type.id;
const identifierNode = selectedFilter.getChild(Identifier);
const operatorNode = identifierNode && identifierNode.nextSibling;
let valueNode;
if (selectedFilterType === DurationFilter) {
valueNode = selectedFilter.getChild(Duration);
} else if (selectedFilterType === BytesFilter) {
valueNode = selectedFilter.getChild(Bytes);
} else if (selectedFilterType === NumberFilter) {
valueNode = selectedFilter.getChild(LiteralExpr);
} else {
valueNode = selectedFilter.getChild(String);
}
const identifier = identifierNode && query.substring(identifierNode.from, identifierNode.to);
const operator = operatorNode && query.substring(operatorNode.from, operatorNode.to);
const value = valueNode && query.substring(valueNode.from, valueNode.to);
if (selectedFilterType === IpLabelFilter) {
return `| ${identifier}${operator}ip(${value})`;
}
return `| ${identifier}${operator}${value}`;
}
function formatLineFormatExpr(node, query) {
const stringNode = node.getChild(String);
const string = stringNode && query.substring(stringNode.from, stringNode.to);
return `| line_format ${string}`;
}
function formatLabelFormatExpr(node, query) {
const labelFormatMatcherNodes = iterateNode(node, [LabelFormatMatcher]);
let response = '| label_format ';
labelFormatMatcherNodes.forEach((labelFormatMatcherNode) => {
let identifierNode;
let valueNode;
if (labelFormatMatcherNode.getChildren(Identifier).length === 2) {
[identifierNode, valueNode] = labelFormatMatcherNode.getChildren(Identifier);
} else {
identifierNode = labelFormatMatcherNode.getChild(Identifier);
valueNode = labelFormatMatcherNode.getChild(String);
}
const identifier = identifierNode && query.substring(identifierNode.from, identifierNode.to);
const value = valueNode && query.substring(valueNode.from, valueNode.to);
response += `${identifier}=${value}, `;
});
return trimEnd(response, ', ');
}
function formatDecolorizeExpr() {
return `| decolorize`;
}
const formatMetricExpr = (node, query) => {
const { addBrackets, newNode } = needsBrackets(node, MetricExpr);
node = newNode;
let formatted = '';
const childNode = node.firstChild;
switch (childNode && childNode.type.id) {
case RangeAggregationExpr:
formatted = formatRangeAggregationExpr(node, query);
break;
case VectorAggregationExpr:
formatted = formatVectorAggregationExpr(node, query);
break;
case BinOpExpr:
formatted = formatBinOpExpr(node, query);
break;
case LiteralExpr:
formatted = formatLiteralExpr(node, query);
break;
case LabelReplaceExpr:
formatted = formatLabelReplaceExpr(node, query);
break;
case VectorExpr:
formatted = formatVectorExpr(node, query);
break;
}
return addBrackets ? '(' + formatted + ')' : formatted;
};
function formatRangeAggregationExpr(node, query) {
let response = '';
iterateNode(node, [RangeOp, Number, LogRangeExpr, Grouping]).forEach((node) => {
if (node.parent?.type.id !== RangeAggregationExpr) {
return;
}
switch (node.type.id) {
case RangeOp:
response += `${query.substring(node.from, node.to)}(\n`;
break;
case Number:
response += `${indent(1) + query.substring(node.from, node.to)},\n`;
break;
case LogRangeExpr:
response += formatLogRangeExpr(node, query);
break;
case Grouping:
response += formatGrouping(node, query);
break;
}
});
return response;
}
function formatLogRangeExpr(node, query) {
const nodes = [];
let selector = '';
let pipeline = '';
let range = '';
let offset = '';
let unwrap = '';
iterateNode(node, [Selector, Range, OffsetExpr, UnwrapExpr, PipelineExpr]).forEach((node) => {
if (node.parent?.type.id !== LogRangeExpr) {
return;
}
nodes.push(node);
switch (node.type.id) {
case Selector: {
let logExpr = query.substring(node.from, node.to);
selector += formatSelector({ ...node, from: 0, to: logExpr.length }, logExpr);
break;
}
case PipelineExpr:
pipeline += formatPipelineExpr(node, query);
break;
case Range:
range += query.substring(node.from, node.to);
break;
case OffsetExpr: {
const durationNode = node.getChild(Duration);
offset += ` offset ${durationNode ? query.substring(durationNode.from, durationNode.to) : ''}`;
break;
}
case UnwrapExpr:
iterateNode(node, [Identifier, ConvOp, LabelFilter]).forEach((node, _, arr) => {
switch (node.type.id) {
case Identifier: {
if (node.parent?.type.id !== UnwrapExpr) {
return;
}
const hasConvOp = arr.find((node) => node.type.id === ConvOp);
if (hasConvOp) {
return;
}
unwrap += `| unwrap ${query.substring(node.from, node.to)} `;
return;
}
case ConvOp: {
const identifierNode = arr.find((node) => node.type.id === Identifier);
const identifier = identifierNode ? query.substring(identifierNode.from, identifierNode.to) : '';
unwrap += `| unwrap ${query.substring(node.from, node.to)}(${identifier}) `;
return;
}
case LabelFilter:
unwrap += formatLabelFilter(node, query);
return;
}
});
break;
}
});
let response = '';
nodes.forEach((node, index, array) => {
const previousNode = array[index - 1];
if (node.type.id === Selector) {
response += indent(1) + selector;
}
if (node.type.id === PipelineExpr) {
response += indentMultiline(pipeline, 1);
}
if (node.type.id === Range) {
response += '\n' + indent(1) + range;
}
if (node.type.id === OffsetExpr) {
response += offset;
}
if (node.type.id === UnwrapExpr) {
if (previousNode?.type.id !== OffsetExpr && previousNode?.type.id !== Range) {
response += '\n' + indent(1) + unwrap;
} else {
response += ' ' + unwrap;
}
}
});
return (response += '\n)');
}
function formatGrouping(node, query) {
let response = '';
const labels = iterateNode(node, [Identifier]).map((node) => {
return query.substring(node.from, node.to);
});
iterateNode(node, [By, Without]).forEach((node) => {
if (node.parent?.type.id !== Grouping) {
return;
}
switch (node.type.id) {
case By:
response = ` by (${labels.join(', ')}) `;
break;
case Without:
response = ` without (${labels.join(', ')}) `;
break;
}
});
return response;
}
function formatVectorAggregationExpr(node, query) {
let response = '';
iterateNode(node, [VectorOp, Number, MetricExpr, Grouping]).forEach((node, _, arr) => {
if (node.parent?.type.id !== VectorAggregationExpr) {
return;
}
switch (node.type.id) {
case VectorOp:
response += `${query.substring(node.from, node.to)}`;
break;
case Number:
response += `(\n`;
response += `${indent(1) + query.substring(node.from, node.to)},\n`;
break;
case MetricExpr: {
const hasNumber = arr.find((node) => node.type.id === Number && node.parent?.type.id === VectorAggregationExpr);
response += hasNumber ? '' : '(\n';
const metricExpr = query.substring(node.from, node.to);
const metricNode = getNodeFromQuery(metricExpr, MetricExpr);
response += indentMultiline(formatMetricExpr(metricNode, metricExpr), 1);
response += '\n)';
break;
}
case Grouping:
response += formatGrouping(node, query);
break;
}
});
return response;
}
function formatBinOpExpr(node, query) {
let operator;
const [leftExpr, rightExpr] = iterateNode(node, [Expr]).map((node, idx) => {
if (idx === 0) {
operator = query.substring(node.nextSibling?.from ?? 0, node.nextSibling?.to);
}
const expr = query.substring(node.from, node.to);
let expressionNode;
if (isLogsQuery(expr)) {
expressionNode = getNodeFromQuery(expr, LogExpr);
return formatLogExpr(expressionNode, expr);
} else {
expressionNode = getNodeFromQuery(expr, MetricExpr);
return formatMetricExpr(expressionNode, expr);
}
});
return leftExpr + '\n' + operator + '\n' + rightExpr;
}
function formatLiteralExpr(node, query) {
node = node.getChild(LiteralExpr) ?? node;
const addNode = node.getChild(Add);
const subNode = node.getChild(Sub);
const numberNode = node.getChild(Number);
if (!numberNode) {
return '';
}
if (addNode) {
return `+${query.substring(numberNode.from, numberNode.to)}`;
}
if (subNode) {
return `-${query.substring(numberNode.from, numberNode.to)}`;
}
return query.substring(numberNode.from, numberNode.to);
}
function formatLabelReplaceExpr(node, query) {
let response = 'label_replace(\n';
iterateNode(node, [MetricExpr, String]).forEach((node) => {
if (node.parent?.type.id !== LabelReplaceExpr) {
return;
}
if (node.type.id === MetricExpr) {
const metricExpr = query.substring(node.from, node.to);
const metricNode = getNodeFromQuery(metricExpr, MetricExpr);
response += indentMultiline(formatMetricExpr(metricNode, metricExpr), 1) + ',\n';
} else {
response += indent(1) + query.substring(node.from, node.to) + ',\n';
}
});
return trimEnd(response, ',\n') + '\n)';
}
function formatVectorExpr(node, query) {
node = node.getChild(VectorExpr) ?? node;
const numberNode = node.getChild(Number);
if (!numberNode) {
return '';
}
return `vector(${query.substring(numberNode.from, numberNode.to)})`;
}
/**
* @experimental This feature is subject to change or removal in future versions.
*/
const formatLokiQuery = (query) => {
const tree = parser.parse(query);
let formatted = '';
tree.iterate({
enter: (ref) => {
const node = ref.node;
if (node.parent?.type.id !== Expr || node.parent?.parent?.type.id === BinOpExpr) {
return;
}
switch (node.type.id) {
case MetricExpr:
formatted = formatMetricExpr(node, query);
return false;
case LogExpr:
formatted = formatLogExpr(node, query);
return false;
}
},
});
return trimMultiline(formatted);
};
export { AbsentOverTime, Add, And, Avg, AvgOverTime, BinOpExpr, BinOpModifier, Bool, Bottomk, By, Bytes, BytesConv, BytesFilter, BytesOverTime, BytesRate, ConvOp, Count, CountOverTime, Decolorize, DecolorizeExpr, Div, Drop, DropLabel, DropLabels, DropLabelsExpr, Duration, DurationConv, DurationFilter, DurationSecondsConv, Eq, Eql, Expr, Filter, FilterOp, FirstOverTime, GroupLeft, GroupRight, Grouping, GroupingLabel, GroupingLabelList, GroupingLabels, Gte, Gtr, Identifier, Ignoring, Ip, IpLabelFilter, Json, JsonExpressionParser, Keep, KeepLabel, KeepLabels, KeepLabelsExpr, LabelExtractionExpression, LabelExtractionExpressionList, LabelFilter, LabelFormat, LabelFormatExpr, LabelFormatMatcher, LabelName, LabelParser, LabelReplace, LabelReplaceExpr, Labels, LabelsFormat, LastOverTime, LineComment, LineFilter, LineFilters, LineFormat, LineFormatExpr, LiteralExpr, LogExpr, LogQL, LogRangeExpr, Logfmt, LogfmtExpressionParser, LogfmtParser, LogfmtParserFlags, Lss, Lte, Matcher, Matchers, Max, MaxOverTime, MetricExpr, Min, MinOverTime, Mod, Mul, Neq, Nre, Number, NumberFilter, Offset, OffsetExpr, On, OnOrIgnoringModifier, Or, OrFilter, ParserFlag, Pattern, Pipe, PipeExact, PipeMatch, PipelineExpr, PipelineStage, Pow, QuantileOverTime, Range, RangeAggregationExpr, RangeOp, Rate, RateCounter, Re, Regexp, Selector, Sort, Sort_Desc, Stddev, StddevOverTime, Stdvar, StdvarOverTime, String, Sub, Sum, SumOverTime, Topk, UnitFilter, Unless, Unpack, Unwrap, UnwrapExpr, Vector, VectorAggregationExpr, VectorExpr, VectorOp, Without, formatLokiQuery, parser };
export { AbsentOverTime, Add, And, Avg, AvgOverTime, BinOpExpr, BinOpModifier, Bool, Bottomk, By, Bytes, BytesConv, BytesFilter, BytesOverTime, BytesRate, ConvOp, Count, CountOverTime, Decolorize, DecolorizeExpr, Div, Drop, DropLabel, DropLabels, DropLabelsExpr, Duration, DurationConv, DurationFilter, DurationSecondsConv, Eq, Eql, Expr, Filter, FilterOp, FirstOverTime, GroupLeft, GroupRight, Grouping, GroupingLabel, GroupingLabelList, GroupingLabels, Gte, Gtr, Identifier, Ignoring, Ip, IpLabelFilter, Json, JsonExpressionParser, Keep, KeepLabel, KeepLabels, KeepLabelsExpr, LabelExtractionExpression, LabelExtractionExpressionList, LabelFilter, LabelFormat, LabelFormatExpr, LabelFormatMatcher, LabelName, LabelParser, LabelReplace, LabelReplaceExpr, Labels, LabelsFormat, LastOverTime, LineComment, LineFilter, LineFilters, LineFormat, LineFormatExpr, LiteralExpr, LogExpr, LogQL, LogRangeExpr, Logfmt, LogfmtExpressionParser, LogfmtParser, LogfmtParserFlags, Lss, Lte, Matcher, Matchers, Max, MaxOverTime, MetricExpr, Min, MinOverTime, Mod, Mul, Neq, Nre, Number, NumberFilter, Offset, OffsetExpr, On, OnOrIgnoringModifier, Or, OrFilter, ParserFlag, Pattern, Pipe, PipeExact, PipeMatch, PipelineExpr, PipelineStage, Pow, QuantileOverTime, Range, RangeAggregationExpr, RangeOp, Rate, RateCounter, Re, Regexp, Selector, Sort, Sort_Desc, Stddev, StddevOverTime, Stdvar, StdvarOverTime, String, Sub, Sum, SumOverTime, Topk, UnitFilter, Unless, Unpack, Unwrap, UnwrapExpr, Vector, VectorAggregationExpr, VectorExpr, VectorOp, Without, parser };
{
"name": "@grafana/lezer-logql",
"version": "0.2.4",
"version": "0.2.5",
"description": "Grafana Loki logQL lezer grammar",

@@ -51,2 +51,3 @@ "main": "index.cjs",

"exports": {
"types": "./index.d.ts",
"import": "./index.es.js",

@@ -53,0 +54,0 @@ "require": "./index.cjs"

Sorry, the diff of this file is not supported yet