mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-11 05:47:27 -08:00
UI: stabilize dependencies and environment (#10517)
* create lezer-promql module + move codemirror to a pure esm module + unified dependencies Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * ignore test utils file and remove the type "module" in package.json Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * use jest to run the lezer-promql test Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * give an automatic way to update the ui dependencies Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * update all dependencies using make update-npm-deps Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * fix react-app test Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * remove generated file Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * remove unnecessary backslash in script Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * fix reviews Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * rewording Signed-off-by: Augustin Husson <husson.augustin@gmail.com> * use npx to run lezer-generator Signed-off-by: Augustin Husson <husson.augustin@gmail.com>
This commit is contained in:
parent
063319087c
commit
043a2954f8
12
Makefile
12
Makefile
|
@ -29,6 +29,16 @@ include Makefile.common
|
|||
|
||||
DOCKER_IMAGE_NAME ?= prometheus
|
||||
|
||||
.PHONY: update-npm-deps
|
||||
update-npm-deps:
|
||||
@echo ">> updating npm dependencies"
|
||||
./scripts/npm-deps.sh "minor"
|
||||
|
||||
.PHONY: upgrade-npm-deps
|
||||
upgrade-npm-deps:
|
||||
@echo ">> upgrading npm dependencies"
|
||||
./scripts/npm-deps.sh "latest"
|
||||
|
||||
.PHONY: ui-install
|
||||
ui-install:
|
||||
cd $(UI_PATH) && npm install
|
||||
|
@ -43,7 +53,7 @@ ui-build-module:
|
|||
|
||||
.PHONY: ui-test
|
||||
ui-test:
|
||||
cd $(UI_PATH) && CI=true npm run test:coverage
|
||||
cd $(UI_PATH) && CI=true npm run test
|
||||
|
||||
.PHONY: ui-lint
|
||||
ui-lint:
|
||||
|
|
15
RELEASE.md
15
RELEASE.md
|
@ -104,12 +104,19 @@ git commit -m "Update dependencies"
|
|||
#### Updating React dependencies
|
||||
|
||||
The React application recently moved to a monorepo system with multiple internal npm packages. Dependency upgrades are
|
||||
quite sensitive for the time being and should be done manually with caution.
|
||||
quite sensitive for the time being.
|
||||
|
||||
When you want to update a dependency, you have to go to every internal npm package where the dependency is used and
|
||||
manually change the version. Once you have taken care of that, you need to go back to `web/ui` and run `npm install`
|
||||
In case you want to update the UI dependencies, you can run the following command:
|
||||
|
||||
**NOTE**: We are researching ways to automate and improve this.
|
||||
```bash
|
||||
make update-npm-deps
|
||||
```
|
||||
|
||||
Once this step completes, please verify that no additional `node_modules` directory was created in any of the module subdirectories
|
||||
(which could indicate conflicting dependency versions across modules). Then run `make ui-build` to verify that the build is still working.
|
||||
|
||||
Note: Once in a while, the npm dependencies should also be updated to their latest release versions (major or minor) with `make upgrade-npm-deps`,
|
||||
though this may be done at convenient times (e.g. by the UI maintainers) that are out-of-sync with Prometheus releases.
|
||||
|
||||
### 1. Prepare your release
|
||||
|
||||
|
|
16
scripts/npm-deps.sh
Executable file
16
scripts/npm-deps.sh
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
function ncu() {
|
||||
target=$1
|
||||
npx npm-check-updates -u --target "${target}"
|
||||
}
|
||||
|
||||
cd web/ui
|
||||
for workspace in $(npm ls --production --depth 1 -json | jq -r '.dependencies[].resolved[8:]'); do
|
||||
cd "${workspace}"
|
||||
ncu "$1"
|
||||
cd ../
|
||||
done
|
||||
|
||||
ncu "$1"
|
||||
npm install
|
|
@ -16,7 +16,7 @@
|
|||
set -e
|
||||
current=$(pwd)
|
||||
|
||||
buildOrder=(module/codemirror-promql)
|
||||
buildOrder=(module/lezer-promql module/codemirror-promql)
|
||||
|
||||
function buildModule() {
|
||||
for module in "${buildOrder[@]}"; do
|
||||
|
|
4
web/ui/module/codemirror-promql/.gitignore
vendored
4
web/ui/module/codemirror-promql/.gitignore
vendored
|
@ -4,8 +4,4 @@ node_modules/
|
|||
dist/
|
||||
lib/
|
||||
|
||||
src/grammar/**.ts
|
||||
src/grammar/parser.js
|
||||
src/grammar/parser.terms.js
|
||||
|
||||
/.nyc_output
|
||||
|
|
|
@ -16,5 +16,5 @@
|
|||
set -ex
|
||||
|
||||
# build the lib (both ES2015 and CommonJS)
|
||||
tsc --module ES2015 --target ES2015 --outDir dist/esm
|
||||
tsc --module esnext --target es2018 --outDir dist/esm
|
||||
tsc --module commonjs --target es5 --outDir dist/cjs --downlevelIteration
|
||||
|
|
18
web/ui/module/codemirror-promql/jest.config.cjs
Normal file
18
web/ui/module/codemirror-promql/jest.config.cjs
Normal file
|
@ -0,0 +1,18 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
extensionsToTreatAsEsm: ['.ts'],
|
||||
testEnvironment: 'node',
|
||||
setupFiles: [
|
||||
'./setupJest.cjs'
|
||||
],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
useESM: true,
|
||||
},
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'lezer-promql': '<rootDir>/../../node_modules/lezer-promql/dist/index.es.js'
|
||||
},
|
||||
transformIgnorePatterns: ["<rootDir>/../../node_modules/(?!lezer-promql)/"]
|
||||
};
|
|
@ -2,21 +2,19 @@
|
|||
"name": "codemirror-promql",
|
||||
"version": "0.19.0",
|
||||
"description": "a CodeMirror mode for the PromQL language",
|
||||
"main": "dist/cjs/index.js",
|
||||
"types": "dist/esm/index.d.ts",
|
||||
"module": "dist/esm/index.js",
|
||||
"main": "dist/cjs/index.js",
|
||||
"scripts": {
|
||||
"build": "npm run build:grammar && npm run build:lib",
|
||||
"build:grammar": "npx lezer-generator src/grammar/promql.grammar -o src/grammar/parser",
|
||||
"build": "npm run build:lib",
|
||||
"build:lib": "bash ./build.sh",
|
||||
"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 src/**/*.test.ts",
|
||||
"codecov": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
||||
"lint": "eslint src/ --ext .ts",
|
||||
"lint:fix": "eslint --fix src/ --ext .ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/prometheus/codemirror-promql.git"
|
||||
"url": "git+https://github.com/prometheus/prometheus.git"
|
||||
},
|
||||
"keywords": [
|
||||
"promql",
|
||||
|
@ -27,54 +25,34 @@
|
|||
"author": "Prometheus Authors <prometheus-developers@googlegroups.com>",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/prometheus/codemirror-promql/issues"
|
||||
"url": "https://github.com/prometheus/prometheus/issues"
|
||||
},
|
||||
"homepage": "https://github.com/prometheus/codemirror-promql/blob/main/README.md",
|
||||
"homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/codemirror-promql/README.md",
|
||||
"dependencies": {
|
||||
"lezer-promql": "0.23.0",
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codemirror/autocomplete": "^0.19.9",
|
||||
"@codemirror/basic-setup": "^0.19.0",
|
||||
"@codemirror/highlight": "^0.19.6",
|
||||
"@codemirror/language": "^0.19.7",
|
||||
"@codemirror/lint": "^0.19.3",
|
||||
"@codemirror/state": "^0.19.6",
|
||||
"@codemirror/view": "^0.19.27",
|
||||
"@lezer/common": "^0.15.11",
|
||||
"@lezer/lr": "^0.15.5",
|
||||
"@lezer/generator": "^0.15.2",
|
||||
"@types/chai": "^4.2.22",
|
||||
"@codemirror/autocomplete": "^0.19.15",
|
||||
"@codemirror/highlight": "^0.19.8",
|
||||
"@codemirror/language": "^0.19.10",
|
||||
"@codemirror/lint": "^0.19.6",
|
||||
"@codemirror/state": "^0.19.9",
|
||||
"@codemirror/view": "^0.19.48",
|
||||
"@lezer/common": "^0.15.12",
|
||||
"@lezer/lr": "^0.15.8",
|
||||
"@types/lru-cache": "^5.1.1",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/node": "^16.11.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
||||
"@typescript-eslint/parser": "^5.8.0",
|
||||
"chai": "^4.2.0",
|
||||
"codecov": "^3.8.3",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-flowtype": "^8.0.3",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"mocha": "^8.4.0",
|
||||
"nock": "^13.2.1",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
"ts-loader": "^7.0.5",
|
||||
"ts-mocha": "^8.0.0",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^4.6.2"
|
||||
"nock": "^13.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@codemirror/autocomplete": "^0.19.9",
|
||||
"@codemirror/highlight": "^0.19.6",
|
||||
"@codemirror/language": "^0.19.7",
|
||||
"@codemirror/lint": "^0.19.3",
|
||||
"@codemirror/state": "^0.19.6",
|
||||
"@codemirror/view": "^0.19.27",
|
||||
"@lezer/common": "^0.15.11"
|
||||
"@codemirror/autocomplete": "^0.19.15",
|
||||
"@codemirror/highlight": "^0.19.8",
|
||||
"@codemirror/language": "^0.19.10",
|
||||
"@codemirror/lint": "^0.19.6",
|
||||
"@codemirror/state": "^0.19.9",
|
||||
"@codemirror/view": "^0.19.48",
|
||||
"@lezer/common": "^0.15.12"
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true,
|
||||
|
|
1
web/ui/module/codemirror-promql/setupJest.cjs
Normal file
1
web/ui/module/codemirror-promql/setupJest.cjs
Normal file
|
@ -0,0 +1 @@
|
|||
global.fetch = require('isomorphic-fetch')
|
|
@ -11,9 +11,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import chai from 'chai';
|
||||
import { analyzeCompletion, computeStartCompletePosition, ContextKind } from './hybrid';
|
||||
import { createEditorState, mockedMetricsTerms, mockPrometheusServer } from '../test/utils.test';
|
||||
import { createEditorState, mockedMetricsTerms, mockPrometheusServer } from '../test/utils-test';
|
||||
import { Completion, CompletionContext } from '@codemirror/autocomplete';
|
||||
import {
|
||||
aggregateOpModifierTerms,
|
||||
|
@ -27,7 +26,7 @@ import {
|
|||
numberTerms,
|
||||
snippets,
|
||||
} from './promql.terms';
|
||||
import { EqlSingle, Neq } from '../grammar/parser.terms';
|
||||
import { EqlSingle, Neq } from 'lezer-promql';
|
||||
import { syntaxTree } from '@codemirror/language';
|
||||
import { newCompleteStrategy } from './index';
|
||||
|
||||
|
@ -530,7 +529,7 @@ describe('analyzeCompletion test', () => {
|
|||
const state = createEditorState(value.expr);
|
||||
const node = syntaxTree(state).resolve(value.pos, -1);
|
||||
const result = analyzeCompletion(state, node);
|
||||
chai.expect(value.expectedContext).to.deep.equal(result);
|
||||
expect(value.expectedContext).toEqual(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -717,7 +716,7 @@ describe('computeStartCompletePosition test', () => {
|
|||
const state = createEditorState(value.expr);
|
||||
const node = syntaxTree(state).resolve(value.pos, -1);
|
||||
const result = computeStartCompletePosition(node, value.pos);
|
||||
chai.expect(value.expectedStart).to.equal(result);
|
||||
expect(value.expectedStart).toEqual(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1285,7 +1284,7 @@ describe('autocomplete promQL test', () => {
|
|||
const context = new CompletionContext(state, value.pos, true);
|
||||
const completion = newCompleteStrategy(value.conf);
|
||||
const result = await completion.promQL(context);
|
||||
chai.expect(value.expectedResult).to.deep.equal(result);
|
||||
expect(value.expectedResult).toEqual(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -58,7 +58,7 @@ import {
|
|||
SubqueryExpr,
|
||||
Unless,
|
||||
VectorSelector,
|
||||
} from '../grammar/parser.terms';
|
||||
} from 'lezer-promql';
|
||||
import { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { buildLabelMatchers, containsAtLeastOneChild, containsChild, retrieveAllRecursiveNodes, walkBackward, walkThrough } from '../parser';
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import { parser } from '../parser';
|
||||
import { fileTests } from '@lezer/generator/dist/test';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const caseDir = './src/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));
|
||||
});
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
// 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,
|
||||
Atan2,
|
||||
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,
|
||||
atan2: Atan2,
|
||||
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;
|
||||
};
|
|
@ -11,10 +11,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { EqlRegex, EqlSingle, Neq, NeqRegex } from '../grammar/parser.terms';
|
||||
import { EqlRegex, EqlSingle, Neq, NeqRegex } from 'lezer-promql';
|
||||
import { labelMatchersToString } from './matcher';
|
||||
import { Matcher } from '../types';
|
||||
import chai from 'chai';
|
||||
|
||||
describe('labelMatchersToString test', () => {
|
||||
const testCases = [
|
||||
|
@ -131,7 +130,7 @@ describe('labelMatchersToString test', () => {
|
|||
|
||||
testCases.forEach((value) => {
|
||||
it(value.title, () => {
|
||||
chai.expect(labelMatchersToString(value.metricName, value.matchers, value.labelName)).to.equal(value.result);
|
||||
expect(labelMatchersToString(value.metricName, value.matchers, value.labelName)).toEqual(value.result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { SyntaxNode } from '@lezer/common';
|
||||
import { EqlRegex, EqlSingle, LabelName, MatchOp, Neq, NeqRegex, StringLiteral } from '../grammar/parser.terms';
|
||||
import { EqlRegex, EqlSingle, LabelName, MatchOp, Neq, NeqRegex, StringLiteral } from 'lezer-promql';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { Matcher } from '../types';
|
||||
|
||||
|
|
|
@ -11,10 +11,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import chai from 'chai';
|
||||
import { Parser } from './parser';
|
||||
import { Diagnostic } from '@codemirror/lint';
|
||||
import { createEditorState } from '../test/utils.test';
|
||||
import { createEditorState } from '../test/utils-test';
|
||||
import { syntaxTree } from '@codemirror/language';
|
||||
import { ValueType } from '../types';
|
||||
|
||||
|
@ -752,8 +751,8 @@ describe('promql operations', () => {
|
|||
const state = createEditorState(value.expr);
|
||||
const parser = new Parser(state);
|
||||
it(value.expr, () => {
|
||||
chai.expect(parser.checkAST(syntaxTree(state).topNode.firstChild)).to.equal(value.expectedValueType);
|
||||
chai.expect(parser.getDiagnostics()).to.deep.equal(value.expectedDiag);
|
||||
expect(parser.checkAST(syntaxTree(state).topNode.firstChild)).toEqual(value.expectedValueType);
|
||||
expect(parser.getDiagnostics()).toEqual(value.expectedDiag);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -47,7 +47,7 @@ import {
|
|||
UnaryExpr,
|
||||
Unless,
|
||||
VectorSelector,
|
||||
} from '../grammar/parser.terms';
|
||||
} from 'lezer-promql';
|
||||
import { containsAtLeastOneChild, retrieveAllRecursiveNodes, walkThrough } from './path-finder';
|
||||
import { getType } from './type';
|
||||
import { buildLabelMatchers } from './matcher';
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import chai from 'chai';
|
||||
import {
|
||||
Add,
|
||||
AggregateExpr,
|
||||
|
@ -32,8 +31,8 @@ import {
|
|||
NumberLiteral,
|
||||
Sub,
|
||||
VectorSelector,
|
||||
} from '../grammar/parser.terms';
|
||||
import { createEditorState } from '../test/utils.test';
|
||||
} from 'lezer-promql';
|
||||
import { createEditorState } from '../test/utils-test';
|
||||
import { containsAtLeastOneChild, containsChild, retrieveAllRecursiveNodes, walkBackward, walkThrough } from './path-finder';
|
||||
import { SyntaxNode } from '@lezer/common';
|
||||
import { syntaxTree } from '@codemirror/language';
|
||||
|
@ -86,12 +85,12 @@ describe('walkThrough test', () => {
|
|||
const subTree = syntaxTree(state).resolve(value.pos, -1);
|
||||
const node = walkThrough(subTree, ...value.path);
|
||||
if (typeof value.expectedNode === 'number') {
|
||||
chai.expect(value.expectedNode).to.equal(node?.type.id);
|
||||
expect(value.expectedNode).toEqual(node?.type.id);
|
||||
} else {
|
||||
chai.expect(value.expectedNode).to.equal(node?.type.name);
|
||||
expect(value.expectedNode).toEqual(node?.type.name);
|
||||
}
|
||||
if (node) {
|
||||
chai.expect(value.expectedDoc).to.equal(state.sliceDoc(node.from, node.to));
|
||||
expect(value.expectedDoc).toEqual(state.sliceDoc(node.from, node.to));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -129,9 +128,9 @@ describe('containsAtLeastOneChild test', () => {
|
|||
const state = createEditorState(value.expr);
|
||||
const subTree = syntaxTree(state).resolve(value.pos, -1);
|
||||
const node = walkThrough(subTree, ...value.walkThrough);
|
||||
chai.expect(node).to.not.null;
|
||||
expect(node).toBeTruthy();
|
||||
if (node) {
|
||||
chai.expect(value.expectedResult).to.equal(containsAtLeastOneChild(node, ...value.child));
|
||||
expect(value.expectedResult).toEqual(containsAtLeastOneChild(node, ...value.child));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -162,9 +161,9 @@ describe('containsChild test', () => {
|
|||
const subTree = syntaxTree(state).resolve(value.pos, -1);
|
||||
const node: SyntaxNode | null = walkThrough(subTree, ...value.walkThrough);
|
||||
|
||||
chai.expect(node).to.not.null;
|
||||
expect(node).toBeTruthy();
|
||||
if (node) {
|
||||
chai.expect(value.expectedResult).to.equal(containsChild(node, ...value.child));
|
||||
expect(value.expectedResult).toEqual(containsChild(node, ...value.child));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -174,9 +173,9 @@ describe('retrieveAllRecursiveNodes test', () => {
|
|||
it('should find every occurrence', () => {
|
||||
const state = createEditorState('rate(1,2,3)');
|
||||
const tree = syntaxTree(state).topNode.firstChild;
|
||||
chai.expect(tree).to.not.null;
|
||||
expect(tree).toBeTruthy();
|
||||
if (tree) {
|
||||
chai.expect(3).to.equal(retrieveAllRecursiveNodes(walkThrough(tree, FunctionCall, FunctionCallBody), FunctionCallArgs, Expr).length);
|
||||
expect(3).toEqual(retrieveAllRecursiveNodes(walkThrough(tree, FunctionCall, FunctionCallBody), FunctionCallArgs, Expr).length);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -195,7 +194,7 @@ describe('walkbackward test', () => {
|
|||
it(value.title, () => {
|
||||
const state = createEditorState(value.expr);
|
||||
const tree = syntaxTree(state).resolve(value.pos, -1);
|
||||
chai.expect(value.expectedResult).to.equal(walkBackward(tree, value.exit)?.type.id);
|
||||
expect(value.expectedResult).toEqual(walkBackward(tree, value.exit)?.type.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
SubqueryExpr,
|
||||
UnaryExpr,
|
||||
VectorSelector,
|
||||
} from '../grammar/parser.terms';
|
||||
} from 'lezer-promql';
|
||||
import { walkThrough } from './path-finder';
|
||||
import { getFunction, ValueType } from '../types';
|
||||
|
||||
|
|
|
@ -12,10 +12,9 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { buildVectorMatching } from './vector';
|
||||
import { createEditorState } from '../test/utils.test';
|
||||
import { createEditorState } from '../test/utils-test';
|
||||
import { walkThrough } from './path-finder';
|
||||
import { BinaryExpr, Expr } from '../grammar/parser.terms';
|
||||
import chai from 'chai';
|
||||
import { BinaryExpr, Expr } from 'lezer-promql';
|
||||
import { syntaxTree } from '@codemirror/language';
|
||||
import { VectorMatchCardinality } from '../types';
|
||||
|
||||
|
@ -203,10 +202,9 @@ describe('buildVectorMatching test', () => {
|
|||
it(value.binaryExpr, () => {
|
||||
const state = createEditorState(value.binaryExpr);
|
||||
const node = walkThrough(syntaxTree(state).topNode, Expr, BinaryExpr);
|
||||
chai.expect(node).to.not.null;
|
||||
chai.expect(node).to.not.undefined;
|
||||
expect(node).toBeTruthy();
|
||||
if (node) {
|
||||
chai.expect(value.expectedVectorMatching).to.deep.equal(buildVectorMatching(state, node));
|
||||
expect(value.expectedVectorMatching).toEqual(buildVectorMatching(state, node));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
OnOrIgnoring,
|
||||
Or,
|
||||
Unless,
|
||||
} from '../grammar/parser.terms';
|
||||
} from 'lezer-promql';
|
||||
import { VectorMatchCardinality, VectorMatching } from '../types';
|
||||
import { containsAtLeastOneChild, retrieveAllRecursiveNodes } from './path-finder';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { parser } from './grammar/parser';
|
||||
import { parser } from 'lezer-promql';
|
||||
import { styleTags, tags } from '@codemirror/highlight';
|
||||
import { Extension } from '@codemirror/state';
|
||||
import { CompleteConfiguration, CompleteStrategy, newCompleteStrategy } from './complete';
|
||||
|
|
|
@ -11,16 +11,17 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { parser } from '../grammar/parser';
|
||||
import { parser } from 'lezer-promql';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { LRLanguage } from '@codemirror/language';
|
||||
import nock from 'nock';
|
||||
|
||||
// used to inject an implementation of fetch in NodeJS
|
||||
require('isomorphic-fetch');
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const lightPromQLSyntax = LRLanguage.define({ parser: parser });
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export function createEditorState(expr: string): EditorState {
|
||||
return EditorState.create({
|
||||
doc: expr,
|
|
@ -78,7 +78,7 @@ import {
|
|||
Timestamp,
|
||||
Vector,
|
||||
Year,
|
||||
} from '../grammar/parser.terms';
|
||||
} from 'lezer-promql';
|
||||
|
||||
export enum ValueType {
|
||||
none = 'none',
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { EqlSingle, Neq } from '../grammar/parser.terms';
|
||||
import { EqlSingle, Neq } from 'lezer-promql';
|
||||
|
||||
export class Matcher {
|
||||
type: number;
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"target": "ES2015",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"target": "es2018",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
|
@ -21,6 +18,7 @@
|
|||
"src/"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/*.test.ts"
|
||||
"src/**/*.test.ts",
|
||||
"src/test/**"
|
||||
]
|
||||
}
|
||||
|
|
5
web/ui/module/lezer-promql/.gitignore
vendored
Normal file
5
web/ui/module/lezer-promql/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
node_modules/
|
||||
dist/
|
||||
lib/
|
||||
src/parser.js
|
||||
src/parser.terms.js
|
25
web/ui/module/lezer-promql/build.sh
Normal file
25
web/ui/module/lezer-promql/build.sh
Normal file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
set -ex
|
||||
|
||||
npx lezer-generator src/promql.grammar -o src/parser
|
||||
|
||||
cat src/parser.terms.js >> src/parser.js
|
||||
|
||||
bash ./generate-types.sh
|
||||
|
||||
rollup -c
|
45
web/ui/module/lezer-promql/generate-types.sh
Normal file
45
web/ui/module/lezer-promql/generate-types.sh
Normal file
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
set -ex
|
||||
|
||||
mkdir -p ./dist
|
||||
indexFile='./dist/index.d.ts'
|
||||
if [[ -f ${indexFile} ]]; then
|
||||
rm ${indexFile}
|
||||
fi
|
||||
|
||||
cat <<EOF >> ${indexFile}
|
||||
// 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.
|
||||
|
||||
// This file was generated by lezer-promql. You probably should not edit it.
|
||||
import { LRParser } from '@lezer/lr'
|
||||
|
||||
export const parser: LRParser
|
||||
$(sed -E 's/ = [0-9]+/: number/' src/parser.terms.js)
|
||||
EOF
|
11
web/ui/module/lezer-promql/jest.config.cjs
Normal file
11
web/ui/module/lezer-promql/jest.config.cjs
Normal file
|
@ -0,0 +1,11 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
extensionsToTreatAsEsm: ['.ts'],
|
||||
testEnvironment: 'node',
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
useESM: true,
|
||||
},
|
||||
},
|
||||
};
|
39
web/ui/module/lezer-promql/package.json
Normal file
39
web/ui/module/lezer-promql/package.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"name": "lezer-promql",
|
||||
"version": "0.23.0",
|
||||
"description": "lezer-based PromQL grammar",
|
||||
"main": "index.cjs",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"import": "./dist/index.es.js",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"module": "dist/index.es.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"author": "Prometheus Authors <prometheus-developers@googlegroups.com>",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/prometheus/prometheus.git"
|
||||
},
|
||||
"keywords": [
|
||||
"lezer",
|
||||
"promql"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/prometheus/prometheus/issues"
|
||||
},
|
||||
"homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/lezer-promql/README.md",
|
||||
"scripts": {
|
||||
"build": "bash ./build.sh",
|
||||
"lint": "echo 'nothing to do'",
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^0.15.4",
|
||||
"@lezer/lr": "^0.15.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lezer/lr": "^0.15.8"
|
||||
}
|
||||
}
|
16
web/ui/module/lezer-promql/rollup.config.js
Normal file
16
web/ui/module/lezer-promql/rollup.config.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { nodeResolve } from "@rollup/plugin-node-resolve"
|
||||
|
||||
export default {
|
||||
input: "./src/parser.js",
|
||||
output: [{
|
||||
format: "cjs",
|
||||
file: "./dist/index.cjs"
|
||||
}, {
|
||||
format: "es",
|
||||
file: "./dist/index.es.js"
|
||||
}],
|
||||
external(id) { return !/^[.\/]/.test(id) },
|
||||
plugins: [
|
||||
nodeResolve()
|
||||
]
|
||||
}
|
85
web/ui/module/lezer-promql/src/tokens.js
Normal file
85
web/ui/module/lezer-promql/src/tokens.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
// 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,
|
||||
Atan2,
|
||||
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,
|
||||
atan2: Atan2,
|
||||
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;
|
||||
};
|
16
web/ui/module/lezer-promql/test/promql.test.js
Normal file
16
web/ui/module/lezer-promql/test/promql.test.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { parser } from '../dist/index.es.js';
|
||||
import { fileTests } from '@lezer/generator/dist/test';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
let caseDir = path.dirname(fileURLToPath(import.meta.url))
|
||||
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));
|
||||
});
|
||||
}
|
13300
web/ui/package-lock.json
generated
13300
web/ui/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,6 @@
|
|||
"build:module": "bash build_ui.sh --build-module",
|
||||
"start": "npm run start -w react-app",
|
||||
"test": "npm run test --workspaces",
|
||||
"test:coverage": "npm run test:coverage --workspaces",
|
||||
"lint": "npm run lint --workspaces"
|
||||
},
|
||||
"workspaces": [
|
||||
|
@ -15,5 +14,18 @@
|
|||
],
|
||||
"engines": {
|
||||
"npm": ">=7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/node": "^16.11.26",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-react-app": "^7.0.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest-canvas-mock": "^2.3.1",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"react-scripts": "^5.0.0",
|
||||
"prettier": "^2.6.1",
|
||||
"ts-jest": "^27.1.4",
|
||||
"typescript": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,9 +69,7 @@
|
|||
"@testing-library/react-hooks": "^7.0.1",
|
||||
"@types/enzyme": "^3.10.10",
|
||||
"@types/flot": "0.0.32",
|
||||
"@types/jest": "^27.0.3",
|
||||
"@types/jquery": "^3.5.9",
|
||||
"@types/node": "^16.11.12",
|
||||
"@types/react": "^17.0.39",
|
||||
"@types/react-copy-to-clipboard": "^5.0.2",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
|
@ -82,16 +80,8 @@
|
|||
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.6",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-to-json": "^3.6.2",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-react-app": "^7.0.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest-canvas-mock": "^2.3.1",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"mutationobserver-shim": "^0.3.7",
|
||||
"prettier": "^2.5.1",
|
||||
"react-scripts": "5.0.0",
|
||||
"sinon": "^12.0.1",
|
||||
"typescript": "^4.6.2"
|
||||
"sinon": "^12.0.1"
|
||||
},
|
||||
"proxy": "http://localhost:9090",
|
||||
"jest": {
|
||||
|
@ -99,8 +89,12 @@
|
|||
"enzyme-to-json/serializer"
|
||||
],
|
||||
"transformIgnorePatterns": [
|
||||
"/node_modules/(?!codemirror-promql).+(js|jsx)$"
|
||||
]
|
||||
"<rootDir>/../node_modules/(?!codemirror-promql)/",
|
||||
"<rootDir>/../node_modules/(?!lezer-promql)/"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"lezer-promql": "<rootDir>/../node_modules/lezer-promql/dist/index.cjs"
|
||||
}
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "^2.3.2"
|
||||
|
|
Loading…
Reference in a new issue