diff --git a/.gitignore b/.gitignore index 07e4af692..22a1810f5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ lib node_modules *.tsbuildinfo .angular +__screenshots__ diff --git a/docs/versions-and-history.md b/docs/versions-and-history.md index 4a9bb74fc..187b3678d 100644 --- a/docs/versions-and-history.md +++ b/docs/versions-and-history.md @@ -6,6 +6,7 @@ The following table describes which version of **monaco-languageclient** and **@ | monaco-languageclient | monaco-editor-wrapper | monaco-editor-react | monaco-vscode-api / editor-api | vscode | monaco-editor | release date | comment | | :---- | :---- | :--- | :--- | :--- | :--- | :--- | :--- | +| 9.0.0-next.0 | 6.0.0-next.0 | 6.0.0-next.0 | 8.0.4 | 1.92.2 | 0.51.0 | 2024-09-xy | | | 8.8.3 | 5.5.3 | 4.5.3 | 8.0.4 | 1.92.2 | 0.51.0 | 2024-08-26 | | | 8.8.2 | 5.5.2 | 4.5.2 | 8.0.2 | 1.92.2 | 0.50.0 | 2024-08-21 | | | 8.8.1 | 5.5.1 | 4.5.1 | 8.0.1 | 1.92.1 | 0.50.0 | 2024-08-12 | | diff --git a/index.html b/index.html index b55d8fefd..39af637ec 100644 --- a/index.html +++ b/index.html @@ -54,6 +54,11 @@

Groovy

Groovy Language Client & Language Server (Web Socket)
+

Multiple Languageclients

+ Please execute npm run start:example:server:python and npm run start:example:server:json beforehand:
+ Json & Python Languageclients & Language Server (Web Socket) +
+

Monaco Editor React

React: Langium Statemachine Language Client & Language Server (Worker)
@@ -65,8 +70,6 @@

Monaco Editor React

monaco-editor related examples

Monaco Editor Wrapper TypeScript Example
- Multiple Editors -

Verification

Angular

