From bc9cb61aaf1a4ca466cebd4645fe19286042e56d Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Tue, 15 Sep 2026 09:42:37 +0800 Subject: [PATCH] build(site): [SITE-07] reproduce and validate Monaco language modes --- .gitattributes | 1 + package.json | 3 +- .../baselines/monaco-language-notices.json | 19 +- .../baselines/monaco-modes-provenance.json | 450 ++++++ .../baselines/monaco-modes-validation.json | 464 ++++++ .../monaco-css-src-cssMode.ts.txt | 122 ++ .../monaco-css-src-languageFeatures.ts.txt | 725 ++++++++++ .../monaco-css-src-workerManager.ts.txt | 87 ++ .../monaco-html-src-htmlMode.ts.txt | 164 +++ .../monaco-html-src-languageFeatures.ts.txt | 608 ++++++++ .../monaco-html-src-workerManager.ts.txt | 89 ++ .../monaco-json-src-jsonMode.ts.txt | 143 ++ .../monaco-json-src-languageFeatures.ts.txt | 716 ++++++++++ .../monaco-json-src-tokenization.ts.txt | 245 ++++ .../monaco-json-src-workerManager.ts.txt | 88 ++ ...aco-typescript-src-languageFeatures.ts.txt | 1265 +++++++++++++++++ ...monaco-typescript-src-lib-lib.index.ts.txt | 72 + .../monaco-typescript-src-tsMode.ts.txt | 87 ++ .../monaco-typescript-src-tsconfig.json.txt | 11 + ...monaco-typescript-src-workerManager.ts.txt | 114 ++ .../2026-09-15-SITE-07-monaco-modes.md | 45 + refactor/plan.md | 2 +- refactor/progress.md | 9 + refactor/risks.json | 9 +- refactor/tasks.json | 5 +- refactor/third-party.json | 2 +- scripts/site-vendor/manifest.json | 8 +- scripts/site-vendor/monaco/README.md | 31 +- scripts/site-vendor/monaco/compiler.ts | 34 + scripts/site-vendor/monaco/languages.ts | 4 +- scripts/site-vendor/monaco/notices.ts | 3 +- .../site-vendor/monaco/reproduce-languages.ts | 28 +- scripts/site-vendor/monaco/reproduce-modes.ts | 81 ++ test/browser/README.md | 6 + test/browser/editor-modes.spec.js | 72 + test/monaco-provenance.test.js | 15 + 36 files changed, 5784 insertions(+), 43 deletions(-) create mode 100644 refactor/baselines/monaco-modes-provenance.json create mode 100644 refactor/baselines/monaco-modes-validation.json create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-css-src-cssMode.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-css-src-languageFeatures.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-css-src-workerManager.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-html-src-htmlMode.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-html-src-languageFeatures.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-html-src-workerManager.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-json-src-jsonMode.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-json-src-languageFeatures.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-json-src-tokenization.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-json-src-workerManager.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-languageFeatures.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-lib-lib.index.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsMode.ts.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsconfig.json.txt create mode 100644 refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-workerManager.ts.txt create mode 100644 refactor/changes/2026-09-15-SITE-07-monaco-modes.md create mode 100644 scripts/site-vendor/monaco/compiler.ts create mode 100644 scripts/site-vendor/monaco/reproduce-modes.ts create mode 100644 test/browser/editor-modes.spec.js diff --git a/.gitattributes b/.gitattributes index 427eeebd7..d6095a2da 100644 --- a/.gitattributes +++ b/.gitattributes @@ -35,3 +35,4 @@ docs/licenses/monaco-editor/typescript/** -text whitespace=-trailing-space,cr-at refactor/baselines/site-vendor/monaco-languages/** -text whitespace=-trailing-space,cr-at-eol refactor/baselines/site-vendor/monaco-language-notices/** -text whitespace=-trailing-space,cr-at-eol docs/licenses/monaco-editor/language-services/** -text whitespace=-trailing-space,cr-at-eol +refactor/baselines/site-vendor/monaco-modes/** -text whitespace=-trailing-space,cr-at-eol diff --git a/package.json b/package.json index da73d04d9..dcb418955 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,8 @@ "check:console": "node scripts/build-console.mjs --check", "test:site-console": "node --test test/site-console.test.js", "verify:monaco-typescript-source": "node scripts/site-vendor/monaco/reproduce-typescript.ts", - "verify:monaco-language-sources": "node scripts/site-vendor/monaco/reproduce-languages.ts" + "verify:monaco-language-sources": "node scripts/site-vendor/monaco/reproduce-languages.ts", + "verify:monaco-mode-sources": "node scripts/site-vendor/monaco/reproduce-modes.ts" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/refactor/baselines/monaco-language-notices.json b/refactor/baselines/monaco-language-notices.json index 63015c424..a03fdae0a 100644 --- a/refactor/baselines/monaco-language-notices.json +++ b/refactor/baselines/monaco-language-notices.json @@ -10,7 +10,8 @@ "tarball": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", "archive": "jsonc-parser-3.0.0", "assets": [ - "docs/assets/js/vs/language/json/jsonWorker.js" + "docs/assets/js/vs/language/json/jsonWorker.js", + "docs/assets/js/vs/language/json/jsonMode.js" ], "notices": [ "docs/licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md" @@ -76,7 +77,10 @@ "assets": [ "docs/assets/js/vs/language/css/cssWorker.js", "docs/assets/js/vs/language/html/htmlWorker.js", - "docs/assets/js/vs/language/json/jsonWorker.js" + "docs/assets/js/vs/language/json/jsonWorker.js", + "docs/assets/js/vs/language/css/cssMode.js", + "docs/assets/js/vs/language/html/htmlMode.js", + "docs/assets/js/vs/language/json/jsonMode.js" ], "notices": [ "docs/licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt" @@ -104,7 +108,8 @@ "tarball": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", "archive": "jsonc-parser-3.0.0", "assets": [ - "docs/assets/js/vs/language/json/jsonWorker.js" + "docs/assets/js/vs/language/json/jsonWorker.js", + "docs/assets/js/vs/language/json/jsonMode.js" ], "notices": [ "docs/licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md", @@ -175,7 +180,10 @@ "assets": [ "docs/assets/js/vs/language/css/cssWorker.js", "docs/assets/js/vs/language/html/htmlWorker.js", - "docs/assets/js/vs/language/json/jsonWorker.js" + "docs/assets/js/vs/language/json/jsonWorker.js", + "docs/assets/js/vs/language/css/cssMode.js", + "docs/assets/js/vs/language/html/htmlMode.js", + "docs/assets/js/vs/language/json/jsonMode.js" ], "notices": [ "docs/licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt", @@ -318,5 +326,6 @@ "target": "docs/licenses/monaco-editor/language-services/ATTRIBUTION.md", "sha256": "432cca135809edabcd9ccedd05576138b64b167445999005a6e1550132391d98" } - ] + ], + "modeSourceRecord": "refactor/baselines/monaco-modes-provenance.json" } diff --git a/refactor/baselines/monaco-modes-provenance.json b/refactor/baselines/monaco-modes-provenance.json new file mode 100644 index 000000000..2aa277ed7 --- /dev/null +++ b/refactor/baselines/monaco-modes-provenance.json @@ -0,0 +1,450 @@ +{ + "schemaVersion": 1, + "task": "SITE-07", + "commit": "5a7ba61be909ae9e4889768a3453ebb0dec392e2", + "scope": "All four language mode bundles; exact module/helper and minified output coverage, not a complete upstream typecheck.", + "archives": [ + { + "name": "monaco-editor", + "version": "0.30.1", + "tarball": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", + "integrity": "sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg==", + "sha256": "d7872ab742036036eca48cd54e43d751bede56742f0689bcf4049bcf701468c7" + }, + { + "name": "typescript", + "version": "4.4.4", + "tarball": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "sha256": "7524841bbf63777fef1fe6e1a826026b1dd4849f54f5affa481502faab2cdb16" + }, + { + "name": "terser", + "version": "5.9.0", + "tarball": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", + "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", + "sha256": "2ca0d9c4731b6ebd3b86ed1a7b735f685f98636ee5a067ae9e27e83246069619" + }, + { + "name": "source-map", + "version": "0.7.3", + "tarball": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "sha256": "ad69b787ba774733c3e4f0eb20403df7b1fa466252d453533dbcc6a5ad15833e" + }, + { + "name": "jsonc-parser", + "version": "3.0.0", + "tarball": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "sha256": "807c53e781c6c6181165f6214db5f6892742041338d9891ce3c335cf3bc25da8" + }, + { + "name": "vscode-languageserver-types", + "version": "3.16.0", + "tarball": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", + "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", + "sha256": "eb934ea5eda6fd6b5d21ae8706922be1179501c30350260e07998e76c6946a2c" + } + ], + "remotes": [ + { + "source": "refactor/baselines/site-vendor/monaco-typescript/package-lock.json.txt", + "sha256": "84c66bfe8ae95b2226ca289279133999356e64137db7ba001817737fa1ac8cf8", + "gitBlobSha": "9f647e9fc82150a5d06a9c02dc781d2dbe902ed6", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/package-lock.json?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-languages/monaco-css-scripts-bundle.js.txt", + "sha256": "2a9dbfbd62b6106835ac69d930e4e1024000196154d0fd98e7a42bfab9977751", + "gitBlobSha": "49709bc5efb3f5e81c2797fa771b0576f86c71fb", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-css/scripts/bundle.js?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-languages/monaco-css-src-tsconfig.json.txt", + "sha256": "d5739d74d37ae0ff0d8b55f19b1116433bae9b0f8a81c8b410bd587e11bc7694", + "gitBlobSha": "707f714dd2869a2e1fe3c5a679cf1eb116f0f542", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-css/src/tsconfig.json?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-languages/monaco-html-scripts-bundle.js.txt", + "sha256": "9a101e8926d384a880bdfc13ae72559f72d1b4e8b1d7dd755a6a999ca6383718", + "gitBlobSha": "d5932edf6307028d76be68e76fcaf08ec2768a58", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-html/scripts/bundle.js?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-languages/monaco-html-src-tsconfig.json.txt", + "sha256": "d5739d74d37ae0ff0d8b55f19b1116433bae9b0f8a81c8b410bd587e11bc7694", + "gitBlobSha": "707f714dd2869a2e1fe3c5a679cf1eb116f0f542", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-html/src/tsconfig.json?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-languages/monaco-json-scripts-bundle.js.txt", + "sha256": "1326211da917b321808ae29987c666226028ad276af3e1d376cd7d0ed3902fd6", + "gitBlobSha": "cb54926f4a3fb00d16824d2be6c6e51b3a6524ec", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-json/scripts/bundle.js?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-languages/monaco-json-src-tsconfig.json.txt", + "sha256": "d5739d74d37ae0ff0d8b55f19b1116433bae9b0f8a81c8b410bd587e11bc7694", + "gitBlobSha": "707f714dd2869a2e1fe3c5a679cf1eb116f0f542", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-json/src/tsconfig.json?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-typescript/bundle.js.txt", + "sha256": "1f418cf3a1c27d9c466ce315ebb185451e47e70847e3fb53f383aae2bb5250d9", + "gitBlobSha": "2478682d11c9122debd33d6a7339183b16238799", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-typescript/scripts/bundle.js?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsconfig.json.txt", + "sha256": "0db526f0bf18e6022981cde7257af00875f4c2027d4f2a5e88221f6541f80452", + "gitBlobSha": "001f587e6dd21981e63aff2bebdfd8a6a79a74eb", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-typescript/src/tsconfig.json?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-css-src-workerManager.ts.txt", + "sha256": "8705e3989d308a42c23f5f9d3ea422fcb11315787c1e937cd8f9539ce9c49504", + "gitBlobSha": "335396d5d17303bca55cf8f043762501e6a55d4a", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-css/src/workerManager.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-css-src-languageFeatures.ts.txt", + "sha256": "0f2f6b94992a614c930dc3c2516cd875c77424f05bb9ad730e123fbc6ac1e7da", + "gitBlobSha": "462521c8aa98a1527b00c2510b5f00c8570716ae", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-css/src/languageFeatures.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-css-src-cssMode.ts.txt", + "sha256": "24af822e60188a50129779164aef98415355a3e7aa29e2cb200987b0fa7c4fbe", + "gitBlobSha": "ec3ea26039c2df9889a0769b9cbfe38bb14c2a10", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-css/src/cssMode.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-html-src-workerManager.ts.txt", + "sha256": "c46c7286896e5c8eff4f0eb8dbcee0d114486419314c861d52dafcd5b7fef0f9", + "gitBlobSha": "5122168b53c9ef913d76e9cd9baf1b6f6c9e30a5", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-html/src/workerManager.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-html-src-languageFeatures.ts.txt", + "sha256": "f444cec1b734bfc64d2941291ffc172e6e9326b0f4112c53660fe4e07064e9eb", + "gitBlobSha": "2d6ec03408b5dc1f96b58aced67240521af4bc2b", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-html/src/languageFeatures.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-html-src-htmlMode.ts.txt", + "sha256": "a48c1bc729ea7a609bbd5bf122a37c7960437763498c58828f4a69424e28d495", + "gitBlobSha": "95b560cb358b16920eb204b5ab4d362b3a59de49", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-html/src/htmlMode.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-workerManager.ts.txt", + "sha256": "88f875df4f3358d1759e7c60efeed6033a3490f7e6a51f6ad89b96d97aceb75c", + "gitBlobSha": "6c32e001806ee072a11b0a763a2ff8b3178d2da5", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-json/src/workerManager.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-languageFeatures.ts.txt", + "sha256": "4b0e8d14b8c6553e078173217e6fcd7c50b5d56b1718cad6f37733db90998da8", + "gitBlobSha": "cc6391a0b00a922503c799a3181848c5c9540371", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-json/src/languageFeatures.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-tokenization.ts.txt", + "sha256": "14cab1d17770916632f94955a5cd14664d7fe02facc8ce3c9354e515c22ffec1", + "gitBlobSha": "aa9bd5a447d9fbe78b685d5765bdf2f02e5445c0", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-json/src/tokenization.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-jsonMode.ts.txt", + "sha256": "7e098ac320154c14b9f026df9189b06c1433e71171e6c6c6b1d9f0ce5406a684", + "gitBlobSha": "7d66f6a0e1b14951b81c43cb3486ac0a7862aa79", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-json/src/jsonMode.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-workerManager.ts.txt", + "sha256": "a0d0f19f8b8819e6a38144dd1a30cd27763eeca1f2ac94501f76dba46a73e43f", + "gitBlobSha": "6e70ae025f568ab8468d0c86ada8e0e70ec58ea5", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-typescript/src/workerManager.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-lib-lib.index.ts.txt", + "sha256": "722036bc714d9c5e1b06e419dd96400d0f59eec13a20bec44a0403bca50b6383", + "gitBlobSha": "a501460f03cbd6a88b45bfee44a9ab6ef595db4f", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-typescript/src/lib/lib.index.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-languageFeatures.ts.txt", + "sha256": "4be07e7664d0127a7339e70b81b4dd783479c40f3020bf83de24c9beb8ab1580", + "gitBlobSha": "2dba4a863fca7f516b7009e2a09d41c78c48f262", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-typescript/src/languageFeatures.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + }, + { + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsMode.ts.txt", + "sha256": "2be7c0ef70f9c0d819680057e87b041f3ba34b1d4f60801f5058bfd4fc12232d", + "gitBlobSha": "9ebf59cf6bcc66b93c2e728644fb6eba695bbe6a", + "apiUrl": "https://api.github.com/repos/microsoft/monaco-editor/contents/monaco-typescript/src/tsMode.ts?ref=5a7ba61be909ae9e4889768a3453ebb0dec392e2" + } + ], + "compilerMembers": [ + { + "archive": "typescript-4.4.4", + "member": "package/lib/typescript.js", + "sha256": "69fde5346b9468255c32d8d0bff32842445822528b25da1a323ec1c076979384" + }, + { + "archive": "typescript-4.4.4", + "member": "package/lib/lib.es5.d.ts", + "sha256": "aa9fb4c70f369237c2f45f9d969c9a59e0eae9a192962eb48581fe864aa609db" + }, + { + "archive": "typescript-4.4.4", + "member": "package/lib/lib.dom.d.ts", + "sha256": "e54c8715a4954cfdc66cd69489f2b725c09ebf37492dbd91cff0a1688b1159e8" + }, + { + "archive": "typescript-4.4.4", + "member": "package/lib/lib.es2015.collection.d.ts", + "sha256": "43fb1d932e4966a39a41b464a12a81899d9ae5f2c829063f5571b6b87e6d2f9c" + }, + { + "archive": "typescript-4.4.4", + "member": "package/lib/lib.es2015.promise.d.ts", + "sha256": "2bb4b3927299434052b37851a47bf5c39764f2ba88a888a107b32262e9292b7c" + }, + { + "archive": "typescript-4.4.4", + "member": "package/lib/lib.es2015.iterable.d.ts", + "sha256": "2c8c5ee58f30e7c944e04ab1fb5506fdbb4dd507c9efa6972cf4b91cec90c503" + }, + { + "archive": "terser-5.9.0", + "member": "package/dist/bundle.min.js", + "sha256": "b8b44743a529c5bd1cf8d6676f040c3c9bed29c7c114e5a26dde5e0fb2125838" + } + ], + "declaration": { + "archive": "jsonc-parser-3.0.0", + "member": "package/lib/umd/main.d.ts", + "sha256": "5c65cfde6c6384c36d66bdbe76316d4fa274183c63258cb75b922306e845171f" + }, + "npmModules": [ + { + "id": "vscode-languageserver-types/main", + "archive": "vscode-languageserver-types-3.16.0", + "member": "package/lib/umd/main.js", + "sha256": "bc54d0255c6527858d4b2a6c9fd366dd5bdc08d627aa6a81ebb52b27fe1bb17d" + }, + { + "id": "jsonc-parser/impl/scanner", + "archive": "jsonc-parser-3.0.0", + "member": "package/lib/umd/impl/scanner.js", + "sha256": "1de9d507a6fc3cbe314fe77d4129db5d0d717b453d6340dc822869f6be6f01ef" + }, + { + "id": "jsonc-parser/impl/format", + "archive": "jsonc-parser-3.0.0", + "member": "package/lib/umd/impl/format.js", + "sha256": "0a6e9addcaba963b19bdc28a9e563affe7ecfa9d710bbbf88a798e134b8c2d9e" + }, + { + "id": "jsonc-parser/impl/parser", + "archive": "jsonc-parser-3.0.0", + "member": "package/lib/umd/impl/parser.js", + "sha256": "0bcb61b4cddc09380ae45a8bb74d97162a46733dd87bada5590579f91abc2a62" + }, + { + "id": "jsonc-parser/impl/edit", + "archive": "jsonc-parser-3.0.0", + "member": "package/lib/umd/impl/edit.js", + "sha256": "be5cbec07265803c812a888d8aeaf18f69c77c827a120486ef38515d6225008d" + }, + { + "id": "jsonc-parser/main", + "archive": "jsonc-parser-3.0.0", + "member": "package/lib/umd/main.js", + "sha256": "09e425ed64c68688277ed7ef8e0b627700134e4e2290aa36b175530b658245aa" + } + ], + "aliases": [ + { + "id": "jsonc-parser", + "main": "main" + }, + { + "id": "vscode-languageserver-types", + "main": "main" + } + ], + "files": [ + { + "language": "css", + "name": "cssMode", + "development": { + "archive": "monaco-editor-0.30.1", + "member": "package/dev/vs/language/css/cssMode.js", + "sha256": "a541bd23805055fda946f0b462a56cfe1f9ff1ec3cf8c63aa5dd1f56a86a9001" + }, + "target": { + "path": "docs/assets/js/vs/language/css/cssMode.js", + "sha256": "c0f3a99395d07b421ef75f6eb78389c6ef29477f6a05556f9b94e2bb918dd6c1" + }, + "ids": [ + "vs/language/css/workerManager", + "vscode-languageserver-types/main", + "vscode-languageserver-types", + "vs/language/css/languageFeatures", + "vs/language/css/cssMode" + ], + "modules": [ + { + "id": "vs/language/css/workerManager", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-css-src-workerManager.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/css/languageFeatures", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-css-src-languageFeatures.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/css/cssMode", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-css-src-cssMode.ts.txt", + "resolveJsonc": false + } + ], + "config": "refactor/baselines/site-vendor/monaco-languages/monaco-css-src-tsconfig.json.txt" + }, + { + "language": "html", + "name": "htmlMode", + "development": { + "archive": "monaco-editor-0.30.1", + "member": "package/dev/vs/language/html/htmlMode.js", + "sha256": "d5f1df4fcfb72023f0a35ccc339ba35c08ffa9d5677361246d4e8bcd49c912a5" + }, + "target": { + "path": "docs/assets/js/vs/language/html/htmlMode.js", + "sha256": "91f7b295ddc3b0b679c669b84865f3ace79fdd30bfcd814f2960c06f3e24d600" + }, + "ids": [ + "vs/language/html/workerManager", + "vscode-languageserver-types/main", + "vscode-languageserver-types", + "vs/language/html/languageFeatures", + "vs/language/html/htmlMode" + ], + "modules": [ + { + "id": "vs/language/html/workerManager", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-html-src-workerManager.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/html/languageFeatures", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-html-src-languageFeatures.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/html/htmlMode", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-html-src-htmlMode.ts.txt", + "resolveJsonc": false + } + ], + "config": "refactor/baselines/site-vendor/monaco-languages/monaco-html-src-tsconfig.json.txt" + }, + { + "language": "json", + "name": "jsonMode", + "development": { + "archive": "monaco-editor-0.30.1", + "member": "package/dev/vs/language/json/jsonMode.js", + "sha256": "75451dc400862d52cf48e3da7d1810f3fbb6958ec00a98fc1745ca101b968ee0" + }, + "target": { + "path": "docs/assets/js/vs/language/json/jsonMode.js", + "sha256": "9abacb664dcd8564f28ef004465da0f4b3c551b2741424bf42e61c0a26e61adb" + }, + "ids": [ + "vs/language/json/workerManager", + "vscode-languageserver-types/main", + "vscode-languageserver-types", + "vs/language/json/languageFeatures", + "jsonc-parser/impl/scanner", + "jsonc-parser/impl/format", + "jsonc-parser/impl/parser", + "jsonc-parser/impl/edit", + "jsonc-parser/main", + "jsonc-parser", + "vs/language/json/tokenization", + "vs/language/json/jsonMode" + ], + "modules": [ + { + "id": "vs/language/json/workerManager", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-workerManager.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/json/languageFeatures", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-languageFeatures.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/json/tokenization", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-tokenization.ts.txt", + "resolveJsonc": true + }, + { + "id": "vs/language/json/jsonMode", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-json-src-jsonMode.ts.txt", + "resolveJsonc": false + } + ], + "config": "refactor/baselines/site-vendor/monaco-languages/monaco-json-src-tsconfig.json.txt" + }, + { + "language": "typescript", + "name": "tsMode", + "development": { + "archive": "monaco-editor-0.30.1", + "member": "package/dev/vs/language/typescript/tsMode.js", + "sha256": "6e360cea797f62d8547a55a6a9f9e51075580ee299e500920c46636a30bd09ef" + }, + "target": { + "path": "docs/assets/js/vs/language/typescript/tsMode.js", + "sha256": "35d94edaf7982c8b59c95cda38c5ebffcf93479ee91a5c9820b9bf60719351c2" + }, + "ids": [ + "vs/language/typescript/workerManager", + "vs/language/typescript/lib/lib.index", + "vs/language/typescript/languageFeatures", + "vs/language/typescript/tsMode" + ], + "modules": [ + { + "id": "vs/language/typescript/workerManager", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-workerManager.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/typescript/lib/lib.index", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-lib-lib.index.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/typescript/languageFeatures", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-languageFeatures.ts.txt", + "resolveJsonc": false + }, + { + "id": "vs/language/typescript/tsMode", + "source": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsMode.ts.txt", + "resolveJsonc": false + } + ], + "config": "refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsconfig.json.txt" + } + ] +} diff --git a/refactor/baselines/monaco-modes-validation.json b/refactor/baselines/monaco-modes-validation.json new file mode 100644 index 000000000..257855f25 --- /dev/null +++ b/refactor/baselines/monaco-modes-validation.json @@ -0,0 +1,464 @@ +{ + "schemaVersion": 1, + "task": "SITE-07", + "status": "checkpoint-incomplete", + "recordedAt": "2026-09-15T01:41:29.392Z", + "baseCommit": "99c208aeee331eec2d9ffa9bb15a608fdc17a840", + "node": "v24.21.0", + "yarn": "1.22.22", + "fingerprints": { + "sourceRecord": "e360eff36f2d424dd8f6dfcc65a68c9c527216f8bf1dda7635cc8bc52524782a", + "noticeRecord": "2bb8c11e6fa5f971a7abf89516dde88abe0d29e1e5e417566505d6f8c7f756da", + "manifest": "20c856848f0801d4f6fd66d5b86a37c81bb0b374bf7062b7363602dcc2921971", + "runtimeChanges": "No Monaco runtime or notice text changes" + }, + "reproduction": { + "result": { + "archives": 6, + "gitSources": 23, + "ownModules": 14, + "npmModules": 6, + "aliases": 2, + "modes": [ + { + "language": "css", + "modules": 5, + "exactSources": true, + "exactOutput": true, + "sha256": "c0f3a99395d07b421ef75f6eb78389c6ef29477f6a05556f9b94e2bb918dd6c1" + }, + { + "language": "html", + "modules": 5, + "exactSources": true, + "exactOutput": true, + "sha256": "91f7b295ddc3b0b679c669b84865f3ace79fdd30bfcd814f2960c06f3e24d600" + }, + { + "language": "json", + "modules": 12, + "exactSources": true, + "exactOutput": true, + "sha256": "9abacb664dcd8564f28ef004465da0f4b3c551b2741424bf42e61c0a26e61adb" + }, + { + "language": "typescript", + "modules": 4, + "exactSources": true, + "exactOutput": true, + "sha256": "35d94edaf7982c8b59c95cda38c5ebffcf93479ee91a5c9820b9bf60719351c2" + } + ], + "coreAndBasicLanguagesReviewed": false + }, + "offlineLog": "refactor/.cache/monaco-modes-offline.log", + "firstFetch": { + "exitCode": 1, + "error": "getaddrinfo ENOTFOUND registry.npmjs.org", + "log": "refactor/.cache/monaco-modes-fetch.log" + }, + "retryFetch": { + "exitCode": 0, + "log": "refactor/.cache/monaco-modes-fetch-retry.log" + }, + "workerRegression": { + "result": { + "archives": 11, + "gitSources": 13, + "npmModules": 91, + "aliases": 8, + "workers": [ + { + "language": "css", + "modules": 48, + "exactSources": true, + "exactWorker": true, + "sha256": "073e09f9301dcf147e40ef675e3f18d8cc29de9f49673ec8d17711569144552d" + }, + { + "language": "html", + "modules": 38, + "exactSources": true, + "exactWorker": true, + "sha256": "0b14f0af7ae7ab85732574fb384496dae3e85d28f953188cc842eec468a8a457" + }, + { + "language": "json", + "modules": 33, + "exactSources": true, + "exactWorker": true, + "sha256": "0eb929c56d44afddb3030c011913010311ce34e5eadb1129a3ce9cbafd4c771d" + } + ], + "notices": 12, + "licenseReviewComplete": false, + "otherMonacoComponentsReviewed": false + }, + "log": "refactor/.cache/monaco-modes-worker-regression.log" + } + }, + "unit": { + "passed": 15, + "log": "refactor/.cache/monaco-modes-unit.log" + }, + "browser": { + "report": "refactor/.cache/browser/report.json", + "sha256": "491703cee7accd59f58b154dec0f5841b4195cbe60ee9fe3d64b47efb0fb8b14", + "tests": [ + { + "project": "chromium", + "title": "docs Monaco mode registrations update editor diagnostics and formatting across languages", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "results": { + "evidence": [ + { + "language": "css", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-css", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-css", + "_fsPath": null + }, + "owner": "css", + "code": "css-propertyvalueexpected", + "severity": 8, + "message": "property value expected", + "source": "css", + "startLineNumber": 1, + "startColumn": 12, + "endLineNumber": 1, + "endColumn": 13 + } + ] + }, + { + "language": "json", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-json", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-json", + "_fsPath": null + }, + "owner": "json", + "code": "516", + "severity": 8, + "message": "Value expected", + "source": "json", + "startLineNumber": 1, + "startColumn": 10, + "endLineNumber": 1, + "endColumn": 11 + } + ] + }, + { + "language": "json", + "formatted": "{\r\n \"value\": 1\r\n}" + }, + { + "language": "typescript", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-typescript", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-typescript", + "_fsPath": null + }, + "owner": "typescript", + "code": "2322", + "severity": 8, + "message": "Type 'string' is not assignable to type 'number'.", + "startLineNumber": 1, + "startColumn": 7, + "endLineNumber": 1, + "endColumn": 12, + "relatedInformation": [], + "tags": [] + } + ] + }, + { + "language": "html", + "formatted": "
\r\n

hello

\r\n

world

\r\n
" + } + ], + "loadedModes": [ + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/css/cssMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/json/jsonMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/typescript/tsMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/html/htmlMode.js", + "status": 200 + } + ] + } + }, + { + "project": "firefox", + "title": "docs Monaco mode registrations update editor diagnostics and formatting across languages", + "status": "passed", + "retry": 0, + "browser": "155.0", + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "results": { + "evidence": [ + { + "language": "css", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-css", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-css", + "_fsPath": null + }, + "owner": "css", + "code": "css-propertyvalueexpected", + "severity": 8, + "message": "property value expected", + "source": "css", + "startLineNumber": 1, + "startColumn": 12, + "endLineNumber": 1, + "endColumn": 13 + } + ] + }, + { + "language": "json", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-json", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-json", + "_fsPath": null + }, + "owner": "json", + "code": "516", + "severity": 8, + "message": "Value expected", + "source": "json", + "startLineNumber": 1, + "startColumn": 10, + "endLineNumber": 1, + "endColumn": 11 + } + ] + }, + { + "language": "json", + "formatted": "{\r\n \"value\": 1\r\n}" + }, + { + "language": "typescript", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-typescript", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-typescript", + "_fsPath": null + }, + "owner": "typescript", + "code": "2322", + "severity": 8, + "message": "Type 'string' is not assignable to type 'number'.", + "startLineNumber": 1, + "startColumn": 7, + "endLineNumber": 1, + "endColumn": 12, + "relatedInformation": [], + "tags": [] + } + ] + }, + { + "language": "html", + "formatted": "
\r\n

hello

\r\n

world

\r\n
" + } + ], + "loadedModes": [ + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/css/cssMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/json/jsonMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/typescript/tsMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/html/htmlMode.js", + "status": 200 + } + ] + } + }, + { + "project": "webkit", + "title": "docs Monaco mode registrations update editor diagnostics and formatting across languages", + "status": "passed", + "retry": 0, + "browser": "26.6", + "errors": [], + "consoleErrors": [], + "failedRequests": [], + "results": { + "evidence": [ + { + "language": "css", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-css", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-css", + "_fsPath": null + }, + "owner": "css", + "code": "css-propertyvalueexpected", + "severity": 8, + "message": "property value expected", + "source": "css", + "startLineNumber": 1, + "startColumn": 12, + "endLineNumber": 1, + "endColumn": 13 + } + ] + }, + { + "language": "json", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-json", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-json", + "_fsPath": null + }, + "owner": "json", + "code": "516", + "severity": 8, + "message": "Value expected", + "source": "json", + "startLineNumber": 1, + "startColumn": 10, + "endLineNumber": 1, + "endColumn": 11 + } + ] + }, + { + "language": "json", + "formatted": "{\n \"value\": 1\n}" + }, + { + "language": "typescript", + "markers": [ + { + "resource": { + "scheme": "file", + "authority": "", + "path": "/mode-probe-typescript", + "query": "", + "fragment": "", + "_formatted": "file:///mode-probe-typescript", + "_fsPath": null + }, + "owner": "typescript", + "code": "2322", + "severity": 8, + "message": "Type 'string' is not assignable to type 'number'.", + "startLineNumber": 1, + "startColumn": 7, + "endLineNumber": 1, + "endColumn": 12, + "relatedInformation": [], + "tags": [] + } + ] + }, + { + "language": "html", + "formatted": "
\n

hello

\n

world

\n
" + } + ], + "loadedModes": [ + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/css/cssMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/json/jsonMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/typescript/tsMode.js", + "status": 200 + }, + { + "url": "http://127.0.0.1:8084/assets/js/vs/language/html/htmlMode.js", + "status": 200 + } + ] + } + } + ] + }, + "limitations": [ + "Exact source emission is not a complete upstream semantic typecheck.", + "Editor core/basic-language and remaining embedded origin review remain open.", + "No playback, device, external SDK, remote CI or publication verification in this checkpoint.", + "Thumbnail compatibility choice remains pending and its defaults unchanged." + ] +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-cssMode.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-cssMode.ts.txt new file mode 100644 index 000000000..ec3ea2603 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-cssMode.ts.txt @@ -0,0 +1,122 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { WorkerManager } from './workerManager'; +import type { CSSWorker } from './cssWorker'; +import { LanguageServiceDefaults } from './monaco.contribution'; +import * as languageFeatures from './languageFeatures'; +import { Uri, IDisposable, languages } from './fillers/monaco-editor-core'; + +export function setupMode(defaults: LanguageServiceDefaults): IDisposable { + const disposables: IDisposable[] = []; + const providers: IDisposable[] = []; + + const client = new WorkerManager(defaults); + disposables.push(client); + + const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise => { + return client.getLanguageServiceWorker(...uris); + }; + + function registerProviders(): void { + const { languageId, modeConfiguration } = defaults; + + disposeAll(providers); + + if (modeConfiguration.completionItems) { + providers.push( + languages.registerCompletionItemProvider( + languageId, + new languageFeatures.CompletionAdapter(worker) + ) + ); + } + if (modeConfiguration.hovers) { + providers.push( + languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)) + ); + } + if (modeConfiguration.documentHighlights) { + providers.push( + languages.registerDocumentHighlightProvider( + languageId, + new languageFeatures.DocumentHighlightAdapter(worker) + ) + ); + } + if (modeConfiguration.definitions) { + providers.push( + languages.registerDefinitionProvider( + languageId, + new languageFeatures.DefinitionAdapter(worker) + ) + ); + } + if (modeConfiguration.references) { + providers.push( + languages.registerReferenceProvider( + languageId, + new languageFeatures.ReferenceAdapter(worker) + ) + ); + } + if (modeConfiguration.documentSymbols) { + providers.push( + languages.registerDocumentSymbolProvider( + languageId, + new languageFeatures.DocumentSymbolAdapter(worker) + ) + ); + } + if (modeConfiguration.rename) { + providers.push( + languages.registerRenameProvider(languageId, new languageFeatures.RenameAdapter(worker)) + ); + } + if (modeConfiguration.colors) { + providers.push( + languages.registerColorProvider( + languageId, + new languageFeatures.DocumentColorAdapter(worker) + ) + ); + } + if (modeConfiguration.foldingRanges) { + providers.push( + languages.registerFoldingRangeProvider( + languageId, + new languageFeatures.FoldingRangeAdapter(worker) + ) + ); + } + if (modeConfiguration.diagnostics) { + providers.push(new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults)); + } + if (modeConfiguration.selectionRanges) { + providers.push( + languages.registerSelectionRangeProvider( + languageId, + new languageFeatures.SelectionRangeAdapter(worker) + ) + ); + } + } + + registerProviders(); + + disposables.push(asDisposable(providers)); + + return asDisposable(disposables); +} + +function asDisposable(disposables: IDisposable[]): IDisposable { + return { dispose: () => disposeAll(disposables) }; +} + +function disposeAll(disposables: IDisposable[]) { + while (disposables.length) { + disposables.pop().dispose(); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-languageFeatures.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-languageFeatures.ts.txt new file mode 100644 index 000000000..462521c8a --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-languageFeatures.ts.txt @@ -0,0 +1,725 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LanguageServiceDefaults } from './monaco.contribution'; +import type { CSSWorker } from './cssWorker'; +import * as lsTypes from 'vscode-languageserver-types'; +import { + languages, + editor, + IMarkdownString, + Uri, + Position, + IRange, + Range, + CancellationToken, + IDisposable, + MarkerSeverity +} from './fillers/monaco-editor-core'; +import { TextEdit } from 'vscode-css-languageservice'; +import { InsertReplaceEdit } from 'vscode-languageserver-types'; + +export interface WorkerAccessor { + (first: Uri, ...more: Uri[]): Promise; +} + +// --- diagnostics --- --- + +export class DiagnosticsAdapter { + private _disposables: IDisposable[] = []; + private _listener: { [uri: string]: IDisposable } = Object.create(null); + + constructor( + private _languageId: string, + private _worker: WorkerAccessor, + defaults: LanguageServiceDefaults + ) { + const onModelAdd = (model: editor.IModel): void => { + let modeId = model.getLanguageId(); + if (modeId !== this._languageId) { + return; + } + + let handle: number; + this._listener[model.uri.toString()] = model.onDidChangeContent(() => { + window.clearTimeout(handle); + handle = window.setTimeout(() => this._doValidate(model.uri, modeId), 500); + }); + + this._doValidate(model.uri, modeId); + }; + + const onModelRemoved = (model: editor.IModel): void => { + editor.setModelMarkers(model, this._languageId, []); + + let uriStr = model.uri.toString(); + let listener = this._listener[uriStr]; + if (listener) { + listener.dispose(); + delete this._listener[uriStr]; + } + }; + + this._disposables.push(editor.onDidCreateModel(onModelAdd)); + this._disposables.push(editor.onWillDisposeModel(onModelRemoved)); + this._disposables.push( + editor.onDidChangeModelLanguage((event) => { + onModelRemoved(event.model); + onModelAdd(event.model); + }) + ); + + defaults.onDidChange((_) => { + editor.getModels().forEach((model) => { + if (model.getLanguageId() === this._languageId) { + onModelRemoved(model); + onModelAdd(model); + } + }); + }); + + this._disposables.push({ + dispose: () => { + for (let key in this._listener) { + this._listener[key].dispose(); + } + } + }); + + editor.getModels().forEach(onModelAdd); + } + + public dispose(): void { + this._disposables.forEach((d) => d && d.dispose()); + this._disposables = []; + } + + private _doValidate(resource: Uri, languageId: string): void { + this._worker(resource) + .then((worker) => { + return worker.doValidation(resource.toString()); + }) + .then((diagnostics) => { + const markers = diagnostics.map((d) => toDiagnostics(resource, d)); + let model = editor.getModel(resource); + if (model && model.getLanguageId() === languageId) { + editor.setModelMarkers(model, languageId, markers); + } + }) + .then(undefined, (err) => { + console.error(err); + }); + } +} + +function toSeverity(lsSeverity: number): MarkerSeverity { + switch (lsSeverity) { + case lsTypes.DiagnosticSeverity.Error: + return MarkerSeverity.Error; + case lsTypes.DiagnosticSeverity.Warning: + return MarkerSeverity.Warning; + case lsTypes.DiagnosticSeverity.Information: + return MarkerSeverity.Info; + case lsTypes.DiagnosticSeverity.Hint: + return MarkerSeverity.Hint; + default: + return MarkerSeverity.Info; + } +} + +function toDiagnostics(resource: Uri, diag: lsTypes.Diagnostic): editor.IMarkerData { + let code = typeof diag.code === 'number' ? String(diag.code) : diag.code; + + return { + severity: toSeverity(diag.severity), + startLineNumber: diag.range.start.line + 1, + startColumn: diag.range.start.character + 1, + endLineNumber: diag.range.end.line + 1, + endColumn: diag.range.end.character + 1, + message: diag.message, + code: code, + source: diag.source + }; +} + +// --- completion ------ + +function fromPosition(position: Position): lsTypes.Position { + if (!position) { + return void 0; + } + return { character: position.column - 1, line: position.lineNumber - 1 }; +} + +function fromRange(range: IRange): lsTypes.Range { + if (!range) { + return void 0; + } + return { + start: { + line: range.startLineNumber - 1, + character: range.startColumn - 1 + }, + end: { line: range.endLineNumber - 1, character: range.endColumn - 1 } + }; +} + +function toRange(range: lsTypes.Range): Range { + if (!range) { + return void 0; + } + return new Range( + range.start.line + 1, + range.start.character + 1, + range.end.line + 1, + range.end.character + 1 + ); +} + +function isInsertReplaceEdit(edit: TextEdit | InsertReplaceEdit): edit is InsertReplaceEdit { + return ( + typeof (edit).insert !== 'undefined' && + typeof (edit).replace !== 'undefined' + ); +} + +function toCompletionItemKind(kind: number): languages.CompletionItemKind { + let mItemKind = languages.CompletionItemKind; + + switch (kind) { + case lsTypes.CompletionItemKind.Text: + return mItemKind.Text; + case lsTypes.CompletionItemKind.Method: + return mItemKind.Method; + case lsTypes.CompletionItemKind.Function: + return mItemKind.Function; + case lsTypes.CompletionItemKind.Constructor: + return mItemKind.Constructor; + case lsTypes.CompletionItemKind.Field: + return mItemKind.Field; + case lsTypes.CompletionItemKind.Variable: + return mItemKind.Variable; + case lsTypes.CompletionItemKind.Class: + return mItemKind.Class; + case lsTypes.CompletionItemKind.Interface: + return mItemKind.Interface; + case lsTypes.CompletionItemKind.Module: + return mItemKind.Module; + case lsTypes.CompletionItemKind.Property: + return mItemKind.Property; + case lsTypes.CompletionItemKind.Unit: + return mItemKind.Unit; + case lsTypes.CompletionItemKind.Value: + return mItemKind.Value; + case lsTypes.CompletionItemKind.Enum: + return mItemKind.Enum; + case lsTypes.CompletionItemKind.Keyword: + return mItemKind.Keyword; + case lsTypes.CompletionItemKind.Snippet: + return mItemKind.Snippet; + case lsTypes.CompletionItemKind.Color: + return mItemKind.Color; + case lsTypes.CompletionItemKind.File: + return mItemKind.File; + case lsTypes.CompletionItemKind.Reference: + return mItemKind.Reference; + } + return mItemKind.Property; +} + +function toTextEdit(textEdit: lsTypes.TextEdit): editor.ISingleEditOperation { + if (!textEdit) { + return void 0; + } + return { + range: toRange(textEdit.range), + text: textEdit.newText + }; +} + +function toCommand(c: lsTypes.Command | undefined): languages.Command { + return c && c.command === 'editor.action.triggerSuggest' + ? { id: c.command, title: c.title, arguments: c.arguments } + : undefined; +} + +export class CompletionAdapter implements languages.CompletionItemProvider { + constructor(private _worker: WorkerAccessor) {} + + public get triggerCharacters(): string[] { + return ['/', '-', ':']; + } + + provideCompletionItems( + model: editor.IReadOnlyModel, + position: Position, + context: languages.CompletionContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doComplete(resource.toString(), fromPosition(position)); + }) + .then((info) => { + if (!info) { + return; + } + const wordInfo = model.getWordUntilPosition(position); + const wordRange = new Range( + position.lineNumber, + wordInfo.startColumn, + position.lineNumber, + wordInfo.endColumn + ); + + let items: languages.CompletionItem[] = info.items.map((entry) => { + let item: languages.CompletionItem = { + label: entry.label, + insertText: entry.insertText || entry.label, + sortText: entry.sortText, + filterText: entry.filterText, + documentation: entry.documentation, + detail: entry.detail, + command: toCommand(entry.command), + range: wordRange, + kind: toCompletionItemKind(entry.kind) + }; + if (entry.textEdit) { + if (isInsertReplaceEdit(entry.textEdit)) { + item.range = { + insert: toRange(entry.textEdit.insert), + replace: toRange(entry.textEdit.replace) + }; + } else { + item.range = toRange(entry.textEdit.range); + } + item.insertText = entry.textEdit.newText; + } + if (entry.additionalTextEdits) { + item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit); + } + if (entry.insertTextFormat === lsTypes.InsertTextFormat.Snippet) { + item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet; + } + return item; + }); + + return { + isIncomplete: info.isIncomplete, + suggestions: items + }; + }); + } +} + +function isMarkupContent(thing: any): thing is lsTypes.MarkupContent { + return ( + thing && typeof thing === 'object' && typeof (thing).kind === 'string' + ); +} + +function toMarkdownString(entry: lsTypes.MarkupContent | lsTypes.MarkedString): IMarkdownString { + if (typeof entry === 'string') { + return { + value: entry + }; + } + if (isMarkupContent(entry)) { + if (entry.kind === 'plaintext') { + return { + value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&') + }; + } + return { + value: entry.value + }; + } + + return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' }; +} + +function toMarkedStringArray( + contents: lsTypes.MarkupContent | lsTypes.MarkedString | lsTypes.MarkedString[] +): IMarkdownString[] { + if (!contents) { + return void 0; + } + if (Array.isArray(contents)) { + return contents.map(toMarkdownString); + } + return [toMarkdownString(contents)]; +} + +// --- hover ------ + +export class HoverAdapter implements languages.HoverProvider { + constructor(private _worker: WorkerAccessor) {} + + provideHover( + model: editor.IReadOnlyModel, + position: Position, + token: CancellationToken + ): Promise { + let resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doHover(resource.toString(), fromPosition(position)); + }) + .then((info) => { + if (!info) { + return; + } + return { + range: toRange(info.range), + contents: toMarkedStringArray(info.contents) + }; + }); + } +} + +// --- document highlights ------ + +function toDocumentHighlightKind(kind: number): languages.DocumentHighlightKind { + switch (kind) { + case lsTypes.DocumentHighlightKind.Read: + return languages.DocumentHighlightKind.Read; + case lsTypes.DocumentHighlightKind.Write: + return languages.DocumentHighlightKind.Write; + case lsTypes.DocumentHighlightKind.Text: + return languages.DocumentHighlightKind.Text; + } + return languages.DocumentHighlightKind.Text; +} + +export class DocumentHighlightAdapter implements languages.DocumentHighlightProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentHighlights( + model: editor.IReadOnlyModel, + position: Position, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.findDocumentHighlights(resource.toString(), fromPosition(position)); + }) + .then((entries) => { + if (!entries) { + return; + } + return entries.map((entry) => { + return { + range: toRange(entry.range), + kind: toDocumentHighlightKind(entry.kind) + }; + }); + }); + } +} + +// --- definition ------ + +function toLocation(location: lsTypes.Location): languages.Location { + return { + uri: Uri.parse(location.uri), + range: toRange(location.range) + }; +} + +export class DefinitionAdapter { + constructor(private _worker: WorkerAccessor) {} + + public provideDefinition( + model: editor.IReadOnlyModel, + position: Position, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.findDefinition(resource.toString(), fromPosition(position)); + }) + .then((definition) => { + if (!definition) { + return; + } + return [toLocation(definition)]; + }); + } +} + +// --- references ------ + +export class ReferenceAdapter implements languages.ReferenceProvider { + constructor(private _worker: WorkerAccessor) {} + + provideReferences( + model: editor.IReadOnlyModel, + position: Position, + context: languages.ReferenceContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.findReferences(resource.toString(), fromPosition(position)); + }) + .then((entries) => { + if (!entries) { + return; + } + return entries.map(toLocation); + }); + } +} + +// --- rename ------ + +function toWorkspaceEdit(edit: lsTypes.WorkspaceEdit): languages.WorkspaceEdit { + if (!edit || !edit.changes) { + return void 0; + } + let resourceEdits: languages.WorkspaceTextEdit[] = []; + for (let uri in edit.changes) { + const _uri = Uri.parse(uri); + // let edits: languages.TextEdit[] = []; + for (let e of edit.changes[uri]) { + resourceEdits.push({ + resource: _uri, + edit: { + range: toRange(e.range), + text: e.newText + } + }); + } + } + return { + edits: resourceEdits + }; +} + +export class RenameAdapter implements languages.RenameProvider { + constructor(private _worker: WorkerAccessor) {} + + provideRenameEdits( + model: editor.IReadOnlyModel, + position: Position, + newName: string, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doRename(resource.toString(), fromPosition(position), newName); + }) + .then((edit) => { + return toWorkspaceEdit(edit); + }); + } +} + +// --- document symbols ------ + +function toSymbolKind(kind: lsTypes.SymbolKind): languages.SymbolKind { + let mKind = languages.SymbolKind; + + switch (kind) { + case lsTypes.SymbolKind.File: + return mKind.Array; + case lsTypes.SymbolKind.Module: + return mKind.Module; + case lsTypes.SymbolKind.Namespace: + return mKind.Namespace; + case lsTypes.SymbolKind.Package: + return mKind.Package; + case lsTypes.SymbolKind.Class: + return mKind.Class; + case lsTypes.SymbolKind.Method: + return mKind.Method; + case lsTypes.SymbolKind.Property: + return mKind.Property; + case lsTypes.SymbolKind.Field: + return mKind.Field; + case lsTypes.SymbolKind.Constructor: + return mKind.Constructor; + case lsTypes.SymbolKind.Enum: + return mKind.Enum; + case lsTypes.SymbolKind.Interface: + return mKind.Interface; + case lsTypes.SymbolKind.Function: + return mKind.Function; + case lsTypes.SymbolKind.Variable: + return mKind.Variable; + case lsTypes.SymbolKind.Constant: + return mKind.Constant; + case lsTypes.SymbolKind.String: + return mKind.String; + case lsTypes.SymbolKind.Number: + return mKind.Number; + case lsTypes.SymbolKind.Boolean: + return mKind.Boolean; + case lsTypes.SymbolKind.Array: + return mKind.Array; + } + return mKind.Function; +} + +export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentSymbols( + model: editor.IReadOnlyModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentSymbols(resource.toString())) + .then((items) => { + if (!items) { + return; + } + return items.map((item) => ({ + name: item.name, + detail: '', + containerName: item.containerName, + kind: toSymbolKind(item.kind), + tags: [], + range: toRange(item.location.range), + selectionRange: toRange(item.location.range) + })); + }); + } +} + +export class DocumentColorAdapter implements languages.DocumentColorProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentColors( + model: editor.IReadOnlyModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentColors(resource.toString())) + .then((infos) => { + if (!infos) { + return; + } + return infos.map((item) => ({ + color: item.color, + range: toRange(item.range) + })); + }); + } + + public provideColorPresentations( + model: editor.IReadOnlyModel, + info: languages.IColorInformation, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => + worker.getColorPresentations(resource.toString(), info.color, fromRange(info.range)) + ) + .then((presentations) => { + if (!presentations) { + return; + } + return presentations.map((presentation) => { + let item: languages.IColorPresentation = { + label: presentation.label + }; + if (presentation.textEdit) { + item.textEdit = toTextEdit(presentation.textEdit); + } + if (presentation.additionalTextEdits) { + item.additionalTextEdits = presentation.additionalTextEdits.map(toTextEdit); + } + return item; + }); + }); + } +} + +export class FoldingRangeAdapter implements languages.FoldingRangeProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideFoldingRanges( + model: editor.IReadOnlyModel, + context: languages.FoldingContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.getFoldingRanges(resource.toString(), context)) + .then((ranges) => { + if (!ranges) { + return; + } + return ranges.map((range) => { + let result: languages.FoldingRange = { + start: range.startLine + 1, + end: range.endLine + 1 + }; + if (typeof range.kind !== 'undefined') { + result.kind = toFoldingRangeKind(range.kind); + } + return result; + }); + }); + } +} + +function toFoldingRangeKind(kind: lsTypes.FoldingRangeKind): languages.FoldingRangeKind { + switch (kind) { + case lsTypes.FoldingRangeKind.Comment: + return languages.FoldingRangeKind.Comment; + case lsTypes.FoldingRangeKind.Imports: + return languages.FoldingRangeKind.Imports; + case lsTypes.FoldingRangeKind.Region: + return languages.FoldingRangeKind.Region; + } +} + +export class SelectionRangeAdapter implements languages.SelectionRangeProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideSelectionRanges( + model: editor.IReadOnlyModel, + positions: Position[], + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.getSelectionRanges(resource.toString(), positions.map(fromPosition))) + .then((selectionRanges) => { + if (!selectionRanges) { + return; + } + return selectionRanges.map((selectionRange) => { + const result: languages.SelectionRange[] = []; + while (selectionRange) { + result.push({ range: toRange(selectionRange.range) }); + selectionRange = selectionRange.parent; + } + return result; + }); + }); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-workerManager.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-workerManager.ts.txt new file mode 100644 index 000000000..335396d5d --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-css-src-workerManager.ts.txt @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LanguageServiceDefaults } from './monaco.contribution'; +import type { CSSWorker } from './cssWorker'; +import { editor, IDisposable, Uri } from './fillers/monaco-editor-core'; + +const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min + +export class WorkerManager { + private _defaults: LanguageServiceDefaults; + private _idleCheckInterval: number; + private _lastUsedTime: number; + private _configChangeListener: IDisposable; + + private _worker: editor.MonacoWebWorker; + private _client: Promise; + + constructor(defaults: LanguageServiceDefaults) { + this._defaults = defaults; + this._worker = null; + this._idleCheckInterval = window.setInterval(() => this._checkIfIdle(), 30 * 1000); + this._lastUsedTime = 0; + this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker()); + } + + private _stopWorker(): void { + if (this._worker) { + this._worker.dispose(); + this._worker = null; + } + this._client = null; + } + + dispose(): void { + clearInterval(this._idleCheckInterval); + this._configChangeListener.dispose(); + this._stopWorker(); + } + + private _checkIfIdle(): void { + if (!this._worker) { + return; + } + let timePassedSinceLastUsed = Date.now() - this._lastUsedTime; + if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) { + this._stopWorker(); + } + } + + private _getClient(): Promise { + this._lastUsedTime = Date.now(); + + if (!this._client) { + this._worker = editor.createWebWorker({ + // module that exports the create() method and returns a `CSSWorker` instance + moduleId: 'vs/language/css/cssWorker', + + label: this._defaults.languageId, + + // passed in to the create() method + createData: { + options: this._defaults.options, + languageId: this._defaults.languageId + } + }); + + this._client = >(this._worker.getProxy()); + } + + return this._client; + } + + getLanguageServiceWorker(...resources: Uri[]): Promise { + let _client: CSSWorker; + return this._getClient() + .then((client) => { + _client = client; + }) + .then((_) => { + return this._worker.withSyncedResources(resources); + }) + .then((_) => _client); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-htmlMode.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-htmlMode.ts.txt new file mode 100644 index 000000000..95b560cb3 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-htmlMode.ts.txt @@ -0,0 +1,164 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { WorkerManager } from './workerManager'; +import type { HTMLWorker } from './htmlWorker'; +import { LanguageServiceDefaults } from './monaco.contribution'; +import * as languageFeatures from './languageFeatures'; +import { Uri, IDisposable, languages } from './fillers/monaco-editor-core'; + +export function setupMode1(defaults: LanguageServiceDefaults): void { + const client = new WorkerManager(defaults); + + const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise => { + return client.getLanguageServiceWorker(...uris); + }; + + let languageId = defaults.languageId; + + // all modes + languages.registerCompletionItemProvider( + languageId, + new languageFeatures.CompletionAdapter(worker) + ); + languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)); + + languages.registerDocumentHighlightProvider( + languageId, + new languageFeatures.DocumentHighlightAdapter(worker) + ); + languages.registerLinkProvider(languageId, new languageFeatures.DocumentLinkAdapter(worker)); + languages.registerFoldingRangeProvider( + languageId, + new languageFeatures.FoldingRangeAdapter(worker) + ); + languages.registerDocumentSymbolProvider( + languageId, + new languageFeatures.DocumentSymbolAdapter(worker) + ); + languages.registerSelectionRangeProvider( + languageId, + new languageFeatures.SelectionRangeAdapter(worker) + ); + languages.registerRenameProvider(languageId, new languageFeatures.RenameAdapter(worker)); + + // only html + if (languageId === 'html') { + languages.registerDocumentFormattingEditProvider( + languageId, + new languageFeatures.DocumentFormattingEditProvider(worker) + ); + languages.registerDocumentRangeFormattingEditProvider( + languageId, + new languageFeatures.DocumentRangeFormattingEditProvider(worker) + ); + } +} + +export function setupMode(defaults: LanguageServiceDefaults): IDisposable { + const disposables: IDisposable[] = []; + const providers: IDisposable[] = []; + + const client = new WorkerManager(defaults); + disposables.push(client); + + const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise => { + return client.getLanguageServiceWorker(...uris); + }; + + function registerProviders(): void { + const { languageId, modeConfiguration } = defaults; + + disposeAll(providers); + + if (modeConfiguration.completionItems) { + providers.push( + languages.registerCompletionItemProvider( + languageId, + new languageFeatures.CompletionAdapter(worker) + ) + ); + } + if (modeConfiguration.hovers) { + providers.push( + languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)) + ); + } + if (modeConfiguration.documentHighlights) { + providers.push( + languages.registerDocumentHighlightProvider( + languageId, + new languageFeatures.DocumentHighlightAdapter(worker) + ) + ); + } + if (modeConfiguration.links) { + providers.push( + languages.registerLinkProvider(languageId, new languageFeatures.DocumentLinkAdapter(worker)) + ); + } + if (modeConfiguration.documentSymbols) { + providers.push( + languages.registerDocumentSymbolProvider( + languageId, + new languageFeatures.DocumentSymbolAdapter(worker) + ) + ); + } + if (modeConfiguration.rename) { + providers.push( + languages.registerRenameProvider(languageId, new languageFeatures.RenameAdapter(worker)) + ); + } + if (modeConfiguration.foldingRanges) { + providers.push( + languages.registerFoldingRangeProvider( + languageId, + new languageFeatures.FoldingRangeAdapter(worker) + ) + ); + } + if (modeConfiguration.selectionRanges) { + providers.push( + languages.registerSelectionRangeProvider( + languageId, + new languageFeatures.SelectionRangeAdapter(worker) + ) + ); + } + if (modeConfiguration.documentFormattingEdits) { + providers.push( + languages.registerDocumentFormattingEditProvider( + languageId, + new languageFeatures.DocumentFormattingEditProvider(worker) + ) + ); + } + if (modeConfiguration.documentRangeFormattingEdits) { + providers.push( + languages.registerDocumentRangeFormattingEditProvider( + languageId, + new languageFeatures.DocumentRangeFormattingEditProvider(worker) + ) + ); + } + } + + registerProviders(); + + disposables.push(asDisposable(providers)); + + return asDisposable(disposables); +} + +function asDisposable(disposables: IDisposable[]): IDisposable { + return { dispose: () => disposeAll(disposables) }; +} + +function disposeAll(disposables: IDisposable[]) { + while (disposables.length) { + disposables.pop().dispose(); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-languageFeatures.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-languageFeatures.ts.txt new file mode 100644 index 000000000..2d6ec0340 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-languageFeatures.ts.txt @@ -0,0 +1,608 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { HTMLWorker } from './htmlWorker'; +import * as lsTypes from 'vscode-languageserver-types'; +import { + languages, + editor, + Uri, + Position, + Range, + CancellationToken, + IMarkdownString +} from './fillers/monaco-editor-core'; + +export interface WorkerAccessor { + (...more: Uri[]): Promise; +} + +// --- completion ------ + +function fromPosition(position: Position): lsTypes.Position { + if (!position) { + return void 0; + } + return { character: position.column - 1, line: position.lineNumber - 1 }; +} + +function fromRange(range: Range): lsTypes.Range { + if (!range) { + return void 0; + } + return { + start: fromPosition(range.getStartPosition()), + end: fromPosition(range.getEndPosition()) + }; +} + +function toRange(range: lsTypes.Range): Range { + if (!range) { + return void 0; + } + return new Range( + range.start.line + 1, + range.start.character + 1, + range.end.line + 1, + range.end.character + 1 + ); +} + +function isInsertReplaceEdit( + edit: lsTypes.TextEdit | lsTypes.InsertReplaceEdit +): edit is lsTypes.InsertReplaceEdit { + return ( + typeof (edit).insert !== 'undefined' && + typeof (edit).replace !== 'undefined' + ); +} + +function toCompletionItemKind(kind: number): languages.CompletionItemKind { + const mItemKind = languages.CompletionItemKind; + + switch (kind) { + case lsTypes.CompletionItemKind.Text: + return mItemKind.Text; + case lsTypes.CompletionItemKind.Method: + return mItemKind.Method; + case lsTypes.CompletionItemKind.Function: + return mItemKind.Function; + case lsTypes.CompletionItemKind.Constructor: + return mItemKind.Constructor; + case lsTypes.CompletionItemKind.Field: + return mItemKind.Field; + case lsTypes.CompletionItemKind.Variable: + return mItemKind.Variable; + case lsTypes.CompletionItemKind.Class: + return mItemKind.Class; + case lsTypes.CompletionItemKind.Interface: + return mItemKind.Interface; + case lsTypes.CompletionItemKind.Module: + return mItemKind.Module; + case lsTypes.CompletionItemKind.Property: + return mItemKind.Property; + case lsTypes.CompletionItemKind.Unit: + return mItemKind.Unit; + case lsTypes.CompletionItemKind.Value: + return mItemKind.Value; + case lsTypes.CompletionItemKind.Enum: + return mItemKind.Enum; + case lsTypes.CompletionItemKind.Keyword: + return mItemKind.Keyword; + case lsTypes.CompletionItemKind.Snippet: + return mItemKind.Snippet; + case lsTypes.CompletionItemKind.Color: + return mItemKind.Color; + case lsTypes.CompletionItemKind.File: + return mItemKind.File; + case lsTypes.CompletionItemKind.Reference: + return mItemKind.Reference; + } + return mItemKind.Property; +} + +function fromCompletionItemKind(kind: languages.CompletionItemKind): lsTypes.CompletionItemKind { + const mItemKind = languages.CompletionItemKind; + + switch (kind) { + case mItemKind.Text: + return lsTypes.CompletionItemKind.Text; + case mItemKind.Method: + return lsTypes.CompletionItemKind.Method; + case mItemKind.Function: + return lsTypes.CompletionItemKind.Function; + case mItemKind.Constructor: + return lsTypes.CompletionItemKind.Constructor; + case mItemKind.Field: + return lsTypes.CompletionItemKind.Field; + case mItemKind.Variable: + return lsTypes.CompletionItemKind.Variable; + case mItemKind.Class: + return lsTypes.CompletionItemKind.Class; + case mItemKind.Interface: + return lsTypes.CompletionItemKind.Interface; + case mItemKind.Module: + return lsTypes.CompletionItemKind.Module; + case mItemKind.Property: + return lsTypes.CompletionItemKind.Property; + case mItemKind.Unit: + return lsTypes.CompletionItemKind.Unit; + case mItemKind.Value: + return lsTypes.CompletionItemKind.Value; + case mItemKind.Enum: + return lsTypes.CompletionItemKind.Enum; + case mItemKind.Keyword: + return lsTypes.CompletionItemKind.Keyword; + case mItemKind.Snippet: + return lsTypes.CompletionItemKind.Snippet; + case mItemKind.Color: + return lsTypes.CompletionItemKind.Color; + case mItemKind.File: + return lsTypes.CompletionItemKind.File; + case mItemKind.Reference: + return lsTypes.CompletionItemKind.Reference; + } + return lsTypes.CompletionItemKind.Property; +} + +function toTextEdit(textEdit: lsTypes.TextEdit): editor.ISingleEditOperation { + if (!textEdit) { + return void 0; + } + return { + range: toRange(textEdit.range), + text: textEdit.newText + }; +} + +function toCommand(c: lsTypes.Command | undefined): languages.Command { + return c && c.command === 'editor.action.triggerSuggest' + ? { id: c.command, title: c.title, arguments: c.arguments } + : undefined; +} + +export class CompletionAdapter implements languages.CompletionItemProvider { + constructor(private _worker: WorkerAccessor) {} + + public get triggerCharacters(): string[] { + return ['.', ':', '<', '"', '=', '/']; + } + + provideCompletionItems( + model: editor.IReadOnlyModel, + position: Position, + context: languages.CompletionContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doComplete(resource.toString(), fromPosition(position)); + }) + .then((info) => { + if (!info) { + return; + } + const wordInfo = model.getWordUntilPosition(position); + const wordRange = new Range( + position.lineNumber, + wordInfo.startColumn, + position.lineNumber, + wordInfo.endColumn + ); + + const items: languages.CompletionItem[] = info.items.map((entry) => { + const item: languages.CompletionItem = { + label: entry.label, + insertText: entry.insertText || entry.label, + sortText: entry.sortText, + filterText: entry.filterText, + documentation: entry.documentation, + command: toCommand(entry.command), + detail: entry.detail, + range: wordRange, + kind: toCompletionItemKind(entry.kind) + }; + if (entry.textEdit) { + if (isInsertReplaceEdit(entry.textEdit)) { + item.range = { + insert: toRange(entry.textEdit.insert), + replace: toRange(entry.textEdit.replace) + }; + } else { + item.range = toRange(entry.textEdit.range); + } + item.insertText = entry.textEdit.newText; + } + if (entry.additionalTextEdits) { + item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit); + } + if (entry.insertTextFormat === lsTypes.InsertTextFormat.Snippet) { + item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet; + } + return item; + }); + + return { + isIncomplete: info.isIncomplete, + suggestions: items + }; + }); + } +} + +// --- hover ------ + +function isMarkupContent(thing: any): thing is lsTypes.MarkupContent { + return ( + thing && typeof thing === 'object' && typeof (thing).kind === 'string' + ); +} + +function toMarkdownString(entry: lsTypes.MarkupContent | lsTypes.MarkedString): IMarkdownString { + if (typeof entry === 'string') { + return { + value: entry + }; + } + if (isMarkupContent(entry)) { + if (entry.kind === 'plaintext') { + return { + value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&') + }; + } + return { + value: entry.value + }; + } + + return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' }; +} + +function toMarkedStringArray( + contents: lsTypes.MarkupContent | lsTypes.MarkedString | lsTypes.MarkedString[] +): IMarkdownString[] { + if (!contents) { + return void 0; + } + if (Array.isArray(contents)) { + return contents.map(toMarkdownString); + } + return [toMarkdownString(contents)]; +} + +export class HoverAdapter implements languages.HoverProvider { + constructor(private _worker: WorkerAccessor) {} + + provideHover( + model: editor.IReadOnlyModel, + position: Position, + token: CancellationToken + ): Promise { + let resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doHover(resource.toString(), fromPosition(position)); + }) + .then((info) => { + if (!info) { + return; + } + return { + range: toRange(info.range), + contents: toMarkedStringArray(info.contents) + }; + }); + } +} + +// --- document highlights ------ + +function toHighlighKind(kind: lsTypes.DocumentHighlightKind): languages.DocumentHighlightKind { + const mKind = languages.DocumentHighlightKind; + + switch (kind) { + case lsTypes.DocumentHighlightKind.Read: + return mKind.Read; + case lsTypes.DocumentHighlightKind.Write: + return mKind.Write; + case lsTypes.DocumentHighlightKind.Text: + return mKind.Text; + } + return mKind.Text; +} + +export class DocumentHighlightAdapter implements languages.DocumentHighlightProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentHighlights( + model: editor.IReadOnlyModel, + position: Position, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentHighlights(resource.toString(), fromPosition(position))) + .then((items) => { + if (!items) { + return; + } + return items.map((item) => ({ + range: toRange(item.range), + kind: toHighlighKind(item.kind) + })); + }); + } +} + +// --- document symbols ------ + +function toSymbolKind(kind: lsTypes.SymbolKind): languages.SymbolKind { + let mKind = languages.SymbolKind; + + switch (kind) { + case lsTypes.SymbolKind.File: + return mKind.Array; + case lsTypes.SymbolKind.Module: + return mKind.Module; + case lsTypes.SymbolKind.Namespace: + return mKind.Namespace; + case lsTypes.SymbolKind.Package: + return mKind.Package; + case lsTypes.SymbolKind.Class: + return mKind.Class; + case lsTypes.SymbolKind.Method: + return mKind.Method; + case lsTypes.SymbolKind.Property: + return mKind.Property; + case lsTypes.SymbolKind.Field: + return mKind.Field; + case lsTypes.SymbolKind.Constructor: + return mKind.Constructor; + case lsTypes.SymbolKind.Enum: + return mKind.Enum; + case lsTypes.SymbolKind.Interface: + return mKind.Interface; + case lsTypes.SymbolKind.Function: + return mKind.Function; + case lsTypes.SymbolKind.Variable: + return mKind.Variable; + case lsTypes.SymbolKind.Constant: + return mKind.Constant; + case lsTypes.SymbolKind.String: + return mKind.String; + case lsTypes.SymbolKind.Number: + return mKind.Number; + case lsTypes.SymbolKind.Boolean: + return mKind.Boolean; + case lsTypes.SymbolKind.Array: + return mKind.Array; + } + return mKind.Function; +} + +export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentSymbols( + model: editor.IReadOnlyModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentSymbols(resource.toString())) + .then((items) => { + if (!items) { + return; + } + return items.map((item) => ({ + name: item.name, + detail: '', + containerName: item.containerName, + kind: toSymbolKind(item.kind), + tags: [], + range: toRange(item.location.range), + selectionRange: toRange(item.location.range) + })); + }); + } +} + +export class DocumentLinkAdapter implements languages.LinkProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideLinks( + model: editor.IReadOnlyModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentLinks(resource.toString())) + .then((items) => { + if (!items) { + return; + } + return { + links: items.map((item) => ({ + range: toRange(item.range), + url: item.target + })) + }; + }); + } +} + +function fromFormattingOptions(options: languages.FormattingOptions): lsTypes.FormattingOptions { + return { + tabSize: options.tabSize, + insertSpaces: options.insertSpaces + }; +} + +export class DocumentFormattingEditProvider implements languages.DocumentFormattingEditProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentFormattingEdits( + model: editor.IReadOnlyModel, + options: languages.FormattingOptions, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource).then((worker) => { + return worker + .format(resource.toString(), null, fromFormattingOptions(options)) + .then((edits) => { + if (!edits || edits.length === 0) { + return; + } + return edits.map(toTextEdit); + }); + }); + } +} + +export class DocumentRangeFormattingEditProvider + implements languages.DocumentRangeFormattingEditProvider +{ + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentRangeFormattingEdits( + model: editor.IReadOnlyModel, + range: Range, + options: languages.FormattingOptions, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource).then((worker) => { + return worker + .format(resource.toString(), fromRange(range), fromFormattingOptions(options)) + .then((edits) => { + if (!edits || edits.length === 0) { + return; + } + return edits.map(toTextEdit); + }); + }); + } +} + +export class RenameAdapter implements languages.RenameProvider { + constructor(private _worker: WorkerAccessor) {} + + provideRenameEdits( + model: editor.IReadOnlyModel, + position: Position, + newName: string, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doRename(resource.toString(), fromPosition(position), newName); + }) + .then((edit) => { + return toWorkspaceEdit(edit); + }); + } +} + +function toWorkspaceEdit(edit: lsTypes.WorkspaceEdit): languages.WorkspaceEdit { + if (!edit || !edit.changes) { + return void 0; + } + let resourceEdits: languages.WorkspaceTextEdit[] = []; + for (let uri in edit.changes) { + const _uri = Uri.parse(uri); + for (let e of edit.changes[uri]) { + resourceEdits.push({ + resource: _uri, + edit: { + range: toRange(e.range), + text: e.newText + } + }); + } + } + return { + edits: resourceEdits + }; +} + +export class FoldingRangeAdapter implements languages.FoldingRangeProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideFoldingRanges( + model: editor.IReadOnlyModel, + context: languages.FoldingContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.getFoldingRanges(resource.toString(), context)) + .then((ranges) => { + if (!ranges) { + return; + } + return ranges.map((range) => { + const result: languages.FoldingRange = { + start: range.startLine + 1, + end: range.endLine + 1 + }; + if (typeof range.kind !== 'undefined') { + result.kind = toFoldingRangeKind(range.kind); + } + return result; + }); + }); + } +} + +function toFoldingRangeKind(kind: lsTypes.FoldingRangeKind): languages.FoldingRangeKind { + switch (kind) { + case lsTypes.FoldingRangeKind.Comment: + return languages.FoldingRangeKind.Comment; + case lsTypes.FoldingRangeKind.Imports: + return languages.FoldingRangeKind.Imports; + case lsTypes.FoldingRangeKind.Region: + return languages.FoldingRangeKind.Region; + } +} + +export class SelectionRangeAdapter implements languages.SelectionRangeProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideSelectionRanges( + model: editor.IReadOnlyModel, + positions: Position[], + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.getSelectionRanges(resource.toString(), positions.map(fromPosition))) + .then((selectionRanges) => { + if (!selectionRanges) { + return; + } + return selectionRanges.map((selectionRange) => { + const result: languages.SelectionRange[] = []; + while (selectionRange) { + result.push({ range: toRange(selectionRange.range) }); + selectionRange = selectionRange.parent; + } + return result; + }); + }); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-workerManager.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-workerManager.ts.txt new file mode 100644 index 000000000..5122168b5 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-html-src-workerManager.ts.txt @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LanguageServiceDefaults } from './monaco.contribution'; +import type { HTMLWorker } from './htmlWorker'; +import { Uri, IDisposable, editor } from './fillers/monaco-editor-core'; + +const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min + +export class WorkerManager { + private _defaults: LanguageServiceDefaults; + private _idleCheckInterval: number; + private _lastUsedTime: number; + private _configChangeListener: IDisposable; + + private _worker: editor.MonacoWebWorker; + private _client: Promise; + + constructor(defaults: LanguageServiceDefaults) { + this._defaults = defaults; + this._worker = null; + this._idleCheckInterval = window.setInterval(() => this._checkIfIdle(), 30 * 1000); + this._lastUsedTime = 0; + this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker()); + } + + private _stopWorker(): void { + if (this._worker) { + this._worker.dispose(); + this._worker = null; + } + this._client = null; + } + + dispose(): void { + clearInterval(this._idleCheckInterval); + this._configChangeListener.dispose(); + this._stopWorker(); + } + + private _checkIfIdle(): void { + if (!this._worker) { + return; + } + let timePassedSinceLastUsed = Date.now() - this._lastUsedTime; + if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) { + this._stopWorker(); + } + } + + private _getClient(): Promise { + this._lastUsedTime = Date.now(); + + if (!this._client) { + this._worker = editor.createWebWorker({ + // module that exports the create() method and returns a `HTMLWorker` instance + moduleId: 'vs/language/html/htmlWorker', + + // passed in to the create() method + createData: { + languageSettings: this._defaults.options, + languageId: this._defaults.languageId + }, + + label: this._defaults.languageId + }); + + this._client = >this._worker.getProxy(); + } + + return this._client; + } + + getLanguageServiceWorker(...resources: Uri[]): Promise { + let _client: HTMLWorker; + return this._getClient() + .then((client) => { + _client = client; + }) + .then((_) => { + if (this._worker) { + return this._worker.withSyncedResources(resources); + } + }) + .then((_) => _client); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-jsonMode.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-jsonMode.ts.txt new file mode 100644 index 000000000..7d66f6a0e --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-jsonMode.ts.txt @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { WorkerManager } from './workerManager'; +import type { JSONWorker } from './jsonWorker'; +import { LanguageServiceDefaults } from './monaco.contribution'; +import * as languageFeatures from './languageFeatures'; +import { createTokenizationSupport } from './tokenization'; +import { Uri, IDisposable, languages } from './fillers/monaco-editor-core'; + +export function setupMode(defaults: LanguageServiceDefaults): IDisposable { + const disposables: IDisposable[] = []; + const providers: IDisposable[] = []; + + const client = new WorkerManager(defaults); + disposables.push(client); + + const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise => { + return client.getLanguageServiceWorker(...uris); + }; + + function registerProviders(): void { + const { languageId, modeConfiguration } = defaults; + + disposeAll(providers); + + if (modeConfiguration.documentFormattingEdits) { + providers.push( + languages.registerDocumentFormattingEditProvider( + languageId, + new languageFeatures.DocumentFormattingEditProvider(worker) + ) + ); + } + if (modeConfiguration.documentRangeFormattingEdits) { + providers.push( + languages.registerDocumentRangeFormattingEditProvider( + languageId, + new languageFeatures.DocumentRangeFormattingEditProvider(worker) + ) + ); + } + if (modeConfiguration.completionItems) { + providers.push( + languages.registerCompletionItemProvider( + languageId, + new languageFeatures.CompletionAdapter(worker) + ) + ); + } + if (modeConfiguration.hovers) { + providers.push( + languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)) + ); + } + if (modeConfiguration.documentSymbols) { + providers.push( + languages.registerDocumentSymbolProvider( + languageId, + new languageFeatures.DocumentSymbolAdapter(worker) + ) + ); + } + if (modeConfiguration.tokens) { + providers.push(languages.setTokensProvider(languageId, createTokenizationSupport(true))); + } + if (modeConfiguration.colors) { + providers.push( + languages.registerColorProvider( + languageId, + new languageFeatures.DocumentColorAdapter(worker) + ) + ); + } + if (modeConfiguration.foldingRanges) { + providers.push( + languages.registerFoldingRangeProvider( + languageId, + new languageFeatures.FoldingRangeAdapter(worker) + ) + ); + } + if (modeConfiguration.diagnostics) { + providers.push(new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults)); + } + if (modeConfiguration.selectionRanges) { + providers.push( + languages.registerSelectionRangeProvider( + languageId, + new languageFeatures.SelectionRangeAdapter(worker) + ) + ); + } + } + + registerProviders(); + + disposables.push(languages.setLanguageConfiguration(defaults.languageId, richEditConfiguration)); + + let modeConfiguration = defaults.modeConfiguration; + defaults.onDidChange((newDefaults) => { + if (newDefaults.modeConfiguration !== modeConfiguration) { + modeConfiguration = newDefaults.modeConfiguration; + registerProviders(); + } + }); + + disposables.push(asDisposable(providers)); + + return asDisposable(disposables); +} + +function asDisposable(disposables: IDisposable[]): IDisposable { + return { dispose: () => disposeAll(disposables) }; +} + +function disposeAll(disposables: IDisposable[]) { + while (disposables.length) { + disposables.pop().dispose(); + } +} + +const richEditConfiguration: languages.LanguageConfiguration = { + wordPattern: /(-?\d*\.\d\w*)|([^\[\{\]\}\:\"\,\s]+)/g, + + comments: { + lineComment: '//', + blockComment: ['/*', '*/'] + }, + + brackets: [ + ['{', '}'], + ['[', ']'] + ], + + autoClosingPairs: [ + { open: '{', close: '}', notIn: ['string'] }, + { open: '[', close: ']', notIn: ['string'] }, + { open: '"', close: '"', notIn: ['string'] } + ] +}; diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-languageFeatures.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-languageFeatures.ts.txt new file mode 100644 index 000000000..cc6391a0b --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-languageFeatures.ts.txt @@ -0,0 +1,716 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LanguageServiceDefaults } from './monaco.contribution'; +import type { JSONWorker } from './jsonWorker'; +import { + Uri, + Position, + Range, + IRange, + CancellationToken, + IDisposable, + editor, + languages, + MarkerSeverity, + IMarkdownString +} from './fillers/monaco-editor-core'; +import * as lsTypes from 'vscode-languageserver-types'; + +export interface WorkerAccessor { + (...more: Uri[]): Promise; +} + +// --- diagnostics --- --- + +export class DiagnosticsAdapter { + private _disposables: IDisposable[] = []; + private _listener: { [uri: string]: IDisposable } = Object.create(null); + + constructor( + private _languageId: string, + private _worker: WorkerAccessor, + defaults: LanguageServiceDefaults + ) { + const onModelAdd = (model: editor.IModel): void => { + let modeId = model.getLanguageId(); + if (modeId !== this._languageId) { + return; + } + + let handle: number; + this._listener[model.uri.toString()] = model.onDidChangeContent(() => { + clearTimeout(handle); + handle = window.setTimeout(() => this._doValidate(model.uri, modeId), 500); + }); + + this._doValidate(model.uri, modeId); + }; + + const onModelRemoved = (model: editor.IModel): void => { + editor.setModelMarkers(model, this._languageId, []); + let uriStr = model.uri.toString(); + let listener = this._listener[uriStr]; + if (listener) { + listener.dispose(); + delete this._listener[uriStr]; + } + }; + + this._disposables.push(editor.onDidCreateModel(onModelAdd)); + this._disposables.push( + editor.onWillDisposeModel((model) => { + onModelRemoved(model); + this._resetSchema(model.uri); + }) + ); + this._disposables.push( + editor.onDidChangeModelLanguage((event) => { + onModelRemoved(event.model); + onModelAdd(event.model); + this._resetSchema(event.model.uri); + }) + ); + + this._disposables.push( + defaults.onDidChange((_) => { + editor.getModels().forEach((model) => { + if (model.getLanguageId() === this._languageId) { + onModelRemoved(model); + onModelAdd(model); + } + }); + }) + ); + + this._disposables.push({ + dispose: () => { + editor.getModels().forEach(onModelRemoved); + for (let key in this._listener) { + this._listener[key].dispose(); + } + } + }); + + editor.getModels().forEach(onModelAdd); + } + + public dispose(): void { + this._disposables.forEach((d) => d && d.dispose()); + this._disposables = []; + } + + private _resetSchema(resource: Uri): void { + this._worker().then((worker) => { + worker.resetSchema(resource.toString()); + }); + } + + private _doValidate(resource: Uri, languageId: string): void { + this._worker(resource) + .then((worker) => { + return worker.doValidation(resource.toString()).then((diagnostics) => { + const markers = diagnostics.map((d) => toDiagnostics(resource, d)); + let model = editor.getModel(resource); + if (model && model.getLanguageId() === languageId) { + editor.setModelMarkers(model, languageId, markers); + } + }); + }) + .then(undefined, (err) => { + console.error(err); + }); + } +} + +function toSeverity(lsSeverity: number): MarkerSeverity { + switch (lsSeverity) { + case lsTypes.DiagnosticSeverity.Error: + return MarkerSeverity.Error; + case lsTypes.DiagnosticSeverity.Warning: + return MarkerSeverity.Warning; + case lsTypes.DiagnosticSeverity.Information: + return MarkerSeverity.Info; + case lsTypes.DiagnosticSeverity.Hint: + return MarkerSeverity.Hint; + default: + return MarkerSeverity.Info; + } +} + +function toDiagnostics(resource: Uri, diag: lsTypes.Diagnostic): editor.IMarkerData { + let code = typeof diag.code === 'number' ? String(diag.code) : diag.code; + + return { + severity: toSeverity(diag.severity), + startLineNumber: diag.range.start.line + 1, + startColumn: diag.range.start.character + 1, + endLineNumber: diag.range.end.line + 1, + endColumn: diag.range.end.character + 1, + message: diag.message, + code: code, + source: diag.source + }; +} + +// --- completion ------ + +function fromPosition(position: Position): lsTypes.Position { + if (!position) { + return void 0; + } + return { character: position.column - 1, line: position.lineNumber - 1 }; +} + +function fromRange(range: IRange): lsTypes.Range { + if (!range) { + return void 0; + } + return { + start: { + line: range.startLineNumber - 1, + character: range.startColumn - 1 + }, + end: { line: range.endLineNumber - 1, character: range.endColumn - 1 } + }; +} +function toRange(range: lsTypes.Range): Range { + if (!range) { + return void 0; + } + return new Range( + range.start.line + 1, + range.start.character + 1, + range.end.line + 1, + range.end.character + 1 + ); +} + +interface InsertReplaceEdit { + /** + * The string to be inserted. + */ + newText: string; + /** + * The range if the insert is requested + */ + insert: lsTypes.Range; + /** + * The range if the replace is requested. + */ + replace: lsTypes.Range; +} + +function isInsertReplaceEdit( + edit: lsTypes.TextEdit | InsertReplaceEdit +): edit is InsertReplaceEdit { + return ( + typeof (edit).insert !== 'undefined' && + typeof (edit).replace !== 'undefined' + ); +} + +function toCompletionItemKind(kind: number): languages.CompletionItemKind { + let mItemKind = languages.CompletionItemKind; + + switch (kind) { + case lsTypes.CompletionItemKind.Text: + return mItemKind.Text; + case lsTypes.CompletionItemKind.Method: + return mItemKind.Method; + case lsTypes.CompletionItemKind.Function: + return mItemKind.Function; + case lsTypes.CompletionItemKind.Constructor: + return mItemKind.Constructor; + case lsTypes.CompletionItemKind.Field: + return mItemKind.Field; + case lsTypes.CompletionItemKind.Variable: + return mItemKind.Variable; + case lsTypes.CompletionItemKind.Class: + return mItemKind.Class; + case lsTypes.CompletionItemKind.Interface: + return mItemKind.Interface; + case lsTypes.CompletionItemKind.Module: + return mItemKind.Module; + case lsTypes.CompletionItemKind.Property: + return mItemKind.Property; + case lsTypes.CompletionItemKind.Unit: + return mItemKind.Unit; + case lsTypes.CompletionItemKind.Value: + return mItemKind.Value; + case lsTypes.CompletionItemKind.Enum: + return mItemKind.Enum; + case lsTypes.CompletionItemKind.Keyword: + return mItemKind.Keyword; + case lsTypes.CompletionItemKind.Snippet: + return mItemKind.Snippet; + case lsTypes.CompletionItemKind.Color: + return mItemKind.Color; + case lsTypes.CompletionItemKind.File: + return mItemKind.File; + case lsTypes.CompletionItemKind.Reference: + return mItemKind.Reference; + } + return mItemKind.Property; +} + +function fromCompletionItemKind(kind: languages.CompletionItemKind): lsTypes.CompletionItemKind { + let mItemKind = languages.CompletionItemKind; + + switch (kind) { + case mItemKind.Text: + return lsTypes.CompletionItemKind.Text; + case mItemKind.Method: + return lsTypes.CompletionItemKind.Method; + case mItemKind.Function: + return lsTypes.CompletionItemKind.Function; + case mItemKind.Constructor: + return lsTypes.CompletionItemKind.Constructor; + case mItemKind.Field: + return lsTypes.CompletionItemKind.Field; + case mItemKind.Variable: + return lsTypes.CompletionItemKind.Variable; + case mItemKind.Class: + return lsTypes.CompletionItemKind.Class; + case mItemKind.Interface: + return lsTypes.CompletionItemKind.Interface; + case mItemKind.Module: + return lsTypes.CompletionItemKind.Module; + case mItemKind.Property: + return lsTypes.CompletionItemKind.Property; + case mItemKind.Unit: + return lsTypes.CompletionItemKind.Unit; + case mItemKind.Value: + return lsTypes.CompletionItemKind.Value; + case mItemKind.Enum: + return lsTypes.CompletionItemKind.Enum; + case mItemKind.Keyword: + return lsTypes.CompletionItemKind.Keyword; + case mItemKind.Snippet: + return lsTypes.CompletionItemKind.Snippet; + case mItemKind.Color: + return lsTypes.CompletionItemKind.Color; + case mItemKind.File: + return lsTypes.CompletionItemKind.File; + case mItemKind.Reference: + return lsTypes.CompletionItemKind.Reference; + } + return lsTypes.CompletionItemKind.Property; +} + +function toTextEdit(textEdit: lsTypes.TextEdit): editor.ISingleEditOperation { + if (!textEdit) { + return void 0; + } + return { + range: toRange(textEdit.range), + text: textEdit.newText + }; +} + +function toCommand(c: lsTypes.Command | undefined): languages.Command { + return c && c.command === 'editor.action.triggerSuggest' + ? { id: c.command, title: c.title, arguments: c.arguments } + : undefined; +} + +export class CompletionAdapter implements languages.CompletionItemProvider { + constructor(private _worker: WorkerAccessor) {} + + public get triggerCharacters(): string[] { + return [' ', ':', '"']; + } + + provideCompletionItems( + model: editor.IReadOnlyModel, + position: Position, + context: languages.CompletionContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doComplete(resource.toString(), fromPosition(position)); + }) + .then((info) => { + if (!info) { + return; + } + const wordInfo = model.getWordUntilPosition(position); + const wordRange = new Range( + position.lineNumber, + wordInfo.startColumn, + position.lineNumber, + wordInfo.endColumn + ); + + let items: languages.CompletionItem[] = info.items.map((entry) => { + let item: languages.CompletionItem = { + label: entry.label, + insertText: entry.insertText || entry.label, + sortText: entry.sortText, + filterText: entry.filterText, + documentation: entry.documentation, + detail: entry.detail, + command: toCommand(entry.command), + range: wordRange, + kind: toCompletionItemKind(entry.kind) + }; + if (entry.textEdit) { + if (isInsertReplaceEdit(entry.textEdit)) { + item.range = { + insert: toRange(entry.textEdit.insert), + replace: toRange(entry.textEdit.replace) + }; + } else { + item.range = toRange(entry.textEdit.range); + } + item.insertText = entry.textEdit.newText; + } + if (entry.additionalTextEdits) { + item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit); + } + if (entry.insertTextFormat === lsTypes.InsertTextFormat.Snippet) { + item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet; + } + return item; + }); + + return { + isIncomplete: info.isIncomplete, + suggestions: items + }; + }); + } +} + +function isMarkupContent(thing: any): thing is lsTypes.MarkupContent { + return ( + thing && typeof thing === 'object' && typeof (thing).kind === 'string' + ); +} + +function toMarkdownString(entry: lsTypes.MarkupContent | lsTypes.MarkedString): IMarkdownString { + if (typeof entry === 'string') { + return { + value: entry + }; + } + if (isMarkupContent(entry)) { + if (entry.kind === 'plaintext') { + return { + value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&') + }; + } + return { + value: entry.value + }; + } + + return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' }; +} + +function toMarkedStringArray( + contents: lsTypes.MarkupContent | lsTypes.MarkedString | lsTypes.MarkedString[] +): IMarkdownString[] { + if (!contents) { + return void 0; + } + if (Array.isArray(contents)) { + return contents.map(toMarkdownString); + } + return [toMarkdownString(contents)]; +} + +// --- hover ------ + +export class HoverAdapter implements languages.HoverProvider { + constructor(private _worker: WorkerAccessor) {} + + provideHover( + model: editor.IReadOnlyModel, + position: Position, + token: CancellationToken + ): Promise { + let resource = model.uri; + + return this._worker(resource) + .then((worker) => { + return worker.doHover(resource.toString(), fromPosition(position)); + }) + .then((info) => { + if (!info) { + return; + } + return { + range: toRange(info.range), + contents: toMarkedStringArray(info.contents) + }; + }); + } +} + +// --- definition ------ + +function toLocation(location: lsTypes.Location): languages.Location { + return { + uri: Uri.parse(location.uri), + range: toRange(location.range) + }; +} + +// --- document symbols ------ + +function toSymbolKind(kind: lsTypes.SymbolKind): languages.SymbolKind { + let mKind = languages.SymbolKind; + + switch (kind) { + case lsTypes.SymbolKind.File: + return mKind.Array; + case lsTypes.SymbolKind.Module: + return mKind.Module; + case lsTypes.SymbolKind.Namespace: + return mKind.Namespace; + case lsTypes.SymbolKind.Package: + return mKind.Package; + case lsTypes.SymbolKind.Class: + return mKind.Class; + case lsTypes.SymbolKind.Method: + return mKind.Method; + case lsTypes.SymbolKind.Property: + return mKind.Property; + case lsTypes.SymbolKind.Field: + return mKind.Field; + case lsTypes.SymbolKind.Constructor: + return mKind.Constructor; + case lsTypes.SymbolKind.Enum: + return mKind.Enum; + case lsTypes.SymbolKind.Interface: + return mKind.Interface; + case lsTypes.SymbolKind.Function: + return mKind.Function; + case lsTypes.SymbolKind.Variable: + return mKind.Variable; + case lsTypes.SymbolKind.Constant: + return mKind.Constant; + case lsTypes.SymbolKind.String: + return mKind.String; + case lsTypes.SymbolKind.Number: + return mKind.Number; + case lsTypes.SymbolKind.Boolean: + return mKind.Boolean; + case lsTypes.SymbolKind.Array: + return mKind.Array; + } + return mKind.Function; +} + +export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentSymbols( + model: editor.IReadOnlyModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentSymbols(resource.toString())) + .then((items) => { + if (!items) { + return; + } + return items.map((item) => ({ + name: item.name, + detail: '', + containerName: item.containerName, + kind: toSymbolKind(item.kind), + range: toRange(item.location.range), + selectionRange: toRange(item.location.range), + tags: [] + })); + }); + } +} + +function fromFormattingOptions(options: languages.FormattingOptions): lsTypes.FormattingOptions { + return { + tabSize: options.tabSize, + insertSpaces: options.insertSpaces + }; +} + +export class DocumentFormattingEditProvider implements languages.DocumentFormattingEditProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentFormattingEdits( + model: editor.IReadOnlyModel, + options: languages.FormattingOptions, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource).then((worker) => { + return worker + .format(resource.toString(), null, fromFormattingOptions(options)) + .then((edits) => { + if (!edits || edits.length === 0) { + return; + } + return edits.map(toTextEdit); + }); + }); + } +} + +export class DocumentRangeFormattingEditProvider + implements languages.DocumentRangeFormattingEditProvider +{ + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentRangeFormattingEdits( + model: editor.IReadOnlyModel, + range: Range, + options: languages.FormattingOptions, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource).then((worker) => { + return worker + .format(resource.toString(), fromRange(range), fromFormattingOptions(options)) + .then((edits) => { + if (!edits || edits.length === 0) { + return; + } + return edits.map(toTextEdit); + }); + }); + } +} + +export class DocumentColorAdapter implements languages.DocumentColorProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideDocumentColors( + model: editor.IReadOnlyModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.findDocumentColors(resource.toString())) + .then((infos) => { + if (!infos) { + return; + } + return infos.map((item) => ({ + color: item.color, + range: toRange(item.range) + })); + }); + } + + public provideColorPresentations( + model: editor.IReadOnlyModel, + info: languages.IColorInformation, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => + worker.getColorPresentations(resource.toString(), info.color, fromRange(info.range)) + ) + .then((presentations) => { + if (!presentations) { + return; + } + return presentations.map((presentation) => { + let item: languages.IColorPresentation = { + label: presentation.label + }; + if (presentation.textEdit) { + item.textEdit = toTextEdit(presentation.textEdit); + } + if (presentation.additionalTextEdits) { + item.additionalTextEdits = presentation.additionalTextEdits.map(toTextEdit); + } + return item; + }); + }); + } +} + +export class FoldingRangeAdapter implements languages.FoldingRangeProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideFoldingRanges( + model: editor.IReadOnlyModel, + context: languages.FoldingContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.getFoldingRanges(resource.toString(), context)) + .then((ranges) => { + if (!ranges) { + return; + } + return ranges.map((range) => { + let result: languages.FoldingRange = { + start: range.startLine + 1, + end: range.endLine + 1 + }; + if (typeof range.kind !== 'undefined') { + result.kind = toFoldingRangeKind(range.kind); + } + return result; + }); + }); + } +} + +function toFoldingRangeKind(kind: lsTypes.FoldingRangeKind): languages.FoldingRangeKind { + switch (kind) { + case lsTypes.FoldingRangeKind.Comment: + return languages.FoldingRangeKind.Comment; + case lsTypes.FoldingRangeKind.Imports: + return languages.FoldingRangeKind.Imports; + case lsTypes.FoldingRangeKind.Region: + return languages.FoldingRangeKind.Region; + } + return void 0; +} + +export class SelectionRangeAdapter implements languages.SelectionRangeProvider { + constructor(private _worker: WorkerAccessor) {} + + public provideSelectionRanges( + model: editor.IReadOnlyModel, + positions: Position[], + token: CancellationToken + ): Promise { + const resource = model.uri; + + return this._worker(resource) + .then((worker) => worker.getSelectionRanges(resource.toString(), positions.map(fromPosition))) + .then((selectionRanges) => { + if (!selectionRanges) { + return; + } + return selectionRanges.map((selectionRange) => { + const result: languages.SelectionRange[] = []; + while (selectionRange) { + result.push({ range: toRange(selectionRange.range) }); + selectionRange = selectionRange.parent; + } + return result; + }); + }); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-tokenization.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-tokenization.ts.txt new file mode 100644 index 000000000..aa9bd5a44 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-tokenization.ts.txt @@ -0,0 +1,245 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as json from 'jsonc-parser'; +import { languages } from './fillers/monaco-editor-core'; + +export function createTokenizationSupport(supportComments: boolean): languages.TokensProvider { + return { + getInitialState: () => new JSONState(null, null, false, null), + tokenize: (line, state, offsetDelta?, stopAtOffset?) => + tokenize(supportComments, line, state, offsetDelta, stopAtOffset) + }; +} + +export const TOKEN_DELIM_OBJECT = 'delimiter.bracket.json'; +export const TOKEN_DELIM_ARRAY = 'delimiter.array.json'; +export const TOKEN_DELIM_COLON = 'delimiter.colon.json'; +export const TOKEN_DELIM_COMMA = 'delimiter.comma.json'; +export const TOKEN_VALUE_BOOLEAN = 'keyword.json'; +export const TOKEN_VALUE_NULL = 'keyword.json'; +export const TOKEN_VALUE_STRING = 'string.value.json'; +export const TOKEN_VALUE_NUMBER = 'number.json'; +export const TOKEN_PROPERTY_NAME = 'string.key.json'; +export const TOKEN_COMMENT_BLOCK = 'comment.block.json'; +export const TOKEN_COMMENT_LINE = 'comment.line.json'; + +const enum JSONParent { + Object = 0, + Array = 1 +} + +class ParentsStack { + constructor(public readonly parent: ParentsStack | null, public readonly type: JSONParent) {} + + public static pop(parents: ParentsStack | null): ParentsStack | null { + if (parents) { + return parents.parent; + } + return null; + } + + public static push(parents: ParentsStack | null, type: JSONParent): ParentsStack { + return new ParentsStack(parents, type); + } + + public static equals(a: ParentsStack | null, b: ParentsStack | null): boolean { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + while (a && b) { + if (a === b) { + return true; + } + if (a.type !== b.type) { + return false; + } + a = a.parent; + b = b.parent; + } + return true; + } +} + +class JSONState implements languages.IState { + private _state: languages.IState; + + public scanError: json.ScanError; + public lastWasColon: boolean; + public parents: ParentsStack | null; + + constructor( + state: languages.IState, + scanError: json.ScanError, + lastWasColon: boolean, + parents: ParentsStack | null + ) { + this._state = state; + this.scanError = scanError; + this.lastWasColon = lastWasColon; + this.parents = parents; + } + + public clone(): JSONState { + return new JSONState(this._state, this.scanError, this.lastWasColon, this.parents); + } + + public equals(other: languages.IState): boolean { + if (other === this) { + return true; + } + if (!other || !(other instanceof JSONState)) { + return false; + } + return ( + this.scanError === other.scanError && + this.lastWasColon === other.lastWasColon && + ParentsStack.equals(this.parents, other.parents) + ); + } + + public getStateData(): languages.IState { + return this._state; + } + + public setStateData(state: languages.IState): void { + this._state = state; + } +} + +function tokenize( + comments: boolean, + line: string, + state: JSONState, + offsetDelta: number = 0, + stopAtOffset?: number +): languages.ILineTokens { + // handle multiline strings and block comments + let numberOfInsertedCharacters = 0; + let adjustOffset = false; + + switch (state.scanError) { + case json.ScanError.UnexpectedEndOfString: + line = '"' + line; + numberOfInsertedCharacters = 1; + break; + case json.ScanError.UnexpectedEndOfComment: + line = '/*' + line; + numberOfInsertedCharacters = 2; + break; + } + + const scanner = json.createScanner(line); + let lastWasColon = state.lastWasColon; + let parents = state.parents; + + const ret: languages.ILineTokens = { + tokens: [], + endState: state.clone() + }; + + while (true) { + let offset = offsetDelta + scanner.getPosition(); + let type = ''; + + const kind = scanner.scan(); + if (kind === json.SyntaxKind.EOF) { + break; + } + + // Check that the scanner has advanced + if (offset === offsetDelta + scanner.getPosition()) { + throw new Error( + 'Scanner did not advance, next 3 characters are: ' + line.substr(scanner.getPosition(), 3) + ); + } + + // In case we inserted /* or " character, we need to + // adjust the offset of all tokens (except the first) + if (adjustOffset) { + offset -= numberOfInsertedCharacters; + } + adjustOffset = numberOfInsertedCharacters > 0; + + // brackets and type + switch (kind) { + case json.SyntaxKind.OpenBraceToken: + parents = ParentsStack.push(parents, JSONParent.Object); + type = TOKEN_DELIM_OBJECT; + lastWasColon = false; + break; + case json.SyntaxKind.CloseBraceToken: + parents = ParentsStack.pop(parents); + type = TOKEN_DELIM_OBJECT; + lastWasColon = false; + break; + case json.SyntaxKind.OpenBracketToken: + parents = ParentsStack.push(parents, JSONParent.Array); + type = TOKEN_DELIM_ARRAY; + lastWasColon = false; + break; + case json.SyntaxKind.CloseBracketToken: + parents = ParentsStack.pop(parents); + type = TOKEN_DELIM_ARRAY; + lastWasColon = false; + break; + case json.SyntaxKind.ColonToken: + type = TOKEN_DELIM_COLON; + lastWasColon = true; + break; + case json.SyntaxKind.CommaToken: + type = TOKEN_DELIM_COMMA; + lastWasColon = false; + break; + case json.SyntaxKind.TrueKeyword: + case json.SyntaxKind.FalseKeyword: + type = TOKEN_VALUE_BOOLEAN; + lastWasColon = false; + break; + case json.SyntaxKind.NullKeyword: + type = TOKEN_VALUE_NULL; + lastWasColon = false; + break; + case json.SyntaxKind.StringLiteral: + const currentParent = parents ? parents.type : JSONParent.Object; + const inArray = currentParent === JSONParent.Array; + type = lastWasColon || inArray ? TOKEN_VALUE_STRING : TOKEN_PROPERTY_NAME; + lastWasColon = false; + break; + case json.SyntaxKind.NumericLiteral: + type = TOKEN_VALUE_NUMBER; + lastWasColon = false; + break; + } + + // comments, iff enabled + if (comments) { + switch (kind) { + case json.SyntaxKind.LineCommentTrivia: + type = TOKEN_COMMENT_LINE; + break; + case json.SyntaxKind.BlockCommentTrivia: + type = TOKEN_COMMENT_BLOCK; + break; + } + } + + ret.endState = new JSONState( + state.getStateData(), + scanner.getTokenError(), + lastWasColon, + parents + ); + ret.tokens.push({ + startIndex: offset, + scopes: type + }); + } + + return ret; +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-workerManager.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-workerManager.ts.txt new file mode 100644 index 000000000..6c32e0018 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-json-src-workerManager.ts.txt @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LanguageServiceDefaults } from './monaco.contribution'; +import type { JSONWorker } from './jsonWorker'; +import { IDisposable, Uri, editor } from './fillers/monaco-editor-core'; + +const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min + +export class WorkerManager { + private _defaults: LanguageServiceDefaults; + private _idleCheckInterval: number; + private _lastUsedTime: number; + private _configChangeListener: IDisposable; + + private _worker: editor.MonacoWebWorker; + private _client: Promise; + + constructor(defaults: LanguageServiceDefaults) { + this._defaults = defaults; + this._worker = null; + this._idleCheckInterval = window.setInterval(() => this._checkIfIdle(), 30 * 1000); + this._lastUsedTime = 0; + this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker()); + } + + private _stopWorker(): void { + if (this._worker) { + this._worker.dispose(); + this._worker = null; + } + this._client = null; + } + + dispose(): void { + clearInterval(this._idleCheckInterval); + this._configChangeListener.dispose(); + this._stopWorker(); + } + + private _checkIfIdle(): void { + if (!this._worker) { + return; + } + let timePassedSinceLastUsed = Date.now() - this._lastUsedTime; + if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) { + this._stopWorker(); + } + } + + private _getClient(): Promise { + this._lastUsedTime = Date.now(); + + if (!this._client) { + this._worker = editor.createWebWorker({ + // module that exports the create() method and returns a `JSONWorker` instance + moduleId: 'vs/language/json/jsonWorker', + + label: this._defaults.languageId, + + // passed in to the create() method + createData: { + languageSettings: this._defaults.diagnosticsOptions, + languageId: this._defaults.languageId, + enableSchemaRequest: this._defaults.diagnosticsOptions.enableSchemaRequest + } + }); + + this._client = >(this._worker.getProxy()); + } + + return this._client; + } + + getLanguageServiceWorker(...resources: Uri[]): Promise { + let _client: JSONWorker; + return this._getClient() + .then((client) => { + _client = client; + }) + .then((_) => { + return this._worker.withSyncedResources(resources); + }) + .then((_) => _client); + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-languageFeatures.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-languageFeatures.ts.txt new file mode 100644 index 000000000..2dba4a863 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-languageFeatures.ts.txt @@ -0,0 +1,1265 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { + Diagnostic, + DiagnosticRelatedInformation, + LanguageServiceDefaults, + typescriptDefaults +} from './monaco.contribution'; +import type * as ts from './lib/typescriptServices'; +import type { TypeScriptWorker } from './tsWorker'; +import { libFileSet } from './lib/lib.index'; +import { + editor, + languages, + Uri, + Position, + Range, + CancellationToken, + IDisposable, + IRange, + MarkerTag, + MarkerSeverity +} from './fillers/monaco-editor-core'; + +//#region utils copied from typescript to prevent loading the entire typescriptServices --- + +enum IndentStyle { + None = 0, + Block = 1, + Smart = 2 +} + +export function flattenDiagnosticMessageText( + diag: string | ts.DiagnosticMessageChain | undefined, + newLine: string, + indent = 0 +): string { + if (typeof diag === 'string') { + return diag; + } else if (diag === undefined) { + return ''; + } + let result = ''; + if (indent) { + result += newLine; + + for (let i = 0; i < indent; i++) { + result += ' '; + } + } + result += diag.messageText; + indent++; + if (diag.next) { + for (const kid of diag.next) { + result += flattenDiagnosticMessageText(kid, newLine, indent); + } + } + return result; +} + +function displayPartsToString(displayParts: ts.SymbolDisplayPart[] | undefined): string { + if (displayParts) { + return displayParts.map((displayPart) => displayPart.text).join(''); + } + return ''; +} + +//#endregion + +export abstract class Adapter { + constructor(protected _worker: (...uris: Uri[]) => Promise) {} + + // protected _positionToOffset(model: editor.ITextModel, position: monaco.IPosition): number { + // return model.getOffsetAt(position); + // } + + // protected _offsetToPosition(model: editor.ITextModel, offset: number): monaco.IPosition { + // return model.getPositionAt(offset); + // } + + protected _textSpanToRange(model: editor.ITextModel, span: ts.TextSpan): IRange { + let p1 = model.getPositionAt(span.start); + let p2 = model.getPositionAt(span.start + span.length); + let { lineNumber: startLineNumber, column: startColumn } = p1; + let { lineNumber: endLineNumber, column: endColumn } = p2; + return { startLineNumber, startColumn, endLineNumber, endColumn }; + } +} + +// --- lib files + +export class LibFiles { + private _libFiles: Record; + private _hasFetchedLibFiles: boolean; + private _fetchLibFilesPromise: Promise | null; + + constructor(private readonly _worker: (...uris: Uri[]) => Promise) { + this._libFiles = {}; + this._hasFetchedLibFiles = false; + this._fetchLibFilesPromise = null; + } + + public isLibFile(uri: Uri | null): boolean { + if (!uri) { + return false; + } + if (uri.path.indexOf('/lib.') === 0) { + return !!libFileSet[uri.path.slice(1)]; + } + return false; + } + + public getOrCreateModel(fileName: string): editor.ITextModel | null { + const uri = Uri.parse(fileName); + const model = editor.getModel(uri); + if (model) { + return model; + } + if (this.isLibFile(uri) && this._hasFetchedLibFiles) { + return editor.createModel(this._libFiles[uri.path.slice(1)], 'typescript', uri); + } + const matchedLibFile = typescriptDefaults.getExtraLibs()[fileName]; + if (matchedLibFile) { + return editor.createModel(matchedLibFile.content, 'typescript', uri); + } + return null; + } + + private _containsLibFile(uris: (Uri | null)[]): boolean { + for (let uri of uris) { + if (this.isLibFile(uri)) { + return true; + } + } + return false; + } + + public async fetchLibFilesIfNecessary(uris: (Uri | null)[]): Promise { + if (!this._containsLibFile(uris)) { + // no lib files necessary + return; + } + await this._fetchLibFiles(); + } + + private _fetchLibFiles(): Promise { + if (!this._fetchLibFilesPromise) { + this._fetchLibFilesPromise = this._worker() + .then((w) => w.getLibFiles()) + .then((libFiles) => { + this._hasFetchedLibFiles = true; + this._libFiles = libFiles; + }); + } + return this._fetchLibFilesPromise; + } +} + +// --- diagnostics --- --- + +enum DiagnosticCategory { + Warning = 0, + Error = 1, + Suggestion = 2, + Message = 3 +} + +/** + * temporary interface until the editor API exposes + * `IModel.isAttachedToEditor` and `IModel.onDidChangeAttached` + */ +interface IInternalEditorModel extends editor.IModel { + onDidChangeAttached(listener: () => void): IDisposable; + isAttachedToEditor(): boolean; +} + +export class DiagnosticsAdapter extends Adapter { + private _disposables: IDisposable[] = []; + private _listener: { [uri: string]: IDisposable } = Object.create(null); + + constructor( + private readonly _libFiles: LibFiles, + private _defaults: LanguageServiceDefaults, + private _selector: string, + worker: (...uris: Uri[]) => Promise + ) { + super(worker); + + const onModelAdd = (model: IInternalEditorModel): void => { + if (model.getLanguageId() !== _selector) { + return; + } + + const maybeValidate = () => { + const { onlyVisible } = this._defaults.getDiagnosticsOptions(); + if (onlyVisible) { + if (model.isAttachedToEditor()) { + this._doValidate(model); + } + } else { + this._doValidate(model); + } + }; + + let handle: number; + const changeSubscription = model.onDidChangeContent(() => { + clearTimeout(handle); + handle = window.setTimeout(maybeValidate, 500); + }); + + const visibleSubscription = model.onDidChangeAttached(() => { + const { onlyVisible } = this._defaults.getDiagnosticsOptions(); + if (onlyVisible) { + if (model.isAttachedToEditor()) { + // this model is now attached to an editor + // => compute diagnostics + maybeValidate(); + } else { + // this model is no longer attached to an editor + // => clear existing diagnostics + editor.setModelMarkers(model, this._selector, []); + } + } + }); + + this._listener[model.uri.toString()] = { + dispose() { + changeSubscription.dispose(); + visibleSubscription.dispose(); + clearTimeout(handle); + } + }; + + maybeValidate(); + }; + + const onModelRemoved = (model: editor.IModel): void => { + editor.setModelMarkers(model, this._selector, []); + const key = model.uri.toString(); + if (this._listener[key]) { + this._listener[key].dispose(); + delete this._listener[key]; + } + }; + + this._disposables.push( + editor.onDidCreateModel((model) => onModelAdd(model)) + ); + this._disposables.push(editor.onWillDisposeModel(onModelRemoved)); + this._disposables.push( + editor.onDidChangeModelLanguage((event) => { + onModelRemoved(event.model); + onModelAdd(event.model); + }) + ); + + this._disposables.push({ + dispose() { + for (const model of editor.getModels()) { + onModelRemoved(model); + } + } + }); + + const recomputeDiagostics = () => { + // redo diagnostics when options change + for (const model of editor.getModels()) { + onModelRemoved(model); + onModelAdd(model); + } + }; + this._disposables.push(this._defaults.onDidChange(recomputeDiagostics)); + this._disposables.push(this._defaults.onDidExtraLibsChange(recomputeDiagostics)); + + editor.getModels().forEach((model) => onModelAdd(model)); + } + + public dispose(): void { + this._disposables.forEach((d) => d && d.dispose()); + this._disposables = []; + } + + private async _doValidate(model: editor.ITextModel): Promise { + const worker = await this._worker(model.uri); + + if (model.isDisposed()) { + // model was disposed in the meantime + return; + } + + const promises: Promise[] = []; + const { noSyntaxValidation, noSemanticValidation, noSuggestionDiagnostics } = + this._defaults.getDiagnosticsOptions(); + if (!noSyntaxValidation) { + promises.push(worker.getSyntacticDiagnostics(model.uri.toString())); + } + if (!noSemanticValidation) { + promises.push(worker.getSemanticDiagnostics(model.uri.toString())); + } + if (!noSuggestionDiagnostics) { + promises.push(worker.getSuggestionDiagnostics(model.uri.toString())); + } + + const allDiagnostics = await Promise.all(promises); + + if (!allDiagnostics || model.isDisposed()) { + // model was disposed in the meantime + return; + } + + const diagnostics = allDiagnostics + .reduce((p, c) => c.concat(p), []) + .filter( + (d) => + (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === + -1 + ); + + // Fetch lib files if necessary + const relatedUris = diagnostics + .map((d) => d.relatedInformation || []) + .reduce((p, c) => c.concat(p), []) + .map((relatedInformation) => + relatedInformation.file ? Uri.parse(relatedInformation.file.fileName) : null + ); + + await this._libFiles.fetchLibFilesIfNecessary(relatedUris); + + if (model.isDisposed()) { + // model was disposed in the meantime + return; + } + + editor.setModelMarkers( + model, + this._selector, + diagnostics.map((d) => this._convertDiagnostics(model, d)) + ); + } + + private _convertDiagnostics(model: editor.ITextModel, diag: Diagnostic): editor.IMarkerData { + const diagStart = diag.start || 0; + const diagLength = diag.length || 1; + const { lineNumber: startLineNumber, column: startColumn } = model.getPositionAt(diagStart); + const { lineNumber: endLineNumber, column: endColumn } = model.getPositionAt( + diagStart + diagLength + ); + + const tags: MarkerTag[] = []; + if (diag.reportsUnnecessary) { + tags.push(MarkerTag.Unnecessary); + } + if (diag.reportsDeprecated) { + tags.push(MarkerTag.Deprecated); + } + + return { + severity: this._tsDiagnosticCategoryToMarkerSeverity(diag.category), + startLineNumber, + startColumn, + endLineNumber, + endColumn, + message: flattenDiagnosticMessageText(diag.messageText, '\n'), + code: diag.code.toString(), + tags, + relatedInformation: this._convertRelatedInformation(model, diag.relatedInformation) + }; + } + + private _convertRelatedInformation( + model: editor.ITextModel, + relatedInformation?: DiagnosticRelatedInformation[] + ): editor.IRelatedInformation[] { + if (!relatedInformation) { + return []; + } + + const result: editor.IRelatedInformation[] = []; + relatedInformation.forEach((info) => { + let relatedResource: editor.ITextModel | null = model; + if (info.file) { + relatedResource = this._libFiles.getOrCreateModel(info.file.fileName); + } + + if (!relatedResource) { + return; + } + const infoStart = info.start || 0; + const infoLength = info.length || 1; + const { lineNumber: startLineNumber, column: startColumn } = + relatedResource.getPositionAt(infoStart); + const { lineNumber: endLineNumber, column: endColumn } = relatedResource.getPositionAt( + infoStart + infoLength + ); + + result.push({ + resource: relatedResource.uri, + startLineNumber, + startColumn, + endLineNumber, + endColumn, + message: flattenDiagnosticMessageText(info.messageText, '\n') + }); + }); + return result; + } + + private _tsDiagnosticCategoryToMarkerSeverity(category: ts.DiagnosticCategory): MarkerSeverity { + switch (category) { + case DiagnosticCategory.Error: + return MarkerSeverity.Error; + case DiagnosticCategory.Message: + return MarkerSeverity.Info; + case DiagnosticCategory.Warning: + return MarkerSeverity.Warning; + case DiagnosticCategory.Suggestion: + return MarkerSeverity.Hint; + } + return MarkerSeverity.Info; + } +} + +// --- suggest ------ + +interface MyCompletionItem extends languages.CompletionItem { + label: string; + uri: Uri; + position: Position; + offset: number; +} + +export class SuggestAdapter extends Adapter implements languages.CompletionItemProvider { + public get triggerCharacters(): string[] { + return ['.']; + } + + public async provideCompletionItems( + model: editor.ITextModel, + position: Position, + _context: languages.CompletionContext, + token: CancellationToken + ): Promise { + const wordInfo = model.getWordUntilPosition(position); + const wordRange = new Range( + position.lineNumber, + wordInfo.startColumn, + position.lineNumber, + wordInfo.endColumn + ); + const resource = model.uri; + const offset = model.getOffsetAt(position); + + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const info = await worker.getCompletionsAtPosition(resource.toString(), offset); + + if (!info || model.isDisposed()) { + return; + } + + const suggestions: MyCompletionItem[] = info.entries.map((entry) => { + let range = wordRange; + if (entry.replacementSpan) { + const p1 = model.getPositionAt(entry.replacementSpan.start); + const p2 = model.getPositionAt(entry.replacementSpan.start + entry.replacementSpan.length); + range = new Range(p1.lineNumber, p1.column, p2.lineNumber, p2.column); + } + + const tags: languages.CompletionItemTag[] = []; + if (entry.kindModifiers?.indexOf('deprecated') !== -1) { + tags.push(languages.CompletionItemTag.Deprecated); + } + + return { + uri: resource, + position: position, + offset: offset, + range: range, + label: entry.name, + insertText: entry.name, + sortText: entry.sortText, + kind: SuggestAdapter.convertKind(entry.kind), + tags + }; + }); + + return { + suggestions + }; + } + + public async resolveCompletionItem( + item: languages.CompletionItem, + token: CancellationToken + ): Promise { + const myItem = item; + const resource = myItem.uri; + const position = myItem.position; + const offset = myItem.offset; + + const worker = await this._worker(resource); + const details = await worker.getCompletionEntryDetails( + resource.toString(), + offset, + myItem.label + ); + if (!details) { + return myItem; + } + return { + uri: resource, + position: position, + label: details.name, + kind: SuggestAdapter.convertKind(details.kind), + detail: displayPartsToString(details.displayParts), + documentation: { + value: SuggestAdapter.createDocumentationString(details) + } + }; + } + + private static convertKind(kind: string): languages.CompletionItemKind { + switch (kind) { + case Kind.primitiveType: + case Kind.keyword: + return languages.CompletionItemKind.Keyword; + case Kind.variable: + case Kind.localVariable: + return languages.CompletionItemKind.Variable; + case Kind.memberVariable: + case Kind.memberGetAccessor: + case Kind.memberSetAccessor: + return languages.CompletionItemKind.Field; + case Kind.function: + case Kind.memberFunction: + case Kind.constructSignature: + case Kind.callSignature: + case Kind.indexSignature: + return languages.CompletionItemKind.Function; + case Kind.enum: + return languages.CompletionItemKind.Enum; + case Kind.module: + return languages.CompletionItemKind.Module; + case Kind.class: + return languages.CompletionItemKind.Class; + case Kind.interface: + return languages.CompletionItemKind.Interface; + case Kind.warning: + return languages.CompletionItemKind.File; + } + + return languages.CompletionItemKind.Property; + } + + private static createDocumentationString(details: ts.CompletionEntryDetails): string { + let documentationString = displayPartsToString(details.documentation); + if (details.tags) { + for (const tag of details.tags) { + documentationString += `\n\n${tagToString(tag)}`; + } + } + return documentationString; + } +} + +function tagToString(tag: ts.JSDocTagInfo): string { + let tagLabel = `*@${tag.name}*`; + if (tag.name === 'param' && tag.text) { + const [paramName, ...rest] = tag.text; + tagLabel += `\`${paramName.text}\``; + if (rest.length > 0) tagLabel += ` — ${rest.map((r) => r.text).join(' ')}`; + } else if (Array.isArray(tag.text)) { + tagLabel += ` — ${tag.text.map((r) => r.text).join(' ')}`; + } else if (tag.text) { + tagLabel += ` — ${tag.text}`; + } + return tagLabel; +} + +export class SignatureHelpAdapter extends Adapter implements languages.SignatureHelpProvider { + public signatureHelpTriggerCharacters = ['(', ',']; + + private static _toSignatureHelpTriggerReason( + context: languages.SignatureHelpContext + ): ts.SignatureHelpTriggerReason { + switch (context.triggerKind) { + case languages.SignatureHelpTriggerKind.TriggerCharacter: + if (context.triggerCharacter) { + if (context.isRetrigger) { + return { kind: 'retrigger', triggerCharacter: context.triggerCharacter as any }; + } else { + return { kind: 'characterTyped', triggerCharacter: context.triggerCharacter as any }; + } + } else { + return { kind: 'invoked' }; + } + + case languages.SignatureHelpTriggerKind.ContentChange: + return context.isRetrigger ? { kind: 'retrigger' } : { kind: 'invoked' }; + + case languages.SignatureHelpTriggerKind.Invoke: + default: + return { kind: 'invoked' }; + } + } + + public async provideSignatureHelp( + model: editor.ITextModel, + position: Position, + token: CancellationToken, + context: languages.SignatureHelpContext + ): Promise { + const resource = model.uri; + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const info = await worker.getSignatureHelpItems(resource.toString(), offset, { + triggerReason: SignatureHelpAdapter._toSignatureHelpTriggerReason(context) + }); + + if (!info || model.isDisposed()) { + return; + } + + const ret: languages.SignatureHelp = { + activeSignature: info.selectedItemIndex, + activeParameter: info.argumentIndex, + signatures: [] + }; + + info.items.forEach((item) => { + const signature: languages.SignatureInformation = { + label: '', + parameters: [] + }; + + signature.documentation = { + value: displayPartsToString(item.documentation) + }; + signature.label += displayPartsToString(item.prefixDisplayParts); + item.parameters.forEach((p, i, a) => { + const label = displayPartsToString(p.displayParts); + const parameter: languages.ParameterInformation = { + label: label, + documentation: { + value: displayPartsToString(p.documentation) + } + }; + signature.label += label; + signature.parameters.push(parameter); + if (i < a.length - 1) { + signature.label += displayPartsToString(item.separatorDisplayParts); + } + }); + signature.label += displayPartsToString(item.suffixDisplayParts); + ret.signatures.push(signature); + }); + + return { + value: ret, + dispose() {} + }; + } +} + +// --- hover ------ + +export class QuickInfoAdapter extends Adapter implements languages.HoverProvider { + public async provideHover( + model: editor.ITextModel, + position: Position, + token: CancellationToken + ): Promise { + const resource = model.uri; + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const info = await worker.getQuickInfoAtPosition(resource.toString(), offset); + + if (!info || model.isDisposed()) { + return; + } + + const documentation = displayPartsToString(info.documentation); + const tags = info.tags ? info.tags.map((tag) => tagToString(tag)).join(' \n\n') : ''; + const contents = displayPartsToString(info.displayParts); + return { + range: this._textSpanToRange(model, info.textSpan), + contents: [ + { + value: '```typescript\n' + contents + '\n```\n' + }, + { + value: documentation + (tags ? '\n\n' + tags : '') + } + ] + }; + } +} + +// --- occurrences ------ + +export class OccurrencesAdapter extends Adapter implements languages.DocumentHighlightProvider { + public async provideDocumentHighlights( + model: editor.ITextModel, + position: Position, + token: CancellationToken + ): Promise { + const resource = model.uri; + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const entries = await worker.getOccurrencesAtPosition(resource.toString(), offset); + + if (!entries || model.isDisposed()) { + return; + } + + return entries.map((entry) => { + return { + range: this._textSpanToRange(model, entry.textSpan), + kind: entry.isWriteAccess + ? languages.DocumentHighlightKind.Write + : languages.DocumentHighlightKind.Text + }; + }); + } +} + +// --- definition ------ + +export class DefinitionAdapter extends Adapter { + constructor( + private readonly _libFiles: LibFiles, + worker: (...uris: Uri[]) => Promise + ) { + super(worker); + } + + public async provideDefinition( + model: editor.ITextModel, + position: Position, + token: CancellationToken + ): Promise { + const resource = model.uri; + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const entries = await worker.getDefinitionAtPosition(resource.toString(), offset); + + if (!entries || model.isDisposed()) { + return; + } + + // Fetch lib files if necessary + await this._libFiles.fetchLibFilesIfNecessary( + entries.map((entry) => Uri.parse(entry.fileName)) + ); + + if (model.isDisposed()) { + return; + } + + const result: languages.Location[] = []; + for (let entry of entries) { + const refModel = this._libFiles.getOrCreateModel(entry.fileName); + if (refModel) { + result.push({ + uri: refModel.uri, + range: this._textSpanToRange(refModel, entry.textSpan) + }); + } + } + return result; + } +} + +// --- references ------ + +export class ReferenceAdapter extends Adapter implements languages.ReferenceProvider { + constructor( + private readonly _libFiles: LibFiles, + worker: (...uris: Uri[]) => Promise + ) { + super(worker); + } + + public async provideReferences( + model: editor.ITextModel, + position: Position, + context: languages.ReferenceContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const entries = await worker.getReferencesAtPosition(resource.toString(), offset); + + if (!entries || model.isDisposed()) { + return; + } + + // Fetch lib files if necessary + await this._libFiles.fetchLibFilesIfNecessary( + entries.map((entry) => Uri.parse(entry.fileName)) + ); + + if (model.isDisposed()) { + return; + } + + const result: languages.Location[] = []; + for (let entry of entries) { + const refModel = this._libFiles.getOrCreateModel(entry.fileName); + if (refModel) { + result.push({ + uri: refModel.uri, + range: this._textSpanToRange(refModel, entry.textSpan) + }); + } + } + return result; + } +} + +// --- outline ------ + +export class OutlineAdapter extends Adapter implements languages.DocumentSymbolProvider { + public async provideDocumentSymbols( + model: editor.ITextModel, + token: CancellationToken + ): Promise { + const resource = model.uri; + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const items = await worker.getNavigationBarItems(resource.toString()); + + if (!items || model.isDisposed()) { + return; + } + + const convert = ( + bucket: languages.DocumentSymbol[], + item: ts.NavigationBarItem, + containerLabel?: string + ): void => { + let result: languages.DocumentSymbol = { + name: item.text, + detail: '', + kind: (outlineTypeTable[item.kind] || languages.SymbolKind.Variable), + range: this._textSpanToRange(model, item.spans[0]), + selectionRange: this._textSpanToRange(model, item.spans[0]), + tags: [] + }; + + if (containerLabel) result.containerName = containerLabel; + + if (item.childItems && item.childItems.length > 0) { + for (let child of item.childItems) { + convert(bucket, child, result.name); + } + } + + bucket.push(result); + }; + + let result: languages.DocumentSymbol[] = []; + items.forEach((item) => convert(result, item)); + return result; + } +} + +export class Kind { + public static unknown: string = ''; + public static keyword: string = 'keyword'; + public static script: string = 'script'; + public static module: string = 'module'; + public static class: string = 'class'; + public static interface: string = 'interface'; + public static type: string = 'type'; + public static enum: string = 'enum'; + public static variable: string = 'var'; + public static localVariable: string = 'local var'; + public static function: string = 'function'; + public static localFunction: string = 'local function'; + public static memberFunction: string = 'method'; + public static memberGetAccessor: string = 'getter'; + public static memberSetAccessor: string = 'setter'; + public static memberVariable: string = 'property'; + public static constructorImplementation: string = 'constructor'; + public static callSignature: string = 'call'; + public static indexSignature: string = 'index'; + public static constructSignature: string = 'construct'; + public static parameter: string = 'parameter'; + public static typeParameter: string = 'type parameter'; + public static primitiveType: string = 'primitive type'; + public static label: string = 'label'; + public static alias: string = 'alias'; + public static const: string = 'const'; + public static let: string = 'let'; + public static warning: string = 'warning'; +} + +let outlineTypeTable: { + [kind: string]: languages.SymbolKind; +} = Object.create(null); +outlineTypeTable[Kind.module] = languages.SymbolKind.Module; +outlineTypeTable[Kind.class] = languages.SymbolKind.Class; +outlineTypeTable[Kind.enum] = languages.SymbolKind.Enum; +outlineTypeTable[Kind.interface] = languages.SymbolKind.Interface; +outlineTypeTable[Kind.memberFunction] = languages.SymbolKind.Method; +outlineTypeTable[Kind.memberVariable] = languages.SymbolKind.Property; +outlineTypeTable[Kind.memberGetAccessor] = languages.SymbolKind.Property; +outlineTypeTable[Kind.memberSetAccessor] = languages.SymbolKind.Property; +outlineTypeTable[Kind.variable] = languages.SymbolKind.Variable; +outlineTypeTable[Kind.const] = languages.SymbolKind.Variable; +outlineTypeTable[Kind.localVariable] = languages.SymbolKind.Variable; +outlineTypeTable[Kind.variable] = languages.SymbolKind.Variable; +outlineTypeTable[Kind.function] = languages.SymbolKind.Function; +outlineTypeTable[Kind.localFunction] = languages.SymbolKind.Function; + +// --- formatting ---- + +export abstract class FormatHelper extends Adapter { + protected static _convertOptions(options: languages.FormattingOptions): ts.FormatCodeOptions { + return { + ConvertTabsToSpaces: options.insertSpaces, + TabSize: options.tabSize, + IndentSize: options.tabSize, + IndentStyle: IndentStyle.Smart, + NewLineCharacter: '\n', + InsertSpaceAfterCommaDelimiter: true, + InsertSpaceAfterSemicolonInForStatements: true, + InsertSpaceBeforeAndAfterBinaryOperators: true, + InsertSpaceAfterKeywordsInControlFlowStatements: true, + InsertSpaceAfterFunctionKeywordForAnonymousFunctions: true, + InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, + PlaceOpenBraceOnNewLineForControlBlocks: false, + PlaceOpenBraceOnNewLineForFunctions: false + }; + } + + protected _convertTextChanges( + model: editor.ITextModel, + change: ts.TextChange + ): languages.TextEdit { + return { + text: change.newText, + range: this._textSpanToRange(model, change.span) + }; + } +} + +export class FormatAdapter + extends FormatHelper + implements languages.DocumentRangeFormattingEditProvider +{ + public async provideDocumentRangeFormattingEdits( + model: editor.ITextModel, + range: Range, + options: languages.FormattingOptions, + token: CancellationToken + ): Promise { + const resource = model.uri; + const startOffset = model.getOffsetAt({ + lineNumber: range.startLineNumber, + column: range.startColumn + }); + const endOffset = model.getOffsetAt({ + lineNumber: range.endLineNumber, + column: range.endColumn + }); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const edits = await worker.getFormattingEditsForRange( + resource.toString(), + startOffset, + endOffset, + FormatHelper._convertOptions(options) + ); + + if (!edits || model.isDisposed()) { + return; + } + + return edits.map((edit) => this._convertTextChanges(model, edit)); + } +} + +export class FormatOnTypeAdapter + extends FormatHelper + implements languages.OnTypeFormattingEditProvider +{ + get autoFormatTriggerCharacters() { + return [';', '}', '\n']; + } + + public async provideOnTypeFormattingEdits( + model: editor.ITextModel, + position: Position, + ch: string, + options: languages.FormattingOptions, + token: CancellationToken + ): Promise { + const resource = model.uri; + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const edits = await worker.getFormattingEditsAfterKeystroke( + resource.toString(), + offset, + ch, + FormatHelper._convertOptions(options) + ); + + if (!edits || model.isDisposed()) { + return; + } + + return edits.map((edit) => this._convertTextChanges(model, edit)); + } +} + +// --- code actions ------ + +export class CodeActionAdaptor extends FormatHelper implements languages.CodeActionProvider { + public async provideCodeActions( + model: editor.ITextModel, + range: Range, + context: languages.CodeActionContext, + token: CancellationToken + ): Promise { + const resource = model.uri; + const start = model.getOffsetAt({ + lineNumber: range.startLineNumber, + column: range.startColumn + }); + const end = model.getOffsetAt({ + lineNumber: range.endLineNumber, + column: range.endColumn + }); + const formatOptions = FormatHelper._convertOptions(model.getOptions()); + const errorCodes = context.markers + .filter((m) => m.code) + .map((m) => m.code) + .map(Number); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const codeFixes = await worker.getCodeFixesAtPosition( + resource.toString(), + start, + end, + errorCodes, + formatOptions + ); + + if (!codeFixes || model.isDisposed()) { + return { actions: [], dispose: () => {} }; + } + + const actions = codeFixes + .filter((fix) => { + // Removes any 'make a new file'-type code fix + return fix.changes.filter((change) => change.isNewFile).length === 0; + }) + .map((fix) => { + return this._tsCodeFixActionToMonacoCodeAction(model, context, fix); + }); + + return { + actions: actions, + dispose: () => {} + }; + } + + private _tsCodeFixActionToMonacoCodeAction( + model: editor.ITextModel, + context: languages.CodeActionContext, + codeFix: ts.CodeFixAction + ): languages.CodeAction { + const edits: languages.WorkspaceTextEdit[] = []; + for (const change of codeFix.changes) { + for (const textChange of change.textChanges) { + edits.push({ + resource: model.uri, + edit: { + range: this._textSpanToRange(model, textChange.span), + text: textChange.newText + } + }); + } + } + + const action: languages.CodeAction = { + title: codeFix.description, + edit: { edits: edits }, + diagnostics: context.markers, + kind: 'quickfix' + }; + + return action; + } +} +// --- rename ---- + +export class RenameAdapter extends Adapter implements languages.RenameProvider { + constructor( + private readonly _libFiles: LibFiles, + worker: (...uris: Uri[]) => Promise + ) { + super(worker); + } + public async provideRenameEdits( + model: editor.ITextModel, + position: Position, + newName: string, + token: CancellationToken + ): Promise<(languages.WorkspaceEdit & languages.Rejection) | undefined> { + const resource = model.uri; + const fileName = resource.toString(); + const offset = model.getOffsetAt(position); + const worker = await this._worker(resource); + + if (model.isDisposed()) { + return; + } + + const renameInfo = await worker.getRenameInfo(fileName, offset, { + allowRenameOfImportPath: false + }); + if (renameInfo.canRename === false) { + // use explicit comparison so that the discriminated union gets resolved properly + return { + edits: [], + rejectReason: renameInfo.localizedErrorMessage + }; + } + if (renameInfo.fileToRename !== undefined) { + throw new Error('Renaming files is not supported.'); + } + + const renameLocations = await worker.findRenameLocations( + fileName, + offset, + /*strings*/ false, + /*comments*/ false, + /*prefixAndSuffix*/ false + ); + + if (!renameLocations || model.isDisposed()) { + return; + } + + const edits: languages.WorkspaceTextEdit[] = []; + for (const renameLocation of renameLocations) { + const model = this._libFiles.getOrCreateModel(renameLocation.fileName); + if (model) { + edits.push({ + resource: model.uri, + edit: { + range: this._textSpanToRange(model, renameLocation.textSpan), + text: newName + } + }); + } else { + throw new Error(`Unknown file ${renameLocation.fileName}.`); + } + } + + return { edits }; + } +} + +// --- inlay hints ---- + +export class InlayHintsAdapter extends Adapter implements languages.InlayHintsProvider { + public async provideInlayHints( + model: editor.ITextModel, + range: Range, + token: CancellationToken + ): Promise { + const resource = model.uri; + const fileName = resource.toString(); + const start = model.getOffsetAt({ + lineNumber: range.startLineNumber, + column: range.startColumn + }); + const end = model.getOffsetAt({ + lineNumber: range.endLineNumber, + column: range.endColumn + }); + const worker = await this._worker(resource); + if (model.isDisposed()) { + return []; + } + + const hints = await worker.provideInlayHints(fileName, start, end); + + return hints.map((hint) => { + return { + ...hint, + position: model.getPositionAt(hint.position), + kind: this._convertHintKind(hint.kind) + }; + }); + } + + private _convertHintKind(kind?: ts.InlayHintKind) { + switch (kind) { + case 'Parameter': + return languages.InlayHintKind.Parameter; + case 'Type': + return languages.InlayHintKind.Type; + default: + return languages.InlayHintKind.Other; + } + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-lib-lib.index.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-lib-lib.index.ts.txt new file mode 100644 index 000000000..a501460f0 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-lib-lib.index.ts.txt @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// +// **NOTE**: Do not edit directly! This file is generated using `npm run import-typescript` +// + + +/** Contains all the lib files */ +export const libFileSet: Record = {} +libFileSet['lib.d.ts'] = true; +libFileSet['lib.dom.d.ts'] = true; +libFileSet['lib.dom.iterable.d.ts'] = true; +libFileSet['lib.es2015.collection.d.ts'] = true; +libFileSet['lib.es2015.core.d.ts'] = true; +libFileSet['lib.es2015.d.ts'] = true; +libFileSet['lib.es2015.generator.d.ts'] = true; +libFileSet['lib.es2015.iterable.d.ts'] = true; +libFileSet['lib.es2015.promise.d.ts'] = true; +libFileSet['lib.es2015.proxy.d.ts'] = true; +libFileSet['lib.es2015.reflect.d.ts'] = true; +libFileSet['lib.es2015.symbol.d.ts'] = true; +libFileSet['lib.es2015.symbol.wellknown.d.ts'] = true; +libFileSet['lib.es2016.array.include.d.ts'] = true; +libFileSet['lib.es2016.d.ts'] = true; +libFileSet['lib.es2016.full.d.ts'] = true; +libFileSet['lib.es2017.d.ts'] = true; +libFileSet['lib.es2017.full.d.ts'] = true; +libFileSet['lib.es2017.intl.d.ts'] = true; +libFileSet['lib.es2017.object.d.ts'] = true; +libFileSet['lib.es2017.sharedmemory.d.ts'] = true; +libFileSet['lib.es2017.string.d.ts'] = true; +libFileSet['lib.es2017.typedarrays.d.ts'] = true; +libFileSet['lib.es2018.asyncgenerator.d.ts'] = true; +libFileSet['lib.es2018.asynciterable.d.ts'] = true; +libFileSet['lib.es2018.d.ts'] = true; +libFileSet['lib.es2018.full.d.ts'] = true; +libFileSet['lib.es2018.intl.d.ts'] = true; +libFileSet['lib.es2018.promise.d.ts'] = true; +libFileSet['lib.es2018.regexp.d.ts'] = true; +libFileSet['lib.es2019.array.d.ts'] = true; +libFileSet['lib.es2019.d.ts'] = true; +libFileSet['lib.es2019.full.d.ts'] = true; +libFileSet['lib.es2019.object.d.ts'] = true; +libFileSet['lib.es2019.string.d.ts'] = true; +libFileSet['lib.es2019.symbol.d.ts'] = true; +libFileSet['lib.es2020.bigint.d.ts'] = true; +libFileSet['lib.es2020.d.ts'] = true; +libFileSet['lib.es2020.full.d.ts'] = true; +libFileSet['lib.es2020.intl.d.ts'] = true; +libFileSet['lib.es2020.promise.d.ts'] = true; +libFileSet['lib.es2020.sharedmemory.d.ts'] = true; +libFileSet['lib.es2020.string.d.ts'] = true; +libFileSet['lib.es2020.symbol.wellknown.d.ts'] = true; +libFileSet['lib.es2021.d.ts'] = true; +libFileSet['lib.es2021.full.d.ts'] = true; +libFileSet['lib.es2021.promise.d.ts'] = true; +libFileSet['lib.es2021.string.d.ts'] = true; +libFileSet['lib.es2021.weakref.d.ts'] = true; +libFileSet['lib.es5.d.ts'] = true; +libFileSet['lib.es6.d.ts'] = true; +libFileSet['lib.esnext.d.ts'] = true; +libFileSet['lib.esnext.full.d.ts'] = true; +libFileSet['lib.esnext.intl.d.ts'] = true; +libFileSet['lib.esnext.promise.d.ts'] = true; +libFileSet['lib.esnext.string.d.ts'] = true; +libFileSet['lib.esnext.weakref.d.ts'] = true; +libFileSet['lib.scripthost.d.ts'] = true; +libFileSet['lib.webworker.d.ts'] = true; +libFileSet['lib.webworker.importscripts.d.ts'] = true; +libFileSet['lib.webworker.iterable.d.ts'] = true; diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsMode.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsMode.ts.txt new file mode 100644 index 000000000..9ebf59cf6 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsMode.ts.txt @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { WorkerManager } from './workerManager'; +import type { TypeScriptWorker } from './tsWorker'; +import { LanguageServiceDefaults } from './monaco.contribution'; +import * as languageFeatures from './languageFeatures'; +import { languages, Uri } from './fillers/monaco-editor-core'; + +let javaScriptWorker: (...uris: Uri[]) => Promise; +let typeScriptWorker: (...uris: Uri[]) => Promise; + +export function setupTypeScript(defaults: LanguageServiceDefaults): void { + typeScriptWorker = setupMode(defaults, 'typescript'); +} + +export function setupJavaScript(defaults: LanguageServiceDefaults): void { + javaScriptWorker = setupMode(defaults, 'javascript'); +} + +export function getJavaScriptWorker(): Promise<(...uris: Uri[]) => Promise> { + return new Promise((resolve, reject) => { + if (!javaScriptWorker) { + return reject('JavaScript not registered!'); + } + + resolve(javaScriptWorker); + }); +} + +export function getTypeScriptWorker(): Promise<(...uris: Uri[]) => Promise> { + return new Promise((resolve, reject) => { + if (!typeScriptWorker) { + return reject('TypeScript not registered!'); + } + + resolve(typeScriptWorker); + }); +} + +function setupMode( + defaults: LanguageServiceDefaults, + modeId: string +): (...uris: Uri[]) => Promise { + const client = new WorkerManager(modeId, defaults); + const worker = (...uris: Uri[]): Promise => { + return client.getLanguageServiceWorker(...uris); + }; + + const libFiles = new languageFeatures.LibFiles(worker); + + languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker)); + languages.registerSignatureHelpProvider( + modeId, + new languageFeatures.SignatureHelpAdapter(worker) + ); + languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker)); + languages.registerDocumentHighlightProvider( + modeId, + new languageFeatures.OccurrencesAdapter(worker) + ); + languages.registerDefinitionProvider( + modeId, + new languageFeatures.DefinitionAdapter(libFiles, worker) + ); + languages.registerReferenceProvider( + modeId, + new languageFeatures.ReferenceAdapter(libFiles, worker) + ); + languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker)); + languages.registerDocumentRangeFormattingEditProvider( + modeId, + new languageFeatures.FormatAdapter(worker) + ); + languages.registerOnTypeFormattingEditProvider( + modeId, + new languageFeatures.FormatOnTypeAdapter(worker) + ); + languages.registerCodeActionProvider(modeId, new languageFeatures.CodeActionAdaptor(worker)); + languages.registerRenameProvider(modeId, new languageFeatures.RenameAdapter(libFiles, worker)); + languages.registerInlayHintsProvider(modeId, new languageFeatures.InlayHintsAdapter(worker)); + new languageFeatures.DiagnosticsAdapter(libFiles, defaults, modeId, worker); + return worker; +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsconfig.json.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsconfig.json.txt new file mode 100644 index 000000000..001f587e6 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-tsconfig.json.txt @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "amd", + "moduleResolution": "node", + "outDir": "../out/amd", + "declaration": true, + "target": "es5", + "lib": ["dom", "es5", "es2015.collection", "es2015.iterable", "es2015.promise"], + "strict": true + } +} diff --git a/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-workerManager.ts.txt b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-workerManager.ts.txt new file mode 100644 index 000000000..6e70ae025 --- /dev/null +++ b/refactor/baselines/site-vendor/monaco-modes/monaco-typescript-src-workerManager.ts.txt @@ -0,0 +1,114 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { LanguageServiceDefaults } from './monaco.contribution'; +import type { TypeScriptWorker } from './tsWorker'; +import { editor, Uri, IDisposable } from './fillers/monaco-editor-core'; + +export class WorkerManager { + private _modeId: string; + private _defaults: LanguageServiceDefaults; + private _configChangeListener: IDisposable; + private _updateExtraLibsToken: number; + private _extraLibsChangeListener: IDisposable; + + private _worker: editor.MonacoWebWorker | null; + private _client: Promise | null; + + constructor(modeId: string, defaults: LanguageServiceDefaults) { + this._modeId = modeId; + this._defaults = defaults; + this._worker = null; + this._client = null; + this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker()); + this._updateExtraLibsToken = 0; + this._extraLibsChangeListener = this._defaults.onDidExtraLibsChange(() => + this._updateExtraLibs() + ); + } + + private _stopWorker(): void { + if (this._worker) { + this._worker.dispose(); + this._worker = null; + } + this._client = null; + } + + dispose(): void { + this._configChangeListener.dispose(); + this._extraLibsChangeListener.dispose(); + this._stopWorker(); + } + + private async _updateExtraLibs(): Promise { + if (!this._worker) { + return; + } + const myToken = ++this._updateExtraLibsToken; + const proxy = await this._worker.getProxy(); + if (this._updateExtraLibsToken !== myToken) { + // avoid multiple calls + return; + } + proxy.updateExtraLibs(this._defaults.getExtraLibs()); + } + + private _getClient(): Promise { + if (!this._client) { + this._worker = editor.createWebWorker({ + // module that exports the create() method and returns a `TypeScriptWorker` instance + moduleId: 'vs/language/typescript/tsWorker', + + label: this._modeId, + + keepIdleModels: true, + + // passed in to the create() method + createData: { + compilerOptions: this._defaults.getCompilerOptions(), + extraLibs: this._defaults.getExtraLibs(), + customWorkerPath: this._defaults.workerOptions.customWorkerPath, + inlayHintsOptions: this._defaults.inlayHintsOptions + } + }); + + let p = >this._worker.getProxy(); + + if (this._defaults.getEagerModelSync()) { + p = p.then((worker) => { + if (this._worker) { + return this._worker.withSyncedResources( + editor + .getModels() + .filter((model) => model.getLanguageId() === this._modeId) + .map((model) => model.uri) + ); + } + return worker; + }); + } + + this._client = p; + } + + return this._client; + } + + getLanguageServiceWorker(...resources: Uri[]): Promise { + let _client: TypeScriptWorker; + return this._getClient() + .then((client) => { + _client = client; + }) + .then((_) => { + if (this._worker) { + return this._worker.withSyncedResources(resources); + } + }) + .then((_) => _client); + } +} diff --git a/refactor/changes/2026-09-15-SITE-07-monaco-modes.md b/refactor/changes/2026-09-15-SITE-07-monaco-modes.md new file mode 100644 index 000000000..c776a93f1 --- /dev/null +++ b/refactor/changes/2026-09-15-SITE-07-monaco-modes.md @@ -0,0 +1,45 @@ +# SITE-07 Monaco 四种语言模式来源与编辑器集成 + +修改前 HEAD:99c208aeee331eec2d9ffa9bb15a608fdc17a840。 +Thumbnail 默认策略仍待用户选择,本批不改变该包的配置。 + +## 本批实现 + +新增四个 mode bundle 的固定来源记录及可重复执行脚本。六份 npm 归档、23 份 +固定 Git 文件包含构建配方、配置、14 个 Monaco TS 模块与六个依赖源码;另有 +两个包别名。CSS/HTML/JSON/TypeScript 分别有 5/5/12/4 个模块实例。复用全片段 +检查覆盖辅助代码和模块之间所有非空白字节,不只比较 AMD 模块名。 +四个完整压缩产物均与当前站点逐字节相等。 + +抽出 compiler.ts 统一固定 TypeScript 4.4.4 发射,保持原标准库与各包 strict +配置。JSON tokenization 使用 jsonc-parser 3.0.0 原始声明解析 const enum;孤立 +编译保留属性访问不能复现旧产物,因此不能手工替换数字。解析器仅允许显式 +传入的声明,不意外读当前工作区依赖。仍不声称已恢复上游完整语义类型检查。 + +AMD 模块名增加合法 lib.index 支持,继续拒绝路径遍历段。新反例验证错误枚举 +声明会导致复现失败;此前 TypeScript 源转换和缺失模块/额外辅助代码测试保留。 +共享编译器改动后重跑全部三个语言 worker 源码及压缩复现,保持精确相等。 + +jsonc-parser 与 vscode-languageserver-types 的 notice 资产绑定扩大到模式文件。 +这两包原有完整许可已随站点交付,没有新增或改写 notice 正文。站点依然有 +81 份 notice 加一个索引。Monaco 运行代码、旧 URL、根依赖和 yarn.lock 未变。 + +## 实际编辑器验证 + +新增 editor-modes.spec.js 使用真实 Monaco editor,通过自动模式加载和 provider +注册检测 CSS/JSON/TypeScript 错误,再改成合法代码等待诊断清空。调用编辑器的 +文档格式化 action 验证 JSON/HTML 输出分行且内容保留;四个 mode 请求必须成功。 +同一个编辑器依次切换模型,最后销毁并检查旧模型诊断被清理。 + +早期测试读取了不属于 0.30.1 的 getModeId;对照该包原始声明后使用 getLanguageId。 +这是测试元数据接口修正,没有改生产逻辑或放宽诊断/格式化断言。 + +三引擎 3/3 通过,无重试/跳过;15/15 单元、严格 docs-tools 类型与相关 lint +通过。来源复现、网络尝试和浏览器环境见 +[验证记录](../baselines/monaco-modes-validation.json)。网络首次请求出现 npm DNS +ENOTFOUND,保留失败记录;缓存离线验证不被冒充为首次联网成功。 + +SITE-07 doing / VENDOR-06 open,整体仍 199/265。Monaco editor-core、基础语言 +定义及其余上游来源细节继续审查,物理设备/外部 SDK/远端 CI/三轮复盘门槛 +未完成。回退本批脚本、绑定和测试即可,运行资产未改。独立本地提交,不推送、 +不部署、不发布,也不替用户决定 Thumbnail 默认行为。 diff --git a/refactor/plan.md b/refactor/plan.md index e0a8cfe45..46430ec35 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -653,7 +653,7 @@ - SITE-AI-DOCS-01: [记录](changes/2026-09-14-SITE-AI-DOCS-01-documentation-pipeline.md) [记录](baselines/documentation-pipeline-validation.json) - SITE-BUILD-01: [记录](changes/2026-09-14-SITE-BUILD-01-staged-builds.md) [记录](baselines/site-build-validation.json) - SITE-03: [记录](changes/2026-09-14-SITE-03-desktop-editor.md) [记录](baselines/site-editor-validation.json) -- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json) [记录](changes/2026-09-14-SITE-07-vendor-notices.md) [记录](baselines/site-notices-checkpoint.json) [记录](baselines/site-codicons-provenance.json) [记录](baselines/site-codicons-validation.json) [记录](changes/2026-09-15-SITE-07-codicons.md) [记录](baselines/vconsole-notices-provenance.json) [记录](baselines/vconsole-notices-validation.json) [记录](changes/2026-09-15-SITE-07-vconsole-notices.md) [记录](console-modernization.md) [记录](baselines/site-console-inventory.json) [记录](baselines/site-console-validation.json) [记录](changes/2026-09-15-SITE-07-console-baseline.md) [记录](baselines/console-feed-provenance.json) [记录](changes/2026-09-15-SITE-07-console-feed-source.md) [记录](baselines/console-commonjs-provenance.json) [记录](changes/2026-09-15-SITE-07-console-commonjs.md) [记录](baselines/console-esm-provenance.json) [记录](changes/2026-09-15-SITE-07-console-esm.md) [记录](baselines/console-embedded-notices.json) [记录](baselines/console-notices-validation.json) [记录](changes/2026-09-15-SITE-07-console-notices.md) [记录](baselines/console-embedded-sources.json) [记录](baselines/console-embedded-validation.json) [记录](changes/2026-09-15-SITE-07-console-embedded-sources.md) [记录](baselines/console-derived-attribution.json) [记录](baselines/console-derived-validation.json) [记录](changes/2026-09-15-SITE-07-console-derived-attribution.md) [记录](baselines/console-stackoverflow-provenance.json) [记录](baselines/console-stackoverflow-validation.json) [记录](changes/2026-09-15-SITE-07-console-stackoverflow.md) [记录](baselines/console-shallowequal-validation.json) [记录](changes/2026-09-15-SITE-07-console-shallowequal.md) [记录](console-notice-review.md) [记录](baselines/console-notice-review-validation.json) [记录](changes/2026-09-15-SITE-07-console-notice-review.md) [记录](baselines/monaco-typescript-provenance.json) [记录](baselines/monaco-typescript-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-typescript.md) [记录](baselines/monaco-languages-provenance.json) [记录](baselines/monaco-languages-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-languages.md) [记录](baselines/monaco-language-notices.json) [记录](baselines/monaco-language-notices-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-language-notices.md) +- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json) [记录](changes/2026-09-14-SITE-07-vendor-notices.md) [记录](baselines/site-notices-checkpoint.json) [记录](baselines/site-codicons-provenance.json) [记录](baselines/site-codicons-validation.json) [记录](changes/2026-09-15-SITE-07-codicons.md) [记录](baselines/vconsole-notices-provenance.json) [记录](baselines/vconsole-notices-validation.json) [记录](changes/2026-09-15-SITE-07-vconsole-notices.md) [记录](console-modernization.md) [记录](baselines/site-console-inventory.json) [记录](baselines/site-console-validation.json) [记录](changes/2026-09-15-SITE-07-console-baseline.md) [记录](baselines/console-feed-provenance.json) [记录](changes/2026-09-15-SITE-07-console-feed-source.md) [记录](baselines/console-commonjs-provenance.json) [记录](changes/2026-09-15-SITE-07-console-commonjs.md) [记录](baselines/console-esm-provenance.json) [记录](changes/2026-09-15-SITE-07-console-esm.md) [记录](baselines/console-embedded-notices.json) [记录](baselines/console-notices-validation.json) [记录](changes/2026-09-15-SITE-07-console-notices.md) [记录](baselines/console-embedded-sources.json) [记录](baselines/console-embedded-validation.json) [记录](changes/2026-09-15-SITE-07-console-embedded-sources.md) [记录](baselines/console-derived-attribution.json) [记录](baselines/console-derived-validation.json) [记录](changes/2026-09-15-SITE-07-console-derived-attribution.md) [记录](baselines/console-stackoverflow-provenance.json) [记录](baselines/console-stackoverflow-validation.json) [记录](changes/2026-09-15-SITE-07-console-stackoverflow.md) [记录](baselines/console-shallowequal-validation.json) [记录](changes/2026-09-15-SITE-07-console-shallowequal.md) [记录](console-notice-review.md) [记录](baselines/console-notice-review-validation.json) [记录](changes/2026-09-15-SITE-07-console-notice-review.md) [记录](baselines/monaco-typescript-provenance.json) [记录](baselines/monaco-typescript-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-typescript.md) [记录](baselines/monaco-languages-provenance.json) [记录](baselines/monaco-languages-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-languages.md) [记录](baselines/monaco-language-notices.json) [记录](baselines/monaco-language-notices-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-language-notices.md) [记录](baselines/monaco-modes-provenance.json) [记录](baselines/monaco-modes-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-modes.md) - EX-01: [记录](changes/2026-09-14-EX-01-react-consumer.md) [记录](baselines/react-consumer-validation.json) [记录](scripts/react-consumer.mjs) - EX-02: [记录](changes/2026-09-14-EX-02-vue-consumer.md) [记录](baselines/vue-consumer-validation.json) [记录](scripts/vue-consumer.mjs) - MOD-01: [记录](changes/2026-09-15-MOD-01-bun-evaluation.md) [记录](baselines/bun-install-validation.json) [记录](bun-evaluation.md) diff --git a/refactor/progress.md b/refactor/progress.md index bed2fcf36..6c2e4f1b9 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,14 @@ # 进度与证据 +## SITE-07 Monaco 四种语言模式 + +CSS/HTML/JSON/TypeScript mode 的 26 个模块实例及完整压缩产物已精确复现, +使用 6 归档/23 Git 来源,jsonc 原声明驱动 const enum 编译;许可绑定补齐模式 +资产。单元 15/15,自动编辑器诊断/格式化/切换/销毁三引擎 3/3,三个 worker +共享编译器回归复现通过。联网首次 DNS 失败后重试成功,离线复现独立通过。 +见[记录](changes/2026-09-15-SITE-07-monaco-modes.md)。运行/notice 字节与锁未变, +199/265,SITE-07/VENDOR-06 仍开放;Thumbnail 默认决策仍待答。 + ## PKG-TOOL-THUMB-04 默认兼容策略待选择 重新核对恢复的 3.5.31 与工作区 4.4.0,历史契约/行为 62/62 通过。已将先前待答 diff --git a/refactor/risks.json b/refactor/risks.json index 8bb862c17..5b1ce6ef2 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -638,11 +638,16 @@ "refactor/baselines/monaco-language-notices.json", "refactor/baselines/monaco-language-notices-validation.json", "refactor/changes/2026-09-15-SITE-07-monaco-language-notices.md", - "scripts/site-vendor/monaco/notices.ts" + "scripts/site-vendor/monaco/notices.ts", + "refactor/baselines/monaco-modes-provenance.json", + "refactor/baselines/monaco-modes-validation.json", + "refactor/changes/2026-09-15-SITE-07-monaco-modes.md", + "scripts/site-vendor/monaco/compiler.ts", + "scripts/site-vendor/monaco/reproduce-modes.ts" ], "compatibleResolution": "Keep separate from owned TS migration. Verify source/version/diff and license notices before replacement; preserve API/CSS/worker URLs and run owning package tests.", "closureCriteria": "固定上游版本/内容差异、完整组件许可与分发 notices,兼容测试通过;仅当前上游许可证名称不足以关闭。", - "workspaceState": "Monaco 0.30.1 TypeScript worker identifies 4.4.4, unlike the original stale 2.7.2 notice. Fixed Git lock/recipes and four archives prove the 9698327-character adapted service segment and exact minified worker. Three original TypeScript notices plus a version/modification explanation are delivered. Unit 10/10 and three-engine editor/notice checks 6/6 pass. Other language services, shim, core embedded libraries and language definitions remain under review; VENDOR-06 is open. CSS/HTML/JSON complete workers now have exact source coverage for 119 module instances from 91 npm sources, 8 aliases, a shared Monaco-owned nls shim and three adapters; 11 archives/13 Git sources and all three minified outputs match. Four unit tests and three real-engine diagnostics/completion/formatting checks pass. Service notices, embedded attribution, mode bundles, core and basic languages remain open. Seven language-service packages now deliver nine original notices, two complete formatter source headers and attribution. JSON glob BSD terms and the HTML formatter author-year difference are preserved. Component/source/notice bindings and all 81 site notice HTTP bytes/links pass; unit 14/14 and three-engine language/mobile suites 6/6. Broader Monaco origin review remains open." + "workspaceState": "Monaco 0.30.1 TypeScript worker identifies 4.4.4, unlike the original stale 2.7.2 notice. Fixed Git lock/recipes and four archives prove the 9698327-character adapted service segment and exact minified worker. Three original TypeScript notices plus a version/modification explanation are delivered. Unit 10/10 and three-engine editor/notice checks 6/6 pass. Other language services, shim, core embedded libraries and language definitions remain under review; VENDOR-06 is open. CSS/HTML/JSON complete workers now have exact source coverage for 119 module instances from 91 npm sources, 8 aliases, a shared Monaco-owned nls shim and three adapters; 11 archives/13 Git sources and all three minified outputs match. Four unit tests and three real-engine diagnostics/completion/formatting checks pass. Service notices, embedded attribution, mode bundles, core and basic languages remain open. Seven language-service packages now deliver nine original notices, two complete formatter source headers and attribution. JSON glob BSD terms and the HTML formatter author-year difference are preserved. Component/source/notice bindings and all 81 site notice HTTP bytes/links pass; unit 14/14 and three-engine language/mobile suites 6/6. Broader Monaco origin review remains open. All four mode bundles now reproduce exactly from 14 Monaco sources, 6 npm modules and 2 aliases (26 instances), with 6 archives/23 Git files. jsonc-parser declarations drive const enum emission; mode assets are included in license bindings. Automatic editor diagnostics/formatting/model-switch/cleanup checks pass in three engines, unit 15/15 and all three worker source regressions pass. Core/basic-language and remaining origin review remain open." }, { "id": "VENDOR-07", diff --git a/refactor/tasks.json b/refactor/tasks.json index 1d104f78a..e875e1101 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -4522,7 +4522,10 @@ "changes/2026-09-15-SITE-07-monaco-languages.md", "baselines/monaco-language-notices.json", "baselines/monaco-language-notices-validation.json", - "changes/2026-09-15-SITE-07-monaco-language-notices.md" + "changes/2026-09-15-SITE-07-monaco-language-notices.md", + "baselines/monaco-modes-provenance.json", + "baselines/monaco-modes-validation.json", + "changes/2026-09-15-SITE-07-monaco-modes.md" ] }, { diff --git a/refactor/third-party.json b/refactor/third-party.json index b7bd7cae3..df9a8ba54 100644 --- a/refactor/third-party.json +++ b/refactor/third-party.json @@ -512,7 +512,7 @@ "SITE-05" ], "sourceStatus": "Monaco 0.30.1 verified against official npm archive: 98 byte-exact files, one CSS newline-only difference. The bundled font additionally matches @vscode/codicons 0.0.26 exactly; see site-codicons-provenance.json.", - "licenseStatus": "Full Monaco root notices and Codicons historical notices are delivered. The actual TypeScript 4.4.4 worker is exactly reproduced and has a complete original LICENSE/CopyrightNotice/ThirdPartyNoticeText supplement plus attribution; the original stale 2.7.2 label is preserved with explanation. Other bundled-component completeness remains under VENDOR-06. No permission for unrelated fonts/media is inferred. CSS/HTML/JSON worker source proof now binds seven service packages to nine original license/third-party notice files, two embedded formatter headers and attribution. JSON glob BSD conditions and actual formatter author years are retained; all 81 site notices pass HTTP byte checks. Mode/core/basic-language and remaining embedded-source completeness stay open.", + "licenseStatus": "Full Monaco root notices and Codicons historical notices are delivered. The actual TypeScript 4.4.4 worker is exactly reproduced and has a complete original LICENSE/CopyrightNotice/ThirdPartyNoticeText supplement plus attribution; the original stale 2.7.2 label is preserved with explanation. Other bundled-component completeness remains under VENDOR-06. No permission for unrelated fonts/media is inferred. CSS/HTML/JSON worker source proof now binds seven service packages to nine original license/third-party notice files, two embedded formatter headers and attribution. JSON glob BSD conditions and actual formatter author years are retained; all 81 site notices pass HTTP byte checks. Mode/core/basic-language and remaining embedded-source completeness stay open. All four language mode bundles are now exactly reproduced and the two shared npm dependencies are bound to those mode assets as well as workers. Core/basic-language and remaining upstream-origin review stay open.", "upstreamSources": [ "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.26.tgz" diff --git a/scripts/site-vendor/manifest.json b/scripts/site-vendor/manifest.json index be4976978..305277428 100644 --- a/scripts/site-vendor/manifest.json +++ b/scripts/site-vendor/manifest.json @@ -1037,7 +1037,8 @@ "version": "3.0.0", "tarball": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", "assets": [ - "docs/assets/js/vs/language/json/jsonWorker.js" + "docs/assets/js/vs/language/json/jsonWorker.js", + "docs/assets/js/vs/language/json/jsonMode.js" ], "notices": [ "docs/licenses/monaco-editor/language-services/jsonc-parser/LICENSE.md", @@ -1103,7 +1104,10 @@ "assets": [ "docs/assets/js/vs/language/css/cssWorker.js", "docs/assets/js/vs/language/html/htmlWorker.js", - "docs/assets/js/vs/language/json/jsonWorker.js" + "docs/assets/js/vs/language/json/jsonWorker.js", + "docs/assets/js/vs/language/css/cssMode.js", + "docs/assets/js/vs/language/html/htmlMode.js", + "docs/assets/js/vs/language/json/jsonMode.js" ], "notices": [ "docs/licenses/monaco-editor/language-services/vscode-languageserver-types/License.txt", diff --git a/scripts/site-vendor/monaco/README.md b/scripts/site-vendor/monaco/README.md index fe1bddb99..4d9ba55b9 100644 --- a/scripts/site-vendor/monaco/README.md +++ b/scripts/site-vendor/monaco/README.md @@ -80,6 +80,35 @@ disposes both workers and models. Monaco 0.30.1 has no public CSS/HTML/JSON work getter equivalent to `getTypeScriptWorker`. Tests exercise valid/invalid CSS and JSON, HTML tag completion, document symbols, and HTML/JSON formatting on three engines. +## Mode registration bundles + +`reproduce-modes.ts` covers cssMode, htmlMode, jsonMode and tsMode. The fixed record +has six archives, 23 Git files, 14 Monaco sources, six npm source modules and two +package aliases. All 26 module instances and intervening helper bytes match the +development bundles; their four complete minified outputs match existing assets. +`jsonc-parser` and `vscode-languageserver-types` notice bindings include these mode +assets as well as workers. No runtime or notice text is rewritten. + +`compiler.ts` shares pinned TypeScript emission with the worker reproducer. +JSON tokenization needs the original jsonc-parser 3.0.0 main.d.ts to inline const +enums. The compiler host resolves only explicitly supplied declarations, avoiding +accidental resolution against current root dependencies. Module names may contain +a dot (`lib.index`); traversal segments remain rejected. TypeScript mode compilation +uses the fixed strict config. Exact emission is not a complete upstream typecheck. + +```sh +yarn verify:monaco-mode-sources --fetch +yarn verify:monaco-mode-sources +yarn verify:monaco-language-sources +yarn test:browser test/browser/editor-modes.spec.js --workers=1 +``` + +`editor-modes.spec.js` uses a real editor, automatic mode loading/provider registration +and model switching. CSS/JSON/TypeScript errors appear and clear after correction; +the editor's document-format action formats JSON/HTML while preserving content. +All four mode URLs must return 200; disposed models must lose their diagnostics. +This complements direct worker methods and the typed player test. + ## Language-service notices `monaco-language-notices.json` binds seven verified package versions to their nine @@ -99,7 +128,7 @@ ranges. Preserve raw bytes and the `-text` Git attributes for frozen/output noti 12 relative links, alongside mobile player playback and console cleanup. This does not close all Monaco embedded-source review. Core embedded libraries, -mode bundles, language definitions and remaining upstream data/origin details stay +language definitions and remaining upstream data/origin details stay under VENDOR-06. Revalidate editor-types and site-vendor tests when changing declarations or delivered notices. Whole-site, physical-device and remote release gates remain separate. diff --git a/scripts/site-vendor/monaco/compiler.ts b/scripts/site-vendor/monaco/compiler.ts new file mode 100644 index 000000000..cc7c48fb9 --- /dev/null +++ b/scripts/site-vendor/monaco/compiler.ts @@ -0,0 +1,34 @@ +import assert from 'node:assert/strict' + +export interface CompilerModule { name: string, source: string } + +// Reproduce emission with pinned standard libraries and optional verified module +// declarations. This is intentionally not a full upstream semantic typecheck. +export function emitAmd(ts: typeof import('typescript'), source: string, libraries: string[], strict = false, modules: CompilerModule[] = []): string { + const options: import('typescript').CompilerOptions = { + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.AMD, + newLine: ts.NewLineKind.LineFeed, + noResolve: modules.length === 0, + lib: libraries.map(library => `lib.${library}.d.ts`), + strict, + } + const host = ts.createCompilerHost(options) + const getSourceFile = host.getSourceFile.bind(host) + const inputs = new Map([['worker.ts', source], ...modules.map((module, index): [string, string] => [`pinned-${index}.d.ts`, module.source])]) + host.getSourceFile = (file, languageVersion, onError, createNew) => inputs.has(file) + ? ts.createSourceFile(file, inputs.get(file)!, languageVersion, true) + : getSourceFile(file, languageVersion, onError, createNew) + host.resolveModuleNames = names => names.map((name) => { + const index = modules.findIndex(module => module.name === name) + return index < 0 ? undefined : { resolvedFileName: `pinned-${index}.d.ts`, extension: ts.Extension.Dts } + }) + let output = '' + host.writeFile = (file, text) => { + assert(file.endsWith('.js') && !output, 'Unexpected compiler output') + output = text + } + const result = ts.createProgram(['worker.ts'], options, host).emit() + assert(!result.emitSkipped && output, 'Missing source emission') + return output +} diff --git a/scripts/site-vendor/monaco/languages.ts b/scripts/site-vendor/monaco/languages.ts index 1e2d0c54f..32d0d15b3 100644 --- a/scripts/site-vendor/monaco/languages.ts +++ b/scripts/site-vendor/monaco/languages.ts @@ -25,7 +25,7 @@ export function moduleIds(source: string): string[] { // RequireJS names one anonymous AMD definition and removes newline-ended maps. // Locate the call syntactically so comments/strings containing define( are inert. export function nameModule(source: string, id: string): string { - assert(/^[\w/-]+$/.test(id), 'Unexpected AMD identifier') + assert(/^[\w./-]+$/.test(id) && id.split('/').every(part => part !== '.' && part !== '..'), 'Unexpected AMD identifier') const calls = definitions(source) assert.equal(calls.length, 1, 'Expected one anonymous AMD definition') const call = calls[0]! @@ -70,7 +70,7 @@ export function verifyWorkerSources(worker: string, ids: string[], fragments: { } export function languageHeader(language: string): string { - assert(['css', 'html', 'json'].includes(language), 'Unexpected Monaco language') + assert(['css', 'html', 'json', 'typescript'].includes(language), 'Unexpected Monaco language') return `/*!----------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * monaco-${language} version: 0.30.1(5a7ba61be909ae9e4889768a3453ebb0dec392e2) diff --git a/scripts/site-vendor/monaco/notices.ts b/scripts/site-vendor/monaco/notices.ts index 2998ae2c5..1e3e42631 100644 --- a/scripts/site-vendor/monaco/notices.ts +++ b/scripts/site-vendor/monaco/notices.ts @@ -29,6 +29,7 @@ function readNotices(root: string): NoticeRecord { export function verifyMonacoLanguageNotices(root: string, manifest: VendorManifest): number { const record = readNotices(root) const sources: Sources = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/monaco-languages-provenance.json'), 'utf8')) + const modes: { files: Sources['workers'] } = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/monaco-modes-provenance.json'), 'utf8')) assert.equal(record.notices.length, 12, 'Missing Monaco language notice source') assert.equal(record.components.length, 9, 'Missing Monaco language component source') assert.deepEqual(record.packages.map(item => item.name).sort(), [...new Set(sources.modules.map(item => item.id.split('/')[0]))].sort(), 'Incomplete Monaco service attribution') @@ -38,7 +39,7 @@ export function verifyMonacoLanguageNotices(root: string, manifest: VendorManife const archive = sources.archives.find(item => `${item.name}-${item.version}` === pkg.archive) assert(archive && archive.name === pkg.name && archive.version === pkg.version && archive.tarball === pkg.tarball, 'Wrong Monaco service source identity') const modules = sources.modules.filter(item => item.archive === pkg.archive).map(item => item.id) - const assets = sources.workers.filter(worker => worker.ids.some(id => modules.includes(id))).map(worker => worker.target.path) + const assets = [...sources.workers, ...modes.files].filter(worker => worker.ids.some(id => modules.includes(id))).map(worker => worker.target.path) assert.deepEqual(pkg.assets, assets, 'Wrong Monaco service asset binding') } for (const expected of record.components) { diff --git a/scripts/site-vendor/monaco/reproduce-languages.ts b/scripts/site-vendor/monaco/reproduce-languages.ts index 78b037cfb..cf684ffcb 100644 --- a/scripts/site-vendor/monaco/reproduce-languages.ts +++ b/scripts/site-vendor/monaco/reproduce-languages.ts @@ -6,6 +6,7 @@ import path from 'node:path' import process from 'node:process' import { fileURLToPath } from 'node:url' import { ArchiveCache, hash } from './archives.ts' +import { emitAmd } from './compiler.ts' import { aliasModule, languageHeader, nameModule, verifyWorkerSources } from './languages.ts' import { verifyMonacoLanguageNoticeArchives } from './notices.ts' @@ -65,32 +66,7 @@ assert.equal(require('terser/package.json').version, '5.9.0', 'Wrong Terser comp assert.equal(require('source-map/package.json').version, '0.7.3', 'Wrong minifier dependency') -function compile(source: string): string { - // Emit with the real pinned standard libraries. Isolated transpileModule loses - // Promise type resolution and emits a different async helper argument here. - // Unresolved service imports are intentionally not a full upstream typecheck. - const options: import('typescript').CompilerOptions = { - target: ts.ScriptTarget.ES5, - module: ts.ModuleKind.AMD, - newLine: ts.NewLineKind.LineFeed, - noResolve: true, - lib: ['lib.es5.d.ts', 'lib.dom.d.ts', 'lib.es2015.collection.d.ts', 'lib.es2015.promise.d.ts', 'lib.es2015.iterable.d.ts'], - } - const host = ts.createCompilerHost(options) - const getSourceFile = host.getSourceFile.bind(host) - host.getSourceFile = (file, languageVersion, onError, createNew) => file === 'worker.ts' - ? ts.createSourceFile(file, source, languageVersion, true) - : getSourceFile(file, languageVersion, onError, createNew) - let output = '' - host.writeFile = (file, text) => { - assert(file.endsWith('.js') && !output, 'Unexpected compiler output') - output = text - } - const program = ts.createProgram(['worker.ts'], options, host) - const result = program.emit() - assert(!result.emitSkipped && output, 'Missing language source emission') - return output -} +const compile = (source: string) => emitAmd(ts, source, ['es5', 'dom', 'es2015.collection', 'es2015.promise', 'es2015.iterable']) const modules = new Map(record.modules.map(member => [member.id, nameModule(cache.member(member).toString('utf8'), member.id)])) const aliases = new Map(record.aliases.map(alias => [alias.id, aliasModule(alias.id, alias.main)])) const results = [] diff --git a/scripts/site-vendor/monaco/reproduce-modes.ts b/scripts/site-vendor/monaco/reproduce-modes.ts new file mode 100644 index 000000000..13fc471aa --- /dev/null +++ b/scripts/site-vendor/monaco/reproduce-modes.ts @@ -0,0 +1,81 @@ +import type { Archive, Member, Remote } from './archives.ts' +import assert from 'node:assert/strict' +import fs from 'node:fs' +import { createRequire } from 'node:module' +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { ArchiveCache, hash } from './archives.ts' +import { emitAmd } from './compiler.ts' +import { aliasModule, languageHeader, nameModule, verifyWorkerSources } from './languages.ts' + +interface Provenance { + archives: Archive[] + remotes: Remote[] + compilerMembers: Member[] + declaration: Member + npmModules: (Member & { id: string })[] + aliases: { id: string, main: string }[] + files: { + language: string + development: Member + target: { path: string, sha256: string } + ids: string[] + modules: { id: string, source: string, resolveJsonc: boolean }[] + config: string + }[] +} +const root = fileURLToPath(new URL('../../../', import.meta.url)) +assert(process.argv.slice(2).every(arg => arg === '--fetch'), 'Use reproduce-modes.ts [--fetch]') +assert.equal(process.version, `v${fs.readFileSync(path.join(root, '.node-version'), 'utf8').trim()}`, 'Use canonical Node') +const record: Provenance = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/monaco-modes-provenance.json'), 'utf8')) +assert.deepEqual(record.files.map(file => file.language), ['css', 'html', 'json', 'typescript'], 'Missing mode bundle') +assert.equal(record.files.flatMap(file => file.modules).length, 14, 'Missing Monaco mode source') +assert.equal(record.npmModules.length, 6, 'Missing mode dependency source') +const cache = new ArchiveCache(root, path.join(root, 'refactor/.cache/monaco-review')) +await cache.verify(record.archives, record.remotes, process.argv.includes('--fetch')) +for (const name of ['typescript', 'terser', 'source-map']) { + const archive = record.archives.find(item => item.name === name) + assert(archive, 'Missing historical compiler dependency') + cache.extractCompiler(archive) +} +for (const member of record.compilerMembers) + cache.member(member) +const require = createRequire(path.join(cache.directory, 'compiler/entry.cjs')) +const ts = require('typescript') as typeof import('typescript') + +const terser = require('terser') as { minify: (source: string, options: { output: { comments: string } }) => Promise<{ code: string }> } + +assert.equal(ts.version, '4.4.4') +assert.equal(require('terser/package.json').version, '5.9.0') + +assert.equal(require('source-map/package.json').version, '0.7.3') + +const jsonc = cache.member(record.declaration).toString('utf8') +const modules = new Map(record.npmModules.map(member => [member.id, nameModule(cache.member(member).toString('utf8'), member.id)])) +const aliases = new Map(record.aliases.map(alias => [alias.id, aliasModule(alias.id, alias.main)])) +const results = [] +for (const file of record.files) { + assert(record.remotes.some(remote => remote.source === file.config), 'Unverified mode compiler config') + const config: { compilerOptions: { module: string, target: string, lib: string[], strict?: boolean } } = JSON.parse(fs.readFileSync(path.join(root, file.config), 'utf8')) + assert.equal(config.compilerOptions.module, 'amd') + assert.equal(config.compilerOptions.target, 'es5') + const local = new Map(file.modules.map((module) => { + assert(record.remotes.some(remote => remote.source === module.source), 'Unverified mode source') + const source = fs.readFileSync(path.join(root, module.source), 'utf8') + const compiled = emitAmd(ts, source, config.compilerOptions.lib, config.compilerOptions.strict, module.resolveJsonc ? [{ name: 'jsonc-parser', source: jsonc }] : []) + return [module.id, nameModule(compiled, module.id)] + })) + const development = cache.member(file.development).toString('utf8') + verifyWorkerSources(development, file.ids, file.ids.map((id) => { + const source = local.get(id) ?? modules.get(id) ?? aliases.get(id) + assert(source, `Missing mode source: ${id}`) + return { id, source } + })) + const target = fs.readFileSync(path.join(root, file.target.path)) + assert.equal(hash(target), file.target.sha256, 'Shipped Monaco mode changed') + const { code } = await terser.minify(development, { output: { comments: 'some' } }) + assert.equal(languageHeader(file.language) + code, target.toString('utf8'), 'Minified mode bundle differs') + results.push({ language: file.language, modules: file.ids.length, exactSources: true, exactOutput: true, sha256: hash(target) }) +} +console.log(JSON.stringify({ archives: record.archives.length, gitSources: record.remotes.length, ownModules: 14, npmModules: modules.size, aliases: aliases.size, modes: results, coreAndBasicLanguagesReviewed: false })) diff --git a/test/browser/README.md b/test/browser/README.md index 2de6116fd..7f8157f32 100644 --- a/test/browser/README.md +++ b/test/browser/README.md @@ -1,5 +1,11 @@ # Browser regression entry +`editor-modes.spec.js` exercises Monaco's actual automatic mode/provider registration +through a real editor. It switches CSS/JSON/TypeScript/HTML models, checks diagnostic +arrival/removal and document formatting, verifies all four mode bundle responses, +and checks model disposal clears markers. It complements direct worker tests; +neither suite alone proves all editor UI, physical-device or player integration paths. + `editor-languages.spec.js` loads the frozen Monaco 0.30.1 CSS/HTML/JSON workers, checks real Worker creation, positive/negative diagnostics, tag completion, document symbols and formatting, and disposes models/workers. It uses `createWebWorker` with diff --git a/test/browser/editor-modes.spec.js b/test/browser/editor-modes.spec.js new file mode 100644 index 000000000..fed4086f8 --- /dev/null +++ b/test/browser/editor-modes.spec.js @@ -0,0 +1,72 @@ +import { expect, test } from './fixtures.js' + +test('docs Monaco mode registrations update editor diagnostics and formatting across languages', async ({ page }, testInfo) => { + const loadedModes = [] + page.on('response', (response) => { + if (/\/language\/(?:css|html|json|typescript)\/\w+Mode\.js$/.test(response.url())) + loadedModes.push({ url: response.url(), status: response.status() }) + }) + await page.goto('/test/player.html?core=candidate&chapter=published') + await page.addScriptTag({ url: '/assets/js/vs/loader.js' }) + await page.evaluate(async () => { + window.require.config({ paths: { vs: '/assets/js/vs' } }) + await new Promise((resolve, reject) => window.require(['vs/editor/editor.main'], resolve, reject)) + const host = document.createElement('div') + host.style.cssText = 'width:800px;height:400px' + document.body.appendChild(host) + const editor = window.monaco.editor.create(host, { model: null, minimap: { enabled: false } }) + window.modeProbe = { editor, host, models: [] } + }) + const evidence = [] + try { + for (const phase of [ + { language: 'css', invalid: 'a { color: ; }', valid: 'a { color: red; }' }, + { language: 'json', invalid: '{"value":}', valid: '{"value":1}' }, + { language: 'typescript', invalid: 'const value: number = "wrong";', valid: 'const value: number = 1;' }, + ]) { + await page.evaluate((phase) => { + const api = window.monaco + const model = api.editor.createModel(phase.invalid, phase.language, api.Uri.parse(`file:///mode-probe-${phase.language}`)) + model.updateOptions({ tabSize: 2, insertSpaces: true }) + window.modeProbe.models.push(model) + window.modeProbe.editor.setModel(model) + }, phase) + await expect.poll(() => page.evaluate(() => window.monaco.editor.getModelMarkers({ resource: window.modeProbe.editor.getModel().uri }).filter(marker => marker.severity === window.monaco.MarkerSeverity.Error).length)).toBeGreaterThan(0) + evidence.push(await page.evaluate(() => ({ language: window.modeProbe.editor.getModel().getLanguageId(), markers: window.monaco.editor.getModelMarkers({ resource: window.modeProbe.editor.getModel().uri }) }))) + await page.evaluate(value => window.modeProbe.editor.getModel().setValue(value), phase.valid) + await expect.poll(() => page.evaluate(() => window.monaco.editor.getModelMarkers({ resource: window.modeProbe.editor.getModel().uri }).length)).toBe(0) + if (phase.language === 'json') { + await expect.poll(() => page.evaluate(() => window.modeProbe.editor.getAction('editor.action.formatDocument').isSupported())).toBe(true) + await page.evaluate(() => window.modeProbe.editor.getAction('editor.action.formatDocument').run()) + const formatted = await page.evaluate(() => window.modeProbe.editor.getValue()) + expect(formatted).toContain('\n') + expect(JSON.parse(formatted)).toEqual({ value: 1 }) + evidence.push({ language: 'json', formatted }) + } + } + await page.evaluate(() => { + const api = window.monaco + const model = api.editor.createModel('

hello

world

', 'html', api.Uri.parse('file:///mode-probe-html')) + model.updateOptions({ tabSize: 2, insertSpaces: true }) + window.modeProbe.models.push(model) + window.modeProbe.editor.setModel(model) + }) + await expect.poll(() => page.evaluate(() => window.modeProbe.editor.getAction('editor.action.formatDocument').isSupported())).toBe(true) + await page.evaluate(() => window.modeProbe.editor.getAction('editor.action.formatDocument').run()) + const formatted = await page.evaluate(() => window.modeProbe.editor.getValue()) + expect(formatted).toContain('\n') + expect(formatted.replace(/\s+/g, '')).toBe('

hello

world

') + evidence.push({ language: 'html', formatted }) + expect(loadedModes.map(item => item.url.split('/').pop()).sort()).toEqual(['cssMode.js', 'htmlMode.js', 'jsonMode.js', 'tsMode.js']) + expect(loadedModes.every(item => item.status === 200)).toBe(true) + await testInfo.attach('monaco-mode-results', { contentType: 'application/json', body: JSON.stringify({ evidence, loadedModes }, null, 2) }) + } + finally { + await page.evaluate(() => { + window.modeProbe.editor.dispose() + window.modeProbe.models.forEach(model => model.dispose()) + window.modeProbe.host.remove() + }) + } + await expect.poll(() => page.evaluate(() => window.modeProbe.models.flatMap(model => window.monaco.editor.getModelMarkers({ resource: model.uri })).length)).toBe(0) +}) diff --git a/test/monaco-provenance.test.js b/test/monaco-provenance.test.js index b42f759b7..eca365a6b 100644 --- a/test/monaco-provenance.test.js +++ b/test/monaco-provenance.test.js @@ -1,6 +1,8 @@ import assert from 'node:assert/strict' // eslint-disable-next-line test/no-import-node-test -- Verify fixed source transforms without executing archived runtime. import test from 'node:test' +import ts from 'typescript' +import { emitAmd } from '../scripts/site-vendor/monaco/compiler.ts' import { aliasModule, moduleIds, nameModule, verifyWorkerSources } from '../scripts/site-vendor/monaco/languages.ts' import { browserTypeScript, verifyTypeScriptSource } from '../scripts/site-vendor/monaco/typescript.ts' @@ -46,6 +48,8 @@ test('Monaco AMD naming ignores strings and preserves source bodies', () => { assert(named.includes('define(\'library/main\',["exports"]')) assert(!named.includes('sourceMappingURL')) assert.deepEqual(moduleIds(named), ['library/main']) + assert.deepEqual(moduleIds(nameModule(anonymous, 'library/lib.index')), ['library/lib.index']) + assert.throws(() => nameModule(anonymous, '../library'), /identifier/) assert(nameModule(anonymous.trimEnd(), 'library/main').endsWith('//# sourceMappingURL=source.js.map;')) assert.throws(() => nameModule(named, 'library/main'), /anonymous AMD dependency array/) assert.throws(() => nameModule(anonymous + anonymous, 'library/main'), /one anonymous/) @@ -53,6 +57,17 @@ test('Monaco AMD naming ignores strings and preserves source bodies', () => { assert.throws(() => nameModule(`${anonymous}//# sourceMappingURL=second.map\n`, 'library/main'), /Duplicate source map/) }) +test('Monaco mode emission resolves const enums only from explicit declaration inputs', () => { + const source = 'import { ScanError } from "pinned-json"; export const code = ScanError.End;' + const declarations = [{ name: 'pinned-json', source: 'export declare const enum ScanError { End = 2 }' }] + const compiled = emitAmd(ts, source, ['es5'], true, declarations) + assert.match(compiled, /exports.code = 2/) + const wrong = emitAmd(ts, source, ['es5'], true, [{ ...declarations[0], source: declarations[0].source.replace('2', '3') }]) + const fragment = nameModule(compiled, 'mode') + assert.throws(() => verifyWorkerSources(nameModule(wrong, 'mode'), ['mode'], [{ id: 'mode', source: fragment }]), /Source differs/) + assert(!emitAmd(ts, source, ['es5'], true).includes('exports.code = 2')) +}) + test('Monaco worker proof covers helper code, aliases and all module boundaries', () => { const id = 'library/main' const source = nameModule('const helper = 1;\ndefine(["exports"], function (exports) { exports.value = helper; });', id)