add lezer-promql module (#9229)

* add lezer-promql module

Signed-off-by: Augustin Husson <husson.augustin@gmail.com>

* integrate lezer-promql in codemirror-promql

Signed-off-by: Augustin Husson <husson.augustin@gmail.com>
pull/9227/head^2
Augustin Husson 2021-08-29 15:16:25 +02:00 committed by GitHub
parent a96bd28d3c
commit a2665a9f73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1394 additions and 38 deletions

View File

@ -3,6 +3,9 @@
node_modules/
dist/
lib/
src/**/codemirror_grammar.js
src/lang-promql/grammar/**.ts
src/lang-promql/grammar/parser.js
src/lang-promql/grammar/parser.terms.js
/.nyc_output

0
web/ui/module/codemirror-promql/build.sh Normal file → Executable file
View File

View File

@ -5,10 +5,9 @@
"requires": true,
"packages": {
"": {
"version": "0.16.0",
"version": "0.17.0",
"license": "MIT",
"dependencies": {
"lezer-promql": "^0.20.0",
"lru-cache": "^6.0.0"
},
"devDependencies": {
@ -35,6 +34,8 @@
"eslint-plugin-prettier": "^3.1.4",
"html-webpack-plugin": "^4.3.0",
"isomorphic-fetch": "^3.0.0",
"lezer": "^0.13.1",
"lezer-generator": "^0.13.1",
"mocha": "^8.1.2",
"nock": "^13.0.11",
"nyc": "^15.1.0",
@ -56,7 +57,8 @@
"@codemirror/language": "^0.18.0",
"@codemirror/lint": "^0.18.1",
"@codemirror/state": "^0.18.2",
"@codemirror/view": "^0.18.1"
"@codemirror/view": "^0.18.1",
"lezer": "^0.13.0"
}
},
"node_modules/@babel/code-frame": {
@ -6333,22 +6335,28 @@
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.4.tgz",
"integrity": "sha512-cLQxUVY28VBBqKBt/R8CYeH57KQnIvscAnoahzvhlZTK8qxMkIyGExR6ecEpYYDX06ZhROZrEm1IiPvjLAsTig==",
"dev": true,
"dependencies": {
"lezer-tree": "^0.13.2"
}
},
"node_modules/lezer-promql": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/lezer-promql/-/lezer-promql-0.20.0.tgz",
"integrity": "sha512-1CHG77fFghl032FfHT33buGyAHiTaMy2fqicEhcp2wWnbxZxS+Jt6gMzEUaf/TmRTIUJofj9uLar7iL22Jazug==",
"peerDependencies": {
"lezer": "^0.13.0"
"node_modules/lezer-generator": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/lezer-generator/-/lezer-generator-0.13.4.tgz",
"integrity": "sha512-pTWxEgw6U41jM/IwMbhPBPonrcQV5YYL3XoY4QPR7ibOjgo2RaF4wVrdabN1ILtBbGvtHZekTGyrbsqfKnMHMA==",
"dev": true,
"dependencies": {
"lezer": "^0.13.2"
},
"bin": {
"lezer-generator": "dist/lezer-generator.cjs"
}
},
"node_modules/lezer-tree": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz",
"integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ=="
"integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==",
"dev": true
},
"node_modules/load-json-file": {
"version": "2.0.0",
@ -17369,20 +17377,25 @@
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.4.tgz",
"integrity": "sha512-cLQxUVY28VBBqKBt/R8CYeH57KQnIvscAnoahzvhlZTK8qxMkIyGExR6ecEpYYDX06ZhROZrEm1IiPvjLAsTig==",
"dev": true,
"requires": {
"lezer-tree": "^0.13.2"
}
},
"lezer-promql": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/lezer-promql/-/lezer-promql-0.20.0.tgz",
"integrity": "sha512-1CHG77fFghl032FfHT33buGyAHiTaMy2fqicEhcp2wWnbxZxS+Jt6gMzEUaf/TmRTIUJofj9uLar7iL22Jazug==",
"requires": {}
"lezer-generator": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/lezer-generator/-/lezer-generator-0.13.4.tgz",
"integrity": "sha512-pTWxEgw6U41jM/IwMbhPBPonrcQV5YYL3XoY4QPR7ibOjgo2RaF4wVrdabN1ILtBbGvtHZekTGyrbsqfKnMHMA==",
"dev": true,
"requires": {
"lezer": "^0.13.2"
}
},
"lezer-tree": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz",
"integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ=="
"integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==",
"dev": true
},
"load-json-file": {
"version": "2.0.0",

View File

@ -6,11 +6,12 @@
"module": "esm/index.js",
"scripts": {
"start": "webpack-dev-server --config webpack.config.cjs --open",
"build": "npm run build-lib && npm run build-app",
"build-lib": "bash ./build.sh",
"build-app": "webpack --config webpack.config.cjs",
"test": "ts-mocha -p tsconfig.json src/**/*.test.ts",
"test-coverage": "nyc ts-mocha -p ./tsconfig.json ./**/*.test.ts",
"build": "npm run build:grammar && npm run build:lib && npm run build:app",
"build:grammar": "lezer-generator src/lang-promql/grammar/promql.grammar -o src/lang-promql/grammar/parser",
"build:lib": "bash ./build.sh",
"build:app": "webpack --config webpack.config.cjs",
"test": "npm run build:grammar && ts-mocha -p tsconfig.json src/**/*.test.ts",
"test-coverage": "npm run build:grammar && nyc ts-mocha -p ./tsconfig.json ./**/*.test.ts",
"codecov": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"lint": "eslint src/ --ext .ts",
"lint:fix": "eslint --fix src/ --ext .ts"
@ -32,7 +33,6 @@
},
"homepage": "https://github.com/prometheus-community/codemirror-promql/blob/master/README.md",
"dependencies": {
"lezer-promql": "^0.20.0",
"lru-cache": "^6.0.0"
},
"devDependencies": {
@ -59,6 +59,8 @@
"eslint-plugin-prettier": "^3.1.4",
"html-webpack-plugin": "^4.3.0",
"isomorphic-fetch": "^3.0.0",
"lezer": "^0.13.1",
"lezer-generator": "^0.13.1",
"mocha": "^8.1.2",
"nock": "^13.0.11",
"nyc": "^15.1.0",
@ -77,7 +79,8 @@
"@codemirror/language": "^0.18.0",
"@codemirror/lint": "^0.18.1",
"@codemirror/state": "^0.18.2",
"@codemirror/view": "^0.18.1"
"@codemirror/view": "^0.18.1",
"lezer": "^0.13.0"
},
"prettier": {
"singleQuote": true,

View File

@ -27,7 +27,7 @@ import {
numberTerms,
snippets,
} from './promql.terms';
import { EqlSingle, Neq } from 'lezer-promql';
import { EqlSingle, Neq } from '../grammar/parser.terms';
import { syntaxTree } from '@codemirror/language';
import { newCompleteStrategy } from './index';

View File

@ -58,7 +58,7 @@ import {
SubqueryExpr,
Unless,
VectorSelector,
} from 'lezer-promql';
} from '../grammar/parser.terms';
import { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import { EditorState } from '@codemirror/state';
import { buildLabelMatchers, containsAtLeastOneChild, containsChild, retrieveAllRecursiveNodes, walkBackward, walkThrough } from '../parser';

View File

@ -0,0 +1,396 @@
// 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.
@top PromQL { Expr }
@top MetricName { MetricIdentifier }
@precedence {
pow @right,
mul @left,
add @left,
eql @left,
and @left,
or @left
}
Expr {
AggregateExpr |
BinaryExpr |
FunctionCall |
MatrixSelector |
NumberLiteral |
OffsetExpr |
ParenExpr |
StringLiteral |
SubqueryExpr |
UnaryExpr |
VectorSelector |
StepInvariantExpr
}
AggregateExpr {
AggregateOp AggregateModifier FunctionCallBody |
AggregateOp FunctionCallBody AggregateModifier |
AggregateOp FunctionCallBody
}
AggregateOp {
Avg |
Bottomk |
Count |
CountValues |
Group |
Max |
Min |
Quantile |
Stddev |
Stdvar |
Sum |
Topk
}
AggregateModifier {
By GroupingLabels |
Without GroupingLabels
}
BinaryExpr {
Expr !pow Pow BinModifiers Expr |
Expr !mul Mul BinModifiers Expr |
Expr !mul Div BinModifiers Expr |
Expr !mul Mod BinModifiers Expr |
Expr !add Add BinModifiers Expr |
Expr !add Sub BinModifiers Expr |
Expr !eql Eql BinModifiers Expr |
Expr !eql Gte BinModifiers Expr |
Expr !eql Gtr BinModifiers Expr |
Expr !eql Lte BinModifiers Expr |
Expr !eql Lss BinModifiers Expr |
Expr !eql Neq BinModifiers Expr |
Expr !and And BinModifiers Expr |
Expr !and Unless BinModifiers Expr |
Expr !or Or BinModifiers Expr
}
OnOrIgnoring {
Ignoring GroupingLabels |
On GroupingLabels
}
BinModifiers {
Bool?
(
OnOrIgnoring
(
(GroupLeft | GroupRight)
(!mul GroupingLabels)? // TODO: Is the "!mul" here correct? Inserted it to resolve a shift/reduce conflict because we always want to count opening parenthesis after this to be counted toward this modifier, not toward a next sub-expression.
)?
)?
}
GroupingLabels {
"(" GroupingLabelList ")" |
"(" GroupingLabelList "," ")" |
"(" ")"
}
GroupingLabelList {
GroupingLabelList "," GroupingLabel |
GroupingLabel
}
GroupingLabel {
LabelName
}
FunctionCall {
FunctionIdentifier FunctionCallBody
}
FunctionIdentifier {
AbsentOverTime |
Absent |
Abs |
AvgOverTime |
Ceil |
Changes |
Clamp |
ClampMax |
ClampMin |
CountOverTime |
DaysInMonth |
DayOfMonth |
DayOfWeek |
Delta |
Deriv |
Exp |
Floor |
HistogramQuantile |
HoltWinters |
Hour |
Idelta |
Increase |
Irate |
LabelReplace |
LabelJoin |
LastOverTime |
Ln |
Log10 |
Log2 |
MaxOverTime |
MinOverTime |
Minute |
Month |
PredictLinear |
PresentOverTime |
QuantileOverTime |
Rate |
Resets |
Round |
Scalar |
Sgn |
Sort |
SortDesc |
Sqrt |
StddevOverTime |
StdvarOverTime |
SumOverTime |
Timestamp |
Time |
Vector |
Year
}
FunctionCallBody {
"(" FunctionCallArgs ")" |
"(" ")"
}
FunctionCallArgs {
FunctionCallArgs "," Expr |
Expr
}
ParenExpr {
"(" Expr ")"
}
OffsetExpr {
Expr Offset Sub? Duration
}
MatrixSelector {
// TODO: Can this not be more specific than "Expr"?
Expr "[" Duration "]"
}
SubqueryExpr {
Expr "[" Duration ":" ("" | Duration) "]"
}
UnaryExpr {
!mul UnaryOp~signed Expr
}
UnaryOp {
"-" |
"+"
}
VectorSelector {
MetricIdentifier LabelMatchers |
MetricIdentifier |
LabelMatchers
}
LabelMatchers {
"{" LabelMatchList "}" |
"{" LabelMatchList "," "}" |
"{" "}"
}
LabelMatchList {
LabelMatchList "," LabelMatcher |
LabelMatcher
}
MatchOp {
EqlSingle |
Neq |
EqlRegex |
NeqRegex
}
LabelMatcher {
LabelName MatchOp StringLiteral
}
MetricIdentifier {
Identifier
}
StepInvariantExpr {
Expr At ( NumberLiteral | AtModifierPreprocessors "(" ")" )
}
AtModifierPreprocessors {
Start | End
}
NumberLiteral {
("-"|"+")?~signed (number | inf | nan)
}
@skip { whitespace | LineComment }
@tokens {
whitespace { std.whitespace+ }
LineComment { "#" ![\n]* }
number {
(std.digit+ ("." std.digit*)? | "." std.digit+) (("e" | "E") ("+" | "-")? std.digit+)? |
"0x" (std.digit | $[a-fA-F])+
}
StringLiteral { // TODO: This is for JS, make this work for PromQL.
'"' (![\\\n"] | "\\" _)* '"'? |
"'" (![\\\n'] | "\\" _)* "'"? |
"`" ![`]* "`"
}
Duration {
// Each line below is just the same regex repeated over and over, but each time with one of the units made non-optional,
// to ensure that at least one <number>+<unit> pair is provided and an empty string is not recognized as a valid duration.
( ( std.digit+ "y" ) ( std.digit+ "w" )? ( std.digit+ "d" )? ( std.digit+ "h" )? ( std.digit+ "m" )? ( std.digit+ "s" )? ( std.digit+ "ms" )? ) |
( ( std.digit+ "y" )? ( std.digit+ "w" ) ( std.digit+ "d" )? ( std.digit+ "h" )? ( std.digit+ "m" )? ( std.digit+ "s" )? ( std.digit+ "ms" )? ) |
( ( std.digit+ "y" )? ( std.digit+ "w" )? ( std.digit+ "d" ) ( std.digit+ "h" )? ( std.digit+ "m" )? ( std.digit+ "s" )? ( std.digit+ "ms" )? ) |
( ( std.digit+ "y" )? ( std.digit+ "w" )? ( std.digit+ "d" )? ( std.digit+ "h" ) ( std.digit+ "m" )? ( std.digit+ "s" )? ( std.digit+ "ms" )? ) |
( ( std.digit+ "y" )? ( std.digit+ "w" )? ( std.digit+ "d" )? ( std.digit+ "h" )? ( std.digit+ "m" ) ( std.digit+ "s" )? ( std.digit+ "ms" )? ) |
( ( std.digit+ "y" )? ( std.digit+ "w" )? ( std.digit+ "d" )? ( std.digit+ "h" )? ( std.digit+ "m" )? ( std.digit+ "s" ) ( std.digit+ "ms" )? ) |
( ( std.digit+ "y" )? ( std.digit+ "w" )? ( std.digit+ "d" )? ( std.digit+ "h" )? ( std.digit+ "m" )? ( std.digit+ "s" )? ( std.digit+ "ms" ) )
}
Identifier { (std.asciiLetter | "_" | ":") (std.asciiLetter | std.digit | "_" | ":" )*}
LabelName { (std.asciiLetter | "_") (std.asciiLetter | std.digit | "_")* }
// Operator
Sub { "-" }
Add { "+" }
Mul { "*" }
Mod { "%" }
Div { "/" }
Eql { "==" }
Neq { "!=" }
Lte { "<=" }
Lss { "<" }
Gte { ">=" }
Gtr { ">" }
EqlRegex { "=~" }
EqlSingle { "=" }
NeqRegex { "!~" }
Pow { "^" }
// Special Modifier
At { "@" }
}
// Keywords
@external specialize {Identifier} specializeIdentifier from "./tokens" {
inf,
nan,
Bool,
Ignoring,
On,
GroupLeft,
GroupRight,
Offset
}
// Contextual keywords
@external extend {Identifier} extendIdentifier from "./tokens" {
Avg,
Bottomk,
Count,
CountValues,
Group,
Max,
Min,
Quantile,
Stddev,
Stdvar,
Sum,
Topk,
By,
Without,
And,
Or,
Unless,
Start,
End
}
// FunctionIdentifier definitions
Abs { condFn<"abs"> }
Absent { condFn<"absent"> }
AbsentOverTime { condFn<"absent_over_time"> }
AvgOverTime { condFn<"avg_over_time"> }
Ceil { condFn<"ceil"> }
Changes { condFn<"changes"> }
Clamp { condFn<"clamp"> }
ClampMax { condFn<"clamp_max"> }
ClampMin { condFn<"clamp_min"> }
CountOverTime { condFn<"count_over_time"> }
DaysInMonth { condFn<"days_in_month"> }
DayOfMonth { condFn<"day_of_month"> }
DayOfWeek { condFn<"day_of_week"> }
Delta { condFn<"delta"> }
Deriv { condFn<"deriv"> }
Exp { condFn<"exp"> }
Floor { condFn<"floor"> }
HistogramQuantile { condFn<"histogram_quantile"> }
HoltWinters { condFn<"holt_winters"> }
Hour { condFn<"hour"> }
Idelta { condFn<"idelta"> }
Increase { condFn<"increase"> }
Irate { condFn<"irate"> }
LabelReplace { condFn<"label_replace"> }
LabelJoin { condFn<"label_join"> }
LastOverTime {condFn<"last_over_time">}
Ln { condFn<"ln"> }
Log10 { condFn<"log10"> }
Log2 { condFn<"log2"> }
MaxOverTime { condFn<"max_over_time"> }
MinOverTime { condFn<"min_over_time"> }
Minute { condFn<"minute"> }
Month { condFn<"month"> }
PredictLinear { condFn<"predict_linear"> }
PresentOverTime { condFn<"present_over_time"> }
QuantileOverTime { condFn<"quantile_over_time"> }
Rate { condFn<"rate"> }
Resets { condFn<"resets"> }
Round { condFn<"round"> }
Scalar { condFn<"scalar"> }
Sgn { condFn<"sgn"> }
Sort { condFn<"sort"> }
SortDesc { condFn<"sort_desc"> }
Sqrt { condFn<"sqrt"> }
StddevOverTime { condFn<"stddev_over_time"> }
StdvarOverTime { condFn<"stdvar_over_time"> }
SumOverTime { condFn<"sum_over_time"> }
Time { condFn<"time"> }
Timestamp { condFn<"timestamp"> }
Vector { condFn<"vector"> }
Year { condFn<"year"> }
// Conditional function names (only parsed as function names when used as such).
condFn<term> { @extend<Identifier, term> }

View File

@ -0,0 +1,842 @@
# Numeric literals
0.123e3
==>
PromQL(Expr(NumberLiteral))
# Double-quoted string literal
"test string"
==>
PromQL(Expr(StringLiteral))
# Single-quoted string literal
'test string'
==>
PromQL(Expr(StringLiteral))
# Backtick-quoted string literal
`test string`
==>
PromQL(Expr(StringLiteral))
# Backtick-quoted multi-line string literal
`test
string`
==>
PromQL(Expr(StringLiteral))
# Addition
1 + 2
==>
PromQL(Expr(BinaryExpr(Expr(NumberLiteral), Add, BinModifiers, Expr(NumberLiteral))))
# Complex expression
sum by(job, mode) (rate(node_cpu_seconds_total[1m])) / on(job) group_left sum by(job)(rate(node_cpu_seconds_total[1m]))
==>
PromQL(
Expr(
BinaryExpr(
Expr(
AggregateExpr(
AggregateOp(Sum),
AggregateModifier(
By,
GroupingLabels(
GroupingLabelList(
GroupingLabelList(
GroupingLabel(LabelName)
),
GroupingLabel(LabelName)
)
)
),
FunctionCallBody(
FunctionCallArgs(
Expr(
FunctionCall(
FunctionIdentifier(Rate),
FunctionCallBody(
FunctionCallArgs(
Expr(
MatrixSelector(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
),
Duration
)
)
)
)
)
)
)
)
)
),
Div,
BinModifiers(
OnOrIgnoring(
On,
GroupingLabels(
GroupingLabelList(
GroupingLabel(LabelName)
)
)
),
GroupLeft
),
Expr(
AggregateExpr(
AggregateOp(Sum),
AggregateModifier(
By,
GroupingLabels(
GroupingLabelList(
GroupingLabel(LabelName)
)
)
),
FunctionCallBody(
FunctionCallArgs(
Expr(
FunctionCall(
FunctionIdentifier(Rate),
FunctionCallBody(
FunctionCallArgs(
Expr(
MatrixSelector(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
),
Duration
)
)
)
)
)
)
)
)
)
)
)
)
)
# Case insensitivity for aggregations and binop modifiers.
SuM BY(testlabel1) (testmetric1) / IGNOring(testlabel2) AVG withOUT(testlabel3) (testmetric2)
==>
PromQL(
Expr(
BinaryExpr(
Expr(
AggregateExpr(
AggregateOp(Sum),
AggregateModifier(
By,
GroupingLabels(
GroupingLabelList(
GroupingLabel(LabelName)
)
)
),
FunctionCallBody(
FunctionCallArgs(
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
)
)
),
Div,
BinModifiers(
OnOrIgnoring(
Ignoring,
GroupingLabels(
GroupingLabelList(
GroupingLabel(LabelName)
)
)
)
),
Expr(
AggregateExpr(
AggregateOp(Avg),
AggregateModifier(
Without,
GroupingLabels(
GroupingLabelList(
GroupingLabel(LabelName)
)
)
),
FunctionCallBody(
FunctionCallArgs(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
)
)
)
)
)
)
)
# Case insensitivity for set operators
metric1 and metric2 AND metric3 unless metric4 UNLESS metric5 or metric6 OR metric7
==>
PromQL(
Expr(
BinaryExpr(
Expr(
BinaryExpr(
Expr(
BinaryExpr(
Expr(
BinaryExpr(
Expr(
BinaryExpr(
Expr(
BinaryExpr(
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
),
And,
BinModifiers,
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
),
And,
BinModifiers,
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
),
Unless,
BinModifiers,
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
),
Unless,
BinModifiers,
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
),
Or,
BinModifiers,
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
),
Or,
BinModifiers,
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
)
)
)
)
# Duration units
foo[1y2w3d4h5m6s7ms]
==>
PromQL(Expr(MatrixSelector(Expr(VectorSelector(MetricIdentifier(Identifier))),Duration)))
# Incorrectly ordered duration units
foo[1m2h]
==>
PromQL(Expr(SubqueryExpr(Expr(VectorSelector(MetricIdentifier(Identifier))),Duration,⚠,Duration)))
# Using a function name as a metric name
rate
==>
PromQL(Expr(VectorSelector(MetricIdentifier(Identifier))))
# Match operators
metric_name{a="1",b!="2",c=~"3",d!~"4"}
==>
PromQL(
Expr(
VectorSelector(
MetricIdentifier(Identifier),
LabelMatchers(
LabelMatchList(
LabelMatchList(
LabelMatchList(
LabelMatchList(
LabelMatcher(
LabelName,
MatchOp(EqlSingle),
StringLiteral
)
),
LabelMatcher(
LabelName,
MatchOp(Neq),
StringLiteral
)
),
LabelMatcher(
LabelName,
MatchOp(EqlRegex),
StringLiteral
)
),
LabelMatcher(
LabelName,
MatchOp(NeqRegex),
StringLiteral
)
),
)
)
)
)
# Binary expression with bool modifier
metric_name > bool 1
==>
PromQL(
Expr(
BinaryExpr(
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
),
Gtr,
BinModifiers(Bool),
Expr(NumberLiteral)
)
)
)
# Binary expression with group_x() labels.
metric1 + on(foo) group_left(bar, baz) metric2
==>
PromQL(
Expr(
BinaryExpr(
Expr(
VectorSelector(
MetricIdentifier(Identifier)
)
),
Add,
BinModifiers(
OnOrIgnoring(
On,
GroupingLabels(
GroupingLabelList(
GroupingLabel(LabelName)
)
)
),
GroupLeft,
GroupingLabels(
GroupingLabelList(
GroupingLabelList(
GroupingLabel(LabelName)
),
GroupingLabel(LabelName)
)
)
),
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
)
)
)
# Function last_over_time
last_over_time(data[1m])
==>
PromQL(
Expr(
FunctionCall(
FunctionIdentifier(LastOverTime),
FunctionCallBody(
FunctionCallArgs(
Expr(
MatrixSelector(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
),
Duration
)
)
)
)
)
)
)
# Function sgn
sgn(data)
==>
PromQL(
Expr(
FunctionCall(
FunctionIdentifier(Sgn),
FunctionCallBody(
FunctionCallArgs(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
)
)
)
)
)
# Function clamp
clamp(data,0,1)
==>
PromQL(
Expr(
FunctionCall(
FunctionIdentifier(Clamp),
FunctionCallBody(
FunctionCallArgs(
FunctionCallArgs(
FunctionCallArgs(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
),
Expr(NumberLiteral)
),
Expr(NumberLiteral)
)
)
)
)
)
# Metric start
start
==>
PromQL(Expr(VectorSelector(MetricIdentifier(Identifier))))
# Metric end
end
==>
PromQL(Expr(VectorSelector(MetricIdentifier(Identifier))))
# Simple At start
foo @ start()
==>
PromQL(
Expr(
StepInvariantExpr(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
At,
AtModifierPreprocessors(Start),
)
)
)
# Simple At end
foo @ end()
==>
PromQL(
Expr(
StepInvariantExpr(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
At,
AtModifierPreprocessors(End),
)
)
)
# Simple At number
foo @ 1234
==>
PromQL(
Expr(
StepInvariantExpr(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
At,
NumberLiteral
)
)
)
# At Modifier with space between bracket
foo @ start( )
==>
PromQL(
Expr(
StepInvariantExpr(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
At,
AtModifierPreprocessors(Start),
)
)
)
# Complex test with At modifier
rate(process_cpu_seconds_total[1m])
and
topk(7, rate(process_cpu_seconds_total[1h] @ 1234))
==>
PromQL(
Expr(
BinaryExpr(
Expr(
FunctionCall(
FunctionIdentifier(Rate),
FunctionCallBody(
FunctionCallArgs(
Expr(
MatrixSelector(
Expr(VectorSelector(MetricIdentifier(Identifier))),
Duration
)
)
)
)
)
),
And,
BinModifiers,
Expr(
AggregateExpr(
AggregateOp(Topk),
FunctionCallBody(
FunctionCallArgs(
FunctionCallArgs(Expr(NumberLiteral)),
Expr(
FunctionCall(
FunctionIdentifier(Rate),
FunctionCallBody(
FunctionCallArgs(
Expr(
StepInvariantExpr(
Expr(
MatrixSelector(
Expr(
VectorSelector(MetricIdentifier(Identifier))
),
Duration
)
),
At,
NumberLiteral
)
)
)
)
)
)
)
)
)
)
)
)
)
# At modifier with negative number
foo @ - 1234
==>
PromQL(
Expr(
StepInvariantExpr(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
At,
NumberLiteral
)
)
)
# At modifier with explicit positive number
foo @ + 1234
==>
PromQL(
Expr(
StepInvariantExpr(
Expr(
VectorSelector(
MetricIdentifier(
Identifier
)
)
)
At,
NumberLiteral
)
)
)
# Metric prefixed by Inf
infra
==>
PromQL(Expr(VectorSelector(MetricIdentifier(Identifier))))
# Metric prefixed by Nan
nananere
==>
PromQL(Expr(VectorSelector(MetricIdentifier(Identifier))))
# Mixed-case NaN.
NaN
==>
PromQL(Expr(NumberLiteral))
# Lower-cased NaN.
nan
==>
PromQL(Expr(NumberLiteral))
# Inf.
Inf
==>
PromQL(Expr(NumberLiteral))
# Negative Inf.
-Inf
==>
PromQL(Expr(NumberLiteral))
# Positive Inf.
+Inf
==>
PromQL(Expr(NumberLiteral))
# Lower-cased Inf.
inf
==>
PromQL(Expr(NumberLiteral))
# Upper-cased Inf.
INF
==>
PromQL(Expr(NumberLiteral))
# Negative number literal.
-42
==>
PromQL(Expr(NumberLiteral))
# Explicitly positive number literal.
+42
==>
PromQL(Expr(NumberLiteral))
# Trying to illegally use NaN as a metric name.
NaN{foo="bar"}
==>
PromQL(Expr(BinaryExpr(Expr(NumberLiteral),⚠,BinModifiers,Expr(VectorSelector(LabelMatchers(LabelMatchList(LabelMatcher(LabelName,MatchOp(EqlSingle),StringLiteral))))))))
# Trying to illegally use Inf as a metric name.
Inf{foo="bar"}
==>
PromQL(Expr(BinaryExpr(Expr(NumberLiteral),⚠,BinModifiers,Expr(VectorSelector(LabelMatchers(LabelMatchList(LabelMatcher(LabelName,MatchOp(EqlSingle),StringLiteral))))))))
# Negative offset
foo offset -5d
==>
PromQL(Expr(OffsetExpr(Expr(VectorSelector(MetricIdentifier(Identifier))), Offset, Sub, Duration)))
# Negative offset with space
foo offset - 5d
==>
PromQL(Expr(OffsetExpr(Expr(VectorSelector(MetricIdentifier(Identifier))), Offset, Sub, Duration)))
# Positive offset
foo offset 5d
==>
PromQL(Expr(OffsetExpr(Expr(VectorSelector(MetricIdentifier(Identifier))), Offset, Duration)))
# Parsing only metric names with alternative @top { "top": "MetricName" }
sum:my_metric_name:rate5m
==>
MetricName(MetricIdentifier(Identifier))

View File

@ -0,0 +1,15 @@
import { parser } from '../parser';
import { fileTests } from 'lezer-generator/dist/test';
import * as fs from 'fs';
import * as path from 'path';
const caseDir = './src/lang-promql/grammar/test';
for (const file of fs.readdirSync(caseDir)) {
if (!/\.txt$/.test(file)) continue;
const name = /^[^\.]*/.exec(file)[0];
describe(name, () => {
for (const { name, run } of fileTests(fs.readFileSync(path.join(caseDir, file), 'utf8'), file)) it(name, () => run(parser));
});
}

View File

@ -0,0 +1,83 @@
// 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 {
And,
Avg,
Bool,
Bottomk,
By,
Count,
CountValues,
End,
Group,
GroupLeft,
GroupRight,
Ignoring,
inf,
Max,
Min,
nan,
Offset,
On,
Or,
Quantile,
Start,
Stddev,
Stdvar,
Sum,
Topk,
Unless,
Without,
} from './parser.terms.js';
const keywordTokens = {
inf: inf,
nan: nan,
bool: Bool,
ignoring: Ignoring,
on: On,
group_left: GroupLeft,
group_right: GroupRight,
offset: Offset,
};
export const specializeIdentifier = (value, stack) => {
return keywordTokens[value.toLowerCase()] || -1;
};
const contextualKeywordTokens = {
avg: Avg,
bottomk: Bottomk,
count: Count,
count_values: CountValues,
group: Group,
max: Max,
min: Min,
quantile: Quantile,
stddev: Stddev,
stdvar: Stdvar,
sum: Sum,
topk: Topk,
by: By,
without: Without,
and: And,
or: Or,
unless: Unless,
start: Start,
end: End,
};
export const extendIdentifier = (value, stack) => {
return contextualKeywordTokens[value.toLowerCase()] || -1;
};

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { EqlRegex, EqlSingle, Neq, NeqRegex } from 'lezer-promql';
import { EqlRegex, EqlSingle, Neq, NeqRegex } from '../grammar/parser.terms';
import { labelMatchersToString } from './matcher';
import { Matcher } from '../types';
import chai from 'chai';

View File

@ -12,7 +12,7 @@
// limitations under the License.
import { SyntaxNode } from 'lezer-tree';
import { EqlRegex, EqlSingle, LabelName, MatchOp, Neq, NeqRegex, StringLiteral } from 'lezer-promql';
import { EqlRegex, EqlSingle, LabelName, MatchOp, Neq, NeqRegex, StringLiteral } from '../grammar/parser.terms';
import { EditorState } from '@codemirror/state';
import { Matcher } from '../types';

View File

@ -47,7 +47,7 @@ import {
UnaryExpr,
Unless,
VectorSelector,
} from 'lezer-promql';
} from '../grammar/parser.terms';
import { containsAtLeastOneChild, retrieveAllRecursiveNodes, walkThrough } from './path-finder';
import { getType } from './type';
import { buildLabelMatchers } from './matcher';

View File

@ -32,7 +32,7 @@ import {
NumberLiteral,
Sub,
VectorSelector,
} from 'lezer-promql';
} from '../grammar/parser.terms';
import { createEditorState } from '../../test/utils';
import { containsAtLeastOneChild, containsChild, retrieveAllRecursiveNodes, walkBackward, walkThrough } from './path-finder';
import { SyntaxNode } from 'lezer-tree';

View File

@ -26,7 +26,7 @@ import {
SubqueryExpr,
UnaryExpr,
VectorSelector,
} from 'lezer-promql';
} from '../grammar/parser.terms';
import { walkThrough } from './path-finder';
import { getFunction, ValueType } from '../types';

View File

@ -14,7 +14,7 @@
import { buildVectorMatching } from './vector';
import { createEditorState } from '../../test/utils';
import { walkThrough } from './path-finder';
import { BinaryExpr, Expr } from 'lezer-promql';
import { BinaryExpr, Expr } from '../grammar/parser.terms';
import chai from 'chai';
import { syntaxTree } from '@codemirror/language';
import { VectorMatchCardinality } from '../types';

View File

@ -26,7 +26,7 @@ import {
OnOrIgnoring,
Or,
Unless,
} from 'lezer-promql';
} from '../grammar/parser.terms';
import { VectorMatchCardinality, VectorMatching } from '../types';
import { containsAtLeastOneChild, retrieveAllRecursiveNodes } from './path-finder';

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { parser } from 'lezer-promql';
import { parser } from './grammar/parser';
import { styleTags, tags } from '@codemirror/highlight';
import { Extension } from '@codemirror/state';
import { CompleteConfiguration, CompleteStrategy, newCompleteStrategy } from './complete';

View File

@ -63,7 +63,7 @@ import {
Timestamp,
Vector,
Year,
} from 'lezer-promql';
} from '../grammar/parser.terms';
export enum ValueType {
none = 'none',

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { EqlSingle, Neq } from 'lezer-promql';
import { EqlSingle, Neq } from '../grammar/parser.terms';
export class Matcher {
type: number;

View File

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { parser } from 'lezer-promql';
import { parser } from '../lang-promql/grammar/parser';
import { EditorState } from '@codemirror/state';
import { LezerLanguage } from '@codemirror/language';
import nock from 'nock';

View File

@ -13,7 +13,8 @@
"sourceMap": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": true,
"allowJs": true
},
"include": [
"src/lang-promql"