Run prettier

This commit is contained in:
Alex Dima 2020-09-07 18:08:18 +02:00
parent 21ceb6a387
commit b87c75d7e9
No known key found for this signature in database
GPG key ID: 6E58D7B045760DA0
20 changed files with 3351 additions and 2779 deletions

View file

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

View file

@ -4,7 +4,7 @@ Simple TypeScript and JavaScript language support for the Monaco Editor.
![typescript](https://cloud.githubusercontent.com/assets/5047891/15926623/5262fe08-2e3d-11e6-9b90-1d43fda07178.gif) ![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. _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 ## Issues
@ -14,27 +14,26 @@ Please file issues concerning `monaco-typescript` in the [`monaco-editor` reposi
This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module. This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
## Development ## Development
* `git clone https://github.com/Microsoft/monaco-typescript` - `git clone https://github.com/Microsoft/monaco-typescript`
* `cd monaco-typescript` - `cd monaco-typescript`
* `npm install .` - `npm install .`
* `npm run compile` - `npm run compile`
* `npm run watch` - `npm run watch`
* open `$/monaco-typescript/test/index.html` in your favorite browser. - open `$/monaco-typescript/test/index.html` in your favorite browser.
## Updating TypeScript ## Updating TypeScript
* change typescript's version in `package.json`. - change typescript's version in `package.json`.
* execute `npm install .` - execute `npm install .`
* execute `npm run import-typescript` - execute `npm run import-typescript`
* adopt new APIs - adopt new APIs
## Code of Conduct ## 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. 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 ## License
[MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md) [MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md)

220
package-lock.json generated
View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@
import { LanguageServiceDefaultsImpl } from './monaco.contribution'; import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import * as ts from './lib/typescriptServices'; import * as ts from './lib/typescriptServices';
import { TypeScriptWorker } from './tsWorker'; import { TypeScriptWorker } from './tsWorker';
import { libFileSet } from "./lib/lib.index" import { libFileSet } from './lib/lib.index';
import Uri = monaco.Uri; import Uri = monaco.Uri;
import Position = monaco.Position; import Position = monaco.Position;
@ -23,19 +23,22 @@ enum IndentStyle {
Smart = 2 Smart = 2
} }
export function flattenDiagnosticMessageText(diag: string | ts.DiagnosticMessageChain | undefined, newLine: string, indent = 0): string { export function flattenDiagnosticMessageText(
if (typeof diag === "string") { diag: string | ts.DiagnosticMessageChain | undefined,
newLine: string,
indent = 0
): string {
if (typeof diag === 'string') {
return diag; return diag;
} else if (diag === undefined) {
return '';
} }
else if (diag === undefined) { let result = '';
return "";
}
let result = "";
if (indent) { if (indent) {
result += newLine; result += newLine;
for (let i = 0; i < indent; i++) { for (let i = 0; i < indent; i++) {
result += " "; result += ' ';
} }
} }
result += diag.messageText; result += diag.messageText;
@ -48,19 +51,21 @@ export function flattenDiagnosticMessageText(diag: string | ts.DiagnosticMessage
return result; return result;
} }
function displayPartsToString(displayParts: ts.SymbolDisplayPart[] | undefined): string { function displayPartsToString(
displayParts: ts.SymbolDisplayPart[] | undefined
): string {
if (displayParts) { if (displayParts) {
return displayParts.map((displayPart) => displayPart.text).join(""); return displayParts.map((displayPart) => displayPart.text).join('');
} }
return ""; return '';
} }
//#endregion //#endregion
export abstract class Adapter { export abstract class Adapter {
constructor(
constructor(protected _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>) { protected _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
} ) {}
// protected _positionToOffset(model: monaco.editor.ITextModel, position: monaco.IPosition): number { // protected _positionToOffset(model: monaco.editor.ITextModel, position: monaco.IPosition): number {
// return model.getOffsetAt(position); // return model.getOffsetAt(position);
@ -70,7 +75,10 @@ export abstract class Adapter {
// return model.getPositionAt(offset); // return model.getPositionAt(offset);
// } // }
protected _textSpanToRange(model: monaco.editor.ITextModel, span: ts.TextSpan): monaco.IRange { protected _textSpanToRange(
model: monaco.editor.ITextModel,
span: ts.TextSpan
): monaco.IRange {
let p1 = model.getPositionAt(span.start); let p1 = model.getPositionAt(span.start);
let p2 = model.getPositionAt(span.start + span.length); let p2 = model.getPositionAt(span.start + span.length);
let { lineNumber: startLineNumber, column: startColumn } = p1; let { lineNumber: startLineNumber, column: startColumn } = p1;
@ -82,7 +90,6 @@ export abstract class Adapter {
// --- lib files // --- lib files
export class LibFiles { export class LibFiles {
private _libFiles: Record<string, string>; private _libFiles: Record<string, string>;
private _hasFetchedLibFiles: boolean; private _hasFetchedLibFiles: boolean;
private _fetchLibFilesPromise: Promise<void> | null; private _fetchLibFilesPromise: Promise<void> | null;
@ -99,7 +106,7 @@ export class LibFiles {
if (!uri) { if (!uri) {
return false; return false;
} }
if (uri.path.indexOf("/lib.") === 0) { if (uri.path.indexOf('/lib.') === 0) {
return !!libFileSet[uri.path.slice(1)]; return !!libFileSet[uri.path.slice(1)];
} }
return false; return false;
@ -111,7 +118,11 @@ export class LibFiles {
return model; return model;
} }
if (this.isLibFile(uri) && this._hasFetchedLibFiles) { if (this.isLibFile(uri) && this._hasFetchedLibFiles) {
return monaco.editor.createModel(this._libFiles[uri.path.slice(1)], "javascript", uri); return monaco.editor.createModel(
this._libFiles[uri.path.slice(1)],
'javascript',
uri
);
} }
return null; return null;
} }
@ -135,14 +146,12 @@ export class LibFiles {
private _fetchLibFiles(): Promise<void> { private _fetchLibFiles(): Promise<void> {
if (!this._fetchLibFilesPromise) { if (!this._fetchLibFilesPromise) {
this._fetchLibFilesPromise = ( this._fetchLibFilesPromise = this._worker()
this._worker() .then((w) => w.getLibFiles())
.then(w => w.getLibFiles()) .then((libFiles) => {
.then((libFiles) => { this._hasFetchedLibFiles = true;
this._hasFetchedLibFiles = true; this._libFiles = libFiles;
this._libFiles = libFiles; });
})
);
} }
return this._fetchLibFilesPromise; return this._fetchLibFilesPromise;
} }
@ -158,7 +167,6 @@ enum DiagnosticCategory {
} }
export class DiagnosticsAdapter extends Adapter { export class DiagnosticsAdapter extends Adapter {
private _disposables: IDisposable[] = []; private _disposables: IDisposable[] = [];
private _listener: { [uri: string]: IDisposable } = Object.create(null); private _listener: { [uri: string]: IDisposable } = Object.create(null);
@ -202,10 +210,12 @@ export class DiagnosticsAdapter extends Adapter {
this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd)); this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
this._disposables.push(monaco.editor.onWillDisposeModel(onModelRemoved)); this._disposables.push(monaco.editor.onWillDisposeModel(onModelRemoved));
this._disposables.push(monaco.editor.onDidChangeModelLanguage(event => { this._disposables.push(
onModelRemoved(event.model); monaco.editor.onDidChangeModelLanguage((event) => {
onModelAdd(event.model); onModelRemoved(event.model);
})); onModelAdd(event.model);
})
);
this._disposables.push({ this._disposables.push({
dispose() { dispose() {
@ -223,13 +233,15 @@ export class DiagnosticsAdapter extends Adapter {
} }
}; };
this._disposables.push(this._defaults.onDidChange(recomputeDiagostics)); this._disposables.push(this._defaults.onDidChange(recomputeDiagostics));
this._disposables.push(this._defaults.onDidExtraLibsChange(recomputeDiagostics)); this._disposables.push(
this._defaults.onDidExtraLibsChange(recomputeDiagostics)
);
monaco.editor.getModels().forEach(onModelAdd); monaco.editor.getModels().forEach(onModelAdd);
} }
public dispose(): void { public dispose(): void {
this._disposables.forEach(d => d && d.dispose()); this._disposables.forEach((d) => d && d.dispose());
this._disposables = []; this._disposables = [];
} }
@ -242,7 +254,11 @@ export class DiagnosticsAdapter extends Adapter {
} }
const promises: Promise<ts.Diagnostic[]>[] = []; const promises: Promise<ts.Diagnostic[]>[] = [];
const { noSyntaxValidation, noSemanticValidation, noSuggestionDiagnostics } = this._defaults.getDiagnosticsOptions(); const {
noSyntaxValidation,
noSemanticValidation,
noSuggestionDiagnostics
} = this._defaults.getDiagnosticsOptions();
if (!noSyntaxValidation) { if (!noSyntaxValidation) {
promises.push(worker.getSyntacticDiagnostics(model.uri.toString())); promises.push(worker.getSyntacticDiagnostics(model.uri.toString()));
} }
@ -262,13 +278,22 @@ export class DiagnosticsAdapter extends Adapter {
const diagnostics = allDiagnostics const diagnostics = allDiagnostics
.reduce((p, c) => c.concat(p), []) .reduce((p, c) => c.concat(p), [])
.filter(d => (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === -1); .filter(
(d) =>
(
this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []
).indexOf(d.code) === -1
);
// Fetch lib files if necessary // Fetch lib files if necessary
const relatedUris = diagnostics const relatedUris = diagnostics
.map(d => d.relatedInformation || []) .map((d) => d.relatedInformation || [])
.reduce((p, c) => c.concat(p), []) .reduce((p, c) => c.concat(p), [])
.map(relatedInformation => relatedInformation.file ? monaco.Uri.parse(relatedInformation.file.fileName) : null); .map((relatedInformation) =>
relatedInformation.file
? monaco.Uri.parse(relatedInformation.file.fileName)
: null
);
await this._libFiles.fetchLibFilesIfNecessary(relatedUris); await this._libFiles.fetchLibFilesIfNecessary(relatedUris);
@ -277,14 +302,27 @@ export class DiagnosticsAdapter extends Adapter {
return; return;
} }
monaco.editor.setModelMarkers(model, this._selector, diagnostics.map(d => this._convertDiagnostics(model, d))); 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 { private _convertDiagnostics(
model: monaco.editor.ITextModel,
diag: ts.Diagnostic
): monaco.editor.IMarkerData {
const diagStart = diag.start || 0; const diagStart = diag.start || 0;
const diagLength = diag.length || 1; const diagLength = diag.length || 1;
const { lineNumber: startLineNumber, column: startColumn } = model.getPositionAt(diagStart); const {
const { lineNumber: endLineNumber, column: endColumn } = model.getPositionAt(diagStart + diagLength); lineNumber: startLineNumber,
column: startColumn
} = model.getPositionAt(diagStart);
const {
lineNumber: endLineNumber,
column: endColumn
} = model.getPositionAt(diagStart + diagLength);
return { return {
severity: this._tsDiagnosticCategoryToMarkerSeverity(diag.category), severity: this._tsDiagnosticCategoryToMarkerSeverity(diag.category),
@ -295,11 +333,17 @@ export class DiagnosticsAdapter extends Adapter {
message: flattenDiagnosticMessageText(diag.messageText, '\n'), message: flattenDiagnosticMessageText(diag.messageText, '\n'),
code: diag.code.toString(), code: diag.code.toString(),
tags: diag.reportsUnnecessary ? [monaco.MarkerTag.Unnecessary] : [], tags: diag.reportsUnnecessary ? [monaco.MarkerTag.Unnecessary] : [],
relatedInformation: this._convertRelatedInformation(model, diag.relatedInformation), relatedInformation: this._convertRelatedInformation(
model,
diag.relatedInformation
)
}; };
} }
private _convertRelatedInformation(model: monaco.editor.ITextModel, relatedInformation?: ts.DiagnosticRelatedInformation[]): monaco.editor.IRelatedInformation[] | undefined { private _convertRelatedInformation(
model: monaco.editor.ITextModel,
relatedInformation?: ts.DiagnosticRelatedInformation[]
): monaco.editor.IRelatedInformation[] | undefined {
if (!relatedInformation) { if (!relatedInformation) {
return; return;
} }
@ -317,8 +361,14 @@ export class DiagnosticsAdapter extends Adapter {
} }
const infoStart = info.start || 0; const infoStart = info.start || 0;
const infoLength = info.length || 1; const infoLength = info.length || 1;
const { lineNumber: startLineNumber, column: startColumn } = relatedResource.getPositionAt(infoStart); const {
const { lineNumber: endLineNumber, column: endColumn } = relatedResource.getPositionAt(infoStart + infoLength); lineNumber: startLineNumber,
column: startColumn
} = relatedResource.getPositionAt(infoStart);
const {
lineNumber: endLineNumber,
column: endColumn
} = relatedResource.getPositionAt(infoStart + infoLength);
result.push({ result.push({
resource: relatedResource.uri, resource: relatedResource.uri,
@ -332,12 +382,18 @@ export class DiagnosticsAdapter extends Adapter {
return result; return result;
} }
private _tsDiagnosticCategoryToMarkerSeverity(category: ts.DiagnosticCategory): monaco.MarkerSeverity { private _tsDiagnosticCategoryToMarkerSeverity(
category: ts.DiagnosticCategory
): monaco.MarkerSeverity {
switch (category) { switch (category) {
case DiagnosticCategory.Error: return monaco.MarkerSeverity.Error case DiagnosticCategory.Error:
case DiagnosticCategory.Message: return monaco.MarkerSeverity.Info return monaco.MarkerSeverity.Error;
case DiagnosticCategory.Warning: return monaco.MarkerSeverity.Warning case DiagnosticCategory.Message:
case DiagnosticCategory.Suggestion: return monaco.MarkerSeverity.Hint return monaco.MarkerSeverity.Info;
case DiagnosticCategory.Warning:
return monaco.MarkerSeverity.Warning;
case DiagnosticCategory.Suggestion:
return monaco.MarkerSeverity.Hint;
} }
return monaco.MarkerSeverity.Info; return monaco.MarkerSeverity.Info;
} }
@ -351,30 +407,46 @@ interface MyCompletionItem extends monaco.languages.CompletionItem {
position: Position; position: Position;
} }
export class SuggestAdapter extends Adapter implements monaco.languages.CompletionItemProvider { export class SuggestAdapter
extends Adapter
implements monaco.languages.CompletionItemProvider {
public get triggerCharacters(): string[] { public get triggerCharacters(): string[] {
return ['.']; return ['.'];
} }
public async provideCompletionItems(model: monaco.editor.ITextModel, position: Position, _context: monaco.languages.CompletionContext, token: CancellationToken): Promise<monaco.languages.CompletionList | undefined> { 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 wordInfo = model.getWordUntilPosition(position);
const wordRange = new Range(position.lineNumber, wordInfo.startColumn, position.lineNumber, wordInfo.endColumn); const wordRange = new Range(
position.lineNumber,
wordInfo.startColumn,
position.lineNumber,
wordInfo.endColumn
);
const resource = model.uri; const resource = model.uri;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const info = await worker.getCompletionsAtPosition(resource.toString(), offset); const info = await worker.getCompletionsAtPosition(
resource.toString(),
offset
);
if (!info || model.isDisposed()) { if (!info || model.isDisposed()) {
return; return;
} }
const suggestions: MyCompletionItem[] = info.entries.map(entry => { const suggestions: MyCompletionItem[] = info.entries.map((entry) => {
let range = wordRange; let range = wordRange;
if (entry.replacementSpan) { if (entry.replacementSpan) {
const p1 = model.getPositionAt(entry.replacementSpan.start); const p1 = model.getPositionAt(entry.replacementSpan.start);
const p2 = model.getPositionAt(entry.replacementSpan.start + entry.replacementSpan.length); const p2 = model.getPositionAt(
entry.replacementSpan.start + entry.replacementSpan.length
);
range = new Range(p1.lineNumber, p1.column, p2.lineNumber, p2.column); range = new Range(p1.lineNumber, p1.column, p2.lineNumber, p2.column);
} }
@ -394,14 +466,23 @@ export class SuggestAdapter extends Adapter implements monaco.languages.Completi
}; };
} }
public async resolveCompletionItem(model: monaco.editor.ITextModel, _position: Position, item: monaco.languages.CompletionItem, token: CancellationToken): Promise<monaco.languages.CompletionItem> { public async resolveCompletionItem(
model: monaco.editor.ITextModel,
_position: Position,
item: monaco.languages.CompletionItem,
token: CancellationToken
): Promise<monaco.languages.CompletionItem> {
const myItem = <MyCompletionItem>item; const myItem = <MyCompletionItem>item;
const resource = myItem.uri; const resource = myItem.uri;
const position = myItem.position; const position = myItem.position;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const details = await worker.getCompletionEntryDetails(resource.toString(), offset, myItem.label); const details = await worker.getCompletionEntryDetails(
resource.toString(),
offset,
myItem.label
);
if (!details || model.isDisposed()) { if (!details || model.isDisposed()) {
return myItem; return myItem;
} }
@ -417,7 +498,9 @@ export class SuggestAdapter extends Adapter implements monaco.languages.Completi
}; };
} }
private static convertKind(kind: string): monaco.languages.CompletionItemKind { private static convertKind(
kind: string
): monaco.languages.CompletionItemKind {
switch (kind) { switch (kind) {
case Kind.primitiveType: case Kind.primitiveType:
case Kind.keyword: case Kind.keyword:
@ -451,15 +534,23 @@ export class SuggestAdapter extends Adapter implements monaco.languages.Completi
} }
} }
export class SignatureHelpAdapter extends Adapter implements monaco.languages.SignatureHelpProvider { export class SignatureHelpAdapter
extends Adapter
implements monaco.languages.SignatureHelpProvider {
public signatureHelpTriggerCharacters = ['(', ',']; public signatureHelpTriggerCharacters = ['(', ','];
public async provideSignatureHelp(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.SignatureHelpResult | undefined> { public async provideSignatureHelp(
model: monaco.editor.ITextModel,
position: Position,
token: CancellationToken
): Promise<monaco.languages.SignatureHelpResult | undefined> {
const resource = model.uri; const resource = model.uri;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const info = await worker.getSignatureHelpItems(resource.toString(), offset); const info = await worker.getSignatureHelpItems(
resource.toString(),
offset
);
if (!info || model.isDisposed()) { if (!info || model.isDisposed()) {
return; return;
@ -471,8 +562,7 @@ export class SignatureHelpAdapter extends Adapter implements monaco.languages.Si
signatures: [] signatures: []
}; };
info.items.forEach(item => { info.items.forEach((item) => {
const signature: monaco.languages.SignatureInformation = { const signature: monaco.languages.SignatureInformation = {
label: '', label: '',
parameters: [] parameters: []
@ -502,63 +592,91 @@ export class SignatureHelpAdapter extends Adapter implements monaco.languages.Si
return { return {
value: ret, value: ret,
dispose() { } dispose() {}
}; };
} }
} }
// --- hover ------ // --- hover ------
export class QuickInfoAdapter extends Adapter implements monaco.languages.HoverProvider { export class QuickInfoAdapter
extends Adapter
public async provideHover(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.Hover | undefined> { 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 resource = model.uri;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const info = await worker.getQuickInfoAtPosition(resource.toString(), offset); const info = await worker.getQuickInfoAtPosition(
resource.toString(),
offset
);
if (!info || model.isDisposed()) { if (!info || model.isDisposed()) {
return; return;
} }
const documentation = displayPartsToString(info.documentation); const documentation = displayPartsToString(info.documentation);
const tags = info.tags ? info.tags.map(tag => { const tags = info.tags
const label = `*@${tag.name}*`; ? info.tags
if (!tag.text) { .map((tag) => {
return label; const label = `*@${tag.name}*`;
} if (!tag.text) {
return label + (tag.text.match(/\r\n|\n/g) ? ' \n' + tag.text : ` - ${tag.text}`); return label;
}).join(' \n\n') : ''; }
return (
label +
(tag.text.match(/\r\n|\n/g) ? ' \n' + tag.text : ` - ${tag.text}`)
);
})
.join(' \n\n')
: '';
const contents = displayPartsToString(info.displayParts); const contents = displayPartsToString(info.displayParts);
return { return {
range: this._textSpanToRange(model, info.textSpan), range: this._textSpanToRange(model, info.textSpan),
contents: [{ contents: [
value: '```js\n' + contents + '\n```\n' {
}, { value: '```js\n' + contents + '\n```\n'
value: documentation + (tags ? '\n\n' + tags : '') },
}] {
value: documentation + (tags ? '\n\n' + tags : '')
}
]
}; };
} }
} }
// --- occurrences ------ // --- occurrences ------
export class OccurrencesAdapter extends Adapter implements monaco.languages.DocumentHighlightProvider { export class OccurrencesAdapter
extends Adapter
public async provideDocumentHighlights(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.DocumentHighlight[] | undefined> { 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 resource = model.uri;
const offset = model.getOffsetAt(position) const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const entries = await worker.getOccurrencesAtPosition(resource.toString(), offset); const entries = await worker.getOccurrencesAtPosition(
resource.toString(),
offset
);
if (!entries || model.isDisposed()) { if (!entries || model.isDisposed()) {
return; return;
} }
return entries.map(entry => { return entries.map((entry) => {
return <monaco.languages.DocumentHighlight>{ return <monaco.languages.DocumentHighlight>{
range: this._textSpanToRange(model, entry.textSpan), range: this._textSpanToRange(model, entry.textSpan),
kind: entry.isWriteAccess ? monaco.languages.DocumentHighlightKind.Write : monaco.languages.DocumentHighlightKind.Text kind: entry.isWriteAccess
? monaco.languages.DocumentHighlightKind.Write
: monaco.languages.DocumentHighlightKind.Text
}; };
}); });
} }
@ -567,7 +685,6 @@ export class OccurrencesAdapter extends Adapter implements monaco.languages.Docu
// --- definition ------ // --- definition ------
export class DefinitionAdapter extends Adapter { export class DefinitionAdapter extends Adapter {
constructor( constructor(
private readonly _libFiles: LibFiles, private readonly _libFiles: LibFiles,
worker: (...uris: Uri[]) => Promise<TypeScriptWorker> worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
@ -575,18 +692,27 @@ export class DefinitionAdapter extends Adapter {
super(worker); super(worker);
} }
public async provideDefinition(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.Definition | undefined> { public async provideDefinition(
model: monaco.editor.ITextModel,
position: Position,
token: CancellationToken
): Promise<monaco.languages.Definition | undefined> {
const resource = model.uri; const resource = model.uri;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const entries = await worker.getDefinitionAtPosition(resource.toString(), offset); const entries = await worker.getDefinitionAtPosition(
resource.toString(),
offset
);
if (!entries || model.isDisposed()) { if (!entries || model.isDisposed()) {
return; return;
} }
// Fetch lib files if necessary // Fetch lib files if necessary
await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName))); await this._libFiles.fetchLibFilesIfNecessary(
entries.map((entry) => Uri.parse(entry.fileName))
);
if (model.isDisposed()) { if (model.isDisposed()) {
return; return;
@ -609,8 +735,9 @@ export class DefinitionAdapter extends Adapter {
// --- references ------ // --- references ------
export class ReferenceAdapter extends Adapter implements monaco.languages.ReferenceProvider { export class ReferenceAdapter
extends Adapter
implements monaco.languages.ReferenceProvider {
constructor( constructor(
private readonly _libFiles: LibFiles, private readonly _libFiles: LibFiles,
worker: (...uris: Uri[]) => Promise<TypeScriptWorker> worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
@ -618,18 +745,28 @@ export class ReferenceAdapter extends Adapter implements monaco.languages.Refere
super(worker); super(worker);
} }
public async provideReferences(model: monaco.editor.ITextModel, position: Position, context: monaco.languages.ReferenceContext, token: CancellationToken): Promise<monaco.languages.Location[] | undefined> { 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 resource = model.uri;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const entries = await worker.getReferencesAtPosition(resource.toString(), offset); const entries = await worker.getReferencesAtPosition(
resource.toString(),
offset
);
if (!entries || model.isDisposed()) { if (!entries || model.isDisposed()) {
return; return;
} }
// Fetch lib files if necessary // Fetch lib files if necessary
await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName))); await this._libFiles.fetchLibFilesIfNecessary(
entries.map((entry) => Uri.parse(entry.fileName))
);
if (model.isDisposed()) { if (model.isDisposed()) {
return; return;
@ -652,9 +789,13 @@ export class ReferenceAdapter extends Adapter implements monaco.languages.Refere
// --- outline ------ // --- outline ------
export class OutlineAdapter extends Adapter implements monaco.languages.DocumentSymbolProvider { export class OutlineAdapter
extends Adapter
public async provideDocumentSymbols(model: monaco.editor.ITextModel, token: CancellationToken): Promise<monaco.languages.DocumentSymbol[] | undefined> { implements monaco.languages.DocumentSymbolProvider {
public async provideDocumentSymbols(
model: monaco.editor.ITextModel,
token: CancellationToken
): Promise<monaco.languages.DocumentSymbol[] | undefined> {
const resource = model.uri; const resource = model.uri;
const worker = await this._worker(resource); const worker = await this._worker(resource);
const items = await worker.getNavigationBarItems(resource.toString()); const items = await worker.getNavigationBarItems(resource.toString());
@ -663,11 +804,17 @@ export class OutlineAdapter extends Adapter implements monaco.languages.Document
return; return;
} }
const convert = (bucket: monaco.languages.DocumentSymbol[], item: ts.NavigationBarItem, containerLabel?: string): void => { const convert = (
bucket: monaco.languages.DocumentSymbol[],
item: ts.NavigationBarItem,
containerLabel?: string
): void => {
let result: monaco.languages.DocumentSymbol = { let result: monaco.languages.DocumentSymbol = {
name: item.text, name: item.text,
detail: '', detail: '',
kind: <monaco.languages.SymbolKind>(outlineTypeTable[item.kind] || monaco.languages.SymbolKind.Variable), kind: <monaco.languages.SymbolKind>(
(outlineTypeTable[item.kind] || monaco.languages.SymbolKind.Variable)
),
range: this._textSpanToRange(model, item.spans[0]), range: this._textSpanToRange(model, item.spans[0]),
selectionRange: this._textSpanToRange(model, item.spans[0]), selectionRange: this._textSpanToRange(model, item.spans[0]),
tags: [], tags: [],
@ -681,10 +828,10 @@ export class OutlineAdapter extends Adapter implements monaco.languages.Document
} }
bucket.push(result); bucket.push(result);
} };
let result: monaco.languages.DocumentSymbol[] = []; let result: monaco.languages.DocumentSymbol[] = [];
items.forEach(item => convert(result, item)); items.forEach((item) => convert(result, item));
return result; return result;
} }
} }
@ -720,7 +867,9 @@ export class Kind {
public static warning: string = 'warning'; public static warning: string = 'warning';
} }
let outlineTypeTable: { [kind: string]: monaco.languages.SymbolKind } = Object.create(null); let outlineTypeTable: {
[kind: string]: monaco.languages.SymbolKind;
} = Object.create(null);
outlineTypeTable[Kind.module] = monaco.languages.SymbolKind.Module; outlineTypeTable[Kind.module] = monaco.languages.SymbolKind.Module;
outlineTypeTable[Kind.class] = monaco.languages.SymbolKind.Class; outlineTypeTable[Kind.class] = monaco.languages.SymbolKind.Class;
outlineTypeTable[Kind.enum] = monaco.languages.SymbolKind.Enum; outlineTypeTable[Kind.enum] = monaco.languages.SymbolKind.Enum;
@ -739,7 +888,9 @@ outlineTypeTable[Kind.localFunction] = monaco.languages.SymbolKind.Function;
// --- formatting ---- // --- formatting ----
export abstract class FormatHelper extends Adapter { export abstract class FormatHelper extends Adapter {
protected static _convertOptions(options: monaco.languages.FormattingOptions): ts.FormatCodeOptions { protected static _convertOptions(
options: monaco.languages.FormattingOptions
): ts.FormatCodeOptions {
return { return {
ConvertTabsToSpaces: options.insertSpaces, ConvertTabsToSpaces: options.insertSpaces,
TabSize: options.tabSize, TabSize: options.tabSize,
@ -759,7 +910,10 @@ export abstract class FormatHelper extends Adapter {
}; };
} }
protected _convertTextChanges(model: monaco.editor.ITextModel, change: ts.TextChange): monaco.languages.TextEdit { protected _convertTextChanges(
model: monaco.editor.ITextModel,
change: ts.TextChange
): monaco.languages.TextEdit {
return { return {
text: change.newText, text: change.newText,
range: this._textSpanToRange(model, change.span) range: this._textSpanToRange(model, change.span)
@ -767,75 +921,130 @@ export abstract class FormatHelper extends Adapter {
} }
} }
export class FormatAdapter extends FormatHelper implements monaco.languages.DocumentRangeFormattingEditProvider { export class FormatAdapter
extends FormatHelper
public async provideDocumentRangeFormattingEdits(model: monaco.editor.ITextModel, range: Range, options: monaco.languages.FormattingOptions, token: CancellationToken): Promise<monaco.languages.TextEdit[] | undefined> { 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 resource = model.uri;
const startOffset = model.getOffsetAt({ lineNumber: range.startLineNumber, column: range.startColumn }); const startOffset = model.getOffsetAt({
const endOffset = model.getOffsetAt({ lineNumber: range.endLineNumber, column: range.endColumn }); lineNumber: range.startLineNumber,
column: range.startColumn
});
const endOffset = model.getOffsetAt({
lineNumber: range.endLineNumber,
column: range.endColumn
});
const worker = await this._worker(resource); const worker = await this._worker(resource);
const edits = await worker.getFormattingEditsForRange(resource.toString(), startOffset, endOffset, FormatHelper._convertOptions(options)); const edits = await worker.getFormattingEditsForRange(
resource.toString(),
startOffset,
endOffset,
FormatHelper._convertOptions(options)
);
if (!edits || model.isDisposed()) { if (!edits || model.isDisposed()) {
return; return;
} }
return edits.map(edit => this._convertTextChanges(model, edit)); return edits.map((edit) => this._convertTextChanges(model, edit));
} }
} }
export class FormatOnTypeAdapter extends FormatHelper implements monaco.languages.OnTypeFormattingEditProvider { export class FormatOnTypeAdapter
extends FormatHelper
implements monaco.languages.OnTypeFormattingEditProvider {
get autoFormatTriggerCharacters() { get autoFormatTriggerCharacters() {
return [';', '}', '\n']; return [';', '}', '\n'];
} }
public async provideOnTypeFormattingEdits(model: monaco.editor.ITextModel, position: Position, ch: string, options: monaco.languages.FormattingOptions, token: CancellationToken): Promise<monaco.languages.TextEdit[] | undefined> { 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 resource = model.uri;
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const edits = await worker.getFormattingEditsAfterKeystroke(resource.toString(), offset, ch, FormatHelper._convertOptions(options)); const edits = await worker.getFormattingEditsAfterKeystroke(
resource.toString(),
offset,
ch,
FormatHelper._convertOptions(options)
);
if (!edits || model.isDisposed()) { if (!edits || model.isDisposed()) {
return; return;
} }
return edits.map(edit => this._convertTextChanges(model, edit)); return edits.map((edit) => this._convertTextChanges(model, edit));
} }
} }
// --- code actions ------ // --- code actions ------
export class CodeActionAdaptor extends FormatHelper implements monaco.languages.CodeActionProvider { export class CodeActionAdaptor
extends FormatHelper
public async provideCodeActions(model: monaco.editor.ITextModel, range: Range, context: monaco.languages.CodeActionContext, token: CancellationToken): Promise<monaco.languages.CodeActionList> { 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 resource = model.uri;
const start = model.getOffsetAt({ lineNumber: range.startLineNumber, column: range.startColumn }); const start = model.getOffsetAt({
const end = model.getOffsetAt({ lineNumber: range.endLineNumber, column: range.endColumn }); lineNumber: range.startLineNumber,
column: range.startColumn
});
const end = model.getOffsetAt({
lineNumber: range.endLineNumber,
column: range.endColumn
});
const formatOptions = FormatHelper._convertOptions(model.getOptions()); const formatOptions = FormatHelper._convertOptions(model.getOptions());
const errorCodes = context.markers.filter(m => m.code).map(m => m.code).map(Number); const errorCodes = context.markers
.filter((m) => m.code)
.map((m) => m.code)
.map(Number);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const codeFixes = await worker.getCodeFixesAtPosition(resource.toString(), start, end, errorCodes, formatOptions); const codeFixes = await worker.getCodeFixesAtPosition(
resource.toString(),
start,
end,
errorCodes,
formatOptions
);
if (!codeFixes || model.isDisposed()) { if (!codeFixes || model.isDisposed()) {
return { actions: [], dispose: () => { } }; return { actions: [], dispose: () => {} };
} }
const actions = codeFixes.filter(fix => { const actions = codeFixes
// Removes any 'make a new file'-type code fix .filter((fix) => {
return fix.changes.filter(change => change.isNewFile).length === 0; // Removes any 'make a new file'-type code fix
}).map(fix => { return fix.changes.filter((change) => change.isNewFile).length === 0;
return this._tsCodeFixActionToMonacoCodeAction(model, context, fix); })
}); .map((fix) => {
return this._tsCodeFixActionToMonacoCodeAction(model, context, fix);
});
return { return {
actions: actions, actions: actions,
dispose: () => { } dispose: () => {}
}; };
} }
private _tsCodeFixActionToMonacoCodeAction(
private _tsCodeFixActionToMonacoCodeAction(model: monaco.editor.ITextModel, context: monaco.languages.CodeActionContext, codeFix: ts.CodeFixAction): monaco.languages.CodeAction { model: monaco.editor.ITextModel,
context: monaco.languages.CodeActionContext,
codeFix: ts.CodeFixAction
): monaco.languages.CodeAction {
const edits: monaco.languages.WorkspaceTextEdit[] = []; const edits: monaco.languages.WorkspaceTextEdit[] = [];
for (const change of codeFix.changes) { for (const change of codeFix.changes) {
for (const textChange of change.textChanges) { for (const textChange of change.textChanges) {
@ -853,7 +1062,7 @@ export class CodeActionAdaptor extends FormatHelper implements monaco.languages.
title: codeFix.description, title: codeFix.description,
edit: { edits: edits }, edit: { edits: edits },
diagnostics: context.markers, diagnostics: context.markers,
kind: "quickfix" kind: 'quickfix'
}; };
return action; return action;
@ -861,26 +1070,43 @@ export class CodeActionAdaptor extends FormatHelper implements monaco.languages.
} }
// --- rename ---- // --- rename ----
export class RenameAdapter extends Adapter implements monaco.languages.RenameProvider { export class RenameAdapter
extends Adapter
public async provideRenameEdits(model: monaco.editor.ITextModel, position: Position, newName: string, token: CancellationToken): Promise<monaco.languages.WorkspaceEdit & monaco.languages.Rejection | undefined> { 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 resource = model.uri;
const fileName = resource.toString(); const fileName = resource.toString();
const offset = model.getOffsetAt(position); const offset = model.getOffsetAt(position);
const worker = await this._worker(resource); const worker = await this._worker(resource);
const renameInfo = await worker.getRenameInfo(fileName, offset, { allowRenameOfImportPath: false }); const renameInfo = await worker.getRenameInfo(fileName, offset, {
if (renameInfo.canRename === false) { // use explicit comparison so that the discriminated union gets resolved properly allowRenameOfImportPath: false
});
if (renameInfo.canRename === false) {
// use explicit comparison so that the discriminated union gets resolved properly
return { return {
edits: [], edits: [],
rejectReason: renameInfo.localizedErrorMessage rejectReason: renameInfo.localizedErrorMessage
}; };
} }
if (renameInfo.fileToRename !== undefined) { if (renameInfo.fileToRename !== undefined) {
throw new Error("Renaming files is not supported."); throw new Error('Renaming files is not supported.');
} }
const renameLocations = await worker.findRenameLocations(fileName, offset, /*strings*/ false, /*comments*/ false, /*prefixAndSuffix*/ false); const renameLocations = await worker.findRenameLocations(
fileName,
offset,
/*strings*/ false,
/*comments*/ false,
/*prefixAndSuffix*/ false
);
if (!renameLocations || model.isDisposed()) { if (!renameLocations || model.isDisposed()) {
return; return;

View file

@ -22,8 +22,8 @@ export interface IExtraLibs {
[path: string]: IExtraLib; [path: string]: IExtraLib;
} }
export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.LanguageServiceDefaults { export class LanguageServiceDefaultsImpl
implements monaco.languages.typescript.LanguageServiceDefaults {
private _onDidChange = new Emitter<void>(); private _onDidChange = new Emitter<void>();
private _onDidExtraLibsChange = new Emitter<void>(); private _onDidExtraLibsChange = new Emitter<void>();
@ -34,12 +34,16 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
private _workerOptions!: monaco.languages.typescript.WorkerOptions; private _workerOptions!: monaco.languages.typescript.WorkerOptions;
private _onDidExtraLibsChangeTimeout: number; private _onDidExtraLibsChangeTimeout: number;
constructor(compilerOptions: monaco.languages.typescript.CompilerOptions, diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions, workerOptions: monaco.languages.typescript.WorkerOptions) { constructor(
compilerOptions: monaco.languages.typescript.CompilerOptions,
diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions,
workerOptions: monaco.languages.typescript.WorkerOptions
) {
this._extraLibs = Object.create(null); this._extraLibs = Object.create(null);
this._eagerModelSync = false; this._eagerModelSync = false;
this.setCompilerOptions(compilerOptions); this.setCompilerOptions(compilerOptions);
this.setDiagnosticsOptions(diagnosticsOptions); this.setDiagnosticsOptions(diagnosticsOptions);
this.setWorkerOptions(workerOptions) this.setWorkerOptions(workerOptions);
this._onDidExtraLibsChangeTimeout = -1; this._onDidExtraLibsChangeTimeout = -1;
} }
@ -52,7 +56,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
} }
get workerOptions(): monaco.languages.typescript.WorkerOptions { get workerOptions(): monaco.languages.typescript.WorkerOptions {
return this._workerOptions return this._workerOptions;
} }
getExtraLibs(): IExtraLibs { getExtraLibs(): IExtraLibs {
@ -67,10 +71,13 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
filePath = _filePath; filePath = _filePath;
} }
if (this._extraLibs[filePath] && this._extraLibs[filePath].content === content) { if (
this._extraLibs[filePath] &&
this._extraLibs[filePath].content === content
) {
// no-op, there already exists an extra lib with this content // no-op, there already exists an extra lib with this content
return { return {
dispose: () => { } dispose: () => {}
}; };
} }
@ -81,7 +88,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
this._extraLibs[filePath] = { this._extraLibs[filePath] = {
content: content, content: content,
version: myVersion, version: myVersion
}; };
this._fireOnDidExtraLibsChangeSoon(); this._fireOnDidExtraLibsChangeSoon();
@ -107,7 +114,9 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
if (libs && libs.length > 0) { if (libs && libs.length > 0) {
for (const lib of libs) { for (const lib of libs) {
const filePath = lib.filePath || `ts:extralib-${Math.random().toString(36).substring(2, 15)}`; const filePath =
lib.filePath ||
`ts:extralib-${Math.random().toString(36).substring(2, 15)}`;
const content = lib.content; const content = lib.content;
this._extraLibs[filePath] = { this._extraLibs[filePath] = {
content: content, content: content,
@ -134,7 +143,9 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
return this._compilerOptions; return this._compilerOptions;
} }
setCompilerOptions(options: monaco.languages.typescript.CompilerOptions): void { setCompilerOptions(
options: monaco.languages.typescript.CompilerOptions
): void {
this._compilerOptions = options || Object.create(null); this._compilerOptions = options || Object.create(null);
this._onDidChange.fire(undefined); this._onDidChange.fire(undefined);
} }
@ -143,7 +154,9 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
return this._diagnosticsOptions; return this._diagnosticsOptions;
} }
setDiagnosticsOptions(options: monaco.languages.typescript.DiagnosticsOptions): void { setDiagnosticsOptions(
options: monaco.languages.typescript.DiagnosticsOptions
): void {
this._diagnosticsOptions = options || Object.create(null); this._diagnosticsOptions = options || Object.create(null);
this._onDidChange.fire(undefined); this._onDidChange.fire(undefined);
} }
@ -153,8 +166,7 @@ export class LanguageServiceDefaultsImpl implements monaco.languages.typescript.
this._onDidChange.fire(undefined); this._onDidChange.fire(undefined);
} }
setMaximumWorkerIdleTime(value: number): void { setMaximumWorkerIdleTime(value: number): void {}
}
setEagerModelSync(value: boolean) { setEagerModelSync(value: boolean) {
// doesn't fire an event since no // doesn't fire an event since no
@ -202,7 +214,7 @@ enum ScriptTarget {
ES2020 = 7, ES2020 = 7,
ESNext = 99, ESNext = 99,
JSON = 100, JSON = 100,
Latest = ESNext, Latest = ESNext
} }
enum ModuleResolutionKind { enum ModuleResolutionKind {
@ -214,19 +226,29 @@ enum ModuleResolutionKind {
const typescriptDefaults = new LanguageServiceDefaultsImpl( const typescriptDefaults = new LanguageServiceDefaultsImpl(
{ allowNonTsExtensions: true, target: ScriptTarget.Latest }, { allowNonTsExtensions: true, target: ScriptTarget.Latest },
{ noSemanticValidation: false, noSyntaxValidation: false }, { noSemanticValidation: false, noSyntaxValidation: false },
{}); {}
);
const javascriptDefaults = new LanguageServiceDefaultsImpl( const javascriptDefaults = new LanguageServiceDefaultsImpl(
{ allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest }, { allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
{ noSemanticValidation: true, noSyntaxValidation: false }, { noSemanticValidation: true, noSyntaxValidation: false },
{}); {}
);
function getTypeScriptWorker(): Promise<(...uris: monaco.Uri[]) => Promise<monaco.languages.typescript.TypeScriptWorker>> { function getTypeScriptWorker(): Promise<
return getMode().then(mode => mode.getTypeScriptWorker()); (
...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>> { function getJavaScriptWorker(): Promise<
return getMode().then(mode => mode.getJavaScriptWorker()); (
...uris: monaco.Uri[]
) => Promise<monaco.languages.typescript.TypeScriptWorker>
> {
return getMode().then((mode) => mode.getJavaScriptWorker());
} }
// Export API // Export API
@ -242,7 +264,7 @@ function createAPI(): typeof monaco.languages.typescript {
javascriptDefaults: javascriptDefaults, javascriptDefaults: javascriptDefaults,
getTypeScriptWorker: getTypeScriptWorker, getTypeScriptWorker: getTypeScriptWorker,
getJavaScriptWorker: getJavaScriptWorker getJavaScriptWorker: getJavaScriptWorker
} };
} }
monaco.languages.typescript = createAPI(); monaco.languages.typescript = createAPI();
@ -253,8 +275,8 @@ function getMode(): Promise<typeof mode> {
} }
monaco.languages.onLanguage('typescript', () => { monaco.languages.onLanguage('typescript', () => {
return getMode().then(mode => mode.setupTypeScript(typescriptDefaults)); return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
}); });
monaco.languages.onLanguage('javascript', () => { monaco.languages.onLanguage('javascript', () => {
return getMode().then(mode => mode.setupJavaScript(javascriptDefaults)); return getMode().then((mode) => mode.setupJavaScript(javascriptDefaults));
}); });

759
src/monaco.d.ts vendored
View file

@ -1,397 +1,458 @@
declare module monaco.languages.typescript { declare module monaco.languages.typescript {
enum ModuleKind {
None = 0,
CommonJS = 1,
AMD = 2,
UMD = 3,
System = 4,
ES2015 = 5,
ESNext = 99
}
enum ModuleKind { enum JsxEmit {
None = 0, None = 0,
CommonJS = 1, Preserve = 1,
AMD = 2, React = 2,
UMD = 3, ReactNative = 3
System = 4, }
ES2015 = 5, enum NewLineKind {
ESNext = 99 CarriageReturnLineFeed = 0,
} LineFeed = 1
}
enum JsxEmit { enum ScriptTarget {
None = 0, ES3 = 0,
Preserve = 1, ES5 = 1,
React = 2, ES2015 = 2,
ReactNative = 3 ES2016 = 3,
} ES2017 = 4,
enum NewLineKind { ES2018 = 5,
CarriageReturnLineFeed = 0, ES2019 = 6,
LineFeed = 1 ES2020 = 7,
} ESNext = 99,
JSON = 100,
Latest = ESNext
}
enum ScriptTarget { export enum ModuleResolutionKind {
ES3 = 0, Classic = 1,
ES5 = 1, NodeJs = 2
ES2015 = 2, }
ES2016 = 3,
ES2017 = 4,
ES2018 = 5,
ES2019 = 6,
ES2020 = 7,
ESNext = 99,
JSON = 100,
Latest = ESNext,
}
export enum ModuleResolutionKind { interface MapLike<T> {
Classic = 1, [index: string]: T;
NodeJs = 2 }
}
interface MapLike<T> { type CompilerOptionsValue =
[index: string]: T; | 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;
}
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | null | undefined; export interface DiagnosticsOptions {
interface CompilerOptions { noSemanticValidation?: boolean;
allowJs?: boolean; noSyntaxValidation?: boolean;
allowSyntheticDefaultImports?: boolean; noSuggestionDiagnostics?: boolean;
allowUmdGlobalAccess?: boolean; diagnosticCodesToIgnore?: number[];
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 { export interface WorkerOptions {
noSemanticValidation?: boolean; /** A full HTTP path to a JavaScript file which adds a function `customTSWorkerFactory` to the self inside a web-worker */
noSyntaxValidation?: boolean; customWorkerPath?: string;
noSuggestionDiagnostics?: boolean; }
diagnosticCodesToIgnore?: number[];
}
export interface WorkerOptions { interface IExtraLib {
/** A full HTTP path to a JavaScript file which adds a function `customTSWorkerFactory` to the self inside a web-worker */ content: string;
customWorkerPath?: string; version: number;
} }
interface IExtraLib { interface IExtraLibs {
content: string; [path: string]: IExtraLib;
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 {
* A linked list of formatted diagnostic messages to be used as part of a multiline message. outputFiles: OutputFile[];
* It is built from the bottom up, leaving the head to be the "main" diagnostic. emitSkipped: boolean;
*/ }
interface DiagnosticMessageChain { interface OutputFile {
messageText: string; name: string;
/** Diagnostic category: warning = 0, error = 1, suggestion = 2, message = 3 */ writeByteOrderMark: boolean;
category: 0 | 1 | 2 | 3; text: string;
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 { export interface LanguageServiceDefaults {
outputFiles: OutputFile[]; /**
emitSkipped: boolean; * Event fired when compiler options or diagnostics options are changed.
} */
interface OutputFile { readonly onDidChange: IEvent<void>;
name: string;
writeByteOrderMark: boolean;
text: string;
}
export interface LanguageServiceDefaults { /**
/** * Event fired when extra libraries registered with the language service change.
* Event fired when compiler options or diagnostics options are changed. */
*/ readonly onDidExtraLibsChange: IEvent<void>;
readonly onDidChange: IEvent<void>;
/** /**
* Event fired when extra libraries registered with the language service change. * Get the current extra libs registered with the language service.
*/ */
readonly onDidExtraLibsChange: IEvent<void>; getExtraLibs(): IExtraLibs;
/** /**
* Get the current extra libs registered with the language service. * Add an additional source file to the language service. Use this
*/ * for typescript (definition) files that won't be loaded as editor
getExtraLibs(): IExtraLibs; * 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;
/** /**
* Add an additional source file to the language service. Use this * Remove all existing extra libs and set the additional source
* for typescript (definition) files that won't be loaded as editor * files to the language service. Use this for typescript definition
* documents, like `jquery.d.ts`. * files that won't be loaded as editor documents, like `jquery.d.ts`.
* * @param libs An array of entries to register.
* @param content The file content */
* @param filePath An optional file path setExtraLibs(libs: { content: string; filePath?: string }[]): void;
* @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 * Get current TypeScript compiler options for the language service.
* files to the language service. Use this for typescript definition */
* files that won't be loaded as editor documents, like `jquery.d.ts`. getCompilerOptions(): CompilerOptions;
* @param libs An array of entries to register.
*/
setExtraLibs(libs: { content: string; filePath?: string }[]): void;
/** /**
* Get current TypeScript compiler options for the language service. * Set TypeScript compiler options.
*/ */
getCompilerOptions(): CompilerOptions; setCompilerOptions(options: CompilerOptions): void;
/** /**
* Set TypeScript compiler options. * Get the current diagnostics options for the language service.
*/ */
setCompilerOptions(options: CompilerOptions): void; getDiagnosticsOptions(): DiagnosticsOptions;
/** /**
* Get the current diagnostics options for the language service. * Configure whether syntactic and/or semantic validation should
*/ * be performed
getDiagnosticsOptions(): DiagnosticsOptions; */
setDiagnosticsOptions(options: DiagnosticsOptions): void;
/** /**
* Configure whether syntactic and/or semantic validation should * No-op.
* be performed */
*/ setMaximumWorkerIdleTime(value: number): void;
setDiagnosticsOptions(options: DiagnosticsOptions): void;
/** /**
* No-op. * Configure if all existing models should be eagerly sync'd
*/ * to the worker on start or restart.
setMaximumWorkerIdleTime(value: number): void; */
setEagerModelSync(value: boolean): void;
/** /**
* Configure if all existing models should be eagerly sync'd * Get the current setting for whether all existing models should be eagerly sync'd
* to the worker on start or restart. * to the worker on start or restart.
*/ */
setEagerModelSync(value: boolean): void; getEagerModelSync(): boolean;
}
/** export interface TypeScriptWorker {
* Get the current setting for whether all existing models should be eagerly sync'd /**
* to the worker on start or restart. * Get diagnostic messages for any syntax issues in the given file.
*/ */
getEagerModelSync(): boolean; getSyntacticDiagnostics(fileName: string): Promise<Diagnostic[]>;
}
export interface TypeScriptWorker { /**
/** * Get diagnostic messages for any semantic issues in the given file.
* Get diagnostic messages for any syntax issues in the given file. */
*/ getSemanticDiagnostics(fileName: string): Promise<Diagnostic[]>;
getSyntacticDiagnostics(fileName: string): Promise<Diagnostic[]>;
/** /**
* Get diagnostic messages for any semantic issues in the given file. * Get diagnostic messages for any suggestions related to the given file.
*/ */
getSemanticDiagnostics(fileName: string): Promise<Diagnostic[]>; getSuggestionDiagnostics(fileName: string): Promise<Diagnostic[]>;
/** /**
* Get diagnostic messages for any suggestions related to the given file. * Get the content of a given file.
*/ */
getSuggestionDiagnostics(fileName: string): Promise<Diagnostic[]>; getScriptText(fileName: string): Promise<string | undefined>;
/** /**
* Get the content of a given file. * Get diagnostic messages related to the current compiler options.
*/ * @param fileName Not used
getScriptText(fileName: string): Promise<string | undefined>; */
getCompilerOptionsDiagnostics(fileName: string): Promise<Diagnostic[]>;
/** /**
* Get diagnostic messages related to the current compiler options. * Get code completions for the given file and position.
* @param fileName Not used * @returns `Promise<typescript.CompletionInfo | undefined>`
*/ */
getCompilerOptionsDiagnostics(fileName: string): Promise<Diagnostic[]>; getCompletionsAtPosition(
fileName: string,
position: number
): Promise<any | undefined>;
/** /**
* Get code completions for the given file and position. * Get code completion details for the given file, position, and entry.
* @returns `Promise<typescript.CompletionInfo | undefined>` * @returns `Promise<typescript.CompletionEntryDetails | undefined>`
*/ */
getCompletionsAtPosition(fileName: string, position: number): Promise<any | undefined>; getCompletionEntryDetails(
fileName: string,
position: number,
entry: string
): Promise<any | undefined>;
/** /**
* Get code completion details for the given file, position, and entry. * Get signature help items for the item at the given file and position.
* @returns `Promise<typescript.CompletionEntryDetails | undefined>` * @returns `Promise<typescript.SignatureHelpItems | undefined>`
*/ */
getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<any | undefined>; getSignatureHelpItems(
fileName: string,
position: number
): Promise<any | undefined>;
/** /**
* Get signature help items for the item at the given file and position. * Get quick info for the item at the given position in the file.
* @returns `Promise<typescript.SignatureHelpItems | undefined>` * @returns `Promise<typescript.QuickInfo | undefined>`
*/ */
getSignatureHelpItems(fileName: string, position: number): Promise<any | undefined>; getQuickInfoAtPosition(
fileName: string,
position: number
): Promise<any | undefined>;
/** /**
* Get quick info for the item at the given position in the file. * Get other ranges which are related to the item at the given position in the file (often used for highlighting).
* @returns `Promise<typescript.QuickInfo | undefined>` * @returns `Promise<ReadonlyArray<typescript.ReferenceEntry> | undefined>`
*/ */
getQuickInfoAtPosition(fileName: string, position: number): Promise<any | undefined>; getOccurrencesAtPosition(
fileName: string,
position: number
): Promise<ReadonlyArray<any> | undefined>;
/** /**
* Get other ranges which are related to the item at the given position in the file (often used for highlighting). * Get the definition of the item at the given position in the file.
* @returns `Promise<ReadonlyArray<typescript.ReferenceEntry> | undefined>` * @returns `Promise<ReadonlyArray<typescript.DefinitionInfo> | undefined>`
*/ */
getOccurrencesAtPosition(fileName: string, position: number): Promise<ReadonlyArray<any> | undefined>; getDefinitionAtPosition(
fileName: string,
position: number
): Promise<ReadonlyArray<any> | undefined>;
/** /**
* Get the definition of the item at the given position in the file. * Get references to the item at the given position in the file.
* @returns `Promise<ReadonlyArray<typescript.DefinitionInfo> | undefined>` * @returns `Promise<typescript.ReferenceEntry[] | undefined>`
*/ */
getDefinitionAtPosition(fileName: string, position: number): Promise<ReadonlyArray<any> | undefined>; getReferencesAtPosition(
fileName: string,
position: number
): Promise<any[] | undefined>;
/** /**
* Get references to the item at the given position in the file. * Get outline entries for the item at the given position in the file.
* @returns `Promise<typescript.ReferenceEntry[] | undefined>` * @returns `Promise<typescript.NavigationBarItem[]>`
*/ */
getReferencesAtPosition(fileName: string, position: number): Promise<any[] | undefined>; getNavigationBarItems(fileName: string): Promise<any[]>;
/** /**
* Get outline entries for the item at the given position in the file. * Get changes which should be applied to format the given file.
* @returns `Promise<typescript.NavigationBarItem[]>` * @param options `typescript.FormatCodeOptions`
*/ * @returns `Promise<typescript.TextChange[]>`
getNavigationBarItems(fileName: string): Promise<any[]>; */
getFormattingEditsForDocument(
fileName: string,
options: any
): Promise<any[]>;
/** /**
* Get changes which should be applied to format the given file. * Get changes which should be applied to format the given range in the file.
* @param options `typescript.FormatCodeOptions` * @param options `typescript.FormatCodeOptions`
* @returns `Promise<typescript.TextChange[]>` * @returns `Promise<typescript.TextChange[]>`
*/ */
getFormattingEditsForDocument(fileName: string, options: any): Promise<any[]>; getFormattingEditsForRange(
fileName: string,
start: number,
end: number,
options: any
): Promise<any[]>;
/** /**
* Get changes which should be applied to format the given range in the file. * Get formatting changes which should be applied after the given keystroke.
* @param options `typescript.FormatCodeOptions` * @param options `typescript.FormatCodeOptions`
* @returns `Promise<typescript.TextChange[]>` * @returns `Promise<typescript.TextChange[]>`
*/ */
getFormattingEditsForRange(fileName: string, start: number, end: number, options: any): Promise<any[]>; getFormattingEditsAfterKeystroke(
fileName: string,
postion: number,
ch: string,
options: any
): Promise<any[]>;
/** /**
* Get formatting changes which should be applied after the given keystroke. * Get other occurrences which should be updated when renaming the item at the given file and position.
* @param options `typescript.FormatCodeOptions` * @returns `Promise<readonly typescript.RenameLocation[] | undefined>`
* @returns `Promise<typescript.TextChange[]>` */
*/ findRenameLocations(
getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: any): Promise<any[]>; fileName: string,
positon: number,
findInStrings: boolean,
findInComments: boolean,
providePrefixAndSuffixTextForRename: boolean
): Promise<readonly any[] | undefined>;
/** /**
* Get other occurrences which should be updated when renaming the item at the given file and position. * Get edits which should be applied to rename the item at the given file and position (or a failure reason).
* @returns `Promise<readonly typescript.RenameLocation[] | undefined>` * @param options `typescript.RenameInfoOptions`
*/ * @returns `Promise<typescript.RenameInfo>`
findRenameLocations(fileName: string, positon: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise<readonly any[] | undefined>; */
getRenameInfo(
fileName: string,
positon: number,
options: any
): Promise<any>;
/** /**
* Get edits which should be applied to rename the item at the given file and position (or a failure reason). * Get transpiled output for the given file.
* @param options `typescript.RenameInfoOptions` * @returns `typescript.EmitOutput`
* @returns `Promise<typescript.RenameInfo>` */
*/ getEmitOutput(fileName: string): Promise<any>;
getRenameInfo(fileName: string, positon: number, options: any): Promise<any>;
/** /**
* Get transpiled output for the given file. * Get possible code fixes at the given position in the file.
* @returns `typescript.EmitOutput` * @param formatOptions `typescript.FormatCodeOptions`
*/ * @returns `Promise<ReadonlyArray<typescript.CodeFixAction>>`
getEmitOutput(fileName: string): Promise<any>; */
getCodeFixesAtPosition(
fileName: string,
start: number,
end: number,
errorCodes: number[],
formatOptions: any
): Promise<ReadonlyArray<any>>;
}
/** export const typescriptVersion: string;
* 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 typescriptDefaults: LanguageServiceDefaults; export const getTypeScriptWorker: () => Promise<
export const javascriptDefaults: LanguageServiceDefaults; (...uris: Uri[]) => Promise<TypeScriptWorker>
>;
export const getTypeScriptWorker: () => Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>>; export const getJavaScriptWorker: () => Promise<
export const getJavaScriptWorker: () => Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>>; (...uris: Uri[]) => Promise<TypeScriptWorker>
>;
} }

View file

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

View file

@ -15,41 +15,41 @@ let javaScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
let typeScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>; let typeScriptWorker: (...uris: Uri[]) => Promise<TypeScriptWorker>;
export function setupTypeScript(defaults: LanguageServiceDefaultsImpl): void { export function setupTypeScript(defaults: LanguageServiceDefaultsImpl): void {
typeScriptWorker = setupMode( typeScriptWorker = setupMode(defaults, 'typescript');
defaults,
'typescript'
);
} }
export function setupJavaScript(defaults: LanguageServiceDefaultsImpl): void { export function setupJavaScript(defaults: LanguageServiceDefaultsImpl): void {
javaScriptWorker = setupMode( javaScriptWorker = setupMode(defaults, 'javascript');
defaults,
'javascript'
);
} }
export function getJavaScriptWorker(): Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>> { export function getJavaScriptWorker(): Promise<
(...uris: Uri[]) => Promise<TypeScriptWorker>
> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!javaScriptWorker) { if (!javaScriptWorker) {
return reject("JavaScript not registered!"); return reject('JavaScript not registered!');
} }
resolve(javaScriptWorker); resolve(javaScriptWorker);
}); });
} }
export function getTypeScriptWorker(): Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>> { export function getTypeScriptWorker(): Promise<
(...uris: Uri[]) => Promise<TypeScriptWorker>
> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!typeScriptWorker) { if (!typeScriptWorker) {
return reject("TypeScript not registered!"); return reject('TypeScript not registered!');
} }
resolve(typeScriptWorker); resolve(typeScriptWorker);
}); });
} }
function setupMode(defaults: LanguageServiceDefaultsImpl, modeId: string): (...uris: Uri[]) => Promise<TypeScriptWorker> { function setupMode(
defaults: LanguageServiceDefaultsImpl,
modeId: string
): (...uris: Uri[]) => Promise<TypeScriptWorker> {
const client = new WorkerManager(modeId, defaults); const client = new WorkerManager(modeId, defaults);
const worker = (...uris: Uri[]): Promise<TypeScriptWorker> => { const worker = (...uris: Uri[]): Promise<TypeScriptWorker> => {
return client.getLanguageServiceWorker(...uris); return client.getLanguageServiceWorker(...uris);
@ -57,17 +57,50 @@ function setupMode(defaults: LanguageServiceDefaultsImpl, modeId: string): (...u
const libFiles = new languageFeatures.LibFiles(worker); const libFiles = new languageFeatures.LibFiles(worker);
monaco.languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker)); monaco.languages.registerCompletionItemProvider(
monaco.languages.registerSignatureHelpProvider(modeId, new languageFeatures.SignatureHelpAdapter(worker)); modeId,
monaco.languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker)); new languageFeatures.SuggestAdapter(worker)
monaco.languages.registerDocumentHighlightProvider(modeId, new languageFeatures.OccurrencesAdapter(worker)); );
monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(libFiles, worker)); monaco.languages.registerSignatureHelpProvider(
monaco.languages.registerReferenceProvider(modeId, new languageFeatures.ReferenceAdapter(libFiles, worker)); modeId,
monaco.languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker)); new languageFeatures.SignatureHelpAdapter(worker)
monaco.languages.registerDocumentRangeFormattingEditProvider(modeId, new languageFeatures.FormatAdapter(worker)); );
monaco.languages.registerOnTypeFormattingEditProvider(modeId, new languageFeatures.FormatOnTypeAdapter(worker)); monaco.languages.registerHoverProvider(
monaco.languages.registerCodeActionProvider(modeId, new languageFeatures.CodeActionAdaptor(worker)); modeId,
monaco.languages.registerRenameProvider(modeId, new languageFeatures.RenameAdapter(worker)); 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); new languageFeatures.DiagnosticsAdapter(libFiles, defaults, modeId, worker);
return worker; return worker;

View file

@ -10,9 +10,10 @@ import { IExtraLibs } from './monaco.contribution';
import IWorkerContext = monaco.worker.IWorkerContext; import IWorkerContext = monaco.worker.IWorkerContext;
export class TypeScriptWorker
export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.languages.typescript.TypeScriptWorker { implements
ts.LanguageServiceHost,
monaco.languages.typescript.TypeScriptWorker {
// --- model sync ----------------------- // --- model sync -----------------------
private _ctx: IWorkerContext; private _ctx: IWorkerContext;
@ -33,7 +34,9 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
} }
getScriptFileNames(): string[] { getScriptFileNames(): string[] {
let models = this._ctx.getMirrorModels().map(model => model.uri.toString()); let models = this._ctx
.getMirrorModels()
.map((model) => model.uri.toString());
return models.concat(Object.keys(this._extraLibs)); return models.concat(Object.keys(this._extraLibs));
} }
@ -72,7 +75,6 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
text = model.getValue(); text = model.getValue();
} else if (fileName in libFileMap) { } else if (fileName in libFileMap) {
text = libFileMap[fileName]; text = libFileMap[fileName];
} else if (fileName in this._extraLibs) { } else if (fileName in this._extraLibs) {
// extra lib // extra lib
text = this._extraLibs[fileName].content; text = this._extraLibs[fileName].content;
@ -99,13 +101,18 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
getScriptKind?(fileName: string): ts.ScriptKind { getScriptKind?(fileName: string): ts.ScriptKind {
const suffix = fileName.substr(fileName.lastIndexOf('.') + 1); const suffix = fileName.substr(fileName.lastIndexOf('.') + 1);
switch (suffix) { switch (suffix) {
case 'ts': return ts.ScriptKind.TS; case 'ts':
case 'tsx': return ts.ScriptKind.TSX; return ts.ScriptKind.TS;
case 'js': return ts.ScriptKind.JS; case 'tsx':
case 'jsx': return ts.ScriptKind.JSX; return ts.ScriptKind.TSX;
default: return this.getCompilationSettings().allowJs case 'js':
? ts.ScriptKind.JS return ts.ScriptKind.JS;
: ts.ScriptKind.TS; case 'jsx':
return ts.ScriptKind.JSX;
default:
return this.getCompilationSettings().allowJs
? ts.ScriptKind.JS
: ts.ScriptKind.TS;
} }
} }
@ -116,8 +123,8 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
getDefaultLibFileName(options: ts.CompilerOptions): string { getDefaultLibFileName(options: ts.CompilerOptions): string {
switch (options.target) { switch (options.target) {
case 99 /* ESNext */: case 99 /* ESNext */:
const esnext = "lib.esnext.full.d.ts"; const esnext = 'lib.esnext.full.d.ts';
if (esnext in libFileMap || esnext in this._extraLibs) return esnext if (esnext in libFileMap || esnext in this._extraLibs) return esnext;
case 7 /* ES2020 */: case 7 /* ES2020 */:
case 6 /* ES2019 */: case 6 /* ES2019 */:
case 5 /* ES2018 */: case 5 /* ES2018 */:
@ -135,10 +142,10 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
return eslib; return eslib;
} }
return "lib.es6.d.ts"; // We don't use lib.es2015.full.d.ts due to breaking change. return 'lib.es6.d.ts'; // We don't use lib.es2015.full.d.ts due to breaking change.
case 1: case 1:
case 0: case 0:
return "lib.d.ts"; return 'lib.d.ts';
} }
} }
@ -152,98 +159,223 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
// --- language features // --- language features
private static clearFiles(diagnostics: ts.Diagnostic[]): monaco.languages.typescript.Diagnostic[] { private static clearFiles(
diagnostics: ts.Diagnostic[]
): monaco.languages.typescript.Diagnostic[] {
// Clear the `file` field, which cannot be JSON'yfied because it // Clear the `file` field, which cannot be JSON'yfied because it
// contains cyclic data structures. // contains cyclic data structures.
diagnostics.forEach(diag => { diagnostics.forEach((diag) => {
diag.file = undefined; diag.file = undefined;
const related = <ts.Diagnostic[]>diag.relatedInformation; const related = <ts.Diagnostic[]>diag.relatedInformation;
if (related) { if (related) {
related.forEach(diag2 => diag2.file = undefined); related.forEach((diag2) => (diag2.file = undefined));
} }
}); });
return <monaco.languages.typescript.Diagnostic[]>diagnostics; return <monaco.languages.typescript.Diagnostic[]>diagnostics;
} }
getSyntacticDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> { getSyntacticDiagnostics(
fileName: string
): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getSyntacticDiagnostics(fileName); const diagnostics = this._languageService.getSyntacticDiagnostics(fileName);
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics)); return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
} }
getSemanticDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> { getSemanticDiagnostics(
fileName: string
): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getSemanticDiagnostics(fileName); const diagnostics = this._languageService.getSemanticDiagnostics(fileName);
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics)); return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
} }
getSuggestionDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> { getSuggestionDiagnostics(
const diagnostics = this._languageService.getSuggestionDiagnostics(fileName); fileName: string
): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getSuggestionDiagnostics(
fileName
);
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics)); return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
} }
getCompilerOptionsDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> { getCompilerOptionsDiagnostics(
fileName: string
): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getCompilerOptionsDiagnostics(); const diagnostics = this._languageService.getCompilerOptionsDiagnostics();
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics)); return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
} }
getCompletionsAtPosition(fileName: string, position: number): Promise<ts.CompletionInfo | undefined> { getCompletionsAtPosition(
return Promise.resolve(this._languageService.getCompletionsAtPosition(fileName, position, undefined)); 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> { getCompletionEntryDetails(
return Promise.resolve(this._languageService.getCompletionEntryDetails(fileName, position, entry, undefined, undefined, undefined)); 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> { getSignatureHelpItems(
return Promise.resolve(this._languageService.getSignatureHelpItems(fileName, position, undefined)); 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> { getQuickInfoAtPosition(
return Promise.resolve(this._languageService.getQuickInfoAtPosition(fileName, position)); 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> { getOccurrencesAtPosition(
return Promise.resolve(this._languageService.getOccurrencesAtPosition(fileName, position)); 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> { getDefinitionAtPosition(
return Promise.resolve(this._languageService.getDefinitionAtPosition(fileName, position)); 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> { getReferencesAtPosition(
return Promise.resolve(this._languageService.getReferencesAtPosition(fileName, position)); fileName: string,
position: number
): Promise<ts.ReferenceEntry[] | undefined> {
return Promise.resolve(
this._languageService.getReferencesAtPosition(fileName, position)
);
} }
getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> { getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> {
return Promise.resolve(this._languageService.getNavigationBarItems(fileName)); return Promise.resolve(
this._languageService.getNavigationBarItems(fileName)
);
} }
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> { getFormattingEditsForDocument(
return Promise.resolve(this._languageService.getFormattingEditsForDocument(fileName, options)); 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[]> { getFormattingEditsForRange(
return Promise.resolve(this._languageService.getFormattingEditsForRange(fileName, start, end, options)); 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[]> { getFormattingEditsAfterKeystroke(
return Promise.resolve(this._languageService.getFormattingEditsAfterKeystroke(fileName, postion, ch, options)); 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> { findRenameLocations(
return Promise.resolve(this._languageService.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename)); 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> { getRenameInfo(
return Promise.resolve(this._languageService.getRenameInfo(fileName, position, options)); 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> { getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
return Promise.resolve(this._languageService.getEmitOutput(fileName)); return Promise.resolve(this._languageService.getEmitOutput(fileName));
} }
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: ts.FormatCodeOptions): Promise<ReadonlyArray<ts.CodeFixAction>> { getCodeFixesAtPosition(
const preferences = {} fileName: string,
return Promise.resolve(this._languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences)); 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) { updateExtraLibs(extraLibs: IExtraLibs) {
@ -254,31 +386,45 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
export interface ICreateData { export interface ICreateData {
compilerOptions: ts.CompilerOptions; compilerOptions: ts.CompilerOptions;
extraLibs: IExtraLibs; extraLibs: IExtraLibs;
customWorkerPath?: string customWorkerPath?: string;
} }
/** The shape of the factory */ /** The shape of the factory */
export interface CustomTSWebWorkerFactory { export interface CustomTSWebWorkerFactory {
(TSWorkerClass: typeof TypeScriptWorker, tsc: typeof ts, libs: Record<string, string>): typeof TypeScriptWorker (
TSWorkerClass: typeof TypeScriptWorker,
tsc: typeof ts,
libs: Record<string, string>
): typeof TypeScriptWorker;
} }
export function create(ctx: IWorkerContext, createData: ICreateData): TypeScriptWorker { declare global {
let TSWorkerClass = TypeScriptWorker var importScripts: (path: string) => void | undefined;
if (createData.customWorkerPath) { var customTSWorkerFactory: CustomTSWebWorkerFactory | undefined;
// @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 export function create(
const workerFactoryFunc: CustomTSWebWorkerFactory | undefined = self.customTSWorkerFactory 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) { if (!workerFactoryFunc) {
throw new Error(`The script at ${createData.customWorkerPath} does not add customTSWorkerFactory to self`) throw new Error(
`The script at ${createData.customWorkerPath} does not add customTSWorkerFactory to self`
);
} }
TSWorkerClass = workerFactoryFunc(TypeScriptWorker, ts, libFileMap) TSWorkerClass = workerFactoryFunc(TypeScriptWorker, ts, libFileMap);
} }
} }

View file

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

View file

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

View file

@ -11,7 +11,6 @@ import IDisposable = monaco.IDisposable;
import Uri = monaco.Uri; import Uri = monaco.Uri;
export class WorkerManager { export class WorkerManager {
private _modeId: string; private _modeId: string;
private _defaults: LanguageServiceDefaultsImpl; private _defaults: LanguageServiceDefaultsImpl;
private _configChangeListener: IDisposable; private _configChangeListener: IDisposable;
@ -26,9 +25,13 @@ export class WorkerManager {
this._defaults = defaults; this._defaults = defaults;
this._worker = null; this._worker = null;
this._client = null; this._client = null;
this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker()); this._configChangeListener = this._defaults.onDidChange(() =>
this._stopWorker()
);
this._updateExtraLibsToken = 0; this._updateExtraLibsToken = 0;
this._extraLibsChangeListener = this._defaults.onDidExtraLibsChange(() => this._updateExtraLibs()); this._extraLibsChangeListener = this._defaults.onDidExtraLibsChange(() =>
this._updateExtraLibs()
);
} }
private _stopWorker(): void { private _stopWorker(): void {
@ -61,7 +64,6 @@ export class WorkerManager {
private _getClient(): Promise<TypeScriptWorker> { private _getClient(): Promise<TypeScriptWorker> {
if (!this._client) { if (!this._client) {
this._worker = monaco.editor.createWebWorker<TypeScriptWorker>({ this._worker = monaco.editor.createWebWorker<TypeScriptWorker>({
// module that exports the create() method and returns a `TypeScriptWorker` instance // module that exports the create() method and returns a `TypeScriptWorker` instance
moduleId: 'vs/language/typescript/tsWorker', moduleId: 'vs/language/typescript/tsWorker',
@ -80,11 +82,13 @@ export class WorkerManager {
let p = <Promise<TypeScriptWorker>>this._worker.getProxy(); let p = <Promise<TypeScriptWorker>>this._worker.getProxy();
if (this._defaults.getEagerModelSync()) { if (this._defaults.getEagerModelSync()) {
p = p.then(worker => { p = p.then((worker) => {
if (this._worker) { if (this._worker) {
return this._worker.withSyncedResources(monaco.editor.getModels() return this._worker.withSyncedResources(
.filter(model => model.getModeId() === this._modeId) monaco.editor
.map(model => model.uri) .getModels()
.filter((model) => model.getModeId() === this._modeId)
.map((model) => model.uri)
); );
} }
return worker; return worker;
@ -99,12 +103,15 @@ export class WorkerManager {
getLanguageServiceWorker(...resources: Uri[]): Promise<TypeScriptWorker> { getLanguageServiceWorker(...resources: Uri[]): Promise<TypeScriptWorker> {
let _client: TypeScriptWorker; let _client: TypeScriptWorker;
return this._getClient().then((client) => { return this._getClient()
_client = client .then((client) => {
}).then(_ => { _client = client;
if (this._worker) { })
return this._worker.withSyncedResources(resources) .then((_) => {
} if (this._worker) {
}).then(_ => _client); return this._worker.withSyncedResources(resources);
}
})
.then((_) => _client);
} }
} }

View file

@ -8,215 +8,230 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <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"> <link
</head> rel="stylesheet"
<body> 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> <script>
<button id="resetBtn">Reset Sample</button> var paths = {
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div> 'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
<h3>Custom webworker</h3> 'vs/language/typescript': '../release/dev',
<button id="logDTS">Log DTS</button> vs: '../node_modules/monaco-editor-core/dev/vs'
<button id="getAST">Print AST to console</button> };
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> <script>
var paths = { function getDefaultCode() {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev', return [
'vs/language/typescript': '../release/dev', '/* Game of Life',
'vs': '../node_modules/monaco-editor-core/dev/vs' ' * Implemented in TypeScript',
}; ' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
if (document.location.protocol === 'http:') { ' */',
// Add support for running local http server '',
let testIndex = document.location.pathname.indexOf('/test/'); 'module Conway {',
if (testIndex !== -1) { '',
let prefix = document.location.pathname.substr(0, testIndex); ' export class Cell {',
paths['vs/language/typescript'] = prefix + '/release/dev'; ' public row: number;',
} ' public col: number;',
} ' public live: boolean;',
var require = { '',
paths: paths ' constructor(row: number, col: number, live: boolean) {',
}; ' this.row = row;',
</script> ' this.col = col;',
<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script> ' this.live = live',
<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> ' }',
'',
' 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 getDefaultComplierOpts() {
function getDefaultCode() { return { target: 99, jsx: 1, allowNonTsExtensions: true };
return [ }
'/* Game of Life', require([
' * Implemented in TypeScript', 'vs/basic-languages/monaco.contribution',
' * To learn more about TypeScript, please visit http://www.typescriptlang.org/', 'vs/language/typescript/monaco.contribution'
' */', ], () => {
'', monaco.languages.typescript.typescriptDefaults.setWorkerOptions({
'module Conway {', customWorkerPath: 'http://localhost:5000/test/custom-worker.js'
'', });
' export class Cell {', monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
' public row: number;', target: 99,
' public col: number;', jsx: 1,
' public live: boolean;', allowNonTsExtensions: true,
'', declaration: true,
' constructor(row: number, col: number, live: boolean) {', noLibCheck: true
' 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() { var editor = monaco.editor.create(
return { target: 99, jsx: 1, allowNonTsExtensions: true } document.getElementById('container'),
} {
require([ value: localStorage.getItem('code') || getDefaultCode(),
'vs/basic-languages/monaco.contribution', language: 'typescript',
'vs/language/typescript/monaco.contribution' lightbulb: { enabled: true }
], () => { }
);
monaco.languages.typescript.typescriptDefaults.setWorkerOptions({ customWorkerPath: "http://localhost:5000/test/custom-worker.js" }) editor.onDidChangeModelContent(() => {
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ target: 99, jsx: 1, allowNonTsExtensions: true, declaration: true, noLibCheck: true }) const code = editor.getModel().getValue();
localStorage.setItem('code', code);
});
var editor = monaco.editor.create(document.getElementById('container'), { document.getElementById('resetBtn').onclick = () => {
value: localStorage.getItem("code") || getDefaultCode(), editor.setValue(getDefaultCode());
language: 'typescript', };
lightbulb: { enabled: true }
});
editor.onDidChangeModelContent(() => { document.getElementById('logDTS').onclick = async () => {
const code = editor.getModel().getValue() const model = editor.getModel();
localStorage.setItem("code", code) 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 = () => { document.getElementById('getAST').onclick = async () => {
editor.setValue(getDefaultCode()); const model = editor.getModel();
}; const worker = await monaco.languages.typescript.getTypeScriptWorker();
const thisWorker = await worker(model.uri);
document.getElementById('logDTS').onclick = async () => { const ast = await thisWorker.printAST(model.uri.toString());
const model = editor.getModel() console.log(ast);
const worker = await monaco.languages.typescript.getTypeScriptWorker() };
const thisWorker = await worker(model.uri) });
const dts = await thisWorker.getDTSEmitForFile(model.uri.toString()) </script>
console.log(dts) </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> </html>

View file

@ -2,59 +2,58 @@
// which can do work on a bg thread. // 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') // 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") } */ /** @type { import("@typescript/vfs") } */
const tsvfs = globalThis.tsvfs const tsvfs = globalThis.tsvfs;
/** @type {import("../src/tsWorker").CustomTSWebWorkerFactory }*/ /** @type {import("../src/tsWorker").CustomTSWebWorkerFactory }*/
const worker = (TypeScriptWorker, ts, libFileMap) => { const worker = (TypeScriptWorker, ts, libFileMap) => {
return class MonacoTSWorker extends TypeScriptWorker { 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) || '';
}
// Adds a custom function to the webworker async printAST(fileName) {
async getDTSEmitForFile(fileName) { console.log('Creating virtual TS project');
const result = await this.getEmitOutput(fileName) const compilerOptions = this.getCompilationSettings();
const firstDTS = result.outputFiles.find(o => o.name.endsWith(".d.ts")) const fsMap = new Map();
return (firstDTS && firstDTS.text) || "" for (const key of Object.keys(libFileMap)) {
} fsMap.set(key, '/' + libFileMap[key]);
}
async printAST(fileName) { const thisCode = await this.getScriptText(fileName);
console.log("Creating virtual TS project") fsMap.set('index.ts', thisCode);
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) console.log('Starting up TS program');
fsMap.set("index.ts", thisCode) const system = tsvfs.createSystem(fsMap);
const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts);
console.log("Starting up TS program") const program = ts.createProgram({
const system = tsvfs.createSystem(fsMap) rootNames: [...fsMap.keys()],
const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts) options: compilerOptions,
host: host.compilerHost
});
const program = ts.createProgram({ // Now I can look at the AST for the .ts file too
rootNames: [...fsMap.keys()], const mainSrcFile = program.getSourceFile('index.ts');
options: compilerOptions, let miniAST = 'SourceFile';
host: host.compilerHost,
})
// Now I can look at the AST for the .ts file too const recurse = (parent, depth) => {
const mainSrcFile = program.getSourceFile("index.ts") if (depth > 5) return;
let miniAST = "SourceFile" 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;
}
};
};
const recurse = (parent, depth) => { self.customTSWorkerFactory = worker;
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

View file

@ -1,205 +1,224 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <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"> <link
</head> rel="stylesheet"
<body> 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>
<h2>Monaco Editor TypeScript test page</h2> <script>
<button id="resetBtn">Reset Sample</button> var paths = {
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div> 'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
<h3>Compiler settings</h3> 'vs/language/typescript': '../release/dev',
<textarea style="font-family: monospace;" id="compilerOpts" cols="60" rows="30"></textarea><br/> vs: '../node_modules/monaco-editor-core/dev/vs'
<button id="updateCompilerSettingsBtn">Update compiler settings</button> };
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> <script>
var paths = { function getDefaultCode() {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev', return [
'vs/language/typescript': '../release/dev', '/* Game of Life',
'vs': '../node_modules/monaco-editor-core/dev/vs' ' * Implemented in TypeScript',
}; ' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
if (document.location.protocol === 'http:') { ' */',
// Add support for running local http server '',
let testIndex = document.location.pathname.indexOf('/test/'); 'module Conway {',
if (testIndex !== -1) { '',
let prefix = document.location.pathname.substr(0, testIndex); ' export class Cell {',
paths['vs/language/typescript'] = prefix + '/release/dev'; ' public row: number;',
} ' public col: number;',
} ' public live: boolean;',
var require = { '',
paths: paths ' constructor(row: number, col: number, live: boolean) {',
}; ' this.row = row;',
</script> ' this.col = col;',
<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script> ' this.live = live',
<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> ' }',
'',
' 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 getDefaultComplierOpts() {
function getDefaultCode() { return { target: 99, jsx: 1, allowNonTsExtensions: true };
return [ }
'/* Game of Life', require([
' * Implemented in TypeScript', 'vs/basic-languages/monaco.contribution',
' * To learn more about TypeScript, please visit http://www.typescriptlang.org/', 'vs/language/typescript/monaco.contribution'
' */', ], () => {
'', var editor = monaco.editor.create(
'module Conway {', document.getElementById('container'),
'', {
' export class Cell {', value: localStorage.getItem('code') || getDefaultCode(),
' public row: number;', language: 'typescript',
' public col: number;', lightbulb: { enabled: true }
' 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() { editor.onDidChangeModelContent(() => {
return { target: 99, jsx: 1, allowNonTsExtensions: true } const code = editor.getModel().getValue();
} localStorage.setItem('code', code);
require([ });
'vs/basic-languages/monaco.contribution',
'vs/language/typescript/monaco.contribution'
], () => {
var editor = monaco.editor.create(document.getElementById('container'), { document.getElementById('resetBtn').onclick = () => {
value: localStorage.getItem("code") || getDefaultCode(), editor.setValue(getDefaultCode());
language: 'typescript', };
lightbulb: { enabled: true }
});
editor.onDidChangeModelContent(() => { const optsString =
const code = editor.getModel().getValue() localStorage.getItem('compiler-opts') ||
localStorage.setItem("code", code) JSON.stringify(getDefaultComplierOpts(), null, 4);
}); document.getElementById('compilerOpts').textContent = optsString;
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
JSON.parse(optsString)
);
document.getElementById('resetBtn').onclick = () => { document.getElementById('updateCompilerSettingsBtn').onclick = () => {
editor.setValue(getDefaultCode()); const newOpts = document.getElementById('compilerOpts').value;
}; monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
JSON.parse(newOpts)
const optsString = localStorage.getItem("compiler-opts") || JSON.stringify(getDefaultComplierOpts(), null, 4) );
document.getElementById("compilerOpts").textContent = optsString localStorage.setItem('compiler-opts', newOpts);
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(JSON.parse(optsString)) };
});
document.getElementById('updateCompilerSettingsBtn').onclick = () => { </script>
const newOpts = document.getElementById('compilerOpts').value </body>
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(JSON.parse(newOpts))
localStorage.setItem("compiler-opts", newOpts)
};
});
</script>
</body>
</html> </html>