build(site): [SITE-07] reproduce and validate Monaco language modes

This commit is contained in:
Harvey Zhao committed 2026-09-15 09:42:37 +08:00
1 parent 99c208aeee
commit bc9cb61aaf
36 files changed
+5784 -43

No files matched your search

+1
View File
@@ -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
+2 -1
View File
@@ -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": {
@@ -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"
}
@@ -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"
}
]
}
@@ -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": "<div>\r\n <p>hello</p>\r\n <p>world</p>\r\n</div>"
}
],
"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": "<div>\r\n <p>hello</p>\r\n <p>world</p>\r\n</div>"
}
],
"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": "<div>\n <p>hello</p>\n <p>world</p>\n</div>"
}
],
"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."
]
}
@@ -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<CSSWorker> => {
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();
}
}
@@ -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<CSSWorker>;
}
// --- 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) : <string>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 (<InsertReplaceEdit>edit).insert !== 'undefined' &&
typeof (<InsertReplaceEdit>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<languages.CompletionList> {
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 (<lsTypes.MarkupContent>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<languages.Hover> {
let resource = model.uri;
return this._worker(resource)
.then((worker) => {
return worker.doHover(resource.toString(), fromPosition(position));
})
.then((info) => {
if (!info) {
return;
}
return <languages.Hover>{
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<languages.DocumentHighlight[]> {
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 <languages.DocumentHighlight>{
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<languages.Definition> {
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<languages.Location[]> {
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<languages.WorkspaceEdit> {
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<languages.DocumentSymbol[]> {
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<languages.IColorInformation[]> {
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<languages.IColorPresentation[]> {
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<languages.FoldingRange[]> {
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(<lsTypes.FoldingRangeKind>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<languages.SelectionRange[][]> {
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;
});
});
}
}
@@ -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<CSSWorker>;
private _client: Promise<CSSWorker>;
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<CSSWorker> {
this._lastUsedTime = Date.now();
if (!this._client) {
this._worker = editor.createWebWorker<CSSWorker>({
// 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 = <Promise<CSSWorker>>(<any>this._worker.getProxy());
}
return this._client;
}
getLanguageServiceWorker(...resources: Uri[]): Promise<CSSWorker> {
let _client: CSSWorker;
return this._getClient()
.then((client) => {
_client = client;
})
.then((_) => {
return this._worker.withSyncedResources(resources);
})
.then((_) => _client);
}
}
@@ -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<HTMLWorker> => {
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<HTMLWorker> => {
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();
}
}
@@ -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<HTMLWorker>;
}
// --- 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 (<lsTypes.InsertReplaceEdit>edit).insert !== 'undefined' &&
typeof (<lsTypes.InsertReplaceEdit>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<languages.CompletionList> {
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 (<lsTypes.MarkupContent>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<languages.Hover> {
let resource = model.uri;
return this._worker(resource)
.then((worker) => {
return worker.doHover(resource.toString(), fromPosition(position));
})
.then((info) => {
if (!info) {
return;
}
return <languages.Hover>{
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<languages.DocumentHighlight[]> {
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<languages.DocumentSymbol[]> {
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<languages.ILinksList> {
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<editor.ISingleEditOperation[]> {
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<editor.ISingleEditOperation[]> {
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<languages.WorkspaceEdit> {
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<languages.FoldingRange[]> {
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(<lsTypes.FoldingRangeKind>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<languages.SelectionRange[][]> {
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;
});
});
}
}
@@ -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<HTMLWorker>;
private _client: Promise<HTMLWorker>;
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<HTMLWorker> {
this._lastUsedTime = Date.now();
if (!this._client) {
this._worker = editor.createWebWorker<HTMLWorker>({
// 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 = <Promise<HTMLWorker>>this._worker.getProxy();
}
return this._client;
}
getLanguageServiceWorker(...resources: Uri[]): Promise<HTMLWorker> {
let _client: HTMLWorker;
return this._getClient()
.then((client) => {
_client = client;
})
.then((_) => {
if (this._worker) {
return this._worker.withSyncedResources(resources);
}
})
.then((_) => _client);
}
}
@@ -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<JSONWorker> => {
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'] }
]
};
@@ -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<JSONWorker>;
}
// --- 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) : <string>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 (<InsertReplaceEdit>edit).insert !== 'undefined' &&
typeof (<InsertReplaceEdit>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<languages.CompletionList> {
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 (<lsTypes.MarkupContent>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<languages.Hover> {
let resource = model.uri;
return this._worker(resource)
.then((worker) => {
return worker.doHover(resource.toString(), fromPosition(position));
})
.then((info) => {
if (!info) {
return;
}
return <languages.Hover>{
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<languages.DocumentSymbol[]> {
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<editor.ISingleEditOperation[]> {
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<editor.ISingleEditOperation[]> {
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<languages.IColorInformation[]> {
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<languages.IColorPresentation[]> {
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<languages.FoldingRange[]> {
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(<lsTypes.FoldingRangeKind>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<languages.SelectionRange[][]> {
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;
});
});
}
}
@@ -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, <JSONState>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: <languages.IToken[]>[],
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;
}
@@ -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<JSONWorker>;
private _client: Promise<JSONWorker>;
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<JSONWorker> {
this._lastUsedTime = Date.now();
if (!this._client) {
this._worker = editor.createWebWorker<JSONWorker>({
// 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 = <Promise<JSONWorker>>(<any>this._worker.getProxy());
}
return this._client;
}
getLanguageServiceWorker(...resources: Uri[]): Promise<JSONWorker> {
let _client: JSONWorker;
return this._getClient()
.then((client) => {
_client = client;
})
.then((_) => {
return this._worker.withSyncedResources(resources);
})
.then((_) => _client);
}
}
@@ -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<string, boolean> = {}
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;
@@ -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<TypeScriptWorker>;
let typeScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
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<TypeScriptWorker>> {
return new Promise((resolve, reject) => {
if (!javaScriptWorker) {
return reject('JavaScript not registered!');
}
resolve(javaScriptWorker);
});
}
export function getTypeScriptWorker(): Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>> {
return new Promise((resolve, reject) => {
if (!typeScriptWorker) {
return reject('TypeScript not registered!');
}
resolve(typeScriptWorker);
});
}
function setupMode(
defaults: LanguageServiceDefaults,
modeId: string
): (...uris: Uri[]) => Promise<TypeScriptWorker> {
const client = new WorkerManager(modeId, defaults);
const worker = (...uris: Uri[]): Promise<TypeScriptWorker> => {
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;
}
@@ -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
}
}
@@ -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<TypeScriptWorker> | null;
private _client: Promise<TypeScriptWorker> | 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<void> {
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<TypeScriptWorker> {
if (!this._client) {
this._worker = editor.createWebWorker<TypeScriptWorker>({
// 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 = <Promise<TypeScriptWorker>>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<TypeScriptWorker> {
let _client: TypeScriptWorker;
return this._getClient()
.then((client) => {
_client = client;
})
.then((_) => {
if (this._worker) {
return this._worker.withSyncedResources(resources);
}
})
.then((_) => _client);
}
}
@@ -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 默认行为。
+1 -1
View File
@@ -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)
+9
View File
@@ -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 通过。已将先前待答
+7 -2
View File
@@ -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",
+4 -1
View File
@@ -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"
]
},
{
+1 -1
View File
@@ -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"
+6 -2
View File
@@ -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",
+30 -1
View File
@@ -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.
+34
View File
@@ -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
}
+2 -2
View File
@@ -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)
+2 -1
View File
@@ -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) {
@@ -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 = []
@@ -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 }))
+6
View File
@@ -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
+72
View File
@@ -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('<div><p>hello</p><p>world</p></div>', '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('<div><p>hello</p><p>world</p></div>')
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)
})
+15
View File
@@ -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)