1
0
Alex Dima 4 жил өмнө
parent
commit
b87c75d7e9

+ 2 - 2
.github/workflows/ci.yml

@@ -1,8 +1,8 @@
-name: "CI"
+name: 'CI'
 on: [pull_request]
 jobs:
   build:
-    name: "Builds and Compiles"
+    name: 'Builds and Compiles'
     runs-on: ubuntu-latest
 
     steps:

+ 1 - 1
.vscode/settings.json

@@ -5,4 +5,4 @@
 		"**/node_modules": true,
 		"**/release": true
 	}
-}
+}

+ 21 - 21
LICENSE.md

@@ -1,21 +1,21 @@
-The MIT License (MIT)
-
-Copyright (c) Microsoft Corporation
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+The MIT License (MIT)
+
+Copyright (c) Microsoft Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 39 - 40
README.md

@@ -1,40 +1,39 @@
-# Monaco TypeScript
-
-Simple TypeScript and JavaScript language support for the Monaco Editor.
-
-![typescript](https://cloud.githubusercontent.com/assets/5047891/15926623/5262fe08-2e3d-11e6-9b90-1d43fda07178.gif)
-
-*Note* that this project focuses on single-file scenarios and that things like project-isolation, cross-file-features like Rename etc. are *outside* the scope of this project and not supported.
-
-## Issues
-
-Please file issues concerning `monaco-typescript` in the [`monaco-editor` repository](https://github.com/Microsoft/monaco-editor/issues).
-
-## Installing
-
-This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
-
-
-## Development
-
-* `git clone https://github.com/Microsoft/monaco-typescript`
-* `cd monaco-typescript`
-* `npm install .`
-* `npm run compile`
-* `npm run watch`
-* open `$/monaco-typescript/test/index.html` in your favorite browser.
-
-## Updating TypeScript
-
-* change typescript's version in `package.json`.
-* execute `npm install .`
-* execute `npm run import-typescript`
-* adopt new APIs
-
-## Code of Conduct
-
-This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
-
-
-## License
-[MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md)
+# Monaco TypeScript
+
+Simple TypeScript and JavaScript language support for the Monaco Editor.
+
+![typescript](https://cloud.githubusercontent.com/assets/5047891/15926623/5262fe08-2e3d-11e6-9b90-1d43fda07178.gif)
+
+_Note_ that this project focuses on single-file scenarios and that things like project-isolation, cross-file-features like Rename etc. are _outside_ the scope of this project and not supported.
+
+## Issues
+
+Please file issues concerning `monaco-typescript` in the [`monaco-editor` repository](https://github.com/Microsoft/monaco-editor/issues).
+
+## Installing
+
+This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
+
+## Development
+
+- `git clone https://github.com/Microsoft/monaco-typescript`
+- `cd monaco-typescript`
+- `npm install .`
+- `npm run compile`
+- `npm run watch`
+- open `$/monaco-typescript/test/index.html` in your favorite browser.
+
+## Updating TypeScript
+
+- change typescript's version in `package.json`.
+- execute `npm install .`
+- execute `npm run import-typescript`
+- adopt new APIs
+
+## Code of Conduct
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+
+## License
+
+[MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md)

+ 110 - 110
package-lock.json

@@ -1,112 +1,112 @@
 {
-  "name": "monaco-typescript",
-  "version": "3.7.0",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "@typescript/vfs": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.3.0.tgz",
-      "integrity": "sha512-Bd1LdvQpm0uU2eclcCfO8H8oAGAfEJiKn0acKy/xeZV4sARwXx9MHBMuDX0XDPLmI2JpIm+mFV9Ers65xnoaQg==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.1"
-      }
-    },
-    "buffer-from": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
-      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
-      "dev": true
-    },
-    "commander": {
-      "version": "2.20.3",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-      "dev": true
-    },
-    "debug": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-      "dev": true,
-      "requires": {
-        "ms": "^2.1.1"
-      }
-    },
-    "monaco-editor-core": {
-      "version": "0.20.0",
-      "resolved": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.20.0.tgz",
-      "integrity": "sha512-4mdmfEejTvRZzrEIn70jqqNl3g15vnkRdTkJ8uMK4jiljntlwhiSc5vknZOLt1QM8za16C3tDrSl2mTL9ma2Sg==",
-      "dev": true
-    },
-    "monaco-languages": {
-      "version": "1.10.0",
-      "resolved": "https://registry.npmjs.org/monaco-languages/-/monaco-languages-1.10.0.tgz",
-      "integrity": "sha512-ARAws17Xh0K4WsZYkJY6CqHn9EYdYN8CjzK6w/jgXIwU0owzCdUWxzu+FNJ/LeDLcKxL/YK3phcwGFj9IqX2yw==",
-      "dev": true
-    },
-    "monaco-plugin-helpers": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/monaco-plugin-helpers/-/monaco-plugin-helpers-1.0.3.tgz",
-      "integrity": "sha512-6AYI3ONAy8ki74qG2JqtFrLdiJHQlgeO5l4Rwr0OMyIpGXhc94y5rZuFxOtgGkxgSrZfHSwOt/MulUNZ/mOQOw==",
-      "dev": true,
-      "requires": {
-        "typescript": "^2.7.2"
-      },
-      "dependencies": {
-        "typescript": {
-          "version": "2.9.2",
-          "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
-          "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
-          "dev": true
-        }
-      }
-    },
-    "ms": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-      "dev": true
-    },
-    "requirejs": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
-      "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
-      "dev": true
-    },
-    "source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "dev": true
-    },
-    "source-map-support": {
-      "version": "0.5.19",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
-      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "^1.0.0",
-        "source-map": "^0.6.0"
-      }
-    },
-    "terser": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz",
-      "integrity": "sha512-XTT3D3AwxC54KywJijmY2mxZ8nJiEjBHVYzq8l9OaYuRFWeQNBwvipuzzYEP4e+/AVcd1hqG/CqgsdIRyT45Fg==",
-      "dev": true,
-      "requires": {
-        "commander": "^2.20.0",
-        "source-map": "~0.6.1",
-        "source-map-support": "~0.5.12"
-      }
-    },
-    "typescript": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
-      "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
-      "dev": true
-    }
-  }
+	"name": "monaco-typescript",
+	"version": "3.7.0",
+	"lockfileVersion": 1,
+	"requires": true,
+	"dependencies": {
+		"@typescript/vfs": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.3.0.tgz",
+			"integrity": "sha512-Bd1LdvQpm0uU2eclcCfO8H8oAGAfEJiKn0acKy/xeZV4sARwXx9MHBMuDX0XDPLmI2JpIm+mFV9Ers65xnoaQg==",
+			"dev": true,
+			"requires": {
+				"debug": "^4.1.1"
+			}
+		},
+		"buffer-from": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+			"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+			"dev": true
+		},
+		"commander": {
+			"version": "2.20.3",
+			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+			"dev": true
+		},
+		"debug": {
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+			"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+			"dev": true,
+			"requires": {
+				"ms": "^2.1.1"
+			}
+		},
+		"monaco-editor-core": {
+			"version": "0.20.0",
+			"resolved": "https://registry.npmjs.org/monaco-editor-core/-/monaco-editor-core-0.20.0.tgz",
+			"integrity": "sha512-4mdmfEejTvRZzrEIn70jqqNl3g15vnkRdTkJ8uMK4jiljntlwhiSc5vknZOLt1QM8za16C3tDrSl2mTL9ma2Sg==",
+			"dev": true
+		},
+		"monaco-languages": {
+			"version": "1.10.0",
+			"resolved": "https://registry.npmjs.org/monaco-languages/-/monaco-languages-1.10.0.tgz",
+			"integrity": "sha512-ARAws17Xh0K4WsZYkJY6CqHn9EYdYN8CjzK6w/jgXIwU0owzCdUWxzu+FNJ/LeDLcKxL/YK3phcwGFj9IqX2yw==",
+			"dev": true
+		},
+		"monaco-plugin-helpers": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/monaco-plugin-helpers/-/monaco-plugin-helpers-1.0.3.tgz",
+			"integrity": "sha512-6AYI3ONAy8ki74qG2JqtFrLdiJHQlgeO5l4Rwr0OMyIpGXhc94y5rZuFxOtgGkxgSrZfHSwOt/MulUNZ/mOQOw==",
+			"dev": true,
+			"requires": {
+				"typescript": "^2.7.2"
+			},
+			"dependencies": {
+				"typescript": {
+					"version": "2.9.2",
+					"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
+					"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
+					"dev": true
+				}
+			}
+		},
+		"ms": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+			"dev": true
+		},
+		"requirejs": {
+			"version": "2.3.6",
+			"resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
+			"integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
+			"dev": true
+		},
+		"source-map": {
+			"version": "0.6.1",
+			"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+			"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+			"dev": true
+		},
+		"source-map-support": {
+			"version": "0.5.19",
+			"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+			"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+			"dev": true,
+			"requires": {
+				"buffer-from": "^1.0.0",
+				"source-map": "^0.6.0"
+			}
+		},
+		"terser": {
+			"version": "5.3.0",
+			"resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz",
+			"integrity": "sha512-XTT3D3AwxC54KywJijmY2mxZ8nJiEjBHVYzq8l9OaYuRFWeQNBwvipuzzYEP4e+/AVcd1hqG/CqgsdIRyT45Fg==",
+			"dev": true,
+			"requires": {
+				"commander": "^2.20.0",
+				"source-map": "~0.6.1",
+				"source-map-support": "~0.5.12"
+			}
+		},
+		"typescript": {
+			"version": "4.0.2",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
+			"integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
+			"dev": true
+		}
+	}
 }

+ 38 - 33
package.json

@@ -1,35 +1,40 @@
 {
-  "name": "monaco-typescript",
-  "version": "3.7.0",
-  "description": "TypeScript and JavaScript language support for Monaco Editor",
-  "scripts": {
-    "compile-amd": "mcopy ./src/lib/typescriptServices-amd.js ./release/dev/lib/typescriptServices.js && tsc -p ./src/tsconfig.json",
-    "compile-esm": "mcopy ./src/lib/typescriptServices.js ./release/esm/lib/typescriptServices.js && tsc -p ./src/tsconfig.esm.json",
-    "compile": "mrmdir ./release && npm run compile-amd && npm run compile-esm",
-    "watch": "tsc -p ./src --watch",
-    "prepublishOnly": "npm run compile && node ./scripts/bundle && mcopy ./src/monaco.d.ts ./release/monaco.d.ts",
-    "import-typescript": "node ./scripts/importTypescript",
-    "prettier": "prettier --write ."
-  },
-  "author": "Microsoft Corporation",
-  "license": "MIT",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/Microsoft/monaco-typescript"
-  },
-  "bugs": {
-    "url": "https://github.com/Microsoft/monaco-typescript/issues"
-  },
-  "devDependencies": {
-    "@typescript/vfs": "^1.3.0",
-    "husky": "^4.3.0",
-    "monaco-editor-core": "^0.20.0",
-    "monaco-languages": "^1.10.0",
-    "monaco-plugin-helpers": "^1.0.3",
-    "prettier": "^2.1.1",
-    "pretty-quick": "^3.0.0",
-    "requirejs": "^2.3.6",
-    "terser": "^5.3.0",
-    "typescript": "^4.0.2"
-  }
+	"name": "monaco-typescript",
+	"version": "3.7.0",
+	"description": "TypeScript and JavaScript language support for Monaco Editor",
+	"scripts": {
+		"compile-amd": "mcopy ./src/lib/typescriptServices-amd.js ./release/dev/lib/typescriptServices.js && tsc -p ./src/tsconfig.json",
+		"compile-esm": "mcopy ./src/lib/typescriptServices.js ./release/esm/lib/typescriptServices.js && tsc -p ./src/tsconfig.esm.json",
+		"compile": "mrmdir ./release && npm run compile-amd && npm run compile-esm",
+		"watch": "tsc -p ./src --watch",
+		"prepublishOnly": "npm run compile && node ./scripts/bundle && mcopy ./src/monaco.d.ts ./release/monaco.d.ts",
+		"import-typescript": "node ./scripts/importTypescript",
+		"prettier": "prettier --write ."
+	},
+	"author": "Microsoft Corporation",
+	"license": "MIT",
+	"repository": {
+		"type": "git",
+		"url": "https://github.com/Microsoft/monaco-typescript"
+	},
+	"bugs": {
+		"url": "https://github.com/Microsoft/monaco-typescript/issues"
+	},
+	"devDependencies": {
+		"@typescript/vfs": "^1.3.0",
+		"husky": "^4.3.0",
+		"monaco-editor-core": "^0.20.0",
+		"monaco-languages": "^1.10.0",
+		"monaco-plugin-helpers": "^1.0.3",
+		"prettier": "^2.1.1",
+		"pretty-quick": "^3.0.0",
+		"requirejs": "^2.3.6",
+		"terser": "^5.3.0",
+		"typescript": "^4.0.2"
+	},
+	"husky": {
+		"hooks": {
+			"pre-commit": "pretty-quick --staged"
+		}
+	}
 }

+ 20 - 17
scripts/bundle.js

