From 1cd6cccc9102ee17998b0541e1b1fe1032591990 Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Thu, 23 Nov 2023 14:47:41 +0100 Subject: [PATCH 1/2] Upgrade to Langium 2.1.3 Langium > 2.0.0 only supports ESM so we refactor the extension to ESM Setup Changes - Set type to 'module' in package.json and update configs accordingly - Use esbuild to develop in ESM but compile to CJS for VSX Code Changes - Adapt all relative imports to use '.js' extension (even for '.ts') - Remove now obsolete adaptations of workspace manager Test Changes - Provide custom Jest configuration for ES modules - Use 'jest.useFakeTimers()' as specified in Jest documentation for ESM - Add '--experimental-vm-modules' Node flag to ESM test executions - Add 'NODE_NO_WARNINGS' environment variable to ignore ESM warning - Use unique report file names as we need to run twice (CJS, ESM) - Add display name to all test configs for nicer output - Adapt launch configs to properly debug single test or all tests --- .eslintrc.js | 12 +- .github/workflows/build-and-test.yml | 10 +- .vscode/launch.json | 65 ++- applications/browser-app/jest.config.js | 4 +- applications/electron-app/jest.config.js | 4 +- configs/base.esm.jest.config.js | 20 + configs/base.jest.config.js | 16 +- configs/esm.jest.config.js | 5 + configs/jest.config.js | 4 +- e2e-tests/package.json | 3 +- extensions/crossmodel-lang/.eslintrc.cjs | 9 + extensions/crossmodel-lang/esbuild.mjs | 56 +++ extensions/crossmodel-lang/jest.config.cjs | 7 + extensions/crossmodel-lang/jest.config.js | 5 - extensions/crossmodel-lang/package.json | 37 +- .../crossmodel-lang/src/cli/generator.ts | 4 +- extensions/crossmodel-lang/src/cli/index.ts | 10 +- extensions/crossmodel-lang/src/extension.ts | 5 +- .../add-entity-action-provider.ts | 8 +- .../glsp-server/diagram/cross-model-module.ts | 22 +- .../handler/add-entity-operation-handler.ts | 12 +- .../change-bounds-operation-handler.ts | 6 +- .../handler/create-edge-operation-handler.ts | 10 +- .../handler/cross-model-command.ts | 2 +- .../handler/delete-operation-handler.ts | 8 +- .../handler/drop-entity-operation-handler.ts | 10 +- .../crossmodel-lang/src/glsp-server/launch.ts | 16 +- .../model/builders/node-builder.ts | 2 +- .../model/cross-model-gmodel-factory.ts | 8 +- .../glsp-server/model/cross-model-index.ts | 6 +- .../glsp-server/model/cross-model-state.ts | 22 +- .../glsp-server/model/cross-model-storage.ts | 14 +- extensions/crossmodel-lang/src/integration.ts | 2 +- .../cross-model-client-logger.ts | 2 +- .../cross-model-completion-provider.ts | 21 +- .../cross-model-document-builder.ts | 4 +- .../cross-model-langium-documents.ts | 4 +- .../src/language-server/cross-model-module.ts | 46 +- .../src/language-server/cross-model-naming.ts | 4 +- .../cross-model-package-manager.ts | 4 +- .../cross-model-scope-provider.ts | 4 +- .../src/language-server/cross-model-scope.ts | 8 +- .../language-server/cross-model-serializer.ts | 6 +- .../language-server/cross-model-validator.ts | 4 +- .../cross-model-workspace-manager.ts | 47 +- .../src/language-server/generated/ast.ts | 2 +- .../src/language-server/generated/grammar.ts | 2 +- .../src/language-server/generated/module.ts | 6 +- .../lexer/cross-model-indent-stack.ts | 2 +- .../lexer/cross-model-indentation-tokens.ts | 4 +- .../lexer/cross-model-lexer.ts | 6 +- .../lexer/cross-model-token-generator.ts | 8 +- .../src/language-server/util/ast-util.ts | 2 +- .../src/language-server/util/name-util.ts | 2 +- extensions/crossmodel-lang/src/main.ts | 8 +- .../src/model-server/model-module.ts | 6 +- .../src/model-server/model-server.ts | 4 +- .../src/model-server/model-service.ts | 14 +- .../open-text-document-manager.ts | 6 +- .../model-server/openable-text-documents.ts | 4 +- .../cross-model-lang-diagram.test.ts | 12 +- .../cross-model-lang-entity.test.ts | 12 +- .../cross-model-lang-relationship.test.ts | 12 +- .../lexer/cross-model-indent-stack.test.ts | 6 +- .../cross-model-indentation-tokens.test.ts | 8 +- .../lexer/cross-model-lexer.test.ts | 4 +- .../lexer/cross-model-token-generator.test.ts | 4 +- .../serializer/cross-model-serializer.test.ts | 10 +- .../test-documents/diagram/index.ts | 12 +- .../test-utils/test-documents/entity/index.ts | 8 +- .../test-documents/relationship/index.ts | 4 +- .../language-server/util/name-util.test.ts | 12 +- .../test/model-server/model-server.test.ts | 8 +- extensions/crossmodel-lang/tsconfig.json | 19 +- package.json | 4 +- packages/core/jest.config.js | 4 +- packages/form-client/jest.config.js | 4 +- packages/glsp-client/jest.config.js | 4 +- packages/model-service/jest.config.js | 4 +- packages/product/jest.config.js | 4 +- packages/property-view/jest.config.js | 4 +- packages/protocol/jest.config.js | 4 +- packages/protocol/package.json | 2 +- packages/react-model-ui/jest.config.js | 4 +- yarn.lock | 463 +++++++++++++----- 85 files changed, 858 insertions(+), 428 deletions(-) create mode 100644 configs/base.esm.jest.config.js create mode 100644 configs/esm.jest.config.js create mode 100644 extensions/crossmodel-lang/.eslintrc.cjs create mode 100644 extensions/crossmodel-lang/esbuild.mjs create mode 100644 extensions/crossmodel-lang/jest.config.cjs delete mode 100644 extensions/crossmodel-lang/jest.config.js diff --git a/.eslintrc.js b/.eslintrc.js index d487cab0..85cd684e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,11 +2,21 @@ module.exports = { root: true, extends: ['./configs/base.eslintrc.js', './configs/warnings.eslintrc.js', './configs/errors.eslintrc.js'], - ignorePatterns: ['**/{node_modules,lib}', '**/.eslintrc.js', 'extensions/**/generated'], + ignorePatterns: [ + '**/{node_modules,lib}', + '**/.eslintrc.js', + 'extensions/**/generated', + '**/*jest.config.js', + '**/*.eslintrc.js', + '**/*.eslintrc.cjs', + '**/language-server/generated/**' + ], parserOptions: { tsconfigRootDir: __dirname, project: 'tsconfig.eslint.json' }, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], settings: { react: { version: 'detect' diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7d3f3127..3c79464d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -50,14 +50,14 @@ jobs: run: yarn test env: # The test result file name can be controlled using the following environment variable. - JEST_JUNIT_OUTPUT_NAME: unit-test-results-${{ runner.os }}.xml + JEST_JUNIT_OUTPUT_NAME: ${{ runner.os }}-unit-test-results # Upload Unit Test Results (The different files for the OSes will end up in the same artifact). - name: Upload Unit Test Results if: always() uses: actions/upload-artifact@v3 with: - name: unit-test-tesults + name: unit-test-results # Include the unit-test-results folders (which is in the root of the workspace). path: unit-test-results retention-days: 30 @@ -95,12 +95,12 @@ jobs: - name: Download Unit Test Results uses: actions/download-artifact@v3 with: - name: unit-test-tesults - path: unit-test-tesults + name: unit-test-results + path: unit-test-results # Publish Test Results - name: Publish Unit Test Results uses: EnricoMi/publish-unit-test-result-action@v2 with: check_name: Unit Test Results files: | - unit-test-tesults/**/*.xml + unit-test-results/**/*.xml diff --git a/.vscode/launch.json b/.vscode/launch.json index 3dd9dc02..3b9f1719 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -40,6 +40,7 @@ "${workspaceFolder}/applications/electron-app/src-gen/backend/server.js", "${workspaceFolder}/applications/electron-app/src-gen/backend/main.js", "${workspaceFolder}/extensions/*/out/**/*.js", + "${workspaceFolder}/extensions/*/out/**/*.cjs", "${workspaceFolder}/packages/*/lib/**/*.js", "${workspaceFolder}/node_modules/langium/lib/**/*.js", "${workspaceFolder}/node_modules/@eclipse-glsp/*/lib/**/*.js" @@ -79,6 +80,7 @@ "${workspaceFolder}/applications/electron-app/src-gen/backend/server.js", "${workspaceFolder}/applications/electron-app/src-gen/backend/main.js", "${workspaceFolder}/extensions/*/out/**/*.js", + "${workspaceFolder}/extensions/*/out/**/*.cjs", "${workspaceFolder}/packages/*/lib/**/*.js", "${workspaceFolder}/node_modules/langium/lib/**/*.js", "${workspaceFolder}/node_modules/@eclipse-glsp/*/lib/**/*.js" @@ -116,18 +118,75 @@ ] }, { - "name": "Debug Jest Tests", + "name": "Debug All CJS Jest Tests", "type": "node", "request": "launch", "runtimeArgs": [ "--inspect-brk", "${workspaceRoot}/node_modules/jest/bin/jest.js", "--runInBand", - "--config=${workspaceRoot}/config/jest.config.js", - "--testPathPattern={extensions|packages}/*/test/**/*.test.ts" + "--config=${workspaceRoot}/configs/jest.config.js" ], "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" + }, + { + "name": "Debug All ESM Jest Tests", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--experimental-vm-modules", + "--inspect-brk", + "${workspaceRoot}/node_modules/jest/bin/jest.js", + "--runInBand", + "--config=${workspaceRoot}/configs/esm.jest.config.js" + ], + "env": { + "NODE_NO_WARNINGS": "1" + }, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Debug Open CJS Jest Test", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/node_modules/jest/bin/jest.js", + "--runInBand", + "--config=${workspaceRoot}/configs/jest.config.js", + "${file}" + ], + "env": { + "NODE_NO_WARNINGS": "1" + }, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Debug Open ESM Jest Test", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--experimental-vm-modules", + "--inspect-brk", + "${workspaceRoot}/node_modules/jest/bin/jest.js", + "--runInBand", + "--config=${workspaceRoot}/configs/esm.jest.config.js", + "${file}" + ], + "env": { + "NODE_NO_WARNINGS": "1" + }, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + } + ], + "compounds": [ + { + "name": "Debug All Jest Tests", + "configurations": ["Debug All CJS Jest Tests", "Debug All ESM Jest Tests"] } ] } diff --git a/applications/browser-app/jest.config.js b/applications/browser-app/jest.config.js index 0349530b..fe12009d 100644 --- a/applications/browser-app/jest.config.js +++ b/applications/browser-app/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Browser App' }; diff --git a/applications/electron-app/jest.config.js b/applications/electron-app/jest.config.js index 0349530b..847e161f 100644 --- a/applications/electron-app/jest.config.js +++ b/applications/electron-app/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Electron App' }; diff --git a/configs/base.esm.jest.config.js b/configs/base.esm.jest.config.js new file mode 100644 index 00000000..0c175bad --- /dev/null +++ b/configs/base.esm.jest.config.js @@ -0,0 +1,20 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +const baseConfig = require('./base.jest.config'); + +module.exports = { + ...baseConfig, + extensionsToTreatAsEsm: ['.ts', '.tsx'], + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1' + }, + transform: { + // '^.+\\.[tj]sx?$' to process js/ts with `ts-jest` + // '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest` + '^.+\\.tsx?$': [ + 'ts-jest', + { + useESM: true + } + ] + } +}; diff --git a/configs/base.jest.config.js b/configs/base.jest.config.js index 0d5e0c7f..8c8bf509 100644 --- a/configs/base.jest.config.js +++ b/configs/base.jest.config.js @@ -1,6 +1,20 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ +const path = require('path'); + module.exports = { preset: 'ts-jest', testEnvironment: 'node', - testPathIgnorePatterns: ['./node_modules/'] + testPathIgnorePatterns: ['./node_modules/'], + reporters: [ + [ + 'jest-junit', + { + outputDirectory: path.join(__dirname, '..', 'unit-test-results'), + outputName: 'jest-report', + uniqueOutputName: 'true' + } + ], + ['github-actions', { silent: false }], + 'summary' + ] }; diff --git a/configs/esm.jest.config.js b/configs/esm.jest.config.js new file mode 100644 index 00000000..c008e34b --- /dev/null +++ b/configs/esm.jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + rootDir: '../', + projects: ['/extensions/*'] +}; diff --git a/configs/jest.config.js b/configs/jest.config.js index 7d5a1ae2..dc7624b7 100644 --- a/configs/jest.config.js +++ b/configs/jest.config.js @@ -1,5 +1,5 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { rootDir: '../', - projects: ['/applications/*', '/extensions/*', '/packages/*'], - reporters: ['default', ['jest-junit', { outputDirectory: 'unit-test-results', outputName: 'jest-report.xml' }]] + projects: ['/applications/*', '/packages/*'] }; diff --git a/e2e-tests/package.json b/e2e-tests/package.json index 006504f0..3a3d7542 100644 --- a/e2e-tests/package.json +++ b/e2e-tests/package.json @@ -13,7 +13,8 @@ "lint": "eslint -c ../.eslintrc.js --ext .ts ./src", "playwright:install": "yarn playwright install --with-deps", "prepare": "yarn clean && yarn build && yarn lint", - "test": "yarn playwright test" + "test": "", + "ui-test": "yarn playwright test" }, "dependencies": { "@playwright/test": "^1.37.1", diff --git a/extensions/crossmodel-lang/.eslintrc.cjs b/extensions/crossmodel-lang/.eslintrc.cjs new file mode 100644 index 00000000..18f2a1b8 --- /dev/null +++ b/extensions/crossmodel-lang/.eslintrc.cjs @@ -0,0 +1,9 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: ['../../.eslintrc.js'], + ignorePatterns: ['language-server/generated/**', 'jest.config.cjs', 'jest.setup.js'], + rules: { + // turn import issues off as eslint cannot handle ES modules + 'import/no-unresolved': 'off' + } +}; diff --git a/extensions/crossmodel-lang/esbuild.mjs b/extensions/crossmodel-lang/esbuild.mjs new file mode 100644 index 00000000..462bbff2 --- /dev/null +++ b/extensions/crossmodel-lang/esbuild.mjs @@ -0,0 +1,56 @@ +//@ts-check +import * as esbuild from 'esbuild'; + +const watch = process.argv.includes('--watch'); +const minify = process.argv.includes('--minify'); + +const success = watch ? 'Watch build succeeded' : 'Build succeeded'; + +function getTime() { + const date = new Date(); + return `[${`${padZeroes(date.getHours())}:${padZeroes(date.getMinutes())}:${padZeroes(date.getSeconds())}`}] `; +} + +function padZeroes(i) { + return i.toString().padStart(2, '0'); +} + +const plugins = [ + { + name: 'watch-plugin', + setup(build) { + build.onEnd(result => { + if (result.errors.length === 0) { + console.log(getTime() + success); + } + }); + } + } +]; + +const ctx = await esbuild.context({ + // Entry points for the vscode extension and the language server + entryPoints: ['src/extension.ts', 'src/main.ts'], + outdir: 'out', + bundle: true, + target: 'ES2017', + // VSCode's extension host is still using cjs, so we need to transform the code + format: 'cjs', + // To prevent confusing node, we explicitly use the `.cjs` extension + outExtension: { + '.js': '.cjs' + }, + loader: { '.ts': 'ts' }, + external: ['vscode'], + platform: 'node', + sourcemap: !minify, + minify, + plugins +}); + +if (watch) { + await ctx.watch(); +} else { + await ctx.rebuild(); + ctx.dispose(); +} diff --git a/extensions/crossmodel-lang/jest.config.cjs b/extensions/crossmodel-lang/jest.config.cjs new file mode 100644 index 00000000..6483f5eb --- /dev/null +++ b/extensions/crossmodel-lang/jest.config.cjs @@ -0,0 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +const baseConfig = require('../../configs/base.esm.jest.config'); + +module.exports = { + ...baseConfig, + displayName: 'Extension' +}; diff --git a/extensions/crossmodel-lang/jest.config.js b/extensions/crossmodel-lang/jest.config.js deleted file mode 100644 index 0349530b..00000000 --- a/extensions/crossmodel-lang/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -const baseConfig = require('../../configs/base.jest.config'); - -module.exports = { - ...baseConfig -}; diff --git a/extensions/crossmodel-lang/package.json b/extensions/crossmodel-lang/package.json index 8a47fa88..8186d088 100644 --- a/extensions/crossmodel-lang/package.json +++ b/extensions/crossmodel-lang/package.json @@ -17,7 +17,8 @@ "name": "CrossBreeze", "email": "devops@crossbreeze.nl" }, - "main": "./out/extension.js", + "type": "module", + "main": "./out/extension.cjs", "bin": { "cross-model-cli": "./bin/cli" }, @@ -27,13 +28,14 @@ "src" ], "scripts": { - "build": "yarn langium:generate && yarn build:webpack", + "build": "yarn langium:generate && yarn build:esbuild", + "build:esbuild": "node esbuild.mjs", "build:tsc": "tsc -b tsconfig.json", "build:webpack": "webpack --mode development", "clean": "rimraf out && rimraf tsconfig.tsbuildinfo", "langium:generate": "langium generate", "langium:watch": "langium generate --watch", - "lint": "eslint src --ext ts", + "lint": "eslint -c ./.eslintrc.cjs --ext .ts,.tsx ./src", "package": "rimraf out && yarn package:webpack && yarn package:vsix", "package:vsix": "vsce package --yarn --allow-star-activation", "package:webpack": "webpack --mode production --devtool hidden-source-map", @@ -41,9 +43,10 @@ "symlink": "yarn symlink:browser && yarn symlink:electron", "symlink:browser": "symlink-dir . ../../applications/browser-app/plugins/crossmodel-lang", "symlink:electron": "symlink-dir . ../../applications/electron-app/plugins/crossmodel-lang", - "test": "jest --passWithNoTests", + "test": "cross-env NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest --passWithNoTests", "vscode:prepublish": "yarn lint", "watch": "yarn watch:webpack", + "watch:esbuild": "node esbuild.mjs --watch", "watch:tsc": "tsc -b tsconfig.json --watch", "watch:webpack": "webpack --mode development --watch" }, @@ -94,27 +97,29 @@ "@eclipse-glsp/layout-elk": "2.0.0", "@eclipse-glsp/server": "2.0.0", "chalk": "~4.1.2", - "chevrotain": "~10.4.2", + "chevrotain": "~11.0.3", "commander": "~10.0.0", - "langium": "~1.3.0", + "langium": "~2.1.3", "type-fest": "^3.6.1", - "vscode-languageclient": "8.0.2", - "vscode-languageserver": "8.0.2", - "vscode-languageserver-protocol": "^3.17.3", - "vscode-languageserver-textdocument": "^1.0.8", + "vscode-languageclient": "9.0.1", + "vscode-languageserver": "9.0.1", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.2" }, "devDependencies": { "@types/jest": "^29.5.6", - "@types/node": "^14.17.3", - "@types/vscode": "^1.56.0", - "@typescript-eslint/eslint-plugin": "^5.28.0", - "@typescript-eslint/parser": "^5.28.0", + "@types/node": "~16.18.41", + "@types/vscode": "~1.67.0", + "@typescript-eslint/eslint-plugin": "~6.4.1", + "@typescript-eslint/parser": "~6.4.1", "@vscode/vsce": "^2.17.0", + "cross-env": "~7.0.3", + "esbuild": "~0.19.7", "eslint": "^8.17.0", - "langium-cli": "~1.3.0", + "langium-cli": "~2.1.0", "ts-loader": "^9.4.2", - "typescript": "^4.9.4" + "typescript": "~5.3.2" }, "engines": { "vscode": "^1.56.0" diff --git a/extensions/crossmodel-lang/src/cli/generator.ts b/extensions/crossmodel-lang/src/cli/generator.ts index 3aab662c..15a32555 100644 --- a/extensions/crossmodel-lang/src/cli/generator.ts +++ b/extensions/crossmodel-lang/src/cli/generator.ts @@ -4,8 +4,8 @@ import fs from 'fs'; import { CompositeGeneratorNode, NL, toString } from 'langium'; import path from 'path'; -import { CrossModelRoot } from '../language-server/generated/ast'; -import { extractDestinationAndName } from './cli-util'; +import { CrossModelRoot } from '../language-server/generated/ast.js'; +import { extractDestinationAndName } from './cli-util.js'; export function generateJavaScript(root: CrossModelRoot, filePath: string, destination: string | undefined): string { const data = extractDestinationAndName(filePath, destination); diff --git a/extensions/crossmodel-lang/src/cli/index.ts b/extensions/crossmodel-lang/src/cli/index.ts index ddd0030f..08a72145 100644 --- a/extensions/crossmodel-lang/src/cli/index.ts +++ b/extensions/crossmodel-lang/src/cli/index.ts @@ -4,11 +4,11 @@ import chalk from 'chalk'; import { Command } from 'commander'; import { NodeFileSystem } from 'langium/node'; -import { createCrossModelServices } from '../language-server/cross-model-module'; -import { CrossModelRoot } from '../language-server/generated/ast'; -import { CrossModelLanguageMetaData } from '../language-server/generated/module'; -import { extractAstNode } from './cli-util'; -import { generateJavaScript } from './generator'; +import { createCrossModelServices } from '../language-server/cross-model-module.js'; +import { CrossModelRoot } from '../language-server/generated/ast.js'; +import { CrossModelLanguageMetaData } from '../language-server/generated/module.js'; +import { extractAstNode } from './cli-util.js'; +import { generateJavaScript } from './generator.js'; export const generateAction = async (fileName: string, opts: GenerateOptions): Promise => { const services = createCrossModelServices(NodeFileSystem).CrossModel; diff --git a/extensions/crossmodel-lang/src/extension.ts b/extensions/crossmodel-lang/src/extension.ts index f215299a..1de3c2b2 100644 --- a/extensions/crossmodel-lang/src/extension.ts +++ b/extensions/crossmodel-lang/src/extension.ts @@ -2,9 +2,8 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import * as path from 'path'; -// eslint-disable-next-line import/no-unresolved import * as vscode from 'vscode'; -import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node'; +import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node.js'; let client: LanguageClient | undefined; @@ -35,7 +34,7 @@ function launchLanguageClient(context: vscode.ExtensionContext): LanguageClient function createServerOptions(context: vscode.ExtensionContext): ServerOptions { // needs to match the configuration in tsconfig.json and webpack.config.js - const serverModule = context.asAbsolutePath(path.join('out', 'server-main')); + const serverModule = context.asAbsolutePath(path.join('out', 'main.cjs')); // The debug options for the server // --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging. // By setting `process.env.DEBUG_BREAK` to a truthy value, the language server will wait until a debugger is attached. diff --git a/extensions/crossmodel-lang/src/glsp-server/command-palette/add-entity-action-provider.ts b/extensions/crossmodel-lang/src/glsp-server/command-palette/add-entity-action-provider.ts index 418d91d9..1a204a96 100644 --- a/extensions/crossmodel-lang/src/glsp-server/command-palette/add-entity-action-provider.ts +++ b/extensions/crossmodel-lang/src/glsp-server/command-palette/add-entity-action-provider.ts @@ -6,9 +6,9 @@ import { EditorContext, LabeledAction } from '@eclipse-glsp/protocol'; import { ContextActionsProvider, Point } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; import { codiconCSSString } from 'sprotty'; -import { isExternalDescriptionForLocalPackage } from '../../language-server/cross-model-scope'; -import { createNodeToEntityReference } from '../../language-server/util/ast-util'; -import { CrossModelState } from '../model/cross-model-state'; +import { isExternalDescriptionForLocalPackage } from '../../language-server/cross-model-scope.js'; +import { createNodeToEntityReference } from '../../language-server/util/ast-util.js'; +import { CrossModelState } from '../model/cross-model-state.js'; /** * An action provider for the command palette (Ctrl+Space) to allow adding entities to an existing diagram. @@ -18,7 +18,7 @@ import { CrossModelState } from '../model/cross-model-state'; export class CrossModelAddEntityActionProvider implements ContextActionsProvider { contextId = 'command-palette'; - @inject(CrossModelState) protected state: CrossModelState; + @inject(CrossModelState) protected state!: CrossModelState; async getActions(editorContext: EditorContext): Promise { const scopeProvider = this.state.services.language.references.ScopeProvider; diff --git a/extensions/crossmodel-lang/src/glsp-server/diagram/cross-model-module.ts b/extensions/crossmodel-lang/src/glsp-server/diagram/cross-model-module.ts index 5884229f..0b51741e 100644 --- a/extensions/crossmodel-lang/src/glsp-server/diagram/cross-model-module.ts +++ b/extensions/crossmodel-lang/src/glsp-server/diagram/cross-model-module.ts @@ -15,17 +15,17 @@ import { SourceModelStorage } from '@eclipse-glsp/server'; import { injectable } from 'inversify'; -import { CrossModelAddEntityActionProvider } from '../command-palette/add-entity-action-provider'; -import { CrossModelAddEntityOperationHandler } from '../handler/add-entity-operation-handler'; -import { CrossModelChangeBoundsOperationHandler } from '../handler/change-bounds-operation-handler'; -import { CrossModelCreateEdgeOperationHandler } from '../handler/create-edge-operation-handler'; -import { CrossModelDeleteOperationHandler } from '../handler/delete-operation-handler'; -import { CrossModelDropEntityOperationHandler } from '../handler/drop-entity-operation-handler'; -import { CrossModelGModelFactory } from '../model/cross-model-gmodel-factory'; -import { CrossModelIndex } from '../model/cross-model-index'; -import { CrossModelState } from '../model/cross-model-state'; -import { CrossModelStorage } from '../model/cross-model-storage'; -import { CrossModelDiagramConfiguration } from './cross-model-diagram-configuration'; +import { CrossModelAddEntityActionProvider } from '../command-palette/add-entity-action-provider.js'; +import { CrossModelAddEntityOperationHandler } from '../handler/add-entity-operation-handler.js'; +import { CrossModelChangeBoundsOperationHandler } from '../handler/change-bounds-operation-handler.js'; +import { CrossModelCreateEdgeOperationHandler } from '../handler/create-edge-operation-handler.js'; +import { CrossModelDeleteOperationHandler } from '../handler/delete-operation-handler.js'; +import { CrossModelDropEntityOperationHandler } from '../handler/drop-entity-operation-handler.js'; +import { CrossModelGModelFactory } from '../model/cross-model-gmodel-factory.js'; +import { CrossModelIndex } from '../model/cross-model-index.js'; +import { CrossModelState } from '../model/cross-model-state.js'; +import { CrossModelStorage } from '../model/cross-model-storage.js'; +import { CrossModelDiagramConfiguration } from './cross-model-diagram-configuration.js'; /** * Provides configuration about our crossmodel diagrams. diff --git a/extensions/crossmodel-lang/src/glsp-server/handler/add-entity-operation-handler.ts b/extensions/crossmodel-lang/src/glsp-server/handler/add-entity-operation-handler.ts index c32376b7..564225f5 100644 --- a/extensions/crossmodel-lang/src/glsp-server/handler/add-entity-operation-handler.ts +++ b/extensions/crossmodel-lang/src/glsp-server/handler/add-entity-operation-handler.ts @@ -5,11 +5,11 @@ import { AddEntityOperation } from '@crossbreeze/protocol'; import { Command, JsonOperationHandler, ModelState } from '@eclipse-glsp/server'; import { injectable, inject } from 'inversify'; -import { DiagramNode, Entity } from '../../language-server/generated/ast'; -import { createNodeToEntityReference } from '../../language-server/util/ast-util'; -import { findAvailableNodeName } from '../../language-server/util/name-util'; -import { CrossModelState } from '../model/cross-model-state'; -import { CrossModelCommand } from './cross-model-command'; +import { DiagramNode, Entity } from '../../language-server/generated/ast.js'; +import { createNodeToEntityReference } from '../../language-server/util/ast-util.js'; +import { findAvailableNodeName } from '../../language-server/util/name-util.js'; +import { CrossModelState } from '../model/cross-model-state.js'; +import { CrossModelCommand } from './cross-model-command.js'; /** * An operation handler for the 'AddEntityOperation' that resolves the referenced entity by name and places it in a new node on the diagram. @@ -17,7 +17,7 @@ import { CrossModelCommand } from './cross-model-command'; @injectable() export class CrossModelAddEntityOperationHandler extends JsonOperationHandler { override operationType = AddEntityOperation.KIND; - @inject(ModelState) protected override modelState: CrossModelState; + @inject(ModelState) protected override modelState!: CrossModelState; createCommand(operation: AddEntityOperation): Command { return new CrossModelCommand(this.modelState, () => this.createEntityNode(operation)); diff --git a/extensions/crossmodel-lang/src/glsp-server/handler/change-bounds-operation-handler.ts b/extensions/crossmodel-lang/src/glsp-server/handler/change-bounds-operation-handler.ts index 70add70c..0ba7af34 100644 --- a/extensions/crossmodel-lang/src/glsp-server/handler/change-bounds-operation-handler.ts +++ b/extensions/crossmodel-lang/src/glsp-server/handler/change-bounds-operation-handler.ts @@ -3,13 +3,13 @@ ********************************************************************************/ import { ChangeBoundsOperation, Command, JsonOperationHandler, ModelState } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; -import { CrossModelState } from '../model/cross-model-state'; -import { CrossModelCommand } from './cross-model-command'; +import { CrossModelState } from '../model/cross-model-state.js'; +import { CrossModelCommand } from './cross-model-command.js'; @injectable() export class CrossModelChangeBoundsOperationHandler extends JsonOperationHandler { operationType = ChangeBoundsOperation.KIND; - @inject(ModelState) protected override modelState: CrossModelState; + @inject(ModelState) protected override modelState!: CrossModelState; createCommand(operation: ChangeBoundsOperation): Command { return new CrossModelCommand(this.modelState, () => this.changeBounds(operation)); diff --git a/extensions/crossmodel-lang/src/glsp-server/handler/create-edge-operation-handler.ts b/extensions/crossmodel-lang/src/glsp-server/handler/create-edge-operation-handler.ts index 8d9f2afa..c21b5926 100644 --- a/extensions/crossmodel-lang/src/glsp-server/handler/create-edge-operation-handler.ts +++ b/extensions/crossmodel-lang/src/glsp-server/handler/create-edge-operation-handler.ts @@ -5,17 +5,17 @@ import { Command, CreateEdgeOperation, DefaultTypes, JsonCreateEdgeOperationHandler, ModelState } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; import { URI, Utils as UriUtils } from 'vscode-uri'; -import { CrossModelRoot, DiagramEdge, DiagramNode, Relationship, isCrossModelRoot } from '../../language-server/generated/ast'; -import { Utils } from '../../language-server/util/uri-util'; -import { CrossModelState } from '../model/cross-model-state'; -import { CrossModelCommand } from './cross-model-command'; +import { CrossModelRoot, DiagramEdge, DiagramNode, Relationship, isCrossModelRoot } from '../../language-server/generated/ast.js'; +import { Utils } from '../../language-server/util/uri-util.js'; +import { CrossModelState } from '../model/cross-model-state.js'; +import { CrossModelCommand } from './cross-model-command.js'; @injectable() export class CrossModelCreateEdgeOperationHandler extends JsonCreateEdgeOperationHandler { override label = '1:1 Relationship'; elementTypeIds = [DefaultTypes.EDGE]; - @inject(ModelState) protected override modelState: CrossModelState; + @inject(ModelState) protected override modelState!: CrossModelState; createCommand(operation: CreateEdgeOperation): Command { return new CrossModelCommand(this.modelState, () => this.createEdge(operation)); diff --git a/extensions/crossmodel-lang/src/glsp-server/handler/cross-model-command.ts b/extensions/crossmodel-lang/src/glsp-server/handler/cross-model-command.ts index 495a8d8d..6045bbb5 100644 --- a/extensions/crossmodel-lang/src/glsp-server/handler/cross-model-command.ts +++ b/extensions/crossmodel-lang/src/glsp-server/handler/cross-model-command.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import { JsonRecordingCommand, MaybePromise } from '@eclipse-glsp/server'; -import { CrossModelSourceModel, CrossModelState } from '../model/cross-model-state'; +import { CrossModelSourceModel, CrossModelState } from '../model/cross-model-state.js'; import * as jsonPatch from 'fast-json-patch'; /** diff --git a/extensions/crossmodel-lang/src/glsp-server/handler/delete-operation-handler.ts b/extensions/crossmodel-lang/src/glsp-server/handler/delete-operation-handler.ts index fec689c0..832955ea 100644 --- a/extensions/crossmodel-lang/src/glsp-server/handler/delete-operation-handler.ts +++ b/extensions/crossmodel-lang/src/glsp-server/handler/delete-operation-handler.ts @@ -3,15 +3,15 @@ ********************************************************************************/ import { Command, DeleteElementOperation, JsonOperationHandler } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; -import { DiagramEdge, DiagramNode, isDiagramEdge, isDiagramNode } from '../../language-server/generated/ast'; -import { CrossModelState } from '../model/cross-model-state'; -import { CrossModelCommand } from './cross-model-command'; +import { DiagramEdge, DiagramNode, isDiagramEdge, isDiagramNode } from '../../language-server/generated/ast.js'; +import { CrossModelState } from '../model/cross-model-state.js'; +import { CrossModelCommand } from './cross-model-command.js'; @injectable() export class CrossModelDeleteOperationHandler extends JsonOperationHandler { operationType = DeleteElementOperation.KIND; - @inject(CrossModelState) protected override modelState: CrossModelState; + @inject(CrossModelState) protected override modelState!: CrossModelState; createCommand(operation: DeleteElementOperation): Command | undefined { if (!operation.elementIds || operation.elementIds.length === 0) { diff --git a/extensions/crossmodel-lang/src/glsp-server/handler/drop-entity-operation-handler.ts b/extensions/crossmodel-lang/src/glsp-server/handler/drop-entity-operation-handler.ts index 8820c22e..fabc483d 100644 --- a/extensions/crossmodel-lang/src/glsp-server/handler/drop-entity-operation-handler.ts +++ b/extensions/crossmodel-lang/src/glsp-server/handler/drop-entity-operation-handler.ts @@ -6,10 +6,10 @@ import { DropEntityOperation } from '@crossbreeze/protocol'; import { Command, JsonOperationHandler } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; import { URI } from 'vscode-uri'; -import { CrossModelRoot, DiagramNode, isCrossModelRoot } from '../../language-server/generated/ast'; -import { findAvailableNodeName } from '../../language-server/util/name-util'; -import { CrossModelState } from '../model/cross-model-state'; -import { CrossModelCommand } from './cross-model-command'; +import { CrossModelRoot, DiagramNode, isCrossModelRoot } from '../../language-server/generated/ast.js'; +import { findAvailableNodeName } from '../../language-server/util/name-util.js'; +import { CrossModelState } from '../model/cross-model-state.js'; +import { CrossModelCommand } from './cross-model-command.js'; /** * An operation handler for the 'DropEntityOperation' that finds an entity for each of the given file URIs and @@ -20,7 +20,7 @@ import { CrossModelCommand } from './cross-model-command'; export class CrossModelDropEntityOperationHandler extends JsonOperationHandler { override operationType = DropEntityOperation.KIND; - @inject(CrossModelState) protected override modelState: CrossModelState; + @inject(CrossModelState) protected override modelState!: CrossModelState; createCommand(operation: DropEntityOperation): Command { return new CrossModelCommand(this.modelState, () => this.createEntityNode(operation)); diff --git a/extensions/crossmodel-lang/src/glsp-server/launch.ts b/extensions/crossmodel-lang/src/glsp-server/launch.ts index 03143f0d..077539af 100644 --- a/extensions/crossmodel-lang/src/glsp-server/launch.ts +++ b/extensions/crossmodel-lang/src/glsp-server/launch.ts @@ -1,22 +1,24 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -/* eslint-disable import/no-duplicates */ import { GLSP_PORT_FILE } from '@crossbreeze/protocol'; import { configureELKLayoutModule } from '@eclipse-glsp/layout-elk'; -import { LogLevel, LoggerFactory, MaybePromise, ServerModule } from '@eclipse-glsp/server'; import { + LogLevel, + LoggerFactory, + MaybePromise, + ServerModule, SocketLaunchOptions, SocketServerLauncher, createAppModule, defaultSocketLaunchOptions -} from '@eclipse-glsp/server/lib/node/index'; +} from '@eclipse-glsp/server/node.js'; import { Container, ContainerModule } from 'inversify'; import { URI } from 'vscode-uri'; -import { CrossModelLSPServices, writePortFileToWorkspace } from '../integration'; -import { CrossModelServices, CrossModelSharedServices } from '../language-server/cross-model-module'; -import { CrossModelDiagramModule } from './diagram/cross-model-module'; -import { CrossModelLayoutConfigurator } from './layout/cross-model-layout-configurator'; +import { CrossModelLSPServices, writePortFileToWorkspace } from '../integration.js'; +import { CrossModelServices, CrossModelSharedServices } from '../language-server/cross-model-module.js'; +import { CrossModelDiagramModule } from './diagram/cross-model-module.js'; +import { CrossModelLayoutConfigurator } from './layout/cross-model-layout-configurator.js'; /** * Launches a GLSP server with access to the given language services on the default port. diff --git a/extensions/crossmodel-lang/src/glsp-server/model/builders/node-builder.ts b/extensions/crossmodel-lang/src/glsp-server/model/builders/node-builder.ts index c6b7d957..248f8b9f 100644 --- a/extensions/crossmodel-lang/src/glsp-server/model/builders/node-builder.ts +++ b/extensions/crossmodel-lang/src/glsp-server/model/builders/node-builder.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import { ArgsUtil, GCompartment, GLabel, GNode, GNodeBuilder } from '@eclipse-glsp/server'; -import { DiagramNode } from '../../../language-server/generated/ast'; +import { DiagramNode } from '../../../language-server/generated/ast.js'; export class GEntityNode extends GNode { override type = 'node:entity'; diff --git a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-gmodel-factory.ts b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-gmodel-factory.ts index 490a32ca..65f9b4ce 100644 --- a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-gmodel-factory.ts +++ b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-gmodel-factory.ts @@ -3,9 +3,9 @@ ********************************************************************************/ import { GEdge, GGraph, GModelFactory, GNode } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; -import { DiagramEdge, DiagramNode } from '../../language-server/generated/ast'; -import { GEntityNode } from './builders/node-builder'; -import { CrossModelState } from './cross-model-state'; +import { DiagramEdge, DiagramNode } from '../../language-server/generated/ast.js'; +import { GEntityNode } from './builders/node-builder.js'; +import { CrossModelState } from './cross-model-state.js'; /** * Custom factory that translates the semantic diagram root from Langium to a GLSP graph. @@ -14,7 +14,7 @@ import { CrossModelState } from './cross-model-state'; */ @injectable() export class CrossModelGModelFactory implements GModelFactory { - @inject(CrossModelState) protected readonly modelState: CrossModelState; + @inject(CrossModelState) protected readonly modelState!: CrossModelState; createModel(): void { const newRoot = this.createGraph(); diff --git a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-index.ts b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-index.ts index 721e9bca..183d84b1 100644 --- a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-index.ts +++ b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-index.ts @@ -4,7 +4,7 @@ import { GModelIndex } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; import { AstNode, streamAst } from 'langium'; -import { CrossModelLSPServices } from '../../integration'; +import { CrossModelLSPServices } from '../../integration.js'; import { CrossModelRoot, DiagramEdge, @@ -15,14 +15,14 @@ import { isDiagramNode, isEntity, isRelationship -} from '../../language-server/generated/ast'; +} from '../../language-server/generated/ast.js'; /** * Custom model index that not only indexes the GModel elements but also the semantic elements (AstNodes) they represent. */ @injectable() export class CrossModelIndex extends GModelIndex { - @inject(CrossModelLSPServices) services: CrossModelLSPServices; + @inject(CrossModelLSPServices) services!: CrossModelLSPServices; protected idToSemanticNode = new Map(); diff --git a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-state.ts b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-state.ts index ab811f54..77474b29 100644 --- a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-state.ts +++ b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-state.ts @@ -4,12 +4,12 @@ import { DefaultModelState, JsonModelState, ModelState, hasFunctionProp } from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; import { URI } from 'vscode-uri'; -import { CrossModelLSPServices } from '../../integration'; -import { QualifiedNameProvider } from '../../language-server/cross-model-naming'; -import { CrossModelRoot, SystemDiagram } from '../../language-server/generated/ast'; -import { ModelService } from '../../model-server/model-service'; -import { Serializer } from '../../model-server/serializer'; -import { CrossModelIndex } from './cross-model-index'; +import { CrossModelLSPServices } from '../../integration.js'; +import { QualifiedNameProvider } from '../../language-server/cross-model-naming.js'; +import { CrossModelRoot, SystemDiagram } from '../../language-server/generated/ast.js'; +import { ModelService } from '../../model-server/model-service.js'; +import { Serializer } from '../../model-server/serializer.js'; +import { CrossModelIndex } from './cross-model-index.js'; export interface CrossModelSourceModel { text: string; @@ -21,12 +21,12 @@ export interface CrossModelSourceModel { */ @injectable() export class CrossModelState extends DefaultModelState implements JsonModelState { - @inject(CrossModelIndex) override readonly index: CrossModelIndex; - @inject(CrossModelLSPServices) readonly services: CrossModelLSPServices; + @inject(CrossModelIndex) override readonly index!: CrossModelIndex; + @inject(CrossModelLSPServices) readonly services!: CrossModelLSPServices; - protected _semanticUri: string; - protected _semanticRoot: CrossModelRoot; - protected _packageId: string; + protected _semanticUri!: string; + protected _semanticRoot!: CrossModelRoot; + protected _packageId!: string; setSemanticRoot(uri: string, semanticRoot: CrossModelRoot): void { this._semanticUri = uri; diff --git a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-storage.ts b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-storage.ts index 631b66e4..09663ad4 100644 --- a/extensions/crossmodel-lang/src/glsp-server/model/cross-model-storage.ts +++ b/extensions/crossmodel-lang/src/glsp-server/model/cross-model-storage.ts @@ -21,8 +21,8 @@ import { import { inject, injectable, postConstruct } from 'inversify'; import { findRootNode, streamReferences } from 'langium'; import { URI } from 'vscode-uri'; -import { CrossModelRoot, isCrossModelRoot } from '../../language-server/generated/ast'; -import { CrossModelState } from './cross-model-state'; +import { CrossModelRoot, isCrossModelRoot } from '../../language-server/generated/ast.js'; +import { CrossModelState } from './cross-model-state.js'; /** * Model storage implementation that loads the model through the ModelService extension in our language services. @@ -31,11 +31,11 @@ import { CrossModelState } from './cross-model-state'; */ @injectable() export class CrossModelStorage implements SourceModelStorage, ClientSessionListener { - @inject(Logger) protected logger: Logger; - @inject(CrossModelState) protected state: CrossModelState; - @inject(ClientSessionManager) protected sessionManager: ClientSessionManager; - @inject(ModelSubmissionHandler) protected submissionHandler: ModelSubmissionHandler; - @inject(ActionDispatcher) protected actionDispatcher: ActionDispatcher; + @inject(Logger) protected logger!: Logger; + @inject(CrossModelState) protected state!: CrossModelState; + @inject(ClientSessionManager) protected sessionManager!: ClientSessionManager; + @inject(ModelSubmissionHandler) protected submissionHandler!: ModelSubmissionHandler; + @inject(ActionDispatcher) protected actionDispatcher!: ActionDispatcher; protected toDispose = new DisposableCollection(); diff --git a/extensions/crossmodel-lang/src/integration.ts b/extensions/crossmodel-lang/src/integration.ts index a20fe82c..f4267221 100644 --- a/extensions/crossmodel-lang/src/integration.ts +++ b/extensions/crossmodel-lang/src/integration.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import { AddressInfo } from 'net'; import { join } from 'path'; import { URI } from 'vscode-uri'; -import { CrossModelServices, CrossModelSharedServices } from './language-server/cross-model-module'; +import { CrossModelServices, CrossModelSharedServices } from './language-server/cross-model-module.js'; /** * Language services required in GLSP. diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-client-logger.ts b/extensions/crossmodel-lang/src/language-server/cross-model-client-logger.ts index 0c16d36f..3bb22015 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-client-logger.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-client-logger.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { CrossModelSharedServices } from './cross-model-module'; +import { CrossModelSharedServices } from './cross-model-module.js'; /** * Centralized logger. diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-completion-provider.ts b/extensions/crossmodel-lang/src/language-server/cross-model-completion-provider.ts index 00526f3b..a1f8d656 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-completion-provider.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-completion-provider.ts @@ -1,10 +1,17 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { AstNodeDescription, CompletionAcceptor, CompletionContext, DefaultCompletionProvider, MaybePromise, NextFeature } from 'langium'; -import { CrossReference } from 'langium/lib/grammar/generated/ast'; -import { CrossModelServices } from './cross-model-module'; -import { isExternalDescriptionForLocalPackage } from './cross-model-scope'; +import { + AstNodeDescription, + CompletionAcceptor, + CompletionContext, + DefaultCompletionProvider, + GrammarAST, + MaybePromise, + NextFeature +} from 'langium'; +import { CrossModelServices } from './cross-model-module.js'; +import { isExternalDescriptionForLocalPackage } from './cross-model-scope.js'; /** * Custom completion provider that only shows the short options to the user if a longer, fully-qualified version is also available. @@ -18,7 +25,7 @@ export class CrossModelCompletionProvider extends DefaultCompletionProvider { protected override completionForCrossReference( context: CompletionContext, - crossRef: NextFeature, + crossRef: NextFeature, acceptor: CompletionAcceptor ): MaybePromise { this.packageId = this.packageManager.getPackageIdByDocument(context.document); @@ -29,9 +36,9 @@ export class CrossModelCompletionProvider extends DefaultCompletionProvider { } } - protected override filterCrossReference(description: AstNodeDescription): boolean { + protected override filterCrossReference(context: CompletionContext, description: AstNodeDescription): boolean { // we want to keep fully qualified names in the scope so we can do proper linking // but want to hide it from the user for local options, i.e., if we are in the same project we can skip the project name - return !isExternalDescriptionForLocalPackage(description, this.packageId) && super.filterCrossReference(description); + return !isExternalDescriptionForLocalPackage(description, this.packageId) && super.filterCrossReference(context, description); } } diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-document-builder.ts b/extensions/crossmodel-lang/src/language-server/cross-model-document-builder.ts index 4d317c53..d271d08f 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-document-builder.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-document-builder.ts @@ -4,8 +4,8 @@ import { DefaultDocumentBuilder, LangiumSharedServices } from 'langium'; import { CancellationToken } from 'vscode-languageclient'; import { URI, Utils as UriUtils } from 'vscode-uri'; -import { isPackageUri } from './cross-model-package-manager'; -import { Utils } from './util/uri-util'; +import { isPackageUri } from './cross-model-package-manager.js'; +import { Utils } from './util/uri-util.js'; /** * A document builder that can also handle directories by flattening out directories to an array of file URIs. diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-langium-documents.ts b/extensions/crossmodel-lang/src/language-server/cross-model-langium-documents.ts index 77141ea5..708b5b90 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-langium-documents.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-langium-documents.ts @@ -3,8 +3,8 @@ ********************************************************************************/ import { DefaultLangiumDocuments } from 'langium'; import { URI } from 'vscode-uri'; -import { isPackageUri } from './cross-model-package-manager'; -import { Utils } from './util/uri-util'; +import { isPackageUri } from './cross-model-package-manager.js'; +import { Utils } from './util/uri-util.js'; export class CrossModelLangiumDocuments extends DefaultLangiumDocuments { override getOrCreateDocument(uri: URI): any { diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-module.ts b/extensions/crossmodel-lang/src/language-server/cross-model-module.ts index 593c4283..29a51828 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-module.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-module.ts @@ -18,27 +18,27 @@ import { } from 'langium'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI } from 'vscode-uri'; -import { AddedSharedModelServices } from '../model-server/model-module'; -import { ModelService } from '../model-server/model-service'; -import { OpenTextDocumentManager } from '../model-server/open-text-document-manager'; -import { OpenableTextDocuments } from '../model-server/openable-text-documents'; -import { Serializer } from '../model-server/serializer'; -import { ClientLogger } from './cross-model-client-logger'; -import { CrossModelCompletionProvider } from './cross-model-completion-provider'; -import { CrossModelDocumentBuilder } from './cross-model-document-builder'; -import { CrossModelModelFormatter } from './cross-model-formatter'; -import { CrossModelLangiumDocuments } from './cross-model-langium-documents'; -import { CrossModelLanguageServer } from './cross-model-language-server'; -import { QualifiedNameProvider } from './cross-model-naming'; -import { CrossModelPackageManager } from './cross-model-package-manager'; -import { CrossModelScopeComputation } from './cross-model-scope'; -import { CrossModelScopeProvider } from './cross-model-scope-provider'; -import { CrossModelSerializer } from './cross-model-serializer'; -import { CrossModelValidator, registerValidationChecks } from './cross-model-validator'; -import { CrossModelWorkspaceManager } from './cross-model-workspace-manager'; -import { CrossModelGeneratedModule, CrossModelGeneratedSharedModule } from './generated/module'; -import { CrossModelLexer } from './lexer/cross-model-lexer'; -import { CrossModelTokenBuilder } from './lexer/cross-model-token-generator'; +import { AddedSharedModelServices } from '../model-server/model-module.js'; +import { ModelService } from '../model-server/model-service.js'; +import { OpenTextDocumentManager } from '../model-server/open-text-document-manager.js'; +import { OpenableTextDocuments } from '../model-server/openable-text-documents.js'; +import { Serializer } from '../model-server/serializer.js'; +import { ClientLogger } from './cross-model-client-logger.js'; +import { CrossModelCompletionProvider } from './cross-model-completion-provider.js'; +import { CrossModelDocumentBuilder } from './cross-model-document-builder.js'; +import { CrossModelModelFormatter } from './cross-model-formatter.js'; +import { CrossModelLangiumDocuments } from './cross-model-langium-documents.js'; +import { CrossModelLanguageServer } from './cross-model-language-server.js'; +import { QualifiedNameProvider } from './cross-model-naming.js'; +import { CrossModelPackageManager } from './cross-model-package-manager.js'; +import { CrossModelScopeComputation } from './cross-model-scope.js'; +import { CrossModelScopeProvider } from './cross-model-scope-provider.js'; +import { CrossModelSerializer } from './cross-model-serializer.js'; +import { CrossModelValidator, registerValidationChecks } from './cross-model-validator.js'; +import { CrossModelWorkspaceManager } from './cross-model-workspace-manager.js'; +import { CrossModelGeneratedModule, CrossModelGeneratedSharedModule } from './generated/module.js'; +import { CrossModelLexer } from './lexer/cross-model-lexer.js'; +import { CrossModelTokenBuilder } from './lexer/cross-model-token-generator.js'; /*************************** * Shared Module @@ -50,7 +50,7 @@ export interface ExtendedLangiumServices extends LangiumServices { }; } -export class ExtendedServiceRegistry extends DefaultServiceRegistry { +export class DefaultExtendedServiceRegistry extends DefaultServiceRegistry { override register(language: ExtendedLangiumServices): void { super.register(language); } @@ -90,7 +90,7 @@ export const CrossModelSharedModule: Module< CrossModelSharedServices, PartialLangiumSharedServices & CrossModelAddedSharedServices & AddedSharedModelServices > = { - ServiceRegistry: () => new ExtendedServiceRegistry(), + ServiceRegistry: () => new DefaultExtendedServiceRegistry(), workspace: { WorkspaceManager: services => new CrossModelWorkspaceManager(services), PackageManager: services => new CrossModelPackageManager(services), diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-naming.ts b/extensions/crossmodel-lang/src/language-server/cross-model-naming.ts index 6f1968d4..dfcc8044 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-naming.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-naming.ts @@ -3,8 +3,8 @@ ********************************************************************************/ import { AstNode, CstNode, findNodeForProperty, getDocument, isNamed, NameProvider } from 'langium'; -import { CrossModelServices } from './cross-model-module'; -import { UNKNOWN_PROJECT_REFERENCE } from './cross-model-package-manager'; +import { CrossModelServices } from './cross-model-module.js'; +import { UNKNOWN_PROJECT_REFERENCE } from './cross-model-package-manager.js'; /** * A name provider that returns the fully qualified name of a node by default but also exposes methods to get other names: diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-package-manager.ts b/extensions/crossmodel-lang/src/language-server/cross-model-package-manager.ts index e68eef8e..a0e16bdd 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-package-manager.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-package-manager.ts @@ -7,8 +7,8 @@ import { DocumentState, LangiumDocument, MultiMap } from 'langium'; import { PackageJson } from 'type-fest'; import { CancellationToken, WorkspaceFolder } from 'vscode-languageserver'; import { URI, Utils as UriUtils } from 'vscode-uri'; -import { CrossModelSharedServices } from './cross-model-module'; -import { Utils } from './util/uri-util'; +import { CrossModelSharedServices } from './cross-model-module.js'; +import { Utils } from './util/uri-util.js'; /** Constant for representing an unknown project ID. */ export const UNKNOWN_PROJECT_ID = 'unknown'; diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-scope-provider.ts b/extensions/crossmodel-lang/src/language-server/cross-model-scope-provider.ts index 85fa5894..0844ce54 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-scope-provider.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-scope-provider.ts @@ -2,8 +2,8 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import { AstNodeDescription, DefaultScopeProvider, getDocument, ReferenceInfo, Scope, StreamScope } from 'langium'; -import { CrossModelServices } from './cross-model-module'; -import { PackageAstNodeDescription, PackageExternalAstNodeDescription } from './cross-model-scope'; +import { CrossModelServices } from './cross-model-module.js'; +import { PackageAstNodeDescription, PackageExternalAstNodeDescription } from './cross-model-scope.js'; /** * A custom scope provider that considers the dependencies between packages to indicate which elements form the global scope diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-scope.ts b/extensions/crossmodel-lang/src/language-server/cross-model-scope.ts index ad39de06..a083be89 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-scope.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-scope.ts @@ -4,10 +4,10 @@ import { AstNode, AstNodeDescription, DefaultScopeComputation, LangiumDocument, PrecomputedScopes, streamAllContents } from 'langium'; import { CancellationToken } from 'vscode-jsonrpc'; -import { CrossModelServices } from './cross-model-module'; -import { QualifiedNameProvider } from './cross-model-naming'; -import { CrossModelPackageManager, UNKNOWN_PROJECT_ID, UNKNOWN_PROJECT_REFERENCE } from './cross-model-package-manager'; -import { isCrossModelRoot } from './generated/ast'; +import { CrossModelServices } from './cross-model-module.js'; +import { QualifiedNameProvider } from './cross-model-naming.js'; +import { CrossModelPackageManager, UNKNOWN_PROJECT_ID, UNKNOWN_PROJECT_REFERENCE } from './cross-model-package-manager.js'; +import { isCrossModelRoot } from './generated/ast.js'; /** * Custom node description that wraps a given description under a potentially new name and also stores the package id for faster access. diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-serializer.ts b/extensions/crossmodel-lang/src/language-server/cross-model-serializer.ts index edb55c78..23a26fe9 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-serializer.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-serializer.ts @@ -3,9 +3,9 @@ ********************************************************************************/ import { isReference } from 'langium'; -import { Serializer } from '../model-server/serializer'; -import { CrossModelServices } from './cross-model-module'; -import { CrossModelRoot, Entity, Relationship, SystemDiagram } from './generated/ast'; +import { Serializer } from '../model-server/serializer.js'; +import { CrossModelServices } from './cross-model-module.js'; +import { CrossModelRoot, Entity, Relationship, SystemDiagram } from './generated/ast.js'; const PROPERTY_ORDER = [ 'id', diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-validator.ts b/extensions/crossmodel-lang/src/language-server/cross-model-validator.ts index ae1b90ad..a03eed01 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-validator.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-validator.ts @@ -2,8 +2,8 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import { ValidationAcceptor, ValidationChecks } from 'langium'; -import type { CrossModelServices } from './cross-model-module'; -import { CrossModelAstType, DiagramEdge, Entity, EntityAttribute, Relationship, SystemDiagram } from './generated/ast'; +import type { CrossModelServices } from './cross-model-module.js'; +import { CrossModelAstType, DiagramEdge, Entity, EntityAttribute, Relationship, SystemDiagram } from './generated/ast.js'; /** * Register custom validation checks. diff --git a/extensions/crossmodel-lang/src/language-server/cross-model-workspace-manager.ts b/extensions/crossmodel-lang/src/language-server/cross-model-workspace-manager.ts index 3f419b0b..183676ea 100644 --- a/extensions/crossmodel-lang/src/language-server/cross-model-workspace-manager.ts +++ b/extensions/crossmodel-lang/src/language-server/cross-model-workspace-manager.ts @@ -1,13 +1,13 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { AstNode, DefaultWorkspaceManager, DocumentState, FileSystemNode, interruptAndCheck, LangiumDocument } from 'langium'; +import { AstNode, DefaultWorkspaceManager, FileSystemNode, LangiumDocument } from 'langium'; import { CancellationToken, Emitter, Event, WorkspaceFolder } from 'vscode-languageserver'; import { URI, Utils } from 'vscode-uri'; -import { CrossModelSharedServices } from './cross-model-module'; +import { CrossModelSharedServices } from './cross-model-module.js'; /** - * A cusotm workspace manager that: + * A custom workspace manager that: * - fires an event when the workspace is initialized (we use this for starting LSP-dependent servers) * - sets up a package-system on top of the workspace folders (including the 'node_modules' folder) * - validates all documents after workspace initialization @@ -17,44 +17,17 @@ export class CrossModelWorkspaceManager extends DefaultWorkspaceManager { constructor(protected services: CrossModelSharedServices, protected logger = services.logger.ClientLogger) { super(services); - const buildListener = this.documentBuilder.onBuildPhase(DocumentState.Validated, () => { - this.logger.info('Workspace Initialized'); - buildListener.dispose(); - this.onWorkspaceInitializedEmitter.fire((this.folders || []).map(folder => this.getRootFolder(folder))); - }); + this.initialBuildOptions = { validation: true }; } - get onWorkspaceInitialized(): Event { - return this.onWorkspaceInitializedEmitter.event; + override async initializeWorkspace(folders: WorkspaceFolder[], cancelToken?: CancellationToken | undefined): Promise { + await super.initializeWorkspace(folders, cancelToken); + this.logger.info('Workspace Initialized'); + this.onWorkspaceInitializedEmitter.fire((this.folders || []).map(folder => this.getRootFolder(folder))); } - override async initializeWorkspace(folders: WorkspaceFolder[], cancelToken = CancellationToken.None): Promise { - // Note: same as super implementation but we also call validation on the build and fire an event after we are done - // so that any errors are shown even without modifying any documents - - const fileExtensions = this.serviceRegistry.all.flatMap(e => e.LanguageMetaData.fileExtensions); - const documents: LangiumDocument[] = []; - const collector = (document: LangiumDocument): void => { - documents.push(document); - if (!this.langiumDocuments.hasDocument(document.uri)) { - this.langiumDocuments.addDocument(document); - } - }; - // Even though we don't await the initialization of the workspace manager, - // we can still assume that all library documents and file documents are loaded by the time we start building documents. - // The mutex prevents anything from performing a workspace build until we check the cancellation token - await this.loadAdditionalDocuments(folders, collector); - await Promise.all( - folders - .map(wf => [wf, this.getRootFolder(wf)] as [WorkspaceFolder, URI]) - .map(async entry => this.traverseFolder(...entry, fileExtensions, collector)) - ); - // Only after creating all documents do we check whether we need to cancel the initialization - // The document builder will later pick up on all unprocessed documents - await interruptAndCheck(cancelToken); - - // CHANGE: Use validation 'all' - await this.documentBuilder.build(documents, { validationChecks: 'all' }, cancelToken); + get onWorkspaceInitialized(): Event { + return this.onWorkspaceInitializedEmitter.event; } protected override async loadAdditionalDocuments( diff --git a/extensions/crossmodel-lang/src/language-server/generated/ast.ts b/extensions/crossmodel-lang/src/language-server/generated/ast.ts index ed39a285..769488e6 100644 --- a/extensions/crossmodel-lang/src/language-server/generated/ast.ts +++ b/extensions/crossmodel-lang/src/language-server/generated/ast.ts @@ -1,5 +1,5 @@ /****************************************************************************** - * This file was generated by langium-cli 1.3.1. + * This file was generated by langium-cli 2.1.0. * DO NOT EDIT MANUALLY! ******************************************************************************/ diff --git a/extensions/crossmodel-lang/src/language-server/generated/grammar.ts b/extensions/crossmodel-lang/src/language-server/generated/grammar.ts index c01f174b..3a0e7f14 100644 --- a/extensions/crossmodel-lang/src/language-server/generated/grammar.ts +++ b/extensions/crossmodel-lang/src/language-server/generated/grammar.ts @@ -1,5 +1,5 @@ /****************************************************************************** - * This file was generated by langium-cli 1.3.1. + * This file was generated by langium-cli 2.1.0. * DO NOT EDIT MANUALLY! ******************************************************************************/ diff --git a/extensions/crossmodel-lang/src/language-server/generated/module.ts b/extensions/crossmodel-lang/src/language-server/generated/module.ts index ea1a4391..973bd326 100644 --- a/extensions/crossmodel-lang/src/language-server/generated/module.ts +++ b/extensions/crossmodel-lang/src/language-server/generated/module.ts @@ -1,11 +1,11 @@ /****************************************************************************** - * This file was generated by langium-cli 1.3.1. + * This file was generated by langium-cli 2.1.0. * DO NOT EDIT MANUALLY! ******************************************************************************/ import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module } from 'langium'; -import { CrossModelAstReflection } from './ast'; -import { CrossModelGrammar } from './grammar'; +import { CrossModelAstReflection } from './ast.js'; +import { CrossModelGrammar } from './grammar.js'; export const CrossModelLanguageMetaData = { languageId: 'cross-model', diff --git a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indent-stack.ts b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indent-stack.ts index e61b763d..728fa84e 100644 --- a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indent-stack.ts +++ b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indent-stack.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import _ from 'lodash'; -import { IndentStackError } from './cross-model-lexer-error'; +import { IndentStackError } from './cross-model-lexer-error.js'; /** * Class to hold the current indentation levels. Has a few basic functions to handle diff --git a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indentation-tokens.ts b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indentation-tokens.ts index ee611cb3..65e3a3b3 100644 --- a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indentation-tokens.ts +++ b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-indentation-tokens.ts @@ -5,8 +5,8 @@ import { IToken, Lexer, createToken, createTokenInstance } from 'chevrotain'; import _ from 'lodash'; -import { indentStack } from './cross-model-indent-stack'; -import { IndentationError } from './cross-model-lexer-error'; +import { indentStack } from './cross-model-indent-stack.js'; +import { IndentationError } from './cross-model-lexer-error.js'; export const NAMES = { INDENT: 'INDENT', diff --git a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-lexer.ts b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-lexer.ts index e8f76c16..5875046c 100644 --- a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-lexer.ts +++ b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-lexer.ts @@ -4,9 +4,9 @@ import { createTokenInstance } from 'chevrotain'; import { DefaultLexer, LexerResult } from 'langium'; -import { indentStack } from './cross-model-indent-stack'; -import { DEDENT, NAMES } from './cross-model-indentation-tokens'; -import { IndentationError } from './cross-model-lexer-error'; +import { indentStack } from './cross-model-indent-stack.js'; +import { DEDENT, NAMES } from './cross-model-indentation-tokens.js'; +import { IndentationError } from './cross-model-lexer-error.js'; /** * Custom CrossModelLexer to get indentation working. diff --git a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-token-generator.ts b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-token-generator.ts index 183a14b7..857eb95f 100644 --- a/extensions/crossmodel-lang/src/language-server/lexer/cross-model-token-generator.ts +++ b/extensions/crossmodel-lang/src/language-server/lexer/cross-model-token-generator.ts @@ -2,11 +2,9 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { DefaultTokenBuilder, TokenBuilderOptions } from 'langium'; -import { Grammar, TerminalRule } from 'langium/lib/grammar/generated/ast'; +import { DefaultTokenBuilder, Grammar, GrammarAST, TokenBuilderOptions } from 'langium'; import { TokenType, TokenVocabulary } from 'chevrotain'; -import { DEDENT, INDENT, NEWLINE, SPACES, NAMES } from './cross-model-indentation-tokens'; - +import { DEDENT, INDENT, NEWLINE, SPACES, NAMES } from './cross-model-indentation-tokens.js'; /** * Custom implementation of TokenBuilder for the CrossModel language. * Overrides the default behavior to handle custom indentation tokens. @@ -64,7 +62,7 @@ export class CrossModelTokenBuilder extends DefaultTokenBuilder { * @returns The TokenType representing the terminal token. * */ - protected override buildTerminalToken(terminal: TerminalRule): TokenType { + protected override buildTerminalToken(terminal: GrammarAST.TerminalRule): TokenType { let token; if (terminal.name === NAMES.NEWLINE) { diff --git a/extensions/crossmodel-lang/src/language-server/util/ast-util.ts b/extensions/crossmodel-lang/src/language-server/util/ast-util.ts index 14e3b517..17bac83e 100644 --- a/extensions/crossmodel-lang/src/language-server/util/ast-util.ts +++ b/extensions/crossmodel-lang/src/language-server/util/ast-util.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import { Reference, ReferenceInfo } from 'langium'; -import { DiagramNode, SystemDiagram } from '../generated/ast'; +import { DiagramNode, SystemDiagram } from '../generated/ast.js'; export function createNodeToEntityReference(root: SystemDiagram): ReferenceInfo { return { diff --git a/extensions/crossmodel-lang/src/language-server/util/name-util.ts b/extensions/crossmodel-lang/src/language-server/util/name-util.ts index 053503b4..d527a1f5 100644 --- a/extensions/crossmodel-lang/src/language-server/util/name-util.ts +++ b/extensions/crossmodel-lang/src/language-server/util/name-util.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { SystemDiagram } from '../generated/ast'; +import { SystemDiagram } from '../generated/ast.js'; export function findAvailableNodeName(container: SystemDiagram, name: string): string { let availableName = name; diff --git a/extensions/crossmodel-lang/src/main.ts b/extensions/crossmodel-lang/src/main.ts index 4c21f372..eb952f6a 100644 --- a/extensions/crossmodel-lang/src/main.ts +++ b/extensions/crossmodel-lang/src/main.ts @@ -3,12 +3,12 @@ ********************************************************************************/ import 'reflect-metadata'; +import { createConnection, ProposedFeatures } from 'vscode-languageserver/node.js'; +import { startGLSPServer } from './glsp-server/launch.js'; +import { createCrossModelServices } from './language-server/cross-model-module.js'; +import { startModelServer } from './model-server/launch.js'; import { startLanguageServer } from 'langium'; import { NodeFileSystem } from 'langium/node'; -import { createConnection, ProposedFeatures } from 'vscode-languageserver/node'; -import { startGLSPServer } from './glsp-server/launch'; -import { createCrossModelServices } from './language-server/cross-model-module'; -import { startModelServer } from './model-server/launch'; /** * This module will be spawned as a separate language server process by the 'extension.ts'. diff --git a/extensions/crossmodel-lang/src/model-server/model-module.ts b/extensions/crossmodel-lang/src/model-server/model-module.ts index 87deb12e..9b549e15 100644 --- a/extensions/crossmodel-lang/src/model-server/model-module.ts +++ b/extensions/crossmodel-lang/src/model-server/model-module.ts @@ -3,9 +3,9 @@ ********************************************************************************/ import { TextDocument } from 'vscode-languageserver-textdocument'; -import { ModelService } from './model-service'; -import { OpenTextDocumentManager } from './open-text-document-manager'; -import { OpenableTextDocuments } from './openable-text-documents'; +import { ModelService } from './model-service.js'; +import { OpenTextDocumentManager } from './open-text-document-manager.js'; +import { OpenableTextDocuments } from './openable-text-documents.js'; /** * Extension to the default shared model services by Langium. diff --git a/extensions/crossmodel-lang/src/model-server/model-server.ts b/extensions/crossmodel-lang/src/model-server/model-server.ts index 27e451e3..4f8b7fc5 100644 --- a/extensions/crossmodel-lang/src/model-server/model-server.ts +++ b/extensions/crossmodel-lang/src/model-server/model-server.ts @@ -19,10 +19,10 @@ import { } from '@crossbreeze/protocol'; import { isReference } from 'langium'; import { Disposable } from 'vscode-jsonrpc'; -import * as rpc from 'vscode-jsonrpc/node'; +import * as rpc from 'vscode-jsonrpc/node.js'; import { CrossModelRoot as CrossModelRootAst, DiagramNode, Entity, isCrossModelRoot } from '../language-server/generated/ast'; -import { ModelService } from './model-service'; +import { ModelService } from './model-service.js'; /** * The model server handles request messages on the RPC connection and ensures that any return value diff --git a/extensions/crossmodel-lang/src/model-server/model-service.ts b/extensions/crossmodel-lang/src/model-server/model-service.ts index d7ee5680..b53d2d86 100644 --- a/extensions/crossmodel-lang/src/model-server/model-service.ts +++ b/extensions/crossmodel-lang/src/model-server/model-service.ts @@ -7,7 +7,7 @@ import { AstNode, Deferred, DocumentState, isAstNode } from 'langium'; import { Disposable, OptionalVersionedTextDocumentIdentifier, Range, TextDocumentEdit, TextEdit, uinteger } from 'vscode-languageserver'; import { URI } from 'vscode-uri'; import { CrossModelSharedServices } from '../language-server/cross-model-module'; -import { LANGUAGE_CLIENT_ID } from './openable-text-documents'; +import { LANGUAGE_CLIENT_ID } from './openable-text-documents.js'; /** * The model service serves as a facade to access and update semantic models from the language server as a non-LSP client. @@ -115,14 +115,20 @@ export class ModelService { const newVersion = textDocument.version + 1; const pendingUpdate = new Deferred(); const listener = this.documentBuilder.onBuildPhase(DocumentState.Validated, (allChangedDocuments, _token) => { - const updatedDocument = allChangedDocuments - .find(doc => doc.uri.toString() === documentUri.toString() && doc.textDocument.version === newVersion); + const updatedDocument = allChangedDocuments.find( + doc => doc.uri.toString() === documentUri.toString() && doc.textDocument.version === newVersion + ); if (updatedDocument) { pendingUpdate.resolve(updatedDocument.parseResult.value as T); listener.dispose(); } }); - const timeout = new Promise((_, reject) => setTimeout(() => { listener.dispose(); reject('Update timed out.'); }, 5000)); + const timeout = new Promise((_, reject) => + setTimeout(() => { + listener.dispose(); + reject('Update timed out.'); + }, 5000) + ); this.documentManager.update(args.uri, newVersion, text, args.clientId); return Promise.race([pendingUpdate.promise, timeout]); } diff --git a/extensions/crossmodel-lang/src/model-server/open-text-document-manager.ts b/extensions/crossmodel-lang/src/model-server/open-text-document-manager.ts index 96e15f50..f00549fb 100644 --- a/extensions/crossmodel-lang/src/model-server/open-text-document-manager.ts +++ b/extensions/crossmodel-lang/src/model-server/open-text-document-manager.ts @@ -17,9 +17,9 @@ import { Disposable } from 'vscode-languageserver'; import { TextDocumentIdentifier, TextDocumentItem, VersionedTextDocumentIdentifier } from 'vscode-languageserver-protocol'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI } from 'vscode-uri'; -import { CrossModelLanguageMetaData } from '../language-server/generated/module'; -import { AddedSharedModelServices } from './model-module'; -import { OpenableTextDocuments } from './openable-text-documents'; +import { CrossModelLanguageMetaData } from '../language-server/generated/module.js'; +import { AddedSharedModelServices } from './model-module.js'; +import { OpenableTextDocuments } from './openable-text-documents.js'; /** * A manager class that suppors handling documents with a simple open-update-save/close lifecycle. diff --git a/extensions/crossmodel-lang/src/model-server/openable-text-documents.ts b/extensions/crossmodel-lang/src/model-server/openable-text-documents.ts index bae68d1d..6bded1a1 100644 --- a/extensions/crossmodel-lang/src/model-server/openable-text-documents.ts +++ b/extensions/crossmodel-lang/src/model-server/openable-text-documents.ts @@ -1,8 +1,8 @@ -/* eslint-disable header/header */ /* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation and EclipseSource. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ +// eslint-disable-next-line header/header import { basename } from 'path'; import { CancellationToken, @@ -25,7 +25,7 @@ import { } from 'vscode-languageserver'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI } from 'vscode-uri'; -import { ClientLogger } from '../language-server/cross-model-client-logger'; +import { ClientLogger } from '../language-server/cross-model-client-logger.js'; export const LANGUAGE_CLIENT_ID = 'language-client'; diff --git a/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts b/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts index ebd10d3c..d3e7c47a 100644 --- a/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts +++ b/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts @@ -1,14 +1,16 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test, jest } from '@jest/globals'; import { EmptyFileSystem, isReference } from 'langium'; -import { diagram1, diagram2, diagram3, diagram4, diagram5, diagram6 } from './test-utils/test-documents/diagram/index'; -import { parseDocument } from './test-utils/utils'; +import { diagram1, diagram2, diagram3, diagram4, diagram5, diagram6 } from './test-utils/test-documents/diagram/index.js'; +import { parseDocument } from './test-utils/utils.js'; -import { createCrossModelServices } from '../../src/language-server/cross-model-module'; -import { CrossModelRoot } from '../../src/language-server/generated/ast'; +import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; +import { CrossModelRoot } from '../../src/language-server/generated/ast.js'; + +jest.useFakeTimers(); const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; diff --git a/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts b/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts index c9a2e7ac..a5a7eb50 100644 --- a/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts +++ b/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts @@ -2,14 +2,16 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test, jest } from '@jest/globals'; import { EmptyFileSystem } from 'langium'; -import { parseDocument } from './test-utils/utils'; -import { entity1, entity2, entity3, entity4 } from './test-utils/test-documents/entity/index'; +import { parseDocument } from './test-utils/utils.js'; +import { entity1, entity2, entity3, entity4 } from './test-utils/test-documents/entity/index.js'; -import { CrossModelRoot } from '../../src/language-server/generated/ast'; -import { createCrossModelServices } from '../../src/language-server/cross-model-module'; +import { CrossModelRoot } from '../../src/language-server/generated/ast.js'; +import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; + +jest.useFakeTimers(); const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; diff --git a/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts b/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts index 567d96bc..f5f761d9 100644 --- a/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts +++ b/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts @@ -2,14 +2,16 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test, jest } from '@jest/globals'; import { EmptyFileSystem, isReference } from 'langium'; -import { parseDocument } from './test-utils/utils'; -import { relationship1, relationship2 } from './test-utils/test-documents/relationship/index'; +import { parseDocument } from './test-utils/utils.js'; +import { relationship1, relationship2 } from './test-utils/test-documents/relationship/index.js'; -import { CrossModelRoot } from '../../src/language-server/generated/ast'; -import { createCrossModelServices } from '../../src/language-server/cross-model-module'; +import { CrossModelRoot } from '../../src/language-server/generated/ast.js'; +import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; + +jest.useFakeTimers(); const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts index 0a2d1fe6..f8d1ea06 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts @@ -2,8 +2,10 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeEach } from '@jest/globals'; -import { indentStack } from '../../../src/language-server/lexer/cross-model-indent-stack'; +import { describe, expect, test, beforeEach, jest } from '@jest/globals'; +import { indentStack } from '../../../src/language-server/lexer/cross-model-indent-stack.js'; + +jest.useFakeTimers(); describe('IndentStack', () => { beforeEach(() => { diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts index d431b4b1..981f5887 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts @@ -1,11 +1,13 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeEach, beforeAll } from '@jest/globals'; +import { describe, expect, test, beforeEach, beforeAll, jest } from '@jest/globals'; import { Lexer, TokenType, createToken, tokenMatcher } from 'chevrotain'; -import { SPACES, NEWLINE, INDENT, DEDENT } from '../../../src/language-server/lexer/cross-model-indentation-tokens'; -import { indentStack } from '../../../src/language-server/lexer/cross-model-indent-stack'; +import { SPACES, NEWLINE, INDENT, DEDENT } from '../../../src/language-server/lexer/cross-model-indentation-tokens.js'; +import { indentStack } from '../../../src/language-server/lexer/cross-model-indent-stack.js'; + +jest.useFakeTimers(); describe('matchIndentBase', () => { let TESTTOKEN: TokenType; diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts index 46338d94..1079c09e 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeAll } from '@jest/globals'; +import { describe, expect, test, beforeAll, jest } from '@jest/globals'; import { EmptyFileSystem } from 'langium'; import { tokenMatcher } from 'chevrotain'; @@ -10,6 +10,8 @@ import { CrossModelLexer } from '../../../src/language-server/lexer/cross-model- import { DEDENT, INDENT } from '../../../src/language-server/lexer/cross-model-indentation-tokens'; import { createCrossModelServices } from '../../../src/language-server/cross-model-module'; +jest.useFakeTimers(); + const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; describe('CrossModelLexer', () => { diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts index 211f5ac5..4cb050ba 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeAll } from '@jest/globals'; +import { describe, expect, test, beforeAll, jest } from '@jest/globals'; import { Grammar } from 'langium'; import { TokenType } from 'chevrotain'; @@ -12,6 +12,8 @@ import { CrossModelTokenBuilder } from '../../../src/language-server/lexer/cross import { CrossModelGrammar } from '../../../src/language-server/generated/grammar'; import _ from 'lodash'; +jest.useFakeTimers(); + describe('CrossModelTokenBuilder', () => { let tokenBuilder: CrossModelTokenBuilder; let crossModelGrammer: Grammar; diff --git a/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts b/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts index d6d387c6..56159460 100644 --- a/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts +++ b/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts @@ -2,13 +2,15 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { beforeAll, describe, expect, test } from '@jest/globals'; +import { beforeAll, describe, expect, test, jest } from '@jest/globals'; import { EmptyFileSystem, Reference } from 'langium'; import _ from 'lodash'; -import { createCrossModelServices } from '../../../src/language-server/cross-model-module'; -import { CrossModelSerializer } from '../../../src/language-server/cross-model-serializer'; -import { CrossModelRoot, Entity, Relationship } from '../../../src/language-server/generated/ast'; +import { createCrossModelServices } from '../../../src/language-server/cross-model-module.js'; +import { CrossModelSerializer } from '../../../src/language-server/cross-model-serializer.js'; +import { CrossModelRoot, Entity, Relationship } from '../../../src/language-server/generated/ast.js'; + +jest.useFakeTimers(); const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; diff --git a/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/diagram/index.ts b/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/diagram/index.ts index 8cc7d55f..9de16236 100644 --- a/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/diagram/index.ts +++ b/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/diagram/index.ts @@ -1,9 +1,9 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -export * from './diagram1'; -export * from './diagram2'; -export * from './diagram3'; -export * from './diagram4'; -export * from './diagram5'; -export * from './diagram6'; +export * from './diagram1.js'; +export * from './diagram2.js'; +export * from './diagram3.js'; +export * from './diagram4.js'; +export * from './diagram5.js'; +export * from './diagram6.js'; diff --git a/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/entity/index.ts b/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/entity/index.ts index c96f8df6..62de41f8 100644 --- a/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/entity/index.ts +++ b/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/entity/index.ts @@ -1,7 +1,7 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -export * from './entity1'; -export * from './entity2'; -export * from './entity3'; -export * from './entity4'; +export * from './entity1.js'; +export * from './entity2.js'; +export * from './entity3.js'; +export * from './entity4.js'; diff --git a/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/relationship/index.ts b/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/relationship/index.ts index 9eee07d4..eaf440ce 100644 --- a/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/relationship/index.ts +++ b/extensions/crossmodel-lang/test/language-server/test-utils/test-documents/relationship/index.ts @@ -1,5 +1,5 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -export * from './relationship1'; -export * from './relationship2'; +export * from './relationship1.js'; +export * from './relationship2.js'; diff --git a/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts b/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts index c3acb466..d4235ef1 100644 --- a/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts +++ b/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts @@ -1,13 +1,15 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test, jest } from '@jest/globals'; import { EmptyFileSystem } from 'langium'; -import { createCrossModelServices } from '../../../src/language-server/cross-model-module'; -import { CrossModelRoot } from '../../../src/language-server/generated/ast'; -import { findAvailableNodeName } from '../../../src/language-server/util/name-util'; -import { parseDocument } from '../test-utils/utils'; +import { createCrossModelServices } from '../../../src/language-server/cross-model-module.js'; +import { CrossModelRoot } from '../../../src/language-server/generated/ast.js'; +import { findAvailableNodeName } from '../../../src/language-server/util/name-util.js'; +import { parseDocument } from '../test-utils/utils.js'; + +jest.useFakeTimers(); const services = createCrossModelServices({ ...EmptyFileSystem }); const cmServices = services.CrossModel; diff --git a/extensions/crossmodel-lang/test/model-server/model-server.test.ts b/extensions/crossmodel-lang/test/model-server/model-server.test.ts index b371f916..031cf093 100644 --- a/extensions/crossmodel-lang/test/model-server/model-server.test.ts +++ b/extensions/crossmodel-lang/test/model-server/model-server.test.ts @@ -2,10 +2,12 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test, jest } from '@jest/globals'; import { NodeFileSystem } from 'langium/node'; -import { createCrossModelServices } from '../../src/language-server/cross-model-module'; -import { ModelService } from '../../src/model-server/model-service'; +import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; +import { ModelService } from '../../src/model-server/model-service.js'; + +jest.useFakeTimers(); // Test written by Martin Fleck, added to this branch for Jest. Using Vitest is not necessary diff --git a/extensions/crossmodel-lang/tsconfig.json b/extensions/crossmodel-lang/tsconfig.json index 3545542c..843864bc 100644 --- a/extensions/crossmodel-lang/tsconfig.json +++ b/extensions/crossmodel-lang/tsconfig.json @@ -1,11 +1,20 @@ { - "extends": "../../configs/base.tsconfig.json", "compilerOptions": { - "composite": true, + "target": "ES2017", + "module": "Node16", + "lib": ["ESNext"], + "sourceMap": true, + "outDir": "out", + "strict": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "noImplicitOverride": true, + "moduleResolution": "Node16", + "experimentalDecorators": true, "esModuleInterop": true, - "rootDir": "src", - "outDir": "out" + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true }, - "include": ["src"], + "include": ["src/**/*.ts", "test/**/*.ts"], "exclude": ["out", "node_modules"] } diff --git a/package.json b/package.json index ad675bc4..ea6353b4 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,10 @@ "start:browser": "yarn theia:browser start", "start:electron": "yarn theia:electron start", "start:verdaccio": "yarn verdaccio --config verdaccio-config.yaml", - "test": "jest --config=configs/jest.config.js", + "test": "rimraf unit-test-results && lerna run test", "theia:browser": "yarn --cwd applications/browser-app", "theia:electron": "yarn --cwd applications/electron-app", - "ui-test": "yarn --cwd ./e2e-tests/ test", + "ui-test": "yarn --cwd e2e-tests ui-test", "watch": "lerna run --parallel watch" }, "devDependencies": { diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js index 0349530b..6917cbd2 100644 --- a/packages/core/jest.config.js +++ b/packages/core/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Core' }; diff --git a/packages/form-client/jest.config.js b/packages/form-client/jest.config.js index 0349530b..38640ccf 100644 --- a/packages/form-client/jest.config.js +++ b/packages/form-client/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Form-Client' }; diff --git a/packages/glsp-client/jest.config.js b/packages/glsp-client/jest.config.js index 0349530b..4ebd798e 100644 --- a/packages/glsp-client/jest.config.js +++ b/packages/glsp-client/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'GLSP-Client' }; diff --git a/packages/model-service/jest.config.js b/packages/model-service/jest.config.js index 0349530b..97522386 100644 --- a/packages/model-service/jest.config.js +++ b/packages/model-service/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'ModelService' }; diff --git a/packages/product/jest.config.js b/packages/product/jest.config.js index 0349530b..062373ec 100644 --- a/packages/product/jest.config.js +++ b/packages/product/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Product' }; diff --git a/packages/property-view/jest.config.js b/packages/property-view/jest.config.js index 0349530b..d44d6880 100644 --- a/packages/property-view/jest.config.js +++ b/packages/property-view/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Property View' }; diff --git a/packages/protocol/jest.config.js b/packages/protocol/jest.config.js index 0349530b..95456052 100644 --- a/packages/protocol/jest.config.js +++ b/packages/protocol/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'Protocol' }; diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 2886a0b2..f9f89e43 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@eclipse-glsp/protocol": "2.0.0", - "langium": "~1.3.0", + "langium": "~2.1.3", "vscode-jsonrpc": "^8.0.2" } } diff --git a/packages/react-model-ui/jest.config.js b/packages/react-model-ui/jest.config.js index 0349530b..e50c1bed 100644 --- a/packages/react-model-ui/jest.config.js +++ b/packages/react-model-ui/jest.config.js @@ -1,5 +1,7 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ const baseConfig = require('../../configs/base.jest.config'); module.exports = { - ...baseConfig + ...baseConfig, + displayName: 'React Model UI' }; diff --git a/yarn.lock b/yarn.lock index fdc7469f..b6a2fcd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -990,32 +990,37 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@chevrotain/cst-dts-gen@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.4.2.tgz#a3426dba2c48cf6c90e49a0676aea750e8f43e88" - integrity sha512-0+4bNjlndNWMoVLH/+y4uHnf6GrTipsC+YTppJxelVJo+xeRVQ0s2PpkdDCVTsu7efyj+8r1gFiwVXsp6JZ0iQ== - dependencies: - "@chevrotain/gast" "10.4.2" - "@chevrotain/types" "10.4.2" - lodash "4.17.21" - -"@chevrotain/gast@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@chevrotain/gast/-/gast-10.4.2.tgz#236dc48e54cba16260c03bece25d5a3b6e2f5dab" - integrity sha512-4ZAn8/mjkmYonilSJ60gGj1tAF0cVWYUMlIGA0e4ATAc3a648aCnvpBw7zlPHDQjFp50XC13iyWEgWAKiRKTOA== - dependencies: - "@chevrotain/types" "10.4.2" - lodash "4.17.21" - -"@chevrotain/types@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-10.4.2.tgz#18be6b7a3226b121fccec08c2ba8433219a6813c" - integrity sha512-QzSCjg6G4MvIoLeIgOiMR0IgzkGEQqrNJJIr3T5ETRa7l4Av4AMIiEctV99mvDr57iXwwk0/kr3RJxiU36Nevw== - -"@chevrotain/utils@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-10.4.2.tgz#87735732184cc5a2f8aad2f3454082294ef3c924" - integrity sha512-V34dacxWLwKcvcy32dx96ADJVdB7kOJLm7LyBkBQw5u5HC9WdEFw2G17zml+U3ivavGTrGPJHl8o9/UJm0PlUw== +"@chevrotain/cst-dts-gen@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz#5e0863cc57dc45e204ccfee6303225d15d9d4783" + integrity sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ== + dependencies: + "@chevrotain/gast" "11.0.3" + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/gast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/gast/-/gast-11.0.3.tgz#e84d8880323fe8cbe792ef69ce3ffd43a936e818" + integrity sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q== + dependencies: + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/regexp-to-ast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz#11429a81c74a8e6a829271ce02fc66166d56dcdb" + integrity sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA== + +"@chevrotain/types@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-11.0.3.tgz#f8a03914f7b937f594f56eb89312b3b8f1c91848" + integrity sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ== + +"@chevrotain/utils@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-11.0.3.tgz#e39999307b102cff3645ec4f5b3665f5297a2224" + integrity sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ== "@colors/colors@1.6.0", "@colors/colors@^1.6.0": version "1.6.0" @@ -1252,6 +1257,116 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== +"@esbuild/android-arm64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.7.tgz#646156aea43e8e6723de6e94a4ac07c5aed41be1" + integrity sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w== + +"@esbuild/android-arm@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.7.tgz#0827b49aed813c33ea18ee257c1728cdc4a01030" + integrity sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww== + +"@esbuild/android-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.7.tgz#fa294ed5214d88219d519e0ab1bbb0253a89b864" + integrity sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw== + +"@esbuild/darwin-arm64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.7.tgz#e24d2ed545749ff251eabe8bce11fefa688892d3" + integrity sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw== + +"@esbuild/darwin-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.7.tgz#02d1f8a572874c90d8f55dde8a859e5145bd06f6" + integrity sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ== + +"@esbuild/freebsd-arm64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.7.tgz#bc6a69b9a7915da278f0a5ebaec069c813982c22" + integrity sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ== + +"@esbuild/freebsd-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.7.tgz#ec3708488625d70e565968ceea1355e7c8613865" + integrity sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA== + +"@esbuild/linux-arm64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.7.tgz#8e04b66c306858f92d4f90f8222775270755e88a" + integrity sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g== + +"@esbuild/linux-arm@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.7.tgz#12d5b65e089029ee1fe4c591b60969c9b1a85355" + integrity sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww== + +"@esbuild/linux-ia32@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.7.tgz#01eabc2a3ad9039e115db650268e4f48f910dbe2" + integrity sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g== + +"@esbuild/linux-loong64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.7.tgz#70681113632970e6a5766607bbdb98aa18cf4d5f" + integrity sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw== + +"@esbuild/linux-mips64el@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.7.tgz#f63c022a71a3d70c482d1943a27cb8997021e230" + integrity sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w== + +"@esbuild/linux-ppc64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.7.tgz#614eafd08b0c50212f287b948b3c08d6e60f221f" + integrity sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ== + +"@esbuild/linux-riscv64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.7.tgz#31d3b63f92f65968268a8e61ba59872538e80e88" + integrity sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw== + +"@esbuild/linux-s390x@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.7.tgz#be94974e0caa0783ae05f9477fd7170b9ac29cb0" + integrity sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg== + +"@esbuild/linux-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.7.tgz#84e8018a913dd4ecee954623e395984aef3d0007" + integrity sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ== + +"@esbuild/netbsd-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.7.tgz#98898ba8800374c9df9bb182ca4f69fcecaf4411" + integrity sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ== + +"@esbuild/openbsd-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.7.tgz#46dc4eda2adb51f16361b1ad10e9b3f4938c4573" + integrity sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ== + +"@esbuild/sunos-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.7.tgz#1650d40dd88412ecc11490119cd23cbaf661a591" + integrity sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw== + +"@esbuild/win32-arm64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.7.tgz#e61de6c4eb204d83fd912f3ae6812cc8c7d32d25" + integrity sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw== + +"@esbuild/win32-ia32@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.7.tgz#3d9c159d42c67e37a433e44ef8217c661cb6f6d0" + integrity sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A== + +"@esbuild/win32-x64@0.19.7": + version "0.19.7" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.7.tgz#02c4446f802706098d8e6ee70cf2b7aba96ded0b" + integrity sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1259,7 +1374,7 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": version "4.10.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== @@ -3079,16 +3194,16 @@ dependencies: undici-types "~5.26.4" -"@types/node@^14.17.3": - version "14.18.63" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" - integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== - "@types/node@^16.11.26": version "16.18.59" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.59.tgz#4cdbd631be6d9be266a96fb17b5d0d7ad6bbe26c" integrity sha512-PJ1w2cNeKUEdey4LiPra0ZuxZFOGvetswE8qHRriV/sUkL5Al4tTmPV9D2+Y/TPIxTHHgxTfRjZVKWhPw/ORhQ== +"@types/node@~16.18.41": + version "16.18.64" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.64.tgz#cd4e41420b77b346695def5a342f6dea0f9d9329" + integrity sha512-TiY2gIDob8+QOPIcVpS0ZY+H1DVTfplBW6UgL2b4gOYbigIlKVIh6Lcv+7YDUciUTqhVLG91PrZBXW10IoBhtw== + "@types/p-queue@^2.3.1": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/p-queue/-/p-queue-2.3.2.tgz#16bc5fece69ef85efaf2bce8b13f3ebe39c5a1c8" @@ -3249,10 +3364,10 @@ resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.8.tgz#5324a03e0885ffe6fef0192900aec317abbb2997" integrity sha512-YhUhnxRYs/NiVUbIs3F/EzviDP/NZCEAE2Mx5DUqLdldUmphOhFCVh7Kc+7zlYEExM0P8dzfbJi0yRlNb2Bw5g== -"@types/vscode@^1.56.0": - version "1.83.1" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.83.1.tgz#fe51b3d913a5c5b265a622179ae4ab6c0af7d54e" - integrity sha512-BHu51NaNKOtDf3BOonY3sKFFmZKEpRkzqkZVpSYxowLbs5JqjOQemYFob7Gs5rpxE5tiGhfpnMpcdF/oKrLg4w== +"@types/vscode@~1.67.0": + version "1.67.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.67.0.tgz#8eaba41d1591aa02f5d960b7dfae3b16e066f08c" + integrity sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g== "@types/write-json-file@^2.2.1": version "2.2.1" @@ -3292,7 +3407,7 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^5.28.0", "@typescript-eslint/eslint-plugin@^5.48.0": +"@typescript-eslint/eslint-plugin@^5.48.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== @@ -3308,7 +3423,24 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.28.0", "@typescript-eslint/parser@^5.45.0": +"@typescript-eslint/eslint-plugin@~6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.1.tgz#bc0c6f000134b53c304ad0bec4ee4753cd3e89d2" + integrity sha512-3F5PtBzUW0dYlq77Lcqo13fv+58KDwUib3BddilE8ajPJT+faGgxmI9Sw+I8ZS22BYwoir9ZhNXcLi+S+I2bkw== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.4.1" + "@typescript-eslint/type-utils" "6.4.1" + "@typescript-eslint/utils" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^5.45.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== @@ -3318,6 +3450,17 @@ "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" +"@typescript-eslint/parser@~6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.4.1.tgz#85ad550bf4ac4aa227504f1becb828f8e46c44e3" + integrity sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg== + dependencies: + "@typescript-eslint/scope-manager" "6.4.1" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/typescript-estree" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" + debug "^4.3.4" + "@typescript-eslint/scope-manager@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" @@ -3326,6 +3469,14 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" +"@typescript-eslint/scope-manager@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.4.1.tgz#4b073a30be2dbe603e44e9ae0cff7e1d3ed19278" + integrity sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A== + dependencies: + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" + "@typescript-eslint/scope-manager@6.9.0": version "6.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz#2626e9a7fe0e004c3e25f3b986c75f584431134e" @@ -3344,11 +3495,26 @@ debug "^4.3.4" tsutils "^3.21.0" +"@typescript-eslint/type-utils@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.4.1.tgz#fa21cb13016c8d6f352fe9b2d6c9ab6edc2d1857" + integrity sha512-7ON8M8NXh73SGZ5XvIqWHjgX2f+vvaOarNliGhjrJnv1vdjG0LVIz+ToYfPirOoBi56jxAKLfsLm40+RvxVVXA== + dependencies: + "@typescript-eslint/typescript-estree" "6.4.1" + "@typescript-eslint/utils" "6.4.1" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== +"@typescript-eslint/types@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.4.1.tgz#b2c61159f46dda210fed9f117f5d027f65bb5c3b" + integrity sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg== + "@typescript-eslint/types@6.9.0": version "6.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.9.0.tgz#86a0cbe7ac46c0761429f928467ff3d92f841098" @@ -3367,6 +3533,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.1.tgz#91ff88101c710adb0f70a317f2f65efa9441da45" + integrity sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg== + dependencies: + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/typescript-estree@6.9.0": version "6.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz#d0601b245be873d8fe49f3737f93f8662c8693d4" @@ -3394,6 +3573,19 @@ eslint-scope "^5.1.1" semver "^7.3.7" +"@typescript-eslint/utils@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.4.1.tgz#81bf62ff0c3119a26c19fab683582e29450717bc" + integrity sha512-F/6r2RieNeorU0zhqZNv89s9bDZSovv3bZQpUNOmmQK1L80/cV4KEu95YUJWi75u5PhboFoKUJBnZ4FQcoqhDw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.4.1" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/typescript-estree" "6.4.1" + semver "^7.5.4" + "@typescript-eslint/utils@^6.0.0": version "6.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.9.0.tgz#5bdac8604fca4823f090e4268e681c84d3597c9f" @@ -3415,6 +3607,14 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.1.tgz#e3ccf7b8d42e625946ac5094ed92a405fb4115e0" + integrity sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ== + dependencies: + "@typescript-eslint/types" "6.4.1" + eslint-visitor-keys "^3.4.1" + "@typescript-eslint/visitor-keys@6.9.0": version "6.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz#cc69421c10c4ac997ed34f453027245988164e80" @@ -4984,6 +5184,11 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@~4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -5026,24 +5231,24 @@ cheerio@^1.0.0-rc.9: parse5 "^7.0.0" parse5-htmlparser2-tree-adapter "^7.0.0" -chevrotain-allstar@~0.1.4: - version "0.1.7" - resolved "https://registry.yarnpkg.com/chevrotain-allstar/-/chevrotain-allstar-0.1.7.tgz#66cb0eed6ce53c9ef07621a29fcf149a9f3bc48d" - integrity sha512-oMSHkXVCDQxnj3tDCqcEoMnNIEiYlAYT0FVja1PaLrT3njXGvg5JXTXs/tk2NI42SR3LMJyqTNgjR4VyDIf19w== +chevrotain-allstar@~0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz#b7412755f5d83cc139ab65810cdb00d8db40e6ca" + integrity sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw== dependencies: - lodash "^4.17.21" + lodash-es "^4.17.21" -chevrotain@~10.4.2: - version "10.4.2" - resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-10.4.2.tgz#9abeac6a60134931c0a0788b206400e5f7a3daba" - integrity sha512-gzF5GxE0Ckti5kZVuKEZycLntB5X2aj9RVY0r4/220GwQjdnljU+/t3kP74/FMWC7IzCDDEjQ9wsFUf0WCdSHg== +chevrotain@~11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-11.0.3.tgz#88ffc1fb4b5739c715807eaeedbbf200e202fc1b" + integrity sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw== dependencies: - "@chevrotain/cst-dts-gen" "10.4.2" - "@chevrotain/gast" "10.4.2" - "@chevrotain/types" "10.4.2" - "@chevrotain/utils" "10.4.2" - lodash "4.17.21" - regexp-to-ast "0.5.0" + "@chevrotain/cst-dts-gen" "11.0.3" + "@chevrotain/gast" "11.0.3" + "@chevrotain/regexp-to-ast" "11.0.3" + "@chevrotain/types" "11.0.3" + "@chevrotain/utils" "11.0.3" + lodash-es "4.17.21" chokidar@3.5.3: version "3.5.3" @@ -5363,6 +5568,11 @@ commander@~10.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@~11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" + integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -5763,7 +5973,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-env@^7.0.3: +cross-env@^7.0.3, cross-env@~7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== @@ -6677,6 +6887,34 @@ es6-promise@^4.2.4: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== +esbuild@~0.19.7: + version "0.19.7" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.7.tgz#b9a7235097b81278dcf090e2532ed13c95a2ee84" + integrity sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ== + optionalDependencies: + "@esbuild/android-arm" "0.19.7" + "@esbuild/android-arm64" "0.19.7" + "@esbuild/android-x64" "0.19.7" + "@esbuild/darwin-arm64" "0.19.7" + "@esbuild/darwin-x64" "0.19.7" + "@esbuild/freebsd-arm64" "0.19.7" + "@esbuild/freebsd-x64" "0.19.7" + "@esbuild/linux-arm" "0.19.7" + "@esbuild/linux-arm64" "0.19.7" + "@esbuild/linux-ia32" "0.19.7" + "@esbuild/linux-loong64" "0.19.7" + "@esbuild/linux-mips64el" "0.19.7" + "@esbuild/linux-ppc64" "0.19.7" + "@esbuild/linux-riscv64" "0.19.7" + "@esbuild/linux-s390x" "0.19.7" + "@esbuild/linux-x64" "0.19.7" + "@esbuild/netbsd-x64" "0.19.7" + "@esbuild/openbsd-x64" "0.19.7" + "@esbuild/sunos-x64" "0.19.7" + "@esbuild/win32-arm64" "0.19.7" + "@esbuild/win32-ia32" "0.19.7" + "@esbuild/win32-x64" "0.19.7" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -7489,7 +7727,7 @@ fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.0.8: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@~11.1.0: +fs-extra@~11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== @@ -9431,37 +9669,37 @@ kuler@^2.0.0: resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== -langium-cli@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/langium-cli/-/langium-cli-1.3.1.tgz#d73777fbf866d429e242b4bf7676d1251aafa994" - integrity sha512-9faKpioKCjBD0Z4y165+wQlDFiDHOXYBlhPVgbV+neSnSB70belZLNfykAVa564360h7Br/5PogR5jW2n/tOKw== +langium-cli@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/langium-cli/-/langium-cli-2.1.0.tgz#34909094e669ec763948923a9932557ccfe8b309" + integrity sha512-Gbj4CvfAc1gP/6ihxikd2Je95j1FWjXZu8bbji2/t2vQ6kEP+vs9Fx7kSGOM0AbU/hjZfy6E35bJPOdwsiyqTA== dependencies: - chalk "~4.1.2" - commander "~10.0.0" - fs-extra "~11.1.0" + chalk "~5.3.0" + commander "~11.0.0" + fs-extra "~11.1.1" jsonschema "~1.4.1" - langium "~1.3.0" - langium-railroad "~1.3.0" + langium "~2.1.0" + langium-railroad "~2.1.0" lodash "~4.17.21" -langium-railroad@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/langium-railroad/-/langium-railroad-1.3.0.tgz#ef2bb50ac26811332c11ea9a62b4e66f96c3f7f4" - integrity sha512-I3gx79iF+Qpn2UjzfHLf2GENAD9mPdSZHL3juAZLBsxznw4se7MBrJX32oPr/35DTjU9q99wFCQoCXu7mcf+Bg== +langium-railroad@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/langium-railroad/-/langium-railroad-2.1.0.tgz#921176c97880803f3bceb5fb960c988b3b415ae3" + integrity sha512-2IeAIUSTQzbDjNnJA+0ql8tyN/mhCSN4FS50Mo9LOtLj523qUEBwHflDmCiOGZzW9iZdni6NXJgh8nLqjhTlDw== dependencies: - langium "~1.3.0" - railroad-diagrams "^1.0.0" + langium "~2.1.0" + railroad-diagrams "~1.0.0" -langium@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/langium/-/langium-1.3.1.tgz#08f570a3e506141f482d32e71814a0d5c991c75c" - integrity sha512-xC+DnAunl6cZIgYjRpgm3s1kYAB5/Wycsj24iYaXG9uai7SgvMaFZSrRvdA5rUK/lSta/CRvgF+ZFoEKEOFJ5w== +langium@~2.1.0, langium@~2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/langium/-/langium-2.1.3.tgz#92960e52c24897726adacd137aa310acc91a1ed5" + integrity sha512-/WN1xHoNBg0mi1Jp9ydMFSHIv8Jhq7K+0stNVURdoG4NgZx4/06AfNeeixmmU8X842wBl9gFZJP5O93Ge5Oasw== dependencies: - chevrotain "~10.4.2" - chevrotain-allstar "~0.1.4" - vscode-languageserver "~8.0.2" - vscode-languageserver-textdocument "~1.0.8" - vscode-uri "~3.0.7" + chevrotain "~11.0.3" + chevrotain-allstar "~0.3.0" + vscode-languageserver "~9.0.1" + vscode-languageserver-textdocument "~1.0.11" + vscode-uri "~3.0.8" lazy-val@^1.0.4, lazy-val@^1.0.5: version "1.0.5" @@ -9679,7 +9917,7 @@ lockfile@1.0.4: dependencies: signal-exit "^3.0.2" -lodash-es@^4.17.21: +lodash-es@4.17.21, lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== @@ -11638,7 +11876,7 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -railroad-diagrams@^1.0.0: +railroad-diagrams@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A== @@ -11961,11 +12199,6 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regexp-to-ast@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz#56c73856bee5e1fef7f73a00f1473452ab712a24" - integrity sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw== - regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" @@ -13690,16 +13923,16 @@ typescript@>=4.9.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== -typescript@^4.9.4: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - typescript@~4.5.5: version "4.5.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== +typescript@~5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.2.tgz#00d1c7c1c46928c5845c1ee8d0cc2791031d4c43" + integrity sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -14050,34 +14283,21 @@ vhost@^3.0.2: resolved "https://registry.yarnpkg.com/vhost/-/vhost-3.0.2.tgz#2fb1decd4c466aa88b0f9341af33dc1aff2478d5" integrity sha512-S3pJdWrpFWrKMboRU4dLYgMrTgoPALsmYwOvyebK2M6X95b9kQrjZy5rwl3uzzpfpENe/XrNYu/2U+e7/bmT5g== -vscode-jsonrpc@8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9" - integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ== - vscode-jsonrpc@8.2.0, vscode-jsonrpc@^8.0.2: version "8.2.0" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9" integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA== -vscode-languageclient@8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz#f1f23ce8c8484aa11e4b7dfb24437d3e59bb61c6" - integrity sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q== - dependencies: - minimatch "^3.0.4" - semver "^7.3.5" - vscode-languageserver-protocol "3.17.2" - -vscode-languageserver-protocol@3.17.2: - version "3.17.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz#beaa46aea06ed061576586c5e11368a9afc1d378" - integrity sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg== +vscode-languageclient@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz#cdfe20267726c8d4db839dc1e9d1816e1296e854" + integrity sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA== dependencies: - vscode-jsonrpc "8.0.2" - vscode-languageserver-types "3.17.2" + minimatch "^5.1.0" + semver "^7.3.7" + vscode-languageserver-protocol "3.17.5" -vscode-languageserver-protocol@^3.17.2, vscode-languageserver-protocol@^3.17.3: +vscode-languageserver-protocol@3.17.5, vscode-languageserver-protocol@^3.17.2, vscode-languageserver-protocol@^3.17.5: version "3.17.5" resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea" integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg== @@ -14085,27 +14305,22 @@ vscode-languageserver-protocol@^3.17.2, vscode-languageserver-protocol@^3.17.3: vscode-jsonrpc "8.2.0" vscode-languageserver-types "3.17.5" -vscode-languageserver-textdocument@^1.0.1, vscode-languageserver-textdocument@^1.0.8, vscode-languageserver-textdocument@~1.0.8: +vscode-languageserver-textdocument@^1.0.1, vscode-languageserver-textdocument@^1.0.11, vscode-languageserver-textdocument@~1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf" integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA== -vscode-languageserver-types@3.17.2: - version "3.17.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" - integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== - vscode-languageserver-types@3.17.5: version "3.17.5" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a" integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg== -vscode-languageserver@8.0.2, vscode-languageserver@~8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz#cfe2f0996d9dfd40d3854e786b2821604dfec06d" - integrity sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA== +vscode-languageserver@9.0.1, vscode-languageserver@~9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz#500aef82097eb94df90d008678b0b6b5f474015b" + integrity sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g== dependencies: - vscode-languageserver-protocol "3.17.2" + vscode-languageserver-protocol "3.17.5" vscode-oniguruma@1.6.1: version "1.6.1" @@ -14122,7 +14337,7 @@ vscode-uri@^2.1.1: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A== -vscode-uri@^3.0.2, vscode-uri@~3.0.7: +vscode-uri@^3.0.2, vscode-uri@~3.0.8: version "3.0.8" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== From 2c4dba640c63b2ec24cd8a4eb9cb3a1c9305b38c Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Fri, 24 Nov 2023 16:06:55 +0100 Subject: [PATCH 2/2] Improve Jest handling --- .vscode/settings.json | 3 +- .../cross-model-lang-diagram.test.ts | 238 ++++--- .../cross-model-lang-entity.test.ts | 128 ++-- .../cross-model-lang-relationship.test.ts | 62 +- .../lexer/cross-model-indent-stack.test.ts | 244 ++++--- .../cross-model-indentation-tokens.test.ts | 594 +++++++++--------- .../lexer/cross-model-lexer.test.ts | 122 ++-- .../lexer/cross-model-token-generator.test.ts | 82 ++- .../serializer/cross-model-serializer.test.ts | 428 +++++++------ .../language-server/util/name-util.test.ts | 42 +- .../test/model-server/model-server.test.ts | 22 +- package.json | 4 +- 12 files changed, 976 insertions(+), 993 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 23149689..d8e7408d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,5 +40,6 @@ "[yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "jest.jestCommandLine": "npm exec -- jest --config=configs/jest.config.js" + "jest.jestCommandLine": "yarn test", + "jest.debugMode": true } diff --git a/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts b/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts index d3e7c47a..a5c7b792 100644 --- a/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts +++ b/extensions/crossmodel-lang/test/language-server/cross-model-lang-diagram.test.ts @@ -1,7 +1,7 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, jest } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { EmptyFileSystem, isReference } from 'langium'; import { diagram1, diagram2, diagram3, diagram4, diagram5, diagram6 } from './test-utils/test-documents/diagram/index.js'; @@ -10,126 +10,124 @@ import { parseDocument } from './test-utils/utils.js'; import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; import { CrossModelRoot } from '../../src/language-server/generated/ast.js'; -jest.useFakeTimers(); - const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; describe('CrossModel language Diagram', () => { - describe('Diagram without nodes and edges', () => { - test('Simple file for diagram', async () => { - const document = diagram1; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('diagram'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.diagram?.name).toBe('Systemdiagram1'); - }); - - test('Diagram with indentation error', async () => { - const document = diagram4; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('diagram'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(1); - }); - }); - - describe('Diagram with nodes', () => { - test('Simple file for diagram and nodes', async () => { - const document = diagram2; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - const node1 = model.diagram?.nodes[0]; - - expect(model).toHaveProperty('diagram'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.diagram?.nodes.length).toBe(1); - - expect(node1?.name).toBe('CustomerNode'); - expect(isReference(node1?.entity)).toBe(true); - expect(node1?.entity?.$refText).toBe('Customer'); - expect(node1?.x).toBe(100); - }); - }); - - describe('Diagram with edges', () => { - test('Simple file for diagram and edges', async () => { - const document = diagram3; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - const edge1 = model.diagram?.edges[0]; - - expect(model).toHaveProperty('diagram'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.diagram?.edges.length).toBe(1); - - expect(edge1?.name).toBe('OrderCustomerEdge'); - expect(isReference(edge1?.relationship)).toBe(true); - expect(edge1?.relationship?.$refText).toBe('Order_Customer'); - }); - }); - - describe('Diagram with nodes and edges', () => { - test('Simple file for diagram and edges', async () => { - const document = diagram5; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - const node1 = model.diagram?.nodes[0]; - const edge1 = model.diagram?.edges[0]; - - expect(model).toHaveProperty('diagram'); - - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.diagram?.name_val).toBe('System diagram 1'); - expect(model.diagram?.description).toBe('This is a basic diagram with nodes and edges'); - expect(model.diagram?.nodes.length).toBe(1); - expect(model.diagram?.edges.length).toBe(1); - - expect(node1?.name).toBe('CustomerNode'); - expect(isReference(node1?.entity)).toBe(true); - expect(node1?.entity?.$refText).toBe('Customer'); - expect(node1?.x).toBe(100); - - expect(edge1?.name).toBe('OrderCustomerEdge'); - expect(isReference(edge1?.relationship)).toBe(true); - expect(edge1?.relationship?.$refText).toBe('Order_Customer'); - }); - - test('Simple file for diagram and edges, but descirption and name coming last', async () => { - const document = diagram6; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - const node1 = model.diagram?.nodes[0]; - const edge1 = model.diagram?.edges[0]; - - expect(model).toHaveProperty('diagram'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.diagram?.name_val).toBe('System diagram 1'); - expect(model.diagram?.description).toBe('This is a basic diagram with nodes and edges'); - expect(model.diagram?.nodes.length).toBe(1); - expect(model.diagram?.edges.length).toBe(1); - - expect(node1?.name).toBe('CustomerNode'); - expect(isReference(node1?.entity)).toBe(true); - expect(node1?.entity?.$refText).toBe('Customer'); - expect(node1?.x).toBe(100); - - expect(edge1?.name).toBe('OrderCustomerEdge'); - expect(isReference(edge1?.relationship)).toBe(true); - expect(edge1?.relationship?.$refText).toBe('Order_Customer'); - }); - }); + describe('Diagram without nodes and edges', () => { + test('Simple file for diagram', async () => { + const document = diagram1; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('diagram'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.diagram?.name).toBe('Systemdiagram1'); + }); + + test('Diagram with indentation error', async () => { + const document = diagram4; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('diagram'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(1); + }); + }); + + describe('Diagram with nodes', () => { + test('Simple file for diagram and nodes', async () => { + const document = diagram2; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + const node1 = model.diagram?.nodes[0]; + + expect(model).toHaveProperty('diagram'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.diagram?.nodes.length).toBe(1); + + expect(node1?.name).toBe('CustomerNode'); + expect(isReference(node1?.entity)).toBe(true); + expect(node1?.entity?.$refText).toBe('Customer'); + expect(node1?.x).toBe(100); + }); + }); + + describe('Diagram with edges', () => { + test('Simple file for diagram and edges', async () => { + const document = diagram3; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + const edge1 = model.diagram?.edges[0]; + + expect(model).toHaveProperty('diagram'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.diagram?.edges.length).toBe(1); + + expect(edge1?.name).toBe('OrderCustomerEdge'); + expect(isReference(edge1?.relationship)).toBe(true); + expect(edge1?.relationship?.$refText).toBe('Order_Customer'); + }); + }); + + describe('Diagram with nodes and edges', () => { + test('Simple file for diagram and edges', async () => { + const document = diagram5; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + const node1 = model.diagram?.nodes[0]; + const edge1 = model.diagram?.edges[0]; + + expect(model).toHaveProperty('diagram'); + + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.diagram?.name_val).toBe('System diagram 1'); + expect(model.diagram?.description).toBe('This is a basic diagram with nodes and edges'); + expect(model.diagram?.nodes.length).toBe(1); + expect(model.diagram?.edges.length).toBe(1); + + expect(node1?.name).toBe('CustomerNode'); + expect(isReference(node1?.entity)).toBe(true); + expect(node1?.entity?.$refText).toBe('Customer'); + expect(node1?.x).toBe(100); + + expect(edge1?.name).toBe('OrderCustomerEdge'); + expect(isReference(edge1?.relationship)).toBe(true); + expect(edge1?.relationship?.$refText).toBe('Order_Customer'); + }); + + test('Simple file for diagram and edges, but descirption and name coming last', async () => { + const document = diagram6; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + const node1 = model.diagram?.nodes[0]; + const edge1 = model.diagram?.edges[0]; + + expect(model).toHaveProperty('diagram'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.diagram?.name_val).toBe('System diagram 1'); + expect(model.diagram?.description).toBe('This is a basic diagram with nodes and edges'); + expect(model.diagram?.nodes.length).toBe(1); + expect(model.diagram?.edges.length).toBe(1); + + expect(node1?.name).toBe('CustomerNode'); + expect(isReference(node1?.entity)).toBe(true); + expect(node1?.entity?.$refText).toBe('Customer'); + expect(node1?.x).toBe(100); + + expect(edge1?.name).toBe('OrderCustomerEdge'); + expect(isReference(edge1?.relationship)).toBe(true); + expect(edge1?.relationship?.$refText).toBe('Order_Customer'); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts b/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts index a5a7eb50..796ea8de 100644 --- a/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts +++ b/extensions/crossmodel-lang/test/language-server/cross-model-lang-entity.test.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, jest } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { EmptyFileSystem } from 'langium'; import { parseDocument } from './test-utils/utils.js'; @@ -11,71 +11,69 @@ import { entity1, entity2, entity3, entity4 } from './test-utils/test-documents/ import { CrossModelRoot } from '../../src/language-server/generated/ast.js'; import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; -jest.useFakeTimers(); - const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; describe('CrossModel language Entity', () => { - describe('Without attributes', () => { - test('Simple file for entity', async () => { - const document = entity1; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('entity'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.entity?.name).toBe('Customer'); - expect(model.entity?.name_val).toBe('Customer'); - expect(model.entity?.description).toBe('A customer with whom a transaction has been made.'); - }); - }); - - describe('With attributes', () => { - test('entity with attributes', async () => { - const document = entity2; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('entity'); - - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.entity?.attributes.length).toBe(6); - expect(model.entity?.attributes[0].name).toBe('Id'); - expect(model.entity?.attributes[0].name_val).toBe('Id'); - expect(model.entity?.attributes[0].datatype).toBe('int'); - }); - - test('entity with attributes coming before the description and name', async () => { - const document = entity4; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('entity'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.entity?.name).toBe('Customer'); - expect(model.entity?.name_val).toBe('Customer'); - expect(model.entity?.description).toBe('A customer with whom a transaction has been made.'); - - expect(model.entity?.attributes.length).toBe(6); - expect(model.entity?.attributes[0].name).toBe('Id'); - expect(model.entity?.attributes[0].name_val).toBe('Id'); - expect(model.entity?.attributes[0].datatype).toBe('int'); - }); - - test('entity with indentation error', async () => { - const document = entity3; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('entity'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(1); - }); - }); + describe('Without attributes', () => { + test('Simple file for entity', async () => { + const document = entity1; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('entity'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.entity?.name).toBe('Customer'); + expect(model.entity?.name_val).toBe('Customer'); + expect(model.entity?.description).toBe('A customer with whom a transaction has been made.'); + }); + }); + + describe('With attributes', () => { + test('entity with attributes', async () => { + const document = entity2; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('entity'); + + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.entity?.attributes.length).toBe(6); + expect(model.entity?.attributes[0].name).toBe('Id'); + expect(model.entity?.attributes[0].name_val).toBe('Id'); + expect(model.entity?.attributes[0].datatype).toBe('int'); + }); + + test('entity with attributes coming before the description and name', async () => { + const document = entity4; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('entity'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.entity?.name).toBe('Customer'); + expect(model.entity?.name_val).toBe('Customer'); + expect(model.entity?.description).toBe('A customer with whom a transaction has been made.'); + + expect(model.entity?.attributes.length).toBe(6); + expect(model.entity?.attributes[0].name).toBe('Id'); + expect(model.entity?.attributes[0].name_val).toBe('Id'); + expect(model.entity?.attributes[0].datatype).toBe('int'); + }); + + test('entity with indentation error', async () => { + const document = entity3; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('entity'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(1); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts b/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts index f5f761d9..5d030ba1 100644 --- a/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts +++ b/extensions/crossmodel-lang/test/language-server/cross-model-lang-relationship.test.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, jest } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { EmptyFileSystem, isReference } from 'langium'; import { parseDocument } from './test-utils/utils.js'; @@ -11,38 +11,36 @@ import { relationship1, relationship2 } from './test-utils/test-documents/relati import { CrossModelRoot } from '../../src/language-server/generated/ast.js'; import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; -jest.useFakeTimers(); - const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; describe('CrossModel language Relationship', () => { - test('Simple file for relationship', async () => { - const document = relationship1; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('relationship'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(0); - - expect(model.relationship?.name).toBe('Order_Customer'); - expect(model.relationship?.name_val).toBe('Customer Order relationship'); - expect(model.relationship?.type).toBe('1:1'); - expect(model.relationship?.description).toBe('A relationship between a customer and an order.'); - - expect(isReference(model.relationship?.parent)).toBe(true); - expect(isReference(model.relationship?.child)).toBe(true); - expect(model.relationship?.parent?.$refText).toBe('Customer'); - expect(model.relationship?.child?.$refText).toBe('Order'); - }); - - test('relationship with indentation error', async () => { - const document = relationship2; - const parsedDocument = await parseDocument(services, document); - const model = parsedDocument.parseResult.value as CrossModelRoot; - - expect(model).toHaveProperty('relationship'); - expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); - expect(parsedDocument.parseResult.parserErrors.length).toBe(1); - }); + test('Simple file for relationship', async () => { + const document = relationship1; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('relationship'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(0); + + expect(model.relationship?.name).toBe('Order_Customer'); + expect(model.relationship?.name_val).toBe('Customer Order relationship'); + expect(model.relationship?.type).toBe('1:1'); + expect(model.relationship?.description).toBe('A relationship between a customer and an order.'); + + expect(isReference(model.relationship?.parent)).toBe(true); + expect(isReference(model.relationship?.child)).toBe(true); + expect(model.relationship?.parent?.$refText).toBe('Customer'); + expect(model.relationship?.child?.$refText).toBe('Order'); + }); + + test('relationship with indentation error', async () => { + const document = relationship2; + const parsedDocument = await parseDocument(services, document); + const model = parsedDocument.parseResult.value as CrossModelRoot; + + expect(model).toHaveProperty('relationship'); + expect(parsedDocument.parseResult.lexerErrors.length).toBe(0); + expect(parsedDocument.parseResult.parserErrors.length).toBe(1); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts index f8d1ea06..725d75de 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indent-stack.test.ts @@ -2,130 +2,128 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeEach, jest } from '@jest/globals'; +import { describe, expect, test, beforeEach } from '@jest/globals'; import { indentStack } from '../../../src/language-server/lexer/cross-model-indent-stack.js'; -jest.useFakeTimers(); - describe('IndentStack', () => { - beforeEach(() => { - indentStack.reset(); - }); - - describe('get', () => { - test('should return a copy of the current stack', () => { - indentStack.push(2); - indentStack.push(4); - - const stack = indentStack.get(); - - expect(stack).toEqual([0, 2, 4]); - }); - - test('should return an [0] if the stack is empty', () => { - const stack = indentStack.get(); - - expect(stack).toEqual([0]); - }); - - test('should not modify the original stack when modifying the returned array', () => { - indentStack.push(2); - indentStack.push(4); - - const stack = indentStack.get(); - stack.pop(); // Modify the returned array - - expect(stack).toEqual([0, 2]); // The returned array is modified - expect(indentStack.get()).toEqual([0, 2, 4]); // The original stack remains unchanged - }); - }); - - describe('push', () => { - test('should push the given value onto the stack', () => { - indentStack.push(2); - expect(indentStack.get()).toEqual([0, 2]); - }); - - test('should push multiple values onto the stack', () => { - indentStack.push(2); - indentStack.push(4); - indentStack.push(6); - expect(indentStack.get()).toEqual([0, 2, 4, 6]); - }); - }); - - describe('reset', () => { - test('should reset the stack to contain only the initial indentation level', () => { - indentStack.push(2); - indentStack.push(4); - indentStack.reset(); - expect(indentStack.get()).toEqual([0]); - }); - }); - - describe('pop', () => { - test('should remove and return the topmost indentation level from the stack', () => { - indentStack.push(2); - - const poppedValue = indentStack.pop(); - - expect(poppedValue).toBe(2); - expect(indentStack.get()).toEqual([0]); - }); - - test('should return undefined if the stack is empty', () => { - // Pop 0 after reset - const poppedValue1 = indentStack.pop(); - const poppedValue2 = indentStack.pop(); - - expect(poppedValue1).toBe(0); - expect(poppedValue2).toBeUndefined(); - }); - }); - - describe('length', () => { - test('should return 1 when only the initial indentation level is present', () => { - expect(indentStack.length()).toBe(1); - }); - - test('should return the length of indentation levels in the stack', () => { - indentStack.push(2); - indentStack.push(4); - expect(indentStack.length()).toBe(3); - }); - }); - - describe('getLast', () => { - test('should return the last indentation level from the stack', () => { - indentStack.push(2); - indentStack.push(4); - - const lastValue = indentStack.getLast(); - - expect(lastValue).toBe(4); - }); - - test('should throw an IndentStackError if the stack is empty', () => { - indentStack.pop(); - - expect(() => indentStack.getLast()).toThrow(); - }); - }); - - describe('findLastIndex', () => { - test('should return the index of the last occurrence of the given value in the stack', () => { - indentStack.push(2); - indentStack.push(4); - indentStack.push(2); - - const lastIndex = indentStack.findLastIndex(2); - - expect(lastIndex).toBe(3); - }); - - test('should return -1 if the given value is not found in the stack', () => { - const lastIndex = indentStack.findLastIndex(2); - expect(lastIndex).toBe(-1); - }); - }); + beforeEach(() => { + indentStack.reset(); + }); + + describe('get', () => { + test('should return a copy of the current stack', () => { + indentStack.push(2); + indentStack.push(4); + + const stack = indentStack.get(); + + expect(stack).toEqual([0, 2, 4]); + }); + + test('should return an [0] if the stack is empty', () => { + const stack = indentStack.get(); + + expect(stack).toEqual([0]); + }); + + test('should not modify the original stack when modifying the returned array', () => { + indentStack.push(2); + indentStack.push(4); + + const stack = indentStack.get(); + stack.pop(); // Modify the returned array + + expect(stack).toEqual([0, 2]); // The returned array is modified + expect(indentStack.get()).toEqual([0, 2, 4]); // The original stack remains unchanged + }); + }); + + describe('push', () => { + test('should push the given value onto the stack', () => { + indentStack.push(2); + expect(indentStack.get()).toEqual([0, 2]); + }); + + test('should push multiple values onto the stack', () => { + indentStack.push(2); + indentStack.push(4); + indentStack.push(6); + expect(indentStack.get()).toEqual([0, 2, 4, 6]); + }); + }); + + describe('reset', () => { + test('should reset the stack to contain only the initial indentation level', () => { + indentStack.push(2); + indentStack.push(4); + indentStack.reset(); + expect(indentStack.get()).toEqual([0]); + }); + }); + + describe('pop', () => { + test('should remove and return the topmost indentation level from the stack', () => { + indentStack.push(2); + + const poppedValue = indentStack.pop(); + + expect(poppedValue).toBe(2); + expect(indentStack.get()).toEqual([0]); + }); + + test('should return undefined if the stack is empty', () => { + // Pop 0 after reset + const poppedValue1 = indentStack.pop(); + const poppedValue2 = indentStack.pop(); + + expect(poppedValue1).toBe(0); + expect(poppedValue2).toBeUndefined(); + }); + }); + + describe('length', () => { + test('should return 1 when only the initial indentation level is present', () => { + expect(indentStack.length()).toBe(1); + }); + + test('should return the length of indentation levels in the stack', () => { + indentStack.push(2); + indentStack.push(4); + expect(indentStack.length()).toBe(3); + }); + }); + + describe('getLast', () => { + test('should return the last indentation level from the stack', () => { + indentStack.push(2); + indentStack.push(4); + + const lastValue = indentStack.getLast(); + + expect(lastValue).toBe(4); + }); + + test('should throw an IndentStackError if the stack is empty', () => { + indentStack.pop(); + + expect(() => indentStack.getLast()).toThrow(); + }); + }); + + describe('findLastIndex', () => { + test('should return the index of the last occurrence of the given value in the stack', () => { + indentStack.push(2); + indentStack.push(4); + indentStack.push(2); + + const lastIndex = indentStack.findLastIndex(2); + + expect(lastIndex).toBe(3); + }); + + test('should return -1 if the given value is not found in the stack', () => { + const lastIndex = indentStack.findLastIndex(2); + expect(lastIndex).toBe(-1); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts index 981f5887..8b4dbb08 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-indentation-tokens.test.ts @@ -1,308 +1,306 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeEach, beforeAll, jest } from '@jest/globals'; +import { describe, expect, test, beforeEach, beforeAll } from '@jest/globals'; import { Lexer, TokenType, createToken, tokenMatcher } from 'chevrotain'; import { SPACES, NEWLINE, INDENT, DEDENT } from '../../../src/language-server/lexer/cross-model-indentation-tokens.js'; import { indentStack } from '../../../src/language-server/lexer/cross-model-indent-stack.js'; -jest.useFakeTimers(); - describe('matchIndentBase', () => { - let TESTTOKEN: TokenType; - let LINETOKEN: TokenType; - let testLexer: Lexer; - - beforeAll(() => { - TESTTOKEN = createToken({ - name: 'TESTTOKEN', - pattern: /TESTTOKEN/ - }); - - LINETOKEN = createToken({ - name: 'LINETOKEN', - pattern: /-/ - }); - - testLexer = new Lexer([NEWLINE, DEDENT, INDENT, LINETOKEN, TESTTOKEN, SPACES]); - }); - - beforeEach(() => { - indentStack.reset(); - }); - - describe('SPACES token', () => { - test('should not produce a token for spaces between words', () => { - const input = 'TESTTOKEN TESTTOKEN'; - - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - lexResult.tokens.map(token => { - expect(tokenMatcher(token, TESTTOKEN)).toBe(true); - }); - }); - - test('should not produce a token for spaces at the end of a line', () => { - const input = 'TESTTOKEN '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(1); - lexResult.tokens.map(token => { - expect(tokenMatcher(token, TESTTOKEN)).toBe(true); - }); - }); - }); - - describe('NEWLINE token', () => { - test('should match a newline character', () => { - const input = '\n'; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(0); - expect(lexResult.groups).toHaveProperty('nl'); - expect(lexResult.groups.nl).toHaveLength(1); - expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); - }); - - test('should match a newline character with carriage return', () => { - const input = '\r\n'; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(0); - expect(lexResult.groups).toHaveProperty('nl'); - expect(lexResult.groups.nl).toHaveLength(1); - expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); - }); - - test('should match a newline in the middle of a line', () => { - const input = 'TESTTOKEN\nTESTTOKEN'; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - expect(tokenMatcher(lexResult.tokens[0], TESTTOKEN)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], TESTTOKEN)).toBe(true); - - expect(lexResult.groups).toHaveProperty('nl'); - expect(lexResult.groups.nl).toHaveLength(1); - expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); - }); - - test('should match a newline preceded by spaces', () => { - const input = ' \n'; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.groups).toHaveProperty('nl'); - expect(lexResult.groups.nl).toHaveLength(1); - expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); - expect(lexResult.groups.nl[0].image).toBe('\n'); - }); - - test('should match a newline followed by spaces', () => { - const input = '\n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.groups).toHaveProperty('nl'); - expect(lexResult.groups.nl).toHaveLength(1); - expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); - expect(lexResult.groups.nl[0].image).toBe('\n'); - }); - }); - - describe('INDENT token', () => { - test('should match indentation at the start of a line', () => { - const input = ' '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(1); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(lexResult.tokens[0].image).toBe(input); - expect(indentStack.getLast()).toBe(4); - }); - - test('should match indentation at the start of a line, when there are other token after it', () => { - const input = ' TESTTOKEN'; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], TESTTOKEN)).toBe(true); - expect(lexResult.tokens[0].image).toBe(' '); - // Check what the current indentation is - expect(indentStack.getLast()).toBe(4); - }); - - test('should match indentation at the start of a line', () => { - const input = 'TESTTOKEN\n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - expect(tokenMatcher(lexResult.tokens[0], TESTTOKEN)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(lexResult.tokens[1].image).toBe(' '); - // Check what the current indentation is - expect(indentStack.getLast()).toBe(4); - }); - - test('should match indentation when only new lines preceding', () => { - const input = '\n\n\n\n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(1); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(lexResult.tokens[0].image).toBe(' '); - expect(indentStack.getLast()).toBe(4); - expect(lexResult.groups.nl).toHaveLength(4); - }); - - test('Should only match follow up indentation', () => { - const input = ' \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - expect(lexResult.groups.nl).toHaveLength(1); - - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(lexResult.tokens[1].image).toBe(' '); - expect(indentStack.getLast()).toBe(6); - }); - - // Should not match - test('should not match indentation after another token', () => { - const input = 'TESTTOKEN '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(1); - expect(tokenMatcher(lexResult.tokens[0], TESTTOKEN)).toBe(true); - expect(indentStack.getLast()).toBe(0); - }); - - test('Should not match sucessive same indentation level', () => { - const input = ' \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(1); - expect(lexResult.groups.nl).toHaveLength(1); - - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(lexResult.tokens[0].image).toBe(' '); - expect(indentStack.getLast()).toBe(4); - }); - - test('Should not match lower indentation', () => { - const input = ' \n \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(3); - expect(lexResult.groups.nl).toHaveLength(2); - - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(lexResult.tokens[1].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); - expect(indentStack.getLast()).toBe(2); - }); - }); - - describe('INDENT token and lists(-)', () => { - test('should match a single level of indentation at the start of a line with -', () => { - const input = ' - '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], LINETOKEN)).toBe(true); - expect(indentStack.getLast()).toBe(6); - }); - - test('should match a indentation after indentation with -', () => { - const input = ' - \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(3); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - - expect(tokenMatcher(lexResult.tokens[1], LINETOKEN)).toBe(true); - - expect(lexResult.tokens[2].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[2], INDENT)).toBe(true); - expect(indentStack.getLast()).toBe(8); - }); - - test('should match a dedentation after indentation with -', () => { - const input = ' \n - \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(4); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(lexResult.tokens[1].image).toBe(' '); - - expect(tokenMatcher(lexResult.tokens[2], LINETOKEN)).toBe(true); - - expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); - expect(indentStack.getLast()).toBe(2); - }); - - test('should not match second indentation with same level', () => { - const input = ' - \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(2); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], LINETOKEN)).toBe(true); - expect(indentStack.getLast()).toBe(6); - }); - }); - - describe('DEDENT token', () => { - test('should match a dedentation', () => { - const input = ' \n \n '; - - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(3); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(lexResult.tokens[1].image).toBe(' '); - - expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); - expect(indentStack.getLast()).toBe(2); - }); - - test('should match a dedentation after dedentation', () => { - const input = ' \n \n \n \n '; - - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(5); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[2], INDENT)).toBe(true); - - expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[4], DEDENT)).toBe(true); - expect(indentStack.getLast()).toBe(2); - }); - - test('should not match a dedentation whens on the same level', () => { - const input = ' \n '; - const lexResult = testLexer.tokenize(input); - - expect(lexResult.tokens).toHaveLength(1); - expect(lexResult.tokens[0].image).toBe(' '); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - }); - }); + let TESTTOKEN: TokenType; + let LINETOKEN: TokenType; + let testLexer: Lexer; + + beforeAll(() => { + TESTTOKEN = createToken({ + name: 'TESTTOKEN', + pattern: /TESTTOKEN/ + }); + + LINETOKEN = createToken({ + name: 'LINETOKEN', + pattern: /-/ + }); + + testLexer = new Lexer([NEWLINE, DEDENT, INDENT, LINETOKEN, TESTTOKEN, SPACES]); + }); + + beforeEach(() => { + indentStack.reset(); + }); + + describe('SPACES token', () => { + test('should not produce a token for spaces between words', () => { + const input = 'TESTTOKEN TESTTOKEN'; + + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + lexResult.tokens.map(token => { + expect(tokenMatcher(token, TESTTOKEN)).toBe(true); + }); + }); + + test('should not produce a token for spaces at the end of a line', () => { + const input = 'TESTTOKEN '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(1); + lexResult.tokens.map(token => { + expect(tokenMatcher(token, TESTTOKEN)).toBe(true); + }); + }); + }); + + describe('NEWLINE token', () => { + test('should match a newline character', () => { + const input = '\n'; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(0); + expect(lexResult.groups).toHaveProperty('nl'); + expect(lexResult.groups.nl).toHaveLength(1); + expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); + }); + + test('should match a newline character with carriage return', () => { + const input = '\r\n'; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(0); + expect(lexResult.groups).toHaveProperty('nl'); + expect(lexResult.groups.nl).toHaveLength(1); + expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); + }); + + test('should match a newline in the middle of a line', () => { + const input = 'TESTTOKEN\nTESTTOKEN'; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + expect(tokenMatcher(lexResult.tokens[0], TESTTOKEN)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], TESTTOKEN)).toBe(true); + + expect(lexResult.groups).toHaveProperty('nl'); + expect(lexResult.groups.nl).toHaveLength(1); + expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); + }); + + test('should match a newline preceded by spaces', () => { + const input = ' \n'; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.groups).toHaveProperty('nl'); + expect(lexResult.groups.nl).toHaveLength(1); + expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); + expect(lexResult.groups.nl[0].image).toBe('\n'); + }); + + test('should match a newline followed by spaces', () => { + const input = '\n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.groups).toHaveProperty('nl'); + expect(lexResult.groups.nl).toHaveLength(1); + expect(tokenMatcher(lexResult.groups.nl[0], NEWLINE)).toBe(true); + expect(lexResult.groups.nl[0].image).toBe('\n'); + }); + }); + + describe('INDENT token', () => { + test('should match indentation at the start of a line', () => { + const input = ' '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(1); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(lexResult.tokens[0].image).toBe(input); + expect(indentStack.getLast()).toBe(4); + }); + + test('should match indentation at the start of a line, when there are other token after it', () => { + const input = ' TESTTOKEN'; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], TESTTOKEN)).toBe(true); + expect(lexResult.tokens[0].image).toBe(' '); + // Check what the current indentation is + expect(indentStack.getLast()).toBe(4); + }); + + test('should match indentation at the start of a line', () => { + const input = 'TESTTOKEN\n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + expect(tokenMatcher(lexResult.tokens[0], TESTTOKEN)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(lexResult.tokens[1].image).toBe(' '); + // Check what the current indentation is + expect(indentStack.getLast()).toBe(4); + }); + + test('should match indentation when only new lines preceding', () => { + const input = '\n\n\n\n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(1); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(lexResult.tokens[0].image).toBe(' '); + expect(indentStack.getLast()).toBe(4); + expect(lexResult.groups.nl).toHaveLength(4); + }); + + test('Should only match follow up indentation', () => { + const input = ' \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + expect(lexResult.groups.nl).toHaveLength(1); + + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(lexResult.tokens[1].image).toBe(' '); + expect(indentStack.getLast()).toBe(6); + }); + + // Should not match + test('should not match indentation after another token', () => { + const input = 'TESTTOKEN '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(1); + expect(tokenMatcher(lexResult.tokens[0], TESTTOKEN)).toBe(true); + expect(indentStack.getLast()).toBe(0); + }); + + test('Should not match sucessive same indentation level', () => { + const input = ' \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(1); + expect(lexResult.groups.nl).toHaveLength(1); + + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(lexResult.tokens[0].image).toBe(' '); + expect(indentStack.getLast()).toBe(4); + }); + + test('Should not match lower indentation', () => { + const input = ' \n \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(3); + expect(lexResult.groups.nl).toHaveLength(2); + + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(lexResult.tokens[1].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); + expect(indentStack.getLast()).toBe(2); + }); + }); + + describe('INDENT token and lists(-)', () => { + test('should match a single level of indentation at the start of a line with -', () => { + const input = ' - '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], LINETOKEN)).toBe(true); + expect(indentStack.getLast()).toBe(6); + }); + + test('should match a indentation after indentation with -', () => { + const input = ' - \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(3); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + + expect(tokenMatcher(lexResult.tokens[1], LINETOKEN)).toBe(true); + + expect(lexResult.tokens[2].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[2], INDENT)).toBe(true); + expect(indentStack.getLast()).toBe(8); + }); + + test('should match a dedentation after indentation with -', () => { + const input = ' \n - \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(4); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(lexResult.tokens[1].image).toBe(' '); + + expect(tokenMatcher(lexResult.tokens[2], LINETOKEN)).toBe(true); + + expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); + expect(indentStack.getLast()).toBe(2); + }); + + test('should not match second indentation with same level', () => { + const input = ' - \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(2); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], LINETOKEN)).toBe(true); + expect(indentStack.getLast()).toBe(6); + }); + }); + + describe('DEDENT token', () => { + test('should match a dedentation', () => { + const input = ' \n \n '; + + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(3); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(lexResult.tokens[1].image).toBe(' '); + + expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); + expect(indentStack.getLast()).toBe(2); + }); + + test('should match a dedentation after dedentation', () => { + const input = ' \n \n \n \n '; + + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(5); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[2], INDENT)).toBe(true); + + expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[4], DEDENT)).toBe(true); + expect(indentStack.getLast()).toBe(2); + }); + + test('should not match a dedentation whens on the same level', () => { + const input = ' \n '; + const lexResult = testLexer.tokenize(input); + + expect(lexResult.tokens).toHaveLength(1); + expect(lexResult.tokens[0].image).toBe(' '); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts index 1079c09e..9ec43843 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-lexer.test.ts @@ -2,96 +2,94 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeAll, jest } from '@jest/globals'; +import { describe, expect, test, beforeAll } from '@jest/globals'; import { EmptyFileSystem } from 'langium'; import { tokenMatcher } from 'chevrotain'; -import { CrossModelLexer } from '../../../src/language-server/lexer/cross-model-lexer'; -import { DEDENT, INDENT } from '../../../src/language-server/lexer/cross-model-indentation-tokens'; -import { createCrossModelServices } from '../../../src/language-server/cross-model-module'; - -jest.useFakeTimers(); +import { CrossModelLexer } from '../../../src/language-server/lexer/cross-model-lexer.js'; +import { DEDENT, INDENT } from '../../../src/language-server/lexer/cross-model-indentation-tokens.js'; +import { createCrossModelServices } from '../../../src/language-server/cross-model-module.js'; const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; describe('CrossModelLexer', () => { - let crossModelLexer: CrossModelLexer; + let crossModelLexer: CrossModelLexer; - beforeAll(() => { - crossModelLexer = new CrossModelLexer(services); - }); + beforeAll(() => { + crossModelLexer = new CrossModelLexer(services); + }); - describe('Simple keywords', () => { - test('should tokenize a simple word', () => { - const input = 'entity'; + describe('Simple keywords', () => { + test('should tokenize a simple word', () => { + const input = 'entity'; - const lexResult = crossModelLexer.tokenize(input); + const lexResult = crossModelLexer.tokenize(input); - expect(lexResult.tokens).toHaveLength(1); - lexResult.tokens.map(token => { - expect(token.image).toBe('entity'); - }); - }); + expect(lexResult.tokens).toHaveLength(1); + lexResult.tokens.map(token => { + expect(token.image).toBe('entity'); + }); + }); - test('should tokenize a couple of simple words', () => { - const input = 'entity entity entity'; + test('should tokenize a couple of simple words', () => { + const input = 'entity entity entity'; - const lexResult = crossModelLexer.tokenize(input); + const lexResult = crossModelLexer.tokenize(input); - expect(lexResult.tokens).toHaveLength(3); - lexResult.tokens.map(token => { - expect(token.image).toBe('entity'); - }); - }); - }); + expect(lexResult.tokens).toHaveLength(3); + lexResult.tokens.map(token => { + expect(token.image).toBe('entity'); + }); + }); + }); - describe('Indentation', () => { - test('Simple indentation, should give indent and dedent token', () => { - const input = ' '; + describe('Indentation', () => { + test('Simple indentation, should give indent and dedent token', () => { + const input = ' '; - const lexResult = crossModelLexer.tokenize(input); + const lexResult = crossModelLexer.tokenize(input); - expect(lexResult.tokens).toHaveLength(2); + expect(lexResult.tokens).toHaveLength(2); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], DEDENT)).toBe(true); - }); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], DEDENT)).toBe(true); + }); - test('single indentation but stay on same level, should give 1 indent and 1 dedent token', () => { - const input = ' \n '; + test('single indentation but stay on same level, should give 1 indent and 1 dedent token', () => { + const input = ' \n '; - const lexResult = crossModelLexer.tokenize(input); + const lexResult = crossModelLexer.tokenize(input); - expect(lexResult.tokens).toHaveLength(2); + expect(lexResult.tokens).toHaveLength(2); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], DEDENT)).toBe(true); - }); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], DEDENT)).toBe(true); + }); - test('double indentation, should give indent and dedent token', () => { - const input = ' \n '; + test('double indentation, should give indent and dedent token', () => { + const input = ' \n '; - const lexResult = crossModelLexer.tokenize(input); + const lexResult = crossModelLexer.tokenize(input); - expect(lexResult.tokens).toHaveLength(4); + expect(lexResult.tokens).toHaveLength(4); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); - }); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); + }); - test('double indentation, but dedent in text', () => { - const input = ' \n \n '; + test('double indentation, but dedent in text', () => { + const input = ' \n \n '; - const lexResult = crossModelLexer.tokenize(input); + const lexResult = crossModelLexer.tokenize(input); - expect(lexResult.tokens).toHaveLength(4); + expect(lexResult.tokens).toHaveLength(4); - expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); - expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); - }); - }); + expect(tokenMatcher(lexResult.tokens[0], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[1], INDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[2], DEDENT)).toBe(true); + expect(tokenMatcher(lexResult.tokens[3], DEDENT)).toBe(true); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts index 4cb050ba..f7dd4e27 100644 --- a/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts +++ b/extensions/crossmodel-lang/test/language-server/lexer/cross-model-token-generator.test.ts @@ -2,64 +2,62 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, beforeAll, jest } from '@jest/globals'; +import { describe, expect, test, beforeAll } from '@jest/globals'; import { Grammar } from 'langium'; import { TokenType } from 'chevrotain'; -import { DEDENT, INDENT, NEWLINE, SPACES } from '../../../src/language-server/lexer/cross-model-indentation-tokens'; -import { CrossModelTokenBuilder } from '../../../src/language-server/lexer/cross-model-token-generator'; -import { CrossModelGrammar } from '../../../src/language-server/generated/grammar'; +import { DEDENT, INDENT, NEWLINE, SPACES } from '../../../src/language-server/lexer/cross-model-indentation-tokens.js'; +import { CrossModelTokenBuilder } from '../../../src/language-server/lexer/cross-model-token-generator.js'; +import { CrossModelGrammar } from '../../../src/language-server/generated/grammar.js'; import _ from 'lodash'; -jest.useFakeTimers(); - describe('CrossModelTokenBuilder', () => { - let tokenBuilder: CrossModelTokenBuilder; - let crossModelGrammer: Grammar; - let crossModelGrammerWithoutIndentation: Grammar; + let tokenBuilder: CrossModelTokenBuilder; + let crossModelGrammer: Grammar; + let crossModelGrammerWithoutIndentation: Grammar; - beforeAll(() => { - tokenBuilder = new CrossModelTokenBuilder(); - crossModelGrammer = CrossModelGrammar(); - // CrossModelGrammar loads the grammar in memory instead of making a new grammar - crossModelGrammerWithoutIndentation = _.cloneDeep(crossModelGrammer); + beforeAll(() => { + tokenBuilder = new CrossModelTokenBuilder(); + crossModelGrammer = CrossModelGrammar(); + // CrossModelGrammar loads the grammar in memory instead of making a new grammar + crossModelGrammerWithoutIndentation = _.cloneDeep(crossModelGrammer); - crossModelGrammerWithoutIndentation.rules = crossModelGrammerWithoutIndentation.rules.filter( - rule => ![DEDENT.name, INDENT.name, NEWLINE.name, SPACES.name].includes(rule.name) - ); - }); + crossModelGrammerWithoutIndentation.rules = crossModelGrammerWithoutIndentation.rules.filter( + rule => ![DEDENT.name, INDENT.name, NEWLINE.name, SPACES.name].includes(rule.name) + ); + }); - describe('buildTokens', () => { - test('Should give NEWLINE token in first spot', () => { - const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; + describe('buildTokens', () => { + test('Should give NEWLINE token in first spot', () => { + const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; - expect(tokens[0]).toBe(NEWLINE); - }); + expect(tokens[0]).toBe(NEWLINE); + }); - test('Should give DEDENT token in second spot', () => { - const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; + test('Should give DEDENT token in second spot', () => { + const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; - expect(tokens[1]).toBe(DEDENT); - }); + expect(tokens[1]).toBe(DEDENT); + }); - test('Should give INDENT token in third spot', () => { - const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; + test('Should give INDENT token in third spot', () => { + const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; - expect(tokens[2]).toBe(INDENT); - }); + expect(tokens[2]).toBe(INDENT); + }); - test('Should give SPACE token in last spot', () => { - const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; + test('Should give SPACE token in last spot', () => { + const tokens = tokenBuilder.buildTokens(crossModelGrammer) as TokenType[]; - const spaceToken = tokens.pop(); - expect(spaceToken).toBe(SPACES); - }); + const spaceToken = tokens.pop(); + expect(spaceToken).toBe(SPACES); + }); - test('Should throw error when missing indentation in grammar', () => { - expect(() => { - tokenBuilder.buildTokens(crossModelGrammerWithoutIndentation) as TokenType[]; - }).toThrow(new Error('Missing indentation, new line or spaces tokens in grammar')); - }); - }); + test('Should throw error when missing indentation in grammar', () => { + expect(() => { + tokenBuilder.buildTokens(crossModelGrammerWithoutIndentation) as TokenType[]; + }).toThrow(new Error('Missing indentation, new line or spaces tokens in grammar')); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts b/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts index 56159460..dbcc2320 100644 --- a/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts +++ b/extensions/crossmodel-lang/test/language-server/serializer/cross-model-serializer.test.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { beforeAll, describe, expect, test, jest } from '@jest/globals'; +import { beforeAll, describe, expect, test } from '@jest/globals'; import { EmptyFileSystem, Reference } from 'langium'; import _ from 'lodash'; @@ -10,223 +10,221 @@ import { createCrossModelServices } from '../../../src/language-server/cross-mod import { CrossModelSerializer } from '../../../src/language-server/cross-model-serializer.js'; import { CrossModelRoot, Entity, Relationship } from '../../../src/language-server/generated/ast.js'; -jest.useFakeTimers(); - const services = createCrossModelServices({ ...EmptyFileSystem }).CrossModel; describe('CrossModelLexer', () => { - let serializer: CrossModelSerializer; - - beforeAll(() => { - serializer = new CrossModelSerializer(services); - }); - - describe('Serialize entity', () => { - let crossModelRoot: CrossModelRoot; - let crossModelRootwithoutAttributes: CrossModelRoot; - let crossModelRootwithAttributesDifPlace: CrossModelRoot; - - beforeAll(() => { - crossModelRoot = { - $type: 'CrossModelRoot' - }; - - crossModelRootwithAttributesDifPlace = _.cloneDeep(crossModelRoot); - - crossModelRoot.entity = { - $container: crossModelRoot, - $type: 'Entity', - description: 'Test description', - name: 'test id', - name_val: 'test Name', - attributes: [] - }; - - crossModelRootwithoutAttributes = _.cloneDeep(crossModelRoot); - - crossModelRoot.entity.attributes = [ - { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 1', datatype: 'Datatype Attribute 1' }, - { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 2', datatype: 'Datatype Attribute 2' } - ]; - - crossModelRootwithAttributesDifPlace.entity = { - $container: crossModelRoot, - $type: 'Entity', - description: 'Test description', - attributes: [], - name: 'test id', - name_val: 'test Name' - }; - crossModelRootwithAttributesDifPlace.entity.attributes = [ - { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 1', datatype: 'Datatype Attribute 1' }, - { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 2', datatype: 'Datatype Attribute 2' } - ]; - }); - - test('serialize entity with attributes', () => { - const parseResult = serializer.serialize(crossModelRoot); - expect(parseResult).toBe(expected_result); - }); - - test('serialize entity without attributes', () => { - const parseResult = serializer.serialize(crossModelRootwithoutAttributes); - - expect(parseResult).toBe(expected_result2); - }); - - test('serialize entity with attributes in different place', () => { - const parseResult = serializer.serialize(crossModelRootwithAttributesDifPlace); - - expect(parseResult).toBe(expected_result3); - }); - }); - - describe('Serialize relationship', () => { - let crossModelRoot: CrossModelRoot; - - beforeAll(() => { - crossModelRoot = { - $type: 'CrossModelRoot' - }; - - const ref1: Reference = { - $refText: 'Ref1', - ref: { - $container: crossModelRoot, - $type: 'Entity', - description: 'Test description', - attributes: [], - name: 'Ref1', - name_val: 'test Name' - } - }; - - const ref2: Reference = { - $refText: 'Ref2', - ref: { - $container: crossModelRoot, - $type: 'Entity', - description: 'Test description', - attributes: [], - name: 'Ref2', - name_val: 'test Name' - } - }; - - crossModelRoot.relationship = { - $container: crossModelRoot, - $type: 'Relationship', - description: 'Test description', - name: 'test id', - name_val: 'test Name', - parent: ref1, - child: ref2, - type: 'n:m' - }; - }); - - test('serialize entity with attributes', () => { - const parseResult = serializer.serialize(crossModelRoot); - expect(parseResult).toBe(expected_result4); - }); - }); - - describe('Serialize diagram', () => { - let crossModelRoot: CrossModelRoot; - - beforeAll(() => { - crossModelRoot = { - $type: 'CrossModelRoot' - }; - - const ref1: Reference = { - $refText: 'Ref1', - ref: { - $container: crossModelRoot, - $type: 'Entity', - description: 'Test description', - attributes: [], - name: 'Ref1', - name_val: 'test Name' - } - }; - - const ref2: Reference = { - $refText: 'Ref2', - ref: { - $container: crossModelRoot, - $type: 'Entity', - description: 'Test description', - attributes: [], - name: 'Ref2', - name_val: 'test Name' - } - }; - - const ref3: Reference = { - $refText: 'Ref3', - ref: { - $container: crossModelRoot, - $type: 'Relationship', - description: 'Test description', - name: 'test id', - name_val: 'test Name', - parent: ref1, - child: ref2, - type: 'n:m' - } - }; - - crossModelRoot.diagram = { - $container: crossModelRoot, - $type: 'SystemDiagram', - description: 'Test description', - name: 'test id', - name_val: 'test Name', - nodes: [], - edges: [] - }; - - crossModelRoot.diagram.nodes = [ - { - $container: crossModelRoot.diagram, - $type: 'DiagramNode', - x: 100, - y: 101, - width: 102, - height: 102, - entity: ref1, - name: 'Node1', - name_val: 'Node 1' - }, - { - $container: crossModelRoot.diagram, - $type: 'DiagramNode', - x: 100, - y: 101, - width: 102, - height: 102, - entity: ref2, - name: 'Node2', - name_val: 'Node 2' - } - ]; - - crossModelRoot.diagram.edges = [ - { - $container: crossModelRoot.diagram, - $type: 'DiagramEdge', - relationship: ref3, - name: 'Edge1' - } - ]; - }); - - test('serialize entity with attributes', () => { - const parseResult = serializer.serialize(crossModelRoot); - expect(parseResult).toBe(expected_result5); - }); - }); + let serializer: CrossModelSerializer; + + beforeAll(() => { + serializer = new CrossModelSerializer(services); + }); + + describe('Serialize entity', () => { + let crossModelRoot: CrossModelRoot; + let crossModelRootwithoutAttributes: CrossModelRoot; + let crossModelRootwithAttributesDifPlace: CrossModelRoot; + + beforeAll(() => { + crossModelRoot = { + $type: 'CrossModelRoot' + }; + + crossModelRootwithAttributesDifPlace = _.cloneDeep(crossModelRoot); + + crossModelRoot.entity = { + $container: crossModelRoot, + $type: 'Entity', + description: 'Test description', + name: 'test id', + name_val: 'test Name', + attributes: [] + }; + + crossModelRootwithoutAttributes = _.cloneDeep(crossModelRoot); + + crossModelRoot.entity.attributes = [ + { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 1', datatype: 'Datatype Attribute 1' }, + { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 2', datatype: 'Datatype Attribute 2' } + ]; + + crossModelRootwithAttributesDifPlace.entity = { + $container: crossModelRoot, + $type: 'Entity', + description: 'Test description', + attributes: [], + name: 'test id', + name_val: 'test Name' + }; + crossModelRootwithAttributesDifPlace.entity.attributes = [ + { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 1', datatype: 'Datatype Attribute 1' }, + { $container: crossModelRoot.entity, $type: 'EntityAttribute', name: 'Attribute 2', datatype: 'Datatype Attribute 2' } + ]; + }); + + test('serialize entity with attributes', () => { + const parseResult = serializer.serialize(crossModelRoot); + expect(parseResult).toBe(expected_result); + }); + + test('serialize entity without attributes', () => { + const parseResult = serializer.serialize(crossModelRootwithoutAttributes); + + expect(parseResult).toBe(expected_result2); + }); + + test('serialize entity with attributes in different place', () => { + const parseResult = serializer.serialize(crossModelRootwithAttributesDifPlace); + + expect(parseResult).toBe(expected_result3); + }); + }); + + describe('Serialize relationship', () => { + let crossModelRoot: CrossModelRoot; + + beforeAll(() => { + crossModelRoot = { + $type: 'CrossModelRoot' + }; + + const ref1: Reference = { + $refText: 'Ref1', + ref: { + $container: crossModelRoot, + $type: 'Entity', + description: 'Test description', + attributes: [], + name: 'Ref1', + name_val: 'test Name' + } + }; + + const ref2: Reference = { + $refText: 'Ref2', + ref: { + $container: crossModelRoot, + $type: 'Entity', + description: 'Test description', + attributes: [], + name: 'Ref2', + name_val: 'test Name' + } + }; + + crossModelRoot.relationship = { + $container: crossModelRoot, + $type: 'Relationship', + description: 'Test description', + name: 'test id', + name_val: 'test Name', + parent: ref1, + child: ref2, + type: 'n:m' + }; + }); + + test('serialize entity with attributes', () => { + const parseResult = serializer.serialize(crossModelRoot); + expect(parseResult).toBe(expected_result4); + }); + }); + + describe('Serialize diagram', () => { + let crossModelRoot: CrossModelRoot; + + beforeAll(() => { + crossModelRoot = { + $type: 'CrossModelRoot' + }; + + const ref1: Reference = { + $refText: 'Ref1', + ref: { + $container: crossModelRoot, + $type: 'Entity', + description: 'Test description', + attributes: [], + name: 'Ref1', + name_val: 'test Name' + } + }; + + const ref2: Reference = { + $refText: 'Ref2', + ref: { + $container: crossModelRoot, + $type: 'Entity', + description: 'Test description', + attributes: [], + name: 'Ref2', + name_val: 'test Name' + } + }; + + const ref3: Reference = { + $refText: 'Ref3', + ref: { + $container: crossModelRoot, + $type: 'Relationship', + description: 'Test description', + name: 'test id', + name_val: 'test Name', + parent: ref1, + child: ref2, + type: 'n:m' + } + }; + + crossModelRoot.diagram = { + $container: crossModelRoot, + $type: 'SystemDiagram', + description: 'Test description', + name: 'test id', + name_val: 'test Name', + nodes: [], + edges: [] + }; + + crossModelRoot.diagram.nodes = [ + { + $container: crossModelRoot.diagram, + $type: 'DiagramNode', + x: 100, + y: 101, + width: 102, + height: 102, + entity: ref1, + name: 'Node1', + name_val: 'Node 1' + }, + { + $container: crossModelRoot.diagram, + $type: 'DiagramNode', + x: 100, + y: 101, + width: 102, + height: 102, + entity: ref2, + name: 'Node2', + name_val: 'Node 2' + } + ]; + + crossModelRoot.diagram.edges = [ + { + $container: crossModelRoot.diagram, + $type: 'DiagramEdge', + relationship: ref3, + name: 'Edge1' + } + ]; + }); + + test('serialize entity with attributes', () => { + const parseResult = serializer.serialize(crossModelRoot); + expect(parseResult).toBe(expected_result5); + }); + }); }); const expected_result = `entity: diff --git a/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts b/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts index d4235ef1..b8baf6ae 100644 --- a/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts +++ b/extensions/crossmodel-lang/test/language-server/util/name-util.test.ts @@ -1,7 +1,7 @@ /******************************************************************************** * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, jest } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { EmptyFileSystem } from 'langium'; import { createCrossModelServices } from '../../../src/language-server/cross-model-module.js'; @@ -9,8 +9,6 @@ import { CrossModelRoot } from '../../../src/language-server/generated/ast.js'; import { findAvailableNodeName } from '../../../src/language-server/util/name-util.js'; import { parseDocument } from '../test-utils/utils.js'; -jest.useFakeTimers(); - const services = createCrossModelServices({ ...EmptyFileSystem }); const cmServices = services.CrossModel; @@ -30,31 +28,31 @@ const ex4 = `diagram: - id: "nodeA4"`; describe('NameUtil', () => { - describe('findAvailableNodeName', () => { - test('should return given name if unique', async () => { - const document = await parseDocument(cmServices, ex1); + describe('findAvailableNodeName', () => { + test('should return given name if unique', async () => { + const document = await parseDocument(cmServices, ex1); - expect(findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA')).toBe('nodeA'); - }); + expect(findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA')).toBe('nodeA'); + }); - test('should return unique name if given is taken', async () => { - const document = await parseDocument(cmServices, ex2); + test('should return unique name if given is taken', async () => { + const document = await parseDocument(cmServices, ex2); - const resultat = findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA'); + const result = findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA'); - expect(resultat).toBe('nodeA1'); - }); + expect(result).toBe('nodeA1'); + }); - test('should properly count up if name is taken', async () => { - const document = await parseDocument(cmServices, ex3); + test('should properly count up if name is taken', async () => { + const document = await parseDocument(cmServices, ex3); - expect(findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA')).toBe('nodeA2'); - }); + expect(findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA')).toBe('nodeA2'); + }); - test('should find lowest count if multiple are taken', async () => { - const document = await parseDocument(cmServices, ex4); + test('should find lowest count if multiple are taken', async () => { + const document = await parseDocument(cmServices, ex4); - expect(findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA')).toBe('nodeA3'); - }); - }); + expect(findAvailableNodeName(document.parseResult.value.diagram!, 'nodeA')).toBe('nodeA3'); + }); + }); }); diff --git a/extensions/crossmodel-lang/test/model-server/model-server.test.ts b/extensions/crossmodel-lang/test/model-server/model-server.test.ts index 031cf093..a9d62b7e 100644 --- a/extensions/crossmodel-lang/test/model-server/model-server.test.ts +++ b/extensions/crossmodel-lang/test/model-server/model-server.test.ts @@ -2,13 +2,11 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ -import { describe, expect, test, jest } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { NodeFileSystem } from 'langium/node'; import { createCrossModelServices } from '../../src/language-server/cross-model-module.js'; import { ModelService } from '../../src/model-server/model-service.js'; -jest.useFakeTimers(); - // Test written by Martin Fleck, added to this branch for Jest. Using Vitest is not necessary // the model service actually needs a file system, so we use the NodeFileSystem @@ -18,13 +16,13 @@ const sharedServices = services.shared; const modelService = new ModelService(sharedServices); describe('Model Service', () => { - test('Open on non-existing file should throw exception', async () => { - try { - await modelService.open({ uri: 'non-existing-uri', clientId: 'non-existing-client' }); - } catch (error) { - expect(error).toBeDefined(); - // We expect the ENOENT (Error No Entity) error to be thrown, because the file doesn't exist. - expect(error).toHaveProperty('code', 'ENOENT'); - } - }); + test('Open on non-existing file should throw exception', async () => { + try { + await modelService.open({ uri: 'non-existing-uri', clientId: 'non-existing-client' }); + } catch (error) { + expect(error).toBeDefined(); + // We expect the ENOENT (Error No Entity) error to be thrown, because the file doesn't exist. + expect(error).toHaveProperty('code', 'ENOENT'); + } + }); }); diff --git a/package.json b/package.json index ea6353b4..50e59478 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,9 @@ "start:browser": "yarn theia:browser start", "start:electron": "yarn theia:electron start", "start:verdaccio": "yarn verdaccio --config verdaccio-config.yaml", - "test": "rimraf unit-test-results && lerna run test", + "test": "rimraf unit-test-results && yarn run test:cjs && yarn run test:esm", + "test:cjs": "jest --config=configs/jest.config.js --passWithNoTests", + "test:esm": "yarn --cwd extensions/crossmodel-lang test", "theia:browser": "yarn --cwd applications/browser-app", "theia:electron": "yarn --cwd applications/electron-app", "ui-test": "yarn --cwd e2e-tests ui-test",