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:
Augustin Husson 2022-04-05 11:49:22 +02:00 committed by GitHub
parent 063319087c
commit 043a2954f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 4971 additions and 8908 deletions

View file

@ -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:

View file

@ -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
View 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

View file

@ -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

View file

@ -4,8 +4,4 @@ node_modules/
dist/
lib/
src/grammar/**.ts
src/grammar/parser.js
src/grammar/parser.terms.js
/.nyc_output

View file

@ -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

View 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)/"]
};

View file

@ -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,

View file

@ -0,0 +1 @@
global.fetch = require('isomorphic-fetch')

View file

@ -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);
});
});
});

View file

@ -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';

View file

@ -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));
});
}

View file

@ -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;
};

View file

@ -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);
});
});
});

View file

@ -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';

View file

@ -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);
});
});
});

View file

@ -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';

View file

@ -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);
});
});
});

View file

@ -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';

View file

@ -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));
}
});
});

View file

@ -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';

View file

@ -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';

View file

@ -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,

View file

@ -78,7 +78,7 @@ import {
Timestamp,
Vector,
Year,
} from '../grammar/parser.terms';
} from 'lezer-promql';
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 '../grammar/parser.terms';
import { EqlSingle, Neq } from 'lezer-promql';
export class Matcher {
type: number;

View file

@ -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
View file

@ -0,0 +1,5 @@
node_modules/
dist/
lib/
src/parser.js
src/parser.terms.js

View 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

View 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

View 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,
},
},
};

View 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"
}
}

View 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()
]
}

View 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;
};

View 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));
});
}

13268
web/ui/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -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"
}
}

View file

@ -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"