@@ -30,22 +30,25 @@ bundleOne('tsMode');
 bundleOne('tsWorker');
 
 function bundleOne(moduleId, exclude) {
-	requirejs.optimize({
-		baseUrl: 'release/dev/',
-		name: 'vs/language/typescript/' + moduleId,
-		out: 'release/min/' + moduleId + '.js',
-		exclude: exclude,
-		paths: {
-			'vs/language/typescript': REPO_ROOT + '/release/dev'
+	requirejs.optimize(
+		{
+			baseUrl: 'release/dev/',
+			name: 'vs/language/typescript/' + moduleId,
+			out: 'release/min/' + moduleId + '.js',
+			exclude: exclude,
+			paths: {
+				'vs/language/typescript': REPO_ROOT + '/release/dev'
+			},
+			optimize: 'none'
 		},
-		optimize: 'none'
-	}, async function(buildResponse) {
-		const filePath = path.join(REPO_ROOT, 'release/min/' + moduleId + '.js');
-		const fileContents = fs.readFileSync(filePath).toString();
-		console.log();
-		console.log(`Minifying ${filePath}...`);
-		const result = await terser.minify(fileContents);
-		console.log(`Done minifying ${filePath}.`);
-		fs.writeFileSync(filePath, BUNDLED_FILE_HEADER + result.code);
-	})
+		async function (buildResponse) {
+			const filePath = path.join(REPO_ROOT, 'release/min/' + moduleId + '.js');
+			const fileContents = fs.readFileSync(filePath).toString();
+			console.log();
+			console.log(`Minifying ${filePath}...`);
+			const result = await terser.minify(fileContents);
+			console.log(`Done minifying ${filePath}.`);
+			fs.writeFileSync(filePath, BUNDLED_FILE_HEADER + result.code);
+		}
+	);
 }

+ 74 - 31
scripts/importTypescript.js

@@ -12,7 +12,10 @@ const generatedNote = `//
 //
 `;
 
-const TYPESCRIPT_LIB_SOURCE = path.join(__dirname, '../node_modules/typescript/lib');
+const TYPESCRIPT_LIB_SOURCE = path.join(
+	__dirname,
+	'../node_modules/typescript/lib'
+);
 const TYPESCRIPT_LIB_DESTINATION = path.join(__dirname, '../src/lib');
 
 (function () {
@@ -23,8 +26,11 @@ const TYPESCRIPT_LIB_DESTINATION = path.join(__dirname, '../src/lib');
 	}
 	importLibs();
 
-	const npmLsOutput = JSON.parse(child_process.execSync("npm ls typescript --depth=0 --json=true").toString());
-	const typeScriptDependencyVersion = npmLsOutput.dependencies.typescript.version;
+	const npmLsOutput = JSON.parse(
+		child_process.execSync('npm ls typescript --depth=0 --json=true').toString()
+	);
+	const typeScriptDependencyVersion =
+		npmLsOutput.dependencies.typescript.version;
 
 	fs.writeFileSync(
 		path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServicesMetadata.ts'),
@@ -32,36 +38,55 @@ const TYPESCRIPT_LIB_DESTINATION = path.join(__dirname, '../src/lib');
 export const typescriptVersion = "${typeScriptDependencyVersion}";\n`
 	);
 
-	var tsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.js')).toString();
+	var tsServices = fs
+		.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.js'))
+		.toString();
 
 	// Ensure we never run into the node system...
 	// (this also removes require calls that trick webpack into shimming those modules...)
-	tsServices = (
-		tsServices.replace(/\n    ts\.sys =([^]*)\n    \}\)\(\);/m, `\n    // MONACOCHANGE\n    ts.sys = undefined;\n    // END MONACOCHANGE`)
+	tsServices = tsServices.replace(
+		/\n    ts\.sys =([^]*)\n    \}\)\(\);/m,
+		`\n    // MONACOCHANGE\n    ts.sys = undefined;\n    // END MONACOCHANGE`
 	);
 
 	// Eliminate more require() calls...
-	tsServices = tsServices.replace(/^( +)etwModule = require\(.*$/m, '$1// MONACOCHANGE\n$1etwModule = undefined;\n$1// END MONACOCHANGE');
-	tsServices = tsServices.replace(/^( +)var result = ts\.sys\.require\(.*$/m, '$1// MONACOCHANGE\n$1var result = undefined;\n$1// END MONACOCHANGE');
+	tsServices = tsServices.replace(
+		/^( +)etwModule = require\(.*$/m,
+		'$1// MONACOCHANGE\n$1etwModule = undefined;\n$1// END MONACOCHANGE'
+	);
+	tsServices = tsServices.replace(
+		/^( +)var result = ts\.sys\.require\(.*$/m,
+		'$1// MONACOCHANGE\n$1var result = undefined;\n$1// END MONACOCHANGE'
+	);
 
 	// Flag any new require calls (outside comments) so they can be corrected preemptively.
 	// To avoid missing cases (or using an even more complex regex), temporarily remove comments
 	// about require() and then check for lines actually calling require().
 	// \/[*/] matches the start of a comment (single or multi-line).
 	// ^\s+\*[^/] matches (presumably) a later line of a multi-line comment.
-	const tsServicesNoCommentedRequire = tsServices.replace(/(\/[*/]|^\s+\*[^/]).*\brequire\(.*/gm, '');
-	const linesWithRequire = tsServicesNoCommentedRequire.match(/^.*?\brequire\(.*$/gm)
+	const tsServicesNoCommentedRequire = tsServices.replace(
+		/(\/[*/]|^\s+\*[^/]).*\brequire\(.*/gm,
+		''
+	);
+	const linesWithRequire = tsServicesNoCommentedRequire.match(
+		/^.*?\brequire\(.*$/gm
+	);
 
 	// Allow error messages to include references to require() in their strings
-	const runtimeRequires = linesWithRequire && linesWithRequire.filter(l => !l.includes(": diag("))
+	const runtimeRequires =
+		linesWithRequire && linesWithRequire.filter((l) => !l.includes(': diag('));
 
 	if (runtimeRequires && runtimeRequires.length && linesWithRequire) {
-		console.error('Found new require() calls on the following lines. These should be removed to avoid breaking webpack builds.\n');
+		console.error(
+			'Found new require() calls on the following lines. These should be removed to avoid breaking webpack builds.\n'
+		);
 		console.error(linesWithRequire.join('\n'));
 		process.exit(1);
 	}
 
-	var tsServices_amd = generatedNote + tsServices +
+	var tsServices_amd =
+		generatedNote +
+		tsServices +
 		`
 // MONACOCHANGE
 // Defining the entire module name because r.js has an issue and cannot bundle this file
@@ -69,9 +94,14 @@ export const typescriptVersion = "${typeScriptDependencyVersion}";\n`
 define("vs/language/typescript/lib/typescriptServices", [], function() { return ts; });
 // END MONACOCHANGE
 `;
-	fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices-amd.js'), stripSourceMaps(tsServices_amd));
+	fs.writeFileSync(
+		path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices-amd.js'),
+		stripSourceMaps(tsServices_amd)
+	);
 
-	var tsServices_esm = generatedNote + tsServices +
+	var tsServices_esm =
+		generatedNote +
+		tsServices +
 		`
 // MONACOCHANGE
 export var createClassifier = ts.createClassifier;
@@ -85,17 +115,23 @@ export var ScriptTarget = ts.ScriptTarget;
 export var TokenClass = ts.TokenClass;
 // END MONACOCHANGE
 `;
-	fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.js'), stripSourceMaps(tsServices_esm));
+	fs.writeFileSync(
+		path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.js'),
+		stripSourceMaps(tsServices_esm)
+	);
 
-	var dtsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.d.ts')).toString();
-	dtsServices +=
-		`
+	var dtsServices = fs
+		.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.d.ts'))
+		.toString();
+	dtsServices += `
 // MONACOCHANGE
 export = ts;
 // END MONACOCHANGE
 `;
-	fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.d.ts'), generatedNote + dtsServices);
-
+	fs.writeFileSync(
+		path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.d.ts'),
+		generatedNote + dtsServices
+	);
 })();
 
 function importLibs() {
@@ -112,9 +148,7 @@ ${generatedNote}
 
 /** Contains all the lib files */
 export const libFileMap: Record<string, string> = {}
-`
-;
-
+`;
 	var strIndexResult = `/*---------------------------------------------------------------------------------------------
  *  Copyright (c) Microsoft Corporation. All rights reserved.
  *  Licensed under the MIT License. See License.txt in the project root for license information.
@@ -123,10 +157,10 @@ ${generatedNote}
 
 /** Contains all the lib files */
 export const libFileSet: Record<string, boolean> = {}
-`
-;
-
-	var dtsFiles = fs.readdirSync(TYPESCRIPT_LIB_SOURCE).filter(f => f.includes("lib."));
+`;
+	var dtsFiles = fs
+		.readdirSync(TYPESCRIPT_LIB_SOURCE)
+		.filter((f) => f.includes('lib.'));
 	while (dtsFiles.length > 0) {
 		var name = dtsFiles.shift();
 		var output = readLibFile(name).replace(/\r\n/g, '\n');
@@ -134,8 +168,14 @@ export const libFileSet: Record<string, boolean> = {}
 		strIndexResult += `libFileSet['${name}'] = true;\n`;
 	}
 
-	fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts'), strLibResult);
-	fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.index.ts'), strIndexResult);
+	fs.writeFileSync(
+		path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts'),
+		strLibResult
+	);
+	fs.writeFileSync(
+		path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.index.ts'),
+		strIndexResult
+	);
 }
 
 /**
@@ -153,7 +193,10 @@ function escapeText(text) {
 	var _backslash = '\\'.charCodeAt(0);
 	var _doubleQuote = '"'.charCodeAt(0);
 
-	var startPos = 0, chrCode, replaceWith = null, resultPieces = [];
+	var startPos = 0,
+		chrCode,
+		replaceWith = null,
+		resultPieces = [];
 
 	for (var i = 0, len = text.length; i < len; i++) {
 		chrCode = text.charCodeAt(i);

+ 1128 - 902
src/languageFeatures.ts

@@ -1,902 +1,1128 @@
-/*---------------------------------------------------------------------------------------------
- *  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 { LanguageServiceDefaultsImpl } from './monaco.contribution';
-import * as ts from './lib/typescriptServices';
-import { TypeScriptWorker } from './tsWorker';
-import { libFileSet } from "./lib/lib.index"
-
-import Uri = monaco.Uri;
-import Position = monaco.Position;
-import Range = monaco.Range;
-import CancellationToken = monaco.CancellationToken;
-import IDisposable = monaco.IDisposable;
-
-//#region utils copied from typescript to prevent loading the entire typescriptServices ---
-
-enum IndentStyle {
-	None = 0,
-	Block = 1,
-	Smart = 2
-}
-
-export function flattenDiagnosticMessageText(diag: string | ts.DiagnosticMessageChain | undefined, newLine: string, indent = 0): string {
-	if (typeof diag === "string") {
-		return diag;
-	}
-	else if (diag === undefined) {
-		return "";
-	}
-	let result = "";
-	if (indent) {
-		result += newLine;
-
-		for (let i = 0; i < indent; i++) {
-			result += "  ";
-		}
-	}
-	result += diag.messageText;
-	indent++;
-	if (diag.next) {
-		for (const kid of diag.next) {
-			result += flattenDiagnosticMessageText(kid, newLine, indent);
-		}
-	}
-	return result;
-}
-
-function displayPartsToString(displayParts: ts.SymbolDisplayPart[] | undefined): string {
-	if (displayParts) {
-		return displayParts.map((displayPart) => displayPart.text).join("");
-	}
-	return "";
-}
-
-//#endregion
-
-export abstract class Adapter {
-
-	constructor(protected _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>) {
-	}
-
-	// protected _positionToOffset(model: monaco.editor.ITextModel, position: monaco.IPosition): number {
-	// 	return model.getOffsetAt(position);
-	// }
-
-	// protected _offsetToPosition(model: monaco.editor.ITextModel, offset: number): monaco.IPosition {
-	// 	return model.getPositionAt(offset);
-	// }
-
-	protected _textSpanToRange(model: monaco.editor.ITextModel, span: ts.TextSpan): monaco.IRange {
-		let p1 = model.getPositionAt(span.start);
-		let p2 = model.getPositionAt(span.start + span.length);
-		let { lineNumber: startLineNumber, column: startColumn } = p1;
-		let { lineNumber: endLineNumber, column: endColumn } = p2;
-		return { startLineNumber, startColumn, endLineNumber, endColumn };
-	}
-}
-
-// --- lib files
-
-export class LibFiles {
-
-	private _libFiles: Record<string, string>;
-	private _hasFetchedLibFiles: boolean;
-	private _fetchLibFilesPromise: Promise<void> | null;
-
-	constructor(
-		private readonly _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
-	) {
-		this._libFiles = {};
-		this._hasFetchedLibFiles = false;
-		this._fetchLibFilesPromise = null;
-	}
-
-	public isLibFile(uri: Uri | null): boolean {
-		if (!uri) {
-			return false;
-		}
-		if (uri.path.indexOf("/lib.") === 0) {
-			return !!libFileSet[uri.path.slice(1)];
-		}
-		return false;
-	}
-
-	public getOrCreateModel(uri: Uri): monaco.editor.ITextModel | null {
-		const model = monaco.editor.getModel(uri);
-		if (model) {
-			return model;
-		}
-		if (this.isLibFile(uri) && this._hasFetchedLibFiles) {
-			return monaco.editor.createModel(this._libFiles[uri.path.slice(1)], "javascript", uri);
-		}
-		return null;
-	}
-
-	private _containsLibFile(uris: (Uri | null)[]): boolean {
-		for (let uri of uris) {
-			if (this.isLibFile(uri)) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	public async fetchLibFilesIfNecessary(uris: (Uri | null)[]): Promise<void> {
-		if (!this._containsLibFile(uris)) {
-			// no lib files necessary
-			return;
-		}
-		await this._fetchLibFiles();
-	}
-
-	private _fetchLibFiles(): Promise<void> {
-		if (!this._fetchLibFilesPromise) {
-			this._fetchLibFilesPromise = (
-				this._worker()
-					.then(w => w.getLibFiles())
-					.then((libFiles) => {
-						this._hasFetchedLibFiles = true;
-						this._libFiles = libFiles;
-					})
-			);
-		}
-		return this._fetchLibFilesPromise;
-	}
-}
-
-// --- diagnostics --- ---
-
-enum DiagnosticCategory {
-	Warning = 0,
-	Error = 1,
-	Suggestion = 2,
-	Message = 3
-}
-
-export class DiagnosticsAdapter extends Adapter {
-
-	private _disposables: IDisposable[] = [];
-	private _listener: { [uri: string]: IDisposable } = Object.create(null);
-
-	constructor(
-		private readonly _libFiles: LibFiles,
-		private _defaults: LanguageServiceDefaultsImpl,
-		private _selector: string,
-		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
-	) {
-		super(worker);
-
-		const onModelAdd = (model: monaco.editor.IModel): void => {
-			if (model.getModeId() !== _selector) {
-				return;
-			}
-
-			let handle: number;
-			const changeSubscription = model.onDidChangeContent(() => {
-				clearTimeout(handle);
-				handle = setTimeout(() => this._doValidate(model), 500);
-			});
-
-			this._listener[model.uri.toString()] = {
-				dispose() {
-					changeSubscription.dispose();
-					clearTimeout(handle);
-				}
-			};
-
-			this._doValidate(model);
-		};
-
-		const onModelRemoved = (model: monaco.editor.IModel): void => {
-			monaco.editor.setModelMarkers(model, this._selector, []);
-			const key = model.uri.toString();
-			if (this._listener[key]) {
-				this._listener[key].dispose();
-				delete this._listener[key];
-			}
-		};
-
-		this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
-		this._disposables.push(monaco.editor.onWillDisposeModel(onModelRemoved));
-		this._disposables.push(monaco.editor.onDidChangeModelLanguage(event => {
-			onModelRemoved(event.model);
-			onModelAdd(event.model);
-		}));
-
-		this._disposables.push({
-			dispose() {
-				for (const model of monaco.editor.getModels()) {
-					onModelRemoved(model);
-				}
-			}
-		});
-
-		const recomputeDiagostics = () => {
-			// redo diagnostics when options change
-			for (const model of monaco.editor.getModels()) {
-				onModelRemoved(model);
-				onModelAdd(model);
-			}
-		};
-		this._disposables.push(this._defaults.onDidChange(recomputeDiagostics));
-		this._disposables.push(this._defaults.onDidExtraLibsChange(recomputeDiagostics));
-
-		monaco.editor.getModels().forEach(onModelAdd);
-	}
-
-	public dispose(): void {
-		this._disposables.forEach(d => d && d.dispose());
-		this._disposables = [];
-	}
-
-	private async _doValidate(model: monaco.editor.ITextModel): Promise<void> {
-		const worker = await this._worker(model.uri);
-
-		if (model.isDisposed()) {
-			// model was disposed in the meantime
-			return;
-		}
-
-		const promises: Promise<ts.Diagnostic[]>[] = [];
-		const { noSyntaxValidation, noSemanticValidation, noSuggestionDiagnostics } = this._defaults.getDiagnosticsOptions();
-		if (!noSyntaxValidation) {
-			promises.push(worker.getSyntacticDiagnostics(model.uri.toString()));
-		}
-		if (!noSemanticValidation) {
-			promises.push(worker.getSemanticDiagnostics(model.uri.toString()));
-		}
-		if (!noSuggestionDiagnostics) {
-			promises.push(worker.getSuggestionDiagnostics(model.uri.toString()));
-		}
-
-		const allDiagnostics = await Promise.all(promises);
-
-		if (!allDiagnostics || model.isDisposed()) {
-			// model was disposed in the meantime
-			return;
-		}
-
-		const diagnostics = allDiagnostics
-			.reduce((p, c) => c.concat(p), [])
-			.filter(d => (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === -1);
-
-		// Fetch lib files if necessary
-		const relatedUris = diagnostics
-			.map(d => d.relatedInformation || [])
-			.reduce((p, c) => c.concat(p), [])
-			.map(relatedInformation => relatedInformation.file ? monaco.Uri.parse(relatedInformation.file.fileName) : null);
-
-		await this._libFiles.fetchLibFilesIfNecessary(relatedUris);
-
-		if (model.isDisposed()) {
-			// model was disposed in the meantime
-			return;
-		}
-
-		monaco.editor.setModelMarkers(model, this._selector, diagnostics.map(d => this._convertDiagnostics(model, d)));
-	}
-
-	private _convertDiagnostics(model: monaco.editor.ITextModel, diag: ts.Diagnostic): monaco.editor.IMarkerData {
-		const diagStart = diag.start || 0;
-		const diagLength = diag.length || 1;
-		const { lineNumber: startLineNumber, column: startColumn } = model.getPositionAt(diagStart);
-		const { lineNumber: endLineNumber, column: endColumn } = model.getPositionAt(diagStart + diagLength);
-
-		return {
-			severity: this._tsDiagnosticCategoryToMarkerSeverity(diag.category),
-			startLineNumber,
-			startColumn,
-			endLineNumber,
-			endColumn,
-			message: flattenDiagnosticMessageText(diag.messageText, '\n'),
-			code: diag.code.toString(),
-			tags: diag.reportsUnnecessary ? [monaco.MarkerTag.Unnecessary] : [],
-			relatedInformation: this._convertRelatedInformation(model, diag.relatedInformation),
-		};
-	}
-
-	private _convertRelatedInformation(model: monaco.editor.ITextModel, relatedInformation?: ts.DiagnosticRelatedInformation[]): monaco.editor.IRelatedInformation[] | undefined {
-		if (!relatedInformation) {
-			return;
-		}
-
-		const result: monaco.editor.IRelatedInformation[] = [];
-		relatedInformation.forEach((info) => {
-			let relatedResource: monaco.editor.ITextModel | null = model;
-			if (info.file) {
-				const relatedResourceUri = monaco.Uri.parse(info.file.fileName);
-				relatedResource = this._libFiles.getOrCreateModel(relatedResourceUri);
-			}
-
-			if (!relatedResource) {
-				return;
-			}
-			const infoStart = info.start || 0;
-			const infoLength = info.length || 1;
-			const { lineNumber: startLineNumber, column: startColumn } = relatedResource.getPositionAt(infoStart);
-			const { lineNumber: endLineNumber, column: endColumn } = relatedResource.getPositionAt(infoStart + infoLength);
-
-			result.push({
-				resource: relatedResource.uri,
-				startLineNumber,
-				startColumn,
-				endLineNumber,
-				endColumn,
-				message: flattenDiagnosticMessageText(info.messageText, '\n')
-			});
-		});
-		return result;
-	}
-
-	private _tsDiagnosticCategoryToMarkerSeverity(category: ts.DiagnosticCategory): monaco.MarkerSeverity {
-		switch (category) {
-			case DiagnosticCategory.Error: return monaco.MarkerSeverity.Error
-			case DiagnosticCategory.Message: return monaco.MarkerSeverity.Info
-			case DiagnosticCategory.Warning: return monaco.MarkerSeverity.Warning
-			case DiagnosticCategory.Suggestion: return monaco.MarkerSeverity.Hint
-		}
-		return monaco.MarkerSeverity.Info;
-	}
-}
-
-// --- suggest ------
-
-interface MyCompletionItem extends monaco.languages.CompletionItem {
-	label: string;
-	uri: Uri;
-	position: Position;
-}
-
-export class SuggestAdapter extends Adapter implements monaco.languages.CompletionItemProvider {
-
-	public get triggerCharacters(): string[] {
-		return ['.'];
-	}
-
-	public async provideCompletionItems(model: monaco.editor.ITextModel, position: Position, _context: monaco.languages.CompletionContext, token: CancellationToken): Promise<monaco.languages.CompletionList | undefined> {
-		const wordInfo = model.getWordUntilPosition(position);
-		const wordRange = new Range(position.lineNumber, wordInfo.startColumn, position.lineNumber, wordInfo.endColumn);
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position);
-
-		const worker = await this._worker(resource);
-		const info = await worker.getCompletionsAtPosition(resource.toString(), offset);
-
-		if (!info || model.isDisposed()) {
-			return;
-		}
-
-		const suggestions: MyCompletionItem[] = info.entries.map(entry => {
-			let range = wordRange;
-			if (entry.replacementSpan) {
-				const p1 = model.getPositionAt(entry.replacementSpan.start);
-				const p2 = model.getPositionAt(entry.replacementSpan.start + entry.replacementSpan.length);
-				range = new Range(p1.lineNumber, p1.column, p2.lineNumber, p2.column);
-			}
-
-			return {
-				uri: resource,
-				position: position,
-				range: range,
-				label: entry.name,
-				insertText: entry.name,
-				sortText: entry.sortText,
-				kind: SuggestAdapter.convertKind(entry.kind)
-			};
-		});
-
-		return {
-			suggestions
-		};
-	}
-
-	public async resolveCompletionItem(model: monaco.editor.ITextModel, _position: Position, item: monaco.languages.CompletionItem, token: CancellationToken): Promise<monaco.languages.CompletionItem> {
-		const myItem = <MyCompletionItem>item;
-		const resource = myItem.uri;
-		const position = myItem.position;
-		const offset = model.getOffsetAt(position);
-
-		const worker = await this._worker(resource);
-		const details = await worker.getCompletionEntryDetails(resource.toString(), offset, myItem.label);
-		if (!details || model.isDisposed()) {
-			return myItem;
-		}
-		return <MyCompletionItem>{
-			uri: resource,
-			position: position,
-			label: details.name,
-			kind: SuggestAdapter.convertKind(details.kind),
-			detail: displayPartsToString(details.displayParts),
-			documentation: {
-				value: displayPartsToString(details.documentation)
-			}
-		};
-	}
-
-	private static convertKind(kind: string): monaco.languages.CompletionItemKind {
-		switch (kind) {
-			case Kind.primitiveType:
-			case Kind.keyword:
-				return monaco.languages.CompletionItemKind.Keyword;
-			case Kind.variable:
-			case Kind.localVariable:
-				return monaco.languages.CompletionItemKind.Variable;
-			case Kind.memberVariable:
-			case Kind.memberGetAccessor:
-			case Kind.memberSetAccessor:
-				return monaco.languages.CompletionItemKind.Field;
-			case Kind.function:
-			case Kind.memberFunction:
-			case Kind.constructSignature:
-			case Kind.callSignature:
-			case Kind.indexSignature:
-				return monaco.languages.CompletionItemKind.Function;
-			case Kind.enum:
-				return monaco.languages.CompletionItemKind.Enum;
-			case Kind.module:
-				return monaco.languages.CompletionItemKind.Module;
-			case Kind.class:
-				return monaco.languages.CompletionItemKind.Class;
-			case Kind.interface:
-				return monaco.languages.CompletionItemKind.Interface;
-			case Kind.warning:
-				return monaco.languages.CompletionItemKind.File;
-		}
-
-		return monaco.languages.CompletionItemKind.Property;
-	}
-}
-
-export class SignatureHelpAdapter extends Adapter implements monaco.languages.SignatureHelpProvider {
-
-	public signatureHelpTriggerCharacters = ['(', ','];
-
-	public async provideSignatureHelp(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.SignatureHelpResult | undefined> {
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position);
-		const worker = await this._worker(resource);
-		const info = await worker.getSignatureHelpItems(resource.toString(), offset);
-
-		if (!info || model.isDisposed()) {
-			return;
-		}
-
-		const ret: monaco.languages.SignatureHelp = {
-			activeSignature: info.selectedItemIndex,
-			activeParameter: info.argumentIndex,
-			signatures: []
-		};
-
-		info.items.forEach(item => {
-
-			const signature: monaco.languages.SignatureInformation = {
-				label: '',
-				parameters: []
-			};
-
-			signature.documentation = {
-				value: displayPartsToString(item.documentation)
-			};
-			signature.label += displayPartsToString(item.prefixDisplayParts);
-			item.parameters.forEach((p, i, a) => {
-				const label = displayPartsToString(p.displayParts);
-				const parameter: monaco.languages.ParameterInformation = {
-					label: label,
-					documentation: {
-						value: displayPartsToString(p.documentation)
-					}
-				};
-				signature.label += label;
-				signature.parameters.push(parameter);
-				if (i < a.length - 1) {
-					signature.label += displayPartsToString(item.separatorDisplayParts);
-				}
-			});
-			signature.label += displayPartsToString(item.suffixDisplayParts);
-			ret.signatures.push(signature);
-		});
-
-		return {
-			value: ret,
-			dispose() { }
-		};
-	}
-}
-
-// --- hover ------
-
-export class QuickInfoAdapter extends Adapter implements monaco.languages.HoverProvider {
-
-	public async provideHover(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.Hover | undefined> {
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position);
-		const worker = await this._worker(resource);
-		const info = await worker.getQuickInfoAtPosition(resource.toString(), offset);
-
-		if (!info || model.isDisposed()) {
-			return;
-		}
-
-		const documentation = displayPartsToString(info.documentation);
-		const tags = info.tags ? info.tags.map(tag => {
-			const label = `*@${tag.name}*`;
-			if (!tag.text) {
-				return label;
-			}
-			return label + (tag.text.match(/\r\n|\n/g) ? ' \n' + tag.text : ` - ${tag.text}`);
-		}).join('  \n\n') : '';
-		const contents = displayPartsToString(info.displayParts);
-		return {
-			range: this._textSpanToRange(model, info.textSpan),
-			contents: [{
-				value: '```js\n' + contents + '\n```\n'
-			}, {
-				value: documentation + (tags ? '\n\n' + tags : '')
-			}]
-		};
-	}
-}
-
-// --- occurrences ------
-
-export class OccurrencesAdapter extends Adapter implements monaco.languages.DocumentHighlightProvider {
-
-	public async provideDocumentHighlights(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.DocumentHighlight[] | undefined> {
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position)
-		const worker = await this._worker(resource);
-		const entries = await worker.getOccurrencesAtPosition(resource.toString(), offset);
-
-		if (!entries || model.isDisposed()) {
-			return;
-		}
-
-		return entries.map(entry => {
-			return <monaco.languages.DocumentHighlight>{
-				range: this._textSpanToRange(model, entry.textSpan),
-				kind: entry.isWriteAccess ? monaco.languages.DocumentHighlightKind.Write : monaco.languages.DocumentHighlightKind.Text
-			};
-		});
-	}
-}
-
-// --- definition ------
-
-export class DefinitionAdapter extends Adapter {
-
-	constructor(
-		private readonly _libFiles: LibFiles,
-		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
-	) {
-		super(worker);
-	}
-
-	public async provideDefinition(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.Definition | undefined> {
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position);
-		const worker = await this._worker(resource);
-		const entries = await worker.getDefinitionAtPosition(resource.toString(), offset);
-
-		if (!entries || model.isDisposed()) {
-			return;
-		}
-
-		// Fetch lib files if necessary
-		await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName)));
-
-		if (model.isDisposed()) {
-			return;
-		}
-
-		const result: monaco.languages.Location[] = [];
-		for (let entry of entries) {
-			const uri = Uri.parse(entry.fileName);
-			const refModel = this._libFiles.getOrCreateModel(uri);
-			if (refModel) {
-				result.push({
-					uri: uri,
-					range: this._textSpanToRange(refModel, entry.textSpan)
-				});
-			}
-		}
-		return result;
-	}
-}
-
-// --- references ------
-
-export class ReferenceAdapter extends Adapter implements monaco.languages.ReferenceProvider {
-
-	constructor(
-		private readonly _libFiles: LibFiles,
-		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
-	) {
-		super(worker);
-	}
-
-	public async provideReferences(model: monaco.editor.ITextModel, position: Position, context: monaco.languages.ReferenceContext, token: CancellationToken): Promise<monaco.languages.Location[] | undefined> {
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position);
-		const worker = await this._worker(resource);
-		const entries = await worker.getReferencesAtPosition(resource.toString(), offset);
-
-		if (!entries || model.isDisposed()) {
-			return;
-		}
-
-		// Fetch lib files if necessary
-		await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName)));
-
-		if (model.isDisposed()) {
-			return;
-		}
-
-		const result: monaco.languages.Location[] = [];
-		for (let entry of entries) {
-			const uri = Uri.parse(entry.fileName);
-			const refModel = this._libFiles.getOrCreateModel(uri);
-			if (refModel) {
-				result.push({
-					uri: uri,
-					range: this._textSpanToRange(refModel, entry.textSpan)
-				});
-			}
-		}
-		return result;
-	}
-}
-
-// --- outline ------
-
-export class OutlineAdapter extends Adapter implements monaco.languages.DocumentSymbolProvider {
-
-	public async provideDocumentSymbols(model: monaco.editor.ITextModel, token: CancellationToken): Promise<monaco.languages.DocumentSymbol[] | undefined> {
-		const resource = model.uri;
-		const worker = await this._worker(resource);
-		const items = await worker.getNavigationBarItems(resource.toString());
-
-		if (!items || model.isDisposed()) {
-			return;
-		}
-
-		const convert = (bucket: monaco.languages.DocumentSymbol[], item: ts.NavigationBarItem, containerLabel?: string): void => {
-			let result: monaco.languages.DocumentSymbol = {
-				name: item.text,
-				detail: '',
-				kind: <monaco.languages.SymbolKind>(outlineTypeTable[item.kind] || monaco.languages.SymbolKind.Variable),
-				range: this._textSpanToRange(model, item.spans[0]),
-				selectionRange: this._textSpanToRange(model, item.spans[0]),
-				tags: [],
-				containerName: containerLabel
-			};
-
-			if (item.childItems && item.childItems.length > 0) {
-				for (let child of item.childItems) {
-					convert(bucket, child, result.name);
-				}
-			}
-
-			bucket.push(result);
-		}
-
-		let result: monaco.languages.DocumentSymbol[] = [];
-		items.forEach(item => convert(result, item));
-		return result;
-	}
-}
-
-export class Kind {
-	public static unknown: string = '';
-	public static keyword: string = 'keyword';
-	public static script: string = 'script';
-	public static module: string = 'module';
-	public static class: string = 'class';
-	public static interface: string = 'interface';
-	public static type: string = 'type';
-	public static enum: string = 'enum';
-	public static variable: string = 'var';
-	public static localVariable: string = 'local var';
-	public static function: string = 'function';
-	public static localFunction: string = 'local function';
-	public static memberFunction: string = 'method';
-	public static memberGetAccessor: string = 'getter';
-	public static memberSetAccessor: string = 'setter';
-	public static memberVariable: string = 'property';
-	public static constructorImplementation: string = 'constructor';
-	public static callSignature: string = 'call';
-	public static indexSignature: string = 'index';
-	public static constructSignature: string = 'construct';
-	public static parameter: string = 'parameter';
-	public static typeParameter: string = 'type parameter';
-	public static primitiveType: string = 'primitive type';
-	public static label: string = 'label';
-	public static alias: string = 'alias';
-	public static const: string = 'const';
-	public static let: string = 'let';
-	public static warning: string = 'warning';
-}
-
-let outlineTypeTable: { [kind: string]: monaco.languages.SymbolKind } = Object.create(null);
-outlineTypeTable[Kind.module] = monaco.languages.SymbolKind.Module;
-outlineTypeTable[Kind.class] = monaco.languages.SymbolKind.Class;
-outlineTypeTable[Kind.enum] = monaco.languages.SymbolKind.Enum;
-outlineTypeTable[Kind.interface] = monaco.languages.SymbolKind.Interface;
-outlineTypeTable[Kind.memberFunction] = monaco.languages.SymbolKind.Method;
-outlineTypeTable[Kind.memberVariable] = monaco.languages.SymbolKind.Property;
-outlineTypeTable[Kind.memberGetAccessor] = monaco.languages.SymbolKind.Property;
-outlineTypeTable[Kind.memberSetAccessor] = monaco.languages.SymbolKind.Property;
-outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
-outlineTypeTable[Kind.const] = monaco.languages.SymbolKind.Variable;
-outlineTypeTable[Kind.localVariable] = monaco.languages.SymbolKind.Variable;
-outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
-outlineTypeTable[Kind.function] = monaco.languages.SymbolKind.Function;
-outlineTypeTable[Kind.localFunction] = monaco.languages.SymbolKind.Function;
-
-// --- formatting ----
-
-export abstract class FormatHelper extends Adapter {
-	protected static _convertOptions(options: monaco.languages.FormattingOptions): ts.FormatCodeOptions {
-		return {
-			ConvertTabsToSpaces: options.insertSpaces,
-			TabSize: options.tabSize,
-			IndentSize: options.tabSize,
-			IndentStyle: IndentStyle.Smart,
-			NewLineCharacter: '\n',
-			InsertSpaceAfterCommaDelimiter: true,
-			InsertSpaceAfterSemicolonInForStatements: true,
-			InsertSpaceBeforeAndAfterBinaryOperators: true,
-			InsertSpaceAfterKeywordsInControlFlowStatements: true,
-			InsertSpaceAfterFunctionKeywordForAnonymousFunctions: true,
-			InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
-			InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
-			InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
-			PlaceOpenBraceOnNewLineForControlBlocks: false,
-			PlaceOpenBraceOnNewLineForFunctions: false
-		};
-	}
-
-	protected _convertTextChanges(model: monaco.editor.ITextModel, change: ts.TextChange): monaco.languages.TextEdit {
-		return {
-			text: change.newText,
-			range: this._textSpanToRange(model, change.span)
-		};
-	}
-}
-
-export class FormatAdapter extends FormatHelper implements monaco.languages.DocumentRangeFormattingEditProvider {
-
-	public async provideDocumentRangeFormattingEdits(model: monaco.editor.ITextModel, range: Range, options: monaco.languages.FormattingOptions, token: CancellationToken): Promise<monaco.languages.TextEdit[] | undefined> {
-		const resource = model.uri;
-		const startOffset = model.getOffsetAt({ lineNumber: range.startLineNumber, column: range.startColumn });
-		const endOffset = model.getOffsetAt({ lineNumber: range.endLineNumber, column: range.endColumn });
-		const worker = await this._worker(resource);
-		const edits = await worker.getFormattingEditsForRange(resource.toString(), startOffset, endOffset, FormatHelper._convertOptions(options));
-
-		if (!edits || model.isDisposed()) {
-			return;
-		}
-
-		return edits.map(edit => this._convertTextChanges(model, edit));
-	}
-}
-
-export class FormatOnTypeAdapter extends FormatHelper implements monaco.languages.OnTypeFormattingEditProvider {
-
-	get autoFormatTriggerCharacters() {
-		return [';', '}', '\n'];
-	}
-
-	public async provideOnTypeFormattingEdits(model: monaco.editor.ITextModel, position: Position, ch: string, options: monaco.languages.FormattingOptions, token: CancellationToken): Promise<monaco.languages.TextEdit[] | undefined> {
-		const resource = model.uri;
-		const offset = model.getOffsetAt(position);
-		const worker = await this._worker(resource);
-		const edits = await worker.getFormattingEditsAfterKeystroke(resource.toString(), offset, ch, FormatHelper._convertOptions(options));
-
-		if (!edits || model.isDisposed()) {
-			return;
-		}
-
-		return edits.map(edit => this._convertTextChanges(model, edit));
-	}
-}
-
-// --- code actions ------
-
-export class CodeActionAdaptor extends FormatHelper implements monaco.languages.CodeActionProvider {
-
-	public async provideCodeActions(model: monaco.editor.ITextModel, range: Range, context: monaco.languages.CodeActionContext, token: CancellationToken): Promise<monaco.languages.CodeActionList> {
-		const resource = model.uri;
-		const start = model.getOffsetAt({ lineNumber: range.startLineNumber, column: range.startColumn });
-		const end = model.getOffsetAt({ lineNumber: range.endLineNumber, column: range.endColumn });
-		const formatOptions = FormatHelper._convertOptions(model.getOptions());
-		const errorCodes = context.markers.filter(m => m.code).map(m => m.code).map(Number);
-		const worker = await this._worker(resource);
-		const codeFixes = await worker.getCodeFixesAtPosition(resource.toString(), start, end, errorCodes, formatOptions);
-
-		if (!codeFixes || model.isDisposed()) {
-			return { actions: [], dispose: () => { } };
-		}
-
-		const actions = codeFixes.filter(fix => {
-			// Removes any 'make a new file'-type code fix
-			return fix.changes.filter(change => change.isNewFile).length === 0;
-		}).map(fix => {
-			return this._tsCodeFixActionToMonacoCodeAction(model, context, fix);
-		});
-
-		return {
-			actions: actions,
-			dispose: () => { }
-		};
-	}
-
-
-	private _tsCodeFixActionToMonacoCodeAction(model: monaco.editor.ITextModel, context: monaco.languages.CodeActionContext, codeFix: ts.CodeFixAction): monaco.languages.CodeAction {
-		const edits: monaco.languages.WorkspaceTextEdit[] = [];
-		for (const change of codeFix.changes) {
-			for (const textChange of change.textChanges) {
-				edits.push({
-					resource: model.uri,
-					edit: {
-						range: this._textSpanToRange(model, textChange.span),
-						text: textChange.newText
-					}
-				});
-			}
-		}
-
-		const action: monaco.languages.CodeAction = {
-			title: codeFix.description,
-			edit: { edits: edits },
-			diagnostics: context.markers,
-			kind: "quickfix"
-		};
-
-		return action;
-	}
-}
-// --- rename ----
-
-export class RenameAdapter extends Adapter implements monaco.languages.RenameProvider {
-
-	public async provideRenameEdits(model: monaco.editor.ITextModel, position: Position, newName: string, token: CancellationToken): Promise<monaco.languages.WorkspaceEdit & monaco.languages.Rejection | undefined> {
-		const resource = model.uri;
-		const fileName = resource.toString();
-		const offset = model.getOffsetAt(position);
-		const worker = await this._worker(resource);
-
-		const renameInfo = await worker.getRenameInfo(fileName, offset, { allowRenameOfImportPath: false });
-		if (renameInfo.canRename === false) { // use explicit comparison so that the discriminated union gets resolved properly
-			return {
-				edits: [],
-				rejectReason: renameInfo.localizedErrorMessage
-			};
-		}
-		if (renameInfo.fileToRename !== undefined) {
-			throw new Error("Renaming files is not supported.");
-		}
-
-		const renameLocations = await worker.findRenameLocations(fileName, offset, /*strings*/ false, /*comments*/ false, /*prefixAndSuffix*/ false);
-
-		if (!renameLocations || model.isDisposed()) {
-			return;
-		}
-
-		const edits: monaco.languages.WorkspaceTextEdit[] = [];
-		for (const renameLocation of renameLocations) {
-			edits.push({
-				resource: monaco.Uri.parse(renameLocation.fileName),
-				edit: {
-					range: this._textSpanToRange(model, renameLocation.textSpan),
-					text: newName
-				}
-			});
-		}
-
-		return { edits };
-	}
-}
+/*---------------------------------------------------------------------------------------------
+ *  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 { LanguageServiceDefaultsImpl } from './monaco.contribution';
+import * as ts from './lib/typescriptServices';
+import { TypeScriptWorker } from './tsWorker';
+import { libFileSet } from './lib/lib.index';
+
+import Uri = monaco.Uri;
+import Position = monaco.Position;
+import Range = monaco.Range;
+import CancellationToken = monaco.CancellationToken;
+import IDisposable = monaco.IDisposable;
+
+//#region utils copied from typescript to prevent loading the entire typescriptServices ---
+
+enum IndentStyle {
+	None = 0,
+	Block = 1,
+	Smart = 2
+}
+
+export function flattenDiagnosticMessageText(
+	diag: string | ts.DiagnosticMessageChain | undefined,
+	newLine: string,
+	indent = 0
+): string {
+	if (typeof diag === 'string') {
+		return diag;
+	} else if (diag === undefined) {
+		return '';
+	}
+	let result = '';
+	if (indent) {
+		result += newLine;
+
+		for (let i = 0; i < indent; i++) {
+			result += '  ';
+		}
+	}
+	result += diag.messageText;
+	indent++;
+	if (diag.next) {
+		for (const kid of diag.next) {
+			result += flattenDiagnosticMessageText(kid, newLine, indent);
+		}
+	}
+	return result;
+}
+
+function displayPartsToString(
+	displayParts: ts.SymbolDisplayPart[] | undefined
+): string {
+	if (displayParts) {
+		return displayParts.map((displayPart) => displayPart.text).join('');
+	}
+	return '';
+}
+
+//#endregion
+
+export abstract class Adapter {
+	constructor(
+		protected _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
+	) {}
+
+	// protected _positionToOffset(model: monaco.editor.ITextModel, position: monaco.IPosition): number {
+	// 	return model.getOffsetAt(position);
+	// }
+
+	// protected _offsetToPosition(model: monaco.editor.ITextModel, offset: number): monaco.IPosition {
+	// 	return model.getPositionAt(offset);
+	// }
+
+	protected _textSpanToRange(
+		model: monaco.editor.ITextModel,
+		span: ts.TextSpan
+	): monaco.IRange {
+		let p1 = model.getPositionAt(span.start);
+		let p2 = model.getPositionAt(span.start + span.length);
+		let { lineNumber: startLineNumber, column: startColumn } = p1;
+		let { lineNumber: endLineNumber, column: endColumn } = p2;
+		return { startLineNumber, startColumn, endLineNumber, endColumn };
+	}
+}
+
+// --- lib files
+
+export class LibFiles {
+	private _libFiles: Record<string, string>;
+	private _hasFetchedLibFiles: boolean;
+	private _fetchLibFilesPromise: Promise<void> | null;
+
+	constructor(
+		private readonly _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
+	) {
+		this._libFiles = {};
+		this._hasFetchedLibFiles = false;
+		this._fetchLibFilesPromise = null;
+	}
+
+	public isLibFile(uri: Uri | null): boolean {
+		if (!uri) {
+			return false;
+		}
+		if (uri.path.indexOf('/lib.') === 0) {
+			return !!libFileSet[uri.path.slice(1)];
+		}
+		return false;
+	}
+
+	public getOrCreateModel(uri: Uri): monaco.editor.ITextModel | null {
+		const model = monaco.editor.getModel(uri);
+		if (model) {
+			return model;
+		}
+		if (this.isLibFile(uri) && this._hasFetchedLibFiles) {
+			return monaco.editor.createModel(
+				this._libFiles[uri.path.slice(1)],
+				'javascript',
+				uri
+			);
+		}
+		return null;
+	}
+
+	private _containsLibFile(uris: (Uri | null)[]): boolean {
+		for (let uri of uris) {
+			if (this.isLibFile(uri)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public async fetchLibFilesIfNecessary(uris: (Uri | null)[]): Promise<void> {
+		if (!this._containsLibFile(uris)) {
+			// no lib files necessary
+			return;
+		}
+		await this._fetchLibFiles();
+	}
+
+	private _fetchLibFiles(): Promise<void> {
+		if (!this._fetchLibFilesPromise) {
+			this._fetchLibFilesPromise = this._worker()
+				.then((w) => w.getLibFiles())
+				.then((libFiles) => {
+					this._hasFetchedLibFiles = true;
+					this._libFiles = libFiles;
+				});
+		}
+		return this._fetchLibFilesPromise;
+	}
+}
+
+// --- diagnostics --- ---
+
+enum DiagnosticCategory {
+	Warning = 0,
+	Error = 1,
+	Suggestion = 2,
+	Message = 3
+}
+
+export class DiagnosticsAdapter extends Adapter {
+	private _disposables: IDisposable[] = [];
+	private _listener: { [uri: string]: IDisposable } = Object.create(null);
+
+	constructor(
+		private readonly _libFiles: LibFiles,
+		private _defaults: LanguageServiceDefaultsImpl,
+		private _selector: string,
+		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
+	) {
+		super(worker);
+
+		const onModelAdd = (model: monaco.editor.IModel): void => {
+			if (model.getModeId() !== _selector) {
+				return;
+			}
+
+			let handle: number;
+			const changeSubscription = model.onDidChangeContent(() => {
+				clearTimeout(handle);
+				handle = setTimeout(() => this._doValidate(model), 500);
+			});
+
+			this._listener[model.uri.toString()] = {
+				dispose() {
+					changeSubscription.dispose();
+					clearTimeout(handle);
+				}
+			};
+
+			this._doValidate(model);
+		};
+
+		const onModelRemoved = (model: monaco.editor.IModel): void => {
+			monaco.editor.setModelMarkers(model, this._selector, []);
+			const key = model.uri.toString();
+			if (this._listener[key]) {
+				this._listener[key].dispose();
+				delete this._listener[key];
+			}
+		};
+
+		this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
+		this._disposables.push(monaco.editor.onWillDisposeModel(onModelRemoved));
+		this._disposables.push(
+			monaco.editor.onDidChangeModelLanguage((event) => {
+				onModelRemoved(event.model);
+				onModelAdd(event.model);
+			})
+		);
+
+		this._disposables.push({
+			dispose() {
+				for (const model of monaco.editor.getModels()) {
+					onModelRemoved(model);
+				}
+			}
+		});
+
+		const recomputeDiagostics = () => {
+			// redo diagnostics when options change
+			for (const model of monaco.editor.getModels()) {
+				onModelRemoved(model);
+				onModelAdd(model);
+			}
+		};
+		this._disposables.push(this._defaults.onDidChange(recomputeDiagostics));
+		this._disposables.push(
+			this._defaults.onDidExtraLibsChange(recomputeDiagostics)
+		);
+
+		monaco.editor.getModels().forEach(onModelAdd);
+	}
+
+	public dispose(): void {
+		this._disposables.forEach((d) => d && d.dispose());
+		this._disposables = [];
+	}
+
+	private async _doValidate(model: monaco.editor.ITextModel): Promise<void> {
+		const worker = await this._worker(model.uri);
+
+		if (model.isDisposed()) {
+			// model was disposed in the meantime
+			return;
+		}
+
+		const promises: Promise<ts.Diagnostic[]>[] = [];
+		const {
+			noSyntaxValidation,
+			noSemanticValidation,
+			noSuggestionDiagnostics
+		} = this._defaults.getDiagnosticsOptions();
+		if (!noSyntaxValidation) {
+			promises.push(worker.getSyntacticDiagnostics(model.uri.toString()));
+		}
+		if (!noSemanticValidation) {
+			promises.push(worker.getSemanticDiagnostics(model.uri.toString()));
+		}
+		if (!noSuggestionDiagnostics) {
+			promises.push(worker.getSuggestionDiagnostics(model.uri.toString()));
+		}
+
+		const allDiagnostics = await Promise.all(promises);
+
+		if (!allDiagnostics || model.isDisposed()) {
+			// model was disposed in the meantime
+			return;
+		}
+
+		const diagnostics = allDiagnostics
+			.reduce((p, c) => c.concat(p), [])
+			.filter(
+				(d) =>
+					(
+						this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []
+					).indexOf(d.code) === -1
+			);
+
+		// Fetch lib files if necessary
+		const relatedUris = diagnostics
+			.map((d) => d.relatedInformation || [])
+			.reduce((p, c) => c.concat(p), [])
+			.map((relatedInformation) =>
+				relatedInformation.file
+					? monaco.Uri.parse(relatedInformation.file.fileName)
+					: null
+			);
+
+		await this._libFiles.fetchLibFilesIfNecessary(relatedUris);
+
+		if (model.isDisposed()) {
+			// model was disposed in the meantime
+			return;
+		}
+
+		monaco.editor.setModelMarkers(
+			model,
+			this._selector,
+			diagnostics.map((d) => this._convertDiagnostics(model, d))
+		);
+	}
+
+	private _convertDiagnostics(
+		model: monaco.editor.ITextModel,
+		diag: ts.Diagnostic
+	): monaco.editor.IMarkerData {
+		const diagStart = diag.start || 0;
+		const diagLength = diag.length || 1;
+		const {
+			lineNumber: startLineNumber,
+			column: startColumn
+		} = model.getPositionAt(diagStart);
+		const {
+			lineNumber: endLineNumber,
+			column: endColumn
+		} = model.getPositionAt(diagStart + diagLength);
+
+		return {
+			severity: this._tsDiagnosticCategoryToMarkerSeverity(diag.category),
+			startLineNumber,
+			startColumn,
+			endLineNumber,
+			endColumn,
+			message: flattenDiagnosticMessageText(diag.messageText, '\n'),
+			code: diag.code.toString(),
+			tags: diag.reportsUnnecessary ? [monaco.MarkerTag.Unnecessary] : [],
+			relatedInformation: this._convertRelatedInformation(
+				model,
+				diag.relatedInformation
+			)
+		};
+	}
+
+	private _convertRelatedInformation(
+		model: monaco.editor.ITextModel,
+		relatedInformation?: ts.DiagnosticRelatedInformation[]
+	): monaco.editor.IRelatedInformation[] | undefined {
+		if (!relatedInformation) {
+			return;
+		}
+
+		const result: monaco.editor.IRelatedInformation[] = [];
+		relatedInformation.forEach((info) => {
+			let relatedResource: monaco.editor.ITextModel | null = model;
+			if (info.file) {
+				const relatedResourceUri = monaco.Uri.parse(info.file.fileName);
+				relatedResource = this._libFiles.getOrCreateModel(relatedResourceUri);
+			}
+
+			if (!relatedResource) {
+				return;
+			}
+			const infoStart = info.start || 0;
+			const infoLength = info.length || 1;
+			const {
+				lineNumber: startLineNumber,
+				column: startColumn
+			} = relatedResource.getPositionAt(infoStart);
+			const {
+				lineNumber: endLineNumber,
+				column: endColumn
+			} = relatedResource.getPositionAt(infoStart + infoLength);
+
+			result.push({
+				resource: relatedResource.uri,
+				startLineNumber,
+				startColumn,
+				endLineNumber,
+				endColumn,
+				message: flattenDiagnosticMessageText(info.messageText, '\n')
+			});
+		});
+		return result;
+	}
+
+	private _tsDiagnosticCategoryToMarkerSeverity(
+		category: ts.DiagnosticCategory
+	): monaco.MarkerSeverity {
+		switch (category) {
+			case DiagnosticCategory.Error:
+				return monaco.MarkerSeverity.Error;
+			case DiagnosticCategory.Message:
+				return monaco.MarkerSeverity.Info;
+			case DiagnosticCategory.Warning:
+				return monaco.MarkerSeverity.Warning;
+			case DiagnosticCategory.Suggestion:
+				return monaco.MarkerSeverity.Hint;
+		}
+		return monaco.MarkerSeverity.Info;
+	}
+}
+
+// --- suggest ------
+
+interface MyCompletionItem extends monaco.languages.CompletionItem {
+	label: string;
+	uri: Uri;
+	position: Position;
+}
+
+export class SuggestAdapter
+	extends Adapter
+	implements monaco.languages.CompletionItemProvider {
+	public get triggerCharacters(): string[] {
+		return ['.'];
+	}
+
+	public async provideCompletionItems(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		_context: monaco.languages.CompletionContext,
+		token: CancellationToken
+	): Promise<monaco.languages.CompletionList | undefined> {
+		const wordInfo = model.getWordUntilPosition(position);
+		const wordRange = new Range(
+			position.lineNumber,
+			wordInfo.startColumn,
+			position.lineNumber,
+			wordInfo.endColumn
+		);
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+
+		const worker = await this._worker(resource);
+		const info = await worker.getCompletionsAtPosition(
+			resource.toString(),
+			offset
+		);
+
+		if (!info || model.isDisposed()) {
+			return;
+		}
+
+		const suggestions: MyCompletionItem[] = info.entries.map((entry) => {
+			let range = wordRange;
+			if (entry.replacementSpan) {
+				const p1 = model.getPositionAt(entry.replacementSpan.start);
+				const p2 = model.getPositionAt(
+					entry.replacementSpan.start + entry.replacementSpan.length
+				);
+				range = new Range(p1.lineNumber, p1.column, p2.lineNumber, p2.column);
+			}
+
+			return {
+				uri: resource,
+				position: position,
+				range: range,
+				label: entry.name,
+				insertText: entry.name,
+				sortText: entry.sortText,
+				kind: SuggestAdapter.convertKind(entry.kind)
+			};
+		});
+
+		return {
+			suggestions
+		};
+	}
+
+	public async resolveCompletionItem(
+		model: monaco.editor.ITextModel,
+		_position: Position,
+		item: monaco.languages.CompletionItem,
+		token: CancellationToken
+	): Promise<monaco.languages.CompletionItem> {
+		const myItem = <MyCompletionItem>item;
+		const resource = myItem.uri;
+		const position = myItem.position;
+		const offset = model.getOffsetAt(position);
+
+		const worker = await this._worker(resource);
+		const details = await worker.getCompletionEntryDetails(
+			resource.toString(),
+			offset,
+			myItem.label
+		);
+		if (!details || model.isDisposed()) {
+			return myItem;
+		}
+		return <MyCompletionItem>{
+			uri: resource,
+			position: position,
+			label: details.name,
+			kind: SuggestAdapter.convertKind(details.kind),
+			detail: displayPartsToString(details.displayParts),
+			documentation: {
+				value: displayPartsToString(details.documentation)
+			}
+		};
+	}
+
+	private static convertKind(
+		kind: string
+	): monaco.languages.CompletionItemKind {
+		switch (kind) {
+			case Kind.primitiveType:
+			case Kind.keyword:
+				return monaco.languages.CompletionItemKind.Keyword;
+			case Kind.variable:
+			case Kind.localVariable:
+				return monaco.languages.CompletionItemKind.Variable;
+			case Kind.memberVariable:
+			case Kind.memberGetAccessor:
+			case Kind.memberSetAccessor:
+				return monaco.languages.CompletionItemKind.Field;
+			case Kind.function:
+			case Kind.memberFunction:
+			case Kind.constructSignature:
+			case Kind.callSignature:
+			case Kind.indexSignature:
+				return monaco.languages.CompletionItemKind.Function;
+			case Kind.enum:
+				return monaco.languages.CompletionItemKind.Enum;
+			case Kind.module:
+				return monaco.languages.CompletionItemKind.Module;
+			case Kind.class:
+				return monaco.languages.CompletionItemKind.Class;
+			case Kind.interface:
+				return monaco.languages.CompletionItemKind.Interface;
+			case Kind.warning:
+				return monaco.languages.CompletionItemKind.File;
+		}
+
+		return monaco.languages.CompletionItemKind.Property;
+	}
+}
+
+export class SignatureHelpAdapter
+	extends Adapter
+	implements monaco.languages.SignatureHelpProvider {
+	public signatureHelpTriggerCharacters = ['(', ','];
+
+	public async provideSignatureHelp(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		token: CancellationToken
+	): Promise<monaco.languages.SignatureHelpResult | undefined> {
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+		const info = await worker.getSignatureHelpItems(
+			resource.toString(),
+			offset
+		);
+
+		if (!info || model.isDisposed()) {
+			return;
+		}
+
+		const ret: monaco.languages.SignatureHelp = {
+			activeSignature: info.selectedItemIndex,
+			activeParameter: info.argumentIndex,
+			signatures: []
+		};
+
+		info.items.forEach((item) => {
+			const signature: monaco.languages.SignatureInformation = {
+				label: '',
+				parameters: []
+			};
+
+			signature.documentation = {
+				value: displayPartsToString(item.documentation)
+			};
+			signature.label += displayPartsToString(item.prefixDisplayParts);
+			item.parameters.forEach((p, i, a) => {
+				const label = displayPartsToString(p.displayParts);
+				const parameter: monaco.languages.ParameterInformation = {
+					label: label,
+					documentation: {
+						value: displayPartsToString(p.documentation)
+					}
+				};
+				signature.label += label;
+				signature.parameters.push(parameter);
+				if (i < a.length - 1) {
+					signature.label += displayPartsToString(item.separatorDisplayParts);
+				}
+			});
+			signature.label += displayPartsToString(item.suffixDisplayParts);
+			ret.signatures.push(signature);
+		});
+
+		return {
+			value: ret,
+			dispose() {}
+		};
+	}
+}
+
+// --- hover ------
+
+export class QuickInfoAdapter
+	extends Adapter
+	implements monaco.languages.HoverProvider {
+	public async provideHover(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		token: CancellationToken
+	): Promise<monaco.languages.Hover | undefined> {
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+		const info = await worker.getQuickInfoAtPosition(
+			resource.toString(),
+			offset
+		);
+
+		if (!info || model.isDisposed()) {
+			return;
+		}
+
+		const documentation = displayPartsToString(info.documentation);
+		const tags = info.tags
+			? info.tags
+					.map((tag) => {
+						const label = `*@${tag.name}*`;
+						if (!tag.text) {
+							return label;
+						}
+						return (
+							label +
+							(tag.text.match(/\r\n|\n/g) ? ' \n' + tag.text : ` - ${tag.text}`)
+						);
+					})
+					.join('  \n\n')
+			: '';
+		const contents = displayPartsToString(info.displayParts);
+		return {
+			range: this._textSpanToRange(model, info.textSpan),
+			contents: [
+				{
+					value: '```js\n' + contents + '\n```\n'
+				},
+				{
+					value: documentation + (tags ? '\n\n' + tags : '')
+				}
+			]
+		};
+	}
+}
+
+// --- occurrences ------
+
+export class OccurrencesAdapter
+	extends Adapter
+	implements monaco.languages.DocumentHighlightProvider {
+	public async provideDocumentHighlights(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		token: CancellationToken
+	): Promise<monaco.languages.DocumentHighlight[] | undefined> {
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+		const entries = await worker.getOccurrencesAtPosition(
+			resource.toString(),
+			offset
+		);
+
+		if (!entries || model.isDisposed()) {
+			return;
+		}
+
+		return entries.map((entry) => {
+			return <monaco.languages.DocumentHighlight>{
+				range: this._textSpanToRange(model, entry.textSpan),
+				kind: entry.isWriteAccess
+					? monaco.languages.DocumentHighlightKind.Write
+					: monaco.languages.DocumentHighlightKind.Text
+			};
+		});
+	}
+}
+
+// --- definition ------
+
+export class DefinitionAdapter extends Adapter {
+	constructor(
+		private readonly _libFiles: LibFiles,
+		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
+	) {
+		super(worker);
+	}
+
+	public async provideDefinition(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		token: CancellationToken
+	): Promise<monaco.languages.Definition | undefined> {
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+		const entries = await worker.getDefinitionAtPosition(
+			resource.toString(),
+			offset
+		);
+
+		if (!entries || model.isDisposed()) {
+			return;
+		}
+
+		// Fetch lib files if necessary
+		await this._libFiles.fetchLibFilesIfNecessary(
+			entries.map((entry) => Uri.parse(entry.fileName))
+		);
+
+		if (model.isDisposed()) {
+			return;
+		}
+
+		const result: monaco.languages.Location[] = [];
+		for (let entry of entries) {
+			const uri = Uri.parse(entry.fileName);
+			const refModel = this._libFiles.getOrCreateModel(uri);
+			if (refModel) {
+				result.push({
+					uri: uri,
+					range: this._textSpanToRange(refModel, entry.textSpan)
+				});
+			}
+		}
+		return result;
+	}
+}
+
+// --- references ------
+
+export class ReferenceAdapter
+	extends Adapter
+	implements monaco.languages.ReferenceProvider {
+	constructor(
+		private readonly _libFiles: LibFiles,
+		worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
+	) {
+		super(worker);
+	}
+
+	public async provideReferences(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		context: monaco.languages.ReferenceContext,
+		token: CancellationToken
+	): Promise<monaco.languages.Location[] | undefined> {
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+		const entries = await worker.getReferencesAtPosition(
+			resource.toString(),
+			offset
+		);
+
+		if (!entries || model.isDisposed()) {
+			return;
+		}
+
+		// Fetch lib files if necessary
+		await this._libFiles.fetchLibFilesIfNecessary(
+			entries.map((entry) => Uri.parse(entry.fileName))
+		);
+
+		if (model.isDisposed()) {
+			return;
+		}
+
+		const result: monaco.languages.Location[] = [];
+		for (let entry of entries) {
+			const uri = Uri.parse(entry.fileName);
+			const refModel = this._libFiles.getOrCreateModel(uri);
+			if (refModel) {
+				result.push({
+					uri: uri,
+					range: this._textSpanToRange(refModel, entry.textSpan)
+				});
+			}
+		}
+		return result;
+	}
+}
+
+// --- outline ------
+
+export class OutlineAdapter
+	extends Adapter
+	implements monaco.languages.DocumentSymbolProvider {
+	public async provideDocumentSymbols(
+		model: monaco.editor.ITextModel,
+		token: CancellationToken
+	): Promise<monaco.languages.DocumentSymbol[] | undefined> {
+		const resource = model.uri;
+		const worker = await this._worker(resource);
+		const items = await worker.getNavigationBarItems(resource.toString());
+
+		if (!items || model.isDisposed()) {
+			return;
+		}
+
+		const convert = (
+			bucket: monaco.languages.DocumentSymbol[],
+			item: ts.NavigationBarItem,
+			containerLabel?: string
+		): void => {
+			let result: monaco.languages.DocumentSymbol = {
+				name: item.text,
+				detail: '',
+				kind: <monaco.languages.SymbolKind>(
+					(outlineTypeTable[item.kind] || monaco.languages.SymbolKind.Variable)
+				),
+				range: this._textSpanToRange(model, item.spans[0]),
+				selectionRange: this._textSpanToRange(model, item.spans[0]),
+				tags: [],
+				containerName: containerLabel
+			};
+
+			if (item.childItems && item.childItems.length > 0) {
+				for (let child of item.childItems) {
+					convert(bucket, child, result.name);
+				}
+			}
+
+			bucket.push(result);
+		};
+
+		let result: monaco.languages.DocumentSymbol[] = [];
+		items.forEach((item) => convert(result, item));
+		return result;
+	}
+}
+
+export class Kind {
+	public static unknown: string = '';
+	public static keyword: string = 'keyword';
+	public static script: string = 'script';
+	public static module: string = 'module';
+	public static class: string = 'class';
+	public static interface: string = 'interface';
+	public static type: string = 'type';
+	public static enum: string = 'enum';
+	public static variable: string = 'var';
+	public static localVariable: string = 'local var';
+	public static function: string = 'function';
+	public static localFunction: string = 'local function';
+	public static memberFunction: string = 'method';
+	public static memberGetAccessor: string = 'getter';
+	public static memberSetAccessor: string = 'setter';
+	public static memberVariable: string = 'property';
+	public static constructorImplementation: string = 'constructor';
+	public static callSignature: string = 'call';
+	public static indexSignature: string = 'index';
+	public static constructSignature: string = 'construct';
+	public static parameter: string = 'parameter';
+	public static typeParameter: string = 'type parameter';
+	public static primitiveType: string = 'primitive type';
+	public static label: string = 'label';
+	public static alias: string = 'alias';
+	public static const: string = 'const';
+	public static let: string = 'let';
+	public static warning: string = 'warning';
+}
+
+let outlineTypeTable: {
+	[kind: string]: monaco.languages.SymbolKind;
+} = Object.create(null);
+outlineTypeTable[Kind.module] = monaco.languages.SymbolKind.Module;
+outlineTypeTable[Kind.class] = monaco.languages.SymbolKind.Class;
+outlineTypeTable[Kind.enum] = monaco.languages.SymbolKind.Enum;
+outlineTypeTable[Kind.interface] = monaco.languages.SymbolKind.Interface;
+outlineTypeTable[Kind.memberFunction] = monaco.languages.SymbolKind.Method;
+outlineTypeTable[Kind.memberVariable] = monaco.languages.SymbolKind.Property;
+outlineTypeTable[Kind.memberGetAccessor] = monaco.languages.SymbolKind.Property;
+outlineTypeTable[Kind.memberSetAccessor] = monaco.languages.SymbolKind.Property;
+outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
+outlineTypeTable[Kind.const] = monaco.languages.SymbolKind.Variable;
+outlineTypeTable[Kind.localVariable] = monaco.languages.SymbolKind.Variable;
+outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
+outlineTypeTable[Kind.function] = monaco.languages.SymbolKind.Function;
+outlineTypeTable[Kind.localFunction] = monaco.languages.SymbolKind.Function;
+
+// --- formatting ----
+
+export abstract class FormatHelper extends Adapter {
+	protected static _convertOptions(
+		options: monaco.languages.FormattingOptions
+	): ts.FormatCodeOptions {
+		return {
+			ConvertTabsToSpaces: options.insertSpaces,
+			TabSize: options.tabSize,
+			IndentSize: options.tabSize,
+			IndentStyle: IndentStyle.Smart,
+			NewLineCharacter: '\n',
+			InsertSpaceAfterCommaDelimiter: true,
+			InsertSpaceAfterSemicolonInForStatements: true,
+			InsertSpaceBeforeAndAfterBinaryOperators: true,
+			InsertSpaceAfterKeywordsInControlFlowStatements: true,
+			InsertSpaceAfterFunctionKeywordForAnonymousFunctions: true,
+			InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
+			InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
+			InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
+			PlaceOpenBraceOnNewLineForControlBlocks: false,
+			PlaceOpenBraceOnNewLineForFunctions: false
+		};
+	}
+
+	protected _convertTextChanges(
+		model: monaco.editor.ITextModel,
+		change: ts.TextChange
+	): monaco.languages.TextEdit {
+		return {
+			text: change.newText,
+			range: this._textSpanToRange(model, change.span)
+		};
+	}
+}
+
+export class FormatAdapter
+	extends FormatHelper
+	implements monaco.languages.DocumentRangeFormattingEditProvider {
+	public async provideDocumentRangeFormattingEdits(
+		model: monaco.editor.ITextModel,
+		range: Range,
+		options: monaco.languages.FormattingOptions,
+		token: CancellationToken
+	): Promise<monaco.languages.TextEdit[] | undefined> {
+		const resource = model.uri;
+		const startOffset = model.getOffsetAt({
+			lineNumber: range.startLineNumber,
+			column: range.startColumn
+		});
+		const endOffset = model.getOffsetAt({
+			lineNumber: range.endLineNumber,
+			column: range.endColumn
+		});
+		const worker = await this._worker(resource);
+		const edits = await worker.getFormattingEditsForRange(
+			resource.toString(),
+			startOffset,
+			endOffset,
+			FormatHelper._convertOptions(options)
+		);
+
+		if (!edits || model.isDisposed()) {
+			return;
+		}
+
+		return edits.map((edit) => this._convertTextChanges(model, edit));
+	}
+}
+
+export class FormatOnTypeAdapter
+	extends FormatHelper
+	implements monaco.languages.OnTypeFormattingEditProvider {
+	get autoFormatTriggerCharacters() {
+		return [';', '}', '\n'];
+	}
+
+	public async provideOnTypeFormattingEdits(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		ch: string,
+		options: monaco.languages.FormattingOptions,
+		token: CancellationToken
+	): Promise<monaco.languages.TextEdit[] | undefined> {
+		const resource = model.uri;
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+		const edits = await worker.getFormattingEditsAfterKeystroke(
+			resource.toString(),
+			offset,
+			ch,
+			FormatHelper._convertOptions(options)
+		);
+
+		if (!edits || model.isDisposed()) {
+			return;
+		}
+
+		return edits.map((edit) => this._convertTextChanges(model, edit));
+	}
+}
+
+// --- code actions ------
+
+export class CodeActionAdaptor
+	extends FormatHelper
+	implements monaco.languages.CodeActionProvider {
+	public async provideCodeActions(
+		model: monaco.editor.ITextModel,
+		range: Range,
+		context: monaco.languages.CodeActionContext,
+		token: CancellationToken
+	): Promise<monaco.languages.CodeActionList> {
+		const resource = model.uri;
+		const start = model.getOffsetAt({
+			lineNumber: range.startLineNumber,
+			column: range.startColumn
+		});
+		const end = model.getOffsetAt({
+			lineNumber: range.endLineNumber,
+			column: range.endColumn
+		});
+		const formatOptions = FormatHelper._convertOptions(model.getOptions());
+		const errorCodes = context.markers
+			.filter((m) => m.code)
+			.map((m) => m.code)
+			.map(Number);
+		const worker = await this._worker(resource);
+		const codeFixes = await worker.getCodeFixesAtPosition(
+			resource.toString(),
+			start,
+			end,
+			errorCodes,
+			formatOptions
+		);
+
+		if (!codeFixes || model.isDisposed()) {
+			return { actions: [], dispose: () => {} };
+		}
+
+		const actions = codeFixes
+			.filter((fix) => {
+				// Removes any 'make a new file'-type code fix
+				return fix.changes.filter((change) => change.isNewFile).length === 0;
+			})
+			.map((fix) => {
+				return this._tsCodeFixActionToMonacoCodeAction(model, context, fix);
+			});
+
+		return {
+			actions: actions,
+			dispose: () => {}
+		};
+	}
+
+	private _tsCodeFixActionToMonacoCodeAction(
+		model: monaco.editor.ITextModel,
+		context: monaco.languages.CodeActionContext,
+		codeFix: ts.CodeFixAction
+	): monaco.languages.CodeAction {
+		const edits: monaco.languages.WorkspaceTextEdit[] = [];
+		for (const change of codeFix.changes) {
+			for (const textChange of change.textChanges) {
+				edits.push({
+					resource: model.uri,
+					edit: {
+						range: this._textSpanToRange(model, textChange.span),
+						text: textChange.newText
+					}
+				});
+			}
+		}
+
+		const action: monaco.languages.CodeAction = {
+			title: codeFix.description,
+			edit: { edits: edits },
+			diagnostics: context.markers,
+			kind: 'quickfix'
+		};
+
+		return action;
+	}
+}
+// --- rename ----
+
+export class RenameAdapter
+	extends Adapter
+	implements monaco.languages.RenameProvider {
+	public async provideRenameEdits(
+		model: monaco.editor.ITextModel,
+		position: Position,
+		newName: string,
+		token: CancellationToken
+	): Promise<
+		(monaco.languages.WorkspaceEdit & monaco.languages.Rejection) | undefined
+	> {
+		const resource = model.uri;
+		const fileName = resource.toString();
+		const offset = model.getOffsetAt(position);
+		const worker = await this._worker(resource);
+
+		const renameInfo = await worker.getRenameInfo(fileName, offset, {
+			allowRenameOfImportPath: false
+		});
+		if (renameInfo.canRename === false) {
+			// use explicit comparison so that the discriminated union gets resolved properly
+			return {
+				edits: [],
+				rejectReason: renameInfo.localizedErrorMessage
+			};
+		}
+		if (renameInfo.fileToRename !== undefined) {
+			throw new Error('Renaming files is not supported.');
+		}
+
+		const renameLocations = await worker.findRenameLocations(
+			fileName,
+			offset,
+			/*strings*/ false,
+			/*comments*/ false,
+			/*prefixAndSuffix*/ false
+		);
+
+		if (!renameLocations || model.isDisposed()) {
+			return;
+		}
+
+		const edits: monaco.languages.WorkspaceTextEdit[] = [];
+		for (const renameLocation of renameLocations) {
+			edits.push({
+				resource: monaco.Uri.parse(renameLocation.fileName),
+				edit: {
+					range: this._textSpanToRange(model, renameLocation.textSpan),
+					text: newName
+				}
+			});
+		}
+
+		return { edits };
+	}
+}

+ 282 - 260
src/monaco.contribution.ts

@@ -1,260 +1,282 @@
-/*---------------------------------------------------------------------------------------------
- *  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 * as mode from './tsMode';
-import { typescriptVersion } from './lib/typescriptServicesMetadata'; // do not import the whole typescriptServices here
-
-import Emitter = monaco.Emitter;
-import IEvent = monaco.IEvent;
-import IDisposable = monaco.IDisposable;
-
-// --- TypeScript configuration and defaults ---------
-
-export interface IExtraLib {
-	content: string;
-	version: number;
-}
-
-export interface IExtraLibs {
-	[path: string]: IExtraLib;
-}
-
-export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.LanguageServiceDefaults {
-
-	private _onDidChange = new Emitter<void>();
-	private _onDidExtraLibsChange = new Emitter<void>();
-
-	private _extraLibs: IExtraLibs;
-	private _eagerModelSync: boolean;
-	private _compilerOptions!: monaco.languages.typescript.CompilerOptions;
-	private _diagnosticsOptions!: monaco.languages.typescript.DiagnosticsOptions;
-	private _workerOptions!: monaco.languages.typescript.WorkerOptions;
-	private _onDidExtraLibsChangeTimeout: number;
-
-	constructor(compilerOptions: monaco.languages.typescript.CompilerOptions, diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions, workerOptions: monaco.languages.typescript.WorkerOptions) {
-		this._extraLibs = Object.create(null);
-		this._eagerModelSync = false;
-		this.setCompilerOptions(compilerOptions);
-		this.setDiagnosticsOptions(diagnosticsOptions);
-		this.setWorkerOptions(workerOptions)
-		this._onDidExtraLibsChangeTimeout = -1;
-	}
-
-	get onDidChange(): IEvent<void> {
-		return this._onDidChange.event;
-	}
-
-	get onDidExtraLibsChange(): IEvent<void> {
-		return this._onDidExtraLibsChange.event;
-	}
-
-	get workerOptions(): monaco.languages.typescript.WorkerOptions {
-		return this._workerOptions
-	}
-
-	getExtraLibs(): IExtraLibs {
-		return this._extraLibs;
-	}
-
-	addExtraLib(content: string, _filePath?: string): IDisposable {
-		let filePath: string;
-		if (typeof _filePath === 'undefined') {
-			filePath = `ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
-		} else {
-			filePath = _filePath;
-		}
-
-		if (this._extraLibs[filePath] && this._extraLibs[filePath].content === content) {
-			// no-op, there already exists an extra lib with this content
-			return {
-				dispose: () => { }
-			};
-		}
-
-		let myVersion = 1;
-		if (this._extraLibs[filePath]) {
-			myVersion = this._extraLibs[filePath].version + 1;
-		}
-
-		this._extraLibs[filePath] = {
-			content: content,
-			version: myVersion,
-		};
-		this._fireOnDidExtraLibsChangeSoon();
-
-		return {
-			dispose: () => {
-				let extraLib = this._extraLibs[filePath];
-				if (!extraLib) {
-					return;
-				}
-				if (extraLib.version !== myVersion) {
-					return;
-				}
-
-				delete this._extraLibs[filePath];
-				this._fireOnDidExtraLibsChangeSoon();
-			}
-		};
-	}
-
-	setExtraLibs(libs: { content: string; filePath?: string }[]): void {
-		// clear out everything
-		this._extraLibs = Object.create(null);
-
-		if (libs && libs.length > 0) {
-			for (const lib of libs) {
-				const filePath = lib.filePath || `ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
-				const content = lib.content;
-				this._extraLibs[filePath] = {
-					content: content,
-					version: 1
-				};
-			}
-		}
-
-		this._fireOnDidExtraLibsChangeSoon();
-	}
-
-	private _fireOnDidExtraLibsChangeSoon(): void {
-		if (this._onDidExtraLibsChangeTimeout !== -1) {
-			// already scheduled
-			return;
-		}
-		this._onDidExtraLibsChangeTimeout = setTimeout(() => {
-			this._onDidExtraLibsChangeTimeout = -1;
-			this._onDidExtraLibsChange.fire(undefined);
-		}, 0);
-	}
-
-	getCompilerOptions(): monaco.languages.typescript.CompilerOptions {
-		return this._compilerOptions;
-	}
-
-	setCompilerOptions(options: monaco.languages.typescript.CompilerOptions): void {
-		this._compilerOptions = options || Object.create(null);
-		this._onDidChange.fire(undefined);
-	}
-
-	getDiagnosticsOptions(): monaco.languages.typescript.DiagnosticsOptions {
-		return this._diagnosticsOptions;
-	}
-
-	setDiagnosticsOptions(options: monaco.languages.typescript.DiagnosticsOptions): void {
-		this._diagnosticsOptions = options || Object.create(null);
-		this._onDidChange.fire(undefined);
-	}
-
-	setWorkerOptions(options: monaco.languages.typescript.WorkerOptions): void {
-		this._workerOptions = options || Object.create(null);
-		this._onDidChange.fire(undefined);
-	}
-
-	setMaximumWorkerIdleTime(value: number): void {
-	}
-
-	setEagerModelSync(value: boolean) {
-		// doesn't fire an event since no
-		// worker restart is required here
-		this._eagerModelSync = value;
-	}
-
-	getEagerModelSync() {
-		return this._eagerModelSync;
-	}
-}
-
-//#region enums copied from typescript to prevent loading the entire typescriptServices ---
-
-enum ModuleKind {
-	None = 0,
-	CommonJS = 1,
-	AMD = 2,
-	UMD = 3,
-	System = 4,
-	ES2015 = 5,
-	ESNext = 99
-}
-
-enum JsxEmit {
-	None = 0,
-	Preserve = 1,
-	React = 2,
-	ReactNative = 3
-}
-
-enum NewLineKind {
-	CarriageReturnLineFeed = 0,
-	LineFeed = 1
-}
-
-enum ScriptTarget {
-	ES3 = 0,
-	ES5 = 1,
-	ES2015 = 2,
-	ES2016 = 3,
-	ES2017 = 4,
-	ES2018 = 5,
-	ES2019 = 6,
-	ES2020 = 7,
-	ESNext = 99,
-	JSON = 100,
-	Latest = ESNext,
-}
-
-enum ModuleResolutionKind {
-	Classic = 1,
-	NodeJs = 2
-}
-//#endregion
-
-const typescriptDefaults = new LanguageServiceDefaultsImpl(
-	{ allowNonTsExtensions: true, target: ScriptTarget.Latest },
-	{ noSemanticValidation: false, noSyntaxValidation: false },
-	{});
-
-const javascriptDefaults = new LanguageServiceDefaultsImpl(
-	{ allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
-	{ noSemanticValidation: true, noSyntaxValidation: false },
-	{});
-
-function getTypeScriptWorker(): Promise<(...uris: monaco.Uri[]) => Promise<monaco.languages.typescript.TypeScriptWorker>> {
-	return getMode().then(mode => mode.getTypeScriptWorker());
-}
-
-function getJavaScriptWorker(): Promise<(...uris: monaco.Uri[]) => Promise<monaco.languages.typescript.TypeScriptWorker>> {
-	return getMode().then(mode => mode.getJavaScriptWorker());
-}
-
-// Export API
-function createAPI(): typeof monaco.languages.typescript {
-	return {
-		ModuleKind: ModuleKind,
-		JsxEmit: JsxEmit,
-		NewLineKind: NewLineKind,
-		ScriptTarget: ScriptTarget,
-		ModuleResolutionKind: ModuleResolutionKind,
-		typescriptVersion,
-		typescriptDefaults: typescriptDefaults,
-		javascriptDefaults: javascriptDefaults,
-		getTypeScriptWorker: getTypeScriptWorker,
-		getJavaScriptWorker: getJavaScriptWorker
-	}
-}
-monaco.languages.typescript = createAPI();
-
-// --- Registration to monaco editor ---
-
-function getMode(): Promise<typeof mode> {
-	return import('./tsMode');
-}
-
-monaco.languages.onLanguage('typescript', () => {
-	return getMode().then(mode => mode.setupTypeScript(typescriptDefaults));
-});
-monaco.languages.onLanguage('javascript', () => {
-	return getMode().then(mode => mode.setupJavaScript(javascriptDefaults));
-});
+/*---------------------------------------------------------------------------------------------
+ *  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 * as mode from './tsMode';
+import { typescriptVersion } from './lib/typescriptServicesMetadata'; // do not import the whole typescriptServices here
+
+import Emitter = monaco.Emitter;
+import IEvent = monaco.IEvent;
+import IDisposable = monaco.IDisposable;
+
+// --- TypeScript configuration and defaults ---------
+
+export interface IExtraLib {
+	content: string;
+	version: number;
+}
+
+export interface IExtraLibs {
+	[path: string]: IExtraLib;
+}
+
+export class LanguageServiceDefaultsImpl
+	implements monaco.languages.typescript.LanguageServiceDefaults {
+	private _onDidChange = new Emitter<void>();
+	private _onDidExtraLibsChange = new Emitter<void>();
+
+	private _extraLibs: IExtraLibs;
+	private _eagerModelSync: boolean;
+	private _compilerOptions!: monaco.languages.typescript.CompilerOptions;
+	private _diagnosticsOptions!: monaco.languages.typescript.DiagnosticsOptions;
+	private _workerOptions!: monaco.languages.typescript.WorkerOptions;
+	private _onDidExtraLibsChangeTimeout: number;
+
+	constructor(
+		compilerOptions: monaco.languages.typescript.CompilerOptions,
+		diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions,
+		workerOptions: monaco.languages.typescript.WorkerOptions
+	) {
+		this._extraLibs = Object.create(null);
+		this._eagerModelSync = false;
+		this.setCompilerOptions(compilerOptions);
+		this.setDiagnosticsOptions(diagnosticsOptions);
+		this.setWorkerOptions(workerOptions);
+		this._onDidExtraLibsChangeTimeout = -1;
+	}
+
+	get onDidChange(): IEvent<void> {
+		return this._onDidChange.event;
+	}
+
+	get onDidExtraLibsChange(): IEvent<void> {
+		return this._onDidExtraLibsChange.event;
+	}
+
+	get workerOptions(): monaco.languages.typescript.WorkerOptions {
+		return this._workerOptions;
+	}
+
+	getExtraLibs(): IExtraLibs {
+		return this._extraLibs;
+	}
+
+	addExtraLib(content: string, _filePath?: string): IDisposable {
+		let filePath: string;
+		if (typeof _filePath === 'undefined') {
+			filePath = `ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
+		} else {
+			filePath = _filePath;
+		}
+
+		if (
+			this._extraLibs[filePath] &&
+			this._extraLibs[filePath].content === content
+		) {
+			// no-op, there already exists an extra lib with this content
+			return {
+				dispose: () => {}
+			};
+		}
+
+		let myVersion = 1;
+		if (this._extraLibs[filePath]) {
+			myVersion = this._extraLibs[filePath].version + 1;
+		}
+
+		this._extraLibs[filePath] = {
+			content: content,
+			version: myVersion
+		};
+		this._fireOnDidExtraLibsChangeSoon();
+
+		return {
+			dispose: () => {
+				let extraLib = this._extraLibs[filePath];
+				if (!extraLib) {
+					return;
+				}
+				if (extraLib.version !== myVersion) {
+					return;
+				}
+
+				delete this._extraLibs[filePath];
+				this._fireOnDidExtraLibsChangeSoon();
+			}
+		};
+	}
+
+	setExtraLibs(libs: { content: string; filePath?: string }[]): void {
+		// clear out everything
+		this._extraLibs = Object.create(null);
+
+		if (libs && libs.length > 0) {
+			for (const lib of libs) {
+				const filePath =
+					lib.filePath ||
+					`ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
+				const content = lib.content;
+				this._extraLibs[filePath] = {
+					content: content,
+					version: 1
+				};
+			}
+		}
+
+		this._fireOnDidExtraLibsChangeSoon();
+	}
+
+	private _fireOnDidExtraLibsChangeSoon(): void {
+		if (this._onDidExtraLibsChangeTimeout !== -1) {
+			// already scheduled
+			return;
+		}
+		this._onDidExtraLibsChangeTimeout = setTimeout(() => {
+			this._onDidExtraLibsChangeTimeout = -1;
+			this._onDidExtraLibsChange.fire(undefined);
+		}, 0);
+	}
+
+	getCompilerOptions(): monaco.languages.typescript.CompilerOptions {
+		return this._compilerOptions;
+	}
+
+	setCompilerOptions(
+		options: monaco.languages.typescript.CompilerOptions
+	): void {
+		this._compilerOptions = options || Object.create(null);
+		this._onDidChange.fire(undefined);
+	}
+
+	getDiagnosticsOptions(): monaco.languages.typescript.DiagnosticsOptions {
+		return this._diagnosticsOptions;
+	}
+
+	setDiagnosticsOptions(
+		options: monaco.languages.typescript.DiagnosticsOptions
+	): void {
+		this._diagnosticsOptions = options || Object.create(null);
+		this._onDidChange.fire(undefined);
+	}
+
+	setWorkerOptions(options: monaco.languages.typescript.WorkerOptions): void {
+		this._workerOptions = options || Object.create(null);
+		this._onDidChange.fire(undefined);
+	}
+
+	setMaximumWorkerIdleTime(value: number): void {}
+
+	setEagerModelSync(value: boolean) {
+		// doesn't fire an event since no
+		// worker restart is required here
+		this._eagerModelSync = value;
+	}
+
+	getEagerModelSync() {
+		return this._eagerModelSync;
+	}
+}
+
+//#region enums copied from typescript to prevent loading the entire typescriptServices ---
+
+enum ModuleKind {
+	None = 0,
+	CommonJS = 1,
+	AMD = 2,
+	UMD = 3,
+	System = 4,
+	ES2015 = 5,
+	ESNext = 99
+}
+
+enum JsxEmit {
+	None = 0,
+	Preserve = 1,
+	React = 2,
+	ReactNative = 3
+}
+
+enum NewLineKind {
+	CarriageReturnLineFeed = 0,
+	LineFeed = 1
+}
+
+enum ScriptTarget {
+	ES3 = 0,
+	ES5 = 1,
+	ES2015 = 2,
+	ES2016 = 3,
+	ES2017 = 4,
+	ES2018 = 5,
+	ES2019 = 6,
+	ES2020 = 7,
+	ESNext = 99,
+	JSON = 100,
+	Latest = ESNext
+}
+
+enum ModuleResolutionKind {
+	Classic = 1,
+	NodeJs = 2
+}
+//#endregion
+
+const typescriptDefaults = new LanguageServiceDefaultsImpl(
+	{ allowNonTsExtensions: true, target: ScriptTarget.Latest },
+	{ noSemanticValidation: false, noSyntaxValidation: false },
+	{}
+);
+
+const javascriptDefaults = new LanguageServiceDefaultsImpl(
+	{ allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
+	{ noSemanticValidation: true, noSyntaxValidation: false },
+	{}
+);
+
+function getTypeScriptWorker(): Promise<
+	(
+		...uris: monaco.Uri[]
+	) => Promise<monaco.languages.typescript.TypeScriptWorker>
+> {
+	return getMode().then((mode) => mode.getTypeScriptWorker());
+}
+
+function getJavaScriptWorker(): Promise<
+	(
+		...uris: monaco.Uri[]
+	) => Promise<monaco.languages.typescript.TypeScriptWorker>
+> {
+	return getMode().then((mode) => mode.getJavaScriptWorker());
+}
+
+// Export API
+function createAPI(): typeof monaco.languages.typescript {
+	return {
+		ModuleKind: ModuleKind,
+		JsxEmit: JsxEmit,
+		NewLineKind: NewLineKind,
+		ScriptTarget: ScriptTarget,
+		ModuleResolutionKind: ModuleResolutionKind,
+		typescriptVersion,
+		typescriptDefaults: typescriptDefaults,
+		javascriptDefaults: javascriptDefaults,
+		getTypeScriptWorker: getTypeScriptWorker,
+		getJavaScriptWorker: getJavaScriptWorker
+	};
+}
+monaco.languages.typescript = createAPI();
+
+// --- Registration to monaco editor ---
+
+function getMode(): Promise<typeof mode> {
+	return import('./tsMode');
+}
+
+monaco.languages.onLanguage('typescript', () => {
+	return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
+});
+monaco.languages.onLanguage('javascript', () => {
+	return getMode().then((mode) => mode.setupJavaScript(javascriptDefaults));
+});

+ 458 - 397
src/monaco.d.ts

@@ -1,397 +1,458 @@
-
-declare module monaco.languages.typescript {
-
-    enum ModuleKind {
-        None = 0,
-        CommonJS = 1,
-        AMD = 2,
-        UMD = 3,
-        System = 4,
-        ES2015 = 5,
-        ESNext = 99
-    }
-
-    enum JsxEmit {
-        None = 0,
-        Preserve = 1,
-        React = 2,
-        ReactNative = 3
-    }
-    enum NewLineKind {
-        CarriageReturnLineFeed = 0,
-        LineFeed = 1
-    }
-
-    enum ScriptTarget {
-        ES3 = 0,
-        ES5 = 1,
-        ES2015 = 2,
-        ES2016 = 3,
-        ES2017 = 4,
-        ES2018 = 5,
-        ES2019 = 6,
-        ES2020 = 7,
-        ESNext = 99,
-        JSON = 100,
-        Latest = ESNext,
-    }
-
-    export enum ModuleResolutionKind {
-        Classic = 1,
-        NodeJs = 2
-    }
-
-    interface MapLike<T> {
-        [index: string]: T;
-    }
-
-    type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | null | undefined;
-    interface CompilerOptions {
-        allowJs?: boolean;
-        allowSyntheticDefaultImports?: boolean;
-        allowUmdGlobalAccess?: boolean;
-        allowUnreachableCode?: boolean;
-        allowUnusedLabels?: boolean;
-        alwaysStrict?: boolean;
-        baseUrl?: string;
-        charset?: string;
-        checkJs?: boolean;
-        declaration?: boolean;
-        declarationMap?: boolean;
-        emitDeclarationOnly?: boolean;
-        declarationDir?: string;
-        disableSizeLimit?: boolean;
-        disableSourceOfProjectReferenceRedirect?: boolean;
-        downlevelIteration?: boolean;
-        emitBOM?: boolean;
-        emitDecoratorMetadata?: boolean;
-        experimentalDecorators?: boolean;
-        forceConsistentCasingInFileNames?: boolean;
-        importHelpers?: boolean;
-        inlineSourceMap?: boolean;
-        inlineSources?: boolean;
-        isolatedModules?: boolean;
-        jsx?: JsxEmit;
-        keyofStringsOnly?: boolean;
-        lib?: string[];
-        locale?: string;
-        mapRoot?: string;
-        maxNodeModuleJsDepth?: number;
-        module?: ModuleKind;
-        moduleResolution?: ModuleResolutionKind;
-        newLine?: NewLineKind;
-        noEmit?: boolean;
-        noEmitHelpers?: boolean;
-        noEmitOnError?: boolean;
-        noErrorTruncation?: boolean;
-        noFallthroughCasesInSwitch?: boolean;
-        noImplicitAny?: boolean;
-        noImplicitReturns?: boolean;
-        noImplicitThis?: boolean;
-        noStrictGenericChecks?: boolean;
-        noUnusedLocals?: boolean;
-        noUnusedParameters?: boolean;
-        noImplicitUseStrict?: boolean;
-        noLib?: boolean;
-        noResolve?: boolean;
-        out?: string;
-        outDir?: string;
-        outFile?: string;
-        paths?: MapLike<string[]>;
-        preserveConstEnums?: boolean;
-        preserveSymlinks?: boolean;
-        project?: string;
-        reactNamespace?: string;
-        jsxFactory?: string;
-        composite?: boolean;
-        removeComments?: boolean;
-        rootDir?: string;
-        rootDirs?: string[];
-        skipLibCheck?: boolean;
-        skipDefaultLibCheck?: boolean;
-        sourceMap?: boolean;
-        sourceRoot?: string;
-        strict?: boolean;
-        strictFunctionTypes?: boolean;
-        strictBindCallApply?: boolean;
-        strictNullChecks?: boolean;
-        strictPropertyInitialization?: boolean;
-        stripInternal?: boolean;
-        suppressExcessPropertyErrors?: boolean;
-        suppressImplicitAnyIndexErrors?: boolean;
-        target?: ScriptTarget;
-        traceResolution?: boolean;
-        resolveJsonModule?: boolean;
-        types?: string[];
-        /** Paths used to compute primary types search locations */
-        typeRoots?: string[];
-        esModuleInterop?: boolean;
-        useDefineForClassFields?: boolean;
-        [option: string]: CompilerOptionsValue | undefined;
-    }
-
-    export interface DiagnosticsOptions {
-        noSemanticValidation?: boolean;
-        noSyntaxValidation?: boolean;
-        noSuggestionDiagnostics?: boolean;
-        diagnosticCodesToIgnore?: number[];
-    }
-
-    export interface WorkerOptions {
-        /** A full HTTP path to a JavaScript file which adds a function `customTSWorkerFactory` to the self inside a web-worker */
-        customWorkerPath?: string;
-    }
-
-    interface IExtraLib {
-        content: string;
-        version: number;
-    }
-
-    interface IExtraLibs {
-        [path: string]: IExtraLib;
-    }
-
-    /**
-     * A linked list of formatted diagnostic messages to be used as part of a multiline message.
-     * It is built from the bottom up, leaving the head to be the "main" diagnostic.
-     */
-    interface DiagnosticMessageChain {
-        messageText: string;
-        /** Diagnostic category: warning = 0, error = 1, suggestion = 2, message = 3 */
-        category: 0 | 1 | 2 | 3;
-        code: number;
-        next?: DiagnosticMessageChain[];
-    }
-    interface Diagnostic extends DiagnosticRelatedInformation {
-        /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
-        reportsUnnecessary?: {};
-        source?: string;
-        relatedInformation?: DiagnosticRelatedInformation[];
-    }
-    interface DiagnosticRelatedInformation {
-        /** Diagnostic category: warning = 0, error = 1, suggestion = 2, message = 3 */
-        category: 0 | 1 | 2 | 3;
-        code: number;
-        /** TypeScriptWorker removes this to avoid serializing circular JSON structures. */
-        file: undefined;
-        start: number | undefined;
-        length: number | undefined;
-        messageText: string | DiagnosticMessageChain;
-    }
-
-    interface EmitOutput {
-        outputFiles: OutputFile[];
-        emitSkipped: boolean;
-    }
-    interface OutputFile {
-        name: string;
-        writeByteOrderMark: boolean;
-        text: string;
-    }
-
-    export interface LanguageServiceDefaults {
-        /**
-         * Event fired when compiler options or diagnostics options are changed.
-         */
-        readonly onDidChange: IEvent<void>;
-
-        /**
-         * Event fired when extra libraries registered with the language service change.
-         */
-        readonly onDidExtraLibsChange: IEvent<void>;
-
-        /**
-         * Get the current extra libs registered with the language service.
-         */
-        getExtraLibs(): IExtraLibs;
-
-        /**
-         * Add an additional source file to the language service. Use this
-         * for typescript (definition) files that won't be loaded as editor
-         * documents, like `jquery.d.ts`.
-         *
-         * @param content The file content
-         * @param filePath An optional file path
-         * @returns A disposable which will remove the file from the
-         * language service upon disposal.
-         */
-        addExtraLib(content: string, filePath?: string): IDisposable;
-
-        /**
-         * Remove all existing extra libs and set the additional source
-         * files to the language service. Use this for typescript definition
-         * files that won't be loaded as editor documents, like `jquery.d.ts`.
-         * @param libs An array of entries to register.
-         */
-        setExtraLibs(libs: { content: string; filePath?: string }[]): void;
-
-        /**
-         * Get current TypeScript compiler options for the language service.
-         */
-        getCompilerOptions(): CompilerOptions;
-
-        /**
-         * Set TypeScript compiler options.
-         */
-        setCompilerOptions(options: CompilerOptions): void;
-
-        /**
-         * Get the current diagnostics options for the language service.
-         */
-        getDiagnosticsOptions(): DiagnosticsOptions;
-
-        /**
-         * Configure whether syntactic and/or semantic validation should
-         * be performed
-         */
-        setDiagnosticsOptions(options: DiagnosticsOptions): void;
-
-        /**
-         * No-op.
-         */
-        setMaximumWorkerIdleTime(value: number): void;
-
-        /**
-         * Configure if all existing models should be eagerly sync'd
-         * to the worker on start or restart.
-         */
-        setEagerModelSync(value: boolean): void;
-
-        /**
-         * Get the current setting for whether all existing models should be eagerly sync'd
-         * to the worker on start or restart.
-         */
-        getEagerModelSync(): boolean;
-    }
-
-    export interface TypeScriptWorker {
-        /**
-         * Get diagnostic messages for any syntax issues in the given file.
-         */
-        getSyntacticDiagnostics(fileName: string): Promise<Diagnostic[]>;
-
-        /**
-         * Get diagnostic messages for any semantic issues in the given file.
-         */
-        getSemanticDiagnostics(fileName: string): Promise<Diagnostic[]>;
-
-        /**
-         * Get diagnostic messages for any suggestions related to the given file.
-         */
-        getSuggestionDiagnostics(fileName: string): Promise<Diagnostic[]>;
-
-        /**
-         * Get the content of a given file.
-         */
-        getScriptText(fileName: string): Promise<string | undefined>;
-
-        /**
-         * Get diagnostic messages related to the current compiler options.
-         * @param fileName Not used
-         */
-        getCompilerOptionsDiagnostics(fileName: string): Promise<Diagnostic[]>;
-
-        /**
-         * Get code completions for the given file and position.
-         * @returns `Promise<typescript.CompletionInfo | undefined>`
-         */
-        getCompletionsAtPosition(fileName: string, position: number): Promise<any | undefined>;
-
-        /**
-         * Get code completion details for the given file, position, and entry.
-         * @returns `Promise<typescript.CompletionEntryDetails | undefined>`
-         */
-        getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<any | undefined>;
-
-        /**
-         * Get signature help items for the item at the given file and position.
-         * @returns `Promise<typescript.SignatureHelpItems | undefined>`
-         */
-        getSignatureHelpItems(fileName: string, position: number): Promise<any | undefined>;
-
-        /**
-         * Get quick info for the item at the given position in the file.
-         * @returns `Promise<typescript.QuickInfo | undefined>`
-         */
-        getQuickInfoAtPosition(fileName: string, position: number): Promise<any | undefined>;
-
-        /**
-         * Get other ranges which are related to the item at the given position in the file (often used for highlighting).
-         * @returns `Promise<ReadonlyArray<typescript.ReferenceEntry> | undefined>`
-         */
-        getOccurrencesAtPosition(fileName: string, position: number): Promise<ReadonlyArray<any> | undefined>;
-
-        /**
-         * Get the definition of the item at the given position in the file.
-         * @returns `Promise<ReadonlyArray<typescript.DefinitionInfo> | undefined>`
-         */
-        getDefinitionAtPosition(fileName: string, position: number): Promise<ReadonlyArray<any> | undefined>;
-
-        /**
-         * Get references to the item at the given position in the file.
-         * @returns `Promise<typescript.ReferenceEntry[] | undefined>`
-         */
-        getReferencesAtPosition(fileName: string, position: number): Promise<any[] | undefined>;
-
-        /**
-         * Get outline entries for the item at the given position in the file.
-         * @returns `Promise<typescript.NavigationBarItem[]>`
-         */
-        getNavigationBarItems(fileName: string): Promise<any[]>;
-
-        /**
-         * Get changes which should be applied to format the given file.
-         * @param options `typescript.FormatCodeOptions`
-         * @returns `Promise<typescript.TextChange[]>`
-         */
-        getFormattingEditsForDocument(fileName: string, options: any): Promise<any[]>;
-
-        /**
-         * Get changes which should be applied to format the given range in the file.
-         * @param options `typescript.FormatCodeOptions`
-         * @returns `Promise<typescript.TextChange[]>`
-         */
-        getFormattingEditsForRange(fileName: string, start: number, end: number, options: any): Promise<any[]>;
-
-        /**
-         * Get formatting changes which should be applied after the given keystroke.
-         * @param options `typescript.FormatCodeOptions`
-         * @returns `Promise<typescript.TextChange[]>`
-         */
-        getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: any): Promise<any[]>;
-
-        /**
-         * Get other occurrences which should be updated when renaming the item at the given file and position.
-         * @returns `Promise<readonly typescript.RenameLocation[] | undefined>`
-         */
-        findRenameLocations(fileName: string, positon: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise<readonly any[] | undefined>;
-
-        /**
-         * Get edits which should be applied to rename the item at the given file and position (or a failure reason).
-         * @param options `typescript.RenameInfoOptions`
-         * @returns `Promise<typescript.RenameInfo>`
-         */
-        getRenameInfo(fileName: string, positon: number, options: any): Promise<any>;
-
-        /**
-         * Get transpiled output for the given file.
-         * @returns `typescript.EmitOutput`
-         */
-        getEmitOutput(fileName: string): Promise<any>;
-
-        /**
-         * Get possible code fixes at the given position in the file.
-         * @param formatOptions `typescript.FormatCodeOptions`
-         * @returns `Promise<ReadonlyArray<typescript.CodeFixAction>>`
-         */
-        getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: any): Promise<ReadonlyArray<any>>;
-    }
-
-    export const typescriptVersion: string;
-
-    export const typescriptDefaults: LanguageServiceDefaults;
-    export const javascriptDefaults: LanguageServiceDefaults;
-
-    export const getTypeScriptWorker: () => Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>>;
-    export const getJavaScriptWorker: () => Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>>;
-}
+declare module monaco.languages.typescript {
+	enum ModuleKind {
+		None = 0,
+		CommonJS = 1,
+		AMD = 2,
+		UMD = 3,
+		System = 4,
+		ES2015 = 5,
+		ESNext = 99
+	}
+
+	enum JsxEmit {
+		None = 0,
+		Preserve = 1,
+		React = 2,
+		ReactNative = 3
+	}
+	enum NewLineKind {
+		CarriageReturnLineFeed = 0,
+		LineFeed = 1
+	}
+
+	enum ScriptTarget {
+		ES3 = 0,
+		ES5 = 1,
+		ES2015 = 2,
+		ES2016 = 3,
+		ES2017 = 4,
+		ES2018 = 5,
+		ES2019 = 6,
+		ES2020 = 7,
+		ESNext = 99,
+		JSON = 100,
+		Latest = ESNext
+	}
+
+	export enum ModuleResolutionKind {
+		Classic = 1,
+		NodeJs = 2
+	}
+
+	interface MapLike<T> {
+		[index: string]: T;
+	}
+
+	type CompilerOptionsValue =
+		| string
+		| number
+		| boolean
+		| (string | number)[]
+		| string[]
+		| MapLike<string[]>
+		| null
+		| undefined;
+	interface CompilerOptions {
+		allowJs?: boolean;
+		allowSyntheticDefaultImports?: boolean;
+		allowUmdGlobalAccess?: boolean;
+		allowUnreachableCode?: boolean;
+		allowUnusedLabels?: boolean;
+		alwaysStrict?: boolean;
+		baseUrl?: string;
+		charset?: string;
+		checkJs?: boolean;
+		declaration?: boolean;
+		declarationMap?: boolean;
+		emitDeclarationOnly?: boolean;
+		declarationDir?: string;
+		disableSizeLimit?: boolean;
+		disableSourceOfProjectReferenceRedirect?: boolean;
+		downlevelIteration?: boolean;
+		emitBOM?: boolean;
+		emitDecoratorMetadata?: boolean;
+		experimentalDecorators?: boolean;
+		forceConsistentCasingInFileNames?: boolean;
+		importHelpers?: boolean;
+		inlineSourceMap?: boolean;
+		inlineSources?: boolean;
+		isolatedModules?: boolean;
+		jsx?: JsxEmit;
+		keyofStringsOnly?: boolean;
+		lib?: string[];
+		locale?: string;
+		mapRoot?: string;
+		maxNodeModuleJsDepth?: number;
+		module?: ModuleKind;
+		moduleResolution?: ModuleResolutionKind;
+		newLine?: NewLineKind;
+		noEmit?: boolean;
+		noEmitHelpers?: boolean;
+		noEmitOnError?: boolean;
+		noErrorTruncation?: boolean;
+		noFallthroughCasesInSwitch?: boolean;
+		noImplicitAny?: boolean;
+		noImplicitReturns?: boolean;
+		noImplicitThis?: boolean;
+		noStrictGenericChecks?: boolean;
+		noUnusedLocals?: boolean;
+		noUnusedParameters?: boolean;
+		noImplicitUseStrict?: boolean;
+		noLib?: boolean;
+		noResolve?: boolean;
+		out?: string;
+		outDir?: string;
+		outFile?: string;
+		paths?: MapLike<string[]>;
+		preserveConstEnums?: boolean;
+		preserveSymlinks?: boolean;
+		project?: string;
+		reactNamespace?: string;
+		jsxFactory?: string;
+		composite?: boolean;
+		removeComments?: boolean;
+		rootDir?: string;
+		rootDirs?: string[];
+		skipLibCheck?: boolean;
+		skipDefaultLibCheck?: boolean;
+		sourceMap?: boolean;
+		sourceRoot?: string;
+		strict?: boolean;
+		strictFunctionTypes?: boolean;
+		strictBindCallApply?: boolean;
+		strictNullChecks?: boolean;
+		strictPropertyInitialization?: boolean;
+		stripInternal?: boolean;
+		suppressExcessPropertyErrors?: boolean;
+		suppressImplicitAnyIndexErrors?: boolean;
+		target?: ScriptTarget;
+		traceResolution?: boolean;
+		resolveJsonModule?: boolean;
+		types?: string[];
+		/** Paths used to compute primary types search locations */
+		typeRoots?: string[];
+		esModuleInterop?: boolean;
+		useDefineForClassFields?: boolean;
+		[option: string]: CompilerOptionsValue | undefined;
+	}
+
+	export interface DiagnosticsOptions {
+		noSemanticValidation?: boolean;
+		noSyntaxValidation?: boolean;
+		noSuggestionDiagnostics?: boolean;
+		diagnosticCodesToIgnore?: number[];
+	}
+
+	export interface WorkerOptions {
+		/** A full HTTP path to a JavaScript file which adds a function `customTSWorkerFactory` to the self inside a web-worker */
+		customWorkerPath?: string;
+	}
+
+	interface IExtraLib {
+		content: string;
+		version: number;
+	}
+
+	interface IExtraLibs {
+		[path: string]: IExtraLib;
+	}
+
+	/**
+	 * A linked list of formatted diagnostic messages to be used as part of a multiline message.
+	 * It is built from the bottom up, leaving the head to be the "main" diagnostic.
+	 */
+	interface DiagnosticMessageChain {
+		messageText: string;
+		/** Diagnostic category: warning = 0, error = 1, suggestion = 2, message = 3 */
+		category: 0 | 1 | 2 | 3;
+		code: number;
+		next?: DiagnosticMessageChain[];
+	}
+	interface Diagnostic extends DiagnosticRelatedInformation {
+		/** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
+		reportsUnnecessary?: {};
+		source?: string;
+		relatedInformation?: DiagnosticRelatedInformation[];
+	}
+	interface DiagnosticRelatedInformation {
+		/** Diagnostic category: warning = 0, error = 1, suggestion = 2, message = 3 */
+		category: 0 | 1 | 2 | 3;
+		code: number;
+		/** TypeScriptWorker removes this to avoid serializing circular JSON structures. */
+		file: undefined;
+		start: number | undefined;
+		length: number | undefined;
+		messageText: string | DiagnosticMessageChain;
+	}
+
+	interface EmitOutput {
+		outputFiles: OutputFile[];
+		emitSkipped: boolean;
+	}
+	interface OutputFile {
+		name: string;
+		writeByteOrderMark: boolean;
+		text: string;
+	}
+
+	export interface LanguageServiceDefaults {
+		/**
+		 * Event fired when compiler options or diagnostics options are changed.
+		 */
+		readonly onDidChange: IEvent<void>;
+
+		/**
+		 * Event fired when extra libraries registered with the language service change.
+		 */
+		readonly onDidExtraLibsChange: IEvent<void>;
+
+		/**
+		 * Get the current extra libs registered with the language service.
+		 */
+		getExtraLibs(): IExtraLibs;
+
+		/**
+		 * Add an additional source file to the language service. Use this
+		 * for typescript (definition) files that won't be loaded as editor
+		 * documents, like `jquery.d.ts`.
+		 *
+		 * @param content The file content
+		 * @param filePath An optional file path
+		 * @returns A disposable which will remove the file from the
+		 * language service upon disposal.
+		 */
+		addExtraLib(content: string, filePath?: string): IDisposable;
+
+		/**
+		 * Remove all existing extra libs and set the additional source
+		 * files to the language service. Use this for typescript definition
+		 * files that won't be loaded as editor documents, like `jquery.d.ts`.
+		 * @param libs An array of entries to register.
+		 */
+		setExtraLibs(libs: { content: string; filePath?: string }[]): void;
+
+		/**
+		 * Get current TypeScript compiler options for the language service.
+		 */
+		getCompilerOptions(): CompilerOptions;
+
+		/**
+		 * Set TypeScript compiler options.
+		 */
+		setCompilerOptions(options: CompilerOptions): void;
+
+		/**
+		 * Get the current diagnostics options for the language service.
+		 */
+		getDiagnosticsOptions(): DiagnosticsOptions;
+
+		/**
+		 * Configure whether syntactic and/or semantic validation should
+		 * be performed
+		 */
+		setDiagnosticsOptions(options: DiagnosticsOptions): void;
+
+		/**
+		 * No-op.
+		 */
+		setMaximumWorkerIdleTime(value: number): void;
+
+		/**
+		 * Configure if all existing models should be eagerly sync'd
+		 * to the worker on start or restart.
+		 */
+		setEagerModelSync(value: boolean): void;
+
+		/**
+		 * Get the current setting for whether all existing models should be eagerly sync'd
+		 * to the worker on start or restart.
+		 */
+		getEagerModelSync(): boolean;
+	}
+
+	export interface TypeScriptWorker {
+		/**
+		 * Get diagnostic messages for any syntax issues in the given file.
+		 */
+		getSyntacticDiagnostics(fileName: string): Promise<Diagnostic[]>;
+
+		/**
+		 * Get diagnostic messages for any semantic issues in the given file.
+		 */
+		getSemanticDiagnostics(fileName: string): Promise<Diagnostic[]>;
+
+		/**
+		 * Get diagnostic messages for any suggestions related to the given file.
+		 */
+		getSuggestionDiagnostics(fileName: string): Promise<Diagnostic[]>;
+
+		/**
+		 * Get the content of a given file.
+		 */
+		getScriptText(fileName: string): Promise<string | undefined>;
+
+		/**
+		 * Get diagnostic messages related to the current compiler options.
+		 * @param fileName Not used
+		 */
+		getCompilerOptionsDiagnostics(fileName: string): Promise<Diagnostic[]>;
+
+		/**
+		 * Get code completions for the given file and position.
+		 * @returns `Promise<typescript.CompletionInfo | undefined>`
+		 */
+		getCompletionsAtPosition(
+			fileName: string,
+			position: number
+		): Promise<any | undefined>;
+
+		/**
+		 * Get code completion details for the given file, position, and entry.
+		 * @returns `Promise<typescript.CompletionEntryDetails | undefined>`
+		 */
+		getCompletionEntryDetails(
+			fileName: string,
+			position: number,
+			entry: string
+		): Promise<any | undefined>;
+
+		/**
+		 * Get signature help items for the item at the given file and position.
+		 * @returns `Promise<typescript.SignatureHelpItems | undefined>`
+		 */
+		getSignatureHelpItems(
+			fileName: string,
+			position: number
+		): Promise<any | undefined>;
+
+		/**
+		 * Get quick info for the item at the given position in the file.
+		 * @returns `Promise<typescript.QuickInfo | undefined>`
+		 */
+		getQuickInfoAtPosition(
+			fileName: string,
+			position: number
+		): Promise<any | undefined>;
+
+		/**
+		 * Get other ranges which are related to the item at the given position in the file (often used for highlighting).
+		 * @returns `Promise<ReadonlyArray<typescript.ReferenceEntry> | undefined>`
+		 */
+		getOccurrencesAtPosition(
+			fileName: string,
+			position: number
+		): Promise<ReadonlyArray<any> | undefined>;
+
+		/**
+		 * Get the definition of the item at the given position in the file.
+		 * @returns `Promise<ReadonlyArray<typescript.DefinitionInfo> | undefined>`
+		 */
+		getDefinitionAtPosition(
+			fileName: string,
+			position: number
+		): Promise<ReadonlyArray<any> | undefined>;
+
+		/**
+		 * Get references to the item at the given position in the file.
+		 * @returns `Promise<typescript.ReferenceEntry[] | undefined>`
+		 */
+		getReferencesAtPosition(
+			fileName: string,
+			position: number
+		): Promise<any[] | undefined>;
+
+		/**
+		 * Get outline entries for the item at the given position in the file.
+		 * @returns `Promise<typescript.NavigationBarItem[]>`
+		 */
+		getNavigationBarItems(fileName: string): Promise<any[]>;
+
+		/**
+		 * Get changes which should be applied to format the given file.
+		 * @param options `typescript.FormatCodeOptions`
+		 * @returns `Promise<typescript.TextChange[]>`
+		 */
+		getFormattingEditsForDocument(
+			fileName: string,
+			options: any
+		): Promise<any[]>;
+
+		/**
+		 * Get changes which should be applied to format the given range in the file.
+		 * @param options `typescript.FormatCodeOptions`
+		 * @returns `Promise<typescript.TextChange[]>`
+		 */
+		getFormattingEditsForRange(
+			fileName: string,
+			start: number,
+			end: number,
+			options: any
+		): Promise<any[]>;
+
+		/**
+		 * Get formatting changes which should be applied after the given keystroke.
+		 * @param options `typescript.FormatCodeOptions`
+		 * @returns `Promise<typescript.TextChange[]>`
+		 */
+		getFormattingEditsAfterKeystroke(
+			fileName: string,
+			postion: number,
+			ch: string,
+			options: any
+		): Promise<any[]>;
+
+		/**
+		 * Get other occurrences which should be updated when renaming the item at the given file and position.
+		 * @returns `Promise<readonly typescript.RenameLocation[] | undefined>`
+		 */
+		findRenameLocations(
+			fileName: string,
+			positon: number,
+			findInStrings: boolean,
+			findInComments: boolean,
+			providePrefixAndSuffixTextForRename: boolean
+		): Promise<readonly any[] | undefined>;
+
+		/**
+		 * Get edits which should be applied to rename the item at the given file and position (or a failure reason).
+		 * @param options `typescript.RenameInfoOptions`
+		 * @returns `Promise<typescript.RenameInfo>`
+		 */
+		getRenameInfo(
+			fileName: string,
+			positon: number,
+			options: any
+		): Promise<any>;
+
+		/**
+		 * Get transpiled output for the given file.
+		 * @returns `typescript.EmitOutput`
+		 */
+		getEmitOutput(fileName: string): Promise<any>;
+
+		/**
+		 * Get possible code fixes at the given position in the file.
+		 * @param formatOptions `typescript.FormatCodeOptions`
+		 * @returns `Promise<ReadonlyArray<typescript.CodeFixAction>>`
+		 */
+		getCodeFixesAtPosition(
+			fileName: string,
+			start: number,
+			end: number,
+			errorCodes: number[],
+			formatOptions: any
+		): Promise<ReadonlyArray<any>>;
+	}
+
+	export const typescriptVersion: string;
+
+	export const typescriptDefaults: LanguageServiceDefaults;
+	export const javascriptDefaults: LanguageServiceDefaults;
+
+	export const getTypeScriptWorker: () => Promise<
+		(...uris: Uri[]) => Promise<TypeScriptWorker>
+	>;
+	export const getJavaScriptWorker: () => Promise<
+		(...uris: Uri[]) => Promise<TypeScriptWorker>
+	>;
+}

+ 5 - 3
src/ts.worker.ts

@@ -9,7 +9,9 @@ import { TypeScriptWorker, ICreateData } from './tsWorker';
 
 self.onmessage = () => {
 	// ignore the first message
-	worker.initialize((ctx: monaco.worker.IWorkerContext, createData: ICreateData) => {
-		return new TypeScriptWorker(ctx, createData)
-	});
+	worker.initialize(
+		(ctx: monaco.worker.IWorkerContext, createData: ICreateData) => {
+			return new TypeScriptWorker(ctx, createData);
+		}
+	);
 };

+ 107 - 74
src/tsMode.ts

@@ -1,74 +1,107 @@
-/*---------------------------------------------------------------------------------------------
- *  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 { TypeScriptWorker } from './tsWorker';
-import { LanguageServiceDefaultsImpl } from './monaco.contribution';
-import * as languageFeatures from './languageFeatures';
-
-import Uri = monaco.Uri;
-
-let javaScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
-let typeScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
-
-export function setupTypeScript(defaults: LanguageServiceDefaultsImpl): void {
-	typeScriptWorker = setupMode(
-		defaults,
-		'typescript'
-	);
-}
-
-export function setupJavaScript(defaults: LanguageServiceDefaultsImpl): 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: LanguageServiceDefaultsImpl, 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);
-
-	monaco.languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker));
-	monaco.languages.registerSignatureHelpProvider(modeId, new languageFeatures.SignatureHelpAdapter(worker));
-	monaco.languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker));
-	monaco.languages.registerDocumentHighlightProvider(modeId, new languageFeatures.OccurrencesAdapter(worker));
-	monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(libFiles, worker));
-	monaco.languages.registerReferenceProvider(modeId, new languageFeatures.ReferenceAdapter(libFiles, worker));
-	monaco.languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker));
-	monaco.languages.registerDocumentRangeFormattingEditProvider(modeId, new languageFeatures.FormatAdapter(worker));
-	monaco.languages.registerOnTypeFormattingEditProvider(modeId, new languageFeatures.FormatOnTypeAdapter(worker));
-	monaco.languages.registerCodeActionProvider(modeId, new languageFeatures.CodeActionAdaptor(worker));
-	monaco.languages.registerRenameProvider(modeId, new languageFeatures.RenameAdapter(worker));
-	new languageFeatures.DiagnosticsAdapter(libFiles, defaults, modeId, worker);
-
-	return worker;
-}
+/*---------------------------------------------------------------------------------------------
+ *  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 { TypeScriptWorker } from './tsWorker';
+import { LanguageServiceDefaultsImpl } from './monaco.contribution';
+import * as languageFeatures from './languageFeatures';
+
+import Uri = monaco.Uri;
+
+let javaScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
+let typeScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
+
+export function setupTypeScript(defaults: LanguageServiceDefaultsImpl): void {
+	typeScriptWorker = setupMode(defaults, 'typescript');
+}
+
+export function setupJavaScript(defaults: LanguageServiceDefaultsImpl): 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: LanguageServiceDefaultsImpl,
+	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);
+
+	monaco.languages.registerCompletionItemProvider(
+		modeId,
+		new languageFeatures.SuggestAdapter(worker)
+	);
+	monaco.languages.registerSignatureHelpProvider(
+		modeId,
+		new languageFeatures.SignatureHelpAdapter(worker)
+	);
+	monaco.languages.registerHoverProvider(
+		modeId,
+		new languageFeatures.QuickInfoAdapter(worker)
+	);
+	monaco.languages.registerDocumentHighlightProvider(
+		modeId,
+		new languageFeatures.OccurrencesAdapter(worker)
+	);
+	monaco.languages.registerDefinitionProvider(
+		modeId,
+		new languageFeatures.DefinitionAdapter(libFiles, worker)
+	);
+	monaco.languages.registerReferenceProvider(
+		modeId,
+		new languageFeatures.ReferenceAdapter(libFiles, worker)
+	);
+	monaco.languages.registerDocumentSymbolProvider(
+		modeId,
+		new languageFeatures.OutlineAdapter(worker)
+	);
+	monaco.languages.registerDocumentRangeFormattingEditProvider(
+		modeId,
+		new languageFeatures.FormatAdapter(worker)
+	);
+	monaco.languages.registerOnTypeFormattingEditProvider(
+		modeId,
+		new languageFeatures.FormatOnTypeAdapter(worker)
+	);
+	monaco.languages.registerCodeActionProvider(
+		modeId,
+		new languageFeatures.CodeActionAdaptor(worker)
+	);
+	monaco.languages.registerRenameProvider(
+		modeId,
+		new languageFeatures.RenameAdapter(worker)
+	);
+	new languageFeatures.DiagnosticsAdapter(libFiles, defaults, modeId, worker);
+
+	return worker;
+}

+ 432 - 286
src/tsWorker.ts

@@ -1,286 +1,432 @@
-/*---------------------------------------------------------------------------------------------
- *  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 * as ts from './lib/typescriptServices';
-import { libFileMap } from './lib/lib';
-import { IExtraLibs } from './monaco.contribution';
-
-import IWorkerContext = monaco.worker.IWorkerContext;
-
-
-export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.languages.typescript.TypeScriptWorker {
-
-	// --- model sync -----------------------
-
-	private _ctx: IWorkerContext;
-	private _extraLibs: IExtraLibs = Object.create(null);
-	private _languageService = ts.createLanguageService(this);
-	private _compilerOptions: ts.CompilerOptions;
-
-	constructor(ctx: IWorkerContext, createData: ICreateData) {
-		this._ctx = ctx;
-		this._compilerOptions = createData.compilerOptions;
-		this._extraLibs = createData.extraLibs;
-	}
-
-	// --- language service host ---------------
-
-	getCompilationSettings(): ts.CompilerOptions {
-		return this._compilerOptions;
-	}
-
-	getScriptFileNames(): string[] {
-		let models = this._ctx.getMirrorModels().map(model => model.uri.toString());
-		return models.concat(Object.keys(this._extraLibs));
-	}
-
-	private _getModel(fileName: string): monaco.worker.IMirrorModel | null {
-		let models = this._ctx.getMirrorModels();
-		for (let i = 0; i < models.length; i++) {
-			if (models[i].uri.toString() === fileName) {
-				return models[i];
-			}
-		}
-		return null;
-	}
-
-	getScriptVersion(fileName: string): string {
-		let model = this._getModel(fileName);
-		if (model) {
-			return model.version.toString();
-		} else if (this.isDefaultLibFileName(fileName)) {
-			// default lib is static
-			return '1';
-		} else if (fileName in this._extraLibs) {
-			return String(this._extraLibs[fileName].version);
-		}
-		return '';
-	}
-
-	getScriptText(fileName: string): Promise<string | undefined> {
-		return Promise.resolve(this._getScriptText(fileName));
-	}
-
-	_getScriptText(fileName: string): string | undefined {
-		let text: string;
-		let model = this._getModel(fileName);
-		if (model) {
-			// a true editor model
-			text = model.getValue();
-		} else if (fileName in libFileMap) {
-			text = libFileMap[fileName];
-
-		} else if (fileName in this._extraLibs) {
-			// extra lib
-			text = this._extraLibs[fileName].content;
-		} else {
-			return;
-		}
-
-		return text;
-	}
-
-	getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
-		const text = this._getScriptText(fileName);
-		if (text === undefined) {
-			return;
-		}
-
-		return <ts.IScriptSnapshot>{
-			getText: (start, end) => text.substring(start, end),
-			getLength: () => text.length,
-			getChangeRange: () => undefined
-		};
-	}
-
-	getScriptKind?(fileName: string): ts.ScriptKind {
-		const suffix = fileName.substr(fileName.lastIndexOf('.') + 1);
-		switch (suffix) {
-			case 'ts': return ts.ScriptKind.TS;
-			case 'tsx': return ts.ScriptKind.TSX;
-			case 'js': return ts.ScriptKind.JS;
-			case 'jsx': return ts.ScriptKind.JSX;
-			default: return this.getCompilationSettings().allowJs
-				? ts.ScriptKind.JS
-				: ts.ScriptKind.TS;
-		}
-	}
-
-	getCurrentDirectory(): string {
-		return '';
-	}
-
-	getDefaultLibFileName(options: ts.CompilerOptions): string {
-		switch (options.target) {
-			case 99 /* ESNext */:
-				const esnext = "lib.esnext.full.d.ts";
-				if (esnext in libFileMap || esnext in this._extraLibs) return esnext
-			case 7 /* ES2020 */:
-			case 6 /* ES2019 */:
-			case 5 /* ES2018 */:
-			case 4 /* ES2017 */:
-			case 3 /* ES2016 */:
-			case 2 /* ES2015 */:
-			default:
-				// Support a dynamic lookup for the ES20XX version based on the target
-				// which is safe unless TC39 changes their numbering system
-				const eslib = `lib.es${2013 + (options.target || 99)}.full.d.ts`;
-				// Note: This also looks in _extraLibs, If you want
-				// to add support for additional target options, you will need to
-				// add the extra dts files to _extraLibs via the API.
-				if (eslib in libFileMap || eslib in this._extraLibs) {
-					return eslib;
-				}
-
-				return "lib.es6.d.ts"; // We don't use lib.es2015.full.d.ts due to breaking change.
-			case 1:
-			case 0:
-				return "lib.d.ts";
-		}
-	}
-
-	isDefaultLibFileName(fileName: string): boolean {
-		return fileName === this.getDefaultLibFileName(this._compilerOptions);
-	}
-
-	getLibFiles(): Promise<Record<string, string>> {
-		return Promise.resolve(libFileMap);
-	}
-
-	// --- language features
-
-	private static clearFiles(diagnostics: ts.Diagnostic[]): monaco.languages.typescript.Diagnostic[] {
-		// Clear the `file` field, which cannot be JSON'yfied because it
-		// contains cyclic data structures.
-		diagnostics.forEach(diag => {
-			diag.file = undefined;
-			const related = <ts.Diagnostic[]>diag.relatedInformation;
-			if (related) {
-				related.forEach(diag2 => diag2.file = undefined);
-			}
-		});
-		return <monaco.languages.typescript.Diagnostic[]>diagnostics;
-	}
-
-	getSyntacticDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> {
-		const diagnostics = this._languageService.getSyntacticDiagnostics(fileName);
-		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
-	}
-
-	getSemanticDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> {
-		const diagnostics = this._languageService.getSemanticDiagnostics(fileName);
-		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
-	}
-
-	getSuggestionDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> {
-		const diagnostics = this._languageService.getSuggestionDiagnostics(fileName);
-		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
-	}
-
-	getCompilerOptionsDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> {
-		const diagnostics = this._languageService.getCompilerOptionsDiagnostics();
-		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
-	}
-
-	getCompletionsAtPosition(fileName: string, position: number): Promise<ts.CompletionInfo | undefined> {
-		return Promise.resolve(this._languageService.getCompletionsAtPosition(fileName, position, undefined));
-	}
-
-	getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<ts.CompletionEntryDetails | undefined> {
-		return Promise.resolve(this._languageService.getCompletionEntryDetails(fileName, position, entry, undefined, undefined, undefined));
-	}
-
-	getSignatureHelpItems(fileName: string, position: number): Promise<ts.SignatureHelpItems | undefined> {
-		return Promise.resolve(this._languageService.getSignatureHelpItems(fileName, position, undefined));
-	}
-
-	getQuickInfoAtPosition(fileName: string, position: number): Promise<ts.QuickInfo | undefined> {
-		return Promise.resolve(this._languageService.getQuickInfoAtPosition(fileName, position));
-	}
-
-	getOccurrencesAtPosition(fileName: string, position: number): Promise<ReadonlyArray<ts.ReferenceEntry> | undefined> {
-		return Promise.resolve(this._languageService.getOccurrencesAtPosition(fileName, position));
-	}
-
-	getDefinitionAtPosition(fileName: string, position: number): Promise<ReadonlyArray<ts.DefinitionInfo> | undefined> {
-		return Promise.resolve(this._languageService.getDefinitionAtPosition(fileName, position));
-	}
-
-	getReferencesAtPosition(fileName: string, position: number): Promise<ts.ReferenceEntry[] | undefined> {
-		return Promise.resolve(this._languageService.getReferencesAtPosition(fileName, position));
-	}
-
-	getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> {
-		return Promise.resolve(this._languageService.getNavigationBarItems(fileName));
-	}
-
-	getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
-		return Promise.resolve(this._languageService.getFormattingEditsForDocument(fileName, options));
-	}
-
-	getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
-		return Promise.resolve(this._languageService.getFormattingEditsForRange(fileName, start, end, options));
-	}
-
-	getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
-		return Promise.resolve(this._languageService.getFormattingEditsAfterKeystroke(fileName, postion, ch, options));
-	}
-
-	findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise<readonly ts.RenameLocation[] | undefined> {
-		return Promise.resolve(this._languageService.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename));
-	}
-
-	getRenameInfo(fileName: string, position: number, options: ts.RenameInfoOptions): Promise<ts.RenameInfo> {
-		return Promise.resolve(this._languageService.getRenameInfo(fileName, position, options));
-	}
-
-	getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
-		return Promise.resolve(this._languageService.getEmitOutput(fileName));
-	}
-
-	getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: ts.FormatCodeOptions): Promise<ReadonlyArray<ts.CodeFixAction>> {
-		const preferences = {}
-		return Promise.resolve(this._languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences));
-	}
-
-	updateExtraLibs(extraLibs: IExtraLibs) {
-		this._extraLibs = extraLibs;
-	}
-}
-
-export interface ICreateData {
-	compilerOptions: ts.CompilerOptions;
-	extraLibs: IExtraLibs;
-	customWorkerPath?: string
-}
-
-/** The shape of the factory */
-export interface CustomTSWebWorkerFactory {
-	(TSWorkerClass: typeof TypeScriptWorker, tsc: typeof ts, libs: Record<string, string>): typeof TypeScriptWorker
-}
-
-export function create(ctx: IWorkerContext, createData: ICreateData): TypeScriptWorker {
-	let TSWorkerClass = TypeScriptWorker
-	if (createData.customWorkerPath) {
-		// @ts-ignore - This is available in a webworker
-		if (typeof importScripts === "undefined") {
-			console.warn("Monaco is not using webworkers for background tasks, and that is needed to support the customWorkerPath flag")
-		} else {
-			// @ts-ignore - This is available in a webworker
-			importScripts(createData.customWorkerPath)
-
-			// @ts-ignore - This should come from the above eval
-			const workerFactoryFunc: CustomTSWebWorkerFactory | undefined = self.customTSWorkerFactory
-			if (!workerFactoryFunc) {
-				throw new Error(`The script at ${createData.customWorkerPath} does not add customTSWorkerFactory to self`)
-			}
-
-			TSWorkerClass = workerFactoryFunc(TypeScriptWorker, ts, libFileMap)
-		}
-	}
-
-	return new TSWorkerClass(ctx, createData);
-}
+/*---------------------------------------------------------------------------------------------
+ *  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 * as ts from './lib/typescriptServices';
+import { libFileMap } from './lib/lib';
+import { IExtraLibs } from './monaco.contribution';
+
+import IWorkerContext = monaco.worker.IWorkerContext;
+
+export class TypeScriptWorker
+	implements
+		ts.LanguageServiceHost,
+		monaco.languages.typescript.TypeScriptWorker {
+	// --- model sync -----------------------
+
+	private _ctx: IWorkerContext;
+	private _extraLibs: IExtraLibs = Object.create(null);
+	private _languageService = ts.createLanguageService(this);
+	private _compilerOptions: ts.CompilerOptions;
+
+	constructor(ctx: IWorkerContext, createData: ICreateData) {
+		this._ctx = ctx;
+		this._compilerOptions = createData.compilerOptions;
+		this._extraLibs = createData.extraLibs;
+	}
+
+	// --- language service host ---------------
+
+	getCompilationSettings(): ts.CompilerOptions {
+		return this._compilerOptions;
+	}
+
+	getScriptFileNames(): string[] {
+		let models = this._ctx
+			.getMirrorModels()
+			.map((model) => model.uri.toString());
+		return models.concat(Object.keys(this._extraLibs));
+	}
+
+	private _getModel(fileName: string): monaco.worker.IMirrorModel | null {
+		let models = this._ctx.getMirrorModels();
+		for (let i = 0; i < models.length; i++) {
+			if (models[i].uri.toString() === fileName) {
+				return models[i];
+			}
+		}
+		return null;
+	}
+
+	getScriptVersion(fileName: string): string {
+		let model = this._getModel(fileName);
+		if (model) {
+			return model.version.toString();
+		} else if (this.isDefaultLibFileName(fileName)) {
+			// default lib is static
+			return '1';
+		} else if (fileName in this._extraLibs) {
+			return String(this._extraLibs[fileName].version);
+		}
+		return '';
+	}
+
+	getScriptText(fileName: string): Promise<string | undefined> {
+		return Promise.resolve(this._getScriptText(fileName));
+	}
+
+	_getScriptText(fileName: string): string | undefined {
+		let text: string;
+		let model = this._getModel(fileName);
+		if (model) {
+			// a true editor model
+			text = model.getValue();
+		} else if (fileName in libFileMap) {
+			text = libFileMap[fileName];
+		} else if (fileName in this._extraLibs) {
+			// extra lib
+			text = this._extraLibs[fileName].content;
+		} else {
+			return;
+		}
+
+		return text;
+	}
+
+	getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
+		const text = this._getScriptText(fileName);
+		if (text === undefined) {
+			return;
+		}
+
+		return <ts.IScriptSnapshot>{
+			getText: (start, end) => text.substring(start, end),
+			getLength: () => text.length,
+			getChangeRange: () => undefined
+		};
+	}
+
+	getScriptKind?(fileName: string): ts.ScriptKind {
+		const suffix = fileName.substr(fileName.lastIndexOf('.') + 1);
+		switch (suffix) {
+			case 'ts':
+				return ts.ScriptKind.TS;
+			case 'tsx':
+				return ts.ScriptKind.TSX;
+			case 'js':
+				return ts.ScriptKind.JS;
+			case 'jsx':
+				return ts.ScriptKind.JSX;
+			default:
+				return this.getCompilationSettings().allowJs
+					? ts.ScriptKind.JS
+					: ts.ScriptKind.TS;
+		}
+	}
+
+	getCurrentDirectory(): string {
+		return '';
+	}
+
+	getDefaultLibFileName(options: ts.CompilerOptions): string {
+		switch (options.target) {
+			case 99 /* ESNext */:
+				const esnext = 'lib.esnext.full.d.ts';
+				if (esnext in libFileMap || esnext in this._extraLibs) return esnext;
+			case 7 /* ES2020 */:
+			case 6 /* ES2019 */:
+			case 5 /* ES2018 */:
+			case 4 /* ES2017 */:
+			case 3 /* ES2016 */:
+			case 2 /* ES2015 */:
+			default:
+				// Support a dynamic lookup for the ES20XX version based on the target
+				// which is safe unless TC39 changes their numbering system
+				const eslib = `lib.es${2013 + (options.target || 99)}.full.d.ts`;
+				// Note: This also looks in _extraLibs, If you want
+				// to add support for additional target options, you will need to
+				// add the extra dts files to _extraLibs via the API.
+				if (eslib in libFileMap || eslib in this._extraLibs) {
+					return eslib;
+				}
+
+				return 'lib.es6.d.ts'; // We don't use lib.es2015.full.d.ts due to breaking change.
+			case 1:
+			case 0:
+				return 'lib.d.ts';
+		}
+	}
+
+	isDefaultLibFileName(fileName: string): boolean {
+		return fileName === this.getDefaultLibFileName(this._compilerOptions);
+	}
+
+	getLibFiles(): Promise<Record<string, string>> {
+		return Promise.resolve(libFileMap);
+	}
+
+	// --- language features
+
+	private static clearFiles(
+		diagnostics: ts.Diagnostic[]
+	): monaco.languages.typescript.Diagnostic[] {
+		// Clear the `file` field, which cannot be JSON'yfied because it
+		// contains cyclic data structures.
+		diagnostics.forEach((diag) => {
+			diag.file = undefined;
+			const related = <ts.Diagnostic[]>diag.relatedInformation;
+			if (related) {
+				related.forEach((diag2) => (diag2.file = undefined));
+			}
+		});
+		return <monaco.languages.typescript.Diagnostic[]>diagnostics;
+	}
+
+	getSyntacticDiagnostics(
+		fileName: string
+	): Promise<monaco.languages.typescript.Diagnostic[]> {
+		const diagnostics = this._languageService.getSyntacticDiagnostics(fileName);
+		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
+	}
+
+	getSemanticDiagnostics(
+		fileName: string
+	): Promise<monaco.languages.typescript.Diagnostic[]> {
+		const diagnostics = this._languageService.getSemanticDiagnostics(fileName);
+		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
+	}
+
+	getSuggestionDiagnostics(
+		fileName: string
+	): Promise<monaco.languages.typescript.Diagnostic[]> {
+		const diagnostics = this._languageService.getSuggestionDiagnostics(
+			fileName
+		);
+		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
+	}
+
+	getCompilerOptionsDiagnostics(
+		fileName: string
+	): Promise<monaco.languages.typescript.Diagnostic[]> {
+		const diagnostics = this._languageService.getCompilerOptionsDiagnostics();
+		return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
+	}
+
+	getCompletionsAtPosition(
+		fileName: string,
+		position: number
+	): Promise<ts.CompletionInfo | undefined> {
+		return Promise.resolve(
+			this._languageService.getCompletionsAtPosition(
+				fileName,
+				position,
+				undefined
+			)
+		);
+	}
+
+	getCompletionEntryDetails(
+		fileName: string,
+		position: number,
+		entry: string
+	): Promise<ts.CompletionEntryDetails | undefined> {
+		return Promise.resolve(
+			this._languageService.getCompletionEntryDetails(
+				fileName,
+				position,
+				entry,
+				undefined,
+				undefined,
+				undefined
+			)
+		);
+	}
+
+	getSignatureHelpItems(
+		fileName: string,
+		position: number
+	): Promise<ts.SignatureHelpItems | undefined> {
+		return Promise.resolve(
+			this._languageService.getSignatureHelpItems(fileName, position, undefined)
+		);
+	}
+
+	getQuickInfoAtPosition(
+		fileName: string,
+		position: number
+	): Promise<ts.QuickInfo | undefined> {
+		return Promise.resolve(
+			this._languageService.getQuickInfoAtPosition(fileName, position)
+		);
+	}
+
+	getOccurrencesAtPosition(
+		fileName: string,
+		position: number
+	): Promise<ReadonlyArray<ts.ReferenceEntry> | undefined> {
+		return Promise.resolve(
+			this._languageService.getOccurrencesAtPosition(fileName, position)
+		);
+	}
+
+	getDefinitionAtPosition(
+		fileName: string,
+		position: number
+	): Promise<ReadonlyArray<ts.DefinitionInfo> | undefined> {
+		return Promise.resolve(
+			this._languageService.getDefinitionAtPosition(fileName, position)
+		);
+	}
+
+	getReferencesAtPosition(
+		fileName: string,
+		position: number
+	): Promise<ts.ReferenceEntry[] | undefined> {
+		return Promise.resolve(
+			this._languageService.getReferencesAtPosition(fileName, position)
+		);
+	}
+
+	getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> {
+		return Promise.resolve(
+			this._languageService.getNavigationBarItems(fileName)
+		);
+	}
+
+	getFormattingEditsForDocument(
+		fileName: string,
+		options: ts.FormatCodeOptions
+	): Promise<ts.TextChange[]> {
+		return Promise.resolve(
+			this._languageService.getFormattingEditsForDocument(fileName, options)
+		);
+	}
+
+	getFormattingEditsForRange(
+		fileName: string,
+		start: number,
+		end: number,
+		options: ts.FormatCodeOptions
+	): Promise<ts.TextChange[]> {
+		return Promise.resolve(
+			this._languageService.getFormattingEditsForRange(
+				fileName,
+				start,
+				end,
+				options
+			)
+		);
+	}
+
+	getFormattingEditsAfterKeystroke(
+		fileName: string,
+		postion: number,
+		ch: string,
+		options: ts.FormatCodeOptions
+	): Promise<ts.TextChange[]> {
+		return Promise.resolve(
+			this._languageService.getFormattingEditsAfterKeystroke(
+				fileName,
+				postion,
+				ch,
+				options
+			)
+		);
+	}
+
+	findRenameLocations(
+		fileName: string,
+		position: number,
+		findInStrings: boolean,
+		findInComments: boolean,
+		providePrefixAndSuffixTextForRename: boolean
+	): Promise<readonly ts.RenameLocation[] | undefined> {
+		return Promise.resolve(
+			this._languageService.findRenameLocations(
+				fileName,
+				position,
+				findInStrings,
+				findInComments,
+				providePrefixAndSuffixTextForRename
+			)
+		);
+	}
+
+	getRenameInfo(
+		fileName: string,
+		position: number,
+		options: ts.RenameInfoOptions
+	): Promise<ts.RenameInfo> {
+		return Promise.resolve(
+			this._languageService.getRenameInfo(fileName, position, options)
+		);
+	}
+
+	getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
+		return Promise.resolve(this._languageService.getEmitOutput(fileName));
+	}
+
+	getCodeFixesAtPosition(
+		fileName: string,
+		start: number,
+		end: number,
+		errorCodes: number[],
+		formatOptions: ts.FormatCodeOptions
+	): Promise<ReadonlyArray<ts.CodeFixAction>> {
+		const preferences = {};
+		return Promise.resolve(
+			this._languageService.getCodeFixesAtPosition(
+				fileName,
+				start,
+				end,
+				errorCodes,
+				formatOptions,
+				preferences
+			)
+		);
+	}
+
+	updateExtraLibs(extraLibs: IExtraLibs) {
+		this._extraLibs = extraLibs;
+	}
+}
+
+export interface ICreateData {
+	compilerOptions: ts.CompilerOptions;
+	extraLibs: IExtraLibs;
+	customWorkerPath?: string;
+}
+
+/** The shape of the factory */
+export interface CustomTSWebWorkerFactory {
+	(
+		TSWorkerClass: typeof TypeScriptWorker,
+		tsc: typeof ts,
+		libs: Record<string, string>
+	): typeof TypeScriptWorker;
+}
+
+declare global {
+	var importScripts: (path: string) => void | undefined;
+	var customTSWorkerFactory: CustomTSWebWorkerFactory | undefined;
+}
+
+export function create(
+	ctx: IWorkerContext,
+	createData: ICreateData
+): TypeScriptWorker {
+	let TSWorkerClass = TypeScriptWorker;
+	if (createData.customWorkerPath) {
+		if (typeof importScripts === 'undefined') {
+			console.warn(
+				'Monaco is not using webworkers for background tasks, and that is needed to support the customWorkerPath flag'
+			);
+		} else {
+			importScripts(createData.customWorkerPath);
+
+			const workerFactoryFunc: CustomTSWebWorkerFactory | undefined =
+				self.customTSWorkerFactory;
+			if (!workerFactoryFunc) {
+				throw new Error(
+					`The script at ${createData.customWorkerPath} does not add customTSWorkerFactory to self`
+				);
+			}
+
+			TSWorkerClass = workerFactoryFunc(TypeScriptWorker, ts, libFileMap);
+		}
+	}
+
+	return new TSWorkerClass(ctx, createData);
+}

+ 16 - 20
src/tsconfig.esm.json

@@ -1,22 +1,18 @@
 {
-  "compilerOptions": {
-    "module": "esnext",
-    "moduleResolution": "node",
-    "outDir": "../release/esm",
-    "target": "es5",
-    "lib": [
-      "dom",
-      "es5",
-      "es2015.collection",
-      "es2015.iterable",
-      "es2015.promise"
-    ],
-    "strict": true
-  },
-  "include": [
-    "**/*.ts"
-  ],
-  "files": [
-    "../node_modules/monaco-editor-core/monaco.d.ts"
-  ]
+	"compilerOptions": {
+		"module": "esnext",
+		"moduleResolution": "node",
+		"outDir": "../release/esm",
+		"target": "es5",
+		"lib": [
+			"dom",
+			"es5",
+			"es2015.collection",
+			"es2015.iterable",
+			"es2015.promise"
+		],
+		"strict": true
+	},
+	"include": ["**/*.ts"],
+	"files": ["../node_modules/monaco-editor-core/monaco.d.ts"]
 }

+ 16 - 20
src/tsconfig.json

@@ -1,22 +1,18 @@
 {
-  "compilerOptions": {
-    "module": "amd",
-    "moduleResolution": "node",
-    "outDir": "../release/dev",
-    "target": "es5",
-    "lib": [
-      "dom",
-      "es5",
-      "es2015.collection",
-      "es2015.iterable",
-      "es2015.promise"
-    ],
-    "strict": true
-  },
-  "include": [
-    "**/*.ts"
-  ],
-  "files": [
-    "../node_modules/monaco-editor-core/monaco.d.ts"
-  ]
+	"compilerOptions": {
+		"module": "amd",
+		"moduleResolution": "node",
+		"outDir": "../release/dev",
+		"target": "es5",
+		"lib": [
+			"dom",
+			"es5",
+			"es2015.collection",
+			"es2015.iterable",
+			"es2015.promise"
+		],
+		"strict": true
+	},
+	"include": ["**/*.ts"],
+	"files": ["../node_modules/monaco-editor-core/monaco.d.ts"]
 }

+ 117 - 110
src/workerManager.ts

@@ -1,110 +1,117 @@
-/*---------------------------------------------------------------------------------------------
- *  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 { LanguageServiceDefaultsImpl } from './monaco.contribution';
-import { TypeScriptWorker } from './tsWorker';
-
-import IDisposable = monaco.IDisposable;
-import Uri = monaco.Uri;
-
-export class WorkerManager {
-
-	private _modeId: string;
-	private _defaults: LanguageServiceDefaultsImpl;
-	private _configChangeListener: IDisposable;
-	private _updateExtraLibsToken: number;
-	private _extraLibsChangeListener: IDisposable;
-
-	private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker> | null;
-	private _client: Promise<TypeScriptWorker> | null;
-
-	constructor(modeId: string, defaults: LanguageServiceDefaultsImpl) {
-		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 = monaco.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
-				}
-			});
-
-			let p = <Promise<TypeScriptWorker>>this._worker.getProxy();
-
-			if (this._defaults.getEagerModelSync()) {
-				p = p.then(worker => {
-					if (this._worker) {
-						return this._worker.withSyncedResources(monaco.editor.getModels()
-							.filter(model => model.getModeId() === 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);
-	}
-}
+/*---------------------------------------------------------------------------------------------
+ *  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 { LanguageServiceDefaultsImpl } from './monaco.contribution';
+import { TypeScriptWorker } from './tsWorker';
+
+import IDisposable = monaco.IDisposable;
+import Uri = monaco.Uri;
+
+export class WorkerManager {
+	private _modeId: string;
+	private _defaults: LanguageServiceDefaultsImpl;
+	private _configChangeListener: IDisposable;
+	private _updateExtraLibsToken: number;
+	private _extraLibsChangeListener: IDisposable;
+
+	private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker> | null;
+	private _client: Promise<TypeScriptWorker> | null;
+
+	constructor(modeId: string, defaults: LanguageServiceDefaultsImpl) {
+		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 = monaco.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
+				}
+			});
+
+			let p = <Promise<TypeScriptWorker>>this._worker.getProxy();
+
+			if (this._defaults.getEagerModelSync()) {
+				p = p.then((worker) => {
+					if (this._worker) {
+						return this._worker.withSyncedResources(
+							monaco.editor
+								.getModels()
+								.filter((model) => model.getModeId() === 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);
+	}
+}

+ 218 - 203
test/custom-worker.html

@@ -8,215 +8,230 @@
 
 <!DOCTYPE html>
 <html>
-<head>
-	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
-	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-	<link rel="stylesheet" data-name="vs/editor/editor.main" href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
-</head>
-<body>
+	<head>
+		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+		<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+		<link
+			rel="stylesheet"
+			data-name="vs/editor/editor.main"
+			href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
+		/>
+	</head>
+	<body>
+		<h2>Monaco Editor TypeScript test page</h2>
+		<button id="resetBtn">Reset Sample</button>
+		<div
+			id="container"
+			style="width: 800px; height: 600px; border: 1px solid grey"
+		></div>
+		<h3>Custom webworker</h3>
+		<button id="logDTS">Log DTS</button>
+		<button id="getAST">Print AST to console</button>
 
-<h2>Monaco Editor TypeScript test page</h2>
-<button id="resetBtn">Reset Sample</button>
-<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
-<h3>Custom webworker</h3>
-<button id="logDTS">Log DTS</button>
-<button id="getAST">Print AST to console</button>
+		<script>
+			var paths = {
+				'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
+				'vs/language/typescript': '../release/dev',
+				vs: '../node_modules/monaco-editor-core/dev/vs'
+			};
+			if (document.location.protocol === 'http:') {
+				// Add support for running local http server
+				let testIndex = document.location.pathname.indexOf('/test/');
+				if (testIndex !== -1) {
+					let prefix = document.location.pathname.substr(0, testIndex);
+					paths['vs/language/typescript'] = prefix + '/release/dev';
+				}
+			}
+			var require = {
+				paths: paths
+			};
+		</script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
 
-<script>
-	var paths = {
-		'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
-		'vs/language/typescript': '../release/dev',
-		'vs': '../node_modules/monaco-editor-core/dev/vs'
-	};
-	if (document.location.protocol === 'http:') {
-		// Add support for running local http server
-		let testIndex = document.location.pathname.indexOf('/test/');
-		if (testIndex !== -1) {
-			let prefix = document.location.pathname.substr(0, testIndex);
-			paths['vs/language/typescript'] = prefix + '/release/dev';
-		}
-	}
-	var require = {
-		paths: paths
-	};
-</script>
-<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
-<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
-<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
+		<script>
+			function getDefaultCode() {
+				return [
+					'/* Game of Life',
+					' * Implemented in TypeScript',
+					' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
+					' */',
+					'',
+					'module Conway {',
+					'',
+					'	export class Cell {',
+					'		public row: number;',
+					'		public col: number;',
+					'		public live: boolean;',
+					'',
+					'		constructor(row: number, col: number, live: boolean) {',
+					'			this.row = row;',
+					'			this.col = col;',
+					'			this.live = live',
+					'		}',
+					'	}',
+					'',
+					'	export class GameOfLife {',
+					'		private gridSize: number;',
+					'		private canvasSize: number;',
+					'		private lineColor: string;',
+					'		private liveColor: string;',
+					'		private deadColor: string;',
+					'		private initialLifeProbability: number;',
+					'		private animationRate: number;',
+					'		private cellSize: number;',
+					'		private context: CanvasRenderingContext2D;',
+					'		private world;',
+					'',
+					'',
+					'		constructor() {',
+					'			this.gridSize = 50;',
+					'			this.canvasSize = 600;',
+					"			this.lineColor = '#cdcdcd';",
+					"			this.liveColor = '#666';",
+					"			this.deadColor = '#eee';",
+					'			this.initialLifeProbability = 0.5;',
+					'			this.animationRate = 60;',
+					'			this.cellSize = 0;',
+					'			this.world = this.createWorld();',
+					'			this.circleOfLife();',
+					'		}',
+					'',
+					'		public createWorld() {',
+					'			return this.travelWorld( (cell : Cell) =>  {',
+					'				cell.live = Math.random() < this.initialLifeProbability;',
+					'				return cell;',
+					'			});',
+					'		}',
+					'',
+					'		public circleOfLife() : void {',
+					'			this.world = this.travelWorld( (cell: Cell) => {',
+					'				cell = this.world[cell.row][cell.col];',
+					'				this.draw(cell);',
+					'				return this.resolveNextGeneration(cell);',
+					'			});',
+					'			setTimeout( () => {this.circleOfLife()}, this.animationRate);',
+					'		}',
+					'',
+					'		public resolveNextGeneration(cell : Cell) {',
+					'			var count = this.countNeighbors(cell);',
+					'			var newCell = new Cell(cell.row, cell.col, cell.live);',
+					'			if(count < 2 || count > 3) newCell.live = false;',
+					'			else if(count == 3) newCell.live = true;',
+					'			return newCell;',
+					'		}',
+					'',
+					'		public countNeighbors(cell : Cell) {',
+					'			var neighbors = 0;',
+					'			for(var row = -1; row <=1; row++) {',
+					'				for(var col = -1; col <= 1; col++) {',
+					'					if(row == 0 && col == 0) continue;',
+					'					if(this.isAlive(cell.row + row, cell.col + col)) {',
+					'						neighbors++;',
+					'					}',
+					'				}',
+					'			}',
+					'			return neighbors;',
+					'		}',
+					'',
+					'		public isAlive(row : number, col : number) {',
+					'			if(row < 0 || col < 0 || row >= this.gridSize || col >= this.gridSize) return false;',
+					'			return this.world[row][col].live;',
+					'		}',
+					'',
+					'		public travelWorld(callback) {',
+					'			var result = [];',
+					'			for(var row = 0; row < this.gridSize; row++) {',
+					'				var rowData = [];',
+					'				for(var col = 0; col < this.gridSize; col++) {',
+					'					rowData.push(callback(new Cell(row, col, false)));',
+					'				}',
+					'				result.push(rowData);',
+					'			}',
+					'			return result;',
+					'		}',
+					'',
+					'		public draw(cell : Cell) {',
+					'			if(this.context == null) this.context = this.createDrawingContext();',
+					'			if(this.cellSize == 0) this.cellSize = this.canvasSize/this.gridSize;',
+					'',
+					'			this.context.strokeStyle = this.lineColor;',
+					'			this.context.strokeRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
+					'			this.context.fillStyle = cell.live ? this.liveColor : this.deadColor;',
+					'			this.context.fillRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
+					'		}',
+					'',
+					'		public createDrawingContext() {',
+					"			var canvas = <HTMLCanvasElement> document.getElementById('conway-canvas');",
+					'			if(canvas == null) {',
+					"					canvas = document.createElement('canvas');",
+					"					canvas.id = 'conway-canvas';",
+					'					canvas.width = this.canvasSize;',
+					'					canvas.height = this.canvasSize;',
+					'					document.body.appendChild(canvas);',
+					'			}',
+					"			return canvas.getContext('2d');",
+					'		}',
+					'	}',
+					'}',
+					'',
+					'var game = new Conway.GameOfLife();'
+				].join('\n');
+			}
 
-<script>
-	function getDefaultCode() {
-		return [
-			'/* Game of Life',
-			' * Implemented in TypeScript',
-			' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
-			' */',
-			'',
-			'module Conway {',
-			'',
-			'	export class Cell {',
-			'		public row: number;',
-			'		public col: number;',
-			'		public live: boolean;',
-			'',
-			'		constructor(row: number, col: number, live: boolean) {',
-			'			this.row = row;',
-			'			this.col = col;',
-			'			this.live = live',
-			'		}',
-			'	}',
-			'',
-			'	export class GameOfLife {',
-			'		private gridSize: number;',
-			'		private canvasSize: number;',
-			'		private lineColor: string;',
-			'		private liveColor: string;',
-			'		private deadColor: string;',
-			'		private initialLifeProbability: number;',
-			'		private animationRate: number;',
-			'		private cellSize: number;',
-			'		private context: CanvasRenderingContext2D;',
-			'		private world;',
-			'',
-			'',
-			'		constructor() {',
-			'			this.gridSize = 50;',
-			'			this.canvasSize = 600;',
-			'			this.lineColor = \'#cdcdcd\';',
-			'			this.liveColor = \'#666\';',
-			'			this.deadColor = \'#eee\';',
-			'			this.initialLifeProbability = 0.5;',
-			'			this.animationRate = 60;',
-			'			this.cellSize = 0;',
-			'			this.world = this.createWorld();',
-			'			this.circleOfLife();',
-			'		}',
-			'',
-			'		public createWorld() {',
-			'			return this.travelWorld( (cell : Cell) =>  {',
-			'				cell.live = Math.random() < this.initialLifeProbability;',
-			'				return cell;',
-			'			});',
-			'		}',
-			'',
-			'		public circleOfLife() : void {',
-			'			this.world = this.travelWorld( (cell: Cell) => {',
-			'				cell = this.world[cell.row][cell.col];',
-			'				this.draw(cell);',
-			'				return this.resolveNextGeneration(cell);',
-			'			});',
-			'			setTimeout( () => {this.circleOfLife()}, this.animationRate);',
-			'		}',
-			'',
-			'		public resolveNextGeneration(cell : Cell) {',
-			'			var count = this.countNeighbors(cell);',
-			'			var newCell = new Cell(cell.row, cell.col, cell.live);',
-			'			if(count < 2 || count > 3) newCell.live = false;',
-			'			else if(count == 3) newCell.live = true;',
-			'			return newCell;',
-			'		}',
-			'',
-			'		public countNeighbors(cell : Cell) {',
-			'			var neighbors = 0;',
-			'			for(var row = -1; row <=1; row++) {',
-			'				for(var col = -1; col <= 1; col++) {',
-			'					if(row == 0 && col == 0) continue;',
-			'					if(this.isAlive(cell.row + row, cell.col + col)) {',
-			'						neighbors++;',
-			'					}',
-			'				}',
-			'			}',
-			'			return neighbors;',
-			'		}',
-			'',
-			'		public isAlive(row : number, col : number) {',
-			'			if(row < 0 || col < 0 || row >= this.gridSize || col >= this.gridSize) return false;',
-			'			return this.world[row][col].live;',
-			'		}',
-			'',
-			'		public travelWorld(callback) {',
-			'			var result = [];',
-			'			for(var row = 0; row < this.gridSize; row++) {',
-			'				var rowData = [];',
-			'				for(var col = 0; col < this.gridSize; col++) {',
-			'					rowData.push(callback(new Cell(row, col, false)));',
-			'				}',
-			'				result.push(rowData);',
-			'			}',
-			'			return result;',
-			'		}',
-			'',
-			'		public draw(cell : Cell) {',
-			'			if(this.context == null) this.context = this.createDrawingContext();',
-			'			if(this.cellSize == 0) this.cellSize = this.canvasSize/this.gridSize;',
-			'',
-			'			this.context.strokeStyle = this.lineColor;',
-			'			this.context.strokeRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
-			'			this.context.fillStyle = cell.live ? this.liveColor : this.deadColor;',
-			'			this.context.fillRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
-			'		}',
-			'',
-			'		public createDrawingContext() {',
-			'			var canvas = <HTMLCanvasElement> document.getElementById(\'conway-canvas\');',
-			'			if(canvas == null) {',
-			'					canvas = document.createElement(\'canvas\');',
-			'					canvas.id = \'conway-canvas\';',
-			'					canvas.width = this.canvasSize;',
-			'					canvas.height = this.canvasSize;',
-			'					document.body.appendChild(canvas);',
-			'			}',
-			'			return canvas.getContext(\'2d\');',
-			'		}',
-			'	}',
-			'}',
-			'',
-			'var game = new Conway.GameOfLife();',
-		].join('\n');
-	}
+			function getDefaultComplierOpts() {
+				return { target: 99, jsx: 1, allowNonTsExtensions: true };
+			}
+			require([
+				'vs/basic-languages/monaco.contribution',
+				'vs/language/typescript/monaco.contribution'
+			], () => {
+				monaco.languages.typescript.typescriptDefaults.setWorkerOptions({
+					customWorkerPath: 'http://localhost:5000/test/custom-worker.js'
+				});
+				monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
+					target: 99,
+					jsx: 1,
+					allowNonTsExtensions: true,
+					declaration: true,
+					noLibCheck: true
+				});
 
-	function getDefaultComplierOpts() {
-		return { target: 99, jsx: 1, allowNonTsExtensions: true }
-	}
-	require([
-		'vs/basic-languages/monaco.contribution',
-		'vs/language/typescript/monaco.contribution'
-	], () => {
+				var editor = monaco.editor.create(
+					document.getElementById('container'),
+					{
+						value: localStorage.getItem('code') || getDefaultCode(),
+						language: 'typescript',
+						lightbulb: { enabled: true }
+					}
+				);
 
-	monaco.languages.typescript.typescriptDefaults.setWorkerOptions({ customWorkerPath: "http://localhost:5000/test/custom-worker.js" })
-	monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ target: 99, jsx: 1, allowNonTsExtensions: true, declaration: true, noLibCheck: true })
+				editor.onDidChangeModelContent(() => {
+					const code = editor.getModel().getValue();
+					localStorage.setItem('code', code);
+				});
 
-	var editor = monaco.editor.create(document.getElementById('container'), {
-		value: localStorage.getItem("code") || getDefaultCode(),
-		language: 'typescript',
-		lightbulb: { enabled: true }
-	});
+				document.getElementById('resetBtn').onclick = () => {
+					editor.setValue(getDefaultCode());
+				};
 
-	editor.onDidChangeModelContent(() => {
-		const code = editor.getModel().getValue()
-		localStorage.setItem("code", code)
-	});
+				document.getElementById('logDTS').onclick = async () => {
+					const model = editor.getModel();
+					const worker = await monaco.languages.typescript.getTypeScriptWorker();
+					const thisWorker = await worker(model.uri);
+					const dts = await thisWorker.getDTSEmitForFile(model.uri.toString());
+					console.log(dts);
+				};
 
-	document.getElementById('resetBtn').onclick = () => {
-		editor.setValue(getDefaultCode());
-	};
-
-	document.getElementById('logDTS').onclick = async () => {
-		const model = editor.getModel()
-		const worker = await monaco.languages.typescript.getTypeScriptWorker()
-		const thisWorker = await worker(model.uri)
-		const dts = await thisWorker.getDTSEmitForFile(model.uri.toString())
-		console.log(dts)
-	};
-
-	document.getElementById('getAST').onclick = async () => {
-		const model = editor.getModel()
-		const worker = await monaco.languages.typescript.getTypeScriptWorker()
-		const thisWorker = await worker(model.uri)
-		const ast = await thisWorker.printAST(model.uri.toString())
-		console.log(ast)
-	};
-
-});
-</script>
-</body>
+				document.getElementById('getAST').onclick = async () => {
+					const model = editor.getModel();
+					const worker = await monaco.languages.typescript.getTypeScriptWorker();
+					const thisWorker = await worker(model.uri);
+					const ast = await thisWorker.printAST(model.uri.toString());
+					console.log(ast);
+				};
+			});
+		</script>
+	</body>
 </html>

+ 50 - 51
test/custom-worker.js

@@ -2,59 +2,58 @@
 // which can do work on a bg thread.
 
 // This version of the vfs edits the global scope (in the case of a webworker, this is 'self')
-importScripts("https://unpkg.com/@typescript/vfs@1.3.0/dist/vfs.globals.js")
+importScripts('https://unpkg.com/@typescript/vfs@1.3.0/dist/vfs.globals.js');
 
 /** @type { import("@typescript/vfs") } */
-const tsvfs = globalThis.tsvfs
+const tsvfs = globalThis.tsvfs;
 
 /** @type {import("../src/tsWorker").CustomTSWebWorkerFactory }*/
 const worker = (TypeScriptWorker, ts, libFileMap) => {
-  return class MonacoTSWorker extends TypeScriptWorker {
-
-    // Adds a custom function to the webworker
-    async getDTSEmitForFile(fileName) {
-      const result = await this.getEmitOutput(fileName)
-      const firstDTS = result.outputFiles.find(o => o.name.endsWith(".d.ts"))
-      return (firstDTS && firstDTS.text) || ""
-    }
-
-    async printAST(fileName) {
-      console.log("Creating virtual TS project")
-      const compilerOptions = this.getCompilationSettings()
-      const fsMap = new Map()
-      for (const key of Object.keys(libFileMap)) {
-        fsMap.set(key, "/" + libFileMap[key])
-      }
-
-      const thisCode =  await this.getScriptText(fileName)
-      fsMap.set("index.ts", thisCode)
-
-      console.log("Starting up TS program")
-      const system = tsvfs.createSystem(fsMap)
-      const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts)
-
-      const program = ts.createProgram({
-        rootNames: [...fsMap.keys()],
-        options: compilerOptions,
-        host: host.compilerHost,
-      })
-
-      // Now I can look at the AST for the .ts file too
-      const mainSrcFile = program.getSourceFile("index.ts")
-      let miniAST = "SourceFile"
-
-      const recurse = (parent, depth) => {
-        if (depth > 5) return
-        ts.forEachChild(parent, node => {
-          const spaces = "  ".repeat(depth + 1)
-          miniAST += `\n${spaces}${ts.SyntaxKind[node.kind]}`
-          recurse(node, depth + 1)
-        })
-      }
-      recurse(mainSrcFile, 0)
-      return miniAST
-    }
-  }
-}
-
-self.customTSWorkerFactory = worker
+	return class MonacoTSWorker extends TypeScriptWorker {
+		// Adds a custom function to the webworker
+		async getDTSEmitForFile(fileName) {
+			const result = await this.getEmitOutput(fileName);
+			const firstDTS = result.outputFiles.find((o) => o.name.endsWith('.d.ts'));
+			return (firstDTS && firstDTS.text) || '';
+		}
+
+		async printAST(fileName) {
+			console.log('Creating virtual TS project');
+			const compilerOptions = this.getCompilationSettings();
+			const fsMap = new Map();
+			for (const key of Object.keys(libFileMap)) {
+				fsMap.set(key, '/' + libFileMap[key]);
+			}
+
+			const thisCode = await this.getScriptText(fileName);
+			fsMap.set('index.ts', thisCode);
+
+			console.log('Starting up TS program');
+			const system = tsvfs.createSystem(fsMap);
+			const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts);
+
+			const program = ts.createProgram({
+				rootNames: [...fsMap.keys()],
+				options: compilerOptions,
+				host: host.compilerHost
+			});
+
+			// Now I can look at the AST for the .ts file too
+			const mainSrcFile = program.getSourceFile('index.ts');
+			let miniAST = 'SourceFile';
+
+			const recurse = (parent, depth) => {
+				if (depth > 5) return;
+				ts.forEachChild(parent, (node) => {
+					const spaces = '  '.repeat(depth + 1);
+					miniAST += `\n${spaces}${ts.SyntaxKind[node.kind]}`;
+					recurse(node, depth + 1);
+				});
+			};
+			recurse(mainSrcFile, 0);
+			return miniAST;
+		}
+	};
+};
+
+self.customTSWorkerFactory = worker;

+ 224 - 205
test/index.html

@@ -1,205 +1,224 @@
-<!DOCTYPE html>
-<html>
-<head>
-	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
-	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-	<link rel="stylesheet" data-name="vs/editor/editor.main" href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
-</head>
-<body>
-
-<h2>Monaco Editor TypeScript test page</h2>
-<button id="resetBtn">Reset Sample</button>
-<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
-<h3>Compiler settings</h3>
-<textarea style="font-family: monospace;" id="compilerOpts" cols="60" rows="30"></textarea><br/>
-<button id="updateCompilerSettingsBtn">Update compiler settings</button>
-
-<script>
-	var paths = {
-		'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
-		'vs/language/typescript': '../release/dev',
-		'vs': '../node_modules/monaco-editor-core/dev/vs'
-	};
-	if (document.location.protocol === 'http:') {
-		// Add support for running local http server
-		let testIndex = document.location.pathname.indexOf('/test/');
-		if (testIndex !== -1) {
-			let prefix = document.location.pathname.substr(0, testIndex);
-			paths['vs/language/typescript'] = prefix + '/release/dev';
-		}
-	}
-	var require = {
-		paths: paths
-	};
-</script>
-<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
-<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
-<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
-
-<script>
-	function getDefaultCode() {
-		return [
-			'/* Game of Life',
-			' * Implemented in TypeScript',
-			' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
-			' */',
-			'',
-			'module Conway {',
-			'',
-			'	export class Cell {',
-			'		public row: number;',
-			'		public col: number;',
-			'		public live: boolean;',
-			'',
-			'		constructor(row: number, col: number, live: boolean) {',
-			'			this.row = row;',
-			'			this.col = col;',
-			'			this.live = live',
-			'		}',
-			'	}',
-			'',
-			'	export class GameOfLife {',
-			'		private gridSize: number;',
-			'		private canvasSize: number;',
-			'		private lineColor: string;',
-			'		private liveColor: string;',
-			'		private deadColor: string;',
-			'		private initialLifeProbability: number;',
-			'		private animationRate: number;',
-			'		private cellSize: number;',
-			'		private context: CanvasRenderingContext2D;',
-			'		private world;',
-			'',
-			'',
-			'		constructor() {',
-			'			this.gridSize = 50;',
-			'			this.canvasSize = 600;',
-			'			this.lineColor = \'#cdcdcd\';',
-			'			this.liveColor = \'#666\';',
-			'			this.deadColor = \'#eee\';',
-			'			this.initialLifeProbability = 0.5;',
-			'			this.animationRate = 60;',
-			'			this.cellSize = 0;',
-			'			this.world = this.createWorld();',
-			'			this.circleOfLife();',
-			'		}',
-			'',
-			'		public createWorld() {',
-			'			return this.travelWorld( (cell : Cell) =>  {',
-			'				cell.live = Math.random() < this.initialLifeProbability;',
-			'				return cell;',
-			'			});',
-			'		}',
-			'',
-			'		public circleOfLife() : void {',
-			'			this.world = this.travelWorld( (cell: Cell) => {',
-			'				cell = this.world[cell.row][cell.col];',
-			'				this.draw(cell);',
-			'				return this.resolveNextGeneration(cell);',
-			'			});',
-			'			setTimeout( () => {this.circleOfLife()}, this.animationRate);',
-			'		}',
-			'',
-			'		public resolveNextGeneration(cell : Cell) {',
-			'			var count = this.countNeighbors(cell);',
-			'			var newCell = new Cell(cell.row, cell.col, cell.live);',
-			'			if(count < 2 || count > 3) newCell.live = false;',
-			'			else if(count == 3) newCell.live = true;',
-			'			return newCell;',
-			'		}',
-			'',
-			'		public countNeighbors(cell : Cell) {',
-			'			var neighbors = 0;',
-			'			for(var row = -1; row <=1; row++) {',
-			'				for(var col = -1; col <= 1; col++) {',
-			'					if(row == 0 && col == 0) continue;',
-			'					if(this.isAlive(cell.row + row, cell.col + col)) {',
-			'						neighbors++;',
-			'					}',
-			'				}',
-			'			}',
-			'			return neighbors;',
-			'		}',
-			'',
-			'		public isAlive(row : number, col : number) {',
-			'			if(row < 0 || col < 0 || row >= this.gridSize || col >= this.gridSize) return false;',
-			'			return this.world[row][col].live;',
-			'		}',
-			'',
-			'		public travelWorld(callback) {',
-			'			var result = [];',
-			'			for(var row = 0; row < this.gridSize; row++) {',
-			'				var rowData = [];',
-			'				for(var col = 0; col < this.gridSize; col++) {',
-			'					rowData.push(callback(new Cell(row, col, false)));',
-			'				}',
-			'				result.push(rowData);',
-			'			}',
-			'			return result;',
-			'		}',
-			'',
-			'		public draw(cell : Cell) {',
-			'			if(this.context == null) this.context = this.createDrawingContext();',
-			'			if(this.cellSize == 0) this.cellSize = this.canvasSize/this.gridSize;',
-			'',
-			'			this.context.strokeStyle = this.lineColor;',
-			'			this.context.strokeRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
-			'			this.context.fillStyle = cell.live ? this.liveColor : this.deadColor;',
-			'			this.context.fillRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
-			'		}',
-			'',
-			'		public createDrawingContext() {',
-			'			var canvas = <HTMLCanvasElement> document.getElementById(\'conway-canvas\');',
-			'			if(canvas == null) {',
-			'					canvas = document.createElement(\'canvas\');',
-			'					canvas.id = \'conway-canvas\';',
-			'					canvas.width = this.canvasSize;',
-			'					canvas.height = this.canvasSize;',
-			'					document.body.appendChild(canvas);',
-			'			}',
-			'			return canvas.getContext(\'2d\');',
-			'		}',
-			'	}',
-			'}',
-			'',
-			'var game = new Conway.GameOfLife();',
-		].join('\n');
-	}
-
-	function getDefaultComplierOpts() {
-		return { target: 99, jsx: 1, allowNonTsExtensions: true }
-	}
-	require([
-		'vs/basic-languages/monaco.contribution',
-		'vs/language/typescript/monaco.contribution'
-	], () => {
-
-		var editor = monaco.editor.create(document.getElementById('container'), {
-			value: localStorage.getItem("code") || getDefaultCode(),
-			language: 'typescript',
-			lightbulb: { enabled: true }
-		});
-
-		editor.onDidChangeModelContent(() => {
-			const code = editor.getModel().getValue()
-			localStorage.setItem("code", code)
-		});
-
-		document.getElementById('resetBtn').onclick = () => {
-			editor.setValue(getDefaultCode());
-		};
-
-		const optsString = localStorage.getItem("compiler-opts") || JSON.stringify(getDefaultComplierOpts(), null, 4)
-		document.getElementById("compilerOpts").textContent = optsString
-		monaco.languages.typescript.typescriptDefaults.setCompilerOptions(JSON.parse(optsString))
-
-		document.getElementById('updateCompilerSettingsBtn').onclick = () => {
-			const newOpts = document.getElementById('compilerOpts').value
-			monaco.languages.typescript.typescriptDefaults.setCompilerOptions(JSON.parse(newOpts))
-			localStorage.setItem("compiler-opts", newOpts)
-		};
-
-	});
-</script>
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+		<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+		<link
+			rel="stylesheet"
+			data-name="vs/editor/editor.main"
+			href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
+		/>
+	</head>
+	<body>
+		<h2>Monaco Editor TypeScript test page</h2>
+		<button id="resetBtn">Reset Sample</button>
+		<div
+			id="container"
+			style="width: 800px; height: 600px; border: 1px solid grey"
+		></div>
+		<h3>Compiler settings</h3>
+		<textarea
+			style="font-family: monospace"
+			id="compilerOpts"
+			cols="60"
+			rows="30"
+		></textarea
+		><br />
+		<button id="updateCompilerSettingsBtn">Update compiler settings</button>
+
+		<script>
+			var paths = {
+				'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
+				'vs/language/typescript': '../release/dev',
+				vs: '../node_modules/monaco-editor-core/dev/vs'
+			};
+			if (document.location.protocol === 'http:') {
+				// Add support for running local http server
+				let testIndex = document.location.pathname.indexOf('/test/');
+				if (testIndex !== -1) {
+					let prefix = document.location.pathname.substr(0, testIndex);
+					paths['vs/language/typescript'] = prefix + '/release/dev';
+				}
+			}
+			var require = {
+				paths: paths
+			};
+		</script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
+
+		<script>
+			function getDefaultCode() {
+				return [
+					'/* Game of Life',
+					' * Implemented in TypeScript',
+					' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
+					' */',
+					'',
+					'module Conway {',
+					'',
+					'	export class Cell {',
+					'		public row: number;',
+					'		public col: number;',
+					'		public live: boolean;',
+					'',
+					'		constructor(row: number, col: number, live: boolean) {',
+					'			this.row = row;',
+					'			this.col = col;',
+					'			this.live = live',
+					'		}',
+					'	}',
+					'',
+					'	export class GameOfLife {',
+					'		private gridSize: number;',
+					'		private canvasSize: number;',
+					'		private lineColor: string;',
+					'		private liveColor: string;',
+					'		private deadColor: string;',
+					'		private initialLifeProbability: number;',
+					'		private animationRate: number;',
+					'		private cellSize: number;',
+					'		private context: CanvasRenderingContext2D;',
+					'		private world;',
+					'',
+					'',
+					'		constructor() {',
+					'			this.gridSize = 50;',
+					'			this.canvasSize = 600;',
+					"			this.lineColor = '#cdcdcd';",
+					"			this.liveColor = '#666';",
+					"			this.deadColor = '#eee';",
+					'			this.initialLifeProbability = 0.5;',
+					'			this.animationRate = 60;',
+					'			this.cellSize = 0;',
+					'			this.world = this.createWorld();',
+					'			this.circleOfLife();',
+					'		}',
+					'',
+					'		public createWorld() {',
+					'			return this.travelWorld( (cell : Cell) =>  {',
+					'				cell.live = Math.random() < this.initialLifeProbability;',
+					'				return cell;',
+					'			});',
+					'		}',
+					'',
+					'		public circleOfLife() : void {',
+					'			this.world = this.travelWorld( (cell: Cell) => {',
+					'				cell = this.world[cell.row][cell.col];',
+					'				this.draw(cell);',
+					'				return this.resolveNextGeneration(cell);',
+					'			});',
+					'			setTimeout( () => {this.circleOfLife()}, this.animationRate);',
+					'		}',
+					'',
+					'		public resolveNextGeneration(cell : Cell) {',
+					'			var count = this.countNeighbors(cell);',
+					'			var newCell = new Cell(cell.row, cell.col, cell.live);',
+					'			if(count < 2 || count > 3) newCell.live = false;',
+					'			else if(count == 3) newCell.live = true;',
+					'			return newCell;',
+					'		}',
+					'',
+					'		public countNeighbors(cell : Cell) {',
+					'			var neighbors = 0;',
+					'			for(var row = -1; row <=1; row++) {',
+					'				for(var col = -1; col <= 1; col++) {',
+					'					if(row == 0 && col == 0) continue;',
+					'					if(this.isAlive(cell.row + row, cell.col + col)) {',
+					'						neighbors++;',
+					'					}',
+					'				}',
+					'			}',
+					'			return neighbors;',
+					'		}',
+					'',
+					'		public isAlive(row : number, col : number) {',
+					'			if(row < 0 || col < 0 || row >= this.gridSize || col >= this.gridSize) return false;',
+					'			return this.world[row][col].live;',
+					'		}',
+					'',
+					'		public travelWorld(callback) {',
+					'			var result = [];',
+					'			for(var row = 0; row < this.gridSize; row++) {',
+					'				var rowData = [];',
+					'				for(var col = 0; col < this.gridSize; col++) {',
+					'					rowData.push(callback(new Cell(row, col, false)));',
+					'				}',
+					'				result.push(rowData);',
+					'			}',
+					'			return result;',
+					'		}',
+					'',
+					'		public draw(cell : Cell) {',
+					'			if(this.context == null) this.context = this.createDrawingContext();',
+					'			if(this.cellSize == 0) this.cellSize = this.canvasSize/this.gridSize;',
+					'',
+					'			this.context.strokeStyle = this.lineColor;',
+					'			this.context.strokeRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
+					'			this.context.fillStyle = cell.live ? this.liveColor : this.deadColor;',
+					'			this.context.fillRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
+					'		}',
+					'',
+					'		public createDrawingContext() {',
+					"			var canvas = <HTMLCanvasElement> document.getElementById('conway-canvas');",
+					'			if(canvas == null) {',
+					"					canvas = document.createElement('canvas');",
+					"					canvas.id = 'conway-canvas';",
+					'					canvas.width = this.canvasSize;',
+					'					canvas.height = this.canvasSize;',
+					'					document.body.appendChild(canvas);',
+					'			}',
+					"			return canvas.getContext('2d');",
+					'		}',
+					'	}',
+					'}',
+					'',
+					'var game = new Conway.GameOfLife();'
+				].join('\n');
+			}
+
+			function getDefaultComplierOpts() {
+				return { target: 99, jsx: 1, allowNonTsExtensions: true };
+			}
+			require([
+				'vs/basic-languages/monaco.contribution',
+				'vs/language/typescript/monaco.contribution'
+			], () => {
+				var editor = monaco.editor.create(
+					document.getElementById('container'),
+					{
+						value: localStorage.getItem('code') || getDefaultCode(),
+						language: 'typescript',
+						lightbulb: { enabled: true }
+					}
+				);
+
+				editor.onDidChangeModelContent(() => {
+					const code = editor.getModel().getValue();
+					localStorage.setItem('code', code);
+				});
+
+				document.getElementById('resetBtn').onclick = () => {
+					editor.setValue(getDefaultCode());
+				};
+
+				const optsString =
+					localStorage.getItem('compiler-opts') ||
+					JSON.stringify(getDefaultComplierOpts(), null, 4);
+				document.getElementById('compilerOpts').textContent = optsString;
+				monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
+					JSON.parse(optsString)
+				);
+
+				document.getElementById('updateCompilerSettingsBtn').onclick = () => {
+					const newOpts = document.getElementById('compilerOpts').value;
+					monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
+						JSON.parse(newOpts)
+					);
+					localStorage.setItem('compiler-opts', newOpts);
+				};
+			});
+		</script>
+	</body>
+</html>