Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Step 1][ESQL] Syntax part #146379

Merged
merged 30 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b2edc68
[ES_QL] Initial commit. Add antlr syntax
alexwizp Nov 28, 2022
14ca2be
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 28, 2022
eb2addc
add ESQLLineTokens token provider
alexwizp Nov 28, 2022
1e9fa94
export ESQLLang lang
alexwizp Nov 28, 2022
1a2f39c
rename esql -> sql
alexwizp Nov 29, 2022
b5a1af1
add antlr_facade.ts
alexwizp Nov 29, 2022
6dd093c
rename theme
alexwizp Nov 29, 2022
08034cb
fix JEST
alexwizp Nov 29, 2022
cfb221e
made some code from painless folder reusable
alexwizp Nov 29, 2022
ce54747
fix broken CI
alexwizp Nov 29, 2022
707ff00
fix typo
alexwizp Nov 30, 2022
16b7dee
add base syntax highligting
alexwizp Nov 30, 2022
9a4a91c
fix for dark-mode
alexwizp Nov 30, 2022
4ee51c3
rename getRuleGroup -> buildRuleGroup
alexwizp Nov 30, 2022
0b605ad
some cleanup
alexwizp Nov 30, 2022
5dc8e81
add kbn-ui-theme into BUILD.bazel
alexwizp Nov 30, 2022
8cdb08b
add syntax validating highligting
alexwizp Dec 1, 2022
09ca272
push some cleanup
alexwizp Dec 1, 2022
0962590
some cleanup
alexwizp Dec 1, 2022
0fc80da
cleanup
alexwizp Dec 1, 2022
a37ef16
move Workers out of main chunk
alexwizp Dec 2, 2022
57408f3
small renaming
alexwizp Dec 2, 2022
8905e13
Merge branch 'main' into es_ql_syntax
kibanamachine Dec 5, 2022
f2de10d
Update packages/kbn-monaco/src/esql/lib/monaco/esql_tokens_provider.ts
alexwizp Dec 5, 2022
9f125e7
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Dec 5, 2022
0a7a3e9
add license
alexwizp Dec 5, 2022
bce38ac
fix typo
alexwizp Dec 5, 2022
680067b
Update esql_tokens_provider.ts
alexwizp Dec 5, 2022
dd36c3b
update syntax to cover math functions
alexwizp Dec 5, 2022
a53069a
Merge remote-tracking branch 'upstream/main' into es_ql_syntax
alexwizp Dec 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ snapshots.js
/packages/kbn-test/src/functional_test_runner/lib/config/__tests__/fixtures/
/packages/kbn-ui-framework/dist
/packages/kbn-flot-charts/lib
/packages/kbn-monaco/src/painless/antlr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be the source of the 2MB drop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/packages/kbn-monaco/src/**/antlr