diff --git a/package-lock.json b/package-lock.json index 391158240..a85637691 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,9 @@ "@codingame/esbuild-import-meta-url-plugin": "~1.0.2", "@codingame/monaco-vscode-rollup-vsix-plugin": "~8.0.4", "@rollup/pluginutils": "~5.1.0", - "@testing-library/react": "~16.0.0", - "@types/node": "~20.14.15", - "@types/react": "~18.3.4", + "@testing-library/react": "~16.0.1", + "@types/node": "~20.16.5", + "@types/react": "~18.3.5", "@types/react-dom": "~18.3.0", "@types/vscode": "~1.92.0", "@typescript-eslint/eslint-plugin": "~7.18.0", @@ -33,10 +33,10 @@ "http-server": "~14.1.1", "minimatch": "~10.0.1", "typescript": "~5.5.4", - "vite": "~5.4.2", + "vite": "~5.4.3", "vite-node": "~2.0.5", "vitest": "~2.0.5", - "webdriverio": "~9.0.6" + "webdriverio": "~9.0.7" } }, "node_modules/@ampproject/remapping": { @@ -1953,9 +1953,9 @@ "dev": true }, "node_modules/@promptbook/utils": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.66.0.tgz", - "integrity": "sha512-L8CDhFE2p6lEGFW4sWSICljfXCQTeQ10hQrhVjULf8e2UDpqJ2C3nSTe3a890nGLwI5Rg8SStpIIndkQo/zpIw==", + "version": "0.70.0-1", + "resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.70.0-1.tgz", + "integrity": "sha512-qd2lLRRN+sE6UuNMi2tEeUUeb4zmXnxY5EMdfHVXNE+bqBDpUC7/aEfXgA3jnUXEr+xFjQ8PTFQgWvBMaKvw0g==", "dev": true, "funding": [ { @@ -1973,9 +1973,9 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.3.1.tgz", - "integrity": "sha512-uK7o3hHkK+naEobMSJ+2ySYyXtQkBxIH8Gn4MK9ciePjNV+Pf+PgY/W7iPzn2MTjl3stcYB5AlcTmPYw7AXDwA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", + "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2262,10 +2262,11 @@ } }, "node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" }, @@ -2468,13 +2469,13 @@ } }, "node_modules/@types/node": { - "version": "20.14.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz", - "integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==", + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/prop-types": { @@ -2496,9 +2497,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", - "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", + "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", "dev": true, "license": "MIT", "dependencies": { @@ -3148,9 +3149,9 @@ } }, "node_modules/@zip.js/zip.js": { - "version": "2.7.48", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.48.tgz", - "integrity": "sha512-J7cliimZ2snAbr0IhLx2U8BwfA1pKucahKzTpFtYq4hEgKxwvFJcIjCIVNPwQpfVab7iVP+AKmoH1gidBlyhiQ==", + "version": "2.7.52", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.52.tgz", + "integrity": "sha512-+5g7FQswvrCHwYKNMd/KFxZSObctLSsQOgqBSi0LzwHo3li9Eh1w5cF5ndjQw9Zbr3ajVnd2+XyiX85gAetx1Q==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3603,9 +3604,9 @@ "optional": true }, "node_modules/bare-fs": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", - "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.3.tgz", + "integrity": "sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -3616,9 +3617,9 @@ } }, "node_modules/bare-os": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", - "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.2.tgz", + "integrity": "sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==", "dev": true, "license": "Apache-2.0", "optional": true @@ -3635,13 +3636,14 @@ } }, "node_modules/bare-stream": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", - "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.2.1.tgz", + "integrity": "sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==", "dev": true, "license": "Apache-2.0", "optional": true, "dependencies": { + "b4a": "^1.6.6", "streamx": "^2.18.0" } }, @@ -5701,9 +5703,9 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", "dev": true, "funding": [ { @@ -6001,9 +6003,9 @@ } }, "node_modules/geckodriver": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.3.tgz", - "integrity": "sha512-79rvaq8pvKVUtuM9XBjQApb04kOVkl3TFRX+zTt1wlmL+wqpt85ocWCdqiENU/3zIzg2Me21eClUcnE7F1kL2w==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.4.4.tgz", + "integrity": "sha512-0zaw19tcmWeluqx7+Y559JGBtidu1D0Lb8ElYKiNEQu8r3sCfrLUf5V10xypl8u29ZLbgRV7WflxCJVTCkCMFA==", "dev": true, "hasInstallScript": true, "license": "MPL-2.0", @@ -7299,9 +7301,9 @@ } }, "node_modules/locate-app": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.4.28.tgz", - "integrity": "sha512-+fcrSieGg19C7YS7MBrngAcaWmdeTpljyWneKof7X9NGe3F2xPodl3y9kx1MpyaXtRmzFnV1/frARI3O73agQg==", + "version": "2.4.38", + "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.4.38.tgz", + "integrity": "sha512-fJNTsDQZSiy+bn98RicvVX8e7HwH3YqZnRRisircGDGPpf0eZ2x57Ev7LGs0pCBO7hzjINVtVr5QFfK8KH7hjg==", "dev": true, "funding": [ { @@ -7315,7 +7317,7 @@ ], "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@promptbook/utils": "0.66.0", + "@promptbook/utils": "0.70.0-1", "type-fest": "2.13.0", "userhome": "1.0.0" } @@ -8281,9 +8283,9 @@ } }, "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "version": "8.4.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", "dev": true, "funding": [ { @@ -8446,9 +8448,9 @@ } }, "node_modules/pyright": { - "version": "1.1.377", - "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.377.tgz", - "integrity": "sha512-y6ENYuyZXTczPnPWZnqx78pE+ZgyIotEas2M/LFRTq3EfbgVk84EcvuSKLIy2DJeDKjKDxVP/LVmDNHabljD3g==", + "version": "1.1.379", + "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.379.tgz", + "integrity": "sha512-n0X+IMqot6zL5b54vfU9GattS8jM9IOh8TRFho1k/6VoyjrpzQ7TnU6PtZzwEZNJaZi5izoLIDeMnGmbin8n8Q==", "license": "MIT", "bin": { "pyright": "index.js", @@ -9877,10 +9879,11 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" }, "node_modules/union": { "version": "0.5.0", @@ -10012,14 +10015,14 @@ } }, "node_modules/vite": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", - "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.3.tgz", + "integrity": "sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.41", + "postcss": "^8.4.43", "rollup": "^4.20.0" }, "bin": { @@ -10584,13 +10587,14 @@ } }, "node_modules/vscode-json-languageservice": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.4.0.tgz", - "integrity": "sha512-NCkkCr63OHVkE4lcb0xlUAaix6vE5gHQW4NrswbLEh3ArXj81lrGuFTsGEYEUXlNHdnc53vWPcjeSy/nMTrfXg==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.4.1.tgz", + "integrity": "sha512-5czFGNyVPxz3ZJYl8R3a3SuIj5gjhmGF4Wv05MRPvD4DEnHK6b8km4VbNMJNHBlTCh7A0aHzUbPVzo+0C18mCA==", + "license": "MIT", "dependencies": { "@vscode/l10n": "^0.0.18", - "jsonc-parser": "^3.3.0", - "vscode-languageserver-textdocument": "^1.0.11", + "jsonc-parser": "^3.3.1", + "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.0.8" } @@ -10656,9 +10660,10 @@ } }, "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", - "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==" + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", @@ -10723,9 +10728,9 @@ } }, "node_modules/webdriver": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.0.6.tgz", - "integrity": "sha512-S9f1qkEuIN1RgDFF0KmfWUc2NiBUb9d1UpGI/Y9IkSy9wTnAJk+xTvCezSUGO2D9rtZYHLal7jU+yOf9ntBg5Q==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.0.7.tgz", + "integrity": "sha512-0PN4omqCGlgi3RG0LyrQXr0RUmlDCenNtpN+dfzikfYoV+CHiCw2GMnZp2XCuYUnU01MaCKgRQxLuGobyZov+A==", "dev": true, "license": "MIT", "dependencies": { @@ -10744,9 +10749,9 @@ } }, "node_modules/webdriverio": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.0.6.tgz", - "integrity": "sha512-STRjhpC18tUPFox1DSRPMhKfMXwsgr7ZqyWWbLXCPUeKpejVXlVigcXM4bXVWXpuAbLVo8PHGtX/zy28Jkwmow==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.0.7.tgz", + "integrity": "sha512-/6CvJkKpUWYbX/59PNJCHXGLPwulQ/bXZwlIUrsF6MWKdf8Eb6yTaXkMJBaBy5x496b50PQcXkbe+qpfsnqXsg==", "dev": true, "license": "MIT", "dependencies": { @@ -10776,7 +10781,7 @@ "rgb2hex": "0.2.5", "serialize-error": "^11.0.3", "urlpattern-polyfill": "^10.0.0", - "webdriver": "9.0.6" + "webdriver": "9.0.7" }, "engines": { "node": ">=18" @@ -11079,7 +11084,7 @@ }, "packages/client": { "name": "monaco-languageclient", - "version": "8.8.3", + "version": "9.0.0-next.0", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-extensions-service-override": "~8.0.4", @@ -11109,7 +11114,7 @@ }, "packages/examples": { "name": "monaco-languageclient-examples", - "version": "2024.8.4", + "version": "2024.9.1", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-configuration-service-override": "~8.0.4", @@ -11130,18 +11135,18 @@ "@codingame/monaco-vscode-theme-service-override": "~8.0.4", "@codingame/monaco-vscode-typescript-basics-default-extension": "~8.0.4", "@codingame/monaco-vscode-typescript-language-features-default-extension": "~8.0.4", - "@typefox/monaco-editor-react": "~4.5.3", + "@typefox/monaco-editor-react": "~6.0.0-next.0", "express": "~4.19.2", "langium": "~3.1.3", "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3", - "monaco-languageclient": "~8.8.3", - "pyright": "~1.1.377", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient": "~9.0.0-next.0", + "pyright": "~1.1.379", "react": "~18.3.1", "react-dom": "~18.3.1", "request-light": "~0.8.0", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4", - "vscode-json-languageservice": "~5.4.0", + "vscode-json-languageservice": "~5.4.1", "vscode-languageclient": "~9.0.1", "vscode-languageserver": "~9.0.1", "vscode-uri": "~3.0.8", @@ -11169,7 +11174,7 @@ }, "packages/wrapper": { "name": "monaco-editor-wrapper", - "version": "5.5.3", + "version": "6.0.0-next.0", "license": "MIT", "dependencies": { "@codingame/monaco-vscode-configuration-service-override": "~8.0.4", @@ -11207,7 +11212,7 @@ }, "peerDependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-languageclient": "~8.8.3", + "monaco-languageclient": "~9.0.0-next.0", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4" }, "peerDependenciesMeta": { @@ -11224,19 +11229,19 @@ }, "packages/wrapper-react": { "name": "@typefox/monaco-editor-react", - "version": "4.5.3", + "version": "6.0.0-next.0", "license": "MIT", "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3", - "monaco-languageclient": "~8.8.3", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient": "~9.0.0-next.0", "react": "~18.3.1", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4" }, "peerDependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3", - "monaco-languageclient": "~8.8.3", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient": "~9.0.0-next.0", "react": "~18.3.1", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4" }, diff --git a/package.json b/package.json index 13c353eca..d3ca70917 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "@codingame/esbuild-import-meta-url-plugin": "~1.0.2", "@codingame/monaco-vscode-rollup-vsix-plugin": "~8.0.4", "@rollup/pluginutils": "~5.1.0", - "@testing-library/react": "~16.0.0", - "@types/node": "~20.14.15", - "@types/react": "~18.3.4", + "@testing-library/react": "~16.0.1", + "@types/node": "~20.16.5", + "@types/react": "~18.3.5", "@types/react-dom": "~18.3.0", "@types/vscode": "~1.92.0", "@typescript-eslint/eslint-plugin": "~7.18.0", @@ -23,14 +23,14 @@ "http-server": "~14.1.1", "minimatch": "~10.0.1", "typescript": "~5.5.4", - "vite": "~5.4.2", + "vite": "~5.4.3", "vite-node": "~2.0.5", "vitest": "~2.0.5", - "webdriverio": "~9.0.6" + "webdriverio": "~9.0.7" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "scripts": { "clean": "npm run clean --workspaces", diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index 523b90d4f..559d25601 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this npm module are documented in this file. +## [9.0.0-next.0] - 2024-08-26 + +- Pass MessageTransports directly + ## [8.8.3] - 2024-08-26 - Update to monaco-vscode-api 8.0.4 (monaco-editor 0.51.0) diff --git a/packages/client/package.json b/packages/client/package.json index 0ac9e208c..dd8e84871 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "monaco-languageclient", - "version": "8.8.3", + "version": "9.0.0-next.0", "description": "Monaco Language client implementation", "author": { "name": "TypeFox GmbH", @@ -51,8 +51,8 @@ "npm": ">=9.0.0" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "files": [ "lib", diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts new file mode 100644 index 000000000..9a3bd7ed9 --- /dev/null +++ b/packages/client/src/client.ts @@ -0,0 +1,26 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) 2024 TypeFox and others. + * Licensed under the MIT License. See LICENSE in the package root for license information. + * ------------------------------------------------------------------------------------------ */ + +import { BaseLanguageClient, MessageTransports, LanguageClientOptions } from 'vscode-languageclient/browser.js'; + +export type MonacoLanguageClientOptions = { + name: string; + id?: string; + clientOptions: LanguageClientOptions; + messageTransports: MessageTransports; +} + +export class MonacoLanguageClient extends BaseLanguageClient { + protected readonly 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); + } +} diff --git a/packages/wrapper/src/commonTypes.ts b/packages/client/src/commonTypes.ts similarity index 57% rename from packages/wrapper/src/commonTypes.ts rename to packages/client/src/commonTypes.ts index 263476b10..bdc31dbad 100644 --- a/packages/wrapper/src/commonTypes.ts +++ b/packages/client/src/commonTypes.ts @@ -3,52 +3,58 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { MonacoLanguageClient } from 'monaco-languageclient'; +import { MonacoLanguageClient } from './client.js'; -export type WebSocketCallOptions = { +export type ConnetionConfigOptions = WebSocketConfigOptionsDirect | WebSocketConfigOptionsParams | WebSocketConfigOptionsUrl | WorkerConfigOptionsParams | WorkerConfigOptionsDirect; + +export interface WebSocketCallOptions { /** Adds handle on languageClient */ onCall: (languageClient?: MonacoLanguageClient) => void; /** Reports Status Of Language Client */ reportStatus?: boolean; } -export type LanguageClientConfigType = 'WebSocket' | 'WebSocketUrl' | 'WorkerConfig' | 'Worker'; - -export type WebSocketUrl = { - secured: boolean; - host: string; - port?: number; - path?: string; +export interface WebSocketConfigOptionsDirect { + $type: 'WebSocketDirect' + webSocket: WebSocket + startOptions?: WebSocketCallOptions; + stopOptions?: WebSocketCallOptions; } -export type WebSocketConfigOptions = { - $type: 'WebSocket' +export interface WebSocketUrlParams { secured: boolean; host: string; port?: number; path?: string; extraParams?: Record>; +} + +export interface WebSocketConfigOptionsParams extends WebSocketUrlParams { + $type: 'WebSocketParams' startOptions?: WebSocketCallOptions; stopOptions?: WebSocketCallOptions; } -export type WebSocketConfigOptionsUrl = { - $type: 'WebSocketUrl' +export interface WebSocketUrlString { url: string; +} + +export interface WebSocketConfigOptionsUrl extends WebSocketUrlString { + $type: 'WebSocketUrl' startOptions?: WebSocketCallOptions; stopOptions?: WebSocketCallOptions; } -export type WorkerConfigOptions = { +export interface WorkerConfigOptionsParams { $type: 'WorkerConfig' url: URL; type: 'classic' | 'module'; messagePort?: MessagePort; workerName?: string; -}; +} -export type WorkerConfigDirect = { +export interface WorkerConfigOptionsDirect { $type: 'WorkerDirect'; worker: Worker; messagePort?: MessagePort; -}; +} diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index bf4ef8e5f..de65a7bd3 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -3,28 +3,7 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { BaseLanguageClient, MessageTransports, LanguageClientOptions } from 'vscode-languageclient/lib/common/client.js'; - -export interface IConnectionProvider { - get(encoding: string): Promise; -} - -export type MonacoLanguageClientOptions = { - name: string; - id?: string; - clientOptions: LanguageClientOptions; - connectionProvider: IConnectionProvider; -} - -export class MonacoLanguageClient extends BaseLanguageClient { - protected readonly connectionProvider: IConnectionProvider; - - constructor({ id, name, clientOptions, connectionProvider }: MonacoLanguageClientOptions) { - super(id ?? name.toLowerCase(), name, clientOptions); - this.connectionProvider = connectionProvider; - } - - protected override createMessageTransports(encoding: string): Promise { - return this.connectionProvider.get(encoding); - } -} +export type * from './client.js'; +export * from './client.js'; +export type * from './commonTypes.js'; +export * from './commonTypes.js'; diff --git a/packages/client/src/vscode/services.ts b/packages/client/src/vscode/services.ts index 19e6002ae..744a591dc 100644 --- a/packages/client/src/vscode/services.ts +++ b/packages/client/src/vscode/services.ts @@ -19,12 +19,12 @@ export interface MonacoEnvironmentEnhanced extends monaco.Environment { vscodeApiInitialised?: boolean; } -export type InitializeServiceConfig = { +export interface InitializeServiceConfig { userServices?: monaco.editor.IEditorOverrideServices; enableExtHostWorker?: boolean; debugLogging?: boolean; workspaceConfig?: IWorkbenchConstructionOptions; -}; +} export const initEnhancedMonacoEnvironment = () => { const monWin = (self as Window); @@ -61,12 +61,12 @@ export const mergeServices = (services: monaco.editor.IEditorOverrideServices, o } }; -export type InitServicesInstruction = { +export interface InitServicesInstruction { serviceConfig?: InitializeServiceConfig; caller?: string; performChecks?: () => boolean; logger?: Logger; -}; +} export const initServices = async (instruction: InitServicesInstruction) => { const envEnhanced = initEnhancedMonacoEnvironment(); diff --git a/packages/client/tsconfig.src.json b/packages/client/tsconfig.src.json index fe6194cd2..33c4b69bf 100644 --- a/packages/client/tsconfig.src.json +++ b/packages/client/tsconfig.src.json @@ -4,9 +4,10 @@ "rootDir": "src", "outDir": "lib", "declarationDir": "lib", - "types": [ - "vscode" - ] + // because vscode-jsonrpc requires DedicatedWorkerGlobalScope + // we are required to include both DOM and WebWorker libs + // the only way out currently is to disable lib checking + "skipLibCheck": true }, "include": [ "src/**/*.ts", diff --git a/packages/examples/CHANGELOG.md b/packages/examples/CHANGELOG.md index 995d2f26a..b0b521bca 100644 --- a/packages/examples/CHANGELOG.md +++ b/packages/examples/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this npm module are documented in this file. +## [2024.9.1] - 2024-09-xy + +- Updated to `monaco-languageclient@9.0.0-next.0`, `monaco-editor-wrapper@6.0.0-next.0` and `@typefox/monaco-editor-react@6.0.0-next.0`. Updated all `@codingame/monaco-vscode` packages to `8.0.4`. + ## [2024.8.4] - 2024-08-26 - Updated to `monaco-languageclient@8.8.3`, `monaco-editor-wrapper@5.5.3` and `@typefox/monaco-editor-react@4.5.3`. Updated all `@codingame/monaco-vscode` packages to `8.0.4`. diff --git a/packages/examples/build/downloadResources.mts b/packages/examples/build/downloadResources.mts index d62f497af..8494dcbb6 100644 --- a/packages/examples/build/downloadResources.mts +++ b/packages/examples/build/downloadResources.mts @@ -28,5 +28,12 @@ const downloadVsix = async (url: string, targetDir: string, filename: string) => } }; +// 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 downloadVsix('https://marketplace.visualstudio.com/_apis/public/gallery/publishers/GitHub/vsextensions/github-vscode-theme/6.3.4/vspackage', - resolve(getLocalDirectory(), '../resources/vsix/'), 'GitHub.github-vscode-theme-6.3.4.vsix'); + resolve(getLocalDirectory(), '../resources/vsix/'), 'github-vscode-theme.vsix'); + +// not yet used +await downloadVsix('https://marketplace.visualstudio.com/_apis/public/gallery/publishers/TypeFox/vsextensions/open-collaboration-tools/0.2.3/vspackage', + resolve(getLocalDirectory(), '../resources/vsix/'), 'open-collaboration-tools.vsix'); diff --git a/packages/examples/package.json b/packages/examples/package.json index 60473c769..2ce10f289 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -1,6 +1,6 @@ { "name": "monaco-languageclient-examples", - "version": "2024.8.4", + "version": "2024.9.1", "description": "Monaco Language client examples", "author": { "name": "TypeFox GmbH", @@ -72,18 +72,18 @@ "@codingame/monaco-vscode-theme-service-override": "~8.0.4", "@codingame/monaco-vscode-typescript-basics-default-extension": "~8.0.4", "@codingame/monaco-vscode-typescript-language-features-default-extension": "~8.0.4", - "@typefox/monaco-editor-react": "~4.5.3", + "@typefox/monaco-editor-react": "~6.0.0-next.0", "express": "~4.19.2", "langium": "~3.1.3", "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3", - "monaco-languageclient": "~8.8.3", - "pyright": "~1.1.377", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient": "~9.0.0-next.0", + "pyright": "~1.1.379", "react": "~18.3.1", "react-dom": "~18.3.1", "request-light": "~0.8.0", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4", - "vscode-json-languageservice": "~5.4.0", + "vscode-json-languageservice": "~5.4.1", "vscode-languageclient": "~9.0.1", "vscode-languageserver": "~9.0.1", "vscode-uri": "~3.0.8", @@ -98,8 +98,8 @@ "vscode-languageserver-types": "~3.17.5" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "files": [ "dist", diff --git a/packages/examples/src/bare/client.ts b/packages/examples/src/bare/client.ts index 1a020b45c..8e6ca5e1e 100644 --- a/packages/examples/src/bare/client.ts +++ b/packages/examples/src/bare/client.ts @@ -13,7 +13,7 @@ import '@codingame/monaco-vscode-theme-defaults-default-extension'; import '@codingame/monaco-vscode-json-default-extension'; import { MonacoLanguageClient } from 'monaco-languageclient'; import { WebSocketMessageReader, WebSocketMessageWriter, toSocket } from 'vscode-ws-jsonrpc'; -import { CloseAction, ErrorAction, MessageTransports } from 'vscode-languageclient'; +import { CloseAction, ErrorAction, MessageTransports } from 'vscode-languageclient/browser.js'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; export const configureMonacoWorkers = () => { @@ -73,7 +73,7 @@ export const initWebSocketAndStartClient = (url: string): WebSocket => { return webSocket; }; -export const createLanguageClient = (transports: MessageTransports): MonacoLanguageClient => { +export const createLanguageClient = (messageTransports: MessageTransports): MonacoLanguageClient => { return new MonacoLanguageClient({ name: 'Sample Language Client', clientOptions: { @@ -86,10 +86,6 @@ export const createLanguageClient = (transports: MessageTransports): MonacoLangu } }, // create a language client connection from the JSON RPC connection on demand - connectionProvider: { - get: () => { - return Promise.resolve(transports); - } - } + messageTransports }); }; diff --git a/packages/examples/src/browser/main.ts b/packages/examples/src/browser/main.ts index 3b0ad381c..0ea6f7d31 100644 --- a/packages/examples/src/browser/main.ts +++ b/packages/examples/src/browser/main.ts @@ -10,7 +10,7 @@ import '@codingame/monaco-vscode-json-default-extension'; import { getLanguageService, TextDocument } from 'vscode-json-languageservice'; import { createConverter as createCodeConverter } from 'vscode-languageclient/lib/common/codeConverter.js'; import { createConverter as createProtocolConverter } from 'vscode-languageclient/lib/common/protocolConverter.js'; -import { MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; +import { MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; export const configureMonacoWorkers = () => { @@ -36,30 +36,28 @@ export const runBrowserEditor = async () => { const codeUri = '/workspace/model.json'; const wrapper = new MonacoEditorLanguageClientWrapper(); - const jsonClientUserConfig: UserConfig = { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride(), - }, - debugLogging: true + const jsonClientUserConfig: WrapperConfig = { + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride(), }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: code, - uri: codeUri - } - }, - useDiffEditor: false, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.lightbulb.enabled': 'On' - }) + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: code, + uri: codeUri } + }, + useDiffEditor: false, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.lightbulb.enabled': 'On' + }) } } }; diff --git a/packages/examples/src/common/client/utils.ts b/packages/examples/src/common/client/utils.ts new file mode 100644 index 000000000..f06902591 --- /dev/null +++ b/packages/examples/src/common/client/utils.ts @@ -0,0 +1,11 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) 2024 TypeFox and others. + * Licensed under the MIT License. See LICENSE in the package root for license information. + * ------------------------------------------------------------------------------------------ */ + +export const disableButton = (id: string, disabled: boolean) => { + const button = document.getElementById(id) as HTMLButtonElement | null; + if (button !== null) { + button.disabled = disabled; + } +}; diff --git a/packages/examples/src/common/node/server-commons.ts b/packages/examples/src/common/node/server-commons.ts index 55af67eef..bf95c60ef 100644 --- a/packages/examples/src/common/node/server-commons.ts +++ b/packages/examples/src/common/node/server-commons.ts @@ -10,7 +10,7 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { IWebSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'; import { createConnection, createServerProcess, forward } from 'vscode-ws-jsonrpc/server'; -import { Message, InitializeRequest, InitializeParams } from 'vscode-languageserver'; +import { Message, InitializeRequest, InitializeParams, RequestMessage, ResponseMessage } from 'vscode-languageserver-protocol'; import * as cp from 'child_process'; export enum LanguageName { @@ -28,6 +28,9 @@ export interface LanguageServerRunConfig { runCommandArgs: string[]; wsServerOptions: ServerOptions, spawnOptions?: cp.SpawnOptions; + logMessages?: boolean; + requestMessageHandler?: (message: RequestMessage) => RequestMessage; + responseMessageHandler?: (message: ResponseMessage) => ResponseMessage; } /** @@ -43,16 +46,27 @@ export const launchLanguageServer = (runconfig: LanguageServerRunConfig, socket: if (serverConnection) { forward(socketConnection, serverConnection, message => { if (Message.isRequest(message)) { - console.log(`${serverName} Server received:`); - console.log(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)) { - console.log(`${serverName} Server sent:`); - console.log(message); + if (runconfig.logMessages ?? false) { + console.log(`${serverName} Server sent:`); + console.log(message); + } + if (runconfig.responseMessageHandler !== undefined) { + return runconfig.responseMessageHandler(message); + } } return message; }); @@ -76,7 +90,6 @@ export const upgradeWsServer = (runconfig: LanguageServerRunConfig, } }), onMessage: cb => webSocket.on('message', (data) => { - console.log(data.toString()); cb(data); }), onError: cb => webSocket.on('error', cb), diff --git a/packages/examples/src/eclipse.jdt.ls/client/main.ts b/packages/examples/src/eclipse.jdt.ls/client/main.ts index 895a915b9..f4d0ebc3d 100644 --- a/packages/examples/src/eclipse.jdt.ls/client/main.ts +++ b/packages/examples/src/eclipse.jdt.ls/client/main.ts @@ -7,10 +7,10 @@ import * as vscode from 'vscode'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; // this is required syntax highlighting import '@codingame/monaco-vscode-java-default-extension'; -import { MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; +import { MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'; -import { eclipseJdtLsConfig } from '../config'; +import { eclipseJdtLsConfig } from '../config.js'; import helloJavaCode from '../../../resources/eclipse.jdt.ls/workspace/hello.java?raw'; export const configureMonacoWorkers = () => { @@ -28,46 +28,49 @@ export const runEclipseJdtLsClient = () => { fileSystemProvider.registerFile(new RegisteredMemoryFile(helloJavaUri, helloJavaCode)); registerFileSystemOverlay(1, fileSystemProvider); - const userConfig: UserConfig = { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride(), - }, - debugLogging: true + const userConfig: WrapperConfig = { + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride(), }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: helloJavaCode, - uri: `${eclipseJdtLsConfig.basePath}/workspace/hello.java` - } - }, - useDiffEditor: false, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off' - }) + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: helloJavaCode, + uri: `${eclipseJdtLsConfig.basePath}/workspace/hello.java` } + }, + useDiffEditor: false, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off' + }) } + }, - languageClientConfig: { - languageId: 'java', - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:30003/jdtls' - }, - clientOptions: { - documentSelector: ['java'], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.parse(`${eclipseJdtLsConfig.basePath}/workspace`) + languageClientConfigs: { + java: { + languageId: 'java', + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:30003/jdtls' + } }, - }, + clientOptions: { + documentSelector: ['java'], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.parse(`${eclipseJdtLsConfig.basePath}/workspace`) + } + } + } } }; diff --git a/packages/examples/src/groovy/client/main.ts b/packages/examples/src/groovy/client/main.ts index 9996c2e96..95720250a 100644 --- a/packages/examples/src/groovy/client/main.ts +++ b/packages/examples/src/groovy/client/main.ts @@ -6,7 +6,7 @@ import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; // this is required syntax highlighting import '@codingame/monaco-vscode-groovy-default-extension'; -import { MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; +import { MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; import { groovyConfig } from '../config.js'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; @@ -24,37 +24,39 @@ import java.io.File; File file = new File("E:/Example.txt"); `; -const userConfig: UserConfig = { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride(), - }, - debugLogging: true +const userConfig: WrapperConfig = { + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride(), }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: code, - fileExt: 'groovy' - } - }, - useDiffEditor: false, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off' - }) + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: code, + fileExt: 'groovy' } + }, + useDiffEditor: false, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off' + }) } }, - languageClientConfig: { - languageId: 'groovy', - options: { - $type: 'WebSocketUrl', - url: `ws://localhost:${groovyConfig.port}${groovyConfig.path}` + languageClientConfigs: { + groovy: { + languageId: 'groovy', + connection: { + options: { + $type: 'WebSocketUrl', + url: `ws://localhost:${groovyConfig.port}${groovyConfig.path}` + } + } } } }; diff --git a/packages/examples/src/json/client/wrapperWs.ts b/packages/examples/src/json/client/wrapperWs.ts index 3582b2f9d..7460bb188 100644 --- a/packages/examples/src/json/client/wrapperWs.ts +++ b/packages/examples/src/json/client/wrapperWs.ts @@ -6,7 +6,7 @@ import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; // this is required syntax highlighting import '@codingame/monaco-vscode-json-default-extension'; -import { MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; +import { MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; export const configureMonacoWorkers = () => { @@ -24,49 +24,51 @@ const text = `{ "line_endings": {"value": "unix"} }`; -export const jsonClientUserConfig: UserConfig = { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride(), - }, - debugLogging: true +export const jsonClientUserConfig: WrapperConfig = { + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride(), }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text, - fileExt: 'json' - } - }, - useDiffEditor: false, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.lightbulb.enabled': 'On', - 'editor.wordBasedSuggestions': 'off' - }) + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text, + fileExt: 'json' } + }, + useDiffEditor: false, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.lightbulb.enabled': 'On', + 'editor.wordBasedSuggestions': 'off' + }) } }, - languageClientConfig: { - languageId: 'json', - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:30000/sampleServer', - startOptions: { - onCall: () => { - console.log('Connected to socket.'); - }, - reportStatus: true - }, - stopOptions: { - onCall: () => { - console.log('Disconnected from socket.'); - }, - reportStatus: true + languageClientConfigs: { + json: { + languageId: 'json', + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:30000/sampleServer', + startOptions: { + onCall: () => { + console.log('Connected to socket.'); + }, + reportStatus: true + }, + stopOptions: { + onCall: () => { + console.log('Disconnected from socket.'); + }, + reportStatus: true + } + } } } } diff --git a/packages/examples/src/langium/langium-dsl/config/classicConfig.ts b/packages/examples/src/langium/langium-dsl/config/classicConfig.ts index 2cb396efa..488e76162 100644 --- a/packages/examples/src/langium/langium-dsl/config/classicConfig.ts +++ b/packages/examples/src/langium/langium-dsl/config/classicConfig.ts @@ -7,53 +7,55 @@ import getConfigurationServiceOverride from '@codingame/monaco-vscode-configurat import getEditorServiceOverride from '@codingame/monaco-vscode-editor-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import { useOpenEditorStub } from 'monaco-editor-wrapper/vscode/services'; -import { UserConfig } from 'monaco-editor-wrapper'; +import { WrapperConfig } from 'monaco-editor-wrapper'; import { LangiumMonarchContent } from './langium.monarch.js'; import { loadLangiumWorker } from '../wrapperLangium.js'; import code from '../content/example.langium?raw'; -export const setupLangiumClientClassic = async (): Promise => { +export const setupLangiumClientClassic = async (): Promise => { const langiumWorker = loadLangiumWorker(); return { loggerConfig: { enabled: true, debugEnabled: true }, - wrapperConfig: { - serviceConfig: { - userServices: { - ...getConfigurationServiceOverride(), - ...getEditorServiceOverride(useOpenEditorStub), - ...getKeybindingsServiceOverride() - }, - debugLogging: true + serviceConfig: { + userServices: { + ...getConfigurationServiceOverride(), + ...getEditorServiceOverride(useOpenEditorStub), + ...getKeybindingsServiceOverride() }, - editorAppConfig: { - $type: 'classic', - codeResources: { - main: { - text: code, - fileExt: 'langium', - enforceLanguageId: 'langium' - } - }, - useDiffEditor: false, - editorOptions: { - 'semanticHighlighting.enabled': true, - wordBasedSuggestions: 'off', - theme: 'vs-dark' - }, - languageDef: { - monarchLanguage: LangiumMonarchContent, - languageExtensionConfig: { id: 'langium' }, + debugLogging: true + }, + editorAppConfig: { + $type: 'classic', + codeResources: { + main: { + text: code, + fileExt: 'langium', + enforceLanguageId: 'langium' } + }, + useDiffEditor: false, + editorOptions: { + 'semanticHighlighting.enabled': true, + wordBasedSuggestions: 'off', + theme: 'vs-dark' + }, + languageDef: { + monarchLanguage: LangiumMonarchContent, + languageExtensionConfig: { id: 'langium' }, } }, - languageClientConfig: { - languageId: 'langium', - options: { - $type: 'WorkerDirect', - worker: langiumWorker + languageClientConfigs: { + langium: { + languageId: 'langium', + connection: { + options: { + $type: 'WorkerDirect', + worker: langiumWorker + } + } } } }; diff --git a/packages/examples/src/langium/langium-dsl/config/extendedConfig.ts b/packages/examples/src/langium/langium-dsl/config/extendedConfig.ts index 425ffc76d..5cc60226b 100644 --- a/packages/examples/src/langium/langium-dsl/config/extendedConfig.ts +++ b/packages/examples/src/langium/langium-dsl/config/extendedConfig.ts @@ -5,16 +5,16 @@ import getEditorServiceOverride from '@codingame/monaco-vscode-editor-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; -import '../../../../resources/vsix/GitHub.github-vscode-theme-6.3.4.vsix'; +import '../../../../resources/vsix/github-vscode-theme.vsix'; import { useOpenEditorStub } from 'monaco-editor-wrapper/vscode/services'; -import { UserConfig } from 'monaco-editor-wrapper'; +import { WrapperConfig } from 'monaco-editor-wrapper'; import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageclient/browser.js'; import { loadLangiumWorker } from '../wrapperLangium.js'; import langiumLanguageConfig from './langium.configuration.json?raw'; import langiumTextmateGrammar from './langium.tmLanguage.json?raw'; import text from '../content/example.langium?raw'; -export const setupLangiumClientExtended = async (): Promise => { +export const setupLangiumClientExtended = async (): Promise => { const extensionFilesOrContents = new Map(); // vite build is easier with string content @@ -26,64 +26,64 @@ export const setupLangiumClientExtended = async (): Promise => { const writer = new BrowserMessageWriter(langiumWorker); return { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getEditorServiceOverride(useOpenEditorStub), - ...getKeybindingsServiceOverride() - }, - debugLogging: true + serviceConfig: { + userServices: { + ...getEditorServiceOverride(useOpenEditorStub), + ...getKeybindingsServiceOverride() }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text, - fileExt: 'langium' + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text, + fileExt: 'langium' + } + }, + useDiffEditor: false, + extensions: [{ + config: { + name: 'langium-example', + publisher: 'monaco-editor-wrapper-examples', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [{ + id: 'langium', + extensions: ['.langium'], + aliases: ['langium', 'LANGIUM'], + configuration: './langium-configuration.json' + }], + grammars: [{ + language: 'langium', + scopeName: 'source.langium', + path: './langium-grammar.json' + }] } }, - useDiffEditor: false, - extensions: [{ - config: { - name: 'langium-example', - publisher: 'monaco-editor-wrapper-examples', - version: '1.0.0', - engines: { - vscode: '*' - }, - contributes: { - languages: [{ - id: 'langium', - extensions: ['.langium'], - aliases: ['langium', 'LANGIUM'], - configuration: './langium-configuration.json' - }], - grammars: [{ - language: 'langium', - scopeName: 'source.langium', - path: './langium-grammar.json' - }] - } - }, - filesOrContents: extensionFilesOrContents - }], - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'GitHub Dark High Contrast', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off' - }) - } + filesOrContents: extensionFilesOrContents + }], + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'GitHub Dark High Contrast', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off' + }) } }, - languageClientConfig: { - languageId: 'langium', - options: { - $type: 'WorkerDirect', - worker: langiumWorker - }, - connectionProvider: { - get: async () => ({ reader, writer }), + languageClientConfigs: { + langium: { + languageId: 'langium', + connection: { + options: { + $type: 'WorkerDirect', + worker: langiumWorker + }, + messageTransports: { reader, writer } + } } } }; diff --git a/packages/examples/src/langium/langium-dsl/wrapperLangium.ts b/packages/examples/src/langium/langium-dsl/wrapperLangium.ts index 20713d10e..9ca1aacae 100644 --- a/packages/examples/src/langium/langium-dsl/wrapperLangium.ts +++ b/packages/examples/src/langium/langium-dsl/wrapperLangium.ts @@ -8,6 +8,7 @@ import { setupLangiumClientExtended } from './config/extendedConfig.js'; import { setupLangiumClientClassic } from './config/classicConfig.js'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; import workerUrl from './worker/langium-server?worker&url'; +import { disableButton } from '../../common/client/utils.js'; let wrapper: MonacoEditorLanguageClientWrapper | undefined; let extended = false; @@ -67,13 +68,6 @@ const checkStarted = () => { return false; }; -const disableButton = (id: string, disabled: boolean) => { - const button = document.getElementById(id) as HTMLButtonElement | null; - if (button !== null) { - button.disabled = disabled; - } -}; - export const disposeEditor = async () => { if (!wrapper) return; wrapper.reportStatus(); diff --git a/packages/examples/src/langium/statemachine/config/wrapperStatemachineConfig.ts b/packages/examples/src/langium/statemachine/config/wrapperStatemachineConfig.ts index cae12bddf..e54abc400 100644 --- a/packages/examples/src/langium/statemachine/config/wrapperStatemachineConfig.ts +++ b/packages/examples/src/langium/statemachine/config/wrapperStatemachineConfig.ts @@ -6,12 +6,12 @@ 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'; -import { IConnectionProvider } from 'monaco-languageclient'; import { createDefaultLocaleConfiguration } from 'monaco-languageclient/vscode/services'; -import { LanguageClientConfig, UserConfig } from 'monaco-editor-wrapper'; +import { LanguageClientConfig, WrapperConfig } from 'monaco-editor-wrapper'; // cannot be imported with assert as json contains comments import statemachineLanguageConfig from './language-configuration.json?raw'; import responseStatemachineTm from '../syntaxes/statemachine.tmLanguage.json?raw'; +import { MessageTransports } from 'vscode-languageclient'; export const createLangiumGlobalConfig = async (params: { languageServerId: string, @@ -19,8 +19,8 @@ export const createLangiumGlobalConfig = async (params: { text?: string, worker?: Worker, messagePort?: MessagePort, - connectionProvider?: IConnectionProvider -}): Promise => { + messageTransports?: MessageTransports +}): Promise => { const extensionFilesOrContents = new Map(); extensionFilesOrContents.set(`/${params.languageServerId}-statemachine-configuration.json`, statemachineLanguageConfig); extensionFilesOrContents.set(`/${params.languageServerId}-statemachine-grammar.json`, responseStatemachineTm); @@ -33,66 +33,68 @@ export const createLangiumGlobalConfig = async (params: { }; } - const languageClientConfig: LanguageClientConfig | undefined = params.useLanguageClient && params.worker ? { - languageId: 'statemachine', - options: { - $type: 'WorkerDirect', - worker: params.worker, - messagePort: params.messagePort, - }, - connectionProvider: params.connectionProvider + const languageClientConfigs: Record | undefined = params.useLanguageClient && params.worker ? { + statemachine: { + languageId: 'statemachine', + connection: { + options: { + $type: 'WorkerDirect', + worker: params.worker, + messagePort: params.messagePort, + }, + messageTransports: params.messageTransports + } + } } : undefined; return { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride(), - ...getLifecycleServiceOverride(), - ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), - }, - debugLogging: true + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride(), + ...getLifecycleServiceOverride(), + ...getLocalizationServiceOverride(createDefaultLocaleConfiguration()), }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main - }, - useDiffEditor: false, - extensions: [{ - config: { - name: 'statemachine-example', - publisher: 'monaco-editor-wrapper-examples', - 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` - }] - } + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main + }, + useDiffEditor: false, + extensions: [{ + config: { + name: 'statemachine-example', + publisher: 'monaco-editor-wrapper-examples', + version: '1.0.0', + engines: { + vscode: '*' }, - filesOrContents: extensionFilesOrContents - }], - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off' - }) - } + 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 + }], + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off' + }) } }, - languageClientConfig, + languageClientConfigs, loggerConfig: { enabled: true, debugEnabled: true diff --git a/packages/examples/src/langium/statemachine/main-react.tsx b/packages/examples/src/langium/statemachine/main-react.tsx index 3ba131a42..3543116eb 100644 --- a/packages/examples/src/langium/statemachine/main-react.tsx +++ b/packages/examples/src/langium/statemachine/main-react.tsx @@ -48,7 +48,7 @@ export const runStatemachineReact = async () => {
+ wrapperConfig={langiumGlobalConfig} />
); }; diff --git a/packages/examples/src/langium/statemachine/main.ts b/packages/examples/src/langium/statemachine/main.ts index 48e5bc06c..a64819925 100644 --- a/packages/examples/src/langium/statemachine/main.ts +++ b/packages/examples/src/langium/statemachine/main.ts @@ -55,9 +55,7 @@ const startEditor = async () => { useLanguageClient: true, worker: stateMachineWorkerPort, messagePort: channel.port1, - connectionProvider: { - get: async () => ({ reader, writer }) - } + messageTransports: { reader, writer } }); await wrapper.initAndStart(langiumGlobalConfig, document.getElementById('monaco-editor-root')); diff --git a/packages/examples/src/multi/twoLanguageClients.ts b/packages/examples/src/multi/twoLanguageClients.ts new file mode 100644 index 000000000..d4085e14f --- /dev/null +++ b/packages/examples/src/multi/twoLanguageClients.ts @@ -0,0 +1,149 @@ +/* -------------------------------------------------------------------------------------------- + * 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 getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; +// this is required syntax highlighting +import '@codingame/monaco-vscode-json-default-extension'; +import '@codingame/monaco-vscode-python-default-extension'; +import { CodePlusFileExt, MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; +import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; +import { MonacoLanguageClient } from 'monaco-languageclient'; +import { disableButton } from '../common/client/utils.js'; + +export const configureMonacoWorkers = () => { + useWorkerFactory({ + ignoreMapping: true, + workerLoaders: { + editorWorkerService: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }) + } + }); +}; + +export const runMultipleLanguageClientsExample = async () => { + disableButton('button-flip', true); + + const textJson = `{ + "$schema": "http://json.schemastore.org/coffeelint", + "line_endings": {"value": "unix"} +}`; + + const textPython = `from hello2 import print_hello + +print_hello() +print("Hello Moon!") +`; + + let currentText = textJson; + let currenFileExt = 'json'; + + const wrapperConfig: WrapperConfig = { + id: '42', + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride() + }, + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: currentText, + fileExt: currenFileExt + } + }, + useDiffEditor: false, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.wordBasedSuggestions': 'off' + }) + } + }, + languageClientConfigs: { + json: { + languageId: 'json', + name: 'JSON Client', + connection: { + options: { + $type: 'WebSocketParams', + host: 'localhost', + port: 30000, + path: 'sampleServer', + secured: false + } + } + }, + python: { + languageId: 'python', + name: 'Python Client', + connection: { + options: { + $type: 'WebSocketParams', + host: 'localhost', + port: 30001, + path: 'pyright', + secured: false, + extraParams: { + authorization: 'UserAuth' + }, + startOptions: { + onCall: (languageClient?: MonacoLanguageClient) => { + setTimeout(() => { + ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { + vscode.commands.registerCommand(cmdName, (...args: unknown[]) => { + 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') + } + } + } + } + }; + + const htmlElement = document.getElementById('monaco-editor-root'); + const wrapper = new MonacoEditorLanguageClientWrapper(); + + try { + document.querySelector('#button-start')?.addEventListener('click', async () => { + if (wrapperConfig.editorAppConfig.codeResources?.main !== undefined) { + (wrapperConfig.editorAppConfig.codeResources.main as CodePlusFileExt).text = currentText; + (wrapperConfig.editorAppConfig.codeResources.main as CodePlusFileExt).fileExt = currenFileExt; + } + + await wrapper.initAndStart(wrapperConfig, htmlElement); + disableButton('button-flip', false); + }); + document.querySelector('#button-dispose')?.addEventListener('click', async () => { + await wrapper.dispose(); + disableButton('button-flip', true); + }); + document.querySelector('#button-flip')?.addEventListener('click', async () => { + currentText = currentText === textJson ? textPython : textJson; + currenFileExt = currenFileExt === 'json' ? 'py' : 'json'; + wrapper.updateCodeResources({ + main: { + text: currentText, + fileExt: currenFileExt + } + }); + }); + } catch (e) { + console.error(e); + } +}; diff --git a/packages/examples/src/python/client/config.ts b/packages/examples/src/python/client/config.ts index cdb670e5a..72b5fa352 100644 --- a/packages/examples/src/python/client/config.ts +++ b/packages/examples/src/python/client/config.ts @@ -7,71 +7,83 @@ import * as vscode from 'vscode'; import getEditorServiceOverride from '@codingame/monaco-vscode-editor-service-override'; import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; import '@codingame/monaco-vscode-python-default-extension'; -import { UserConfig } from 'monaco-editor-wrapper'; +import { createUrl, WrapperConfig } from 'monaco-editor-wrapper'; import { useOpenEditorStub } from 'monaco-editor-wrapper/vscode/services'; import { MonacoLanguageClient } from 'monaco-languageclient'; +import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'; + +export const createUserConfig = (workspaceRoot: string, code: string, codeUri: string): WrapperConfig => { + 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); -export const createUserConfig = (workspaceRoot: string, code: string, codeUri: string): UserConfig => { return { - languageClientConfig: { - languageId: 'python', - name: 'Python Language Server Example', - options: { - $type: 'WebSocket', - host: 'localhost', - port: 30001, - path: 'pyright', - extraParams: { - authorization: 'UserAuth' + languageClientConfigs: { + python: { + languageId: 'python', + name: 'Python Language Server Example', + connection: { + options: { + $type: 'WebSocketDirect', + webSocket: webSocket, + startOptions: { + onCall: (languageClient?: MonacoLanguageClient) => { + setTimeout(() => { + ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { + vscode.commands.registerCommand(cmdName, (...args: unknown[]) => { + languageClient?.sendRequest('workspace/executeCommand', { command: cmdName, arguments: args }); + }); + }); + }, 250); + }, + reportStatus: true, + } + }, + messageTransports: { reader, writer } }, - secured: false, - startOptions: { - onCall: (languageClient?: MonacoLanguageClient) => { - setTimeout(() => { - ['pyright.restartserver', 'pyright.organizeimports'].forEach((cmdName) => { - vscode.commands.registerCommand(cmdName, (...args: unknown[]) => { - languageClient?.sendRequest('workspace/executeCommand', { command: cmdName, arguments: args }); - }); - }); - }, 250); + clientOptions: { + documentSelector: ['python'], + workspaceFolder: { + index: 0, + name: 'workspace', + uri: vscode.Uri.parse(workspaceRoot) }, - reportStatus: true, } + } + }, + serviceConfig: { + userServices: { + ...getEditorServiceOverride(useOpenEditorStub), + ...getKeybindingsServiceOverride() }, - clientOptions: { - documentSelector: ['python'], - workspaceFolder: { - index: 0, - name: 'workspace', - uri: vscode.Uri.parse(workspaceRoot) - }, - }, + debugLogging: true }, - wrapperConfig: { - serviceConfig: { - userServices: { - ...getEditorServiceOverride(useOpenEditorStub), - ...getKeybindingsServiceOverride() - }, - debugLogging: true + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: code, + uri: codeUri + } }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: code, - uri: codeUri - } - }, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'editor.guides.bracketPairsHorizontal': 'active', - 'editor.wordBasedSuggestions': 'off' - }) - }, - useDiffEditor: false - } + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.guides.bracketPairsHorizontal': 'active', + 'editor.wordBasedSuggestions': 'off' + }) + }, + useDiffEditor: false }, loggerConfig: { enabled: true, diff --git a/packages/examples/src/python/client/reactPython.tsx b/packages/examples/src/python/client/reactPython.tsx index b644d9c1e..38d35849a 100644 --- a/packages/examples/src/python/client/reactPython.tsx +++ b/packages/examples/src/python/client/reactPython.tsx @@ -41,7 +41,7 @@ export const runPythonReact = async () => { return (
{ diff --git a/packages/examples/src/python/server/main.ts b/packages/examples/src/python/server/main.ts index 684f9b6e9..1e736b5df 100644 --- a/packages/examples/src/python/server/main.ts +++ b/packages/examples/src/python/server/main.ts @@ -35,6 +35,7 @@ export const runPythonServer = (baseDir: string, relativeDir: string) => { callback(false); } } - } + }, + logMessages: true }); }; diff --git a/packages/examples/src/ts/wrapperAdvanced.ts b/packages/examples/src/ts/wrapperAdvanced.ts deleted file mode 100644 index a8e80dab8..000000000 --- a/packages/examples/src/ts/wrapperAdvanced.ts +++ /dev/null @@ -1,236 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2024 TypeFox and others. - * Licensed under the MIT License. See LICENSE in the package root for license information. - * ------------------------------------------------------------------------------------------ */ - -import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; -import '@codingame/monaco-vscode-standalone-languages'; -import '@codingame/monaco-vscode-standalone-typescript-language-features'; -import { EditorAppConfigClassic, LanguageClientError, MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; -import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; - -export const configureMonacoWorkers = () => { - useWorkerFactory({ - ignoreMapping: true, - workerLoaders: { - editorWorkerService: () => new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }), - javascript: () => new Worker(new URL('monaco-editor-wrapper/workers/module/ts', import.meta.url), { type: 'module' }), - } - }); -}; - -const wrapper42 = new MonacoEditorLanguageClientWrapper(); -const wrapper43 = new MonacoEditorLanguageClientWrapper(); -const wrapper44 = new MonacoEditorLanguageClientWrapper(); - -const wrapper42Config: UserConfig = { - id: '42', - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride() - }, - debugLogging: true - }, - editorAppConfig: { - $type: 'classic', - codeResources: { - original: { - text: `This line is equal. -This number is different 2002 -Misspeelled! -Same again.`, - fileExt: 'txt' - }, - main: { - text: `This line is equal. -This number is different 2022 -Misspelled! -Same again.`, - fileExt: 'txt' - } - }, - useDiffEditor: true, - } - }, - languageClientConfig: { - languageId: 'json', - name: 'wrapper42 language client', - options: { - $type: 'WebSocket', - host: 'localhost', - port: 30000, - path: 'sampleServer', - secured: false - } - } -}; - -const wrapper43Config: UserConfig = { - id: '43', - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride() - }, - debugLogging: true - }, - editorAppConfig: { - $type: 'classic', - codeResources: { - original: { - text: 'This line is equal.\nThis number is different 3022.\nMisspelled!Same again.', - fileExt: 'txt' - }, - main: { - text: 'This line is equal.\nThis number is different 3002.\nMisspelled!Same again.', - fileExt: 'txt' - } - }, - useDiffEditor: true, - editorOptions: { - lineNumbers: 'off' - }, - diffEditorOptions: { - lineNumbers: 'off' - } - } - } -}; - -const wrapper44Config: UserConfig = { - id: '44', - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride() - }, - debugLogging: true - }, - editorAppConfig: { - $type: 'classic', - codeResources: { - main: { - text: `function logMe() { - console.log('Hello monaco-editor-wrapper!'); -};`, - fileExt: 'js' - } - }, - useDiffEditor: false, - editorOptions: { - minimap: { - enabled: true - }, - theme: 'vs-dark' - } - } - } -}; - -const startWrapper42 = async () => { - await wrapper42.initAndStart(wrapper42Config, document.getElementById('monaco-editor-root-42')); - console.log('wrapper42 was started.'); -}; - -const startWrapper43 = async () => { - await wrapper43.initAndStart(wrapper43Config, document.getElementById('monaco-editor-root-43')); - console.log('wrapper43 was started.'); -}; -const startWrapper44 = async () => { - await wrapper44.initAndStart(wrapper44Config, document.getElementById('monaco-editor-root-44')); - console.log('wrapper44 was started.'); -}; - -const sleepOne = (milliseconds: number) => { - setTimeout(async () => { - alert(`Updating editors after ${milliseconds}ms`); - - await wrapper42.dispose(); - wrapper42Config.languageClientConfig = undefined; - const appConfig42 = wrapper42Config.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - appConfig42.codeResources = { - main: { - text: `function logMe() { - console.log('Hello swap editors!'); -};`, - fileExt: 'js' - } - }; - appConfig42.useDiffEditor = false; - const w42Start = wrapper42.initAndStart(wrapper42Config, document.getElementById('monaco-editor-root-42')); - - const w43Start = await wrapper43.updateCodeResources({ - main: { - text: 'text 5678', - fileExt: 'txt' - }, - original: { - text: 'text 1234', - fileExt: 'txt' - } - }); - - await wrapper44.dispose(); - const appConfig44 = wrapper44Config.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - appConfig44.useDiffEditor = true; - appConfig44.codeResources = { - original: { - text: 'oh la la la!', - fileExt: 'txt' - }, - main: { - text: 'oh lo lo lo!', - fileExt: 'txt' - } - }; - // This affects all editors globally and is only effective - // if it is not in contrast to one configured later - appConfig44.editorOptions = { - theme: 'vs-light' - }; - const w44Start = wrapper44.initAndStart(wrapper44Config, document.getElementById('monaco-editor-root-44')); - - await w42Start; - console.log('Restarted wrapper42.'); - await w43Start; - console.log('Updated diffmodel of wrapper43.'); - await w44Start; - console.log('Restarted wrapper44.'); - }, milliseconds); -}; - -const sleepTwo = (milliseconds: number) => { - setTimeout(async () => { - alert(`Updating last editor after ${milliseconds}ms`); - - await wrapper44.dispose(); - const appConfig44 = wrapper44Config.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - appConfig44.useDiffEditor = false; - appConfig44.editorOptions = { - theme: 'vs-dark' - }; - await wrapper44.initAndStart(wrapper44Config, document.getElementById('monaco-editor-root-44')); - console.log('Restarted wrapper44.'); - }, milliseconds); -}; - -export const runAdvancedExample = async () => { - try { - await startWrapper43(); - await startWrapper44(); - try { - await startWrapper42(); - } catch (e) { - console.log(`Catched expected connection error: ${(e as LanguageClientError).message}`); - } - - // change the editors config, content or swap normal and diff editors after five seconds - sleepOne(5000); - - // change last editor to regular mode - sleepTwo(10000); - } catch (e) { - console.error(e); - } -}; diff --git a/packages/examples/src/ts/wrapperTs.ts b/packages/examples/src/ts/wrapperTs.ts index 5b10c12bb..56867bf12 100644 --- a/packages/examples/src/ts/wrapperTs.ts +++ b/packages/examples/src/ts/wrapperTs.ts @@ -8,7 +8,7 @@ import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings- import '@codingame/monaco-vscode-theme-defaults-default-extension'; import '@codingame/monaco-vscode-typescript-basics-default-extension'; import '@codingame/monaco-vscode-typescript-language-features-default-extension'; -import { CodePlusUri, MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; +import { CodePlusUri, MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; import { useWorkerFactory } from 'monaco-editor-wrapper/workerFactory'; export const configureMonacoWorkers = () => { @@ -31,39 +31,37 @@ export const runTsWrapper = async () => { return "Goodbye"; };`; - const userConfig: UserConfig = { - wrapperConfig: { - serviceConfig: { - userServices: { - ...getKeybindingsServiceOverride() - }, - enableExtHostWorker: true, - debugLogging: true + const wrapperConfig: WrapperConfig = { + serviceConfig: { + userServices: { + ...getKeybindingsServiceOverride() }, - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: code, - uri: codeUri - }, - original: { - text: codeOriginal, - uri: codeOriginalUri, - } + enableExtHostWorker: true, + debugLogging: true + }, + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: code, + uri: codeUri }, - useDiffEditor: false, - userConfiguration: { - json: JSON.stringify({ - 'workbench.colorTheme': 'Default Dark Modern', - 'typescript.tsserver.web.projectWideIntellisense.enabled': true, - 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false, - 'diffEditor.renderSideBySide': false, - 'editor.lightbulb.enabled': 'on', - 'editor.glyphMargin': true, - 'editor.guides.bracketPairsHorizontal': true - }) + original: { + text: codeOriginal, + uri: codeOriginalUri, } + }, + useDiffEditor: false, + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'typescript.tsserver.web.projectWideIntellisense.enabled': true, + 'typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors': false, + 'diffEditor.renderSideBySide': false, + 'editor.lightbulb.enabled': 'on', + 'editor.glyphMargin': true, + 'editor.guides.bracketPairsHorizontal': true + }) } } }; @@ -73,7 +71,7 @@ export const runTsWrapper = async () => { try { document.querySelector('#button-start')?.addEventListener('click', async () => { - await wrapper.initAndStart(userConfig, htmlElement); + await wrapper.initAndStart(wrapperConfig, htmlElement); vscode.commands.getCommands().then((x) => { console.log(`Found ${x.length} commands`); @@ -112,9 +110,9 @@ export const runTsWrapper = async () => { }); document.querySelector('#button-diff')?.addEventListener('click', async () => { // ensure it is boolean value and not undefined - const useDiffEditor = userConfig.wrapperConfig.editorAppConfig.useDiffEditor ?? false; - userConfig.wrapperConfig.editorAppConfig.useDiffEditor = !useDiffEditor; - await wrapper.initAndStart(userConfig, htmlElement); + const useDiffEditor = wrapperConfig.editorAppConfig.useDiffEditor ?? false; + wrapperConfig.editorAppConfig.useDiffEditor = !useDiffEditor; + await wrapper.initAndStart(wrapperConfig, htmlElement); }); document.querySelector('#button-dispose')?.addEventListener('click', async () => { await wrapper.dispose(); diff --git a/packages/examples/tsconfig.build.json b/packages/examples/tsconfig.build.json index e41c77a38..0cb7e416d 100644 --- a/packages/examples/tsconfig.build.json +++ b/packages/examples/tsconfig.build.json @@ -2,11 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "rootDir": "./build", - "noEmit": true, - // all other types are not needed here - "types": [ - "node" - ] + "noEmit": true }, "include": [ "build/**/*.ts", diff --git a/packages/examples/two_langauge_clients.html b/packages/examples/two_langauge_clients.html new file mode 100644 index 000000000..a8d6b9d31 --- /dev/null +++ b/packages/examples/two_langauge_clients.html @@ -0,0 +1,25 @@ + + + + + Json & Python Languageclients & Language Server (Web Socket) + + + + + + +

Json & Python Languageclients & Language Server (Web Socket)

+ + + +
+ + + + diff --git a/packages/examples/wrapper_adv.html b/packages/examples/wrapper_adv.html deleted file mode 100644 index e8e79f041..000000000 --- a/packages/examples/wrapper_adv.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - Multiple Editors - - - - -

Multiple Editors -
-
-
-
-
-
- - - - diff --git a/packages/examples/wrapper_ws.html b/packages/examples/wrapper_ws.html index d1fd7c2f3..82472b9bc 100644 --- a/packages/examples/wrapper_ws.html +++ b/packages/examples/wrapper_ws.html @@ -2,9 +2,9 @@ + JSON Language Client & Language Server (Web Socket) - JSON Language Client & Language Server (Web Socket) diff --git a/packages/vscode-ws-jsonrpc/package.json b/packages/vscode-ws-jsonrpc/package.json index 068865a3f..9e5f6a51c 100644 --- a/packages/vscode-ws-jsonrpc/package.json +++ b/packages/vscode-ws-jsonrpc/package.json @@ -51,8 +51,8 @@ "npm": ">=8.0.0" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "files": [ "lib", diff --git a/packages/vscode-ws-jsonrpc/tsconfig.src.json b/packages/vscode-ws-jsonrpc/tsconfig.src.json index 618618919..b7c5ac54f 100644 --- a/packages/vscode-ws-jsonrpc/tsconfig.src.json +++ b/packages/vscode-ws-jsonrpc/tsconfig.src.json @@ -3,9 +3,7 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib", - "declarationDir": "lib", - // no types definitions are required to undertand dependent code - "types": [] + "declarationDir": "lib" }, "include": [ "src/**/*.ts", diff --git a/packages/wrapper-react/CHANGELOG.md b/packages/wrapper-react/CHANGELOG.md index 715d34385..19c250728 100644 --- a/packages/wrapper-react/CHANGELOG.md +++ b/packages/wrapper-react/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to npm module [@typefox/monaco-editor-react](https://www.npmjs.com/package/@typefox/monaco-editor-react) are documented in this file. +## [6.0.0-next.0] - 2024-09-xy + +- Updated to `monaco-editor-wrapper@9.0.0-next.0` and `monaco-languageclient@6.0.0-next.0`. Updated all `@codingame/monaco-vscode` packages to `8.0.4`. + ## [4.5.3] - 2024-08-26 - Updated to `monaco-editor-wrapper@5.5.3` and `monaco-languageclient@8.8.3`. Updated all `@codingame/monaco-vscode` packages to `8.0.4`. diff --git a/packages/wrapper-react/package.json b/packages/wrapper-react/package.json index 302868429..e7fee5f18 100644 --- a/packages/wrapper-react/package.json +++ b/packages/wrapper-react/package.json @@ -1,6 +1,6 @@ { "name": "@typefox/monaco-editor-react", - "version": "4.5.3", + "version": "6.0.0-next.0", "license": "MIT", "description": "React component for Monaco-Editor and Monaco Languageclient", "keywords": [ @@ -38,20 +38,20 @@ "build": "npm run clean && npm run compile" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "dependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3", - "monaco-languageclient": "~8.8.3", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient": "~9.0.0-next.0", "react": "~18.3.1", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4" }, "peerDependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3", - "monaco-languageclient": "~8.8.3", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient": "~9.0.0-next.0", "react": "~18.3.1", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4" }, diff --git a/packages/wrapper-react/src/index.tsx b/packages/wrapper-react/src/index.tsx index 4af8680f9..475d38d79 100644 --- a/packages/wrapper-react/src/index.tsx +++ b/packages/wrapper-react/src/index.tsx @@ -5,7 +5,7 @@ import * as monaco from 'monaco-editor'; import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react'; -import { MonacoEditorLanguageClientWrapper, TextContents, UserConfig } from 'monaco-editor-wrapper'; +import { MonacoEditorLanguageClientWrapper, TextContents, WrapperConfig } from 'monaco-editor-wrapper'; import { Logger } from 'monaco-languageclient/tools'; export type TextChanges = TextContents & { @@ -15,7 +15,7 @@ export type TextChanges = TextContents & { export type MonacoEditorProps = { style?: CSSProperties; className?: string; - userConfig: UserConfig, + wrapperConfig: WrapperConfig, onTextChanged?: (textChanges: TextChanges) => void; onLoad?: (wrapper: MonacoEditorLanguageClientWrapper) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -26,7 +26,7 @@ export const MonacoEditorReactComp: React.FC = (props) => { const { style, className, - userConfig, + wrapperConfig, onTextChanged, onLoad, onError @@ -38,7 +38,7 @@ export const MonacoEditorReactComp: React.FC = (props) => { const [onTextChangedSubscriptions, setOnTextChangedSubscriptions] = useState([]); useEffect(() => { - loggerRef.current.updateConfig(userConfig.loggerConfig); + loggerRef.current.updateConfig(wrapperConfig.loggerConfig); return () => { destroyMonaco(); }; @@ -46,7 +46,7 @@ export const MonacoEditorReactComp: React.FC = (props) => { useEffect(() => { handleReInit(); - }, [userConfig]); + }, [wrapperConfig]); useEffect(() => { handleOnTextChanged(); @@ -72,11 +72,11 @@ export const MonacoEditorReactComp: React.FC = (props) => { await wrapperRef.current.isStarting(); } - }, [userConfig]); + }, [wrapperConfig]); const initMonaco = useCallback(async () => { - await wrapperRef.current.init(userConfig); - }, [userConfig]); + await wrapperRef.current.init(wrapperConfig); + }, [wrapperConfig]); const startMonaco = useCallback(async () => { if (containerRef.current) { @@ -105,7 +105,7 @@ export const MonacoEditorReactComp: React.FC = (props) => { const verifyModelContent = () => { const text = textModels.text?.getValue() ?? ''; const textOriginal = textModels.textOriginal?.getValue() ?? ''; - const codeResources = userConfig.wrapperConfig.editorAppConfig.codeResources; + const codeResources = wrapperConfig.editorAppConfig.codeResources; const dirty = text !== codeResources?.main?.text; const dirtyOriginal = textOriginal !== codeResources?.original?.text; onTextChanged({ @@ -132,7 +132,7 @@ export const MonacoEditorReactComp: React.FC = (props) => { // do it initially verifyModelContent(); } - }, [onTextChanged, userConfig]); + }, [onTextChanged, wrapperConfig]); const destroyMonaco = useCallback(async () => { try { diff --git a/packages/wrapper-react/test/index.test.tsx b/packages/wrapper-react/test/index.test.tsx index 3a4a8e399..9d16f15a4 100644 --- a/packages/wrapper-react/test/index.test.tsx +++ b/packages/wrapper-react/test/index.test.tsx @@ -7,37 +7,35 @@ import { describe, expect, test } from 'vitest'; import { render, RenderResult } from '@testing-library/react'; import React from 'react'; import { MonacoEditorReactComp, TextChanges } from '@typefox/monaco-editor-react'; -import { MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; -import { updateExtendedAppPrototyp } from './helper'; +import { MonacoEditorLanguageClientWrapper, WrapperConfig } from 'monaco-editor-wrapper'; +import { updateExtendedAppPrototyp } from './helper.js'; describe('Test MonacoEditorReactComp', () => { test('rerender', async () => { updateExtendedAppPrototyp(); - const userConfig: UserConfig = { - wrapperConfig: { - editorAppConfig: { - $type: 'extended', - } + const wrapperConfig: WrapperConfig = { + editorAppConfig: { + $type: 'extended', }, loggerConfig: { enabled: true, debugEnabled: true, } }; - const { rerender } = render(); - rerender(); + const { rerender } = render(); + rerender(); await Promise.resolve(); - rerender(); + rerender(); let renderResult: RenderResult; // we have to await the full start of the editor with the onLoad callback, then it is save to contine const p = await new Promise(resolve => { const handleOnLoad = async (_wrapper: MonacoEditorLanguageClientWrapper) => { - renderResult.rerender(); + renderResult.rerender(); resolve(); }; - renderResult = render(); + renderResult = render(); }); // void promise is undefined after it was awaited expect(p).toBeUndefined(); @@ -45,15 +43,13 @@ describe('Test MonacoEditorReactComp', () => { test('update onTextChanged', async () => { updateExtendedAppPrototyp(); - const userConfig: UserConfig = { - wrapperConfig: { - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: 'hello world', - fileExt: 'js' - } + const wrapperConfig: WrapperConfig = { + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: 'hello world', + fileExt: 'js' } } }, @@ -74,13 +70,13 @@ describe('Test MonacoEditorReactComp', () => { p1Resolve(); }; // because the onTextChanged callback is updated there will be a result even if the text is unchanged - renderResult.rerender(); + renderResult.rerender(); }); expect(p1).toBeUndefined(); resolve(); }; - renderResult = render(); + renderResult = render(); }); // void promise is undefined after it was awaited expect(p).toBeUndefined(); @@ -88,15 +84,13 @@ describe('Test MonacoEditorReactComp', () => { test('update codeResources', async () => { updateExtendedAppPrototyp(); - const userConfig: UserConfig = { - wrapperConfig: { - editorAppConfig: { - $type: 'extended', - codeResources: { - main: { - text: 'hello world', - fileExt: 'js' - } + const wrapperConfig: WrapperConfig = { + editorAppConfig: { + $type: 'extended', + codeResources: { + main: { + text: 'hello world', + fileExt: 'js' } } }, @@ -125,13 +119,13 @@ describe('Test MonacoEditorReactComp', () => { p1Resolve(); }; - renderResult.rerender(); + renderResult.rerender(); }); expect(p1).toBeUndefined(); resolve(); }; - renderResult = render(); + renderResult = render(); }); // void promise is undefined after it was awaited expect(p).toBeUndefined(); diff --git a/packages/wrapper-react/tsconfig.src.json b/packages/wrapper-react/tsconfig.src.json index fe71f2b09..36d5005ae 100644 --- a/packages/wrapper-react/tsconfig.src.json +++ b/packages/wrapper-react/tsconfig.src.json @@ -4,9 +4,10 @@ "rootDir": "src", "outDir": "dist", "declarationDir": "dist", - "types": [ - "vscode" - ] + // because vscode-jsonrpc requires DedicatedWorkerGlobalScope + // we are required to include both DOM and WebWorker libs + // the only way out currently is to disable lib checking + "skipLibCheck": true }, "references": [{ "path": "../wrapper/tsconfig.src.json" diff --git a/packages/wrapper-react/tsconfig.test.json b/packages/wrapper-react/tsconfig.test.json index b3ee8ba7a..dfccd5b7a 100644 --- a/packages/wrapper-react/tsconfig.test.json +++ b/packages/wrapper-react/tsconfig.test.json @@ -2,7 +2,11 @@ "extends": "./tsconfig.src.json", "compilerOptions": { "noEmit": true, - "rootDir": "test" + "rootDir": "test", + // because vscode-jsonrpc requires DedicatedWorkerGlobalScope + // we are required to include both DOM and WebWorker libs + // the only way out currently is to disable lib checking + "skipLibCheck": true }, "references": [{ "path": "./tsconfig.src.json" diff --git a/packages/wrapper/CHANGELOG.md b/packages/wrapper/CHANGELOG.md index 127c0db1f..7d5701b77 100644 --- a/packages/wrapper/CHANGELOG.md +++ b/packages/wrapper/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to npm module [monaco-editor-wrapper](https://www.npmjs.com/package/monaco-editor-wrapper) are documented in this file. +## [6.0.0-next.0] - 2024-08-xy + +- Updated to `monaco-languageclient@9.0.0-next.0`. Updated all `@codingame/monaco-vscode` packages to `8.0.4`. + ## [5.5.3] - 2024-08-26 - Updated to `monaco-languageclient@8.8.3`. Updated all `@codingame/monaco-vscode` packages to `8.0.4`. diff --git a/packages/wrapper/package.json b/packages/wrapper/package.json index 441498f80..5cc3da210 100644 --- a/packages/wrapper/package.json +++ b/packages/wrapper/package.json @@ -1,6 +1,6 @@ { "name": "monaco-editor-wrapper", - "version": "5.5.3", + "version": "6.0.0-next.0", "license": "MIT", "description": "Wrapper for monaco-vscode-editor-api and monaco-languageclient", "keywords": [ @@ -81,8 +81,8 @@ "build": "npm run clean && npm run compile && npm run build:workers:esbuild && npm run build:workers:vite" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "dependencies": { "@codingame/monaco-vscode-configuration-service-override": "~8.0.4", @@ -120,7 +120,7 @@ }, "peerDependencies": { "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-languageclient": "~8.8.3", + "monaco-languageclient": "~9.0.0-next.0", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4" }, "peerDependenciesMeta": { diff --git a/packages/wrapper/src/editorAppBase.ts b/packages/wrapper/src/editorAppBase.ts index 041492cdb..24ed6f381 100644 --- a/packages/wrapper/src/editorAppBase.ts +++ b/packages/wrapper/src/editorAppBase.ts @@ -10,27 +10,27 @@ import { getUserConfiguration, updateUserConfiguration as vscodeUpdateUserConfig import { getEditorUri, isModelUpdateRequired, ModelUpdateType } from './utils.js'; import { Logger } from 'monaco-languageclient/tools'; -export type CodeContent = { +export interface CodeContent { text: string; enforceLanguageId?: string; } -export type CodePlusUri = CodeContent & { +export interface CodePlusUri extends CodeContent { uri: string; } -export type CodePlusFileExt = CodeContent & { +export interface CodePlusFileExt extends CodeContent { fileExt: string; } -export type CodeResources = { +export interface CodeResources { main?: CodePlusUri | CodePlusFileExt; original?: CodePlusUri | CodePlusFileExt; } export type EditorAppType = 'extended' | 'classic'; -export type EditorAppConfigBase = { +export interface EditorAppConfigBase { $type: EditorAppType; codeResources?: CodeResources; useDiffEditor?: boolean; @@ -42,17 +42,17 @@ export type EditorAppConfigBase = { diffEditorOptions?: monaco.editor.IStandaloneDiffEditorConstructionOptions; } -export type ModelRefs = { +export interface ModelRefs { modelRef?: IReference; modelRefOriginal?: IReference; } -export type TextModels = { +export interface TextModels { text?: monaco.editor.ITextModel; textOriginal?: monaco.editor.ITextModel; } -export type TextContents = { +export interface TextContents { text?: string; textOriginal?: string; } diff --git a/packages/wrapper/src/editorAppClassic.ts b/packages/wrapper/src/editorAppClassic.ts index 333870627..33cc177a2 100644 --- a/packages/wrapper/src/editorAppClassic.ts +++ b/packages/wrapper/src/editorAppClassic.ts @@ -7,9 +7,8 @@ import * as monaco from 'monaco-editor'; import { Logger } from 'monaco-languageclient/tools'; import { EditorAppBase, EditorAppConfigBase } from './editorAppBase.js'; import { ModelUpdateType, isEqual, isModelUpdateRequired } from './utils.js'; -import { UserConfig } from './userConfig.js'; -export type EditorAppConfigClassic = EditorAppConfigBase & { +export interface EditorAppConfigClassic extends EditorAppConfigBase { $type: 'classic'; languageDef?: { languageExtensionConfig: monaco.languages.ILanguageExtensionPoint; @@ -19,7 +18,7 @@ export type EditorAppConfigClassic = EditorAppConfigBase & { data: monaco.editor.IStandaloneThemeData; } } -}; +} /** * The classic monaco-editor app uses the classic monaco-editor configuration. @@ -28,11 +27,10 @@ export class EditorAppClassic extends EditorAppBase { private config: EditorAppConfigClassic; - constructor(id: string, userConfig: UserConfig, logger?: Logger) { + constructor(id: string, editorAppConfig: EditorAppConfigClassic, logger?: Logger) { super(id, logger); - const userAppConfig = userConfig.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - this.config = this.buildConfig(userAppConfig) as EditorAppConfigClassic; - this.config.languageDef = userAppConfig.languageDef; + this.config = this.buildConfig(editorAppConfig) as EditorAppConfigClassic; + this.config.languageDef = editorAppConfig.languageDef; } getConfig(): EditorAppConfigClassic { @@ -88,7 +86,7 @@ export class EditorAppClassic extends EditorAppBase { this.disposeEditors(); } - isAppConfigDifferent(orgConfig: EditorAppConfigClassic, config: EditorAppConfigClassic, includeModelData: boolean): boolean { + isAppConfigDifferent(orgConfig: EditorAppConfigBase, config: EditorAppConfigBase, includeModelData: boolean): boolean { let different = false; if (includeModelData) { different = isModelUpdateRequired(orgConfig.codeResources, config.codeResources) !== ModelUpdateType.NONE; diff --git a/packages/wrapper/src/editorAppExtended.ts b/packages/wrapper/src/editorAppExtended.ts index 22e8367ab..83d6ee15e 100644 --- a/packages/wrapper/src/editorAppExtended.ts +++ b/packages/wrapper/src/editorAppExtended.ts @@ -8,39 +8,38 @@ import * as monaco from 'monaco-editor'; import { EditorAppBase, EditorAppConfigBase } from './editorAppBase.js'; import { registerExtension, IExtensionManifest, ExtensionHostKind } from 'vscode/extensions'; import { Logger } from 'monaco-languageclient/tools'; -import { UserConfig } from './userConfig.js'; import { verifyUrlOrCreateDataUrl, ModelUpdateType, isEqual, isModelUpdateRequired } from './utils.js'; import { DisposableStore } from 'vscode/monaco'; -export type ExtensionConfig = { +export interface ExtensionConfig { config: IExtensionManifest | object; filesOrContents?: Map; -}; +} -export type UserConfiguration = { +export interface UserConfiguration { json?: string; } -export type EditorAppConfigExtended = EditorAppConfigBase & { +export interface EditorAppConfigExtended extends EditorAppConfigBase { $type: 'extended'; extensions?: ExtensionConfig[]; userConfiguration?: UserConfiguration; -}; +} -export type RegisterExtensionResult = { +export interface RegisterExtensionResult { id: string; dispose(): Promise; whenReady(): Promise; } -interface RegisterLocalExtensionResult extends RegisterExtensionResult { +export interface RegisterLocalExtensionResult extends RegisterExtensionResult { registerFileUrl: (path: string, url: string) => monaco.IDisposable; } -export type RegisterLocalProcessExtensionResult = RegisterLocalExtensionResult & { +export interface RegisterLocalProcessExtensionResult extends RegisterLocalExtensionResult { getApi(): Promise; setAsDefaultApi(): Promise; -}; +} /** * The vscode-apo monaco-editor app uses vscode user and extension configuration for monaco-editor. @@ -51,13 +50,12 @@ export class EditorAppExtended extends EditorAppBase { private extensionRegisterResults: Map = new Map(); private subscriptions: DisposableStore = new DisposableStore(); - constructor(id: string, userConfig: UserConfig, logger?: Logger) { + constructor(id: string, editorAppConfig: EditorAppConfigExtended, logger?: Logger) { super(id); this.logger = logger; - const userAppConfig = userConfig.wrapperConfig.editorAppConfig as EditorAppConfigExtended; - this.config = this.buildConfig(userAppConfig) as EditorAppConfigExtended; - this.config.extensions = userAppConfig.extensions ?? undefined; - this.config.userConfiguration = userAppConfig.userConfiguration ?? undefined; + this.config = this.buildConfig(editorAppConfig) as EditorAppConfigExtended; + this.config.extensions = editorAppConfig.extensions ?? undefined; + this.config.userConfiguration = editorAppConfig.userConfiguration ?? undefined; } getConfig(): EditorAppConfigExtended { @@ -112,7 +110,7 @@ export class EditorAppExtended extends EditorAppBase { this.subscriptions.dispose(); } - isAppConfigDifferent(orgConfig: EditorAppConfigExtended, config: EditorAppConfigExtended, includeModelData: boolean): boolean { + isAppConfigDifferent(orgConfig: EditorAppConfigBase, config: EditorAppConfigBase, includeModelData: boolean): boolean { let different = false; if (includeModelData) { different = isModelUpdateRequired(orgConfig.codeResources, config.codeResources) !== ModelUpdateType.NONE; diff --git a/packages/wrapper/src/index.ts b/packages/wrapper/src/index.ts index 46e0035c4..f7598fac8 100644 --- a/packages/wrapper/src/index.ts +++ b/packages/wrapper/src/index.ts @@ -3,104 +3,20 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { - EditorAppBase, -} from './editorAppBase.js'; +export type * from './editorAppBase.js'; +export * from './editorAppBase.js'; -import type { - EditorAppConfigBase, - EditorAppType, - CodeContent, - CodePlusUri, - CodePlusFileExt, - CodeResources, - ModelRefs, - TextModels, - TextContents -} from './editorAppBase.js'; +export type * from './editorAppClassic.js'; +export * from './editorAppClassic.js'; -import type { - EditorAppConfigClassic, -} from './editorAppClassic.js'; +export type * from './editorAppExtended.js'; +export * from './editorAppExtended.js'; -import { - EditorAppClassic -} from './editorAppClassic.js'; +export type * from './languageClientWrapper.js'; +export * from './languageClientWrapper.js'; -import type { - ExtensionConfig, - EditorAppConfigExtended, - RegisterExtensionResult, - RegisterLocalProcessExtensionResult, - UserConfiguration -} from './editorAppExtended.js'; - -import { - EditorAppExtended -} from './editorAppExtended.js'; - -import type { - WebSocketCallOptions, - LanguageClientConfigType, - WebSocketConfigOptions, - WebSocketConfigOptionsUrl, - WorkerConfigOptions, - WorkerConfigDirect -} from './commonTypes.js'; - -import type { - LanguageClientConfig, - LanguageClientError -} from './languageClientWrapper.js'; - -import { - LanguageClientWrapper, -} from './languageClientWrapper.js'; - -import type { - UserConfig, - WrapperConfig -} from './userConfig.js'; - -import { - MonacoEditorLanguageClientWrapper, -} from './wrapper.js'; - -export type { - WrapperConfig, - EditorAppConfigBase, - EditorAppType, - EditorAppConfigClassic, - ExtensionConfig, - EditorAppConfigExtended, - RegisterExtensionResult, - RegisterLocalProcessExtensionResult, - UserConfiguration, - WebSocketCallOptions, - LanguageClientConfigType, - WebSocketConfigOptions, - WebSocketConfigOptionsUrl, - WorkerConfigOptions, - WorkerConfigDirect, - LanguageClientConfig, - LanguageClientError, - UserConfig, - CodeContent, - CodePlusUri, - CodePlusFileExt, - CodeResources, - ModelRefs, - TextModels, - TextContents -}; - -export { - MonacoEditorLanguageClientWrapper, - LanguageClientWrapper, - EditorAppBase, - EditorAppClassic, - EditorAppExtended -}; +export type * from './wrapper.js'; +export * from './wrapper.js'; export * from './utils.js'; export type * from './utils.js'; diff --git a/packages/wrapper/src/languageClientWrapper.ts b/packages/wrapper/src/languageClientWrapper.ts index a964e1770..aba92f200 100644 --- a/packages/wrapper/src/languageClientWrapper.ts +++ b/packages/wrapper/src/languageClientWrapper.ts @@ -3,40 +3,48 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { MonacoLanguageClient, IConnectionProvider } from 'monaco-languageclient'; -import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'; -import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageserver-protocol/browser.js'; -import { CloseAction, ErrorAction, LanguageClientOptions, MessageTransports, State } from 'vscode-languageclient/lib/common/client.js'; +import { MonacoLanguageClient, ConnetionConfigOptions, WorkerConfigOptionsDirect, WorkerConfigOptionsParams } from 'monaco-languageclient'; import { Logger } from 'monaco-languageclient/tools'; +import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageserver-protocol/browser.js'; +import { CloseAction, ErrorAction, LanguageClientOptions, MessageTransports, State } from 'vscode-languageclient/browser.js'; import { createUrl } from './utils.js'; -import { WebSocketConfigOptions, WebSocketConfigOptionsUrl, WorkerConfigDirect, WorkerConfigOptions } from './commonTypes.js'; +import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'; -export type LanguageClientConfig = { - languageId: string; - options: WebSocketConfigOptions | WebSocketConfigOptionsUrl | WorkerConfigOptions | WorkerConfigDirect; +export interface ConnectionConfig { + options: ConnetionConfigOptions; + messageTransports?: MessageTransports; +} + +export interface LanguageClientConfig { name?: string; + languageId: string; + connection: ConnectionConfig; clientOptions?: LanguageClientOptions; - connectionProvider?: IConnectionProvider; + restartOptions?: LanguageClientRestartOptions; } -export type LanguageClientError = { +export interface LanguageClientRestartOptions { + retries: number; + timeout: number; + keepWorker?: boolean; +} + +export interface LanguageClientError { message: string; error: Error | string; -}; +} export class LanguageClientWrapper { private languageClient?: MonacoLanguageClient; - private languageClientConfig?: LanguageClientConfig; - private messageTransports?: MessageTransports; - private connectionProvider?: IConnectionProvider; + private languageClientConfig: LanguageClientConfig; private languageId: string; private worker?: Worker; private port?: MessagePort; private name?: string; private logger: Logger | undefined; - async init(config: { + constructor(config: { languageClientConfig: LanguageClientConfig, logger?: Logger }) { @@ -50,10 +58,6 @@ export class LanguageClientWrapper { return this.languageClient !== undefined; } - haveLanguageClientConfig(): boolean { - return this.languageClientConfig !== undefined; - } - getLanguageClient(): MonacoLanguageClient | undefined { return this.languageClient; } @@ -66,24 +70,24 @@ export class LanguageClientWrapper { return this.languageClient !== undefined && this.languageClient.isRunning(); } - getMessageTransports(): MessageTransports | undefined { - return this.messageTransports; - } + async start(): Promise { + if (this.languageClient?.isRunning() ?? false) { + this.logger?.info('startLanguageClientConnection: monaco-languageclient already running!'); + return Promise.resolve(); + } - getConnectionProvider(): IConnectionProvider | undefined { - return this.connectionProvider; - } + return new Promise((resolve, reject) => { + const conConfig = this.languageClientConfig.connection; + const conOptions = conConfig.options; - async start() { - if (this.languageClientConfig) { - return this.startLanguageClientConnection(); - } else { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.name}): Unable to start monaco-languageclient. No configuration was provided.`, - error: 'No error was provided.' - }; - return Promise.reject(languageClientError); - } + if (conOptions.$type === 'WebSocketDirect' || conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl') { + const webSocket = conOptions.$type === 'WebSocketDirect' ? conOptions.webSocket : new WebSocket(createUrl(conOptions)); + this.initMessageTransportWebSocket(webSocket, resolve, reject); + } else { + // init of worker and start of languageclient can be handled directly, because worker available already + this.initMessageTransportWorker(conOptions, resolve, reject); + } + }); } /** @@ -92,108 +96,91 @@ export class LanguageClientWrapper { * @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 keepWorker Set to true if worker should not be disposed */ - async restartLanguageClient(updatedWorker?: Worker, keepWorker?: boolean): Promise { - if (updatedWorker) { - await this.disposeLanguageClient(false); - } else { - await this.disposeLanguageClient(keepWorker); - } + async restartLanguageClient(updatedWorker?: Worker, keepWorker: boolean = false): Promise { + await this.disposeLanguageClient(keepWorker); + this.worker = updatedWorker; - if (this.languageClientConfig) { - this.logger?.info('Re-Starting monaco-languageclient'); - return this.startLanguageClientConnection(); - } else { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.name}): Unable to restart languageclient. No configuration was provided.`, - error: 'No error was provided.' + 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) }; - return Promise.reject(languageClientError); } - } - private startLanguageClientConnection(): Promise { - if (this.languageClient && this.languageClient.isRunning()) { - this.logger?.info('monaco-languageclient already running!'); - return Promise.resolve(); + // if websocket is already open, then start the languageclient directly + if (webSocket.readyState === WebSocket.OPEN) { + await this.performLanguageClientStart(messageTransports, resolve, reject); } - const lcConfig = this.languageClientConfig?.options; - // allow to fully override the clonnecetionProvider - // if it is undefined it will be created from the message transports in handleLanguageClientStart - this.connectionProvider = this.languageClientConfig?.connectionProvider; + // otherwise start on open + webSocket.onopen = async () => { + await this.performLanguageClientStart(messageTransports, resolve, reject); + }; + webSocket.onerror = (ev: Event) => { + const languageClientError: LanguageClientError = { + message: `languageClientWrapper (${this.name}): Websocket connection failed.`, + error: (ev as ErrorEvent).error ?? 'No error was provided.' + }; + reject(languageClientError); + }; + } - return new Promise((resolve, reject) => { - if (lcConfig?.$type === 'WebSocket' || lcConfig?.$type === 'WebSocketUrl') { - const url = createUrl(lcConfig); - const webSocket = new WebSocket(url); - - webSocket.onopen = async () => { - const socket = toSocket(webSocket); - this.messageTransports = await this.connectionProvider?.get('') ?? { - reader: new WebSocketMessageReader(socket), - writer: new WebSocketMessageWriter(socket) - }; - this.handleLanguageClientStart(resolve, reject); - }; - webSocket.onerror = (ev: Event) => { + protected async initMessageTransportWorker(lccOptions: WorkerConfigOptionsDirect | WorkerConfigOptionsParams, resolve: () => void, reject: (reason?: unknown) => void) { + if (!this.worker) { + if (lccOptions.$type === 'WorkerConfig') { + const workerConfig = lccOptions as WorkerConfigOptionsParams; + this.worker = new Worker(new URL(workerConfig.url, import.meta.url).href, { + type: workerConfig.type, + name: workerConfig.workerName + }); + + this.worker.onerror = (ev) => { const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.name}): Websocket connection failed.`, - error: (ev as ErrorEvent).error ?? 'No error was provided.' + message: `languageClientWrapper (${this.name}): Illegal worker configuration detected. Potentially the url is wrong.`, + error: ev.error ?? 'No error was provided.' }; reject(languageClientError); }; } else { - if (!this.worker) { - if (lcConfig?.$type === 'WorkerConfig') { - const workerConfig = lcConfig as WorkerConfigOptions; - this.worker = new Worker(new URL(workerConfig.url, import.meta.url).href, { - type: workerConfig.type, - name: workerConfig.workerName - }); - - this.worker.onerror = (ev) => { - const languageClientError: LanguageClientError = { - message: `languageClientWrapper (${this.name}): Illegal worker configuration detected. Potentially the url is wrong.`, - error: ev.error ?? 'No error was provided.' - }; - reject(languageClientError); - }; - } else { - const workerDirectConfig = lcConfig as WorkerConfigDirect; - this.worker = workerDirectConfig.worker; - } - if (lcConfig?.messagePort) { - this.port = lcConfig.messagePort; - } - } - - const startWorkerLS = async (port: MessagePort | Worker) => { - this.messageTransports = await this.connectionProvider?.get('') ?? { - reader: new BrowserMessageReader(port), - writer: new BrowserMessageWriter(port) - }; - this.handleLanguageClientStart(resolve, reject); - }; - startWorkerLS(this.port ? this.port : this.worker); + const workerDirectConfig = lccOptions as WorkerConfigOptionsDirect; + this.worker = workerDirectConfig.worker; } - }); - } + if (lccOptions.messagePort !== undefined) { + this.port = lccOptions.messagePort; + } + } - private async handleLanguageClientStart(resolve: () => void, reject: (reason?: unknown) => void) { - if (!this.connectionProvider) { - this.connectionProvider = { - get: () => { - // even with the check "if (this.messageTransports)" the compiler requires the ! here - return Promise.resolve(this.messageTransports!); - } + const portOrWorker = this.port ? this.port : this.worker; + let messageTransports = this.languageClientConfig.connection.messageTransports; + if (messageTransports === undefined) { + 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) { + // 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 = { - name: this.languageClientConfig?.name ?? 'Monaco Wrapper Language Client', + name: this.languageClientConfig.name ?? 'Monaco Wrapper Language Client', // allow to fully override the clientOptions - clientOptions: this.languageClientConfig?.clientOptions ?? { + clientOptions: this.languageClientConfig.clientOptions ?? { documentSelector: [this.languageId], // disable the default error handler errorHandler: { @@ -201,18 +188,19 @@ export class LanguageClientWrapper { closed: () => ({ action: CloseAction.DoNotRestart }) } }, - - connectionProvider: this.connectionProvider! + messageTransports }; + this.languageClient = new MonacoLanguageClient(mlcConfig); - const lcConfig = this.languageClientConfig?.options; + const conOptions = this.languageClientConfig.connection.options; + this.initRestartConfiguration(messageTransports, this.languageClientConfig.restartOptions); - this.messageTransports?.reader.onClose(async () => { + messageTransports.reader.onClose(async () => { await this.languageClient?.stop(); - if ((lcConfig?.$type === 'WebSocket' || lcConfig?.$type === 'WebSocketUrl') && lcConfig.stopOptions) { - const stopOptions = lcConfig.stopOptions; + if ((conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl') && conOptions.stopOptions !== undefined) { + const stopOptions = conOptions.stopOptions; stopOptions.onCall(this.getLanguageClient()); if (stopOptions.reportStatus !== undefined) { this.logger?.info(this.reportStatus().join('\n')); @@ -223,8 +211,8 @@ export class LanguageClientWrapper { try { await this.languageClient.start(); - if ((lcConfig?.$type === 'WebSocket' || lcConfig?.$type === 'WebSocketUrl') && lcConfig.startOptions) { - const startOptions = lcConfig.startOptions; + if ((conOptions.$type === 'WebSocketParams' || conOptions.$type === 'WebSocketUrl') && conOptions.startOptions !== undefined) { + const startOptions = conOptions.startOptions; startOptions.onCall(this.getLanguageClient()); if (startOptions.reportStatus !== undefined) { this.logger?.info(this.reportStatus().join('\n')); @@ -241,14 +229,43 @@ export class LanguageClientWrapper { resolve(); } - private disposeWorker(keepWorker?: boolean) { + 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.restartLanguageClient(this.worker, restartOptions.keepWorker); + } finally { + retry++; + if (retry > (restartOptions.retries) && !this.isStarted()) { + this.logger?.info('Disabling Language Client. Failed to start clangd after 5 retries'); + } else { + setTimeout(async () => { + await this.restartLanguageClient(this.worker, restartOptions.keepWorker); + }, restartOptions.timeout); + } + } + } + }; + } + } + + protected disposeWorker(keepWorker?: boolean) { if (keepWorker === undefined || keepWorker === false) { this.worker?.terminate(); this.worker = undefined; } } - public async disposeLanguageClient(keepWorker?: boolean): Promise { + async disposeLanguageClient(keepWorker?: boolean): Promise { // If there is no language client, try to terminate the worker if (!this.languageClient) { this.disposeWorker(keepWorker); diff --git a/packages/wrapper/src/userConfig.ts b/packages/wrapper/src/userConfig.ts deleted file mode 100644 index 463e5b74c..000000000 --- a/packages/wrapper/src/userConfig.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2024 TypeFox and others. - * Licensed under the MIT License. See LICENSE in the package root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { InitializeServiceConfig } from 'monaco-languageclient/vscode/services'; -import type { LoggerConfig } from 'monaco-languageclient/tools'; -import { EditorAppConfigExtended } from './editorAppExtended.js'; -import { EditorAppConfigClassic } from './editorAppClassic.js'; -import { LanguageClientConfig } from './languageClientWrapper.js'; - -export type WrapperConfig = { - serviceConfig?: InitializeServiceConfig; - editorAppConfig: EditorAppConfigExtended | EditorAppConfigClassic; -}; - -export type UserConfig = { - id?: string; - loggerConfig?: LoggerConfig; - wrapperConfig: WrapperConfig; - languageClientConfig?: LanguageClientConfig; -} diff --git a/packages/wrapper/src/utils.ts b/packages/wrapper/src/utils.ts index 04782788f..56ff50dbf 100644 --- a/packages/wrapper/src/utils.ts +++ b/packages/wrapper/src/utils.ts @@ -4,22 +4,22 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { WebSocketConfigOptions, WebSocketConfigOptionsUrl, WorkerConfigDirect, WorkerConfigOptions } from './commonTypes.js'; +import { WebSocketUrlParams, WebSocketUrlString } from 'monaco-languageclient'; import { CodePlusFileExt, CodePlusUri, CodeResources } from './editorAppBase.js'; import { EditorAppClassic } from './editorAppClassic.js'; -import { UserConfig } from './userConfig.js'; import { EditorAppExtended } from './editorAppExtended.js'; +import { EditorAppConfigBase } from './editorAppBase.js'; -export const createUrl = (config: WebSocketConfigOptions | WebSocketConfigOptionsUrl) => { +export const createUrl = (config: WebSocketUrlParams | WebSocketUrlString) => { let buildUrl = ''; - if ((config as WebSocketConfigOptionsUrl).url) { - const options = config as WebSocketConfigOptionsUrl; + if ((config as WebSocketUrlString).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 WebSocketConfigOptions; + const options = config as WebSocketUrlParams; const protocol = options.secured ? 'wss' : 'ws'; buildUrl = `${protocol}://${options.host}`; if (options.port !== undefined) { @@ -115,34 +115,15 @@ export const isEqual = (obj1: unknown, obj2: unknown) => { * @param previousUserConfig * @returns */ -export const isReInitRequired = (editorApp: EditorAppClassic | EditorAppExtended, userConfig: UserConfig, previousUserConfig: UserConfig): boolean => { +export const isReInitRequired = (editorApp: EditorAppClassic | EditorAppExtended, config: EditorAppConfigBase, previousConfig: EditorAppConfigBase): boolean => { let mustReInit = false; - const config = userConfig.wrapperConfig.editorAppConfig; - const prevConfig = previousUserConfig.wrapperConfig.editorAppConfig; - const prevWorkerOptions = previousUserConfig.languageClientConfig?.options; - const currentWorkerOptions = userConfig.languageClientConfig?.options; - const prevIsWorker = (prevWorkerOptions?.$type === 'WorkerDirect'); - const currentIsWorker = (currentWorkerOptions?.$type === 'WorkerDirect'); - const prevIsWorkerConfig = (prevWorkerOptions?.$type === 'WorkerConfig'); - const currentIsWorkerConfig = (currentWorkerOptions?.$type === 'WorkerConfig'); - - // check if both are configs and the workers are both undefined - if (prevIsWorkerConfig && !prevIsWorker && currentIsWorkerConfig && !currentIsWorker) { - mustReInit = (prevWorkerOptions as WorkerConfigOptions).url !== (currentWorkerOptions as WorkerConfigOptions).url; - // check if both are workers and configs are both undefined - } else if (!prevIsWorkerConfig && prevIsWorker && !currentIsWorkerConfig && currentIsWorker) { - mustReInit = (prevWorkerOptions as WorkerConfigDirect).worker !== (currentWorkerOptions as WorkerConfigDirect).worker; - // previous was worker and current config is not or the other way around - } else if (prevIsWorker && currentIsWorkerConfig || prevIsWorkerConfig && currentIsWorker) { - mustReInit = true; - } - if (prevConfig.$type !== config.$type) { + if (previousConfig.$type !== config.$type) { mustReInit = true; - } else if (prevConfig.$type === 'classic' && config.$type === 'classic') { - mustReInit = (editorApp as EditorAppClassic).isAppConfigDifferent(prevConfig, config, false) === true; - } else if (prevConfig.$type === 'extended' && config.$type === 'extended') { - mustReInit = (editorApp as EditorAppExtended).isAppConfigDifferent(prevConfig, config, false) === true; + } else if (previousConfig.$type === 'classic' && config.$type === 'classic') { + mustReInit = (editorApp as EditorAppClassic).isAppConfigDifferent(previousConfig, config, false) === true; + } else if (previousConfig.$type === 'extended' && config.$type === 'extended') { + mustReInit = (editorApp as EditorAppExtended).isAppConfigDifferent(previousConfig, config, false) === true; } return mustReInit; diff --git a/packages/wrapper/src/vscode/services.ts b/packages/wrapper/src/vscode/services.ts index 283957481..955929920 100644 --- a/packages/wrapper/src/vscode/services.ts +++ b/packages/wrapper/src/vscode/services.ts @@ -10,11 +10,11 @@ import { OpenEditor } from '@codingame/monaco-vscode-editor-service-override'; import { mergeServices, InitializeServiceConfig } from 'monaco-languageclient/vscode/services'; import { Logger } from 'monaco-languageclient/tools'; -export type VscodeServicesConfig = { +export interface VscodeServicesConfig { serviceConfig?: InitializeServiceConfig; specificServices?: monaco.editor.IEditorOverrideServices; logger?: Logger; -}; +} /** * Child classes are allow to override the services configuration implementation. diff --git a/packages/wrapper/src/workerFactory.ts b/packages/wrapper/src/workerFactory.ts index e4db1c1a0..a8fabd080 100644 --- a/packages/wrapper/src/workerFactory.ts +++ b/packages/wrapper/src/workerFactory.ts @@ -3,9 +3,10 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ +import { Logger } from 'monaco-languageclient/tools'; import { initEnhancedMonacoEnvironment } from 'monaco-languageclient/vscode/services'; -export type WorkerOverrides = { +export interface WorkerOverrides { rootPath?: string | URL; basePath?: string | URL; workerLoaders?: Partial>; @@ -13,7 +14,7 @@ export type WorkerOverrides = { userDefinedMapping?: (label: string) => string; } -export type WorkerConfig = { +export interface WorkerConfig { rootPath: string | URL; basePath?: string | URL; workerFile: string | URL; @@ -60,7 +61,7 @@ export const defaultWorkerLoaders: Partial { +export const buildWorker = (config: WorkerConfig, workerOverrides?: WorkerOverrides, logger?: Logger): Worker => { if (workerOverrides?.rootPath !== undefined) { config.rootPath = workerOverrides.rootPath; } @@ -72,7 +73,7 @@ export const buildWorker = (config: WorkerConfig, workerOverrides?: WorkerOverri workerFile = `${config.basePath}/${config.workerFile}`; } const fullUrl = new URL(workerFile, config.rootPath).href; - console.log(`Creating worker: ${fullUrl}`); + logger?.info(`Creating worker: ${fullUrl}`); // default to 'module' if not specified const workerOptions = config.options ?? {}; @@ -85,11 +86,11 @@ export const buildWorker = (config: WorkerConfig, workerOverrides?: WorkerOverri return new Worker(URL.createObjectURL(blob), workerOptions); }; -export const useWorkerFactory = (workerOverrides?: WorkerOverrides) => { +export const useWorkerFactory = (workerOverrides?: WorkerOverrides, logger?: Logger) => { const envEnhanced = initEnhancedMonacoEnvironment(); const getWorker = (moduleId: string, label: string) => { - console.log(`getWorker: moduleId: ${moduleId} label: ${label}`); + logger?.info(`getWorker: moduleId: ${moduleId} label: ${label}`); let selector = label; let workerLoaders; @@ -116,7 +117,7 @@ export const useWorkerFactory = (workerOverrides?: WorkerOverrides) => { if (workerOrConfig) { const invoked = workerOrConfig(); if (Object.hasOwn(invoked, 'workerFile')) { - return buildWorker(invoked as WorkerConfig, workerOverrides); + return buildWorker(invoked as WorkerConfig, workerOverrides, logger); } else { return invoked as Worker; } diff --git a/packages/wrapper/src/wrapper.ts b/packages/wrapper/src/wrapper.ts index d9630bb75..5adb2115e 100644 --- a/packages/wrapper/src/wrapper.ts +++ b/packages/wrapper/src/wrapper.ts @@ -5,14 +5,21 @@ import * as monaco from 'monaco-editor'; import { MonacoLanguageClient } from 'monaco-languageclient'; -import { initServices } from 'monaco-languageclient/vscode/services'; -import { Logger } from 'monaco-languageclient/tools'; +import { InitializeServiceConfig, initServices } from 'monaco-languageclient/vscode/services'; +import { Logger, LoggerConfig } from 'monaco-languageclient/tools'; import { checkServiceConsistency, configureServices } from './vscode/services.js'; -import { EditorAppExtended } from './editorAppExtended.js'; -import { EditorAppClassic } from './editorAppClassic.js'; +import { EditorAppConfigExtended, EditorAppExtended } from './editorAppExtended.js'; +import { EditorAppClassic, EditorAppConfigClassic } from './editorAppClassic.js'; import { CodeResources, ModelRefs, TextContents, TextModels } from './editorAppBase.js'; -import { LanguageClientWrapper } from './languageClientWrapper.js'; -import { UserConfig } from './userConfig.js'; +import { LanguageClientConfig, LanguageClientWrapper } from './languageClientWrapper.js'; + +export interface WrapperConfig { + id?: string; + loggerConfig?: LoggerConfig; + serviceConfig?: InitializeServiceConfig; + editorAppConfig: EditorAppConfigExtended | EditorAppConfigClassic; + languageClientConfigs?: Record; +} /** * This class is responsible for the overall ochestration. @@ -23,7 +30,7 @@ export class MonacoEditorLanguageClientWrapper { private id: string; private editorApp: EditorAppClassic | EditorAppExtended | undefined; - private languageClientWrapper?: LanguageClientWrapper; + private languageClientWrappers: Map = new Map(); private logger: Logger = new Logger(); private initDone = false; private starting?: Promise; @@ -34,32 +41,32 @@ export class MonacoEditorLanguageClientWrapper { /** * Perform an isolated initialization of the user services and the languageclient wrapper (if used). */ - async init(userConfig: UserConfig) { + async init(wrapperConfig: WrapperConfig) { this.markStarting(); if (this.initDone) { throw new Error('init was already performed. Please call dispose first if you want to re-start.'); } - const editorAppConfig = userConfig.wrapperConfig.editorAppConfig; + const editorAppConfig = wrapperConfig.editorAppConfig; if ((editorAppConfig.useDiffEditor ?? false) && !editorAppConfig.codeResources?.original) { throw new Error(`Use diff editor was used without a valid config. code: ${editorAppConfig.codeResources?.main} codeOriginal: ${editorAppConfig.codeResources?.original}`); } // Always dispose old instances before start this.dispose(false); - this.id = userConfig.id ?? Math.floor(Math.random() * 101).toString(); - this.logger.updateConfig(userConfig.loggerConfig); + this.id = wrapperConfig.id ?? Math.floor(Math.random() * 101).toString(); + this.logger.updateConfig(wrapperConfig.loggerConfig); if (editorAppConfig.$type === 'classic') { - this.editorApp = new EditorAppClassic(this.id, userConfig, this.logger); + this.editorApp = new EditorAppClassic(this.id, wrapperConfig.editorAppConfig as EditorAppConfigClassic, this.logger); } else { - this.editorApp = new EditorAppExtended(this.id, userConfig, this.logger); + this.editorApp = new EditorAppExtended(this.id, wrapperConfig.editorAppConfig as EditorAppConfigExtended, this.logger); } // editorApps init their own service thats why they have to be created first const specificServices = await this.editorApp.specifyServices(); const serviceConfig = await configureServices({ - serviceConfig: userConfig.wrapperConfig.serviceConfig, + serviceConfig: wrapperConfig.serviceConfig, specificServices, logger: this.logger }); @@ -70,12 +77,15 @@ export class MonacoEditorLanguageClientWrapper { logger: this.logger }); - if (userConfig.languageClientConfig) { - this.languageClientWrapper = new LanguageClientWrapper(); - await this.languageClientWrapper.init({ - languageClientConfig: userConfig.languageClientConfig, - logger: this.logger - }); + const lccEntries = Object.entries(wrapperConfig.languageClientConfigs ?? {}); + if (lccEntries.length > 0) { + for (const [languageId, lcc] of lccEntries) { + const lcw = new LanguageClientWrapper({ + languageClientConfig: lcc, + logger: this.logger + }); + this.languageClientWrappers.set(languageId, lcw); + } } this.initDone = true; @@ -84,8 +94,8 @@ export class MonacoEditorLanguageClientWrapper { /** * Performs a full user configuration and the languageclient wrapper (if used) init and then start the application. */ - async initAndStart(userConfig: UserConfig, htmlElement: HTMLElement | null) { - await this.init(userConfig); + async initAndStart(wrapperConfig: WrapperConfig, htmlElement: HTMLElement | null) { + await this.init(wrapperConfig); await this.start(htmlElement); } @@ -104,9 +114,10 @@ export class MonacoEditorLanguageClientWrapper { await this.editorApp?.init(); await this.editorApp?.createEditors(htmlElement); - if (this.languageClientWrapper?.haveLanguageClientConfig() ?? false) { - await this.languageClientWrapper?.start(); + for (const lcw of this.languageClientWrappers.values()) { + await lcw.start(); } + this.markStarted(); } @@ -135,14 +146,19 @@ export class MonacoEditorLanguageClientWrapper { return false; } - if (this.languageClientWrapper?.haveLanguageClient() ?? false) { - return this.languageClientWrapper?.isStarted() ?? false; + for (const lcw of this.languageClientWrappers.values()) { + if (lcw.haveLanguageClient()) { + // as soon as one is not started return + if (!lcw.isStarted()) { + return false; + } + } } return true; } - haveLanguageClient(): boolean { - return this.languageClientWrapper !== undefined; + haveLanguageClients(): boolean { + return this.languageClientWrappers.size > 0; } getMonacoEditorApp() { @@ -157,12 +173,12 @@ export class MonacoEditorLanguageClientWrapper { return this.editorApp?.getDiffEditor(); } - getLanguageClientWrapper(): LanguageClientWrapper | undefined { - return this.languageClientWrapper; + getLanguageClientWrapper(languageId: string): LanguageClientWrapper | undefined { + return this.languageClientWrappers.get(languageId); } - getLanguageClient(): MonacoLanguageClient | undefined { - return this.languageClientWrapper?.getLanguageClient(); + getLanguageClient(languageId: string): MonacoLanguageClient | undefined { + return this.languageClientWrappers.get(languageId)?.getLanguageClient(); } getTextContents(): TextContents | undefined { @@ -177,8 +193,8 @@ export class MonacoEditorLanguageClientWrapper { return this.editorApp?.getModelRefs(); } - getWorker(): Worker | undefined { - return this.languageClientWrapper?.getWorker(); + getWorker(languageId: string): Worker | undefined { + return this.languageClientWrappers.get(languageId)?.getWorker(); } async updateCodeResources(codeResources?: CodeResources): Promise { @@ -200,21 +216,23 @@ export class MonacoEditorLanguageClientWrapper { /** * Disposes all application and editor resources, plus the languageclient (if used). */ - async dispose(disposeLanguageClient: boolean = true): Promise { + async dispose(disposeLanguageClients: boolean = true) { this.markStopping(); this.editorApp?.disposeApp(); - - if ((disposeLanguageClient && this.languageClientWrapper?.haveLanguageClient()) ?? false) { - await this.languageClientWrapper?.disposeLanguageClient(false); - this.editorApp = undefined; - await Promise.resolve('Monaco editor and languageclient completed disposed.'); + this.editorApp = undefined; + + if (disposeLanguageClients) { + const allPromises: Array> = []; + for (const lcw of this.languageClientWrappers.values()) { + if (lcw.haveLanguageClient()) { + allPromises.push(lcw.disposeLanguageClient(false)); + } + } + await Promise.all(allPromises); } - else { - await Promise.resolve('Monaco editor has been disposed.'); - } - this.initDone = false; + this.initDone = false; this.markStopped(); } diff --git a/packages/wrapper/test/editorAppBase.test.ts b/packages/wrapper/test/editorAppBase.test.ts index 1b60d5ea5..d58bb9944 100644 --- a/packages/wrapper/test/editorAppBase.test.ts +++ b/packages/wrapper/test/editorAppBase.test.ts @@ -5,17 +5,17 @@ import { describe, expect, test } from 'vitest'; import { isCodeUpdateRequired, isModelUpdateRequired, ModelUpdateType } from 'monaco-editor-wrapper'; -import { createEditorAppConfig, createWrapperConfig } from './helper.js'; +import { createEditorAppConfig, createBaseConfig } from './helper.js'; describe('Test EditorAppBase', () => { test('classic type: empty EditorAppConfigClassic', () => { - const wrapperConfig = createWrapperConfig('classic'); + const wrapperConfig = createBaseConfig('classic'); expect(wrapperConfig.editorAppConfig.$type).toBe('classic'); }); test('extended type: empty EditorAppConfigExtended', () => { - const wrapperConfig = createWrapperConfig('extended'); + const wrapperConfig = createBaseConfig('extended'); expect(wrapperConfig.editorAppConfig.$type).toBe('extended'); }); diff --git a/packages/wrapper/test/editorAppClassic.test.ts b/packages/wrapper/test/editorAppClassic.test.ts index 7c4f7b740..4e7c6f4ad 100644 --- a/packages/wrapper/test/editorAppClassic.test.ts +++ b/packages/wrapper/test/editorAppClassic.test.ts @@ -4,49 +4,49 @@ * ------------------------------------------------------------------------------------------ */ import { describe, expect, test } from 'vitest'; -import { EditorAppClassic, EditorAppConfigClassic } from 'monaco-editor-wrapper'; +import { EditorAppClassic, EditorAppConfigClassic, WrapperConfig } from 'monaco-editor-wrapper'; import { createBaseConfig, createEditorAppConfig } from './helper.js'; -const buildConfig = () => { - const config = createBaseConfig('classic'); - (config.wrapperConfig.editorAppConfig as EditorAppConfigClassic).editorOptions = {}; - return config; +const buildConfig = (): WrapperConfig => { + const wrapperConfig = createBaseConfig('classic'); + (wrapperConfig.editorAppConfig as EditorAppConfigClassic).editorOptions = {}; + return wrapperConfig; }; describe('Test EditorAppClassic', () => { test('editorOptions: semanticHighlighting=true', () => { - const config = buildConfig(); - const configclassic = config.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - configclassic.editorOptions!['semanticHighlighting.enabled'] = true; + const wrapperConfig = buildConfig(); + const configClassic = wrapperConfig.editorAppConfig as EditorAppConfigClassic; + configClassic.editorOptions!['semanticHighlighting.enabled'] = true; - const app = new EditorAppClassic('config defaults', config); - expect(configclassic.$type).toEqual('classic'); + const app = new EditorAppClassic('config defaults', configClassic); + expect(configClassic.$type).toEqual('classic'); expect(app.getConfig().editorOptions?.['semanticHighlighting.enabled']).toBeTruthy(); }); test('editorOptions: semanticHighlighting=false', () => { - const config = buildConfig(); - const configclassic = config.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - configclassic.editorOptions!['semanticHighlighting.enabled'] = false; + const wrapperConfig = buildConfig(); + const configClassic = wrapperConfig.editorAppConfig as EditorAppConfigClassic; + configClassic.editorOptions!['semanticHighlighting.enabled'] = false; - const app = new EditorAppClassic('config defaults', config); + const app = new EditorAppClassic('config defaults', configClassic); expect(app.getConfig().editorOptions?.['semanticHighlighting.enabled']).toBeFalsy(); }); test('editorOptions: semanticHighlighting="configuredByTheme"', () => { - const config = buildConfig(); - const configclassic = config.wrapperConfig.editorAppConfig as EditorAppConfigClassic; - configclassic.editorOptions!['semanticHighlighting.enabled'] = 'configuredByTheme'; + const wrapperConfig = buildConfig(); + const configClassic = wrapperConfig.editorAppConfig as EditorAppConfigClassic; + configClassic.editorOptions!['semanticHighlighting.enabled'] = 'configuredByTheme'; - const app = new EditorAppClassic('config defaults', config); + const app = new EditorAppClassic('config defaults', configClassic); expect(app.getConfig().editorOptions?.['semanticHighlighting.enabled']).toEqual('configuredByTheme'); }); test('isAppConfigDifferent: basic', () => { const orgConfig = createEditorAppConfig('classic') as EditorAppConfigClassic; const config = createEditorAppConfig('classic') as EditorAppConfigClassic; - const app = new EditorAppClassic('test', createBaseConfig('classic')); + const app = new EditorAppClassic('test', config); expect(app.isAppConfigDifferent(orgConfig, config, false)).toBeFalsy(); config.codeResources ??= {}; @@ -66,20 +66,20 @@ describe('Test EditorAppClassic', () => { }); test('isAppConfigDifferent: non-simple properties"', () => { - const config1 = buildConfig(); - const config2 = buildConfig(); - const configclassic1 = config1.wrapperConfig.editorAppConfig as EditorAppConfigClassic; + const wrapperConfig1 = buildConfig(); + const wrapperConfig2 = buildConfig(); + const configclassic1 = wrapperConfig1.editorAppConfig as EditorAppConfigClassic; configclassic1.editorOptions!['semanticHighlighting.enabled'] = true; - const configclassic2 = config2.wrapperConfig.editorAppConfig as EditorAppConfigClassic; + const configclassic2 = wrapperConfig2.editorAppConfig as EditorAppConfigClassic; configclassic2.editorOptions!['semanticHighlighting.enabled'] = true; - const app = new EditorAppClassic('config defaults', config1); + const app = new EditorAppClassic('config defaults', configclassic1); expect(app.isAppConfigDifferent(configclassic1, configclassic2, false)).toBeFalsy(); }); test('config defaults', () => { - const config = createBaseConfig('classic'); - const app = new EditorAppClassic('config defaults', config); + const editorAppConfig = createEditorAppConfig('classic') as EditorAppConfigClassic; + const app = new EditorAppClassic('config defaults', editorAppConfig); expect(app.getConfig().codeResources?.main?.text).toEqual(''); expect(app.getConfig().codeResources?.original).toBeUndefined(); expect(app.getConfig().useDiffEditor ?? false).toBeFalsy(); diff --git a/packages/wrapper/test/editorAppExtended.test.ts b/packages/wrapper/test/editorAppExtended.test.ts index d959280e8..55280da8f 100644 --- a/packages/wrapper/test/editorAppExtended.test.ts +++ b/packages/wrapper/test/editorAppExtended.test.ts @@ -21,19 +21,19 @@ describe('Test EditorAppExtended', () => { }); test('config userConfiguration', () => { - const config = createBaseConfig('extended'); - const appConfig = config.wrapperConfig.editorAppConfig as EditorAppConfigExtended; + const wrapperConfig = createBaseConfig('extended'); + const appConfig = wrapperConfig.editorAppConfig as EditorAppConfigExtended; appConfig.userConfiguration = { json: '{ "editor.semanticHighlighting.enabled": true }' }; - const app = new EditorAppExtended('config defaults', config); + const app = new EditorAppExtended('config defaults', appConfig); expect(app.getConfig().userConfiguration?.json).toEqual('{ "editor.semanticHighlighting.enabled": true }'); }); test('isAppConfigDifferent: basic', () => { const orgConfig = createEditorAppConfig('extended') as EditorAppConfigExtended; const config = createEditorAppConfig('extended') as EditorAppConfigExtended; - const app = new EditorAppExtended('test', createBaseConfig('extended')); + const app = new EditorAppExtended('test', config); expect(app.isAppConfigDifferent(orgConfig, config, false)).toBeFalsy(); config.codeResources ??= {}; @@ -61,8 +61,8 @@ describe('Test EditorAppExtended', () => { }); test('config defaults', () => { - const config = createBaseConfig('extended'); - const app = new EditorAppExtended('config defaults', config); + const editorAppConfig = createEditorAppConfig('extended') as EditorAppConfigExtended; + const app = new EditorAppExtended('config defaults', editorAppConfig); expect(app.getConfig().codeResources?.main?.text).toEqual(''); expect(app.getConfig().codeResources?.original).toBeUndefined(); expect(app.getConfig().useDiffEditor ?? false).toBeFalsy(); diff --git a/packages/wrapper/test/helper.ts b/packages/wrapper/test/helper.ts index 098dcb01d..6897d5b9e 100644 --- a/packages/wrapper/test/helper.ts +++ b/packages/wrapper/test/helper.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See LICENSE in the package root for license information. * ------------------------------------------------------------------------------------------ */ -import { UserConfig, EditorAppType } from 'monaco-editor-wrapper'; +import { EditorAppType, WrapperConfig } from 'monaco-editor-wrapper'; export const createMonacoEditorDiv = () => { const div = document.createElement('div'); @@ -11,13 +11,7 @@ export const createMonacoEditorDiv = () => { document.body.insertAdjacentElement('beforeend', div); }; -export const createBaseConfig = (type: EditorAppType): UserConfig => { - return { - wrapperConfig: createWrapperConfig(type) - }; -}; - -export const createWrapperConfig = (type: EditorAppType) => { +export const createBaseConfig = (type: EditorAppType): WrapperConfig => { return { editorAppConfig: createEditorAppConfig(type) }; @@ -35,12 +29,3 @@ export const createEditorAppConfig = (type: EditorAppType) => { useDiffEditor: false, }; }; - -/** - * Helper to generate a quick worker from a function blob - */ -export const createWorkerFromFunction = (fn: () => void): Worker => { - return new Worker(URL.createObjectURL( - new Blob([`(${fn.toString()})()`], { type: 'application/javascript' }) - )); -}; diff --git a/packages/wrapper/test/languageClientWrapper.test.ts b/packages/wrapper/test/languageClientWrapper.test.ts index e73e00987..d458a38c3 100644 --- a/packages/wrapper/test/languageClientWrapper.test.ts +++ b/packages/wrapper/test/languageClientWrapper.test.ts @@ -5,7 +5,7 @@ import { describe, expect, test } from 'vitest'; import { LanguageClientConfig, LanguageClientWrapper, MonacoEditorLanguageClientWrapper } from 'monaco-editor-wrapper'; -import { createBaseConfig, createWorkerFromFunction } from './helper.js'; +import { createBaseConfig } from './helper.js'; describe('Test LanguageClientWrapper', () => { @@ -13,98 +13,113 @@ describe('Test LanguageClientWrapper', () => { const wrapper = new MonacoEditorLanguageClientWrapper(); await wrapper.init(createBaseConfig('extended')); - const languageClientWrapper = wrapper.getLanguageClientWrapper(); + const languageClientWrapper = wrapper.getLanguageClientWrapper('unknown'); expect(languageClientWrapper).toBeUndefined(); }); test('Constructor: no config', async () => { // create a web worker to pass to the wrapper - const worker = createWorkerFromFunction(() => { - console.info('Hello'); + const worker = new Worker('./worker/langium-server.ts', { + type: 'module', + name: 'Langium LS', }); const languageClientConfig: LanguageClientConfig = { languageId: 'javascript', - options: { - $type: 'WorkerDirect', - worker + connection: { + options: { + $type: 'WorkerDirect', + worker + } } }; - const languageClientWrapper = new LanguageClientWrapper(); - languageClientWrapper.init({ + const languageClientWrapper = new LanguageClientWrapper({ languageClientConfig }); expect(languageClientWrapper).toBeDefined(); expect(languageClientWrapper.haveLanguageClient).toBeTruthy(); - expect(languageClientWrapper.haveLanguageClientConfig).toBeTruthy(); }); test('Dispose: direct worker is cleaned up afterwards', async () => { // create a web worker to pass to the wrapper - const worker = createWorkerFromFunction(() => { - console.info('Hello'); + const worker = new Worker('./worker/langium-server.ts', { + type: 'module', + name: 'Langium LS', }); // setup the wrapper const config = createBaseConfig('extended'); - config.languageClientConfig = { - languageId: 'javascript', - options: { - $type: 'WorkerDirect', - worker + config.languageClientConfigs = { + javascript: { + languageId: 'javascript', + connection: { + options: { + $type: 'WorkerDirect', + worker + } + } } }; const wrapper = new MonacoEditorLanguageClientWrapper(); await wrapper.init(config); - const languageClientWrapper = wrapper.getLanguageClientWrapper(); + const languageClientWrapper = wrapper.getLanguageClientWrapper('javascript'); expect(languageClientWrapper).toBeDefined(); - // start up & verify (don't wait for start to finish, just roll past it, we only care about the worker) - languageClientWrapper!.start(); - expect(languageClientWrapper!.getWorker()).toBeTruthy(); + expect(languageClientWrapper?.getWorker()).toBeFalsy(); + + // WA: for whatever reasons "await" kills the test, + // but the languageClientWrapper needs to be fully initialised as otherwise the follow up steps fail + languageClientWrapper?.start(); - // dispose & verify - languageClientWrapper!.disposeLanguageClient(); - expect(languageClientWrapper!.getWorker()).toBeUndefined(); + setTimeout(async () => { + // dispose & verify + await languageClientWrapper?.disposeLanguageClient(); + expect(languageClientWrapper?.getWorker()).toBeUndefined(); + }, 250); + expect(languageClientWrapper?.getWorker()).toBeTruthy(); }); test('Constructor: config', async () => { const config = createBaseConfig('extended'); - config.languageClientConfig = { - languageId: 'javascript', - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:12345/Tester' + config.languageClientConfigs = { + javascript: { + languageId: 'javascript', + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:12345/Tester' + } + } } }; const wrapper = new MonacoEditorLanguageClientWrapper(); await wrapper.init(config); - const languageClientWrapper = wrapper.getLanguageClientWrapper(); + const languageClientWrapper = wrapper.getLanguageClientWrapper('javascript'); expect(languageClientWrapper).toBeDefined(); - - expect(languageClientWrapper!.haveLanguageClientConfig()).toBeTruthy(); }); test('Start: unreachable url', async () => { const config = createBaseConfig('extended'); - config.languageClientConfig = { - languageId: 'javascript', - name: 'test-unreachable', - options: { - $type: 'WebSocketUrl', - url: 'ws://localhost:12345/Tester' + config.languageClientConfigs = { + javascript: { + languageId: 'javascript', + name: 'test-unreachable', + connection: { + options: { + $type: 'WebSocketUrl', + url: 'ws://localhost:12345/Tester' + } + } } }; const wrapper = new MonacoEditorLanguageClientWrapper(); await wrapper.init(config); - const languageClientWrapper = wrapper.getLanguageClientWrapper(); + const languageClientWrapper = wrapper.getLanguageClientWrapper('javascript'); expect(languageClientWrapper).toBeDefined(); - expect(languageClientWrapper!.haveLanguageClientConfig()).toBeTruthy(); - console.log('start'); await expect(languageClientWrapper!.start()).rejects.toEqual({ message: 'languageClientWrapper (test-unreachable): Websocket connection failed.', error: 'No error was provided.' @@ -124,21 +139,24 @@ describe('Test LanguageClientWrapper', () => { test('Start: unreachable worker url', async () => { const config = createBaseConfig('extended'); - config.languageClientConfig = { - languageId: 'javascript', - options: { - $type: 'WorkerConfig', - url: new URL('http://localhost:20101'), - type: 'classic' + config.languageClientConfigs = { + javascript: { + languageId: 'javascript', + connection: { + options: { + $type: 'WorkerConfig', + url: new URL('http://localhost:20101'), + type: 'classic' + } + } } }; const wrapper = new MonacoEditorLanguageClientWrapper(); await wrapper.init(config); - const languageClientWrapper = wrapper.getLanguageClientWrapper(); + const languageClientWrapper = wrapper.getLanguageClientWrapper('javascript'); expect(languageClientWrapper).toBeDefined(); - expect(languageClientWrapper!.haveLanguageClientConfig()).toBeTruthy(); await expect(languageClientWrapper!.start()).rejects.toEqual({ message: 'languageClientWrapper (unnamed): Illegal worker configuration detected. Potentially the url is wrong.', error: 'No error was provided.' diff --git a/packages/wrapper/test/utils.test.ts b/packages/wrapper/test/utils.test.ts index 7ab0e4536..5b07c0bd5 100644 --- a/packages/wrapper/test/utils.test.ts +++ b/packages/wrapper/test/utils.test.ts @@ -4,7 +4,8 @@ * ------------------------------------------------------------------------------------------ */ import { describe, expect, test } from 'vitest'; -import { WebSocketConfigOptions, WebSocketConfigOptionsUrl, createUrl } from 'monaco-editor-wrapper'; +import { WebSocketConfigOptionsParams, WebSocketConfigOptionsUrl } from 'monaco-languageclient'; +import { createUrl } from 'monaco-editor-wrapper'; describe('createUrl', () => { @@ -14,7 +15,7 @@ describe('createUrl', () => { host: 'localhost', port: 30000, path: 'sampleServer' - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('ws://localhost:30000/sampleServer'); }); @@ -25,7 +26,7 @@ describe('createUrl', () => { host: 'localhost', port: 30000, path: 'sampleServer' - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('wss://localhost:30000/sampleServer'); }); @@ -35,7 +36,7 @@ describe('createUrl', () => { secured: true, host: 'localhost', path: 'sampleServer' - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('wss://localhost/sampleServer'); }); @@ -45,7 +46,7 @@ describe('createUrl', () => { secured: true, host: 'localhost', port: 30000 - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('wss://localhost:30000'); }); @@ -54,7 +55,7 @@ describe('createUrl', () => { const url = createUrl({ secured: true, host: 'localhost' - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('wss://localhost'); }); @@ -64,7 +65,7 @@ describe('createUrl', () => { secured: false, host: 'localhost', port: 80 - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('ws://localhost'); }); @@ -75,7 +76,7 @@ describe('createUrl', () => { host: 'localhost', port: 80, path: 'sampleServer' - } as WebSocketConfigOptions); + } as WebSocketConfigOptionsParams); expect(url).toBe('ws://localhost/sampleServer'); }); diff --git a/packages/wrapper/test/worker/langium-server.ts b/packages/wrapper/test/worker/langium-server.ts new file mode 100644 index 000000000..be1c511f5 --- /dev/null +++ b/packages/wrapper/test/worker/langium-server.ts @@ -0,0 +1,24 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) 2018-2022 TypeFox and others. + * Licensed under the MIT License. See LICENSE in the package root for license information. + * ------------------------------------------------------------------------------------------ */ +/// + +import { EmptyFileSystem } from 'langium'; +import { DefaultSharedModuleContext, startLanguageServer } from 'langium/lsp'; +import { createLangiumGrammarServices } from 'langium/grammar'; +import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser.js'; + +/* browser specific setup code */ +const messageReader = new BrowserMessageReader(self as DedicatedWorkerGlobalScope); +const messageWriter = new BrowserMessageWriter(self as DedicatedWorkerGlobalScope); + +// Inject the shared services and language-specific services +const context = { + connection: createConnection(messageReader, messageWriter), + ...EmptyFileSystem +} as unknown as DefaultSharedModuleContext; +const { shared } = createLangiumGrammarServices(context); + +// Start the language server with the shared services +startLanguageServer(shared); diff --git a/packages/wrapper/test/wrapper.test.ts b/packages/wrapper/test/wrapper.test.ts index 161080715..5ee1e9b52 100644 --- a/packages/wrapper/test/wrapper.test.ts +++ b/packages/wrapper/test/wrapper.test.ts @@ -13,7 +13,7 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test('New wrapper has undefined editor', () => { const wrapper = new MonacoEditorLanguageClientWrapper(); - expect(wrapper.haveLanguageClient()).toBeFalsy(); + expect(wrapper.haveLanguageClients()).toBeFalsy(); expect(wrapper.getEditor()).toBeUndefined(); }); @@ -63,20 +63,20 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test('Verify if configuration changes make re-init necessary', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfigClassic = createBaseConfig('classic'); - wrapper.init(userConfigClassic); + const wrapperConfigClassic = createBaseConfig('classic'); + wrapper.init(wrapperConfigClassic); const app = wrapper.getMonacoEditorApp(); expect(app).toBeDefined(); if (app) { - expect(isReInitRequired(app, userConfigClassic, userConfigClassic)).toBeFalsy(); + expect(isReInitRequired(app, wrapperConfigClassic.editorAppConfig, wrapperConfigClassic.editorAppConfig)).toBeFalsy(); - const userConfigExtended = createBaseConfig('extended'); - expect(isReInitRequired(app, userConfigClassic, userConfigExtended)).toBeTruthy(); + const wrapperConfigExtended = createBaseConfig('extended'); + expect(isReInitRequired(app, wrapperConfigClassic.editorAppConfig, wrapperConfigExtended.editorAppConfig)).toBeTruthy(); - const userConfigClassicNew = createBaseConfig('classic'); - userConfigClassicNew.wrapperConfig.editorAppConfig.useDiffEditor = true; + const wrapperConfigClassicNew = createBaseConfig('classic'); + wrapperConfigClassicNew.editorAppConfig.useDiffEditor = true; - expect(isReInitRequired(app, userConfigClassicNew, userConfigClassic)).toBeTruthy(); + expect(isReInitRequired(app, wrapperConfigClassicNew.editorAppConfig, wrapperConfigClassic.editorAppConfig)).toBeTruthy(); } }); @@ -96,8 +96,8 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test('code resources original', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfig = createBaseConfig('classic'); - let codeResources = userConfig.wrapperConfig.editorAppConfig.codeResources; + const wrapperConfig = createBaseConfig('classic'); + let codeResources = wrapperConfig.editorAppConfig.codeResources; if (!codeResources) { codeResources = {}; } @@ -106,7 +106,7 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { text: 'original', fileExt: 'js' }; - await wrapper.initAndStart(userConfig, document.getElementById('monaco-editor-root')); + await wrapper.initAndStart(wrapperConfig, document.getElementById('monaco-editor-root')); const app = wrapper.getMonacoEditorApp(); const modelRefs = app?.getModelRefs(); @@ -118,8 +118,8 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test('code resources main and original', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfig = createBaseConfig('classic'); - let codeResources = userConfig.wrapperConfig.editorAppConfig.codeResources; + const wrapperConfig = createBaseConfig('classic'); + let codeResources = wrapperConfig.editorAppConfig.codeResources; if (!codeResources) { codeResources = {}; } @@ -127,7 +127,7 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { text: 'original', fileExt: 'js' }; - await wrapper.initAndStart(userConfig, document.getElementById('monaco-editor-root')); + await wrapper.initAndStart(wrapperConfig, document.getElementById('monaco-editor-root')); const app = wrapper.getMonacoEditorApp(); const modelRefs = app?.getModelRefs(); @@ -146,9 +146,9 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test('code resources empty', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfig = createBaseConfig('classic'); - userConfig.wrapperConfig.editorAppConfig.codeResources = {}; - await wrapper.initAndStart(userConfig, document.getElementById('monaco-editor-root')); + const wrapperConfig = createBaseConfig('classic'); + wrapperConfig.editorAppConfig.codeResources = {}; + await wrapper.initAndStart(wrapperConfig, document.getElementById('monaco-editor-root')); const app = wrapper.getMonacoEditorApp(); const modelRefs = app?.getModelRefs(); @@ -159,9 +159,9 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test('code resources model direct', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfig = createBaseConfig('classic'); - userConfig.wrapperConfig.editorAppConfig.codeResources = {}; - await wrapper.initAndStart(userConfig, document.getElementById('monaco-editor-root')); + const wrapperConfig = createBaseConfig('classic'); + wrapperConfig.editorAppConfig.codeResources = {}; + await wrapper.initAndStart(wrapperConfig, document.getElementById('monaco-editor-root')); const app = wrapper.getMonacoEditorApp(); @@ -183,8 +183,8 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { test.skip('extended editor disposes extensions', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfig = createBaseConfig('extended'); - (userConfig.wrapperConfig.editorAppConfig as EditorAppConfigExtended).extensions = [{ + const wrapperConfig = createBaseConfig('extended'); + (wrapperConfig.editorAppConfig as EditorAppConfigExtended).extensions = [{ config: { engines: { vscode: '*' @@ -207,18 +207,18 @@ describe('Test MonacoEditorLanguageClientWrapper', () => { ['/javascript.tmLanguage.json', '{}'] ]), }]; - await wrapper.initAndStart(userConfig, document.getElementById('monaco-editor-root')); + await wrapper.initAndStart(wrapperConfig, document.getElementById('monaco-editor-root')); await wrapper.dispose(); - await wrapper.initAndStart(userConfig, document.getElementById('monaco-editor-root')); + await wrapper.initAndStart(wrapperConfig, document.getElementById('monaco-editor-root')); }); test('Early code resources update on wrapper are ok', async () => { createMonacoEditorDiv(); const wrapper = new MonacoEditorLanguageClientWrapper(); - const userConfig = createBaseConfig('classic'); - userConfig.wrapperConfig.editorAppConfig.codeResources = {}; + const wrapperConfig = createBaseConfig('classic'); + wrapperConfig.editorAppConfig.codeResources = {}; - await wrapper.init(userConfig); + await wrapper.init(wrapperConfig); const app = wrapper.getMonacoEditorApp(); const promise = await wrapper.updateCodeResources({ main: { diff --git a/packages/wrapper/tsconfig.build.json b/packages/wrapper/tsconfig.build.json index e41c77a38..0cb7e416d 100644 --- a/packages/wrapper/tsconfig.build.json +++ b/packages/wrapper/tsconfig.build.json @@ -2,11 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "rootDir": "./build", - "noEmit": true, - // all other types are not needed here - "types": [ - "node" - ] + "noEmit": true }, "include": [ "build/**/*.ts", diff --git a/packages/wrapper/tsconfig.src.json b/packages/wrapper/tsconfig.src.json index 47c7bcf03..5f42eb538 100644 --- a/packages/wrapper/tsconfig.src.json +++ b/packages/wrapper/tsconfig.src.json @@ -7,10 +7,7 @@ // because vscode-jsonrpc requires DedicatedWorkerGlobalScope // we are required to include both DOM and WebWorker libs // the only way out currently is to disable lib checking - "skipLibCheck": true, - "types": [ - "vscode" - ] + "skipLibCheck": true }, "references": [{ "path": "../client/tsconfig.src.json", diff --git a/packages/wrapper/tsconfig.test.json b/packages/wrapper/tsconfig.test.json index 606d704d7..143bf44ec 100644 --- a/packages/wrapper/tsconfig.test.json +++ b/packages/wrapper/tsconfig.test.json @@ -2,7 +2,11 @@ "extends": "./tsconfig.src.json", "compilerOptions": { "noEmit": true, - "rootDir": "test" + "rootDir": "test", + // because vscode-jsonrpc requires DedicatedWorkerGlobalScope + // we are required to include both DOM and WebWorker libs + // the only way out currently is to disable lib checking + "skipLibCheck": true }, "references": [{ "path": "./tsconfig.src.json" diff --git a/tsconfig.json b/tsconfig.json index bc75e2d94..cc281bbe0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", + "module": "NodeNext", + "moduleResolution": "NodeNext", "lib": [ "ESNext", "DOM" diff --git a/verify/angular/package.json b/verify/angular/package.json index f1758a006..3a5e760fb 100644 --- a/verify/angular/package.json +++ b/verify/angular/package.json @@ -39,7 +39,7 @@ "style-loader": "~4.0.0" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" } } diff --git a/verify/pnpm/package.json b/verify/pnpm/package.json index 49b452485..1c272e5f6 100644 --- a/verify/pnpm/package.json +++ b/verify/pnpm/package.json @@ -14,8 +14,8 @@ "vite": "~5.3.3" }, "volta": { - "node": "20.16.0", - "pnpm": "9.7.0" + "node": "20.17.0", + "pnpm": "9.9.0" }, "scripts": { "verify": "pnpm install && pnpm run build && pnpm run start", diff --git a/verify/vite/package.json b/verify/vite/package.json index f0166e7fa..cea2b9cdb 100644 --- a/verify/vite/package.json +++ b/verify/vite/package.json @@ -14,8 +14,8 @@ "vite": "~5.3.3" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "scripts": { "verify": "npm install && npm run build && npm run start", diff --git a/verify/webpack/package.json b/verify/webpack/package.json index 0dbd3d03f..b7178f549 100644 --- a/verify/webpack/package.json +++ b/verify/webpack/package.json @@ -19,8 +19,8 @@ "webpack-cli": "~5.1.4" }, "volta": { - "node": "20.16.0", - "npm": "10.8.1" + "node": "20.17.0", + "npm": "10.8.3" }, "scripts": { "verify": "npm install && npm run build && npm run start", diff --git a/verify/yarn/package.json b/verify/yarn/package.json index f846e338c..474b9e998 100644 --- a/verify/yarn/package.json +++ b/verify/yarn/package.json @@ -4,10 +4,10 @@ "private": true, "type": "module", "dependencies": { - "@typefox/monaco-editor-react": "~4.5.3", + "@typefox/monaco-editor-react": "~6.0.0-next.0", "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~8.0.4", - "monaco-editor-wrapper": "~5.5.3s", - "monaco-languageclient-examples": "~2024.8.4", + "monaco-editor-wrapper": "~6.0.0-next.0", + "monaco-languageclient-examples": "~2024.9.1", "vscode": "npm:@codingame/monaco-vscode-api@~8.0.4", "vscode-ws-jsonrpc": "~3.3.2" }, @@ -16,7 +16,7 @@ "vite": "~5.3.3" }, "volta": { - "node": "20.16.0", + "node": "20.17.0", "yarn": "1.22.22" }, "scripts": { diff --git a/vite.config.ts b/vite.config.ts index 1c6f59563..94ca38d64 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -32,6 +32,9 @@ const viteConfig = defineViteConfig({ // grrovy groovy: path.resolve(__dirname, 'packages/examples/groovy.html'), + // json & python + twoLangaugeClients: path.resolve(__dirname, 'packages/examples/two_langauge_clients.html'), + // monaco-editor-react // langium reactStatemachine: path.resolve(__dirname, 'packages/examples/react_statemachine.html'), @@ -39,8 +42,7 @@ const viteConfig = defineViteConfig({ reactPython: path.resolve(__dirname, 'packages/examples/react_python.html'), // other examples - wrapperTs: path.resolve(__dirname, 'packages/examples/wrapper_ts.html'), - wrapperAdvanced: path.resolve(__dirname, 'packages/examples/wrapper_adv.html'), + wrapperTs: path.resolve(__dirname, 'packages/examples/wrapper_ts.html') } } },