diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 14039a4e7..000000000 --- a/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.json] -indent_size = 2 - -[*.md] -indent_size = 2 - -[*.yml] -indent_size = 2 diff --git a/.github/gitpod.yml b/.github/gitpod.yml deleted file mode 100644 index e176b198f..000000000 --- a/.github/gitpod.yml +++ /dev/null @@ -1,15 +0,0 @@ -pulls: -# Enable for pull requests - perform: true -# Customize a comment to post on a pull request. Comment out to use the default -# comment: - -issues: -# enable for issues - perform: true -# issues with these labels will be considered. Set to `[]` to disable for issues - labels: - - help wanted - - good first issue -# Customize a comment to post on an issue. Comment out to use the default -# comment: diff --git a/.github/stale.yml b/.github/stale.yml index 69614646a..adc346ef7 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -16,4 +16,4 @@ markComment: > # Comment to post when removing the stale label. Set to `false` to disable unmarkComment: false # Comment to post when closing a stale Issue or Pull Request. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false diff --git a/.github/workflows/debugger-py.yml b/.github/workflows/debugger-py.yml index c47e6d84b..1d784b161 100644 --- a/.github/workflows/debugger-py.yml +++ b/.github/workflows/debugger-py.yml @@ -22,39 +22,39 @@ jobs: timeout-minutes: 15 steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} - # enforce latest tag for now - tags: | - type=raw,value=latest - - - name: Build & Push - id: push - uses: docker/build-push-action@v6 - with: - context: . - file: ${{ env.PATH_CONTEXT }}/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Attest - uses: actions/attest-build-provenance@v3 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true + - name: Checkout + uses: actions/checkout@v6 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} + # enforce latest tag for now + tags: | + type=raw,value=latest + + - name: Build & Push + id: push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ env.PATH_CONTEXT }}/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Attest + uses: actions/attest-build-provenance@v3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/ghp.yml b/.github/workflows/ghp.yml index 243a8b617..8f77b0474 100644 --- a/.github/workflows/ghp.yml +++ b/.github/workflows/ghp.yml @@ -2,8 +2,8 @@ name: Build Production for GitHub Pages on: push: - branches: - - "ghp" + branches: + - 'ghp' # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: @@ -17,38 +17,38 @@ jobs: timeout-minutes: 15 steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: mise-en-place - uses: jdx/mise-action@v2 - - - name: Install - shell: bash - run: | - npm ci - - - name: Versions Report - shell: bash - run: | - npm run report:versions - - - name: Build - run: | - npm run build - - - name: Build Production - run: | - npm run production:build - - - name: Setup Pages - id: pages - uses: actions/configure-pages@v5 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v4 - with: - path: ./packages/examples/production/ + - name: Checkout + uses: actions/checkout@v6 + + - name: mise-en-place + uses: jdx/mise-action@v2 + + - name: Install + shell: bash + run: | + npm ci + + - name: Versions Report + shell: bash + run: | + npm run report:versions + + - name: Build + run: | + npm run build + + - name: Build Production + run: | + npm run production:build + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + path: ./packages/examples/production/ ghp-deploy: needs: ghp-build diff --git a/.github/workflows/ls-clangd.yml b/.github/workflows/ls-clangd.yml index 9782f4be6..4c58176aa 100644 --- a/.github/workflows/ls-clangd.yml +++ b/.github/workflows/ls-clangd.yml @@ -23,66 +23,66 @@ jobs: timeout-minutes: 150 steps: - - name: Checkout - uses: actions/checkout@v6 + - name: Checkout + uses: actions/checkout@v6 - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (configure) - id: meta_configure - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_CONFIGURE }} - # enforce latest tag for now - tags: | - type=raw,value=latest + - name: Extract metadata (configure) + id: meta_configure + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_CONFIGURE }} + # enforce latest tag for now + tags: | + type=raw,value=latest - - name: Build & Push (configure) - id: push_configure - uses: docker/build-push-action@v6 - with: - context: ${{ env.PATH_CONTEXT }} - file: ${{ env.PATH_CONTEXT }}/configure.Dockerfile - push: true - tags: ${{ steps.meta_configure.outputs.tags }} - labels: ${{ steps.meta_configure.outputs.labels }} + - name: Build & Push (configure) + id: push_configure + uses: docker/build-push-action@v6 + with: + context: ${{ env.PATH_CONTEXT }} + file: ${{ env.PATH_CONTEXT }}/configure.Dockerfile + push: true + tags: ${{ steps.meta_configure.outputs.tags }} + labels: ${{ steps.meta_configure.outputs.labels }} - - name: Attest (configure) - uses: actions/attest-build-provenance@v3 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_CONFIGURE }} - subject-digest: ${{ steps.push_configure.outputs.digest }} - push-to-registry: true + - name: Attest (configure) + uses: actions/attest-build-provenance@v3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_CONFIGURE }} + subject-digest: ${{ steps.push_configure.outputs.digest }} + push-to-registry: true - - name: Extract metadata (build) - id: meta_build - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_BUILD }} - # enforce latest tag for now - tags: | - type=raw,value=latest + - name: Extract metadata (build) + id: meta_build + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_BUILD }} + # enforce latest tag for now + tags: | + type=raw,value=latest - - name: Build & Push (build) - id: push_build - uses: docker/build-push-action@v6 - with: - context: ${{ env.PATH_CONTEXT }} - file: ${{ env.PATH_CONTEXT }}/build.Dockerfile - push: true - tags: ${{ steps.meta_build.outputs.tags }} - labels: ${{ steps.meta_build.outputs.labels }} + - name: Build & Push (build) + id: push_build + uses: docker/build-push-action@v6 + with: + context: ${{ env.PATH_CONTEXT }} + file: ${{ env.PATH_CONTEXT }}/build.Dockerfile + push: true + tags: ${{ steps.meta_build.outputs.tags }} + labels: ${{ steps.meta_build.outputs.labels }} - - name: Attest (build) - uses: actions/attest-build-provenance@v3 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_BUILD }} - subject-digest: ${{ steps.push_build.outputs.digest }} - push-to-registry: true + - name: Attest (build) + uses: actions/attest-build-provenance@v3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME_BUILD }} + subject-digest: ${{ steps.push_build.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/ls-eclipsejdt.yml b/.github/workflows/ls-eclipsejdt.yml index 6f3ec13f5..9e5100a98 100644 --- a/.github/workflows/ls-eclipsejdt.yml +++ b/.github/workflows/ls-eclipsejdt.yml @@ -22,39 +22,39 @@ jobs: timeout-minutes: 15 steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} - # enforce latest tag for now - tags: | - type=raw,value=latest - - - name: Build & Push - id: push - uses: docker/build-push-action@v6 - with: - context: . - file: ${{ env.PATH_CONTEXT }}/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Attest - uses: actions/attest-build-provenance@v3 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true + - name: Checkout + uses: actions/checkout@v6 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} + # enforce latest tag for now + tags: | + type=raw,value=latest + + - name: Build & Push + id: push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ env.PATH_CONTEXT }}/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Attest + uses: actions/attest-build-provenance@v3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/ls-groovy.yml b/.github/workflows/ls-groovy.yml index 3cb7de4d1..75e0432a0 100644 --- a/.github/workflows/ls-groovy.yml +++ b/.github/workflows/ls-groovy.yml @@ -22,39 +22,39 @@ jobs: timeout-minutes: 15 steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} - # enforce latest tag for now - tags: | - type=raw,value=latest - - - name: Build & Push - id: push - uses: docker/build-push-action@v6 - with: - context: . - file: ${{ env.PATH_CONTEXT }}/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Attest - uses: actions/attest-build-provenance@v3 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true + - name: Checkout + uses: actions/checkout@v6 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} + # enforce latest tag for now + tags: | + type=raw,value=latest + + - name: Build & Push + id: push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ env.PATH_CONTEXT }}/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Attest + uses: actions/attest-build-provenance@v3 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/${{ env.CONTAINER_NAME }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index de3563ce3..d15c504e4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,33 +19,33 @@ jobs: timeout-minutes: 10 steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: mise-en-place - uses: jdx/mise-action@v2 - - - name: Install - shell: bash - run: | - npm ci - - - name: Versions Report - shell: bash - run: | - npm run report:versions - - - name: Build - shell: bash - run: | - npm run build - - - name: Lint - shell: bash - run: | - npm run lint - - - name: Test - shell: bash - run: | - npm run test + - name: Checkout + uses: actions/checkout@v6 + + - name: mise-en-place + uses: jdx/mise-action@v2 + + - name: Install + shell: bash + run: | + npm ci + + - name: Versions Report + shell: bash + run: | + npm run report:versions + + - name: Build + shell: bash + run: | + npm run build + + - name: Lint + shell: bash + run: | + npm run lint + + - name: Test + shell: bash + run: | + npm run test:ci diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 7b89ee1b1..109cabdaf 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -12,24 +12,24 @@ jobs: timeout-minutes: 10 steps: - - name: Checkout - uses: actions/checkout@v6 + - name: Checkout + uses: actions/checkout@v6 - - name: mise-en-place - uses: jdx/mise-action@v2 + - name: mise-en-place + uses: jdx/mise-action@v2 - - name: Install - shell: bash - run: | - npm ci + - name: Install + shell: bash + run: | + npm ci - - name: Versions Report - shell: bash - run: | - npm run report:versions + - name: Versions Report + shell: bash + run: | + npm run report:versions - - name: Execute verification - shell: bash - run: | - bash ./verify/buildPeers.sh - bash ./verify/buildAll.sh + - name: Execute verification + shell: bash + run: | + bash ./verify/buildPeers.sh + bash ./verify/buildAll.sh diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 000000000..8b30dba1c --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,29 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "singleQuote": true, + "ignorePatterns": [ + ".chrome/**/*", + "**/bundle/**/*", + "**/dist/**/*", + "**/lib/**/*", + "**/node_modules/**/*", + "**/production/**/*" + // Exclude this file because `**` can be interpreted as Markdown bold/nesting and cause slow formatting (oxc issue #19929). + // If formatted as list the problems are gone + // "packages/examples/resources/clangd/clangd-include.files.md" + ], + "endOfLine": "lf", + "trailingComma": "none", + "insertFinalNewline": true, + "sortPackageJson": true, + "tabWidth": 2, + "printWidth": 140, + "overrides": [ + { + "files": ["*.json"], + "options": { + "printWidth": 80 + } + } + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index ffe1bd8d7..b46583491 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,8 @@ { "recommendations": [ - "oxc.oxc-vscode", - "editorconfig.editorconfig", "davidanson.vscode-markdownlint", + "editorconfig.editorconfig", + "oxc.oxc-vscode", "vitest.explorer" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 1b286244e..2215de92f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,63 +1,74 @@ { - // Use IntelliSense to learn about possible Node.js debug attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch JSON LS", - "type": "node", - "request": "launch", - "runtimeExecutable": "tsx", - "args": ["${workspaceRoot}/packages/examples/src/json/server/direct.ts"], - "cwd": "${workspaceRoot}/packages/examples", - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": "Launch Python LS", - "type": "node", - "request": "launch", - "runtimeExecutable": "tsx", - "args": ["${workspaceRoot}/packages/examples/src/python/server/direct.ts"], - "cwd": "${workspaceRoot}/packages/examples", - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": "Chrome", - "type": "chrome", - "request": "launch", - "url": "http://localhost:20001", - "webRoot": "${workspaceFolder}", - "userDataDir": "${workspaceFolder}/.chrome/profile" - }, - { - "name": "Chrome Preview", - "type": "chrome", - "request": "launch", - "url": "http://localhost:20002", - "webRoot": "${workspaceFolder}/packages/examples/production", - "userDataDir": "${workspaceFolder}/.chrome/profile" - }, - { - "type": "node", - "request": "launch", - "name": "Run Vitest Browser Debug", - "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs", - "args": ["--config", "vitest.config.ts", "--inspect-brk=20222", "--browser", "--no-file-parallelism"], - "console": "integratedTerminal" - }, - { - "type": "chrome", - "request": "attach", - "name": "Attach to Playwright Chromium", - "port": 20222 - } - ], - "compounds": [ - { - "name": "Debug Vitest Browser", - "configurations": ["Attach to Playwright Chromium", "Run Vitest Browser Debug"], - "stopAll": true - } - ] + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch JSON LS", + "type": "node", + "request": "launch", + "runtimeExecutable": "tsx", + "args": ["${workspaceRoot}/packages/examples/src/json/server/direct.ts"], + "cwd": "${workspaceRoot}/packages/examples", + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": "Launch Python LS", + "type": "node", + "request": "launch", + "runtimeExecutable": "tsx", + "args": [ + "${workspaceRoot}/packages/examples/src/python/server/direct.ts" + ], + "cwd": "${workspaceRoot}/packages/examples", + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": "Chrome", + "type": "chrome", + "request": "launch", + "url": "http://localhost:20001", + "webRoot": "${workspaceFolder}", + "userDataDir": "${workspaceFolder}/.chrome/profile" + }, + { + "name": "Chrome Preview", + "type": "chrome", + "request": "launch", + "url": "http://localhost:20002", + "webRoot": "${workspaceFolder}/packages/examples/production", + "userDataDir": "${workspaceFolder}/.chrome/profile" + }, + { + "type": "node", + "request": "launch", + "name": "Run Vitest Browser Debug", + "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs", + "args": [ + "--config", + "vitest.config.ts", + "--inspect-brk=20222", + "--browser", + "--no-file-parallelism" + ], + "console": "integratedTerminal" + }, + { + "type": "chrome", + "request": "attach", + "name": "Attach to Playwright Chromium", + "port": 20222 + } + ], + "compounds": [ + { + "name": "Debug Vitest Browser", + "configurations": [ + "Attach to Playwright Chromium", + "Run Vitest Browser Debug" + ], + "stopAll": true + } + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index e9111a693..5a1b7686e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,19 +1,12 @@ { - "typescript.tsdk": "node_modules/typescript/lib", + "js/ts.tsdk.path": "node_modules/typescript/lib", "editor.guides.bracketPairs": true, - "editor.formatOnSave": false, - "workbench.editor.revealIfOpen": true, + "editor.defaultFormatter": "oxc.oxc-vscode", + "oxc.enable": true, "oxc.enable.oxlint": true, "oxc.typeAware": true, - "[javascript]": { - "editor.formatOnSave": true, - }, - "[typescript]": { - "editor.formatOnSave": true, - }, - "[json]": { - "editor.defaultFormatter": "vscode.json-language-features" - }, + "editor.formatOnSave": true, + "workbench.editor.revealIfOpen": true, "terminal.integrated.scrollback": 10000, "editor.minimap.enabled": false } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b58bcb971..55b5bfb48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,8 @@ - Contributions to catch up with latest versions of LSP and Monaco are always welcomed! - Contributions to propose a new example should be only accepted if an author is ready to become a maintainer and help with upgrading and testing it with latest versions of LSP and Monaco. -## Pull Request +## Pull Request + Please do not `git merge` main branch into a feature branch. Always `git rebase` a feature or bugfix branch to the latest main if you require changes from main. ## Maintaining diff --git a/README.md b/README.md index a5f4cc208..ddd68ee02 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ These are the current versions of packages from this repository and their alignm - **monaco-languageclient**: `10.7.0` (release date: 2026-02-04) - **@typefox/monaco-editor-react**: `7.7.0` (release date: unrel2026-02-04eased) - Aligned with: - - **@codingame/monaco-vscode-[editor]-api**: `26.2.1` + - **@codingame/monaco-vscode-[editor]-api**: `26.2.2` - **vscode**: `1.108.2` - **monaco-editor**: `0.55.1` - **vscode-ws-jsonrpc**: `3.5.0` (release date: 2025-08-11) @@ -145,7 +145,7 @@ The **json-client using classic mode** as [editor app](./packages/examples/src/j The **python-server** runs an external Node.js [Express app](./packages/examples/src/python/server/main.ts) where web sockets are used to enable communication between the language server process and the client web application (see [Pyright Language Server](#pyright-language-server)). The **python-client** contains the [editor app](./packages/examples/src/python/client/main.ts) which connects to the language server and therefore requires the node server app to be run in parallel. - It is also possible to use a [@typefox/monaco-editor-react app](./packages/examples/src/python/client/reactPython.tsx) to connect to the server. Both versions now feature a debugger, see [here](#graalpy-debugger). +It is also possible to use a [@typefox/monaco-editor-react app](./packages/examples/src/python/client/reactPython.tsx) to connect to the server. Both versions now feature a debugger, see [here](#graalpy-debugger). #### Groovy Language client and language server example ([Location](./packages/examples/src/groovy)) diff --git a/docs/guides/configuration.md b/docs/guides/configuration.md index 4ed6a2460..f31967aa0 100644 --- a/docs/guides/configuration.md +++ b/docs/guides/configuration.md @@ -18,10 +18,10 @@ Independent of the type of configuration (`classic` or `extendend`), you have to import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } }; const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); @@ -140,10 +140,10 @@ Classic Mode uses the standard Monaco Editor with language client features added import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'classic', - viewsConfig: { - $type: 'EditorService' - } + $type: 'classic', + viewsConfig: { + $type: 'EditorService' + } }; const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); @@ -163,27 +163,27 @@ You can further configure VSCode related settings through the user configuration ```typescript userConfiguration: { - json: JSON.stringify({ - // Editor appearance - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.fontSize': 14, - 'editor.fontFamily': 'Consolas, monospace', - - // Editor behavior - 'editor.tabSize': 2, - 'editor.wordWrap': 'on', - 'editor.minimap.enabled': true, - 'editor.lineNumbers': 'on', - - // Language features - 'editor.quickSuggestions': true, - 'editor.wordBasedSuggestions': 'off', - 'editor.parameterHints.enabled': true, - - // Advanced features - 'editor.experimental.asyncTokenization': true, - 'editor.guides.bracketPairsHorizontal': 'active' - }) + json: JSON.stringify({ + // Editor appearance + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.fontSize': 14, + 'editor.fontFamily': 'Consolas, monospace', + + // Editor behavior + 'editor.tabSize': 2, + 'editor.wordWrap': 'on', + 'editor.minimap.enabled': true, + 'editor.lineNumbers': 'on', + + // Language features + 'editor.quickSuggestions': true, + 'editor.wordBasedSuggestions': 'off', + 'editor.parameterHints.enabled': true, + + // Advanced features + 'editor.experimental.asyncTokenization': true, + 'editor.guides.bracketPairsHorizontal': 'active' + }); } ``` @@ -192,14 +192,15 @@ userConfiguration: { In most cases you'll need to setup an in-memory or remote file system for the editor to work with. ```typescript -import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; +import { + RegisteredFileSystemProvider, + RegisteredMemoryFile, + registerFileSystemOverlay +} from '@codingame/monaco-vscode-files-service-override'; // In-memory file system const fileSystemProvider = new RegisteredFileSystemProvider(false); -fileSystemProvider.registerFile(new RegisteredMemoryFile( - vscode.Uri.file('/project/main.ts'), - 'console.log("Hello from TypeScript");' -)); +fileSystemProvider.registerFile(new RegisteredMemoryFile(vscode.Uri.file('/project/main.ts'), 'console.log("Hello from TypeScript");')); registerFileSystemOverlay(1, fileSystemProvider); ``` @@ -254,12 +255,12 @@ connection: { const isDevelopment = process.env.NODE_ENV === 'development'; const config = { - logLevel: isDevelopment ? LogLevel.Debug : LogLevel.Error, - userConfiguration: { - json: JSON.stringify({ - 'editor.wordBasedSuggestions': isDevelopment ? 'on' : 'off' - }) - } + logLevel: isDevelopment ? LogLevel.Debug : LogLevel.Error, + userConfiguration: { + json: JSON.stringify({ + 'editor.wordBasedSuggestions': isDevelopment ? 'on' : 'off' + }) + } }; ``` @@ -270,35 +271,32 @@ You can configure multiple language clients for different file types: ```typescript // Eclipse JDT language client const javaConfig = { - connection: { - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:3001/jdtls' - } - }, - clientOptions: { - documentSelector: ['java'] + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:3001/jdtls' } + }, + clientOptions: { + documentSelector: ['java'] + } }; // JSON language client const jsonConfig = { - connection: { - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:3001/json' - } - }, - clientOptions: { - documentSelector: ['json'] + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:3001/json' } + }, + clientOptions: { + documentSelector: ['json'] + } }; // Initialize both -await Promise.all([ - new LanguageClientWrapper().init(javaConfig), - new LanguageClientWrapper().init(jsonConfig) -]); +await Promise.all([new LanguageClientWrapper().init(javaConfig), new LanguageClientWrapper().init(jsonConfig)]); ``` ## Configuration Validation diff --git a/docs/guides/examples.md b/docs/guides/examples.md index 8efb11cdf..2050467de 100644 --- a/docs/guides/examples.md +++ b/docs/guides/examples.md @@ -21,72 +21,72 @@ import * as vscode from 'vscode'; import { LogLevel } from '@codingame/monaco-vscode-api'; async function createJsonEditor() { - const languageId = 'json'; - // Sample JSON content - const code = `{ + const languageId = 'json'; + // Sample JSON content + const code = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": "unix" }`; - const codeUri = '/workspace/hello.json'; - - // Monaco VSCode API configuration - const vscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - }, - logLevel: LogLevel.Debug, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off' - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - // Language client configuration - const languageClientConfig = { - languageId, - connection: { - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:30000/sampleServer' - } - }, - clientOptions: { - documentSelector: [languageId], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.file('/workspace') - } - } - }; - - // Create the monaco-vscode api Wrapper - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - // Create language client wrapper - const lcWrapper = new LanguageClientWrapper(languageClientConfig); - await lcWrapper.start(); - - // Create the editor app - const editorApp = new EditorApp({ - codeResources: { - modified: { - text: jsonContent, - uri: codeUri - } - } - }); - - // Start the editor - const htmlContainer = document.getElementById('monaco-editor-root')!; - await editorApp.start(htmlContainer); - - console.log('JSON editor with language client is ready!'); + const codeUri = '/workspace/hello.json'; + + // Monaco VSCode API configuration + const vscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + }, + logLevel: LogLevel.Debug, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off' + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + // Language client configuration + const languageClientConfig = { + languageId, + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:30000/sampleServer' + } + }, + clientOptions: { + documentSelector: [languageId], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.file('/workspace') + } + } + }; + + // Create the monaco-vscode api Wrapper + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + // Create language client wrapper + const lcWrapper = new LanguageClientWrapper(languageClientConfig); + await lcWrapper.start(); + + // Create the editor app + const editorApp = new EditorApp({ + codeResources: { + modified: { + text: jsonContent, + uri: codeUri + } + } + }); + + // Start the editor + const htmlContainer = document.getElementById('monaco-editor-root')!; + await editorApp.start(htmlContainer); + + console.log('JSON editor with language client is ready!'); } createJsonEditor().catch(console.error); ``` @@ -104,77 +104,74 @@ import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-langu import { defineDefaultWorkerLoaders, useWorkerFactory } from 'monaco-languageclient/workerFactory'; export const runClient = async () => { - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'classic', - viewsConfig: { - $type: 'EditorService' - }, - logLevel: LogLevel.Debug, - userConfiguration: { - json: JSON.stringify({ - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureClassicWorkerFactory - }; - - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - const languageId = 'json'; - const code = `{ + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'classic', + viewsConfig: { + $type: 'EditorService' + }, + logLevel: LogLevel.Debug, + userConfiguration: { + json: JSON.stringify({ + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureClassicWorkerFactory + }; + + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + const languageId = 'json'; + const code = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": "unix" }`; - const codeUri = '/workspace/model.json'; - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: { - text: code, - uri: codeUri - } - }, - languageDef: { - languageExtensionConfig: { - id: languageId, - extensions: ['.json', '.jsonc'], - aliases: ['JSON', 'json'], - mimetypes: ['application/json'] - } - } - }; - const editorApp = new EditorApp(editorAppConfig); - const htmlContainer = document.getElementById('monaco-editor-root')!; - await editorApp.start(htmlContainer); - - const languageClientConfig: LanguageClientConfig = { - languageId, - clientOptions: { - documentSelector: [languageId] - }, - connection: { - options: { - $type: 'WebSocketUrl', - // at this url the language server must be reachable - url: 'ws://localhost:30000/jsonLS' - } - } - }; - const languageClientWrapper = new LanguageClientWrapper( - languageClientConfig, - apiWrapper.getLogger() - ); - await languageClientWrapper.start(); + const codeUri = '/workspace/model.json'; + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: { + text: code, + uri: codeUri + } + }, + languageDef: { + languageExtensionConfig: { + id: languageId, + extensions: ['.json', '.jsonc'], + aliases: ['JSON', 'json'], + mimetypes: ['application/json'] + } + } + }; + const editorApp = new EditorApp(editorAppConfig); + const htmlContainer = document.getElementById('monaco-editor-root')!; + await editorApp.start(htmlContainer); + + const languageClientConfig: LanguageClientConfig = { + languageId, + clientOptions: { + documentSelector: [languageId] + }, + connection: { + options: { + $type: 'WebSocketUrl', + // at this url the language server must be reachable + url: 'ws://localhost:30000/jsonLS' + } + } + }; + const languageClientWrapper = new LanguageClientWrapper(languageClientConfig, apiWrapper.getLogger()); + await languageClientWrapper.start(); }; export const configureClassicWorkerFactory = (logger?: Logger) => { - const defaultworkerLoaders = defineDefaultWorkerLoaders(); - // remove textmate worker as it is not compatible with classic mode - defaultworkerLoaders.TextMateWorker = undefined; - useWorkerFactory({ - workerLoaders: defaultworkerLoaders, - logger - }); + const defaultworkerLoaders = defineDefaultWorkerLoaders(); + // remove textmate worker as it is not compatible with classic mode + defaultworkerLoaders.TextMateWorker = undefined; + useWorkerFactory({ + workerLoaders: defaultworkerLoaders, + logger + }); }; ``` @@ -216,39 +213,39 @@ import '@codingame/monaco-vscode-json-default-extension'; import '@codingame/monacovscode-java-default-extension'; async function createMultiLanguageEditor() { - const apiWrapper = new MonacoVscodeApiWrapper({ - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }); - await apiWrapper.start(); - - // JSON Language Client - const jsonClient = new LanguageClientWrapper(); - await jsonClient.init({ - connection: { options: { $type: 'WebSocketUrl', url: 'ws://localhost:3001/json' }}, - clientOptions: { documentSelector: ['json'] } - }); - - // Java Language Client - const javaClient = new LanguageClientWrapper(); - await javaClient.init({ - connection: { options: { $type: 'WebSocketUrl', url: 'ws://localhost:3002/java' }}, - clientOptions: { documentSelector: ['java'] } - }); - - // Editor can now handle both JSON and Java files - const editorApp = new EditorApp({ - codeResources: { - json: { text: '{"test": true}', uri: '/workspace/config.json', fileExt: 'json' }, - ts: { text: 'const x: number = 42;', uri: '/workspace/main.ts', fileExt: 'ts' } - } - }); - - const htmlContainer = document.getElementById('monaco-editor-root')!; - await editorApp.start(htmlContainer); + const apiWrapper = new MonacoVscodeApiWrapper({ + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }); + await apiWrapper.start(); + + // JSON Language Client + const jsonClient = new LanguageClientWrapper(); + await jsonClient.init({ + connection: { options: { $type: 'WebSocketUrl', url: 'ws://localhost:3001/json' } }, + clientOptions: { documentSelector: ['json'] } + }); + + // Java Language Client + const javaClient = new LanguageClientWrapper(); + await javaClient.init({ + connection: { options: { $type: 'WebSocketUrl', url: 'ws://localhost:3002/java' } }, + clientOptions: { documentSelector: ['java'] } + }); + + // Editor can now handle both JSON and Java files + const editorApp = new EditorApp({ + codeResources: { + json: { text: '{"test": true}', uri: '/workspace/config.json', fileExt: 'json' }, + ts: { text: 'const x: number = 42;', uri: '/workspace/main.ts', fileExt: 'ts' } + } + }); + + const htmlContainer = document.getElementById('monaco-editor-root')!; + await editorApp.start(htmlContainer); } ``` @@ -260,31 +257,31 @@ Running a language server in a Web Worker: import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageclient/browser.js'; async function createWebWorkerClient() { - // Create worker - const worker = new Worker('./language-server.js', { type: 'module' }); - - const reader = new BrowserMessageReader(worker); - const writer = new BrowserMessageWriter(worker); - - // log every message received from the worker - reader.listen((message) => { - console.log('Received message from worker:', message); - }); - - // Configure language client - const lcWrapper = new LanguageClientWrapper(); - await lcWrapper.init({ - connection: { - options: { - $type: 'MessageChannel', - worker - }, - messageTransports: { reader, writer } - }, - clientOptions: { - documentSelector: ['mydsl'] - } - }); + // Create worker + const worker = new Worker('./language-server.js', { type: 'module' }); + + const reader = new BrowserMessageReader(worker); + const writer = new BrowserMessageWriter(worker); + + // log every message received from the worker + reader.listen((message) => { + console.log('Received message from worker:', message); + }); + + // Configure language client + const lcWrapper = new LanguageClientWrapper(); + await lcWrapper.init({ + connection: { + options: { + $type: 'MessageChannel', + worker + }, + messageTransports: { reader, writer } + }, + clientOptions: { + documentSelector: ['mydsl'] + } + }); } ``` diff --git a/docs/guides/getting-started.md b/docs/guides/getting-started.md index 702b3c337..1ce85dcf9 100644 --- a/docs/guides/getting-started.md +++ b/docs/guides/getting-started.md @@ -24,20 +24,21 @@ Start by creating a basic HTML file to give a place for monaco to setup: ```html - - + + Monaco Language Client - JSON Example - - + +
- + ``` If you already have one setup, just be sure to add the root element for the Monaco Editor to attach to. If you're following along using Vite with the React TS template, you can add this to your main component (App.tsx): + ```tsx
``` @@ -65,23 +66,23 @@ npm install @codingame/esbuild-import-meta-url-plugin Then update your `vite.config.ts` as follows: ```typescript -import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin' +import importMetaUrlPlugin from '@codingame/esbuild-import-meta-url-plugin'; export default { - // ... other vite config options - plugins: [ - importMetaUrlPlugin, - // ... other plugins - ], - worker: { - format: 'es' - }, - optimizeDeps: { - esbuildOptions: { - plugins: [importMetaUrlPlugin] - } + // ... other vite config options + plugins: [ + importMetaUrlPlugin + // ... other plugins + ], + worker: { + format: 'es' + }, + optimizeDeps: { + esbuildOptions: { + plugins: [importMetaUrlPlugin] } -} + } +}; ``` ### Monaco Editor & Language Client Setup @@ -93,7 +94,6 @@ Note that we'll still need a running language server for JSON language support, Once you have that installed, you can setup your `main.ts` file as follows to setup the editor & language client: ```typescript - // import Monaco Language Client components import { EditorApp, type EditorAppConfig } from 'monaco-languageclient/editorApp'; import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFactory'; @@ -103,10 +103,14 @@ import { LanguageClientWrapper, type LanguageClientConfig } from 'monaco-languag // VSCode API for file system operations import * as vscode from 'vscode'; import { LogLevel } from '@codingame/monaco-vscode-api'; -import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; +import { + RegisteredFileSystemProvider, + RegisteredMemoryFile, + registerFileSystemOverlay +} from '@codingame/monaco-vscode-files-service-override'; // import extension for JSON support -import "@codingame/monaco-vscode-json-default-extension"; +import '@codingame/monaco-vscode-json-default-extension'; // Sample JSON content const jsonContent = `{ @@ -117,76 +121,76 @@ const jsonContent = `{ }`; async function createJsonEditor() { - // Set up an in-memory file system (won't persist on reload) - const fileUri = vscode.Uri.file('/workspace/package.json'); - const fileSystemProvider = new RegisteredFileSystemProvider(false); - fileSystemProvider.registerFile(new RegisteredMemoryFile(fileUri, jsonContent)); - registerFileSystemOverlay(1, fileSystemProvider); - - // Monaco VSCode API configuration - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer: document.getElementById("monaco-editor-root")! - }, - logLevel: LogLevel.Debug, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.lightbulb.enabled': 'On', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - const languageId = 'json'; - - // Language client configuration - const languageClientConfig: LanguageClientConfig = { - languageId, - connection: { - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:30000/sampleServer' - } - }, - clientOptions: { - documentSelector: [languageId], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.file('/workspace') - } - } - }; - - // editor app / monaco-editor configuration - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: { - text: jsonContent, - uri: fileUri.path, - } - } - }; - - // create the monaco-vscode api Wrapper - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - // create language client wrapper & app - const lcWrapper = new LanguageClientWrapper(languageClientConfig); - const editorApp = new EditorApp(editorAppConfig); - - // start editor app first, then language client - await editorApp.start(document.getElementById("monaco-editor-root")!); - await lcWrapper.start(); - - console.log('JSON editor with language client is ready!'); + // Set up an in-memory file system (won't persist on reload) + const fileUri = vscode.Uri.file('/workspace/package.json'); + const fileSystemProvider = new RegisteredFileSystemProvider(false); + fileSystemProvider.registerFile(new RegisteredMemoryFile(fileUri, jsonContent)); + registerFileSystemOverlay(1, fileSystemProvider); + + // Monaco VSCode API configuration + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer: document.getElementById('monaco-editor-root')! + }, + logLevel: LogLevel.Debug, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.lightbulb.enabled': 'On', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + const languageId = 'json'; + + // Language client configuration + const languageClientConfig: LanguageClientConfig = { + languageId, + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:30000/sampleServer' + } + }, + clientOptions: { + documentSelector: [languageId], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.file('/workspace') + } + } + }; + + // editor app / monaco-editor configuration + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: { + text: jsonContent, + uri: fileUri.path + } + } + }; + + // create the monaco-vscode api Wrapper + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + // create language client wrapper & app + const lcWrapper = new LanguageClientWrapper(languageClientConfig); + const editorApp = new EditorApp(editorAppConfig); + + // start editor app first, then language client + await editorApp.start(document.getElementById('monaco-editor-root')!); + await lcWrapper.start(); + + console.log('JSON editor with language client is ready!'); } createJsonEditor().catch(console.error); ``` @@ -271,5 +275,4 @@ Also ensure that you have compatible versions of `monaco-languageclient` and any **Import errors**: Make sure you have the correct package versions and bundler configuration from the [Installation guide](../installation.md). - For more help, see our [Troubleshooting Guide](./troubleshooting.md). diff --git a/docs/guides/index.md b/docs/guides/index.md index 1808071f5..92d62b3f2 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -22,12 +22,12 @@ Compared with the classic mode the only difference regarding the `monaco-vscode- import type { MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; const vscodeApiConfig: MonacoVscodeApiConfig = { - // both $type and viewsConfig are mandatory - $type: 'extended', - viewsConfig: { - $type: 'ViewsService' - }, - // further configuration + // both $type and viewsConfig are mandatory + $type: 'extended', + viewsConfig: { + $type: 'ViewsService' + } + // further configuration }; ``` @@ -39,13 +39,13 @@ Light-weight integration with standalone Monaco Editor. import type { MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; const vscodeApiConfig: MonacoVscodeApiConfig = { - // both $type and viewsConfig are mandatory - $type: 'classic', - viewsConfig: { - // in classic mode only one type can be configured - $type: 'EditorService' - }, - // further configuration + // both $type and viewsConfig are mandatory + $type: 'classic', + viewsConfig: { + // in classic mode only one type can be configured + $type: 'EditorService' + } + // further configuration }; ``` diff --git a/docs/guides/troubleshooting.md b/docs/guides/troubleshooting.md index b3cf14116..5d231b92f 100644 --- a/docs/guides/troubleshooting.md +++ b/docs/guides/troubleshooting.md @@ -11,7 +11,7 @@ Whenever you use `monaco-editor`/`@codingame/monaco-vscode-editor-api` `vscode`/ If you use pnpm or yarn, you have to add `vscode` / `@codingame/monaco-vscode-api` as direct dependency, otherwise the installation will fail: ```json -"vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1" +"vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2" ``` ### Missing Overrides or Resolutions @@ -23,7 +23,7 @@ To ensure all Monaco-related packages use a single, compatible version, you must ```json { "overrides": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.2" } } ``` @@ -33,7 +33,7 @@ To ensure all Monaco-related packages use a single, compatible version, you must ```json { "resolutions": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.2" } } ``` @@ -50,7 +50,7 @@ Additionally, if you see a message in the browser console starting with `Another ### @codingame/monaco-vscode-editor-api / monaco-editor usage -When you use the libraries from this project you are no longer required to proxy `monaco-editor` like `"monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.1"` in you `package.json`. You can directly use it like so: +When you use the libraries from this project you are no longer required to proxy `monaco-editor` like `"monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.2"` in you `package.json`. You can directly use it like so: ```js import * as monaco from '@codingame/monaco-vscode-editor-api'; @@ -60,7 +60,7 @@ If your dependency stack already contains a reference `monaco-editor` you must e ```json "overrides": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.2" } ``` @@ -76,17 +76,19 @@ We use [mise-en-place](https://mise.jdx.dev/) for tool management. In the past w Uncaught Error: Unexpected non—whitespace character after JSON at position 2 SyntaxError: Unexpected non—whitespace character after JSON at position 2 - at JSON. parse («anonymous>) + at JSON. parse («anonymous>) ``` Then it's likely you have an old version of `buffer` interfering (see [#538](https://github.com/TypeFox/monaco-languageclient/issues/538) and [#546](https://github.com/TypeFox/monaco-languageclient/issues/546)). You can enforce a current version by adding a `resolution` as shown below to your projects' `package.json`. ```json { - "resolutions": { // For Yarn + "resolutions": { + // For Yarn "buffer": "~6.0.3" }, - "overrides": { // For npm/pnpm + "overrides": { + // For npm/pnpm "buffer": "~6.0.3" } } @@ -154,8 +156,8 @@ We recommend you now use `typefox/monaco-editor-react`. But if you need to use `@monaco-editor/react`, then add the `monaco-editor` import at the top of your editor component file [source](https://github.com/suren-atoyan/monaco-react#use-monaco-editor-as-an-npm-package): ```javascript -import * as monaco from "monaco-editor"; -import { loader } from "@monaco-editor/react"; +import * as monaco from 'monaco-editor'; +import { loader } from '@monaco-editor/react'; loader.config({ monaco }); ``` @@ -216,14 +218,17 @@ Monaco Language Client requires a browser environment and will not run during Se // ex. pages/editor.tsx import dynamic from 'next/dynamic'; -const MyEditorComponent = dynamic(async () => { - const comp = await import('@typefox/monaco-editor-react'); - const { window, workspace, Uri } = (await import('vscode')); - // ... cont setup -}, { - ssr: false, - loading: () =>

Loading Editor...

-}); +const MyEditorComponent = dynamic( + async () => { + const comp = await import('@typefox/monaco-editor-react'); + const { window, workspace, Uri } = await import('vscode'); + // ... cont setup + }, + { + ssr: false, + loading: () =>

Loading Editor...

+ } +); export default function EditorPage() { return ; @@ -244,17 +249,19 @@ For more details, see the [Next.js example](./../../verify/next). Uncaught Error: Unexpected non—whitespace character after JSON at position 2 SyntaxError: Unexpected non—whitespace character after JSON at position 2 - at JSON. parse («anonymous>) + at JSON. parse («anonymous>) ``` Then it's likely you have an old version of `buffer` interfering (see [#538](https://github.com/TypeFox/monaco-languageclient/issues/538) and [#546](https://github.com/TypeFox/monaco-languageclient/issues/546)). You can enforce a current version by adding a `resolution` as shown below to your projects' `package.json`. ```json { - "resolutions": { // For Yarn + "resolutions": { + // For Yarn "buffer": "~6.0.3" }, - "overrides": { // For npm/pnpm + "overrides": { + // For npm/pnpm "buffer": "~6.0.3" } } @@ -272,11 +279,11 @@ Then it's likely you have an old version of `buffer` interfering (see [#538](htt - **Async Tokenization**: For large files, enable asynchronous tokenization in your editor configuration: - ```json - { - "editor.experimental.asyncTokenization": true - } - ``` + ```json + { + "editor.experimental.asyncTokenization": true + } + ``` - **Web Workers**: Offload language server processing to a Web Worker to keep the main UI thread responsive. @@ -290,8 +297,8 @@ To see detailed logs from the language client and server communication, set the import { LogLevel } from '@codingame/monaco-vscode-api'; const vscodeApiConfig = { - // ... - logLevel: LogLevel.Debug + // ... + logLevel: LogLevel.Debug }; ``` diff --git a/docs/installation.md b/docs/installation.md index 356f9066c..64a23228e 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -57,7 +57,7 @@ If using npm or pnpm, and your dependencies already contain a reference to `mona ```json { "overrides": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.2" } } ``` @@ -71,7 +71,7 @@ In yarn you have to specify `resolutions` instead of `overrides`: ```json { "resolutions": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@^26.2.2" } } ``` @@ -83,17 +83,17 @@ If using pnpm, you have to add more transitive dependencies that npm or yarn aut ```json { "dependencies": { - "@codingame/monaco-vscode-api": "^26.2.1", - "@codingame/monaco-vscode-configuration-service-override": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-editor-service-override": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "^26.2.1", - "@codingame/monaco-vscode-languages-service-override": "^26.2.1", - "@codingame/monaco-vscode-localization-service-override": "^26.2.1", - "@codingame/monaco-vscode-log-service-override": "^26.2.1", - "@codingame/monaco-vscode-model-service-override": "^26.2.1", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1" + "@codingame/monaco-vscode-api": "^26.2.2", + "@codingame/monaco-vscode-configuration-service-override": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-editor-service-override": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "^26.2.2", + "@codingame/monaco-vscode-languages-service-override": "^26.2.2", + "@codingame/monaco-vscode-localization-service-override": "^26.2.2", + "@codingame/monaco-vscode-log-service-override": "^26.2.2", + "@codingame/monaco-vscode-model-service-override": "^26.2.2", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2" } } ``` @@ -113,7 +113,7 @@ export default defineConfig({ resolve: { dedupe: ['vscode'] } -}) +}); ``` This ensures that only one version of the `vscode` package is used, in case you have multiple dependencies that reference differing versions. diff --git a/docs/migration.md b/docs/migration.md index 1877b57c8..fe7a8d6cf 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -19,21 +19,21 @@ Instead of using `MonacoEditorLanguageClientWrapper` to `init` the configuration import { MonacoEditorLanguageClientWrapper, type WrapperConfig } from 'monaco-editor-wrapper'; const wrapperConfig: WrapperConfig = { - $type: 'extended', - htmlContainer: document.getElementById('monaco-editor-root')!, - vscodeApiConfig: { - // ... - }, - languageClientConfigs: { - configs: { - myLang: { - // ... - } - } - }, - editorAppConfig: { + $type: 'extended', + htmlContainer: document.getElementById('monaco-editor-root')!, + vscodeApiConfig: { + // ... + }, + languageClientConfigs: { + configs: { + myLang: { // ... + } } + }, + editorAppConfig: { + // ... + } }; const wrapper = new MonacoEditorLanguageClientWrapper(); @@ -104,11 +104,11 @@ const wrapperConfig: WrapperConfig = { ```ts const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } - // ... + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } + // ... }; ``` @@ -154,22 +154,22 @@ const wrapperConfig: WrapperConfig = { ```ts const languageClientConfig: LanguageClientConfig = { - languageId, - connection: { - options: { - $type: 'WebSocketUrl', - // at this url the language server for myLang must be reachable - url: 'ws://localhost:30000/myLangLS' - } - }, - clientOptions: { - documentSelector: [languageId], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.file('/workspace') - } + languageId, + connection: { + options: { + $type: 'WebSocketUrl', + // at this url the language server for myLang must be reachable + url: 'ws://localhost:30000/myLangLS' } + }, + clientOptions: { + documentSelector: [languageId], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.file('/workspace') + } + } }; const lcWrapper = new LanguageClientWrapper(languageClientConfig); @@ -183,14 +183,14 @@ await lcWrapper.start(); ```ts const lcManager = new LanguageClientManager(); const languageClientConfigs: LanguageClientConfigs = { - configs: { - myLang1: { - // ... - }, - myLang2: { - // ... - } + configs: { + myLang1: { + // ... + }, + myLang2: { + // ... } + } }; await lcManager.setConfigs(languageClientConfigs); @@ -228,13 +228,13 @@ const wrapperConfig: WrapperConfig = { ```ts const editorAppConfig: EditorAppConfig = { - codeResources: { - main: { - text: code, - uri: codeUri - } - }, - // ... + codeResources: { + main: { + text: code, + uri: codeUri + } + } + // ... }; ``` @@ -251,24 +251,26 @@ const editorAppConfig: EditorAppConfig = { ```tsx { - console.error(e); - }} /> + wrapperConfig={appConfig.wrapperConfig} + style={{ height: '100%' }} + onError={(e) => { + console.error(e); + }} +/> ``` ```tsx { - console.error(e); - }} /> + vscodeApiConfig={appConfig.vscodeApiConfig} + editorAppConfig={appConfig.editorAppConfig} + languageClientConfig={appConfig.languageClientConfig} + style={{ height: '100%' }} + onError={(e) => { + console.error(e); + }} +/> ``` @@ -310,13 +312,13 @@ import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-langu import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'classic', - viewsConfig: { - $type: 'EditorService' - }, - serviceOverrides: { - ...getKeybindingsServiceOverride() - } + $type: 'classic', + viewsConfig: { + $type: 'EditorService' + }, + serviceOverrides: { + ...getKeybindingsServiceOverride() + } }; const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); await apiWrapper.start(); diff --git a/docs/versions-and-history.md b/docs/versions-and-history.md index e2c83440e..689bf0c41 100644 --- a/docs/versions-and-history.md +++ b/docs/versions-and-history.md @@ -4,89 +4,89 @@ The following table describes which version of **monaco-languageclient** and **@codingame/monaco-vscode-api** are compatible with a specific version of **monaco-editor** and **vscode**. The listing starts with version 2.0.0 because **@codingame/monaco-vscode-api** was introduced for the first time. -| monaco-languageclient | vscode-ws-jsonrpc | monaco-editor-wrapper | monaco-editor-react | monaco-vscode-api / editor-api | vscode | monaco-editor | release date | comment | -| :---- | :---- | :---- | :--- | :--- | :--- | :--- | :--- | :--- | -| 10.8.0 | 3.5.0 | 7.8.0 | | 26.2.1 | 1.109.0 | 0.55.1 | unreleased | | -| 10.7.0 | 3.5.0 | 7.7.0 | | 25.1.2 | 1.108.2 | 0.55.1 | 2026-02-04 | | -| 10.6.0 | 3.5.0 | 7.6.0 | | 25.0.0 | 1.108.0 | 0.55.1 | 2026-01-14 | | -| 10.5.0 | 3.5.0 | 7.5.0 | | 24.2.0 | 1.107.1 | 0.55.1 | 2025-12-23 | | -| 10.4.0 | 3.5.0 | 7.4.0 | | 23.2.2 | 1.106.2 | 0.55.1 | 2025-11-26 | | -| 10.3.0 | 3.5.0 | 7.3.0 | | 23.0.0 | 1.106.0 | 0.54.0 | 2025-11-16 | | -| 10.2.0 | 3.5.0 | 7.2.0 | | 22.1.0 | 1.105.0 | 0.54.0 | 2025-10-20 | | -| 10.1.0 | 3.5.0 | 7.1.0 | | 21.3.2 | 1.104.2 | 0.53.0 | 2025-09-30 | | -| 10.0.0 | 3.5.0 | 7.0.0 | | 21.1.0 | 1.104.0 | 0.53.0 | 2025-09-19 | | -| 9.11.0 | 3.5.0 | 6.12.0 | 6.12.0 | 20.2.1 | 1.103.1 | 0.52.2 | 2025-08-21 | | -| 9.10.0 | 3.5.0 | 6.11.0 | 6.11.0 | 20.1.1 | 1.103.1 | 0.52.2 | 2025-08-14 | | -| 9.9.0 | 3.5.0 | 6.10.0 | 6.10.0 | 19.1.4 | 1.102.3 | 0.52.2 | 2025-08-11 | | -| 9.8.0 | 3.4.0 | 6.9.0 | 6.9.0 | 18.1.0 | 1.101.1 | 0.52.2 | 2025-06-24 | | -| 9.7.1 | 3.4.0 | 6.8.1 | 6.8.1 | 17.2.1 | 1.100.3 | 0.52.2 | 2025-06-17 | | -| 9.7.0 | 3.4.0 | 6.8.0 | 6.8.0 | 17.1.2 | 1.100.2 | 0.52.2 | 2025-05-28 | | -| 9.6.0 | 3.4.0 | 6.7.0 | 6.7.0 | 16.1.1 | 1.99.3 | 0.52.2 | 2025-05-06 | | -| 9.5.0 | 3.4.0 | 6.6.0 | 6.6.0 | 15.0.2 | 1.97.2 | 0.52.2 | 2025-03-13 | | -| 9.4.0 | 3.4.0 | 6.4.0 | 6.4.0 | 14.0.4 | 1.97.2 | 0.52.2 | 2025-02-18 | | -| 9.3.0 | 3.4.0 | 6.3.0 | 6.3.0 | 14.0.2 | 1.97.0 | 0.52.2 | 2025-02-12 | | -| 9.2.5 | 3.4.0 | 6.2.5 | 6.2.5 | 13.1.6 | 1.96.4 | 0.52.2 | 2025-02-08 | | -| 9.2.4 | 3.4.0 | 6.2.4 | 6.2.4 | 13.1.4 | 1.96.4 | 0.52.2 | 2025-02-06 | | -| 9.2.3 | 3.4.0 | 6.2.3 | 6.2.3 | 13.1.3 | 1.96.4 | 0.52.2 | 2025-02-04 | | -| 9.2.2 | 3.4.0 | 6.2.2 | 6.2.2 | 13.1.2 | 1.96.4 | 0.52.2 | 2025-02-03 | | -| 9.2.1 | 3.4.0 | 6.2.1 | 6.2.1 | 13.1.1 | 1.96.4 | 0.52.2 | 2025-01-31 | | -| 9.2.0 | 3.4.0 | 6.2.0 | 6.2.0 | 13.1.1 | 1.96.4 | 0.52.2 | 2025-01-31 | | -| 9.1.1 | 3.4.0 | 6.1.1 | 6.1.1 | 11.1.2 | 1.95.3 | 0.52.0 | 2025-01-20 | | -| 9.1.0 | 3.4.0 | 6.1.0 | 6.1.0 | 11.1.2 | 1.95.3 | 0.52.0 | 2025-01-10 | | -| 9.0.0 | 3.4.0 | 6.0.0 | 6.0.0 | 11.1.2 | 1.95.3 | 0.52.0 | 2024-12-18 | | -| 8.8.3 | 3.3.2 | 5.5.3 | 4.5.3 | 8.0.4 | 1.92.2 | 0.51.0 | 2024-08-26 | | -| 8.8.2 | 3.3.2 | 5.5.2 | 4.5.2 | 8.0.2 | 1.92.2 | 0.50.0 | 2024-08-21 | | -| 8.8.1 | 3.3.2 | 5.5.1 | 4.5.1 | 8.0.1 | 1.92.1 | 0.50.0 | 2024-08-12 | | -| 8.8.0 | 3.3.2 | 5.5.0 | 4.5.0 | 8.0.0 | 1.92.0 | 0.50.0 | 2024-08-08 | | -| 8.7.0 | 3.3.2 | 5.4.0 | 4.4.0 | 7.0.7 | 1.91.1 | 0.50.0 | 2024-07-16 | | -| 8.6.0 | 3.3.2 | 5.3.1 | 4.3.2 | 6.0.3 | 1.90.0 | 0.50.0 | 2024-07-02 | | -| 8.6.0 | 3.3.2 | 5.3.0 | 4.3.0 | 6.0.3 | 1.90.0 | 0.50.0 | 2024-06-29 | | -| 8.5.0 | 3.3.2 | 5.2.0 | 4.2.0 | 5.2.0 | 1.89.1 | 0.48.0 | 2024-06-04 | | -| 8.4.0 | 3.3.1 | 5.1.2 | 4.1.2 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-17 | | -| 8.4.0 | 3.3.1 | 5.1.1 | 4.1.1 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-15 | | -| 8.4.0 | 3.3.1 | 5.1.0 | 4.1.0 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-15 | | -| 8.4.0 | 3.3.1 | 5.0.0 | 4.0.0 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-15 | | -| 8.3.1 | 3.3.1 | 4.2.1 | 3.2.1 | 4.3.2 | 1.88.1 | 0.47.0 | 2024-04-17 | | -| 8.3.0 | 3.3.1 | 4.2.0 | 3.2.0 | 4.2.1 | 1.88.1 | 0.47.0 | 2024-04-12 | | -| 8.2.0 | 3.3.1 | 4.1.0 | 3.1.0 | 4.1.2 | 1.88.0 | 0.47.0 | 2024-04-10 | | -| 8.1.1 | 3.3.0 | 4.0.2 | 3.0.2 | 3.2.3 | 1.87.2 | 0.47.0 | 2024-04-03 | | -| 8.1.0 | 3.3.0 | 4.0.1 | 3.0.1 | 3.2.1 | 1.87.2 | 0.47.0 | 2024-03-22 | | -| 8.0.0 | 3.3.0 | 4.0.0 | 3.0.0 | 3.1.2 | 1.87.2 | 0.47.0 | 2024-03-18 | `@codingame/monaco-vscode-api` implements its own versioning scheme
`@codingame/monaco-vscode-editor-api` replaces
`@codingame/monaco-editor-treemended`
Added `monaco-editor-wrapper` and `@typefox/monaco-editor-react` to the table | -| 7.3.0 | 3.2.0 | | | 1.85.0 | 1.85.0 | 0.45.0 | 2024-01-04 | | -| 7.2.0 | 3.1.0 | | | 1.83.16 | 1.83.16 | 0.44.0 | 2023-12-07 | | -| 7.1.0 | 3.1.0 | | | 1.83.12 | 1.83.12 | 0.44.0 | 2023-11-27 | | -| 7.0.2 | 3.1.0 | | | 1.83.7 | 1.83.7 | 0.44.0 | 2023-11-02 | | -| 7.0.1 | 3.1.0 | | | 1.83.5 | 1.83.5 | 0.44.0 | 2023-11-10 | | -| 7.0.0 | 3.1.0 | | | 1.83.5 | 1.83.5 | 0.44.0 | 2023-11-02 | Introduction of `@codingame/monaco-editor-treemended` | -| 6.6.1 | 3.0.0 | | | 1.83.3 | | 0.44.0 | 2023-10-20 | | -| 6.6.0 | 3.0.0 | | | 1.83.2 | | 0.44.0 | 2023-10-16 | | -| 6.5.3 | 3.0.0 | | | 1.82.5 | | 0.43.0 | 2023-10-11 | | -| 6.5.2 | 3.0.0 | | | 1.82.4 | | 0.43.0 | 2023-10-07 | | -| 6.5.1 | 3.0.0 | | | 1.82.3 | | 0.43.0 | 2023-10-04 | | -| 6.5.0 | 3.0.0 | | | 1.82.2 | | 0.43.0 | 2023-09-29 | | -| 6.4.6 | 3.0.0 | | | 1.81.7 | | 0.41.0 | 2023-09-05 | | -| 6.4.5 | 3.0.0 | | | 1.81.5 | | 0.41.0 | 2023-08-30 | | -| 6.4.4 | 3.0.0 | | | 1.81.5 | | 0.41.0 | 2023-08-24 | | -| 6.4.3 | 3.0.0 | | | 1.81.3 | | 0.41.0 | 2023-08-22 | | -| 6.4.2 | 3.0.0 | | | 1.81.2 | | 0.41.0 | 2023-08-19 | | -| 6.4.1 | 3.0.0 | | | 1.81.1 | | 0.41.0 | 2023-08-18 | | -| 6.4.0 | 3.0.0 | | | 1.81.0 | | 0.41.0 | 2023-08-10 | | -| 6.3.0 | 3.0.0 | | | 1.80.2 | | 0.40.0 | 2023-08-04 | | -| 6.2.0 | 3.0.0 | | | 1.79.3 | | 0.39.0 | 2023-06-16 | | -| 6.1.0 | 3.0.0 | | | 1.79.1 | | 0.38.0 | 2023-06-12 | | -| 6.0.3 | 3.0.0 | | | 1.78.8 | | 0.37.1 | 2023-05-31 | | -| 6.0.2 | 3.0.0 | | | 1.78.6 | | 0.37.1 | 2023-05-24 | | -| 6.0.1 | 3.0.0 | | | 1.78.6 | | 0.37.1 | 2023-05-12 | | -| 6.0.0 | 3.0.0 | | | 1.78.5 | | 0.37.1 | 2023-05-04 | | -| 5.0.1 | 3.0.0 | | | 1.76.6 | | 0.36.1 | 2023-04-05 | | -| 5.0.0 | 3.0.0 | | | 1.76.6 | | 0.36.1 | 2023-04-04 | | -| 4.0.3 | 2.0.2 | | | 1.69.13 | | 0.34.1 | | | -| 4.0.1 | 2.0.2 | | | 1.69.12 | | 0.34.1 | | | -| 4.0.0 | 2.0.2 | | | 1.69.10 | | 0.34.0 | | | -| 3.0.1 | 2.0.2 | | | 1.69.9 | | 0.34.0 | | | -| 3.0.0 | 2.0.2 | | | 1.69.0 | | 0.34.0 | | | -| 2.1.0 | 2.0.2 | | | 1.67.20 | | 0.33.0 | | monaco-editor and vscode compatible again | -| 2.0.0 - 2.0.2 | 2.0.2 | | | 1.68.4 | | 0.33.0 | | monaco-editor and vscode incompatible | +| monaco-languageclient | vscode-ws-jsonrpc | monaco-editor-wrapper | monaco-editor-react | monaco-vscode-api / editor-api | vscode | monaco-editor | release date | comment | +| :-------------------- | :---------------- | :-------------------- | :------------------ | :----------------------------- | :------ | :------------ | :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 10.8.0 | 3.5.0 | 7.8.0 | | 26.2.2 | 1.109.0 | 0.55.1 | unreleased | | +| 10.7.0 | 3.5.0 | 7.7.0 | | 25.1.2 | 1.108.2 | 0.55.1 | 2026-02-04 | | +| 10.6.0 | 3.5.0 | 7.6.0 | | 25.0.0 | 1.108.0 | 0.55.1 | 2026-01-14 | | +| 10.5.0 | 3.5.0 | 7.5.0 | | 24.2.0 | 1.107.1 | 0.55.1 | 2025-12-23 | | +| 10.4.0 | 3.5.0 | 7.4.0 | | 23.2.2 | 1.106.2 | 0.55.1 | 2025-11-26 | | +| 10.3.0 | 3.5.0 | 7.3.0 | | 23.0.0 | 1.106.0 | 0.54.0 | 2025-11-16 | | +| 10.2.0 | 3.5.0 | 7.2.0 | | 22.1.0 | 1.105.0 | 0.54.0 | 2025-10-20 | | +| 10.1.0 | 3.5.0 | 7.1.0 | | 21.3.2 | 1.104.2 | 0.53.0 | 2025-09-30 | | +| 10.0.0 | 3.5.0 | 7.0.0 | | 21.1.0 | 1.104.0 | 0.53.0 | 2025-09-19 | | +| 9.11.0 | 3.5.0 | 6.12.0 | 6.12.0 | 20.2.1 | 1.103.1 | 0.52.2 | 2025-08-21 | | +| 9.10.0 | 3.5.0 | 6.11.0 | 6.11.0 | 20.1.1 | 1.103.1 | 0.52.2 | 2025-08-14 | | +| 9.9.0 | 3.5.0 | 6.10.0 | 6.10.0 | 19.1.4 | 1.102.3 | 0.52.2 | 2025-08-11 | | +| 9.8.0 | 3.4.0 | 6.9.0 | 6.9.0 | 18.1.0 | 1.101.1 | 0.52.2 | 2025-06-24 | | +| 9.7.1 | 3.4.0 | 6.8.1 | 6.8.1 | 17.2.1 | 1.100.3 | 0.52.2 | 2025-06-17 | | +| 9.7.0 | 3.4.0 | 6.8.0 | 6.8.0 | 17.1.2 | 1.100.2 | 0.52.2 | 2025-05-28 | | +| 9.6.0 | 3.4.0 | 6.7.0 | 6.7.0 | 16.1.1 | 1.99.3 | 0.52.2 | 2025-05-06 | | +| 9.5.0 | 3.4.0 | 6.6.0 | 6.6.0 | 15.0.2 | 1.97.2 | 0.52.2 | 2025-03-13 | | +| 9.4.0 | 3.4.0 | 6.4.0 | 6.4.0 | 14.0.4 | 1.97.2 | 0.52.2 | 2025-02-18 | | +| 9.3.0 | 3.4.0 | 6.3.0 | 6.3.0 | 14.0.2 | 1.97.0 | 0.52.2 | 2025-02-12 | | +| 9.2.5 | 3.4.0 | 6.2.5 | 6.2.5 | 13.1.6 | 1.96.4 | 0.52.2 | 2025-02-08 | | +| 9.2.4 | 3.4.0 | 6.2.4 | 6.2.4 | 13.1.4 | 1.96.4 | 0.52.2 | 2025-02-06 | | +| 9.2.3 | 3.4.0 | 6.2.3 | 6.2.3 | 13.1.3 | 1.96.4 | 0.52.2 | 2025-02-04 | | +| 9.2.2 | 3.4.0 | 6.2.2 | 6.2.2 | 13.1.2 | 1.96.4 | 0.52.2 | 2025-02-03 | | +| 9.2.1 | 3.4.0 | 6.2.1 | 6.2.1 | 13.1.1 | 1.96.4 | 0.52.2 | 2025-01-31 | | +| 9.2.0 | 3.4.0 | 6.2.0 | 6.2.0 | 13.1.1 | 1.96.4 | 0.52.2 | 2025-01-31 | | +| 9.1.1 | 3.4.0 | 6.1.1 | 6.1.1 | 11.1.2 | 1.95.3 | 0.52.0 | 2025-01-20 | | +| 9.1.0 | 3.4.0 | 6.1.0 | 6.1.0 | 11.1.2 | 1.95.3 | 0.52.0 | 2025-01-10 | | +| 9.0.0 | 3.4.0 | 6.0.0 | 6.0.0 | 11.1.2 | 1.95.3 | 0.52.0 | 2024-12-18 | | +| 8.8.3 | 3.3.2 | 5.5.3 | 4.5.3 | 8.0.4 | 1.92.2 | 0.51.0 | 2024-08-26 | | +| 8.8.2 | 3.3.2 | 5.5.2 | 4.5.2 | 8.0.2 | 1.92.2 | 0.50.0 | 2024-08-21 | | +| 8.8.1 | 3.3.2 | 5.5.1 | 4.5.1 | 8.0.1 | 1.92.1 | 0.50.0 | 2024-08-12 | | +| 8.8.0 | 3.3.2 | 5.5.0 | 4.5.0 | 8.0.0 | 1.92.0 | 0.50.0 | 2024-08-08 | | +| 8.7.0 | 3.3.2 | 5.4.0 | 4.4.0 | 7.0.7 | 1.91.1 | 0.50.0 | 2024-07-16 | | +| 8.6.0 | 3.3.2 | 5.3.1 | 4.3.2 | 6.0.3 | 1.90.0 | 0.50.0 | 2024-07-02 | | +| 8.6.0 | 3.3.2 | 5.3.0 | 4.3.0 | 6.0.3 | 1.90.0 | 0.50.0 | 2024-06-29 | | +| 8.5.0 | 3.3.2 | 5.2.0 | 4.2.0 | 5.2.0 | 1.89.1 | 0.48.0 | 2024-06-04 | | +| 8.4.0 | 3.3.1 | 5.1.2 | 4.1.2 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-17 | | +| 8.4.0 | 3.3.1 | 5.1.1 | 4.1.1 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-15 | | +| 8.4.0 | 3.3.1 | 5.1.0 | 4.1.0 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-15 | | +| 8.4.0 | 3.3.1 | 5.0.0 | 4.0.0 | 5.1.1 | 1.89.1 | 0.48.0 | 2024-05-15 | | +| 8.3.1 | 3.3.1 | 4.2.1 | 3.2.1 | 4.3.2 | 1.88.1 | 0.47.0 | 2024-04-17 | | +| 8.3.0 | 3.3.1 | 4.2.0 | 3.2.0 | 4.2.1 | 1.88.1 | 0.47.0 | 2024-04-12 | | +| 8.2.0 | 3.3.1 | 4.1.0 | 3.1.0 | 4.1.2 | 1.88.0 | 0.47.0 | 2024-04-10 | | +| 8.1.1 | 3.3.0 | 4.0.2 | 3.0.2 | 3.2.3 | 1.87.2 | 0.47.0 | 2024-04-03 | | +| 8.1.0 | 3.3.0 | 4.0.1 | 3.0.1 | 3.2.1 | 1.87.2 | 0.47.0 | 2024-03-22 | | +| 8.0.0 | 3.3.0 | 4.0.0 | 3.0.0 | 3.1.2 | 1.87.2 | 0.47.0 | 2024-03-18 | `@codingame/monaco-vscode-api` implements its own versioning scheme
`@codingame/monaco-vscode-editor-api` replaces
`@codingame/monaco-editor-treemended`
Added `monaco-editor-wrapper` and `@typefox/monaco-editor-react` to the table | +| 7.3.0 | 3.2.0 | | | 1.85.0 | 1.85.0 | 0.45.0 | 2024-01-04 | | +| 7.2.0 | 3.1.0 | | | 1.83.16 | 1.83.16 | 0.44.0 | 2023-12-07 | | +| 7.1.0 | 3.1.0 | | | 1.83.12 | 1.83.12 | 0.44.0 | 2023-11-27 | | +| 7.0.2 | 3.1.0 | | | 1.83.7 | 1.83.7 | 0.44.0 | 2023-11-02 | | +| 7.0.1 | 3.1.0 | | | 1.83.5 | 1.83.5 | 0.44.0 | 2023-11-10 | | +| 7.0.0 | 3.1.0 | | | 1.83.5 | 1.83.5 | 0.44.0 | 2023-11-02 | Introduction of `@codingame/monaco-editor-treemended` | +| 6.6.1 | 3.0.0 | | | 1.83.3 | | 0.44.0 | 2023-10-20 | | +| 6.6.0 | 3.0.0 | | | 1.83.2 | | 0.44.0 | 2023-10-16 | | +| 6.5.3 | 3.0.0 | | | 1.82.5 | | 0.43.0 | 2023-10-11 | | +| 6.5.2 | 3.0.0 | | | 1.82.4 | | 0.43.0 | 2023-10-07 | | +| 6.5.1 | 3.0.0 | | | 1.82.3 | | 0.43.0 | 2023-10-04 | | +| 6.5.0 | 3.0.0 | | | 1.82.2 | | 0.43.0 | 2023-09-29 | | +| 6.4.6 | 3.0.0 | | | 1.81.7 | | 0.41.0 | 2023-09-05 | | +| 6.4.5 | 3.0.0 | | | 1.81.5 | | 0.41.0 | 2023-08-30 | | +| 6.4.4 | 3.0.0 | | | 1.81.5 | | 0.41.0 | 2023-08-24 | | +| 6.4.3 | 3.0.0 | | | 1.81.3 | | 0.41.0 | 2023-08-22 | | +| 6.4.2 | 3.0.0 | | | 1.81.2 | | 0.41.0 | 2023-08-19 | | +| 6.4.1 | 3.0.0 | | | 1.81.1 | | 0.41.0 | 2023-08-18 | | +| 6.4.0 | 3.0.0 | | | 1.81.0 | | 0.41.0 | 2023-08-10 | | +| 6.3.0 | 3.0.0 | | | 1.80.2 | | 0.40.0 | 2023-08-04 | | +| 6.2.0 | 3.0.0 | | | 1.79.3 | | 0.39.0 | 2023-06-16 | | +| 6.1.0 | 3.0.0 | | | 1.79.1 | | 0.38.0 | 2023-06-12 | | +| 6.0.3 | 3.0.0 | | | 1.78.8 | | 0.37.1 | 2023-05-31 | | +| 6.0.2 | 3.0.0 | | | 1.78.6 | | 0.37.1 | 2023-05-24 | | +| 6.0.1 | 3.0.0 | | | 1.78.6 | | 0.37.1 | 2023-05-12 | | +| 6.0.0 | 3.0.0 | | | 1.78.5 | | 0.37.1 | 2023-05-04 | | +| 5.0.1 | 3.0.0 | | | 1.76.6 | | 0.36.1 | 2023-04-05 | | +| 5.0.0 | 3.0.0 | | | 1.76.6 | | 0.36.1 | 2023-04-04 | | +| 4.0.3 | 2.0.2 | | | 1.69.13 | | 0.34.1 | | | +| 4.0.1 | 2.0.2 | | | 1.69.12 | | 0.34.1 | | | +| 4.0.0 | 2.0.2 | | | 1.69.10 | | 0.34.0 | | | +| 3.0.1 | 2.0.2 | | | 1.69.9 | | 0.34.0 | | | +| 3.0.0 | 2.0.2 | | | 1.69.0 | | 0.34.0 | | | +| 2.1.0 | 2.0.2 | | | 1.67.20 | | 0.33.0 | | monaco-editor and vscode compatible again | +| 2.0.0 - 2.0.2 | 2.0.2 | | | 1.68.4 | | 0.33.0 | | monaco-editor and vscode incompatible | ## Important Project Changes diff --git a/index.html b/index.html index 3ea05380e..4e9a693d3 100644 --- a/index.html +++ b/index.html @@ -1,88 +1,96 @@ - + - - + monaco-languageclient Examples - - + + - +
-

Examples

- - Please run npm run build first. +

Examples

-

Langium

+ Please run npm run build first. - Langium Grammar DSL (Language Server in Worker): [ Example Page ] -
- Langium Statemachine (Language Server in Worker): [ Example Page | React Example Page ] -
-   ->  Localized Versions: [ - cs - - de - - es - - fr - - it - - ja - - ko - - pl - - pt-br - - qps-ploc - - ru - - tr - - zh-hans - - zh-hant ] +

Langium

-

JSON

+ Langium Grammar DSL (Language Server in Worker): [ Example Page ] +
+ Langium Statemachine (Language Server in Worker): [ Example Page | + React Example Page ] +
+   ->  Localized Versions: [ + cs - de - + es - fr - + it - ja - + ko - pl - + pt-br - + qps-ploc - + ru - tr - + zh-hans - + zh-hant ] - Beforehand, start Language Server with: npm run start:example:server:json -
- Extended (Language Server via Web Socket): [ Example Page ] -
- Classic (Language Server via Web Socket): [ Example Page ] -
- Pure Browser Implementation: [ Example Page ] +

JSON

-

Python

- Beforehand, start Language Server with: npm run start:example:server:python
- Debugger runs in container. Beforehand, start it with: docker compose -f ./packages/examples/resources/debugger/docker-compose.yml up -d
- Python (Language Server via Web Socket): [ Example Page | React Example Page ] + Beforehand, start Language Server with: npm run start:example:server:json +
+ Extended (Language Server via Web Socket): [ Example Page ] +
+ Classic (Language Server via Web Socket): [ Example Page ] +
+ Pure Browser Implementation: [ Example Page ] -

Java / Eclipse JDT LS

- Language Server runs in container. Beforehand, start it with: docker compose -f ./packages/examples/resources/eclipse.jdt.ls/docker-compose.yml up -d
- Java (Language Server via Web Socket): [ Example Page ] +

Python

+ Beforehand, start Language Server with: npm run start:example:server:python
+ Debugger runs in container. Beforehand, start it with: + docker compose -f ./packages/examples/resources/debugger/docker-compose.yml up -d
+ Python (Language Server via Web Socket): [ Example Page | + React Example Page ] -

Groovy

- Language Server runs in container. Beforehand, start it with: docker compose -f ./packages/examples/resources/groovy/docker-compose.yml up -d
- Groovy (Language Server via Web Socket): [ Example Page ] +

Java / Eclipse JDT LS

+ Language Server runs in container. Beforehand, start it with: + docker compose -f ./packages/examples/resources/eclipse.jdt.ls/docker-compose.yml up -d
+ Java (Language Server via Web Socket): [ Example Page ] -

Cpp / Clangd

- Cpp (Language Server in Worker/Wasm): [ Example Page ] +

Groovy

+ Language Server runs in container. Beforehand, start it with: + docker compose -f ./packages/examples/resources/groovy/docker-compose.yml up -d
+ Groovy (Language Server via Web Socket): [ Example Page ] -

Multi-Language Client

- Json & Python Language Clients App: [ Example Page ] (Requires Json and Python Language Servers, see above) -

Application Playground

- Application Playground (incl. Open Collaboration Tools): [ Example Page | React Example Page ] -

TypeScript

- TypeScript Extension Host Worker: [ Example Page ] +

Cpp / Clangd

+ Cpp (Language Server in Worker/Wasm): [ Example Page ] -

Tools & Framework Verification Examples

-

Vite

- Beforehand, start: cd verify/vite && npm run verify
- JSON example (vite build): [ Example Page ] -

Webpack

- Beforehand, start: cd verify/webpack && npm run verify
- JSON example (webpack build): [ Example Page ] -

Next.js

- Beforehand, start: cd verify/next && npm run verify
- Langium DSL example (Next.js Dev Server): [ Example Page ] -

Angular

- Beforehand, start: cd verify/angular && npm run verify
- JSON example (Angular/vite build): [ Example Page ] -
- +

Multi-Language Client

+ Json & Python Language Clients App: [ Example Page ] (Requires Json and + Python Language Servers, see above) +

Application Playground

+ Application Playground (incl. Open Collaboration Tools): [ Example Page | + React Example Page ] +

TypeScript

+ TypeScript Extension Host Worker: [ Example Page ] +

Tools & Framework Verification Examples

+

Vite

+ Beforehand, start: cd verify/vite && npm run verify
+ JSON example (vite build): [ Example Page ] +

Webpack

+ Beforehand, start: cd verify/webpack && npm run verify
+ JSON example (webpack build): [ Example Page ] +

Next.js

+ Beforehand, start: cd verify/next && npm run verify
+ Langium DSL example (Next.js Dev Server): [ Example Page ] +

Angular

+ Beforehand, start: cd verify/angular && npm run verify
+ JSON example (Angular/vite build): [ Example Page ] + + diff --git a/package-lock.json b/package-lock.json index 035e1f9ac..723320fe8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,18 +12,19 @@ "packages/examples" ], "devDependencies": { - "@codingame/monaco-vscode-rollup-vsix-plugin": "^26.2.1", + "@codingame/monaco-vscode-rollup-vsix-plugin": "^26.2.2", "@testing-library/react": "~16.3.2", "@types/node": "~24.10.15", "@types/react": "~19.2.14", "@types/react-dom": "~19.2.3", - "@typescript/native-preview": "~7.0.0-dev.20260302.1", + "@typescript/native-preview": "~7.0.0-dev.20260305.1", "@vitest/browser": "~4.0.18", "@vitest/browser-playwright": "~4.0.18", "@vitest/coverage-v8": "~4.0.18", "editorconfig": "~3.0.2", "esbuild": "~0.27.3", "minimatch": "~10.2.4", + "oxfmt": "~0.36.0", "oxlint": "~1.51.0", "oxlint-tsgolint": "~0.16.0", "shx": "~0.4.0", @@ -162,18 +163,18 @@ "license": "Apache-2.0" }, "node_modules/@codingame/monaco-vscode-api": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-api/-/monaco-vscode-api-26.2.1.tgz", - "integrity": "sha512-fyW5QlJidBbbz15lHfUi3er67mUaIWjQaTrapu01ooaiN6+Gocoayk3DGn23Aa1mY2P/u8TJesbE+CTOyEF/Bg==", - "license": "MIT", - "dependencies": { - "@codingame/monaco-vscode-base-service-override": "26.2.1", - "@codingame/monaco-vscode-environment-service-override": "26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1", - "@codingame/monaco-vscode-host-service-override": "26.2.1", - "@codingame/monaco-vscode-layout-service-override": "26.2.1", - "@codingame/monaco-vscode-quickaccess-service-override": "26.2.1", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-api/-/monaco-vscode-api-26.2.2.tgz", + "integrity": "sha512-WnetFOCxs+zBEChh22D+ipvudXvrTZn42JQv3sSmvf48Och4TnCW/E8bTGmQ+xhZYO8T4b+70n4J6jYqLlqpgg==", + "license": "MIT", + "dependencies": { + "@codingame/monaco-vscode-base-service-override": "26.2.2", + "@codingame/monaco-vscode-environment-service-override": "26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2", + "@codingame/monaco-vscode-host-service-override": "26.2.2", + "@codingame/monaco-vscode-layout-service-override": "26.2.2", + "@codingame/monaco-vscode-quickaccess-service-override": "26.2.2", "@vscode/iconv-lite-umd": "0.7.1", "dompurify": "3.3.1", "jschardet": "3.1.4", @@ -181,421 +182,421 @@ } }, "node_modules/@codingame/monaco-vscode-base-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-base-service-override/-/monaco-vscode-base-service-override-26.2.1.tgz", - "integrity": "sha512-qaOou8Z6ewk2yB5ey3mrXRYPtk00Gtp7Y5E2ys+vslhf5NBzIT9XMrV88nPAim+hVJ8WW7+MW9E5nrWjdngIMw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-base-service-override/-/monaco-vscode-base-service-override-26.2.2.tgz", + "integrity": "sha512-E97AVIKDtQgZmRaIkZgwLmsoOVt5pWzaSj0nwRcvH2V/ikO0ksxOJ+CkoVQ4VYPjw/+tVmQ1A1S5CsREAQwhbQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-bulk-edit-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-bulk-edit-service-override/-/monaco-vscode-bulk-edit-service-override-26.2.1.tgz", - "integrity": "sha512-0QCgLNQFNx4RUzZ+fpgnj3Md8NdZv+nN1rm3qdUUElaLsA/z5E7TSn847t5xYFhWVx6FUBoS4K9pha2OheUUng==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-bulk-edit-service-override/-/monaco-vscode-bulk-edit-service-override-26.2.2.tgz", + "integrity": "sha512-hxjdSmzD18TcNjeT5b1byuf4saSizktEE8aNvwYn/pJGHQLnfJFaF37tr+fPYJmfF0Wl10s9oxNZrxYZZYbJvw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-configuration-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-configuration-service-override/-/monaco-vscode-configuration-service-override-26.2.1.tgz", - "integrity": "sha512-8RSHtb97u0Diiohk5zbK167KmhnB5zuddCGkpKaIV5mg9T0qkOT1QlfZ3hpAHCy57UwZJWs3i4gQyYYq1cynvQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-configuration-service-override/-/monaco-vscode-configuration-service-override-26.2.2.tgz", + "integrity": "sha512-DbF4hI3YPg0GWxM+z/7n2e92hS9oY5XxauHhvRpfFB4UfF5nnJ2GzWSVBsgG79mk2Y9njm8z3Ski5LnG14VvQw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-cpp-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-cpp-default-extension/-/monaco-vscode-cpp-default-extension-26.2.1.tgz", - "integrity": "sha512-EcW1Oi2ipnlxgqQXfKMbontgmd6Ivvr7qQC+353npArB8l13acs/lwEuFyFptBNWsdcqWgrsFRmnEfUBBsZ1OA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-cpp-default-extension/-/monaco-vscode-cpp-default-extension-26.2.2.tgz", + "integrity": "sha512-Jv7UWp3N4zqeIZ9VNuRpbo7f89thO1upLeLbxPIejTH7sSVT/N1U+UsLWp+KZpK7AmeIQqeoLBxMfC0mAj6a8A==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-debug-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-debug-service-override/-/monaco-vscode-debug-service-override-26.2.1.tgz", - "integrity": "sha512-ADtfdB5rAXKiZjSZz+WWljuPjHgEbNxIR9UeBlUMDCJ4BwMtNg3vEEHfKhu+g/9p2/HhmoEYcQWuo97txXNsnA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-debug-service-override/-/monaco-vscode-debug-service-override-26.2.2.tgz", + "integrity": "sha512-7FhtkszuvV5gVvq3LjIdYuSpC2afuqUloFpUk5Yeh+CAtCTeWoE84SY+O4t8efVjRiN//oyrCUpb8y86IlWmdQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-editor-api": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-api/-/monaco-vscode-editor-api-26.2.1.tgz", - "integrity": "sha512-xWBNiE2zY0t4c3jZU3NeNccaZ0Z0qlyEOwSZOoC9W0cPy8yXoI2QbIdElKUuXux02y290j5uJF8x/S3Hx9PeNg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-api/-/monaco-vscode-editor-api-26.2.2.tgz", + "integrity": "sha512-F8XTkB+9CAv+9XKpdWVdjaNK17WDvkhdF0Ko19V4Kk4f73t9R8mqv1HC/g/BNXLbKbOuwUUsX96pXO1UnA+Dng==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-editor-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-service-override/-/monaco-vscode-editor-service-override-26.2.1.tgz", - "integrity": "sha512-X1s6eQ+He6XwwubNsKfr0SAejcNpquAkezIYcU7npBRPskkZE9diXN9s/40S1lou7KZWegFDsb1Qr9V2AXMclA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-service-override/-/monaco-vscode-editor-service-override-26.2.2.tgz", + "integrity": "sha512-WuRFcvBTAs1bc7uoRnZymTEGOLqDPR3ZWnKpgbCHEAQNHBGPNbcQvKHbuhPTYvs4M2JyPFw2mfAHOzqGaHHeBg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-environment-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-environment-service-override/-/monaco-vscode-environment-service-override-26.2.1.tgz", - "integrity": "sha512-tl3CtoOpjc73q5CntNWIjV6kZNHkqQmxNbZfP3HFdZhLyR6dVbMivMd/coz6n/+tqiGpDIL2bmTJEvRq3ZTM0w==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-environment-service-override/-/monaco-vscode-environment-service-override-26.2.2.tgz", + "integrity": "sha512-Rq+pDxsSs/H0Bkr3BHcvyOKNTD9znu0k0ayG78SljjKsYUqoHnNbBolKwT8euK9kaMesMBxTfOInZkqtf+nJAg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-explorer-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-explorer-service-override/-/monaco-vscode-explorer-service-override-26.2.1.tgz", - "integrity": "sha512-5wSnDvDFHESG0SuD8zWf+mDIXAqA/BV0zN6hgHEoKtnZV0Gsewls1scusc6W3VFMaMNVuOx1+5UZvRrZa+vQXg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-explorer-service-override/-/monaco-vscode-explorer-service-override-26.2.2.tgz", + "integrity": "sha512-01OvvivTpRhrpWpyTiDLakn9nxEbZUxwJUNaocESXD7JRlicYwNzBC8CrhHLxc41Q6bBGqkQrllGLPuy9d8oGg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-extension-api": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extension-api/-/monaco-vscode-extension-api-26.2.1.tgz", - "integrity": "sha512-6gKBpM+UMMILFJlhgPNPGPlpLiiqaqR6/lQ0CoS3QDEO0JosUYoF9NG1lJNaS4LIWrQ5Zy31bFyG/wbjb/LKgA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extension-api/-/monaco-vscode-extension-api-26.2.2.tgz", + "integrity": "sha512-aQ6i4F610ApCp8X9x934fIXBn3DyJml5nNh7Aw8N2JJNIwcbJVsHVCk9dPG+MsqknhK85xolo2E8Is6ycuoT5g==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-extensions-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extensions-service-override/-/monaco-vscode-extensions-service-override-26.2.1.tgz", - "integrity": "sha512-K1hCuSRruQm+NYIP7lO81Omi5M+3ufYiBG9dXoq/o8v63WUWsbPxCx5zO2vJ9qQlYZVxlbHkK6wYuJyCMu84WA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extensions-service-override/-/monaco-vscode-extensions-service-override-26.2.2.tgz", + "integrity": "sha512-8bPY7qYE0F5c9NuGuufq6KQUqPpZCyqz5eimV8lq9O0DlmBJrIgV8Aduvt7YzjOfu++qcsLwY/wAky27bxtr0A==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-files-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-files-service-override/-/monaco-vscode-files-service-override-26.2.1.tgz", - "integrity": "sha512-4xazWpPaSqJRF24kD35+/XVCjTxyuxm3+Sld8L0SzONSmk3QrtgXjaJcB2D38OwcC4J7awWUCf09xv8X8xC3uQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-files-service-override/-/monaco-vscode-files-service-override-26.2.2.tgz", + "integrity": "sha512-VXey5FQ7sdheMzT1Yw3Fs/Mkb81ML2p1bWxH53zaKgLAF42RH5QVYIlNabaxN2geFwAPh0iMiaR/iKtNCgmpjw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-groovy-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-groovy-default-extension/-/monaco-vscode-groovy-default-extension-26.2.1.tgz", - "integrity": "sha512-RtpUMN+gnW0Xj/mCrMW0HjC78bCF5D9wnX9+LL5B/hZPG8jhfGXhyAOLqrBBsbRlJG9Qie8m5ClL4pBLd+1F1A==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-groovy-default-extension/-/monaco-vscode-groovy-default-extension-26.2.2.tgz", + "integrity": "sha512-KFLyHi4/YYxiSCVHFCacRlMiytV1fvnbkSsLosQFyV3nm4Oyj3mYdlUceOv74dfydCU/ptinYpeUbbt/HGi01g==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-host-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-host-service-override/-/monaco-vscode-host-service-override-26.2.1.tgz", - "integrity": "sha512-Quy9H69fYQK8uQObEtaPc93TkbLZLkCkXilQRamf00BS7dKhMPYMy5z3T+H9fqD0dT6CJiQ1EWhBd7UmYy5/yA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-host-service-override/-/monaco-vscode-host-service-override-26.2.2.tgz", + "integrity": "sha512-8B9LGnPz9IMbWg7aSQgfMd8FrRXO/SYw5FS6R3gYlVWAz03fdMGEA4QsfL865VFOon8ym5tl1qfIWqt4/32isQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-java-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-java-default-extension/-/monaco-vscode-java-default-extension-26.2.1.tgz", - "integrity": "sha512-3e3qJk/zZTmM8LMSgLqFCDmgeKLqMrAbKO/rigL4rzDNOy/i28vdWs0sF87U1pMMLrwfWictw0m3es+rSUfYyQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-java-default-extension/-/monaco-vscode-java-default-extension-26.2.2.tgz", + "integrity": "sha512-U6zX1QvV6v4e8KMxibeGG7pKYl9TqmR6U/NVHynRrh+0dMtUAE1aTGx36ePXMveaWy9z/MmfrOhgb1L+taHdGQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-javascript-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-javascript-default-extension/-/monaco-vscode-javascript-default-extension-26.2.1.tgz", - "integrity": "sha512-iNTLrmXW4N6+80zpHFf3qFwxbslbcMCRMDdNQVnP6JaSvPkXuUeUY3zJj8jTyiCETNzKuN1+g45xwoRXz1LTbQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-javascript-default-extension/-/monaco-vscode-javascript-default-extension-26.2.2.tgz", + "integrity": "sha512-83q0iGTAhoGf7+gbhheeMy6tcu/XG2JwsVQ6f1koY0Ilm9auPhyjq/VFSgO/lo4Si1PJeaAeY2hupTVsqQkjOQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-json-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-json-default-extension/-/monaco-vscode-json-default-extension-26.2.1.tgz", - "integrity": "sha512-prU24rqEv3q7n5qdcj4Fbd+TdwNZuwrkcSj2In6JErczqf6GrdF2CRlDEKetL/ajld2KELGQaZuxMz8l8GUf5A==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-json-default-extension/-/monaco-vscode-json-default-extension-26.2.2.tgz", + "integrity": "sha512-WTnI4SzYU0rk0cDFlhXUcSWwuirplzr6rZTvcvqKqxrU7pSTWM2Nph0k+7REL8rbrPoc6hQQ0OVOrnmVZQY25w==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-json-language-features-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-json-language-features-default-extension/-/monaco-vscode-json-language-features-default-extension-26.2.1.tgz", - "integrity": "sha512-vhTQ3AmgoBZZbhQpypPl0/6EAdWYO8quGNjuS7oFsha2mnwjwJJeciLd04pw5h5xxwi155UOvsZ0xUuYfbh3ow==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-json-language-features-default-extension/-/monaco-vscode-json-language-features-default-extension-26.2.2.tgz", + "integrity": "sha512-pdYDhKR7HP/iXMUORkrUzHj0s8Tzvgjxn/8CLmwWlGA7drJ7HnuBIQ5QtxCU7u/ctfLVAX6QKBQSWZxSE5ZgZA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-keybindings-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-keybindings-service-override/-/monaco-vscode-keybindings-service-override-26.2.1.tgz", - "integrity": "sha512-98hbiDLGe3mtYkMZHvfiOOaGi4eh6GmTp4IGuG52H01WglkQKQUawLUqdkVf5xTJ4In8OY9rUytV+OeTvXj6DA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-keybindings-service-override/-/monaco-vscode-keybindings-service-override-26.2.2.tgz", + "integrity": "sha512-51rraxwXwL/QRCzmQ+yGCTjEClbn7uNr/3EVZcLomxchT87vuimvt6Lwvfwdg+K3EkpNa+FUqMma7BTkYdMD2w==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-cs": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-cs/-/monaco-vscode-language-pack-cs-26.2.1.tgz", - "integrity": "sha512-tKiq/JUW+CYkKVFRNrzzg/fFUeqxqX/cfZubxTAQrfF3Nx0/jAWtF8xA/d+6rdTQmwUOzVUFYiSKLMXU3YntsA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-cs/-/monaco-vscode-language-pack-cs-26.2.2.tgz", + "integrity": "sha512-TtWa0Xsz2DwMQ6vMmV1aiNnWQf8UbdSNGT63k30XDB8Q5qV7pHqthEshoEz4h83hjIP+WW5NOOzkeblLTnr5Lw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-de": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-de/-/monaco-vscode-language-pack-de-26.2.1.tgz", - "integrity": "sha512-z1tMN+66l5Bb9oY6u+ENwRGoroFMJVgL9CdQ/5t7qfF2DpNPEhvv5z+aqRcEe84yheyCupYkceLgPSLJdOI5Yg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-de/-/monaco-vscode-language-pack-de-26.2.2.tgz", + "integrity": "sha512-iDJAiVVJ5T4Pb6abIAE5OgdGLDFMHwyYLJEq2MaSttIRlL3POQmPYgetaFuDxvbXo8p2diC0uZ7fCv/CpVrDHw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-es": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-es/-/monaco-vscode-language-pack-es-26.2.1.tgz", - "integrity": "sha512-fzVkp0eM196nLr8mtIBKbLIj4j82b6JZJ63UdYYyS6nDA0SGSNg5TVuim09Nbvjbv26cTLd1nrKtI2zyd2Qkpg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-es/-/monaco-vscode-language-pack-es-26.2.2.tgz", + "integrity": "sha512-qyWh7JctUJYwdmriUyRI7ZehgYtq0XKfDGY+0i2m7D9Kos/j+kgYdB0aJTwYbAk+7uIQkyk7nNIJGmYRmFzzCw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-fr": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-fr/-/monaco-vscode-language-pack-fr-26.2.1.tgz", - "integrity": "sha512-LWsIzv1o59yPgaA95TPDUfDrQ31mBR1eP23gPn0XvUOCe9A3YxtD4d7Tfj05L1mUJzTEZo+HdOSt0rdziEexBg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-fr/-/monaco-vscode-language-pack-fr-26.2.2.tgz", + "integrity": "sha512-Lg5bWhFPLn+/6caR9sUPr+B+Mvv29cLWcb1RbyFNiKFc2mhM4KFxeOQ+6LYCmuBBSaZRmIJNBKBUR1RET+FIqw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-it": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-it/-/monaco-vscode-language-pack-it-26.2.1.tgz", - "integrity": "sha512-KqREwuoq4JHFgtNkYp1qIubTQSCxE7yyuNWQDcwVKLXHrdYyg3WPJBESalYh8nj+eApnksIosEFvoDQCNxp/PQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-it/-/monaco-vscode-language-pack-it-26.2.2.tgz", + "integrity": "sha512-ooZJK0jk8Vm5GP2NR/Slh6eDtqlD2fbYJVVvrdy1L43vH1uSXgWs1bZqNI0V2N7PtlxTolkeb5LxZgYZrSDmEw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-ja": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ja/-/monaco-vscode-language-pack-ja-26.2.1.tgz", - "integrity": "sha512-pUOpQgTEuhsO7aN3U5yL5qr7/r1Y5oyMn9Q6mm4pKgplZdLh9SV480WkEMCLb2JYDBoYC3701zgMIWm9Li/75w==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ja/-/monaco-vscode-language-pack-ja-26.2.2.tgz", + "integrity": "sha512-khVnX1kMzMkkscRHgSPxCEcQYqTO+23xZb/mOnD/xlW7goU0zTSya3pPXgP/4YoQdxsLFZT7NpwvxmfYt5XlVQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-ko": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ko/-/monaco-vscode-language-pack-ko-26.2.1.tgz", - "integrity": "sha512-uIlZ7gZVah1jbDdOBe2cZsfe1y19fy6yh14Xk2R5PuJBLfQSNpKbSM14ajFzKT0iC7omWsjlY/KGDipE0P459w==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ko/-/monaco-vscode-language-pack-ko-26.2.2.tgz", + "integrity": "sha512-g/6m4v9o7TYVzss7L/uDSjJs6CdAAl976cS1+OAspH3tdnNAwr9I2g7Irupj3R0621yg21nKE2sRweZ6F9ZdDQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-pl": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-pl/-/monaco-vscode-language-pack-pl-26.2.1.tgz", - "integrity": "sha512-NItbHl6KAj5BQiDNA3Tte4AovNOIUHoVrQCA7llhw+RKyFbR3yoeBJuOlcoPL6NGFLkeR5/z17JUGLP/T1DyQQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-pl/-/monaco-vscode-language-pack-pl-26.2.2.tgz", + "integrity": "sha512-U3NNHFXGHupaYU0Emb5dJQwnwqA1nJgpz7cnqCcEM/1G/VcjYC+DvRxhsgMkSfR/xdLdGC8JebdP7GY6HRN3Dw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-pt-br": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-pt-br/-/monaco-vscode-language-pack-pt-br-26.2.1.tgz", - "integrity": "sha512-mG7AsuUbvqXfL9Z8PO7udXDuFqwVN6qF8uPPPn28AWlKzHkGxb91xsWp/PD9p4a/f8Fqg2IzRC7AiQPliMgbcA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-pt-br/-/monaco-vscode-language-pack-pt-br-26.2.2.tgz", + "integrity": "sha512-PKkKRQBjCMX/sSOUhc4wWZZPZ1yt06BBM7xqPFEnyCfZSzlvscWxoA4HjoYjp1dDPt1jJGp9zanM3TPeLmlKfA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-qps-ploc": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-qps-ploc/-/monaco-vscode-language-pack-qps-ploc-26.2.1.tgz", - "integrity": "sha512-mCojL4Uf2CJ7071skUMhgb+jGgufm06hKATTaIwk7+8JSiiZaWb27js2xpx7abbI2u04LIHzKZo14ez0srfTBA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-qps-ploc/-/monaco-vscode-language-pack-qps-ploc-26.2.2.tgz", + "integrity": "sha512-wogfSUnZpdtwv33Gc/y7MLk/p9JHjQZLNWgjfm9JdqiyC+qWtZ3cvw0z4FyRECS+34L7B7XBRCzin9nFTBjQiA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-ru": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ru/-/monaco-vscode-language-pack-ru-26.2.1.tgz", - "integrity": "sha512-bI5KyTq8GLBgG5yvPPPeJ9T4g0M8bQ0EQj3PfvvnpNjrE999EodAYmSexlmP24u3sqanv1Jns2MXiA3oI7MyKw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-ru/-/monaco-vscode-language-pack-ru-26.2.2.tgz", + "integrity": "sha512-h7dsG1/gUMoHHhp4C/w57a08JBBTH9V5+MfC362SNx/SOQ7xpZ/rLVuE29w0TdriKnx7Q3ci5cKpS4jkBv7Vsg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-tr": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-tr/-/monaco-vscode-language-pack-tr-26.2.1.tgz", - "integrity": "sha512-/X1juHLrm1DB+zPUPIc/XkDKvG2s99dW3IMFZYb/Gtgk/kYyEDv1C+37mfTXQPJJ7eN6rO0XrKcFjzP83OsQMg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-tr/-/monaco-vscode-language-pack-tr-26.2.2.tgz", + "integrity": "sha512-cS1DLyrUxVPQ8pB5EXdNMcwhgqgXivbfRcB+hdvtXOQleB60ZlpusRIP7Od2QWnb8spxAs3Y4tAOaOvsFchaLw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-zh-hans": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-zh-hans/-/monaco-vscode-language-pack-zh-hans-26.2.1.tgz", - "integrity": "sha512-hAQsjfuQWiaAi6qvkJgrC6wtlBbkUDkvXbrfXf3Zb1VVslC5uITdbxaZj1lVVD/GRlwVnBulufoL9ziPiLiM8A==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-zh-hans/-/monaco-vscode-language-pack-zh-hans-26.2.2.tgz", + "integrity": "sha512-i4GNmt+gnmtsNxVoMnNyou9eCxep1aHLaJKD3vEmr8ATQG7HvKsiqMDkQ2mZzFhzU5mIcDld5pFayfSE0xcADg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-language-pack-zh-hant": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-zh-hant/-/monaco-vscode-language-pack-zh-hant-26.2.1.tgz", - "integrity": "sha512-4q2SqsY+/7hvxEs9WzIAGW78Wzl2Ow+3NGptch0xTJSJXUC2aGgOK689GLx/mhR89oTDltJ/eSO8shupMiLdDQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-language-pack-zh-hant/-/monaco-vscode-language-pack-zh-hant-26.2.2.tgz", + "integrity": "sha512-rqhTDx/ZbbpKLRdnfdK4jPhS69RiICEI7qb9zqMdyEwk4z8tbg7LctNrK0nXk0eEorQx7oD0bB2fe8db8vKmQw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-languages-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-languages-service-override/-/monaco-vscode-languages-service-override-26.2.1.tgz", - "integrity": "sha512-YBeecd1CuxRd7/TtavMfNv5UrSamHQ0xwumMfbES8PBUcdZN5/BR/vaopsOurjB3xMW/vclj2fmcla17596OlA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-languages-service-override/-/monaco-vscode-languages-service-override-26.2.2.tgz", + "integrity": "sha512-fPpAXoqRxQ7hlC4kAqrIuW+sfH9UEsOSBncgWOM7V+gNoULwc3OfP39VtZHzW4viRuguimIC27OC/TidTVjMTA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-layout-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-layout-service-override/-/monaco-vscode-layout-service-override-26.2.1.tgz", - "integrity": "sha512-X2GRWYElM1VzvPL/rF9UT6Goy5G14e27NNX/NHa+N6FCq2aRwgYJubHgucnGrPP/1Sgh0rJ0KAd9/Hr2Gj9JYg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-layout-service-override/-/monaco-vscode-layout-service-override-26.2.2.tgz", + "integrity": "sha512-+UfhKCxu+oIvDM71wi/mJ5NHWSxVaWpH86s1atG7922tZiZzLWdeGSKg63TcB1aiJBoxmHFNxKhCAfqF6qQDaw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-lifecycle-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-lifecycle-service-override/-/monaco-vscode-lifecycle-service-override-26.2.1.tgz", - "integrity": "sha512-52YelbU3LaDJPB0W/+tgwKnc+DfRQ69/wSlrUmeWcE6FV5G6qV02mei8zQClxNaJMDyckA01p87Ssc9iEtUgGA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-lifecycle-service-override/-/monaco-vscode-lifecycle-service-override-26.2.2.tgz", + "integrity": "sha512-7MuHsjMUSR0EMl2g+dH2RQu6WUNTxkMlAH9JX5fyiHLRGRTe+fIxaNwCIon8MnMFu/B459UCLfAc+TpSKRRL/A==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-localization-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-localization-service-override/-/monaco-vscode-localization-service-override-26.2.1.tgz", - "integrity": "sha512-VOX5YhIo/wW04w51k90k+W9bK8+Akn5fnxhm/I2mjyI8gbLQGgRNOPBAl+YhUKMeYAnqF3B2F0lFJDWCMb+6HA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-localization-service-override/-/monaco-vscode-localization-service-override-26.2.2.tgz", + "integrity": "sha512-v5GuKed+MujYpF0SUlYVBh8SjtJ4G2F587/LWsAWM78tctN9qyvmoznnmc68zfDIUGUnyTmUUkZ43+vpGMgFJw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-log-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-log-service-override/-/monaco-vscode-log-service-override-26.2.1.tgz", - "integrity": "sha512-DR9hqX4SmaKShsrH7VDou0ZYg+WarGHn0WhbcnOkqiEBFWhegX7MxpXD9w9WXaqxMRCQjvPGUUs2WdzlbcL+wQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-log-service-override/-/monaco-vscode-log-service-override-26.2.2.tgz", + "integrity": "sha512-28bvb8syjZk5+wJVkRAZHwWoE44le0VZDjWiA6sSfpHIq/0TSuHygYmgieeXny1JINpPZ5ZbRib+uwsxBt9CIA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-environment-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-environment-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-model-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-model-service-override/-/monaco-vscode-model-service-override-26.2.1.tgz", - "integrity": "sha512-lwK6IXCmCNHd847gHKsKLH7mFu+kB4T8Ur38efNxYFc+U7NOhGtcXmPVPlOiwTImw0Mb4ZgnMcvj2uBv3Au1Rw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-model-service-override/-/monaco-vscode-model-service-override-26.2.2.tgz", + "integrity": "sha512-wZ/9SNGOQYVK/DD1fV3etmD1Y9s7qi/fxHbzjo+DjBU2ONHu9oRqZYp/ctWcnxiRCioKt5q6O+9OVD+aHvMmOQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-monarch-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-monarch-service-override/-/monaco-vscode-monarch-service-override-26.2.1.tgz", - "integrity": "sha512-vpYAmmMRhRytcr3UycIizX0oAKvJa6eQdIEhNALAnMEnWehay2frSR+6wbLFRAhqEGMRl/KgbWmCeL3QcE5x7w==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-monarch-service-override/-/monaco-vscode-monarch-service-override-26.2.2.tgz", + "integrity": "sha512-Ndl00yTBNoQg4w38D3QNYsC2ms980/OMSeI4wnjqVZtKsP6ITINuELO4HFx4TLCFL8EqHgL3kzj+IsqcxBj9kg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-outline-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-outline-service-override/-/monaco-vscode-outline-service-override-26.2.1.tgz", - "integrity": "sha512-eOtbJDzU+yQpKSAKNrlyNyH8WVCa0Fw6lK+3BbxNO1lvIctswPyWQNqZqZPUh2CQZkgHd+blqY9cx50uIU20wQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-outline-service-override/-/monaco-vscode-outline-service-override-26.2.2.tgz", + "integrity": "sha512-yTb9fHwo+BS4vu0a2FNlVkLhrqsU3kefSlPOe+ZcVYaJnGILlcZxyy2ZV9hZouiGV9oBjmw/CsU6mSDrDKI11w==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-preferences-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-preferences-service-override/-/monaco-vscode-preferences-service-override-26.2.1.tgz", - "integrity": "sha512-FxhXLISk+PXctgSA1ZK5n4mbMnxLgZ1s5lXZIOQxPq90DSXjtzDewJIbmVFu5g0g5jYsiWOOit9RN/1/yhnaWg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-preferences-service-override/-/monaco-vscode-preferences-service-override-26.2.2.tgz", + "integrity": "sha512-wHW/IqMCH3HGrbPk9MZWKiKGeVoX2+Q+QU2Hp9IEowdtXe1B9HAD9joRPEiUYbU86Al0kkOvPWeT4Sl1yPNzLw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-python-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-python-default-extension/-/monaco-vscode-python-default-extension-26.2.1.tgz", - "integrity": "sha512-hB+qgO8LEbcB3aggFe89HtLWVuZckw5jCfwgxqsrj4AeJwUdghliBT/C5/FdxDeyqrzWjrbDEr+z6Qf5i/KZsw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-python-default-extension/-/monaco-vscode-python-default-extension-26.2.2.tgz", + "integrity": "sha512-tYWFOYQ4a5qFmxv8KBFDAJuT9JiIDJzF3JfQU8RFKj+P5Ud5b5avFUT6+FytYQsJX0pa79wKl0UOR/pWc1tXVw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-quickaccess-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-quickaccess-service-override/-/monaco-vscode-quickaccess-service-override-26.2.1.tgz", - "integrity": "sha512-JanDy+7NzSb46bCnofQj5o2rweuOwsmqMzLx/vClfqMQxTL/qgfQ6wi4xnHT/92N2DuGuv6IieKlUptnl0c8+g==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-quickaccess-service-override/-/monaco-vscode-quickaccess-service-override-26.2.2.tgz", + "integrity": "sha512-worUOlyo4Ppfry6P3Jrg3ajlNXgRlRkBReBEzoxA4yrrpYOh3cTpw+2Krxvds4LeATLgsetCyWp+m5oDI+PVGA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-remote-agent-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-remote-agent-service-override/-/monaco-vscode-remote-agent-service-override-26.2.1.tgz", - "integrity": "sha512-c/PvmKThZDnFKgMumT1OYCO9i4UI/z2yej8IPksw44damT8nZoyY8s96o2G0tit0epUCjM6MNKPV9CYEyuZQTQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-remote-agent-service-override/-/monaco-vscode-remote-agent-service-override-26.2.2.tgz", + "integrity": "sha512-v8yak0+6ZkcYonwbJ5gRWP64f/Q/34CnnewHgWOwJnsSFfKTRDdtaYZzRgqMzf+AEwafXQLjhJtm9G4PlIo0Yw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-environment-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-environment-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-rollup-vsix-plugin": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-rollup-vsix-plugin/-/monaco-vscode-rollup-vsix-plugin-26.2.1.tgz", - "integrity": "sha512-IuNXC/Cz9vdbqc5k26rntM99N/W1R4geSsXescMxa0jGAFwOYQKwmG08FxYWW1rK9l2cSOmlzmyJ4tfWSVFbwg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-rollup-vsix-plugin/-/monaco-vscode-rollup-vsix-plugin-26.2.2.tgz", + "integrity": "sha512-udPF6IvPuMv8y3LPh6is5CRbt5oHCHSHqFdGKFcCt6ipfeYEvBA7NFnOJP1veiK7+qhNsh83LY7GXfOe3qL4yg==", "dev": true, "license": "MIT", "dependencies": { @@ -608,66 +609,66 @@ } }, "node_modules/@codingame/monaco-vscode-search-result-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-search-result-default-extension/-/monaco-vscode-search-result-default-extension-26.2.1.tgz", - "integrity": "sha512-Jxl8O1k8V2/h74i5Tuzxg+DkpVFZ2PKTQbSqMsh2DVrxYG0q/4U/R53KjPy7QAal7K5aWyaTuRXxXIUY5QdmQg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-search-result-default-extension/-/monaco-vscode-search-result-default-extension-26.2.2.tgz", + "integrity": "sha512-Xu/H93hwlcyT2Pfo9i8gTPZqZDxVR1IpQs7WOnIs+f+rAOEEY1jBOufLzxJjTc1FxV3uUzFeVr/lCUzP2TvjmA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-search-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-search-service-override/-/monaco-vscode-search-service-override-26.2.1.tgz", - "integrity": "sha512-bqMcpH8CAACnpCAoKeU/XM+ZIretUqIIuWiHSfl7wixaP+5zy+yB3EypgfefiO51JOJjV+nYoKQZ3NmnvVSteQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-search-service-override/-/monaco-vscode-search-service-override-26.2.2.tgz", + "integrity": "sha512-pna8fSXlxH9WF8OIInUwKEzXAp4cuz65vVBSTWfZw+3LDF/QIT/rm+a1xrODza64pa2H5DDgvra+IiB//9n3Zg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-secret-storage-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-secret-storage-service-override/-/monaco-vscode-secret-storage-service-override-26.2.1.tgz", - "integrity": "sha512-ROZIjRYlwdzrkqqxDIQ3KmfgMWVsWIyiMWkpYgh5eX0HAxwZrI+MaUaWDTwDuc6rL81SGlnX8VHG16BpM6c0lw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-secret-storage-service-override/-/monaco-vscode-secret-storage-service-override-26.2.2.tgz", + "integrity": "sha512-8kgyYjBV8JT7WBBfTtp16DF1wA5s7KoDv3nyCYIQGi2JyUW/T8uTN9qsXbHhbUVywf+w58JyxIDvPbHeFDx3/g==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-standalone-css-language-features": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-css-language-features/-/monaco-vscode-standalone-css-language-features-26.2.1.tgz", - "integrity": "sha512-ncKncWgXMSDktbd2mywI0ZcOOpwTSwC3vkIVaRsf2TnB0D1kl8MZoY/xR23Hm1OO1CHE8h0J9PPRh0LHZLCjag==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-css-language-features/-/monaco-vscode-standalone-css-language-features-26.2.2.tgz", + "integrity": "sha512-c7O9YRSiGmRqq0PPFNSmrkad6uYMdz8/anbNaiXpHEZiMgpg/2XxpSdpLNn+kRNmcAExOtGy0IkYxrj89aYauA==", "dev": true, "license": "MIT", "dependencies": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.1", + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.2", "vscode-css-languageservice": "6.2.14", "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5" } }, "node_modules/@codingame/monaco-vscode-standalone-html-language-features": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-html-language-features/-/monaco-vscode-standalone-html-language-features-26.2.1.tgz", - "integrity": "sha512-scb37ibMygnGN2mLOWX10ofAvgqtak74HD3nYs+DaHof0+7T6MqGbmEFLfht58lw8WrJtJgF5Zj7BqPY5XQQ5Q==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-html-language-features/-/monaco-vscode-standalone-html-language-features-26.2.2.tgz", + "integrity": "sha512-A1if1KERIToO7k7Ihrepf6ODEXQKMWWi64pyYKnaUxCXtgT2usQ5ea2CQSappNmCPK3HIb8VOc0M5R+4clE5zQ==", "dev": true, "license": "MIT", "dependencies": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.1", + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.2", "vscode-html-languageservice": "5.2.0", "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5" } }, "node_modules/@codingame/monaco-vscode-standalone-json-language-features": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-json-language-features/-/monaco-vscode-standalone-json-language-features-26.2.1.tgz", - "integrity": "sha512-EZr1nEDa0Vt2ypASzKPqtXtgawm2bdsM1fD7Q7atFXitxhNDu/GL/zDf6s8dMashwQ5Te6UMDTWx0yBFByxZtw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-json-language-features/-/monaco-vscode-standalone-json-language-features-26.2.2.tgz", + "integrity": "sha512-raIoX8fbKQmqnpVidzYJ8BYZeCjSinzsFI50emd2aFqUdb3nh2b6T8P6zWMTky6Ubf2VjQZwTsnhAfWynW0ZhQ==", "license": "MIT", "dependencies": { "jsonc-parser": "3.3.1", - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.1", + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.2", "vscode-json-languageservice": "5.3.11", "vscode-languageserver-textdocument": "1.0.12", "vscode-languageserver-types": "3.17.5", @@ -694,174 +695,174 @@ "license": "MIT" }, "node_modules/@codingame/monaco-vscode-standalone-languages": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-languages/-/monaco-vscode-standalone-languages-26.2.1.tgz", - "integrity": "sha512-Q226pX6DPKzmWupTS09rWHgsxaxRiqkEPagMjyq23NUsX5cqmxn9bG+gQQwLrWLMHgm6l5MxeZRuJcjjlXmcWQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-languages/-/monaco-vscode-standalone-languages-26.2.2.tgz", + "integrity": "sha512-uVYOU3rgMkiZbl+G1prPdLqIcnZIyeSO2cQ0TWdknlsYiOgNOqNGxl1+3jGtJxJBxNa8jmHM0cJ1t0s0z7rSuw==", "dev": true, "license": "MIT", "dependencies": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.2" } }, "node_modules/@codingame/monaco-vscode-standalone-typescript-language-features": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-typescript-language-features/-/monaco-vscode-standalone-typescript-language-features-26.2.1.tgz", - "integrity": "sha512-HoEO6toayfr3BQJ1jW+Yt7szMciRCLtIViSJ9ZU6bqcBX4xVCMiL802X5nwQk2Q5fiJqu4s4/fCcQ2EtFBct1A==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-standalone-typescript-language-features/-/monaco-vscode-standalone-typescript-language-features-26.2.2.tgz", + "integrity": "sha512-F6Ntplxmedm4Sj4NeHQKYxzk8XEAcg/V5zcMuuiAcA//NBAG2LngorCEEadMZmkV1PPFN41H702irDTwqr8Mcg==", "license": "MIT", "dependencies": { - "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.1" + "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@26.2.2" } }, "node_modules/@codingame/monaco-vscode-storage-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-storage-service-override/-/monaco-vscode-storage-service-override-26.2.1.tgz", - "integrity": "sha512-OcDysZh6c2ZSlXxk11KPkhPhn6oQ8TEYTCaHqauJpnRqSnm0z22tLO2lgHKkVaRC7XD+q2UpUctC+mSp4gG8hQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-storage-service-override/-/monaco-vscode-storage-service-override-26.2.2.tgz", + "integrity": "sha512-LAhnqObgNtcmkgl/Yv8B8PF9NbKckTcJ6oNTHX72uLIsg7kIoUAWN6Ig/vMDtdyZxM95DJVo4x9fX0oljzAS4A==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-terminal-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-terminal-service-override/-/monaco-vscode-terminal-service-override-26.2.1.tgz", - "integrity": "sha512-s+S46byKjw4bO8FPCO/EXno5Kz46PTy50QVlqNraHahafyrxpC1omn+D30Kr6GUVfQ5WQwbfMAKD96dbLHpUrA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-terminal-service-override/-/monaco-vscode-terminal-service-override-26.2.2.tgz", + "integrity": "sha512-NP9Zb/tYa2DSLyHsFAzG/6qFmfxieLHoNkE8W3W4wo1DBhgcTC06IbeDrs6+lPdokTNRdwzu8ul8mOW7oq44xQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-xterm-addons-common": "26.2.1", - "@codingame/monaco-vscode-xterm-common": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-xterm-addons-common": "26.2.2", + "@codingame/monaco-vscode-xterm-common": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-testing-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-testing-service-override/-/monaco-vscode-testing-service-override-26.2.1.tgz", - "integrity": "sha512-jkkMZdStd2j1oi/HtHbG2z4NifECSvu/KgA396ebgEI1ITdU0POL4sCd2Ap69xP6b2Q9TfsZashrqaG4ikUAAw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-testing-service-override/-/monaco-vscode-testing-service-override-26.2.2.tgz", + "integrity": "sha512-J9WjmGcw+jHsZXH4znzKDc5w1gEVt75IRDU9ocQZJG+2c9qd0FYQYrNp91Vx4tkg0cL9H7r7Mkbv2ex3d7T5qA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-terminal-service-override": "26.2.1", - "@codingame/monaco-vscode-xterm-addons-common": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-terminal-service-override": "26.2.2", + "@codingame/monaco-vscode-xterm-addons-common": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-textmate-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-textmate-service-override/-/monaco-vscode-textmate-service-override-26.2.1.tgz", - "integrity": "sha512-djhxc2TPvaM4KG8n2u5TlUT15CSRCuOiK1XBkd77nFxqkFsM8TGKH7+uszdvqxo2dH3lq+84vX2LZa0NutlPrQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-textmate-service-override/-/monaco-vscode-textmate-service-override-26.2.2.tgz", + "integrity": "sha512-nKb9ejSN8c4v2iPqo92gcHArrwmonOSdT+1CVfwu19yUWb3MbhSJqa7arUIKCUzAYDq8FtWy69Yjk3r6q6Kndg==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-theme-defaults-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-theme-defaults-default-extension/-/monaco-vscode-theme-defaults-default-extension-26.2.1.tgz", - "integrity": "sha512-Ng3eErfs0iFiPQaPFf5dUpjTzDc9uql7dCbZfofHkgkdJ86dzrGLXgbCzQGMyVLmMdMEXkLVL9aRPmAcknnbDg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-theme-defaults-default-extension/-/monaco-vscode-theme-defaults-default-extension-26.2.2.tgz", + "integrity": "sha512-lZJmoPp2kiZ7Xz/qhWsUPTRvG6QP4+a+BdcZLzpDuIG0cOwQ47T+Ea3LpsZ4+KsVXtE2gADdIwL83KuI48JuNQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-theme-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-theme-service-override/-/monaco-vscode-theme-service-override-26.2.1.tgz", - "integrity": "sha512-doBv4Mwbfum33sF1x45HksQr6UCdF2DsiMVIbgwB6aGOzVa3iXHj6/25SyFhPUXJHyhidsqz84GxMPYzEDM2Mg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-theme-service-override/-/monaco-vscode-theme-service-override-26.2.2.tgz", + "integrity": "sha512-S/2wUX6gOoDrm8UjKgPzXoJV0/4gAit7neGbZcaaNEEIrY6A/mZ+Uc70WY/fe9wPMvjVtaDlkURrots6H/N3qQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-files-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-files-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-typescript-basics-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-typescript-basics-default-extension/-/monaco-vscode-typescript-basics-default-extension-26.2.1.tgz", - "integrity": "sha512-Lneo6owOZxOvLwZHqyfEoHmrrvZ0X6yZEY2har8ul3oQ7rvkL9Doi6jMyBMtWpSEvtODAHvahKhQt/mV5M0lIQ==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-typescript-basics-default-extension/-/monaco-vscode-typescript-basics-default-extension-26.2.2.tgz", + "integrity": "sha512-lSCu8eBn7fcUPYWS3qmEwqdC2nm8Qyva7FaSNt4aX4lCB2+Ax7/xFUDNE97ibk4Q7lTBLrwDOY7BZSe3kyvn1Q==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-typescript-language-features-default-extension/-/monaco-vscode-typescript-language-features-default-extension-26.2.1.tgz", - "integrity": "sha512-IkzeX6ZjftDgeMSoKeUgCmoWiETppamZtiXKTpHh5C3hcwRrxutd7mfI08+Rly0+RpdFUdkDgw5Ag6Hn9yzcfw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-typescript-language-features-default-extension/-/monaco-vscode-typescript-language-features-default-extension-26.2.2.tgz", + "integrity": "sha512-SXTxeHU/l615wiyWMirSgqrdcd14P/ipp4psEsGuxKYP8K9AainCP2wls7+AQZmTrj90eI6YtlkWgYmwh9LLtA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-view-banner-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-banner-service-override/-/monaco-vscode-view-banner-service-override-26.2.1.tgz", - "integrity": "sha512-4dpbQ9OATz/r3wkh8+INGBIi5x2KhE8YuFBFb/yKLnAybWfsHfqbulDBHURA6elyiuDXjmsniALJfQ9aBNtYVw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-banner-service-override/-/monaco-vscode-view-banner-service-override-26.2.2.tgz", + "integrity": "sha512-qOIZZt7CaaTWrGCbO+uAFG3DSRGOdZ/THhMijZ1ioqkRTUFmL3H6ERF0N3uwiCJuh1ifFN5dowsdOqx4wRgj5A==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-view-common-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-common-service-override/-/monaco-vscode-view-common-service-override-26.2.1.tgz", - "integrity": "sha512-kGwtXFiKMIuM1cPoZ6TddSIBYbCl8KkgH5z9cW6OC9wkWNcftM1zHyD78c/e815gvXL9AfJ8a6tAKRBFitOERA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-common-service-override/-/monaco-vscode-view-common-service-override-26.2.2.tgz", + "integrity": "sha512-I0iucIWsvwExBUQsGZY1ujPk5JWyjCVPm6hF+1KKCEim4MSKQ/CufxCEs5noZLowyB2aUon0hTTa5+qDNDobfQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-bulk-edit-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-bulk-edit-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-view-status-bar-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-status-bar-service-override/-/monaco-vscode-view-status-bar-service-override-26.2.1.tgz", - "integrity": "sha512-Waz6vS3NAK4Q8JsfTePcAy1oATEmoKJ69HjVQjY8RbTOuJzPqz5UsN40je99swK80gp1+eyhInmJESi5HOyxEA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-status-bar-service-override/-/monaco-vscode-view-status-bar-service-override-26.2.2.tgz", + "integrity": "sha512-Zfh9KBjGA5AQdKv1gmI/EkfuRcOaSUVzPUhpNWaKY+/cjfR2jhQxM3arq+G+wX1Hpi1nE4YBzzPRXBAqgNEiCA==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-view-title-bar-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-title-bar-service-override/-/monaco-vscode-view-title-bar-service-override-26.2.1.tgz", - "integrity": "sha512-MC+oqAZPheDOnK9MSC/Rwzljo8qZ8b0lqWwj3RlHhwLSlPOhP7CEXL6SRZAdMzprUONaXVu7uTlm1DkZ9Xodig==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-view-title-bar-service-override/-/monaco-vscode-view-title-bar-service-override-26.2.2.tgz", + "integrity": "sha512-aDjITy8gkuj7P2afAYIWsPaXhQqtwq8aH5cYfQu3zgszmG4/8PMOAsMPlKQsVSpKKZAzWMufBjFPkwTFVRTWKQ==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-views-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-views-service-override/-/monaco-vscode-views-service-override-26.2.1.tgz", - "integrity": "sha512-NqQU+sJh+xiCPWipPgMesyXRWxzbraBF2mOSyVqsTS2frV1HePMpvCEEf6TO0WYvgH4gSLuSbwcM8ejainTXVw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-views-service-override/-/monaco-vscode-views-service-override-26.2.2.tgz", + "integrity": "sha512-xJjEdErv91OldODFtH1LvBxzDwST/wV9t5ZpGNkydKGfAn1m/gn+S9Xhgw5Xzt76KYSoL0sD+kHWGCwoARrdGw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-keybindings-service-override": "26.2.1", - "@codingame/monaco-vscode-layout-service-override": "26.2.1", - "@codingame/monaco-vscode-quickaccess-service-override": "26.2.1", - "@codingame/monaco-vscode-view-common-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-keybindings-service-override": "26.2.2", + "@codingame/monaco-vscode-layout-service-override": "26.2.2", + "@codingame/monaco-vscode-quickaccess-service-override": "26.2.2", + "@codingame/monaco-vscode-view-common-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-workbench-service-override": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-workbench-service-override/-/monaco-vscode-workbench-service-override-26.2.1.tgz", - "integrity": "sha512-sFuGZFNI5zakgBH8g/fJRXNbfhFttyN5OIDkahBF8YT7uzwYvUG9e5DYvrIcBAjEkVQQ/otCY1qBEe8I8qwrIw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-workbench-service-override/-/monaco-vscode-workbench-service-override-26.2.2.tgz", + "integrity": "sha512-PaiHtdB6PUlnqGJInaX1P5nTrkJ3OEN0leAJn9L9JP0Y6qq/fe4Ky3qsx6B1MQglwShRZH8A6hZLaBHhhRIfvw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-keybindings-service-override": "26.2.1", - "@codingame/monaco-vscode-quickaccess-service-override": "26.2.1", - "@codingame/monaco-vscode-view-banner-service-override": "26.2.1", - "@codingame/monaco-vscode-view-common-service-override": "26.2.1", - "@codingame/monaco-vscode-view-status-bar-service-override": "26.2.1", - "@codingame/monaco-vscode-view-title-bar-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-keybindings-service-override": "26.2.2", + "@codingame/monaco-vscode-quickaccess-service-override": "26.2.2", + "@codingame/monaco-vscode-view-banner-service-override": "26.2.2", + "@codingame/monaco-vscode-view-common-service-override": "26.2.2", + "@codingame/monaco-vscode-view-status-bar-service-override": "26.2.2", + "@codingame/monaco-vscode-view-title-bar-service-override": "26.2.2" } }, "node_modules/@codingame/monaco-vscode-xterm-addons-common": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-xterm-addons-common/-/monaco-vscode-xterm-addons-common-26.2.1.tgz", - "integrity": "sha512-6JthDS6P2Vy33O2p+ZVRFSEP0OmNKV5fF/yHNW1ypvYT8W8aZnkw9oMke8gtYBetmwRYmhnkrY/BqgDaGo+qmw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-xterm-addons-common/-/monaco-vscode-xterm-addons-common-26.2.2.tgz", + "integrity": "sha512-kPS+ZI5qo1nAQgIedURH6cLTks3o+lWsuYfhZVZDHxCV9zQyWTLQou0Jl2vo1eAGlKmqqNkvR8rEo+ztkR60gw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", + "@codingame/monaco-vscode-api": "26.2.2", "@xterm/addon-clipboard": "0.3.0-beta.147", "@xterm/addon-image": "0.10.0-beta.147", "@xterm/addon-ligatures": "0.11.0-beta.147", @@ -873,13 +874,13 @@ } }, "node_modules/@codingame/monaco-vscode-xterm-common": { - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-xterm-common/-/monaco-vscode-xterm-common-26.2.1.tgz", - "integrity": "sha512-gbQ/Vp2rNBPNoJLnaqKOlYZmEi8trDWeQhSPRNsfV6NzvglBaNKwnq4NX8+9vF6r58/390ow2TR2jK6rODEyXw==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-xterm-common/-/monaco-vscode-xterm-common-26.2.2.tgz", + "integrity": "sha512-MY0Q5jb827XeuOFcBbXeGAUkdlsBmNeWOqaIUlGkjAZlVM4qQFRxvsx8uw8mqFK1PgIIe6NVStEUX0Cuq6NvSw==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-xterm-addons-common": "26.2.1", + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-xterm-addons-common": "26.2.2", "@xterm/xterm": "6.1.0-beta.147" } }, @@ -1908,6 +1909,329 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@oxfmt/binding-android-arm-eabi": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.36.0.tgz", + "integrity": "sha512-Z4yVHJWx/swHHjtr0dXrBZb6LxS+qNz1qdza222mWwPTUK4L790+5i3LTgjx3KYGBzcYpjaiZBw4vOx94dH7MQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-android-arm64": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.36.0.tgz", + "integrity": "sha512-3ElCJRFNPQl7jexf2CAa9XmAm8eC5JPrIDSjc9jSchkVSFTEqyL0NtZinBB2h1a4i4JgP1oGl/5G5n8YR4FN8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-darwin-arm64": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.36.0.tgz", + "integrity": "sha512-nak4znWCqIExKhYSY/mz/lWsqWIpdsS7o0+SRzXR1Q0m7GrMcG1UrF1pS7TLGZhhkf7nTfEF7q6oZzJiodRDuw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-darwin-x64": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.36.0.tgz", + "integrity": "sha512-V4GP96thDnpKx6ADnMDnhIXNdtV+Ql9D4HUU+a37VTeVbs5qQSF/s6hhUP1b3xUqU7iRcwh72jUU2Y12rtGHAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-freebsd-x64": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.36.0.tgz", + "integrity": "sha512-/xapWCADfI5wrhxpEUjhI9fnw7MV5BUZizVa8e24n3VSK6A3Y1TB/ClOP1tfxNspykFKXp4NBWl6NtDJP3osqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.36.0.tgz", + "integrity": "sha512-1lOmv61XMFIH5uNm27620kRRzWt/RK6tdn250BRDoG9W7OXGOQ5UyI1HVT+SFkoOoKztBiinWgi68+NA1MjBVQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm-musleabihf": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.36.0.tgz", + "integrity": "sha512-vMH23AskdR1ujUS9sPck2Df9rBVoZUnCVY86jisILzIQ/QQ/yKUTi7tgnIvydPx7TyB/48wsQ5QMr5Knq5p/aw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm64-gnu": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.36.0.tgz", + "integrity": "sha512-Hy1V+zOBHpBiENRx77qrUTt5aPDHeCASRc8K5KwwAHkX2AKP0nV89eL17hsZrE9GmnXFjsNmd80lyf7aRTXsbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm64-musl": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.36.0.tgz", + "integrity": "sha512-SPGLJkOIHSIC6ABUQ5V8NqJpvYhMJueJv26NYqfCnwi/Mn6A61amkpJJ9Suy0Nmvs+OWESJpcebrBUbXPGZyQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-ppc64-gnu": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.36.0.tgz", + "integrity": "sha512-3EuoyB8x9x8ysYJjbEO/M9fkSk72zQKnXCvpZMDHXlnY36/1qMp55Nm0PrCwjGO/1pen5hdOVkz9WmP3nAp2IQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-riscv64-gnu": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.36.0.tgz", + "integrity": "sha512-MpY3itLwpGh8dnywtrZtaZ604T1m715SydCKy0+qTxetv+IHzuA+aO/AGzrlzUNYZZmtWtmDBrChZGibvZxbRQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-riscv64-musl": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.36.0.tgz", + "integrity": "sha512-mmDhe4Vtx+XwQPRPn/V25+APnkApYgZ23q+6GVsNYY98pf3aU0aI3Me96pbRs/AfJ1jIiGC+/6q71FEu8dHcHw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-s390x-gnu": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.36.0.tgz", + "integrity": "sha512-AYXhU+DmNWLSnvVwkHM92fuYhogtVHab7UQrPNaDf1sxadugg9gWVmcgJDlIwxJdpk5CVW/TFvwUKwI432zhhA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-x64-gnu": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.36.0.tgz", + "integrity": "sha512-H16QhhQ3usoakMleiAAQ2mg0NsBDAdyE9agUgfC8IHHh3jZEbr0rIKwjEqwbOHK5M0EmfhJmr+aGO/MgZPsneA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-x64-musl": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.36.0.tgz", + "integrity": "sha512-EFFGkixA39BcmHiCe2ECdrq02D6FCve5ka6ObbvrheXl4V+R0U/E+/uLyVx1X65LW8TA8QQHdnbdDallRekohw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-openharmony-arm64": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.36.0.tgz", + "integrity": "sha512-zr/t369wZWFOj1qf06Z5gGNjFymfUNDrxKMmr7FKiDRVI1sNsdKRCuRL4XVjtcptKQ+ao3FfxLN1vrynivmCYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-arm64-msvc": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.36.0.tgz", + "integrity": "sha512-FxO7UksTv8h4olzACgrqAXNF6BP329+H322323iDrMB5V/+a1kcAw07fsOsUmqNrb9iJBsCQgH/zqcqp5903ag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-ia32-msvc": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.36.0.tgz", + "integrity": "sha512-OjoMQ89H01M0oLMfr/CPNH1zi48ZIwxAKObUl57oh7ssUBNDp/2Vjf7E1TQ8M4oj4VFQ/byxl2SmcPNaI2YNDg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-x64-msvc": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.36.0.tgz", + "integrity": "sha512-MoyeQ9S36ZTz/4bDhOKJgOBIDROd4dQ5AkT9iezhEaUBxAPdNX9Oq0jD8OSnCj3G4wam/XNxVWKMA52kmzmPtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@oxlint-tsgolint/darwin-arm64": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-arm64/-/darwin-arm64-0.16.0.tgz", @@ -2831,28 +3155,28 @@ } }, "node_modules/@typescript/native-preview": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-KR2mM+hGSF9CcYRFLe/8jAFuRr0Ao3vJDnfGtEoSSpgfw0kCZTMv8fyBc5Vicrg/ByZSwGhZf7Q8HDc5lPYLGg==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-vdRnhkcNKwDZiCd/gBoSxax5crAtu+DqmZ6pMeqxAYZkpFwg6lhns+utcqLZrTvfRbljQw15s2BB2wRN+3z4FA==", "dev": true, "license": "Apache-2.0", "bin": { "tsgo": "bin/tsgo.js" }, "optionalDependencies": { - "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260302.1", - "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260302.1", - "@typescript/native-preview-linux-arm": "7.0.0-dev.20260302.1", - "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260302.1", - "@typescript/native-preview-linux-x64": "7.0.0-dev.20260302.1", - "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260302.1", - "@typescript/native-preview-win32-x64": "7.0.0-dev.20260302.1" + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260305.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260305.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20260305.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260305.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20260305.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260305.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20260305.1" } }, "node_modules/@typescript/native-preview-darwin-arm64": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-bSSHf2/3/pUa1FHdHkoD2SbACh4G8GQElQmkHksf42L30rgED+thloZPyQEvaIXE44IsfFDEvsa6reF/pob5Aw==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-RIGSpCYlOSyYBH653Fp25eBtfIXYCCnb/DwPcluVw6hp3UEYYiKvVxXiFY6sEpjtxgClcIUu5mZi+WnXlEgERg==", "cpu": [ "arm64" ], @@ -2864,9 +3188,9 @@ ] }, "node_modules/@typescript/native-preview-darwin-x64": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-CfBxf/qEFgoe1zZ8U/DfgP2izrDEnERXj2uuX5Mi2m6NIdS6yo9fv+TiQS7UDINIOcRaN17NMUmIRrj8RLz3TA==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-vXoIHxhfbhg1E0n9Qp0ahce8cuPBG6Q3Ugh7esBQZaB3H7YGUFY44aURIdtH9pE9nJ1cAuL3GYs/hjlxSJ0igg==", "cpu": [ "x64" ], @@ -2878,9 +3202,9 @@ ] }, "node_modules/@typescript/native-preview-linux-arm": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-TWdwsqactujpdAuu/pepoXg7DK2TQ6Q3kYeqLlTic+0d61jece12yqk4hlmXXzQrc5D2ht9Qr3ny4BHyBvKlZw==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-+Ed7S8d68LOmK1A+LUUqfIkMBUqVaN6J4o6RYRBKCdo+zFUMmuCriWXe/7tKzlE+CUamCNLNBMrBlO8vZXKwKQ==", "cpu": [ "arm" ], @@ -2892,9 +3216,9 @@ ] }, "node_modules/@typescript/native-preview-linux-arm64": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-Ojecn2PD9Pgs3UUkxzKNwesFmKiCrRHHc6DFlE7Tpsf53tLEOkVTS8SdYOxoPvbM+ee9lQ+WDWyHsOHfbUXFuQ==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-xI/nryrjTITDF+0+dZLjcRT464E1EXmme3JKinQHWmAEnBxOIEBfOSQIFk5sNE6pwMYewmp0wyOWJp0J7a1joA==", "cpu": [ "arm64" ], @@ -2906,9 +3230,9 @@ ] }, "node_modules/@typescript/native-preview-linux-x64": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-f+8wzy/4xcDMgAdkJy722BL0pau8O0S4+HUR2CyFJy7HbDIGbbl/Zm5ZAq2xjMGEdq83+klp+7y/JuDIb0herA==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-mtQ0g7xRhXUCDqJVUT4HbuRu6qW6/iP7YHdUiog72w1C5kPkZVA/nr/GadPDU4JQ6e0xkiuCMNtgEAl3akYmBw==", "cpu": [ "x64" ], @@ -2920,9 +3244,9 @@ ] }, "node_modules/@typescript/native-preview-win32-arm64": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-yN+UMH41G2UgXn5ER0FzgVQPQ6YLfpSoSaWV38l+hIkgKQSv7TsF778Svgh0dd5OpFKoeQ1aPOMalugxI3FnWw==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-saAEfY97ARhmyw/dSgmwXOJGiznZCDzcwUImpSWzL4XneAoCQsov3hRZq9SOM6f7+0QLMbpP6Zn35pJhGkVdfQ==", "cpu": [ "arm64" ], @@ -2934,9 +3258,9 @@ ] }, "node_modules/@typescript/native-preview-win32-x64": { - "version": "7.0.0-dev.20260302.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260302.1.tgz", - "integrity": "sha512-Ni9nVkZRt3MofSUSilF51w1tkxlPegz3+zJLDPZZdc0IIaENTP37gfVkngio4tdsjIjsPFieJOkogej/wYT1AA==", + "version": "7.0.0-dev.20260305.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260305.1.tgz", + "integrity": "sha512-aA8ebJ8gUBWui0x6CSOdIR4BbkMM7swmZV2loH6uySKSzsqETeqc8AIYUnpChZJAnCfZOC2FF2P3d0DKyJjsmA==", "cpu": [ "x64" ], @@ -3243,9 +3567,9 @@ } }, "node_modules/@xterm/xterm": { - "version": "6.1.0-beta.167", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.1.0-beta.167.tgz", - "integrity": "sha512-OOG2gcH9OhEjY+KW3X2s30e1KzaRlynhkF9/oKfb2PNUJBYUdXeww4YAugrz7+nLP8KxCeOdSJrq7VvRzyZrwA==", + "version": "6.1.0-beta.168", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.1.0-beta.168.tgz", + "integrity": "sha512-emtXKWZmyOZhcEg6StZ3qFU6M++FM506+2V/E//iqMitCDFfJAGJNJYUS5o0/PRN0MaIKo1ladXhfnozAKaGTA==", "license": "MIT", "peer": true, "workspaces": [ @@ -5095,12 +5419,12 @@ }, "node_modules/monaco-editor": { "name": "@codingame/monaco-vscode-editor-api", - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-api/-/monaco-vscode-editor-api-26.2.1.tgz", - "integrity": "sha512-xWBNiE2zY0t4c3jZU3NeNccaZ0Z0qlyEOwSZOoC9W0cPy8yXoI2QbIdElKUuXux02y290j5uJF8x/S3Hx9PeNg==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-editor-api/-/monaco-vscode-editor-api-26.2.2.tgz", + "integrity": "sha512-F8XTkB+9CAv+9XKpdWVdjaNK17WDvkhdF0Ko19V4Kk4f73t9R8mqv1HC/g/BNXLbKbOuwUUsX96pXO1UnA+Dng==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2" } }, "node_modules/monaco-languageclient": { @@ -5250,6 +5574,46 @@ "ot": "bin/ot" } }, + "node_modules/oxfmt": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.36.0.tgz", + "integrity": "sha512-/ejJ+KoSW6J9bcNT9a9UtJSJNWhJ3yOLSBLbkoFHJs/8CZjmaZVZAJe4YgO1KMJlKpNQasrn/G9JQUEZI3p0EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinypool": "2.1.0" + }, + "bin": { + "oxfmt": "bin/oxfmt" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxfmt/binding-android-arm-eabi": "0.36.0", + "@oxfmt/binding-android-arm64": "0.36.0", + "@oxfmt/binding-darwin-arm64": "0.36.0", + "@oxfmt/binding-darwin-x64": "0.36.0", + "@oxfmt/binding-freebsd-x64": "0.36.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.36.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.36.0", + "@oxfmt/binding-linux-arm64-gnu": "0.36.0", + "@oxfmt/binding-linux-arm64-musl": "0.36.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.36.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.36.0", + "@oxfmt/binding-linux-riscv64-musl": "0.36.0", + "@oxfmt/binding-linux-s390x-gnu": "0.36.0", + "@oxfmt/binding-linux-x64-gnu": "0.36.0", + "@oxfmt/binding-linux-x64-musl": "0.36.0", + "@oxfmt/binding-openharmony-arm64": "0.36.0", + "@oxfmt/binding-win32-arm64-msvc": "0.36.0", + "@oxfmt/binding-win32-ia32-msvc": "0.36.0", + "@oxfmt/binding-win32-x64-msvc": "0.36.0" + } + }, "node_modules/oxlint": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.51.0.tgz", @@ -6245,6 +6609,16 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinypool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", + "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + } + }, "node_modules/tinyrainbow": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", @@ -6615,13 +6989,13 @@ }, "node_modules/vscode": { "name": "@codingame/monaco-vscode-extension-api", - "version": "26.2.1", - "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extension-api/-/monaco-vscode-extension-api-26.2.1.tgz", - "integrity": "sha512-6gKBpM+UMMILFJlhgPNPGPlpLiiqaqR6/lQ0CoS3QDEO0JosUYoF9NG1lJNaS4LIWrQ5Zy31bFyG/wbjb/LKgA==", + "version": "26.2.2", + "resolved": "https://registry.npmjs.org/@codingame/monaco-vscode-extension-api/-/monaco-vscode-extension-api-26.2.2.tgz", + "integrity": "sha512-aQ6i4F610ApCp8X9x934fIXBn3DyJml5nNh7Aw8N2JJNIwcbJVsHVCk9dPG+MsqknhK85xolo2E8Is6ycuoT5g==", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "26.2.1" + "@codingame/monaco-vscode-api": "26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "26.2.2" } }, "node_modules/vscode-css-languageservice": { @@ -6854,47 +7228,47 @@ "version": "10.7.0", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-api": "^26.2.1", - "@codingame/monaco-vscode-configuration-service-override": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-editor-service-override": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "^26.2.1", - "@codingame/monaco-vscode-language-pack-cs": "^26.2.1", - "@codingame/monaco-vscode-language-pack-de": "^26.2.1", - "@codingame/monaco-vscode-language-pack-es": "^26.2.1", - "@codingame/monaco-vscode-language-pack-fr": "^26.2.1", - "@codingame/monaco-vscode-language-pack-it": "^26.2.1", - "@codingame/monaco-vscode-language-pack-ja": "^26.2.1", - "@codingame/monaco-vscode-language-pack-ko": "^26.2.1", - "@codingame/monaco-vscode-language-pack-pl": "^26.2.1", - "@codingame/monaco-vscode-language-pack-pt-br": "^26.2.1", - "@codingame/monaco-vscode-language-pack-qps-ploc": "^26.2.1", - "@codingame/monaco-vscode-language-pack-ru": "^26.2.1", - "@codingame/monaco-vscode-language-pack-tr": "^26.2.1", - "@codingame/monaco-vscode-language-pack-zh-hans": "^26.2.1", - "@codingame/monaco-vscode-language-pack-zh-hant": "^26.2.1", - "@codingame/monaco-vscode-languages-service-override": "^26.2.1", - "@codingame/monaco-vscode-localization-service-override": "^26.2.1", - "@codingame/monaco-vscode-log-service-override": "^26.2.1", - "@codingame/monaco-vscode-model-service-override": "^26.2.1", - "@codingame/monaco-vscode-monarch-service-override": "^26.2.1", - "@codingame/monaco-vscode-textmate-service-override": "^26.2.1", - "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.1", - "@codingame/monaco-vscode-theme-service-override": "^26.2.1", - "@codingame/monaco-vscode-views-service-override": "^26.2.1", - "@codingame/monaco-vscode-workbench-service-override": "^26.2.1", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "@codingame/monaco-vscode-api": "^26.2.2", + "@codingame/monaco-vscode-configuration-service-override": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-editor-service-override": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "^26.2.2", + "@codingame/monaco-vscode-language-pack-cs": "^26.2.2", + "@codingame/monaco-vscode-language-pack-de": "^26.2.2", + "@codingame/monaco-vscode-language-pack-es": "^26.2.2", + "@codingame/monaco-vscode-language-pack-fr": "^26.2.2", + "@codingame/monaco-vscode-language-pack-it": "^26.2.2", + "@codingame/monaco-vscode-language-pack-ja": "^26.2.2", + "@codingame/monaco-vscode-language-pack-ko": "^26.2.2", + "@codingame/monaco-vscode-language-pack-pl": "^26.2.2", + "@codingame/monaco-vscode-language-pack-pt-br": "^26.2.2", + "@codingame/monaco-vscode-language-pack-qps-ploc": "^26.2.2", + "@codingame/monaco-vscode-language-pack-ru": "^26.2.2", + "@codingame/monaco-vscode-language-pack-tr": "^26.2.2", + "@codingame/monaco-vscode-language-pack-zh-hans": "^26.2.2", + "@codingame/monaco-vscode-language-pack-zh-hant": "^26.2.2", + "@codingame/monaco-vscode-languages-service-override": "^26.2.2", + "@codingame/monaco-vscode-localization-service-override": "^26.2.2", + "@codingame/monaco-vscode-log-service-override": "^26.2.2", + "@codingame/monaco-vscode-model-service-override": "^26.2.2", + "@codingame/monaco-vscode-monarch-service-override": "^26.2.2", + "@codingame/monaco-vscode-textmate-service-override": "^26.2.2", + "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.2", + "@codingame/monaco-vscode-theme-service-override": "^26.2.2", + "@codingame/monaco-vscode-views-service-override": "^26.2.2", + "@codingame/monaco-vscode-workbench-service-override": "^26.2.2", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "vscode-languageclient": "~9.0.1", "vscode-languageserver-protocol": "~3.17.5", "vscode-ws-jsonrpc": "~3.5.0" }, "devDependencies": { - "@codingame/monaco-vscode-standalone-css-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-html-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-languages": "^26.2.1", - "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.1" + "@codingame/monaco-vscode-standalone-css-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-html-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-languages": "^26.2.2", + "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.2" }, "engines": { "node": ">=20.10.0", @@ -6906,42 +7280,42 @@ "version": "2026.2.1", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-configuration-service-override": "^26.2.1", - "@codingame/monaco-vscode-cpp-default-extension": "^26.2.1", - "@codingame/monaco-vscode-debug-service-override": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-environment-service-override": "^26.2.1", - "@codingame/monaco-vscode-explorer-service-override": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "@codingame/monaco-vscode-files-service-override": "^26.2.1", - "@codingame/monaco-vscode-groovy-default-extension": "^26.2.1", - "@codingame/monaco-vscode-java-default-extension": "^26.2.1", - "@codingame/monaco-vscode-javascript-default-extension": "^26.2.1", - "@codingame/monaco-vscode-json-default-extension": "^26.2.1", - "@codingame/monaco-vscode-json-language-features-default-extension": "^26.2.1", - "@codingame/monaco-vscode-keybindings-service-override": "^26.2.1", - "@codingame/monaco-vscode-lifecycle-service-override": "^26.2.1", - "@codingame/monaco-vscode-localization-service-override": "^26.2.1", - "@codingame/monaco-vscode-outline-service-override": "^26.2.1", - "@codingame/monaco-vscode-preferences-service-override": "^26.2.1", - "@codingame/monaco-vscode-python-default-extension": "^26.2.1", - "@codingame/monaco-vscode-remote-agent-service-override": "^26.2.1", - "@codingame/monaco-vscode-search-result-default-extension": "^26.2.1", - "@codingame/monaco-vscode-search-service-override": "^26.2.1", - "@codingame/monaco-vscode-secret-storage-service-override": "^26.2.1", - "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.1", - "@codingame/monaco-vscode-storage-service-override": "^26.2.1", - "@codingame/monaco-vscode-testing-service-override": "^26.2.1", - "@codingame/monaco-vscode-textmate-service-override": "^26.2.1", - "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.1", - "@codingame/monaco-vscode-theme-service-override": "^26.2.1", - "@codingame/monaco-vscode-typescript-basics-default-extension": "^26.2.1", - "@codingame/monaco-vscode-typescript-language-features-default-extension": "^26.2.1", - "@codingame/monaco-vscode-view-banner-service-override": "^26.2.1", - "@codingame/monaco-vscode-view-status-bar-service-override": "^26.2.1", - "@codingame/monaco-vscode-view-title-bar-service-override": "^26.2.1", - "@codingame/monaco-vscode-views-service-override": "^26.2.1", + "@codingame/monaco-vscode-configuration-service-override": "^26.2.2", + "@codingame/monaco-vscode-cpp-default-extension": "^26.2.2", + "@codingame/monaco-vscode-debug-service-override": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-environment-service-override": "^26.2.2", + "@codingame/monaco-vscode-explorer-service-override": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "@codingame/monaco-vscode-files-service-override": "^26.2.2", + "@codingame/monaco-vscode-groovy-default-extension": "^26.2.2", + "@codingame/monaco-vscode-java-default-extension": "^26.2.2", + "@codingame/monaco-vscode-javascript-default-extension": "^26.2.2", + "@codingame/monaco-vscode-json-default-extension": "^26.2.2", + "@codingame/monaco-vscode-json-language-features-default-extension": "^26.2.2", + "@codingame/monaco-vscode-keybindings-service-override": "^26.2.2", + "@codingame/monaco-vscode-lifecycle-service-override": "^26.2.2", + "@codingame/monaco-vscode-localization-service-override": "^26.2.2", + "@codingame/monaco-vscode-outline-service-override": "^26.2.2", + "@codingame/monaco-vscode-preferences-service-override": "^26.2.2", + "@codingame/monaco-vscode-python-default-extension": "^26.2.2", + "@codingame/monaco-vscode-remote-agent-service-override": "^26.2.2", + "@codingame/monaco-vscode-search-result-default-extension": "^26.2.2", + "@codingame/monaco-vscode-search-service-override": "^26.2.2", + "@codingame/monaco-vscode-secret-storage-service-override": "^26.2.2", + "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.2", + "@codingame/monaco-vscode-storage-service-override": "^26.2.2", + "@codingame/monaco-vscode-testing-service-override": "^26.2.2", + "@codingame/monaco-vscode-textmate-service-override": "^26.2.2", + "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.2", + "@codingame/monaco-vscode-theme-service-override": "^26.2.2", + "@codingame/monaco-vscode-typescript-basics-default-extension": "^26.2.2", + "@codingame/monaco-vscode-typescript-language-features-default-extension": "^26.2.2", + "@codingame/monaco-vscode-view-banner-service-override": "^26.2.2", + "@codingame/monaco-vscode-view-status-bar-service-override": "^26.2.2", + "@codingame/monaco-vscode-view-title-bar-service-override": "^26.2.2", + "@codingame/monaco-vscode-views-service-override": "^26.2.2", "@typefox/monaco-editor-react": "~7.7.0", "cors": "~2.8.6", "express": "~5.2.1", @@ -6952,7 +7326,7 @@ "react": "~19.2.4", "react-dom": "~19.2.4", "request-light": "~0.8.0", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "vscode-json-languageservice": "~5.7.2", "vscode-languageclient": "~9.0.1", "vscode-languageserver": "~9.0.1", @@ -6992,10 +7366,10 @@ "version": "7.7.0", "license": "MIT", "dependencies": { - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", "react": ">=18.0.0 || <20.0.0", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1" + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2" }, "engines": { "node": ">=20.10.0", diff --git a/package.json b/package.json index d3c9d626b..dbf145fd1 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,13 @@ { "private": true, + "workspaces": [ + "packages/vscode-ws-jsonrpc", + "packages/client", + "packages/wrapper", + "packages/wrapper-react", + "packages/examples" + ], "type": "module", - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, - "volta": { - "node": "24.13.0", - "npm": "11.6.2" - }, - "devDependencies": { - "@codingame/monaco-vscode-rollup-vsix-plugin": "^26.2.1", - "@testing-library/react": "~16.3.2", - "@types/node": "~24.10.15", - "@types/react": "~19.2.14", - "@types/react-dom": "~19.2.3", - "@typescript/native-preview": "~7.0.0-dev.20260302.1", - "@vitest/browser": "~4.0.18", - "@vitest/browser-playwright": "~4.0.18", - "@vitest/coverage-v8": "~4.0.18", - "editorconfig": "~3.0.2", - "esbuild": "~0.27.3", - "minimatch": "~10.2.4", - "oxlint": "~1.51.0", - "oxlint-tsgolint": "~0.16.0", - "shx": "~0.4.0", - "tsx": "~4.21.0", - "typescript": "~5.9.3", - "vite": "~8.0.0-beta.16", - "vitest": "~4.0.18" - }, - "overrides": { - "minimatch": "~10.2.4", - "react": "~19.2.4", - "react-dom": "~19.2.4", - "vite": "~8.0.0-beta.16" - }, "scripts": { "clean": "npm run clean --workspaces", "compile": "npm run compile --workspaces", @@ -68,22 +40,53 @@ "release:prepare": "npm run reset:repo && npm ci && npm run build && npm run lint && npm run test", "reset:chrome": "shx rm -fr ./.chrome", "reset:repo": "git clean -f -d -x --exclude=.chrome", - "test": "npm run test:install && npm run test:direct", - "test:direct:watch": "vitest --config vitest.config.ts", - "test:watch": "npm run test:install && npm run test:direct:watch", - "test:direct": "vitest --config vitest.config.ts run", + "test": "vitest --config vitest.config.ts run", + "test:watch": "vitest --config vitest.config.ts", + "test:ci": "npm run test:install && npm run test", + "test:ci:watch": "npm run test:install && npm run test:watch", "test:coverage": "vitest --config vitest.config.ts run --coverage", "test:debug": "npm run test:playwright -- --inspect-brk=20222 --browser --no-file-parallelism", "test:install": "playwright install --with-deps chromium", "license:check": "docker compose -f ./scripts/addlicense/docker-compose.yml run --rm addlicense-check", "license:add": "docker compose -f ./scripts/addlicense/docker-compose.yml run --rm addlicense-add", - "license:help": "docker compose -f ./scripts/addlicense/docker-compose.yml run --rm addlicense-help" + "license:help": "docker compose -f ./scripts/addlicense/docker-compose.yml run --rm addlicense-help", + "fmt": "oxfmt", + "fmt:check": "oxfmt --check" }, - "workspaces": [ - "packages/vscode-ws-jsonrpc", - "packages/client", - "packages/wrapper", - "packages/wrapper-react", - "packages/examples" - ] + "devDependencies": { + "@codingame/monaco-vscode-rollup-vsix-plugin": "^26.2.2", + "@testing-library/react": "~16.3.2", + "@types/node": "~24.10.15", + "@types/react": "~19.2.14", + "@types/react-dom": "~19.2.3", + "@typescript/native-preview": "~7.0.0-dev.20260305.1", + "@vitest/browser": "~4.0.18", + "@vitest/browser-playwright": "~4.0.18", + "@vitest/coverage-v8": "~4.0.18", + "editorconfig": "~3.0.2", + "esbuild": "~0.27.3", + "minimatch": "~10.2.4", + "oxfmt": "~0.36.0", + "oxlint": "~1.51.0", + "oxlint-tsgolint": "~0.16.0", + "shx": "~0.4.0", + "tsx": "~4.21.0", + "typescript": "~5.9.3", + "vite": "~8.0.0-beta.16", + "vitest": "~4.0.18" + }, + "overrides": { + "minimatch": "~10.2.4", + "react": "~19.2.4", + "react-dom": "~19.2.4", + "vite": "~8.0.0-beta.16" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "volta": { + "node": "24.13.0", + "npm": "11.6.2" + } } diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index f04d89463..aa3979139 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this npm module are documented in this file. ## [10.8.0] - unreleased -- Updated all `@codingame/monaco-vscode` packages to `26.2.1` +- Updated all `@codingame/monaco-vscode` packages to `26.2.2` - Dropped eslint and rely fully on oxlint. ## [10.7.0] - 2026-02-04 @@ -291,7 +291,7 @@ All notable changes to this npm module are documented in this file. - Updated to `monaco-editor` `0.43.0` and `monaco-vscode-api` `1.82.2` - Only keep user services in`initServices`. It requires to specifically import and use services provided by [monaco-vscode-api](https://github.com/CodinGame/monaco-vscode-api#monaco-standalone-services) - - All *enable...* and *configure* type parameters have been removed from `monaco-languagclient` + - All _enable..._ and _configure_ type parameters have been removed from `monaco-languagclient` - languages and model services are always added by `monaco-languagclient` - layout, environment, extension, files and quickAccess servies are always added by `monaco-vscode-api` - Additional services need to be added to the package dependencies and imported and configured as shown in the [examples](https://github.com/TypeFox/monaco-languageclient#examples) @@ -428,7 +428,7 @@ The npm packages exports the following: ## [2.0.2] - 2022-06-22 - Align all tsconfigs and vscode-ws-jsonrpc provides esm/cjs [#390](https://github.com/TypeFox/monaco-languageclient/pull/390) - - Use `typesVersions` in **package.json*- for proper TypeScript import support (used in node example) + - Use `typesVersions` in \*_package.json_- for proper TypeScript import support (used in node example) - Remove AMD and CJS builds adn exports of the main library. Only `monaco-converters` and `monaco-converters/cjs` are left ## [2.0.1] - 2022-06-21 @@ -466,7 +466,7 @@ The npm packages exports the following: - Bugfixes resulting from this: - fix: Fix vscode-compatibility using webpack [#342](https://github.com/TypeFox/monaco-languageclient/pull/342) - Use ts-node for example [#344](https://github.com/TypeFox/monaco-languageclient/pull/344) - - Update README.md [#345](https://github.com/TypeFox/monaco-languageclient/pull/345) + - Update README.md [#345](https://github.com/TypeFox/monaco-languageclient/pull/345) - Integrate webpack client example as second option [#353](https://github.com/TypeFox/monaco-languageclient/pull/353) - Make monaco workspace disposable [#330](https://github.com/TypeFox/monaco-languageclient/pull/330) - Update the protocol to version 3.17 [#350](https://github.com/TypeFox/monaco-languageclient/pull/350) @@ -685,7 +685,10 @@ In order to use `vscode-languageclient` directly the compatibility layer was imp import { MonacoServices, Services } from 'monaco-languageclient'; const services: MonacoServices = { - worspace, languages, commands, window + worspace, + languages, + commands, + window }; Services.install(services); ``` diff --git a/packages/client/README.md b/packages/client/README.md index 193efb8d0..2c1e6bc78 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -17,9 +17,9 @@ This is npm package is part of the [monaco-languageclient mono repo](https://git You find detailed information in the [official documentation](https://github.com/TypeFox/monaco-languageclient/blob/main/docs/index.md). -If interested, check [quick start for local development](). +If interested, check [quick start for local development](https://github.com/TypeFox/monaco-languageclient#getting-started). -A detailed list of examples is contained in the GitHub repository, please see [this listing](). +A detailed list of examples is contained in the GitHub repository, please see [this listing](https://github.com/TypeFox/monaco-languageclient#examples-overview). ## Version 10: A toolbox for language client applications @@ -44,67 +44,67 @@ import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-langu import { LanguageClientWrapper, type LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; async function createEditorAndLanguageClient() { - const languageId = 'mylang'; - const code = '// initial editor content'; - const codeUri = '/workspace/hello.mylang'; - - // Monaco VSCode API configuration - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off' - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - // Language client configuration - const languageClientConfig: LanguageClientConfig = { - languageId: languageId, - connection: { - options: { - $type: 'WebSocketUrl', - // at this url the language server for myLang must be reachable - url: 'ws://localhost:30000/myLangLS' - } - }, - clientOptions: { - documentSelector: [languageId], - orkspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.file('/workspace') - } - } - }; - - // editor app / monaco-editor configuration - const editorAppConfig: EditorAppConfig = { - codeResources: { - main: { - text: code, - uri: codeUri - } - } - }; - - // Create the monaco-vscode api Wrapper and start it before anything else - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - // Create language client wrapper - const lcWrapper = new LanguageClientWrapper(languageClientConfig); - await lcWrapper.start(); - - // Create and start the editor app - const editorApp = new EditorApp(editorAppConfig); - const htmlContainer = document.getElementById('monaco-editor-root')!; - await editorApp.start(htmlContainer); + const languageId = 'mylang'; + const code = '// initial editor content'; + const codeUri = '/workspace/hello.mylang'; + + // Monaco VSCode API configuration + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off' + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + // Language client configuration + const languageClientConfig: LanguageClientConfig = { + languageId: languageId, + connection: { + options: { + $type: 'WebSocketUrl', + // at this url the language server for myLang must be reachable + url: 'ws://localhost:30000/myLangLS' + } + }, + clientOptions: { + documentSelector: [languageId], + orkspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.file('/workspace') + } + } + }; + + // editor app / monaco-editor configuration + const editorAppConfig: EditorAppConfig = { + codeResources: { + main: { + text: code, + uri: codeUri + } + } + }; + + // Create the monaco-vscode api Wrapper and start it before anything else + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + // Create language client wrapper + const lcWrapper = new LanguageClientWrapper(languageClientConfig); + await lcWrapper.start(); + + // Create and start the editor app + const editorApp = new EditorApp(editorAppConfig); + const htmlContainer = document.getElementById('monaco-editor-root')!; + await editorApp.start(htmlContainer); } createEditorAndLanguageClient().catch(console.error); diff --git a/packages/client/package.json b/packages/client/package.json index 6109696eb..3c6708976 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -2,23 +2,61 @@ "name": "monaco-languageclient", "version": "10.7.0", "description": "Monaco Language client implementation", + "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/client/README.md", + "bugs": { + "url": "https://github.com/TypeFox/monaco-languageclient/issues" + }, + "license": "MIT", "author": { "name": "TypeFox GmbH", "url": "http://www.typefox.io" }, - "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/client/README.md", - "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/TypeFox/monaco-languageclient.git", "directory": "packages/client" }, - "bugs": { - "url": "https://github.com/TypeFox/monaco-languageclient/issues" - }, + "files": [ + "lib", + "src", + "README.md", + "CHANGELOG.md", + "LICENSE" + ], "type": "module", "main": "./lib/index.js", "module": "./lib/index.js", + "typesVersions": { + "*": { + ".": [ + "lib/index.d.ts" + ], + "common": [ + "lib/common/index" + ], + "vscodeApiWrapper": [ + "lib/vscode/index" + ], + "vscodeApiLocales": [ + "lib/vscode/locales" + ], + "fs": [ + "lib/fs/index" + ], + "workerFactory": [ + "lib/worker/index" + ], + "lcwrapper": [ + "lib/wrapper/index" + ], + "editorApp": [ + "lib/editorApp/index" + ], + "debugger": [ + "lib/debugger/index" + ] + } + }, "exports": { ".": { "types": "./lib/index.d.ts", @@ -57,99 +95,61 @@ "default": "./lib/debugger/index.js" } }, - "typesVersions": { - "*": { - ".": [ - "lib/index.d.ts" - ], - "common": [ - "lib/common/index" - ], - "vscodeApiWrapper": [ - "lib/vscode/index" - ], - "vscodeApiLocales": [ - "lib/vscode/locales" - ], - "fs": [ - "lib/fs/index" - ], - "workerFactory": [ - "lib/worker/index" - ], - "lcwrapper": [ - "lib/wrapper/index" - ], - "editorApp": [ - "lib/editorApp/index" - ], - "debugger": [ - "lib/debugger/index" - ] - } - }, - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, - "volta": { - "node": "24.13.0", - "npm": "11.6.2" + "scripts": { + "clean": "shx rm -fr ./lib *.tsbuildinfo", + "compile": "tsgo --build tsconfig.src.json", + "build:msg": "echo Building monaco-languageclient:", + "build": "npm run build:msg && npm run clean && npm run compile" }, - "files": [ - "lib", - "src", - "README.md", - "CHANGELOG.md", - "LICENSE" - ], "dependencies": { - "@codingame/monaco-vscode-api": "^26.2.1", - "@codingame/monaco-vscode-configuration-service-override": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-editor-service-override": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "^26.2.1", - "@codingame/monaco-vscode-language-pack-cs": "^26.2.1", - "@codingame/monaco-vscode-language-pack-de": "^26.2.1", - "@codingame/monaco-vscode-language-pack-es": "^26.2.1", - "@codingame/monaco-vscode-language-pack-fr": "^26.2.1", - "@codingame/monaco-vscode-language-pack-it": "^26.2.1", - "@codingame/monaco-vscode-language-pack-ja": "^26.2.1", - "@codingame/monaco-vscode-language-pack-ko": "^26.2.1", - "@codingame/monaco-vscode-language-pack-pl": "^26.2.1", - "@codingame/monaco-vscode-language-pack-pt-br": "^26.2.1", - "@codingame/monaco-vscode-language-pack-qps-ploc": "^26.2.1", - "@codingame/monaco-vscode-language-pack-ru": "^26.2.1", - "@codingame/monaco-vscode-language-pack-tr": "^26.2.1", - "@codingame/monaco-vscode-language-pack-zh-hans": "^26.2.1", - "@codingame/monaco-vscode-language-pack-zh-hant": "^26.2.1", - "@codingame/monaco-vscode-languages-service-override": "^26.2.1", - "@codingame/monaco-vscode-localization-service-override": "^26.2.1", - "@codingame/monaco-vscode-log-service-override": "^26.2.1", - "@codingame/monaco-vscode-model-service-override": "^26.2.1", - "@codingame/monaco-vscode-monarch-service-override": "^26.2.1", - "@codingame/monaco-vscode-textmate-service-override": "^26.2.1", - "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.1", - "@codingame/monaco-vscode-theme-service-override": "^26.2.1", - "@codingame/monaco-vscode-views-service-override": "^26.2.1", - "@codingame/monaco-vscode-workbench-service-override": "^26.2.1", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "@codingame/monaco-vscode-api": "^26.2.2", + "@codingame/monaco-vscode-configuration-service-override": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-editor-service-override": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "^26.2.2", + "@codingame/monaco-vscode-language-pack-cs": "^26.2.2", + "@codingame/monaco-vscode-language-pack-de": "^26.2.2", + "@codingame/monaco-vscode-language-pack-es": "^26.2.2", + "@codingame/monaco-vscode-language-pack-fr": "^26.2.2", + "@codingame/monaco-vscode-language-pack-it": "^26.2.2", + "@codingame/monaco-vscode-language-pack-ja": "^26.2.2", + "@codingame/monaco-vscode-language-pack-ko": "^26.2.2", + "@codingame/monaco-vscode-language-pack-pl": "^26.2.2", + "@codingame/monaco-vscode-language-pack-pt-br": "^26.2.2", + "@codingame/monaco-vscode-language-pack-qps-ploc": "^26.2.2", + "@codingame/monaco-vscode-language-pack-ru": "^26.2.2", + "@codingame/monaco-vscode-language-pack-tr": "^26.2.2", + "@codingame/monaco-vscode-language-pack-zh-hans": "^26.2.2", + "@codingame/monaco-vscode-language-pack-zh-hant": "^26.2.2", + "@codingame/monaco-vscode-languages-service-override": "^26.2.2", + "@codingame/monaco-vscode-localization-service-override": "^26.2.2", + "@codingame/monaco-vscode-log-service-override": "^26.2.2", + "@codingame/monaco-vscode-model-service-override": "^26.2.2", + "@codingame/monaco-vscode-monarch-service-override": "^26.2.2", + "@codingame/monaco-vscode-textmate-service-override": "^26.2.2", + "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.2", + "@codingame/monaco-vscode-theme-service-override": "^26.2.2", + "@codingame/monaco-vscode-views-service-override": "^26.2.2", + "@codingame/monaco-vscode-workbench-service-override": "^26.2.2", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "vscode-languageclient": "~9.0.1", "vscode-languageserver-protocol": "~3.17.5", "vscode-ws-jsonrpc": "~3.5.0" }, "devDependencies": { - "@codingame/monaco-vscode-standalone-css-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-html-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-languages": "^26.2.1", - "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.1" + "@codingame/monaco-vscode-standalone-css-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-html-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-languages": "^26.2.2", + "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.2" }, - "scripts": { - "clean": "shx rm -fr ./lib *.tsbuildinfo", - "compile": "tsgo --build tsconfig.src.json", - "build:msg": "echo Building monaco-languageclient:", - "build": "npm run build:msg && npm run clean && npm run compile" + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "volta": { + "node": "24.13.0", + "npm": "11.6.2" } } diff --git a/packages/client/src/common/commonTypes.ts b/packages/client/src/common/commonTypes.ts index adba89557..5b326eb94 100644 --- a/packages/client/src/common/commonTypes.ts +++ b/packages/client/src/common/commonTypes.ts @@ -5,56 +5,61 @@ import type { BaseLanguageClient } from 'vscode-languageclient/browser.js'; -export type ConnectionConfigOptions = WebSocketConfigOptionsDirect | WebSocketConfigOptionsParams | WebSocketConfigOptionsUrl | WorkerConfigOptionsParams | WorkerConfigOptionsDirect; +export type ConnectionConfigOptions = + | WebSocketConfigOptionsDirect + | WebSocketConfigOptionsParams + | WebSocketConfigOptionsUrl + | WorkerConfigOptionsParams + | WorkerConfigOptionsDirect; export interface WebSocketCallOptions { - /** Adds handle on languageClient */ - onCall: (languageClient?: BaseLanguageClient) => void; - /** Reports Status Of Language Client */ - reportStatus?: boolean; + /** Adds handle on languageClient */ + onCall: (languageClient?: BaseLanguageClient) => void; + /** Reports Status Of Language Client */ + reportStatus?: boolean; } export interface WebSocketConfigOptionsDirect { - $type: 'WebSocketDirect' - webSocket: WebSocket - startOptions?: WebSocketCallOptions; - stopOptions?: WebSocketCallOptions; + $type: 'WebSocketDirect'; + webSocket: WebSocket; + startOptions?: WebSocketCallOptions; + stopOptions?: WebSocketCallOptions; } export interface WebSocketUrlParams { - secured: boolean; - host: string; - port?: number; - path?: string; - extraParams?: Record>; + secured: boolean; + host: string; + port?: number; + path?: string; + extraParams?: Record>; } export interface WebSocketConfigOptionsParams extends WebSocketUrlParams { - $type: 'WebSocketParams' - startOptions?: WebSocketCallOptions; - stopOptions?: WebSocketCallOptions; + $type: 'WebSocketParams'; + startOptions?: WebSocketCallOptions; + stopOptions?: WebSocketCallOptions; } export interface WebSocketUrlString { - url: string; + url: string; } export interface WebSocketConfigOptionsUrl extends WebSocketUrlString { - $type: 'WebSocketUrl' - startOptions?: WebSocketCallOptions; - stopOptions?: WebSocketCallOptions; + $type: 'WebSocketUrl'; + startOptions?: WebSocketCallOptions; + stopOptions?: WebSocketCallOptions; } export interface WorkerConfigOptionsParams { - $type: 'WorkerConfig' - url: URL; - type: 'classic' | 'module'; - messagePort?: MessagePort; - workerName?: string; + $type: 'WorkerConfig'; + url: URL; + type: 'classic' | 'module'; + messagePort?: MessagePort; + workerName?: string; } export interface WorkerConfigOptionsDirect { - $type: 'WorkerDirect'; - worker: Worker; - messagePort?: MessagePort; + $type: 'WorkerDirect'; + worker: Worker; + messagePort?: MessagePort; } diff --git a/packages/client/src/common/index.ts b/packages/client/src/common/index.ts index 86f3faa02..603935d96 100644 --- a/packages/client/src/common/index.ts +++ b/packages/client/src/common/index.ts @@ -5,4 +5,3 @@ export * from './commonTypes.js'; export * from './utils.js'; - diff --git a/packages/client/src/common/utils.ts b/packages/client/src/common/utils.ts index 29b8e28e9..cda8f44e2 100644 --- a/packages/client/src/common/utils.ts +++ b/packages/client/src/common/utils.ts @@ -6,62 +6,62 @@ import type { WebSocketUrlParams, WebSocketUrlString } from './commonTypes.js'; export const createUrl = (config: WebSocketUrlParams | WebSocketUrlString) => { - let buildUrl = ''; - if (Object.hasOwn(config, 'url')) { - const options = config as WebSocketUrlString; - if (!options.url.startsWith('ws://') && !options.url.startsWith('wss://')) { - throw new Error(`This is not a proper websocket url: ${options.url}`); - } - buildUrl = options.url; - } else { - const options = config as WebSocketUrlParams; - const protocol = options.secured ? 'wss' : 'ws'; - buildUrl = `${protocol}://${options.host}`; - if (options.port !== undefined) { - if (options.port !== 80) { - buildUrl += `:${options.port}`; - } - } - if (options.path !== undefined) { - buildUrl += `/${options.path}`; - } - if (options.extraParams !== undefined) { - const url = new URL(buildUrl); + let buildUrl = ''; + if (Object.hasOwn(config, 'url')) { + const options = config as WebSocketUrlString; + if (!options.url.startsWith('ws://') && !options.url.startsWith('wss://')) { + throw new Error(`This is not a proper websocket url: ${options.url}`); + } + buildUrl = options.url; + } else { + const options = config as WebSocketUrlParams; + const protocol = options.secured ? 'wss' : 'ws'; + buildUrl = `${protocol}://${options.host}`; + if (options.port !== undefined) { + if (options.port !== 80) { + buildUrl += `:${options.port}`; + } + } + if (options.path !== undefined) { + buildUrl += `/${options.path}`; + } + if (options.extraParams !== undefined) { + const url = new URL(buildUrl); - for (const [key, value] of Object.entries(options.extraParams)) { - url.searchParams.set(key, value instanceof Array ? value.join(',') : value.toString()); - } + for (const [key, value] of Object.entries(options.extraParams)) { + url.searchParams.set(key, value instanceof Array ? value.join(',') : value.toString()); + } - buildUrl = url.toString(); - } + buildUrl = url.toString(); } - return buildUrl; + } + return buildUrl; }; export const encodeStringOrUrlToDataUrl = (input: string | URL) => { - if (input instanceof URL) { - return input.href; - } else { - const bytes = new TextEncoder().encode(input); - const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join(''); - const base64 = btoa(binString); - return new URL(`data:text/plain;base64,${base64}`).href; - } + if (input instanceof URL) { + return input.href; + } else { + const bytes = new TextEncoder().encode(input); + const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join(''); + const base64 = btoa(binString); + return new URL(`data:text/plain;base64,${base64}`).href; + } }; export const delayExecution = (ms: number) => { - return new Promise((resolve) => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); }; export class Deferred { - promise: Promise; - resolve: (value: T | PromiseLike) => void; - reject: (reason?: unknown) => void; + promise: Promise; + resolve: (value: T | PromiseLike) => void; + reject: (reason?: unknown) => void; - constructor() { - this.promise = new Promise((res, rej) => { - this.resolve = res; - this.reject = rej; - }); - } + constructor() { + this.promise = new Promise((res, rej) => { + this.resolve = res; + this.reject = rej; + }); + } } diff --git a/packages/client/src/debugger/index.ts b/packages/client/src/debugger/index.ts index 5f7365b69..c5416404b 100644 --- a/packages/client/src/debugger/index.ts +++ b/packages/client/src/debugger/index.ts @@ -14,155 +14,152 @@ import { Uri } from 'vscode'; // The client configuration is generic and can be used for a another language export type FileDefinition = { - path: string; - code: string; - uri: Uri; -} + path: string; + code: string; + uri: Uri; +}; export type InitMessage = { - id: 'init', - files: Record - defaultFile: string; - debuggerExecCall: string; + id: 'init'; + files: Record; + defaultFile: string; + debuggerExecCall: string; }; export type ConfigParams = { - extensionName: string; - version: string; - publisher: string; - languageId: string; - documentSelector: string[]; - homeDir: string; - workspaceRoot: string; - workspaceFile: Uri; - htmlContainer: HTMLElement; - protocol: 'ws' | 'wss'; - hostname: string; - port: number; - files: Map; - defaultFile: string; - helpContainerCmd: string; - debuggerExecCall: string; -} + extensionName: string; + version: string; + publisher: string; + languageId: string; + documentSelector: string[]; + homeDir: string; + workspaceRoot: string; + workspaceFile: Uri; + htmlContainer: HTMLElement; + protocol: 'ws' | 'wss'; + hostname: string; + port: number; + files: Map; + defaultFile: string; + helpContainerCmd: string; + debuggerExecCall: string; +}; export const provideDebuggerExtensionConfig = (config: ConfigParams): ExtensionConfig => { - const filesOrContents = new Map(); - filesOrContents.set('./extension.js', '// nothing'); - - return { - config: { - name: config.extensionName, - publisher: config.publisher, - version: config.version, - engines: { - vscode: '*' - }, - // A browser field is mandatory for the extension to be flagged as `web` - browser: 'extension.js', - contributes: { - debuggers: [ - { - type: config.languageId, - label: 'Test', - languages: [config.languageId] - } - ], - breakpoints: [ - { - language: config.languageId - } - ] - }, - activationEvents: [ - 'onDebug' - ] - }, - filesOrContents - }; + const filesOrContents = new Map(); + filesOrContents.set('./extension.js', '// nothing'); + + return { + config: { + name: config.extensionName, + publisher: config.publisher, + version: config.version, + engines: { + vscode: '*' + }, + // A browser field is mandatory for the extension to be flagged as `web` + browser: 'extension.js', + contributes: { + debuggers: [ + { + type: config.languageId, + label: 'Test', + languages: [config.languageId] + } + ], + breakpoints: [ + { + language: config.languageId + } + ] + }, + activationEvents: ['onDebug'] + }, + filesOrContents + }; }; export const configureDebugging = async (api: typeof vscode, config: ConfigParams, logger?: ILogger) => { - class WebsocketDebugAdapter implements vscode.DebugAdapter { - private websocket: WebSocket; - - constructor(websocket: WebSocket) { - this.websocket = websocket; - this.websocket.onmessage = (message) => { - this._onDidSendMessage.fire(JSON.parse(message.data)); - }; - } + class WebsocketDebugAdapter implements vscode.DebugAdapter { + private websocket: WebSocket; + + constructor(websocket: WebSocket) { + this.websocket = websocket; + this.websocket.onmessage = (message) => { + this._onDidSendMessage.fire(JSON.parse(message.data)); + }; + } - _onDidSendMessage = new api.EventEmitter(); - onDidSendMessage = this._onDidSendMessage.event; + _onDidSendMessage = new api.EventEmitter(); + onDidSendMessage = this._onDidSendMessage.event; - handleMessage(message: vscode.DebugProtocolMessage): void { - // path with on Windows (Chrome/Firefox) arrive here with \\ and not like expected with / - // Chrome on Ubuntu behaves as expected - const msg = JSON.stringify(message).replaceAll('\\\\', '/'); - this.websocket.send(msg); - } - - dispose() { - this.websocket.close(); - } + handleMessage(message: vscode.DebugProtocolMessage): void { + // path with on Windows (Chrome/Firefox) arrive here with \\ and not like expected with / + // Chrome on Ubuntu behaves as expected + const msg = JSON.stringify(message).replaceAll('\\\\', '/'); + this.websocket.send(msg); } - api.debug.registerDebugAdapterDescriptorFactory(config.languageId, { - async createDebugAdapterDescriptor() { - const websocket = new WebSocket(`${config.protocol}://${config.hostname}:${config.port}`); - - await new Promise((resolve, reject) => { - websocket.onopen = resolve; - websocket.onerror = () => - reject(new Error(`Unable to connect to debugger server. Run "${config.helpContainerCmd}"`)); - }); - - const adapter = new WebsocketDebugAdapter(websocket); - - const initMessage: InitMessage = { - id: 'init', - files: {}, - // the default file is the one that will be used by the debugger - defaultFile: config.defaultFile, - debuggerExecCall: config.debuggerExecCall - }; - for (const [name, fileDef] of config.files.entries()) { - logger?.info(`Found: ${name} Sending file: ${fileDef.path}`); - initMessage.files[name] = { - path: fileDef.path, - code: fileDef.code, - uri: fileDef.uri - }; - } - websocket.send(JSON.stringify(initMessage)); - - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - adapter.onDidSendMessage((message: any) => { - if (message.type === 'event' && message.event === 'output') { - logger?.info('OUTPUT', message.body.output); - } - }); - return new api.DebugAdapterInlineImplementation(adapter); + dispose() { + this.websocket.close(); + } + } + + api.debug.registerDebugAdapterDescriptorFactory(config.languageId, { + async createDebugAdapterDescriptor() { + const websocket = new WebSocket(`${config.protocol}://${config.hostname}:${config.port}`); + + await new Promise((resolve, reject) => { + websocket.onopen = resolve; + websocket.onerror = () => reject(new Error(`Unable to connect to debugger server. Run "${config.helpContainerCmd}"`)); + }); + + const adapter = new WebsocketDebugAdapter(websocket); + + const initMessage: InitMessage = { + id: 'init', + files: {}, + // the default file is the one that will be used by the debugger + defaultFile: config.defaultFile, + debuggerExecCall: config.debuggerExecCall + }; + for (const [name, fileDef] of config.files.entries()) { + logger?.info(`Found: ${name} Sending file: ${fileDef.path}`); + initMessage.files[name] = { + path: fileDef.path, + code: fileDef.code, + uri: fileDef.uri + }; + } + websocket.send(JSON.stringify(initMessage)); + + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + adapter.onDidSendMessage((message: any) => { + if (message.type === 'event' && message.event === 'output') { + logger?.info('OUTPUT', message.body.output); } - }); + }); + return new api.DebugAdapterInlineImplementation(adapter); + } + }); }; export const createDebugLaunchConfigFile = (workspacePath: string, type: string) => { - return new RegisteredMemoryFile( - Uri.file(`${workspacePath}/.vscode/launch.json`), - JSON.stringify( - { - version: '0.2.0', - configurations: [ - { - name: 'Debugger: Lauch', - type, - request: 'attach', - } - ] - }, - null, - 2 - ) - ); + return new RegisteredMemoryFile( + Uri.file(`${workspacePath}/.vscode/launch.json`), + JSON.stringify( + { + version: '0.2.0', + configurations: [ + { + name: 'Debugger: Lauch', + type, + request: 'attach' + } + ] + }, + null, + 2 + ) + ); }; diff --git a/packages/client/src/editorApp/config.ts b/packages/client/src/editorApp/config.ts index 1872806e1..f3460e006 100644 --- a/packages/client/src/editorApp/config.ts +++ b/packages/client/src/editorApp/config.ts @@ -9,57 +9,57 @@ import * as monaco from '@codingame/monaco-vscode-editor-api'; import type { IReference } from '@codingame/monaco-vscode-editor-service-override'; export class ModelRefs { - modified?: IReference; - original?: IReference; + modified?: IReference; + original?: IReference; } export interface TextModels { - modified?: monaco.editor.ITextModel | null; - original?: monaco.editor.ITextModel | null; + modified?: monaco.editor.ITextModel | null; + original?: monaco.editor.ITextModel | null; } export interface TextContents { - modified?: string; - original?: string; + modified?: string; + original?: string; } export interface CodeContent { - text: string; - uri: string; - enforceLanguageId?: string; + text: string; + uri: string; + enforceLanguageId?: string; } export interface CodeResources { - modified?: CodeContent; - original?: CodeContent; + modified?: CodeContent; + original?: CodeContent; } export interface CallbackDisposeable { - modified?: monaco.IDisposable; - original?: monaco.IDisposable; + modified?: monaco.IDisposable; + original?: monaco.IDisposable; } export interface DisposableModelRefs { - modified?: IReference; - original?: IReference; + modified?: IReference; + original?: IReference; } export interface EditorAppConfig { - id?: string; - logLevel?: LogLevel | number; - codeResources?: CodeResources; - useDiffEditor?: boolean; - domReadOnly?: boolean; - readOnly?: boolean; - overrideAutomaticLayout?: boolean; - editorOptions?: monaco.editor.IStandaloneEditorConstructionOptions; - diffEditorOptions?: monaco.editor.IStandaloneDiffEditorConstructionOptions; - languageDef?: { - languageExtensionConfig: monaco.languages.ILanguageExtensionPoint; - monarchLanguage?: monaco.languages.IMonarchLanguage; - theme?: { - name: string; - data: monaco.editor.IStandaloneThemeData; - } - } + id?: string; + logLevel?: LogLevel | number; + codeResources?: CodeResources; + useDiffEditor?: boolean; + domReadOnly?: boolean; + readOnly?: boolean; + overrideAutomaticLayout?: boolean; + editorOptions?: monaco.editor.IStandaloneEditorConstructionOptions; + diffEditorOptions?: monaco.editor.IStandaloneDiffEditorConstructionOptions; + languageDef?: { + languageExtensionConfig: monaco.languages.ILanguageExtensionPoint; + monarchLanguage?: monaco.languages.IMonarchLanguage; + theme?: { + name: string; + data: monaco.editor.IStandaloneThemeData; + }; + }; } diff --git a/packages/client/src/editorApp/editorApp.ts b/packages/client/src/editorApp/editorApp.ts index 411376dce..e8fd6844c 100644 --- a/packages/client/src/editorApp/editorApp.ts +++ b/packages/client/src/editorApp/editorApp.ts @@ -11,7 +11,15 @@ import type { ILogger } from '@codingame/monaco-vscode-log-service-override'; import { ConsoleLogger } from '@codingame/monaco-vscode-log-service-override'; import { getEnhancedMonacoEnvironment } from 'monaco-languageclient/vscodeApiWrapper'; import * as vscode from 'vscode'; -import type { CallbackDisposeable, CodeContent, CodeResources, DisposableModelRefs, EditorAppConfig, TextContents, TextModels } from './config.js'; +import type { + CallbackDisposeable, + CodeContent, + CodeResources, + DisposableModelRefs, + EditorAppConfig, + TextContents, + TextModels +} from './config.js'; import { ModelRefs } from './config.js'; /** @@ -22,421 +30,428 @@ import { ModelRefs } from './config.js'; * It provides the generic functionality for both implementations. */ export class EditorApp { + private id: string; + private config: EditorAppConfig; - private id: string; - private config: EditorAppConfig; + protected logger: ILogger = new ConsoleLogger(); - protected logger: ILogger = new ConsoleLogger(); + private editor: monaco.editor.IStandaloneCodeEditor | undefined; + private diffEditor: monaco.editor.IStandaloneDiffEditor | undefined; - private editor: monaco.editor.IStandaloneCodeEditor | undefined; - private diffEditor: monaco.editor.IStandaloneDiffEditor | undefined; + private modelRefs: ModelRefs = new ModelRefs(); - private modelRefs: ModelRefs = new ModelRefs(); + private onTextChanged?: (textChanges: TextContents) => void; + private textChangedDisposables: CallbackDisposeable = {}; + private modelDisposables: DisposableModelRefs = {}; - private onTextChanged?: (textChanges: TextContents) => void; - private textChangedDisposables: CallbackDisposeable = {}; - private modelDisposables: DisposableModelRefs = {}; + private modelRefDisposeTimeout = -1; - private modelRefDisposeTimeout = -1; + private startingAwait?: Promise; - private startingAwait?: Promise; + private disposingAwait?: Promise; - private disposingAwait?: Promise; - - constructor(userAppConfig?: EditorAppConfig) { - this.id = userAppConfig?.id ?? Math.floor(Math.random() * 1000001).toString(); - this.config = { - codeResources: userAppConfig?.codeResources ?? undefined, - useDiffEditor: userAppConfig?.useDiffEditor ?? false, - readOnly: userAppConfig?.readOnly ?? false, - domReadOnly: userAppConfig?.domReadOnly ?? false, - overrideAutomaticLayout: userAppConfig?.overrideAutomaticLayout ?? true - }; - this.config.editorOptions = { - ...userAppConfig?.editorOptions, - automaticLayout: userAppConfig?.overrideAutomaticLayout ?? true - }; - this.config.diffEditorOptions = { - ...userAppConfig?.diffEditorOptions, - automaticLayout: userAppConfig?.overrideAutomaticLayout ?? true - }; - this.config.languageDef = userAppConfig?.languageDef; - this.config.logLevel = userAppConfig?.logLevel ?? LogLevel.Off; - - this.logger.setLevel(this.config.logLevel); - } - - isDiffEditor() { - return this.config.useDiffEditor === true; - } + constructor(userAppConfig?: EditorAppConfig) { + this.id = userAppConfig?.id ?? Math.floor(Math.random() * 1000001).toString(); + this.config = { + codeResources: userAppConfig?.codeResources ?? undefined, + useDiffEditor: userAppConfig?.useDiffEditor ?? false, + readOnly: userAppConfig?.readOnly ?? false, + domReadOnly: userAppConfig?.domReadOnly ?? false, + overrideAutomaticLayout: userAppConfig?.overrideAutomaticLayout ?? true + }; + this.config.editorOptions = { + ...userAppConfig?.editorOptions, + automaticLayout: userAppConfig?.overrideAutomaticLayout ?? true + }; + this.config.diffEditorOptions = { + ...userAppConfig?.diffEditorOptions, + automaticLayout: userAppConfig?.overrideAutomaticLayout ?? true + }; + this.config.languageDef = userAppConfig?.languageDef; + this.config.logLevel = userAppConfig?.logLevel ?? LogLevel.Off; - getConfig(): EditorAppConfig { - return this.config; - } + this.logger.setLevel(this.config.logLevel); + } - getEditor(): monaco.editor.IStandaloneCodeEditor | undefined { - return this.editor; - } + isDiffEditor() { + return this.config.useDiffEditor === true; + } - getDiffEditor(): monaco.editor.IStandaloneDiffEditor | undefined { - return this.diffEditor; - } + getConfig(): EditorAppConfig { + return this.config; + } - getTextModels(): TextModels { - return { - modified: this.modelRefs.modified?.object.textEditorModel ?? undefined, - original: this.modelRefs.original?.object.textEditorModel ?? undefined - }; - } + getEditor(): monaco.editor.IStandaloneCodeEditor | undefined { + return this.editor; + } - registerOnTextChangedCallback(onTextChanged?: (textChanges: TextContents) => void) { - this.onTextChanged = onTextChanged; - } + getDiffEditor(): monaco.editor.IStandaloneDiffEditor | undefined { + return this.diffEditor; + } - public setModelRefDisposeTimeout(modelRefDisposeTimeout: number) { - this.modelRefDisposeTimeout = modelRefDisposeTimeout; - } - - isStarting() { - return this.startingAwait !== undefined; - } - - getStartingAwait() { - return this.startingAwait; + getTextModels(): TextModels { + return { + modified: this.modelRefs.modified?.object.textEditorModel ?? undefined, + original: this.modelRefs.original?.object.textEditorModel ?? undefined + }; + } + + registerOnTextChangedCallback(onTextChanged?: (textChanges: TextContents) => void) { + this.onTextChanged = onTextChanged; + } + + public setModelRefDisposeTimeout(modelRefDisposeTimeout: number) { + this.modelRefDisposeTimeout = modelRefDisposeTimeout; + } + + isStarting() { + return this.startingAwait !== undefined; + } + + getStartingAwait() { + return this.startingAwait; + } + + isStarted() { + return this.editor !== undefined || this.diffEditor !== undefined; + } + + /** + * Starts the single editor application. + */ + async start(htmlContainer: HTMLElement) { + if (this.isStarting()) { + await this.getStartingAwait(); } - isStarted() { - return this.editor !== undefined || this.diffEditor !== undefined; - } + let startingResolve: (value: void | PromiseLike) => void = () => {}; + this.startingAwait = new Promise((resolve) => { + startingResolve = resolve; + }); - /** - * Starts the single editor application. - */ - async start(htmlContainer: HTMLElement) { - if (this.isStarting()) { - await this.getStartingAwait(); + try { + const envEnhanced = getEnhancedMonacoEnvironment(); + const viewServiceType = envEnhanced.viewServiceType; + + // check general error case first + if (!(envEnhanced.vscodeApiInitialised ?? false)) { + return Promise.reject('monaco-vscode-api was not initialized. Aborting.'); + } + if (viewServiceType !== 'EditorService' && viewServiceType !== undefined) { + return Promise.reject('No EditorService configured. monaco-editor will not be started.'); + } + if (!this.isDisposed()) { + return Promise.reject('Start was called without properly disposing the EditorApp first.'); + } + + const languageDef = this.config.languageDef; + if (languageDef !== undefined) { + // register own language first + monaco.languages.register(languageDef.languageExtensionConfig); + + const languageRegistered = monaco.languages.getLanguages().filter((x) => x.id === languageDef.languageExtensionConfig.id); + if (languageRegistered.length === 0) { + // this is only meaningful for languages supported by monaco out of the box + monaco.languages.register({ + id: languageDef.languageExtensionConfig.id + }); } - let startingResolve: (value: void | PromiseLike) => void = () => { }; - this.startingAwait = new Promise((resolve) => { - startingResolve = resolve; - }); + // apply monarch definitions + if (languageDef.monarchLanguage !== undefined) { + monaco.languages.setMonarchTokensProvider(languageDef.languageExtensionConfig.id, languageDef.monarchLanguage); + } - try { - const envEnhanced = getEnhancedMonacoEnvironment(); - const viewServiceType = envEnhanced.viewServiceType; - - // check general error case first - if (!(envEnhanced.vscodeApiInitialised ?? false)) { - return Promise.reject('monaco-vscode-api was not initialized. Aborting.'); - } - if (viewServiceType !== 'EditorService' && viewServiceType !== undefined) { - return Promise.reject('No EditorService configured. monaco-editor will not be started.'); - } - if (!this.isDisposed()) { - return Promise.reject('Start was called without properly disposing the EditorApp first.'); - } - - const languageDef = this.config.languageDef; - if (languageDef !== undefined) { - // register own language first - monaco.languages.register(languageDef.languageExtensionConfig); - - const languageRegistered = monaco.languages.getLanguages().filter(x => x.id === languageDef.languageExtensionConfig.id); - if (languageRegistered.length === 0) { - // this is only meaningful for languages supported by monaco out of the box - monaco.languages.register({ - id: languageDef.languageExtensionConfig.id - }); - } - - // apply monarch definitions - if (languageDef.monarchLanguage !== undefined) { - monaco.languages.setMonarchTokensProvider(languageDef.languageExtensionConfig.id, languageDef.monarchLanguage); - } - - if (languageDef.theme !== undefined) { - monaco.editor.defineTheme(languageDef.theme.name, languageDef.theme.data); - monaco.editor.setTheme(languageDef.theme.name); - } - } - - if (this.config.editorOptions?.['semanticHighlighting.enabled'] !== undefined) { - await StandaloneServices.get(IConfigurationService).updateValue('editor.semanticHighlighting.enabled', - this.config.editorOptions['semanticHighlighting.enabled'], ConfigurationTarget.USER); - } - - await this.createEditors(htmlContainer); - - // everything is fine at this point - startingResolve(); - this.logger.info('EditorApp start completed successfully.'); - } catch (e) { - // in case of further errors (after general ones above) - // take the error and build a new rejection to complete the promise - return Promise.reject(e); - } finally { - this.startingAwait = undefined; + if (languageDef.theme !== undefined) { + monaco.editor.defineTheme(languageDef.theme.name, languageDef.theme.data); + monaco.editor.setTheme(languageDef.theme.name); } + } + + if (this.config.editorOptions?.['semanticHighlighting.enabled'] !== undefined) { + await StandaloneServices.get(IConfigurationService).updateValue( + 'editor.semanticHighlighting.enabled', + this.config.editorOptions['semanticHighlighting.enabled'], + ConfigurationTarget.USER + ); + } + + await this.createEditors(htmlContainer); + + // everything is fine at this point + startingResolve(); + this.logger.info('EditorApp start completed successfully.'); + } catch (e) { + // in case of further errors (after general ones above) + // take the error and build a new rejection to complete the promise + return Promise.reject(e); + } finally { + this.startingAwait = undefined; + } + } + + async createEditors(htmlContainer: HTMLElement): Promise { + // ensure proper default resources are initialized, uris have to be unique + const modified = { + text: this.config.codeResources?.modified?.text ?? '', + uri: this.config.codeResources?.modified?.uri ?? `default-uri-modified-${this.id}`, + enforceLanguageId: this.config.codeResources?.modified?.enforceLanguageId ?? undefined + }; + this.modelRefs.modified = await this.buildModelReference(modified); + + if (this.isDiffEditor()) { + const original = { + text: this.config.codeResources?.original?.text ?? '', + uri: this.config.codeResources?.original?.uri ?? `default-uri-original-${this.id}`, + enforceLanguageId: this.config.codeResources?.original?.enforceLanguageId ?? undefined + }; + this.modelRefs.original = await this.buildModelReference(original); } - async createEditors(htmlContainer: HTMLElement): Promise { - // ensure proper default resources are initialized, uris have to be unique - const modified = { - text: this.config.codeResources?.modified?.text ?? '', - uri: this.config.codeResources?.modified?.uri ?? `default-uri-modified-${this.id}`, - enforceLanguageId: this.config.codeResources?.modified?.enforceLanguageId ?? undefined + this.logger.info(`Starting monaco-editor (${this.id})`); + if (this.isDiffEditor()) { + this.diffEditor = monaco.editor.createDiffEditor(htmlContainer, this.config.diffEditorOptions); + const modified = this.modelRefs.modified.object.textEditorModel ?? undefined; + const original = this.modelRefs.original?.object.textEditorModel ?? undefined; + if (modified !== undefined && original !== undefined) { + const model = { + modified, + original }; - this.modelRefs.modified = await this.buildModelReference(modified); - - if (this.isDiffEditor()) { - const original = { - text: this.config.codeResources?.original?.text ?? '', - uri: this.config.codeResources?.original?.uri ?? `default-uri-original-${this.id}`, - enforceLanguageId: this.config.codeResources?.original?.enforceLanguageId ?? undefined - }; - this.modelRefs.original = await this.buildModelReference(original); - } - - this.logger.info(`Starting monaco-editor (${this.id})`); - if (this.isDiffEditor()) { - this.diffEditor = monaco.editor.createDiffEditor(htmlContainer, this.config.diffEditorOptions); - const modified = this.modelRefs.modified.object.textEditorModel ?? undefined; - const original = this.modelRefs.original?.object.textEditorModel ?? undefined; - if (modified !== undefined && original !== undefined) { - const model = { - modified, - original - }; - this.diffEditor.setModel(model); - this.announceModelUpdate(model); - } - } else { - const model = { - modified: this.modelRefs.modified.object.textEditorModel - }; - this.editor = monaco.editor.create(htmlContainer, { - ...this.config.editorOptions, - model: model.modified - }); - this.announceModelUpdate(model); - } + this.diffEditor.setModel(model); + this.announceModelUpdate(model); + } + } else { + const model = { + modified: this.modelRefs.modified.object.textEditorModel + }; + this.editor = monaco.editor.create(htmlContainer, { + ...this.config.editorOptions, + model: model.modified + }); + this.announceModelUpdate(model); + } + } + + updateCode(code: { modified?: string; original?: string }) { + if (this.isDiffEditor()) { + if (code.modified !== undefined) { + this.diffEditor?.getModifiedEditor().setValue(code.modified); + } + if (code.original !== undefined) { + this.diffEditor?.getOriginalEditor().setValue(code.original); + } + } else { + if (code.modified !== undefined) { + this.editor?.setValue(code.modified); + } } + } - updateCode(code: { modified?: string, original?: string }) { - if (this.isDiffEditor()) { - if (code.modified !== undefined) { - this.diffEditor?.getModifiedEditor().setValue(code.modified); - } - if (code.original !== undefined) { - this.diffEditor?.getOriginalEditor().setValue(code.original); - } - } else { - if (code.modified !== undefined) { - this.editor?.setValue(code.modified); - } + async updateCodeResources(codeResources?: CodeResources): Promise { + let updateModified = false; + let updateOriginal = false; + let updated = false; - } + if (codeResources?.modified !== undefined && codeResources.modified.uri !== this.modelRefs.modified?.object.resource.path) { + this.modelDisposables.modified = this.modelRefs.modified; + this.modelRefs.modified = await this.buildModelReference(codeResources.modified); + updateModified = true; + } + if (codeResources?.original !== undefined && codeResources.original.uri !== this.modelRefs.original?.object.resource.path) { + this.modelDisposables.original = this.modelRefs.original; + this.modelRefs.original = await this.buildModelReference(codeResources.original); + updateOriginal = true; } - async updateCodeResources(codeResources?: CodeResources): Promise { - let updateModified = false; - let updateOriginal = false; - let updated = false; - - if (codeResources?.modified !== undefined && codeResources.modified.uri !== this.modelRefs.modified?.object.resource.path) { - this.modelDisposables.modified = this.modelRefs.modified; - this.modelRefs.modified = await this.buildModelReference(codeResources.modified); - updateModified = true; - } - if (codeResources?.original !== undefined && codeResources.original.uri !== this.modelRefs.original?.object.resource.path) { - this.modelDisposables.original = this.modelRefs.original; - this.modelRefs.original = await this.buildModelReference(codeResources.original); - updateOriginal = true; + if (this.isDiffEditor()) { + if (updateModified || updateOriginal) { + const modified = this.modelRefs.modified?.object.textEditorModel ?? undefined; + const original = this.modelRefs.original?.object.textEditorModel ?? undefined; + if (modified !== undefined && original !== undefined) { + const model = { + modified, + original + }; + this.diffEditor?.setModel(model); + this.announceModelUpdate(model); + await this.disposeModelRefs(); + updated = true; } - - if (this.isDiffEditor()) { - if (updateModified || updateOriginal) { - const modified = this.modelRefs.modified?.object.textEditorModel ?? undefined; - const original = this.modelRefs.original?.object.textEditorModel ?? undefined; - if (modified !== undefined && original !== undefined) { - const model = { - modified, - original - }; - this.diffEditor?.setModel(model); - this.announceModelUpdate(model); - await this.disposeModelRefs(); - updated = true; - } - } else { - this.logger.info('Diff Editor: Code resources were not updated. They are ether unchanged or undefined.'); - } - } else { - if (updateModified) { - const model = { - modified: this.modelRefs.modified?.object.textEditorModel - }; - if (model.modified !== undefined && model.modified !== null) { - this.editor?.setModel(model.modified); - this.announceModelUpdate(model); - await this.disposeModelRefs(); - updated = true; - } - } else { - this.logger.info('Editor: Code resources were not updated. They are either unchanged or undefined.'); - } + } else { + this.logger.info('Diff Editor: Code resources were not updated. They are ether unchanged or undefined.'); + } + } else { + if (updateModified) { + const model = { + modified: this.modelRefs.modified?.object.textEditorModel + }; + if (model.modified !== undefined && model.modified !== null) { + this.editor?.setModel(model.modified); + this.announceModelUpdate(model); + await this.disposeModelRefs(); + updated = true; } - return updated; + } else { + this.logger.info('Editor: Code resources were not updated. They are either unchanged or undefined.'); + } } + return updated; + } - async buildModelReference(codeContent: CodeContent): Promise> { - const code = codeContent.text; - const modelRef = await createModelReference(vscode.Uri.parse(codeContent.uri), code); + async buildModelReference(codeContent: CodeContent): Promise> { + const code = codeContent.text; + const modelRef = await createModelReference(vscode.Uri.parse(codeContent.uri), code); - // update the text if different - if (modelRef.object.textEditorModel?.getValue() !== code) { - modelRef.object.textEditorModel?.setValue(code); - } - const enforceLanguageId = codeContent.enforceLanguageId; - if (enforceLanguageId !== undefined) { - modelRef.object.setLanguageId(enforceLanguageId); - this.logger.info(`Main languageId is enforced: ${enforceLanguageId}`); - } - return modelRef; - }; - - private announceModelUpdate(textModels: TextModels) { - if (this.onTextChanged !== undefined) { - let changed = false; - if (textModels.modified !== undefined && textModels.modified !== null) { - const old = this.textChangedDisposables.modified; - this.textChangedDisposables.modified = textModels.modified.onDidChangeContent(() => { - didModelContentChange(textModels, this.onTextChanged); - }); - old?.dispose(); - changed = true; - } - - if (textModels.original !== undefined && textModels.original !== null) { - const old = this.textChangedDisposables.original; - this.textChangedDisposables.original = textModels.original.onDidChangeContent(() => { - didModelContentChange(textModels, this.onTextChanged); - }); - old?.dispose(); - changed = true; - } - - if (changed) { - // do it initially - didModelContentChange(textModels, this.onTextChanged); - } - } + // update the text if different + if (modelRef.object.textEditorModel?.getValue() !== code) { + modelRef.object.textEditorModel?.setValue(code); } - - async dispose() { - if (this.isDisposing()) { - await this.getDisposingAwait(); - } - let disposingResolve: (value: void | PromiseLike) => void = () => { }; - this.disposingAwait = new Promise((resolve) => { - disposingResolve = resolve; + const enforceLanguageId = codeContent.enforceLanguageId; + if (enforceLanguageId !== undefined) { + modelRef.object.setLanguageId(enforceLanguageId); + this.logger.info(`Main languageId is enforced: ${enforceLanguageId}`); + } + return modelRef; + } + + private announceModelUpdate(textModels: TextModels) { + if (this.onTextChanged !== undefined) { + let changed = false; + if (textModels.modified !== undefined && textModels.modified !== null) { + const old = this.textChangedDisposables.modified; + this.textChangedDisposables.modified = textModels.modified.onDidChangeContent(() => { + didModelContentChange(textModels, this.onTextChanged); }); - - if (this.editor !== undefined) { - this.editor.dispose(); - this.editor = undefined; - } - if (this.diffEditor !== undefined) { - this.diffEditor.dispose(); - this.diffEditor = undefined; - } - - this.textChangedDisposables.modified?.dispose(); - this.textChangedDisposables.original?.dispose(); - this.textChangedDisposables.modified = undefined; - this.textChangedDisposables.original = undefined; - - await this.disposeModelRefs(); - - disposingResolve(); - this.disposingAwait = undefined; + old?.dispose(); + changed = true; + } + + if (textModels.original !== undefined && textModels.original !== null) { + const old = this.textChangedDisposables.original; + this.textChangedDisposables.original = textModels.original.onDidChangeContent(() => { + didModelContentChange(textModels, this.onTextChanged); + }); + old?.dispose(); + changed = true; + } + + if (changed) { + // do it initially + didModelContentChange(textModels, this.onTextChanged); + } } + } - isDisposed(): boolean { - return this.editor === undefined && this.diffEditor === undefined && - this.modelDisposables.original === undefined && this.modelDisposables.modified === undefined; + async dispose() { + if (this.isDisposing()) { + await this.getDisposingAwait(); } + let disposingResolve: (value: void | PromiseLike) => void = () => {}; + this.disposingAwait = new Promise((resolve) => { + disposingResolve = resolve; + }); - isDisposing() { - return this.disposingAwait !== undefined; + if (this.editor !== undefined) { + this.editor.dispose(); + this.editor = undefined; } - - getDisposingAwait() { - return this.disposingAwait; + if (this.diffEditor !== undefined) { + this.diffEditor.dispose(); + this.diffEditor = undefined; } - async disposeModelRefs() { - const disposeRefs = () => { - if (this.logger.getLevel() === LogLevel.Debug) { - const models = monaco.editor.getModels(); - this.logger.debug('Current model URIs:'); - models.forEach((model, _index) => { - this.logger.debug(`${model.uri.toString()}`); - }); - } - - if (this.modelDisposables.modified !== undefined && !this.modelDisposables.modified.object.isDisposed()) { - this.modelDisposables.modified.dispose(); - this.modelDisposables.modified = undefined; - } - if (this.modelDisposables.original !== undefined && !this.modelDisposables.original.object.isDisposed()) { - this.modelDisposables.original.dispose(); - this.modelDisposables.original = undefined; - } - - if (this.logger.getLevel() === LogLevel.Debug) { - if (this.modelDisposables.modified === undefined && this.modelDisposables.original === undefined) { - this.logger.debug('All model references are disposed.'); - } else { - this.logger.debug('Model references are still available.'); - } - } - }; - - if (this.modelRefDisposeTimeout > 0) { - this.logger.debug('Using async dispose of model references'); - await new Promise(resolve => setTimeout(() => { - disposeRefs(); - resolve(); - }, this.modelRefDisposeTimeout)); + this.textChangedDisposables.modified?.dispose(); + this.textChangedDisposables.original?.dispose(); + this.textChangedDisposables.modified = undefined; + this.textChangedDisposables.original = undefined; + + await this.disposeModelRefs(); + + disposingResolve(); + this.disposingAwait = undefined; + } + + isDisposed(): boolean { + return ( + this.editor === undefined && + this.diffEditor === undefined && + this.modelDisposables.original === undefined && + this.modelDisposables.modified === undefined + ); + } + + isDisposing() { + return this.disposingAwait !== undefined; + } + + getDisposingAwait() { + return this.disposingAwait; + } + + async disposeModelRefs() { + const disposeRefs = () => { + if (this.logger.getLevel() === LogLevel.Debug) { + const models = monaco.editor.getModels(); + this.logger.debug('Current model URIs:'); + models.forEach((model, _index) => { + this.logger.debug(`${model.uri.toString()}`); + }); + } + + if (this.modelDisposables.modified !== undefined && !this.modelDisposables.modified.object.isDisposed()) { + this.modelDisposables.modified.dispose(); + this.modelDisposables.modified = undefined; + } + if (this.modelDisposables.original !== undefined && !this.modelDisposables.original.object.isDisposed()) { + this.modelDisposables.original.dispose(); + this.modelDisposables.original = undefined; + } + + if (this.logger.getLevel() === LogLevel.Debug) { + if (this.modelDisposables.modified === undefined && this.modelDisposables.original === undefined) { + this.logger.debug('All model references are disposed.'); } else { - disposeRefs(); + this.logger.debug('Model references are still available.'); } - } + } + }; - updateLayout(dimension?: monaco.editor.IDimension, postponeRendering?: boolean) { - if (this.isDiffEditor()) { - this.diffEditor?.layout(dimension, postponeRendering); - } else { - this.editor?.layout(dimension, postponeRendering); - } + if (this.modelRefDisposeTimeout > 0) { + this.logger.debug('Using async dispose of model references'); + await new Promise((resolve) => + setTimeout(() => { + disposeRefs(); + resolve(); + }, this.modelRefDisposeTimeout) + ); + } else { + disposeRefs(); } + } - reportStatus() { - const status: string[] = []; - status.push('EditorApp status:'); - status.push(`Editor: ${this.editor?.getId()}`); - status.push(`DiffEditor: ${this.diffEditor?.getId()}`); - return status; + updateLayout(dimension?: monaco.editor.IDimension, postponeRendering?: boolean) { + if (this.isDiffEditor()) { + this.diffEditor?.layout(dimension, postponeRendering); + } else { + this.editor?.layout(dimension, postponeRendering); } + } + + reportStatus() { + const status: string[] = []; + status.push('EditorApp status:'); + status.push(`Editor: ${this.editor?.getId()}`); + status.push(`DiffEditor: ${this.diffEditor?.getId()}`); + return status; + } } export const didModelContentChange = (textModels: TextModels, onTextChanged?: (textChanges: TextContents) => void) => { - const modified = textModels.modified?.getValue() ?? ''; - const original = textModels.original?.getValue() ?? ''; - onTextChanged?.({ - modified, - original - }); + const modified = textModels.modified?.getValue() ?? ''; + const original = textModels.original?.getValue() ?? ''; + onTextChanged?.({ + modified, + original + }); }; diff --git a/packages/client/src/fs/definitions.ts b/packages/client/src/fs/definitions.ts index c76a4e179..764d322de 100644 --- a/packages/client/src/fs/definitions.ts +++ b/packages/client/src/fs/definitions.ts @@ -6,117 +6,114 @@ import type { ILogger } from '@codingame/monaco-vscode-log-service-override'; export interface FileReadRequest { - resourceUri: string + resourceUri: string; } export type FileReadResultStatus = 'success' | 'denied'; export interface FileReadRequestResult { - status: FileReadResultStatus - content: string | ArrayBuffer | ArrayBufferLike | BlobPart + status: FileReadResultStatus; + content: string | ArrayBuffer | ArrayBufferLike | BlobPart; } export interface FileUpdate { - resourceUri: string - content: string | ArrayBuffer | ArrayBufferLike | BlobPart + resourceUri: string; + content: string | ArrayBuffer | ArrayBufferLike | BlobPart; } export type FileUpdateResultStatus = 'equal' | 'updated' | 'created' | 'denied'; export interface FileUpdateResult { - status: FileUpdateResultStatus - message?: string + status: FileUpdateResultStatus; + message?: string; } export interface DirectoryListingRequest { - directoryUri: string + directoryUri: string; } export interface DirectoryListingRequestResult { - files: string[] + files: string[]; } export type StatsRequestType = 'directory' | 'file'; export interface StatsRequest { - type: StatsRequestType, - resourceUri: string + type: StatsRequestType; + resourceUri: string; } export interface StatsRequestResult { - type: StatsRequestType - size: number - name: string - mtime: number + type: StatsRequestType; + size: number; + name: string; + mtime: number; } export type EndpointType = 'DRIVER' | 'FOLLOWER' | 'LOCAL' | 'EMPTY'; export interface FileSystemCapabilities { - - /** - * Get a text file content - * @param params the resourceUri of the file - * @returns The ReadFileResult containing the content of the file - */ - readFile(params: FileReadRequest): Promise - - /** - * Save a file on the filesystem - * @param params the resourceUri and the content of the file - * @returns The FileUpdateResult containing the result of the operation and an optional message - */ - writeFile(params: FileUpdate): Promise; - - /** - * The implementation has to decide if the file at given uri at need to be updated - * @param params the resourceUri and the content of the file - * @returns The FileUpdateResult containing the result of the operation and an optional message - */ - syncFile(params: FileUpdate): Promise; - - /** - * Get file stats on a given file - * @param params the resourceUri and if a file or a directory is requested - */ - getFileStats(params: StatsRequest): Promise - - /** - * List the files of a directory - * @param resourceUri the Uri of the directory - */ - listFiles(params: DirectoryListingRequest): Promise - + /** + * Get a text file content + * @param params the resourceUri of the file + * @returns The ReadFileResult containing the content of the file + */ + readFile(params: FileReadRequest): Promise; + + /** + * Save a file on the filesystem + * @param params the resourceUri and the content of the file + * @returns The FileUpdateResult containing the result of the operation and an optional message + */ + writeFile(params: FileUpdate): Promise; + + /** + * The implementation has to decide if the file at given uri at need to be updated + * @param params the resourceUri and the content of the file + * @returns The FileUpdateResult containing the result of the operation and an optional message + */ + syncFile(params: FileUpdate): Promise; + + /** + * Get file stats on a given file + * @param params the resourceUri and if a file or a directory is requested + */ + getFileStats(params: StatsRequest): Promise; + + /** + * List the files of a directory + * @param resourceUri the Uri of the directory + */ + listFiles(params: DirectoryListingRequest): Promise; } /** * Defines the APT for a file system endpoint */ export interface FileSystemEndpoint extends FileSystemCapabilities { - - /** - * Whatever can't be handled in the constructor should be done here - */ - init?(): void; - - /** - * Set an optional logger - * @param logger the logger implemenation - */ - setLogger?(logger: ILogger): void; - - /** - * Get the type of the client - */ - getEndpointType(): EndpointType; - - /** - * Provide info about the file system - */ - getFileSystemInfo(): string; - - /** - * Signal readiness - */ - ready?(): void; + /** + * Whatever can't be handled in the constructor should be done here + */ + init?(): void; + + /** + * Set an optional logger + * @param logger the logger implemenation + */ + setLogger?(logger: ILogger): void; + + /** + * Get the type of the client + */ + getEndpointType(): EndpointType; + + /** + * Provide info about the file system + */ + getFileSystemInfo(): string; + + /** + * Signal readiness + */ + ready?(): void; } diff --git a/packages/client/src/fs/endpoints/defaultEndpoint.ts b/packages/client/src/fs/endpoints/defaultEndpoint.ts index 799458378..0607f3775 100644 --- a/packages/client/src/fs/endpoints/defaultEndpoint.ts +++ b/packages/client/src/fs/endpoints/defaultEndpoint.ts @@ -4,57 +4,66 @@ * ------------------------------------------------------------------------------------------ */ import { type ILogger } from '@codingame/monaco-vscode-log-service-override'; -import type { DirectoryListingRequest, DirectoryListingRequestResult, EndpointType, FileReadRequest, FileReadRequestResult, FileSystemEndpoint, FileUpdate, FileUpdateResult, StatsRequest, StatsRequestResult } from '../definitions.js'; +import type { + DirectoryListingRequest, + DirectoryListingRequestResult, + EndpointType, + FileReadRequest, + FileReadRequestResult, + FileSystemEndpoint, + FileUpdate, + FileUpdateResult, + StatsRequest, + StatsRequestResult +} from '../definitions.js'; export class EmptyFileSystemEndpoint implements FileSystemEndpoint { + private endpointType: EndpointType; + private logger?: ILogger; - private endpointType: EndpointType; - private logger?: ILogger; + constructor(endpointType: EndpointType) { + this.endpointType = endpointType; + } - constructor(endpointType: EndpointType) { - this.endpointType = endpointType; - } + init(): void {} - init(): void { } + getFileSystemInfo(): string { + return 'This file system performs no operations.'; + } - getFileSystemInfo(): string { - return 'This file system performs no operations.'; - } + setLogger(logger: ILogger): void { + this.logger = logger; + } - setLogger(logger: ILogger): void { - this.logger = logger; - } + getEndpointType(): EndpointType { + return this.endpointType; + } - getEndpointType(): EndpointType { - return this.endpointType; - } + readFile(params: FileReadRequest): Promise { + this.logger?.info(`Reading file: ${params.resourceUri}`); + return Promise.resolve({ + status: 'denied', + content: '' + }); + } - readFile(params: FileReadRequest): Promise { - this.logger?.info(`Reading file: ${params.resourceUri}`); - return Promise.resolve({ - status: 'denied', - content: '' - }); - } + writeFile(params: FileUpdate): Promise { + this.logger?.info(`Writing file: ${params.resourceUri}`); + return Promise.resolve({ status: 'denied' }); + } - writeFile(params: FileUpdate): Promise { - this.logger?.info(`Writing file: ${params.resourceUri}`); - return Promise.resolve({ status: 'denied' }); - } + syncFile(params: FileUpdate): Promise { + this.logger?.info(`Syncing file: ${params.resourceUri}`); + return Promise.resolve({ status: 'denied' }); + } - syncFile(params: FileUpdate): Promise { - this.logger?.info(`Syncing file: ${params.resourceUri}`); - return Promise.resolve({ status: 'denied' }); - } - - getFileStats(params: StatsRequest): Promise { - this.logger?.info(`Getting file stats for: "${params.resourceUri}" (${params.type})`); - return Promise.reject('No stats available.'); - } - - listFiles(params: DirectoryListingRequest): Promise { - this.logger?.info(`Listing files for directory: "${params.directoryUri}"`); - return Promise.reject('No file listing possible.'); - } + getFileStats(params: StatsRequest): Promise { + this.logger?.info(`Getting file stats for: "${params.resourceUri}" (${params.type})`); + return Promise.reject('No stats available.'); + } + listFiles(params: DirectoryListingRequest): Promise { + this.logger?.info(`Listing files for directory: "${params.directoryUri}"`); + return Promise.reject('No file listing possible.'); + } } diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index fa5e09073..b1d0c687e 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -6,28 +6,28 @@ import { BaseLanguageClient, MessageTransports, ProposedFeatures, type LanguageClientOptions } from 'vscode-languageclient/browser.js'; export type MonacoLanguageClientOptions = { - name: string; - id?: string; - clientOptions: LanguageClientOptions; - messageTransports: MessageTransports; -} + name: string; + id?: string; + clientOptions: LanguageClientOptions; + messageTransports: MessageTransports; +}; export class MonacoLanguageClient extends BaseLanguageClient { - protected readonly messageTransports: MessageTransports; + protected readonly messageTransports: MessageTransports; - constructor({ id, name, clientOptions, messageTransports }: MonacoLanguageClientOptions) { - super(id ?? name.toLowerCase(), name, clientOptions); - this.messageTransports = messageTransports; - } + constructor({ id, name, clientOptions, messageTransports }: MonacoLanguageClientOptions) { + super(id ?? name.toLowerCase(), name, clientOptions); + this.messageTransports = messageTransports; + } - protected override createMessageTransports(_encoding: string): Promise { - return Promise.resolve(this.messageTransports); - } + protected override createMessageTransports(_encoding: string): Promise { + return Promise.resolve(this.messageTransports); + } } export class MonacoLanguageClientWithProposedFeatures extends MonacoLanguageClient { - constructor({ id, name, clientOptions, messageTransports }: MonacoLanguageClientOptions) { - super({ id, name, clientOptions, messageTransports }); - ProposedFeatures.createAll(this); - } + constructor({ id, name, clientOptions, messageTransports }: MonacoLanguageClientOptions) { + super({ id, name, clientOptions, messageTransports }); + ProposedFeatures.createAll(this); + } } diff --git a/packages/client/src/vscode/apiWrapper.ts b/packages/client/src/vscode/apiWrapper.ts index 85fe14138..5aa596fac 100644 --- a/packages/client/src/vscode/apiWrapper.ts +++ b/packages/client/src/vscode/apiWrapper.ts @@ -4,7 +4,13 @@ * ------------------------------------------------------------------------------------------ */ import { initialize, LogLevel } from '@codingame/monaco-vscode-api'; -import { ExtensionHostKind, getBuiltinExtensions, registerExtension, type IExtensionManifest, type RegisterExtensionResult } from '@codingame/monaco-vscode-api/extensions'; +import { + ExtensionHostKind, + getBuiltinExtensions, + registerExtension, + type IExtensionManifest, + type RegisterExtensionResult +} from '@codingame/monaco-vscode-api/extensions'; import { DisposableStore, setUnexpectedErrorHandler } from '@codingame/monaco-vscode-api/monaco'; import getConfigurationServiceOverride, { initUserConfiguration } from '@codingame/monaco-vscode-configuration-service-override'; import * as monaco from '@codingame/monaco-vscode-editor-api'; @@ -18,348 +24,351 @@ import type { ExtensionConfig, MonacoVscodeApiConfig, ViewsConfig } from './conf import { getEnhancedMonacoEnvironment, mergeServices, reportServiceLoading, useOpenEditorStub } from './utils.js'; export interface MonacoVscodeApiConfigRuntime extends MonacoVscodeApiConfig { - serviceOverrides: monaco.editor.IEditorOverrideServices; - logLevel: LogLevel | number; - viewsConfig: ViewsConfig; + serviceOverrides: monaco.editor.IEditorOverrideServices; + logLevel: LogLevel | number; + viewsConfig: ViewsConfig; } export interface StartInstructions { - caller?: string; - performServiceConsistencyChecks?: boolean; + caller?: string; + performServiceConsistencyChecks?: boolean; } export class MonacoVscodeApiWrapper { - - private logger: ILogger = new ConsoleLogger(); - private extensionRegisterResults: Map = new Map(); - private disposableStore: DisposableStore = new DisposableStore(); - private apiConfig: MonacoVscodeApiConfigRuntime; - - constructor(apiConfig: MonacoVscodeApiConfig) { - this.apiConfig = { - ...apiConfig, - serviceOverrides: apiConfig.serviceOverrides ?? {}, - logLevel: apiConfig.logLevel ?? LogLevel.Off, - }; - this.logger.setLevel(this.apiConfig.logLevel); + private logger: ILogger = new ConsoleLogger(); + private extensionRegisterResults: Map = new Map(); + private disposableStore: DisposableStore = new DisposableStore(); + private apiConfig: MonacoVscodeApiConfigRuntime; + + constructor(apiConfig: MonacoVscodeApiConfig) { + this.apiConfig = { + ...apiConfig, + serviceOverrides: apiConfig.serviceOverrides ?? {}, + logLevel: apiConfig.logLevel ?? LogLevel.Off + }; + this.logger.setLevel(this.apiConfig.logLevel); + } + + getExtensionRegisterResult(extensionName: string) { + return this.extensionRegisterResults.get(extensionName); + } + + getMonacoVscodeApiConfig(): MonacoVscodeApiConfig { + return this.apiConfig; + } + + protected configureMonacoWorkers() { + if (typeof this.apiConfig.monacoWorkerFactory === 'function') { + this.apiConfig.monacoWorkerFactory(this.logger); + } else { + useWorkerFactory({ + logger: this.logger + }); } - - getExtensionRegisterResult(extensionName: string) { - return this.extensionRegisterResults.get(extensionName); + } + + private performErrorHandling = (message: string) => { + getEnhancedMonacoEnvironment().vscodeApiInitialising = false; + throw new Error(message); + }; + + protected async configureHighlightingServices() { + if (this.apiConfig.$type === 'extended') { + const getTextmateServiceOverride = (await import('@codingame/monaco-vscode-textmate-service-override')).default; + const getThemeServiceOverride = (await import('@codingame/monaco-vscode-theme-service-override')).default; + const getLanguagesServiceOverride = (await import('@codingame/monaco-vscode-languages-service-override')).default; + mergeServices(this.apiConfig.serviceOverrides, { + ...getLanguagesServiceOverride(), + ...getTextmateServiceOverride(), + ...getThemeServiceOverride() + }); + } else { + const getMonarchServiceOverride = (await import('@codingame/monaco-vscode-monarch-service-override')).default; + mergeServices(this.apiConfig.serviceOverrides, { + ...getMonarchServiceOverride() + }); } - - getMonacoVscodeApiConfig(): MonacoVscodeApiConfig { - return this.apiConfig; + } + + protected async configureViewsServices() { + const viewsConfigType = this.apiConfig.viewsConfig.$type; + if (viewsConfigType === 'ViewsService' || viewsConfigType === 'WorkbenchService') { + if (this.apiConfig.$type === 'classic') { + this.performErrorHandling(`View Service Type "${viewsConfigType}" cannot be used with classic configuration.`); + } + if (this.apiConfig.viewsConfig.htmlContainer === undefined) { + this.performErrorHandling(`View Service Type "${viewsConfigType}" requires a HTMLElement.`); + } } - protected configureMonacoWorkers() { - if (typeof this.apiConfig.monacoWorkerFactory === 'function') { - this.apiConfig.monacoWorkerFactory(this.logger); - } else { - useWorkerFactory({ - logger: this.logger - }); - } + const envEnhanced = getEnhancedMonacoEnvironment(); + if (viewsConfigType === 'ViewsService') { + const getViewsServiceOverride = (await import('@codingame/monaco-vscode-views-service-override')).default; + mergeServices(this.apiConfig.serviceOverrides, { + ...getViewsServiceOverride(this.apiConfig.viewsConfig.openEditorFunc ?? useOpenEditorStub) + }); + envEnhanced.viewServiceType = 'ViewsService'; + } else if (viewsConfigType === 'WorkbenchService') { + const getWorkbenchServiceOverride = (await import('@codingame/monaco-vscode-workbench-service-override')).default; + mergeServices(this.apiConfig.serviceOverrides, { + ...getWorkbenchServiceOverride() + }); + envEnhanced.viewServiceType = 'WorkbenchService'; + } else { + const getEditorServiceOverride = (await import('@codingame/monaco-vscode-editor-service-override')).default; + mergeServices(this.apiConfig.serviceOverrides, { + ...getEditorServiceOverride(this.apiConfig.viewsConfig.openEditorFunc ?? useOpenEditorStub) + }); + envEnhanced.viewServiceType = 'EditorService'; } + } - private performErrorHandling = (message: string) => { - getEnhancedMonacoEnvironment().vscodeApiInitialising = false; - throw new Error(message); - }; - - protected async configureHighlightingServices() { - if (this.apiConfig.$type === 'extended') { - const getTextmateServiceOverride = (await import('@codingame/monaco-vscode-textmate-service-override')).default; - const getThemeServiceOverride = (await import('@codingame/monaco-vscode-theme-service-override')).default; - const getLanguagesServiceOverride = (await import('@codingame/monaco-vscode-languages-service-override')).default; - mergeServices(this.apiConfig.serviceOverrides, { - ...getLanguagesServiceOverride(), - ...getTextmateServiceOverride(), - ...getThemeServiceOverride() - }); - } else { - const getMonarchServiceOverride = (await import('@codingame/monaco-vscode-monarch-service-override')).default; - mergeServices(this.apiConfig.serviceOverrides, { - ...getMonarchServiceOverride() - }); - } + protected async applyViewsPostConfig() { + const viewsConfigType = this.apiConfig.viewsConfig.$type; + if (viewsConfigType === 'ViewsService' || viewsConfigType === 'WorkbenchService') { + this.apiConfig.viewsConfig.htmlAugmentationInstructions?.(this.apiConfig.viewsConfig.htmlContainer); + await this.apiConfig.viewsConfig.viewsInitFunc?.(); } - - protected async configureViewsServices() { - const viewsConfigType = this.apiConfig.viewsConfig.$type; - if (viewsConfigType === 'ViewsService' || viewsConfigType === 'WorkbenchService') { - if (this.apiConfig.$type === 'classic') { - this.performErrorHandling(`View Service Type "${viewsConfigType}" cannot be used with classic configuration.`); - } - if (this.apiConfig.viewsConfig.htmlContainer === undefined) { - this.performErrorHandling(`View Service Type "${viewsConfigType}" requires a HTMLElement.`); - } - } - - const envEnhanced = getEnhancedMonacoEnvironment(); - if (viewsConfigType === 'ViewsService') { - const getViewsServiceOverride = (await import('@codingame/monaco-vscode-views-service-override')).default; - mergeServices(this.apiConfig.serviceOverrides, { - ...getViewsServiceOverride(this.apiConfig.viewsConfig.openEditorFunc ?? useOpenEditorStub) - }); - envEnhanced.viewServiceType = 'ViewsService'; - } else if (viewsConfigType === 'WorkbenchService') { - const getWorkbenchServiceOverride = (await import('@codingame/monaco-vscode-workbench-service-override')).default; - mergeServices(this.apiConfig.serviceOverrides, { - ...getWorkbenchServiceOverride() - }); - envEnhanced.viewServiceType = 'WorkbenchService'; - } else { - const getEditorServiceOverride = (await import('@codingame/monaco-vscode-editor-service-override')).default; - mergeServices(this.apiConfig.serviceOverrides, { - ...getEditorServiceOverride(this.apiConfig.viewsConfig.openEditorFunc ?? useOpenEditorStub) - }); - envEnhanced.viewServiceType = 'EditorService'; - } - } - - protected async applyViewsPostConfig() { - const viewsConfigType = this.apiConfig.viewsConfig.$type; - if (viewsConfigType === 'ViewsService' || viewsConfigType === 'WorkbenchService') { - this.apiConfig.viewsConfig.htmlAugmentationInstructions?.(this.apiConfig.viewsConfig.htmlContainer); - await this.apiConfig.viewsConfig.viewsInitFunc?.(); + } + + /** + * Adding the default workspace config if not provided + */ + protected configureWorkspaceConfig() { + this.apiConfig.workspaceConfig ??= { + workspaceProvider: { + trusted: true, + workspace: { + workspaceUri: vscode.Uri.file('/workspace.code-workspace') + }, + async open() { + window.open(window.location.href); + return true; } + } + }; + } + + /** + * Set the log-level via the development settings. + * VSCode developmentOptions are read-only. There are no functions exposed to set options directly. + * Therefore the Object properties need to be manipulated directly via Object.assign. + */ + protected configureDevLogLevel() { + const devLogLevel = this.apiConfig.workspaceConfig?.developmentOptions?.logLevel; + if (devLogLevel === undefined) { + const devOptions: Record = { + ...this.apiConfig.workspaceConfig!.developmentOptions + }; + devOptions.logLevel = this.apiConfig.logLevel; + (this.apiConfig.workspaceConfig!.developmentOptions as Record) = Object.assign({}, devOptions); + } else if (devLogLevel !== this.apiConfig.logLevel) { + this.performErrorHandling( + `You have configured mismatching logLevels: ${this.apiConfig.logLevel} (wrapperConfig) ${devLogLevel} (workspaceConfig.developmentOptions)` + ); + } else { + this.logger.debug('Development log level and api log level are in aligned.'); } - - /** - * Adding the default workspace config if not provided - */ - protected configureWorkspaceConfig() { - this.apiConfig.workspaceConfig ??= { - workspaceProvider: { - trusted: true, - workspace: { - workspaceUri: vscode.Uri.file('/workspace.code-workspace') - }, - async open() { - window.open(window.location.href); - return true; - } - }, - }; + } + + /** + * enable semantic highlighting in the default configuration + */ + protected configureSemanticHighlighting() { + if (this.apiConfig.advanced?.enforceSemanticHighlighting === true) { + const configDefaults: Record = { + ...(this.apiConfig.workspaceConfig!.configurationDefaults ?? {}) + }; + configDefaults['editor.semanticHighlighting.enabled'] = true; + (this.apiConfig.workspaceConfig!.configurationDefaults as Record) = Object.assign({}, configDefaults); } + } - /** - * Set the log-level via the development settings. - * VSCode developmentOptions are read-only. There are no functions exposed to set options directly. - * Therefore the Object properties need to be manipulated directly via Object.assign. - */ - protected configureDevLogLevel() { - const devLogLevel = this.apiConfig.workspaceConfig?.developmentOptions?.logLevel; - if (devLogLevel === undefined) { - const devOptions: Record = { - ...this.apiConfig.workspaceConfig!.developmentOptions - }; - devOptions.logLevel = this.apiConfig.logLevel; - (this.apiConfig.workspaceConfig!.developmentOptions as Record) = Object.assign({}, devOptions); - } else if (devLogLevel !== this.apiConfig.logLevel) { - this.performErrorHandling(`You have configured mismatching logLevels: ${this.apiConfig.logLevel} (wrapperConfig) ${devLogLevel} (workspaceConfig.developmentOptions)`); - } else { - this.logger.debug('Development log level and api log level are in aligned.'); - } + protected async initUserConfiguration() { + if (this.apiConfig.userConfiguration?.json !== undefined) { + await initUserConfiguration(this.apiConfig.userConfiguration.json); } + } - /** - * enable semantic highlighting in the default configuration - */ - protected configureSemanticHighlighting() { - if (this.apiConfig.advanced?.enforceSemanticHighlighting === true) { - const configDefaults: Record = { - ...this.apiConfig.workspaceConfig!.configurationDefaults ?? {} - }; - configDefaults['editor.semanticHighlighting.enabled'] = true; - (this.apiConfig.workspaceConfig!.configurationDefaults as Record) = Object.assign({}, configDefaults); - } + protected async supplyRequiredServices() { + return { + ...getConfigurationServiceOverride(), + ...getLogServiceOverride(), + ...getModelServiceOverride() + }; + } + + protected checkServiceConsistency() { + const userServices = this.apiConfig.serviceOverrides; + const haveThemeService = Object.keys(userServices).includes('themeService'); + const haveTextmateService = Object.keys(userServices).includes('textMateTokenizationFeature'); + const haveMarkersService = Object.keys(userServices).includes('markersService'); + const haveViewsService = Object.keys(userServices).includes('viewsService'); + + // theme requires textmate + if (haveThemeService && !haveTextmateService) { + this.performErrorHandling('"theme" service requires "textmate" service. Please add it to the "userServices".'); } - protected async initUserConfiguration() { - if (this.apiConfig.userConfiguration?.json !== undefined) { - await initUserConfiguration(this.apiConfig.userConfiguration.json); - } + // markers service requires views service + if (haveMarkersService && !haveViewsService) { + this.performErrorHandling('"markers" service requires "views" service. Please add it to the "userServices".'); } - - protected async supplyRequiredServices() { - return { - ...getConfigurationServiceOverride(), - ...getLogServiceOverride(), - ...getModelServiceOverride() - }; + } + + /** + * monaco-vscode-api automatically loads the following services: + * - layout + * - environment + * - extension + * - files + * - quickAccess + * monaco-languageclient always adds the following services: + * - languages + * - log + * - model + * - configuration services + */ + protected async initAllServices(performServiceConsistencyChecks?: boolean) { + const services = await this.supplyRequiredServices(); + + mergeServices(services, this.apiConfig.serviceOverrides); + if (this.apiConfig.advanced?.loadExtensionServices === undefined ? true : this.apiConfig.advanced.loadExtensionServices === true) { + const { default: getExtensionServiceOverride } = await import('@codingame/monaco-vscode-extensions-service-override'); + mergeServices(services, { + ...getExtensionServiceOverride({ + enableWorkerExtensionHost: this.apiConfig.advanced?.enableExtHostWorker === true + }) + }); } - protected checkServiceConsistency() { - const userServices = this.apiConfig.serviceOverrides; - const haveThemeService = Object.keys(userServices).includes('themeService'); - const haveTextmateService = Object.keys(userServices).includes('textMateTokenizationFeature'); - const haveMarkersService = Object.keys(userServices).includes('markersService'); - const haveViewsService = Object.keys(userServices).includes('viewsService'); + reportServiceLoading(services, this.logger); - // theme requires textmate - if (haveThemeService && !haveTextmateService) { - this.performErrorHandling('"theme" service requires "textmate" service. Please add it to the "userServices".'); - } - - // markers service requires views service - if (haveMarkersService && !haveViewsService) { - this.performErrorHandling('"markers" service requires "views" service. Please add it to the "userServices".'); - } + if (performServiceConsistencyChecks ?? true) { + this.checkServiceConsistency(); } - /** - * monaco-vscode-api automatically loads the following services: - * - layout - * - environment - * - extension - * - files - * - quickAccess - * monaco-languageclient always adds the following services: - * - languages - * - log - * - model - * - configuration services - */ - protected async initAllServices(performServiceConsistencyChecks?: boolean) { - const services = await this.supplyRequiredServices(); - - mergeServices(services, this.apiConfig.serviceOverrides); - if (this.apiConfig.advanced?.loadExtensionServices === undefined ? true : this.apiConfig.advanced.loadExtensionServices === true) { - const { default: getExtensionServiceOverride } = await import('@codingame/monaco-vscode-extensions-service-override'); - mergeServices(services, { - ...getExtensionServiceOverride({ - enableWorkerExtensionHost: this.apiConfig.advanced?.enableExtHostWorker === true - }) - }); - } - - reportServiceLoading(services, this.logger); - - if (performServiceConsistencyChecks ?? true) { - this.checkServiceConsistency(); - } - - if (this.apiConfig.viewsConfig.$type === 'ViewsService' || this.apiConfig.viewsConfig.$type === 'WorkbenchService') { - await initialize(services, this.apiConfig.viewsConfig.htmlContainer, this.apiConfig.workspaceConfig, this.apiConfig.envOptions); - } else { - await initialize(services, undefined, this.apiConfig.workspaceConfig, this.apiConfig.envOptions); - } - - setUnexpectedErrorHandler((e) => { - const message = 'Unexpected error'; - if (this.logger.getLevel() !== LogLevel.Off) { - this.logger.error(message, e); - } - }); + if (this.apiConfig.viewsConfig.$type === 'ViewsService' || this.apiConfig.viewsConfig.$type === 'WorkbenchService') { + await initialize(services, this.apiConfig.viewsConfig.htmlContainer, this.apiConfig.workspaceConfig, this.apiConfig.envOptions); + } else { + await initialize(services, undefined, this.apiConfig.workspaceConfig, this.apiConfig.envOptions); } - async initExtensions(): Promise { - if (this.apiConfig.$type === 'extended' && (this.apiConfig.advanced?.loadThemes === undefined ? true : this.apiConfig.advanced.loadThemes === true)) { - await import('@codingame/monaco-vscode-theme-defaults-default-extension'); - } - - const extensions = this.apiConfig.extensions; - if (this.apiConfig.extensions !== undefined && this.apiConfig.extensions.length > 0) { - const allPromises: Array> = []; - const extensionIds: string[] = []; - getBuiltinExtensions().forEach((ext) => { - extensionIds.push(ext.identifier.id); - }); - for (const extensionConfig of extensions ?? []) { - if (!extensionIds.includes(`${extensionConfig.config.publisher}.${extensionConfig.config.name}`)) { - allPromises.push(this.initExtension(extensionConfig, extensionIds)); - } - } - await Promise.all(allPromises); - } + setUnexpectedErrorHandler((e) => { + const message = 'Unexpected error'; + if (this.logger.getLevel() !== LogLevel.Off) { + this.logger.error(message, e); + } + }); + } + + async initExtensions(): Promise { + if ( + this.apiConfig.$type === 'extended' && + (this.apiConfig.advanced?.loadThemes === undefined ? true : this.apiConfig.advanced.loadThemes === true) + ) { + await import('@codingame/monaco-vscode-theme-defaults-default-extension'); } - protected initExtension(extensionConfig: ExtensionConfig, extensionIds: string[]): Promise { + const extensions = this.apiConfig.extensions; + if (this.apiConfig.extensions !== undefined && this.apiConfig.extensions.length > 0) { + const allPromises: Array> = []; + const extensionIds: string[] = []; + getBuiltinExtensions().forEach((ext) => { + extensionIds.push(ext.identifier.id); + }); + for (const extensionConfig of extensions ?? []) { if (!extensionIds.includes(`${extensionConfig.config.publisher}.${extensionConfig.config.name}`)) { - const manifest = extensionConfig.config as IExtensionManifest; - const extRegResult = registerExtension(manifest, ExtensionHostKind.LocalProcess); - this.extensionRegisterResults.set(manifest.name, extRegResult); - if (extensionConfig.filesOrContents !== undefined && Object.hasOwn(extRegResult, 'registerFileUrl')) { - for (const entry of extensionConfig.filesOrContents) { - this.disposableStore.add(extRegResult.registerFileUrl(entry[0], encodeStringOrUrlToDataUrl(entry[1]))); - } - } - return extRegResult.whenReady(); - } else { - return Promise.resolve(); + allPromises.push(this.initExtension(extensionConfig, extensionIds)); } + } + await Promise.all(allPromises); } - - protected markGlobalInit() { - this.logger.debug('markGlobalInit'); - - const envEnhanced = getEnhancedMonacoEnvironment(); - envEnhanced.vscodeApiGlobalInitAwait = new Promise((resolve) => { - envEnhanced.vscodeApiGlobalInitResolve = resolve; - }); + } + + protected initExtension(extensionConfig: ExtensionConfig, extensionIds: string[]): Promise { + if (!extensionIds.includes(`${extensionConfig.config.publisher}.${extensionConfig.config.name}`)) { + const manifest = extensionConfig.config as IExtensionManifest; + const extRegResult = registerExtension(manifest, ExtensionHostKind.LocalProcess); + this.extensionRegisterResults.set(manifest.name, extRegResult); + if (extensionConfig.filesOrContents !== undefined && Object.hasOwn(extRegResult, 'registerFileUrl')) { + for (const entry of extensionConfig.filesOrContents) { + this.disposableStore.add(extRegResult.registerFileUrl(entry[0], encodeStringOrUrlToDataUrl(entry[1]))); + } + } + return extRegResult.whenReady(); + } else { + return Promise.resolve(); } + } - protected markGlobalInitDone() { - const envEnhanced = getEnhancedMonacoEnvironment(); - envEnhanced.vscodeApiGlobalInitResolve?.(); + protected markGlobalInit() { + this.logger.debug('markGlobalInit'); - envEnhanced.vscodeApiInitialised = true; - envEnhanced.vscodeApiGlobalInitAwait = undefined; - envEnhanced.vscodeApiGlobalInitResolve = undefined; - this.logger.debug('markGlobalInitDone'); - } + const envEnhanced = getEnhancedMonacoEnvironment(); + envEnhanced.vscodeApiGlobalInitAwait = new Promise((resolve) => { + envEnhanced.vscodeApiGlobalInitResolve = resolve; + }); + } - async start(startInstructions?: StartInstructions): Promise { - const envEnhanced = getEnhancedMonacoEnvironment(); - if (envEnhanced.vscodeApiInitialised === true) { - this.logger.warn('Initialization of monaco-vscode api can only performed once!'); - } else { - if (!(envEnhanced.vscodeApiInitialising === true)) { + protected markGlobalInitDone() { + const envEnhanced = getEnhancedMonacoEnvironment(); + envEnhanced.vscodeApiGlobalInitResolve?.(); - envEnhanced.vscodeApiInitialising = true; - this.markGlobalInit(); + envEnhanced.vscodeApiInitialised = true; + envEnhanced.vscodeApiGlobalInitAwait = undefined; + envEnhanced.vscodeApiGlobalInitResolve = undefined; + this.logger.debug('markGlobalInitDone'); + } - // ensures "vscodeApiConfig.workspaceConfig" is available - this.configureWorkspaceConfig(); + async start(startInstructions?: StartInstructions): Promise { + const envEnhanced = getEnhancedMonacoEnvironment(); + if (envEnhanced.vscodeApiInitialised === true) { + this.logger.warn('Initialization of monaco-vscode api can only performed once!'); + } else { + if (!(envEnhanced.vscodeApiInitialising === true)) { + envEnhanced.vscodeApiInitialising = true; + this.markGlobalInit(); - // ensure logging and development logging options are in-line - this.configureDevLogLevel(); - this.logger.info(`Initializing monaco-vscode api. Caller: ${startInstructions?.caller ?? 'unknown'}`); + // ensures "vscodeApiConfig.workspaceConfig" is available + this.configureWorkspaceConfig(); - this.configureMonacoWorkers(); + // ensure logging and development logging options are in-line + this.configureDevLogLevel(); + this.logger.info(`Initializing monaco-vscode api. Caller: ${startInstructions?.caller ?? 'unknown'}`); - // ensure either classic (monarch) or textmate (extended) highlighting is used - await this.configureHighlightingServices(); + this.configureMonacoWorkers(); - // ensure one of the three potential view services are configured - await this.configureViewsServices(); + // ensure either classic (monarch) or textmate (extended) highlighting is used + await this.configureHighlightingServices(); - // enforce semantic highlighting if configured - this.configureSemanticHighlighting(); + // ensure one of the three potential view services are configured + await this.configureViewsServices(); - await this.initUserConfiguration(); + // enforce semantic highlighting if configured + this.configureSemanticHighlighting(); - await this.initAllServices(startInstructions?.performServiceConsistencyChecks); + await this.initUserConfiguration(); - await this.applyViewsPostConfig(); + await this.initAllServices(startInstructions?.performServiceConsistencyChecks); - await this.initExtensions(); + await this.applyViewsPostConfig(); - this.markGlobalInitDone(); - this.logger.debug('Initialization of monaco-vscode api completed successfully.'); - } else { - this.logger.debug('Initialization of monaco-vscode api is already ongoing.'); - } - } + await this.initExtensions(); + + this.markGlobalInitDone(); + this.logger.debug('Initialization of monaco-vscode api completed successfully.'); + } else { + this.logger.debug('Initialization of monaco-vscode api is already ongoing.'); + } } + } - dispose() { - this.extensionRegisterResults.forEach((k) => k.dispose()); - this.disposableStore.dispose(); + dispose() { + this.extensionRegisterResults.forEach((k) => k.dispose()); + this.disposableStore.dispose(); - // re-create disposable stores - this.disposableStore = new DisposableStore(); - } + // re-create disposable stores + this.disposableStore = new DisposableStore(); + } } diff --git a/packages/client/src/vscode/config.ts b/packages/client/src/vscode/config.ts index a79d75025..81bc6f0f4 100644 --- a/packages/client/src/vscode/config.ts +++ b/packages/client/src/vscode/config.ts @@ -18,44 +18,44 @@ export type ViewsConfigTypes = 'EditorService' | 'ViewsService' | 'WorkbenchServ // export type HtmlContainerConfig = HTMLElement; export interface MonacoEnvironmentEnhanced extends monaco.Environment { - vscodeApiInitialising?: boolean; - vscodeApiInitialised?: boolean; - vscodeApiGlobalInitAwait?: Promise; - vscodeApiGlobalInitResolve?: ((value: void | PromiseLike) => void); - viewServiceType?: ViewsConfigTypes; + vscodeApiInitialising?: boolean; + vscodeApiInitialised?: boolean; + vscodeApiGlobalInitAwait?: Promise; + vscodeApiGlobalInitResolve?: (value: void | PromiseLike) => void; + viewServiceType?: ViewsConfigTypes; } export interface UserConfiguration { - json?: string; + json?: string; } export interface ViewsConfig { - $type: ViewsConfigTypes; - htmlContainer?: HTMLElement; - openEditorFunc?: OpenEditor; - htmlAugmentationInstructions?: (htmlContainer: HTMLElement | null | undefined) => void; - viewsInitFunc?: () => Promise; + $type: ViewsConfigTypes; + htmlContainer?: HTMLElement; + openEditorFunc?: OpenEditor; + htmlAugmentationInstructions?: (htmlContainer: HTMLElement | null | undefined) => void; + viewsInitFunc?: () => Promise; } export interface ExtensionConfig { - config: IExtensionManifest; - filesOrContents?: Map; + config: IExtensionManifest; + filesOrContents?: Map; } export interface MonacoVscodeApiConfig { - $type: OverallConfigType; - viewsConfig: ViewsConfig, - serviceOverrides?: monaco.editor.IEditorOverrideServices; - logLevel?: LogLevel | number; - workspaceConfig?: IWorkbenchConstructionOptions; - userConfiguration?: UserConfiguration; - envOptions?: EnvironmentOverride; - extensions?: ExtensionConfig[]; - monacoWorkerFactory?: (logger?: ILogger) => void; - advanced?: { - loadExtensionServices?: boolean; - enableExtHostWorker?: boolean; - loadThemes?: boolean; - enforceSemanticHighlighting?: boolean; - }; + $type: OverallConfigType; + viewsConfig: ViewsConfig; + serviceOverrides?: monaco.editor.IEditorOverrideServices; + logLevel?: LogLevel | number; + workspaceConfig?: IWorkbenchConstructionOptions; + userConfiguration?: UserConfiguration; + envOptions?: EnvironmentOverride; + extensions?: ExtensionConfig[]; + monacoWorkerFactory?: (logger?: ILogger) => void; + advanced?: { + loadExtensionServices?: boolean; + enableExtHostWorker?: boolean; + loadThemes?: boolean; + enforceSemanticHighlighting?: boolean; + }; } diff --git a/packages/client/src/vscode/locales.ts b/packages/client/src/vscode/locales.ts index 77a26cd19..e167dec9e 100644 --- a/packages/client/src/vscode/locales.ts +++ b/packages/client/src/vscode/locales.ts @@ -7,123 +7,140 @@ import type { LocalizationOptions } from '@codingame/monaco-vscode-localization- import type { ILogger } from '@codingame/monaco-vscode-log-service-override'; export const createDefaultLocaleConfiguration = (): LocalizationOptions => { - return { - async clearLocale() { - const url = new URL(window.location.href); - url.searchParams.delete('locale'); - window.history.pushState(null, '', url.toString()); - }, - async setLocale(id: string) { - const url = new URL(window.location.href); - url.searchParams.set('locale', id); - window.history.pushState(null, '', url.toString()); - }, - availableLanguages: [{ - locale: 'en', - languageName: 'English' - }, { - locale: 'cs', - languageName: 'Czech' - }, { - locale: 'de', - languageName: 'German' - }, { - locale: 'es', - languageName: 'Spanish' - }, { - locale: 'fr', - languageName: 'French' - }, { - locale: 'it', - languageName: 'Italian' - }, { - locale: 'ja', - languageName: 'Japanese' - }, { - locale: 'ko', - languageName: 'Korean' - }, { - locale: 'pl', - languageName: 'Polish' - }, { - locale: 'pt-br', - languageName: 'Portuguese (Brazil)' - }, { - locale: 'qps-ploc', - languageName: 'Pseudo Language' - }, { - locale: 'ru', - languageName: 'Russian' - }, { - locale: 'tr', - languageName: 'Turkish' - }, { - locale: 'zh-hans', - languageName: 'Chinese (Simplified)' - }, { - locale: 'zh-hant', - languageName: 'Chinese (Traditional)' - }, { - locale: 'en', - languageName: 'English' - }] - }; + return { + async clearLocale() { + const url = new URL(window.location.href); + url.searchParams.delete('locale'); + window.history.pushState(null, '', url.toString()); + }, + async setLocale(id: string) { + const url = new URL(window.location.href); + url.searchParams.set('locale', id); + window.history.pushState(null, '', url.toString()); + }, + availableLanguages: [ + { + locale: 'en', + languageName: 'English' + }, + { + locale: 'cs', + languageName: 'Czech' + }, + { + locale: 'de', + languageName: 'German' + }, + { + locale: 'es', + languageName: 'Spanish' + }, + { + locale: 'fr', + languageName: 'French' + }, + { + locale: 'it', + languageName: 'Italian' + }, + { + locale: 'ja', + languageName: 'Japanese' + }, + { + locale: 'ko', + languageName: 'Korean' + }, + { + locale: 'pl', + languageName: 'Polish' + }, + { + locale: 'pt-br', + languageName: 'Portuguese (Brazil)' + }, + { + locale: 'qps-ploc', + languageName: 'Pseudo Language' + }, + { + locale: 'ru', + languageName: 'Russian' + }, + { + locale: 'tr', + languageName: 'Turkish' + }, + { + locale: 'zh-hans', + languageName: 'Chinese (Simplified)' + }, + { + locale: 'zh-hant', + languageName: 'Chinese (Traditional)' + }, + { + locale: 'en', + languageName: 'English' + } + ] + }; }; const localeLoader: Partial Promise>> = { - cs: async () => { - await import('@codingame/monaco-vscode-language-pack-cs'); - }, - de: async () => { - await import('@codingame/monaco-vscode-language-pack-de'); - }, - es: async () => { - await import('@codingame/monaco-vscode-language-pack-es'); - }, - fr: async () => { - await import('@codingame/monaco-vscode-language-pack-fr'); - }, - it: async () => { - await import('@codingame/monaco-vscode-language-pack-it'); - }, - ja: async () => { - await import('@codingame/monaco-vscode-language-pack-ja'); - }, - ko: async () => { - await import('@codingame/monaco-vscode-language-pack-ko'); - }, - pl: async () => { - await import('@codingame/monaco-vscode-language-pack-pl'); - }, - 'pt-br': async () => { - await import('@codingame/monaco-vscode-language-pack-pt-br'); - }, - 'qps-ploc': async () => { - await import('@codingame/monaco-vscode-language-pack-qps-ploc'); - }, - ru: async () => { - await import('@codingame/monaco-vscode-language-pack-ru'); - }, - tr: async () => { - await import('@codingame/monaco-vscode-language-pack-tr'); - }, - 'zh-hans': async () => { - await import('@codingame/monaco-vscode-language-pack-zh-hans'); - }, - 'zh-hant': async () => { - await import('@codingame/monaco-vscode-language-pack-zh-hant'); - } + cs: async () => { + await import('@codingame/monaco-vscode-language-pack-cs'); + }, + de: async () => { + await import('@codingame/monaco-vscode-language-pack-de'); + }, + es: async () => { + await import('@codingame/monaco-vscode-language-pack-es'); + }, + fr: async () => { + await import('@codingame/monaco-vscode-language-pack-fr'); + }, + it: async () => { + await import('@codingame/monaco-vscode-language-pack-it'); + }, + ja: async () => { + await import('@codingame/monaco-vscode-language-pack-ja'); + }, + ko: async () => { + await import('@codingame/monaco-vscode-language-pack-ko'); + }, + pl: async () => { + await import('@codingame/monaco-vscode-language-pack-pl'); + }, + 'pt-br': async () => { + await import('@codingame/monaco-vscode-language-pack-pt-br'); + }, + 'qps-ploc': async () => { + await import('@codingame/monaco-vscode-language-pack-qps-ploc'); + }, + ru: async () => { + await import('@codingame/monaco-vscode-language-pack-ru'); + }, + tr: async () => { + await import('@codingame/monaco-vscode-language-pack-tr'); + }, + 'zh-hans': async () => { + await import('@codingame/monaco-vscode-language-pack-zh-hans'); + }, + 'zh-hant': async () => { + await import('@codingame/monaco-vscode-language-pack-zh-hant'); + } }; export const locales = Object.keys(localeLoader); export const initLocaleLoader = async (locale = new URLSearchParams(window.location.search).get('locale'), logger?: ILogger) => { - if (locale !== null) { - const loader = localeLoader[locale]; - if (loader !== undefined) { - await loader(); - } else { - logger?.error(`Unknown locale ${locale}`); - } + if (locale !== null) { + const loader = localeLoader[locale]; + if (loader !== undefined) { + await loader(); + } else { + logger?.error(`Unknown locale ${locale}`); } + } }; diff --git a/packages/client/src/vscode/utils.ts b/packages/client/src/vscode/utils.ts index d93c4b6c4..1cb306c85 100644 --- a/packages/client/src/vscode/utils.ts +++ b/packages/client/src/vscode/utils.ts @@ -9,32 +9,35 @@ import type { ILogger } from '@codingame/monaco-vscode-log-service-override'; import type { MonacoEnvironmentEnhanced } from './config.js'; export const getEnhancedMonacoEnvironment = (): MonacoEnvironmentEnhanced => { - if (typeof MonacoEnvironment === 'undefined') { - globalThis.MonacoEnvironment = {}; - } - const envEnhanced = MonacoEnvironment as MonacoEnvironmentEnhanced; - envEnhanced.vscodeApiInitialising ??= false; - envEnhanced.vscodeApiInitialised ??= false; - envEnhanced.viewServiceType ??= 'EditorService'; + if (typeof MonacoEnvironment === 'undefined') { + globalThis.MonacoEnvironment = {}; + } + const envEnhanced = MonacoEnvironment as MonacoEnvironmentEnhanced; + envEnhanced.vscodeApiInitialising ??= false; + envEnhanced.vscodeApiInitialised ??= false; + envEnhanced.viewServiceType ??= 'EditorService'; - return envEnhanced; + return envEnhanced; }; export const reportServiceLoading = (services: monaco.editor.IEditorOverrideServices, logger?: ILogger) => { - for (const serviceName of Object.keys(services)) { - logger?.debug(`Loading service: ${serviceName}`); - } + for (const serviceName of Object.keys(services)) { + logger?.debug(`Loading service: ${serviceName}`); + } }; -export const mergeServices = (overrideServices: monaco.editor.IEditorOverrideServices, services?: monaco.editor.IEditorOverrideServices) => { - if (services !== undefined) { - for (const [name, service] of Object.entries(services)) { - overrideServices[name] = service; - } +export const mergeServices = ( + overrideServices: monaco.editor.IEditorOverrideServices, + services?: monaco.editor.IEditorOverrideServices +) => { + if (services !== undefined) { + for (const [name, service] of Object.entries(services)) { + overrideServices[name] = service; } + } }; export const useOpenEditorStub: OpenEditor = async (modelRef, options, sideBySide, logger?: ILogger) => { - logger?.info('Received open editor call with parameters: ', modelRef, options, sideBySide); - return undefined; + logger?.info('Received open editor call with parameters: ', modelRef, options, sideBySide); + return undefined; }; diff --git a/packages/client/src/vscode/viewsService.ts b/packages/client/src/vscode/viewsService.ts index 3e372c9ef..0b5f54729 100644 --- a/packages/client/src/vscode/viewsService.ts +++ b/packages/client/src/vscode/viewsService.ts @@ -4,44 +4,51 @@ * ------------------------------------------------------------------------------------------ */ export const defaultViewsInit = async () => { - const { Parts, Position, onPartVisibilityChange, isPartVisibile, attachPart, getSideBarPosition, onDidChangeSideBarPosition } = await import('@codingame/monaco-vscode-views-service-override'); + const { Parts, Position, onPartVisibilityChange, isPartVisibile, attachPart, getSideBarPosition, onDidChangeSideBarPosition } = + await import('@codingame/monaco-vscode-views-service-override'); - for (const config of [ - { part: Parts.TITLEBAR_PART, element: '#titleBar' }, - { part: Parts.BANNER_PART, element: '#banner' }, - { - part: Parts.SIDEBAR_PART, get element() { - return getSideBarPosition() === Position.LEFT ? '#sidebar' : '#sidebar-right'; - }, onDidElementChange: onDidChangeSideBarPosition - }, - { - part: Parts.ACTIVITYBAR_PART, get element() { - return getSideBarPosition() === Position.LEFT ? '#activityBar' : '#activityBar-right'; - }, onDidElementChange: onDidChangeSideBarPosition - }, - { - part: Parts.AUXILIARYBAR_PART, get element() { - return getSideBarPosition() === Position.LEFT ? '#auxiliaryBar' : '#auxiliaryBar-left'; - }, onDidElementChange: onDidChangeSideBarPosition - }, - { part: Parts.EDITOR_PART, element: '#editors' }, - { part: Parts.PANEL_PART, element: '#panel' }, - { part: Parts.STATUSBAR_PART, element: '#statusBar' } - ]) { - attachPart(config.part, document.querySelector(config.element)!); + for (const config of [ + { part: Parts.TITLEBAR_PART, element: '#titleBar' }, + { part: Parts.BANNER_PART, element: '#banner' }, + { + part: Parts.SIDEBAR_PART, + get element() { + return getSideBarPosition() === Position.LEFT ? '#sidebar' : '#sidebar-right'; + }, + onDidElementChange: onDidChangeSideBarPosition + }, + { + part: Parts.ACTIVITYBAR_PART, + get element() { + return getSideBarPosition() === Position.LEFT ? '#activityBar' : '#activityBar-right'; + }, + onDidElementChange: onDidChangeSideBarPosition + }, + { + part: Parts.AUXILIARYBAR_PART, + get element() { + return getSideBarPosition() === Position.LEFT ? '#auxiliaryBar' : '#auxiliaryBar-left'; + }, + onDidElementChange: onDidChangeSideBarPosition + }, + { part: Parts.EDITOR_PART, element: '#editors' }, + { part: Parts.PANEL_PART, element: '#panel' }, + { part: Parts.STATUSBAR_PART, element: '#statusBar' } + ]) { + attachPart(config.part, document.querySelector(config.element)!); - config.onDidElementChange?.(() => { - attachPart(config.part, document.querySelector(config.element)!); - }); + config.onDidElementChange?.(() => { + attachPart(config.part, document.querySelector(config.element)!); + }); - if (!isPartVisibile(config.part)) { - document.querySelector(config.element)!.style.display = 'none'; - } - - onPartVisibilityChange(config.part, visible => { - document.querySelector(config.element)!.style.display = visible ? 'block' : 'none'; - }); + if (!isPartVisibile(config.part)) { + document.querySelector(config.element)!.style.display = 'none'; } + + onPartVisibilityChange(config.part, (visible) => { + document.querySelector(config.element)!.style.display = visible ? 'block' : 'none'; + }); + } }; export const defaultViewsHtml = `
@@ -67,7 +74,7 @@ export const defaultViewsHtml = `
`; export const defaultHtmlAugmentationInstructions = (htmlElement: HTMLElement | null | undefined) => { - const htmlContainer = document.createElement('div', { is: 'app' }); - htmlContainer.innerHTML = defaultViewsHtml; - htmlElement?.append(htmlContainer); + const htmlContainer = document.createElement('div', { is: 'app' }); + htmlContainer.innerHTML = defaultViewsHtml; + htmlElement?.append(htmlContainer); }; diff --git a/packages/client/src/worker/index.ts b/packages/client/src/worker/index.ts index 29835f05d..80592e480 100644 --- a/packages/client/src/worker/index.ts +++ b/packages/client/src/worker/index.ts @@ -7,67 +7,60 @@ import type { ILogger } from '@codingame/monaco-vscode-log-service-override'; import { getEnhancedMonacoEnvironment } from 'monaco-languageclient/vscodeApiWrapper'; export class Worker { - url: string | URL; - options?: WorkerOptions; + url: string | URL; + options?: WorkerOptions; - constructor(url: string | URL, options?: WorkerOptions) { - this.url = url; - this.options = options; - } + constructor(url: string | URL, options?: WorkerOptions) { + this.url = url; + this.options = options; + } } export type WorkerLoader = (() => Worker) | undefined; export interface WorkerFactoryConfig { - workerLoaders?: Partial>; - logger?: ILogger; + workerLoaders?: Partial>; + logger?: ILogger; } export const useWorkerFactory = (config: WorkerFactoryConfig) => { - const envEnhanced = getEnhancedMonacoEnvironment(); + const envEnhanced = getEnhancedMonacoEnvironment(); - envEnhanced.getWorkerUrl = (workerId: string, label: string) => { - config.logger?.info(`getWorkerUrl: workerId: ${workerId} label: ${label}`); - return config.workerLoaders?.[label]?.().url.toString(); - }; + envEnhanced.getWorkerUrl = (workerId: string, label: string) => { + config.logger?.info(`getWorkerUrl: workerId: ${workerId} label: ${label}`); + return config.workerLoaders?.[label]?.().url.toString(); + }; - envEnhanced.getWorkerOptions = (moduleId: string, label: string) => { - config.logger?.info(`getWorkerOptions: moduleId: ${moduleId} label: ${label}`); - return config.workerLoaders?.[label]?.().options; - }; + envEnhanced.getWorkerOptions = (moduleId: string, label: string) => { + config.logger?.info(`getWorkerOptions: moduleId: ${moduleId} label: ${label}`); + return config.workerLoaders?.[label]?.().options; + }; }; export const defineDefaultWorkerLoaders: () => Partial> = () => { - const defaultEditorWorkerService = () => new Worker( - new URL('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js', import.meta.url), - { type: 'module' } - ); - const defaultExtensionHostWorkerMain = () => new Worker( - new URL('@codingame/monaco-vscode-api/workers/extensionHost.worker', import.meta.url), - { type: 'module' } - ); - const defaultTextMateWorker = () => new Worker( - new URL('@codingame/monaco-vscode-textmate-service-override/worker', import.meta.url), - { type: 'module' } - ); + const defaultEditorWorkerService = () => + new Worker(new URL('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }); + const defaultExtensionHostWorkerMain = () => + new Worker(new URL('@codingame/monaco-vscode-api/workers/extensionHost.worker', import.meta.url), { type: 'module' }); + const defaultTextMateWorker = () => + new Worker(new URL('@codingame/monaco-vscode-textmate-service-override/worker', import.meta.url), { type: 'module' }); - return { - // if you import monaco api as 'monaco-editor': monaco-editor/esm/vs/editor/editor.worker.js - editorWorkerService: defaultEditorWorkerService, - extensionHostWorkerMain: defaultExtensionHostWorkerMain, - TextMateWorker: defaultTextMateWorker, - // these are other possible workers not configured by default - OutputLinkDetectionWorker: undefined, - LanguageDetectionWorker: undefined, - NotebookEditorWorker: undefined, - LocalFileSearchWorker: undefined - }; + return { + // if you import monaco api as 'monaco-editor': monaco-editor/esm/vs/editor/editor.worker.js + editorWorkerService: defaultEditorWorkerService, + extensionHostWorkerMain: defaultExtensionHostWorkerMain, + TextMateWorker: defaultTextMateWorker, + // these are other possible workers not configured by default + OutputLinkDetectionWorker: undefined, + LanguageDetectionWorker: undefined, + NotebookEditorWorker: undefined, + LocalFileSearchWorker: undefined + }; }; export const configureDefaultWorkerFactory = (logger?: ILogger) => { - useWorkerFactory({ - workerLoaders: defineDefaultWorkerLoaders(), - logger - }); + useWorkerFactory({ + workerLoaders: defineDefaultWorkerLoaders(), + logger + }); }; - diff --git a/packages/client/src/wrapper/lcconfig.ts b/packages/client/src/wrapper/lcconfig.ts index bc67ae1c6..61b41bfdd 100644 --- a/packages/client/src/wrapper/lcconfig.ts +++ b/packages/client/src/wrapper/lcconfig.ts @@ -8,28 +8,28 @@ import { type ConnectionConfigOptions } from 'monaco-languageclient/common'; import type { DynamicFeature, LanguageClientOptions, MessageTransports, StaticFeature } from 'vscode-languageclient/browser.js'; export interface ConnectionConfig { - options: ConnectionConfigOptions; - messageTransports?: MessageTransports; + options: ConnectionConfigOptions; + messageTransports?: MessageTransports; } export interface LanguageClientConfig { - languageId: string; - connection: ConnectionConfig; - clientOptions: LanguageClientOptions; - restartOptions?: LanguageClientRestartOptions; - useClientWithProposedFeatures?: boolean; - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - registerFeatures?: Array<(StaticFeature | DynamicFeature)>; - disposeWorker?: boolean; - logLevel?: LogLevel | number; + languageId: string; + connection: ConnectionConfig; + clientOptions: LanguageClientOptions; + restartOptions?: LanguageClientRestartOptions; + useClientWithProposedFeatures?: boolean; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + registerFeatures?: Array>; + disposeWorker?: boolean; + logLevel?: LogLevel | number; } export interface LanguageClientRestartOptions { - retries: number; - timeout: number; - keepWorker?: boolean; + retries: number; + timeout: number; + keepWorker?: boolean; } export interface LanguageClientConfigs { - configs: Record; + configs: Record; } diff --git a/packages/client/src/wrapper/lcmanager.ts b/packages/client/src/wrapper/lcmanager.ts index 111aac4d3..84aca0249 100644 --- a/packages/client/src/wrapper/lcmanager.ts +++ b/packages/client/src/wrapper/lcmanager.ts @@ -9,89 +9,88 @@ import type { LanguageClientConfig, LanguageClientConfigs } from './lcconfig.js' import { LanguageClientWrapper } from './lcwrapper.js'; export class LanguageClientManager { + private logger: ILogger = new ConsoleLogger(); + private languageClientConfigs?: LanguageClientConfigs; + private languageClientWrappers: Map = new Map(); - private logger: ILogger = new ConsoleLogger(); - private languageClientConfigs?: LanguageClientConfigs; - private languageClientWrappers: Map = new Map(); + setLogLevel(logLevel?: LogLevel | number) { + this.logger.setLevel(logLevel ?? LogLevel.Off); + } - setLogLevel(logLevel?: LogLevel | number) { - this.logger.setLevel(logLevel ?? LogLevel.Off); - } + haveLanguageClients(): boolean { + return this.languageClientWrappers.size > 0; + } - haveLanguageClients(): boolean { - return this.languageClientWrappers.size > 0; - } + getLanguageClientWrapper(languageId: string): LanguageClientWrapper | undefined { + return this.languageClientWrappers.get(languageId); + } - getLanguageClientWrapper(languageId: string): LanguageClientWrapper | undefined { - return this.languageClientWrappers.get(languageId); - } + getLanguageClient(languageId: string) { + return this.languageClientWrappers.get(languageId)?.getLanguageClient(); + } - getLanguageClient(languageId: string) { - return this.languageClientWrappers.get(languageId)?.getLanguageClient(); - } + getWorker(languageId: string): Worker | undefined { + return this.languageClientWrappers.get(languageId)?.getWorker(); + } - getWorker(languageId: string): Worker | undefined { - return this.languageClientWrappers.get(languageId)?.getWorker(); - } + setConfig(languageClientConfig?: LanguageClientConfig) { + if (languageClientConfig === undefined) return; - setConfig(languageClientConfig?: LanguageClientConfig) { - if (languageClientConfig === undefined) return; + const languageId = languageClientConfig.languageId; + let lcw = this.languageClientWrappers.get(languageId); - const languageId = languageClientConfig.languageId; - let lcw = this.languageClientWrappers.get(languageId); - - if (lcw === undefined) { - lcw = new LanguageClientWrapper(languageClientConfig); - this.languageClientWrappers.set(languageId, lcw); - } + if (lcw === undefined) { + lcw = new LanguageClientWrapper(languageClientConfig); + this.languageClientWrappers.set(languageId, lcw); } + } - setConfigs(languageClientConfigs: LanguageClientConfigs) { - this.languageClientConfigs = languageClientConfigs; + setConfigs(languageClientConfigs: LanguageClientConfigs) { + this.languageClientConfigs = languageClientConfigs; - const lccs = Object.values(this.languageClientConfigs.configs); - if (lccs.length > 0) { - for (const lcc of lccs) { - this.setConfig(lcc); - } - } + const lccs = Object.values(this.languageClientConfigs.configs); + if (lccs.length > 0) { + for (const lcc of lccs) { + this.setConfig(lcc); + } } - - async start(): Promise { - this.logger.debug('Starting all LanguageClientWrappers...'); - const allPromises: Array> = []; - for (const lcw of this.languageClientWrappers.values()) { - if (!lcw.isStarted()) { - allPromises.push(lcw.start()); - } - } - return Promise.all(allPromises); + } + + async start(): Promise { + this.logger.debug('Starting all LanguageClientWrappers...'); + const allPromises: Array> = []; + for (const lcw of this.languageClientWrappers.values()) { + if (!lcw.isStarted()) { + allPromises.push(lcw.start()); + } } - - isStarted(): boolean { - // fast-fail - if (this.languageClientWrappers.size === 0) return false; - for (const lcw of this.languageClientWrappers.values()) { - // as soon as one is not started return - if (!lcw.isStarted()) { - return false; - } - } - return true; + return Promise.all(allPromises); + } + + isStarted(): boolean { + // fast-fail + if (this.languageClientWrappers.size === 0) return false; + for (const lcw of this.languageClientWrappers.values()) { + // as soon as one is not started return + if (!lcw.isStarted()) { + return false; + } + } + return true; + } + + async dispose(clearClients: boolean = false): Promise { + this.logger.debug('Disposing all LanguageClientWrappers...'); + const allPromises: Array> = []; + for (const lcw of this.languageClientWrappers.values()) { + if (lcw.haveLanguageClient()) { + allPromises.push(lcw.dispose()); + } } + await Promise.all(allPromises); - async dispose(clearClients: boolean = false): Promise { - this.logger.debug('Disposing all LanguageClientWrappers...'); - const allPromises: Array> = []; - for (const lcw of this.languageClientWrappers.values()) { - if (lcw.haveLanguageClient()) { - allPromises.push(lcw.dispose()); - } - } - await Promise.all(allPromises); - - if (clearClients) { - this.languageClientWrappers.clear(); - } + if (clearClients) { + this.languageClientWrappers.clear(); } + } } diff --git a/packages/client/src/wrapper/lcwrapper.ts b/packages/client/src/wrapper/lcwrapper.ts index 394d840c8..54fecd084 100644 --- a/packages/client/src/wrapper/lcwrapper.ts +++ b/packages/client/src/wrapper/lcwrapper.ts @@ -13,272 +13,282 @@ import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode import type { LanguageClientConfig, LanguageClientRestartOptions } from './lcconfig.js'; export interface LanguageClientError { - message: string; - error: Error | string; + message: string; + error: Error | string; } export class LanguageClientWrapper { - - private languageClient?: MonacoLanguageClient | MonacoLanguageClientWithProposedFeatures; - private languageClientConfig: LanguageClientConfig; - private worker?: Worker; - private port?: MessagePort; - private languageId: string; - private logger: ILogger | undefined; - - constructor(config: LanguageClientConfig) { - this.languageClientConfig = config; - this.languageId = this.languageClientConfig.languageId; - this.logger = new ConsoleLogger(this.languageClientConfig.logLevel ?? LogLevel.Off); - } - - haveLanguageClient(): boolean { - return this.languageClient !== undefined; + private languageClient?: MonacoLanguageClient | MonacoLanguageClientWithProposedFeatures; + private languageClientConfig: LanguageClientConfig; + private worker?: Worker; + private port?: MessagePort; + private languageId: string; + private logger: ILogger | undefined; + + constructor(config: LanguageClientConfig) { + this.languageClientConfig = config; + this.languageId = this.languageClientConfig.languageId; + this.logger = new ConsoleLogger(this.languageClientConfig.logLevel ?? LogLevel.Off); + } + + haveLanguageClient(): boolean { + return this.languageClient !== undefined; + } + + getLanguageClient(): MonacoLanguageClient | undefined { + return this.languageClient; + } + + getWorker(): Worker | undefined { + return this.worker; + } + + isStarted(): boolean { + return this.languageClient?.isRunning() ?? false; + } + + async start(): Promise { + if (this.languageClient?.isRunning() ?? false) { + this.logger?.info('startLanguageClientConnection: monaco-languageclient already running!'); + return Promise.resolve(); } - getLanguageClient(): MonacoLanguageClient | undefined { - return this.languageClient; + return new Promise((resolve, reject) => { + const conConfig = this.languageClientConfig.connection; + const conOptions = conConfig.options; + + if (conOptions.$type === 'WebSocketDirect' || conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl') { + const webSocket = conOptions.$type === 'WebSocketDirect' ? conOptions.webSocket : new WebSocket(createUrl(conOptions)); + return this.initMessageTransportWebSocket(webSocket, resolve, reject); + } else { + // init of worker and start of languageclient can be handled directly, because worker available already + return this.initMessageTransportWorker(conOptions, resolve, reject); + } + }); + } + + /** + * Restart the languageclient with options to control worker handling + * + * @param updatedWorker Set a new worker here that should be used. keepWorker has no effect then, as we want to dispose of the prior workers + * @param disposeWorker Set to false if worker should not be disposed + */ + async restart(updatedWorker?: Worker, forceWorkerDispose?: boolean): Promise { + await this.dispose(forceWorkerDispose); + + this.worker = updatedWorker; + this.logger?.info('Re-Starting monaco-languageclient'); + return this.start(); + } + + protected async initMessageTransportWebSocket(webSocket: WebSocket, resolve: () => void, reject: (reason?: unknown) => void) { + let messageTransports = this.languageClientConfig.connection.messageTransports; + if (messageTransports === undefined) { + const iWebSocket = toSocket(webSocket); + messageTransports = { + reader: new WebSocketMessageReader(iWebSocket), + writer: new WebSocketMessageWriter(iWebSocket) + }; } - getWorker(): Worker | undefined { - return this.worker; + // if websocket is already open, then start the languageclient directly + if (webSocket.readyState === WebSocket.OPEN) { + await this.performLanguageClientStart(messageTransports, resolve, reject); } - isStarted(): boolean { - return this.languageClient?.isRunning() ?? false; - } - - async start(): Promise { - if (this.languageClient?.isRunning() ?? false) { - this.logger?.info('startLanguageClientConnection: monaco-languageclient already running!'); - return Promise.resolve(); - } - - return new Promise((resolve, reject) => { - const conConfig = this.languageClientConfig.connection; - const conOptions = conConfig.options; - - if (conOptions.$type === 'WebSocketDirect' || conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl') { - const webSocket = conOptions.$type === 'WebSocketDirect' ? conOptions.webSocket : new WebSocket(createUrl(conOptions)); - return this.initMessageTransportWebSocket(webSocket, resolve, reject); - } else { - // init of worker and start of languageclient can be handled directly, because worker available already - return this.initMessageTransportWorker(conOptions, resolve, reject); - } + // otherwise start on open + webSocket.onopen = async () => { + await this.performLanguageClientStart(messageTransports, resolve, reject); + }; + webSocket.onerror = (ev: Event) => { + const languageClientError: LanguageClientError = { + message: `languageClientWrapper (${this.languageId}): Websocket connection failed.`, + error: (ev as ErrorEvent).error ?? 'No error was provided.' + }; + reject(languageClientError); + }; + } + + protected async initMessageTransportWorker( + lccOptions: WorkerConfigOptionsDirect | WorkerConfigOptionsParams, + resolve: () => void, + reject: (reason?: unknown) => void + ) { + if (this.worker === undefined) { + if (lccOptions.$type === 'WorkerConfig') { + const workerConfig = lccOptions as WorkerConfigOptionsParams; + this.worker = new Worker(workerConfig.url.href, { + type: workerConfig.type, + name: workerConfig.workerName }); - } - - /** - * Restart the languageclient with options to control worker handling - * - * @param updatedWorker Set a new worker here that should be used. keepWorker has no effect then, as we want to dispose of the prior workers - * @param disposeWorker Set to false if worker should not be disposed - */ - async restart(updatedWorker?: Worker, forceWorkerDispose?: boolean): Promise { - await this.dispose(forceWorkerDispose); - - this.worker = updatedWorker; - this.logger?.info('Re-Starting monaco-languageclient'); - return this.start(); - } - - protected async initMessageTransportWebSocket(webSocket: WebSocket, resolve: () => void, reject: (reason?: unknown) => void) { - - let messageTransports = this.languageClientConfig.connection.messageTransports; - if (messageTransports === undefined) { - const iWebSocket = toSocket(webSocket); - messageTransports = { - reader: new WebSocketMessageReader(iWebSocket), - writer: new WebSocketMessageWriter(iWebSocket) - }; - } - - // if websocket is already open, then start the languageclient directly - if (webSocket.readyState === WebSocket.OPEN) { - await this.performLanguageClientStart(messageTransports, resolve, reject); - } - // otherwise start on open - webSocket.onopen = async () => { - await this.performLanguageClientStart(messageTransports, resolve, reject); - }; - webSocket.onerror = (ev: Event) => { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.languageId}): Websocket connection failed.`, - error: (ev as ErrorEvent).error ?? 'No error was provided.' - }; - reject(languageClientError); + this.worker.onerror = (ev) => { + const languageClientError: LanguageClientError = { + message: `languageClientWrapper (${this.languageId}): Illegal worker configuration detected.`, + error: ev.error ?? 'No error was provided.' + }; + reject(languageClientError); }; + } else { + const workerDirectConfig = lccOptions as WorkerConfigOptionsDirect; + this.worker = workerDirectConfig.worker; + } + if (lccOptions.messagePort !== undefined) { + this.port = lccOptions.messagePort; + } } - protected async initMessageTransportWorker(lccOptions: WorkerConfigOptionsDirect | WorkerConfigOptionsParams, resolve: () => void, reject: (reason?: unknown) => void) { - if (this.worker === undefined) { - if (lccOptions.$type === 'WorkerConfig') { - const workerConfig = lccOptions as WorkerConfigOptionsParams; - this.worker = new Worker(workerConfig.url.href, { - type: workerConfig.type, - name: workerConfig.workerName - }); - - this.worker.onerror = (ev) => { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.languageId}): Illegal worker configuration detected.`, - error: ev.error ?? 'No error was provided.' - }; - reject(languageClientError) - }; - } else { - const workerDirectConfig = lccOptions as WorkerConfigOptionsDirect; - this.worker = workerDirectConfig.worker; - } - if (lccOptions.messagePort !== undefined) { - this.port = lccOptions.messagePort; - } - } - - const portOrWorker = this.port ?? this.worker; - let messageTransports = this.languageClientConfig.connection.messageTransports; - messageTransports ??= { - reader: new BrowserMessageReader(portOrWorker), - writer: new BrowserMessageWriter(portOrWorker) - }; - await this.performLanguageClientStart(messageTransports, resolve, reject); + const portOrWorker = this.port ?? this.worker; + let messageTransports = this.languageClientConfig.connection.messageTransports; + messageTransports ??= { + reader: new BrowserMessageReader(portOrWorker), + writer: new BrowserMessageWriter(portOrWorker) + }; + await this.performLanguageClientStart(messageTransports, resolve, reject); + } + + protected async performLanguageClientStart( + messageTransports: MessageTransports, + resolve: () => void, + reject: (reason?: unknown) => void + ) { + let starting = true; + // do not perform another start attempt if already running + if (this.languageClient?.isRunning() ?? false) { + this.logger?.info('performLanguageClientStart: monaco-languageclient already running!'); + resolve(); } - protected async performLanguageClientStart(messageTransports: MessageTransports, resolve: () => void, reject: (reason?: unknown) => void) { - let starting = true; - // do not perform another start attempt if already running - if (this.languageClient?.isRunning() ?? false) { - this.logger?.info('performLanguageClientStart: monaco-languageclient already running!'); - resolve(); - } - - const mlcConfig = { - id: this.languageClientConfig.languageId, - name: 'Monaco Wrapper Language Client', - clientOptions: { - // disable the default error handler... - errorHandler: { - error: (e: Error) => { - if (starting) { - reject(`Error occurred in language client: ${e}`); - return { action: ErrorAction.Shutdown }; - } else { - return { action: ErrorAction.Continue }; - } - }, - closed: () => ({ action: CloseAction.DoNotRestart }) - }, - // ...but allowm to override all options - ...this.languageClientConfig.clientOptions, - }, - messageTransports - }; - - const conOptions = this.languageClientConfig.connection.options; - this.initRestartConfiguration(messageTransports, this.languageClientConfig.restartOptions); - - const isWebSocket = conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl' || conOptions.$type === 'WebSocketDirect'; - - messageTransports.reader.onClose(async () => { - await this.languageClient?.stop(); - - if (isWebSocket && conOptions.stopOptions !== undefined) { - const stopOptions = conOptions.stopOptions; - stopOptions.onCall(this.getLanguageClient()); - if (stopOptions.reportStatus !== undefined) { - this.logger?.info(this.reportStatus().join('\n')); - } - } - }); - - try { - this.languageClient = this.languageClientConfig.useClientWithProposedFeatures === true ? new MonacoLanguageClientWithProposedFeatures(mlcConfig) : new MonacoLanguageClient(mlcConfig); - if (this.languageClientConfig.registerFeatures !== undefined) { - this.languageClient.registerFeatures(this.languageClientConfig.registerFeatures); - } - - await this.languageClient.start(); - - if (isWebSocket && conOptions.startOptions !== undefined) { - const startOptions = conOptions.startOptions; - startOptions.onCall(this.getLanguageClient()); - if (startOptions.reportStatus !== undefined) { - this.logger?.info(this.reportStatus().join('\n')); - } + const mlcConfig = { + id: this.languageClientConfig.languageId, + name: 'Monaco Wrapper Language Client', + clientOptions: { + // disable the default error handler... + errorHandler: { + error: (e: Error) => { + if (starting) { + reject(`Error occurred in language client: ${e}`); + return { action: ErrorAction.Shutdown }; + } else { + return { action: ErrorAction.Continue }; } - } catch (e: unknown) { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.languageId}): Start was unsuccessful.`, - error: Object.hasOwn(e ?? {}, 'cause') ? (e as Error) : 'No error was provided.' - }; - reject(languageClientError); + }, + closed: () => ({ action: CloseAction.DoNotRestart }) + }, + // ...but allowm to override all options + ...this.languageClientConfig.clientOptions + }, + messageTransports + }; + + const conOptions = this.languageClientConfig.connection.options; + this.initRestartConfiguration(messageTransports, this.languageClientConfig.restartOptions); + + const isWebSocket = + conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl' || conOptions.$type === 'WebSocketDirect'; + + messageTransports.reader.onClose(async () => { + await this.languageClient?.stop(); + + if (isWebSocket && conOptions.stopOptions !== undefined) { + const stopOptions = conOptions.stopOptions; + stopOptions.onCall(this.getLanguageClient()); + if (stopOptions.reportStatus !== undefined) { + this.logger?.info(this.reportStatus().join('\n')); } - this.logger?.info(`languageClientWrapper (${this.languageId}): Started successfully.`); - resolve(); - starting = false; - } - - protected initRestartConfiguration(messageTransports: MessageTransports, restartOptions?: LanguageClientRestartOptions) { - if (restartOptions !== undefined) { - let retry = 0; - - const readerOnError = messageTransports.reader.onError(() => restartLC); - const readerOnClose = messageTransports.reader.onClose(() => restartLC); - - const restartLC = async () => { - if (this.isStarted()) { - try { - readerOnError.dispose(); - readerOnClose.dispose(); - - await this.restart(this.worker, restartOptions.keepWorker); - } finally { - retry++; - if (retry > (restartOptions.retries) && !this.isStarted()) { - this.logger?.info(`Disabling Language Client. Failed to start clangd after ${restartOptions.retries} retries`); - } else { - setTimeout(async () => { - await this.restart(this.worker, restartOptions.keepWorker); - }, restartOptions.timeout); - } - } - } - }; + } + }); + + try { + this.languageClient = + this.languageClientConfig.useClientWithProposedFeatures === true + ? new MonacoLanguageClientWithProposedFeatures(mlcConfig) + : new MonacoLanguageClient(mlcConfig); + if (this.languageClientConfig.registerFeatures !== undefined) { + this.languageClient.registerFeatures(this.languageClientConfig.registerFeatures); + } + + await this.languageClient.start(); + + if (isWebSocket && conOptions.startOptions !== undefined) { + const startOptions = conOptions.startOptions; + startOptions.onCall(this.getLanguageClient()); + if (startOptions.reportStatus !== undefined) { + this.logger?.info(this.reportStatus().join('\n')); } + } + } catch (e: unknown) { + const languageClientError: LanguageClientError = { + message: `languageClientWrapper (${this.languageId}): Start was unsuccessful.`, + error: Object.hasOwn(e ?? {}, 'cause') ? (e as Error) : 'No error was provided.' + }; + reject(languageClientError); } - - protected disposeWorker() { - this.worker?.terminate(); - this.worker = undefined; - } - - async dispose(forceWorkerDispose?: boolean): Promise { - try { - if (this.isStarted()) { - await this.languageClient?.dispose(); - this.languageClient = undefined; - this.logger?.info('monaco-languageclient was successfully disposed.'); - } - } catch (e) { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.languageId}): Disposing the monaco-languageclient resulted in error.`, - error: Object.hasOwn(e ?? {}, 'cause') ? (e as Error) : 'No error was provided.' - }; - return Promise.reject(languageClientError); - } finally { - // always terminate the worker if desired - if (this.languageClientConfig.disposeWorker === true || forceWorkerDispose === true) { - this.disposeWorker(); + this.logger?.info(`languageClientWrapper (${this.languageId}): Started successfully.`); + resolve(); + starting = false; + } + + protected initRestartConfiguration(messageTransports: MessageTransports, restartOptions?: LanguageClientRestartOptions) { + if (restartOptions !== undefined) { + let retry = 0; + + const readerOnError = messageTransports.reader.onError(() => restartLC); + const readerOnClose = messageTransports.reader.onClose(() => restartLC); + + const restartLC = async () => { + if (this.isStarted()) { + try { + readerOnError.dispose(); + readerOnClose.dispose(); + + await this.restart(this.worker, restartOptions.keepWorker); + } finally { + retry++; + if (retry > restartOptions.retries && !this.isStarted()) { + this.logger?.info(`Disabling Language Client. Failed to start clangd after ${restartOptions.retries} retries`); + } else { + setTimeout(async () => { + await this.restart(this.worker, restartOptions.keepWorker); + }, restartOptions.timeout); } + } } + }; } - - reportStatus() { - const status: string[] = []; - const languageClient = this.getLanguageClient(); - status.push('LanguageClientWrapper status:'); - status.push(`LanguageClient: ${languageClient?.name ?? 'Language Client'} is in a '${State[languageClient?.state ?? 1]}' state`); - return status; + } + + protected disposeWorker() { + this.worker?.terminate(); + this.worker = undefined; + } + + async dispose(forceWorkerDispose?: boolean): Promise { + try { + if (this.isStarted()) { + await this.languageClient?.dispose(); + this.languageClient = undefined; + this.logger?.info('monaco-languageclient was successfully disposed.'); + } + } catch (e) { + const languageClientError: LanguageClientError = { + message: `languageClientWrapper (${this.languageId}): Disposing the monaco-languageclient resulted in error.`, + error: Object.hasOwn(e ?? {}, 'cause') ? (e as Error) : 'No error was provided.' + }; + return Promise.reject(languageClientError); + } finally { + // always terminate the worker if desired + if (this.languageClientConfig.disposeWorker === true || forceWorkerDispose === true) { + this.disposeWorker(); + } } + } + + reportStatus() { + const status: string[] = []; + const languageClient = this.getLanguageClient(); + status.push('LanguageClientWrapper status:'); + status.push(`LanguageClient: ${languageClient?.name ?? 'Language Client'} is in a '${State[languageClient?.state ?? 1]}' state`); + return status; + } } diff --git a/packages/client/test/common/logging.test.ts b/packages/client/test/common/logging.test.ts index af999ca0c..7505c214a 100644 --- a/packages/client/test/common/logging.test.ts +++ b/packages/client/test/common/logging.test.ts @@ -8,35 +8,33 @@ import { ConsoleLogger } from '@codingame/monaco-vscode-log-service-override'; import { describe, expect, test } from 'vitest'; describe('Logger', () => { + test('Config: None', () => { + const logger = new ConsoleLogger(); - test('Config: None', () => { - const logger = new ConsoleLogger(); + expect(logger.getLevel()).toBe(LogLevel.Info); + }); - expect(logger.getLevel()).toBe(LogLevel.Info); - }); + test('Config: Off', () => { + const logger = new ConsoleLogger(LogLevel.Off); - test('Config: Off', () => { - const logger = new ConsoleLogger(LogLevel.Off); + expect(logger.getLevel()).toBe(LogLevel.Off); + }); - expect(logger.getLevel()).toBe(LogLevel.Off); - }); + test('Config: Info', () => { + const logger = new ConsoleLogger(LogLevel.Info); - test('Config: Info', () => { - const logger = new ConsoleLogger(LogLevel.Info); + expect(logger.getLevel()).toBe(LogLevel.Info); + }); - expect(logger.getLevel()).toBe(LogLevel.Info); - }); + test('Config: Debug', () => { + const logger = new ConsoleLogger(LogLevel.Debug); - test('Config: Debug', () => { - const logger = new ConsoleLogger(LogLevel.Debug); + expect(logger.getLevel()).toBe(LogLevel.Debug); + }); - expect(logger.getLevel()).toBe(LogLevel.Debug); - }); - - test('Config: checkLogLevel debug', () => { - const logger = new ConsoleLogger(LogLevel.Debug); - - expect(logger.getLevel()).toBe(LogLevel.Debug); - }); + test('Config: checkLogLevel debug', () => { + const logger = new ConsoleLogger(LogLevel.Debug); + expect(logger.getLevel()).toBe(LogLevel.Debug); + }); }); diff --git a/packages/client/test/common/utils.test.ts b/packages/client/test/common/utils.test.ts index f66710112..e8fdb7d6f 100644 --- a/packages/client/test/common/utils.test.ts +++ b/packages/client/test/common/utils.test.ts @@ -7,123 +7,123 @@ import { describe, expect, test } from 'vitest'; import { createUrl, type WebSocketConfigOptionsParams, type WebSocketConfigOptionsUrl } from 'monaco-languageclient/common'; describe('createUrl', () => { - - test('test createUrl: ws', () => { - const url = createUrl({ - secured: false, - host: 'localhost', - port: 30000, - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('ws://localhost:30000/sampleServer'); - }); - - test('test createUrl: wss', () => { - const url = createUrl({ - secured: true, - host: 'localhost', - port: 30000, - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost:30000/sampleServer'); - }); - - test('test createUrl: wss, no port, with path', () => { - const url = createUrl({ - secured: true, - host: 'localhost', - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost/sampleServer'); - }); - - test('test createUrl: wss, with port, no path', () => { - const url = createUrl({ - secured: true, - host: 'localhost', - port: 30000 - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost:30000'); - }); - - test('test createUrl: wss, no port, no path', () => { - const url = createUrl({ - secured: true, - host: 'localhost' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost'); - }); - - test('test createUrl: ws, normalize port 80', () => { - const url = createUrl({ - secured: false, - host: 'localhost', - port: 80 - } as WebSocketConfigOptionsParams); - - expect(url).toBe('ws://localhost'); - }); - - test('test createUrl: ws, normalize port 80, with path', () => { - const url = createUrl({ - secured: false, - host: 'localhost', - port: 80, - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('ws://localhost/sampleServer'); - }); - - test('test createUrl: optionsUrl: ws', () => { - const url = createUrl({ - url: 'ws://localhost:30000/sampleServer' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('ws://localhost:30000/sampleServer'); - }); - - test('test createUrl: optionsUrl: wss', () => { - const url = createUrl({ - url: 'wss://localhost:30000/sampleServer' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('wss://localhost:30000/sampleServer'); - }); - - test('test createUrl: optionsUrl, with port, no path', () => { - const url = createUrl({ - url: 'wss://localhost:30000' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('wss://localhost:30000'); - }); - - test('test createUrl: optionsUrl, no port, with path', () => { - const url = createUrl({ - url: 'ws://localhost/sampleServer' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('ws://localhost/sampleServer'); - }); - - test('test createUrl: optionsUrl, no port, no path', () => { - const url = createUrl({ - url: 'wss://www.testme.com' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('wss://www.testme.com'); - }); - - test('test createUrl: ws, not proper url', () => { - expect(() => createUrl({ - url: 'http://www.testme.com:30000/sampleServer' - } as WebSocketConfigOptionsUrl)).toThrowError('This is not a proper websocket url: http://www.testme.com:30000/sampleServer'); - }); - + test('test createUrl: ws', () => { + const url = createUrl({ + secured: false, + host: 'localhost', + port: 30000, + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('ws://localhost:30000/sampleServer'); + }); + + test('test createUrl: wss', () => { + const url = createUrl({ + secured: true, + host: 'localhost', + port: 30000, + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost:30000/sampleServer'); + }); + + test('test createUrl: wss, no port, with path', () => { + const url = createUrl({ + secured: true, + host: 'localhost', + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost/sampleServer'); + }); + + test('test createUrl: wss, with port, no path', () => { + const url = createUrl({ + secured: true, + host: 'localhost', + port: 30000 + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost:30000'); + }); + + test('test createUrl: wss, no port, no path', () => { + const url = createUrl({ + secured: true, + host: 'localhost' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost'); + }); + + test('test createUrl: ws, normalize port 80', () => { + const url = createUrl({ + secured: false, + host: 'localhost', + port: 80 + } as WebSocketConfigOptionsParams); + + expect(url).toBe('ws://localhost'); + }); + + test('test createUrl: ws, normalize port 80, with path', () => { + const url = createUrl({ + secured: false, + host: 'localhost', + port: 80, + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('ws://localhost/sampleServer'); + }); + + test('test createUrl: optionsUrl: ws', () => { + const url = createUrl({ + url: 'ws://localhost:30000/sampleServer' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('ws://localhost:30000/sampleServer'); + }); + + test('test createUrl: optionsUrl: wss', () => { + const url = createUrl({ + url: 'wss://localhost:30000/sampleServer' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('wss://localhost:30000/sampleServer'); + }); + + test('test createUrl: optionsUrl, with port, no path', () => { + const url = createUrl({ + url: 'wss://localhost:30000' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('wss://localhost:30000'); + }); + + test('test createUrl: optionsUrl, no port, with path', () => { + const url = createUrl({ + url: 'ws://localhost/sampleServer' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('ws://localhost/sampleServer'); + }); + + test('test createUrl: optionsUrl, no port, no path', () => { + const url = createUrl({ + url: 'wss://www.testme.com' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('wss://www.testme.com'); + }); + + test('test createUrl: ws, not proper url', () => { + expect(() => + createUrl({ + url: 'http://www.testme.com:30000/sampleServer' + } as WebSocketConfigOptionsUrl) + ).toThrowError('This is not a proper websocket url: http://www.testme.com:30000/sampleServer'); + }); }); diff --git a/packages/client/test/editorApp/config.test.ts b/packages/client/test/editorApp/config.test.ts index f66710112..e8fdb7d6f 100644 --- a/packages/client/test/editorApp/config.test.ts +++ b/packages/client/test/editorApp/config.test.ts @@ -7,123 +7,123 @@ import { describe, expect, test } from 'vitest'; import { createUrl, type WebSocketConfigOptionsParams, type WebSocketConfigOptionsUrl } from 'monaco-languageclient/common'; describe('createUrl', () => { - - test('test createUrl: ws', () => { - const url = createUrl({ - secured: false, - host: 'localhost', - port: 30000, - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('ws://localhost:30000/sampleServer'); - }); - - test('test createUrl: wss', () => { - const url = createUrl({ - secured: true, - host: 'localhost', - port: 30000, - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost:30000/sampleServer'); - }); - - test('test createUrl: wss, no port, with path', () => { - const url = createUrl({ - secured: true, - host: 'localhost', - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost/sampleServer'); - }); - - test('test createUrl: wss, with port, no path', () => { - const url = createUrl({ - secured: true, - host: 'localhost', - port: 30000 - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost:30000'); - }); - - test('test createUrl: wss, no port, no path', () => { - const url = createUrl({ - secured: true, - host: 'localhost' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('wss://localhost'); - }); - - test('test createUrl: ws, normalize port 80', () => { - const url = createUrl({ - secured: false, - host: 'localhost', - port: 80 - } as WebSocketConfigOptionsParams); - - expect(url).toBe('ws://localhost'); - }); - - test('test createUrl: ws, normalize port 80, with path', () => { - const url = createUrl({ - secured: false, - host: 'localhost', - port: 80, - path: 'sampleServer' - } as WebSocketConfigOptionsParams); - - expect(url).toBe('ws://localhost/sampleServer'); - }); - - test('test createUrl: optionsUrl: ws', () => { - const url = createUrl({ - url: 'ws://localhost:30000/sampleServer' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('ws://localhost:30000/sampleServer'); - }); - - test('test createUrl: optionsUrl: wss', () => { - const url = createUrl({ - url: 'wss://localhost:30000/sampleServer' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('wss://localhost:30000/sampleServer'); - }); - - test('test createUrl: optionsUrl, with port, no path', () => { - const url = createUrl({ - url: 'wss://localhost:30000' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('wss://localhost:30000'); - }); - - test('test createUrl: optionsUrl, no port, with path', () => { - const url = createUrl({ - url: 'ws://localhost/sampleServer' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('ws://localhost/sampleServer'); - }); - - test('test createUrl: optionsUrl, no port, no path', () => { - const url = createUrl({ - url: 'wss://www.testme.com' - } as WebSocketConfigOptionsUrl); - - expect(url).toBe('wss://www.testme.com'); - }); - - test('test createUrl: ws, not proper url', () => { - expect(() => createUrl({ - url: 'http://www.testme.com:30000/sampleServer' - } as WebSocketConfigOptionsUrl)).toThrowError('This is not a proper websocket url: http://www.testme.com:30000/sampleServer'); - }); - + test('test createUrl: ws', () => { + const url = createUrl({ + secured: false, + host: 'localhost', + port: 30000, + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('ws://localhost:30000/sampleServer'); + }); + + test('test createUrl: wss', () => { + const url = createUrl({ + secured: true, + host: 'localhost', + port: 30000, + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost:30000/sampleServer'); + }); + + test('test createUrl: wss, no port, with path', () => { + const url = createUrl({ + secured: true, + host: 'localhost', + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost/sampleServer'); + }); + + test('test createUrl: wss, with port, no path', () => { + const url = createUrl({ + secured: true, + host: 'localhost', + port: 30000 + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost:30000'); + }); + + test('test createUrl: wss, no port, no path', () => { + const url = createUrl({ + secured: true, + host: 'localhost' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('wss://localhost'); + }); + + test('test createUrl: ws, normalize port 80', () => { + const url = createUrl({ + secured: false, + host: 'localhost', + port: 80 + } as WebSocketConfigOptionsParams); + + expect(url).toBe('ws://localhost'); + }); + + test('test createUrl: ws, normalize port 80, with path', () => { + const url = createUrl({ + secured: false, + host: 'localhost', + port: 80, + path: 'sampleServer' + } as WebSocketConfigOptionsParams); + + expect(url).toBe('ws://localhost/sampleServer'); + }); + + test('test createUrl: optionsUrl: ws', () => { + const url = createUrl({ + url: 'ws://localhost:30000/sampleServer' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('ws://localhost:30000/sampleServer'); + }); + + test('test createUrl: optionsUrl: wss', () => { + const url = createUrl({ + url: 'wss://localhost:30000/sampleServer' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('wss://localhost:30000/sampleServer'); + }); + + test('test createUrl: optionsUrl, with port, no path', () => { + const url = createUrl({ + url: 'wss://localhost:30000' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('wss://localhost:30000'); + }); + + test('test createUrl: optionsUrl, no port, with path', () => { + const url = createUrl({ + url: 'ws://localhost/sampleServer' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('ws://localhost/sampleServer'); + }); + + test('test createUrl: optionsUrl, no port, no path', () => { + const url = createUrl({ + url: 'wss://www.testme.com' + } as WebSocketConfigOptionsUrl); + + expect(url).toBe('wss://www.testme.com'); + }); + + test('test createUrl: ws, not proper url', () => { + expect(() => + createUrl({ + url: 'http://www.testme.com:30000/sampleServer' + } as WebSocketConfigOptionsUrl) + ).toThrowError('This is not a proper websocket url: http://www.testme.com:30000/sampleServer'); + }); }); diff --git a/packages/client/test/editorApp/editorApp-classic.test.ts b/packages/client/test/editorApp/editorApp-classic.test.ts index bdba33fc1..ba0dbc270 100644 --- a/packages/client/test/editorApp/editorApp-classic.test.ts +++ b/packages/client/test/editorApp/editorApp-classic.test.ts @@ -12,354 +12,361 @@ import { beforeAll, describe, expect, test } from 'vitest'; import { createDefaultMonacoVscodeApiConfig, createEditorAppConfig, createMonacoEditorDiv } from '../support/helper.js'; describe('Test Test EditorApp (classic)', () => { - - const htmlContainer = createMonacoEditorDiv(); - const apiConfig = createDefaultMonacoVscodeApiConfig('classic', htmlContainer, 'EditorService'); - - beforeAll(async () => { - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await apiWrapper.start(); + const htmlContainer = createMonacoEditorDiv(); + const apiConfig = createDefaultMonacoVscodeApiConfig('classic', htmlContainer, 'EditorService'); + + beforeAll(async () => { + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await apiWrapper.start(); + }); + + test('classic type: empty EditorAppConfigClassic', () => { + const editorAppConfig = createEditorAppConfig({}); + expect(editorAppConfig.editorOptions).toStrictEqual({}); + expect(apiConfig.$type).toBe('classic'); + }); + + test('config defaults', () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('classic type: empty EditorAppConfigClassic', () => { - const editorAppConfig = createEditorAppConfig({}); - expect(editorAppConfig.editorOptions).toStrictEqual({}); - expect(apiConfig.$type).toBe('classic'); - }); - - test('config defaults', () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - editorAppConfig.id = 'test-config-defaults'; - - const editorApp = new EditorApp(editorAppConfig); - expect(editorApp.getConfig().codeResources?.modified?.text).toEqual('const text = "Hello World!";'); - expect(editorApp.getConfig().codeResources?.original).toBeUndefined(); - expect(editorApp.getConfig().useDiffEditor ?? false).toBeFalsy(); - expect(editorApp.getConfig().readOnly).toBeFalsy(); - expect(editorApp.getConfig().domReadOnly).toBeFalsy(); + editorAppConfig.id = 'test-config-defaults'; + + const editorApp = new EditorApp(editorAppConfig); + expect(editorApp.getConfig().codeResources?.modified?.text).toEqual('const text = "Hello World!";'); + expect(editorApp.getConfig().codeResources?.original).toBeUndefined(); + expect(editorApp.getConfig().useDiffEditor ?? false).toBeFalsy(); + expect(editorApp.getConfig().readOnly).toBeFalsy(); + expect(editorApp.getConfig().domReadOnly).toBeFalsy(); + }); + + test('editorOptions: semanticHighlighting=false', () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('editorOptions: semanticHighlighting=false', () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - (editorAppConfig!.editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] = false; - editorAppConfig.id = 'test-semanticHighlighting-false'; - - const editorApp = new EditorApp(editorAppConfig); - expect((editorApp.getConfig().editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled']).toBeFalsy(); + (editorAppConfig!.editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] = false; + editorAppConfig.id = 'test-semanticHighlighting-false'; + + const editorApp = new EditorApp(editorAppConfig); + expect( + (editorApp.getConfig().editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] + ).toBeFalsy(); + }); + + test('editorOptions: semanticHighlighting="configuredByTheme"', () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('editorOptions: semanticHighlighting="configuredByTheme"', () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - (editorAppConfig!.editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] = 'configuredByTheme'; - editorAppConfig.id = 'test-semanticHighlighting-theme'; - - const editorApp = new EditorApp(editorAppConfig); - expect((editorApp.getConfig().editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled']).toEqual('configuredByTheme'); + (editorAppConfig!.editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] = + 'configuredByTheme'; + editorAppConfig.id = 'test-semanticHighlighting-theme'; + + const editorApp = new EditorApp(editorAppConfig); + expect( + (editorApp.getConfig().editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] + ).toEqual('configuredByTheme'); + }); + + test('editorOptions: semanticHighlighting=true', () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('editorOptions: semanticHighlighting=true', () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - (editorAppConfig!.editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] = true; - editorAppConfig.id = 'test-semanticHighlighting-true'; - - const editorApp = new EditorApp(editorAppConfig); - expect((editorApp.getConfig().editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled']).toBeTruthy(); + (editorAppConfig!.editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] = true; + editorAppConfig.id = 'test-semanticHighlighting-true'; + + const editorApp = new EditorApp(editorAppConfig); + expect( + (editorApp.getConfig().editorOptions as monaco.editor.IStandaloneEditorConstructionOptions)['semanticHighlighting.enabled'] + ).toBeTruthy(); + }); + + test('Check default values', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('Check default values', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); + const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - const editorApp = new EditorApp(editorAppConfig); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(editorApp).toBeDefined(); - expect(editorApp).toBeDefined(); + const appConfig = editorApp!.getConfig(); + expect(appConfig.overrideAutomaticLayout).toBeTruthy(); - const appConfig = editorApp!.getConfig(); - expect(appConfig.overrideAutomaticLayout).toBeTruthy(); + await editorApp.dispose(); + }); - await editorApp.dispose(); + test('Code resources main', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const editorApp = new EditorApp(editorAppConfig); - test('Code resources main', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); + const modelRefs = editorApp['modelRefs']; + expect(modelRefs?.modified).toBeDefined(); + expect(modelRefs?.original).toBeUndefined(); - const modelRefs = editorApp['modelRefs']; - expect(modelRefs?.modified).toBeDefined(); - expect(modelRefs?.original).toBeUndefined(); + await editorApp.dispose(); + }); - await editorApp.dispose(); + test('Call start twice without prior disposal', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('Call start twice without prior disposal', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const editorApp = new EditorApp(editorAppConfig); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - await expect(async () => { - await editorApp.start(htmlContainer); - }).rejects.toThrowError('Start was called without properly disposing the EditorApp first.'); - - await editorApp.dispose(); + const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + await expect(async () => { + await editorApp.start(htmlContainer); + }).rejects.toThrowError('Start was called without properly disposing the EditorApp first.'); + + await editorApp.dispose(); + }); + + test('Call start twice with prior disposal', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const editorApp = new EditorApp(editorAppConfig); - test('Call start twice with prior disposal', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + await editorApp.dispose(); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - await editorApp.dispose(); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); + await editorApp.dispose(); + }); - await editorApp.dispose(); + test('Code resources original (regular editor)', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('Code resources original (regular editor)', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const codeResources = editorAppConfig.codeResources ?? {}; - codeResources.modified = undefined; - codeResources.original = { - text: 'original', - uri: '/workspace/test-code-resources-original-regular-editor.js', - }; - - const editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - const modelRefs = editorApp['modelRefs']; - expect(modelRefs?.modified).toBeDefined(); - expect(modelRefs?.original).toBeUndefined(); - await editorApp.dispose(); + const codeResources = editorAppConfig.codeResources ?? {}; + codeResources.modified = undefined; + codeResources.original = { + text: 'original', + uri: '/workspace/test-code-resources-original-regular-editor.js' + }; + + const editorApp = new EditorApp(editorAppConfig); + + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + const modelRefs = editorApp['modelRefs']; + expect(modelRefs?.modified).toBeDefined(); + expect(modelRefs?.original).toBeUndefined(); + await editorApp.dispose(); + }); + + test('Code resources original (diff editor)', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('Code resources original (diff editor)', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - editorAppConfig.useDiffEditor = true; - const codeResources = editorAppConfig.codeResources ?? {}; - codeResources.modified = undefined; - codeResources.original = { - text: 'original', - uri: '/workspace/test-code-resources-original-diff-editor.js', - }; - const editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - const modelRefs = editorApp['modelRefs']; - expect(modelRefs?.modified).toBeDefined(); - expect(modelRefs?.original).toBeDefined(); - await editorApp.dispose(); + editorAppConfig.useDiffEditor = true; + const codeResources = editorAppConfig.codeResources ?? {}; + codeResources.modified = undefined; + codeResources.original = { + text: 'original', + uri: '/workspace/test-code-resources-original-diff-editor.js' + }; + const editorApp = new EditorApp(editorAppConfig); + + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + const modelRefs = editorApp['modelRefs']; + expect(modelRefs?.modified).toBeDefined(); + expect(modelRefs?.original).toBeDefined(); + await editorApp.dispose(); + }); + + test('Code resources main and original', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'modified', + uri: `/workspace/${expect.getState().testPath}_modified.js` + } }); - - test('Code resources main and original', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'modified', - uri: `/workspace/${expect.getState().testPath}_modified.js` - } - }); - const codeResources = editorAppConfig.codeResources!; - codeResources.original = { - text: 'original', - uri: `/workspace/${expect.getState().testPath}_original.js` - }; - const editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - const modelRefs = editorApp['modelRefs']; - expect(modelRefs?.modified).toBeDefined(); - // if no diff editor is used, the original modelRef is undefined - expect(modelRefs?.original).toBeUndefined(); - - const name = modelRefs?.modified.object.name; - const nameOriginal = modelRefs?.original?.object.name; - expect(name).toBeDefined(); - expect(nameOriginal).toBeUndefined(); - expect(name).not.toEqual(nameOriginal); - - await editorApp.dispose(); + const codeResources = editorAppConfig.codeResources!; + codeResources.original = { + text: 'original', + uri: `/workspace/${expect.getState().testPath}_original.js` + }; + const editorApp = new EditorApp(editorAppConfig); + + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + const modelRefs = editorApp['modelRefs']; + expect(modelRefs?.modified).toBeDefined(); + // if no diff editor is used, the original modelRef is undefined + expect(modelRefs?.original).toBeUndefined(); + + const name = modelRefs?.modified.object.name; + const nameOriginal = modelRefs?.original?.object.name; + expect(name).toBeDefined(); + expect(nameOriginal).toBeUndefined(); + expect(name).not.toEqual(nameOriginal); + + await editorApp.dispose(); + }); + + test('Code resources empty', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('Code resources empty', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - editorAppConfig.codeResources = {}; - const editorApp = new EditorApp(editorAppConfig); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - const modelRefs = editorApp['modelRefs']; - // default modelRef is created with regular editor even if no codeResources are given - expect(modelRefs?.modified).toBeDefined(); - expect(modelRefs?.original).toBeUndefined(); - - await editorApp.dispose(); + editorAppConfig.codeResources = {}; + const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + const modelRefs = editorApp['modelRefs']; + // default modelRef is created with regular editor even if no codeResources are given + expect(modelRefs?.modified).toBeDefined(); + expect(modelRefs?.original).toBeUndefined(); + + await editorApp.dispose(); + }); + + test('Code resources model direct', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); + editorAppConfig.codeResources = {}; + const editorApp = new EditorApp(editorAppConfig); - test('Code resources model direct', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - editorAppConfig.codeResources = {}; - const editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - editorApp.setModelRefDisposeTimeout(1000); - - await editorApp.updateCodeResources({ - modified: { - text: 'const text = "Hello World!";', - uri: '/workspace/statemachineUri.statemachine' - } - }); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - const modelRefs = editorApp['modelRefs']; - expect(modelRefs?.modified).toBeDefined(); - expect(modelRefs?.original).toBeUndefined(); + editorApp.setModelRefDisposeTimeout(1000); - await editorApp.dispose(); + await editorApp.updateCodeResources({ + modified: { + text: 'const text = "Hello World!";', + uri: '/workspace/statemachineUri.statemachine' + } }); - test('Early code resources update on editorApp are ok', async () => { - const editorAppConfig = createEditorAppConfig({}); - const editorApp = new EditorApp(editorAppConfig); + const modelRefs = editorApp['modelRefs']; + expect(modelRefs?.modified).toBeDefined(); + expect(modelRefs?.original).toBeUndefined(); - editorApp.setModelRefDisposeTimeout(1000); + await editorApp.dispose(); + }); - expect(editorApp.getEditor()).toBeUndefined(); - expect(editorApp.getDiffEditor()).toBeUndefined(); + test('Early code resources update on editorApp are ok', async () => { + const editorAppConfig = createEditorAppConfig({}); + const editorApp = new EditorApp(editorAppConfig); - const modelRefsBefore = editorApp['modelRefs']; - expect(modelRefsBefore?.modified).toBeUndefined(); - expect(modelRefsBefore?.original).toBeUndefined(); + editorApp.setModelRefDisposeTimeout(1000); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(editorApp.getEditor()).toBeUndefined(); + expect(editorApp.getDiffEditor()).toBeUndefined(); - editorApp.registerOnTextChangedCallback((textChanges: TextContents) => { - console.log(textChanges); - expect(textChanges.modified).toEqual('// comment'); - }); + const modelRefsBefore = editorApp['modelRefs']; + expect(modelRefsBefore?.modified).toBeUndefined(); + expect(modelRefsBefore?.original).toBeUndefined(); - expect(await editorApp.updateCodeResources({ - modified: { - text: '// comment', - uri: '/workspace/test.statemachine', - } - })).toBeTruthy(); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - const modelRefsAfter = editorApp['modelRefs']; - expect(modelRefsAfter?.modified).toBeDefined(); - expect(modelRefsAfter?.original).toBeUndefined(); - - await editorApp.dispose(); + editorApp.registerOnTextChangedCallback((textChanges: TextContents) => { + console.log(textChanges); + expect(textChanges.modified).toEqual('// comment'); }); - test('Check current model is globally removed after dispose', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "test";', - uri: `/workspace/${expect.getState().testPath}_single-model.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - const currentModel = editorApp.getEditor()?.getModel(); - expect(monaco.editor.getModels().includes(currentModel!)).toBeTruthy(); - editorApp.getEditor()?.getModel()!.dispose(); - expect(monaco.editor.getModels().includes(currentModel!)).toBeFalsy(); - - await editorApp.dispose(); + expect( + await editorApp.updateCodeResources({ + modified: { + text: '// comment', + uri: '/workspace/test.statemachine' + } + }) + ).toBeTruthy(); + + const modelRefsAfter = editorApp['modelRefs']; + expect(modelRefsAfter?.modified).toBeDefined(); + expect(modelRefsAfter?.original).toBeUndefined(); + + await editorApp.dispose(); + }); + + test('Check current model is globally removed after dispose', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "test";', + uri: `/workspace/${expect.getState().testPath}_single-model.js` + } + }); + const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + const currentModel = editorApp.getEditor()?.getModel(); + expect(monaco.editor.getModels().includes(currentModel!)).toBeTruthy(); + editorApp.getEditor()?.getModel()!.dispose(); + expect(monaco.editor.getModels().includes(currentModel!)).toBeFalsy(); + + await editorApp.dispose(); + }); + + test('Check current model is globally removed after dispose (second model)', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: 'const text = "test";', + uri: `/workspace/${expect.getState().testPath}_second-model.js` + } }); + const editorApp = new EditorApp(editorAppConfig); + + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + const currentModel = editorApp.getEditor()?.getModel(); + expect(monaco.editor.getModels().includes(currentModel!)).toBeTruthy(); + + editorApp.setModelRefDisposeTimeout(1000); - test('Check current model is globally removed after dispose (second model)', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: 'const text = "test";', - uri: `/workspace/${expect.getState().testPath}_second-model.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - const currentModel = editorApp.getEditor()?.getModel(); - expect(monaco.editor.getModels().includes(currentModel!)).toBeTruthy(); - - editorApp.setModelRefDisposeTimeout(1000); - - await editorApp.updateCodeResources({ - modified: { - text: 'const text = "test 2";', - uri: `/workspace/${expect.getState().testPath}_second-model_2.js` - } - }); - const currentModelMod = editorApp.getEditor()?.getModel(); - expect(monaco.editor.getModels().includes(currentModelMod!)).toBeTruthy(); - expect(monaco.editor.getModels().includes(currentModel!)).toBeFalsy(); - - await editorApp.dispose(); + await editorApp.updateCodeResources({ + modified: { + text: 'const text = "test 2";', + uri: `/workspace/${expect.getState().testPath}_second-model_2.js` + } }); + const currentModelMod = editorApp.getEditor()?.getModel(); + expect(monaco.editor.getModels().includes(currentModelMod!)).toBeTruthy(); + expect(monaco.editor.getModels().includes(currentModel!)).toBeFalsy(); + await editorApp.dispose(); + }); }); diff --git a/packages/client/test/editorApp/editorApp.noservices.test.ts b/packages/client/test/editorApp/editorApp.noservices.test.ts index 3657f69ea..5e2a0290c 100644 --- a/packages/client/test/editorApp/editorApp.noservices.test.ts +++ b/packages/client/test/editorApp/editorApp.noservices.test.ts @@ -8,15 +8,13 @@ import { describe, expect, test } from 'vitest'; import { createEditorAppConfig, createMonacoEditorDiv } from '../support/helper.js'; describe('Test EditorApp', () => { + const htmlContainer = createMonacoEditorDiv(); - const htmlContainer = createMonacoEditorDiv(); - - test('Start EditorApp with no services', async () => { - const editorAppConfig = createEditorAppConfig({}); - const editorApp = new EditorApp(editorAppConfig); - await expect(async () => { - await editorApp.start(htmlContainer); - }).rejects.toThrowError('monaco-vscode-api was not initialized. Aborting.'); - }); - + test('Start EditorApp with no services', async () => { + const editorAppConfig = createEditorAppConfig({}); + const editorApp = new EditorApp(editorAppConfig); + await expect(async () => { + await editorApp.start(htmlContainer); + }).rejects.toThrowError('monaco-vscode-api was not initialized. Aborting.'); + }); }); diff --git a/packages/client/test/editorApp/editorApp.test.ts b/packages/client/test/editorApp/editorApp.test.ts index 691d771c2..ca01ac735 100644 --- a/packages/client/test/editorApp/editorApp.test.ts +++ b/packages/client/test/editorApp/editorApp.test.ts @@ -14,250 +14,250 @@ import { beforeAll, describe, expect, test, vi } from 'vitest'; import { createDefaultMonacoVscodeApiConfig, createEditorAppConfig, createMonacoEditorDiv } from '../support/helper.js'; describe('Test EditorApp', () => { - - const htmlContainer = createMonacoEditorDiv(); - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'EditorService'); - - beforeAll(async () => { - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await apiWrapper.start(); + const htmlContainer = createMonacoEditorDiv(); + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'EditorService'); + + beforeAll(async () => { + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await apiWrapper.start(); + }); + const code = 'const text = "Hello World!";'; + const codeUpdated = 'const text = "Goodbye World!";'; + + test('extended type: empty EditorAppConfigExtended', () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - const code = 'const text = "Hello World!";'; - const codeUpdated = 'const text = "Goodbye World!";'; - - test('extended type: empty EditorAppConfigExtended', () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - expect(editorAppConfig.editorOptions).toStrictEqual({}); - expect(apiConfig.$type).toBe('extended'); + expect(editorAppConfig.editorOptions).toStrictEqual({}); + expect(apiConfig.$type).toBe('extended'); + }); + + test('verifyUrlorCreateDataUrl: url', () => { + const url = new URL('./editorAppExtended.test.ts', import.meta.url); + expect(encodeStringOrUrlToDataUrl(url)).toBe(url.href); + }); + + test('verifyUrlorCreateDataUrl: url', async () => { + const url = new URL('../../../node_modules/langium-statemachine-dsl/syntaxes/statemachine.tmLanguage.json', window.location.href); + const text = await (await fetch(url)).text(); + const bytes = new TextEncoder().encode(text); + const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join(''); + const base64 = btoa(binString); + expect(encodeStringOrUrlToDataUrl(text)).toBe(`data:text/plain;base64,${base64}`); + }); + + test('verifyUrlorCreateDataUrl: url', () => { + const text = '✓✓'; + const bytes = new TextEncoder().encode(text); + const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join(''); + const base64 = btoa(binString); + expect(encodeStringOrUrlToDataUrl(text)).toBe(`data:text/plain;base64,${base64}`); + }); + + test('config defaults', () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('verifyUrlorCreateDataUrl: url', () => { - const url = new URL('./editorAppExtended.test.ts', import.meta.url); - expect(encodeStringOrUrlToDataUrl(url)).toBe(url.href); + editorAppConfig.id = 'test-config-defaults'; + + const editorApp = new EditorApp(editorAppConfig); + expect(editorApp.getConfig().codeResources?.modified?.text).toEqual(code); + expect(editorApp.getConfig().codeResources?.original).toBeUndefined(); + expect(editorApp.getConfig().useDiffEditor ?? false).toBeFalsy(); + expect(editorApp.getConfig().readOnly).toBeFalsy(); + expect(editorApp.getConfig().domReadOnly).toBeFalsy(); + }); + + test('New editorApp has undefined editor', () => { + const editorAppConfig = createEditorAppConfig({}); + const editorApp = new EditorApp(editorAppConfig); + expect(editorApp.getEditor()).toBeUndefined(); + }); + + test('New editorApp has undefined diff editor', () => { + const editorAppConfig = createEditorAppConfig({}); + const editorApp = new EditorApp(editorAppConfig); + expect(editorApp.getDiffEditor()).toBeUndefined(); + }); + + test('Start EditorApp', async () => { + const editorAppConfig = createEditorAppConfig({}); + const editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(await editorApp.dispose()).toBeUndefined(); + }); + + test('Update code resources after start (same file)', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const editorApp = new EditorApp(editorAppConfig); - test('verifyUrlorCreateDataUrl: url', async () => { - const url = new URL('../../../node_modules/langium-statemachine-dsl/syntaxes/statemachine.tmLanguage.json', window.location.href); - const text = await (await fetch(url)).text(); - const bytes = new TextEncoder().encode(text); - const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join(''); - const base64 = btoa(binString); - expect(encodeStringOrUrlToDataUrl(text)).toBe(`data:text/plain;base64,${base64}`); - }); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(editorApp.isStarted()).toBeTruthy(); - test('verifyUrlorCreateDataUrl: url', () => { - const text = '✓✓'; - const bytes = new TextEncoder().encode(text); - const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join(''); - const base64 = btoa(binString); - expect(encodeStringOrUrlToDataUrl(text)).toBe(`data:text/plain;base64,${base64}`); + editorApp.registerOnTextChangedCallback((textChanges: TextContents) => { + console.log(`text: ${textChanges.modified}\ntextOriginal: ${textChanges.original}`); }); - test('config defaults', () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - editorAppConfig.id = 'test-config-defaults'; - - const editorApp = new EditorApp(editorAppConfig); - expect(editorApp.getConfig().codeResources?.modified?.text).toEqual(code); - expect(editorApp.getConfig().codeResources?.original).toBeUndefined(); - expect(editorApp.getConfig().useDiffEditor ?? false).toBeFalsy(); - expect(editorApp.getConfig().readOnly).toBeFalsy(); - expect(editorApp.getConfig().domReadOnly).toBeFalsy(); - }); - - test('New editorApp has undefined editor', () => { - const editorAppConfig = createEditorAppConfig({}); - const editorApp = new EditorApp(editorAppConfig); - expect(editorApp.getEditor()).toBeUndefined(); - }); - - test('New editorApp has undefined diff editor', () => { - const editorAppConfig = createEditorAppConfig({}); - const editorApp = new EditorApp(editorAppConfig); - expect(editorApp.getDiffEditor()).toBeUndefined(); - }); + editorApp.setModelRefDisposeTimeout(1000); - test('Start EditorApp', async () => { - const editorAppConfig = createEditorAppConfig({}); - const editorApp = new EditorApp(editorAppConfig); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - expect(await editorApp.dispose()).toBeUndefined(); + await editorApp.updateCodeResources({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}_2.js` + } }); - test('Update code resources after start (same file)', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); + const textModels = editorApp.getTextModels(); + expect(textModels.modified?.getValue()).toEqual(codeUpdated); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - expect(editorApp.isStarted()).toBeTruthy(); + expect(editorApp.getEditor()?.getModel()?.getValue()).toEqual(codeUpdated); - editorApp.registerOnTextChangedCallback((textChanges: TextContents) => { - console.log(`text: ${textChanges.modified}\ntextOriginal: ${textChanges.original}`); - }); + await editorApp.dispose(); + }); - editorApp.setModelRefDisposeTimeout(1000); + test('Update code resources after start (different file)', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const editorApp = new EditorApp(editorAppConfig); - await editorApp.updateCodeResources({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}_2.js` - } - }); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(editorApp.isStarted()).toBeTruthy(); - const textModels = editorApp.getTextModels(); - expect(textModels.modified?.getValue()).toEqual(codeUpdated); + editorApp.setModelRefDisposeTimeout(1000); - expect(editorApp.getEditor()?.getModel()?.getValue()).toEqual(codeUpdated); + expect( + await editorApp.updateCodeResources({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}_2.js` + } + }) + ).toBeTruthy(); - await editorApp.dispose(); - }); + const textModels = editorApp.getTextModels(); + expect(textModels.modified?.getValue()).toEqual(codeUpdated); - test('Update code resources after start (different file)', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); + expect(editorApp.getEditor()?.getModel()?.getValue()).toEqual(codeUpdated); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - expect(editorApp.isStarted()).toBeTruthy(); + await editorApp.dispose(); + }); - editorApp.setModelRefDisposeTimeout(1000); + test('Verify registerTextChangeCallback', async () => { + const editorAppConfig = createEditorAppConfig({}); - expect(await editorApp.updateCodeResources({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}_2.js`, - } - })).toBeTruthy(); + const onTextChanged = (textChanges: TextContents) => { + console.log(`text: ${textChanges.modified}\ntextOriginal: ${textChanges.original}`); + }; + const editorApp = new EditorApp(editorAppConfig); - const textModels = editorApp.getTextModels(); - expect(textModels.modified?.getValue()).toEqual(codeUpdated); + let onTextChangedDiposeable = editorApp['textChangedDisposables'].modified; + expect(onTextChangedDiposeable).toBeUndefined(); - expect(editorApp.getEditor()?.getModel()?.getValue()).toEqual(codeUpdated); + editorApp.registerOnTextChangedCallback(onTextChanged); - await editorApp.dispose(); - }); + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + const spyAnnounceModelUpdate = vi.spyOn(editorApp as any, 'announceModelUpdate'); - test('Verify registerTextChangeCallback', async () => { - const editorAppConfig = createEditorAppConfig({}); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - const onTextChanged = (textChanges: TextContents) => { - console.log(`text: ${textChanges.modified}\ntextOriginal: ${textChanges.original}`); - }; - const editorApp = new EditorApp(editorAppConfig); + onTextChangedDiposeable = editorApp['textChangedDisposables'].modified; + expect(onTextChangedDiposeable).toBeDefined(); - let onTextChangedDiposeable = editorApp['textChangedDisposables'].modified; - expect(onTextChangedDiposeable).toBeUndefined(); + const spyOnTextChangedDiposeable = vi.spyOn(onTextChangedDiposeable, 'dispose'); - editorApp.registerOnTextChangedCallback(onTextChanged); + // because there are default models now, the first update of models will not lead to onTextChanged dispoe + expect(spyAnnounceModelUpdate).toHaveBeenCalledTimes(1); + expect(spyOnTextChangedDiposeable).toHaveBeenCalledTimes(0); + editorApp.setModelRefDisposeTimeout(1000); - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - const spyAnnounceModelUpdate = vi.spyOn(editorApp as any, 'announceModelUpdate'); + await editorApp.updateCodeResources({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}_2.statemachine` + } + }); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(spyAnnounceModelUpdate).toHaveBeenCalledTimes(2); + expect(spyOnTextChangedDiposeable).toHaveBeenCalledTimes(1); - onTextChangedDiposeable = editorApp['textChangedDisposables'].modified; - expect(onTextChangedDiposeable).toBeDefined(); + await editorApp.dispose(); + }); - const spyOnTextChangedDiposeable = vi.spyOn(onTextChangedDiposeable, 'dispose'); + test('Test editorApp init/start/dispose phase promises', async () => { + let editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + let editorApp = new EditorApp(editorAppConfig); - // because there are default models now, the first update of models will not lead to onTextChanged dispoe - expect(spyAnnounceModelUpdate).toHaveBeenCalledTimes(1); - expect(spyOnTextChangedDiposeable).toHaveBeenCalledTimes(0); - editorApp.setModelRefDisposeTimeout(1000); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(editorApp.isStarting()).toBeFalsy(); + expect(editorApp.isDisposing()).toBeFalsy(); - await editorApp.updateCodeResources({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}_2.statemachine`, - } - }); + expect(await editorApp.dispose()).toBeUndefined(); - expect(spyAnnounceModelUpdate).toHaveBeenCalledTimes(2); - expect(spyOnTextChangedDiposeable).toHaveBeenCalledTimes(1); + expect(editorApp.isStarting()).toBeFalsy(); + expect(editorApp.isDisposing()).toBeFalsy(); - await editorApp.dispose(); + editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}_2.js` + } }); - - test('Test editorApp init/start/dispose phase promises', async () => { - let editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - let editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - expect(editorApp.isStarting()).toBeFalsy(); - expect(editorApp.isDisposing()).toBeFalsy(); - - expect(await editorApp.dispose()).toBeUndefined(); - - expect(editorApp.isStarting()).toBeFalsy(); - expect(editorApp.isDisposing()).toBeFalsy(); - - editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}_2.js` - } - }); - editorApp = new EditorApp(editorAppConfig); - expect(await editorApp.start(htmlContainer)).toBeUndefined(); - - await editorApp.dispose(); + editorApp = new EditorApp(editorAppConfig); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); + + await editorApp.dispose(); + }); + + test('Test html parameter with start', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const editorApp = new EditorApp(editorAppConfig); - test('Test html parameter with start', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const editorApp = new EditorApp(editorAppConfig); - - expect(await editorApp.start(htmlContainer)).toBeUndefined(); + expect(await editorApp.start(htmlContainer)).toBeUndefined(); - await editorApp.dispose(); - }); + await editorApp.dispose(); + }); - test('set verify log levels are applied', async () => { - const editorAppConfig = createEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - let editorApp = new EditorApp(editorAppConfig); - let logLevel = (editorApp['logger'] as ILogger).getLevel(); - expect(logLevel).toBe(LogLevel.Off); - expect(logLevel).toBe(0); - - editorAppConfig.logLevel = LogLevel.Debug; - editorApp = new EditorApp(editorAppConfig); - logLevel = (editorApp['logger'] as ILogger).getLevel(); - expect(logLevel).toBe(LogLevel.Debug); - expect(logLevel).toBe(2); + test('set verify log levels are applied', async () => { + const editorAppConfig = createEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - + let editorApp = new EditorApp(editorAppConfig); + let logLevel = (editorApp['logger'] as ILogger).getLevel(); + expect(logLevel).toBe(LogLevel.Off); + expect(logLevel).toBe(0); + + editorAppConfig.logLevel = LogLevel.Debug; + editorApp = new EditorApp(editorAppConfig); + logLevel = (editorApp['logger'] as ILogger).getLevel(); + expect(logLevel).toBe(LogLevel.Debug); + expect(logLevel).toBe(2); + }); }); diff --git a/packages/client/test/editorApp/editorApp.wrongservices.test.ts b/packages/client/test/editorApp/editorApp.wrongservices.test.ts index a1e3b7bcf..75b11bbbc 100644 --- a/packages/client/test/editorApp/editorApp.wrongservices.test.ts +++ b/packages/client/test/editorApp/editorApp.wrongservices.test.ts @@ -9,18 +9,16 @@ import { describe, expect, test } from 'vitest'; import { createDefaultMonacoVscodeApiConfig, createEditorAppConfig, createMonacoEditorDiv } from '../support/helper.js'; describe('Test EditorApp', () => { + test('Start EditorApp with no services', async () => { + const htmlContainer = createMonacoEditorDiv(); + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'ViewsService'); + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await apiWrapper.start(); - test('Start EditorApp with no services', async () => { - const htmlContainer = createMonacoEditorDiv(); - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'ViewsService'); - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await apiWrapper.start(); - - const editorAppConfig = createEditorAppConfig({}); - const editorApp = new EditorApp(editorAppConfig); - await expect(async () => { - await editorApp.start(htmlContainer); - }).rejects.toThrowError('No EditorService configured. monaco-editor will not be started.'); - }); - + const editorAppConfig = createEditorAppConfig({}); + const editorApp = new EditorApp(editorAppConfig); + await expect(async () => { + await editorApp.start(htmlContainer); + }).rejects.toThrowError('No EditorService configured. monaco-editor will not be started.'); + }); }); diff --git a/packages/client/test/fs/endpoints/emptyEndpoint.test.ts b/packages/client/test/fs/endpoints/emptyEndpoint.test.ts index 33495d216..12a9e44ea 100644 --- a/packages/client/test/fs/endpoints/emptyEndpoint.test.ts +++ b/packages/client/test/fs/endpoints/emptyEndpoint.test.ts @@ -7,52 +7,50 @@ import { EmptyFileSystemEndpoint } from 'monaco-languageclient/fs'; import { describe, expect, test } from 'vitest'; describe('EmptyFileSystemEndpoint Tests', () => { + const endpoint = new EmptyFileSystemEndpoint('EMPTY'); - const endpoint = new EmptyFileSystemEndpoint('EMPTY'); - - test('readFile', async () => { - const result = await endpoint.readFile({ resourceUri: '/tmp/test.js' }); - expect(result).toEqual({ - status: 'denied', - content: '' - }); + test('readFile', async () => { + const result = await endpoint.readFile({ resourceUri: '/tmp/test.js' }); + expect(result).toEqual({ + status: 'denied', + content: '' }); + }); - test('writeFile', async () => { - const result = await endpoint.writeFile({ - resourceUri: '/tmp/test.js', - content: 'const text = "Hello World!";' - }); - expect(result).toEqual({ - status: 'denied' - }); + test('writeFile', async () => { + const result = await endpoint.writeFile({ + resourceUri: '/tmp/test.js', + content: 'const text = "Hello World!";' }); - - test('syncFile', async () => { - const result = await endpoint.syncFile({ - resourceUri: '/tmp/test.js', - content: 'const text = "Hello World!";' - }); - expect(result).toEqual({ - status: 'denied' - }); + expect(result).toEqual({ + status: 'denied' }); + }); - test('getFileStats', async () => { - await expect(async () => { - await endpoint.getFileStats({ - type: 'file', - resourceUri: '/tmp/test.js' - }); - }).rejects.toThrowError('No stats available.'); + test('syncFile', async () => { + const result = await endpoint.syncFile({ + resourceUri: '/tmp/test.js', + content: 'const text = "Hello World!";' }); - - test('listFiles', async () => { - await expect(async () => { - await endpoint.listFiles({ - directoryUri: '/tmp' - }); - }).rejects.toThrowError('No file listing possible.'); + expect(result).toEqual({ + status: 'denied' }); - + }); + + test('getFileStats', async () => { + await expect(async () => { + await endpoint.getFileStats({ + type: 'file', + resourceUri: '/tmp/test.js' + }); + }).rejects.toThrowError('No stats available.'); + }); + + test('listFiles', async () => { + await expect(async () => { + await endpoint.listFiles({ + directoryUri: '/tmp' + }); + }).rejects.toThrowError('No file listing possible.'); + }); }); diff --git a/packages/client/test/support/helper-classic.ts b/packages/client/test/support/helper-classic.ts index 9980d65cc..859c81f4b 100644 --- a/packages/client/test/support/helper-classic.ts +++ b/packages/client/test/support/helper-classic.ts @@ -9,76 +9,63 @@ import { useWorkerFactory, Worker, type WorkerLoader } from 'monaco-languageclie const workerResolver: Map) => void> = new Map(); const workerPromises: Map> = new Map(); export const createWorkerPromises = (keys: string[]) => { - workerResolver.clear(); - workerPromises.clear(); - for (const key of keys) { - const promise = new Promise(resolve => { - workerResolver.set(key, resolve); - }); - workerPromises.set(key, promise); - } + workerResolver.clear(); + workerPromises.clear(); + for (const key of keys) { + const promise = new Promise((resolve) => { + workerResolver.set(key, resolve); + }); + workerPromises.set(key, promise); + } }; export const awaitWorkerPromises = () => { - return Promise.all([...workerPromises.values()]); + return Promise.all([...workerPromises.values()]); }; export const pushAndPrintLastWorker = (lastWorker: string) => { - console.log(`Called: ${lastWorker}`); - workerResolver.get(lastWorker)?.(); + console.log(`Called: ${lastWorker}`); + workerResolver.get(lastWorker)?.(); }; export const defineClassicWorkers: () => Partial> = () => { - const editorWorkerServiceWorker = () => { - pushAndPrintLastWorker('editorWorker'); - return new Worker( - new URL('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js', import.meta.url), - { type: 'module' } - ); - }; - const cssWorker = () => { - pushAndPrintLastWorker('cssWorker'); - return new Worker( - new URL('@codingame/monaco-vscode-standalone-css-language-features', import.meta.url), - { type: 'module' } - ); - }; - const jsonWorker = () => { - pushAndPrintLastWorker('jsonWorker'); - return new Worker( - new URL('@codingame/monaco-vscode-standalone-json-language-features', import.meta.url), - { type: 'module' } - ); - }; - const htmlWorker = () => { - pushAndPrintLastWorker('htmlWorker'); - return new Worker( - new URL('@codingame/monaco-vscode-standalone-html-language-features', import.meta.url), - { type: 'module' } - ); - }; - const tsWorker = () => { - pushAndPrintLastWorker('tsWorker'); - return new Worker( - new URL('@codingame/monaco-vscode-standalone-typescript-language-features', import.meta.url), - { type: 'module' } - ); - }; + const editorWorkerServiceWorker = () => { + pushAndPrintLastWorker('editorWorker'); + return new Worker(new URL('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js', import.meta.url), { + type: 'module' + }); + }; + const cssWorker = () => { + pushAndPrintLastWorker('cssWorker'); + return new Worker(new URL('@codingame/monaco-vscode-standalone-css-language-features', import.meta.url), { type: 'module' }); + }; + const jsonWorker = () => { + pushAndPrintLastWorker('jsonWorker'); + return new Worker(new URL('@codingame/monaco-vscode-standalone-json-language-features', import.meta.url), { type: 'module' }); + }; + const htmlWorker = () => { + pushAndPrintLastWorker('htmlWorker'); + return new Worker(new URL('@codingame/monaco-vscode-standalone-html-language-features', import.meta.url), { type: 'module' }); + }; + const tsWorker = () => { + pushAndPrintLastWorker('tsWorker'); + return new Worker(new URL('@codingame/monaco-vscode-standalone-typescript-language-features', import.meta.url), { type: 'module' }); + }; - return { - editorWorkerService: editorWorkerServiceWorker, - css: cssWorker, - html: htmlWorker, - json: jsonWorker, - // both have to be defined otherwise this leads to a test error - javascript: tsWorker, - typescript: tsWorker - }; + return { + editorWorkerService: editorWorkerServiceWorker, + css: cssWorker, + html: htmlWorker, + json: jsonWorker, + // both have to be defined otherwise this leads to a test error + javascript: tsWorker, + typescript: tsWorker + }; }; export const configureClassicWorkerFactory = (logger?: ILogger) => { - useWorkerFactory({ - workerLoaders: defineClassicWorkers(), - logger - }); + useWorkerFactory({ + workerLoaders: defineClassicWorkers(), + logger + }); }; diff --git a/packages/client/test/support/helper.ts b/packages/client/test/support/helper.ts index d890bc5d2..4c3187bda 100644 --- a/packages/client/test/support/helper.ts +++ b/packages/client/test/support/helper.ts @@ -10,83 +10,90 @@ import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFacto import { MessageTransports } from 'vscode-languageclient/browser.js'; export const createMonacoEditorDiv = () => { - const div = document.createElement('div'); - div.id = 'monaco-editor-root'; - document.body.insertAdjacentElement('beforeend', div); - return div; + const div = document.createElement('div'); + div.id = 'monaco-editor-root'; + document.body.insertAdjacentElement('beforeend', div); + return div; }; -export const createDefaultLcWorkerConfig = (worker: Worker, languageId: string, - messageTransports?: MessageTransports): LanguageClientConfig => { - return { - languageId, - clientOptions: { - documentSelector: [languageId] - }, - connection: { - options: { - $type: 'WorkerDirect', - worker - }, - messageTransports - } - }; +export const createDefaultLcWorkerConfig = ( + worker: Worker, + languageId: string, + messageTransports?: MessageTransports +): LanguageClientConfig => { + return { + languageId, + clientOptions: { + documentSelector: [languageId] + }, + connection: { + options: { + $type: 'WorkerDirect', + worker + }, + messageTransports + } + }; }; export const createUnreachableWorkerConfig = (): LanguageClientConfig => { - return { - languageId: 'javascript', - clientOptions: { - documentSelector: ['javascript'] - }, - connection: { - options: { - $type: 'WorkerConfig', - url: new URL(`${import.meta.url.split('@fs')[0]}/unknown.ts`), - type: 'module' - } - } - }; + return { + languageId: 'javascript', + clientOptions: { + documentSelector: ['javascript'] + }, + connection: { + options: { + $type: 'WorkerConfig', + url: new URL(`${import.meta.url.split('@fs')[0]}/unknown.ts`), + type: 'module' + } + } + }; }; export const createDefaultLcUnreachableUrlConfig = (port: number): LanguageClientConfig => { - return { - languageId: 'javascript', - clientOptions: { - documentSelector: ['javascript'] - }, - connection: { - options: { - $type: 'WebSocketUrl', - url: `ws://localhost:${port}/rester` - }, - } - }; + return { + languageId: 'javascript', + clientOptions: { + documentSelector: ['javascript'] + }, + connection: { + options: { + $type: 'WebSocketUrl', + url: `ws://localhost:${port}/rester` + } + } + }; }; export const createEditorAppConfig = (codeResources: CodeResources): EditorAppConfig => { - return { - codeResources, - editorOptions: {} - }; + return { + codeResources, + editorOptions: {} + }; }; -export const createDefaultMonacoVscodeApiConfig = (overallConfigType: OverallConfigType, htmlContainer: HTMLElement | undefined, viewsConfigType: ViewsConfigTypes): MonacoVscodeApiConfig => { - return { - $type: overallConfigType, - advanced: { - enforceSemanticHighlighting: true, - loadThemes: false - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern' - }) - }, - viewsConfig: { - $type: viewsConfigType, - htmlContainer - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; +export const createDefaultMonacoVscodeApiConfig = ( + overallConfigType: OverallConfigType, + htmlContainer: HTMLElement | undefined, + viewsConfigType: ViewsConfigTypes +): MonacoVscodeApiConfig => { + return { + $type: overallConfigType, + advanced: { + enforceSemanticHighlighting: true, + loadThemes: false + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern' + }) + }, + viewsConfig: { + $type: viewsConfigType, + htmlContainer + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; }; diff --git a/packages/client/test/vscode/manager.editorservice.test.ts b/packages/client/test/vscode/manager.editorservice.test.ts index 8afed856d..dff86d0b1 100644 --- a/packages/client/test/vscode/manager.editorservice.test.ts +++ b/packages/client/test/vscode/manager.editorservice.test.ts @@ -10,16 +10,14 @@ import { describe, expect, test } from 'vitest'; import { createDefaultMonacoVscodeApiConfig } from '../support/helper.js'; describe('MonacoVscodeApiWrapper Tests: Different config', () => { + test('Start MonacoVscodeApiWrapper with EditorService but no htmlContainer', async () => { + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', undefined, 'EditorService'); - test('Start MonacoVscodeApiWrapper with EditorService but no htmlContainer', async () => { - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', undefined, 'EditorService'); - - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig!); - const awaited = await apiWrapper.start(); - expect(awaited).toBeUndefined(); - - // oxlint-disable-next-line dot-notation - expect((apiWrapper['logger'] as ILogger).getLevel()).toBe(LogLevel.Off); - }); + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig!); + const awaited = await apiWrapper.start(); + expect(awaited).toBeUndefined(); + // oxlint-disable-next-line dot-notation + expect((apiWrapper['logger'] as ILogger).getLevel()).toBe(LogLevel.Off); + }); }); diff --git a/packages/client/test/vscode/manager.test.ts b/packages/client/test/vscode/manager.test.ts index 467c5a3fa..d0bc02b4d 100644 --- a/packages/client/test/vscode/manager.test.ts +++ b/packages/client/test/vscode/manager.test.ts @@ -11,116 +11,124 @@ import { getEnhancedMonacoEnvironment, MonacoVscodeApiWrapper } from 'monaco-lan import { createDefaultMonacoVscodeApiConfig, createMonacoEditorDiv } from '../support/helper.js'; describe('MonacoVscodeApiWrapper Tests', () => { - - let apiWrapper: MonacoVscodeApiWrapper; - const htmlContainer = createMonacoEditorDiv(); - - beforeAll(() => { - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'EditorService'); - apiConfig.extensions = [{ - config: { - name: 'unit-test-extension', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - }, - contributes: { - languages: [{ - id: 'js', - extensions: ['.js'], - configuration: './language-configuration.json' - }], - grammars: [{ - language: 'js', - scopeName: 'source.js', - path: './javascript.tmLanguage.json' - }] - } - }, - filesOrContents: new Map([ - ['/language-configuration.json', '{}'], - ['/javascript.tmLanguage.json', '{}'] - ]), - }]; - apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - }); - - test.sequential('test init MonacoVscodeApiWrapper and gloabl state', async () => { - expect(typeof MonacoEnvironment === 'undefined').toBeTruthy(); - - // call init with api config - const promise = apiWrapper.start(); - let envEnhanced = getEnhancedMonacoEnvironment(); - expect(envEnhanced.vscodeApiGlobalInitAwait).toBeDefined(); - expect(envEnhanced.vscodeApiGlobalInitResolve).toBeDefined(); - expect(envEnhanced.vscodeApiInitialised).toBeFalsy(); - - // wait for the initial promise to complete and expect that api init was completed and is no longer ongoing - expect(await promise).toBeUndefined(); - envEnhanced = getEnhancedMonacoEnvironment(); - expect(envEnhanced.vscodeApiGlobalInitAwait).toBeUndefined(); - expect(envEnhanced.vscodeApiGlobalInitResolve).toBeUndefined(); - expect(envEnhanced.vscodeApiInitialised).toBeTruthy(); - expect(envEnhanced.viewServiceType).toBe('EditorService'); - expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.developmentOptions?.logLevel).toBe(LogLevel.Off); - }); - - test.sequential('test configureServices logLevel and developmenet info', () => { - const apiConfig = apiWrapper.getMonacoVscodeApiConfig(); - apiConfig.logLevel = LogLevel.Info; - apiConfig.workspaceConfig = { - ...apiConfig.workspaceConfig, - developmentOptions: { - logLevel: LogLevel.Info - } - }; - - apiWrapper['configureDevLogLevel'](); - expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.developmentOptions?.logLevel).toBe(LogLevel.Info); - }); - - test.sequential('test configureServices logLevel and developmenet debug', () => { - const apiConfig = apiWrapper.getMonacoVscodeApiConfig(); - apiConfig.logLevel = LogLevel.Debug; - apiConfig.workspaceConfig = { - ...apiConfig.workspaceConfig, - developmentOptions: { - logLevel: LogLevel.Debug - } - }; - - apiWrapper['configureDevLogLevel'](); - expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.developmentOptions?.logLevel).toBe(LogLevel.Debug); - }); - - test.sequential('test configureServices logLevel development mismatch', () => { - const apiConfig = apiWrapper.getMonacoVscodeApiConfig(); - apiConfig.logLevel = LogLevel.Trace; - apiConfig.workspaceConfig = { - ...apiConfig.workspaceConfig, - developmentOptions: { - logLevel: LogLevel.Info - } - }; - - expect(() => apiWrapper['configureDevLogLevel']()).toThrowError('You have configured mismatching logLevels: 1 (wrapperConfig) 3 (workspaceConfig.developmentOptions)'); - }); - - test.sequential('test semanticHighlighting.enabled workaround', async () => { - expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.configurationDefaults?.['editor.semanticHighlighting.enabled']).toEqual(true); - - const semHigh = await new Promise(resolve => { - setTimeout(() => { - resolve(StandaloneServices.get(IConfigurationService).getValue('editor.semanticHighlighting.enabled')); - }, 100); - }); - expect(semHigh).toEqual(true); - }); - - test.sequential('test dispose extensions and re-init', async () => { - expect(() => apiWrapper.dispose()).not.toThrowError(); - expect(await apiWrapper.initExtensions()).toBeUndefined(); + let apiWrapper: MonacoVscodeApiWrapper; + const htmlContainer = createMonacoEditorDiv(); + + beforeAll(() => { + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'EditorService'); + apiConfig.extensions = [ + { + config: { + name: 'unit-test-extension', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [ + { + id: 'js', + extensions: ['.js'], + configuration: './language-configuration.json' + } + ], + grammars: [ + { + language: 'js', + scopeName: 'source.js', + path: './javascript.tmLanguage.json' + } + ] + } + }, + filesOrContents: new Map([ + ['/language-configuration.json', '{}'], + ['/javascript.tmLanguage.json', '{}'] + ]) + } + ]; + apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + }); + + test.sequential('test init MonacoVscodeApiWrapper and gloabl state', async () => { + expect(typeof MonacoEnvironment === 'undefined').toBeTruthy(); + + // call init with api config + const promise = apiWrapper.start(); + let envEnhanced = getEnhancedMonacoEnvironment(); + expect(envEnhanced.vscodeApiGlobalInitAwait).toBeDefined(); + expect(envEnhanced.vscodeApiGlobalInitResolve).toBeDefined(); + expect(envEnhanced.vscodeApiInitialised).toBeFalsy(); + + // wait for the initial promise to complete and expect that api init was completed and is no longer ongoing + expect(await promise).toBeUndefined(); + envEnhanced = getEnhancedMonacoEnvironment(); + expect(envEnhanced.vscodeApiGlobalInitAwait).toBeUndefined(); + expect(envEnhanced.vscodeApiGlobalInitResolve).toBeUndefined(); + expect(envEnhanced.vscodeApiInitialised).toBeTruthy(); + expect(envEnhanced.viewServiceType).toBe('EditorService'); + expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.developmentOptions?.logLevel).toBe(LogLevel.Off); + }); + + test.sequential('test configureServices logLevel and developmenet info', () => { + const apiConfig = apiWrapper.getMonacoVscodeApiConfig(); + apiConfig.logLevel = LogLevel.Info; + apiConfig.workspaceConfig = { + ...apiConfig.workspaceConfig, + developmentOptions: { + logLevel: LogLevel.Info + } + }; + + apiWrapper['configureDevLogLevel'](); + expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.developmentOptions?.logLevel).toBe(LogLevel.Info); + }); + + test.sequential('test configureServices logLevel and developmenet debug', () => { + const apiConfig = apiWrapper.getMonacoVscodeApiConfig(); + apiConfig.logLevel = LogLevel.Debug; + apiConfig.workspaceConfig = { + ...apiConfig.workspaceConfig, + developmentOptions: { + logLevel: LogLevel.Debug + } + }; + + apiWrapper['configureDevLogLevel'](); + expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.developmentOptions?.logLevel).toBe(LogLevel.Debug); + }); + + test.sequential('test configureServices logLevel development mismatch', () => { + const apiConfig = apiWrapper.getMonacoVscodeApiConfig(); + apiConfig.logLevel = LogLevel.Trace; + apiConfig.workspaceConfig = { + ...apiConfig.workspaceConfig, + developmentOptions: { + logLevel: LogLevel.Info + } + }; + + expect(() => apiWrapper['configureDevLogLevel']()).toThrowError( + 'You have configured mismatching logLevels: 1 (wrapperConfig) 3 (workspaceConfig.developmentOptions)' + ); + }); + + test.sequential('test semanticHighlighting.enabled workaround', async () => { + expect(apiWrapper.getMonacoVscodeApiConfig().workspaceConfig?.configurationDefaults?.['editor.semanticHighlighting.enabled']).toEqual( + true + ); + + const semHigh = await new Promise((resolve) => { + setTimeout(() => { + resolve(StandaloneServices.get(IConfigurationService).getValue('editor.semanticHighlighting.enabled')); + }, 100); }); + expect(semHigh).toEqual(true); + }); + test.sequential('test dispose extensions and re-init', async () => { + expect(() => apiWrapper.dispose()).not.toThrowError(); + expect(await apiWrapper.initExtensions()).toBeUndefined(); + }); }); diff --git a/packages/client/test/vscode/manager.viewsserivce.test.ts b/packages/client/test/vscode/manager.viewsserivce.test.ts index 42c87d3e4..955f89d97 100644 --- a/packages/client/test/vscode/manager.viewsserivce.test.ts +++ b/packages/client/test/vscode/manager.viewsserivce.test.ts @@ -7,14 +7,12 @@ import { describe, expect, test } from 'vitest'; import { createDefaultMonacoVscodeApiConfig } from '../support/helper.js'; describe('MonacoVscodeApiWrapper Tests: Different config', () => { + test('Start MonacoVscodeApiWrapper with ViewsService but no htmlContainer', async () => { + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', undefined, 'ViewsService'); - test('Start MonacoVscodeApiWrapper with ViewsService but no htmlContainer', async () => { - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', undefined, 'ViewsService'); - - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await expect(async () => { - await apiWrapper.start(); - }).rejects.toThrowError('View Service Type "ViewsService" requires a HTMLElement.'); - }); - + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await expect(async () => { + await apiWrapper.start(); + }).rejects.toThrowError('View Service Type "ViewsService" requires a HTMLElement.'); + }); }); diff --git a/packages/client/test/vscode/manager.workbenchserivce.test.ts b/packages/client/test/vscode/manager.workbenchserivce.test.ts index a47c95c1e..f43a272a0 100644 --- a/packages/client/test/vscode/manager.workbenchserivce.test.ts +++ b/packages/client/test/vscode/manager.workbenchserivce.test.ts @@ -7,14 +7,12 @@ import { describe, expect, test } from 'vitest'; import { createDefaultMonacoVscodeApiConfig } from '../support/helper.js'; describe('MonacoVscodeApiWrapper Tests: Different config', () => { + test('Start MonacoVscodeApiWrapper with WorkbenchService but no htmlContainer', async () => { + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', undefined, 'WorkbenchService'); - test('Start MonacoVscodeApiWrapper with WorkbenchService but no htmlContainer', async () => { - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', undefined, 'WorkbenchService'); - - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await expect(async () => { - await apiWrapper.start(); - }).rejects.toThrowError('View Service Type "WorkbenchService" requires a HTMLElement.'); - }); - + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await expect(async () => { + await apiWrapper.start(); + }).rejects.toThrowError('View Service Type "WorkbenchService" requires a HTMLElement.'); + }); }); diff --git a/packages/client/test/worker/workerFactory.test.ts b/packages/client/test/worker/workerFactory.test.ts index cddfe8f7f..61dd82c34 100644 --- a/packages/client/test/worker/workerFactory.test.ts +++ b/packages/client/test/worker/workerFactory.test.ts @@ -10,34 +10,31 @@ import { useWorkerFactory, Worker } from 'monaco-languageclient/workerFactory'; import { describe, expect, test } from 'vitest'; describe('WorkerFactory Tests', () => { - - test('useWorkerFactory: Nothing', () => { - - useWorkerFactory({}); - - const worker = getEnhancedMonacoEnvironment().getWorker?.('test', 'TextEditorWorker'); - expect(worker).toBeUndefined(); - const workerUrl = getEnhancedMonacoEnvironment().getWorkerUrl?.('test', 'TextEditorWorker'); - expect(workerUrl).toBeUndefined(); - }); - - test('useWorkerFactory: TextEditorWorker', async () => { - const logger = new ConsoleLogger(LogLevel.Info); - - useWorkerFactory({ - workerLoaders: { - editorWorkerService: () => new Worker( - new URL('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js', import.meta.url), - { type: 'module' } - ) - }, - logger - }); - - const workerUrl = getEnhancedMonacoEnvironment().getWorkerUrl?.('test', 'editorWorkerService'); - expect(workerUrl).contains('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js?worker_file&type=module'); - const workerOptions = getEnhancedMonacoEnvironment().getWorkerOptions?.('test', 'editorWorkerService'); - expect(workerOptions).toEqual({ type: 'module' }); + test('useWorkerFactory: Nothing', () => { + useWorkerFactory({}); + + const worker = getEnhancedMonacoEnvironment().getWorker?.('test', 'TextEditorWorker'); + expect(worker).toBeUndefined(); + const workerUrl = getEnhancedMonacoEnvironment().getWorkerUrl?.('test', 'TextEditorWorker'); + expect(workerUrl).toBeUndefined(); + }); + + test('useWorkerFactory: TextEditorWorker', async () => { + const logger = new ConsoleLogger(LogLevel.Info); + + useWorkerFactory({ + workerLoaders: { + editorWorkerService: () => + new Worker(new URL('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js', import.meta.url), { + type: 'module' + }) + }, + logger }); + const workerUrl = getEnhancedMonacoEnvironment().getWorkerUrl?.('test', 'editorWorkerService'); + expect(workerUrl).contains('@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js?worker_file&type=module'); + const workerOptions = getEnhancedMonacoEnvironment().getWorkerOptions?.('test', 'editorWorkerService'); + expect(workerOptions).toEqual({ type: 'module' }); + }); }); diff --git a/packages/client/test/worker/workerLoaders.test.ts b/packages/client/test/worker/workerLoaders.test.ts index 68a30fa0e..001e6050e 100644 --- a/packages/client/test/worker/workerLoaders.test.ts +++ b/packages/client/test/worker/workerLoaders.test.ts @@ -17,55 +17,53 @@ import { createDefaultMonacoVscodeApiConfig, createMonacoEditorDiv } from '../su import { createModelReference } from '@codingame/monaco-vscode-api/monaco'; describe.sequential('Test WorkerLoaders', () => { + let editor: monaco.editor.IStandaloneCodeEditor; + const htmlContainer = createMonacoEditorDiv(); - let editor: monaco.editor.IStandaloneCodeEditor; - const htmlContainer = createMonacoEditorDiv(); + beforeAll(async () => { + const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'EditorService'); + apiConfig.monacoWorkerFactory = configureClassicWorkerFactory; + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await apiWrapper.start(); - beforeAll(async () => { - const apiConfig = createDefaultMonacoVscodeApiConfig('extended', htmlContainer, 'EditorService'); - apiConfig.monacoWorkerFactory = configureClassicWorkerFactory; - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await apiWrapper.start(); - - editor = monaco.editor.create(htmlContainer, { - value: 'const text = "Hello World!";', - language: 'javascript' - }); + editor = monaco.editor.create(htmlContainer, { + value: 'const text = "Hello World!";', + language: 'javascript' }); + }); - test('Test default worker application', async () => { - // default, expect editor and ts worker to be loaded - createWorkerPromises(['editorWorker', 'tsWorker']); - expect(await awaitWorkerPromises()).toStrictEqual([undefined, undefined]); - }); + test('Test default worker application', async () => { + // default, expect editor and ts worker to be loaded + createWorkerPromises(['editorWorker', 'tsWorker']); + expect(await awaitWorkerPromises()).toStrictEqual([undefined, undefined]); + }); - test('Test TS worker application', async () => { - // ts worker, expect no worker to be loaded - createWorkerPromises([]); - const modelRefTs = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.ts`), ''); - editor.setModel(modelRefTs.object.textEditorModel); - expect(await awaitWorkerPromises()).toStrictEqual([]); - }); + test('Test TS worker application', async () => { + // ts worker, expect no worker to be loaded + createWorkerPromises([]); + const modelRefTs = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.ts`), ''); + editor.setModel(modelRefTs.object.textEditorModel); + expect(await awaitWorkerPromises()).toStrictEqual([]); + }); - test('Test CSS worker application', async () => { - createWorkerPromises(['cssWorker']); - const modelRefCss = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.css`), ''); - editor.setModel(modelRefCss.object.textEditorModel); - expect(await awaitWorkerPromises()).toStrictEqual([undefined]); - }); + test('Test CSS worker application', async () => { + createWorkerPromises(['cssWorker']); + const modelRefCss = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.css`), ''); + editor.setModel(modelRefCss.object.textEditorModel); + expect(await awaitWorkerPromises()).toStrictEqual([undefined]); + }); - test('Test JSON worker application', async () => { - createWorkerPromises(['jsonWorker']); - const modelRefJson = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.json`), ''); - editor.setModel(modelRefJson.object.textEditorModel); - expect(await awaitWorkerPromises()).toStrictEqual([undefined]); - }); - - test('Test HTML worker application', async () => { - createWorkerPromises(['htmlWorker']); - const modelRefHtml = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.html`), ''); - editor.setModel(modelRefHtml.object.textEditorModel); - expect(await awaitWorkerPromises()).toStrictEqual([undefined]); - }); + test('Test JSON worker application', async () => { + createWorkerPromises(['jsonWorker']); + const modelRefJson = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.json`), ''); + editor.setModel(modelRefJson.object.textEditorModel); + expect(await awaitWorkerPromises()).toStrictEqual([undefined]); + }); + test('Test HTML worker application', async () => { + createWorkerPromises(['htmlWorker']); + const modelRefHtml = await createModelReference(monaco.Uri.parse(`/workspace/${expect.getState().testPath}.html`), ''); + editor.setModel(modelRefHtml.object.textEditorModel); + expect(await awaitWorkerPromises()).toStrictEqual([undefined]); + }); }); diff --git a/packages/client/test/wrapper/lcmanager.test.ts b/packages/client/test/wrapper/lcmanager.test.ts index 66b002b8c..97122af24 100644 --- a/packages/client/test/wrapper/lcmanager.test.ts +++ b/packages/client/test/wrapper/lcmanager.test.ts @@ -15,76 +15,74 @@ import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageclien import { createDefaultLcWorkerConfig, createMonacoEditorDiv } from '../support/helper.js'; describe('Test LanguageClientWrapper', () => { - - beforeAll(async () => { - const apiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer: createMonacoEditorDiv() - } - }; - const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); - await apiWrapper.start(); - }); - - test('restart with languageclient', async () => { - let error = false; - const lcManager = new LanguageClientManager(); - - const workerUrl = new URL('monaco-languageclient-examples/worker/langium', import.meta.url); - const worker = new Worker(workerUrl, { - type: 'module', - name: 'Langium LS (Regular Test)' - }); - expect(worker).toBeDefined(); - - const reader = new BrowserMessageReader(worker); - const writer = new BrowserMessageWriter(worker); - const languageClientConfig = createDefaultLcWorkerConfig(worker, 'langium', { reader, writer }); - - const lcConfigs = { - configs: { - 'langium': languageClientConfig - } - }; - - try { - expect(async () => lcManager.setConfigs(lcConfigs)).not.toThrowError(); - expect(async () => await lcManager.start()).not.toThrowError(); - expect(async () => await lcManager.dispose()).not.toThrowError(); - - await delayExecution(1000); - - expect(async () => lcManager.setConfigs(lcConfigs)).not.toThrowError(); - expect(async () => await lcManager.start()).not.toThrowError(); - expect(async () => await lcManager.dispose()).not.toThrowError(); - } catch (e: unknown) { - const message = e instanceof Error ? e.message : String(e); - console.error(`Unexpected error occurred: ${message}`); - error = true; - } - - expect(error).toBe(false); - }); - - test('set verify log levels are applied', async () => { - const lcsManager = new LanguageClientManager(); - let logLevel = (lcsManager['logger'] as ILogger).getLevel(); - expect(logLevel).toBe(LogLevel.Info); - expect(logLevel).toBe(3); - - lcsManager.setLogLevel(LogLevel.Debug); - logLevel = (lcsManager['logger'] as ILogger).getLevel(); - expect(logLevel).toBe(LogLevel.Debug); - expect(logLevel).toBe(2); - }); - - test('Check started to be false if nothing is configured', async () => { - const lcsManager = new LanguageClientManager(); - expect(lcsManager.haveLanguageClients()).toBe(false); - expect(lcsManager['languageClientWrappers'].size).toBe(0); - expect(lcsManager.isStarted()).toBe(false); + beforeAll(async () => { + const apiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer: createMonacoEditorDiv() + } + }; + const apiWrapper = new MonacoVscodeApiWrapper(apiConfig); + await apiWrapper.start(); + }); + + test('restart with languageclient', async () => { + let error = false; + const lcManager = new LanguageClientManager(); + + const workerUrl = new URL('monaco-languageclient-examples/worker/langium', import.meta.url); + const worker = new Worker(workerUrl, { + type: 'module', + name: 'Langium LS (Regular Test)' }); - + expect(worker).toBeDefined(); + + const reader = new BrowserMessageReader(worker); + const writer = new BrowserMessageWriter(worker); + const languageClientConfig = createDefaultLcWorkerConfig(worker, 'langium', { reader, writer }); + + const lcConfigs = { + configs: { + langium: languageClientConfig + } + }; + + try { + expect(async () => lcManager.setConfigs(lcConfigs)).not.toThrowError(); + expect(async () => await lcManager.start()).not.toThrowError(); + expect(async () => await lcManager.dispose()).not.toThrowError(); + + await delayExecution(1000); + + expect(async () => lcManager.setConfigs(lcConfigs)).not.toThrowError(); + expect(async () => await lcManager.start()).not.toThrowError(); + expect(async () => await lcManager.dispose()).not.toThrowError(); + } catch (e: unknown) { + const message = e instanceof Error ? e.message : String(e); + console.error(`Unexpected error occurred: ${message}`); + error = true; + } + + expect(error).toBe(false); + }); + + test('set verify log levels are applied', async () => { + const lcsManager = new LanguageClientManager(); + let logLevel = (lcsManager['logger'] as ILogger).getLevel(); + expect(logLevel).toBe(LogLevel.Info); + expect(logLevel).toBe(3); + + lcsManager.setLogLevel(LogLevel.Debug); + logLevel = (lcsManager['logger'] as ILogger).getLevel(); + expect(logLevel).toBe(LogLevel.Debug); + expect(logLevel).toBe(2); + }); + + test('Check started to be false if nothing is configured', async () => { + const lcsManager = new LanguageClientManager(); + expect(lcsManager.haveLanguageClients()).toBe(false); + expect(lcsManager['languageClientWrappers'].size).toBe(0); + expect(lcsManager.isStarted()).toBe(false); + }); }); diff --git a/packages/client/test/wrapper/lcwrapper.test.ts b/packages/client/test/wrapper/lcwrapper.test.ts index 6544e22c1..c4b600494 100644 --- a/packages/client/test/wrapper/lcwrapper.test.ts +++ b/packages/client/test/wrapper/lcwrapper.test.ts @@ -11,146 +11,149 @@ import { LanguageClientWrapper } from 'monaco-languageclient/lcwrapper'; import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; import { beforeAll, describe, expect, test } from 'vitest'; import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageclient/browser.js'; -import { createDefaultLcUnreachableUrlConfig, createDefaultLcWorkerConfig, createMonacoEditorDiv, createUnreachableWorkerConfig } from '../support/helper.js'; +import { + createDefaultLcUnreachableUrlConfig, + createDefaultLcWorkerConfig, + createMonacoEditorDiv, + createUnreachableWorkerConfig +} from '../support/helper.js'; describe('Test LanguageClientWrapper', () => { - - beforeAll(async () => { - const apiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer: createMonacoEditorDiv() - } - }; - const monacoVscodeApiManager = new MonacoVscodeApiWrapper(apiConfig); - await monacoVscodeApiManager.start(); - }); - - const createWorkerAndConfig = () => { - const workerUrl = 'monaco-languageclient-examples/worker/langium'; - const worker = new Worker(workerUrl, { - type: 'module', - name: 'Langium LS' - }); - - const reader = new BrowserMessageReader(worker); - const writer = new BrowserMessageWriter(worker); - reader.listen((message) => { - console.log('Received message from worker:', message); - }); - const languageClientConfig = createDefaultLcWorkerConfig(worker, 'langium', { reader, writer }); - languageClientConfig.disposeWorker = true; - return { - worker, - languageClientConfig - }; + beforeAll(async () => { + const apiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer: createMonacoEditorDiv() + } }; - - test('Constructor: no config', () => { - const workerAndConfig = createWorkerAndConfig(); - const languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); - expect(languageClientWrapper.haveLanguageClient()).toBeFalsy(); - }); - - test('Dispose: direct worker is cleaned up afterwards', async () => { - const workerAndConfig = createWorkerAndConfig(); - const languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); - - expect(workerAndConfig.worker).toBeDefined(); - expect(languageClientWrapper.getWorker()).toBeUndefined(); - - // WA: language client in fails due to vitest (reason not clear, yet) - try { - await languageClientWrapper.start(); - } catch (_error) { - // ignore - }; - - expect(languageClientWrapper.getWorker()).toBeTruthy(); - - // dispose & verify - await languageClientWrapper.dispose(); - expect(languageClientWrapper.getWorker()).toBeUndefined(); + const monacoVscodeApiManager = new MonacoVscodeApiWrapper(apiConfig); + await monacoVscodeApiManager.start(); + }); + + const createWorkerAndConfig = () => { + const workerUrl = 'monaco-languageclient-examples/worker/langium'; + const worker = new Worker(workerUrl, { + type: 'module', + name: 'Langium LS' }); - test('Start: unreachable url', async () => { - const languageClientConfig = createDefaultLcUnreachableUrlConfig(23456); - const languageClientWrapper = new LanguageClientWrapper(languageClientConfig); - - try { - await languageClientWrapper.start(); - } catch (error) { - expect(error).toEqual({ - message: 'languageClientWrapper (javascript): Websocket connection failed.', - error: 'No error was provided.' - }); - } + const reader = new BrowserMessageReader(worker); + const writer = new BrowserMessageWriter(worker); + reader.listen((message) => { + console.log('Received message from worker:', message); }); - - test('Only unreachable worker url', async () => { - const prom = new Promise((_resolve, reject) => { - const worker = new Worker('aBogusUrl'); - - worker.onerror = () => { - reject('error'); - }; - }); - await expect(prom).rejects.toEqual('error'); - }); - - test('Start: unreachable worker url', async () => { - const languageClientConfig = createUnreachableWorkerConfig(); - const languageClientWrapper = new LanguageClientWrapper(languageClientConfig); - - await expect(languageClientWrapper.start()).rejects.toEqual({ - message: 'languageClientWrapper (javascript): Illegal worker configuration detected.', - error: 'No error was provided.' - }); + const languageClientConfig = createDefaultLcWorkerConfig(worker, 'langium', { reader, writer }); + languageClientConfig.disposeWorker = true; + return { + worker, + languageClientConfig + }; + }; + + test('Constructor: no config', () => { + const workerAndConfig = createWorkerAndConfig(); + const languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); + expect(languageClientWrapper.haveLanguageClient()).toBeFalsy(); + }); + + test('Dispose: direct worker is cleaned up afterwards', async () => { + const workerAndConfig = createWorkerAndConfig(); + const languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); + + expect(workerAndConfig.worker).toBeDefined(); + expect(languageClientWrapper.getWorker()).toBeUndefined(); + + // WA: language client in fails due to vitest (reason not clear, yet) + try { + await languageClientWrapper.start(); + } catch (_error) { + // ignore + } + + expect(languageClientWrapper.getWorker()).toBeTruthy(); + + // dispose & verify + await languageClientWrapper.dispose(); + expect(languageClientWrapper.getWorker()).toBeUndefined(); + }); + + test('Start: unreachable url', async () => { + const languageClientConfig = createDefaultLcUnreachableUrlConfig(23456); + const languageClientWrapper = new LanguageClientWrapper(languageClientConfig); + + try { + await languageClientWrapper.start(); + } catch (error) { + expect(error).toEqual({ + message: 'languageClientWrapper (javascript): Websocket connection failed.', + error: 'No error was provided.' + }); + } + }); + + test('Only unreachable worker url', async () => { + const prom = new Promise((_resolve, reject) => { + const worker = new Worker('aBogusUrl'); + + worker.onerror = () => { + reject('error'); + }; }); + await expect(prom).rejects.toEqual('error'); + }); - test('Dispose: start, dispose worker and restart', async () => { - const workerAndConfig = createWorkerAndConfig(); - const languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); - - expect(workerAndConfig.worker).toBeDefined(); - expect(languageClientWrapper.getWorker()).toBeUndefined(); - - // WA: language client in fails due to vitest (reason not clear, yet) - try { - await languageClientWrapper.start(); - } catch (_error) { - // ignore - console.error(_error); - }; - expect(languageClientWrapper.getWorker()).toBeTruthy(); - - // dispose & verify - await languageClientWrapper.dispose(); - expect(languageClientWrapper.getWorker()).toBeUndefined(); - - // restart & verify - try { - await languageClientWrapper.start(); - } catch (_error) { - // ignore - console.error(_error); - }; - expect(languageClientWrapper.getWorker()).toBeTruthy(); - }); + test('Start: unreachable worker url', async () => { + const languageClientConfig = createUnreachableWorkerConfig(); + const languageClientWrapper = new LanguageClientWrapper(languageClientConfig); - test('set verify log levels are applied', async () => { - const workerAndConfig = createWorkerAndConfig(); - let languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); - let logLevel = (languageClientWrapper['logger'] as ILogger).getLevel(); - expect(logLevel).toBe(LogLevel.Off); - expect(logLevel).toBe(0); - - workerAndConfig.languageClientConfig.logLevel = LogLevel.Debug; - languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); - logLevel = (languageClientWrapper['logger'] as ILogger).getLevel(); - expect(logLevel).toBe(LogLevel.Debug); - expect(logLevel).toBe(2); + await expect(languageClientWrapper.start()).rejects.toEqual({ + message: 'languageClientWrapper (javascript): Illegal worker configuration detected.', + error: 'No error was provided.' }); - + }); + + test('Dispose: start, dispose worker and restart', async () => { + const workerAndConfig = createWorkerAndConfig(); + const languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); + + expect(workerAndConfig.worker).toBeDefined(); + expect(languageClientWrapper.getWorker()).toBeUndefined(); + + // WA: language client in fails due to vitest (reason not clear, yet) + try { + await languageClientWrapper.start(); + } catch (_error) { + // ignore + console.error(_error); + } + expect(languageClientWrapper.getWorker()).toBeTruthy(); + + // dispose & verify + await languageClientWrapper.dispose(); + expect(languageClientWrapper.getWorker()).toBeUndefined(); + + // restart & verify + try { + await languageClientWrapper.start(); + } catch (_error) { + // ignore + console.error(_error); + } + expect(languageClientWrapper.getWorker()).toBeTruthy(); + }); + + test('set verify log levels are applied', async () => { + const workerAndConfig = createWorkerAndConfig(); + let languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); + let logLevel = (languageClientWrapper['logger'] as ILogger).getLevel(); + expect(logLevel).toBe(LogLevel.Off); + expect(logLevel).toBe(0); + + workerAndConfig.languageClientConfig.logLevel = LogLevel.Debug; + languageClientWrapper = new LanguageClientWrapper(workerAndConfig.languageClientConfig); + logLevel = (languageClientWrapper['logger'] as ILogger).getLevel(); + expect(logLevel).toBe(LogLevel.Debug); + expect(logLevel).toBe(2); + }); }); diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index 050f9f4ed..4538590b1 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -5,8 +5,5 @@ "noEmit": true, "rootDir": "." }, - "include": [ - "src/**/*", - "test/**/*" - ] + "include": ["src/**/*", "test/**/*"] } diff --git a/packages/client/tsconfig.src.json b/packages/client/tsconfig.src.json index 5f723728c..4fbe84ba3 100644 --- a/packages/client/tsconfig.src.json +++ b/packages/client/tsconfig.src.json @@ -6,10 +6,10 @@ "outDir": "lib", "declarationDir": "lib" }, - "references": [{ - "path": "../vscode-ws-jsonrpc/tsconfig.src.json" - }], - "include": [ - "src/**/*.ts" - ] + "references": [ + { + "path": "../vscode-ws-jsonrpc/tsconfig.src.json" + } + ], + "include": ["src/**/*.ts"] } diff --git a/packages/client/tsconfig.test.json b/packages/client/tsconfig.test.json index 606d704d7..58e513276 100644 --- a/packages/client/tsconfig.test.json +++ b/packages/client/tsconfig.test.json @@ -4,10 +4,10 @@ "noEmit": true, "rootDir": "test" }, - "references": [{ - "path": "./tsconfig.src.json" - }], - "include": [ - "test/**/*.ts", - ] + "references": [ + { + "path": "./tsconfig.src.json" + } + ], + "include": ["test/**/*.ts"] } diff --git a/packages/examples/CHANGELOG.md b/packages/examples/CHANGELOG.md index 8c6c195b8..1fbdc7e43 100644 --- a/packages/examples/CHANGELOG.md +++ b/packages/examples/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this npm module are documented in this file. ## [2026.2.2] - unreleased -- Updated all `@codingame/monaco-vscode` packages to `26.2.1`. +- Updated all `@codingame/monaco-vscode` packages to `26.2.2`. - Updated to `monaco-languageclient@10.8.0` and `@typefox/monaco-editor-react@7.8.0`. - Dropped eslint and rely fully on oxlint. @@ -296,12 +296,12 @@ All notable changes to this npm module are documented in this file. ## [2024.10.4] - 2024-10-23 - Updated to `monaco-languageclient@9.0.0-next.5`, `monaco-editor-wrapper@6.0.0-next.5` and `@typefox/monaco-editor-react@6.0.0-next.5`. -Updated all `@codingame/monaco-vscode` packages to `10.1.1`. + Updated all `@codingame/monaco-vscode` packages to `10.1.1`. ## [2024.10.3] - 2024-10-21 - Updated to `monaco-languageclient@9.0.0-next.4`, `monaco-editor-wrapper@6.0.0-next.4` and `@typefox/monaco-editor-react@6.0.0-next.4`. -Updated all `@codingame/monaco-vscode` packages to `10.1.0`. + Updated all `@codingame/monaco-vscode` packages to `10.1.0`. - Updated to eslint 9 ## [2024.10.2] - 20241-10-11 diff --git a/packages/examples/README.md b/packages/examples/README.md index b7517520d..08bde4627 100644 --- a/packages/examples/README.md +++ b/packages/examples/README.md @@ -13,7 +13,7 @@ All changes are noted in the [CHANGELOG](https://github.com/TypeFox/monaco-langu ## Getting Started -This is npm package is part of the mono repo. Please follow the main repositories [instructions]() to get started with local development. +This is npm package is part of the mono repo. Please follow the main repositories [instructions](https://github.com/TypeFox/monaco-languageclient#getting-started) to get started with local development. ## Usage diff --git a/packages/examples/appPlayground.html b/packages/examples/appPlayground.html index 43665a3b7..a36a18ff1 100644 --- a/packages/examples/appPlayground.html +++ b/packages/examples/appPlayground.html @@ -1,19 +1,18 @@ - + - - + Application Playground - - - + + + - +
- Application Playground - [Back to Index] Heads up: This is a prototype and still evolving. + Application Playground - [Back to Index] Heads up: This is a + prototype and still evolving.
- - + diff --git a/packages/examples/browser.html b/packages/examples/browser.html index 44efc76cf..1267a1c74 100644 --- a/packages/examples/browser.html +++ b/packages/examples/browser.html @@ -1,22 +1,21 @@ - + - - + Language Client Pure Browser Example - - + + - +
- Language Client Pure Browser Example - [Back to Index] + Language Client Pure Browser Example - [Back to Index]
-
+
- + diff --git a/packages/examples/clangd.html b/packages/examples/clangd.html index 072f22bd7..3d3819de5 100644 --- a/packages/examples/clangd.html +++ b/packages/examples/clangd.html @@ -1,26 +1,27 @@ - + - - + Cpp Language Client & Clangd Language Server (Worker/Wasm) - - - - - + + + + + - +
- Cpp Language Client & Clangd Language Server (Worker/Wasm) - [Back to Index] -
- - - The clangd language server worker has been derived from: clangd-in-browser + Cpp Language Client & Clangd Language Server (Worker/Wasm) - [Back to Index] +
+ + + The clangd language server worker has been derived from: + clangd-in-browser
- - + diff --git a/packages/examples/eclipse.jdt.ls.html b/packages/examples/eclipse.jdt.ls.html index f10dc50da..660f31226 100644 --- a/packages/examples/eclipse.jdt.ls.html +++ b/packages/examples/eclipse.jdt.ls.html @@ -1,27 +1,26 @@ - + - - + Java Language Client & Language Server (Web Socket) - - - - + + + + - +
- Java Language Client & Language Server (Web Socket) - [Back to Index] -
- - - Launch backend with: docker compose -f ./packages/examples/resources/eclipse.jdt.ls/docker-compose.yml up -d
+ Java Language Client & Language Server (Web Socket) - [Back to Index] +
+ + + Launch backend with: docker compose -f ./packages/examples/resources/eclipse.jdt.ls/docker-compose.yml up -d
-
+
- - + diff --git a/packages/examples/ghp_appPlayground.html b/packages/examples/ghp_appPlayground.html index 4f5352105..18581bbe2 100644 --- a/packages/examples/ghp_appPlayground.html +++ b/packages/examples/ghp_appPlayground.html @@ -1,20 +1,19 @@ - + - - + Application Playground - - - + + + - +
- Application Playground - [Back to Index] Heads up: This is a prototype and still evolving. + Application Playground - [Back to Index] Heads up: This is a + prototype and still evolving.
- - + diff --git a/packages/examples/ghp_browser.html b/packages/examples/ghp_browser.html index 3ed5cc70a..6c4bfd706 100644 --- a/packages/examples/ghp_browser.html +++ b/packages/examples/ghp_browser.html @@ -1,22 +1,21 @@ - + - - + Language Client Pure Browser Example - - + + - +
- Language Client Pure Browser Example - [Back to Index] + Language Client Pure Browser Example - [Back to Index]
-
+
- + diff --git a/packages/examples/ghp_clangd.html b/packages/examples/ghp_clangd.html index eb7cab2b9..3af805344 100644 --- a/packages/examples/ghp_clangd.html +++ b/packages/examples/ghp_clangd.html @@ -1,27 +1,27 @@ - + - - + Cpp Language Client & Clangd Language Server (Worker/Wasm) - - + + - - - + + + - +
- Cpp Language Client & Clangd Language Server (Worker/Wasm) - [Back to Index] -
- - - The clangd language server worker has been derived from: clangd-in-browser + Cpp Language Client & Clangd Language Server (Worker/Wasm) - [Back to Index] +
+ + + The clangd language server worker has been derived from: + clangd-in-browser
- - + diff --git a/packages/examples/ghp_langium_extended.html b/packages/examples/ghp_langium_extended.html index 564dc4608..47c3890b8 100644 --- a/packages/examples/ghp_langium_extended.html +++ b/packages/examples/ghp_langium_extended.html @@ -1,24 +1,22 @@ - + - - + Langium Grammar DSL (Extended Mode) - - - + + + - +
- Langium Grammar DSL (Extended Mode) - [Back to Index] -
+ Langium Grammar DSL (Extended Mode) - [Back to Index] +
- - + diff --git a/packages/examples/ghp_react_appPlayground.html b/packages/examples/ghp_react_appPlayground.html index 9b680219d..dcb70c37e 100644 --- a/packages/examples/ghp_react_appPlayground.html +++ b/packages/examples/ghp_react_appPlayground.html @@ -1,22 +1,21 @@ - + - - + Application Playground - - - + + + - - + +
- Application Playground - [Back to Index] Heads up: This is a prototype and still evolving. + Application Playground - [Back to Index] Heads up: This is a + prototype and still evolving.
- - + diff --git a/packages/examples/ghp_react_statemachine.html b/packages/examples/ghp_react_statemachine.html index 967117792..1b0ac8363 100644 --- a/packages/examples/ghp_react_statemachine.html +++ b/packages/examples/ghp_react_statemachine.html @@ -1,24 +1,24 @@ - + - - + React: Langium Statemachine Language Client & Language Server (Worker) - - + + - +
- React: Langium Statemachine Language Client & Language Server (Worker) - [Back to Index] -
+ React: Langium Statemachine Language Client & Language Server (Worker) - [Back to Index] +
- - + diff --git a/packages/examples/ghp_statemachine.html b/packages/examples/ghp_statemachine.html index 4a32f797d..93dbcb8bd 100644 --- a/packages/examples/ghp_statemachine.html +++ b/packages/examples/ghp_statemachine.html @@ -1,23 +1,21 @@ - + - - + Langium Statemachine Client & Language Server (Worker) - - + + - +
- Langium Statemachine Client & Language Server (Worker) - [Back to Index] -
- - + Langium Statemachine Client & Language Server (Worker) - [Back to Index] +
+ +
-
-
+
+
- - + diff --git a/packages/examples/ghp_tsExtHost.html b/packages/examples/ghp_tsExtHost.html index 25fa147d5..f136382da 100644 --- a/packages/examples/ghp_tsExtHost.html +++ b/packages/examples/ghp_tsExtHost.html @@ -1,29 +1,27 @@ - + - - + TypeScript Extension Host Worker - - + + - +
- TypeScript Extension Host Worker - [Back to Index] -
- - - - + TypeScript Extension Host Worker - [Back to Index] +
+ + + +
-
+
- - + diff --git a/packages/examples/groovy.html b/packages/examples/groovy.html index b0725df2a..85b171963 100644 --- a/packages/examples/groovy.html +++ b/packages/examples/groovy.html @@ -1,27 +1,26 @@ - + - - + Groovy Language Client & Language Server (Web Socket) - - - - + + + + - +
- Groovy Language Client & Language Server (Web Socket) - [Back to Index] -
- - - Launch backend with: docker compose -f ./packages/examples/resources/groovy/docker-compose.yml up -d
+ Groovy Language Client & Language Server (Web Socket) - [Back to Index] +
+ + + Launch backend with: docker compose -f ./packages/examples/resources/groovy/docker-compose.yml up -d
-
+
- - + diff --git a/packages/examples/index.html b/packages/examples/index.html index 14c54fa78..7098f1465 100644 --- a/packages/examples/index.html +++ b/packages/examples/index.html @@ -1,54 +1,47 @@ - + - - + monaco-languageclient Examples - - + + - +
-

Examples

- - This page contains all examples not requiring a backend. - -

Langium

- - Langium Grammar DSL (Language Server in Worker): [ Example Page ] -
- Langium Statemachine (Language Server in Worker): [ Example Page | React Example Page ] -
-   ->  Localized Versions: [ - cs - - de - - es - - fr - - it - - ja - - ko - - pl - - pt-br - - qps-ploc - - ru - - tr - - zh-hans - - zh-hant ] -
- -

JSON

- Pure Browser Implementation: [ Example Page ] - -

Cpp / Clangd

- Cpp (Language Server in Worker/Wasm): [ Example Page ] - -

Application Playground

- Application Playground (incl. Open Collaboration Tools): [ Example Page | React Example Page ] - -

TypeScript

- TypeScript Extension Host Worker: [ Example Page ] +

Examples

+ + This page contains all examples not requiring a backend. + +

Langium

+ + Langium Grammar DSL (Language Server in Worker): [ Example Page ] +
+ Langium Statemachine (Language Server in Worker): [ Example Page | + React Example Page ] +
+   ->  Localized Versions: [ + cs - de - + es - fr - + it - ja - + ko - pl - + pt-br - qps-ploc - + ru - tr - + zh-hans - zh-hant ] +
+ +

JSON

+ Pure Browser Implementation: [ Example Page ] + +

Cpp / Clangd

+ Cpp (Language Server in Worker/Wasm): [ Example Page ] + +

Application Playground

+ Application Playground (incl. Open Collaboration Tools): [ Example Page | + React Example Page ] + +

TypeScript

+ TypeScript Extension Host Worker: [ Example Page ]
- - + diff --git a/packages/examples/json.html b/packages/examples/json.html index ce81e3a0a..925517792 100644 --- a/packages/examples/json.html +++ b/packages/examples/json.html @@ -1,26 +1,24 @@ - + - - + JSON Language Client & Language Server (Web Socket) - - + + - +
- JSON Language Client & Language Server (Web Socket) - [Back to Index] -
- - + JSON Language Client & Language Server (Web Socket) - [Back to Index] +
+ +
-
+
- - + diff --git a/packages/examples/json_classic.html b/packages/examples/json_classic.html index 83d558da7..ff987e346 100644 --- a/packages/examples/json_classic.html +++ b/packages/examples/json_classic.html @@ -1,23 +1,21 @@ - + - - + JSON Language Client & Language Server (Web Socket) - - - + + - +
- JSON Language Client & Language Server (Web Socket) - [Back to Index] + JSON Language Client & Language Server (Web Socket) - [Back to Index]
-
+
- + diff --git a/packages/examples/langium_extended.html b/packages/examples/langium_extended.html index b21063802..db8767997 100644 --- a/packages/examples/langium_extended.html +++ b/packages/examples/langium_extended.html @@ -1,24 +1,22 @@ - + - - + Langium Grammar DSL (Extended Mode) - - - + + + - +
- Langium Grammar DSL (Extended Mode) - [Back to Index] -
+ Langium Grammar DSL (Extended Mode) - [Back to Index] +
- - + diff --git a/packages/examples/package.json b/packages/examples/package.json index 968c3dc02..291b91674 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -2,23 +2,51 @@ "name": "monaco-languageclient-examples", "version": "2026.2.1", "description": "Monaco Language client examples", + "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/README.md", + "bugs": { + "url": "https://github.com/TypeFox/monaco-languageclient/issues" + }, + "license": "MIT", "author": { "name": "TypeFox GmbH", "url": "http://www.typefox.io" }, - "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/examples/README.md", - "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/TypeFox/monaco-languageclient.git", "directory": "packages/examples" }, - "bugs": { - "url": "https://github.com/TypeFox/monaco-languageclient/issues" - }, + "files": [ + "dist", + "src", + "*.html", + "*.ts", + "README.md", + "CHANGELOG.md", + "LICENSE" + ], "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", + "typesVersions": { + "*": { + ".": [ + "dist/index" + ], + "node": [ + "dist/node" + ], + "json-client": [ + "dist/json/client/extended" + ], + "worker/langium": [ + "dist/langium/langium-dsl/worker/langium-server" + ], + "worker/statemachine": [ + "dist/langium/statemachine/worker/statemachine-server" + ] + } + }, "exports": { ".": { "types": "./dist/index.d.ts", @@ -45,79 +73,62 @@ "default": "./dist/langium/statemachine/worker/statemachine-server.js" } }, - "typesVersions": { - "*": { - ".": [ - "dist/index" - ], - "node": [ - "dist/node" - ], - "json-client": [ - "dist/json/client/extended" - ], - "worker/langium": [ - "dist/langium/langium-dsl/worker/langium-server" - ], - "worker/statemachine": [ - "dist/langium/statemachine/worker/statemachine-server" - ] - } - }, - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, - "volta": { - "node": "24.13.0", - "npm": "11.6.2" + "scripts": { + "clean": "shx rm -fr dist *.tsbuildinfo production ./resources/vsix", + "compile": "tsgo --build tsconfig.src.json", + "resources:download": "tsx ./resources/scripts/downloadResources.ts", + "build:msg": "echo Building main examples:", + "build": "npm run build:msg && npm run clean && npm run resources:download && npm run extract:docker && npm run compile", + "start:server:groovy": "tsx src/groovy/server/direct.ts", + "start:server:jdtls": "tsx src/eclipse.jdt.ls/server/direct.ts", + "start:server:json": "tsx src/json/server/direct.ts", + "start:server:python": "tsx src/python/server/direct.ts", + "langium:generate:statemachine": "langium generate --file ./src/langium/statemachine/config/langium-config.json", + "langium:generate": "npm run langium:generate:statemachine", + "extract:docker": "tsx ./resources/clangd/scripts/extractDockerFiles.ts", + "production:clean": "shx rm -fr ./production", + "production:copy:mini-coi": "mini-coi --service-worker production/mini-coi.js", + "production:build": "npm run production:clean && vite --config vite.config.deploy.ts build && npm run production:copy:mini-coi", + "production:preview:build": "npm run production:clean && vite --config vite.config.preview.ts build && npm run production:copy:mini-coi", + "production:preview": "vite --config vite.config.preview.ts preview -d" }, - "files": [ - "dist", - "src", - "*.html", - "*.ts", - "README.md", - "CHANGELOG.md", - "LICENSE" - ], "dependencies": { - "@codingame/monaco-vscode-configuration-service-override": "^26.2.1", - "@codingame/monaco-vscode-cpp-default-extension": "^26.2.1", - "@codingame/monaco-vscode-debug-service-override": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-environment-service-override": "^26.2.1", - "@codingame/monaco-vscode-explorer-service-override": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "@codingame/monaco-vscode-files-service-override": "^26.2.1", - "@codingame/monaco-vscode-groovy-default-extension": "^26.2.1", - "@codingame/monaco-vscode-java-default-extension": "^26.2.1", - "@codingame/monaco-vscode-javascript-default-extension": "^26.2.1", - "@codingame/monaco-vscode-json-default-extension": "^26.2.1", - "@codingame/monaco-vscode-json-language-features-default-extension": "^26.2.1", - "@codingame/monaco-vscode-keybindings-service-override": "^26.2.1", - "@codingame/monaco-vscode-lifecycle-service-override": "^26.2.1", - "@codingame/monaco-vscode-localization-service-override": "^26.2.1", - "@codingame/monaco-vscode-outline-service-override": "^26.2.1", - "@codingame/monaco-vscode-preferences-service-override": "^26.2.1", - "@codingame/monaco-vscode-python-default-extension": "^26.2.1", - "@codingame/monaco-vscode-remote-agent-service-override": "^26.2.1", - "@codingame/monaco-vscode-search-result-default-extension": "^26.2.1", - "@codingame/monaco-vscode-search-service-override": "^26.2.1", - "@codingame/monaco-vscode-secret-storage-service-override": "^26.2.1", - "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.1", - "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.1", - "@codingame/monaco-vscode-storage-service-override": "^26.2.1", - "@codingame/monaco-vscode-testing-service-override": "^26.2.1", - "@codingame/monaco-vscode-textmate-service-override": "^26.2.1", - "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.1", - "@codingame/monaco-vscode-theme-service-override": "^26.2.1", - "@codingame/monaco-vscode-typescript-basics-default-extension": "^26.2.1", - "@codingame/monaco-vscode-typescript-language-features-default-extension": "^26.2.1", - "@codingame/monaco-vscode-view-banner-service-override": "^26.2.1", - "@codingame/monaco-vscode-view-status-bar-service-override": "^26.2.1", - "@codingame/monaco-vscode-view-title-bar-service-override": "^26.2.1", - "@codingame/monaco-vscode-views-service-override": "^26.2.1", + "@codingame/monaco-vscode-configuration-service-override": "^26.2.2", + "@codingame/monaco-vscode-cpp-default-extension": "^26.2.2", + "@codingame/monaco-vscode-debug-service-override": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-environment-service-override": "^26.2.2", + "@codingame/monaco-vscode-explorer-service-override": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "@codingame/monaco-vscode-files-service-override": "^26.2.2", + "@codingame/monaco-vscode-groovy-default-extension": "^26.2.2", + "@codingame/monaco-vscode-java-default-extension": "^26.2.2", + "@codingame/monaco-vscode-javascript-default-extension": "^26.2.2", + "@codingame/monaco-vscode-json-default-extension": "^26.2.2", + "@codingame/monaco-vscode-json-language-features-default-extension": "^26.2.2", + "@codingame/monaco-vscode-keybindings-service-override": "^26.2.2", + "@codingame/monaco-vscode-lifecycle-service-override": "^26.2.2", + "@codingame/monaco-vscode-localization-service-override": "^26.2.2", + "@codingame/monaco-vscode-outline-service-override": "^26.2.2", + "@codingame/monaco-vscode-preferences-service-override": "^26.2.2", + "@codingame/monaco-vscode-python-default-extension": "^26.2.2", + "@codingame/monaco-vscode-remote-agent-service-override": "^26.2.2", + "@codingame/monaco-vscode-search-result-default-extension": "^26.2.2", + "@codingame/monaco-vscode-search-service-override": "^26.2.2", + "@codingame/monaco-vscode-secret-storage-service-override": "^26.2.2", + "@codingame/monaco-vscode-standalone-json-language-features": "^26.2.2", + "@codingame/monaco-vscode-standalone-typescript-language-features": "^26.2.2", + "@codingame/monaco-vscode-storage-service-override": "^26.2.2", + "@codingame/monaco-vscode-testing-service-override": "^26.2.2", + "@codingame/monaco-vscode-textmate-service-override": "^26.2.2", + "@codingame/monaco-vscode-theme-defaults-default-extension": "^26.2.2", + "@codingame/monaco-vscode-theme-service-override": "^26.2.2", + "@codingame/monaco-vscode-typescript-basics-default-extension": "^26.2.2", + "@codingame/monaco-vscode-typescript-language-features-default-extension": "^26.2.2", + "@codingame/monaco-vscode-view-banner-service-override": "^26.2.2", + "@codingame/monaco-vscode-view-status-bar-service-override": "^26.2.2", + "@codingame/monaco-vscode-view-title-bar-service-override": "^26.2.2", + "@codingame/monaco-vscode-views-service-override": "^26.2.2", "@typefox/monaco-editor-react": "~7.7.0", "cors": "~2.8.6", "express": "~5.2.1", @@ -128,7 +139,7 @@ "react": "~19.2.4", "react-dom": "~19.2.4", "request-light": "~0.8.0", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "vscode-json-languageservice": "~5.7.2", "vscode-languageclient": "~9.0.1", "vscode-languageserver": "~9.0.1", @@ -147,23 +158,12 @@ "vite-plugin-static-copy": "~3.2.0", "vscode-languageserver-types": "~3.17.5" }, - "scripts": { - "clean": "shx rm -fr dist *.tsbuildinfo ./resources/vsix", - "compile": "tsgo --build tsconfig.src.json", - "resources:download": "tsx ./resources/scripts/downloadResources.ts", - "build:msg": "echo Building main examples:", - "build": "npm run build:msg && npm run clean && npm run resources:download && npm run extract:docker && npm run compile", - "start:server:groovy": "tsx src/groovy/server/direct.ts", - "start:server:jdtls": "tsx src/eclipse.jdt.ls/server/direct.ts", - "start:server:json": "tsx src/json/server/direct.ts", - "start:server:python": "tsx src/python/server/direct.ts", - "langium:generate:statemachine": "langium generate --file ./src/langium/statemachine/config/langium-config.json", - "langium:generate": "npm run langium:generate:statemachine", - "extract:docker": "tsx ./resources/clangd/scripts/extractDockerFiles.ts", - "production:clean": "shx rm -fr ./production", - "production:copy:mini-coi": "mini-coi --service-worker production/mini-coi.js", - "production:build": "npm run production:clean && vite --config vite.config.deploy.ts build && npm run production:copy:mini-coi", - "production:preview:build": "npm run production:clean && vite --config vite.config.preview.ts build && npm run production:copy:mini-coi", - "production:preview": "vite --config vite.config.preview.ts preview -d" + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "volta": { + "node": "24.13.0", + "npm": "11.6.2" } } diff --git a/packages/examples/python.html b/packages/examples/python.html index 76d6a96f7..f42a86f5c 100644 --- a/packages/examples/python.html +++ b/packages/examples/python.html @@ -1,23 +1,23 @@ - + - - + Python Language Client & Pyright Language Server (Web Socket) - - - + + + - +
- Python Language Client & Pyright Language Server (Web Socket) - [Back to Index] + Python Language Client & Pyright Language Server (Web Socket) - [Back to Index]
- - + diff --git a/packages/examples/react_appPlayground.html b/packages/examples/react_appPlayground.html index 096eb127d..44ea51eaf 100644 --- a/packages/examples/react_appPlayground.html +++ b/packages/examples/react_appPlayground.html @@ -1,21 +1,20 @@ - + - - + Application Playground - - - + + + - - + +
- Application Playground - [Back to Index] Heads up: This is a prototype and still evolving. + Application Playground - [Back to Index] Heads up: This is a + prototype and still evolving.
- - + diff --git a/packages/examples/react_python.html b/packages/examples/react_python.html index cc6099190..8d4b945a3 100644 --- a/packages/examples/react_python.html +++ b/packages/examples/react_python.html @@ -1,24 +1,24 @@ - + + + + + React: Python Language Client & Language Server (Web Socket) + + + - - - - React: Python Language Client & Language Server (Web Socket) - - - - - -
- React: Python Language Client & Language Server (Web Socket) - [Back to Index] -
-
- - + +
+ React: Python Language Client & Language Server (Web Socket) - [Back to Index] +
+
+ + diff --git a/packages/examples/react_statemachine.html b/packages/examples/react_statemachine.html index 4ab0cd38d..dbe16db6c 100644 --- a/packages/examples/react_statemachine.html +++ b/packages/examples/react_statemachine.html @@ -1,27 +1,27 @@ - + - - + React: Langium Statemachine Language Client & Language Server (Worker) - - + + - +
- React: Langium Statemachine Language Client & Language Server (Worker) - [Back to Index] -
- - - + React: Langium Statemachine Language Client & Language Server (Worker) - [Back to Index] +
+ + +
- - + diff --git a/packages/examples/resources/appPlayground/hello.json b/packages/examples/resources/appPlayground/hello.json index c9c6939f4..5e2255196 100644 --- a/packages/examples/resources/appPlayground/hello.json +++ b/packages/examples/resources/appPlayground/hello.json @@ -1,4 +1,4 @@ { - "$schema": "http://json.schemastore.org/coffeelint", - "line_endings": {"value": "unix"} + "$schema": "http://json.schemastore.org/coffeelint", + "line_endings": { "value": "unix" } } diff --git a/packages/examples/resources/appPlayground/hello.ts b/packages/examples/resources/appPlayground/hello.ts index 8c5f6e220..1eccac6f6 100644 --- a/packages/examples/resources/appPlayground/hello.ts +++ b/packages/examples/resources/appPlayground/hello.ts @@ -1,7 +1,7 @@ function sayHello(): string { - // intentionally erroneous to test import resolution - console.log(sayFoo()); - return 'Hello'; -}; + // intentionally erroneous to test import resolution + console.log(sayFoo()); + return 'Hello'; +} sayHello(); diff --git a/packages/examples/resources/appPlayground/tester.ts b/packages/examples/resources/appPlayground/tester.ts index d1535caa3..10b116aa5 100644 --- a/packages/examples/resources/appPlayground/tester.ts +++ b/packages/examples/resources/appPlayground/tester.ts @@ -1,3 +1,3 @@ export const sayFoo = () => { - return 'Foo'; + return 'Foo'; }; diff --git a/packages/examples/resources/appPlayground/views.html b/packages/examples/resources/appPlayground/views.html index 40cdb9923..f4051fef4 100644 --- a/packages/examples/resources/appPlayground/views.html +++ b/packages/examples/resources/appPlayground/views.html @@ -2,23 +2,23 @@ This is the reference for "defaultViewsHtml" in packages/wrapper/src/services/viewsService.ts -->
-
- -
-
-
- -
-
-
-
-
-
- -
-
-
+
+ +
+
+
+ +
-
-
+
+
+
+
+ +
+
+
+
+
+
diff --git a/packages/examples/resources/clangd/build.docker-compose.yml b/packages/examples/resources/clangd/build.docker-compose.yml index 2bc2595cb..157ddd6ea 100644 --- a/packages/examples/resources/clangd/build.docker-compose.yml +++ b/packages/examples/resources/clangd/build.docker-compose.yml @@ -6,6 +6,6 @@ services: context: . # only linux/amd64 for now platforms: - - "linux/amd64" + - 'linux/amd64' platform: linux/amd64 container_name: clangd-wasm-build diff --git a/packages/examples/resources/clangd/clangd-include.files.md b/packages/examples/resources/clangd/clangd-include.files.md index 49419d14b..0b3e7f313 100644 --- a/packages/examples/resources/clangd/clangd-include.files.md +++ b/packages/examples/resources/clangd/clangd-include.files.md @@ -2,6 +2,7 @@ ## Files +```shell /usr/include/wasm32-wasi-threads/__errno.h /usr/include/wasm32-wasi-threads/__errno_values.h /usr/include/wasm32-wasi-threads/__fd_set.h @@ -6394,3 +6395,4 @@ /usr/include/wasm32-wasip2/netpacket /usr/include/wasm32-wasip2/sys /usr/include/wasm32-wasip2/wasi +``` diff --git a/packages/examples/resources/clangd/configure.docker-compose.yml b/packages/examples/resources/clangd/configure.docker-compose.yml index 33c84b044..74176de12 100644 --- a/packages/examples/resources/clangd/configure.docker-compose.yml +++ b/packages/examples/resources/clangd/configure.docker-compose.yml @@ -6,6 +6,6 @@ services: context: . # only linux/amd64 for now platforms: - - "linux/amd64" + - 'linux/amd64' platform: linux/amd64 container_name: clangd-wasm-configure diff --git a/packages/examples/resources/clangd/scripts/extractDockerFiles.ts b/packages/examples/resources/clangd/scripts/extractDockerFiles.ts index 490e8b052..4cdf4f949 100644 --- a/packages/examples/resources/clangd/scripts/extractDockerFiles.ts +++ b/packages/examples/resources/clangd/scripts/extractDockerFiles.ts @@ -1,23 +1,28 @@ -import * as fs from "node:fs"; -import child_process from "node:child_process"; +import * as fs from 'node:fs'; +import child_process from 'node:child_process'; const outputDir = './resources/clangd/wasm'; try { - child_process.execFileSync('docker', ['create', '--name', 'extract-clangd', 'ghcr.io/typefox/monaco-languageclient/clangd-wasm-build:latest']); + child_process.execFileSync('docker', [ + 'create', + '--name', + 'extract-clangd', + 'ghcr.io/typefox/monaco-languageclient/clangd-wasm-build:latest' + ]); - // clean but only if container start was successful - fs.rmSync(outputDir, { - force: true, - recursive: true - }); - fs.mkdirSync(outputDir); + // clean but only if container start was successful + fs.rmSync(outputDir, { + force: true, + recursive: true + }); + fs.mkdirSync(outputDir); - child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.js', outputDir]); - child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.wasm', outputDir]); - child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.worker.js', outputDir]); - child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.worker.mjs', outputDir]); - child_process.execFileSync('docker', ['rm', 'extract-clangd']); + child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.js', outputDir]); + child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.wasm', outputDir]); + child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.worker.js', outputDir]); + child_process.execFileSync('docker', ['cp', 'extract-clangd:/builder/llvm-project/build/bin/clangd.worker.mjs', outputDir]); + child_process.execFileSync('docker', ['rm', 'extract-clangd']); } catch (e) { - console.warn('Clangd wasm data was not extracted from container image!'); + console.warn('Clangd wasm data was not extracted from container image!'); } diff --git a/packages/examples/resources/clangd/workspace/.clangd b/packages/examples/resources/clangd/workspace/.clangd index 912fddf12..3f42939ae 100644 --- a/packages/examples/resources/clangd/workspace/.clangd +++ b/packages/examples/resources/clangd/workspace/.clangd @@ -1,16 +1,17 @@ { - CompileFlags: + CompileFlags: { - Add: [ - '-xc++', - '-std=c++2b', - '-pedantic-errors', - '-Wall', - '--target=wasm32-wasi', - '-isystem/usr/include/c++/v1', - '-isystem/usr/include/wasm32-wasi/c++/v1', - '-isystem/usr/include', - '-isystem/usr/include/wasm32-wasi' + Add: + [ + '-xc++', + '-std=c++2b', + '-pedantic-errors', + '-Wall', + '--target=wasm32-wasi', + '-isystem/usr/include/c++/v1', + '-isystem/usr/include/wasm32-wasi/c++/v1', + '-isystem/usr/include', + '-isystem/usr/include/wasm32-wasi' ] } } diff --git a/packages/examples/resources/debugger/docker-compose.yml b/packages/examples/resources/debugger/docker-compose.yml index e16366518..28dbc4363 100644 --- a/packages/examples/resources/debugger/docker-compose.yml +++ b/packages/examples/resources/debugger/docker-compose.yml @@ -7,13 +7,11 @@ services: context: ../../../.. # only linux/amd64 for now platforms: - - "linux/amd64" + - 'linux/amd64' platform: linux/amd64 ports: - 55555:5555 tty: true # just for completness. Is already set in the Dockerfile working_dir: /home/mlc/server - command: [ - "bash", "-c", "npm run start" - ] + command: ['bash', '-c', 'npm run start'] diff --git a/packages/examples/resources/debugger/package.json b/packages/examples/resources/debugger/package.json index f12a3a67a..ffb6a8d69 100644 --- a/packages/examples/resources/debugger/package.json +++ b/packages/examples/resources/debugger/package.json @@ -2,20 +2,14 @@ "name": "graalpy-debugger", "version": "2025.2.1", "description": "Monaco Language client Graalpy Debugger", + "license": "MIT", "author": { "name": "TypeFox GmbH", "url": "http://www.typefox.io" }, - "license": "MIT", "type": "module", "main": "./dist/debugServer.js", "module": "./dist/debugServer.js", - "exports": { - ".": { - "types": "./dist/debugServer.d.ts", - "default": "./dist/debugServer.js" - } - }, "typesVersions": { "*": { ".": [ @@ -23,13 +17,14 @@ ] } }, - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" + "exports": { + ".": { + "types": "./dist/debugServer.d.ts", + "default": "./dist/debugServer.js" + } }, - "volta": { - "node": "24.13.0", - "npm": "11.6.2" + "scripts": { + "start": "npm i && tsx src/debugServer.ts" }, "dependencies": { "express": "~4.21.2", @@ -39,7 +34,12 @@ "devDependencies": { "tsx": "~4.19.2" }, - "scripts": { - "start": "npm i && tsx src/debugServer.ts" + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "volta": { + "node": "24.13.0", + "npm": "11.6.2" } } diff --git a/packages/examples/resources/eclipse.jdt.ls/docker-compose.yml b/packages/examples/resources/eclipse.jdt.ls/docker-compose.yml index 30bcba2ba..e643f253a 100644 --- a/packages/examples/resources/eclipse.jdt.ls/docker-compose.yml +++ b/packages/examples/resources/eclipse.jdt.ls/docker-compose.yml @@ -6,11 +6,9 @@ services: context: ../../../.. # only linux/amd64 for now platforms: - - "linux/amd64" + - 'linux/amd64' platform: linux/amd64 - command: [ - "bash", "-c", "npm run start:example:server:jdtls" - ] + command: ['bash', '-c', 'npm run start:example:server:jdtls'] ports: - 30003:30003 working_dir: /home/mlc diff --git a/packages/examples/resources/groovy/docker-compose.yml b/packages/examples/resources/groovy/docker-compose.yml index 3979c00f0..b5a9c4b0d 100644 --- a/packages/examples/resources/groovy/docker-compose.yml +++ b/packages/examples/resources/groovy/docker-compose.yml @@ -6,11 +6,9 @@ services: context: ../../../.. # only linux/amd64 for now platforms: - - "linux/amd64" + - 'linux/amd64' platform: linux/amd64 - command: [ - "bash", "-c", "npm run start:example:server:groovy" - ] + command: ['bash', '-c', 'npm run start:example:server:groovy'] ports: - 30002:30002 working_dir: /home/gradle/mlc diff --git a/packages/examples/resources/scripts/downloadResources.ts b/packages/examples/resources/scripts/downloadResources.ts index 2d84ff1db..8c9812fde 100644 --- a/packages/examples/resources/scripts/downloadResources.ts +++ b/packages/examples/resources/scripts/downloadResources.ts @@ -8,32 +8,38 @@ import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; export const getLocalDirectory = () => { - const __filename = fileURLToPath(import.meta.url); - return dirname(__filename); + const __filename = fileURLToPath(import.meta.url); + return dirname(__filename); }; const downloadResource = async (url: string, targetDir: string, filename: string) => { - const target = resolve(targetDir, filename); - if (existsSync(target)) { - console.log(`Skipping download because ${target} already exists.`); - } else { - const result = mkdirSync(targetDir, { recursive: true }); - if (result) { - console.log(`Created target directory: ${targetDir}`); - } - console.log(`Downloading ${url} to ${target}`); - const resp = await fetch(url); - const buffer = await resp.arrayBuffer(); - writeFileSync(target, Buffer.from(buffer)); + const target = resolve(targetDir, filename); + if (existsSync(target)) { + console.log(`Skipping download because ${target} already exists.`); + } else { + const result = mkdirSync(targetDir, { recursive: true }); + if (result) { + console.log(`Created target directory: ${targetDir}`); } + console.log(`Downloading ${url} to ${target}`); + const resp = await fetch(url); + const buffer = await resp.arrayBuffer(); + writeFileSync(target, Buffer.from(buffer)); + } }; // Source: https://gist.github.com/wanglf/7acc591890dc0d8ceff1e7ec9af32a55?permalink_comment_id=4151555#gistcomment-4151555 // https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher}/vsextensions/${extension}/${version}/vspackage -await downloadResource('https://marketplace.visualstudio.com/_apis/public/gallery/publishers/GitHub/vsextensions/github-vscode-theme/6.3.5/vspackage', - resolve(getLocalDirectory(), '../vsix/'), 'github-vscode-theme.vsix'); +await downloadResource( + 'https://marketplace.visualstudio.com/_apis/public/gallery/publishers/GitHub/vsextensions/github-vscode-theme/6.3.5/vspackage', + resolve(getLocalDirectory(), '../vsix/'), + 'github-vscode-theme.vsix' +); // not yet used -await downloadResource('https://marketplace.visualstudio.com/_apis/public/gallery/publishers/TypeFox/vsextensions/open-collaboration-tools/0.3.5/vspackage', - resolve(getLocalDirectory(), '../vsix/'), 'open-collaboration-tools.vsix'); +await downloadResource( + 'https://marketplace.visualstudio.com/_apis/public/gallery/publishers/TypeFox/vsextensions/open-collaboration-tools/0.3.5/vspackage', + resolve(getLocalDirectory(), '../vsix/'), + 'open-collaboration-tools.vsix' +); diff --git a/packages/examples/resources/styles/views.css b/packages/examples/resources/styles/views.css index 68b03eb0b..f1515fcba 100644 --- a/packages/examples/resources/styles/views.css +++ b/packages/examples/resources/styles/views.css @@ -1,79 +1,79 @@ :root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; } body { - background-color: var(--vscode-editorWidget-background); - color: var(--vscode-editorWidget-foreground); - margin: 0; + background-color: var(--vscode-editorWidget-background); + color: var(--vscode-editorWidget-foreground); + margin: 0; } #sidebarDiv, #sidebarRightDiv { - display: flex; - flex: none; - border: 1px solid var(--vscode-editorWidget-border); + display: flex; + flex: none; + border: 1px solid var(--vscode-editorWidget-border); } #sidebar { - width: 300px; + width: 300px; } #editorsDiv { - flex: 1; - min-width: 0; + flex: 1; + min-width: 0; } #editors { - position: relative; - min-width: 0; - height: 99%; - border: 1px solid var(--vscode-editorWidget-border); + position: relative; + min-width: 0; + height: 99%; + border: 1px solid var(--vscode-editorWidget-border); } #sidebar-right { - max-width: 500px; + max-width: 500px; } #auxiliaryBar-left, #auxiliaryBar { - max-width: 300px; + max-width: 300px; } #panel { - display: none; - flex: 1; - border: 1px solid var(--vscode-editorWidget-border); - min-height: 0; + display: none; + flex: 1; + border: 1px solid var(--vscode-editorWidget-border); + min-height: 0; } #titleBar { - position: relative; - flex: none; + position: relative; + flex: none; } #banner { - flex: none; + flex: none; } #workbench-container { - height: 95vh; - display: flex; - flex-direction: column + height: 95vh; + display: flex; + flex-direction: column; } #workbench-top { - display: flex; - gap: 20px; - flex: 2; - min-height: 0 + display: flex; + gap: 20px; + flex: 2; + min-height: 0; } diff --git a/packages/examples/resources/styles/views.editorOnly.css b/packages/examples/resources/styles/views.editorOnly.css index c8542f4f3..b53529e8a 100644 --- a/packages/examples/resources/styles/views.editorOnly.css +++ b/packages/examples/resources/styles/views.editorOnly.css @@ -1,29 +1,29 @@ :root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; } body { - background-color: var(--vscode-editorWidget-background); - color: var(--vscode-editorWidget-foreground); - margin: 0; + background-color: var(--vscode-editorWidget-background); + color: var(--vscode-editorWidget-foreground); + margin: 0; } #editorsDiv { - min-width: 0; + min-width: 0; } #editors { - position: relative; - min-width: 0; - height: 95vh; - border: 1px solid var(--vscode-editorWidget-border); + position: relative; + min-width: 0; + height: 95vh; + border: 1px solid var(--vscode-editorWidget-border); } diff --git a/packages/examples/src/appPlayground/common.ts b/packages/examples/src/appPlayground/common.ts index 847aaa9da..abd43f641 100644 --- a/packages/examples/src/appPlayground/common.ts +++ b/packages/examples/src/appPlayground/common.ts @@ -1,7 +1,7 @@ /* -------------------------------------------------------------------------------------------- -* Copyright (c) 2024 TypeFox and others. -* Licensed under the MIT License. See LICENSE in the package root for license information. -* ------------------------------------------------------------------------------------------ */ + * Copyright (c) 2024 TypeFox and others. + * Licensed under the MIT License. See LICENSE in the package root for license information. + * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; import type { RegisterLocalProcessExtensionResult } from '@codingame/monaco-vscode-api/extensions'; @@ -9,18 +9,16 @@ import type { ConfigResult } from './config.js'; import type { MonacoVscodeApiWrapper } from 'monaco-languageclient/vscodeApiWrapper'; export const configurePostStart = async (apiWrapper: MonacoVscodeApiWrapper, configResult: ConfigResult) => { - const result = apiWrapper.getExtensionRegisterResult('mlc-app-playground') as RegisterLocalProcessExtensionResult; - await result.setAsDefaultApi(); + const result = apiWrapper.getExtensionRegisterResult('mlc-app-playground') as RegisterLocalProcessExtensionResult; + await result.setAsDefaultApi(); - await Promise.all([ - await vscode.workspace.openTextDocument(configResult.helloTsUri), - await vscode.workspace.openTextDocument(configResult.testerTsUri), - await vscode.workspace.openTextDocument(configResult.helloJsonUri) - ]); + await Promise.all([ + await vscode.workspace.openTextDocument(configResult.helloTsUri), + await vscode.workspace.openTextDocument(configResult.testerTsUri), + await vscode.workspace.openTextDocument(configResult.helloJsonUri) + ]); - await Promise.all([ - await vscode.window.showTextDocument(configResult.helloTsUri) - ]); + await Promise.all([await vscode.window.showTextDocument(configResult.helloTsUri)]); - console.log('Application Playground started'); + console.log('Application Playground started'); }; diff --git a/packages/examples/src/appPlayground/config.ts b/packages/examples/src/appPlayground/config.ts index ed066efd7..308096441 100644 --- a/packages/examples/src/appPlayground/config.ts +++ b/packages/examples/src/appPlayground/config.ts @@ -6,7 +6,11 @@ import { LogLevel } from '@codingame/monaco-vscode-api'; import getEnvironmentServiceOverride from '@codingame/monaco-vscode-environment-service-override'; import getExplorerServiceOverride from '@codingame/monaco-vscode-explorer-service-override'; -import { InMemoryFileSystemProvider, registerFileSystemOverlay, type IFileWriteOptions } from '@codingame/monaco-vscode-files-service-override'; +import { + InMemoryFileSystemProvider, + registerFileSystemOverlay, + type IFileWriteOptions +} from '@codingame/monaco-vscode-files-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import getLifecycleServiceOverride from '@codingame/monaco-vscode-lifecycle-service-override'; import getLocalizationServiceOverride from '@codingame/monaco-vscode-localization-service-override'; @@ -41,117 +45,119 @@ import helloJsonCode from '../../resources/appPlayground/hello.json?raw'; import { createDefaultWorkspaceContent } from '../common/client/utils.js'; export type ConfigResult = { - vscodeApiConfig: MonacoVscodeApiConfig; - workspaceFileUri: vscode.Uri; - helloTsUri: vscode.Uri; - testerTsUri: vscode.Uri; - helloJsonUri: vscode.Uri; + vscodeApiConfig: MonacoVscodeApiConfig; + workspaceFileUri: vscode.Uri; + helloTsUri: vscode.Uri; + testerTsUri: vscode.Uri; + helloJsonUri: vscode.Uri; }; export const configure = async (htmlContainer?: HTMLElement): Promise => { - const workspaceFileUri = vscode.Uri.file('/workspace.code-workspace'); + const workspaceFileUri = vscode.Uri.file('/workspace.code-workspace'); - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - ...getLifecycleServiceOverride(), - ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), - ...getBannerServiceOverride(), - ...getStatusBarServiceOverride(), - ...getTitleBarServiceOverride(), - ...getExplorerServiceOverride(), - ...getRemoteAgentServiceOverride(), - ...getEnvironmentServiceOverride(), - ...getSecretStorageServiceOverride(), - ...getStorageServiceOverride(), - ...getSearchServiceOverride(), - ...getOutlineServiceOverride() + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride(), + ...getLifecycleServiceOverride(), + ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), + ...getBannerServiceOverride(), + ...getStatusBarServiceOverride(), + ...getTitleBarServiceOverride(), + ...getExplorerServiceOverride(), + ...getRemoteAgentServiceOverride(), + ...getEnvironmentServiceOverride(), + ...getSecretStorageServiceOverride(), + ...getStorageServiceOverride(), + ...getSearchServiceOverride(), + ...getOutlineServiceOverride() + }, + viewsConfig: { + $type: 'ViewsService', + htmlContainer, + htmlAugmentationInstructions: defaultHtmlAugmentationInstructions, + viewsInitFunc: defaultViewsInit + }, + workspaceConfig: { + enableWorkspaceTrust: true, + windowIndicator: { + label: 'mlc-app-playground', + tooltip: '', + command: '' + }, + workspaceProvider: { + trusted: true, + async open() { + window.open(window.location.href); + return true; }, - viewsConfig: { - $type: 'ViewsService', - htmlContainer, - htmlAugmentationInstructions: defaultHtmlAugmentationInstructions, - viewsInitFunc: defaultViewsInit - }, - workspaceConfig: { - enableWorkspaceTrust: true, - windowIndicator: { - label: 'mlc-app-playground', - tooltip: '', - command: '' - }, - workspaceProvider: { - trusted: true, - async open() { - window.open(window.location.href); - return true; - }, - workspace: { - workspaceUri: workspaceFileUri - } - }, - configurationDefaults: { - 'window.title': 'mlc-app-playground${separator}${dirty}${activeEditorShort}' - }, - productConfiguration: { - nameShort: 'mlc-app-playground', - nameLong: 'mlc-app-playground' - } - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off', - 'typescript.tsserver.web.projectWideIntellisense.enabled': true, - 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false, - 'editor.guides.bracketPairsHorizontal': true, - 'oct.serverUrl': 'https://api.open-collab.tools/', - 'editor.experimental.asyncTokenization': true - }) - }, - extensions: [{ - config: { - name: 'mlc-app-playground', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - } - } - }], - advanced: { - enableExtHostWorker: true, - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; + workspace: { + workspaceUri: workspaceFileUri + } + }, + configurationDefaults: { + 'window.title': 'mlc-app-playground${separator}${dirty}${activeEditorShort}' + }, + productConfiguration: { + nameShort: 'mlc-app-playground', + nameLong: 'mlc-app-playground' + } + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off', + 'typescript.tsserver.web.projectWideIntellisense.enabled': true, + 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false, + 'editor.guides.bracketPairsHorizontal': true, + 'oct.serverUrl': 'https://api.open-collab.tools/', + 'editor.experimental.asyncTokenization': true + }) + }, + extensions: [ + { + config: { + name: 'mlc-app-playground', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + } + } + } + ], + advanced: { + enableExtHostWorker: true + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; - const workspaceUri = vscode.Uri.file('/workspace'); - const helloTsUri = vscode.Uri.file('/workspace/hello.ts'); - const testerTsUri = vscode.Uri.file('/workspace/tester.ts'); - const helloJsonUri = vscode.Uri.file('/workspace/hello.json'); - const fileSystemProvider = new InMemoryFileSystemProvider(); - const textEncoder = new TextEncoder(); + const workspaceUri = vscode.Uri.file('/workspace'); + const helloTsUri = vscode.Uri.file('/workspace/hello.ts'); + const testerTsUri = vscode.Uri.file('/workspace/tester.ts'); + const helloJsonUri = vscode.Uri.file('/workspace/hello.json'); + const fileSystemProvider = new InMemoryFileSystemProvider(); + const textEncoder = new TextEncoder(); - const options: IFileWriteOptions = { - atomic: false, - unlock: false, - create: true, - overwrite: true - }; - await fileSystemProvider.mkdir(workspaceUri); - await fileSystemProvider.writeFile(helloTsUri, textEncoder.encode(helloTsCode), options); - await fileSystemProvider.writeFile(testerTsUri, textEncoder.encode(testerTsCode), options); - await fileSystemProvider.writeFile(helloJsonUri, textEncoder.encode(helloJsonCode), options); - await fileSystemProvider.writeFile(workspaceFileUri, textEncoder.encode(createDefaultWorkspaceContent('/workspace')), options); - registerFileSystemOverlay(1, fileSystemProvider); + const options: IFileWriteOptions = { + atomic: false, + unlock: false, + create: true, + overwrite: true + }; + await fileSystemProvider.mkdir(workspaceUri); + await fileSystemProvider.writeFile(helloTsUri, textEncoder.encode(helloTsCode), options); + await fileSystemProvider.writeFile(testerTsUri, textEncoder.encode(testerTsCode), options); + await fileSystemProvider.writeFile(helloJsonUri, textEncoder.encode(helloJsonCode), options); + await fileSystemProvider.writeFile(workspaceFileUri, textEncoder.encode(createDefaultWorkspaceContent('/workspace')), options); + registerFileSystemOverlay(1, fileSystemProvider); - return { - vscodeApiConfig, - workspaceFileUri, - helloTsUri, - testerTsUri, - helloJsonUri - }; + return { + vscodeApiConfig, + workspaceFileUri, + helloTsUri, + testerTsUri, + helloJsonUri + }; }; diff --git a/packages/examples/src/appPlayground/main.ts b/packages/examples/src/appPlayground/main.ts index 12a9a0366..2fd291f51 100644 --- a/packages/examples/src/appPlayground/main.ts +++ b/packages/examples/src/appPlayground/main.ts @@ -9,13 +9,13 @@ import { disableElement } from '../common/client/utils.js'; import { MonacoVscodeApiWrapper } from 'monaco-languageclient/vscodeApiWrapper'; export const runApplicationPlayground = async () => { - disableElement('button-start', true); + disableElement('button-start', true); - const configResult = await configure(document.body); + const configResult = await configure(document.body); - // perform global init - const apiWrapper = new MonacoVscodeApiWrapper(configResult.vscodeApiConfig); - await apiWrapper.start(); + // perform global init + const apiWrapper = new MonacoVscodeApiWrapper(configResult.vscodeApiConfig); + await apiWrapper.start(); - await configurePostStart(apiWrapper, configResult); + await configurePostStart(apiWrapper, configResult); }; diff --git a/packages/examples/src/appPlayground/reactMain.tsx b/packages/examples/src/appPlayground/reactMain.tsx index 2e398146e..086bbf3f1 100644 --- a/packages/examples/src/appPlayground/reactMain.tsx +++ b/packages/examples/src/appPlayground/reactMain.tsx @@ -10,22 +10,22 @@ import { configurePostStart } from './common.js'; import { configure } from './config.js'; export const runApplicationPlaygroundReact = async () => { - - const configResult = await configure(document.body); - const root = ReactDOM.createRoot(document.getElementById('react-root')!); - const App = () => { - return ( -
- { - await configurePostStart(apiWrapper, configResult); - }} - onError={(e) => { - console.error(e); - }} /> -
- ); - }; - root.render(); + const configResult = await configure(document.body); + const root = ReactDOM.createRoot(document.getElementById('react-root')!); + const App = () => { + return ( +
+ { + await configurePostStart(apiWrapper, configResult); + }} + onError={(e) => { + console.error(e); + }} + /> +
+ ); + }; + root.render(); }; diff --git a/packages/examples/src/browser/main.ts b/packages/examples/src/browser/main.ts index 0cecc3bf5..9bcc033cd 100644 --- a/packages/examples/src/browser/main.ts +++ b/packages/examples/src/browser/main.ts @@ -19,152 +19,155 @@ import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFacto import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; export const runBrowserEditor = async () => { - const codeConverter = createCodeConverter(); - const protocolConverter = createProtocolConverter(undefined, true, true); + const codeConverter = createCodeConverter(); + const protocolConverter = createProtocolConverter(undefined, true, true); - let mainVscodeDocument: vscode.TextDocument | undefined; - const languageId = 'json'; - const code = `{ + let mainVscodeDocument: vscode.TextDocument | undefined; + const languageId = 'json'; + const code = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": "unix" }`; - const codeUri = '/workspace/model.json'; - - const htmlContainer = document.getElementById('monaco-editor-root')!; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer - }, - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'GitHub Dark High Contrast', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.lightbulb.enabled': 'On', - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: { - text: code, - uri: codeUri - } - } - }; - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - const editorApp = new EditorApp(editorAppConfig); - - vscode.workspace.onDidOpenTextDocument((_event) => { - mainVscodeDocument = _event; + const codeUri = '/workspace/model.json'; + + const htmlContainer = document.getElementById('monaco-editor-root')!; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer + }, + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride() + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'GitHub Dark High Contrast', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.lightbulb.enabled': 'On', + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: { + text: code, + uri: codeUri + } + } + }; + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + const editorApp = new EditorApp(editorAppConfig); + + vscode.workspace.onDidOpenTextDocument((_event) => { + mainVscodeDocument = _event; + }); + + const createDocument = (vscodeDocument: vscode.TextDocument) => { + return TextDocument.create(vscodeDocument.uri.toString(), vscodeDocument.languageId, vscodeDocument.version, vscodeDocument.getText()); + }; + + const resolveSchema = (url: string): Promise => { + const promise = new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.onload = () => resolve(xhr.responseText); + xhr.onerror = () => reject(xhr.statusText); + xhr.open('GET', url, true); + xhr.send(); }); - - const createDocument = (vscodeDocument: vscode.TextDocument) => { - return TextDocument.create(vscodeDocument.uri.toString(), vscodeDocument.languageId, vscodeDocument.version, vscodeDocument.getText()); - }; - - const resolveSchema = (url: string): Promise => { - const promise = new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.onload = () => resolve(xhr.responseText); - xhr.onerror = () => reject(xhr.statusText); - xhr.open('GET', url, true); - xhr.send(); - }); - return promise; - }; - - const jsonService = getLanguageService({ - schemaRequestService: resolveSchema - }); - const pendingValidationRequests = new Map(); - - vscode.languages.registerCompletionItemProvider(languageId, { - async provideCompletionItems(vscodeDocument, position, _token, _context) { - const document = createDocument(vscodeDocument); - const jsonDocument = jsonService.parseJSONDocument(document); - const completionList = await jsonService.doComplete(document, codeConverter.asPosition(position), jsonDocument); - return protocolConverter.asCompletionResult(completionList); - }, - - async resolveCompletionItem(item, _token) { - return await jsonService.doResolve(codeConverter.asCompletionItem(item)).then(result => protocolConverter.asCompletionItem(result)); - } + return promise; + }; + + const jsonService = getLanguageService({ + schemaRequestService: resolveSchema + }); + const pendingValidationRequests = new Map(); + + vscode.languages.registerCompletionItemProvider(languageId, { + async provideCompletionItems(vscodeDocument, position, _token, _context) { + const document = createDocument(vscodeDocument); + const jsonDocument = jsonService.parseJSONDocument(document); + const completionList = await jsonService.doComplete(document, codeConverter.asPosition(position), jsonDocument); + return protocolConverter.asCompletionResult(completionList); + }, + + async resolveCompletionItem(item, _token) { + return await jsonService.doResolve(codeConverter.asCompletionItem(item)).then((result) => protocolConverter.asCompletionItem(result)); + } + }); + + vscode.languages.registerDocumentRangeFormattingEditProvider(languageId, { + provideDocumentRangeFormattingEdits(vscodeDocument, range, options, _token) { + const document = createDocument(vscodeDocument); + const edits = jsonService.format(document, codeConverter.asRange(range), codeConverter.asFormattingOptions(options, {})); + return protocolConverter.asTextEdits(edits); + } + }); + + vscode.languages.registerDocumentSymbolProvider(languageId, { + provideDocumentSymbols(vscodeDocument, _token) { + const document = createDocument(vscodeDocument); + const jsonDocument = jsonService.parseJSONDocument(document); + return protocolConverter.asSymbolInformations(jsonService.findDocumentSymbols(document, jsonDocument)); + } + }); + + vscode.languages.registerHoverProvider(languageId, { + async provideHover(vscodeDocument, position, _token) { + const document = createDocument(vscodeDocument); + const jsonDocument = jsonService.parseJSONDocument(document); + return await jsonService.doHover(document, codeConverter.asPosition(position), jsonDocument).then((hover) => { + return protocolConverter.asHover(hover)!; + }); + } + }); + + const validate = () => { + const document = createDocument(mainVscodeDocument!); + cleanPendingValidation(document); + pendingValidationRequests.set( + document.uri, + window.setTimeout(() => { + pendingValidationRequests.delete(document.uri); + doValidate(document); + }) + ); + }; + + const cleanPendingValidation = (document: TextDocument) => { + const request = pendingValidationRequests.get(document.uri); + if (request !== undefined) { + window.clearTimeout(request); + pendingValidationRequests.delete(document.uri); + } + }; + + const diagnosticCollection = vscode.languages.createDiagnosticCollection('json'); + const doValidate = (document: TextDocument) => { + if (document.getText().length === 0) { + cleanDiagnostics(); + return; + } + const jsonDocument = jsonService.parseJSONDocument(document); + + jsonService.doValidation(document, jsonDocument).then(async (pDiagnostics) => { + const diagnostics = await protocolConverter.asDiagnostics(pDiagnostics); + diagnosticCollection.set(vscode.Uri.parse(codeUri), diagnostics); }); + }; - vscode.languages.registerDocumentRangeFormattingEditProvider(languageId, { - provideDocumentRangeFormattingEdits(vscodeDocument, range, options, _token) { - const document = createDocument(vscodeDocument); - const edits = jsonService.format(document, codeConverter.asRange(range), codeConverter.asFormattingOptions(options, {})); - return protocolConverter.asTextEdits(edits); - } - }); + const cleanDiagnostics = () => { + diagnosticCollection.clear(); + }; - vscode.languages.registerDocumentSymbolProvider(languageId, { - provideDocumentSymbols(vscodeDocument, _token) { - const document = createDocument(vscodeDocument); - const jsonDocument = jsonService.parseJSONDocument(document); - return protocolConverter.asSymbolInformations(jsonService.findDocumentSymbols(document, jsonDocument)); - } - }); + await editorApp.start(htmlContainer); - vscode.languages.registerHoverProvider(languageId, { - async provideHover(vscodeDocument, position, _token) { - const document = createDocument(vscodeDocument); - const jsonDocument = jsonService.parseJSONDocument(document); - return await jsonService.doHover(document, codeConverter.asPosition(position), jsonDocument).then((hover) => { - return protocolConverter.asHover(hover)!; - }); - } - }); - - const validate = () => { - const document = createDocument(mainVscodeDocument!); - cleanPendingValidation(document); - pendingValidationRequests.set(document.uri, window.setTimeout(() => { - pendingValidationRequests.delete(document.uri); - doValidate(document); - })); - }; - - const cleanPendingValidation = (document: TextDocument) => { - const request = pendingValidationRequests.get(document.uri); - if (request !== undefined) { - window.clearTimeout(request); - pendingValidationRequests.delete(document.uri); - } - }; - - const diagnosticCollection = vscode.languages.createDiagnosticCollection('json'); - const doValidate = (document: TextDocument) => { - if (document.getText().length === 0) { - cleanDiagnostics(); - return; - } - const jsonDocument = jsonService.parseJSONDocument(document); - - jsonService.doValidation(document, jsonDocument).then(async (pDiagnostics) => { - const diagnostics = await protocolConverter.asDiagnostics(pDiagnostics); - diagnosticCollection.set(vscode.Uri.parse(codeUri), diagnostics); - }); - }; - - const cleanDiagnostics = () => { - diagnosticCollection.clear(); - }; - - await editorApp.start(htmlContainer); - - editorApp.getTextModels().modified?.onDidChangeContent(() => { - validate(); - }); + editorApp.getTextModels().modified?.onDidChangeContent(() => { + validate(); + }); }; diff --git a/packages/examples/src/clangd/client/config.ts b/packages/examples/src/clangd/client/config.ts index 132d55bae..4382ea73e 100644 --- a/packages/examples/src/clangd/client/config.ts +++ b/packages/examples/src/clangd/client/config.ts @@ -21,115 +21,117 @@ import { Uri } from 'vscode'; import { ClangdWorkerHandler } from './workerHandler.js'; export type ClangdAppConfig = { - languageClientConfig: LanguageClientConfig; - vscodeApiConfig: MonacoVscodeApiConfig; - editorAppConfig: EditorAppConfig; -} + languageClientConfig: LanguageClientConfig; + vscodeApiConfig: MonacoVscodeApiConfig; + editorAppConfig: EditorAppConfig; +}; export const createClangdAppConfig = async (config: { - htmlContainer: HTMLElement, - workspaceUri: Uri, - workspaceFileUri: Uri, - clangdWorkerHandler: ClangdWorkerHandler, - lsMessageLocalPort: MessagePort + htmlContainer: HTMLElement; + workspaceUri: Uri; + workspaceFileUri: Uri; + clangdWorkerHandler: ClangdWorkerHandler; + lsMessageLocalPort: MessagePort; }): Promise => { - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - ...getLifecycleServiceOverride(), - ...getBannerServiceOverride(), - ...getStatusBarServiceOverride(), - ...getTitleBarServiceOverride(), - ...getExplorerServiceOverride(), - ...getRemoteAgentServiceOverride(), - ...getEnvironmentServiceOverride(), - ...getSecretStorageServiceOverride() - }, - viewsConfig: { - $type: 'ViewsService', - htmlContainer: config.htmlContainer, - htmlAugmentationInstructions: defaultHtmlAugmentationInstructions, - viewsInitFunc: defaultViewsInit - }, - workspaceConfig: { - enableWorkspaceTrust: true, - windowIndicator: { - label: 'mlc-clangd-example', - tooltip: '', - command: '' - }, - workspaceProvider: { - trusted: true, - async open() { - window.open(window.location.href); - return true; - }, - workspace: { - workspaceUri: config.workspaceFileUri - }, - }, - configurationDefaults: { - 'window.title': 'mlc-clangd-exampled${separator}${dirty}${activeEditorShort}' - }, - productConfiguration: { - nameShort: 'mlc-clangd-example', - nameLong: 'mlc-clangd-example' - } + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride(), + ...getLifecycleServiceOverride(), + ...getBannerServiceOverride(), + ...getStatusBarServiceOverride(), + ...getTitleBarServiceOverride(), + ...getExplorerServiceOverride(), + ...getRemoteAgentServiceOverride(), + ...getEnvironmentServiceOverride(), + ...getSecretStorageServiceOverride() + }, + viewsConfig: { + $type: 'ViewsService', + htmlContainer: config.htmlContainer, + htmlAugmentationInstructions: defaultHtmlAugmentationInstructions, + viewsInitFunc: defaultViewsInit + }, + workspaceConfig: { + enableWorkspaceTrust: true, + windowIndicator: { + label: 'mlc-clangd-example', + tooltip: '', + command: '' + }, + workspaceProvider: { + trusted: true, + async open() { + window.open(window.location.href); + return true; }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off', - 'editor.guides.bracketPairsHorizontal': true, - 'editor.inlayHints.enabled': 'offUnlessPressed', - 'editor.quickSuggestionsDelay': 200, - 'editor.experimental.asyncTokenization': false - }) - }, - extensions: [{ - config: { - name: 'mlc-clangd-example', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - } - } - }], - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - const languageClientConfig: LanguageClientConfig = { - languageId: 'cpp', - connection: { - options: { - $type: 'WorkerDirect', - worker: await config.clangdWorkerHandler.createWorker(), - messagePort: config.lsMessageLocalPort - } - }, - restartOptions: { - retries: 5, - timeout: 1000, - keepWorker: true - }, - clientOptions: { - documentSelector: ['cpp'], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: config.workspaceUri - } + workspace: { + workspaceUri: config.workspaceFileUri } - }; + }, + configurationDefaults: { + 'window.title': 'mlc-clangd-exampled${separator}${dirty}${activeEditorShort}' + }, + productConfiguration: { + nameShort: 'mlc-clangd-example', + nameLong: 'mlc-clangd-example' + } + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off', + 'editor.guides.bracketPairsHorizontal': true, + 'editor.inlayHints.enabled': 'offUnlessPressed', + 'editor.quickSuggestionsDelay': 200, + 'editor.experimental.asyncTokenization': false + }) + }, + extensions: [ + { + config: { + name: 'mlc-clangd-example', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + } + } + } + ], + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + const languageClientConfig: LanguageClientConfig = { + languageId: 'cpp', + connection: { + options: { + $type: 'WorkerDirect', + worker: await config.clangdWorkerHandler.createWorker(), + messagePort: config.lsMessageLocalPort + } + }, + restartOptions: { + retries: 5, + timeout: 1000, + keepWorker: true + }, + clientOptions: { + documentSelector: ['cpp'], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: config.workspaceUri + } + } + }; - const editorAppConfig: EditorAppConfig = {}; + const editorAppConfig: EditorAppConfig = {}; - return { - vscodeApiConfig, - languageClientConfig, - editorAppConfig - }; + return { + vscodeApiConfig, + languageClientConfig, + editorAppConfig + }; }; diff --git a/packages/examples/src/clangd/client/main.ts b/packages/examples/src/clangd/client/main.ts index a69693792..bea6de354 100644 --- a/packages/examples/src/clangd/client/main.ts +++ b/packages/examples/src/clangd/client/main.ts @@ -3,7 +3,11 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; +import { + RegisteredFileSystemProvider, + RegisteredMemoryFile, + registerFileSystemOverlay +} from '@codingame/monaco-vscode-files-service-override'; import * as vscode from 'vscode'; // this is required syntax highlighting import '@codingame/monaco-vscode-cpp-default-extension'; @@ -16,65 +20,65 @@ import { MainRemoteMessageChannelFs } from './mainRemoteMessageChannelFs.js'; import { ClangdWorkerHandler } from './workerHandler.js'; export const runClangdWrapper = async () => { - const channelLs = new MessageChannel(); - const channelFs = new MessageChannel(); + const channelLs = new MessageChannel(); + const channelFs = new MessageChannel(); - const fileSystemProvider = new RegisteredFileSystemProvider(false); - const workspaceFileUri = vscode.Uri.file(`${HOME_DIR}/workspace.code-workspace`); - fileSystemProvider.registerFile(new RegisteredMemoryFile(workspaceFileUri, createDefaultWorkspaceContent(WORKSPACE_PATH))); - registerFileSystemOverlay(1, fileSystemProvider); + const fileSystemProvider = new RegisteredFileSystemProvider(false); + const workspaceFileUri = vscode.Uri.file(`${HOME_DIR}/workspace.code-workspace`); + fileSystemProvider.registerFile(new RegisteredMemoryFile(workspaceFileUri, createDefaultWorkspaceContent(WORKSPACE_PATH))); + registerFileSystemOverlay(1, fileSystemProvider); - const readiness = async () => { - const resourceUri = vscode.Uri.file(`${WORKSPACE_PATH}/main.cpp`); - await vscode.window.showTextDocument(resourceUri); - }; - new MainRemoteMessageChannelFs(fileSystemProvider, channelFs.port1, readiness); + const readiness = async () => { + const resourceUri = vscode.Uri.file(`${WORKSPACE_PATH}/main.cpp`); + await vscode.window.showTextDocument(resourceUri); + }; + new MainRemoteMessageChannelFs(fileSystemProvider, channelFs.port1, readiness); - const clangdWorkerHandler = new ClangdWorkerHandler(); - const appConfig = await createClangdAppConfig({ - htmlContainer: document.body, - workspaceUri: vscode.Uri.file(WORKSPACE_PATH), - workspaceFileUri, - clangdWorkerHandler, - lsMessageLocalPort: channelLs.port1 - }); + const clangdWorkerHandler = new ClangdWorkerHandler(); + const appConfig = await createClangdAppConfig({ + htmlContainer: document.body, + workspaceUri: vscode.Uri.file(WORKSPACE_PATH), + workspaceFileUri, + clangdWorkerHandler, + lsMessageLocalPort: channelLs.port1 + }); - // perform global init - const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); - await apiWrapper.start(); + // perform global init + const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); + await apiWrapper.start(); - const lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); + const lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); - /* @vite-ignore */ - const compressedWorkspaceUrl = new URL('../../../resources/clangd/workspace.zip', import.meta.url).href; - const initConfig = { - lsMessagePort: channelLs.port2, - fsMessagePort: channelFs.port2, - clearIndexedDb: false, - // set to true to use the compressed workspace at the specified URL - useCompressedWorkspace: false, - compressedWorkspaceUrl - }; + /* @vite-ignore */ + const compressedWorkspaceUrl = new URL('../../../resources/clangd/workspace.zip', import.meta.url).href; + const initConfig = { + lsMessagePort: channelLs.port2, + fsMessagePort: channelFs.port2, + clearIndexedDb: false, + // set to true to use the compressed workspace at the specified URL + useCompressedWorkspace: false, + compressedWorkspaceUrl + }; - const startWrapper = async () => { - await clangdWorkerHandler.init(initConfig); - await clangdWorkerHandler.launch(); - await lcWrapper.start(); - }; + const startWrapper = async () => { + await clangdWorkerHandler.init(initConfig); + await clangdWorkerHandler.launch(); + await lcWrapper.start(); + }; - try { - document.querySelector('#button-start')?.addEventListener('click', async () => { - disableElement('button-start', true); - disableElement('button-start-fresh', true); - await startWrapper(); - }); - document.querySelector('#button-start-fresh')?.addEventListener('click', async () => { - initConfig.clearIndexedDb = true; - disableElement('button-start', true); - disableElement('button-start-fresh', true); - await startWrapper(); - }); - } catch (e) { - console.error(e); - } + try { + document.querySelector('#button-start')?.addEventListener('click', async () => { + disableElement('button-start', true); + disableElement('button-start-fresh', true); + await startWrapper(); + }); + document.querySelector('#button-start-fresh')?.addEventListener('click', async () => { + initConfig.clearIndexedDb = true; + disableElement('button-start', true); + disableElement('button-start-fresh', true); + await startWrapper(); + }); + } catch (e) { + console.error(e); + } }; diff --git a/packages/examples/src/clangd/client/mainRemoteMessageChannelFs.ts b/packages/examples/src/clangd/client/mainRemoteMessageChannelFs.ts index a494b0d3f..9b0ef0b3d 100644 --- a/packages/examples/src/clangd/client/mainRemoteMessageChannelFs.ts +++ b/packages/examples/src/clangd/client/mainRemoteMessageChannelFs.ts @@ -11,79 +11,80 @@ import { ComChannelEndpoint, RawPayload, WorkerMessage, type ComRouter } from 'w * Answer the file create request */ export class FileHandlerMain implements ComRouter { + private endpointFs?: ComChannelEndpoint; + private fileSystemProvider: RegisteredFileSystemProvider; + private readiness: () => void; - private endpointFs?: ComChannelEndpoint; - private fileSystemProvider: RegisteredFileSystemProvider; - private readiness: () => void; + constructor(fileSystemProvider: RegisteredFileSystemProvider, readiness: () => void) { + this.fileSystemProvider = fileSystemProvider; + this.readiness = readiness; + } - constructor(fileSystemProvider: RegisteredFileSystemProvider, readiness: () => void) { - this.fileSystemProvider = fileSystemProvider; - this.readiness = readiness; - } + setComChannelEndpoint(comChannelEndpoint: ComChannelEndpoint): void { + this.endpointFs = comChannelEndpoint; + } - setComChannelEndpoint(comChannelEndpoint: ComChannelEndpoint): void { - this.endpointFs = comChannelEndpoint; - } + async fs_driver_init(message: WorkerMessage) { + await this.endpointFs?.sentAnswer({ + message: WorkerMessage.createFromExisting(message, { + overrideCmd: 'fs_driver_init_confirm' + }), + awaitAnswer: false + }); - async fs_driver_init(message: WorkerMessage) { - await this.endpointFs?.sentAnswer({ - message: WorkerMessage.createFromExisting(message, { - overrideCmd: 'fs_driver_init_confirm', - }), - awaitAnswer: false - }); + // send double confirmation + await this.endpointFs?.sentMessage({ + message: WorkerMessage.fromPayload( + new RawPayload({ + hello: 'worker' + }), + 'fs_follower_init' + ), + awaitAnswer: true, + expectedAnswer: 'fs_follower_init_confirm' + }); + } - // send double confirmation - await this.endpointFs?.sentMessage({ - message: WorkerMessage.fromPayload(new RawPayload({ - hello: 'worker', - }), 'fs_follower_init'), - awaitAnswer: true, - expectedAnswer: 'fs_follower_init_confirm' - }); - } + async syncFile(message: WorkerMessage) { + const rawPayload = message.payloads[0] as RawPayload; + const resourceUri = vscode.Uri.file(rawPayload.message.raw.resourceUri); + this.fileSystemProvider.registerFile(new RegisteredMemoryFile(resourceUri, rawPayload.message.raw.content)); - async syncFile(message: WorkerMessage) { - const rawPayload = message.payloads[0] as RawPayload; - const resourceUri = vscode.Uri.file(rawPayload.message.raw.resourceUri); - this.fileSystemProvider.registerFile(new RegisteredMemoryFile(resourceUri, rawPayload.message.raw.content)); + await this.endpointFs?.sentAnswer({ + message: WorkerMessage.createFromExisting(message, { + overrideCmd: 'syncFile_confirm', + overridePayloads: new RawPayload({ + status: 'created', + message: `Created: ${rawPayload.message.raw.resourceUri}` + }) + }) + }); + } - await this.endpointFs?.sentAnswer({ - message: WorkerMessage.createFromExisting(message, { - overrideCmd: 'syncFile_confirm', - overridePayloads: new RawPayload({ - status: 'created', - message: `Created: ${rawPayload.message.raw.resourceUri}` - }) - }) - }); - } + async fs_driver_ready(message: WorkerMessage) { + this.readiness(); - async fs_driver_ready(message: WorkerMessage) { - this.readiness(); - - await this.endpointFs?.sentAnswer({ - message: WorkerMessage.createFromExisting(message, { - overrideCmd: 'fs_driver_ready_confirm', - }), - awaitAnswer: false - }); - } + await this.endpointFs?.sentAnswer({ + message: WorkerMessage.createFromExisting(message, { + overrideCmd: 'fs_driver_ready_confirm' + }), + awaitAnswer: false + }); + } } export class MainRemoteMessageChannelFs { - - constructor(fileSystemProvider: RegisteredFileSystemProvider, port: MessagePort, readiness: () => void) { - const fileHandlerMain = new FileHandlerMain(fileSystemProvider, readiness); - const endpointFs = new ComChannelEndpoint({ - endpointId: 21, - endpointName: 'port_main_fs', - endpointConfig: { - $type: 'DirectImplConfig', - impl: port - }, - verbose: false - }); - endpointFs.connect(fileHandlerMain); - } + constructor(fileSystemProvider: RegisteredFileSystemProvider, port: MessagePort, readiness: () => void) { + const fileHandlerMain = new FileHandlerMain(fileSystemProvider, readiness); + const endpointFs = new ComChannelEndpoint({ + endpointId: 21, + endpointName: 'port_main_fs', + endpointConfig: { + $type: 'DirectImplConfig', + impl: port + }, + verbose: false + }); + endpointFs.connect(fileHandlerMain); + } } diff --git a/packages/examples/src/clangd/client/workerHandler.ts b/packages/examples/src/clangd/client/workerHandler.ts index 9378c94a4..0eaa62a9b 100644 --- a/packages/examples/src/clangd/client/workerHandler.ts +++ b/packages/examples/src/clangd/client/workerHandler.ts @@ -6,65 +6,65 @@ import { ComChannelEndpoint, type ComRouter, RawPayload, WorkerMessage } from 'wtd-core'; class ClangdInteractionMain implements ComRouter { + setComChannelEndpoint(_comChannelEndpoint: ComChannelEndpoint): void {} - setComChannelEndpoint(_comChannelEndpoint: ComChannelEndpoint): void { - } + clangd_progress(_message: WorkerMessage) {} - clangd_progress(_message: WorkerMessage) { } - - clangd_error(_message: WorkerMessage) { } + clangd_error(_message: WorkerMessage) {} } export class ClangdWorkerHandler { + private interactionMain: ClangdInteractionMain = new ClangdInteractionMain(); + private endpointMain?: ComChannelEndpoint; - private interactionMain: ClangdInteractionMain = new ClangdInteractionMain(); - private endpointMain?: ComChannelEndpoint; - - async createWorker() { - const languageServerWorker = new Worker(new URL('../worker/clangd-server.ts', import.meta.url), { - type: 'module', - name: 'Clangd Server Worker', - }); - this.endpointMain = new ComChannelEndpoint({ - endpointId: 1, - endpointConfig: { - $type: 'DirectImplConfig', - impl: languageServerWorker - }, - verbose: true, - endpointName: 'main_worker' - }); - this.endpointMain.connect(this.interactionMain); + async createWorker() { + const languageServerWorker = new Worker(new URL('../worker/clangd-server.ts', import.meta.url), { + type: 'module', + name: 'Clangd Server Worker' + }); + this.endpointMain = new ComChannelEndpoint({ + endpointId: 1, + endpointConfig: { + $type: 'DirectImplConfig', + impl: languageServerWorker + }, + verbose: true, + endpointName: 'main_worker' + }); + this.endpointMain.connect(this.interactionMain); - return languageServerWorker; - } + return languageServerWorker; + } - async init(config: { - lsMessagePort: MessagePort, - fsMessagePort: MessagePort, - clearIndexedDb: boolean, - useCompressedWorkspace: boolean, - compressedWorkspaceUrl?: string - }) { - await this.endpointMain?.sentMessage({ - message: WorkerMessage.fromPayload(new RawPayload({ - lsMessagePort: config.lsMessagePort, - fsMessagePort: config.fsMessagePort, - clearIndexedDb: config.clearIndexedDb, - useCompressedWorkspace: config.useCompressedWorkspace, - compressedWorkspaceUrl: config.compressedWorkspaceUrl - }), 'clangd_init'), - transferables: [config.lsMessagePort, config.fsMessagePort], - awaitAnswer: true, - expectedAnswer: 'clangd_init_complete' - }); - } + async init(config: { + lsMessagePort: MessagePort; + fsMessagePort: MessagePort; + clearIndexedDb: boolean; + useCompressedWorkspace: boolean; + compressedWorkspaceUrl?: string; + }) { + await this.endpointMain?.sentMessage({ + message: WorkerMessage.fromPayload( + new RawPayload({ + lsMessagePort: config.lsMessagePort, + fsMessagePort: config.fsMessagePort, + clearIndexedDb: config.clearIndexedDb, + useCompressedWorkspace: config.useCompressedWorkspace, + compressedWorkspaceUrl: config.compressedWorkspaceUrl + }), + 'clangd_init' + ), + transferables: [config.lsMessagePort, config.fsMessagePort], + awaitAnswer: true, + expectedAnswer: 'clangd_init_complete' + }); + } - async launch() { - await this.endpointMain?.sentMessage({ - message: WorkerMessage.fromPayload(new RawPayload({}), 'clangd_launch'), - awaitAnswer: true, - expectedAnswer: 'clangd_launch_complete' - }); - } + async launch() { + await this.endpointMain?.sentMessage({ + message: WorkerMessage.fromPayload(new RawPayload({}), 'clangd_launch'), + awaitAnswer: true, + expectedAnswer: 'clangd_launch_complete' + }); + } } diff --git a/packages/examples/src/clangd/worker/clangd-server.ts b/packages/examples/src/clangd/worker/clangd-server.ts index 6799dd7ac..809625a5c 100644 --- a/packages/examples/src/clangd/worker/clangd-server.ts +++ b/packages/examples/src/clangd/worker/clangd-server.ts @@ -17,460 +17,458 @@ import JSZip from 'jszip'; declare const self: DedicatedWorkerGlobalScope; interface RequiredResources { - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - ClangdJsModule: any; - wasmDataUrl: string; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + ClangdJsModule: any; + wasmDataUrl: string; } export class ClangdInteractionWorker implements ComRouter { - - private endpointWorker?: ComChannelEndpoint; - - private reader?: BrowserMessageReader; - private writer?: BrowserMessageWriter; - - private lsMessagePort?: MessagePort; - private fsMessagePort?: MessagePort; - - private emscriptenFS?: typeof FS; - private remoteFs?: WorkerRemoteMessageChannelFs; - - private clearIndexedDb: boolean; - private useCompressedWorkspace: boolean; - private compressedWorkspaceUrl?: string; - - private startingAwait?: Promise; - private startingResolve: (value: void | PromiseLike) => void; - - private synchingFSAwait?: Promise; - private synchingFSResolve: (value: void | PromiseLike) => void; - - setComChannelEndpoint(comChannelEndpoint: ComChannelEndpoint): void { - this.endpointWorker = comChannelEndpoint; - } - - /** - * Triggered by worker message - */ - async clangd_init(message: WorkerMessage) { - const rawPayload = (message.payloads![0] as RawPayload).message.raw; - this.lsMessagePort = rawPayload.lsMessagePort as MessagePort; - this.fsMessagePort = rawPayload.fsMessagePort as MessagePort; - this.clearIndexedDb = rawPayload.clearIndexedDb as boolean; - this.useCompressedWorkspace = rawPayload.useCompressedWorkspace as boolean; - this.compressedWorkspaceUrl = rawPayload.compressedWorkspaceUrl as string; - - this.reader = new BrowserMessageReader(this.lsMessagePort); - this.writer = new BrowserMessageWriter(this.lsMessagePort); - - await this.endpointWorker?.sentAnswer({ - message: WorkerMessage.createFromExisting(message, { - overrideCmd: 'clangd_init_complete' - }) - }); - } - - /** - * Triggered by worker message - */ - async clangd_launch(message: WorkerMessage) { - // load everything needed beforehand - const requiredResurces = await this.loadRequiredResources(); - - // start the clangd language server - const clangd = await this.runClangdLanguageServer(requiredResurces); - - // perform all file system updates - this.emscriptenFS = clangd.FS as typeof FS; - await this.updateWorkerFilesystem(requiredResurces); - await this.updateRemoteFilesystem(); - - // run main clangd - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - (clangd as any).callMain([]); - - // send the launch complete message to the client - await this.endpointWorker?.sentAnswer({ - message: WorkerMessage.createFromExisting(message, { - overrideCmd: 'clangd_launch_complete' - }) - }); + private endpointWorker?: ComChannelEndpoint; + + private reader?: BrowserMessageReader; + private writer?: BrowserMessageWriter; + + private lsMessagePort?: MessagePort; + private fsMessagePort?: MessagePort; + + private emscriptenFS?: typeof FS; + private remoteFs?: WorkerRemoteMessageChannelFs; + + private clearIndexedDb: boolean; + private useCompressedWorkspace: boolean; + private compressedWorkspaceUrl?: string; + + private startingAwait?: Promise; + private startingResolve: (value: void | PromiseLike) => void; + + private synchingFSAwait?: Promise; + private synchingFSResolve: (value: void | PromiseLike) => void; + + setComChannelEndpoint(comChannelEndpoint: ComChannelEndpoint): void { + this.endpointWorker = comChannelEndpoint; + } + + /** + * Triggered by worker message + */ + async clangd_init(message: WorkerMessage) { + const rawPayload = (message.payloads![0] as RawPayload).message.raw; + this.lsMessagePort = rawPayload.lsMessagePort as MessagePort; + this.fsMessagePort = rawPayload.fsMessagePort as MessagePort; + this.clearIndexedDb = rawPayload.clearIndexedDb as boolean; + this.useCompressedWorkspace = rawPayload.useCompressedWorkspace as boolean; + this.compressedWorkspaceUrl = rawPayload.compressedWorkspaceUrl as string; + + this.reader = new BrowserMessageReader(this.lsMessagePort); + this.writer = new BrowserMessageWriter(this.lsMessagePort); + + await this.endpointWorker?.sentAnswer({ + message: WorkerMessage.createFromExisting(message, { + overrideCmd: 'clangd_init_complete' + }) + }); + } + + /** + * Triggered by worker message + */ + async clangd_launch(message: WorkerMessage) { + // load everything needed beforehand + const requiredResurces = await this.loadRequiredResources(); + + // start the clangd language server + const clangd = await this.runClangdLanguageServer(requiredResurces); + + // perform all file system updates + this.emscriptenFS = clangd.FS as typeof FS; + await this.updateWorkerFilesystem(requiredResurces); + await this.updateRemoteFilesystem(); + + // run main clangd + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + (clangd as any).callMain([]); + + // send the launch complete message to the client + await this.endpointWorker?.sentAnswer({ + message: WorkerMessage.createFromExisting(message, { + overrideCmd: 'clangd_launch_complete' + }) + }); + } + + private async loadRequiredResources(): Promise { + const clangdWasmUrl = new URL('../../../resources/clangd/wasm/clangd.wasm', import.meta.url); + const clangdJsUrl = new URL('../../../resources/clangd/wasm/clangd.js', import.meta.url); + + // Pre-fetch wasm file + const wasmReader = (await fetch(clangdWasmUrl)).body!.getReader(); + + const chunks: BlobPart[] = []; + let loadingComplete = false; + while (!loadingComplete) { + const { done, value } = await wasmReader.read(); + loadingComplete = done; + if (value !== undefined) { + chunks.push(value); + } } - - private async loadRequiredResources(): Promise { - const clangdWasmUrl = new URL('../../../resources/clangd/wasm/clangd.wasm', import.meta.url); - const clangdJsUrl = new URL('../../../resources/clangd/wasm/clangd.js', import.meta.url); - - // Pre-fetch wasm file - const wasmReader = (await fetch(clangdWasmUrl)).body!.getReader(); - - const chunks: BlobPart[] = []; - let loadingComplete = false; - while (!loadingComplete) { - const { done, value } = await wasmReader.read(); - loadingComplete = done; - if (value !== undefined) { - chunks.push(value); - } + const wasmBlob = new Blob(chunks, { type: 'application/wasm' }); + const wasmDataUrl = URL.createObjectURL(wasmBlob); + + const jsModule = import(`${clangdJsUrl}`); + const { default: ClangdJsModule } = await jsModule; + + return { ClangdJsModule, wasmDataUrl }; + } + + private markStarting() { + this.startingAwait = new Promise((resolve) => { + this.startingResolve = resolve; + }); + } + + private markStarted() { + this.startingResolve(); + this.startingAwait = undefined; + } + + /** + * Prepares & starts up a clangd language server instance + * @returns + */ + private async runClangdLanguageServer(requiredResurces: RequiredResources) { + this.markStarting(); + + const textEncoder = new TextEncoder(); + let resolveStdinReady = () => {}; + const stdinChunks: string[] = []; + const currentStdinChunk: Array = []; + + const stdin = (): number | null => { + if (currentStdinChunk.length === 0) { + if (stdinChunks.length === 0) { + // Should not reach here + // stdinChunks.push("Content-Length: 0\r\n", "\r\n"); + console.error('Try to fetch exhausted stdin'); + return null; } - const wasmBlob = new Blob(chunks, { type: 'application/wasm' }); - const wasmDataUrl = URL.createObjectURL(wasmBlob); - - const jsModule = import(`${clangdJsUrl}`); - const { default: ClangdJsModule } = await jsModule; - - return { ClangdJsModule, wasmDataUrl }; + const nextChunk = stdinChunks.shift()!; + currentStdinChunk.push(...textEncoder.encode(nextChunk), null); + } + return currentStdinChunk.shift()!; + }; + + const jsonStream = new JsonStream(); + + const stdout = async (charCode: number) => { + const jsonOrNull = jsonStream.insert(charCode); + if (jsonOrNull !== null) { + console.log('%c%s', 'color: green', jsonOrNull); + await this.writer?.write(JSON.parse(jsonOrNull)); + } + }; + + const LF = 10; + let stderrLine = ''; + const stderr = async (charCode: number) => { + if (charCode === LF) { + console.log('%c%s', 'color: darkorange', stderrLine); + stderrLine = ''; + } else { + stderrLine += String.fromCharCode(charCode); + } + }; + + const stdinReady = async () => { + if (stdinChunks.length === 0) { + return new Promise((r) => (resolveStdinReady = r)); + } + }; + + const onAbort = async () => { + this.writer?.end(); + + await this.endpointWorker?.sentMessage({ + message: WorkerMessage.fromPayload( + new RawPayload({ + type: 'error', + value: 'clangd aborted' + }), + 'clangd_error' + ) + }); + }; + + const onRuntimeInitialized = async () => { + console.log('%c%s', 'color: green', 'Clangd runtime initialized'); + this.markStarted(); + return Promise.resolve(); + }; + + const clangd = await requiredResurces.ClangdJsModule({ + thisProgram: '/usr/bin/clangd', + locateFile: (path: string, prefix: string) => { + return path.endsWith('.wasm') ? requiredResurces.wasmDataUrl : `${prefix}${path}`; + }, + stdinReady, + stdin, + stdout, + stderr, + onExit: onAbort, + onAbort, + onRuntimeInitialized + }); + + // listen for messages from the language server + this.reader?.listen((data) => { + // non-ASCII characters cause bad Content-Length. Just escape them. + const body = JSON.stringify(data).replace(/[\u007F-\uFFFF]/g, (ch) => { + return '\\u' + ch.codePointAt(0)!.toString(16).padStart(4, '0'); + }); + const header = `Content-Length: ${body.length}\r\n`; + const delimiter = '\r\n'; + stdinChunks.push(header, delimiter, body); + resolveStdinReady(); + // console.log("%c%s", "color: red", `${header}${delimiter}${body}`); + }); + + await this.startingAwait; + + return clangd; + } + + private markSynchingFS() { + this.synchingFSAwait = new Promise((resolve) => { + this.synchingFSResolve = resolve; + }); + } + + private markSynchingFSDone() { + this.synchingFSResolve(); + this.synchingFSAwait = undefined; + } + + /** + * Initialize the filesystem using the fs's persistent source. Invoked on start-up + */ + private async populateFS() { + console.log('Populating filesystem: Start'); + this.markSynchingFS(); + this.syncFS(true); + await this.synchingFSAwait; + console.log('Populating filesystem: End'); + } + + /** + * Persist the filesystem to IndexedDB. Can be invoked on shutdown or periodically + */ + private async persistFS() { + console.log('Persisting filesystem: Start'); + this.markSynchingFS(); + this.syncFS(false); + await this.synchingFSAwait; + console.log('Persisting filesystem: End'); + } + + /** + * Used to sync the filesystem from memory to IndexedDB or vice versa: + * populate fs = true; persist fs = false + * @param readOrWrite Whether to read or write the filesystem + */ + private syncFS(readOrWrite: boolean) { + if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); + + this.emscriptenFS.syncfs(readOrWrite, (err) => { + if (err !== null) { + console.error(`Error syncing filesystem: ${err}`); + } + this.markSynchingFSDone(); + }); + } + + private async updateWorkerFilesystem(requiredResurces: RequiredResources) { + if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); + + const t0 = performance.now(); + console.log('Updating Worker FS'); + + // Clear the IndexedDB filesystem if requested + if (this.clearIndexedDb) { + indexedDB.deleteDatabase(WORKSPACE_PATH); } - private markStarting() { - this.startingAwait = new Promise((resolve) => { - this.startingResolve = resolve; - }); - } - - private markStarted() { - this.startingResolve(); - this.startingAwait = undefined; - } - - /** - * Prepares & starts up a clangd language server instance - * @returns - */ - private async runClangdLanguageServer(requiredResurces: RequiredResources) { - this.markStarting(); - - const textEncoder = new TextEncoder(); - let resolveStdinReady = () => { }; - const stdinChunks: string[] = []; - const currentStdinChunk: Array = []; - - const stdin = (): number | null => { - if (currentStdinChunk.length === 0) { - if (stdinChunks.length === 0) { - // Should not reach here - // stdinChunks.push("Content-Length: 0\r\n", "\r\n"); - console.error('Try to fetch exhausted stdin'); - return null; - } - const nextChunk = stdinChunks.shift()!; - currentStdinChunk.push(...textEncoder.encode(nextChunk), null); - } - return currentStdinChunk.shift()!; - }; - - const jsonStream = new JsonStream(); - - const stdout = async (charCode: number) => { - const jsonOrNull = jsonStream.insert(charCode); - if (jsonOrNull !== null) { - console.log('%c%s', 'color: green', jsonOrNull); - await this.writer?.write(JSON.parse(jsonOrNull)); - } - }; - - const LF = 10; - let stderrLine = ''; - const stderr = async (charCode: number) => { - if (charCode === LF) { - console.log('%c%s', 'color: darkorange', stderrLine); - stderrLine = ''; - } else { - stderrLine += String.fromCharCode(charCode); - } - }; - - const stdinReady = async () => { - if (stdinChunks.length === 0) { - return new Promise((r) => (resolveStdinReady = r)); - } - }; - - const onAbort = async () => { - this.writer?.end(); - - await this.endpointWorker?.sentMessage({ - message: WorkerMessage.fromPayload( - new RawPayload({ - type: 'error', - value: 'clangd aborted', - }), - 'clangd_error') - }); - }; - - const onRuntimeInitialized = async () => { - console.log('%c%s', 'color: green', 'Clangd runtime initialized'); - this.markStarted(); - return Promise.resolve(); - }; - - const clangd = await requiredResurces.ClangdJsModule({ - thisProgram: '/usr/bin/clangd', - locateFile: (path: string, prefix: string) => { - return path.endsWith('.wasm') ? requiredResurces.wasmDataUrl : `${prefix}${path}`; - }, - stdinReady, - stdin, - stdout, - stderr, - onExit: onAbort, - onAbort, - onRuntimeInitialized - }); - - // listen for messages from the language server - this.reader?.listen((data) => { - // non-ASCII characters cause bad Content-Length. Just escape them. - const body = JSON.stringify(data).replace(/[\u007F-\uFFFF]/g, (ch) => { - return '\\u' + ch.codePointAt(0)!.toString(16).padStart(4, '0'); - }); - const header = `Content-Length: ${body.length}\r\n`; - const delimiter = '\r\n'; - stdinChunks.push(header, delimiter, body); - resolveStdinReady(); - // console.log("%c%s", "color: red", `${header}${delimiter}${body}`); - }); - - await this.startingAwait; - - return clangd; - } + this.emscriptenFS.createPreloadedFile('/', 'clangd.wasm', requiredResurces.wasmDataUrl, true, true); - private markSynchingFS() { - this.synchingFSAwait = new Promise((resolve) => { - this.synchingFSResolve = resolve; - }); - } + await this.loadWorkspaceFiles(); - private markSynchingFSDone() { - this.synchingFSResolve(); - this.synchingFSAwait = undefined; - } + const t1 = performance.now(); + const msg = `Worker FS: File loading completed in ${t1 - t0}ms.`; + console.log(msg); + } - /** - * Initialize the filesystem using the fs's persistent source. Invoked on start-up - */ - private async populateFS() { - console.log('Populating filesystem: Start'); - this.markSynchingFS(); - this.syncFS(true); - await this.synchingFSAwait; - console.log('Populating filesystem: End'); - } + /** + * Loads workspace files separately or the compressed workspace from a zip archive + */ + private async loadWorkspaceFiles() { + if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); - /** - * Persist the filesystem to IndexedDB. Can be invoked on shutdown or periodically - */ - private async persistFS() { - console.log('Persisting filesystem: Start'); - this.markSynchingFS(); - this.syncFS(false); - await this.synchingFSAwait; - console.log('Persisting filesystem: End'); - } + // setup & prepare the filesystem + this.emscriptenFS.mkdir(WORKSPACE_PATH); - /** - * Used to sync the filesystem from memory to IndexedDB or vice versa: - * populate fs = true; persist fs = false - * @param readOrWrite Whether to read or write the filesystem - */ - private syncFS(readOrWrite: boolean) { - if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); - - this.emscriptenFS.syncfs(readOrWrite, (err) => { - if (err !== null) { - console.error(`Error syncing filesystem: ${err}`); - } - this.markSynchingFSDone(); - }); + // Mounting IndexedDB filesystem + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + this.emscriptenFS.mount((this.emscriptenFS as any).filesystems.IDBFS, {}, WORKSPACE_PATH); + + // Synchronize the filesystem from IndexedDB to memory + await this.populateFS(); + + // Determines whether the workspace is already loaded from IndexedDB + let isWorkspaceLoaded = true; + try { + this.emscriptenFS.lookupPath(`${WORKSPACE_PATH}/.clangd`, { parent: false }); + console.log('Workspace FOUND'); + } catch (e) { + console.warn('Workspace NOT found: ' + e); + isWorkspaceLoaded = false; } - private async updateWorkerFilesystem(requiredResurces: RequiredResources) { - if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); - - const t0 = performance.now(); - console.log('Updating Worker FS'); - - // Clear the IndexedDB filesystem if requested - if (this.clearIndexedDb) { - indexedDB.deleteDatabase(WORKSPACE_PATH); + if (!isWorkspaceLoaded) { + let mainFiles: Record Promise> = {}; + if (this.useCompressedWorkspace && this.compressedWorkspaceUrl !== undefined) { + // Fetches a compressed workspace from a given URL (zip file) + // The additional conversion to array buffer is necessary for JSZip to work correctly + // It is expected that there is a workspace directory at top level in the zip file + const compressedWorkspace = await (await fetch(this.compressedWorkspaceUrl)).arrayBuffer(); + const zip = await JSZip.loadAsync(compressedWorkspace); + + for (const [relativePath, file] of Object.entries(zip.files)) { + if (/\.(cpp|c|h|hpp|)|.clangd$/.test(relativePath)) { + // trim off the leading 'workspace' directory part of the path, the rest is okay to have + const rpath = relativePath.replace(/^workspace/, ''); + mainFiles[rpath] = () => file.async('string'); + } } - this.emscriptenFS.createPreloadedFile('/', 'clangd.wasm', requiredResurces.wasmDataUrl, true, true); - - await this.loadWorkspaceFiles(); + await this.processInputFiles(mainFiles, '../../../resources/clangd/workspace'); + } else { + // write clang config + this.emscriptenFS.writeFile(`${WORKSPACE_PATH}/.clangd`, clangdConfig); - const t1 = performance.now(); - const msg = `Worker FS: File loading completed in ${t1 - t0}ms.`; - console.log(msg); + mainFiles = import.meta.glob('../../../resources/clangd/workspace/*.{cpp,c,h,hpp}', { query: '?raw' }); + await this.processInputFiles(mainFiles, '../../../resources/clangd/workspace'); + } } - /** - * Loads workspace files separately or the compressed workspace from a zip archive - */ - private async loadWorkspaceFiles() { - if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); - - // setup & prepare the filesystem - this.emscriptenFS.mkdir(WORKSPACE_PATH); - - // Mounting IndexedDB filesystem - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - this.emscriptenFS.mount((this.emscriptenFS as any).filesystems.IDBFS, {}, WORKSPACE_PATH); - - // Synchronize the filesystem from IndexedDB to memory - await this.populateFS(); - - // Determines whether the workspace is already loaded from IndexedDB - let isWorkspaceLoaded = true; - try { - this.emscriptenFS.lookupPath(`${WORKSPACE_PATH}/.clangd`, { parent: false }); - console.log('Workspace FOUND'); - } catch (e) { - console.warn('Workspace NOT found: ' + e); - isWorkspaceLoaded = false; + // save the workspace to IndexedDB + await this.persistFS(); + } + + private async processInputFiles(files: Record Promise>, dirReplacer: string) { + if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); + + const dirsToCreate = new Set(); + const filesToUse: Record Promise> = {}; + for (const [sourceFile, content] of Object.entries(files)) { + let shortSourceFile = sourceFile.replace(dirReplacer, ''); + if (!shortSourceFile.startsWith('//')) { + shortSourceFile = shortSourceFile.substring(1); + } + const targetFile = `${WORKSPACE_PATH}/${shortSourceFile}`; + const targetDir = targetFile.substring(0, targetFile.lastIndexOf('/')); + + // store only un-ignore target files + filesToUse[targetFile] = content; + + // List all parent directories + let dirToCreate = ''; + const targetDirParts = targetDir.split('/'); + for (const part of targetDirParts) { + if (part.length > 0) { + dirToCreate = `${dirToCreate}/${part}`; + // set reduces to unique directories + dirsToCreate.add(dirToCreate); } - - if (!isWorkspaceLoaded) { - let mainFiles: Record Promise> = {}; - if (this.useCompressedWorkspace && this.compressedWorkspaceUrl !== undefined) { - - // Fetches a compressed workspace from a given URL (zip file) - // The additional conversion to array buffer is necessary for JSZip to work correctly - // It is expected that there is a workspace directory at top level in the zip file - const compressedWorkspace = await (await fetch(this.compressedWorkspaceUrl)).arrayBuffer(); - const zip = await JSZip.loadAsync(compressedWorkspace); - - for (const [relativePath, file] of Object.entries(zip.files)) { - if (/\.(cpp|c|h|hpp|)|.clangd$/.test(relativePath)) { - // trim off the leading 'workspace' directory part of the path, the rest is okay to have - const rpath = relativePath.replace(/^workspace/, ''); - mainFiles[rpath] = () => file.async('string'); - } - } - - await this.processInputFiles(mainFiles, '../../../resources/clangd/workspace'); - } else { - // write clang config - this.emscriptenFS.writeFile(`${WORKSPACE_PATH}/.clangd`, clangdConfig); - - mainFiles = import.meta.glob('../../../resources/clangd/workspace/*.{cpp,c,h,hpp}', { query: '?raw' }); - await this.processInputFiles(mainFiles, '../../../resources/clangd/workspace'); - } - } - - // save the workspace to IndexedDB - await this.persistFS(); + } } - private async processInputFiles(files: Record Promise>, dirReplacer: string) { - if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); - - const dirsToCreate = new Set(); - const filesToUse: Record Promise> = {}; - for (const [sourceFile, content] of Object.entries(files)) { - - let shortSourceFile = sourceFile.replace(dirReplacer, ''); - if (!shortSourceFile.startsWith('//')) { - shortSourceFile = shortSourceFile.substring(1); - } - const targetFile = `${WORKSPACE_PATH}/${shortSourceFile}`; - const targetDir = targetFile.substring(0, targetFile.lastIndexOf('/')); - - // store only un-ignore target files - filesToUse[targetFile] = content; - - // List all parent directories - let dirToCreate = ''; - const targetDirParts = targetDir.split('/'); - for (const part of targetDirParts) { - - if (part.length > 0) { - dirToCreate = `${dirToCreate}/${part}`; - // set reduces to unique directories - dirsToCreate.add(dirToCreate); - } - } + // create unique directories + for (const dirToCreate of dirsToCreate) { + try { + this.emscriptenFS.mkdir(dirToCreate); + const { mode } = this.emscriptenFS.lookupPath(dirToCreate, { parent: false }).node; + if (this.emscriptenFS.isDir(mode)) { + console.log(`Create dir: ${dirToCreate} mode: ${mode}`); } - - // create unique directories - for (const dirToCreate of dirsToCreate) { - try { - this.emscriptenFS.mkdir(dirToCreate); - const { mode } = this.emscriptenFS.lookupPath(dirToCreate, { parent: false }).node; - if (this.emscriptenFS.isDir(mode)) { - console.log(`Create dir: ${dirToCreate} mode: ${mode}`); - } - } catch (e) { - if (e instanceof Object && (e as { code: string }).code === 'EEXIST') { - console.log(`Directory already exists: ${dirToCreate}`); - } - } - } - - // write out files - type RawContent = { default: string }; - for (const [targetFile, content] of Object.entries(filesToUse)) { - try { - let contentAsString: string; - if (this.useCompressedWorkspace) { - contentAsString = await content() as string; - } else { - contentAsString = (await content() as RawContent).default; - } - this.emscriptenFS.writeFile(targetFile, contentAsString); - console.log(`Wrote file: ${targetFile}`); - } catch (e) { - console.error(`Error writing ${targetFile}: ${String(e)}`); - } + } catch (e) { + if (e instanceof Object && (e as { code: string }).code === 'EEXIST') { + console.log(`Directory already exists: ${dirToCreate}`); } + } } - private async updateRemoteFilesystem() { - if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); - if (this.fsMessagePort === undefined) throw new Error('MessagePort is not available! Aborting ...'); - - const t0 = performance.now(); - - console.log('Updating Remote FS'); - const allFilesAndDirectories = fsReadAllFiles(this.emscriptenFS, '/'); - - this.remoteFs = new WorkerRemoteMessageChannelFs(this.fsMessagePort, this.emscriptenFS); - await this.remoteFs.init(); - - const allPromises = []; - for (const filename of allFilesAndDirectories.files) { - try { - // just push the binary content to the client - const content = this.emscriptenFS.readFile(filename, { encoding: 'binary' }); - allPromises.push(this.remoteFs.syncFile({ - resourceUri: filename, - content: content as unknown as ArrayBufferLike - })); - - } catch (e) { - console.error(`Unexpected error when reading file ${filename}: ${String(e)}`); - } + // write out files + type RawContent = { default: string }; + for (const [targetFile, content] of Object.entries(filesToUse)) { + try { + let contentAsString: string; + if (this.useCompressedWorkspace) { + contentAsString = (await content()) as string; + } else { + contentAsString = ((await content()) as RawContent).default; } + this.emscriptenFS.writeFile(targetFile, contentAsString); + console.log(`Wrote file: ${targetFile}`); + } catch (e) { + console.error(`Error writing ${targetFile}: ${String(e)}`); + } + } + } + + private async updateRemoteFilesystem() { + if (this.emscriptenFS === undefined) throw new Error('Emscripten FS is not available! Aborting ...'); + if (this.fsMessagePort === undefined) throw new Error('MessagePort is not available! Aborting ...'); + + const t0 = performance.now(); + + console.log('Updating Remote FS'); + const allFilesAndDirectories = fsReadAllFiles(this.emscriptenFS, '/'); + + this.remoteFs = new WorkerRemoteMessageChannelFs(this.fsMessagePort, this.emscriptenFS); + await this.remoteFs.init(); + + const allPromises = []; + for (const filename of allFilesAndDirectories.files) { + try { + // just push the binary content to the client + const content = this.emscriptenFS.readFile(filename, { encoding: 'binary' }); + allPromises.push( + this.remoteFs.syncFile({ + resourceUri: filename, + content: content as unknown as ArrayBufferLike + }) + ); + } catch (e) { + console.error(`Unexpected error when reading file ${filename}: ${String(e)}`); + } + } - await Promise.all(allPromises); + await Promise.all(allPromises); - // signal the client everything is ready - await this.remoteFs.ready(); + // signal the client everything is ready + await this.remoteFs.ready(); - const t1 = performance.now(); - const msg = `Remote FS: File loading completed in ${t1 - t0}ms.`; - console.log(msg); - } + const t1 = performance.now(); + const msg = `Remote FS: File loading completed in ${t1 - t0}ms.`; + console.log(msg); + } } new ComChannelEndpoint({ - endpointId: 2000, - endpointConfig: { - $type: 'DirectImplConfig', - impl: self - }, - verbose: true, - endpointName: 'clangd_main' + endpointId: 2000, + endpointConfig: { + $type: 'DirectImplConfig', + impl: self + }, + verbose: true, + endpointName: 'clangd_main' }).connect(new ClangdInteractionWorker()); diff --git a/packages/examples/src/clangd/worker/json_stream.ts b/packages/examples/src/clangd/worker/json_stream.ts index 1924b868c..fdf2871a5 100644 --- a/packages/examples/src/clangd/worker/json_stream.ts +++ b/packages/examples/src/clangd/worker/json_stream.ts @@ -9,56 +9,56 @@ const RBRACE = 125; const BACKSLASH = 92; export class JsonStream { - #inJson = false; - #rawText: number[] = []; - #unbalancedBraces = 0; - #inString = false; - #inEscape = 0; - readonly #textDecoder = new TextDecoder(); + #inJson = false; + #rawText: number[] = []; + #unbalancedBraces = 0; + #inString = false; + #inEscape = 0; + readonly #textDecoder = new TextDecoder(); - constructor() { } + constructor() {} - /** - * Insert a char into current partial JSON - * @param charCode - * @returns Complete JSON string if the inserted char makes the JSON complete, otherwise null - */ - insert(charCode: number): string | null { - if (!this.#inJson && charCode === LBRACE) { - this.#inJson = true; - this.#rawText = []; + /** + * Insert a char into current partial JSON + * @param charCode + * @returns Complete JSON string if the inserted char makes the JSON complete, otherwise null + */ + insert(charCode: number): string | null { + if (!this.#inJson && charCode === LBRACE) { + this.#inJson = true; + this.#rawText = []; + } + if (!this.#inJson) { + return null; + } + this.#rawText.push(charCode); + if (this.#inString) { + if (this.#inEscape > 0) { + if (charCode === 75) { + // \uxxxx + this.#inEscape += 4; } - if (!this.#inJson) { - return null; + this.#inEscape--; + } else { + if (charCode === BACKSLASH) { + this.#inEscape = 1; + } else if (charCode === QUOT) { + this.#inString = false; } - this.#rawText.push(charCode); - if (this.#inString) { - if (this.#inEscape > 0) { - if (charCode === 75) { - // \uxxxx - this.#inEscape += 4; - } - this.#inEscape--; - } else { - if (charCode === BACKSLASH) { - this.#inEscape = 1; - } else if (charCode === QUOT) { - this.#inString = false; - } - } - } else { - if (charCode === LBRACE) { - this.#unbalancedBraces++; - } else if (charCode === RBRACE) { - this.#unbalancedBraces--; - if (this.#unbalancedBraces === 0) { - this.#inJson = false; - return this.#textDecoder.decode(new Uint8Array(this.#rawText)); - } - } else if (charCode === QUOT) { - this.#inString = true; - } + } + } else { + if (charCode === LBRACE) { + this.#unbalancedBraces++; + } else if (charCode === RBRACE) { + this.#unbalancedBraces--; + if (this.#unbalancedBraces === 0) { + this.#inJson = false; + return this.#textDecoder.decode(new Uint8Array(this.#rawText)); } - return null; + } else if (charCode === QUOT) { + this.#inString = true; + } } + return null; + } } diff --git a/packages/examples/src/clangd/worker/memfs-tools.ts b/packages/examples/src/clangd/worker/memfs-tools.ts index 8aacb9f1d..18af38b83 100644 --- a/packages/examples/src/clangd/worker/memfs-tools.ts +++ b/packages/examples/src/clangd/worker/memfs-tools.ts @@ -4,40 +4,40 @@ * ------------------------------------------------------------------------------------------ */ export const fsReadAllFiles = (emscriptenFs: typeof FS, baseFolder: string) => { - const files: string[] = []; - const directories: string[] = []; + const files: string[] = []; + const directories: string[] = []; - const crawlFolder = (folder: string) => { - const folderListing = emscriptenFs.readdir(folder); - for (const name of folderListing) { - // do not process the current and parent directory - if (name === '.' || name === '..') { - continue; - } + const crawlFolder = (folder: string) => { + const folderListing = emscriptenFs.readdir(folder); + for (const name of folderListing) { + // do not process the current and parent directory + if (name === '.' || name === '..') { + continue; + } - const path = `${folder}/${name}`.replaceAll('//', '/'); - try { - const { mode } = emscriptenFs.lookupPath(path, { parent: false }).node; - if (emscriptenFs.isFile(mode)) { - files.push(path); - } else if (emscriptenFs.isDir(mode)) { - directories.push(path); - crawlFolder(path); - } else { - console.log(`Ignored: ${path}`); - } - } catch (error) { - console.error(`${path} provoked an error: ${String(error)}`); - } + const path = `${folder}/${name}`.replaceAll('//', '/'); + try { + const { mode } = emscriptenFs.lookupPath(path, { parent: false }).node; + if (emscriptenFs.isFile(mode)) { + files.push(path); + } else if (emscriptenFs.isDir(mode)) { + directories.push(path); + crawlFolder(path); + } else { + console.log(`Ignored: ${path}`); } - }; + } catch (error) { + console.error(`${path} provoked an error: ${String(error)}`); + } + } + }; - crawlFolder(baseFolder); + crawlFolder(baseFolder); - // files.forEach((file) => { console.log(file); }); - console.log(`Found ${files.length} files.`); - return { - files, - directories - }; + // files.forEach((file) => { console.log(file); }); + console.log(`Found ${files.length} files.`); + return { + files, + directories + }; }; diff --git a/packages/examples/src/clangd/worker/workerRemoteMessageChannelFs.ts b/packages/examples/src/clangd/worker/workerRemoteMessageChannelFs.ts index a9bf27bc6..ca7cdf2eb 100644 --- a/packages/examples/src/clangd/worker/workerRemoteMessageChannelFs.ts +++ b/packages/examples/src/clangd/worker/workerRemoteMessageChannelFs.ts @@ -3,111 +3,125 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import type { DirectoryListingRequest, DirectoryListingRequestResult, EndpointType, FileReadRequest, FileReadRequestResult, FileSystemEndpoint, FileUpdate, FileUpdateResult, StatsRequest, StatsRequestResult } from 'monaco-languageclient/fs'; +import type { + DirectoryListingRequest, + DirectoryListingRequestResult, + EndpointType, + FileReadRequest, + FileReadRequestResult, + FileSystemEndpoint, + FileUpdate, + FileUpdateResult, + StatsRequest, + StatsRequestResult +} from 'monaco-languageclient/fs'; import { ComChannelEndpoint, type ComRouter, RawPayload, WorkerMessage } from 'wtd-core'; class FileHandlerWorker implements ComRouter { - - private portClandFsEndpoint: ComChannelEndpoint; - - setComChannelEndpoint(comChannelEndpoint: ComChannelEndpoint): void { - this.portClandFsEndpoint = comChannelEndpoint; - } - - async fs_follower_init(message: WorkerMessage) { - await this.portClandFsEndpoint.sentAnswer({ - message: WorkerMessage.createFromExisting(message, { - overrideCmd: 'fs_follower_init_confirm' - }) - }); - } + private portClandFsEndpoint: ComChannelEndpoint; + + setComChannelEndpoint(comChannelEndpoint: ComChannelEndpoint): void { + this.portClandFsEndpoint = comChannelEndpoint; + } + + async fs_follower_init(message: WorkerMessage) { + await this.portClandFsEndpoint.sentAnswer({ + message: WorkerMessage.createFromExisting(message, { + overrideCmd: 'fs_follower_init_confirm' + }) + }); + } } export class WorkerRemoteMessageChannelFs implements FileSystemEndpoint { - - private clangdFsEndpoint?: ComChannelEndpoint; - private emscriptenFS: typeof FS; - - constructor(port: MessagePort, emscriptenFS: typeof FS) { - this.emscriptenFS = emscriptenFS; - this.clangdFsEndpoint = new ComChannelEndpoint({ - endpointId: 22, - endpointName: 'port_clangd_fs', - endpointConfig: { - $type: 'DirectImplConfig', - impl: port - }, - verbose: false - }); - this.clangdFsEndpoint.connect(new FileHandlerWorker()); - } - - getEndpointType(): EndpointType { - return 'DRIVER'; - } - - async init() { - await this.clangdFsEndpoint?.sentMessage({ - message: WorkerMessage.fromPayload(new RawPayload({ - hello: 'main', - }), 'fs_driver_init'), - awaitAnswer: true, - expectedAnswer: 'fs_driver_init_confirm' - }); - } - - async ready() { - await this.clangdFsEndpoint?.sentMessage({ - message: WorkerMessage.createNew({ - cmd: 'fs_driver_ready' - }), - awaitAnswer: true, - expectedAnswer: 'fs_driver_ready_confirm' - }); - } - - getFileSystemInfo(): string { - return 'This file system sends all requests to the remote end of the message channel.'; - } - - readFile(_params: FileReadRequest): Promise { - return Promise.resolve({ - status: 'denied', - content: '' - }); - } - - writeFile(_params: FileUpdate): Promise { - return Promise.resolve({ status: 'denied' }); - } - - async syncFile(params: FileUpdate): Promise { - const content = this.emscriptenFS.readFile(params.resourceUri, { encoding: 'binary' }); - const result = await this.clangdFsEndpoint?.sentMessage({ - message: WorkerMessage.fromPayload(new RawPayload({ - resourceUri: params.resourceUri, - content: content - }), 'syncFile'), - transferables: [content.buffer], - awaitAnswer: true, - expectedAnswer: 'syncFile_confirm' - }); - - const rawPayload = result?.payloads[0] as RawPayload; - // console.log(rawPayload); - - return Promise.resolve({ - status: rawPayload.message.raw?.status, - message: rawPayload.message.raw?.message - }); - } - - getFileStats(_params: StatsRequest): Promise { - return Promise.reject('No stats available.'); - } - - listFiles(_params: DirectoryListingRequest): Promise { - return Promise.reject('No file listing possible.'); - } - + private clangdFsEndpoint?: ComChannelEndpoint; + private emscriptenFS: typeof FS; + + constructor(port: MessagePort, emscriptenFS: typeof FS) { + this.emscriptenFS = emscriptenFS; + this.clangdFsEndpoint = new ComChannelEndpoint({ + endpointId: 22, + endpointName: 'port_clangd_fs', + endpointConfig: { + $type: 'DirectImplConfig', + impl: port + }, + verbose: false + }); + this.clangdFsEndpoint.connect(new FileHandlerWorker()); + } + + getEndpointType(): EndpointType { + return 'DRIVER'; + } + + async init() { + await this.clangdFsEndpoint?.sentMessage({ + message: WorkerMessage.fromPayload( + new RawPayload({ + hello: 'main' + }), + 'fs_driver_init' + ), + awaitAnswer: true, + expectedAnswer: 'fs_driver_init_confirm' + }); + } + + async ready() { + await this.clangdFsEndpoint?.sentMessage({ + message: WorkerMessage.createNew({ + cmd: 'fs_driver_ready' + }), + awaitAnswer: true, + expectedAnswer: 'fs_driver_ready_confirm' + }); + } + + getFileSystemInfo(): string { + return 'This file system sends all requests to the remote end of the message channel.'; + } + + readFile(_params: FileReadRequest): Promise { + return Promise.resolve({ + status: 'denied', + content: '' + }); + } + + writeFile(_params: FileUpdate): Promise { + return Promise.resolve({ status: 'denied' }); + } + + async syncFile(params: FileUpdate): Promise { + const content = this.emscriptenFS.readFile(params.resourceUri, { encoding: 'binary' }); + const result = await this.clangdFsEndpoint?.sentMessage({ + message: WorkerMessage.fromPayload( + new RawPayload({ + resourceUri: params.resourceUri, + content: content + }), + 'syncFile' + ), + transferables: [content.buffer], + awaitAnswer: true, + expectedAnswer: 'syncFile_confirm' + }); + + const rawPayload = result?.payloads[0] as RawPayload; + // console.log(rawPayload); + + return Promise.resolve({ + status: rawPayload.message.raw?.status, + message: rawPayload.message.raw?.message + }); + } + + getFileStats(_params: StatsRequest): Promise { + return Promise.reject('No stats available.'); + } + + listFiles(_params: DirectoryListingRequest): Promise { + return Promise.reject('No file listing possible.'); + } } diff --git a/packages/examples/src/common/client/extendedClient.ts b/packages/examples/src/common/client/extendedClient.ts index 611eebd54..e57b1d6f1 100644 --- a/packages/examples/src/common/client/extendedClient.ts +++ b/packages/examples/src/common/client/extendedClient.ts @@ -3,7 +3,11 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; +import { + RegisteredFileSystemProvider, + RegisteredMemoryFile, + registerFileSystemOverlay +} from '@codingame/monaco-vscode-files-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import * as vscode from 'vscode'; // this is required syntax highlighting @@ -15,126 +19,126 @@ import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFacto import { createUrl, type ConnectionConfigOptions, type WebSocketConfigOptionsDirect } from 'monaco-languageclient/common'; export const runExtendedClient = async (lsConfig: ExampleLsConfig, helloCode: string) => { - const helloUri = vscode.Uri.file(`${lsConfig.basePath}/workspace/hello.${lsConfig.languageId}`); - const fileSystemProvider = new RegisteredFileSystemProvider(false); - fileSystemProvider.registerFile(new RegisteredMemoryFile(helloUri, helloCode)); - registerFileSystemOverlay(1, fileSystemProvider); + const helloUri = vscode.Uri.file(`${lsConfig.basePath}/workspace/hello.${lsConfig.languageId}`); + const fileSystemProvider = new RegisteredFileSystemProvider(false); + fileSystemProvider.registerFile(new RegisteredMemoryFile(helloUri, helloCode)); + registerFileSystemOverlay(1, fileSystemProvider); - const htmlContainer = document.getElementById('monaco-editor-root')!; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer - }, - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.lightbulb.enabled': 'On', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; + const htmlContainer = document.getElementById('monaco-editor-root')!; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer + }, + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride() + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.lightbulb.enabled': 'On', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + const startOptions = { + onCall: () => { + console.log('Connected to socket.'); + }, + reportStatus: true + }; + const stopOptions = { + onCall: () => { + console.log('Disconnected from socket.'); + }, + reportStatus: true + }; - const startOptions = { - onCall: () => { - console.log('Connected to socket.'); - }, - reportStatus: true + let webSocket: WebSocket | undefined; + let connectionConfigOptions: ConnectionConfigOptions; + const webSocketUrl = `ws://localhost:${lsConfig.port}${lsConfig.path}`; + if (lsConfig.useExternalWebSocket) { + webSocket = new WebSocket(createUrl({ url: webSocketUrl })); + connectionConfigOptions = { + $type: 'WebSocketDirect', + webSocket, + startOptions, + stopOptions }; - const stopOptions = { - onCall: () => { - console.log('Disconnected from socket.'); - }, - reportStatus: true + } else { + connectionConfigOptions = { + $type: 'WebSocketUrl', + url: webSocketUrl, + startOptions, + stopOptions }; + } - let webSocket: WebSocket | undefined; - let connectionConfigOptions: ConnectionConfigOptions; - const webSocketUrl = `ws://localhost:${lsConfig.port}${lsConfig.path}`; - if (lsConfig.useExternalWebSocket) { - webSocket = new WebSocket(createUrl({ url: webSocketUrl })); - connectionConfigOptions = { - $type: 'WebSocketDirect', - webSocket, - startOptions, - stopOptions - }; - } else { - connectionConfigOptions = { - $type: 'WebSocketUrl', - url: webSocketUrl, - startOptions, - stopOptions - }; + const languageClientConfig: LanguageClientConfig = { + languageId: lsConfig.languageId, + connection: { + options: connectionConfigOptions + }, + clientOptions: { + documentSelector: [lsConfig.languageId], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.parse(`${lsConfig.basePath}/workspace`) + } } + }; - const languageClientConfig: LanguageClientConfig = { - languageId: lsConfig.languageId, - connection: { - options: connectionConfigOptions - }, - clientOptions: { - documentSelector: [lsConfig.languageId], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.parse(`${lsConfig.basePath}/workspace`) - } - } - }; - - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: { - text: helloCode, - uri: helloUri.path - } - } - }; + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: { + text: helloCode, + uri: helloUri.path + } + } + }; - // perform global init - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); + // perform global init + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); - const lcWrapper = new LanguageClientWrapper(languageClientConfig); - const editorApp = new EditorApp(editorAppConfig); + const lcWrapper = new LanguageClientWrapper(languageClientConfig); + const editorApp = new EditorApp(editorAppConfig); - try { - document.querySelector('#button-start')?.addEventListener('click', async () => { - if (lsConfig.useExternalWebSocket && webSocket === undefined) { - webSocket = new WebSocket(createUrl({ url: webSocketUrl })); - (connectionConfigOptions as WebSocketConfigOptionsDirect).webSocket = webSocket; - } - await editorApp.start(htmlContainer); - await lcWrapper.start(); + try { + document.querySelector('#button-start')?.addEventListener('click', async () => { + if (lsConfig.useExternalWebSocket && webSocket === undefined) { + webSocket = new WebSocket(createUrl({ url: webSocketUrl })); + (connectionConfigOptions as WebSocketConfigOptionsDirect).webSocket = webSocket; + } + await editorApp.start(htmlContainer); + await lcWrapper.start(); - // open files, so the LS can pick it up - await vscode.workspace.openTextDocument(helloUri); - }); - document.querySelector('#button-dispose')?.addEventListener('click', async () => { - await editorApp.dispose(); - await lcWrapper.dispose(); + // open files, so the LS can pick it up + await vscode.workspace.openTextDocument(helloUri); + }); + document.querySelector('#button-dispose')?.addEventListener('click', async () => { + await editorApp.dispose(); + await lcWrapper.dispose(); - webSocket?.close(); - webSocket = undefined; - }); - } catch (e) { - console.error(e); - } + webSocket?.close(); + webSocket = undefined; + }); + } catch (e) { + console.error(e); + } }; export type ExampleLsConfig = { - port: number; - path: string; - basePath: string; - languageId: string; - useExternalWebSocket: boolean; + port: number; + path: string; + basePath: string; + languageId: string; + useExternalWebSocket: boolean; }; diff --git a/packages/examples/src/common/client/utils.ts b/packages/examples/src/common/client/utils.ts index 4463b76de..0d94cc96f 100644 --- a/packages/examples/src/common/client/utils.ts +++ b/packages/examples/src/common/client/utils.ts @@ -8,28 +8,28 @@ import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; import type { MonacoVscodeApiConfig } from 'monaco-languageclient/vscodeApiWrapper'; export const disableElement = (id: string, disabled: boolean) => { - const button = document.getElementById(id) as HTMLButtonElement | HTMLInputElement | null; - if (button !== null) { - button.disabled = disabled; - } + const button = document.getElementById(id) as HTMLButtonElement | HTMLInputElement | null; + if (button !== null) { + button.disabled = disabled; + } }; export const createDefaultWorkspaceContent = (workspacePath: string) => { - return JSON.stringify( + return JSON.stringify( + { + folders: [ { - folders: [ - { - path: workspacePath - } - ] - }, - null, - 2 - ); + path: workspacePath + } + ] + }, + null, + 2 + ); }; export type ExampleAppConfig = { - vscodeApiConfig: MonacoVscodeApiConfig; - languageClientConfig: LanguageClientConfig; - editorAppConfig: EditorAppConfig; + vscodeApiConfig: MonacoVscodeApiConfig; + languageClientConfig: LanguageClientConfig; + editorAppConfig: EditorAppConfig; }; diff --git a/packages/examples/src/common/node/language-server-runner.ts b/packages/examples/src/common/node/language-server-runner.ts index 0c330e7fa..29fd1e6d5 100644 --- a/packages/examples/src/common/node/language-server-runner.ts +++ b/packages/examples/src/common/node/language-server-runner.ts @@ -9,27 +9,25 @@ import express from 'express'; import { getLocalDirectory, type LanguageServerRunConfig, upgradeWsServer } from './server-commons.js'; /** LSP server runner */ -export const runLanguageServer = ( - languageServerRunConfig: LanguageServerRunConfig -) => { - process.on('uncaughtException', err => { - console.error('Uncaught Exception: ', err.toString()); - if (err.stack !== undefined) { - console.error(err.stack); - } - }); +export const runLanguageServer = (languageServerRunConfig: LanguageServerRunConfig) => { + process.on('uncaughtException', (err) => { + console.error('Uncaught Exception: ', err.toString()); + if (err.stack !== undefined) { + console.error(err.stack); + } + }); - // create the express application - const app = express(); - // server the static content, i.e. index.html - const dir = getLocalDirectory(import.meta.url); - app.use(express.static(dir)); - // start the http server - const httpServer: Server = app.listen(languageServerRunConfig.serverPort); - const wss = new WebSocketServer(languageServerRunConfig.wsServerOptions); - // create the web socket - upgradeWsServer(languageServerRunConfig, { - server: httpServer, - wss - }); + // create the express application + const app = express(); + // server the static content, i.e. index.html + const dir = getLocalDirectory(import.meta.url); + app.use(express.static(dir)); + // start the http server + const httpServer: Server = app.listen(languageServerRunConfig.serverPort); + const wss = new WebSocketServer(languageServerRunConfig.wsServerOptions); + // create the web socket + upgradeWsServer(languageServerRunConfig, { + server: httpServer, + wss + }); }; diff --git a/packages/examples/src/common/node/server-commons.ts b/packages/examples/src/common/node/server-commons.ts index cf441b3de..f6818a93f 100644 --- a/packages/examples/src/common/node/server-commons.ts +++ b/packages/examples/src/common/node/server-commons.ts @@ -10,101 +10,111 @@ import { fileURLToPath, URL } from 'node:url'; import * as cp from 'node:child_process'; import { type IWebSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'; import { createConnection, createServerProcess, forward } from 'vscode-ws-jsonrpc/server'; -import { Message, InitializeRequest, type InitializeParams, type RequestMessage, type ResponseMessage } from 'vscode-languageserver-protocol'; +import { + Message, + InitializeRequest, + type InitializeParams, + type RequestMessage, + type ResponseMessage +} from 'vscode-languageserver-protocol'; export interface LanguageServerRunConfig { - serverName: string; - pathName: string; - serverPort: number; - runCommand: string; - runCommandArgs: string[]; - wsServerOptions: ServerOptions, - spawnOptions?: cp.SpawnOptions; - logMessages?: boolean; - requestMessageHandler?: (message: RequestMessage) => RequestMessage; - responseMessageHandler?: (message: ResponseMessage) => ResponseMessage; + serverName: string; + pathName: string; + serverPort: number; + runCommand: string; + runCommandArgs: string[]; + wsServerOptions: ServerOptions; + spawnOptions?: cp.SpawnOptions; + logMessages?: boolean; + requestMessageHandler?: (message: RequestMessage) => RequestMessage; + responseMessageHandler?: (message: ResponseMessage) => ResponseMessage; } /** * start the language server inside the current process */ export const launchLanguageServer = (runconfig: LanguageServerRunConfig, socket: IWebSocket) => { - const { serverName, runCommand, runCommandArgs, spawnOptions } = runconfig; - // start the language server as an external process - const reader = new WebSocketMessageReader(socket); - const writer = new WebSocketMessageWriter(socket); - const socketConnection = createConnection(reader, writer, () => socket.dispose()); - const serverConnection = createServerProcess(serverName, runCommand, runCommandArgs, spawnOptions); - if (serverConnection !== undefined) { - forward(socketConnection, serverConnection, message => { - if (Message.isRequest(message)) { - if (message.method === InitializeRequest.type.method) { - const initializeParams = message.params as InitializeParams; - initializeParams.processId = process.pid; - } + const { serverName, runCommand, runCommandArgs, spawnOptions } = runconfig; + // start the language server as an external process + const reader = new WebSocketMessageReader(socket); + const writer = new WebSocketMessageWriter(socket); + const socketConnection = createConnection(reader, writer, () => socket.dispose()); + const serverConnection = createServerProcess(serverName, runCommand, runCommandArgs, spawnOptions); + if (serverConnection !== undefined) { + forward(socketConnection, serverConnection, (message) => { + if (Message.isRequest(message)) { + if (message.method === InitializeRequest.type.method) { + const initializeParams = message.params as InitializeParams; + initializeParams.processId = process.pid; + } - if (runconfig.logMessages ?? false) { - console.log(`${serverName} Server received: ${message.method}`); - console.log(message); - } - if (runconfig.requestMessageHandler !== undefined) { - return runconfig.requestMessageHandler(message); - } - } - if (Message.isResponse(message)) { - if (runconfig.logMessages ?? false) { - console.log(`${serverName} Server sent:`); - console.log(message); - } - if (runconfig.responseMessageHandler !== undefined) { - return runconfig.responseMessageHandler(message); - } - } - return message; - }); - } + if (runconfig.logMessages ?? false) { + console.log(`${serverName} Server received: ${message.method}`); + console.log(message); + } + if (runconfig.requestMessageHandler !== undefined) { + return runconfig.requestMessageHandler(message); + } + } + if (Message.isResponse(message)) { + if (runconfig.logMessages ?? false) { + console.log(`${serverName} Server sent:`); + console.log(message); + } + if (runconfig.responseMessageHandler !== undefined) { + return runconfig.responseMessageHandler(message); + } + } + return message; + }); + } }; -export const upgradeWsServer = (runconfig: LanguageServerRunConfig, - config: { - server: Server, - wss: WebSocketServer - }) => { - config.server.on('upgrade', (request: IncomingMessage, socket: Socket, head: Buffer) => { - const baseURL = `http://${request.headers.host}/`; - const pathName = request.url !== undefined ? new URL(request.url, baseURL).pathname : undefined; - if (pathName === runconfig.pathName) { - config.wss.handleUpgrade(request, socket, head, webSocket => { - const socket: IWebSocket = { - send: content => webSocket.send(content, error => { - if (error !== undefined) { - throw error; - } - }), - onMessage: cb => webSocket.on('message', (data) => { - cb(data); - }), - onError: cb => webSocket.on('error', cb), - onClose: cb => webSocket.on('close', cb), - dispose: () => webSocket.close() - }; - // launch the server when the web socket is opened - if (webSocket.readyState === webSocket.OPEN) { - launchLanguageServer(runconfig, socket); - } else { - webSocket.on('open', () => { - launchLanguageServer(runconfig, socket); - }); - } - }); +export const upgradeWsServer = ( + runconfig: LanguageServerRunConfig, + config: { + server: Server; + wss: WebSocketServer; + } +) => { + config.server.on('upgrade', (request: IncomingMessage, socket: Socket, head: Buffer) => { + const baseURL = `http://${request.headers.host}/`; + const pathName = request.url !== undefined ? new URL(request.url, baseURL).pathname : undefined; + if (pathName === runconfig.pathName) { + config.wss.handleUpgrade(request, socket, head, (webSocket) => { + const socket: IWebSocket = { + send: (content) => + webSocket.send(content, (error) => { + if (error !== undefined) { + throw error; + } + }), + onMessage: (cb) => + webSocket.on('message', (data) => { + cb(data); + }), + onError: (cb) => webSocket.on('error', cb), + onClose: (cb) => webSocket.on('close', cb), + dispose: () => webSocket.close() + }; + // launch the server when the web socket is opened + if (webSocket.readyState === webSocket.OPEN) { + launchLanguageServer(runconfig, socket); + } else { + webSocket.on('open', () => { + launchLanguageServer(runconfig, socket); + }); } - }); + }); + } + }); }; /** * Solves: __dirname is not defined in ES module scope */ export const getLocalDirectory = (referenceUrl: string | URL) => { - const __filename = fileURLToPath(referenceUrl); - return dirname(__filename); + const __filename = fileURLToPath(referenceUrl); + return dirname(__filename); }; diff --git a/packages/examples/src/debugger/server/DAPSocket.ts b/packages/examples/src/debugger/server/DAPSocket.ts index 656d53f87..9abf4d2e0 100644 --- a/packages/examples/src/debugger/server/DAPSocket.ts +++ b/packages/examples/src/debugger/server/DAPSocket.ts @@ -13,59 +13,56 @@ const HEADER_LINESEPARATOR = /\r?\n/; const HEADER_FIELDSEPARATOR = /: */; export class DAPSocket { - private socket: net.Socket; - private rawData = Buffer.allocUnsafe(0); - private contentLength = -1; - private onMessage: (message: string) => void; + private socket: net.Socket; + private rawData = Buffer.allocUnsafe(0); + private contentLength = -1; + private onMessage: (message: string) => void; - constructor(onMessage: (message: string) => void) { - this.onMessage = onMessage; - this.socket = new net.Socket(); - this.socket.on('data', this.onData); - } + constructor(onMessage: (message: string) => void) { + this.onMessage = onMessage; + this.socket = new net.Socket(); + this.socket.on('data', this.onData); + } - private onData = (data: Buffer) => { - this.rawData = Buffer.concat([this.rawData, data]); - // oxlint-disable-next-line @typescript-eslint/no-unnecessary-condition - while (true) { - if (this.contentLength >= 0) { - if (this.rawData.length >= this.contentLength) { - const message = this.rawData.toString('utf8', 0, this.contentLength); - this.rawData = this.rawData.subarray(this.contentLength); - this.contentLength = -1; - if (message.length > 0) { - this.onMessage(message); - } - continue; - } - } else { - const idx = this.rawData.indexOf(TWO_CRLF); - if (idx !== -1) { - const header = this.rawData.toString('utf8', 0, idx); - const lines = header.split(HEADER_LINESEPARATOR); - for (const h of lines) { - const kvPair = h.split(HEADER_FIELDSEPARATOR); - if (kvPair[0] === 'Content-Length') { - this.contentLength = Number(kvPair[1]); - } - } - this.rawData = this.rawData.subarray(idx + TWO_CRLF.length); - continue; - } + private onData = (data: Buffer) => { + this.rawData = Buffer.concat([this.rawData, data]); + // oxlint-disable-next-line @typescript-eslint/no-unnecessary-condition + while (true) { + if (this.contentLength >= 0) { + if (this.rawData.length >= this.contentLength) { + const message = this.rawData.toString('utf8', 0, this.contentLength); + this.rawData = this.rawData.subarray(this.contentLength); + this.contentLength = -1; + if (message.length > 0) { + this.onMessage(message); + } + continue; + } + } else { + const idx = this.rawData.indexOf(TWO_CRLF); + if (idx !== -1) { + const header = this.rawData.toString('utf8', 0, idx); + const lines = header.split(HEADER_LINESEPARATOR); + for (const h of lines) { + const kvPair = h.split(HEADER_FIELDSEPARATOR); + if (kvPair[0] === 'Content-Length') { + this.contentLength = Number(kvPair[1]); } - break; + } + this.rawData = this.rawData.subarray(idx + TWO_CRLF.length); + continue; } - }; - - public connect(port: number) { - this.socket.connect(port); + } + break; } + }; - public sendMessage(message: string) { - console.log(`Client->DAP: ${message}`); - this.socket.write( - `Content-Length: ${Buffer.byteLength(message, 'utf8')}${TWO_CRLF}${message}`, - 'utf8' - ); - } + public connect(port: number) { + this.socket.connect(port); + } + + public sendMessage(message: string) { + console.log(`Client->DAP: ${message}`); + this.socket.write(`Content-Length: ${Buffer.byteLength(message, 'utf8')}${TWO_CRLF}${message}`, 'utf8'); + } } diff --git a/packages/examples/src/debugger/server/debugServer.ts b/packages/examples/src/debugger/server/debugServer.ts index 6bc2f87a1..c271f1d75 100644 --- a/packages/examples/src/debugger/server/debugServer.ts +++ b/packages/examples/src/debugger/server/debugServer.ts @@ -16,7 +16,7 @@ import { DAPSocket } from './DAPSocket.js'; // the major difference is that the debug server runs already inside the container const exitHandler = async () => { - console.log('Exiting...'); + console.log('Exiting...'); }; process.on('exit', exitHandler); process.on('SIGINT', exitHandler); @@ -30,93 +30,91 @@ const app = express(); const server = http.createServer(app); const wss = new WebSocketServer({ server }); -const sequential = ( - fn: (...params: P) => Promise -): (...params: P) => Promise => { - let promise = Promise.resolve(); - return (...params: P) => { - const result = promise.then(() => { - return fn(...params); - }); +const sequential = (fn: (...params: P) => Promise): ((...params: P) => Promise) => { + let promise = Promise.resolve(); + return (...params: P) => { + const result = promise.then(() => { + return fn(...params); + }); - promise = result.then( - () => { }, - () => { } - ); - return result; - }; + promise = result.then( + () => {}, + () => {} + ); + return result; + }; }; wss.on('connection', (ws) => { - const onWsMessage = (message: string) => { - console.log(`DAP->Client: ${message}`); - ws.send(message); - }; - const socket = new DAPSocket(onWsMessage); + const onWsMessage = (message: string) => { + console.log(`DAP->Client: ${message}`); + ws.send(message); + }; + const socket = new DAPSocket(onWsMessage); - let initialized = false; + let initialized = false; - ws.on( - 'message', - sequential(async (message: string) => { - if (!initialized) { - try { - const parsed = JSON.parse(message); - if (parsed.id === 'init') { - const initMesssage = parsed as InitMessage; - const defaultFile = initMesssage.defaultFile; - const debuggerExecCall = initMesssage.debuggerExecCall; - for (const [name, fileDef] of Object.entries(initMesssage.files)) { - console.log(`Found file: ${name} path: ${fileDef.path}`); - await fs.promises.writeFile(fileDef.path, fileDef.code); - } - initialized = true; + ws.on( + 'message', + sequential(async (message: string) => { + if (!initialized) { + try { + const parsed = JSON.parse(message); + if (parsed.id === 'init') { + const initMesssage = parsed as InitMessage; + const defaultFile = initMesssage.defaultFile; + const debuggerExecCall = initMesssage.debuggerExecCall; + for (const [name, fileDef] of Object.entries(initMesssage.files)) { + console.log(`Found file: ${name} path: ${fileDef.path}`); + await fs.promises.writeFile(fileDef.path, fileDef.code); + } + initialized = true; - console.log(`Using default file "${defaultFile}" for debugging.`); + console.log(`Using default file "${defaultFile}" for debugging.`); - const sendOutput = (category: 'stdout' | 'stderr', output: string | null | undefined) => { - onWsMessage( - JSON.stringify({ - type: 'event', - event: 'output', - body: { - category, - output - } - }) - ); - }; + const sendOutput = (category: 'stdout' | 'stderr', output: string | null | undefined) => { + onWsMessage( + JSON.stringify({ + type: 'event', + event: 'output', + body: { + category, + output + } + }) + ); + }; - const cmd = `${debuggerExecCall} ${defaultFile} 2>&1 | tee /home/mlc/server/debugger.log`; - console.log(`Executing the debugger: ${cmd}`); - const execGraalpy = exec(cmd); - execGraalpy.stdout?.on('data', (data) => { - sendOutput('stdout', data); - }); - execGraalpy.stderr?.on('data', (data) => { - sendOutput('stderr', data); - }); - execGraalpy.on('error', (err) => { - sendOutput('stderr', err.message); - }); - execGraalpy.on('end', () => { - ws.close(); - }); + const cmd = `${debuggerExecCall} ${defaultFile} 2>&1 | tee /home/mlc/server/debugger.log`; + console.log(`Executing the debugger: ${cmd}`); + const execGraalpy = exec(cmd); + execGraalpy.stdout?.on('data', (data) => { + sendOutput('stdout', data); + }); + execGraalpy.stderr?.on('data', (data) => { + sendOutput('stderr', data); + }); + execGraalpy.on('error', (err) => { + sendOutput('stderr', err.message); + }); + execGraalpy.on('end', () => { + ws.close(); + }); - await new Promise((resolve) => setTimeout(resolve, 1000)); - // 4711 is the default port of the GraalPy debugger - socket.connect(4711); - return; - } - } catch (err) { - console.error('Failed to initialize', err); - } - } - socket.sendMessage(message); - }) - ); + await new Promise((resolve) => setTimeout(resolve, 1000)); + // 4711 is the default port of the GraalPy debugger + socket.connect(4711); + return; + } + } catch (err) { + console.error('Failed to initialize', err); + } + } + socket.sendMessage(message); + }) + ); }); server.listen(PORT, () => { - console.log(`Server started on port ${PORT}!`); + console.log(`Server started on port ${PORT}!`); }); diff --git a/packages/examples/src/eclipse.jdt.ls/client/main.ts b/packages/examples/src/eclipse.jdt.ls/client/main.ts index 8e20cc3c9..6471f8527 100644 --- a/packages/examples/src/eclipse.jdt.ls/client/main.ts +++ b/packages/examples/src/eclipse.jdt.ls/client/main.ts @@ -10,5 +10,5 @@ import { runExtendedClient } from '../../common/client/extendedClient.js'; import { eclipseJdtLsConfig } from '../config.js'; export const runEclipseJdtLsClient = async () => { - await runExtendedClient(eclipseJdtLsConfig, helloJavaCode); + await runExtendedClient(eclipseJdtLsConfig, helloJavaCode); }; diff --git a/packages/examples/src/eclipse.jdt.ls/config.ts b/packages/examples/src/eclipse.jdt.ls/config.ts index a6da551f1..95ebccf5b 100644 --- a/packages/examples/src/eclipse.jdt.ls/config.ts +++ b/packages/examples/src/eclipse.jdt.ls/config.ts @@ -6,9 +6,9 @@ import type { ExampleLsConfig } from '../common/client/extendedClient.js'; export const eclipseJdtLsConfig: ExampleLsConfig = { - port: 30003, - path: '/jdtls', - basePath: '/home/mlc/packages/examples/resources/eclipse.jdt.ls', - languageId: 'java', - useExternalWebSocket: false + port: 30003, + path: '/jdtls', + basePath: '/home/mlc/packages/examples/resources/eclipse.jdt.ls', + languageId: 'java', + useExternalWebSocket: false }; diff --git a/packages/examples/src/eclipse.jdt.ls/server/main.ts b/packages/examples/src/eclipse.jdt.ls/server/main.ts index 027ed2579..acb25a043 100644 --- a/packages/examples/src/eclipse.jdt.ls/server/main.ts +++ b/packages/examples/src/eclipse.jdt.ls/server/main.ts @@ -7,32 +7,32 @@ import { runLanguageServer } from '../../common/node/language-server-runner.js'; import { eclipseJdtLsConfig } from '../config.js'; export const runEclipseJdtLs = () => { - runLanguageServer({ - serverName: 'Eclipse JDT LS', - pathName: eclipseJdtLsConfig.path, - serverPort: eclipseJdtLsConfig.port, - runCommand: 'java', - runCommandArgs: [ - '-Declipse.application=org.eclipse.jdt.ls.core.id1', - '-Dosgi.bundles.defaultStartLevel=4', - '-Declipse.product=org.eclipse.jdt.ls.core.product', - '-Dlog.level=ALL', - '-Xmx1G', - '--add-modules=ALL-SYSTEM', - '--add-opens', - 'java.base/java.util=ALL-UNNAMED', - '--add-opens', - 'java.base/java.lang=ALL-UNNAMED', - '-jar', - `${eclipseJdtLsConfig.basePath}/ls/plugins/org.eclipse.equinox.launcher_1.6.900.v20240613-2009.jar`, - '-configuration', - `${eclipseJdtLsConfig.basePath}/ls/config_linux`, - '-data', - `${eclipseJdtLsConfig.basePath}/workspace` - ], - wsServerOptions: { - noServer: true, - perMessageDeflate: false - } - }); + runLanguageServer({ + serverName: 'Eclipse JDT LS', + pathName: eclipseJdtLsConfig.path, + serverPort: eclipseJdtLsConfig.port, + runCommand: 'java', + runCommandArgs: [ + '-Declipse.application=org.eclipse.jdt.ls.core.id1', + '-Dosgi.bundles.defaultStartLevel=4', + '-Declipse.product=org.eclipse.jdt.ls.core.product', + '-Dlog.level=ALL', + '-Xmx1G', + '--add-modules=ALL-SYSTEM', + '--add-opens', + 'java.base/java.util=ALL-UNNAMED', + '--add-opens', + 'java.base/java.lang=ALL-UNNAMED', + '-jar', + `${eclipseJdtLsConfig.basePath}/ls/plugins/org.eclipse.equinox.launcher_1.6.900.v20240613-2009.jar`, + '-configuration', + `${eclipseJdtLsConfig.basePath}/ls/config_linux`, + '-data', + `${eclipseJdtLsConfig.basePath}/workspace` + ], + wsServerOptions: { + noServer: true, + perMessageDeflate: false + } + }); }; diff --git a/packages/examples/src/groovy/client/main.ts b/packages/examples/src/groovy/client/main.ts index 2c25e8a5b..5d744fe87 100644 --- a/packages/examples/src/groovy/client/main.ts +++ b/packages/examples/src/groovy/client/main.ts @@ -10,5 +10,5 @@ import { runExtendedClient } from '../../common/client/extendedClient.js'; import { groovyConfig } from '../config.js'; export const runGroovyClient = async () => { - await runExtendedClient(groovyConfig, helloGroovyCode); + await runExtendedClient(groovyConfig, helloGroovyCode); }; diff --git a/packages/examples/src/groovy/config.ts b/packages/examples/src/groovy/config.ts index 8a7759553..a96d3aa0a 100644 --- a/packages/examples/src/groovy/config.ts +++ b/packages/examples/src/groovy/config.ts @@ -6,9 +6,9 @@ import type { ExampleLsConfig } from '../common/client/extendedClient.js'; export const groovyConfig: ExampleLsConfig = { - port: 30002, - path: '/groovy', - basePath: '/home/gradle/mlc/packages/examples/resources/groovy', - languageId: 'groovy', - useExternalWebSocket: false + port: 30002, + path: '/groovy', + basePath: '/home/gradle/mlc/packages/examples/resources/groovy', + languageId: 'groovy', + useExternalWebSocket: false }; diff --git a/packages/examples/src/groovy/server/main.ts b/packages/examples/src/groovy/server/main.ts index 997fd6798..fbf073fc6 100644 --- a/packages/examples/src/groovy/server/main.ts +++ b/packages/examples/src/groovy/server/main.ts @@ -7,18 +7,15 @@ import { runLanguageServer } from '../../common/node/language-server-runner.js'; import { groovyConfig } from '../config.js'; export const runGroovyLanguageServer = () => { - runLanguageServer({ - serverName: 'GROOVY', - pathName: groovyConfig.path, - serverPort: groovyConfig.port, - runCommand: 'java', - runCommandArgs: [ - '-jar', - `${groovyConfig.basePath}/lib/groovy-language-server-all.jar` - ], - wsServerOptions: { - noServer: true, - perMessageDeflate: false - } - }); + runLanguageServer({ + serverName: 'GROOVY', + pathName: groovyConfig.path, + serverPort: groovyConfig.port, + runCommand: 'java', + runCommandArgs: ['-jar', `${groovyConfig.basePath}/lib/groovy-language-server-all.jar`], + wsServerOptions: { + noServer: true, + perMessageDeflate: false + } + }); }; diff --git a/packages/examples/src/json/client/classic.ts b/packages/examples/src/json/client/classic.ts index 527dca895..2e71e39d7 100644 --- a/packages/examples/src/json/client/classic.ts +++ b/packages/examples/src/json/client/classic.ts @@ -11,73 +11,73 @@ import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-langu import { defineDefaultWorkerLoaders, useWorkerFactory } from 'monaco-languageclient/workerFactory'; export const runClient = async () => { - const htmlContainer = document.getElementById('monaco-editor-root')!; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'classic', - viewsConfig: { - $type: 'EditorService', - htmlContainer - }, - logLevel: LogLevel.Debug, - userConfiguration: { - json: JSON.stringify({ - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureClassicWorkerFactory - }; + const htmlContainer = document.getElementById('monaco-editor-root')!; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'classic', + viewsConfig: { + $type: 'EditorService', + htmlContainer + }, + logLevel: LogLevel.Debug, + userConfiguration: { + json: JSON.stringify({ + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureClassicWorkerFactory + }; - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); - const languageId = 'json'; - const code = `{ + const languageId = 'json'; + const code = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": "unix" }`; - const codeUri = '/workspace/model.json'; - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: { - text: code, - uri: codeUri - } - }, - languageDef: { - languageExtensionConfig: { - id: languageId, - extensions: ['.json', '.jsonc'], - aliases: ['JSON', 'json'], - mimetypes: ['application/json'] - } - } - }; - const editorApp = new EditorApp(editorAppConfig); - await editorApp.start(htmlContainer); + const codeUri = '/workspace/model.json'; + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: { + text: code, + uri: codeUri + } + }, + languageDef: { + languageExtensionConfig: { + id: languageId, + extensions: ['.json', '.jsonc'], + aliases: ['JSON', 'json'], + mimetypes: ['application/json'] + } + } + }; + const editorApp = new EditorApp(editorAppConfig); + await editorApp.start(htmlContainer); - const languageClientConfig: LanguageClientConfig = { - languageId, - clientOptions: { - documentSelector: [languageId] - }, - connection: { - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:30000/sampleServer' - } - } - }; - const languageClientWrapper = new LanguageClientWrapper(languageClientConfig); - await languageClientWrapper.start(); + const languageClientConfig: LanguageClientConfig = { + languageId, + clientOptions: { + documentSelector: [languageId] + }, + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:30000/sampleServer' + } + } + }; + const languageClientWrapper = new LanguageClientWrapper(languageClientConfig); + await languageClientWrapper.start(); }; export const configureClassicWorkerFactory = (logger?: ILogger) => { - const defaultworkerLoaders = defineDefaultWorkerLoaders(); - // remove textmate worker as it is not compatible with classic mode - defaultworkerLoaders.TextMateWorker = undefined; - defaultworkerLoaders.extensionHostWorkerMain = undefined; - useWorkerFactory({ - workerLoaders: defaultworkerLoaders, - logger - }); + const defaultworkerLoaders = defineDefaultWorkerLoaders(); + // remove textmate worker as it is not compatible with classic mode + defaultworkerLoaders.TextMateWorker = undefined; + defaultworkerLoaders.extensionHostWorkerMain = undefined; + useWorkerFactory({ + workerLoaders: defaultworkerLoaders, + logger + }); }; diff --git a/packages/examples/src/json/client/config.ts b/packages/examples/src/json/client/config.ts index 184cf0ce3..23e79b961 100644 --- a/packages/examples/src/json/client/config.ts +++ b/packages/examples/src/json/client/config.ts @@ -6,9 +6,9 @@ import type { ExampleLsConfig } from '../../common/client/extendedClient.js'; export const jsontLsConfig: ExampleLsConfig = { - port: 30000, - path: '/sampleServer', - basePath: '/home/mlc/packages/examples/resources/json', - languageId: 'json', - useExternalWebSocket: true + port: 30000, + path: '/sampleServer', + basePath: '/home/mlc/packages/examples/resources/json', + languageId: 'json', + useExternalWebSocket: true }; diff --git a/packages/examples/src/json/client/extended.ts b/packages/examples/src/json/client/extended.ts index f05f0fba9..225f49828 100644 --- a/packages/examples/src/json/client/extended.ts +++ b/packages/examples/src/json/client/extended.ts @@ -9,9 +9,9 @@ import { runExtendedClient } from '../../common/client/extendedClient.js'; import { jsontLsConfig } from './config.js'; export const runJsonWrapper = async () => { - const helloJsonCode = `{ + const helloJsonCode = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": {"value": "unix"} }`; - await runExtendedClient(jsontLsConfig, helloJsonCode); + await runExtendedClient(jsontLsConfig, helloJsonCode); }; diff --git a/packages/examples/src/json/server/json-server.ts b/packages/examples/src/json/server/json-server.ts index 7d66964a0..eb8c0810d 100644 --- a/packages/examples/src/json/server/json-server.ts +++ b/packages/examples/src/json/server/json-server.ts @@ -6,279 +6,292 @@ import { readFile } from 'node:fs'; import requestLight, { type XHRResponse } from 'request-light'; import * as URI from 'vscode-uri'; import 'vscode-ws-jsonrpc'; -import { createConnection, type _Connection, TextDocuments, type DocumentSymbolParams, ProposedFeatures } from 'vscode-languageserver/lib/node/main.js'; import { - Diagnostic, Command, CompletionList, CompletionItem, Hover, - SymbolInformation, TextEdit, FoldingRange, ColorInformation, ColorPresentation + createConnection, + type _Connection, + TextDocuments, + type DocumentSymbolParams, + ProposedFeatures +} from 'vscode-languageserver/lib/node/main.js'; +import { + Diagnostic, + Command, + CompletionList, + CompletionItem, + Hover, + SymbolInformation, + TextEdit, + FoldingRange, + ColorInformation, + ColorPresentation } from 'vscode-languageserver-types'; -import type { TextDocumentPositionParams, DocumentRangeFormattingParams, ExecuteCommandParams, CodeActionParams, FoldingRangeParams, DocumentColorParams, ColorPresentationParams } from 'vscode-languageserver-protocol'; +import type { + TextDocumentPositionParams, + DocumentRangeFormattingParams, + ExecuteCommandParams, + CodeActionParams, + FoldingRangeParams, + DocumentColorParams, + ColorPresentationParams +} from 'vscode-languageserver-protocol'; import { TextDocumentSyncKind } from 'vscode-languageserver-protocol'; import { getLanguageService, type LanguageService, type JSONDocument } from 'vscode-json-languageservice'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { Deferred } from 'monaco-languageclient/common'; export class JsonServer { - protected readonly connection: _Connection; - protected workspaceRoot: URI.URI | undefined; - protected readonly documents = new TextDocuments(TextDocument); - - protected readonly jsonService: LanguageService = getLanguageService({ - schemaRequestService: this.resolveSchema.bind(this) - }); + protected readonly connection: _Connection; + protected workspaceRoot: URI.URI | undefined; + protected readonly documents = new TextDocuments(TextDocument); - protected readonly pendingValidationRequests = new Map(); - - constructor(connection: _Connection) { - this.connection = connection; - this.documents.listen(this.connection); - this.documents.onDidChangeContent(change => - this.validate(change.document) - ); - this.documents.onDidClose(event => { - this.cleanPendingValidation(event.document); - this.cleanDiagnostics(event.document).catch(error => { - this.connection.console.error(`Error while cleaning diagnostics: ${String(error)}`); - }); - }); + protected readonly jsonService: LanguageService = getLanguageService({ + schemaRequestService: this.resolveSchema.bind(this) + }); - this.connection.onInitialize(params => { - if (params.rootPath !== null && params.rootPath !== undefined) { - this.workspaceRoot = URI.URI.file(params.rootPath); - } else if (params.rootUri !== null) { - this.workspaceRoot = URI.URI.parse(params.rootUri); - } - this.connection.console.log('The server is initialized.'); - return { - capabilities: { - textDocumentSync: TextDocumentSyncKind.Incremental, - codeActionProvider: true, - completionProvider: { - resolveProvider: true, - triggerCharacters: ['"', ':'] - }, - hoverProvider: true, - documentSymbolProvider: true, - documentRangeFormattingProvider: true, - executeCommandProvider: { - commands: ['json.documentUpper'] - }, - colorProvider: true, - foldingRangeProvider: true - } - }; - }); - this.connection.onCodeAction(params => - this.codeAction(params) - ); - this.connection.onCompletion(params => - this.completion(params) - ); - this.connection.onCompletionResolve(item => - this.resolveCompletion(item) - ); - this.connection.onExecuteCommand(params => - this.executeCommand(params) - ); - this.connection.onHover(params => - this.hover(params) - ); - this.connection.onDocumentSymbol(params => - this.findDocumentSymbols(params) - ); - this.connection.onDocumentRangeFormatting(params => - this.format(params) - ); - this.connection.onDocumentColor(params => - this.findDocumentColors(params) - ); - this.connection.onColorPresentation(params => - this.getColorPresentations(params) - ); - this.connection.onFoldingRanges(params => - this.getFoldingRanges(params) - ); - } + protected readonly pendingValidationRequests = new Map(); - start() { - this.connection.listen(); - } + constructor(connection: _Connection) { + this.connection = connection; + this.documents.listen(this.connection); + this.documents.onDidChangeContent((change) => this.validate(change.document)); + this.documents.onDidClose((event) => { + this.cleanPendingValidation(event.document); + this.cleanDiagnostics(event.document).catch((error) => { + this.connection.console.error(`Error while cleaning diagnostics: ${String(error)}`); + }); + }); - protected getFoldingRanges(params: FoldingRangeParams): FoldingRange[] { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return []; + this.connection.onInitialize((params) => { + if (params.rootPath !== null && params.rootPath !== undefined) { + this.workspaceRoot = URI.URI.file(params.rootPath); + } else if (params.rootUri !== null) { + this.workspaceRoot = URI.URI.parse(params.rootUri); + } + this.connection.console.log('The server is initialized.'); + return { + capabilities: { + textDocumentSync: TextDocumentSyncKind.Incremental, + codeActionProvider: true, + completionProvider: { + resolveProvider: true, + triggerCharacters: ['"', ':'] + }, + hoverProvider: true, + documentSymbolProvider: true, + documentRangeFormattingProvider: true, + executeCommandProvider: { + commands: ['json.documentUpper'] + }, + colorProvider: true, + foldingRangeProvider: true } - return this.jsonService.getFoldingRanges(document); - } + }; + }); + this.connection.onCodeAction((params) => this.codeAction(params)); + this.connection.onCompletion((params) => this.completion(params)); + this.connection.onCompletionResolve((item) => this.resolveCompletion(item)); + this.connection.onExecuteCommand((params) => this.executeCommand(params)); + this.connection.onHover((params) => this.hover(params)); + this.connection.onDocumentSymbol((params) => this.findDocumentSymbols(params)); + this.connection.onDocumentRangeFormatting((params) => this.format(params)); + this.connection.onDocumentColor((params) => this.findDocumentColors(params)); + this.connection.onColorPresentation((params) => this.getColorPresentations(params)); + this.connection.onFoldingRanges((params) => this.getFoldingRanges(params)); + } - protected findDocumentColors(params: DocumentColorParams): Thenable { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return Promise.resolve([]); - } - const jsonDocument = this.getJSONDocument(document); - return this.jsonService.findDocumentColors(document, jsonDocument); - } + start() { + this.connection.listen(); + } - protected getColorPresentations(params: ColorPresentationParams): ColorPresentation[] { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return []; - } - const jsonDocument = this.getJSONDocument(document); - return this.jsonService.getColorPresentations(document, jsonDocument, params.color, params.range); + protected getFoldingRanges(params: FoldingRangeParams): FoldingRange[] { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return []; } + return this.jsonService.getFoldingRanges(document); + } - protected codeAction(params: CodeActionParams): Command[] { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return []; - } - return [{ - title: 'Upper Case Document', - command: 'json.documentUpper', - // Send a VersionedTextDocumentIdentifier - arguments: [{ - ...params.textDocument, - version: document.version - }] - }]; + protected findDocumentColors(params: DocumentColorParams): Thenable { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return Promise.resolve([]); } + const jsonDocument = this.getJSONDocument(document); + return this.jsonService.findDocumentColors(document, jsonDocument); + } - protected format(params: DocumentRangeFormattingParams): TextEdit[] { - const document = this.documents.get(params.textDocument.uri); - return document === undefined ? [] : this.jsonService.format(document, params.range, params.options); + protected getColorPresentations(params: ColorPresentationParams): ColorPresentation[] { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return []; } + const jsonDocument = this.getJSONDocument(document); + return this.jsonService.getColorPresentations(document, jsonDocument, params.color, params.range); + } - protected findDocumentSymbols(params: DocumentSymbolParams): SymbolInformation[] { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return []; - } - const jsonDocument = this.getJSONDocument(document); - return this.jsonService.findDocumentSymbols(document, jsonDocument); + protected codeAction(params: CodeActionParams): Command[] { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return []; } + return [ + { + title: 'Upper Case Document', + command: 'json.documentUpper', + // Send a VersionedTextDocumentIdentifier + arguments: [ + { + ...params.textDocument, + version: document.version + } + ] + } + ]; + } - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - protected async executeCommand(params: ExecuteCommandParams): Promise { - if (params.command === 'json.documentUpper' && params.arguments !== undefined) { - const versionedTextDocumentIdentifier = params.arguments[0]; - const document = this.documents.get(versionedTextDocumentIdentifier.uri); - if (document !== undefined) { - await this.connection.workspace.applyEdit({ - documentChanges: [{ - textDocument: versionedTextDocumentIdentifier, - edits: [{ - range: { - start: { line: 0, character: 0 }, - end: { line: Number.MAX_SAFE_INTEGER, character: Number.MAX_SAFE_INTEGER } - }, - newText: document.getText().toUpperCase() - }] - }] - }); - } - } - } + protected format(params: DocumentRangeFormattingParams): TextEdit[] { + const document = this.documents.get(params.textDocument.uri); + return document === undefined ? [] : this.jsonService.format(document, params.range, params.options); + } - protected hover(params: TextDocumentPositionParams): Thenable { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return Promise.resolve(null); - } - const jsonDocument = this.getJSONDocument(document); - return this.jsonService.doHover(document, params.position, jsonDocument); + protected findDocumentSymbols(params: DocumentSymbolParams): SymbolInformation[] { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return []; } + const jsonDocument = this.getJSONDocument(document); + return this.jsonService.findDocumentSymbols(document, jsonDocument); + } - protected async resolveSchema(url: string): Promise { - const uri = URI.URI.parse(url); - if (uri.scheme === 'file') { - return new Promise((resolve, reject) => { - readFile(uri.fsPath, { encoding: 'utf8' }, (err, result) => { - if (err === null) { - resolve(result.toString()); - } else { - reject(err); - } - }); - }); - } - - const deferred = new Deferred(); - requestLight.xhr({ url, followRedirects: 5 }).then(response => { - deferred.resolve(response.responseText); - }).catch((error: Error | XHRResponse) => { - let errorMessage: string; - if (error instanceof Error) { - errorMessage = `Schema resolution failed: ${error.message}`; - } else { - const xhrResponse = error as XHRResponse; - errorMessage = `Schema resolution failed: ${requestLight.getErrorStatusDescription(xhrResponse.status)} ocurred: ${xhrResponse.responseText}`; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + protected async executeCommand(params: ExecuteCommandParams): Promise { + if (params.command === 'json.documentUpper' && params.arguments !== undefined) { + const versionedTextDocumentIdentifier = params.arguments[0]; + const document = this.documents.get(versionedTextDocumentIdentifier.uri); + if (document !== undefined) { + await this.connection.workspace.applyEdit({ + documentChanges: [ + { + textDocument: versionedTextDocumentIdentifier, + edits: [ + { + range: { + start: { line: 0, character: 0 }, + end: { line: Number.MAX_SAFE_INTEGER, character: Number.MAX_SAFE_INTEGER } + }, + newText: document.getText().toUpperCase() + } + ] } - deferred.reject(errorMessage); + ] }); + } + } + } - return deferred.promise; + protected hover(params: TextDocumentPositionParams): Thenable { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return Promise.resolve(null); } + const jsonDocument = this.getJSONDocument(document); + return this.jsonService.doHover(document, params.position, jsonDocument); + } - protected resolveCompletion(item: CompletionItem): Thenable { - return this.jsonService.doResolve(item); + protected async resolveSchema(url: string): Promise { + const uri = URI.URI.parse(url); + if (uri.scheme === 'file') { + return new Promise((resolve, reject) => { + readFile(uri.fsPath, { encoding: 'utf8' }, (err, result) => { + if (err === null) { + resolve(result.toString()); + } else { + reject(err); + } + }); + }); } - protected completion(params: TextDocumentPositionParams): Thenable { - const document = this.documents.get(params.textDocument.uri); - if (document === undefined) { - return Promise.resolve(null); + const deferred = new Deferred(); + requestLight + .xhr({ url, followRedirects: 5 }) + .then((response) => { + deferred.resolve(response.responseText); + }) + .catch((error: Error | XHRResponse) => { + let errorMessage: string; + if (error instanceof Error) { + errorMessage = `Schema resolution failed: ${error.message}`; + } else { + const xhrResponse = error as XHRResponse; + errorMessage = `Schema resolution failed: ${requestLight.getErrorStatusDescription(xhrResponse.status)} ocurred: ${xhrResponse.responseText}`; } - const jsonDocument = this.getJSONDocument(document); - return this.jsonService.doComplete(document, params.position, jsonDocument); - } + deferred.reject(errorMessage); + }); - protected validate(document: TextDocument): void { - this.cleanPendingValidation(document); - this.pendingValidationRequests.set(document.uri, setTimeout(async () => { - this.pendingValidationRequests.delete(document.uri); - await this.doValidate(document); - })); - } + return deferred.promise; + } - protected cleanPendingValidation(document: TextDocument): void { - const request = this.pendingValidationRequests.get(document.uri); - if (request !== undefined) { - clearTimeout(request); - this.pendingValidationRequests.delete(document.uri); - } - } + protected resolveCompletion(item: CompletionItem): Thenable { + return this.jsonService.doResolve(item); + } - protected async doValidate(document: TextDocument): Promise { - if (document.getText().length === 0) { - await this.cleanDiagnostics(document); - return; - } - const jsonDocument = this.getJSONDocument(document); - this.jsonService.doValidation(document, jsonDocument).then(diagnostics => - this.sendDiagnostics(document, diagnostics) - ); + protected completion(params: TextDocumentPositionParams): Thenable { + const document = this.documents.get(params.textDocument.uri); + if (document === undefined) { + return Promise.resolve(null); } + const jsonDocument = this.getJSONDocument(document); + return this.jsonService.doComplete(document, params.position, jsonDocument); + } - protected async cleanDiagnostics(document: TextDocument): Promise { - await this.sendDiagnostics(document, []); - } + protected validate(document: TextDocument): void { + this.cleanPendingValidation(document); + this.pendingValidationRequests.set( + document.uri, + setTimeout(async () => { + this.pendingValidationRequests.delete(document.uri); + await this.doValidate(document); + }) + ); + } - protected async sendDiagnostics(document: TextDocument, diagnostics: Diagnostic[]): Promise { - await this.connection.sendDiagnostics({ - uri: document.uri, diagnostics - }); + protected cleanPendingValidation(document: TextDocument): void { + const request = this.pendingValidationRequests.get(document.uri); + if (request !== undefined) { + clearTimeout(request); + this.pendingValidationRequests.delete(document.uri); } + } - protected getJSONDocument(document: TextDocument): JSONDocument { - return this.jsonService.parseJSONDocument(document); + protected async doValidate(document: TextDocument): Promise { + if (document.getText().length === 0) { + await this.cleanDiagnostics(document); + return; } + const jsonDocument = this.getJSONDocument(document); + this.jsonService.doValidation(document, jsonDocument).then((diagnostics) => this.sendDiagnostics(document, diagnostics)); + } + + protected async cleanDiagnostics(document: TextDocument): Promise { + await this.sendDiagnostics(document, []); + } + + protected async sendDiagnostics(document: TextDocument, diagnostics: Diagnostic[]): Promise { + await this.connection.sendDiagnostics({ + uri: document.uri, + diagnostics + }); + } + + protected getJSONDocument(document: TextDocument): JSONDocument { + return this.jsonService.parseJSONDocument(document); + } } const scriptExec = process.argv[2]; if (scriptExec === '--stdio') { - const connection = createConnection(ProposedFeatures.all); - const ls = new JsonServer(connection); - ls.start(); + const connection = createConnection(ProposedFeatures.all); + const ls = new JsonServer(connection); + ls.start(); } diff --git a/packages/examples/src/json/server/main.ts b/packages/examples/src/json/server/main.ts index 62d25d951..bae42eeb0 100644 --- a/packages/examples/src/json/server/main.ts +++ b/packages/examples/src/json/server/main.ts @@ -9,37 +9,34 @@ import { resolve } from 'node:path'; import { runLanguageServer } from '../../common/node/language-server-runner.js'; export const runJsonServer = (baseDir: string, relativeDir: string) => { - const processRunPath = resolve(baseDir, relativeDir); - runLanguageServer({ - serverName: 'JSON', - pathName: '/sampleServer', - serverPort: 30000, - runCommand: 'node', - runCommandArgs: [ - processRunPath, - '--stdio' - ], - wsServerOptions: { - noServer: true, - perMessageDeflate: false - } - }); + const processRunPath = resolve(baseDir, relativeDir); + runLanguageServer({ + serverName: 'JSON', + pathName: '/sampleServer', + serverPort: 30000, + runCommand: 'node', + runCommandArgs: [processRunPath, '--stdio'], + wsServerOptions: { + noServer: true, + perMessageDeflate: false + } + }); - startMockHttpServerForSavingCodeFromEditor(); + startMockHttpServerForSavingCodeFromEditor(); }; export const startMockHttpServerForSavingCodeFromEditor = () => { - const app = express(); - app.use(cors()); - app.use(express.json()); - app.post('/save-code', (req, res) => { - const { code } = req.body; - console.log('Received code:', code); - res.json({ success: true, message: code }); - }); + const app = express(); + app.use(cors()); + app.use(express.json()); + app.post('/save-code', (req, res) => { + const { code } = req.body; + console.log('Received code:', code); + res.json({ success: true, message: code }); + }); - const PORT = 3003; - app.listen(PORT, () => { - console.log(`JSON server running on port ${PORT}`); - }); + const PORT = 3003; + app.listen(PORT, () => { + console.log(`JSON server running on port ${PORT}`); + }); }; diff --git a/packages/examples/src/langium/langium-dsl/config/langium.configuration.json b/packages/examples/src/langium/langium-dsl/config/langium.configuration.json index d871c4b41..91326769b 100644 --- a/packages/examples/src/langium/langium-dsl/config/langium.configuration.json +++ b/packages/examples/src/langium/langium-dsl/config/langium.configuration.json @@ -1,134 +1,106 @@ { - "comments": { - "lineComment": "//", - "blockComment": ["/*", "*/"] + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { + "open": "'", + "close": "'", + "notIn": ["string", "comment"] }, - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "autoClosingPairs": [ - { "open": "{", "close": "}" }, - { "open": "[", "close": "]" }, - { "open": "(", "close": ")" }, - { - "open": "'", - "close": "'", - "notIn": [ - "string", - "comment" - ] - }, - { - "open": "\"", - "close": "\"", - "notIn": [ - "string" - ] - }, - { - "open": "/**", - "close": " */", - "notIn": [ - "string" - ] - } - ], - "autoCloseBefore": "}])`\n\t", - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "colorizedBracketPairs": [ - [ - "(", - ")" - ], - [ - "[", - "]" - ], - [ - "{", - "}" - ], - [ - "<", - ">" - ], - [ - "'", - "'" - ], - [ - "\"", - "\"" - ], - [ - "<", - ">" - ] - ], - "onEnterRules": [ - { - "": "// e.g. /** | */", - "beforeText": { - "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" - }, - "afterText": { - "pattern": "^\\s*\\*/$" - }, - "action": { - "indent": "indentOutdent", - "appendText": " * " - } - }, - { - "": "// e.g. /** ...|", - "beforeText": { - "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" - }, - "action": { - "indent": "none", - "appendText": " * " - } - }, - { - "": "// e.g. * ...|", - "beforeText": { - "pattern": "^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$" - }, - "previousLineText": { - "pattern": "(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))" - }, - "action": { - "indent": "none", - "appendText": "* " - } - }, - { - "": "// e.g. */|", - "beforeText": { - "pattern": "^(\\t|[ ])*[ ]\\*/\\s*$" - }, - "action": { - "indent": "none", - "removeText": 1 - } - }, - { - "beforeText": ":\\s*$", - "action": { - "indent": "indent" - } - }, - { - "beforeText": ";\\s*$", - "action": { - "indent": "outdent" - } - } - ] + { + "open": "\"", + "close": "\"", + "notIn": ["string"] + }, + { + "open": "/**", + "close": " */", + "notIn": ["string"] + } + ], + "autoCloseBefore": "}])`\n\t", + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "colorizedBracketPairs": [ + ["(", ")"], + ["[", "]"], + ["{", "}"], + ["<", ">"], + ["'", "'"], + ["\"", "\""], + ["<", ">"] + ], + "onEnterRules": [ + { + "": "// e.g. /** | */", + "beforeText": { + "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" + }, + "afterText": { + "pattern": "^\\s*\\*/$" + }, + "action": { + "indent": "indentOutdent", + "appendText": " * " + } + }, + { + "": "// e.g. /** ...|", + "beforeText": { + "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" + }, + "action": { + "indent": "none", + "appendText": " * " + } + }, + { + "": "// e.g. * ...|", + "beforeText": { + "pattern": "^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$" + }, + "previousLineText": { + "pattern": "(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))" + }, + "action": { + "indent": "none", + "appendText": "* " + } + }, + { + "": "// e.g. */|", + "beforeText": { + "pattern": "^(\\t|[ ])*[ ]\\*/\\s*$" + }, + "action": { + "indent": "none", + "removeText": 1 + } + }, + { + "beforeText": ":\\s*$", + "action": { + "indent": "indent" + } + }, + { + "beforeText": ";\\s*$", + "action": { + "indent": "outdent" + } + } + ] } diff --git a/packages/examples/src/langium/langium-dsl/config/langium.monarch.ts b/packages/examples/src/langium/langium-dsl/config/langium.monarch.ts index 6f11bb2c3..c587dc2c8 100644 --- a/packages/examples/src/langium/langium-dsl/config/langium.monarch.ts +++ b/packages/examples/src/langium/langium-dsl/config/langium.monarch.ts @@ -4,89 +4,68 @@ * ------------------------------------------------------------------------------------------ */ export const LangiumMonarchContent = { - keywords: [ - 'bigint', - 'boolean', - 'current', - 'Date', - 'entry', - 'extends', - 'false', - 'fragment', - 'grammar', - 'hidden', - 'import', - 'infer', - 'infers', - 'interface', - 'number', - 'returns', - 'string', - 'terminal', - 'true', - 'type', - 'with', + keywords: [ + 'bigint', + 'boolean', + 'current', + 'Date', + 'entry', + 'extends', + 'false', + 'fragment', + 'grammar', + 'hidden', + 'import', + 'infer', + 'infers', + 'interface', + 'number', + 'returns', + 'string', + 'terminal', + 'true', + 'type', + 'with' + ], + operators: ['->', ',', ';', ':', '!', '?', '?=', '.', '..', '@', '*', '&', '+', '+=', '<', '=', '=>', '>', '|'], + symbols: /->|,|;|:|!|\?|\?=|\.|\.\.|\(|\)|\[|\[\]|\]|\{|\}|@|\*|&|\+|\+=|<|=|=>|>|\|/, + + tokenizer: { + initial: [ + { + regex: /\/(?![*+?])(?:[^\r\n[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\//, + action: { token: 'string' } + }, + { + regex: /\^?[_a-zA-Z][\w_]*/, + action: { + cases: { + '@keywords': { token: 'keyword' }, + '@default': { token: 'ID' } + } + } + }, + { regex: /"[^"]*"|'[^']*'/, action: { token: 'string' } }, + { include: '@whitespace' }, + { + regex: /@symbols/, + action: { + cases: { + '@operators': { token: 'operator' }, + '@default': { token: '' } + } + } + } ], - operators: [ - '->', - ',', - ';', - ':', - '!', - '?', - '?=', - '.', - '..', - '@', - '*', - '&', - '+', - '+=', - '<', - '=', - '=>', - '>', - '|', + whitespace: [ + { regex: /\s+/, action: { token: 'white' } }, + { regex: /\/\*/, action: { token: 'comment', next: '@comment' } }, + { regex: /\/\/[^\n\r]*/, action: { token: 'comment' } } ], - symbols: - /->|,|;|:|!|\?|\?=|\.|\.\.|\(|\)|\[|\[\]|\]|\{|\}|@|\*|&|\+|\+=|<|=|=>|>|\|/, - - tokenizer: { - initial: [ - { - regex: /\/(?![*+?])(?:[^\r\n[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\//, - action: { token: 'string' }, - }, - { - regex: /\^?[_a-zA-Z][\w_]*/, - action: { - cases: { - '@keywords': { token: 'keyword' }, - '@default': { token: 'ID' }, - }, - }, - }, - { regex: /"[^"]*"|'[^']*'/, action: { token: 'string' } }, - { include: '@whitespace' }, - { - regex: /@symbols/, - action: { - cases: { - '@operators': { token: 'operator' }, - '@default': { token: '' }, - }, - }, - }, - ], - whitespace: [ - { regex: /\s+/, action: { token: 'white' } }, - { regex: /\/\*/, action: { token: 'comment', next: '@comment' } }, - { regex: /\/\/[^\n\r]*/, action: { token: 'comment' } }, - ], - comment: [ - { regex: /[^/*]+/, action: { token: 'comment' } }, - { regex: /\*\//, action: { token: 'comment', next: '@pop' } }, - { regex: /[/*]/, action: { token: 'comment' } }, - ], - }, + comment: [ + { regex: /[^/*]+/, action: { token: 'comment' } }, + { regex: /\*\//, action: { token: 'comment', next: '@pop' } }, + { regex: /[/*]/, action: { token: 'comment' } } + ] + } }; diff --git a/packages/examples/src/langium/langium-dsl/config/langium.tmLanguage.json b/packages/examples/src/langium/langium-dsl/config/langium.tmLanguage.json index 256e47386..764f78328 100644 --- a/packages/examples/src/langium/langium-dsl/config/langium.tmLanguage.json +++ b/packages/examples/src/langium/langium-dsl/config/langium.tmLanguage.json @@ -1,290 +1,288 @@ { - "name": "Langium", - "scopeName": "source.langium", - "fileTypes": [ - "langium" - ], - "patterns": [ + "name": "Langium", + "scopeName": "source.langium", + "fileTypes": ["langium"], + "patterns": [ + { + "include": "#regex" + }, + { + "include": "#comments" + }, + { + "name": "keyword.control.langium", + "match": "\\b(left|right|assoc|current|entry|extends|fragment|grammar|hidden|import|infer|infers|infix|interface|returns|terminal|type|with|on)\\b" + }, + { + "name": "constant.language.langium", + "match": "\\b(?i:true|false)\\b" + }, + { + "name": "keyword.symbol.langium", + "match": "(\\{|\\}|\\:|\\]|\\[|\\(|\\)|(\\??|\\+?)\\=|->|\\=>|<|>|\\,|\\*|\\+|\\@|\\||\\&|\\?|\\!|\\;)" + }, + { + "name": "string.quoted.double.langium", + "begin": "\"", + "end": "\"", + "patterns": [ { - "include": "#regex" + "include": "#string-character-escape" + } + ] + }, + { + "name": "string.quoted.single.langium", + "begin": "'", + "end": "'", + "patterns": [ + { + "include": "#string-character-escape" + } + ] + } + ], + "repository": { + "comments": { + "patterns": [ + { + "name": "comment.block.langium", + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.langium" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.langium" + } + } + }, + { + "begin": "(^\\s+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.cs" + } + }, + "end": "(?=$)", + "name": "comment.line.langium" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.langium", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "regex": { + "patterns": [ + { + "name": "string.regexp.ts", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([a-z]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(/)([a-z]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "keyword.other.ts" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] }, { - "include": "#comments" + "name": "string.regexp.ts", + "begin": "((?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } }, { - "name": "constant.language.langium", - "match": "\\b(?i:true|false)\\b" + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" }, { - "name": "keyword.symbol.langium", - "match": "(\\{|\\}|\\:|\\]|\\[|\\(|\\)|(\\??|\\+?)\\=|->|\\=>|<|>|\\,|\\*|\\+|\\@|\\||\\&|\\?|\\!|\\;)" + "name": "keyword.operator.or.regexp", + "match": "\\|" }, { - "name": "string.quoted.double.langium", - "begin": "\"", - "end": "\"", - "patterns": [ - { - "include": "#string-character-escape" - } - ] + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" }, - { - "begin": "(^\\s+)?(?=//)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.cs" - } - }, - "end": "(?=$)", - "name": "comment.line.langium" + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" } - ] + } + }, + { + "include": "#regex-character-class" + } + ] }, - "string-character-escape": { - "name": "constant.character.escape.langium", - "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." }, - "regex": { - "patterns": [ - { - "name": "string.regexp.ts", - "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([a-z]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.ts" - } - }, - "end": "(/)([a-z]*)", - "endCaptures": { - "1": { - "name": "punctuation.definition.string.end.ts" - }, - "2": { - "name": "keyword.other.ts" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "string.regexp.ts", - "begin": "((?", - "captures": { - "0": { - "name": "keyword.other.back-reference.regexp" - }, - "1": { - "name": "variable.other.regexp" - } - } - }, - { - "name": "keyword.operator.quantifier.regexp", - "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" - }, - { - "name": "keyword.operator.or.regexp", - "match": "\\|" - }, - { - "name": "meta.group.assertion.regexp", - "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", - "beginCaptures": { - "0": { - "name": "punctuation.definition.group.regexp" - }, - "1": { - "name": "punctuation.definition.group.no-capture.regexp" - }, - "2": { - "name": "variable.other.regexp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.group.regexp" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "constant.other.character-class.set.regexp", - "begin": "(\\[)(\\^)?", - "beginCaptures": { - "1": { - "name": "punctuation.definition.character-class.regexp" - }, - "2": { - "name": "keyword.operator.negation.regexp" - } - }, - "end": "(\\])", - "endCaptures": { - "1": { - "name": "punctuation.definition.character-class.regexp" - } - }, - "patterns": [ - { - "name": "constant.other.character-class.range.regexp", - "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", - "captures": { - "1": { - "name": "constant.character.numeric.regexp" - }, - "2": { - "name": "constant.character.control.regexp" - }, - "3": { - "name": "constant.character.escape.backslash.regexp" - }, - "4": { - "name": "constant.character.numeric.regexp" - }, - "5": { - "name": "constant.character.control.regexp" - }, - "6": { - "name": "constant.character.escape.backslash.regexp" - } - } - }, - { - "include": "#regex-character-class" - } - ] - }, - { - "include": "#regex-character-class" - } - ] - }, - "regex-character-class": { - "patterns": [ - { - "name": "constant.other.character-class.regexp", - "match": "\\\\[wWsSdDtrnvf]|\\." - }, - { - "name": "constant.character.numeric.regexp", - "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" - }, - { - "name": "constant.character.control.regexp", - "match": "\\\\c[A-Z]" - }, - { - "name": "constant.character.escape.backslash.regexp", - "match": "\\\\." - } - ] - } + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] } + } } diff --git a/packages/examples/src/langium/langium-dsl/config/langiumDslConfig.ts b/packages/examples/src/langium/langium-dsl/config/langiumDslConfig.ts index b2514f133..f8dbfcf87 100644 --- a/packages/examples/src/langium/langium-dsl/config/langiumDslConfig.ts +++ b/packages/examples/src/langium/langium-dsl/config/langiumDslConfig.ts @@ -4,7 +4,11 @@ * ------------------------------------------------------------------------------------------ */ import { LogLevel } from '@codingame/monaco-vscode-api'; -import { InMemoryFileSystemProvider, registerFileSystemOverlay, type IFileWriteOptions } from '@codingame/monaco-vscode-files-service-override'; +import { + InMemoryFileSystemProvider, + registerFileSystemOverlay, + type IFileWriteOptions +} from '@codingame/monaco-vscode-files-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import type { EditorAppConfig } from 'monaco-languageclient/editorApp'; import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; @@ -19,135 +23,139 @@ import langiumLanguageConfig from './langium.configuration.json?raw'; import langiumTextmateGrammar from './langium.tmLanguage.json?raw'; export const setupLangiumClientExtended = async (): Promise => { - const overallConfigType: OverallConfigType = 'extended'; - const extensionFilesOrContents = new Map(); - // vite build is easier with string content - extensionFilesOrContents.set('/workspace/langium-configuration.json', langiumLanguageConfig); - extensionFilesOrContents.set('/workspace/langium-grammar.json', langiumTextmateGrammar); + const overallConfigType: OverallConfigType = 'extended'; + const extensionFilesOrContents = new Map(); + // vite build is easier with string content + extensionFilesOrContents.set('/workspace/langium-configuration.json', langiumLanguageConfig); + extensionFilesOrContents.set('/workspace/langium-grammar.json', langiumTextmateGrammar); - const loadLangiumWorker = () => { - return new Worker(new URL('../worker/langium-server.ts', import.meta.url), { - type: 'module', - name: 'Langium LS', - }); - }; - - const worker = loadLangiumWorker(); - const reader = new BrowserMessageReader(worker); - const writer = new BrowserMessageWriter(worker); - reader.listen((message) => { - console.log('Received message from worker:', message); + const loadLangiumWorker = () => { + return new Worker(new URL('../worker/langium-server.ts', import.meta.url), { + type: 'module', + name: 'Langium LS' }); + }; + + const worker = loadLangiumWorker(); + const reader = new BrowserMessageReader(worker); + const writer = new BrowserMessageWriter(worker); + reader.listen((message) => { + console.log('Received message from worker:', message); + }); - // prepare all resources that should be preloaded - const workspaceUri = vscode.Uri.file('/workspace'); - const langiumGrammarLangiumUri = vscode.Uri.file('/workspace/langium-grammar.langium'); - const langiumTypesLangiumUri = vscode.Uri.file('/workspace/langium-types.langium'); - const fileSystemProvider = new InMemoryFileSystemProvider(); - const textEncoder = new TextEncoder(); + // prepare all resources that should be preloaded + const workspaceUri = vscode.Uri.file('/workspace'); + const langiumGrammarLangiumUri = vscode.Uri.file('/workspace/langium-grammar.langium'); + const langiumTypesLangiumUri = vscode.Uri.file('/workspace/langium-types.langium'); + const fileSystemProvider = new InMemoryFileSystemProvider(); + const textEncoder = new TextEncoder(); - const options: IFileWriteOptions = { - atomic: false, - unlock: false, - create: true, - overwrite: true - }; - await fileSystemProvider.mkdir(workspaceUri); - await fileSystemProvider.writeFile(langiumGrammarLangiumUri, textEncoder.encode(langiumGrammarLangium), options); - await fileSystemProvider.writeFile(langiumTypesLangiumUri, textEncoder.encode(langiumTypesLangium), options); - registerFileSystemOverlay(1, fileSystemProvider); + const options: IFileWriteOptions = { + atomic: false, + unlock: false, + create: true, + overwrite: true + }; + await fileSystemProvider.mkdir(workspaceUri); + await fileSystemProvider.writeFile(langiumGrammarLangiumUri, textEncoder.encode(langiumGrammarLangium), options); + await fileSystemProvider.writeFile(langiumTypesLangiumUri, textEncoder.encode(langiumTypesLangium), options); + registerFileSystemOverlay(1, fileSystemProvider); - const editorAppConfig: EditorAppConfig = {}; + const editorAppConfig: EditorAppConfig = {}; - const innerHtml = `
+ const innerHtml = `
`; - const viewsInit = async () => { - const { Parts, onPartVisibilityChange, isPartVisibile, attachPart, } = await import('@codingame/monaco-vscode-views-service-override'); + const viewsInit = async () => { + const { Parts, onPartVisibilityChange, isPartVisibile, attachPart } = await import('@codingame/monaco-vscode-views-service-override'); - for (const config of [ - { part: Parts.EDITOR_PART, element: '#editors' }, - ]) { - attachPart(config.part, document.querySelector(config.element)!); + for (const config of [{ part: Parts.EDITOR_PART, element: '#editors' }]) { + attachPart(config.part, document.querySelector(config.element)!); - if (!isPartVisibile(config.part)) { - document.querySelector(config.element)!.style.display = 'none'; - } + if (!isPartVisibile(config.part)) { + document.querySelector(config.element)!.style.display = 'none'; + } - onPartVisibilityChange(config.part, visible => { - document.querySelector(config.element)!.style.display = visible ? 'block' : 'none'; - }); - } - }; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: overallConfigType, - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride() - }, - viewsConfig: { - $type: 'ViewsService', - htmlContainer: document.body, - htmlAugmentationInstructions: (htmlElement: HTMLElement | null | undefined) => { - const htmlContainer = document.createElement('div', { is: 'app' }); - htmlContainer.innerHTML = innerHtml; - htmlElement?.append(htmlContainer); - }, - viewsInitFunc: viewsInit + onPartVisibilityChange(config.part, (visible) => { + document.querySelector(config.element)!.style.display = visible ? 'block' : 'none'; + }); + } + }; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: overallConfigType, + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride() + }, + viewsConfig: { + $type: 'ViewsService', + htmlContainer: document.body, + htmlAugmentationInstructions: (htmlElement: HTMLElement | null | undefined) => { + const htmlContainer = document.createElement('div', { is: 'app' }); + htmlContainer.innerHTML = innerHtml; + htmlElement?.append(htmlContainer); + }, + viewsInitFunc: viewsInit + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true, + 'vitest.disableWorkspaceWarning': true + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory, + extensions: [ + { + config: { + name: 'langium-example', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [ + { + id: 'langium', + extensions: ['.langium'], + aliases: ['langium', 'LANGIUM'], + configuration: '/workspace/langium-configuration.json' + } + ], + grammars: [ + { + language: 'langium', + scopeName: 'source.langium', + path: '/workspace/langium-grammar.json' + } + ] + } }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true, - 'vitest.disableWorkspaceWarning': true - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory, - extensions: [{ - config: { - name: 'langium-example', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - }, - contributes: { - languages: [{ - id: 'langium', - extensions: ['.langium'], - aliases: ['langium', 'LANGIUM'], - configuration: '/workspace/langium-configuration.json' - }], - grammars: [{ - language: 'langium', - scopeName: 'source.langium', - path: '/workspace/langium-grammar.json' - }] - } - }, - filesOrContents: extensionFilesOrContents - }] - }; + filesOrContents: extensionFilesOrContents + } + ] + }; - const languageClientConfig: LanguageClientConfig = { - languageId: 'langium', - clientOptions: { - documentSelector: ['langium'] - }, - connection: { - options: { - $type: 'WorkerDirect', - worker - }, - messageTransports: { reader, writer } - } - }; + const languageClientConfig: LanguageClientConfig = { + languageId: 'langium', + clientOptions: { + documentSelector: ['langium'] + }, + connection: { + options: { + $type: 'WorkerDirect', + worker + }, + messageTransports: { reader, writer } + } + }; - return { - editorAppConfig, - vscodeApiConfig, - languageClientConfig - }; + return { + editorAppConfig, + vscodeApiConfig, + languageClientConfig + }; }; diff --git a/packages/examples/src/langium/langium-dsl/main.ts b/packages/examples/src/langium/langium-dsl/main.ts index 94f6c8841..5b9646d3d 100644 --- a/packages/examples/src/langium/langium-dsl/main.ts +++ b/packages/examples/src/langium/langium-dsl/main.ts @@ -10,22 +10,21 @@ import type { ExampleAppConfig } from '../../common/client/utils.js'; import { setupLangiumClientExtended } from './config/langiumDslConfig.js'; export const runLangiumGrammarDsl = async () => { - try { - const appConfig: ExampleAppConfig = await setupLangiumClientExtended(); + try { + const appConfig: ExampleAppConfig = await setupLangiumClientExtended(); - // perform global init - const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); - await apiWrapper.start(); + // perform global init + const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); + await apiWrapper.start(); - // init language client - const lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); - await lcWrapper.start(); + // init language client + const lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); + await lcWrapper.start(); - await vscode.workspace.openTextDocument('/workspace/langium-types.langium'); - await vscode.workspace.openTextDocument('/workspace/langium-grammar.langium'); - await vscode.window.showTextDocument(vscode.Uri.file('/workspace/langium-grammar.langium')); - } catch (e) { - console.error(e); - } + await vscode.workspace.openTextDocument('/workspace/langium-types.langium'); + await vscode.workspace.openTextDocument('/workspace/langium-grammar.langium'); + await vscode.window.showTextDocument(vscode.Uri.file('/workspace/langium-grammar.langium')); + } catch (e) { + console.error(e); + } }; - diff --git a/packages/examples/src/langium/langium-dsl/worker/langium-server.ts b/packages/examples/src/langium/langium-dsl/worker/langium-server.ts index 8144b3179..0b01c1915 100644 --- a/packages/examples/src/langium/langium-dsl/worker/langium-server.ts +++ b/packages/examples/src/langium/langium-dsl/worker/langium-server.ts @@ -14,13 +14,13 @@ const messageReader = new BrowserMessageReader(self as DedicatedWorkerGlobalScop const messageWriter = new BrowserMessageWriter(self as DedicatedWorkerGlobalScope); messageReader.listen((message) => { - console.log('Received message from main thread:', message); + console.log('Received message from main thread:', message); }); // Inject the shared services and language-specific services const context = { - connection: createConnection(messageReader, messageWriter), - ...EmptyFileSystem + connection: createConnection(messageReader, messageWriter), + ...EmptyFileSystem } as unknown as DefaultSharedModuleContext; const { shared } = createLangiumGrammarServices(context); diff --git a/packages/examples/src/langium/statemachine/config/langium-config.json b/packages/examples/src/langium/statemachine/config/langium-config.json index f0b694217..4fca71e84 100644 --- a/packages/examples/src/langium/statemachine/config/langium-config.json +++ b/packages/examples/src/langium/statemachine/config/langium-config.json @@ -5,9 +5,7 @@ { "id": "statemachine", "grammar": "../ls/statemachine.langium", - "fileExtensions": [ - ".statemachine" - ], + "fileExtensions": [".statemachine"], "textMate": { "out": "../syntaxes/statemachine.tmLanguage.json" } diff --git a/packages/examples/src/langium/statemachine/config/language-configuration.json b/packages/examples/src/langium/statemachine/config/language-configuration.json index 6b619d0cf..2b1e4e94f 100644 --- a/packages/examples/src/langium/statemachine/config/language-configuration.json +++ b/packages/examples/src/langium/statemachine/config/language-configuration.json @@ -1,30 +1,30 @@ { - "comments": { - // symbol used for single line comment. Remove this entry if your language does not support line comments - "lineComment": "//", - // symbols used for start and end a block comment. Remove this entry if your language does not support block comments - "blockComment": [ "/*", "*/" ] - }, - // symbols used as brackets - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - // symbols that are auto closed when typing - "autoClosingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"", "\""], - ["'", "'"] - ], - // symbols that can be used to surround a selection - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"", "\""], - ["'", "'"] - ] + "comments": { + // symbol used for single line comment. Remove this entry if your language does not support line comments + "lineComment": "//", + // symbols used for start and end a block comment. Remove this entry if your language does not support block comments + "blockComment": ["/*", "*/"] + }, + // symbols used as brackets + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ], + // symbols that can be used to surround a selection + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ] } diff --git a/packages/examples/src/langium/statemachine/config/statemachineConfig.ts b/packages/examples/src/langium/statemachine/config/statemachineConfig.ts index 740f8b533..b375a72d9 100644 --- a/packages/examples/src/langium/statemachine/config/statemachineConfig.ts +++ b/packages/examples/src/langium/statemachine/config/statemachineConfig.ts @@ -20,90 +20,96 @@ import responseStatemachineTm from '../syntaxes/statemachine.tmLanguage.json?raw import type { ExampleAppConfig } from '../../../common/client/utils.js'; export const createLangiumGlobalConfig = (params: { - languageServerId: string, - codeContent: CodeContent, - worker: Worker, - messagePort?: MessagePort, - messageTransports?: MessageTransports, - htmlContainer?: HTMLElement + languageServerId: string; + codeContent: CodeContent; + worker: Worker; + messagePort?: MessagePort; + messageTransports?: MessageTransports; + htmlContainer?: HTMLElement; }): ExampleAppConfig => { - const extensionFilesOrContents = new Map(); - extensionFilesOrContents.set(`/${params.languageServerId}-statemachine-configuration.json`, statemachineLanguageConfig); - extensionFilesOrContents.set(`/${params.languageServerId}-statemachine-grammar.json`, responseStatemachineTm); + const extensionFilesOrContents = new Map(); + extensionFilesOrContents.set(`/${params.languageServerId}-statemachine-configuration.json`, statemachineLanguageConfig); + extensionFilesOrContents.set(`/${params.languageServerId}-statemachine-grammar.json`, responseStatemachineTm); - const languageClientConfig: LanguageClientConfig = { - languageId: 'statemachine', - clientOptions: { - documentSelector: ['statemachine'] - }, - connection: { - options: { - $type: 'WorkerDirect', - worker: params.worker, - messagePort: params.messagePort, - }, - messageTransports: params.messageTransports - }, - logLevel: LogLevel.Off - }; + const languageClientConfig: LanguageClientConfig = { + languageId: 'statemachine', + clientOptions: { + documentSelector: ['statemachine'] + }, + connection: { + options: { + $type: 'WorkerDirect', + worker: params.worker, + messagePort: params.messagePort + }, + messageTransports: params.messageTransports + }, + logLevel: LogLevel.Off + }; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer: params.htmlContainer - }, - logLevel: LogLevel.Off, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - ...getLifecycleServiceOverride(), - ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer: params.htmlContainer + }, + logLevel: LogLevel.Off, + serviceOverrides: { + ...getKeybindingsServiceOverride(), + ...getLifecycleServiceOverride(), + ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()) + }, + monacoWorkerFactory: configureDefaultWorkerFactory, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true + }) + }, + extensions: [ + { + config: { + name: 'statemachine-example', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [ + { + id: 'statemachine', + extensions: ['.statemachine'], + aliases: ['statemachine', 'Statemachine'], + configuration: `./${params.languageServerId}-statemachine-configuration.json` + } + ], + grammars: [ + { + language: 'statemachine', + scopeName: 'source.statemachine', + path: `./${params.languageServerId}-statemachine-grammar.json` + } + ] + } }, - monacoWorkerFactory: configureDefaultWorkerFactory, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true - }) - }, - extensions: [{ - config: { - name: 'statemachine-example', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - }, - contributes: { - languages: [{ - id: 'statemachine', - extensions: ['.statemachine'], - aliases: ['statemachine', 'Statemachine'], - configuration: `./${params.languageServerId}-statemachine-configuration.json` - }], - grammars: [{ - language: 'statemachine', - scopeName: 'source.statemachine', - path: `./${params.languageServerId}-statemachine-grammar.json` - }] - } - }, - filesOrContents: extensionFilesOrContents - }] - }; + filesOrContents: extensionFilesOrContents + } + ] + }; - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: params.codeContent - }, - logLevel: LogLevel.Debug - }; + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: params.codeContent + }, + logLevel: LogLevel.Debug + }; - return { - editorAppConfig, - vscodeApiConfig, - languageClientConfig - }; + return { + editorAppConfig, + vscodeApiConfig, + languageClientConfig + }; }; diff --git a/packages/examples/src/langium/statemachine/ls/generated/ast.ts b/packages/examples/src/langium/statemachine/ls/generated/ast.ts index 692430b60..4811f23e2 100644 --- a/packages/examples/src/langium/statemachine/ls/generated/ast.ts +++ b/packages/examples/src/langium/statemachine/ls/generated/ast.ts @@ -7,213 +7,213 @@ import * as langium from 'langium'; export const StatemachineTerminals = { - WS: /\s+/, - ID: /[_a-zA-Z][\w_]*/, - ML_COMMENT: /\/\*[\s\S]*?\*\//, - SL_COMMENT: /\/\/[^\n\r]*/, + WS: /\s+/, + ID: /[_a-zA-Z][\w_]*/, + ML_COMMENT: /\/\*[\s\S]*?\*\//, + SL_COMMENT: /\/\/[^\n\r]*/ }; export type StatemachineTerminalNames = keyof typeof StatemachineTerminals; export type StatemachineKeywordNames = - | "=>" - | "actions" - | "commands" - | "end" - | "events" - | "initialState" - | "state" - | "statemachine" - | "{" - | "}"; + | '=>' + | 'actions' + | 'commands' + | 'end' + | 'events' + | 'initialState' + | 'state' + | 'statemachine' + | '{' + | '}'; export type StatemachineTokenNames = StatemachineTerminalNames | StatemachineKeywordNames; export interface Command extends langium.AstNode { - readonly $container: Statemachine; - readonly $type: 'Command'; - name: string; + readonly $container: Statemachine; + readonly $type: 'Command'; + name: string; } export const Command = { - $type: 'Command', - name: 'name' + $type: 'Command', + name: 'name' } as const; export function isCommand(item: unknown): item is Command { - return reflection.isInstance(item, Command.$type); + return reflection.isInstance(item, Command.$type); } /** An event is the trigger for a transition */ export interface Event extends langium.AstNode { - readonly $container: Statemachine; - readonly $type: 'Event'; - name: string; + readonly $container: Statemachine; + readonly $type: 'Event'; + name: string; } export const Event = { - $type: 'Event', - name: 'name' + $type: 'Event', + name: 'name' } as const; export function isEvent(item: unknown): item is Event { - return reflection.isInstance(item, Event.$type); + return reflection.isInstance(item, Event.$type); } /** A description of the status of a system */ export interface State extends langium.AstNode { - readonly $container: Statemachine; - readonly $type: 'State'; - actions: Array>; - name: string; - /** The transitions to other states that can take place from the current one */ - transitions: Array; + readonly $container: Statemachine; + readonly $type: 'State'; + actions: Array>; + name: string; + /** The transitions to other states that can take place from the current one */ + transitions: Array; } export const State = { - $type: 'State', - actions: 'actions', - name: 'name', - transitions: 'transitions' + $type: 'State', + actions: 'actions', + name: 'name', + transitions: 'transitions' } as const; export function isState(item: unknown): item is State { - return reflection.isInstance(item, State.$type); + return reflection.isInstance(item, State.$type); } /** A textual representation of a state machine */ export interface Statemachine extends langium.AstNode { - readonly $type: 'Statemachine'; - commands: Array; - /** The list of recognized event names */ - events: Array; - /** The starting state for the machine */ - init: langium.Reference; - /** The name of the machine */ - name: string; - /** Definitions of available states */ - states: Array; + readonly $type: 'Statemachine'; + commands: Array; + /** The list of recognized event names */ + events: Array; + /** The starting state for the machine */ + init: langium.Reference; + /** The name of the machine */ + name: string; + /** Definitions of available states */ + states: Array; } export const Statemachine = { - $type: 'Statemachine', - commands: 'commands', - events: 'events', - init: 'init', - name: 'name', - states: 'states' + $type: 'Statemachine', + commands: 'commands', + events: 'events', + init: 'init', + name: 'name', + states: 'states' } as const; export function isStatemachine(item: unknown): item is Statemachine { - return reflection.isInstance(item, Statemachine.$type); + return reflection.isInstance(item, Statemachine.$type); } /** A change from one state to another */ export interface Transition extends langium.AstNode { - readonly $container: State; - readonly $type: 'Transition'; - /** The event triggering the transition */ - event: langium.Reference; - /** The target state */ - state: langium.Reference; + readonly $container: State; + readonly $type: 'Transition'; + /** The event triggering the transition */ + event: langium.Reference; + /** The target state */ + state: langium.Reference; } export const Transition = { - $type: 'Transition', - event: 'event', - state: 'state' + $type: 'Transition', + event: 'event', + state: 'state' } as const; export function isTransition(item: unknown): item is Transition { - return reflection.isInstance(item, Transition.$type); + return reflection.isInstance(item, Transition.$type); } export type StatemachineAstType = { - Command: Command - Event: Event - State: State - Statemachine: Statemachine - Transition: Transition -} + Command: Command; + Event: Event; + State: State; + Statemachine: Statemachine; + Transition: Transition; +}; export class StatemachineAstReflection extends langium.AbstractAstReflection { - override readonly types = { - Command: { - name: Command.$type, - properties: { - name: { - name: Command.name - } - }, - superTypes: [] + override readonly types = { + Command: { + name: Command.$type, + properties: { + name: { + name: Command.name + } + }, + superTypes: [] + }, + Event: { + name: Event.$type, + properties: { + name: { + name: Event.name + } + }, + superTypes: [] + }, + State: { + name: State.$type, + properties: { + actions: { + name: State.actions, + defaultValue: [], + referenceType: Command.$type }, - Event: { - name: Event.$type, - properties: { - name: { - name: Event.name - } - }, - superTypes: [] + name: { + name: State.name }, - State: { - name: State.$type, - properties: { - actions: { - name: State.actions, - defaultValue: [], - referenceType: Command.$type - }, - name: { - name: State.name - }, - transitions: { - name: State.transitions, - defaultValue: [] - } - }, - superTypes: [] + transitions: { + name: State.transitions, + defaultValue: [] + } + }, + superTypes: [] + }, + Statemachine: { + name: Statemachine.$type, + properties: { + commands: { + name: Statemachine.commands, + defaultValue: [] }, - Statemachine: { - name: Statemachine.$type, - properties: { - commands: { - name: Statemachine.commands, - defaultValue: [] - }, - events: { - name: Statemachine.events, - defaultValue: [] - }, - init: { - name: Statemachine.init, - referenceType: State.$type - }, - name: { - name: Statemachine.name - }, - states: { - name: Statemachine.states, - defaultValue: [] - } - }, - superTypes: [] + events: { + name: Statemachine.events, + defaultValue: [] + }, + init: { + name: Statemachine.init, + referenceType: State.$type + }, + name: { + name: Statemachine.name + }, + states: { + name: Statemachine.states, + defaultValue: [] + } + }, + superTypes: [] + }, + Transition: { + name: Transition.$type, + properties: { + event: { + name: Transition.event, + referenceType: Event.$type }, - Transition: { - name: Transition.$type, - properties: { - event: { - name: Transition.event, - referenceType: Event.$type - }, - state: { - name: Transition.state, - referenceType: State.$type - } - }, - superTypes: [] + state: { + name: Transition.state, + referenceType: State.$type } - } as const satisfies langium.AstMetaData + }, + superTypes: [] + } + } as const satisfies langium.AstMetaData; } export const reflection = new StatemachineAstReflection(); diff --git a/packages/examples/src/langium/statemachine/ls/generated/grammar.ts b/packages/examples/src/langium/statemachine/ls/generated/grammar.ts index 95d81e4d8..111739aab 100644 --- a/packages/examples/src/langium/statemachine/ls/generated/grammar.ts +++ b/packages/examples/src/langium/statemachine/ls/generated/grammar.ts @@ -7,7 +7,9 @@ import type { Grammar } from 'langium'; import { loadGrammarFromJson } from 'langium'; let loadedStatemachineModelGrammar: Grammar | undefined; -export const StatemachineModelGrammar = (): Grammar => loadedStatemachineModelGrammar ?? (loadedStatemachineModelGrammar = loadGrammarFromJson(`{ +export const StatemachineModelGrammar = (): Grammar => + loadedStatemachineModelGrammar ?? + (loadedStatemachineModelGrammar = loadGrammarFromJson(`{ "$type": "Grammar", "isDeclared": true, "name": "StatemachineModel", diff --git a/packages/examples/src/langium/statemachine/ls/generated/module.ts b/packages/examples/src/langium/statemachine/ls/generated/module.ts index 6b1233f04..ecea12659 100644 --- a/packages/examples/src/langium/statemachine/ls/generated/module.ts +++ b/packages/examples/src/langium/statemachine/ls/generated/module.ts @@ -3,23 +3,30 @@ * DO NOT EDIT MANUALLY! ******************************************************************************/ -import type { LangiumSharedCoreServices, LangiumCoreServices, LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module } from 'langium'; +import type { + LangiumSharedCoreServices, + LangiumCoreServices, + LangiumGeneratedCoreServices, + LangiumGeneratedSharedCoreServices, + LanguageMetaData, + Module +} from 'langium'; import { StatemachineAstReflection } from './ast.js'; import { StatemachineModelGrammar } from './grammar.js'; export const StatemachineModelLanguageMetaData = { - languageId: 'statemachine', - fileExtensions: ['.statemachine'], - caseInsensitive: false, - mode: 'development' + languageId: 'statemachine', + fileExtensions: ['.statemachine'], + caseInsensitive: false, + mode: 'development' } as const satisfies LanguageMetaData; export const StatemachineGeneratedSharedModule: Module = { - AstReflection: () => new StatemachineAstReflection() + AstReflection: () => new StatemachineAstReflection() }; export const StatemachineModelGeneratedModule: Module = { - Grammar: () => StatemachineModelGrammar(), - LanguageMetaData: () => StatemachineModelLanguageMetaData, - parser: {} + Grammar: () => StatemachineModelGrammar(), + LanguageMetaData: () => StatemachineModelLanguageMetaData, + parser: {} }; diff --git a/packages/examples/src/langium/statemachine/ls/statemachine-module.ts b/packages/examples/src/langium/statemachine/ls/statemachine-module.ts index 6026b9ba2..032f55169 100644 --- a/packages/examples/src/langium/statemachine/ls/statemachine-module.ts +++ b/packages/examples/src/langium/statemachine/ls/statemachine-module.ts @@ -4,7 +4,14 @@ * ------------------------------------------------------------------------------------------ */ import { type Module, inject } from 'langium'; -import { type DefaultSharedModuleContext, type LangiumServices, type LangiumSharedServices, type PartialLangiumServices, createDefaultModule, createDefaultSharedModule } from 'langium/lsp'; +import { + type DefaultSharedModuleContext, + type LangiumServices, + type LangiumSharedServices, + type PartialLangiumServices, + createDefaultModule, + createDefaultSharedModule +} from 'langium/lsp'; import { StatemachineGeneratedSharedModule, StatemachineModelGeneratedModule } from './generated/module.js'; import { StatemachineValidator, registerValidationChecks } from './statemachine-validator.js'; @@ -12,16 +19,16 @@ import { StatemachineValidator, registerValidationChecks } from './statemachine- * Declaration of custom services - add your own service classes here. */ export type StatemachineAddedServices = { - validation: { - StatemachineValidator: StatemachineValidator - } -} + validation: { + StatemachineValidator: StatemachineValidator; + }; +}; /** * Union of Langium default services and your custom services - use this as constructor parameter * of custom service classes. */ -export type StatemachineServices = LangiumServices & StatemachineAddedServices +export type StatemachineServices = LangiumServices & StatemachineAddedServices; /** * Dependency injection module that overrides Langium default services and contributes the @@ -29,9 +36,9 @@ export type StatemachineServices = LangiumServices & StatemachineAddedServices * selected services, while the custom services must be fully specified. */ export const StatemachineModule: Module = { - validation: { - StatemachineValidator: () => new StatemachineValidator() - } + validation: { + StatemachineValidator: () => new StatemachineValidator() + } }; /** @@ -50,24 +57,17 @@ export const StatemachineModule: Module { - const shared = inject( - createDefaultSharedModule(context), - StatemachineGeneratedSharedModule - ); - const statemachine = inject( - createDefaultModule({ shared }), - StatemachineModelGeneratedModule, - StatemachineModule - ); - shared.ServiceRegistry.register(statemachine); - registerValidationChecks(statemachine); - if (context.connection === undefined) { - // We don't run inside a language server - // Therefore, initialize the configuration provider instantly - await shared.workspace.ConfigurationProvider.initialized({}); - } - return { shared, statemachine }; + const shared = inject(createDefaultSharedModule(context), StatemachineGeneratedSharedModule); + const statemachine = inject(createDefaultModule({ shared }), StatemachineModelGeneratedModule, StatemachineModule); + shared.ServiceRegistry.register(statemachine); + registerValidationChecks(statemachine); + if (context.connection === undefined) { + // We don't run inside a language server + // Therefore, initialize the configuration provider instantly + await shared.workspace.ConfigurationProvider.initialized({}); + } + return { shared, statemachine }; } diff --git a/packages/examples/src/langium/statemachine/ls/statemachine-validator.ts b/packages/examples/src/langium/statemachine/ls/statemachine-validator.ts index 1e4774e81..65f290b0c 100644 --- a/packages/examples/src/langium/statemachine/ls/statemachine-validator.ts +++ b/packages/examples/src/langium/statemachine/ls/statemachine-validator.ts @@ -9,48 +9,48 @@ import type { StatemachineServices } from './statemachine-module.js'; import { MultiMap } from 'langium'; export function registerValidationChecks(services: StatemachineServices) { - const registry = services.validation.ValidationRegistry; - const validator = services.validation.StatemachineValidator; - const checks: ValidationChecks = { - State: (state, accept) => validator.checkStateNameStartsWithCapital(state, accept), - Statemachine: (statemachine, accept) => validator.checkUniqueStatesAndEvents(statemachine, accept) - }; - registry.register(checks, validator); + const registry = services.validation.ValidationRegistry; + const validator = services.validation.StatemachineValidator; + const checks: ValidationChecks = { + State: (state, accept) => validator.checkStateNameStartsWithCapital(state, accept), + Statemachine: (statemachine, accept) => validator.checkUniqueStatesAndEvents(statemachine, accept) + }; + registry.register(checks, validator); } export class StatemachineValidator { - /** - * Checks if the state name starts with a capital letter. - * @param state the state to check - * @param accept the acceptor to report errors - */ - checkStateNameStartsWithCapital(state: State, accept: ValidationAcceptor): void { - if (state.name.length > 0) { - const firstChar = state.name.substring(0, 1); - if (firstChar.toUpperCase() !== firstChar) { - accept('warning', 'State name should start with a capital letter.', { node: state, property: 'name' }); - } - } + /** + * Checks if the state name starts with a capital letter. + * @param state the state to check + * @param accept the acceptor to report errors + */ + checkStateNameStartsWithCapital(state: State, accept: ValidationAcceptor): void { + if (state.name.length > 0) { + const firstChar = state.name.substring(0, 1); + if (firstChar.toUpperCase() !== firstChar) { + accept('warning', 'State name should start with a capital letter.', { node: state, property: 'name' }); + } } + } - /** - * Checks if there are duplicate state and event names. - * @param statemachine the statemachine to check - * @param accept the acceptor to report errors - */ - checkUniqueStatesAndEvents(statemachine: Statemachine, accept: ValidationAcceptor): void { - // check for duplicate state and event names and add them to the map - const names = new MultiMap(); - const allSymbols = [...statemachine.states, ...statemachine.events]; - for (const symbol of allSymbols) { - names.add(symbol.name, symbol); - } - for (const [name, symbols] of names.entriesGroupedByKey()) { - if (symbols.length > 1) { - for (const symbol of symbols) { - accept('error', `Duplicate identifier name: ${name}`, { node: symbol, property: 'name' }); - } - } + /** + * Checks if there are duplicate state and event names. + * @param statemachine the statemachine to check + * @param accept the acceptor to report errors + */ + checkUniqueStatesAndEvents(statemachine: Statemachine, accept: ValidationAcceptor): void { + // check for duplicate state and event names and add them to the map + const names = new MultiMap(); + const allSymbols = [...statemachine.states, ...statemachine.events]; + for (const symbol of allSymbols) { + names.add(symbol.name, symbol); + } + for (const [name, symbols] of names.entriesGroupedByKey()) { + if (symbols.length > 1) { + for (const symbol of symbols) { + accept('error', `Duplicate identifier name: ${name}`, { node: symbol, property: 'name' }); } + } } + } } diff --git a/packages/examples/src/langium/statemachine/main-react.tsx b/packages/examples/src/langium/statemachine/main-react.tsx index b13ab6ae5..cc3ba03ab 100644 --- a/packages/examples/src/langium/statemachine/main-react.tsx +++ b/packages/examples/src/langium/statemachine/main-react.tsx @@ -16,94 +16,112 @@ import { createLangiumGlobalConfig } from './config/statemachineConfig.js'; import { loadStatemachineWorkerRegular } from './main.js'; export const runStatemachineReact = async (noControls: boolean) => { - const worker = loadStatemachineWorkerRegular(); - const reader = new BrowserMessageReader(worker); - const writer = new BrowserMessageWriter(worker); - const logger = new ConsoleLogger(LogLevel.Off); - reader.listen((message) => { - logger.info('Received message from worker:', message); - }); + const worker = loadStatemachineWorkerRegular(); + const reader = new BrowserMessageReader(worker); + const writer = new BrowserMessageWriter(worker); + const logger = new ConsoleLogger(LogLevel.Off); + reader.listen((message) => { + logger.info('Received message from worker:', message); + }); - const root = ReactDOM.createRoot(document.getElementById('react-root')!); - const App = () => { - const [codeState, setCodeState] = useState(text); - const [disposeLcState, setDisposeLcState] = useState(undefined); - const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); + const root = ReactDOM.createRoot(document.getElementById('react-root')!); + const App = () => { + const [codeState, setCodeState] = useState(text); + const [disposeLcState, setDisposeLcState] = useState(undefined); + const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); - const onTextChanged = (textChanges: TextContents) => { - if (textChanges.modified !== codeState) { - setCodeState(textChanges.modified as string); - } - }; + const onTextChanged = (textChanges: TextContents) => { + if (textChanges.modified !== codeState) { + setCodeState(textChanges.modified as string); + } + }; - const appConfig = createLangiumGlobalConfig({ - languageServerId: 'react', - codeContent: { - text: codeState, - uri: '/workspace/example.statemachine' - }, - worker, - messageTransports: { reader, writer } - }); + const appConfig = createLangiumGlobalConfig({ + languageServerId: 'react', + codeContent: { + text: codeState, + uri: '/workspace/example.statemachine' + }, + worker, + messageTransports: { reader, writer } + }); - return ( - <> -
- - - + return ( + <> +
+ + + - console.log(' >>> config processed <<<')} - enforceLanguageClientDispose={disposeLcState} - onDisposeLanguageClient={() => console.log(' >>> language client disposed <<<')} - /> - Debug:
{codeState} -
- - ); - }; + console.log(' >>> config processed <<<')} + enforceLanguageClientDispose={disposeLcState} + onDisposeLanguageClient={() => console.log(' >>> language client disposed <<<')} + /> + Debug: +
+ {codeState} +
+ + ); + }; - const renderApp = () => { - const elem = document.getElementById('checkbox-strictmode'); - const strictMode = elem === null ? false : (elem as HTMLInputElement).checked; - if (strictMode) { - root.render(); - } else { - root.render(); - } - }; + const renderApp = () => { + const elem = document.getElementById('checkbox-strictmode'); + const strictMode = elem === null ? false : (elem as HTMLInputElement).checked; + if (strictMode) { + root.render( + + + + ); + } else { + root.render(); + } + }; - try { - if (noControls) { - renderApp(); - } else { - document.querySelector('#button-start')?.addEventListener('click', async () => { - disableElement('button-start', true); - disableElement('button-dispose', false); - renderApp(); - disableElement('checkbox-strictmode', true); - }); - document.querySelector('#button-dispose')?.addEventListener('click', () => { - disableElement('button-start', false); - disableElement('button-dispose', true); + try { + if (noControls) { + renderApp(); + } else { + document.querySelector('#button-start')?.addEventListener('click', async () => { + disableElement('button-start', true); + disableElement('button-dispose', false); + renderApp(); + disableElement('checkbox-strictmode', true); + }); + document.querySelector('#button-dispose')?.addEventListener('click', () => { + disableElement('button-start', false); + disableElement('button-dispose', true); - root.render([]); - }); - } - } catch (e) { - console.error(e); + root.render([]); + }); } + } catch (e) { + console.error(e); + } }; diff --git a/packages/examples/src/langium/statemachine/main.ts b/packages/examples/src/langium/statemachine/main.ts index 4e5e1b750..6a915b3ee 100644 --- a/packages/examples/src/langium/statemachine/main.ts +++ b/packages/examples/src/langium/statemachine/main.ts @@ -19,126 +19,129 @@ let editorApp2: EditorApp | undefined; let lcWrapper: LanguageClientWrapper; const startEditor = async () => { - disableElement('button-start', true); - disableElement('button-dispose', false); - - if (editorApp?.isStarted() === true || editorApp2?.isStarted() === true) { - alert('Editor was already started!'); - return; + disableElement('button-start', true); + disableElement('button-dispose', false); + + if (editorApp?.isStarted() === true || editorApp2?.isStarted() === true) { + alert('Editor was already started!'); + return; + } + + // init worker with port for client and worker + const stateMachineWorkerPort = loadStatemachinWorkerPort(); + // use callback to receive message back from worker independent of the message channel the LSP is using + stateMachineWorkerPort.onmessage = (event) => { + console.log('Received message from worker: ' + event.data); + }; + const channel = new MessageChannel(); + stateMachineWorkerPort.postMessage( + { + port: channel.port2 + }, + [channel.port2] + ); + + const reader = new BrowserMessageReader(channel.port1); + const writer = new BrowserMessageWriter(channel.port1); + reader.listen((message) => { + console.log('Received message from worker:', message); + }); + + const htmlContainer = document.getElementById('monaco-editor-root')!; + // the configuration does not contain any text content + const appConfig = createLangiumGlobalConfig({ + languageServerId: 'first', + codeContent: { + text, + uri: '/workspace/example.statemachine' + }, + worker: stateMachineWorkerPort, + messagePort: channel.port1, + messageTransports: { reader, writer }, + htmlContainer + }); + editorApp = new EditorApp(appConfig.editorAppConfig); + + // perform global monaco-vscode-api init + const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); + await apiWrapper.start(); + + // init language client + lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); + await lcWrapper.start(); + + // run editorApp + await editorApp.start(htmlContainer); + + await editorApp.updateCodeResources({ + modified: { + text, + uri: '/workspace/statemachine-mod.statemachine' } - - // init worker with port for client and worker - const stateMachineWorkerPort = loadStatemachinWorkerPort(); - // use callback to receive message back from worker independent of the message channel the LSP is using - stateMachineWorkerPort.onmessage = (event) => { - console.log('Received message from worker: ' + event.data); - }; - const channel = new MessageChannel(); - stateMachineWorkerPort.postMessage({ - port: channel.port2 - }, [channel.port2]); - - const reader = new BrowserMessageReader(channel.port1); - const writer = new BrowserMessageWriter(channel.port1); - reader.listen((message) => { - console.log('Received message from worker:', message); - }); - - const htmlContainer = document.getElementById('monaco-editor-root')!; - // the configuration does not contain any text content - const appConfig = createLangiumGlobalConfig({ - languageServerId: 'first', - codeContent: { - text, - uri: '/workspace/example.statemachine' - }, - worker: stateMachineWorkerPort, - messagePort: channel.port1, - messageTransports: { reader, writer }, - htmlContainer - }); - editorApp = new EditorApp(appConfig.editorAppConfig); - - // perform global monaco-vscode-api init - const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); - await apiWrapper.start(); - - // init language client - lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); - await lcWrapper.start(); - - // run editorApp - await editorApp.start(htmlContainer); - - await editorApp.updateCodeResources({ - modified: { - text, - uri: '/workspace/statemachine-mod.statemachine' - } - }); - - // start the second editorApp without any languageclient config - // => they share the language server and both text contents have different uris - const appConfig2 = appConfig; - appConfig2.editorAppConfig.codeResources!.modified = { - text: textMod, - uri: '/workspace/example-mod.statemachine' - }; - editorApp2 = new EditorApp(appConfig2.editorAppConfig); - - // run a second editorApp with another dom element - await editorApp2.start(document.getElementById('monaco-editor-root2')!); - - vscode.commands.getCommands().then((x) => { - console.log('Currently registered # of vscode commands: ' + x.length); - }); - - await delayExecution(1000); - - await editorApp.updateCodeResources({ - modified: { - text: `// modified file\n\n${text}`, - uri: '/workspace/statemachine-mod2.statemachine' - } - }); + }); + + // start the second editorApp without any languageclient config + // => they share the language server and both text contents have different uris + const appConfig2 = appConfig; + appConfig2.editorAppConfig.codeResources!.modified = { + text: textMod, + uri: '/workspace/example-mod.statemachine' + }; + editorApp2 = new EditorApp(appConfig2.editorAppConfig); + + // run a second editorApp with another dom element + await editorApp2.start(document.getElementById('monaco-editor-root2')!); + + vscode.commands.getCommands().then((x) => { + console.log('Currently registered # of vscode commands: ' + x.length); + }); + + await delayExecution(1000); + + await editorApp.updateCodeResources({ + modified: { + text: `// modified file\n\n${text}`, + uri: '/workspace/statemachine-mod2.statemachine' + } + }); }; const disposeEditor = async () => { - disableElement('button-start', false); - disableElement('button-dispose', true); + disableElement('button-start', false); + disableElement('button-dispose', true); - await lcWrapper.dispose(); + await lcWrapper.dispose(); - editorApp?.reportStatus(); - await editorApp?.dispose(); - console.log(editorApp?.reportStatus().join('\n')); + editorApp?.reportStatus(); + await editorApp?.dispose(); + console.log(editorApp?.reportStatus().join('\n')); - editorApp2?.reportStatus(); - await editorApp2?.dispose(); - console.log(editorApp2?.reportStatus().join('\n')); + editorApp2?.reportStatus(); + await editorApp2?.dispose(); + console.log(editorApp2?.reportStatus().join('\n')); }; export const runStatemachine = async () => { - try { - document.querySelector('#button-start')?.addEventListener('click', startEditor); - document.querySelector('#button-dispose')?.addEventListener('click', disposeEditor); - } catch (e) { - console.error(e); - } + try { + document.querySelector('#button-start')?.addEventListener('click', startEditor); + document.querySelector('#button-dispose')?.addEventListener('click', disposeEditor); + } catch (e) { + console.error(e); + } }; // Language Server preparation export const loadStatemachineWorkerRegular = () => { - return new Worker(new URL('./worker/statemachine-server.ts', import.meta.url), { - type: 'module', - name: 'Statemachine Server Regular', - }); + return new Worker(new URL('./worker/statemachine-server.ts', import.meta.url), { + type: 'module', + name: 'Statemachine Server Regular' + }); }; export const loadStatemachinWorkerPort = () => { - return new Worker(new URL('./worker/statemachine-server-port.ts', import.meta.url), { - type: 'module', - name: 'Statemachine Server Port', - }); + return new Worker(new URL('./worker/statemachine-server-port.ts', import.meta.url), { + type: 'module', + name: 'Statemachine Server Port' + }); }; diff --git a/packages/examples/src/langium/statemachine/syntaxes/statemachine.tmLanguage.json b/packages/examples/src/langium/statemachine/syntaxes/statemachine.tmLanguage.json index 7aee5e2d2..a3a1be190 100644 --- a/packages/examples/src/langium/statemachine/syntaxes/statemachine.tmLanguage.json +++ b/packages/examples/src/langium/statemachine/syntaxes/statemachine.tmLanguage.json @@ -1,9 +1,7 @@ { "name": "statemachine", "scopeName": "source.statemachine", - "fileTypes": [ - ".statemachine" - ], + "fileTypes": [".statemachine"], "patterns": [ { "include": "#comments" diff --git a/packages/examples/src/langium/statemachine/worker/statemachine-server-port.ts b/packages/examples/src/langium/statemachine/worker/statemachine-server-port.ts index 82959d7e6..90a3db156 100644 --- a/packages/examples/src/langium/statemachine/worker/statemachine-server-port.ts +++ b/packages/examples/src/langium/statemachine/worker/statemachine-server-port.ts @@ -10,14 +10,14 @@ import { start } from './statemachine-server-start.js'; declare const self: DedicatedWorkerGlobalScope; self.onmessage = async (event: MessageEvent) => { - const data = event.data; - console.log(event.data); - if (data.port !== undefined) { - await start(data.port, 'statemachine-server-port'); + const data = event.data; + console.log(event.data); + if (data.port !== undefined) { + await start(data.port, 'statemachine-server-port'); - setTimeout(() => { - // test independent communication - self.postMessage('started'); - }, 1000); - } + setTimeout(() => { + // test independent communication + self.postMessage('started'); + }, 1000); + } }; diff --git a/packages/examples/src/langium/statemachine/worker/statemachine-server-start.ts b/packages/examples/src/langium/statemachine/worker/statemachine-server-start.ts index 4d8adfecb..8ed832682 100644 --- a/packages/examples/src/langium/statemachine/worker/statemachine-server-start.ts +++ b/packages/examples/src/langium/statemachine/worker/statemachine-server-start.ts @@ -14,20 +14,20 @@ export let messageReader: BrowserMessageReader | undefined; export let messageWriter: BrowserMessageWriter | undefined; export const start = async (port: MessagePort | DedicatedWorkerGlobalScope, name: string) => { - console.log(`Starting ${name}...`); - /* browser specific setup code */ - messageReader = new BrowserMessageReader(port); - messageWriter = new BrowserMessageWriter(port); + console.log(`Starting ${name}...`); + /* browser specific setup code */ + messageReader = new BrowserMessageReader(port); + messageWriter = new BrowserMessageWriter(port); - messageReader.listen((message) => { - console.log('Received message from main thread:', message); - }); + messageReader.listen((message) => { + console.log('Received message from main thread:', message); + }); - const connection = createConnection(messageReader, messageWriter); + const connection = createConnection(messageReader, messageWriter); - // Inject the shared services and language-specific services - const { shared } = await createStatemachineServices({ connection, ...EmptyFileSystem }); + // Inject the shared services and language-specific services + const { shared } = await createStatemachineServices({ connection, ...EmptyFileSystem }); - // Start the language server with the shared services - startLanguageServer(shared); + // Start the language server with the shared services + startLanguageServer(shared); }; diff --git a/packages/examples/src/multi/config.ts b/packages/examples/src/multi/config.ts index cc30b83bb..005cd6b56 100644 --- a/packages/examples/src/multi/config.ts +++ b/packages/examples/src/multi/config.ts @@ -8,57 +8,57 @@ import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; import type { BaseLanguageClient } from 'vscode-languageclient/browser.js'; export const createJsonLanguageClientConfig: () => LanguageClientConfig = () => { - return { - languageId: 'json', - clientOptions: { - documentSelector: ['json'] - }, - connection: { - options: { - $type: 'WebSocketParams', - host: 'localhost', - port: 30000, - path: 'sampleServer', - secured: false - } - } - }; + return { + languageId: 'json', + clientOptions: { + documentSelector: ['json'] + }, + connection: { + options: { + $type: 'WebSocketParams', + host: 'localhost', + port: 30000, + path: 'sampleServer', + secured: false + } + } + }; }; export const createPythonLanguageClientConfig: () => LanguageClientConfig = () => { - return { - languageId: 'python', - connection: { - options: { - $type: 'WebSocketParams', - host: 'localhost', - port: 30001, - path: 'pyright', - secured: false, - extraParams: { - authorization: 'UserAuth' - }, - startOptions: { - onCall: async (languageClient?: BaseLanguageClient) => { - setTimeout(() => { - ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { - vscode.commands.registerCommand(cmdName, async (...args: unknown[]) => { - await languageClient?.sendRequest('workspace/executeCommand', { command: cmdName, arguments: args }); - }); - }); - }, 250); - }, - reportStatus: true, - } - } + return { + languageId: 'python', + connection: { + options: { + $type: 'WebSocketParams', + host: 'localhost', + port: 30001, + path: 'pyright', + secured: false, + extraParams: { + authorization: 'UserAuth' }, - clientOptions: { - documentSelector: ['python', 'py'], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.parse('/workspace') - } + startOptions: { + onCall: async (languageClient?: BaseLanguageClient) => { + setTimeout(() => { + ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { + vscode.commands.registerCommand(cmdName, async (...args: unknown[]) => { + await languageClient?.sendRequest('workspace/executeCommand', { command: cmdName, arguments: args }); + }); + }); + }, 250); + }, + reportStatus: true } - }; + } + }, + clientOptions: { + documentSelector: ['python', 'py'], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.parse('/workspace') + } + } + }; }; diff --git a/packages/examples/src/multi/twoLanguageClients.ts b/packages/examples/src/multi/twoLanguageClients.ts index d523a3304..acc6e0adc 100644 --- a/packages/examples/src/multi/twoLanguageClients.ts +++ b/packages/examples/src/multi/twoLanguageClients.ts @@ -17,102 +17,101 @@ import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-langu import { LanguageClientManager, type LanguageClientConfigs } from 'monaco-languageclient/lcwrapper'; export const runMultipleLanguageClientsExample = async () => { - disableElement('button-flip', true); + disableElement('button-flip', true); - const textJson = `{ + const textJson = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": {"value": "unix"} }`; - const textPython = `from hello2 import print_hello + const textPython = `from hello2 import print_hello print_hello() print("Hello Moon!") `; - let currentText = textJson; - let currenFileExt = 'json'; - - const htmlContainer = document.getElementById('monaco-editor-root')!; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer - }, - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride() - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - const editorAppConfig: EditorAppConfig = { - id: '42', - codeResources: { - modified: { - text: currentText, - uri: `/workspace/example.${currenFileExt}` - } - } - }; - - // perform global monaco-vscode-api init - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - const lcManager = new LanguageClientManager(); - const languageClientConfigs: LanguageClientConfigs = { - configs: { - json: createJsonLanguageClientConfig(), - python: createPythonLanguageClientConfig() - } - }; - - const editorApp = new EditorApp(editorAppConfig); - - document.querySelector('#button-start')?.addEventListener('click', async () => { - try { - disableElement('button-start', true); - disableElement('button-flip', false); - - await editorApp.start(htmlContainer); - if (editorAppConfig.codeResources?.modified !== undefined) { - editorAppConfig.codeResources.modified.text = currentText; - editorAppConfig.codeResources.modified.uri = `/workspace/example.${currenFileExt}`; - } - - // init and start language clients after start - lcManager.setConfigs(languageClientConfigs); - await lcManager.start(); - } catch (e) { - console.error(e); - } - }); - document.querySelector('#button-dispose')?.addEventListener('click', async () => { - disableElement('button-flip', true); - disableElement('button-dispose', true); - disableElement('button-start', false); - - await editorApp.dispose(); - await lcManager.dispose(); - }); - document.querySelector('#button-flip')?.addEventListener('click', async () => { - currentText = currentText === textJson ? textPython : textJson; - currenFileExt = currenFileExt === 'json' ? 'py' : 'json'; - await editorApp.updateCodeResources({ - modified: { - text: currentText, - uri: `/workspace/example.${currenFileExt}` - } - }); + let currentText = textJson; + let currenFileExt = 'json'; + + const htmlContainer = document.getElementById('monaco-editor-root')!; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer + }, + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride() + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + const editorAppConfig: EditorAppConfig = { + id: '42', + codeResources: { + modified: { + text: currentText, + uri: `/workspace/example.${currenFileExt}` + } + } + }; + + // perform global monaco-vscode-api init + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + const lcManager = new LanguageClientManager(); + const languageClientConfigs: LanguageClientConfigs = { + configs: { + json: createJsonLanguageClientConfig(), + python: createPythonLanguageClientConfig() + } + }; + + const editorApp = new EditorApp(editorAppConfig); + + document.querySelector('#button-start')?.addEventListener('click', async () => { + try { + disableElement('button-start', true); + disableElement('button-flip', false); + + await editorApp.start(htmlContainer); + if (editorAppConfig.codeResources?.modified !== undefined) { + editorAppConfig.codeResources.modified.text = currentText; + editorAppConfig.codeResources.modified.uri = `/workspace/example.${currenFileExt}`; + } + + // init and start language clients after start + lcManager.setConfigs(languageClientConfigs); + await lcManager.start(); + } catch (e) { + console.error(e); + } + }); + document.querySelector('#button-dispose')?.addEventListener('click', async () => { + disableElement('button-flip', true); + disableElement('button-dispose', true); + disableElement('button-start', false); + + await editorApp.dispose(); + await lcManager.dispose(); + }); + document.querySelector('#button-flip')?.addEventListener('click', async () => { + currentText = currentText === textJson ? textPython : textJson; + currenFileExt = currenFileExt === 'json' ? 'py' : 'json'; + await editorApp.updateCodeResources({ + modified: { + text: currentText, + uri: `/workspace/example.${currenFileExt}` + } }); - + }); }; diff --git a/packages/examples/src/python/client/config.ts b/packages/examples/src/python/client/config.ts index dea011d8e..521afb912 100644 --- a/packages/examples/src/python/client/config.ts +++ b/packages/examples/src/python/client/config.ts @@ -7,7 +7,11 @@ import { LogLevel } from '@codingame/monaco-vscode-api'; import getDebugServiceOverride from '@codingame/monaco-vscode-debug-service-override'; import getEnvironmentServiceOverride from '@codingame/monaco-vscode-environment-service-override'; import getExplorerServiceOverride from '@codingame/monaco-vscode-explorer-service-override'; -import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; +import { + RegisteredFileSystemProvider, + RegisteredMemoryFile, + registerFileSystemOverlay +} from '@codingame/monaco-vscode-files-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import getLifecycleServiceOverride from '@codingame/monaco-vscode-lifecycle-service-override'; import getLocalizationServiceOverride from '@codingame/monaco-vscode-localization-service-override'; @@ -22,7 +26,12 @@ import getBannerServiceOverride from '@codingame/monaco-vscode-view-banner-servi import getStatusBarServiceOverride from '@codingame/monaco-vscode-view-status-bar-service-override'; import getTitleBarServiceOverride from '@codingame/monaco-vscode-view-title-bar-service-override'; import { createUrl } from 'monaco-languageclient/common'; -import { createDebugLaunchConfigFile, provideDebuggerExtensionConfig, type ConfigParams, type FileDefinition } from 'monaco-languageclient/debugger'; +import { + createDebugLaunchConfigFile, + provideDebuggerExtensionConfig, + type ConfigParams, + type FileDefinition +} from 'monaco-languageclient/debugger'; import type { EditorAppConfig } from 'monaco-languageclient/editorApp'; import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; import { createDefaultLocaleConfiguration } from 'monaco-languageclient/vscodeApiLocales'; @@ -37,182 +46,182 @@ import hello2PyCode from '../../../resources/python/hello2.py?raw'; import { createDefaultWorkspaceContent } from '../../common/client/utils.js'; export const createDefaultConfigParams = (homeDir: string, htmlContainer: HTMLElement): ConfigParams => { - const files = new Map(); - const workspaceRoot = `${homeDir}/workspace`; - const configParams: ConfigParams = { - extensionName: 'debugger-py-client', - publisher: 'TypeFox', - version: '1.0.0', - languageId: 'python', - documentSelector: ['python', 'py'], - homeDir, - workspaceRoot: `${homeDir}/workspace`, - workspaceFile: vscode.Uri.file(`${homeDir}/.vscode/workspace.code-workspace`), - htmlContainer, - protocol: 'ws', - hostname: 'localhost', - port: 55555, - files, - defaultFile: `${workspaceRoot}/hello2.py`, - helpContainerCmd: 'docker compose -f ./packages/examples/resources/debugger/docker-compose.yml up -d', - debuggerExecCall: 'graalpy --dap --dap.WaitAttached --dap.Suspend=true' - }; - const helloPyPath = `${workspaceRoot}/hello.py`; - const hello2PyPath = configParams.defaultFile; - const badPyPath = `${workspaceRoot}/bad.py`; + const files = new Map(); + const workspaceRoot = `${homeDir}/workspace`; + const configParams: ConfigParams = { + extensionName: 'debugger-py-client', + publisher: 'TypeFox', + version: '1.0.0', + languageId: 'python', + documentSelector: ['python', 'py'], + homeDir, + workspaceRoot: `${homeDir}/workspace`, + workspaceFile: vscode.Uri.file(`${homeDir}/.vscode/workspace.code-workspace`), + htmlContainer, + protocol: 'ws', + hostname: 'localhost', + port: 55555, + files, + defaultFile: `${workspaceRoot}/hello2.py`, + helpContainerCmd: 'docker compose -f ./packages/examples/resources/debugger/docker-compose.yml up -d', + debuggerExecCall: 'graalpy --dap --dap.WaitAttached --dap.Suspend=true' + }; + const helloPyPath = `${workspaceRoot}/hello.py`; + const hello2PyPath = configParams.defaultFile; + const badPyPath = `${workspaceRoot}/bad.py`; - files.set('hello.py', { code: helloPyCode, path: helloPyPath, uri: vscode.Uri.file(helloPyPath) }); - files.set('hello2.py', { code: hello2PyCode, path: hello2PyPath, uri: vscode.Uri.file(hello2PyPath) }); - files.set('bad.py', { code: badPyCode, path: badPyPath, uri: vscode.Uri.file(badPyPath) }); + files.set('hello.py', { code: helloPyCode, path: helloPyPath, uri: vscode.Uri.file(helloPyPath) }); + files.set('hello2.py', { code: hello2PyCode, path: hello2PyPath, uri: vscode.Uri.file(hello2PyPath) }); + files.set('bad.py', { code: badPyCode, path: badPyPath, uri: vscode.Uri.file(badPyPath) }); - const fileSystemProvider = new RegisteredFileSystemProvider(false); - fileSystemProvider.registerFile(new RegisteredMemoryFile(files.get('hello.py')!.uri, helloPyCode)); - fileSystemProvider.registerFile(new RegisteredMemoryFile(files.get('hello2.py')!.uri, hello2PyCode)); - fileSystemProvider.registerFile(new RegisteredMemoryFile(files.get('bad.py')!.uri, badPyCode)); - fileSystemProvider.registerFile(new RegisteredMemoryFile(configParams.workspaceFile, createDefaultWorkspaceContent(workspaceRoot))); - fileSystemProvider.registerFile(createDebugLaunchConfigFile(workspaceRoot, configParams.languageId)); - registerFileSystemOverlay(1, fileSystemProvider); + const fileSystemProvider = new RegisteredFileSystemProvider(false); + fileSystemProvider.registerFile(new RegisteredMemoryFile(files.get('hello.py')!.uri, helloPyCode)); + fileSystemProvider.registerFile(new RegisteredMemoryFile(files.get('hello2.py')!.uri, hello2PyCode)); + fileSystemProvider.registerFile(new RegisteredMemoryFile(files.get('bad.py')!.uri, badPyCode)); + fileSystemProvider.registerFile(new RegisteredMemoryFile(configParams.workspaceFile, createDefaultWorkspaceContent(workspaceRoot))); + fileSystemProvider.registerFile(createDebugLaunchConfigFile(workspaceRoot, configParams.languageId)); + registerFileSystemOverlay(1, fileSystemProvider); - return configParams; + return configParams; }; export type PythonAppConfig = { - languageClientConfig: LanguageClientConfig; - vscodeApiConfig: MonacoVscodeApiConfig; - editorAppConfig: EditorAppConfig; - configParams: ConfigParams; -} + languageClientConfig: LanguageClientConfig; + vscodeApiConfig: MonacoVscodeApiConfig; + editorAppConfig: EditorAppConfig; + configParams: ConfigParams; +}; export const createPythonAppConfig = (): PythonAppConfig => { - const configParams = createDefaultConfigParams('/home/mlc', document.body); + const configParams = createDefaultConfigParams('/home/mlc', document.body); - const url = createUrl({ - secured: false, - host: 'localhost', - port: 30001, - path: 'pyright', - extraParams: { - authorization: 'UserAuth' - } - }); - const webSocket = new WebSocket(url); - const iWebSocket = toSocket(webSocket); - const reader = new WebSocketMessageReader(iWebSocket); - const writer = new WebSocketMessageWriter(iWebSocket); + const url = createUrl({ + secured: false, + host: 'localhost', + port: 30001, + path: 'pyright', + extraParams: { + authorization: 'UserAuth' + } + }); + const webSocket = new WebSocket(url); + const iWebSocket = toSocket(webSocket); + const reader = new WebSocketMessageReader(iWebSocket); + const writer = new WebSocketMessageWriter(iWebSocket); - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - logLevel: LogLevel.Debug, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - ...getLifecycleServiceOverride(), - ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), - ...getBannerServiceOverride(), - ...getStatusBarServiceOverride(), - ...getTitleBarServiceOverride(), - ...getExplorerServiceOverride(), - ...getRemoteAgentServiceOverride(), - ...getEnvironmentServiceOverride(), - ...getSecretStorageServiceOverride(), - ...getStorageServiceOverride(), - ...getSearchServiceOverride(), - ...getDebugServiceOverride(), - ...getTestingServiceOverride(), - ...getPreferencesServiceOverride() - }, - viewsConfig: { - $type: 'ViewsService', - htmlContainer: configParams.htmlContainer, - htmlAugmentationInstructions: defaultHtmlAugmentationInstructions, - viewsInitFunc: defaultViewsInit - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true, - 'debug.toolBarLocation': 'docked' - }) + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + logLevel: LogLevel.Debug, + serviceOverrides: { + ...getKeybindingsServiceOverride(), + ...getLifecycleServiceOverride(), + ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), + ...getBannerServiceOverride(), + ...getStatusBarServiceOverride(), + ...getTitleBarServiceOverride(), + ...getExplorerServiceOverride(), + ...getRemoteAgentServiceOverride(), + ...getEnvironmentServiceOverride(), + ...getSecretStorageServiceOverride(), + ...getStorageServiceOverride(), + ...getSearchServiceOverride(), + ...getDebugServiceOverride(), + ...getTestingServiceOverride(), + ...getPreferencesServiceOverride() + }, + viewsConfig: { + $type: 'ViewsService', + htmlContainer: configParams.htmlContainer, + htmlAugmentationInstructions: defaultHtmlAugmentationInstructions, + viewsInitFunc: defaultViewsInit + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true, + 'debug.toolBarLocation': 'docked' + }) + }, + workspaceConfig: { + enableWorkspaceTrust: true, + windowIndicator: { + label: 'mlc-python-example', + tooltip: '', + command: '' + }, + workspaceProvider: { + trusted: true, + async open() { + window.open(window.location.href); + return true; }, - workspaceConfig: { - enableWorkspaceTrust: true, - windowIndicator: { - label: 'mlc-python-example', - tooltip: '', - command: '' - }, - workspaceProvider: { - trusted: true, - async open() { - window.open(window.location.href); - return true; - }, - workspace: { - workspaceUri: configParams.workspaceFile - } - }, - configurationDefaults: { - 'window.title': 'mlc-python-example${separator}${dirty}${activeEditorShort}' - }, - productConfiguration: { - nameShort: 'mlc-python-example', - nameLong: 'mlc-python-example' - } - }, - extensions: [ - { - config: { - name: 'mlc-python-example', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - } - } - }, - provideDebuggerExtensionConfig(configParams) - ], - monacoWorkerFactory: configureDefaultWorkerFactory - }; + workspace: { + workspaceUri: configParams.workspaceFile + } + }, + configurationDefaults: { + 'window.title': 'mlc-python-example${separator}${dirty}${activeEditorShort}' + }, + productConfiguration: { + nameShort: 'mlc-python-example', + nameLong: 'mlc-python-example' + } + }, + extensions: [ + { + config: { + name: 'mlc-python-example', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + } + } + }, + provideDebuggerExtensionConfig(configParams) + ], + monacoWorkerFactory: configureDefaultWorkerFactory + }; - const languageClientConfig: LanguageClientConfig = { - languageId: 'python', - connection: { - options: { - $type: 'WebSocketDirect', - webSocket: webSocket, - startOptions: { - onCall: (languageClient?: BaseLanguageClient) => { - setTimeout(() => { - ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { - vscode.commands.registerCommand(cmdName, async (...args: unknown[]) => { - await languageClient?.sendRequest('workspace/executeCommand', { command: cmdName, arguments: args }); - }); - }); - }, 250); - }, - reportStatus: true, - } - }, - messageTransports: { reader, writer } - }, - clientOptions: { - documentSelector: [configParams.languageId], - workspaceFolder: { - index: 0, - name: configParams.workspaceRoot, - uri: vscode.Uri.parse(configParams.workspaceRoot) - }, + const languageClientConfig: LanguageClientConfig = { + languageId: 'python', + connection: { + options: { + $type: 'WebSocketDirect', + webSocket: webSocket, + startOptions: { + onCall: (languageClient?: BaseLanguageClient) => { + setTimeout(() => { + ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { + vscode.commands.registerCommand(cmdName, async (...args: unknown[]) => { + await languageClient?.sendRequest('workspace/executeCommand', { command: cmdName, arguments: args }); + }); + }); + }, 250); + }, + reportStatus: true } - }; + }, + messageTransports: { reader, writer } + }, + clientOptions: { + documentSelector: [configParams.languageId], + workspaceFolder: { + index: 0, + name: configParams.workspaceRoot, + uri: vscode.Uri.parse(configParams.workspaceRoot) + } + } + }; - const editorAppConfig: EditorAppConfig = {}; + const editorAppConfig: EditorAppConfig = {}; - return { - vscodeApiConfig, - languageClientConfig, - editorAppConfig, - configParams: configParams - }; + return { + vscodeApiConfig, + languageClientConfig, + editorAppConfig, + configParams: configParams + }; }; diff --git a/packages/examples/src/python/client/main.ts b/packages/examples/src/python/client/main.ts index e1176c48e..ffaf02cbb 100644 --- a/packages/examples/src/python/client/main.ts +++ b/packages/examples/src/python/client/main.ts @@ -12,30 +12,30 @@ import { configureDebugging } from 'monaco-languageclient/debugger'; import { createPythonAppConfig } from './config.js'; export const runPythonWrapper = async () => { - const appConfig = createPythonAppConfig(); + const appConfig = createPythonAppConfig(); - // perform global monaco-vscode-api init - const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); - await apiWrapper.start(); + // perform global monaco-vscode-api init + const apiWrapper = new MonacoVscodeApiWrapper(appConfig.vscodeApiConfig); + await apiWrapper.start(); - const lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); + const lcWrapper = new LanguageClientWrapper(appConfig.languageClientConfig); - const editorApp = new EditorApp(appConfig.editorAppConfig); + const editorApp = new EditorApp(appConfig.editorAppConfig); - if (editorApp.isStarted()) { - console.warn('Editor was already started!'); - } else { - const result = apiWrapper.getExtensionRegisterResult('mlc-python-example') as RegisterLocalProcessExtensionResult; - await result.setAsDefaultApi(); + if (editorApp.isStarted()) { + console.warn('Editor was already started!'); + } else { + const result = apiWrapper.getExtensionRegisterResult('mlc-python-example') as RegisterLocalProcessExtensionResult; + await result.setAsDefaultApi(); - const initResult = apiWrapper.getExtensionRegisterResult('debugger-py-client') as RegisterLocalProcessExtensionResult | undefined; - if (initResult !== undefined) { - await configureDebugging(await initResult.getApi(), appConfig.configParams); - } + const initResult = apiWrapper.getExtensionRegisterResult('debugger-py-client') as RegisterLocalProcessExtensionResult | undefined; + if (initResult !== undefined) { + await configureDebugging(await initResult.getApi(), appConfig.configParams); + } - await lcWrapper.start(); + await lcWrapper.start(); - await vscode.commands.executeCommand('workbench.view.explorer'); - await vscode.window.showTextDocument(appConfig.configParams.files.get('hello2.py')!.uri); - } + await vscode.commands.executeCommand('workbench.view.explorer'); + await vscode.window.showTextDocument(appConfig.configParams.files.get('hello2.py')!.uri); + } }; diff --git a/packages/examples/src/python/client/reactPython.tsx b/packages/examples/src/python/client/reactPython.tsx index 18977c504..00acfca81 100644 --- a/packages/examples/src/python/client/reactPython.tsx +++ b/packages/examples/src/python/client/reactPython.tsx @@ -1,7 +1,7 @@ /* -------------------------------------------------------------------------------------------- * Copyright (c) 2024 TypeFox and others. * Licensed under the MIT License. See LICENSE in the package root for license information. -* ------------------------------------------------------------------------------------------ */ + * ------------------------------------------------------------------------------------------ */ import { type RegisterLocalProcessExtensionResult } from '@codingame/monaco-vscode-api/extensions'; import { MonacoEditorReactComp } from '@typefox/monaco-editor-react'; @@ -13,38 +13,39 @@ import * as vscode from 'vscode'; import { createPythonAppConfig } from './config.js'; export const runPythonReact = async () => { - const appConfig = createPythonAppConfig(); + const appConfig = createPythonAppConfig(); - const onVscodeApiInitDone = async (apiWrapper: MonacoVscodeApiWrapper) => { - const result = apiWrapper.getExtensionRegisterResult('mlc-python-example') as RegisterLocalProcessExtensionResult; - await result.setAsDefaultApi(); + const onVscodeApiInitDone = async (apiWrapper: MonacoVscodeApiWrapper) => { + const result = apiWrapper.getExtensionRegisterResult('mlc-python-example') as RegisterLocalProcessExtensionResult; + await result.setAsDefaultApi(); - const initResult = apiWrapper.getExtensionRegisterResult('debugger-py-client') as RegisterLocalProcessExtensionResult | undefined; - if (initResult !== undefined) { - await configureDebugging(await initResult.getApi(), appConfig.configParams); - } + const initResult = apiWrapper.getExtensionRegisterResult('debugger-py-client') as RegisterLocalProcessExtensionResult | undefined; + if (initResult !== undefined) { + await configureDebugging(await initResult.getApi(), appConfig.configParams); + } - await vscode.commands.executeCommand('workbench.view.explorer'); - await vscode.window.showTextDocument(appConfig.configParams.files.get('hello2.py')!.uri); - }; + await vscode.commands.executeCommand('workbench.view.explorer'); + await vscode.window.showTextDocument(appConfig.configParams.files.get('hello2.py')!.uri); + }; - const root = ReactDOM.createRoot(document.getElementById('react-root')!); - const App = () => { - return ( - <> -
- { - console.error(e); - }} /> -
- - ); - }; - root.render(); + const root = ReactDOM.createRoot(document.getElementById('react-root')!); + const App = () => { + return ( + <> +
+ { + console.error(e); + }} + /> +
+ + ); + }; + root.render(); }; diff --git a/packages/examples/src/python/server/main.ts b/packages/examples/src/python/server/main.ts index e86623e70..0096e09ee 100644 --- a/packages/examples/src/python/server/main.ts +++ b/packages/examples/src/python/server/main.ts @@ -8,33 +8,27 @@ import { resolve } from 'node:path'; import { runLanguageServer } from '../../common/node/language-server-runner.js'; export const runPythonServer = (baseDir: string, relativeDir: string) => { - const processRunPath = resolve(baseDir, relativeDir); - runLanguageServer({ - serverName: 'PYRIGHT', - pathName: '/pyright', - serverPort: 30001, - runCommand: 'node', - runCommandArgs: [ - processRunPath, - '--stdio' - ], - wsServerOptions: { - noServer: true, - perMessageDeflate: false, - clientTracking: true, - verifyClient: ( - clientInfo: { origin: string; secure: boolean; req: IncomingMessage }, - callback - ) => { - const parsedURL = new URL(`${clientInfo.origin}${clientInfo.req.url ?? ''}`); - const authToken = parsedURL.searchParams.get('authorization'); - if (authToken === 'UserAuth') { - callback(true); - } else { - callback(false); - } - } - }, - logMessages: true - }); + const processRunPath = resolve(baseDir, relativeDir); + runLanguageServer({ + serverName: 'PYRIGHT', + pathName: '/pyright', + serverPort: 30001, + runCommand: 'node', + runCommandArgs: [processRunPath, '--stdio'], + wsServerOptions: { + noServer: true, + perMessageDeflate: false, + clientTracking: true, + verifyClient: (clientInfo: { origin: string; secure: boolean; req: IncomingMessage }, callback) => { + const parsedURL = new URL(`${clientInfo.origin}${clientInfo.req.url ?? ''}`); + const authToken = parsedURL.searchParams.get('authorization'); + if (authToken === 'UserAuth') { + callback(true); + } else { + callback(false); + } + } + }, + logMessages: true + }); }; diff --git a/packages/examples/src/ts/clientTs.ts b/packages/examples/src/ts/clientTs.ts index bc4fa253e..67b61dafb 100644 --- a/packages/examples/src/ts/clientTs.ts +++ b/packages/examples/src/ts/clientTs.ts @@ -4,7 +4,11 @@ * ------------------------------------------------------------------------------------------ */ import { LogLevel } from '@codingame/monaco-vscode-api'; -import { InMemoryFileSystemProvider, registerFileSystemOverlay, type IFileWriteOptions } from '@codingame/monaco-vscode-files-service-override'; +import { + InMemoryFileSystemProvider, + registerFileSystemOverlay, + type IFileWriteOptions +} from '@codingame/monaco-vscode-files-service-override'; import '@codingame/monaco-vscode-javascript-default-extension'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import '@codingame/monaco-vscode-typescript-basics-default-extension'; @@ -17,185 +21,184 @@ import { createDefaultWorkspaceContent, disableElement } from '../common/client/ import getExtensionServiceOverride from '@codingame/monaco-vscode-extensions-service-override'; export const runTsWrapper = async () => { - disableElement('button-diff', true); + disableElement('button-diff', true); - const code = `const takesString = (x: string) => {}; + const code = `const takesString = (x: string) => {}; // you should see an error marker in the next line takesString(0);`; - const codeOriginal = `const takesNumber = (x: number) => {}; + const codeOriginal = `const takesNumber = (x: number) => {}; // you should see an error marker in the next line takesNumber(0);`; - const textEncoder = new TextEncoder(); - const options: IFileWriteOptions = { - atomic: false, - unlock: false, - create: true, - overwrite: true - }; - const workspaceUri = vscode.Uri.file('/workspace'); - const workspaceFileUri = vscode.Uri.file('/workspace.code-workspace'); - const codeUri = vscode.Uri.file('/workspace/hello.ts'); - const codeOriginalUri = vscode.Uri.file('/workspace/goodbye.ts'); - const fileSystemProvider = new InMemoryFileSystemProvider(); - await fileSystemProvider.mkdir(workspaceUri); - await fileSystemProvider.writeFile(codeUri, textEncoder.encode(code), options); - await fileSystemProvider.writeFile(codeOriginalUri, textEncoder.encode(codeOriginal), options); - await fileSystemProvider.writeFile(workspaceFileUri, textEncoder.encode(createDefaultWorkspaceContent('/workspace')), options); - registerFileSystemOverlay(1, fileSystemProvider); - - let currentOriginalCode = codeOriginal; - let currentOriginalCodeUri = codeOriginalUri; - let currentCode = code; - let currentCodeUri = codeUri; - let swapCode = false; - let diffEditor = false; - - const htmlContainer = document.getElementById('monaco-editor-root')!; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer - }, - logLevel: LogLevel.Debug, - // demonstrate that you can enable the ext host worker manually - advanced: { - loadExtensionServices: false - }, - serviceOverrides: { - ...getKeybindingsServiceOverride(), - ...getExtensionServiceOverride({ - enableWorkerExtensionHost: true - }) - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off', - 'typescript.tsserver.web.projectWideIntellisense.enabled': true, - 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false, - 'diffEditor.renderSideBySide': false, - 'editor.guides.bracketPairsHorizontal': true, - 'editor.experimental.asyncTokenization': true - }) + const textEncoder = new TextEncoder(); + const options: IFileWriteOptions = { + atomic: false, + unlock: false, + create: true, + overwrite: true + }; + const workspaceUri = vscode.Uri.file('/workspace'); + const workspaceFileUri = vscode.Uri.file('/workspace.code-workspace'); + const codeUri = vscode.Uri.file('/workspace/hello.ts'); + const codeOriginalUri = vscode.Uri.file('/workspace/goodbye.ts'); + const fileSystemProvider = new InMemoryFileSystemProvider(); + await fileSystemProvider.mkdir(workspaceUri); + await fileSystemProvider.writeFile(codeUri, textEncoder.encode(code), options); + await fileSystemProvider.writeFile(codeOriginalUri, textEncoder.encode(codeOriginal), options); + await fileSystemProvider.writeFile(workspaceFileUri, textEncoder.encode(createDefaultWorkspaceContent('/workspace')), options); + registerFileSystemOverlay(1, fileSystemProvider); + + let currentOriginalCode = codeOriginal; + let currentOriginalCodeUri = codeOriginalUri; + let currentCode = code; + let currentCodeUri = codeUri; + let swapCode = false; + let diffEditor = false; + + const htmlContainer = document.getElementById('monaco-editor-root')!; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer + }, + logLevel: LogLevel.Debug, + // demonstrate that you can enable the ext host worker manually + advanced: { + loadExtensionServices: false + }, + serviceOverrides: { + ...getKeybindingsServiceOverride(), + ...getExtensionServiceOverride({ + enableWorkerExtensionHost: true + }) + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off', + 'typescript.tsserver.web.projectWideIntellisense.enabled': true, + 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false, + 'diffEditor.renderSideBySide': false, + 'editor.guides.bracketPairsHorizontal': true, + 'editor.experimental.asyncTokenization': true + }) + }, + workspaceConfig: { + enableWorkspaceTrust: true, + workspaceProvider: { + trusted: true, + async open() { + window.open(window.location.href); + return true; }, - workspaceConfig: { - enableWorkspaceTrust: true, - workspaceProvider: { - trusted: true, - async open() { - window.open(window.location.href); - return true; - }, - workspace: { - workspaceUri: workspaceFileUri - } - } + workspace: { + workspaceUri: workspaceFileUri + } + } + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + // perform global monaco-vscode-api init + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + + let editorApp: EditorApp | undefined = undefined; + + const createEditorAppConfig = (useDiffEditor: boolean): EditorAppConfig => { + return { + codeResources: { + modified: { + text: currentCode, + uri: currentCodeUri.path }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - // perform global monaco-vscode-api init - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); - - let editorApp: EditorApp | undefined = undefined; - - const createEditorAppConfig = (useDiffEditor: boolean): EditorAppConfig => { - return { - codeResources: { - modified: { - text: currentCode, - uri: currentCodeUri.path - }, - original: { - text: currentOriginalCode, - uri: currentOriginalCodeUri.path, - } - }, - useDiffEditor: useDiffEditor - }; - }; - - const swapCurrentCode = () => { - swapCode = !swapCode; - if (swapCode) { - currentCode = codeOriginal; - currentCodeUri = codeOriginalUri; - currentOriginalCode = code; - currentOriginalCodeUri = codeUri; - } else { - currentCode = code; - currentCodeUri = codeUri; - currentOriginalCode = codeOriginal; - currentOriginalCodeUri = codeOriginalUri; + original: { + text: currentOriginalCode, + uri: currentOriginalCodeUri.path } + }, + useDiffEditor: useDiffEditor }; - - const updateEditorCodeResources = async (editorApp: EditorApp) => { - await editorApp.updateCodeResources({ - modified: { - text: currentCode, - uri: currentCodeUri.path - }, - original: { - text: currentOriginalCode, - uri: currentOriginalCodeUri.path - } - }); - }; - - try { - document.querySelector('#button-start')?.addEventListener('click', async () => { - disableElement('button-start', true); - disableElement('button-diff', false); - editorApp = new EditorApp(createEditorAppConfig(diffEditor)); - await editorApp.start(htmlContainer); - - await vscode.workspace.openTextDocument(codeUri); - await vscode.workspace.openTextDocument(codeOriginalUri); - - vscode.commands.getCommands().then((x) => { - console.log(`Found ${x.length} commands`); - const finding = x.find((elem) => elem === 'actions.find'); - console.log(`Found command: ${finding}`); - }); - - editorApp.getEditor()?.focus(); - await vscode.commands.executeCommand('actions.find'); - - await updateEditorCodeResources(editorApp); - }); - document.querySelector('#button-swap-code')?.addEventListener('click', async () => { - swapCurrentCode(); - - if (editorApp !== undefined) { - await updateEditorCodeResources(editorApp); - } - }); - document.querySelector('#button-diff')?.addEventListener('click', async () => { - diffEditor = !diffEditor; - const editorAppConfig = createEditorAppConfig(diffEditor); - - if (editorApp !== undefined) { - await editorApp.dispose(); - } - editorApp = new EditorApp(editorAppConfig); - await editorApp.start(htmlContainer); - await updateEditorCodeResources(editorApp); - }); - document.querySelector('#button-dispose')?.addEventListener('click', async () => { - disableElement('button-start', false); - disableElement('button-diff', true); - - await editorApp?.dispose(); - }); - } catch (e) { - console.error(e); + }; + + const swapCurrentCode = () => { + swapCode = !swapCode; + if (swapCode) { + currentCode = codeOriginal; + currentCodeUri = codeOriginalUri; + currentOriginalCode = code; + currentOriginalCodeUri = codeUri; + } else { + currentCode = code; + currentCodeUri = codeUri; + currentOriginalCode = codeOriginal; + currentOriginalCodeUri = codeOriginalUri; } + }; + + const updateEditorCodeResources = async (editorApp: EditorApp) => { + await editorApp.updateCodeResources({ + modified: { + text: currentCode, + uri: currentCodeUri.path + }, + original: { + text: currentOriginalCode, + uri: currentOriginalCodeUri.path + } + }); + }; + + try { + document.querySelector('#button-start')?.addEventListener('click', async () => { + disableElement('button-start', true); + disableElement('button-diff', false); + editorApp = new EditorApp(createEditorAppConfig(diffEditor)); + await editorApp.start(htmlContainer); + + await vscode.workspace.openTextDocument(codeUri); + await vscode.workspace.openTextDocument(codeOriginalUri); + + vscode.commands.getCommands().then((x) => { + console.log(`Found ${x.length} commands`); + const finding = x.find((elem) => elem === 'actions.find'); + console.log(`Found command: ${finding}`); + }); + + editorApp.getEditor()?.focus(); + await vscode.commands.executeCommand('actions.find'); + + await updateEditorCodeResources(editorApp); + }); + document.querySelector('#button-swap-code')?.addEventListener('click', async () => { + swapCurrentCode(); + + if (editorApp !== undefined) { + await updateEditorCodeResources(editorApp); + } + }); + document.querySelector('#button-diff')?.addEventListener('click', async () => { + diffEditor = !diffEditor; + const editorAppConfig = createEditorAppConfig(diffEditor); + + if (editorApp !== undefined) { + await editorApp.dispose(); + } + editorApp = new EditorApp(editorAppConfig); + await editorApp.start(htmlContainer); + await updateEditorCodeResources(editorApp); + }); + document.querySelector('#button-dispose')?.addEventListener('click', async () => { + disableElement('button-start', false); + disableElement('button-diff', true); + + await editorApp?.dispose(); + }); + } catch (e) { + console.error(e); + } }; - diff --git a/packages/examples/src/vite-env.d.ts b/packages/examples/src/vite-env.d.ts index 17099f585..01663801e 100644 --- a/packages/examples/src/vite-env.d.ts +++ b/packages/examples/src/vite-env.d.ts @@ -6,6 +6,6 @@ /// declare module '*.vsix' { - const content: string; - export default content; + const content: string; + export default content; } diff --git a/packages/examples/statemachine.html b/packages/examples/statemachine.html index be466766f..111e4766e 100644 --- a/packages/examples/statemachine.html +++ b/packages/examples/statemachine.html @@ -1,23 +1,22 @@ - + - - + Langium Statemachine Client & Language Server (Worker) - - + + - +
- Langium Statemachine Client & Language Server (Worker) - [Back to Index] -
- - + Langium Statemachine Client & Language Server (Worker) - [Back to Index] +
+ +
-
-
+
+
- - + diff --git a/packages/examples/style.css b/packages/examples/style.css index 7b8304556..fd617f761 100644 --- a/packages/examples/style.css +++ b/packages/examples/style.css @@ -1,33 +1,34 @@ body { - font-family: Helvetica, Arial, Sans-Serif; - background-color: #1f1f1f; - color: #cccccc; + font-family: Helvetica, Arial, Sans-Serif; + background-color: #1f1f1f; + color: #cccccc; } .exampleHeadelineDiv { - padding: 5px 0px 5px 0px; + padding: 5px 0px 5px 0px; } .exampleHeadeline { - font-weight: bold; - font-size: 20px; + font-weight: bold; + font-size: 20px; } a:link { - color: #d7ba7d; + color: #d7ba7d; } a:hover { - color: #a2b6c7; + color: #a2b6c7; } a:visited { - color: #3794ff; + color: #3794ff; } -h2, h3 { - color: rgb(190, 120, 0); +h2, +h3 { + color: rgb(190, 120, 0); } h3 { - margin-bottom: 6px; - margin-top: 12px; + margin-bottom: 6px; + margin-top: 12px; } diff --git a/packages/examples/tsExtHost.html b/packages/examples/tsExtHost.html index d6f461ed2..00e717793 100644 --- a/packages/examples/tsExtHost.html +++ b/packages/examples/tsExtHost.html @@ -1,29 +1,27 @@ - + - - + TypeScript Extension Host Worker - - + + - +
- TypeScript Extension Host Worker - [Back to Index] -
- - - - + TypeScript Extension Host Worker - [Back to Index] +
+ + + +
-
+
- - + diff --git a/packages/examples/tsconfig.json b/packages/examples/tsconfig.json index 050f9f4ed..4538590b1 100644 --- a/packages/examples/tsconfig.json +++ b/packages/examples/tsconfig.json @@ -5,8 +5,5 @@ "noEmit": true, "rootDir": "." }, - "include": [ - "src/**/*", - "test/**/*" - ] + "include": ["src/**/*", "test/**/*"] } diff --git a/packages/examples/tsconfig.src.json b/packages/examples/tsconfig.src.json index 7ae6c42ba..8ff8c26de 100644 --- a/packages/examples/tsconfig.src.json +++ b/packages/examples/tsconfig.src.json @@ -6,15 +6,17 @@ "outDir": "dist", "declarationDir": "dist" }, - "references": [{ - "path": "../vscode-ws-jsonrpc/tsconfig.src.json" - }, - { - "path": "../client/tsconfig.src.json", - }, - { - "path": "../wrapper-react/tsconfig.src.json" - }], + "references": [ + { + "path": "../vscode-ws-jsonrpc/tsconfig.src.json" + }, + { + "path": "../client/tsconfig.src.json" + }, + { + "path": "../wrapper-react/tsconfig.src.json" + } + ], "include": [ "src/**/*.ts", "src/**/*.d.ts", diff --git a/packages/examples/two_langauge_clients.html b/packages/examples/two_langauge_clients.html index f4090c775..f24274cf6 100644 --- a/packages/examples/two_langauge_clients.html +++ b/packages/examples/two_langauge_clients.html @@ -1,27 +1,27 @@ - + - - + Json & Python Languageclients & Language Server (Web Socket) - - + + - +
- Json & Python Languageclients & Language Server (Web Socket) - [Back to Index] -
- - - + Json & Python Languageclients & Language Server (Web Socket) - [Back to Index] +
+ + +
-
+
- - + diff --git a/packages/examples/vite.config.deploy.ts b/packages/examples/vite.config.deploy.ts index f79ffd193..144eca5f5 100644 --- a/packages/examples/vite.config.deploy.ts +++ b/packages/examples/vite.config.deploy.ts @@ -7,9 +7,8 @@ import { defineConfig } from 'vite'; import { buildBaseProductionConfig } from './vite.production.base.js'; export default defineConfig(({ command }) => { - console.log(`Running: ${command}`); - const productionConfig = buildBaseProductionConfig(); - productionConfig.base = 'https://typefox.dev/monaco-languageclient/'; - return productionConfig; + console.log(`Running: ${command}`); + const productionConfig = buildBaseProductionConfig(); + productionConfig.base = 'https://typefox.dev/monaco-languageclient/'; + return productionConfig; }); - diff --git a/packages/examples/vite.config.preview.ts b/packages/examples/vite.config.preview.ts index 3cd70bc1b..8815457a7 100644 --- a/packages/examples/vite.config.preview.ts +++ b/packages/examples/vite.config.preview.ts @@ -7,19 +7,18 @@ import { defineConfig } from 'vite'; import { buildBaseProductionConfig } from './vite.production.base.js'; export default defineConfig(({ command }) => { - console.log(`Running: ${command}`); - const productionConfig = buildBaseProductionConfig(); - productionConfig.base = 'http://localhost:20002/'; - productionConfig.preview = { - port: 20002, - cors: { - origin: '*' - }, - headers: { - 'Cross-Origin-Opener-Policy': 'same-origin', - 'Cross-Origin-Embedder-Policy': 'require-corp' - } - }; - return productionConfig; + console.log(`Running: ${command}`); + const productionConfig = buildBaseProductionConfig(); + productionConfig.base = 'http://localhost:20002/'; + productionConfig.preview = { + port: 20002, + cors: { + origin: '*' + }, + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp' + } + }; + return productionConfig; }); - diff --git a/packages/examples/vite.production.base.ts b/packages/examples/vite.production.base.ts index d4b6d0bd6..2b0618ed8 100644 --- a/packages/examples/vite.production.base.ts +++ b/packages/examples/vite.production.base.ts @@ -9,45 +9,45 @@ import { viteStaticCopy } from 'vite-plugin-static-copy'; import path from 'path'; export const buildBaseProductionConfig: () => UserConfig = () => { - return { - build: { - rollupOptions: { - input: { - index: path.resolve(__dirname, 'index.html'), - langiumExtended: path.resolve(__dirname, 'ghp_langium_extended.html'), - statemachine: path.resolve(__dirname, 'ghp_statemachine.html'), - clangd: path.resolve(__dirname, 'ghp_clangd.html'), - appPlayground: path.resolve(__dirname, 'ghp_appPlayground.html'), - browser: path.resolve(__dirname, 'ghp_browser.html'), - tsExtHost: path.resolve(__dirname, 'ghp_tsExtHost.html'), - reactAppPlayground: path.resolve(__dirname, 'ghp_react_appPlayground.html'), - reactStatemachine: path.resolve(__dirname, 'ghp_react_statemachine.html') - } - }, - emptyOutDir: false, - assetsInlineLimit: 0, - outDir: path.resolve(__dirname, 'production') - }, - plugins: [ - vsixPlugin(), - viteStaticCopy({ - targets: [ - { - src: 'resources/clangd/wasm/clangd.js', - dest: 'assets' - }, - { - src: 'resources/clangd/wasm/clangd.worker.mjs', - dest: 'assets' - } - ] - }) - ], - worker: { - format: 'es' - }, - esbuild: { - minifySyntax: false + return { + build: { + rollupOptions: { + input: { + index: path.resolve(__dirname, 'index.html'), + langiumExtended: path.resolve(__dirname, 'ghp_langium_extended.html'), + statemachine: path.resolve(__dirname, 'ghp_statemachine.html'), + clangd: path.resolve(__dirname, 'ghp_clangd.html'), + appPlayground: path.resolve(__dirname, 'ghp_appPlayground.html'), + browser: path.resolve(__dirname, 'ghp_browser.html'), + tsExtHost: path.resolve(__dirname, 'ghp_tsExtHost.html'), + reactAppPlayground: path.resolve(__dirname, 'ghp_react_appPlayground.html'), + reactStatemachine: path.resolve(__dirname, 'ghp_react_statemachine.html') } - }; -} + }, + emptyOutDir: false, + assetsInlineLimit: 0, + outDir: path.resolve(__dirname, 'production') + }, + plugins: [ + vsixPlugin(), + viteStaticCopy({ + targets: [ + { + src: 'resources/clangd/wasm/clangd.js', + dest: 'assets' + }, + { + src: 'resources/clangd/wasm/clangd.worker.mjs', + dest: 'assets' + } + ] + }) + ], + worker: { + format: 'es' + }, + esbuild: { + minifySyntax: false + } + }; +}; diff --git a/packages/vscode-ws-jsonrpc/README.md b/packages/vscode-ws-jsonrpc/README.md index 3044bcfcb..7d45f9e59 100644 --- a/packages/vscode-ws-jsonrpc/README.md +++ b/packages/vscode-ws-jsonrpc/README.md @@ -8,7 +8,7 @@ All changes are noted in the [CHANGELOG](https://github.com/TypeFox/monaco-langu ## Getting Started -This is npm package is part of the mono repo. Please follow the main repositories [instructions]() to get started with local development. +This is npm package is part of the mono repo. Please follow the main repositories [instructions](https://github.com/TypeFox/monaco-languageclient#getting-started) to get started with local development. ## Usage @@ -20,12 +20,12 @@ import { listen } from 'vscode-ws-jsonrpc'; const webSocket = new WebSocket('ws://www.example.com/socketserver'); listen({ - webSocket, - onConnection: (connection: MessageConnection) => { - const notification = new rpc.NotificationType('testNotification'); - connection.listen(); - connection.sendNotification(notification, 'Hello World'); - } + webSocket, + onConnection: (connection: MessageConnection) => { + const notification = new rpc.NotificationType('testNotification'); + connection.listen(); + connection.sendNotification(notification, 'Hello World'); + } }); ``` @@ -56,21 +56,21 @@ import { Message } from 'vscode-languageserver'; const socket: IWebSocket; // open the web socket const reader = new WebSocketMessageReader(socket); const writer = new WebSocketMessageWriter(socket); -const socketConnection = createConnection(reader, writer, () => socket.dispose()) +const socketConnection = createConnection(reader, writer, () => socket.dispose()); const serverConnection = createServerProcess('Example', 'node', ['example.js']); -forward(socketConnection, serverConnection, message => { - if (Message.isNotification(message)) { - if (message.method === 'testNotification') { - // handle the test notification - } +forward(socketConnection, serverConnection, (message) => { + if (Message.isNotification(message)) { + if (message.method === 'testNotification') { + // handle the test notification } - return message; + } + return message; }); ``` ## Examples -For a detailed list of examples please look at [this section]() in the main repository. +For a detailed list of examples please look at [this section](https://github.com/TypeFox/monaco-languageclient#examples-overview) in the main repository. ## License diff --git a/packages/vscode-ws-jsonrpc/package.json b/packages/vscode-ws-jsonrpc/package.json index 1f3e88102..847882c0d 100644 --- a/packages/vscode-ws-jsonrpc/package.json +++ b/packages/vscode-ws-jsonrpc/package.json @@ -2,23 +2,43 @@ "name": "vscode-ws-jsonrpc", "version": "3.5.0", "description": "VSCode JSON RPC over WebSocket", + "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/vscode-ws-jsonrpc/README.md", + "bugs": { + "url": "https://github.com/TypeFox/monaco-languageclient/issues" + }, + "license": "MIT", "author": { "name": "TypeFox GmbH", "url": "http://www.typefox.io" }, - "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/vscode-ws-jsonrpc/README.md", - "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/TypeFox/monaco-languageclient.git", "directory": "packages/vscode-ws-jsonrpc" }, - "bugs": { - "url": "https://github.com/TypeFox/monaco-languageclient/issues" - }, + "files": [ + "lib", + "src", + "README.md", + "CHANGELOG.md", + "LICENSE" + ], "type": "module", "main": "./lib/index.js", "module": "./lib/index.js", + "typesVersions": { + "*": { + ".": [ + "lib/index" + ], + "server": [ + "lib/server" + ], + "socket": [ + "lib/socket" + ] + } + }, "exports": { ".": { "types": "./lib/index.d.ts", @@ -33,18 +53,14 @@ "default": "./lib/socket/index.js" } }, - "typesVersions": { - "*": { - ".": [ - "lib/index" - ], - "server": [ - "lib/server" - ], - "socket": [ - "lib/socket" - ] - } + "scripts": { + "clean": "shx rm -fr ./lib *.tsbuildinfo", + "compile": "tsgo --build tsconfig.src.json", + "build:msg": "echo Building vscode-ws-jsonrpc:", + "build": "npm run build:msg && npm run clean && npm run compile" + }, + "dependencies": { + "vscode-jsonrpc": "~8.2.1" }, "engines": { "node": ">=20.10.0", @@ -53,21 +69,5 @@ "volta": { "node": "24.13.0", "npm": "11.6.2" - }, - "files": [ - "lib", - "src", - "README.md", - "CHANGELOG.md", - "LICENSE" - ], - "dependencies": { - "vscode-jsonrpc": "~8.2.1" - }, - "scripts": { - "clean": "shx rm -fr ./lib *.tsbuildinfo", - "compile": "tsgo --build tsconfig.src.json", - "build:msg": "echo Building vscode-ws-jsonrpc:", - "build": "npm run build:msg && npm run clean && npm run compile" } } diff --git a/packages/vscode-ws-jsonrpc/src/connection.ts b/packages/vscode-ws-jsonrpc/src/connection.ts index acc4323c8..c89fe88d4 100644 --- a/packages/vscode-ws-jsonrpc/src/connection.ts +++ b/packages/vscode-ws-jsonrpc/src/connection.ts @@ -8,37 +8,33 @@ import { createWebSocketConnection } from './socket/connection.js'; import type { IWebSocket } from './socket/socket.js'; import { ConsoleLogger } from './logger.js'; -export function listen(options: { - webSocket: WebSocket; - logger?: Logger; - onConnection: (connection: MessageConnection) => void; -}) { - const { webSocket, onConnection } = options; - const logger = options.logger ?? new ConsoleLogger(); - webSocket.onopen = () => { - const socket = toSocket(webSocket); - const connection = createWebSocketConnection(socket, logger); - onConnection(connection); - }; +export function listen(options: { webSocket: WebSocket; logger?: Logger; onConnection: (connection: MessageConnection) => void }) { + const { webSocket, onConnection } = options; + const logger = options.logger ?? new ConsoleLogger(); + webSocket.onopen = () => { + const socket = toSocket(webSocket); + const connection = createWebSocketConnection(socket, logger); + onConnection(connection); + }; } export function toSocket(webSocket: WebSocket): IWebSocket { - return { - send: content => webSocket.send(content), - onMessage: cb => { - webSocket.onmessage = event => cb(event.data); - }, - onError: cb => { - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - webSocket.onerror = (event: any) => { - if (Object.hasOwn(event, 'message')) { - cb(event.message); - } - }; - }, - onClose: cb => { - webSocket.onclose = event => cb(event.code, event.reason); - }, - dispose: () => webSocket.close() - }; + return { + send: (content) => webSocket.send(content), + onMessage: (cb) => { + webSocket.onmessage = (event) => cb(event.data); + }, + onError: (cb) => { + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + webSocket.onerror = (event: any) => { + if (Object.hasOwn(event, 'message')) { + cb(event.message); + } + }; + }, + onClose: (cb) => { + webSocket.onclose = (event) => cb(event.code, event.reason); + }, + dispose: () => webSocket.close() + }; } diff --git a/packages/vscode-ws-jsonrpc/src/disposable.ts b/packages/vscode-ws-jsonrpc/src/disposable.ts index da1e0584f..608f60544 100644 --- a/packages/vscode-ws-jsonrpc/src/disposable.ts +++ b/packages/vscode-ws-jsonrpc/src/disposable.ts @@ -6,24 +6,24 @@ import { Disposable } from 'vscode-jsonrpc'; export class DisposableCollection implements Disposable { - protected readonly disposables: Disposable[] = []; + protected readonly disposables: Disposable[] = []; - dispose(): void { - while (this.disposables.length !== 0) { - this.disposables.pop()!.dispose(); - } + dispose(): void { + while (this.disposables.length !== 0) { + this.disposables.pop()!.dispose(); } + } - push(disposable: Disposable): Disposable { - const disposables = this.disposables; - disposables.push(disposable); - return { - dispose(): void { - const index = disposables.indexOf(disposable); - if (index !== -1) { - disposables.splice(index, 1); - } - } - }; - } + push(disposable: Disposable): Disposable { + const disposables = this.disposables; + disposables.push(disposable); + return { + dispose(): void { + const index = disposables.indexOf(disposable); + if (index !== -1) { + disposables.splice(index, 1); + } + } + }; + } } diff --git a/packages/vscode-ws-jsonrpc/src/logger.ts b/packages/vscode-ws-jsonrpc/src/logger.ts index 6ecd5ac3a..885d75d25 100644 --- a/packages/vscode-ws-jsonrpc/src/logger.ts +++ b/packages/vscode-ws-jsonrpc/src/logger.ts @@ -5,23 +5,23 @@ import type { Logger } from 'vscode-jsonrpc'; export class ConsoleLogger implements Logger { - public error(message: string): void { - console.error(message); - } + public error(message: string): void { + console.error(message); + } - public warn(message: string): void { - console.warn(message); - } + public warn(message: string): void { + console.warn(message); + } - public info(message: string): void { - console.info(message); - } + public info(message: string): void { + console.info(message); + } - public log(message: string): void { - console.log(message); - } + public log(message: string): void { + console.log(message); + } - public debug(message: string): void { - console.debug(message); - } + public debug(message: string): void { + console.debug(message); + } } diff --git a/packages/vscode-ws-jsonrpc/src/server/connection.ts b/packages/vscode-ws-jsonrpc/src/server/connection.ts index 0571a579a..141d0d438 100644 --- a/packages/vscode-ws-jsonrpc/src/server/connection.ts +++ b/packages/vscode-ws-jsonrpc/src/server/connection.ts @@ -7,37 +7,41 @@ import { MessageReader, MessageWriter, Disposable, Message } from 'vscode-jsonrp import { DisposableCollection } from '../disposable.js'; export interface IConnection extends Disposable { - readonly reader: MessageReader; - readonly writer: MessageWriter; - forward(to: IConnection, map?: (message: Message) => Message): void; - onClose(callback: () => void): Disposable; + readonly reader: MessageReader; + readonly writer: MessageWriter; + forward(to: IConnection, map?: (message: Message) => Message): void; + onClose(callback: () => void): Disposable; } export function forward(clientConnection: IConnection, serverConnection: IConnection, map?: (message: Message) => Message): void { - clientConnection.forward(serverConnection, map); - serverConnection.forward(clientConnection, map); - clientConnection.onClose(() => serverConnection.dispose()); - serverConnection.onClose(() => clientConnection.dispose()); + clientConnection.forward(serverConnection, map); + serverConnection.forward(clientConnection, map); + clientConnection.onClose(() => serverConnection.dispose()); + serverConnection.onClose(() => clientConnection.dispose()); } -export function createConnection(reader: MessageReader, writer: MessageWriter, onDispose: () => void, - extensions: T = {} as T): IConnection & T { - const disposeOnClose = new DisposableCollection(); - reader.onClose(() => disposeOnClose.dispose()); - writer.onClose(() => disposeOnClose.dispose()); - return { - reader, - writer, - forward(to: IConnection, map: (message: Message) => Message = (message) => message): void { - reader.listen(async input => { - const output = map(input); - await to.writer.write(output); - }); - }, - onClose(callback: () => void): Disposable { - return disposeOnClose.push(Disposable.create(callback)); - }, - dispose: () => onDispose(), - ...extensions - }; +export function createConnection( + reader: MessageReader, + writer: MessageWriter, + onDispose: () => void, + extensions: T = {} as T +): IConnection & T { + const disposeOnClose = new DisposableCollection(); + reader.onClose(() => disposeOnClose.dispose()); + writer.onClose(() => disposeOnClose.dispose()); + return { + reader, + writer, + forward(to: IConnection, map: (message: Message) => Message = (message) => message): void { + reader.listen(async (input) => { + const output = map(input); + await to.writer.write(output); + }); + }, + onClose(callback: () => void): Disposable { + return disposeOnClose.push(Disposable.create(callback)); + }, + dispose: () => onDispose(), + ...extensions + }; } diff --git a/packages/vscode-ws-jsonrpc/src/server/launch.ts b/packages/vscode-ws-jsonrpc/src/server/launch.ts index 6ed994fdd..f5e926394 100644 --- a/packages/vscode-ws-jsonrpc/src/server/launch.ts +++ b/packages/vscode-ws-jsonrpc/src/server/launch.ts @@ -12,45 +12,50 @@ import type { IWebSocket, IWebSocketConnection } from '../socket/socket.js'; import { WebSocketMessageReader } from '../socket/reader.js'; import { WebSocketMessageWriter } from '../socket/writer.js'; -export function createServerProcess(serverName: string, command: string, args?: string[], options?: cp.SpawnOptions): IConnection | undefined { - const serverProcess = cp.spawn(command, args ?? [], options ?? {}); - serverProcess.on('error', error => - console.error(`Launching ${serverName} Server failed: ${error}`) - ); - if (serverProcess.stderr !== null) { - serverProcess.stderr.on('data', data => - console.error(`${serverName} Server: ${data}`) - ); - } - return createProcessStreamConnection(serverProcess); +export function createServerProcess( + serverName: string, + command: string, + args?: string[], + options?: cp.SpawnOptions +): IConnection | undefined { + const serverProcess = cp.spawn(command, args ?? [], options ?? {}); + serverProcess.on('error', (error) => console.error(`Launching ${serverName} Server failed: ${error}`)); + if (serverProcess.stderr !== null) { + serverProcess.stderr.on('data', (data) => console.error(`${serverName} Server: ${data}`)); + } + return createProcessStreamConnection(serverProcess); } export function createWebSocketConnection(socket: IWebSocket): IWebSocketConnection { - const reader = new WebSocketMessageReader(socket); - const writer = new WebSocketMessageWriter(socket); - return createConnection(reader, writer, () => socket.dispose(), { socket }); + const reader = new WebSocketMessageReader(socket); + const writer = new WebSocketMessageWriter(socket); + return createConnection(reader, writer, () => socket.dispose(), { socket }); } -export function createProcessSocketConnection(process: cp.ChildProcess, outSocket: net.Socket, inSocket: net.Socket = outSocket): IConnection { - return createSocketConnection(outSocket, inSocket, () => process.kill()); +export function createProcessSocketConnection( + process: cp.ChildProcess, + outSocket: net.Socket, + inSocket: net.Socket = outSocket +): IConnection { + return createSocketConnection(outSocket, inSocket, () => process.kill()); } export function createSocketConnection(outSocket: net.Socket, inSocket: net.Socket, onDispose: () => void): IConnection { - const reader = new SocketMessageReader(outSocket); - const writer = new SocketMessageWriter(inSocket); - return createConnection(reader, writer, onDispose); + const reader = new SocketMessageReader(outSocket); + const writer = new SocketMessageWriter(inSocket); + return createConnection(reader, writer, onDispose); } export function createProcessStreamConnection(process: cp.ChildProcess): IConnection | undefined { - if (process.stdout !== null && process.stdin !== null) { - return createStreamConnection(process.stdout, process.stdin, () => process.kill()); - } else { - return undefined; - } + if (process.stdout !== null && process.stdin !== null) { + return createStreamConnection(process.stdout, process.stdin, () => process.kill()); + } else { + return undefined; + } } export function createStreamConnection(outStream: stream.Readable, inStream: stream.Writable, onDispose: () => void): IConnection { - const reader = new StreamMessageReader(outStream); - const writer = new StreamMessageWriter(inStream); - return createConnection(reader, writer, onDispose); + const reader = new StreamMessageReader(outStream); + const writer = new StreamMessageWriter(inStream); + return createConnection(reader, writer, onDispose); } diff --git a/packages/vscode-ws-jsonrpc/src/socket/connection.ts b/packages/vscode-ws-jsonrpc/src/socket/connection.ts index 6fcde4f7c..71eaf02cf 100644 --- a/packages/vscode-ws-jsonrpc/src/socket/connection.ts +++ b/packages/vscode-ws-jsonrpc/src/socket/connection.ts @@ -10,9 +10,9 @@ import { WebSocketMessageReader } from './reader.js'; import { WebSocketMessageWriter } from './writer.js'; export function createWebSocketConnection(socket: IWebSocket, logger: Logger): MessageConnection { - const messageReader = new WebSocketMessageReader(socket); - const messageWriter = new WebSocketMessageWriter(socket); - const connection = createMessageConnection(messageReader, messageWriter, logger); - connection.onClose(() => connection.dispose()); - return connection; + const messageReader = new WebSocketMessageReader(socket); + const messageWriter = new WebSocketMessageWriter(socket); + const connection = createMessageConnection(messageReader, messageWriter, logger); + connection.onClose(() => connection.dispose()); + return connection; } diff --git a/packages/vscode-ws-jsonrpc/src/socket/reader.ts b/packages/vscode-ws-jsonrpc/src/socket/reader.ts index 8127437a0..3c10ddf4c 100644 --- a/packages/vscode-ws-jsonrpc/src/socket/reader.ts +++ b/packages/vscode-ws-jsonrpc/src/socket/reader.ts @@ -9,99 +9,95 @@ import { AbstractMessageReader, type DataCallback, Disposable, MessageReader } f import type { IWebSocket } from './socket.js'; export class WebSocketMessageReader extends AbstractMessageReader implements MessageReader { - protected readonly socket: IWebSocket; - protected state: 'initial' | 'listening' | 'closed' = 'initial'; - protected callback: DataCallback | undefined; - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - protected readonly events: Array<{ message?: any, error?: any }> = []; + protected readonly socket: IWebSocket; + protected state: 'initial' | 'listening' | 'closed' = 'initial'; + protected callback: DataCallback | undefined; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + protected readonly events: Array<{ message?: any; error?: any }> = []; - constructor(socket: IWebSocket) { - super(); - this.socket = socket; - this.socket.onMessage(message => - this.readMessage(message) - ); - this.socket.onError(error => - this.fireError(error) - ); - this.socket.onClose((code, reason) => { - if (code !== 1000) { - const error: Error = { - name: '' + code, - message: `Error during socket reconnect: code = ${code}, reason = ${reason}` - }; - this.fireError(error); - } - this.fireClose(); - }); - } + constructor(socket: IWebSocket) { + super(); + this.socket = socket; + this.socket.onMessage((message) => this.readMessage(message)); + this.socket.onError((error) => this.fireError(error)); + this.socket.onClose((code, reason) => { + if (code !== 1000) { + const error: Error = { + name: '' + code, + message: `Error during socket reconnect: code = ${code}, reason = ${reason}` + }; + this.fireError(error); + } + this.fireClose(); + }); + } - listen(callback: DataCallback): Disposable { - if (this.state === 'initial') { - this.state = 'listening'; - this.callback = callback; - while (this.events.length !== 0) { - const event = this.events.pop()!; - if (event.message !== undefined) { - this.readMessage(event.message); - } else if (event.error !== undefined) { - this.fireError(event.error); - } else { - this.fireClose(); - } - } + listen(callback: DataCallback): Disposable { + if (this.state === 'initial') { + this.state = 'listening'; + this.callback = callback; + while (this.events.length !== 0) { + const event = this.events.pop()!; + if (event.message !== undefined) { + this.readMessage(event.message); + } else if (event.error !== undefined) { + this.fireError(event.error); + } else { + this.fireClose(); } - return { - dispose: () => { - if (this.callback === callback) { - this.state = 'initial'; - this.callback = undefined; - } - } - }; + } } + return { + dispose: () => { + if (this.callback === callback) { + this.state = 'initial'; + this.callback = undefined; + } + } + }; + } - override dispose() { - super.dispose(); - this.state = 'initial'; - this.callback = undefined; - this.events.splice(0, this.events.length); - } + override dispose() { + super.dispose(); + this.state = 'initial'; + this.callback = undefined; + this.events.splice(0, this.events.length); + } - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - protected readMessage(message: any): void { - if (this.state === 'initial') { - this.events.splice(0, 0, { message }); - } else if (this.state === 'listening') { - try { - const data = JSON.parse(message); - this.callback!(data); - } catch (err) { - const error: Error = { - name: '' + 400, - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - message: `Error during message parsing, reason = ${typeof err === 'object' ? (err as any).message : 'unknown'}` - }; - this.fireError(error); - } - } + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + protected readMessage(message: any): void { + if (this.state === 'initial') { + this.events.splice(0, 0, { message }); + } else if (this.state === 'listening') { + try { + const data = JSON.parse(message); + this.callback!(data); + } catch (err) { + const error: Error = { + name: '' + 400, + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + message: `Error during message parsing, reason = ${typeof err === 'object' ? (err as any).message : 'unknown'}` + }; + this.fireError(error); + } } + } - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - protected override fireError(error: any): void { - if (this.state === 'initial') { - this.events.splice(0, 0, { error }); - } else if (this.state === 'listening') { - super.fireError(error); - } + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + protected override fireError(error: any): void { + if (this.state === 'initial') { + this.events.splice(0, 0, { error }); + } else if (this.state === 'listening') { + super.fireError(error); } + } - protected override fireClose(): void { - if (this.state === 'initial') { - this.events.splice(0, 0, {}); - } else if (this.state === 'listening') { - super.fireClose(); - } - this.state = 'closed'; + protected override fireClose(): void { + if (this.state === 'initial') { + this.events.splice(0, 0, {}); + } else if (this.state === 'listening') { + super.fireClose(); } + this.state = 'closed'; + } } diff --git a/packages/vscode-ws-jsonrpc/src/socket/socket.ts b/packages/vscode-ws-jsonrpc/src/socket/socket.ts index cc6abf596..030216876 100644 --- a/packages/vscode-ws-jsonrpc/src/socket/socket.ts +++ b/packages/vscode-ws-jsonrpc/src/socket/socket.ts @@ -7,14 +7,14 @@ import { Disposable } from 'vscode-jsonrpc'; import type { IConnection } from '../server/connection.js'; export interface IWebSocket extends Disposable { - send(content: string): void; - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - onMessage(cb: (data: any) => void): void; - // oxlint-disable-next-line @typescript-eslint/no-explicit-any - onError(cb: (reason: any) => void): void; - onClose(cb: (code: number, reason: string) => void): void; + send(content: string): void; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + onMessage(cb: (data: any) => void): void; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any + onError(cb: (reason: any) => void): void; + onClose(cb: (code: number, reason: string) => void): void; } export interface IWebSocketConnection extends IConnection { - readonly socket: IWebSocket; + readonly socket: IWebSocket; } diff --git a/packages/vscode-ws-jsonrpc/src/socket/writer.ts b/packages/vscode-ws-jsonrpc/src/socket/writer.ts index c41877623..eb50e6c7d 100644 --- a/packages/vscode-ws-jsonrpc/src/socket/writer.ts +++ b/packages/vscode-ws-jsonrpc/src/socket/writer.ts @@ -7,24 +7,23 @@ import { AbstractMessageWriter, Message, MessageWriter } from 'vscode-jsonrpc'; import type { IWebSocket } from './socket.js'; export class WebSocketMessageWriter extends AbstractMessageWriter implements MessageWriter { - protected errorCount = 0; - protected readonly socket: IWebSocket; + protected errorCount = 0; + protected readonly socket: IWebSocket; - constructor(socket: IWebSocket) { - super(); - this.socket = socket; - } + constructor(socket: IWebSocket) { + super(); + this.socket = socket; + } - end(): void { - } + end(): void {} - async write(msg: Message): Promise { - try { - const content = JSON.stringify(msg); - this.socket.send(content); - } catch (e) { - this.errorCount++; - this.fireError(e, msg, this.errorCount); - } + async write(msg: Message): Promise { + try { + const content = JSON.stringify(msg); + this.socket.send(content); + } catch (e) { + this.errorCount++; + this.fireError(e, msg, this.errorCount); } + } } diff --git a/packages/vscode-ws-jsonrpc/tsconfig.json b/packages/vscode-ws-jsonrpc/tsconfig.json index 050f9f4ed..4538590b1 100644 --- a/packages/vscode-ws-jsonrpc/tsconfig.json +++ b/packages/vscode-ws-jsonrpc/tsconfig.json @@ -5,8 +5,5 @@ "noEmit": true, "rootDir": "." }, - "include": [ - "src/**/*", - "test/**/*" - ] + "include": ["src/**/*", "test/**/*"] } diff --git a/packages/vscode-ws-jsonrpc/tsconfig.src.json b/packages/vscode-ws-jsonrpc/tsconfig.src.json index 33ecc5073..567f6d89d 100644 --- a/packages/vscode-ws-jsonrpc/tsconfig.src.json +++ b/packages/vscode-ws-jsonrpc/tsconfig.src.json @@ -6,7 +6,5 @@ "outDir": "lib", "declarationDir": "lib" }, - "include": [ - "src/**/*.ts", - ] + "include": ["src/**/*.ts"] } diff --git a/packages/wrapper-react/CHANGELOG.md b/packages/wrapper-react/CHANGELOG.md index 422534c4f..2a62b284f 100644 --- a/packages/wrapper-react/CHANGELOG.md +++ b/packages/wrapper-react/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to npm module [@typefox/monaco-editor-react](https://www.npm ## [7.8.0] - unreleased -- Updated all `@codingame/monaco-vscode` packages to `26.2.1`. +- Updated all `@codingame/monaco-vscode` packages to `26.2.2`. - Updated to `monaco-languageclient@10.8.0`. - Dropped eslint and rely fully on oxlint. diff --git a/packages/wrapper-react/README.md b/packages/wrapper-react/README.md index 6415a2fcb..912c58b84 100644 --- a/packages/wrapper-react/README.md +++ b/packages/wrapper-react/README.md @@ -12,13 +12,13 @@ This is npm package is part of the [monaco-languageclient mono repo](https://git You find detailed information in the [official documentation](https://github.com/TypeFox/monaco-languageclient/blob/main/docs/index.md). -If interested, check [quick start for local development](). +If interested, check [quick start for local development](https://github.com/TypeFox/monaco-languageclient#getting-started). -A detailed list of examples is contained in the GitHub repository, please see [this listing](). +A detailed list of examples is contained in the GitHub repository, please see [this listing](https://github.com/TypeFox/monaco-languageclient#examples-overview). ## Usage -You can import the monaco react component for easy use in an existing React project. Below you can see a quick example of a fully functional implementation in TypeScript. The react component uses the same configuration objects you using `monaco-languageclient` directly with TypeScript/JavaScript. +You can import the monaco react component for easy use in an existing React project. Below you can see a quick example of a fully functional implementation in TypeScript. The react component uses the same configuration objects you using `monaco-languageclient` directly with TypeScript/JavaScript. The language client on start can connect to a language server either via jsonrpc over a websocket to an exernal server process, or directly in the browser where the language server runs in a web worker. In both cases they use the Language Server Protocol to communicate. The react component is limited to one language client per component. @@ -34,71 +34,72 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; export const createEditorAndLanguageClient = async () => { - const languageId = 'mylang'; - const code = '// initial editor content'; - const codeUri = '/workspace/hello.mylang'; - - // Monaco VSCode API configuration - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.wordBasedSuggestions': 'off' - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; - - // Language client configuration - const languageClientConfig: LanguageClientConfig = { - languageId, - connection: { - options: { - $type: 'WebSocketUrl', - // at this url the language server for myLang must be reachable - url: 'ws://localhost:30000/myLangLS' - } - }, - clientOptions: { - documentSelector: [languageId], - orkspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.file('/workspace') - } - } - }; - - // editor app / monaco-editor configuration - const editorAppConfig: EditorAppConfig = { - codeResources: { - main: { - text: code, - uri: codeUri - } - } - }; - - const root = ReactDOM.createRoot(document.getElementById('react-root')!); - const App = () => { - return ( -
- { - console.error(e); - }} /> -
- ); - }; - root.render(); + const languageId = 'mylang'; + const code = '// initial editor content'; + const codeUri = '/workspace/hello.mylang'; + + // Monaco VSCode API configuration + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off' + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; + + // Language client configuration + const languageClientConfig: LanguageClientConfig = { + languageId, + connection: { + options: { + $type: 'WebSocketUrl', + // at this url the language server for myLang must be reachable + url: 'ws://localhost:30000/myLangLS' + } + }, + clientOptions: { + documentSelector: [languageId], + orkspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.file('/workspace') + } + } + }; + + // editor app / monaco-editor configuration + const editorAppConfig: EditorAppConfig = { + codeResources: { + main: { + text: code, + uri: codeUri + } + } + }; + + const root = ReactDOM.createRoot(document.getElementById('react-root')!); + const App = () => { + return ( +
+ { + console.error(e); + }} + /> +
+ ); + }; + root.render(); }; createEditorAndLanguageClient(); ``` diff --git a/packages/wrapper-react/package.json b/packages/wrapper-react/package.json index b3254e30e..3e91c5dee 100644 --- a/packages/wrapper-react/package.json +++ b/packages/wrapper-react/package.json @@ -1,23 +1,35 @@ { "name": "@typefox/monaco-editor-react", "version": "7.7.0", - "license": "MIT", "description": "React component for Monaco-Editor and Monaco Languageclient", "keywords": [ "monaco-editor", "monaco-languageclient", - "typescript", - "react" + "react", + "typescript" + ], + "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/wrapper-react/README.md", + "bugs": "https://github.com/TypeFox/monaco-languageclient/issues", + "license": "MIT", + "author": { + "name": "TypeFox", + "url": "https://www.typefox.io" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/TypeFox/monaco-languageclient.git", + "directory": "packages/monaco-editor-react" + }, + "files": [ + "lib", + "src", + "README.md", + "CHANGELOG.md", + "LICENSE" ], "type": "module", "main": "./lib/index.js", "module": "./lib/index.js", - "exports": { - ".": { - "types": "./lib/index.d.ts", - "default": "./lib/index.js" - } - }, "typesVersions": { "*": { ".": [ @@ -25,18 +37,23 @@ ] } }, - "files": [ - "lib", - "src", - "README.md", - "CHANGELOG.md", - "LICENSE" - ], + "exports": { + ".": { + "types": "./lib/index.d.ts", + "default": "./lib/index.js" + } + }, "scripts": { "clean": "shx rm -fr ./lib ./bundle *.tsbuildinfo", "compile": " tsgo --build tsconfig.src.json", "build": "npm run clean && npm run compile" }, + "dependencies": { + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "react": ">=18.0.0 || <20.0.0", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2" + }, "engines": { "node": ">=20.10.0", "npm": ">=10.2.3" @@ -44,22 +61,5 @@ "volta": { "node": "24.13.0", "npm": "11.6.2" - }, - "dependencies": { - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "react": ">=18.0.0 || <20.0.0", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/TypeFox/monaco-languageclient.git", - "directory": "packages/monaco-editor-react" - }, - "homepage": "https://github.com/TypeFox/monaco-languageclient/blob/main/packages/wrapper-react/README.md", - "bugs": "https://github.com/TypeFox/monaco-languageclient/issues", - "author": { - "name": "TypeFox", - "url": "https://www.typefox.io" } } diff --git a/packages/wrapper-react/src/index.tsx b/packages/wrapper-react/src/index.tsx index f5f2bfb74..50ce62040 100644 --- a/packages/wrapper-react/src/index.tsx +++ b/packages/wrapper-react/src/index.tsx @@ -1,7 +1,7 @@ /* -------------------------------------------------------------------------------------------- -* Copyright (c) 2024 TypeFox and others. -* Licensed under the MIT License. See LICENSE in the package root for license information. -* ------------------------------------------------------------------------------------------ */ + * Copyright (c) 2024 TypeFox and others. + * Licensed under the MIT License. See LICENSE in the package root for license information. + * ------------------------------------------------------------------------------------------ */ import { LogLevel } from '@codingame/monaco-vscode-api'; import { ConsoleLogger } from '@codingame/monaco-vscode-log-service-override'; @@ -12,61 +12,61 @@ import React, { type CSSProperties, useEffect, useRef } from 'react'; export type ResolveFc = (value: void | PromiseLike) => void; export type ConfigProcessedResult = { - textUpdated: boolean; - modelUpdated: boolean; - editorApp?: EditorApp; + textUpdated: boolean; + modelUpdated: boolean; + editorApp?: EditorApp; }; export type MonacoEditorProps = { - style?: CSSProperties; - className?: string; - vscodeApiConfig?: MonacoVscodeApiConfig; - editorAppConfig?: EditorAppConfig; - languageClientConfig?: LanguageClientConfig; - onVscodeApiInitDone?: (monacoVscodeApiManager: MonacoVscodeApiWrapper) => void; - onEditorStartDone?: (editorApp?: EditorApp) => void; - onLanguageClientsStartDone?: (lcsManager: LanguageClientManager) => void; - /** - * Called when the text in the editor has changed - */ - onTextChanged?: (textChanges: TextContents) => void; - /** - * Called when an error occurred within the component - */ - onError?: (error: Error) => void; - onDisposeEditor?: () => void; - onDisposeLanguageClient?: () => void; - /** - * Trigger reprocessing oft the editorAppConfig to update code/models or editor options. - * This is performed once and only repeated if the value is increased again. - */ - triggerReprocessConfig?: number; - /** - * Always called after the config was re-processed. - */ - onConfigProcessed?: (result: ConfigProcessedResult) => void; - /** - * Enforce disposal of the language client - */ - enforceLanguageClientDispose?: boolean; - /** - * Set the log level for the internal logger - */ - logLevel?: LogLevel | number; -} + style?: CSSProperties; + className?: string; + vscodeApiConfig?: MonacoVscodeApiConfig; + editorAppConfig?: EditorAppConfig; + languageClientConfig?: LanguageClientConfig; + onVscodeApiInitDone?: (monacoVscodeApiManager: MonacoVscodeApiWrapper) => void; + onEditorStartDone?: (editorApp?: EditorApp) => void; + onLanguageClientsStartDone?: (lcsManager: LanguageClientManager) => void; + /** + * Called when the text in the editor has changed + */ + onTextChanged?: (textChanges: TextContents) => void; + /** + * Called when an error occurred within the component + */ + onError?: (error: Error) => void; + onDisposeEditor?: () => void; + onDisposeLanguageClient?: () => void; + /** + * Trigger reprocessing oft the editorAppConfig to update code/models or editor options. + * This is performed once and only repeated if the value is increased again. + */ + triggerReprocessConfig?: number; + /** + * Always called after the config was re-processed. + */ + onConfigProcessed?: (result: ConfigProcessedResult) => void; + /** + * Enforce disposal of the language client + */ + enforceLanguageClientDispose?: boolean; + /** + * Set the log level for the internal logger + */ + logLevel?: LogLevel | number; +}; // All must be outside of the component as they ars valid across all instances and should not be re-created let apiWrapper: MonacoVscodeApiWrapper | undefined; const lcsManager = new LanguageClientManager(); const haveEditorService = () => { - return getEnhancedMonacoEnvironment().viewServiceType === 'EditorService'; + return getEnhancedMonacoEnvironment().viewServiceType === 'EditorService'; }; const logger = new ConsoleLogger(LogLevel.Off); type QueueEntry = { - id: string; - func: (htmlContainer: HTMLElement | null) => Promise; - currentContainer: HTMLElement | null; + id: string; + func: (htmlContainer: HTMLElement | null) => Promise; + currentContainer: HTMLElement | null; }; const runQueue: QueueEntry[] = []; let runQueueLock = true; @@ -74,385 +74,374 @@ let intervalId: number | ReturnType | undefined = undefined; const queueIntervalMs = 10; const addQueue = (queueEntry: QueueEntry) => { - debugLogging('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'); - debugLogging(`Adding to queue: ${queueEntry.id}: QUEUE SIZE before: ${runQueue.length}`); - runQueue.push(queueEntry); - kickQueue(); + debugLogging('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'); + debugLogging(`Adding to queue: ${queueEntry.id}: QUEUE SIZE before: ${runQueue.length}`); + runQueue.push(queueEntry); + kickQueue(); }; const executeQueue = async () => { - if (runQueue.length > 0) { - runQueueLock = true; - while (runQueue.length > 0) { - const lengthBefore = runQueue.length; - const queueObj = runQueue.shift(); - debugLogging('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'); - debugLogging(`QUEUE ${queueObj?.id} start: SIZE before: ${lengthBefore}`); - await queueObj?.func(queueObj.currentContainer); - debugLogging(`QUEUE ${queueObj?.id} end: SIZE after: ${runQueue.length}`); - } - runQueueLock = false; + if (runQueue.length > 0) { + runQueueLock = true; + while (runQueue.length > 0) { + const lengthBefore = runQueue.length; + const queueObj = runQueue.shift(); + debugLogging('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'); + debugLogging(`QUEUE ${queueObj?.id} start: SIZE before: ${lengthBefore}`); + await queueObj?.func(queueObj.currentContainer); + debugLogging(`QUEUE ${queueObj?.id} end: SIZE after: ${runQueue.length}`); } + runQueueLock = false; + } }; const kickQueue = () => { - if (intervalId === undefined && runQueue.length > 0) { - intervalId = setInterval(async () => { - debugLogging(`Checking queue (lock state: ${runQueueLock})`); - if (!runQueueLock) { - await executeQueue(); - stopQueue(); - } - }, queueIntervalMs); - } + if (intervalId === undefined && runQueue.length > 0) { + intervalId = setInterval(async () => { + debugLogging(`Checking queue (lock state: ${runQueueLock})`); + if (!runQueueLock) { + await executeQueue(); + stopQueue(); + } + }, queueIntervalMs); + } }; const stopQueue = () => { - if (intervalId !== undefined && runQueue.length === 0) { - debugLogging('Stopping queue...'); - clearInterval(intervalId as number); - intervalId = undefined; - } + if (intervalId !== undefined && runQueue.length === 0) { + debugLogging('Stopping queue...'); + clearInterval(intervalId as number); + intervalId = undefined; + } }; const debugLogging = (id: string) => { - const now = new Date(Date.now()); - const hours = now.getHours().toString().padStart(2, '0'); - const minutes = now.getMinutes().toString().padStart(2, '0'); - const seconds = now.getSeconds().toString().padStart(2, '0'); - const milliseconds = now.getMilliseconds().toString().padStart(3, '0'); - logger.debug(`[${hours}:${minutes}:${seconds}.${milliseconds}]: ${id}`); + const now = new Date(Date.now()); + const hours = now.getHours().toString().padStart(2, '0'); + const minutes = now.getMinutes().toString().padStart(2, '0'); + const seconds = now.getSeconds().toString().padStart(2, '0'); + const milliseconds = now.getMilliseconds().toString().padStart(3, '0'); + logger.debug(`[${hours}:${minutes}:${seconds}.${milliseconds}]: ${id}`); }; export const MonacoEditorReactComp: React.FC = (props) => { - const { - style, - className, - vscodeApiConfig, - editorAppConfig, - languageClientConfig, - onVscodeApiInitDone, - onEditorStartDone, - onLanguageClientsStartDone, - onTextChanged, - onConfigProcessed, - onError, - onDisposeEditor, - onDisposeLanguageClient, - logLevel, - triggerReprocessConfig, - enforceLanguageClientDispose - } = props; - - const editorAppRef = useRef(undefined); - const containerRef = useRef(null); - const modifiedCodeUriRef = useRef(undefined); - const modifiedCodeRef = useRef(undefined); - const originalCodeUriRef = useRef(undefined); - const originalCodeRef = useRef(undefined); - const onTextChangedRef = useRef(onTextChanged); - const launchingRef = useRef(false); - const editorAppConfigRef = useRef(undefined); - const triggerReprocessConfigRef = useRef(0); - const enforceLanguageClientDisposeRef = useRef(undefined); - - const performErrorHandling = (error: Error) => { - debugLogging(`ERROR: ${error.message}`); - if (onError !== undefined) { - onError(error); - } else { - debugLogging(`INTERCEPTED Error: ${error}. Stopping queue...`); - runQueueLock = false; - throw error; - } - }; - - const performGlobalInit = async () => { - if (containerRef.current === null) { - performErrorHandling(new Error('No htmlContainer found! Aborting...')); - } - const envEnhanced = getEnhancedMonacoEnvironment(); + const { + style, + className, + vscodeApiConfig, + editorAppConfig, + languageClientConfig, + onVscodeApiInitDone, + onEditorStartDone, + onLanguageClientsStartDone, + onTextChanged, + onConfigProcessed, + onError, + onDisposeEditor, + onDisposeLanguageClient, + logLevel, + triggerReprocessConfig, + enforceLanguageClientDispose + } = props; + + const editorAppRef = useRef(undefined); + const containerRef = useRef(null); + const modifiedCodeUriRef = useRef(undefined); + const modifiedCodeRef = useRef(undefined); + const originalCodeUriRef = useRef(undefined); + const originalCodeRef = useRef(undefined); + const onTextChangedRef = useRef(onTextChanged); + const launchingRef = useRef(false); + const editorAppConfigRef = useRef(undefined); + const triggerReprocessConfigRef = useRef(0); + const enforceLanguageClientDisposeRef = useRef(undefined); + + const performErrorHandling = (error: Error) => { + debugLogging(`ERROR: ${error.message}`); + if (onError !== undefined) { + onError(error); + } else { + debugLogging(`INTERCEPTED Error: ${error}. Stopping queue...`); + runQueueLock = false; + throw error; + } + }; - if (vscodeApiConfig === undefined && envEnhanced.vscodeApiInitialised !== true) { - throw new Error('vscodeApiConfig is not provided, but the monaco-vscode-api is not initialized! Aborting...'); - } + const performGlobalInit = async () => { + if (containerRef.current === null) { + performErrorHandling(new Error('No htmlContainer found! Aborting...')); + } + const envEnhanced = getEnhancedMonacoEnvironment(); - // init will only performed once - if (envEnhanced.vscodeApiInitialising !== true) { - - apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig!); - const globalInitFunc = async () => { - try { - if (apiWrapper === undefined) throw new Error('Unexpected error occurred: apiWrapper is not available! Aborting...'); - - await apiWrapper.start(); - onVscodeApiInitDone?.(apiWrapper); - runQueueLock = false; - } catch (error) { - performErrorHandling(error as Error); - } - }; - // oxlint-disable-next-line typescript/no-floating-promises - globalInitFunc(); - } else if (envEnhanced.vscodeApiInitialised === true) { - if (runQueueLock && intervalId !== undefined) { - runQueueLock = false; - } - } - }; + if (vscodeApiConfig === undefined && envEnhanced.vscodeApiInitialised !== true) { + throw new Error('vscodeApiConfig is not provided, but the monaco-vscode-api is not initialized! Aborting...'); + } - const editorInit = async (htmlContainer: HTMLElement | null) => { + // init will only performed once + if (envEnhanced.vscodeApiInitialising !== true) { + apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig!); + const globalInitFunc = async () => { try { - // it is possible to run without an editorApp, when the ViewsService or WorkbenchService - if (haveEditorService()) { - - // oxlint-disable-next-line typescript/prefer-optional-chain - if (htmlContainer === null || htmlContainer.parentElement === null) { - debugLogging('INIT EDITOR: Unable to create editor. HTML container or the parent is missing.'); - } else { - if (editorAppRef.current === undefined && !launchingRef.current) { - launchingRef.current = true; - - editorAppRef.current = new EditorApp(editorAppConfigRef.current); - if (editorAppRef.current.isStarting() === true || editorAppRef.current.isDisposing() === true) { - await Promise.all([ - editorAppRef.current.getStartingAwait(), - editorAppRef.current.getDisposingAwait() - ]); - } - updateModelRelatedRefs(); - - editorAppRef.current.registerOnTextChangedCallback((textChanges) => { - if (textChanges.modified !== undefined) { - modifiedCodeRef.current = textChanges.modified; - } - if (textChanges.original !== undefined) { - originalCodeRef.current = textChanges.original; - } - if (onTextChangedRef.current !== undefined) { - onTextChangedRef.current(textChanges); - } - }); - // await retrieveContainerRef('INIT EDITOR'); - await editorAppRef.current.start(htmlContainer); - - onEditorStartDone?.(editorAppRef.current); - launchingRef.current = false; - debugLogging('INIT EDITOR: Editor start was successful.'); - } else { - debugLogging('INIT EDITOR: Editor was already started.'); - } - } - } else { - debugLogging('INIT EDITOR: Do nothing: Using ViewsService'); - } - } catch (error) { - performErrorHandling(error as Error); - } - }; + if (apiWrapper === undefined) throw new Error('Unexpected error occurred: apiWrapper is not available! Aborting...'); - const updateEditorModel = async () => { - try { - if (!launchingRef.current && editorAppRef.current !== undefined) { - await editorAppRef.current.updateCodeResources(editorAppConfigRef.current?.codeResources); - updateModelRelatedRefs(); - onConfigProcessed?.({ modelUpdated: true, textUpdated: true, editorApp: editorAppRef.current }); - debugLogging('UPDATE EDITOR MODEL: Model was updated.'); - } else { - onConfigProcessed?.({modelUpdated: false, textUpdated: false, editorApp: editorAppRef.current }); - debugLogging('UPDATE EDITOR MODEL: No editor is avilable. Model update was not possible.'); - } + await apiWrapper.start(); + onVscodeApiInitDone?.(apiWrapper); + runQueueLock = false; } catch (error) { - performErrorHandling(error as Error); + performErrorHandling(error as Error); } - }; - - const updateModelRelatedRefs = () => { - modifiedCodeRef.current = editorAppConfigRef.current?.codeResources?.modified?.text; - originalCodeRef.current = editorAppConfigRef.current?.codeResources?.original?.text; - modifiedCodeUriRef.current = editorAppConfigRef.current?.codeResources?.modified?.uri; - originalCodeUriRef.current = editorAppConfigRef.current?.codeResources?.original?.uri; - }; + }; + // oxlint-disable-next-line typescript/no-floating-promises + globalInitFunc(); + } else if (envEnhanced.vscodeApiInitialised === true) { + if (runQueueLock && intervalId !== undefined) { + runQueueLock = false; + } + } + }; + + const editorInit = async (htmlContainer: HTMLElement | null) => { + try { + // it is possible to run without an editorApp, when the ViewsService or WorkbenchService + if (haveEditorService()) { + // oxlint-disable-next-line typescript/prefer-optional-chain + if (htmlContainer === null || htmlContainer.parentElement === null) { + debugLogging('INIT EDITOR: Unable to create editor. HTML container or the parent is missing.'); + } else { + if (editorAppRef.current === undefined && !launchingRef.current) { + launchingRef.current = true; - const disposeEditor = async () => { - try { - // dispose editor if used - if (editorAppRef.current !== undefined) { - await editorAppRef.current.dispose(); - editorAppRef.current = undefined; - onDisposeEditor?.(); - debugLogging('DISPOSE: EditorApp was disposed'); - } else { - debugLogging('DISPOSE: EditorApp is not disposed'); + editorAppRef.current = new EditorApp(editorAppConfigRef.current); + if (editorAppRef.current.isStarting() === true || editorAppRef.current.isDisposing() === true) { + await Promise.all([editorAppRef.current.getStartingAwait(), editorAppRef.current.getDisposingAwait()]); } - } catch (error) { - performErrorHandling(error as Error); + updateModelRelatedRefs(); + + editorAppRef.current.registerOnTextChangedCallback((textChanges) => { + if (textChanges.modified !== undefined) { + modifiedCodeRef.current = textChanges.modified; + } + if (textChanges.original !== undefined) { + originalCodeRef.current = textChanges.original; + } + if (onTextChangedRef.current !== undefined) { + onTextChangedRef.current(textChanges); + } + }); + // await retrieveContainerRef('INIT EDITOR'); + await editorAppRef.current.start(htmlContainer); + + onEditorStartDone?.(editorAppRef.current); + launchingRef.current = false; + debugLogging('INIT EDITOR: Editor start was successful.'); + } else { + debugLogging('INIT EDITOR: Editor was already started.'); + } } - }; - - const processConfig = () => { - let modelUpdated = false; - let textUpdated = false; - try { - debugLogging('CONFIG PROCESSED: Started'); - if (!launchingRef.current && editorAppRef.current !== undefined) { - if (editorAppConfigRef.current?.codeResources !== undefined) { - const newModifiedCodeUri = editorAppConfigRef.current.codeResources.modified?.uri; - const newOriginalCodeUri = editorAppConfigRef.current.codeResources.original?.uri; - - const modifiedUri = modifiedCodeUriRef.current !== newModifiedCodeUri ? newModifiedCodeUri : undefined; - const originalUri = originalCodeUriRef.current !== newOriginalCodeUri ? newOriginalCodeUri : undefined; - // re-create the editor if the URIs have changed - if (modifiedUri !== undefined || originalUri !== undefined) { - modelUpdated = true; - } else { - const newModifiedCode = editorAppConfigRef.current.codeResources.modified?.text; - const newOriginalCode = editorAppConfigRef.current.codeResources.original?.text; - const modified = modifiedCodeRef.current !== newModifiedCode ? newModifiedCode : undefined; - const original = originalCodeRef.current !== newOriginalCode ? newOriginalCode : undefined; - if (modified !== undefined || original !== undefined) { - textUpdated = true; - editorAppRef.current.updateCode({ modified, original }); - } - } - } - if (editorAppConfigRef.current?.editorOptions !== undefined) { - if (!editorAppRef.current.isDiffEditor()) { - editorAppRef.current.getEditor()?.updateOptions(editorAppConfigRef.current.editorOptions); - } - } - if (editorAppConfigRef.current?.diffEditorOptions !== undefined) { - if (editorAppRef.current.isDiffEditor()) { - editorAppRef.current.getDiffEditor()?.updateOptions(editorAppConfigRef.current.diffEditorOptions); - } - } - } - // notitfy now if no async model update was necessary - if (!modelUpdated) { - onConfigProcessed?.({modelUpdated, textUpdated, editorApp: editorAppRef.current }); + } else { + debugLogging('INIT EDITOR: Do nothing: Using ViewsService'); + } + } catch (error) { + performErrorHandling(error as Error); + } + }; + + const updateEditorModel = async () => { + try { + if (!launchingRef.current && editorAppRef.current !== undefined) { + await editorAppRef.current.updateCodeResources(editorAppConfigRef.current?.codeResources); + updateModelRelatedRefs(); + onConfigProcessed?.({ modelUpdated: true, textUpdated: true, editorApp: editorAppRef.current }); + debugLogging('UPDATE EDITOR MODEL: Model was updated.'); + } else { + onConfigProcessed?.({ modelUpdated: false, textUpdated: false, editorApp: editorAppRef.current }); + debugLogging('UPDATE EDITOR MODEL: No editor is avilable. Model update was not possible.'); + } + } catch (error) { + performErrorHandling(error as Error); + } + }; + + const updateModelRelatedRefs = () => { + modifiedCodeRef.current = editorAppConfigRef.current?.codeResources?.modified?.text; + originalCodeRef.current = editorAppConfigRef.current?.codeResources?.original?.text; + modifiedCodeUriRef.current = editorAppConfigRef.current?.codeResources?.modified?.uri; + originalCodeUriRef.current = editorAppConfigRef.current?.codeResources?.original?.uri; + }; + + const disposeEditor = async () => { + try { + // dispose editor if used + if (editorAppRef.current !== undefined) { + await editorAppRef.current.dispose(); + editorAppRef.current = undefined; + onDisposeEditor?.(); + debugLogging('DISPOSE: EditorApp was disposed'); + } else { + debugLogging('DISPOSE: EditorApp is not disposed'); + } + } catch (error) { + performErrorHandling(error as Error); + } + }; + + const processConfig = () => { + let modelUpdated = false; + let textUpdated = false; + try { + debugLogging('CONFIG PROCESSED: Started'); + if (!launchingRef.current && editorAppRef.current !== undefined) { + if (editorAppConfigRef.current?.codeResources !== undefined) { + const newModifiedCodeUri = editorAppConfigRef.current.codeResources.modified?.uri; + const newOriginalCodeUri = editorAppConfigRef.current.codeResources.original?.uri; + + const modifiedUri = modifiedCodeUriRef.current !== newModifiedCodeUri ? newModifiedCodeUri : undefined; + const originalUri = originalCodeUriRef.current !== newOriginalCodeUri ? newOriginalCodeUri : undefined; + // re-create the editor if the URIs have changed + if (modifiedUri !== undefined || originalUri !== undefined) { + modelUpdated = true; + } else { + const newModifiedCode = editorAppConfigRef.current.codeResources.modified?.text; + const newOriginalCode = editorAppConfigRef.current.codeResources.original?.text; + const modified = modifiedCodeRef.current !== newModifiedCode ? newModifiedCode : undefined; + const original = originalCodeRef.current !== newOriginalCode ? newOriginalCode : undefined; + if (modified !== undefined || original !== undefined) { + textUpdated = true; + editorAppRef.current.updateCode({ modified, original }); } - debugLogging('CONFIG PROCESSED: Done'); - } catch (error) { - performErrorHandling(error as Error); + } } - return modelUpdated; - }; - - useEffect(() => { - // fast-fail - if (editorAppConfig === undefined) return; - - // always try to perform global init. Reason: we cannot ensure order - // we can't await this due to the nature of useEffect - // oxlint-disable-next-line typescript/no-floating-promises - performGlobalInit(); - - editorAppConfigRef.current = editorAppConfig; - // it is possible to run without an editorApp, when the ViewsService or WorkbenchService - if (haveEditorService()) { - if (editorAppRef.current === undefined) { - addQueue({ id: 'editorInit', func: editorInit, currentContainer: containerRef.current}); - } else { - debugLogging('CHECK EDITOR: Editor already created. No queueing necessary.'); - } - } else { - debugLogging('INIT EDITOR: Do nothing: Using ViewsService'); + if (editorAppConfigRef.current?.editorOptions !== undefined) { + if (!editorAppRef.current.isDiffEditor()) { + editorAppRef.current.getEditor()?.updateOptions(editorAppConfigRef.current.editorOptions); + } } - }, [editorAppConfig]); - - useEffect(() => { - const triggerValue = triggerReprocessConfig ?? 0; - if (triggerValue > triggerReprocessConfigRef.current) { - debugLogging('REPROCESS CONFIG: Triggered'); - const updateModel = processConfig(); - if (updateModel) { - addQueue({ id: 'modelUpdate', func: updateEditorModel, currentContainer: containerRef.current}); - } - triggerReprocessConfigRef.current = triggerValue; - } else { - debugLogging('REPROCESS CONFIG: Denied'); + if (editorAppConfigRef.current?.diffEditorOptions !== undefined) { + if (editorAppRef.current.isDiffEditor()) { + editorAppRef.current.getDiffEditor()?.updateOptions(editorAppConfigRef.current.diffEditorOptions); + } } - }, [triggerReprocessConfig]); + } + // notitfy now if no async model update was necessary + if (!modelUpdated) { + onConfigProcessed?.({ modelUpdated, textUpdated, editorApp: editorAppRef.current }); + } + debugLogging('CONFIG PROCESSED: Done'); + } catch (error) { + performErrorHandling(error as Error); + } + return modelUpdated; + }; + + useEffect(() => { + // fast-fail + if (editorAppConfig === undefined) return; + + // always try to perform global init. Reason: we cannot ensure order + // we can't await this due to the nature of useEffect + // oxlint-disable-next-line typescript/no-floating-promises + performGlobalInit(); + + editorAppConfigRef.current = editorAppConfig; + // it is possible to run without an editorApp, when the ViewsService or WorkbenchService + if (haveEditorService()) { + if (editorAppRef.current === undefined) { + addQueue({ id: 'editorInit', func: editorInit, currentContainer: containerRef.current }); + } else { + debugLogging('CHECK EDITOR: Editor already created. No queueing necessary.'); + } + } else { + debugLogging('INIT EDITOR: Do nothing: Using ViewsService'); + } + }, [editorAppConfig]); + + useEffect(() => { + const triggerValue = triggerReprocessConfig ?? 0; + if (triggerValue > triggerReprocessConfigRef.current) { + debugLogging('REPROCESS CONFIG: Triggered'); + const updateModel = processConfig(); + if (updateModel) { + addQueue({ id: 'modelUpdate', func: updateEditorModel, currentContainer: containerRef.current }); + } + triggerReprocessConfigRef.current = triggerValue; + } else { + debugLogging('REPROCESS CONFIG: Denied'); + } + }, [triggerReprocessConfig]); + + const lcInitFunc = async () => { + try { + await lcsManager.start(); + onLanguageClientsStartDone?.(lcsManager); + } catch (error) { + performErrorHandling(error as Error); + } + }; + + useEffect(() => { + // fast-fail + if (languageClientConfig === undefined) return; + + // always try to perform global init. Reason: we cannot ensure order + // we can't await this due to the nature of useEffect + // oxlint-disable-next-line typescript/no-floating-promises + performGlobalInit(); + + lcsManager.setLogLevel(languageClientConfig.logLevel); + lcsManager.setConfig(languageClientConfig); + if (!lcsManager.isStarted() && (enforceLanguageClientDisposeRef.current === undefined || !enforceLanguageClientDisposeRef.current)) { + addQueue({ id: 'lcInit', func: lcInitFunc, currentContainer: containerRef.current }); + } else { + debugLogging('INIT LC: Language client is already running. No need to schedule async start.'); + } + }, [languageClientConfig]); - const lcInitFunc = async () => { + useEffect(() => { + enforceLanguageClientDisposeRef.current = enforceLanguageClientDispose === true; + if (enforceLanguageClientDisposeRef.current === true) { + const disposeLCFunc = async () => { try { - await lcsManager.start(); - onLanguageClientsStartDone?.(lcsManager); + await lcsManager.dispose(); + onDisposeLanguageClient?.(); } catch (error) { - performErrorHandling(error as Error); + // The language client may throw an error during disposal, but we want to continue anyway + const message = error instanceof Error ? error.message : String(error); + console.error(`Unexpected error occurred: ${message}`); + performErrorHandling(new Error(`Unexpected error occurred during disposal of the language client: ${message}`)); } - }; - - useEffect(() => { - // fast-fail - if (languageClientConfig === undefined) return; - - // always try to perform global init. Reason: we cannot ensure order - // we can't await this due to the nature of useEffect - // oxlint-disable-next-line typescript/no-floating-promises - performGlobalInit(); + }; + if (lcsManager.isStarted()) { + addQueue({ id: 'lcDispose', func: disposeLCFunc, currentContainer: containerRef.current }); + } else { + debugLogging('ENFORCE DISPOSE LC: Denied: No language client is running.'); + } + } else { + debugLogging('ENFORCE DISPOSE LC: Denied: enforceLanguageClientDisposeRef.current is false.'); + if (!lcsManager.isStarted()) { + addQueue({ id: 'lcInit', func: lcInitFunc, currentContainer: containerRef.current }); + } + } + }, [enforceLanguageClientDispose]); - lcsManager.setLogLevel(languageClientConfig.logLevel); - lcsManager.setConfig(languageClientConfig); - if (!lcsManager.isStarted() && (enforceLanguageClientDisposeRef.current === undefined || !enforceLanguageClientDisposeRef.current)) { - addQueue({ id:'lcInit', func: lcInitFunc, currentContainer: containerRef.current }); - } else { - debugLogging('INIT LC: Language client is already running. No need to schedule async start.'); - } - }, [languageClientConfig]); - - useEffect(() => { - enforceLanguageClientDisposeRef.current = enforceLanguageClientDispose === true; - if (enforceLanguageClientDisposeRef.current === true) { - const disposeLCFunc = async () => { - try { - await lcsManager.dispose(); - onDisposeLanguageClient?.(); - } catch (error) { - // The language client may throw an error during disposal, but we want to continue anyway - const message = error instanceof Error ? error.message : String(error); - console.error(`Unexpected error occurred: ${message}`); - performErrorHandling(new Error(`Unexpected error occurred during disposal of the language client: ${message }`)); - } - }; - if (lcsManager.isStarted()) { - addQueue({ id:'lcDispose', func: disposeLCFunc, currentContainer: containerRef.current }); - } else { - debugLogging('ENFORCE DISPOSE LC: Denied: No language client is running.'); - } - } else { - debugLogging('ENFORCE DISPOSE LC: Denied: enforceLanguageClientDisposeRef.current is false.'); - if (!lcsManager.isStarted()) { - addQueue({ id:'lcInit', func: lcInitFunc, currentContainer: containerRef.current }); - } - } - }, [enforceLanguageClientDispose]); + useEffect(() => { + // this part runs on mount (componentDidMount) - useEffect(() => { - // this part runs on mount (componentDidMount) + // always try to perform global init. Reason: we cannot ensure order + // we can't await this due to the nature of useEffect + // oxlint-disable-next-line typescript/no-floating-promises + performGlobalInit(); - // always try to perform global init. Reason: we cannot ensure order - // we can't await this due to the nature of useEffect - // oxlint-disable-next-line typescript/no-floating-promises - performGlobalInit(); + // this part runs on unmount (componentWillUnmount) + return () => { + addQueue({ id: 'disposeEditor', func: disposeEditor, currentContainer: containerRef.current }); + }; + }, []); - // this part runs on unmount (componentWillUnmount) - return () => { - addQueue({ id:'disposeEditor', func: disposeEditor, currentContainer: containerRef.current }); - }; - }, []); + useEffect(() => { + if (logLevel !== undefined) { + logger.setLevel(logLevel); + } + }, [logLevel]); - useEffect(() => { - if (logLevel !== undefined) { - logger.setLevel(logLevel); - } - }, [logLevel]); - - return ( -
- ); + return
; }; diff --git a/packages/wrapper-react/test/index.extapi.test.tsx b/packages/wrapper-react/test/index.extapi.test.tsx index 659e47fbd..3367ce86e 100644 --- a/packages/wrapper-react/test/index.extapi.test.tsx +++ b/packages/wrapper-react/test/index.extapi.test.tsx @@ -13,247 +13,250 @@ import { beforeAll, describe, expect, test } from 'vitest'; import { cleanHtmlBody, createDefaultEditorAppConfig, hundredMs } from './support/helper.js'; describe.sequential('Test MonacoEditorReactComp: External monaco-vscode-api', () => { - - beforeAll(async () => { - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } - }; - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); + beforeAll(async () => { + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } + }; + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); + }); + + const code = 'const text = "Hello World!";'; + const codeUpdated = 'const text = "Goodbye World!";'; + + test('test render, manual clean-up', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - const code = 'const text = "Hello World!";'; - const codeUpdated = 'const text = "Goodbye World!";'; - - test('test render, manual clean-up', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + deferred.resolve()} /> + ); + expect(await deferred.promise).toBeUndefined(); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, unmount', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('test render, unmount', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} />); - expect(await deferred.promise).toBeUndefined(); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + deferred.resolve()} /> + ); + expect(await deferred.promise).toBeUndefined(); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, rerender', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('test render, rerender', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( { - expect(editorApp).toBeDefined(); - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); - - await delayExecution(hundredMs); - - const deferred2 = new Deferred(); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - renderResult.rerender( { - expect(result.textUpdated).toBeTruthy(); - expect(result.modelUpdated).toBeFalsy(); - expect(result.editorApp).toBeDefined(); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - expect(result.editorApp?.getTextModels().modified?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - />); - expect(await deferred2.promise).toBeUndefined(); - await delayExecution(hundredMs); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + { + expect(editorApp).toBeDefined(); + deferred.resolve(); + }} + /> + ); + expect(await deferred.promise).toBeUndefined(); + + await delayExecution(hundredMs); + + const deferred2 = new Deferred(); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('test render, unmount and render new', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - let renderResult: RenderResult | undefined; - const deferred = new Deferred(); - renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); - - await delayExecution(hundredMs); - renderResult.unmount(); - cleanHtmlBody(); - - const deferred2 = new Deferred(); - renderResult = render( deferred2.resolve()} - />); - expect(await deferred2.promise).toBeUndefined(); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + renderResult.rerender( + { + expect(result.textUpdated).toBeTruthy(); + expect(result.modelUpdated).toBeFalsy(); + expect(result.editorApp).toBeDefined(); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + expect(result.editorApp?.getTextModels().modified?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + /> + ); + expect(await deferred2.promise).toBeUndefined(); + await delayExecution(hundredMs); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, unmount and render new', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('multiple editors in single render', async () => { - const editorAppConfig1 = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "FirstComponent";', - uri: `/workspace/first-${expect.getState().testPath}.js` - } - }); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "SecondComponent";', - uri: `/workspace/second-${expect.getState().testPath}.js` - } - }); - const firstComponentReady = new Deferred(); - const secondComponentReady = new Deferred(); - const renderResult = render(<> - firstComponentReady.resolve()} - /> - secondComponentReady.resolve()} - /> - ); - - const promises = await Promise.all([firstComponentReady.promise, secondComponentReady.promise]); - expect(promises).toEqual([undefined, undefined]); - - await delayExecution(hundredMs); - - expect(renderResult.getAllByRole('code')[0].innerText).contains('FirstComponent'); - expect(renderResult.getAllByRole('code')[1].innerText).contains('SecondComponent'); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + let renderResult: RenderResult | undefined; + const deferred = new Deferred(); + renderResult = render( + deferred.resolve()} /> + ); + expect(await deferred.promise).toBeUndefined(); + + await delayExecution(hundredMs); + renderResult.unmount(); + cleanHtmlBody(); + + const deferred2 = new Deferred(); + renderResult = render( + deferred2.resolve()} /> + ); + expect(await deferred2.promise).toBeUndefined(); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('multiple editors in single render', async () => { + const editorAppConfig1 = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "FirstComponent";', + uri: `/workspace/first-${expect.getState().testPath}.js` + } }); - - test('test render, modify code', async () => { - const deferredStart = new Deferred(); - const deferredChanged = new Deferred(); - const deferredConfigUpdate = new Deferred(); - let modified; - let count = 0; - - const App = () => { - const [codeState, setCodeState] = useState(code); - const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); - - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: codeState, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - return ( - <> - - { - modified = textChanges.modified; - count++; - console.log(`count: ${count} text: ${modified}`); - if (codeUpdated === modified) { - deferredChanged.resolve(); - } - }} - triggerReprocessConfig={triggerReprocessConfig} - onConfigProcessed={(result) => { - expect(result.textUpdated).toBeTruthy(); - expect(result.modelUpdated).toBeFalsy(); - deferredConfigUpdate.resolve(); - }} - onEditorStartDone={() => deferredStart.resolve()} - /> - - ); - }; - const renderResult = render(); - expect(await deferredStart.promise).toBeUndefined(); - - // delay execute/click, so await below is already awaiting the deferredDispose - setTimeout(() => { - document.getElementById('change-button')?.click(); - }, hundredMs); - - expect(await Promise.all([deferredChanged.promise, deferredConfigUpdate.promise])).toStrictEqual([undefined, undefined]); - // one time code, then update - expect(count).toBe(2); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "SecondComponent";', + uri: `/workspace/second-${expect.getState().testPath}.js` + } }); - + const firstComponentReady = new Deferred(); + const secondComponentReady = new Deferred(); + const renderResult = render( + <> + firstComponentReady.resolve()} + /> + secondComponentReady.resolve()} + /> + + ); + + const promises = await Promise.all([firstComponentReady.promise, secondComponentReady.promise]); + expect(promises).toEqual([undefined, undefined]); + + await delayExecution(hundredMs); + + expect(renderResult.getAllByRole('code')[0].innerText).contains('FirstComponent'); + expect(renderResult.getAllByRole('code')[1].innerText).contains('SecondComponent'); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, modify code', async () => { + const deferredStart = new Deferred(); + const deferredChanged = new Deferred(); + const deferredConfigUpdate = new Deferred(); + let modified; + let count = 0; + + const App = () => { + const [codeState, setCodeState] = useState(code); + const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); + + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: codeState, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + + return ( + <> + + { + modified = textChanges.modified; + count++; + console.log(`count: ${count} text: ${modified}`); + if (codeUpdated === modified) { + deferredChanged.resolve(); + } + }} + triggerReprocessConfig={triggerReprocessConfig} + onConfigProcessed={(result) => { + expect(result.textUpdated).toBeTruthy(); + expect(result.modelUpdated).toBeFalsy(); + deferredConfigUpdate.resolve(); + }} + onEditorStartDone={() => deferredStart.resolve()} + /> + + ); + }; + const renderResult = render(); + expect(await deferredStart.promise).toBeUndefined(); + + // delay execute/click, so await below is already awaiting the deferredDispose + setTimeout(() => { + document.getElementById('change-button')?.click(); + }, hundredMs); + + expect(await Promise.all([deferredChanged.promise, deferredConfigUpdate.promise])).toStrictEqual([undefined, undefined]); + // one time code, then update + expect(count).toBe(2); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); }); diff --git a/packages/wrapper-react/test/index.lc.strictmode.test.tsx b/packages/wrapper-react/test/index.lc.strictmode.test.tsx index b0e5e5e2d..67129c96a 100644 --- a/packages/wrapper-react/test/index.lc.strictmode.test.tsx +++ b/packages/wrapper-react/test/index.lc.strictmode.test.tsx @@ -13,245 +13,279 @@ import { describe, expect, test } from 'vitest'; import { cleanHtmlBody, createDefaultEditorAppConfig, createDefaultLanguageClientConfig, hundredMs } from './support/helper.js'; describe.sequential('Test MonacoEditorReactComp StrictMode: Language Client ', () => { + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } + }; + const code = 'const text = "Hello World!";'; + const codeUpdated = 'const text = "Goodbye World!";'; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } - }; - const code = 'const text = "Hello World!";'; - const codeUpdated = 'const text = "Goodbye World!";'; + test('test render, languageclient, manual clean-up', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const languageClientConfig = createDefaultLanguageClientConfig(); - test('test render, languageclient, manual clean-up', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); + const deferred = new Deferred(); + let lcsManager: LanguageClientManager | undefined; + const renderResult = render( + + { + lcsManager = lcsManagerPassed; + deferred.resolve(); + }} + /> + + ); + expect(await deferred.promise).toBeUndefined(); - const deferred = new Deferred(); - let lcsManager: LanguageClientManager | undefined; - const renderResult = render( { - lcsManager = lcsManagerPassed; - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); + await delayExecution(hundredMs); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - await delayExecution(hundredMs); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + await lcsManager?.dispose(true); + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - await lcsManager?.dispose(true); - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + test('test render, languageclient, unmount with enforce dispose', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const languageClientConfig = createDefaultLanguageClientConfig(); - test('test render, languageclient, unmount with enforce dispose', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); + let lcsManager: LanguageClientManager | undefined; + const deferred = new Deferred(); + const renderResult = render( + + { + lcsManager = lcsManagerPassed; + deferred.resolve(); + }} + /> + + ); + expect(await deferred.promise).toBeUndefined(); - let lcsManager: LanguageClientManager | undefined; - const deferred = new Deferred(); - const renderResult = render( { - lcsManager = lcsManagerPassed; - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + await delayExecution(hundredMs); - await delayExecution(hundredMs); + const deferredLc = new Deferred(); + const languageClientConfig2 = createDefaultLanguageClientConfig(); + renderResult.rerender( + + deferredLc.resolve()} + /> + + ); + expect(await deferredLc.promise).toBeUndefined(); - const deferredLc = new Deferred(); - const languageClientConfig2 = createDefaultLanguageClientConfig(); - renderResult.rerender( deferredLc.resolve()} - />); - expect(await deferredLc.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.haveLanguageClient()).toBeFalsy(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeFalsy(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.haveLanguageClient()).toBeFalsy(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeFalsy(); + await lcsManager?.dispose(true); + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - await lcsManager?.dispose(true); - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + test('test render, languageclient, rerender', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const languageClientConfig = createDefaultLanguageClientConfig(); - test('test render, languageclient, rerender', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); - - const deferredLc = new Deferred(); - let lcsManager: LanguageClientManager | undefined; - const renderResult = render( { - lcsManager = lcsManagerPassed; + const deferredLc = new Deferred(); + let lcsManager: LanguageClientManager | undefined; + const renderResult = render( + + { + lcsManager = lcsManagerPassed; - deferredLc.resolve(); - }} - />); - expect(await deferredLc.promise).toBeUndefined(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + deferredLc.resolve(); + }} + /> + + ); + expect(await deferredLc.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - await delayExecution(hundredMs); + await delayExecution(hundredMs); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const deferred2 = new Deferred(); - renderResult.rerender( { - expect(result.textUpdated).toBe(true); - expect(result.editorApp).toBeDefined(); - await delayExecution(hundredMs); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - />); - expect(await deferred2.promise).toBeUndefined(); - - await lcsManager?.dispose(true); - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const deferred2 = new Deferred(); + renderResult.rerender( + + { + expect(result.textUpdated).toBe(true); + expect(result.editorApp).toBeDefined(); + await delayExecution(hundredMs); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + /> + + ); + expect(await deferred2.promise).toBeUndefined(); - test('test render, languageclient, rerender with changed config', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); + await lcsManager?.dispose(true); + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - const deferredLc = new Deferred(); - const deferredEditor = new Deferred(); - let lcsManager: LanguageClientManager | undefined; - const renderResult = render( { - lcsManager = lcsManagerPassed; - expect(lcsManager.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - deferredLc.resolve(); - }} - onEditorStartDone={() => deferredEditor.resolve()} - />); - await expect(Promise.all([deferredEditor.promise, deferredLc.promise])).resolves.toEqual([undefined, undefined]); + test('test render, languageclient, rerender with changed config', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const languageClientConfig = createDefaultLanguageClientConfig(); - await delayExecution(hundredMs); + const deferredLc = new Deferred(); + const deferredEditor = new Deferred(); + let lcsManager: LanguageClientManager | undefined; + const renderResult = render( + + { + lcsManager = lcsManagerPassed; + expect(lcsManager.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + deferredLc.resolve(); + }} + onEditorStartDone={() => deferredEditor.resolve()} + /> + + ); + await expect(Promise.all([deferredEditor.promise, deferredLc.promise])).resolves.toEqual([undefined, undefined]); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfigs2 = createDefaultLanguageClientConfig(); - languageClientConfigs2.clientOptions.markdown = { - supportHtml: true - }; - const deferred2 = new Deferred(); - renderResult.rerender( { - expect(result.textUpdated).toBe(true); - expect(result.editorApp).toBeDefined(); - await delayExecution(hundredMs); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - onError={(error) => { - expect(error.message).toEqual('A languageclient config with id "langium" already exists and you confiured to not override.'); - }} - />); - expect(await deferred2.promise).toBeUndefined(); + await delayExecution(hundredMs); - await delayExecution(hundredMs); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const languageClientConfigs2 = createDefaultLanguageClientConfig(); + languageClientConfigs2.clientOptions.markdown = { + supportHtml: true + }; + const deferred2 = new Deferred(); + renderResult.rerender( + + { + expect(result.textUpdated).toBe(true); + expect(result.editorApp).toBeDefined(); + await delayExecution(hundredMs); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + onError={(error) => { + expect(error.message).toEqual('A languageclient config with id "langium" already exists and you confiured to not override.'); + }} + /> + + ); + expect(await deferred2.promise).toBeUndefined(); - const languageClientConfigs3 = createDefaultLanguageClientConfig(); - const deferred3 = new Deferred(); - // you have to enforce dispose of the LanguageClient if you want to restart with new configuration - renderResult.rerender( deferred3.resolve()} - />); - expect(await deferred3.promise).toBeUndefined(); + await delayExecution(hundredMs); - await delayExecution(hundredMs); + const languageClientConfigs3 = createDefaultLanguageClientConfig(); + const deferred3 = new Deferred(); + // you have to enforce dispose of the LanguageClient if you want to restart with new configuration + renderResult.rerender( + + deferred3.resolve()} + /> + + ); + expect(await deferred3.promise).toBeUndefined(); - const languageClientConfigs4 = createDefaultLanguageClientConfig(); - languageClientConfigs4.clientOptions.markdown = { - supportHtml: true - }; - const deferred4 = new Deferred(); - renderResult.rerender( deferred4.resolve()} - />); - expect(await deferred4.promise).toBeUndefined(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + await delayExecution(hundredMs); - await lcsManager?.dispose(true); - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); - }); + const languageClientConfigs4 = createDefaultLanguageClientConfig(); + languageClientConfigs4.clientOptions.markdown = { + supportHtml: true + }; + const deferred4 = new Deferred(); + renderResult.rerender( + + deferred4.resolve()} + /> + + ); + expect(await deferred4.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + await lcsManager?.dispose(true); + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); }); diff --git a/packages/wrapper-react/test/index.lc.test.tsx b/packages/wrapper-react/test/index.lc.test.tsx index 74f6f2675..844e846ba 100644 --- a/packages/wrapper-react/test/index.lc.test.tsx +++ b/packages/wrapper-react/test/index.lc.test.tsx @@ -13,252 +13,268 @@ import { describe, expect, test } from 'vitest'; import { cleanHtmlBody, createDefaultEditorAppConfig, createDefaultLanguageClientConfig, hundredMs } from './support/helper.js'; describe.sequential('Test MonacoEditorReactComp: Langugae Client', () => { + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } + }; + const code = 'const text = "Hello World!";'; + const codeUpdated = 'const text = "Goodbye World!";'; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } - }; - const code = 'const text = "Hello World!";'; - const codeUpdated = 'const text = "Goodbye World!";'; + test('test render, languageclient, manual clean-up', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const languageClientConfig = createDefaultLanguageClientConfig(); - test('test render, languageclient, manual clean-up', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); + const deferred = new Deferred(); + let lcsManager: LanguageClientManager | undefined; + const renderResult = render( + { + lcsManager = lcsManagerPassed; + deferred.resolve(); + }} + /> + ); + expect(await deferred.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - const deferred = new Deferred(); - let lcsManager: LanguageClientManager | undefined; - const renderResult = render( { - lcsManager = lcsManagerPassed; - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + await delayExecution(hundredMs); + try { + await lcsManager?.dispose(true); + } catch (error) { + console.log('Error during manual dispose of LanguageClientManager:', error); + } + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - await delayExecution(hundredMs); - try { - await lcsManager?.dispose(true); - } catch (error) { - console.log('Error during manual dispose of LanguageClientManager:', error); - } - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + test('test render, languageclient, unmount with enforce dispose', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const languageClientConfig = createDefaultLanguageClientConfig(); - test('test render, languageclient, unmount with enforce dispose', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); + let lcsManager: LanguageClientManager | undefined; + const deferred = new Deferred(); + const renderResult = render( + { + lcsManager = lcsManagerPassed; + deferred.resolve(); + }} + /> + ); + expect(await deferred.promise).toBeUndefined(); - let lcsManager: LanguageClientManager | undefined; - const deferred = new Deferred(); - const renderResult = render( { - lcsManager = lcsManagerPassed; - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + const deferredLc = new Deferred(); + const languageClientConfig2 = createDefaultLanguageClientConfig(); + renderResult.rerender( + deferredLc.resolve()} + /> + ); + expect(await deferredLc.promise).toBeUndefined(); - const deferredLc = new Deferred(); - const languageClientConfig2 = createDefaultLanguageClientConfig(); - renderResult.rerender( deferredLc.resolve()} - />); - expect(await deferredLc.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.haveLanguageClient()).toBeFalsy(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeFalsy(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.haveLanguageClient()).toBeFalsy(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeFalsy(); + await delayExecution(hundredMs); + try { + await lcsManager?.dispose(true); + } catch (error) { + console.log('Error during manual dispose of LanguageClientManager:', error); + } + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - await delayExecution(hundredMs); - try { - await lcsManager?.dispose(true); - } catch (error) { - console.log('Error during manual dispose of LanguageClientManager:', error); - } - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + test('test render, languageclient, rerender', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const languageClientConfig = createDefaultLanguageClientConfig(); - test('test render, languageclient, rerender', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); - - const deferredLc = new Deferred(); - let lcsManager: LanguageClientManager | undefined; - const renderResult = render( { - lcsManager = lcsManagerPassed; - deferredLc.resolve(); - }} - />); - expect(await deferredLc.promise).toBeUndefined(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + const deferredLc = new Deferred(); + let lcsManager: LanguageClientManager | undefined; + const renderResult = render( + { + lcsManager = lcsManagerPassed; + deferredLc.resolve(); + }} + /> + ); + expect(await deferredLc.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const deferred2 = new Deferred(); - renderResult.rerender( { - expect(result.textUpdated).toBe(true); - expect(result.editorApp).toBeDefined(); - await delayExecution(hundredMs); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - />); - expect(await deferred2.promise).toBeUndefined(); - - await delayExecution(hundredMs); - try { - await lcsManager?.dispose(true); - } catch (error) { - console.log('Error during manual dispose of LanguageClientManager:', error); - } - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } }); + const deferred2 = new Deferred(); + renderResult.rerender( + { + expect(result.textUpdated).toBe(true); + expect(result.editorApp).toBeDefined(); + await delayExecution(hundredMs); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + /> + ); + expect(await deferred2.promise).toBeUndefined(); - test('test render, languageclient, rerender with changed config', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfig = createDefaultLanguageClientConfig(); + await delayExecution(hundredMs); + try { + await lcsManager?.dispose(true); + } catch (error) { + console.log('Error during manual dispose of LanguageClientManager:', error); + } + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - const deferredLc = new Deferred(); - const deferredEditor = new Deferred(); - let lcsManager: LanguageClientManager | undefined; - const renderResult = render( { - lcsManager = lcsManagerPassed; - expect(lcsManager.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); - deferredLc.resolve(); - }} - onEditorStartDone={() => deferredEditor.resolve()} - />); - await expect(Promise.all([deferredEditor.promise, deferredLc.promise])).resolves.toEqual([undefined, undefined]); + test('test render, languageclient, rerender with changed config', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const languageClientConfig = createDefaultLanguageClientConfig(); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - const languageClientConfigs2 = createDefaultLanguageClientConfig(); - languageClientConfigs2.clientOptions.markdown = { - supportHtml: true - }; - const deferred2 = new Deferred(); - renderResult.rerender( { - expect(result.textUpdated).toBe(true); - expect(result.editorApp).toBeDefined(); - await delayExecution(hundredMs); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - onError={(error) => { - expect(error.message).toEqual('A languageclient config with id "langium" already exists and you confiured to not override.'); - }} - />); - expect(await deferred2.promise).toBeUndefined(); + const deferredLc = new Deferred(); + const deferredEditor = new Deferred(); + let lcsManager: LanguageClientManager | undefined; + const renderResult = render( + { + lcsManager = lcsManagerPassed; + expect(lcsManager.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + deferredLc.resolve(); + }} + onEditorStartDone={() => deferredEditor.resolve()} + /> + ); + await expect(Promise.all([deferredEditor.promise, deferredLc.promise])).resolves.toEqual([undefined, undefined]); - const languageClientConfigs3 = createDefaultLanguageClientConfig(); - const deferred3 = new Deferred(); - // you have to enforce dispose of the LanguageClient if you want to restart with new configuration - renderResult.rerender( deferred3.resolve()} - />); - expect(await deferred3.promise).toBeUndefined(); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + const languageClientConfigs2 = createDefaultLanguageClientConfig(); + languageClientConfigs2.clientOptions.markdown = { + supportHtml: true + }; + const deferred2 = new Deferred(); + renderResult.rerender( + { + expect(result.textUpdated).toBe(true); + expect(result.editorApp).toBeDefined(); + await delayExecution(hundredMs); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + onError={(error) => { + expect(error.message).toEqual('A languageclient config with id "langium" already exists and you confiured to not override.'); + }} + /> + ); + expect(await deferred2.promise).toBeUndefined(); - const languageClientConfigs4 = createDefaultLanguageClientConfig(); - languageClientConfigs4.clientOptions.markdown = { - supportHtml: true - }; - const deferred4 = new Deferred(); - renderResult.rerender( deferred4.resolve()} - />); - expect(await deferred4.promise).toBeUndefined(); - expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + const languageClientConfigs3 = createDefaultLanguageClientConfig(); + const deferred3 = new Deferred(); + // you have to enforce dispose of the LanguageClient if you want to restart with new configuration + renderResult.rerender( + deferred3.resolve()} + /> + ); + expect(await deferred3.promise).toBeUndefined(); - await delayExecution(hundredMs); - try { - await lcsManager?.dispose(true); - } catch (error) { - console.log('Error during manual dispose of LanguageClientManager:', error); - } - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); - }); + const languageClientConfigs4 = createDefaultLanguageClientConfig(); + languageClientConfigs4.clientOptions.markdown = { + supportHtml: true + }; + const deferred4 = new Deferred(); + renderResult.rerender( + deferred4.resolve()} + /> + ); + expect(await deferred4.promise).toBeUndefined(); + expect(lcsManager?.getLanguageClientWrapper('langium')?.isStarted()).toBeTruthy(); + await delayExecution(hundredMs); + try { + await lcsManager?.dispose(true); + } catch (error) { + console.log('Error during manual dispose of LanguageClientManager:', error); + } + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); }); diff --git a/packages/wrapper-react/test/index.strictmode.test.tsx b/packages/wrapper-react/test/index.strictmode.test.tsx index 6b466abb1..533d8cc06 100644 --- a/packages/wrapper-react/test/index.strictmode.test.tsx +++ b/packages/wrapper-react/test/index.strictmode.test.tsx @@ -14,264 +14,298 @@ import { describe, expect, test } from 'vitest'; import { cleanHtmlBody, createDefaultEditorAppConfig, hundredMs } from './support/helper.js'; describe.sequential('Test MonacoEditorReactComp', () => { - - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } - }; - const code = 'const text = "Hello World!";'; - const codeUpdated = 'const text = "Goodbye World!";'; - - test('strictMode: test render, manual clean-up', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); - - // prevents stack trace during execution (only required in strict mode) - await delayExecution(hundredMs); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } + }; + const code = 'const text = "Hello World!";'; + const codeUpdated = 'const text = "Goodbye World!";'; + + test('strictMode: test render, manual clean-up', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('strictMode: test render, unmount', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} /> - ); - expect(await deferred.promise).toBeUndefined(); - - // prevents stack trace during execution (only required in strict mode) - await delayExecution(hundredMs); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + + deferred.resolve()} + /> + + ); + expect(await deferred.promise).toBeUndefined(); + + // prevents stack trace during execution (only required in strict mode) + await delayExecution(hundredMs); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('strictMode: test render, unmount', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('strictMode: test render, rerender', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( { - expect(editorApp).toBeDefined(); - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); - - await delayExecution(hundredMs); - - const deferred2 = new Deferred(); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - renderResult.rerender( { - expect(result.textUpdated).toBeTruthy(); - expect(result.modelUpdated).toBeFalsy(); - expect(result.editorApp).toBeDefined(); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - expect(result.editorApp?.getTextModels().modified?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - logLevel={LogLevel.Debug} - />); - expect(await deferred2.promise).toBeUndefined(); - - // prevents stack trace during execution (only required in strict mode) - await delayExecution(hundredMs); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + + deferred.resolve()} + /> + + ); + expect(await deferred.promise).toBeUndefined(); + + // prevents stack trace during execution (only required in strict mode) + await delayExecution(hundredMs); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('strictMode: test render, rerender', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('strictMode: test render, unmount and render new', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - let renderResult: RenderResult | undefined; - const deferred = new Deferred(); - renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); - - await delayExecution(hundredMs); - renderResult.unmount(); - cleanHtmlBody(); - - const deferred2 = new Deferred(); - renderResult = render( deferred2.resolve()} - />); - expect(await deferred2.promise).toBeUndefined(); - - // prevents stack trace during execution (only required in strict mode) - await delayExecution(hundredMs); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + + { + expect(editorApp).toBeDefined(); + deferred.resolve(); + }} + /> + + ); + expect(await deferred.promise).toBeUndefined(); + + await delayExecution(hundredMs); + + const deferred2 = new Deferred(); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('strictMode: multiple editors in single render', async () => { - const editorAppConfig1 = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "FirstComponent";', - uri: `/workspace/first-${expect.getState().testPath}.js` - } - }); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "SecondComponent";', - uri: `/workspace/second-${expect.getState().testPath}.js` - } - }); - const firstComponentReady = new Deferred(); - const secondComponentReady = new Deferred(); - const renderResult = render( - firstComponentReady.resolve()} - /> - secondComponentReady.resolve()} - /> - ); - - const promises = await Promise.all([firstComponentReady.promise, secondComponentReady.promise]); - expect(promises).toEqual([undefined, undefined]); - - await delayExecution(hundredMs); - - expect(renderResult.getAllByRole('code')[0].innerText).contains('FirstComponent'); - expect(renderResult.getAllByRole('code')[1].innerText).contains('SecondComponent'); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + renderResult.rerender( + + { + expect(result.textUpdated).toBeTruthy(); + expect(result.modelUpdated).toBeFalsy(); + expect(result.editorApp).toBeDefined(); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + expect(result.editorApp?.getTextModels().modified?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + logLevel={LogLevel.Debug} + /> + + ); + expect(await deferred2.promise).toBeUndefined(); + + // prevents stack trace during execution (only required in strict mode) + await delayExecution(hundredMs); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('strictMode: test render, unmount and render new', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('strict mode: test render, modify code', async () => { - const deferredStart = new Deferred(); - const deferredChanged = new Deferred(); - const deferredConfigUpdate = new Deferred(); - let modified; - let count = 0; - - const App = () => { - const [codeState, setCodeState] = useState(code); - const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); - - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: codeState, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - return ( - <> - - { - modified = textChanges.modified; - count++; - console.log(`count: ${count} text: ${modified}`); - if (codeUpdated === modified) { - deferredChanged.resolve(); - } - }} - triggerReprocessConfig={triggerReprocessConfig} - onConfigProcessed={(result) => { - expect(result.textUpdated).toBeTruthy(); - expect(result.modelUpdated).toBeFalsy(); - deferredConfigUpdate.resolve(); - }} - onEditorStartDone={() => deferredStart.resolve()} - /> - - ); - }; - const renderResult = render(); - expect(await deferredStart.promise).toBeUndefined(); - - // delay execute/click, so await below is already awaiting the deferredDispose - setTimeout(() => { - document.getElementById('change-button')?.click(); - }, hundredMs); - - expect(await Promise.all([deferredChanged.promise, deferredConfigUpdate.promise])).toStrictEqual([undefined, undefined]); - // two times code (strict mode), then update - expect(count).toBe(3); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + let renderResult: RenderResult | undefined; + const deferred = new Deferred(); + renderResult = render( + + deferred.resolve()} + /> + + ); + expect(await deferred.promise).toBeUndefined(); + + await delayExecution(hundredMs); + renderResult.unmount(); + cleanHtmlBody(); + + const deferred2 = new Deferred(); + renderResult = render( + + deferred2.resolve()} + /> + + ); + expect(await deferred2.promise).toBeUndefined(); + + // prevents stack trace during execution (only required in strict mode) + await delayExecution(hundredMs); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('strictMode: multiple editors in single render', async () => { + const editorAppConfig1 = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "FirstComponent";', + uri: `/workspace/first-${expect.getState().testPath}.js` + } }); - + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "SecondComponent";', + uri: `/workspace/second-${expect.getState().testPath}.js` + } + }); + const firstComponentReady = new Deferred(); + const secondComponentReady = new Deferred(); + const renderResult = render( + + firstComponentReady.resolve()} + /> + secondComponentReady.resolve()} + /> + + ); + + const promises = await Promise.all([firstComponentReady.promise, secondComponentReady.promise]); + expect(promises).toEqual([undefined, undefined]); + + await delayExecution(hundredMs); + + expect(renderResult.getAllByRole('code')[0].innerText).contains('FirstComponent'); + expect(renderResult.getAllByRole('code')[1].innerText).contains('SecondComponent'); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('strict mode: test render, modify code', async () => { + const deferredStart = new Deferred(); + const deferredChanged = new Deferred(); + const deferredConfigUpdate = new Deferred(); + let modified; + let count = 0; + + const App = () => { + const [codeState, setCodeState] = useState(code); + const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); + + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: codeState, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + + return ( + <> + + { + modified = textChanges.modified; + count++; + console.log(`count: ${count} text: ${modified}`); + if (codeUpdated === modified) { + deferredChanged.resolve(); + } + }} + triggerReprocessConfig={triggerReprocessConfig} + onConfigProcessed={(result) => { + expect(result.textUpdated).toBeTruthy(); + expect(result.modelUpdated).toBeFalsy(); + deferredConfigUpdate.resolve(); + }} + onEditorStartDone={() => deferredStart.resolve()} + /> + + ); + }; + const renderResult = render( + + + + ); + expect(await deferredStart.promise).toBeUndefined(); + + // delay execute/click, so await below is already awaiting the deferredDispose + setTimeout(() => { + document.getElementById('change-button')?.click(); + }, hundredMs); + + expect(await Promise.all([deferredChanged.promise, deferredConfigUpdate.promise])).toStrictEqual([undefined, undefined]); + // two times code (strict mode), then update + expect(count).toBe(3); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); }); diff --git a/packages/wrapper-react/test/index.test.tsx b/packages/wrapper-react/test/index.test.tsx index 59847d556..e7098de63 100644 --- a/packages/wrapper-react/test/index.test.tsx +++ b/packages/wrapper-react/test/index.test.tsx @@ -13,251 +13,270 @@ import { describe, expect, test } from 'vitest'; import { cleanHtmlBody, createDefaultEditorAppConfig, hundredMs } from './support/helper.js'; describe.sequential('Test MonacoEditorReactComp', () => { - - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService' - } - }; - const code = 'const text = "Hello World!";'; - const codeUpdated = 'const text = "Goodbye World!";'; - - test('test render, manual clean-up', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService' + } + }; + const code = 'const text = "Hello World!";'; + const codeUpdated = 'const text = "Goodbye World!";'; + + test('test render, manual clean-up', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('test render, unmount', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} />); - expect(await deferred.promise).toBeUndefined(); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + deferred.resolve()} + /> + ); + expect(await deferred.promise).toBeUndefined(); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, unmount', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('test render, rerender', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( { - expect(editorApp).toBeDefined(); - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); - - await delayExecution(hundredMs); - - const deferred2 = new Deferred(); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: codeUpdated, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - renderResult.rerender( { - expect(result.textUpdated).toBeTruthy(); - expect(result.modelUpdated).toBeFalsy(); - expect(result.editorApp).toBeDefined(); - expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); - expect(result.editorApp?.getTextModels().modified?.getValue()).toBe(codeUpdated); - deferred2.resolve(); - }} - />); - expect(await deferred2.promise).toBeUndefined(); - await delayExecution(hundredMs); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + deferred.resolve()} + /> + ); + expect(await deferred.promise).toBeUndefined(); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, rerender', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('test render, unmount and render new', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: code, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - let renderResult: RenderResult | undefined; - const deferred = new Deferred(); - renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); - - await delayExecution(hundredMs); - renderResult.unmount(); - cleanHtmlBody(); - - const deferred2 = new Deferred(); - renderResult = render( deferred2.resolve()} - />); - expect(await deferred2.promise).toBeUndefined(); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + const deferred = new Deferred(); + const renderResult = render( + { + expect(editorApp).toBeDefined(); + deferred.resolve(); + }} + /> + ); + expect(await deferred.promise).toBeUndefined(); + + await delayExecution(hundredMs); + + const deferred2 = new Deferred(); + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: codeUpdated, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - - test('multiple editors in single render', async () => { - const editorAppConfig1 = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "FirstComponent";', - uri: `/workspace/first-${expect.getState().testPath}.js` - } - }); - const editorAppConfig2 = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "SecondComponent";', - uri: `/workspace/second-${expect.getState().testPath}.js` - } - }); - const firstComponentReady = new Deferred(); - const secondComponentReady = new Deferred(); - const renderResult = render(<> - firstComponentReady.resolve()} - /> - secondComponentReady.resolve()} - /> - ); - - const promises = await Promise.all([firstComponentReady.promise, secondComponentReady.promise]); - expect(promises).toEqual([undefined, undefined]); - - await delayExecution(hundredMs); - - expect(renderResult.getAllByRole('code')[0].innerText).contains('FirstComponent'); - expect(renderResult.getAllByRole('code')[1].innerText).contains('SecondComponent'); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + renderResult.rerender( + { + expect(result.textUpdated).toBeTruthy(); + expect(result.modelUpdated).toBeFalsy(); + expect(result.editorApp).toBeDefined(); + expect(result.editorApp?.getEditor()?.getValue()).toBe(codeUpdated); + expect(result.editorApp?.getTextModels().modified?.getValue()).toBe(codeUpdated); + deferred2.resolve(); + }} + /> + ); + expect(await deferred2.promise).toBeUndefined(); + await delayExecution(hundredMs); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, unmount and render new', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: code, + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test('test render, modify code', async () => { - const deferredStart = new Deferred(); - const deferredChanged = new Deferred(); - const deferredConfigUpdate = new Deferred(); - let modified; - let count = 0; - - const App = () => { - const [codeState, setCodeState] = useState(code); - const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); - - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: codeState, - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - return ( - <> - - { - modified = textChanges.modified; - count++; - console.log(`count: ${count} text: ${modified}`); - if (codeUpdated === modified) { - deferredChanged.resolve(); - } - }} - triggerReprocessConfig={triggerReprocessConfig} - onConfigProcessed={(result) => { - expect(result.textUpdated).toBeTruthy(); - expect(result.modelUpdated).toBeFalsy(); - deferredConfigUpdate.resolve(); - }} - onEditorStartDone={() => deferredStart.resolve()} - /> - - ); - }; - const renderResult = render(); - expect(await deferredStart.promise).toBeUndefined(); - - // delay execute/click, so await below is already awaiting the deferredDispose - setTimeout(() => { - document.getElementById('change-button')?.click(); - }, hundredMs); - - expect(await Promise.all([deferredChanged.promise, deferredConfigUpdate.promise])).toStrictEqual([undefined, undefined]); - // one time code, then update - expect(count).toBe(2); - - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + let renderResult: RenderResult | undefined; + const deferred = new Deferred(); + renderResult = render( + deferred.resolve()} + /> + ); + expect(await deferred.promise).toBeUndefined(); + + await delayExecution(hundredMs); + renderResult.unmount(); + cleanHtmlBody(); + + const deferred2 = new Deferred(); + renderResult = render( + deferred2.resolve()} + /> + ); + expect(await deferred2.promise).toBeUndefined(); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('multiple editors in single render', async () => { + const editorAppConfig1 = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "FirstComponent";', + uri: `/workspace/first-${expect.getState().testPath}.js` + } }); - + const editorAppConfig2 = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "SecondComponent";', + uri: `/workspace/second-${expect.getState().testPath}.js` + } + }); + const firstComponentReady = new Deferred(); + const secondComponentReady = new Deferred(); + const renderResult = render( + <> + firstComponentReady.resolve()} + /> + secondComponentReady.resolve()} + /> + + ); + + const promises = await Promise.all([firstComponentReady.promise, secondComponentReady.promise]); + expect(promises).toEqual([undefined, undefined]); + + await delayExecution(hundredMs); + + expect(renderResult.getAllByRole('code')[0].innerText).contains('FirstComponent'); + expect(renderResult.getAllByRole('code')[1].innerText).contains('SecondComponent'); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); + + test('test render, modify code', async () => { + const deferredStart = new Deferred(); + const deferredChanged = new Deferred(); + const deferredConfigUpdate = new Deferred(); + let modified; + let count = 0; + + const App = () => { + const [codeState, setCodeState] = useState(code); + const [triggerReprocessConfig, setTriggerReprocessConfig] = useState(0); + + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: codeState, + uri: `/workspace/${expect.getState().testPath}.js` + } + }); + + return ( + <> + + { + modified = textChanges.modified; + count++; + console.log(`count: ${count} text: ${modified}`); + if (codeUpdated === modified) { + deferredChanged.resolve(); + } + }} + triggerReprocessConfig={triggerReprocessConfig} + onConfigProcessed={(result) => { + expect(result.textUpdated).toBeTruthy(); + expect(result.modelUpdated).toBeFalsy(); + deferredConfigUpdate.resolve(); + }} + onEditorStartDone={() => deferredStart.resolve()} + /> + + ); + }; + const renderResult = render(); + expect(await deferredStart.promise).toBeUndefined(); + + // delay execute/click, so await below is already awaiting the deferredDispose + setTimeout(() => { + document.getElementById('change-button')?.click(); + }, hundredMs); + + expect(await Promise.all([deferredChanged.promise, deferredConfigUpdate.promise])).toStrictEqual([undefined, undefined]); + // one time code, then update + expect(count).toBe(2); + + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); }); diff --git a/packages/wrapper-react/test/index.viewsservice.test.tsx b/packages/wrapper-react/test/index.viewsservice.test.tsx index 04800051c..67ce2c4fe 100644 --- a/packages/wrapper-react/test/index.viewsservice.test.tsx +++ b/packages/wrapper-react/test/index.viewsservice.test.tsx @@ -12,59 +12,62 @@ import { describe, expect, test } from 'vitest'; import { cleanHtmlBody, createDefaultEditorAppConfig, hundredMs } from './support/helper.js'; describe('Test MonacoEditorReactComp', () => { + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'ViewsService' + } + }; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'ViewsService' - } - }; + test.sequential('views service: no HTMLElement', async () => { + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } + }); - test.sequential('views service: no HTMLElement', async () => { - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); + const deferred = new Deferred(); + const renderResult = render( + { + expect(error.message).toEqual('View Service Type "ViewsService" requires a HTMLElement.'); + deferred.resolve(); + }} + /> + ); + expect(await deferred.promise).toBeUndefined(); - const deferred = new Deferred(); - const renderResult = render( { - expect(error.message).toEqual('View Service Type "ViewsService" requires a HTMLElement.'); - deferred.resolve(); - }} - />); - expect(await deferred.promise).toBeUndefined(); + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); + test.sequential('views service: HTMLElement', async () => { + vscodeApiConfig.viewsConfig.htmlContainer = document.createElement('div'); + const editorAppConfig = createDefaultEditorAppConfig({ + modified: { + text: 'const text = "Hello World!";', + uri: `/workspace/${expect.getState().testPath}.js` + } }); - test.sequential('views service: HTMLElement', async () => { - vscodeApiConfig.viewsConfig.htmlContainer = document.createElement('div'); - const editorAppConfig = createDefaultEditorAppConfig({ - modified: { - text: 'const text = "Hello World!";', - uri: `/workspace/${expect.getState().testPath}.js` - } - }); - - const deferred = new Deferred(); - const renderResult = render( deferred.resolve()} - />); - expect(await deferred.promise).toBeUndefined(); + const deferred = new Deferred(); + const renderResult = render( + deferred.resolve()} + /> + ); + expect(await deferred.promise).toBeUndefined(); - renderResult.unmount(); - cleanHtmlBody(); - await delayExecution(hundredMs); - }); + renderResult.unmount(); + cleanHtmlBody(); + await delayExecution(hundredMs); + }); }); diff --git a/packages/wrapper-react/test/support/helper.ts b/packages/wrapper-react/test/support/helper.ts index 49ae26559..1df122e3d 100644 --- a/packages/wrapper-react/test/support/helper.ts +++ b/packages/wrapper-react/test/support/helper.ts @@ -9,40 +9,44 @@ import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; import { MessageTransports } from 'vscode-languageclient'; export const createDefaultEditorAppConfig = (codeResources: CodeResources, logLevel?: LogLevel): EditorAppConfig => { - return { - logLevel, - codeResources - }; + return { + logLevel, + codeResources + }; }; -export const createDefaultLcWorkerConfig = (worker: Worker, languageId: string, messageTransports?: MessageTransports): LanguageClientConfig => { - return { - languageId, - clientOptions: { - documentSelector: [languageId] - }, - connection: { - options: { - $type: 'WorkerDirect', - worker - }, - messageTransports - } - }; +export const createDefaultLcWorkerConfig = ( + worker: Worker, + languageId: string, + messageTransports?: MessageTransports +): LanguageClientConfig => { + return { + languageId, + clientOptions: { + documentSelector: [languageId] + }, + connection: { + options: { + $type: 'WorkerDirect', + worker + }, + messageTransports + } + }; }; export const createDefaultLanguageClientConfig = (): LanguageClientConfig => { - const workerUrl = new URL('monaco-languageclient-examples/worker/langium', import.meta.url); - const worker = new Worker(workerUrl, { - type: 'module', - name: 'Langium LS (React Test)' - }); - return createDefaultLcWorkerConfig(worker, 'langium'); + const workerUrl = new URL('monaco-languageclient-examples/worker/langium', import.meta.url); + const worker = new Worker(workerUrl, { + type: 'module', + name: 'Langium LS (React Test)' + }); + return createDefaultLcWorkerConfig(worker, 'langium'); }; export const hundredMs = 100; export const cleanHtmlBody = () => { - // manual clean document body - document.body.innerHTML = ''; + // manual clean document body + document.body.innerHTML = ''; }; diff --git a/packages/wrapper-react/tsconfig.json b/packages/wrapper-react/tsconfig.json index 050f9f4ed..4538590b1 100644 --- a/packages/wrapper-react/tsconfig.json +++ b/packages/wrapper-react/tsconfig.json @@ -5,8 +5,5 @@ "noEmit": true, "rootDir": "." }, - "include": [ - "src/**/*", - "test/**/*" - ] + "include": ["src/**/*", "test/**/*"] } diff --git a/packages/wrapper-react/tsconfig.src.json b/packages/wrapper-react/tsconfig.src.json index eef63ce89..31795aac2 100644 --- a/packages/wrapper-react/tsconfig.src.json +++ b/packages/wrapper-react/tsconfig.src.json @@ -6,11 +6,10 @@ "outDir": "lib", "declarationDir": "lib" }, - "references": [{ - "path": "../client/tsconfig.src.json" - }], - "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ] + "references": [ + { + "path": "../client/tsconfig.src.json" + } + ], + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/packages/wrapper-react/tsconfig.test.json b/packages/wrapper-react/tsconfig.test.json index b3ee8ba7a..542106264 100644 --- a/packages/wrapper-react/tsconfig.test.json +++ b/packages/wrapper-react/tsconfig.test.json @@ -4,11 +4,10 @@ "noEmit": true, "rootDir": "test" }, - "references": [{ - "path": "./tsconfig.src.json" - }], - "include": [ - "test/**/*.ts", - "test/**/*.tsx", - ] + "references": [ + { + "path": "./tsconfig.src.json" + } + ], + "include": ["test/**/*.ts", "test/**/*.tsx"] } diff --git a/scripts/addlicense/docker-compose.yml b/scripts/addlicense/docker-compose.yml index e0280d7ff..31a5e1c66 100644 --- a/scripts/addlicense/docker-compose.yml +++ b/scripts/addlicense/docker-compose.yml @@ -15,7 +15,8 @@ services: working_dir: /workspace volumes: - ../..:/workspace - command: [ "/bin/sh", "-c", "addlicense -v -check -f ./LICENSE.header packages/**/*.ts* packages/**/*.js* verify/**/*.ts* verify/**/*.js*"] + command: + ['/bin/sh', '-c', 'addlicense -v -check -f ./LICENSE.header packages/**/*.ts* packages/**/*.js* verify/**/*.ts* verify/**/*.js*'] addlicense-add: depends_on: @@ -25,11 +26,11 @@ services: working_dir: /workspace volumes: - ../..:/workspace - command: [ "/bin/sh", "-c", "addlicense -v -f ./LICENSE.header packages/**/*.ts* packages/**/*.js* verify/**/*.ts* verify/**/*.js*"] + command: ['/bin/sh', '-c', 'addlicense -v -f ./LICENSE.header packages/**/*.ts* packages/**/*.js* verify/**/*.ts* verify/**/*.js*'] addlicense-help: image: addlicense-builder depends_on: - addlicense-builder container_name: addlicense-help - command: [ "/bin/sh", "-c", "addlicense -h" ] + command: ['/bin/sh', '-c', 'addlicense -h'] diff --git a/scripts/clean.ts b/scripts/clean.ts index db945793d..efbac02e4 100644 --- a/scripts/clean.ts +++ b/scripts/clean.ts @@ -8,74 +8,74 @@ import { minimatch } from 'minimatch'; import { getPathRelativeToRootDirectory } from './helper'; const printHelp = () => { - console.log('\nUse:'); - console.log('--relativePath [--recursive] --paths [paths]\n'); + console.log('\nUse:'); + console.log('--relativePath [--recursive] --paths [paths]\n'); }; const relativePathArg = process.argv[2] as string | undefined; if (relativePathArg !== '--relativePath') { - printHelp(); - process.exit(0); + printHelp(); + process.exit(0); } const relativePath = process.argv[3] as string | undefined; if (relativePath === undefined) { - printHelp(); - process.exit(0); + printHelp(); + process.exit(0); } const workingDir = getPathRelativeToRootDirectory(relativePath); const statsWorkingDir = fs.lstatSync(workingDir); if (!statsWorkingDir.isDirectory()) { - console.error(`Provided working directory is not a directory: ${workingDir}`); - process.exit(0); + console.error(`Provided working directory is not a directory: ${workingDir}`); + process.exit(0); } const recursiveArg = process.argv[4] as string | undefined; -const recursive = (recursiveArg === '--recursive'); +const recursive = recursiveArg === '--recursive'; const pathsArg = recursive ? process.argv[5] : process.argv[4]; if (pathsArg === '--paths') { - const start = recursive ? 6 : 5; - const end = process.argv.length; - if (start >= end) { - console.log('No paths provided after --paths.'); - printHelp(); - } + const start = recursive ? 6 : 5; + const end = process.argv.length; + if (start >= end) { + console.log('No paths provided after --paths.'); + printHelp(); + } - for (let i = start; i < end; i++) { - const input = process.argv[i]; + for (let i = start; i < end; i++) { + const input = process.argv[i]; - const pathToDelete = getPathRelativeToRootDirectory(relativePath, input); - if (fs.existsSync(pathToDelete)) { - const stats = fs.lstatSync(pathToDelete); - if (stats.isDirectory()) { - if (recursive) { - console.log(`Deleting directory: ${pathToDelete}`); - } else { - console.log(`Deleting directory recursively: ${pathToDelete}`); - } - fs.rmSync(pathToDelete, { recursive: recursive }); - // console.log(`Would execute: fs.rmSync(${pathToDelete}, { recursive: ${recursive} })`); - } else if (stats.isFile()) { - console.log(`Deleting file: ${pathToDelete}`); - fs.rmSync(pathToDelete); - // console.log(`Would execute: fs.rmSync(${pathToDelete})`); - } else { - console.log(`Path is not a file or directory: ${pathToDelete}`); - } - } else if (input.includes('*')) { - const list = fs.readdirSync(workingDir).filter(minimatch.filter(input, { matchBase: true })); - for (const file of list) { - console.log(`Deleting file: ${file}`); - fs.rmSync(file); - // console.log(`Would execute: fs.rmSync(${file})`); - } + const pathToDelete = getPathRelativeToRootDirectory(relativePath, input); + if (fs.existsSync(pathToDelete)) { + const stats = fs.lstatSync(pathToDelete); + if (stats.isDirectory()) { + if (recursive) { + console.log(`Deleting directory: ${pathToDelete}`); } else { - console.error(`Provided path does not exist: ${pathToDelete}`); + console.log(`Deleting directory recursively: ${pathToDelete}`); } + fs.rmSync(pathToDelete, { recursive: recursive }); + // console.log(`Would execute: fs.rmSync(${pathToDelete}, { recursive: ${recursive} })`); + } else if (stats.isFile()) { + console.log(`Deleting file: ${pathToDelete}`); + fs.rmSync(pathToDelete); + // console.log(`Would execute: fs.rmSync(${pathToDelete})`); + } else { + console.log(`Path is not a file or directory: ${pathToDelete}`); + } + } else if (input.includes('*')) { + const list = fs.readdirSync(workingDir).filter(minimatch.filter(input, { matchBase: true })); + for (const file of list) { + console.log(`Deleting file: ${file}`); + fs.rmSync(file); + // console.log(`Would execute: fs.rmSync(${file})`); + } + } else { + console.error(`Provided path does not exist: ${pathToDelete}`); } + } } else { - if (recursive) { - console.log('No --paths argument provided after --recursive.'); - } - printHelp(); + if (recursive) { + console.log('No --paths argument provided after --recursive.'); + } + printHelp(); } diff --git a/scripts/helper.ts b/scripts/helper.ts index 7828ba129..598247813 100644 --- a/scripts/helper.ts +++ b/scripts/helper.ts @@ -10,18 +10,18 @@ import * as url from 'node:url'; * Solves: __dirname is not defined in ES module scope */ export function getLocalDirectory() { - const __filename = url.fileURLToPath(import.meta.url); - return path.dirname(__filename); + const __filename = url.fileURLToPath(import.meta.url); + return path.dirname(__filename); } export function getRootDirectory() { - return path.resolve(getLocalDirectory(), '..'); + return path.resolve(getLocalDirectory(), '..'); } export function getPathRelativeToRootDirectory(relativePath: string, pathToDelete?: string) { - if (pathToDelete === undefined) { - return path.resolve(getRootDirectory(), relativePath); - } else { - return path.resolve(getRootDirectory(), relativePath, pathToDelete); - } + if (pathToDelete === undefined) { + return path.resolve(getRootDirectory(), relativePath); + } else { + return path.resolve(getRootDirectory(), relativePath, pathToDelete); + } } diff --git a/tsconfig.build.json b/tsconfig.build.json index e6860273b..c23a0f708 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,11 +1,11 @@ { "files": [], "references": [ - { "path": "./packages/vscode-ws-jsonrpc/tsconfig.src.json" }, - { "path": "./packages/client/tsconfig.src.json" }, - { "path": "./packages/client/tsconfig.test.json" }, - { "path": "./packages/wrapper-react/tsconfig.src.json" }, - { "path": "./packages/wrapper-react/tsconfig.test.json" }, - { "path": "./packages/examples/tsconfig.src.json" } + { "path": "./packages/vscode-ws-jsonrpc/tsconfig.src.json" }, + { "path": "./packages/client/tsconfig.src.json" }, + { "path": "./packages/client/tsconfig.test.json" }, + { "path": "./packages/wrapper-react/tsconfig.src.json" }, + { "path": "./packages/wrapper-react/tsconfig.test.json" }, + { "path": "./packages/examples/tsconfig.src.json" } ] } diff --git a/tsconfig.json b/tsconfig.json index 98cd1faee..e4e166dd8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,9 @@ - { +{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", - "lib": [ - "ES2022", - "DOM", - "DOM.Iterable" - ], + "lib": ["ES2022", "DOM", "DOM.Iterable"], // esModuleInterop=true sets allowSyntheticDefaultImports=true, "esModuleInterop": true, "resolveJsonModule": true, @@ -45,11 +41,7 @@ "**/build/**/*.mts", "*.js", "*.ts", - "*.d.ts", + "*.d.ts" ], - "exclude": [ - "dist/**/*", - "lib/**/*", - "node_modules/**/*" - ] + "exclude": ["dist/**/*", "lib/**/*", "node_modules/**/*"] } diff --git a/verify/angular/angular.json b/verify/angular/angular.json index 23a815943..8e8ac812d 100644 --- a/verify/angular/angular.json +++ b/verify/angular/angular.json @@ -18,9 +18,7 @@ "options": { "browser": "src/main.ts", "tsConfig": "tsconfig.json", - "polyfills": [ - "zone.js" - ], + "polyfills": ["zone.js"], "assets": [ { "glob": "**/*", diff --git a/verify/angular/index.html b/verify/angular/index.html index fb0942428..11a1e7499 100644 --- a/verify/angular/index.html +++ b/verify/angular/index.html @@ -1,16 +1,14 @@ - + + + + Angular Example + + + - - - Angular Example - - - - - - - - - + + + + diff --git a/verify/angular/package.json b/verify/angular/package.json index 0443faeac..3bc516f21 100644 --- a/verify/angular/package.json +++ b/verify/angular/package.json @@ -19,12 +19,12 @@ "@angular/compiler": "^21.1.0", "@angular/core": "^21.1.0", "@angular/platform-browser": "^21.1.0", - "@codingame/monaco-vscode-api": "^26.2.1", - "@codingame/monaco-vscode-files-service-override": "^26.2.1", - "@codingame/monaco-vscode-json-default-extension": "^26.2.1", + "@codingame/monaco-vscode-api": "^26.2.2", + "@codingame/monaco-vscode-files-service-override": "^26.2.2", + "@codingame/monaco-vscode-json-default-extension": "^26.2.2", "monaco-languageclient": "~10.7.0", "rxjs": "~7.8.2", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "zone.js": "^0.16.0" }, "devDependencies": { @@ -34,9 +34,9 @@ "@angular/compiler-cli": "^21.1.0", "@codingame/esbuild-import-meta-url-plugin": "~1.0.3", "@types/node": "~24.10.10", - "vite": "~7.3.1", "shx": "~0.4.0", - "typescript": "~5.9.3" + "typescript": "~5.9.3", + "vite": "~7.3.1" }, "volta": { "node": "24.13.0", diff --git a/verify/angular/src/app/app.component.css b/verify/angular/src/app/app.component.css index 3a7e0476d..ac351fe89 100644 --- a/verify/angular/src/app/app.component.css +++ b/verify/angular/src/app/app.component.css @@ -1,3 +1,3 @@ .monaco-editor { - height: 50vh; + height: 50vh; } diff --git a/verify/angular/src/app/app.component.html b/verify/angular/src/app/app.component.html index a86adb4fd..1d106d960 100644 --- a/verify/angular/src/app/app.component.html +++ b/verify/angular/src/app/app.component.html @@ -1,4 +1,4 @@

Monaco Language Client Angular Client Example

-
+
diff --git a/verify/angular/src/app/app.component.ts b/verify/angular/src/app/app.component.ts index a6e4229e2..c1aa01b29 100644 --- a/verify/angular/src/app/app.component.ts +++ b/verify/angular/src/app/app.component.ts @@ -6,7 +6,11 @@ import { type AfterViewInit, Component } from '@angular/core'; // import { runExtendedClient } from '../../production/mlc-bundle.js'; -import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; +import { + RegisteredFileSystemProvider, + RegisteredMemoryFile, + registerFileSystemOverlay +} from '@codingame/monaco-vscode-files-service-override'; import * as vscode from 'vscode'; import { LogLevel } from '@codingame/monaco-vscode-api'; @@ -18,90 +22,90 @@ import { MonacoVscodeApiWrapper, type MonacoVscodeApiConfig } from 'monaco-langu import { configureDefaultWorkerFactory } from 'monaco-languageclient/workerFactory'; @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'], - standalone: true + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'], + standalone: true }) export class MonacoEditorComponent implements AfterViewInit { - title = 'angular-client'; - initDone = false; + title = 'angular-client'; + initDone = false; - async ngAfterViewInit(): Promise { - await runExtendedClient(); - } + async ngAfterViewInit(): Promise { + await runExtendedClient(); + } } export const runExtendedClient = async () => { - const lsConfig = { - port: 30000, - path: '/sampleServer', - basePath: '/home/mlc/packages/examples/resources/json', - languageId: 'json' - }; - const helloCode = `{ + const lsConfig = { + port: 30000, + path: '/sampleServer', + basePath: '/home/mlc/packages/examples/resources/json', + languageId: 'json' + }; + const helloCode = `{ "$schema": "http://json.schemastore.org/coffeelint", "line_endings": {"value": "unix"} }`; - const helloUri = vscode.Uri.file(`${lsConfig.basePath}/workspace/hello.${lsConfig.languageId}`); - const fileSystemProvider = new RegisteredFileSystemProvider(false); - fileSystemProvider.registerFile(new RegisteredMemoryFile(helloUri, helloCode)); - registerFileSystemOverlay(1, fileSystemProvider); + const helloUri = vscode.Uri.file(`${lsConfig.basePath}/workspace/hello.${lsConfig.languageId}`); + const fileSystemProvider = new RegisteredFileSystemProvider(false); + fileSystemProvider.registerFile(new RegisteredMemoryFile(helloUri, helloCode)); + registerFileSystemOverlay(1, fileSystemProvider); - const htmlContainer = document.getElementById('monaco-editor-root')!; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: 'extended', - viewsConfig: { - $type: 'EditorService', - htmlContainer - }, - logLevel: LogLevel.Debug, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.experimental.asyncTokenization': true - }) - }, - monacoWorkerFactory: configureDefaultWorkerFactory - }; + const htmlContainer = document.getElementById('monaco-editor-root')!; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: 'extended', + viewsConfig: { + $type: 'EditorService', + htmlContainer + }, + logLevel: LogLevel.Debug, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.experimental.asyncTokenization': true + }) + }, + monacoWorkerFactory: configureDefaultWorkerFactory + }; - const languageClientConfig: LanguageClientConfig = { - languageId: lsConfig.languageId, - connection: { - options: { - $type: 'WebSocketUrl', - url: `ws://localhost:${lsConfig.port}${lsConfig.path}`, - } - }, - clientOptions: { - documentSelector: [lsConfig.languageId], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.parse(`${lsConfig.basePath}/workspace`) - } - } - }; + const languageClientConfig: LanguageClientConfig = { + languageId: lsConfig.languageId, + connection: { + options: { + $type: 'WebSocketUrl', + url: `ws://localhost:${lsConfig.port}${lsConfig.path}` + } + }, + clientOptions: { + documentSelector: [lsConfig.languageId], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.parse(`${lsConfig.basePath}/workspace`) + } + } + }; - const editorAppConfig: EditorAppConfig = { - codeResources: { - modified: { - text: helloCode, - uri: helloUri.path - } - } - }; + const editorAppConfig: EditorAppConfig = { + codeResources: { + modified: { + text: helloCode, + uri: helloUri.path + } + } + }; - // perform global init - const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); - await apiWrapper.start(); + // perform global init + const apiWrapper = new MonacoVscodeApiWrapper(vscodeApiConfig); + await apiWrapper.start(); - const lcWrapper = new LanguageClientWrapper(languageClientConfig); - const editorApp = new EditorApp(editorAppConfig); + const lcWrapper = new LanguageClientWrapper(languageClientConfig); + const editorApp = new EditorApp(editorAppConfig); - await editorApp.start(htmlContainer); - await lcWrapper.start(); + await editorApp.start(htmlContainer); + await lcWrapper.start(); - // open files, so the LS can pick it up - await vscode.workspace.openTextDocument(helloUri); + // open files, so the LS can pick it up + await vscode.workspace.openTextDocument(helloUri); }; diff --git a/verify/angular/tsconfig.app.json b/verify/angular/tsconfig.app.json index 16f3486e6..a4f1dc9cd 100644 --- a/verify/angular/tsconfig.app.json +++ b/verify/angular/tsconfig.app.json @@ -4,10 +4,7 @@ "target": "ES2022", "module": "ES2022", "moduleResolution": "Bundler", - "lib": [ - "ES2022", - "DOM", - ], + "lib": ["ES2022", "DOM"], // esModuleInterop=true sets allowSyntheticDefaultImports=true, "esModuleInterop": true, "resolveJsonModule": true, @@ -42,12 +39,6 @@ "strictInputAccessModifiers": true, "strictTemplates": true }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "dist", - "node_modules", - "src/server/**/*.ts" - ] + "include": ["src/**/*.ts"], + "exclude": ["dist", "node_modules", "src/server/**/*.ts"] } diff --git a/verify/angular/vite.config.ts b/verify/angular/vite.config.ts index 969970278..dcb8a19d4 100644 --- a/verify/angular/vite.config.ts +++ b/verify/angular/vite.config.ts @@ -9,46 +9,42 @@ import path from 'path'; import { defineConfig } from 'vite'; export default defineConfig(({ command }) => { - console.log(`Running: ${command}`); - return { - build: { - emptyOutDir: true, - assetsInlineLimit: 0, - outDir: path.resolve(__dirname, 'production') - }, - worker: { - format: 'es' - }, - esbuild: { - minifySyntax: false - }, - plugins: [ - angular() - ], - optimizeDeps: { - esbuildOptions: { - plugins: [ - importMetaUrlPlugin - ] - }, - include: [ - 'vscode/localExtensionHost', - 'vscode-jsonrpc', - 'vscode-languageclient', - 'vscode-languageserver', - 'vscode-languageserver/browser.js', - 'vscode-languageserver-protocol' - ] - }, - server: { - port: 8084, - cors: { - origin: '*' - }, - headers: { - 'Cross-Origin-Opener-Policy': 'same-origin', - 'Cross-Origin-Embedder-Policy': 'require-corp', - } - }, - }; + console.log(`Running: ${command}`); + return { + build: { + emptyOutDir: true, + assetsInlineLimit: 0, + outDir: path.resolve(__dirname, 'production') + }, + worker: { + format: 'es' + }, + esbuild: { + minifySyntax: false + }, + plugins: [angular()], + optimizeDeps: { + esbuildOptions: { + plugins: [importMetaUrlPlugin] + }, + include: [ + 'vscode/localExtensionHost', + 'vscode-jsonrpc', + 'vscode-languageclient', + 'vscode-languageserver', + 'vscode-languageserver/browser.js', + 'vscode-languageserver-protocol' + ] + }, + server: { + port: 8084, + cors: { + origin: '*' + }, + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp' + } + } + }; }); diff --git a/verify/next/app/langium-dsl/config/extendedConfig.ts b/verify/next/app/langium-dsl/config/extendedConfig.ts index 091aa32c3..da2baa7d7 100644 --- a/verify/next/app/langium-dsl/config/extendedConfig.ts +++ b/verify/next/app/langium-dsl/config/extendedConfig.ts @@ -11,173 +11,180 @@ import type { LanguageClientConfig } from 'monaco-languageclient/lcwrapper'; import type { MonacoVscodeApiConfig, OverallConfigType } from 'monaco-languageclient/vscodeApiWrapper'; export type ExampleAppConfig = { - vscodeApiConfig: MonacoVscodeApiConfig; - languageClientConfig: LanguageClientConfig; - editorAppConfig: EditorAppConfig; - MonacoEditorReactComp: React.FC; + vscodeApiConfig: MonacoVscodeApiConfig; + languageClientConfig: LanguageClientConfig; + editorAppConfig: EditorAppConfig; + MonacoEditorReactComp: React.FC; }; -export const setupLangiumClientExtended = async (languageServerWorker: Worker, enableExtHostWorker: boolean, vscodeApiWorkerFactory: (logger?: ILogger) => void): Promise => { - - // perform all imports dynamically - const getKeybindingsServiceOverride = (await import('@codingame/monaco-vscode-keybindings-service-override')).default; - const { InMemoryFileSystemProvider, registerFileSystemOverlay } = (await import('@codingame/monaco-vscode-files-service-override')); - const { LogLevel } = (await import('@codingame/monaco-vscode-api')); - const { Uri } = (await import('vscode')); - const { BrowserMessageReader, BrowserMessageWriter } = (await import('vscode-languageclient/browser.js')); - - // base configurration - const overallConfigType: OverallConfigType = 'extended'; - const langiumLanguageConfigResponse = await fetch(new URL('./langium.configuration.json', import.meta.url)); - const langiumLanguageConfig = await langiumLanguageConfigResponse.text(); - const langiumTextmateGrammarResponse = await fetch(new URL('./langium.tmLanguage.json', import.meta.url)); - const langiumTextmateGrammar = await langiumTextmateGrammarResponse.text(); - - const extensionFilesOrContents = new Map(); - extensionFilesOrContents.set('/workspace/langium-configuration.json', langiumLanguageConfig); - extensionFilesOrContents.set('/workspace/langium-grammar.json', langiumTextmateGrammar); - - // prepare all resources that should be preloaded - const exampleLangiumResponse = await fetch(new URL('./langium-grammar.langium', import.meta.url)); - const exampleLangium = await exampleLangiumResponse.text(); - const langiumTypesResponse = await fetch(new URL('./langium-types.langium', import.meta.url)); - const langiumTypesLangium = await langiumTypesResponse.text(); - - const workspaceUri = Uri.file('/workspace'); - const langiumGrammarLangiumUri = Uri.file('/workspace/langium-grammar.langium'); - const langiumTypesLangiumUri = Uri.file('/workspace/langium-types.langium'); - const tsCodeUri = Uri.file('/workspace/hello.ts'); - const fileSystemProvider = new InMemoryFileSystemProvider(); - const textEncoder = new TextEncoder(); - - const code = `const takesString = (x: string) => {}; +export const setupLangiumClientExtended = async ( + languageServerWorker: Worker, + enableExtHostWorker: boolean, + vscodeApiWorkerFactory: (logger?: ILogger) => void +): Promise => { + // perform all imports dynamically + const getKeybindingsServiceOverride = (await import('@codingame/monaco-vscode-keybindings-service-override')).default; + const { InMemoryFileSystemProvider, registerFileSystemOverlay } = await import('@codingame/monaco-vscode-files-service-override'); + const { LogLevel } = await import('@codingame/monaco-vscode-api'); + const { Uri } = await import('vscode'); + const { BrowserMessageReader, BrowserMessageWriter } = await import('vscode-languageclient/browser.js'); + + // base configurration + const overallConfigType: OverallConfigType = 'extended'; + const langiumLanguageConfigResponse = await fetch(new URL('./langium.configuration.json', import.meta.url)); + const langiumLanguageConfig = await langiumLanguageConfigResponse.text(); + const langiumTextmateGrammarResponse = await fetch(new URL('./langium.tmLanguage.json', import.meta.url)); + const langiumTextmateGrammar = await langiumTextmateGrammarResponse.text(); + + const extensionFilesOrContents = new Map(); + extensionFilesOrContents.set('/workspace/langium-configuration.json', langiumLanguageConfig); + extensionFilesOrContents.set('/workspace/langium-grammar.json', langiumTextmateGrammar); + + // prepare all resources that should be preloaded + const exampleLangiumResponse = await fetch(new URL('./langium-grammar.langium', import.meta.url)); + const exampleLangium = await exampleLangiumResponse.text(); + const langiumTypesResponse = await fetch(new URL('./langium-types.langium', import.meta.url)); + const langiumTypesLangium = await langiumTypesResponse.text(); + + const workspaceUri = Uri.file('/workspace'); + const langiumGrammarLangiumUri = Uri.file('/workspace/langium-grammar.langium'); + const langiumTypesLangiumUri = Uri.file('/workspace/langium-types.langium'); + const tsCodeUri = Uri.file('/workspace/hello.ts'); + const fileSystemProvider = new InMemoryFileSystemProvider(); + const textEncoder = new TextEncoder(); + + const code = `const takesString = (x: string) => {}; // you should see an error marker in the next line takesString(0);`; - const options: IFileWriteOptions = { - atomic: false, - unlock: false, - create: true, - overwrite: true - }; - await fileSystemProvider.mkdir(workspaceUri); - await fileSystemProvider.writeFile(langiumGrammarLangiumUri, textEncoder.encode(exampleLangium), options); - await fileSystemProvider.writeFile(langiumTypesLangiumUri, textEncoder.encode(langiumTypesLangium), options); - await fileSystemProvider.writeFile(tsCodeUri, textEncoder.encode(code), options); - registerFileSystemOverlay(1, fileSystemProvider); - - const editorAppConfig: EditorAppConfig = {}; - const reader = new BrowserMessageReader(languageServerWorker); - const writer = new BrowserMessageWriter(languageServerWorker); - - const innerHtml = `
+ const options: IFileWriteOptions = { + atomic: false, + unlock: false, + create: true, + overwrite: true + }; + await fileSystemProvider.mkdir(workspaceUri); + await fileSystemProvider.writeFile(langiumGrammarLangiumUri, textEncoder.encode(exampleLangium), options); + await fileSystemProvider.writeFile(langiumTypesLangiumUri, textEncoder.encode(langiumTypesLangium), options); + await fileSystemProvider.writeFile(tsCodeUri, textEncoder.encode(code), options); + registerFileSystemOverlay(1, fileSystemProvider); + + const editorAppConfig: EditorAppConfig = {}; + const reader = new BrowserMessageReader(languageServerWorker); + const writer = new BrowserMessageWriter(languageServerWorker); + + const innerHtml = `
`; - const viewsInit = async () => { - const { Parts, onPartVisibilityChange, isPartVisibile, attachPart, } = await import('@codingame/monaco-vscode-views-service-override'); - - for (const config of [ - { part: Parts.EDITOR_PART, element: '#editors' }, - ]) { - attachPart(config.part, document.querySelector(config.element)!); - - if (!isPartVisibile(config.part)) { - document.querySelector(config.element)!.style.display = 'none'; - } - - onPartVisibilityChange(config.part, visible => { - document.querySelector(config.element)!.style.display = visible ? 'block' : 'none'; - }); - } - }; - const vscodeApiConfig: MonacoVscodeApiConfig = { - $type: overallConfigType, - logLevel: LogLevel.Debug, - advanced: { - enableExtHostWorker + const viewsInit = async () => { + const { Parts, onPartVisibilityChange, isPartVisibile, attachPart } = await import('@codingame/monaco-vscode-views-service-override'); + + for (const config of [{ part: Parts.EDITOR_PART, element: '#editors' }]) { + attachPart(config.part, document.querySelector(config.element)!); + + if (!isPartVisibile(config.part)) { + document.querySelector(config.element)!.style.display = 'none'; + } + + onPartVisibilityChange(config.part, (visible) => { + document.querySelector(config.element)!.style.display = visible ? 'block' : 'none'; + }); + } + }; + const vscodeApiConfig: MonacoVscodeApiConfig = { + $type: overallConfigType, + logLevel: LogLevel.Debug, + advanced: { + enableExtHostWorker + }, + serviceOverrides: { + ...getKeybindingsServiceOverride() + }, + viewsConfig: { + $type: 'ViewsService', + htmlContainer: document.getElementById('monaco-editor-root')!, + htmlAugmentationInstructions: (htmlElement: HTMLElement | null | undefined) => { + const htmlContainer = document.createElement('div', { is: 'app' }); + htmlContainer.innerHTML = innerHtml; + htmlElement?.append(htmlContainer); + }, + viewsInitFunc: viewsInit + }, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off', + 'editor.experimental.asyncTokenization': true, + 'vitest.disableWorkspaceWarning': true + }) + }, + monacoWorkerFactory: vscodeApiWorkerFactory, + extensions: [ + { + config: { + name: 'langium-example', + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [ + { + id: 'langium', + extensions: ['.langium'], + aliases: ['langium', 'LANGIUM'], + configuration: '/workspace/langium-configuration.json' + } + ], + grammars: [ + { + language: 'langium', + scopeName: 'source.langium', + path: '/workspace/langium-grammar.json' + } + ] + } }, - serviceOverrides: { - ...getKeybindingsServiceOverride() - }, - viewsConfig: { - $type: 'ViewsService', - htmlContainer: document.getElementById('monaco-editor-root')!, - htmlAugmentationInstructions: (htmlElement: HTMLElement | null | undefined) => { - const htmlContainer = document.createElement('div', { is: 'app' }); - htmlContainer.innerHTML = innerHtml; - htmlElement?.append(htmlContainer); - }, - viewsInitFunc: viewsInit - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off', - 'editor.experimental.asyncTokenization': true, - 'vitest.disableWorkspaceWarning': true - }) - }, - monacoWorkerFactory: vscodeApiWorkerFactory, - extensions: [{ - config: { - name: 'langium-example', - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - }, - contributes: { - languages: [{ - id: 'langium', - extensions: ['.langium'], - aliases: ['langium', 'LANGIUM'], - configuration: '/workspace/langium-configuration.json' - }], - grammars: [{ - language: 'langium', - scopeName: 'source.langium', - path: '/workspace/langium-grammar.json' - }] - } - }, - filesOrContents: extensionFilesOrContents - }] - }; - - const languageClientConfig: LanguageClientConfig = { - languageId: 'langium', - clientOptions: { - documentSelector: ['langium'] - }, - connection: { - options: { - $type: 'WorkerDirect', - worker: languageServerWorker - }, - messageTransports: { reader, writer } - } - }; - - const comp = await import('@typefox/monaco-editor-react'); - - return { - editorAppConfig, - vscodeApiConfig, - languageClientConfig, - MonacoEditorReactComp: comp.MonacoEditorReactComp - }; + filesOrContents: extensionFilesOrContents + } + ] + }; + + const languageClientConfig: LanguageClientConfig = { + languageId: 'langium', + clientOptions: { + documentSelector: ['langium'] + }, + connection: { + options: { + $type: 'WorkerDirect', + worker: languageServerWorker + }, + messageTransports: { reader, writer } + } + }; + + const comp = await import('@typefox/monaco-editor-react'); + + return { + editorAppConfig, + vscodeApiConfig, + languageClientConfig, + MonacoEditorReactComp: comp.MonacoEditorReactComp + }; }; export const openDocument = async (uri: string) => { - const { workspace } = (await import('vscode')); - await workspace.openTextDocument(uri); -} + const { workspace } = await import('vscode'); + await workspace.openTextDocument(uri); +}; export const showDocument = async (uri: string) => { - const { window, Uri } = (await import('vscode')); - await window.showTextDocument(Uri.file(uri)); -} + const { window, Uri } = await import('vscode'); + await window.showTextDocument(Uri.file(uri)); +}; export * as workerFactory from 'monaco-languageclient/workerFactory'; diff --git a/verify/next/app/langium-dsl/config/langium.configuration.json b/verify/next/app/langium-dsl/config/langium.configuration.json index d871c4b41..91326769b 100644 --- a/verify/next/app/langium-dsl/config/langium.configuration.json +++ b/verify/next/app/langium-dsl/config/langium.configuration.json @@ -1,134 +1,106 @@ { - "comments": { - "lineComment": "//", - "blockComment": ["/*", "*/"] + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { + "open": "'", + "close": "'", + "notIn": ["string", "comment"] }, - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "autoClosingPairs": [ - { "open": "{", "close": "}" }, - { "open": "[", "close": "]" }, - { "open": "(", "close": ")" }, - { - "open": "'", - "close": "'", - "notIn": [ - "string", - "comment" - ] - }, - { - "open": "\"", - "close": "\"", - "notIn": [ - "string" - ] - }, - { - "open": "/**", - "close": " */", - "notIn": [ - "string" - ] - } - ], - "autoCloseBefore": "}])`\n\t", - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "colorizedBracketPairs": [ - [ - "(", - ")" - ], - [ - "[", - "]" - ], - [ - "{", - "}" - ], - [ - "<", - ">" - ], - [ - "'", - "'" - ], - [ - "\"", - "\"" - ], - [ - "<", - ">" - ] - ], - "onEnterRules": [ - { - "": "// e.g. /** | */", - "beforeText": { - "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" - }, - "afterText": { - "pattern": "^\\s*\\*/$" - }, - "action": { - "indent": "indentOutdent", - "appendText": " * " - } - }, - { - "": "// e.g. /** ...|", - "beforeText": { - "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" - }, - "action": { - "indent": "none", - "appendText": " * " - } - }, - { - "": "// e.g. * ...|", - "beforeText": { - "pattern": "^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$" - }, - "previousLineText": { - "pattern": "(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))" - }, - "action": { - "indent": "none", - "appendText": "* " - } - }, - { - "": "// e.g. */|", - "beforeText": { - "pattern": "^(\\t|[ ])*[ ]\\*/\\s*$" - }, - "action": { - "indent": "none", - "removeText": 1 - } - }, - { - "beforeText": ":\\s*$", - "action": { - "indent": "indent" - } - }, - { - "beforeText": ";\\s*$", - "action": { - "indent": "outdent" - } - } - ] + { + "open": "\"", + "close": "\"", + "notIn": ["string"] + }, + { + "open": "/**", + "close": " */", + "notIn": ["string"] + } + ], + "autoCloseBefore": "}])`\n\t", + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "colorizedBracketPairs": [ + ["(", ")"], + ["[", "]"], + ["{", "}"], + ["<", ">"], + ["'", "'"], + ["\"", "\""], + ["<", ">"] + ], + "onEnterRules": [ + { + "": "// e.g. /** | */", + "beforeText": { + "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" + }, + "afterText": { + "pattern": "^\\s*\\*/$" + }, + "action": { + "indent": "indentOutdent", + "appendText": " * " + } + }, + { + "": "// e.g. /** ...|", + "beforeText": { + "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" + }, + "action": { + "indent": "none", + "appendText": " * " + } + }, + { + "": "// e.g. * ...|", + "beforeText": { + "pattern": "^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$" + }, + "previousLineText": { + "pattern": "(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))" + }, + "action": { + "indent": "none", + "appendText": "* " + } + }, + { + "": "// e.g. */|", + "beforeText": { + "pattern": "^(\\t|[ ])*[ ]\\*/\\s*$" + }, + "action": { + "indent": "none", + "removeText": 1 + } + }, + { + "beforeText": ":\\s*$", + "action": { + "indent": "indent" + } + }, + { + "beforeText": ";\\s*$", + "action": { + "indent": "outdent" + } + } + ] } diff --git a/verify/next/app/langium-dsl/config/langium.tmLanguage.json b/verify/next/app/langium-dsl/config/langium.tmLanguage.json index 256e47386..764f78328 100644 --- a/verify/next/app/langium-dsl/config/langium.tmLanguage.json +++ b/verify/next/app/langium-dsl/config/langium.tmLanguage.json @@ -1,290 +1,288 @@ { - "name": "Langium", - "scopeName": "source.langium", - "fileTypes": [ - "langium" - ], - "patterns": [ + "name": "Langium", + "scopeName": "source.langium", + "fileTypes": ["langium"], + "patterns": [ + { + "include": "#regex" + }, + { + "include": "#comments" + }, + { + "name": "keyword.control.langium", + "match": "\\b(left|right|assoc|current|entry|extends|fragment|grammar|hidden|import|infer|infers|infix|interface|returns|terminal|type|with|on)\\b" + }, + { + "name": "constant.language.langium", + "match": "\\b(?i:true|false)\\b" + }, + { + "name": "keyword.symbol.langium", + "match": "(\\{|\\}|\\:|\\]|\\[|\\(|\\)|(\\??|\\+?)\\=|->|\\=>|<|>|\\,|\\*|\\+|\\@|\\||\\&|\\?|\\!|\\;)" + }, + { + "name": "string.quoted.double.langium", + "begin": "\"", + "end": "\"", + "patterns": [ { - "include": "#regex" + "include": "#string-character-escape" + } + ] + }, + { + "name": "string.quoted.single.langium", + "begin": "'", + "end": "'", + "patterns": [ + { + "include": "#string-character-escape" + } + ] + } + ], + "repository": { + "comments": { + "patterns": [ + { + "name": "comment.block.langium", + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.langium" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.langium" + } + } + }, + { + "begin": "(^\\s+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.cs" + } + }, + "end": "(?=$)", + "name": "comment.line.langium" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.langium", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "regex": { + "patterns": [ + { + "name": "string.regexp.ts", + "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([a-z]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(/)([a-z]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "keyword.other.ts" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] }, { - "include": "#comments" + "name": "string.regexp.ts", + "begin": "((?", + "captures": { + "0": { + "name": "keyword.other.back-reference.regexp" + }, + "1": { + "name": "variable.other.regexp" + } + } }, { - "name": "constant.language.langium", - "match": "\\b(?i:true|false)\\b" + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" }, { - "name": "keyword.symbol.langium", - "match": "(\\{|\\}|\\:|\\]|\\[|\\(|\\)|(\\??|\\+?)\\=|->|\\=>|<|>|\\,|\\*|\\+|\\@|\\||\\&|\\?|\\!|\\;)" + "name": "keyword.operator.or.regexp", + "match": "\\|" }, { - "name": "string.quoted.double.langium", - "begin": "\"", - "end": "\"", - "patterns": [ - { - "include": "#string-character-escape" - } - ] + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.no-capture.regexp" + }, + "2": { + "name": "variable.other.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" }, - { - "begin": "(^\\s+)?(?=//)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.cs" - } - }, - "end": "(?=$)", - "name": "comment.line.langium" + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" } - ] + } + }, + { + "include": "#regex-character-class" + } + ] }, - "string-character-escape": { - "name": "constant.character.escape.langium", - "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." }, - "regex": { - "patterns": [ - { - "name": "string.regexp.ts", - "begin": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[\\()]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\]|\\(([^\\)\\\\]|\\\\.)+\\))+\\/([a-z]+|(?![\\/\\*])|(?=\\/\\*))(?!\\s*[a-zA-Z0-9_$]))", - "beginCaptures": { - "1": { - "name": "punctuation.definition.string.begin.ts" - } - }, - "end": "(/)([a-z]*)", - "endCaptures": { - "1": { - "name": "punctuation.definition.string.end.ts" - }, - "2": { - "name": "keyword.other.ts" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "string.regexp.ts", - "begin": "((?", - "captures": { - "0": { - "name": "keyword.other.back-reference.regexp" - }, - "1": { - "name": "variable.other.regexp" - } - } - }, - { - "name": "keyword.operator.quantifier.regexp", - "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" - }, - { - "name": "keyword.operator.or.regexp", - "match": "\\|" - }, - { - "name": "meta.group.assertion.regexp", - "begin": "(\\()((\\?=)|(\\?!)|(\\?<=)|(\\?))?", - "beginCaptures": { - "0": { - "name": "punctuation.definition.group.regexp" - }, - "1": { - "name": "punctuation.definition.group.no-capture.regexp" - }, - "2": { - "name": "variable.other.regexp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.group.regexp" - } - }, - "patterns": [ - { - "include": "#regexp" - } - ] - }, - { - "name": "constant.other.character-class.set.regexp", - "begin": "(\\[)(\\^)?", - "beginCaptures": { - "1": { - "name": "punctuation.definition.character-class.regexp" - }, - "2": { - "name": "keyword.operator.negation.regexp" - } - }, - "end": "(\\])", - "endCaptures": { - "1": { - "name": "punctuation.definition.character-class.regexp" - } - }, - "patterns": [ - { - "name": "constant.other.character-class.range.regexp", - "match": "(?:.|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}))|(\\\\c[A-Z])|(\\\\.))", - "captures": { - "1": { - "name": "constant.character.numeric.regexp" - }, - "2": { - "name": "constant.character.control.regexp" - }, - "3": { - "name": "constant.character.escape.backslash.regexp" - }, - "4": { - "name": "constant.character.numeric.regexp" - }, - "5": { - "name": "constant.character.control.regexp" - }, - "6": { - "name": "constant.character.escape.backslash.regexp" - } - } - }, - { - "include": "#regex-character-class" - } - ] - }, - { - "include": "#regex-character-class" - } - ] - }, - "regex-character-class": { - "patterns": [ - { - "name": "constant.other.character-class.regexp", - "match": "\\\\[wWsSdDtrnvf]|\\." - }, - { - "name": "constant.character.numeric.regexp", - "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" - }, - { - "name": "constant.character.control.regexp", - "match": "\\\\c[A-Z]" - }, - { - "name": "constant.character.escape.backslash.regexp", - "match": "\\\\." - } - ] - } + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4})" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] } + } } diff --git a/verify/next/app/langium-dsl/worker/langium-server.ts b/verify/next/app/langium-dsl/worker/langium-server.ts index 38afa1a62..acb0b3990 100644 --- a/verify/next/app/langium-dsl/worker/langium-server.ts +++ b/verify/next/app/langium-dsl/worker/langium-server.ts @@ -14,28 +14,28 @@ export let messageReader: BrowserMessageReader | undefined; export let messageWriter: BrowserMessageWriter | undefined; export const start = (port: MessagePort | DedicatedWorkerGlobalScope, name: string) => { - console.log(`Starting ${name}...`); - /* browser specific setup code */ - messageReader = new BrowserMessageReader(port); - messageWriter = new BrowserMessageWriter(port); + console.log(`Starting ${name}...`); + /* browser specific setup code */ + messageReader = new BrowserMessageReader(port); + messageWriter = new BrowserMessageWriter(port); - messageReader.listen((message) => { - console.log('Received message from main thread:', message); - }); + messageReader.listen((message) => { + console.log('Received message from main thread:', message); + }); - if (!crossOriginIsolated) { - console.error('Cross-origin isolation required'); - } + if (!crossOriginIsolated) { + console.error('Cross-origin isolation required'); + } - const connection = createConnection(messageReader, messageWriter); - // Inject the shared services and language-specific services - const { shared } = createLangiumGrammarServices({ connection, ...EmptyFileSystem }); + const connection = createConnection(messageReader, messageWriter); + // Inject the shared services and language-specific services + const { shared } = createLangiumGrammarServices({ connection, ...EmptyFileSystem }); - console.log('Starting langium-dsl server...'); + console.log('Starting langium-dsl server...'); - // Start the language server with the shared services - startLanguageServer(shared); -} + // Start the language server with the shared services + startLanguageServer(shared); +}; // self.onmessage = async (event: MessageEvent) => { // const data = event.data; diff --git a/verify/next/app/layout.tsx b/verify/next/app/layout.tsx index 5f4612fdc..4f52792c7 100644 --- a/verify/next/app/layout.tsx +++ b/verify/next/app/layout.tsx @@ -3,19 +3,15 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - - {/* */} - {children} - - - ); + {children} + + + ); } diff --git a/verify/next/app/page.tsx b/verify/next/app/page.tsx index d8c9594de..4fcb59605 100644 --- a/verify/next/app/page.tsx +++ b/verify/next/app/page.tsx @@ -11,70 +11,71 @@ import dynamic from 'next/dynamic'; import './views.editorOnly.css'; export default function Page() { + const DynamicMonacoEditorReact = dynamic( + async () => { + await import('@codingame/monaco-vscode-typescript-basics-default-extension'); + // await import('@codingame/monaco-vscode-typescript-language-features-default-extension'); + // await import('../bundle/tsserver/index.js'); - const DynamicMonacoEditorReact = dynamic(async () => { - await import('@codingame/monaco-vscode-typescript-basics-default-extension'); - // await import('@codingame/monaco-vscode-typescript-language-features-default-extension'); - // await import('../bundle/tsserver/index.js'); + const { setupLangiumClientExtended, openDocument, showDocument } = await import('./langium-dsl/config/extendedConfig'); + const mlcWFModule = await import('monaco-languageclient/workerFactory'); - const { setupLangiumClientExtended, openDocument, showDocument } = await import('./langium-dsl/config/extendedConfig'); - const mlcWFModule = await import('monaco-languageclient/workerFactory'); + const languageServerWorker = new Worker(new URL('./langium-dsl/worker/langium-server.ts', import.meta.url), { + type: 'module', + name: 'Langium LS' + }); - const languageServerWorker = new Worker(new URL('./langium-dsl/worker/langium-server.ts', import.meta.url), { - type: 'module', - name: 'Langium LS', - }); - - const defineWorkerLoaders: () => Partial> = () => { - const defaultEditorWorkerService = () => new mlcWFModule.Worker( - new URL('../bundle/editorWorker/editor.worker.js', import.meta.url), - { type: 'module' } - ); - // const defaultExtensionHostWorkerMain = () => new mlcWFModule.Worker( - // new URL('@codingame/monaco-vscode-api/workers/extensionHost.worker', import.meta.url), - // // new URL('../bundle/extHostWorker/extensionHost.worker.js', import.meta.url), - // { type: 'module' } - // ); - const defaultTextMateWorker = () => new mlcWFModule.Worker( - new URL('../bundle/textmateWorker/worker.js', import.meta.url), - { type: 'module' } - ); - return { - editorWorkerService: defaultEditorWorkerService, - // extensionHostWorkerMain: defaultExtensionHostWorkerMain, - TextMateWorker: defaultTextMateWorker, - }; + const defineWorkerLoaders: () => Partial> = () => { + const defaultEditorWorkerService = () => + new mlcWFModule.Worker(new URL('../bundle/editorWorker/editor.worker.js', import.meta.url), { type: 'module' }); + // const defaultExtensionHostWorkerMain = () => new mlcWFModule.Worker( + // new URL('@codingame/monaco-vscode-api/workers/extensionHost.worker', import.meta.url), + // // new URL('../bundle/extHostWorker/extensionHost.worker.js', import.meta.url), + // { type: 'module' } + // ); + const defaultTextMateWorker = () => + new mlcWFModule.Worker(new URL('../bundle/textmateWorker/worker.js', import.meta.url), { type: 'module' }); + return { + editorWorkerService: defaultEditorWorkerService, + // extensionHostWorkerMain: defaultExtensionHostWorkerMain, + TextMateWorker: defaultTextMateWorker }; + }; - const configureWorkerFactory = (logger?: ILogger) => { - mlcWFModule.useWorkerFactory({ - workerLoaders: defineWorkerLoaders(), - logger - }); - }; - const appConfig = await setupLangiumClientExtended(languageServerWorker, false, configureWorkerFactory); + const configureWorkerFactory = (logger?: ILogger) => { + mlcWFModule.useWorkerFactory({ + workerLoaders: defineWorkerLoaders(), + logger + }); + }; + const appConfig = await setupLangiumClientExtended(languageServerWorker, false, configureWorkerFactory); - return () => { - console.log('MonacoEditorReactComp editor started.'); + return () => ( + { + console.log('MonacoEditorReactComp editor started.'); - await openDocument('/workspace/langium-types.langium'); - await openDocument('/workspace/langium-grammar.langium'); - await openDocument('/workspace/hello.ts'); - await showDocument('/workspace/hello.ts'); - await showDocument('/workspace/langium-grammar.langium'); - }} /> - }, { - ssr: false - }); + await openDocument('/workspace/langium-types.langium'); + await openDocument('/workspace/langium-grammar.langium'); + await openDocument('/workspace/hello.ts'); + await showDocument('/workspace/hello.ts'); + await showDocument('/workspace/langium-grammar.langium'); + }} + /> + ); + }, + { + ssr: false + } + ); - return ( -
- -
- ); + return ( +
+ +
+ ); } diff --git a/verify/next/app/views.editorOnly.css b/verify/next/app/views.editorOnly.css index c8542f4f3..b53529e8a 100644 --- a/verify/next/app/views.editorOnly.css +++ b/verify/next/app/views.editorOnly.css @@ -1,29 +1,29 @@ :root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; } body { - background-color: var(--vscode-editorWidget-background); - color: var(--vscode-editorWidget-foreground); - margin: 0; + background-color: var(--vscode-editorWidget-background); + color: var(--vscode-editorWidget-foreground); + margin: 0; } #editorsDiv { - min-width: 0; + min-width: 0; } #editors { - position: relative; - min-width: 0; - height: 95vh; - border: 1px solid var(--vscode-editorWidget-border); + position: relative; + min-width: 0; + height: 95vh; + border: 1px solid var(--vscode-editorWidget-border); } diff --git a/verify/next/app/vite-env.d.ts b/verify/next/app/vite-env.d.ts index 0454d15dd..0bccf4512 100644 --- a/verify/next/app/vite-env.d.ts +++ b/verify/next/app/vite-env.d.ts @@ -6,6 +6,6 @@ /// declare module '*?raw' { - const content: string; - export default content; + const content: string; + export default content; } diff --git a/verify/next/app/vite.tsx b/verify/next/app/vite.tsx index 9aa092193..3900b03d5 100644 --- a/verify/next/app/vite.tsx +++ b/verify/next/app/vite.tsx @@ -8,73 +8,67 @@ import type { WorkerLoader } from 'monaco-languageclient/workerFactory'; import ReactDOM from 'react-dom/client'; export const createDynamicEditorComponent = async () => { - await import('@codingame/monaco-vscode-typescript-basics-default-extension'); - await import('@codingame/monaco-vscode-typescript-language-features-default-extension'); + await import('@codingame/monaco-vscode-typescript-basics-default-extension'); + await import('@codingame/monaco-vscode-typescript-language-features-default-extension'); - const { workerFactory, setupLangiumClientExtended, openDocument, showDocument } = await import('./langium-dsl/config/extendedConfig.js'); + const { workerFactory, setupLangiumClientExtended, openDocument, showDocument } = await import('./langium-dsl/config/extendedConfig.js'); - const defineWorkerLoaders: () => Partial> = () => { - const defaultEditorWorkerService = () => new workerFactory.Worker( - new URL('../bundle/editorWorker/editor.worker.js', import.meta.url), - { type: 'module' } - ); - const defaultExtensionHostWorkerMain = () => new workerFactory.Worker( - new URL('@codingame/monaco-vscode-api/workers/extensionHost.worker', import.meta.url), - { type: 'module' } - ); - const defaultTextMateWorker = () => new workerFactory.Worker( - new URL('../bundle/textmateWorker/worker.js', import.meta.url), - { type: 'module' } - ); + const defineWorkerLoaders: () => Partial> = () => { + const defaultEditorWorkerService = () => + new workerFactory.Worker(new URL('../bundle/editorWorker/editor.worker.js', import.meta.url), { type: 'module' }); + const defaultExtensionHostWorkerMain = () => + new workerFactory.Worker(new URL('@codingame/monaco-vscode-api/workers/extensionHost.worker', import.meta.url), { + type: 'module' + }); + const defaultTextMateWorker = () => + new workerFactory.Worker(new URL('../bundle/textmateWorker/worker.js', import.meta.url), { type: 'module' }); - return { - editorWorkerService: defaultEditorWorkerService, - extensionHostWorkerMain: defaultExtensionHostWorkerMain, - TextMateWorker: defaultTextMateWorker, - }; + return { + editorWorkerService: defaultEditorWorkerService, + extensionHostWorkerMain: defaultExtensionHostWorkerMain, + TextMateWorker: defaultTextMateWorker }; + }; - const configureDefaultWorkerFactory = (logger?: ILogger) => { - workerFactory.useWorkerFactory({ - workerLoaders: defineWorkerLoaders(), - logger - }); - }; - - const workerUrl = new URL('./langium-dsl/worker/langium-server.ts', import.meta.url); - console.log('Worker URL:', workerUrl); - const languageServerWorker = new Worker(workerUrl, { - type: 'module', - name: 'Langium LS', + const configureDefaultWorkerFactory = (logger?: ILogger) => { + workerFactory.useWorkerFactory({ + workerLoaders: defineWorkerLoaders(), + logger }); - const appConfig = await setupLangiumClientExtended(languageServerWorker, true, configureDefaultWorkerFactory); + }; + + const workerUrl = new URL('./langium-dsl/worker/langium-server.ts', import.meta.url); + console.log('Worker URL:', workerUrl); + const languageServerWorker = new Worker(workerUrl, { + type: 'module', + name: 'Langium LS' + }); + const appConfig = await setupLangiumClientExtended(languageServerWorker, true, configureDefaultWorkerFactory); - return () => { - console.log('MonacoEditorReactComp editor started.'); + return () => ( + { + console.log('MonacoEditorReactComp editor started.'); - await openDocument('/workspace/langium-types.langium'); - await openDocument('/workspace/langium-grammar.langium'); - await openDocument('/workspace/hello.ts'); - await showDocument('/workspace/hello.ts'); - await showDocument('/workspace/langium-grammar.langium'); - }} /> + await openDocument('/workspace/langium-types.langium'); + await openDocument('/workspace/langium-grammar.langium'); + await openDocument('/workspace/hello.ts'); + await showDocument('/workspace/hello.ts'); + await showDocument('/workspace/langium-grammar.langium'); + }} + /> + ); }; export const runDirectly = async () => { - const root = ReactDOM.createRoot(document.getElementById('monaco-editor-root')!); - const comp = await createDynamicEditorComponent(); - const App = () => { - - return ( -
- { comp() } -
- ); - }; - root.render(); + const root = ReactDOM.createRoot(document.getElementById('monaco-editor-root')!); + const comp = await createDynamicEditorComponent(); + const App = () => { + return
{comp()}
; + }; + root.render(); }; diff --git a/verify/next/esbuild.tsserver.mts b/verify/next/esbuild.tsserver.mts index 9ad07aadc..2603514a0 100644 --- a/verify/next/esbuild.tsserver.mts +++ b/verify/next/esbuild.tsserver.mts @@ -1,13 +1,13 @@ import * as esbuild from 'esbuild'; const ctx = await esbuild.context({ - entryPoints: ['./node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension/index.js'], - outdir: 'bundle', - bundle: true, - target: "ES2022", - format: 'esm', - platform: 'node', - sourcemap: true + entryPoints: ['./node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension/index.js'], + outdir: 'bundle', + bundle: true, + target: 'ES2022', + format: 'esm', + platform: 'node', + sourcemap: true }); await ctx.rebuild(); diff --git a/verify/next/index.html b/verify/next/index.html index ab6abcbed..239df1f0a 100644 --- a/verify/next/index.html +++ b/verify/next/index.html @@ -1,25 +1,21 @@ - + - - + React: Editor - - - + + + - +
-
- -
+
- - - + diff --git a/verify/next/loaders/manipulate.cjs b/verify/next/loaders/manipulate.cjs index 9300a3288..86cfba32d 100644 --- a/verify/next/loaders/manipulate.cjs +++ b/verify/next/loaders/manipulate.cjs @@ -4,7 +4,7 @@ * @returns {string} - The modified source code */ module.exports = function (source) { - console.log(`Source: ${source}`); + console.log(`Source: ${source}`); - return source; + return source; }; diff --git a/verify/next/next-env.d.ts b/verify/next/next-env.d.ts index f5889ef4a..40f541318 100644 --- a/verify/next/next-env.d.ts +++ b/verify/next/next-env.d.ts @@ -5,7 +5,7 @@ /// /// -import "./.next/types/routes.d.ts"; +import './.next/types/routes.d.ts'; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/verify/next/next.config.mjs b/verify/next/next.config.mjs index eb75027eb..f07602a89 100644 --- a/verify/next/next.config.mjs +++ b/verify/next/next.config.mjs @@ -10,43 +10,41 @@ console.log(`Will load Next.js config from: ${__dirname}`); * @type {import('next').NextConfig} */ export default { - typescript: { - tsconfigPath: './tsconfig.json', - }, - trailingSlash: true, - reactStrictMode: true, - output: 'standalone', - serverExternalPackages: [ - '@codingame/monaco-vscode-typescript-language-features-default-extension', - ], - turbopack: { - root: resolve(__dirname), - rules: { - // Target the specific broken dependency file - // You can use a glob pattern to match the file inside node_modules - './node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension/index.js': { - loaders: [ - { - loader: resolve(__dirname, 'loaders/manipulate.cjs'), - options: { - target: 'browser', - }, - }, - ], - // "as": "*.js" tells Turbopack to treat the output as a JS module - as: '*.js', - }, - } - }, - async headers() { - return [ - { - source: '/(.*)', - headers: [ - { key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' }, - { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' } - ] + typescript: { + tsconfigPath: './tsconfig.json' + }, + trailingSlash: true, + reactStrictMode: true, + output: 'standalone', + serverExternalPackages: ['@codingame/monaco-vscode-typescript-language-features-default-extension'], + turbopack: { + root: resolve(__dirname), + rules: { + // Target the specific broken dependency file + // You can use a glob pattern to match the file inside node_modules + './node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension/index.js': { + loaders: [ + { + loader: resolve(__dirname, 'loaders/manipulate.cjs'), + options: { + target: 'browser' } - ]; + } + ], + // "as": "*.js" tells Turbopack to treat the output as a JS module + as: '*.js' + } } + }, + async headers() { + return [ + { + source: '/(.*)', + headers: [ + { key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' }, + { key: 'Cross-Origin-Opener-Policy', value: 'same-origin' } + ] + } + ]; + } }; diff --git a/verify/next/package.json b/verify/next/package.json index 7f62e737b..2190aa465 100644 --- a/verify/next/package.json +++ b/verify/next/package.json @@ -1,10 +1,6 @@ { "private": true, "type": "module", - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, "scripts": { "clean": "shx rm -fr .next dist lib bundle *.tsbuildinfo", "verify": "npm install && npm run dev", @@ -24,29 +20,33 @@ "start": "next start" }, "dependencies": { - "@codingame/monaco-vscode-api": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "^26.2.1", - "@codingame/monaco-vscode-keybindings-service-override": "^26.2.1", - "@codingame/monaco-vscode-textmate-service-override": "^26.2.1", - "@codingame/monaco-vscode-typescript-basics-default-extension": "^26.2.1", - "@codingame/monaco-vscode-typescript-language-features-default-extension": "^26.2.1", - "@codingame/monaco-vscode-views-service-override": "^26.2.1", + "@codingame/monaco-vscode-api": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "^26.2.2", + "@codingame/monaco-vscode-keybindings-service-override": "^26.2.2", + "@codingame/monaco-vscode-textmate-service-override": "^26.2.2", + "@codingame/monaco-vscode-typescript-basics-default-extension": "^26.2.2", + "@codingame/monaco-vscode-typescript-language-features-default-extension": "^26.2.2", + "@codingame/monaco-vscode-views-service-override": "^26.2.2", "@typefox/monaco-editor-react": "~7.7.0", "langium": "~4.2.1", "monaco-languageclient": "~10.7.0", "next": "~16.1.6", "react": "~19.2.4", "react-dom": "~19.2.4", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "vscode-languageclient": "~9.0.1", "vscode-languageserver": "~9.0.1" }, "devDependencies": { - "@typescript/native-preview": "~7.0.0-dev.20260205.1", "@types/react-dom": "~19.2.3", + "@typescript/native-preview": "~7.0.0-dev.20260212.1", "shx": "~0.4.0", - "vite": "~8.0.0-beta.13" + "vite": "~8.0.0-beta.14" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" }, "volta": { "node": "24.13.0", diff --git a/verify/next/tsconfig.base.json b/verify/next/tsconfig.base.json index f5292c86d..93d6b3403 100644 --- a/verify/next/tsconfig.base.json +++ b/verify/next/tsconfig.base.json @@ -1,13 +1,9 @@ - { +{ "compilerOptions": { "target": "ES2022", "module": "esnext", "moduleResolution": "bundler", - "lib": [ - "ES2022", - "DOM", - "DOM.Iterable" - ], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "allowJs": true, // esModuleInterop=true sets allowSyntheticDefaultImports=true, "esModuleInterop": true, @@ -36,6 +32,6 @@ "verbatimModuleSyntax": true, "erasableSyntaxOnly": true, "incremental": true, - "noEmit": true, + "noEmit": true } } diff --git a/verify/next/tsconfig.json b/verify/next/tsconfig.json index fe4edeec6..6f0d79817 100644 --- a/verify/next/tsconfig.json +++ b/verify/next/tsconfig.json @@ -6,9 +6,11 @@ "outDir": "lib", "declarationDir": "lib", "jsx": "react-jsx", - "plugins": [{ + "plugins": [ + { "name": "next" - }] + } + ] }, "include": [ "next-env.d.ts", @@ -21,10 +23,5 @@ "editor/src/**/*", "bundle/**/*" ], - "exclude": [ - "editor/**/*", - "dist/**/*", - "lib/**/*", - "node_modules/**/*" - ] + "exclude": ["editor/**/*", "dist/**/*", "lib/**/*", "node_modules/**/*"] } diff --git a/verify/next/vite.config.bundle.ts b/verify/next/vite.config.bundle.ts index e97d34be7..cdf235545 100644 --- a/verify/next/vite.config.bundle.ts +++ b/verify/next/vite.config.bundle.ts @@ -7,29 +7,26 @@ import path from 'node:path'; import { defineConfig } from 'vite'; const config = defineConfig({ - build: { - assetsInlineLimit: 0, - lib: { - entry: path.resolve(__dirname, './app/langium-dsl/config/extendedConfig.ts'), - name: 'extendedConfig', - fileName: () => 'extendedConfig.js', - formats: ['es'], - cssFileName: 'extendedConfig' - }, - copyPublicDir: false, - rolldownOptions: { - external: [ - 'react', - 'react-dom' - ], - output: { - entryFileNames: '[name].js', - assetFileNames: '[name][extname]' - } - }, - outDir: path.resolve(__dirname, 'bundle/langium-dsl/config'), - emptyOutDir: true - } + build: { + assetsInlineLimit: 0, + lib: { + entry: path.resolve(__dirname, './app/langium-dsl/config/extendedConfig.ts'), + name: 'extendedConfig', + fileName: () => 'extendedConfig.js', + formats: ['es'], + cssFileName: 'extendedConfig' + }, + copyPublicDir: false, + rolldownOptions: { + external: ['react', 'react-dom'], + output: { + entryFileNames: '[name].js', + assetFileNames: '[name][extname]' + } + }, + outDir: path.resolve(__dirname, 'bundle/langium-dsl/config'), + emptyOutDir: true + } }); export default config; diff --git a/verify/next/vite.config.editorWorker.ts b/verify/next/vite.config.editorWorker.ts index 7cbfb0a4e..28d2624ec 100644 --- a/verify/next/vite.config.editorWorker.ts +++ b/verify/next/vite.config.editorWorker.ts @@ -7,25 +7,25 @@ import path from 'node:path'; import { defineConfig } from 'vite'; const config = defineConfig({ - build: { - assetsInlineLimit: 1024 * 1024 * 128, - lib: { - entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-api/workers/editor.worker.js'), - name: 'editor.worker', - fileName: () => 'editor.worker.js', - formats: ['es'], - cssFileName: 'editor.worker' - }, - rolldownOptions: { - output: { - entryFileNames: '[name].js', - assetFileNames: '[name][extname]', - inlineDynamicImports: true - } - }, - outDir: path.resolve(__dirname, 'bundle/editorWorker'), - emptyOutDir: true - } + build: { + assetsInlineLimit: 1024 * 1024 * 128, + lib: { + entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-api/workers/editor.worker.js'), + name: 'editor.worker', + fileName: () => 'editor.worker.js', + formats: ['es'], + cssFileName: 'editor.worker' + }, + rolldownOptions: { + output: { + entryFileNames: '[name].js', + assetFileNames: '[name][extname]', + inlineDynamicImports: true + } + }, + outDir: path.resolve(__dirname, 'bundle/editorWorker'), + emptyOutDir: true + } }); export default config; diff --git a/verify/next/vite.config.extHostWorker.ts b/verify/next/vite.config.extHostWorker.ts index 63360a29b..085f99903 100644 --- a/verify/next/vite.config.extHostWorker.ts +++ b/verify/next/vite.config.extHostWorker.ts @@ -9,51 +9,49 @@ import type { PluginContext } from 'rolldown'; import fs from 'node:fs'; const config = defineConfig({ - optimizeDeps: { - include: [ - 'vscode/localExtensionHost', - ] + optimizeDeps: { + include: ['vscode/localExtensionHost'] + }, + build: { + assetsInlineLimit: 1024 * 1024 * 128, + lib: { + entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-api/workers/extensionHost.worker.js'), + name: 'extensionHostWorker', + fileName: () => 'extensionHostWorker.js', + formats: ['es'], + cssFileName: 'extensionHostWorker' }, - build: { - assetsInlineLimit: 1024 * 1024 * 128, - lib: { - entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-api/workers/extensionHost.worker.js'), - name: 'extensionHostWorker', - fileName: () => 'extensionHostWorker.js', - formats: ['es'], - cssFileName: 'extensionHostWorker' - }, - rolldownOptions: { - output: { - entryFileNames: '[name].js', - assetFileNames: '[name][extname]', - inlineDynamicImports: true - }, - plugins: [ - { - name: 'check-fileLoading', - load(this: PluginContext, id: string) { - if (id.endsWith('html')) { - console.log('checking: ' + id); - } - if (id.endsWith('extHostExtensionService.js')) { - console.log('load: ' + id); - const code = fs.readFileSync(id, 'utf8'); - const search = 'const response = await fetch(( browserUri.toString(true)));'; - const newCode = `console.log("browserUri: " + browserUri.toString()); + rolldownOptions: { + output: { + entryFileNames: '[name].js', + assetFileNames: '[name][extname]', + inlineDynamicImports: true + }, + plugins: [ + { + name: 'check-fileLoading', + load(this: PluginContext, id: string) { + if (id.endsWith('html')) { + console.log('checking: ' + id); + } + if (id.endsWith('extHostExtensionService.js')) { + console.log('load: ' + id); + const code = fs.readFileSync(id, 'utf8'); + const search = 'const response = await fetch(( browserUri.toString(true)));'; + const newCode = `console.log("browserUri: " + browserUri.toString()); let newURL = new URL(browserUri.toString().replace('file://', ''), import.meta.url); console.log("newURL: " + newURL.toString()); const response = await fetch((newURL));`; - const outputCode = code.replace(search, newCode); - return outputCode; - } - } - } - ] - }, - outDir: path.resolve(__dirname, 'bundle/extHostWorker'), - emptyOutDir: true - } + const outputCode = code.replace(search, newCode); + return outputCode; + } + } + } + ] + }, + outDir: path.resolve(__dirname, 'bundle/extHostWorker'), + emptyOutDir: true + } }); export default config; diff --git a/verify/next/vite.config.extensionService.ts b/verify/next/vite.config.extensionService.ts index 3e446da6c..7d04e010e 100644 --- a/verify/next/vite.config.extensionService.ts +++ b/verify/next/vite.config.extensionService.ts @@ -8,51 +8,49 @@ import { defineConfig } from 'vite'; import type { PluginContext } from 'rolldown'; const config = defineConfig({ - optimizeDeps: { - include: [ - 'vscode/localExtensionHost' - ] + optimizeDeps: { + include: ['vscode/localExtensionHost'] + }, + build: { + assetsInlineLimit: 1024 * 1024 * 128, + lib: { + entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-extensions-service-override/index.js'), + name: 'extensionService', + fileName: () => 'extensionService.js', + formats: ['es'], + cssFileName: 'extensionService' }, - build: { - assetsInlineLimit: 1024 * 1024 * 128, - lib: { - entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-extensions-service-override/index.js'), - name: 'extensionService', - fileName: () => 'extensionService.js', - formats: ['es'], - cssFileName: 'extensionService' - }, - rolldownOptions: { - output: { - entryFileNames: '[name].js', - assetFileNames: '[name][extname]', - inlineDynamicImports: true - }, - plugins: [ - { - name: 'check-fileLoading', - load(this: PluginContext, id: string) { - if (id.includes('iframe')) { - console.log('checking: ' + id); - } - if (id.endsWith('extHostExtensionService.js')) { - console.log('load: ' + id); + rolldownOptions: { + output: { + entryFileNames: '[name].js', + assetFileNames: '[name][extname]', + inlineDynamicImports: true + }, + plugins: [ + { + name: 'check-fileLoading', + load(this: PluginContext, id: string) { + if (id.includes('iframe')) { + console.log('checking: ' + id); + } + if (id.endsWith('extHostExtensionService.js')) { + console.log('load: ' + id); - // need to be patched in: @codingame/monaco-vscode-extensions-service-override/vscode/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html - // - } - } - } - ] - }, - outDir: path.resolve(__dirname, 'bundle/extensionService'), - emptyOutDir: true - } + // need to be patched in: @codingame/monaco-vscode-extensions-service-override/vscode/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html + // + } + } + } + ] + }, + outDir: path.resolve(__dirname, 'bundle/extensionService'), + emptyOutDir: true + } }); export default config; diff --git a/verify/next/vite.config.textmateWorker.ts b/verify/next/vite.config.textmateWorker.ts index d1fa98880..f3126a4a3 100644 --- a/verify/next/vite.config.textmateWorker.ts +++ b/verify/next/vite.config.textmateWorker.ts @@ -9,48 +9,47 @@ import { defineConfig } from 'vite'; import type { PluginContext } from 'rolldown'; const config = defineConfig({ - optimizeDeps: { - include: [ - 'vscode/localExtensionHost' - ] + optimizeDeps: { + include: ['vscode/localExtensionHost'] + }, + build: { + assetsInlineLimit: 0, // 1024 * 1024 * 128, + lib: { + entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-textmate-service-override/worker.js'), + name: 'textmateWorker', + fileName: () => 'textmateWorker.js', + formats: ['es'], + cssFileName: 'textmateWorker' }, - build: { - assetsInlineLimit: 0, // 1024 * 1024 * 128, - lib: { - entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-textmate-service-override/worker.js'), - name: 'textmateWorker', - fileName: () => 'textmateWorker.js', - formats: ['es'], - cssFileName: 'textmateWorker' - }, - rolldownOptions: { - output: { - entryFileNames: '[name].js', - assetFileNames: '[name][extname]', - inlineDynamicImports: true - }, - plugins: [ - { - name: 'inline-wasm', - load(this: PluginContext, id: string) { - - if (id.endsWith('textMateTokenizationWorker.worker.js')) { - const code = fs.readFileSync(id, 'utf8'); - const base64 = fs.readFileSync('./node_modules/@codingame/monaco-vscode-textmate-service-override/external/vscode-oniguruma/release/onig.wasm', 'base64'); - const outputCode = code.replace( - 'const response = await fetch(onigurumaWASMUri);', - `const response = await fetch('data:application/wasm;base64,${base64}')` - ); - return outputCode; - } - } - } - ] - }, - outDir: path.resolve(__dirname, 'bundle/textmateWorker'), - emptyOutDir: true - } - + rolldownOptions: { + output: { + entryFileNames: '[name].js', + assetFileNames: '[name][extname]', + inlineDynamicImports: true + }, + plugins: [ + { + name: 'inline-wasm', + load(this: PluginContext, id: string) { + if (id.endsWith('textMateTokenizationWorker.worker.js')) { + const code = fs.readFileSync(id, 'utf8'); + const base64 = fs.readFileSync( + './node_modules/@codingame/monaco-vscode-textmate-service-override/external/vscode-oniguruma/release/onig.wasm', + 'base64' + ); + const outputCode = code.replace( + 'const response = await fetch(onigurumaWASMUri);', + `const response = await fetch('data:application/wasm;base64,${base64}')` + ); + return outputCode; + } + } + } + ] + }, + outDir: path.resolve(__dirname, 'bundle/textmateWorker'), + emptyOutDir: true + } }); export default config; diff --git a/verify/next/vite.config.ts b/verify/next/vite.config.ts index 6da5d4e08..fa1c0f309 100644 --- a/verify/next/vite.config.ts +++ b/verify/next/vite.config.ts @@ -9,48 +9,46 @@ import { defineConfig } from 'vite'; /// export const config = defineConfig({ - build: { - outDir: path.resolve(__dirname, 'production'), - rolldownOptions: { - input: { - index: path.resolve(__dirname, 'index.html') - }, - output: { - entryFileNames: '[name].js', - assetFileNames: 'assets/[name][extname]' - } - } - }, - optimizeDeps: { - include: [ - 'langium', - 'langium/lsp', - 'langium/grammar', - 'vscode/localExtensionHost', - 'vscode-jsonrpc', - 'vscode-languageclient', - 'vscode-languageserver', - 'vscode-languageserver/browser.js', - 'vscode-languageserver-protocol' - ] + build: { + outDir: path.resolve(__dirname, 'production'), + rolldownOptions: { + input: { + index: path.resolve(__dirname, 'index.html') + }, + output: { + entryFileNames: '[name].js', + assetFileNames: 'assets/[name][extname]' + } + } + }, + optimizeDeps: { + include: [ + 'langium', + 'langium/lsp', + 'langium/grammar', + 'vscode/localExtensionHost', + 'vscode-jsonrpc', + 'vscode-languageclient', + 'vscode-languageserver', + 'vscode-languageserver/browser.js', + 'vscode-languageserver-protocol' + ] + }, + worker: { + format: 'es' + }, + server: { + cors: { + origin: '*' }, - worker: { - format: 'es' + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp' }, - server: { - cors: { - origin: '*' - }, - headers: { - 'Cross-Origin-Opener-Policy': 'same-origin', - 'Cross-Origin-Embedder-Policy': 'require-corp', - }, - watch: { - ignored: [ - '**/.chrome/**/*' - ] - } + watch: { + ignored: ['**/.chrome/**/*'] } + } }); export default config; diff --git a/verify/next/vite.config.tsserver.ts b/verify/next/vite.config.tsserver.ts index aae360189..274a95f92 100644 --- a/verify/next/vite.config.tsserver.ts +++ b/verify/next/vite.config.tsserver.ts @@ -7,31 +7,28 @@ import path from 'node:path'; import { defineConfig } from 'vite'; const config = defineConfig({ - optimizeDeps: { - include: [ - 'vscode/localExtensionHost' - ] + optimizeDeps: { + include: ['vscode/localExtensionHost'] + }, + build: { + assetsInlineLimit: 0, // 1024 * 1024 * 128, + lib: { + entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension/index.js'), + name: 'tsserver', + fileName: () => 'tsserver.js', + formats: ['es'], + cssFileName: 'tsserver' }, - build: { - assetsInlineLimit: 0, // 1024 * 1024 * 128, - lib: { - entry: path.resolve(__dirname, './node_modules/@codingame/monaco-vscode-typescript-language-features-default-extension/index.js'), - name: 'tsserver', - fileName: () => 'tsserver.js', - formats: ['es'], - cssFileName: 'tsserver' - }, - rolldownOptions: { - output: { - entryFileNames: '[name].js', - assetFileNames: '[name][extname]', - inlineDynamicImports: false - } - }, - outDir: path.resolve(__dirname, 'bundle/tsserver'), - emptyOutDir: true - } - + rolldownOptions: { + output: { + entryFileNames: '[name].js', + assetFileNames: '[name][extname]', + inlineDynamicImports: false + } + }, + outDir: path.resolve(__dirname, 'bundle/tsserver'), + emptyOutDir: true + } }); export default config; diff --git a/verify/peerNpm/index.html b/verify/peerNpm/index.html index 6eebab492..a1a301188 100644 --- a/verify/peerNpm/index.html +++ b/verify/peerNpm/index.html @@ -1,16 +1,16 @@ - + - + Vite App - - + +

Vite Verification: JSON Client

-
+
diff --git a/verify/peerNpm/package.json b/verify/peerNpm/package.json index 6de505b84..d96081c97 100644 --- a/verify/peerNpm/package.json +++ b/verify/peerNpm/package.json @@ -3,23 +3,6 @@ "version": "0.0.0", "private": true, "type": "module", - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, - "volta": { - "node": "24.13.0", - "npm": "11.6.2" - }, - "dependencies": { - "monaco-languageclient-examples": "^2026.2.1", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1" - }, - "devDependencies": { - "typescript": "~5.9.3", - "shx": "~0.4.0", - "vite": "~8.0.0-beta.13" - }, "scripts": { "verify": "npm install && npm run build && npm run start", "verify:ci": "npm install && npm run build", @@ -31,5 +14,22 @@ "dev:debug": "vite --debug --force", "vite:build": "vite build", "start": "vite preview" + }, + "dependencies": { + "monaco-languageclient-examples": "^2026.2.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2" + }, + "devDependencies": { + "shx": "~0.4.0", + "typescript": "~5.9.3", + "vite": "~8.0.0-beta.14" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "volta": { + "node": "24.13.0", + "npm": "11.6.2" } } diff --git a/verify/peerNpm/tsconfig.json b/verify/peerNpm/tsconfig.json index c1c36faa2..f23a59570 100644 --- a/verify/peerNpm/tsconfig.json +++ b/verify/peerNpm/tsconfig.json @@ -1,21 +1,13 @@ - { +{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", - "lib": [ - "ES2022", - "DOM", - "DOM.Iterable" - ], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "rootDir": ".", "noEmit": true, "skipLibCheck": true }, - "include": [ - "**/src/**/*.ts" - ], - "exclude": [ - "**/node_modules/**/*" - ] + "include": ["**/src/**/*.ts"], + "exclude": ["**/node_modules/**/*"] } diff --git a/verify/peerNpm/vite.config.ts b/verify/peerNpm/vite.config.ts index 2be0ebff0..36abef90b 100644 --- a/verify/peerNpm/vite.config.ts +++ b/verify/peerNpm/vite.config.ts @@ -6,10 +6,10 @@ import { defineConfig } from 'vite'; export default defineConfig({ - preview: { - port: 8081 - }, - worker: { - format: 'es' - } + preview: { + port: 8081 + }, + worker: { + format: 'es' + } }); diff --git a/verify/peerPnpm/package.json b/verify/peerPnpm/package.json index 8b7283a5b..42b8093b9 100644 --- a/verify/peerPnpm/package.json +++ b/verify/peerPnpm/package.json @@ -3,23 +3,23 @@ "version": "0.0.0", "private": true, "type": "module", - "engines": { - "node": ">=20.10.0", - "pnpm": ">=9.15.0" - }, - "volta": { - "node": "24.13.0", - "pnpm": "10.28.2" + "scripts": { + "build": "tsc --build tsconfig.json", + "verify:ci": "pnpm install && pnpm run build" }, "dependencies": { "monaco-languageclient-examples": "~2026.2.1", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1" + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2" }, "devDependencies": { "typescript": "~5.9.3" }, - "scripts": { - "build": "tsc --build tsconfig.json", - "verify:ci": "pnpm install && pnpm run build" + "engines": { + "node": ">=20.10.0", + "pnpm": ">=9.15.0" + }, + "volta": { + "node": "24.13.0", + "pnpm": "10.28.2" } } diff --git a/verify/peerPnpm/src/testerPnpm.ts b/verify/peerPnpm/src/testerPnpm.ts index bc288203e..397acd5b8 100644 --- a/verify/peerPnpm/src/testerPnpm.ts +++ b/verify/peerPnpm/src/testerPnpm.ts @@ -8,4 +8,3 @@ import { runJsonWrapper } from 'monaco-languageclient-examples/json-client'; console.log(vscode.workspace.name); await runJsonWrapper(); - diff --git a/verify/peerPnpm/tsconfig.json b/verify/peerPnpm/tsconfig.json index dc0cf0eb0..f23a59570 100644 --- a/verify/peerPnpm/tsconfig.json +++ b/verify/peerPnpm/tsconfig.json @@ -3,19 +3,11 @@ "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", - "lib": [ - "ES2022", - "DOM", - "DOM.Iterable" - ], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "rootDir": ".", "noEmit": true, "skipLibCheck": true }, - "include": [ - "**/src/**/*.ts" - ], - "exclude": [ - "**/node_modules/**/*" - ] + "include": ["**/src/**/*.ts"], + "exclude": ["**/node_modules/**/*"] } diff --git a/verify/peerYarn/package.json b/verify/peerYarn/package.json index 9ce9696f3..d499e6f01 100644 --- a/verify/peerYarn/package.json +++ b/verify/peerYarn/package.json @@ -3,35 +3,35 @@ "version": "0.0.0", "private": true, "type": "module", - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3", - "yarn": ">=4.6.0" - }, - "volta": { - "node": "24.13.0", - "yarn": "4.12.0" + "scripts": { + "build": "tsc --build tsconfig.json", + "verify:ci": "yarn install && yarn run build" }, "dependencies": { - "@codingame/monaco-vscode-api": "^26.2.1", - "@codingame/monaco-vscode-configuration-service-override": "^26.2.1", - "@codingame/monaco-vscode-editor-api": "^26.2.1", - "@codingame/monaco-vscode-editor-service-override": "^26.2.1", - "@codingame/monaco-vscode-extension-api": "^26.2.1", - "@codingame/monaco-vscode-extensions-service-override": "^26.2.1", - "@codingame/monaco-vscode-languages-service-override": "^26.2.1", - "@codingame/monaco-vscode-localization-service-override": "^26.2.1", - "@codingame/monaco-vscode-log-service-override": "^26.2.1", - "@codingame/monaco-vscode-model-service-override": "^26.2.1", + "@codingame/monaco-vscode-api": "^26.2.2", + "@codingame/monaco-vscode-configuration-service-override": "^26.2.2", + "@codingame/monaco-vscode-editor-api": "^26.2.2", + "@codingame/monaco-vscode-editor-service-override": "^26.2.2", + "@codingame/monaco-vscode-extension-api": "^26.2.2", + "@codingame/monaco-vscode-extensions-service-override": "^26.2.2", + "@codingame/monaco-vscode-languages-service-override": "^26.2.2", + "@codingame/monaco-vscode-localization-service-override": "^26.2.2", + "@codingame/monaco-vscode-log-service-override": "^26.2.2", + "@codingame/monaco-vscode-model-service-override": "^26.2.2", "monaco-languageclient-examples": "^2026.2.1", - "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.1", + "vscode": "npm:@codingame/monaco-vscode-extension-api@^26.2.2", "vscode-languageclient": "~9.0.1" }, "devDependencies": { "typescript": "~5.9.3" }, - "scripts": { - "build": "tsc --build tsconfig.json", - "verify:ci": "yarn install && yarn run build" + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3", + "yarn": ">=4.6.0" + }, + "volta": { + "node": "24.13.0", + "yarn": "4.12.0" } } diff --git a/verify/peerYarn/tsconfig.json b/verify/peerYarn/tsconfig.json index dc0cf0eb0..f23a59570 100644 --- a/verify/peerYarn/tsconfig.json +++ b/verify/peerYarn/tsconfig.json @@ -3,19 +3,11 @@ "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", - "lib": [ - "ES2022", - "DOM", - "DOM.Iterable" - ], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "rootDir": ".", "noEmit": true, "skipLibCheck": true }, - "include": [ - "**/src/**/*.ts" - ], - "exclude": [ - "**/node_modules/**/*" - ] + "include": ["**/src/**/*.ts"], + "exclude": ["**/node_modules/**/*"] } diff --git a/verify/webpack/index.html b/verify/webpack/index.html index 9807872cf..5fed715f4 100644 --- a/verify/webpack/index.html +++ b/verify/webpack/index.html @@ -1,16 +1,16 @@ - + - + Webpack App - - + +

Webpack Verification: JSON Client

-
+
diff --git a/verify/webpack/package.json b/verify/webpack/package.json index b15061570..f8b16f941 100644 --- a/verify/webpack/package.json +++ b/verify/webpack/package.json @@ -3,13 +3,13 @@ "version": "0.0.0", "private": true, "type": "module", - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - }, - "volta": { - "node": "24.13.0", - "npm": "11.6.2" + "scripts": { + "verify": "npm install && npm run build && npm run start", + "verify:ci": "npm install && npm run build", + "clean": "shx rm -fr dist *.tsbuildinfo", + "build:msg": "echo Building client-webpack example:", + "build": "npm run build:msg && npm run clean && webpack", + "start": "http-server ./ --port 8082" }, "dependencies": { "monaco-languageclient-examples": "^2026.2.1" @@ -23,12 +23,12 @@ "ts-loader": "~9.5.4", "webpack-cli": "~6.0.1" }, - "scripts": { - "verify": "npm install && npm run build && npm run start", - "verify:ci": "npm install && npm run build", - "clean": "shx rm -fr dist *.tsbuildinfo", - "build:msg": "echo Building client-webpack example:", - "build": "npm run build:msg && npm run clean && webpack", - "start": "http-server ./ --port 8082" + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + }, + "volta": { + "node": "24.13.0", + "npm": "11.6.2" } } diff --git a/verify/webpack/tsconfig.json b/verify/webpack/tsconfig.json index a080d2c2c..17d43cf2f 100644 --- a/verify/webpack/tsconfig.json +++ b/verify/webpack/tsconfig.json @@ -4,19 +4,12 @@ "outDir": "dist", "declaration": true, "declarationDir": "dist", - "types": [ - "vscode" - ], + "types": ["vscode"], "target": "ES2022", "module": "ES2022", "moduleResolution": "Bundler", - "lib": [ - "ES2022", - "DOM" - ], + "lib": ["ES2022", "DOM"], "skipLibCheck": true }, - "include": [ - "src/**/*.ts", - ] + "include": ["src/**/*.ts"] } diff --git a/verify/webpack/webpack.config.js b/verify/webpack/webpack.config.js index 8f35e7605..269dd18e7 100644 --- a/verify/webpack/webpack.config.js +++ b/verify/webpack/webpack.config.js @@ -10,42 +10,42 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const config = { - entry: resolve(__dirname, 'src', 'client', 'main.ts'), - module: { - rules: [ - { - test: /\.css$/, - use: ['style-loader', 'css-loader'] - }, - { - test: /\.ts?$/, - use: ['ts-loader'] - } - ] - }, - experiments: { - outputModule: true - }, - output: { - filename: 'main.js', - path: resolve(__dirname, 'dist', 'client'), - module: true, - workerChunkLoading: 'import', - environment: { - dynamicImportInWorker: true - } - }, - target: 'web', - resolve: { - extensions: ['.ts', '.js', '.json', '.ttf'], - fallback: { - fs: false, - module: false, - vm: false - } - }, - mode: 'development', - devtool: 'source-map' + entry: resolve(__dirname, 'src', 'client', 'main.ts'), + module: { + rules: [ + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + }, + { + test: /\.ts?$/, + use: ['ts-loader'] + } + ] + }, + experiments: { + outputModule: true + }, + output: { + filename: 'main.js', + path: resolve(__dirname, 'dist', 'client'), + module: true, + workerChunkLoading: 'import', + environment: { + dynamicImportInWorker: true + } + }, + target: 'web', + resolve: { + extensions: ['.ts', '.js', '.json', '.ttf'], + fallback: { + fs: false, + module: false, + vm: false + } + }, + mode: 'development', + devtool: 'source-map' }; export default config; diff --git a/vite.config.ts b/vite.config.ts index 98bfc72db..d261538a4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,86 +13,83 @@ const clangdWasmLocation = 'packages/examples/resources/clangd/wasm/clangd.wasm' /// export const definedViteConfig = defineConfig({ - build: { - rolldownOptions: { - input: { - index: path.resolve(__dirname, 'index.html'), - json_classic: path.resolve(__dirname, 'packages/examples/json_classic.html'), - json: path.resolve(__dirname, 'packages/examples/json.html'), - browser: path.resolve(__dirname, 'packages/examples/browser.html'), - langium_extended: path.resolve(__dirname, 'packages/examples/langium_extended.html'), - statemachine: path.resolve(__dirname, 'packages/examples/statemachine.html'), - python: path.resolve(__dirname, 'packages/examples/python.html'), - groovy: path.resolve(__dirname, 'packages/examples/groovy.html'), - clangd: path.resolve(__dirname, 'packages/examples/clangd.html'), - appPlayground: path.resolve(__dirname, 'packages/examples/appPlayground.html'), - twoLangaugeClients: path.resolve(__dirname, 'packages/examples/two_langauge_clients.html'), - reactAppPlayground: path.resolve(__dirname, 'packages/examples/react_appPlayground.html'), - reactStatemachine: path.resolve(__dirname, 'packages/examples/react_statemachine.html'), - reactPython: path.resolve(__dirname, 'packages/examples/react_python.html'), - tsExtHost: path.resolve(__dirname, 'packages/examples/tsExtHost.html') - } - } - }, - server: { - port: 20001, - cors: { - origin: '*' - }, - headers: { - 'Cross-Origin-Opener-Policy': 'same-origin', - 'Cross-Origin-Embedder-Policy': 'require-corp', - }, - watch: { - ignored: [ - '**/.chrome/**/*', - './verify/**/*' - ] - } - }, - optimizeDeps: { - include: [ - '@codingame/monaco-vscode-standalone-languages', - '@codingame/monaco-vscode-standalone-css-language-features', - '@codingame/monaco-vscode-standalone-html-language-features', - '@codingame/monaco-vscode-standalone-json-language-features', - '@codingame/monaco-vscode-standalone-typescript-language-features', - '@testing-library/react', - 'langium', - 'langium/lsp', - 'langium/grammar', - 'vscode/localExtensionHost', - 'vscode-jsonrpc', - 'vscode-languageclient', - 'vscode-languageserver', - 'vscode-languageserver/browser.js', - 'vscode-languageserver-protocol' - ] + build: { + rolldownOptions: { + input: { + index: path.resolve(__dirname, 'index.html'), + json_classic: path.resolve(__dirname, 'packages/examples/json_classic.html'), + json: path.resolve(__dirname, 'packages/examples/json.html'), + browser: path.resolve(__dirname, 'packages/examples/browser.html'), + langium_extended: path.resolve(__dirname, 'packages/examples/langium_extended.html'), + statemachine: path.resolve(__dirname, 'packages/examples/statemachine.html'), + python: path.resolve(__dirname, 'packages/examples/python.html'), + groovy: path.resolve(__dirname, 'packages/examples/groovy.html'), + clangd: path.resolve(__dirname, 'packages/examples/clangd.html'), + appPlayground: path.resolve(__dirname, 'packages/examples/appPlayground.html'), + twoLangaugeClients: path.resolve(__dirname, 'packages/examples/two_langauge_clients.html'), + reactAppPlayground: path.resolve(__dirname, 'packages/examples/react_appPlayground.html'), + reactStatemachine: path.resolve(__dirname, 'packages/examples/react_statemachine.html'), + reactPython: path.resolve(__dirname, 'packages/examples/react_python.html'), + tsExtHost: path.resolve(__dirname, 'packages/examples/tsExtHost.html') + } + } + }, + server: { + port: 20001, + cors: { + origin: '*' }, - plugins: [ - { - // For the *-language-features extensions which use SharedArrayBuffer - name: 'configure-response-headers', - apply: 'serve', - configureServer: (server) => { - server.middlewares.use((_req, res, next) => { - res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless') - res.setHeader('Cross-Origin-Opener-Policy', 'same-origin') - res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin') - next() - }) - } - }, - vsixPlugin() - ], - define: { - rootDirectory: JSON.stringify(__dirname), - // Server-provided Content-Length header may be gzipped, get the real size in build time - __WASM_SIZE__: fs.existsSync(clangdWasmLocation) ? fs.statSync(clangdWasmLocation).size : 0 + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp' }, - worker: { - format: 'es' + watch: { + ignored: ['**/.chrome/**/*', './verify/**/*'] } + }, + optimizeDeps: { + include: [ + '@codingame/monaco-vscode-standalone-languages', + '@codingame/monaco-vscode-standalone-css-language-features', + '@codingame/monaco-vscode-standalone-html-language-features', + '@codingame/monaco-vscode-standalone-json-language-features', + '@codingame/monaco-vscode-standalone-typescript-language-features', + '@testing-library/react', + 'langium', + 'langium/lsp', + 'langium/grammar', + 'vscode/localExtensionHost', + 'vscode-jsonrpc', + 'vscode-languageclient', + 'vscode-languageserver', + 'vscode-languageserver/browser.js', + 'vscode-languageserver-protocol' + ] + }, + plugins: [ + { + // For the *-language-features extensions which use SharedArrayBuffer + name: 'configure-response-headers', + apply: 'serve', + configureServer: (server) => { + server.middlewares.use((_req, res, next) => { + res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless'); + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); + res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin'); + next(); + }); + } + }, + vsixPlugin() + ], + define: { + rootDirectory: JSON.stringify(__dirname), + // Server-provided Content-Length header may be gzipped, get the real size in build time + __WASM_SIZE__: fs.existsSync(clangdWasmLocation) ? fs.statSync(clangdWasmLocation).size : 0 + }, + worker: { + format: 'es' + } }); export default definedViteConfig; diff --git a/vitest.config.ts b/vitest.config.ts index ff6836eb0..cec526e08 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { playwright } from '@vitest/browser-playwright' +import { playwright } from '@vitest/browser-playwright'; import { mergeConfig } from 'vite'; import { defineConfig as defineVitestConfig } from 'vitest/config'; import externalViteConfig from './vite.config.js'; @@ -11,65 +11,57 @@ import externalViteConfig from './vite.config.js'; /// export const vitestConfig = { - test: { - testTimeout: 15000, - browser: { - enabled: true, - headless: true, - provider: playwright(), - api: { - port: 20101 - }, - instances: [ - { - browser: 'chromium' - } - ] - }, - coverage: { - provider: 'v8', - reporter: ['text', 'html'], - include: [ - 'packages/client', - 'packages/vscode-ws-jsonrpc', - 'packages/wrapper-react' - ], - }, - include: [ - // keep also an explicit list of tests to run, so they can be commented in case of problems - // '**/client/test/common/logging.test.ts', - // '**/client/test/common/utils.test.ts', - // '**/client/test/fs/endpoints/emptyEndpoint.test.ts', - // '**/client/test/vscode/manager.test.ts', - // '**/client/test/vscode/manager.editorservice.test.ts', - // '**/client/test/vscode/manager.viewsserivce.test.ts', - // '**/client/test/vscode/manager.workbenchserivce.test.ts', - // '**/client/test/wrapper/lcmanager.test.ts', - // '**/client/test/wrapper/lcwrapper.test.ts', - // '**/client/test/worker/workerFactory.test.ts', - // '**/client/test/worker/workerLoaders.test.ts', - // '**/client/test/editorApp/editorApp.test.ts', - // '**/client/test/editorApp/editorApp-classic.test.ts', - // '**/client/test/editorApp/editorApp.noservices.test.ts', - // '**/client/test/editorApp/editorApp.wrongservices.test.ts', - // '**/client/test/editorApp/config.test.ts', - // '**/wrapper-react/test/index.test.tsx', - // '**/wrapper-react/test/index.extapi.test.tsx', - // '**/wrapper-react/test/index.strictmode.test.tsx', - // '**/wrapper-react/test/index.lc.test.tsx', - // '**/wrapper-react/test/index.lc.strictmode.test.tsx', - // '**/wrapper-react/test/index.viewsservice.test.tsx', - '**/client/test/**/*', - '**/wrapper-react/test/**/*' - ], - exclude: [ - '**/support/**/*', - '**/__screenshots__/**/*', - ] - } + test: { + testTimeout: 15000, + browser: { + enabled: true, + headless: true, + provider: playwright(), + api: { + port: 20101 + }, + instances: [ + { + browser: 'chromium' + } + ] + }, + coverage: { + provider: 'v8', + reporter: ['text', 'html'], + include: ['packages/client', 'packages/vscode-ws-jsonrpc', 'packages/wrapper-react'] + }, + include: [ + // keep also an explicit list of tests to run, so they can be commented in case of problems + // '**/client/test/common/logging.test.ts', + // '**/client/test/common/utils.test.ts', + // '**/client/test/fs/endpoints/emptyEndpoint.test.ts', + // '**/client/test/vscode/manager.test.ts', + // '**/client/test/vscode/manager.editorservice.test.ts', + // '**/client/test/vscode/manager.viewsserivce.test.ts', + // '**/client/test/vscode/manager.workbenchserivce.test.ts', + // '**/client/test/wrapper/lcmanager.test.ts', + // '**/client/test/wrapper/lcwrapper.test.ts', + // '**/client/test/worker/workerFactory.test.ts', + // '**/client/test/worker/workerLoaders.test.ts', + // '**/client/test/editorApp/editorApp.test.ts', + // '**/client/test/editorApp/editorApp-classic.test.ts', + // '**/client/test/editorApp/editorApp.noservices.test.ts', + // '**/client/test/editorApp/editorApp.wrongservices.test.ts', + // '**/client/test/editorApp/config.test.ts', + // '**/wrapper-react/test/index.test.tsx', + // '**/wrapper-react/test/index.extapi.test.tsx', + // '**/wrapper-react/test/index.strictmode.test.tsx', + // '**/wrapper-react/test/index.lc.test.tsx', + // '**/wrapper-react/test/index.lc.strictmode.test.tsx', + // '**/wrapper-react/test/index.viewsservice.test.tsx', + '**/client/test/**/*', + '**/wrapper-react/test/**/*' + ], + exclude: ['**/support/**/*', '**/__screenshots__/**/*'] + } }; const definedVitestConfig = defineVitestConfig(vitestConfig); export default mergeConfig(definedVitestConfig, externalViteConfig); -