# Bazel
/bazel-*
2 changes: 2 additions & 0 deletions packages/kbn-monaco/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ NPM_MODULE_EXTRA_FILES = [
RUNTIME_DEPS = [
"//packages/kbn-babel-preset",
"//packages/kbn-i18n",
"//packages/kbn-ui-theme",
"@npm//@babel/runtime",
"@npm//antlr4ts",
"@npm//babel-loader",
Expand All @@ -52,6 +53,7 @@ RUNTIME_DEPS = [

TYPES_DEPS = [
"//packages/kbn-i18n:npm_module_types",
"//packages/kbn-ui-theme:npm_module_types",
"@npm//antlr4ts",
"@npm//monaco-editor",
"@npm//rxjs",
Expand Down
4 changes: 3 additions & 1 deletion packages/kbn-monaco/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import './src/register_globals';

export { monaco } from './src/monaco_imports';
export { XJsonLang } from './src/xjson';
export { EsqlLang } from './src/esql';
export { SQLLang } from './src/sql';
export { ESQL_LANG_ID, ESQL_THEME_ID } from './src/esql';

export * from './src/painless';
/* eslint-disable-next-line @kbn/eslint/module_migration */
import * as BarePluginApi from 'monaco-editor/esm/vs/editor/editor.api';
Expand Down
5 changes: 4 additions & 1 deletion packages/kbn-monaco/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"main": "target_node/index.js",
"license": "SSPL-1.0 OR Elastic License 2.0",
"scripts": {
"build:antlr4ts": "../../node_modules/antlr4ts-cli/antlr4ts ./src/painless/antlr/painless_lexer.g4 ./src/painless/antlr/painless_parser.g4 && node ./scripts/fix_generated_antlr.js"
"build:antlr4ts:painless": "../../node_modules/antlr4ts-cli/antlr4ts ./src/painless/antlr/painless_lexer.g4 ./src/painless/antlr/painless_parser.g4 && node ./scripts/fix_generated_antlr.js painless",
"build:antlr4ts:esql": "../../node_modules/antlr4ts-cli/antlr4ts src/esql/antlr/esql_lexer.g4 src/esql/antlr/esql_parser.g4 && node ./scripts/fix_generated_antlr.js esql",
"build:antlr4ts": "npm run build:antlr4ts:painless && npm run build:antlr4ts:esql"

},
"types": "./target_types/index.d.ts"
}
89 changes: 51 additions & 38 deletions packages/kbn-monaco/scripts/fix_generated_antlr.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,60 @@
const { join } = require('path');
const { readdirSync, readFileSync, writeFileSync, renameSync } = require('fs');
const ora = require('ora');
const log = ora('Updating generated antlr grammar').start();

const generatedAntlrFolder = join(__dirname, '..', 'src', 'painless', 'antlr');
const SUPPORTED_FOLDERS = ['painless', 'esql'];

const generatedAntlrFolderContents = readdirSync(generatedAntlrFolder);
function execute(folder) {
const generatedAntlrFolder = join(__dirname, '..', 'src', folder, 'antlr');

const log = ora('Updating generated antlr grammar').start();
const generatedAntlrFolderContents = readdirSync(generatedAntlrFolder);

// The generated TS produces some TS linting errors
// This script adds a //@ts-nocheck comment at the top of each generated file
// so that the errors can be ignored for now
generatedAntlrFolderContents
.filter((file) => {
const fileExtension = file.split('.')[1];
return fileExtension.includes('ts');
})
.forEach((file) => {
try {
const fileContentRows = readFileSync(join(generatedAntlrFolder, file), 'utf8')
.toString()
.split('\n');

fileContentRows.unshift('// @ts-nocheck');

const filePath = join(generatedAntlrFolder, file);
const fileContent = fileContentRows.join('\n');

writeFileSync(filePath, fileContent, { encoding: 'utf8' });
} catch (err) {
return log.fail(err.message);
}
});

// Rename generated parserListener file to snakecase to satisfy file casing check
// There doesn't appear to be a way to fix this OOTB with antlr4ts-cli
try {
renameSync(
join(generatedAntlrFolder, 'painless_parserListener.ts'),
join(generatedAntlrFolder, 'painless_parser_listener.ts')
);
} catch (err) {
log.warn(`Unable to rename parserListener file to snakecase: ${err.message}`);
// The generated TS produces some TS linting errors
// This script adds a //@ts-nocheck comment at the top of each generated file
// so that the errors can be ignored for now
generatedAntlrFolderContents
.filter((file) => {
const fileExtension = file.split('.')[1];
return fileExtension.includes('ts');
})
.forEach((file) => {
try {
const fileContentRows = readFileSync(join(generatedAntlrFolder, file), 'utf8')
.toString()
.split('\n');

fileContentRows.unshift('// @ts-nocheck');

const filePath = join(generatedAntlrFolder, file);
const fileContent = fileContentRows.join('\n');

writeFileSync(filePath, fileContent, { encoding: 'utf8' });
} catch (err) {
return log.fail(err.message);
}
});

// Rename generated parserListener file to snakecase to satisfy file casing check
// There doesn't appear to be a way to fix this OOTB with antlr4ts-cli
try {
renameSync(
join(generatedAntlrFolder, `${folder}_parserListener.ts`),
join(generatedAntlrFolder, `${folder}_parser_listener.ts`)
);
} catch (err) {
log.warn(`Unable to rename parserListener file to snake-case: ${err.message}`);
}

log.succeed('Updated generated antlr grammar successfully');
}

log.succeed('Updated generated antlr grammar successfully');
const [folder] = process.argv.slice(2);

if (!SUPPORTED_FOLDERS.includes(folder)) {
log.warn(
`Target folder should be one of: ${SUPPORTED_FOLDERS.join(' ')}. Got: ${folder ?? '(empty)'}`
);
} else {
execute(folder);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { Subscription } from 'rxjs';
import { MockIModel } from '../__jest__/types';
import { LangValidation } from '../types';
import { monaco } from '../monaco_imports';
import { ID } from './constants';

import { DiagnosticsAdapter } from './diagnostics_adapter';

Expand All @@ -24,10 +23,12 @@ const getMockWorker = async () => {
} as any;
};

const ID = 'painless';

const flushPromises = () =>
new Promise((resolve) => jest.requireActual('timers').setImmediate(resolve));

describe('Painless DiagnosticAdapter', () => {
describe('DiagnosticAdapter', () => {
let diagnosticAdapter: DiagnosticsAdapter;
let subscription: Subscription;
let model: MockIModel;
Expand All @@ -43,7 +44,7 @@ describe('Painless DiagnosticAdapter', () => {

beforeEach(async () => {
model = monaco.editor.createModel(ID) as unknown as MockIModel;
diagnosticAdapter = new DiagnosticsAdapter(getMockWorker);
diagnosticAdapter = new DiagnosticsAdapter(ID, getMockWorker);

// validate() has a promise we need to wait for
// --> await worker.getSyntaxErrors()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@
import { BehaviorSubject } from 'rxjs';

import { monaco } from '../monaco_imports';
import { SyntaxErrors, LangValidation } from '../types';
import { ID } from './constants';
import { WorkerAccessor } from './language';
import { PainlessError } from './worker';
import type { SyntaxErrors, LangValidation, EditorError, BaseWorkerDefinition } from '../types';

const toDiagnostics = (error: PainlessError): monaco.editor.IMarkerData => {
const toDiagnostics = (error: EditorError): monaco.editor.IMarkerData => {
return {
...error,
severity: monaco.MarkerSeverity.Error,
};
};

export type WorkerAccessor = (...uris: monaco.Uri[]) => Promise<BaseWorkerDefinition>;

export class DiagnosticsAdapter {
private errors: SyntaxErrors = {};
private validation = new BehaviorSubject<LangValidation>({
Expand All @@ -33,14 +32,14 @@ export class DiagnosticsAdapter {

public validation$ = this.validation.asObservable();

constructor(private worker: WorkerAccessor) {
constructor(private langId: string, private worker: WorkerAccessor) {
const onModelAdd = (model: monaco.editor.IModel): void => {
let handle: any;

if (model.getModeId() === ID) {
if (model.getModeId() === this.langId) {
model.onDidChangeContent(() => {
// Do not validate if the language ID has changed
if (model.getModeId() !== ID) {
if (model.getModeId() !== this.langId) {
return;
}

Expand All @@ -54,7 +53,7 @@ export class DiagnosticsAdapter {
isValidating: false,
errors: [],
});
return monaco.editor.setModelMarkers(model, ID, []);
return monaco.editor.setModelMarkers(model, this.langId, []);
}

this.validation.next({
Expand All @@ -70,8 +69,8 @@ export class DiagnosticsAdapter {
model.onDidChangeLanguage(({ newLanguage }) => {
// Reset the model markers if the language ID has changed and is no longer "painless"
// Otherwise, re-validate
if (newLanguage !== ID) {
return monaco.editor.setModelMarkers(model, ID, []);
if (newLanguage !== this.langId) {
return monaco.editor.setModelMarkers(model, this.langId, []);
} else {
this.validate(model.uri, ++this.validateIdx);
}
Expand Down Expand Up @@ -107,7 +106,7 @@ export class DiagnosticsAdapter {
[model!.id]: errorMarkers,
};
// Set the error markers and underline them with "Error" severity
monaco.editor.setModelMarkers(model!, ID, errorMarkers.map(toDiagnostics));
monaco.editor.setModelMarkers(model!, this.langId, errorMarkers.map(toDiagnostics));
}

const isValid = errorMarkers === undefined || errorMarkers.length === 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,10 @@
*/

import { ANTLRErrorListener, RecognitionException, Recognizer } from 'antlr4ts';
import type { EditorError } from '../types';

export interface PainlessError {
startLineNumber: number;
startColumn: number;
endLineNumber: number;
endColumn: number;
message: string;
}

export class PainlessErrorListener implements ANTLRErrorListener<any> {
private errors: PainlessError[] = [];
export class ANTLREErrorListener implements ANTLRErrorListener<any> {
private errors: EditorError[] = [];

syntaxError(
recognizer: Recognizer<any, any>,
Expand All @@ -42,7 +35,7 @@ export class PainlessErrorListener implements ANTLRErrorListener<any> {
});
}

getErrors(): PainlessError[] {
getErrors(): EditorError[] {
return this.errors;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,23 @@
* Side Public License, v 1.
*/

import { monaco } from '../../monaco_imports';
import { PainlessWorker } from '../worker';
import { ID } from '../constants';
import { monaco } from '../monaco_imports';
import type { BaseWorkerDefinition } from '../types';

export class WorkerProxyService {
private worker: monaco.editor.MonacoWebWorker<PainlessWorker> | undefined;
export class WorkerProxyService<IWorker extends BaseWorkerDefinition> {
private worker: monaco.editor.MonacoWebWorker<IWorker> | undefined;

public async getWorker(resources: monaco.Uri[]) {
if (!this.worker) {
throw new Error('Worker Proxy Service has not been setup!');
}

await this.worker.withSyncedResources(resources);
const proxy = await this.worker.getProxy();
return proxy;
return await this.worker.getProxy();
}

public setup() {
this.worker = monaco.editor.createWebWorker({ label: ID, moduleId: '' });
public setup(langId: string) {
this.worker = monaco.editor.createWebWorker({ label: langId, moduleId: '' });
}

public stop() {
Expand Down
Loading