diff --git a/package.json b/package.json index 05aeff0fccc..852aa5346a4 100644 --- a/package.json +++ b/package.json @@ -257,21 +257,23 @@ "@grafana/e2e-selectors": "workspace:*", "@grafana/experimental": "^0.0.2-canary.36", "@grafana/google-sdk": "0.0.3", - "@grafana/lezer-logql": "0.0.14", + "@grafana/lezer-logql": "0.0.15", "@grafana/runtime": "workspace:*", "@grafana/schema": "workspace:*", "@grafana/slate-react": "0.22.10-grafana", "@grafana/ui": "workspace:*", "@jaegertracing/jaeger-ui-components": "workspace:*", "@kusto/monaco-kusto": "5.1.8", - "@lezer/common": "0.15.12", - "@lezer/lr": "0.15.8", + "@lezer/common": "1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "1.0.0", "@lingui/core": "3.14.0", "@lingui/react": "3.14.0", "@opentelemetry/api": "1.1.0", "@opentelemetry/exporter-collector": "0.25.0", "@opentelemetry/semantic-conventions": "1.5.0", "@popperjs/core": "2.11.5", + "@prometheus-io/lezer-promql": "^0.37.0-rc.1", "@react-aria/button": "3.5.1", "@react-aria/dialog": "3.2.1", "@react-aria/focus": "3.6.1", @@ -329,7 +331,6 @@ "json-source-map": "0.6.1", "jsurl": "^0.1.5", "kbar": "0.1.0-beta.36", - "lezer-promql": "0.22.0", "lodash": "4.17.21", "logfmt": "^1.3.2", "lru-cache": "7.13.1", diff --git a/public/app/plugins/datasource/loki/modifyQuery.test.ts b/public/app/plugins/datasource/loki/modifyQuery.test.ts index d893b2ae339..fc7a32a3a7c 100644 --- a/public/app/plugins/datasource/loki/modifyQuery.test.ts +++ b/public/app/plugins/datasource/loki/modifyQuery.test.ts @@ -26,7 +26,7 @@ describe('addLabelToQuery()', () => { it('should detect in-order function use', () => { expect(addLabelToQuery('sum by (host) (rate({} [1m]))', 'bar', '=', 'baz')).toBe( - 'sum by (host) (rate({bar="baz"} [1m]))' + 'sum by (host) (rate({bar="baz"}[1m]))' ); }); @@ -38,7 +38,7 @@ describe('addLabelToQuery()', () => { }); it('should work on arithmetical expressions', () => { - expect(addLabelToQuery('{} + {}', 'bar', '=', 'baz')).toBe('{bar="baz"} + {bar="baz"}'); + expect(addLabelToQuery('{} + {}', 'bar', '=', 'baz')).toBe('{bar="baz"}+ {bar="baz"}'); expect(addLabelToQuery('avg(rate({x="y"} [$__interval]))+ sum(rate({}[5m]))', 'bar', '=', 'baz')).toBe( 'avg(rate({x="y", bar="baz"} [$__interval]))+ sum(rate({bar="baz"}[5m]))' ); @@ -103,7 +103,7 @@ describe('addLabelToQuery()', () => { 'baz' ) ).toBe( - 'max by (id, name, type) ({type=~"foo|bar|baz-test", bar="baz"}) * on(id) group_right(id, type, name) sum by (id) (rate({bar="baz"} [5m])) * 1000' + 'max by (id, name, type) ({type=~"foo|bar|baz-test", bar="baz"}) * on(id) group_right(id, type, name) sum by (id) (rate({bar="baz"}[5m])) * 1000' ); }); it('should not add ad-hoc filter to labels in label list provided with the group modifier', () => { diff --git a/public/app/plugins/datasource/loki/modifyQuery.ts b/public/app/plugins/datasource/loki/modifyQuery.ts index 296a916210e..8c37891c130 100644 --- a/public/app/plugins/datasource/loki/modifyQuery.ts +++ b/public/app/plugins/datasource/loki/modifyQuery.ts @@ -123,7 +123,7 @@ function getStreamSelectorPositions(query: string): Position[] { const tree = parser.parse(query); const positions: Position[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { + enter: ({ type, from, to }): false | void => { if (type.name === 'Selector') { positions.push({ from, to }); return false; @@ -141,7 +141,7 @@ export function getParserPositions(query: string): Position[] { const tree = parser.parse(query); const positions: Position[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { + enter: ({ type, from, to }): false | void => { if (type.name === 'LabelParser' || type.name === 'JsonExpressionParser') { positions.push({ from, to }); return false; @@ -159,8 +159,8 @@ export function getLabelFilterPositions(query: string): Position[] { const tree = parser.parse(query); const positions: Position[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { - if (type.name === 'LabelFilter') { + enter: ({ name, from, to }): false | void => { + if (name === 'LabelFilter') { positions.push({ from, to }); return false; } @@ -177,9 +177,9 @@ function getLineFiltersPositions(query: string): Position[] { const tree = parser.parse(query); const positions: Position[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { - if (type.name === 'LineFilters') { - positions.push({ from, to }); + enter: ({ node }): false | void => { + if (node.name === 'LineFilters') { + positions.push({ from: node.from, to: node.to }); return false; } }, @@ -195,28 +195,28 @@ function getLogQueryPositions(query: string): Position[] { const tree = parser.parse(query); const positions: Position[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { - if (type.name === 'LogExpr') { + enter: ({ name, from, to, node }): false | void => { + if (name === 'LogExpr') { positions.push({ from, to }); return false; } // This is a case in metrics query - if (type.name === 'LogRangeExpr') { + if (name === 'LogRangeExpr') { // Unfortunately, LogRangeExpr includes both log and non-log (e.g. Duration/Range/...) parts of query. // We get position of all log-parts within LogRangeExpr: Selector, PipelineExpr and UnwrapExpr. const logPartsPositions: Position[] = []; - const selector = get().getChild('Selector'); + const selector = node.getChild('Selector'); if (selector) { logPartsPositions.push({ from: selector.from, to: selector.to }); } - const pipeline = get().getChild('PipelineExpr'); + const pipeline = node.getChild('PipelineExpr'); if (pipeline) { logPartsPositions.push({ from: pipeline.from, to: pipeline.to }); } - const unwrap = get().getChild('UnwrapExpr'); + const unwrap = node.getChild('UnwrapExpr'); if (unwrap) { logPartsPositions.push({ from: unwrap.from, to: unwrap.to }); } @@ -359,7 +359,7 @@ function getLineCommentPositions(query: string): Position[] { const tree = parser.parse(query); const positions: Position[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { + enter: ({ type, from, to }): false | void => { if (type.id === LineComment) { positions.push({ from, to }); return false; diff --git a/public/app/plugins/datasource/loki/query_utils.ts b/public/app/plugins/datasource/loki/query_utils.ts index 5a264cfb7a5..a13c4b392e3 100644 --- a/public/app/plugins/datasource/loki/query_utils.ts +++ b/public/app/plugins/datasource/loki/query_utils.ts @@ -21,9 +21,9 @@ export function getHighlighterExpressionsFromQuery(input: string): string[] { const tree = parser.parse(input); const filters: SyntaxNode[] = []; tree.iterate({ - enter: (type, from, to, get): void => { + enter: ({ type, node }): void => { if (type.id === LineFilter) { - filters.push(get()); + filters.push(node); } }, }); @@ -135,9 +135,9 @@ export function isQueryPipelineErrorFiltering(query: string): boolean { let isQueryPipelineErrorFiltering = false; const tree = parser.parse(query); tree.iterate({ - enter: (type, from, to, get): false | void => { - if (type.name === 'LabelFilter') { - const label = get().getChild('Matcher')?.getChild('Identifier'); + enter: ({ name, node }): false | void => { + if (name === 'LabelFilter') { + const label = node.getChild('Matcher')?.getChild('Identifier'); if (label) { const labelName = query.substring(label.from, label.to); if (labelName === '__error__') { @@ -174,8 +174,8 @@ export function getLogQueryFromMetricsQuery(query: string): string { // Log query in metrics query composes of Selector & PipelineExpr let selector = ''; tree.iterate({ - enter: (type, from, to): false | void => { - if (type.name === 'Selector') { + enter: ({ name, from, to }): false | void => { + if (name === 'Selector') { selector = query.substring(from, to); return false; } @@ -184,8 +184,8 @@ export function getLogQueryFromMetricsQuery(query: string): string { let pipelineExpr = ''; tree.iterate({ - enter: (type, from, to): false | void => { - if (type.name === 'PipelineExpr') { + enter: ({ name, from, to }): false | void => { + if (name === 'PipelineExpr') { pipelineExpr = query.substring(from, to); return false; } diff --git a/public/app/plugins/datasource/prometheus/add_label_to_query.ts b/public/app/plugins/datasource/prometheus/add_label_to_query.ts index f08c636626c..696e0cbb8dc 100644 --- a/public/app/plugins/datasource/prometheus/add_label_to_query.ts +++ b/public/app/plugins/datasource/prometheus/add_label_to_query.ts @@ -1,4 +1,4 @@ -import { parser, VectorSelector } from 'lezer-promql'; +import { parser, VectorSelector } from '@prometheus-io/lezer-promql'; import { PromQueryModeller } from './querybuilder/PromQueryModeller'; import { buildVisualQueryFromString } from './querybuilder/parsing'; @@ -44,7 +44,7 @@ function getVectorSelectorPositions(query: string): VectorSelectorPosition[] { const tree = parser.parse(query); const positions: VectorSelectorPosition[] = []; tree.iterate({ - enter: (type, from, to, get): false | void => { + enter: ({ to, from, type }): false | void => { if (type.id === VectorSelector) { const visQuery = buildVisualQueryFromString(query.substring(from, to)); positions.push({ query: visQuery.query, from, to }); diff --git a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts index 77563964b6d..f1e2d522f94 100644 --- a/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts +++ b/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts @@ -20,7 +20,7 @@ import { PromQL, StringLiteral, VectorSelector, -} from 'lezer-promql'; +} from '@prometheus-io/lezer-promql'; import { NeverCaseError } from './util'; @@ -506,7 +506,7 @@ function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number) // by default by lezer. problem is, `next()` will go upward too, // and we do not want to go higher than our node function getErrorNode(tree: Tree, pos: number): SyntaxNode | null { - const cur = tree.cursor(pos); + const cur = tree.cursorAt(pos); while (true) { if (cur.from === pos && cur.to === pos) { const { node } = cur; @@ -547,7 +547,7 @@ export function getSituation(text: string, pos: number): Situation | null { // so first we check if there is an error-node at the cursor-position const maybeErrorNode = getErrorNode(tree, pos); - const cur = maybeErrorNode != null ? maybeErrorNode.cursor : tree.cursor(pos); + const cur = maybeErrorNode != null ? maybeErrorNode.cursor() : tree.cursorAt(pos); const currentNode = cur.node; const ids = [cur.type.id]; diff --git a/public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts b/public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts index a340f44fb63..1b5cdf988ae 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts @@ -53,8 +53,19 @@ describe('buildVisualQueryFromString', () => { buildVisualQueryFromString( 'avg(rate(access_evaluation_duration_count{instance="host.docker.internal:3000"}[$__rate_interval]))' ) - ).toEqual( - noErrors({ + ).toEqual({ + // after upgrading @prometheus-io/lezer-promql, strings containing global grafana variables such as $__rate_interval (https://grafana.com/docs/grafana/latest/variables/variable-types/global-variables/) + // started returning error nodes upon parse, but the resultant tree was otherwise the same. + // My assumption is that the newer version of lezer is more verbose in returning error nodes, and there should be no functional change to the parsed trees. + errors: [ + { + from: 107, + parentType: 'MatrixSelector', + text: '', + to: 107, + }, + ], + query: { metric: 'access_evaluation_duration_count', labels: [ { @@ -73,8 +84,8 @@ describe('buildVisualQueryFromString', () => { params: [], }, ], - }) - ); + }, + }); }); it('parses query with aggregation by labels', () => { @@ -160,8 +171,16 @@ describe('buildVisualQueryFromString', () => { it('parses function with argument', () => { expect( buildVisualQueryFromString('histogram_quantile(0.99, rate(counters_logins{app="backend"}[$__rate_interval]))') - ).toEqual( - noErrors({ + ).toEqual({ + errors: [ + { + from: 88, + parentType: 'MatrixSelector', + text: '', + to: 88, + }, + ], + query: { metric: 'counters_logins', labels: [{ label: 'app', op: '=', value: 'backend' }], operations: [ @@ -174,8 +193,8 @@ describe('buildVisualQueryFromString', () => { params: [0.99], }, ], - }) - ); + }, + }); }); it('parses function with multiple arguments', () => { @@ -183,8 +202,16 @@ describe('buildVisualQueryFromString', () => { buildVisualQueryFromString( 'label_replace(avg_over_time(http_requests_total{instance="foo"}[$__interval]), "instance", "$1", "", "(.*)")' ) - ).toEqual( - noErrors({ + ).toEqual({ + errors: [ + { + from: 86, + parentType: 'MatrixSelector', + text: '', + to: 86, + }, + ], + query: { metric: 'http_requests_total', labels: [{ label: 'instance', op: '=', value: 'foo' }], operations: [ @@ -197,13 +224,21 @@ describe('buildVisualQueryFromString', () => { params: ['instance', '$1', '', '(.*)'], }, ], - }) - ); + }, + }); }); it('parses binary operation with scalar', () => { - expect(buildVisualQueryFromString('avg_over_time(http_requests_total{instance="foo"}[$__interval]) / 2')).toEqual( - noErrors({ + expect(buildVisualQueryFromString('avg_over_time(http_requests_total{instance="foo"}[$__interval]) / 2')).toEqual({ + errors: [ + { + from: 72, + parentType: 'MatrixSelector', + text: '', + to: 72, + }, + ], + query: { metric: 'http_requests_total', labels: [{ label: 'instance', op: '=', value: 'foo' }], operations: [ @@ -216,15 +251,23 @@ describe('buildVisualQueryFromString', () => { params: [2], }, ], - }) - ); + }, + }); }); it('parses binary operation with 2 queries', () => { expect( buildVisualQueryFromString('avg_over_time(http_requests_total{instance="foo"}[$__interval]) / sum(logins_count)') - ).toEqual( - noErrors({ + ).toEqual({ + errors: [ + { + from: 72, + parentType: 'MatrixSelector', + text: '', + to: 72, + }, + ], + query: { metric: 'http_requests_total', labels: [{ label: 'instance', op: '=', value: 'foo' }], operations: [{ id: 'avg_over_time', params: ['$__interval'] }], @@ -238,8 +281,8 @@ describe('buildVisualQueryFromString', () => { }, }, ], - }) - ); + }, + }); }); it('parses template variables in strings', () => { diff --git a/public/app/plugins/datasource/prometheus/querybuilder/parsing.ts b/public/app/plugins/datasource/prometheus/querybuilder/parsing.ts index f95410e97ee..0edfe3543f4 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/parsing.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/parsing.ts @@ -25,7 +25,7 @@ import { StringLiteral, VectorSelector, Without, -} from 'lezer-promql'; +} from '@prometheus-io/lezer-promql'; import { binaryScalarOperatorToOperatorName } from './binaryScalarOperations'; import { diff --git a/public/app/plugins/datasource/prometheus/querybuilder/shared/parsingUtils.test.ts b/public/app/plugins/datasource/prometheus/querybuilder/shared/parsingUtils.test.ts index 700e2dfa744..81c8d255ca6 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/shared/parsingUtils.test.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/shared/parsingUtils.test.ts @@ -1,4 +1,4 @@ -import { parser } from 'lezer-promql'; +import { parser } from '@prometheus-io/lezer-promql'; import { getLeftMostChild, getString, replaceVariables } from './parsingUtils'; diff --git a/yarn.lock b/yarn.lock index 0f2680e0b79..4fe9cde8475 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4981,14 +4981,12 @@ __metadata: languageName: node linkType: hard -"@grafana/lezer-logql@npm:0.0.14": - version: 0.0.14 - resolution: "@grafana/lezer-logql@npm:0.0.14" - dependencies: - lezer: ^0.13.5 +"@grafana/lezer-logql@npm:0.0.15": + version: 0.0.15 + resolution: "@grafana/lezer-logql@npm:0.0.15" peerDependencies: - "@lezer/lr": ^0.15.8 - checksum: 4e35f455b6b7c286dfca9f3770df0d4c325057352dc8241665b667d798db09de54e1c14f7bfd34d4ae5bbef782d28994ceaf5c517fc18cff46ae3a47527e1990 + "@lezer/lr": ^1.0.0 + checksum: 2dac2654b46ee255ae56f12e2c23ecb71a0eda2753f98117d61b79a10dd0f0b443420aa34dd3cbc243a92cd8983411823cb2bebfe04d5b86cf9c72236c054de1 languageName: node linkType: hard @@ -6978,19 +6976,28 @@ __metadata: languageName: node linkType: hard -"@lezer/common@npm:0.15.12, @lezer/common@npm:^0.15.0": - version: 0.15.12 - resolution: "@lezer/common@npm:0.15.12" - checksum: dae65816187bd690bf446bec116313d3b5328e70e3e1f7c806273d9356ca2017cf82aa650ea53b95260fb98898ea73d44f33319f9dbbd48d473e2f20771b2377 +"@lezer/common@npm:1.0.0, @lezer/common@npm:^1.0.0": + version: 1.0.0 + resolution: "@lezer/common@npm:1.0.0" + checksum: 0ba652b39f9ff073a6a8a3376a74279f2c2d2ccdd4d2bb57c7b607341dbdbf64baf9c23a196314f09349d175623bc73a6a0b6a0eeb2cc63f3a1190fd631f7c31 languageName: node linkType: hard -"@lezer/lr@npm:0.15.8": - version: 0.15.8 - resolution: "@lezer/lr@npm:0.15.8" +"@lezer/highlight@npm:^1.0.0": + version: 1.0.0 + resolution: "@lezer/highlight@npm:1.0.0" dependencies: - "@lezer/common": ^0.15.0 - checksum: e741225d6ac9cf08f8016bad49622fbd4a4e0d20c2e8c2b38a0abf0ddca69c58275b0ebdb9d5dde2905cf84f6977bc302f7ed5e5ba42c23afa27e9e65b900f36 + "@lezer/common": ^1.0.0 + checksum: 9ce6c4ea041598e2500f11610e74163eba0361954df8dbf5d12b96dc8b5ab5da8af2defda7ff5728ca460d49f053a7502f2840361bcd8dcf30e8a23f7c30672a + languageName: node + linkType: hard + +"@lezer/lr@npm:1.0.0": + version: 1.0.0 + resolution: "@lezer/lr@npm:1.0.0" + dependencies: + "@lezer/common": ^1.0.0 + checksum: 1365a2d1fa0a40815a03a635506a0215475b778d8b8907d274b8ee4b0732fcb7266799b50db7c4517254da1d245c153c348fd0d7b1db93b7d66926b9c538ee43 languageName: node linkType: hard @@ -8074,6 +8081,16 @@ __metadata: languageName: node linkType: hard +"@prometheus-io/lezer-promql@npm:^0.37.0-rc.1": + version: 0.37.0 + resolution: "@prometheus-io/lezer-promql@npm:0.37.0" + peerDependencies: + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 17722456a67dbbbc92c923656f43c65d99e0e8f7d4a7086fb63438286cc51b02bc1713506ec1b1f3a7337aa4dd9840261d8abdcb6518c90d8b8ebaf2608bb672 + languageName: node + linkType: hard + "@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": version: 1.1.2 resolution: "@protobufjs/aspromise@npm:1.1.2" @@ -21660,7 +21677,7 @@ __metadata: "@grafana/eslint-config": 5.0.0 "@grafana/experimental": ^0.0.2-canary.36 "@grafana/google-sdk": 0.0.3 - "@grafana/lezer-logql": 0.0.14 + "@grafana/lezer-logql": 0.0.15 "@grafana/runtime": "workspace:*" "@grafana/schema": "workspace:*" "@grafana/slate-react": 0.22.10-grafana @@ -21669,8 +21686,9 @@ __metadata: "@grafana/ui": "workspace:*" "@jaegertracing/jaeger-ui-components": "workspace:*" "@kusto/monaco-kusto": 5.1.8 - "@lezer/common": 0.15.12 - "@lezer/lr": 0.15.8 + "@lezer/common": 1.0.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": 1.0.0 "@lingui/cli": 3.14.0 "@lingui/core": 3.14.0 "@lingui/macro": 3.14.0 @@ -21681,6 +21699,7 @@ __metadata: "@opentelemetry/semantic-conventions": 1.5.0 "@pmmmwh/react-refresh-webpack-plugin": 0.5.7 "@popperjs/core": 2.11.5 + "@prometheus-io/lezer-promql": ^0.37.0-rc.1 "@react-aria/button": 3.5.1 "@react-aria/dialog": 3.2.1 "@react-aria/focus": 3.6.1 @@ -21846,7 +21865,6 @@ __metadata: jsurl: ^0.1.5 kbar: 0.1.0-beta.36 lerna: 5.2.0 - lezer-promql: 0.22.0 lint-staged: 13.0.3 lodash: 4.17.21 logfmt: ^1.3.2 @@ -25969,31 +25987,6 @@ __metadata: languageName: node linkType: hard -"lezer-promql@npm:0.22.0": - version: 0.22.0 - resolution: "lezer-promql@npm:0.22.0" - peerDependencies: - "@lezer/lr": ^0.15.8 - checksum: cdce054700874ef95c779899bc8a6a774f83bc613d509011b7d3b8003f07fa853962291c44edf9232e7a927d0753fec77ec55d795abddda9d2efc044f78bb58a - languageName: node - linkType: hard - -"lezer-tree@npm:^0.13.2": - version: 0.13.2 - resolution: "lezer-tree@npm:0.13.2" - checksum: b8be213c780191e0669c7f440aa563218ada762d2cf399b94e755a563cc7da8951929fa3ee65df9ef6586a81223c55cd662e1ec5b49060d892acca4198cf3596 - languageName: node - linkType: hard - -"lezer@npm:^0.13.5": - version: 0.13.5 - resolution: "lezer@npm:0.13.5" - dependencies: - lezer-tree: ^0.13.2 - checksum: a5c3aa01c539aba3377a927063bcd63b311737a7abfd71ad2c2229ed4e48b7858f2e8e11e925f8f5286c2629251f77dfabf7505ea6c707499cd9917ca90934c8 - languageName: node - linkType: hard - "libnpmaccess@npm:^4.0.1": version: 4.0.3 resolution: "libnpmaccess@npm:4.0.3"