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]
jobs:
build:
name: "Builds and Compiles"
name: 'Builds and Compiles'
runs-on: ubuntu-latest
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)
*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
@ -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.
## Development
* `git clone https://github.com/Microsoft/monaco-typescript`
* `cd monaco-typescript`
* `npm install .`
* `npm run compile`
* `npm run watch`
* open `$/monaco-typescript/test/index.html` in your favorite browser.
- `git clone https://github.com/Microsoft/monaco-typescript`
- `cd monaco-typescript`
- `npm install .`
- `npm run compile`
- `npm run watch`
- open `$/monaco-typescript/test/index.html` in your favorite browser.
## Updating TypeScript
* change typescript's version in `package.json`.
* execute `npm install .`
* execute `npm run import-typescript`
* adopt new APIs
- change typescript's version in `package.json`.
- execute `npm install .`
- execute `npm run import-typescript`
- adopt new APIs
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## License
[MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md)

View file

@ -31,5 +31,10 @@
"requirejs": "^2.3.6",
"terser": "^5.3.0",
"typescript": "^4.0.2"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
}
}

View file

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

View file

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

View file

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

99
src/monaco.d.ts vendored
View file

@ -1,6 +1,4 @@
declare module monaco.languages.typescript {
enum ModuleKind {
None = 0,
CommonJS = 1,
@ -33,7 +31,7 @@ declare module monaco.languages.typescript {
ES2020 = 7,
ESNext = 99,
JSON = 100,
Latest = ESNext,
Latest = ESNext
}
export enum ModuleResolutionKind {
@ -45,7 +43,15 @@ declare module monaco.languages.typescript {
[index: string]: T;
}
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | null | undefined;
type CompilerOptionsValue =
| string
| number
| boolean
| (string | number)[]
| string[]
| MapLike<string[]>
| null
| undefined;
interface CompilerOptions {
allowJs?: boolean;
allowSyntheticDefaultImports?: boolean;
@ -295,43 +301,65 @@ declare module monaco.languages.typescript {
* Get code completions for the given file and position.
* @returns `Promise<typescript.CompletionInfo | undefined>`
*/
getCompletionsAtPosition(fileName: string, position: number): Promise<any | undefined>;
getCompletionsAtPosition(
fileName: string,
position: number
): Promise<any | undefined>;
/**
* Get code completion details for the given file, position, and entry.
* @returns `Promise<typescript.CompletionEntryDetails | undefined>`
*/
getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<any | undefined>;
getCompletionEntryDetails(
fileName: string,
position: number,
entry: string
): Promise<any | undefined>;
/**
* Get signature help items for the item at the given file and position.
* @returns `Promise<typescript.SignatureHelpItems | undefined>`
*/
getSignatureHelpItems(fileName: string, position: number): Promise<any | undefined>;
getSignatureHelpItems(
fileName: string,
position: number
): Promise<any | undefined>;
/**
* Get quick info for the item at the given position in the file.
* @returns `Promise<typescript.QuickInfo | undefined>`
*/
getQuickInfoAtPosition(fileName: string, position: number): Promise<any | undefined>;
getQuickInfoAtPosition(
fileName: string,
position: number
): Promise<any | undefined>;
/**
* Get other ranges which are related to the item at the given position in the file (often used for highlighting).
* @returns `Promise<ReadonlyArray<typescript.ReferenceEntry> | undefined>`
*/
getOccurrencesAtPosition(fileName: string, position: number): Promise<ReadonlyArray<any> | undefined>;
getOccurrencesAtPosition(
fileName: string,
position: number
): Promise<ReadonlyArray<any> | undefined>;
/**
* Get the definition of the item at the given position in the file.
* @returns `Promise<ReadonlyArray<typescript.DefinitionInfo> | undefined>`
*/
getDefinitionAtPosition(fileName: string, position: number): Promise<ReadonlyArray<any> | undefined>;
getDefinitionAtPosition(
fileName: string,
position: number
): Promise<ReadonlyArray<any> | undefined>;
/**
* Get references to the item at the given position in the file.
* @returns `Promise<typescript.ReferenceEntry[] | undefined>`
*/
getReferencesAtPosition(fileName: string, position: number): Promise<any[] | undefined>;
getReferencesAtPosition(
fileName: string,
position: number
): Promise<any[] | undefined>;
/**
* Get outline entries for the item at the given position in the file.
@ -344,34 +372,57 @@ declare module monaco.languages.typescript {
* @param options `typescript.FormatCodeOptions`
* @returns `Promise<typescript.TextChange[]>`
*/
getFormattingEditsForDocument(fileName: string, options: any): Promise<any[]>;
getFormattingEditsForDocument(
fileName: string,
options: any
): Promise<any[]>;
/**
* Get changes which should be applied to format the given range in the file.
* @param options `typescript.FormatCodeOptions`
* @returns `Promise<typescript.TextChange[]>`
*/
getFormattingEditsForRange(fileName: string, start: number, end: number, options: any): Promise<any[]>;
getFormattingEditsForRange(
fileName: string,
start: number,
end: number,
options: any
): Promise<any[]>;
/**
* Get formatting changes which should be applied after the given keystroke.
* @param options `typescript.FormatCodeOptions`
* @returns `Promise<typescript.TextChange[]>`
*/
getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: any): Promise<any[]>;
getFormattingEditsAfterKeystroke(
fileName: string,
postion: number,
ch: string,
options: any
): Promise<any[]>;
/**
* Get other occurrences which should be updated when renaming the item at the given file and position.
* @returns `Promise<readonly typescript.RenameLocation[] | undefined>`
*/
findRenameLocations(fileName: string, positon: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise<readonly any[] | undefined>;
findRenameLocations(
fileName: string,
positon: number,
findInStrings: boolean,
findInComments: boolean,
providePrefixAndSuffixTextForRename: boolean
): Promise<readonly any[] | undefined>;
/**
* Get edits which should be applied to rename the item at the given file and position (or a failure reason).
* @param options `typescript.RenameInfoOptions`
* @returns `Promise<typescript.RenameInfo>`
*/
getRenameInfo(fileName: string, positon: number, options: any): Promise<any>;
getRenameInfo(
fileName: string,
positon: number,
options: any
): Promise<any>;
/**
* Get transpiled output for the given file.
@ -384,7 +435,13 @@ declare module monaco.languages.typescript {
* @param formatOptions `typescript.FormatCodeOptions`
* @returns `Promise<ReadonlyArray<typescript.CodeFixAction>>`
*/
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: any): Promise<ReadonlyArray<any>>;
getCodeFixesAtPosition(
fileName: string,
start: number,
end: number,
errorCodes: number[],
formatOptions: any
): Promise<ReadonlyArray<any>>;
}
export const typescriptVersion: string;
@ -392,6 +449,10 @@ declare module monaco.languages.typescript {
export const typescriptDefaults: LanguageServiceDefaults;
export const javascriptDefaults: LanguageServiceDefaults;
export const getTypeScriptWorker: () => Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>>;
export const getJavaScriptWorker: () => Promise<(...uris: Uri[]) => Promise<TypeScriptWorker>>;
export const getTypeScriptWorker: () => Promise<
(...uris: Uri[]) => Promise<TypeScriptWorker>
>;
export const getJavaScriptWorker: () => Promise<
(...uris: Uri[]) => Promise<TypeScriptWorker>
>;
}

View file

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

View file

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

View file

@ -10,9 +10,10 @@ import { IExtraLibs } from './monaco.contribution';
import IWorkerContext = monaco.worker.IWorkerContext;
export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.languages.typescript.TypeScriptWorker {
export class TypeScriptWorker
implements
ts.LanguageServiceHost,
monaco.languages.typescript.TypeScriptWorker {
// --- model sync -----------------------
private _ctx: IWorkerContext;
@ -33,7 +34,9 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
}
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));
}
@ -72,7 +75,6 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
text = model.getValue();
} else if (fileName in libFileMap) {
text = libFileMap[fileName];
} else if (fileName in this._extraLibs) {
// extra lib
text = this._extraLibs[fileName].content;
@ -99,11 +101,16 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
getScriptKind?(fileName: string): ts.ScriptKind {
const suffix = fileName.substr(fileName.lastIndexOf('.') + 1);
switch (suffix) {
case 'ts': return ts.ScriptKind.TS;
case 'tsx': return ts.ScriptKind.TSX;
case 'js': return ts.ScriptKind.JS;
case 'jsx': return ts.ScriptKind.JSX;
default: return this.getCompilationSettings().allowJs
case 'ts':
return ts.ScriptKind.TS;
case 'tsx':
return ts.ScriptKind.TSX;
case 'js':
return ts.ScriptKind.JS;
case 'jsx':
return ts.ScriptKind.JSX;
default:
return this.getCompilationSettings().allowJs
? ts.ScriptKind.JS
: ts.ScriptKind.TS;
}
@ -116,8 +123,8 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
getDefaultLibFileName(options: ts.CompilerOptions): string {
switch (options.target) {
case 99 /* ESNext */:
const esnext = "lib.esnext.full.d.ts";
if (esnext in libFileMap || esnext in this._extraLibs) return esnext
const esnext = 'lib.esnext.full.d.ts';
if (esnext in libFileMap || esnext in this._extraLibs) return esnext;
case 7 /* ES2020 */:
case 6 /* ES2019 */:
case 5 /* ES2018 */:
@ -135,10 +142,10 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
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 0:
return "lib.d.ts";
return 'lib.d.ts';
}
}
@ -152,98 +159,223 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
// --- 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
// contains cyclic data structures.
diagnostics.forEach(diag => {
diagnostics.forEach((diag) => {
diag.file = undefined;
const related = <ts.Diagnostic[]>diag.relatedInformation;
if (related) {
related.forEach(diag2 => diag2.file = undefined);
related.forEach((diag2) => (diag2.file = undefined));
}
});
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);
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);
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
}
getSuggestionDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getSuggestionDiagnostics(fileName);
getSuggestionDiagnostics(
fileName: string
): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getSuggestionDiagnostics(
fileName
);
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
}
getCompilerOptionsDiagnostics(fileName: string): Promise<monaco.languages.typescript.Diagnostic[]> {
getCompilerOptionsDiagnostics(
fileName: string
): Promise<monaco.languages.typescript.Diagnostic[]> {
const diagnostics = this._languageService.getCompilerOptionsDiagnostics();
return Promise.resolve(TypeScriptWorker.clearFiles(diagnostics));
}
getCompletionsAtPosition(fileName: string, position: number): Promise<ts.CompletionInfo | undefined> {
return Promise.resolve(this._languageService.getCompletionsAtPosition(fileName, position, undefined));
getCompletionsAtPosition(
fileName: string,
position: number
): Promise<ts.CompletionInfo | undefined> {
return Promise.resolve(
this._languageService.getCompletionsAtPosition(
fileName,
position,
undefined
)
);
}
getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<ts.CompletionEntryDetails | undefined> {
return Promise.resolve(this._languageService.getCompletionEntryDetails(fileName, position, entry, undefined, undefined, undefined));
getCompletionEntryDetails(
fileName: string,
position: number,
entry: string
): Promise<ts.CompletionEntryDetails | undefined> {
return Promise.resolve(
this._languageService.getCompletionEntryDetails(
fileName,
position,
entry,
undefined,
undefined,
undefined
)
);
}
getSignatureHelpItems(fileName: string, position: number): Promise<ts.SignatureHelpItems | undefined> {
return Promise.resolve(this._languageService.getSignatureHelpItems(fileName, position, undefined));
getSignatureHelpItems(
fileName: string,
position: number
): Promise<ts.SignatureHelpItems | undefined> {
return Promise.resolve(
this._languageService.getSignatureHelpItems(fileName, position, undefined)
);
}
getQuickInfoAtPosition(fileName: string, position: number): Promise<ts.QuickInfo | undefined> {
return Promise.resolve(this._languageService.getQuickInfoAtPosition(fileName, position));
getQuickInfoAtPosition(
fileName: string,
position: number
): Promise<ts.QuickInfo | undefined> {
return Promise.resolve(
this._languageService.getQuickInfoAtPosition(fileName, position)
);
}
getOccurrencesAtPosition(fileName: string, position: number): Promise<ReadonlyArray<ts.ReferenceEntry> | undefined> {
return Promise.resolve(this._languageService.getOccurrencesAtPosition(fileName, position));
getOccurrencesAtPosition(
fileName: string,
position: number
): Promise<ReadonlyArray<ts.ReferenceEntry> | undefined> {
return Promise.resolve(
this._languageService.getOccurrencesAtPosition(fileName, position)
);
}
getDefinitionAtPosition(fileName: string, position: number): Promise<ReadonlyArray<ts.DefinitionInfo> | undefined> {
return Promise.resolve(this._languageService.getDefinitionAtPosition(fileName, position));
getDefinitionAtPosition(
fileName: string,
position: number
): Promise<ReadonlyArray<ts.DefinitionInfo> | undefined> {
return Promise.resolve(
this._languageService.getDefinitionAtPosition(fileName, position)
);
}
getReferencesAtPosition(fileName: string, position: number): Promise<ts.ReferenceEntry[] | undefined> {
return Promise.resolve(this._languageService.getReferencesAtPosition(fileName, position));
getReferencesAtPosition(
fileName: string,
position: number
): Promise<ts.ReferenceEntry[] | undefined> {
return Promise.resolve(
this._languageService.getReferencesAtPosition(fileName, position)
);
}
getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> {
return Promise.resolve(this._languageService.getNavigationBarItems(fileName));
return Promise.resolve(
this._languageService.getNavigationBarItems(fileName)
);
}
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
return Promise.resolve(this._languageService.getFormattingEditsForDocument(fileName, options));
getFormattingEditsForDocument(
fileName: string,
options: ts.FormatCodeOptions
): Promise<ts.TextChange[]> {
return Promise.resolve(
this._languageService.getFormattingEditsForDocument(fileName, options)
);
}
getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
return Promise.resolve(this._languageService.getFormattingEditsForRange(fileName, start, end, options));
getFormattingEditsForRange(
fileName: string,
start: number,
end: number,
options: ts.FormatCodeOptions
): Promise<ts.TextChange[]> {
return Promise.resolve(
this._languageService.getFormattingEditsForRange(
fileName,
start,
end,
options
)
);
}
getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
return Promise.resolve(this._languageService.getFormattingEditsAfterKeystroke(fileName, postion, ch, options));
getFormattingEditsAfterKeystroke(
fileName: string,
postion: number,
ch: string,
options: ts.FormatCodeOptions
): Promise<ts.TextChange[]> {
return Promise.resolve(
this._languageService.getFormattingEditsAfterKeystroke(
fileName,
postion,
ch,
options
)
);
}
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise<readonly ts.RenameLocation[] | undefined> {
return Promise.resolve(this._languageService.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename));
findRenameLocations(
fileName: string,
position: number,
findInStrings: boolean,
findInComments: boolean,
providePrefixAndSuffixTextForRename: boolean
): Promise<readonly ts.RenameLocation[] | undefined> {
return Promise.resolve(
this._languageService.findRenameLocations(
fileName,
position,
findInStrings,
findInComments,
providePrefixAndSuffixTextForRename
)
);
}
getRenameInfo(fileName: string, position: number, options: ts.RenameInfoOptions): Promise<ts.RenameInfo> {
return Promise.resolve(this._languageService.getRenameInfo(fileName, position, options));
getRenameInfo(
fileName: string,
position: number,
options: ts.RenameInfoOptions
): Promise<ts.RenameInfo> {
return Promise.resolve(
this._languageService.getRenameInfo(fileName, position, options)
);
}
getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
return Promise.resolve(this._languageService.getEmitOutput(fileName));
}
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: ts.FormatCodeOptions): Promise<ReadonlyArray<ts.CodeFixAction>> {
const preferences = {}
return Promise.resolve(this._languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences));
getCodeFixesAtPosition(
fileName: string,
start: number,
end: number,
errorCodes: number[],
formatOptions: ts.FormatCodeOptions
): Promise<ReadonlyArray<ts.CodeFixAction>> {
const preferences = {};
return Promise.resolve(
this._languageService.getCodeFixesAtPosition(
fileName,
start,
end,
errorCodes,
formatOptions,
preferences
)
);
}
updateExtraLibs(extraLibs: IExtraLibs) {
@ -254,31 +386,45 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
export interface ICreateData {
compilerOptions: ts.CompilerOptions;
extraLibs: IExtraLibs;
customWorkerPath?: string
customWorkerPath?: string;
}
/** The shape of the factory */
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 {
let TSWorkerClass = TypeScriptWorker
if (createData.customWorkerPath) {
// @ts-ignore - This is available in a webworker
if (typeof importScripts === "undefined") {
console.warn("Monaco is not using webworkers for background tasks, and that is needed to support the customWorkerPath flag")
} else {
// @ts-ignore - This is available in a webworker
importScripts(createData.customWorkerPath)
declare global {
var importScripts: (path: string) => void | undefined;
var customTSWorkerFactory: CustomTSWebWorkerFactory | undefined;
}
// @ts-ignore - This should come from the above eval
const workerFactoryFunc: CustomTSWebWorkerFactory | undefined = self.customTSWorkerFactory
export function create(
ctx: IWorkerContext,
createData: ICreateData
): TypeScriptWorker {
let TSWorkerClass = TypeScriptWorker;
if (createData.customWorkerPath) {
if (typeof importScripts === 'undefined') {
console.warn(
'Monaco is not using webworkers for background tasks, and that is needed to support the customWorkerPath flag'
);
} else {
importScripts(createData.customWorkerPath);
const workerFactoryFunc: CustomTSWebWorkerFactory | undefined =
self.customTSWorkerFactory;
if (!workerFactoryFunc) {
throw new Error(`The script at ${createData.customWorkerPath} does not add customTSWorkerFactory to self`)
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

@ -13,10 +13,6 @@
],
"strict": true
},
"include": [
"**/*.ts"
],
"files": [
"../node_modules/monaco-editor-core/monaco.d.ts"
]
"include": ["**/*.ts"],
"files": ["../node_modules/monaco-editor-core/monaco.d.ts"]
}

View file

@ -13,10 +13,6 @@
],
"strict": true
},
"include": [
"**/*.ts"
],
"files": [
"../node_modules/monaco-editor-core/monaco.d.ts"
]
"include": ["**/*.ts"],
"files": ["../node_modules/monaco-editor-core/monaco.d.ts"]
}

View file

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

View file

@ -8,25 +8,31 @@
<!DOCTYPE html>
<html>
<head>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" data-name="vs/editor/editor.main" href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
</head>
<body>
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
/>
</head>
<body>
<h2>Monaco Editor TypeScript test page</h2>
<button id="resetBtn">Reset Sample</button>
<div
id="container"
style="width: 800px; height: 600px; border: 1px solid grey"
></div>
<h3>Custom webworker</h3>
<button id="logDTS">Log DTS</button>
<button id="getAST">Print AST to console</button>
<h2>Monaco Editor TypeScript test page</h2>
<button id="resetBtn">Reset Sample</button>
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
<h3>Custom webworker</h3>
<button id="logDTS">Log DTS</button>
<button id="getAST">Print AST to console</button>
<script>
<script>
var paths = {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
'vs/language/typescript': '../release/dev',
'vs': '../node_modules/monaco-editor-core/dev/vs'
vs: '../node_modules/monaco-editor-core/dev/vs'
};
if (document.location.protocol === 'http:') {
// Add support for running local http server
@ -39,12 +45,12 @@
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 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>
function getDefaultCode() {
return [
'/* Game of Life',
@ -82,9 +88,9 @@
' constructor() {',
' this.gridSize = 50;',
' this.canvasSize = 600;',
' this.lineColor = \'#cdcdcd\';',
' this.liveColor = \'#666\';',
' this.deadColor = \'#eee\';',
" this.lineColor = '#cdcdcd';",
" this.liveColor = '#666';",
" this.deadColor = '#eee';",
' this.initialLifeProbability = 0.5;',
' this.animationRate = 60;',
' this.cellSize = 0;',
@ -157,43 +163,53 @@
' }',
'',
' public createDrawingContext() {',
' var canvas = <HTMLCanvasElement> document.getElementById(\'conway-canvas\');',
" var canvas = <HTMLCanvasElement> document.getElementById('conway-canvas');",
' if(canvas == null) {',
' canvas = document.createElement(\'canvas\');',
' canvas.id = \'conway-canvas\';',
" canvas = document.createElement('canvas');",
" canvas.id = 'conway-canvas';",
' canvas.width = this.canvasSize;',
' canvas.height = this.canvasSize;',
' document.body.appendChild(canvas);',
' }',
' return canvas.getContext(\'2d\');',
" return canvas.getContext('2d');",
' }',
' }',
'}',
'',
'var game = new Conway.GameOfLife();',
'var game = new Conway.GameOfLife();'
].join('\n');
}
function getDefaultComplierOpts() {
return { target: 99, jsx: 1, allowNonTsExtensions: true }
return { target: 99, jsx: 1, allowNonTsExtensions: true };
}
require([
'vs/basic-languages/monaco.contribution',
'vs/language/typescript/monaco.contribution'
], () => {
monaco.languages.typescript.typescriptDefaults.setWorkerOptions({ customWorkerPath: "http://localhost:5000/test/custom-worker.js" })
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ target: 99, jsx: 1, allowNonTsExtensions: true, declaration: true, noLibCheck: true })
var editor = monaco.editor.create(document.getElementById('container'), {
value: localStorage.getItem("code") || getDefaultCode(),
language: 'typescript',
lightbulb: { enabled: true }
monaco.languages.typescript.typescriptDefaults.setWorkerOptions({
customWorkerPath: 'http://localhost:5000/test/custom-worker.js'
});
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: 99,
jsx: 1,
allowNonTsExtensions: true,
declaration: true,
noLibCheck: true
});
var editor = monaco.editor.create(
document.getElementById('container'),
{
value: localStorage.getItem('code') || getDefaultCode(),
language: 'typescript',
lightbulb: { enabled: true }
}
);
editor.onDidChangeModelContent(() => {
const code = editor.getModel().getValue()
localStorage.setItem("code", code)
const code = editor.getModel().getValue();
localStorage.setItem('code', code);
});
document.getElementById('resetBtn').onclick = () => {
@ -201,22 +217,21 @@
};
document.getElementById('logDTS').onclick = async () => {
const model = editor.getModel()
const worker = await monaco.languages.typescript.getTypeScriptWorker()
const thisWorker = await worker(model.uri)
const dts = await thisWorker.getDTSEmitForFile(model.uri.toString())
console.log(dts)
const model = editor.getModel();
const worker = await monaco.languages.typescript.getTypeScriptWorker();
const thisWorker = await worker(model.uri);
const dts = await thisWorker.getDTSEmitForFile(model.uri.toString());
console.log(dts);
};
document.getElementById('getAST').onclick = async () => {
const model = editor.getModel()
const worker = await monaco.languages.typescript.getTypeScriptWorker()
const thisWorker = await worker(model.uri)
const ast = await thisWorker.printAST(model.uri.toString())
console.log(ast)
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>
});
</script>
</body>
</html>

View file

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

View file

@ -1,24 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" data-name="vs/editor/editor.main" href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
</head>
<body>
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
/>
</head>
<body>
<h2>Monaco Editor TypeScript test page</h2>
<button id="resetBtn">Reset Sample</button>
<div
id="container"
style="width: 800px; height: 600px; border: 1px solid grey"
></div>
<h3>Compiler settings</h3>
<textarea
style="font-family: monospace"
id="compilerOpts"
cols="60"
rows="30"
></textarea
><br />
<button id="updateCompilerSettingsBtn">Update compiler settings</button>
<h2>Monaco Editor TypeScript test page</h2>
<button id="resetBtn">Reset Sample</button>
<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
<h3>Compiler settings</h3>
<textarea style="font-family: monospace;" id="compilerOpts" cols="60" rows="30"></textarea><br/>
<button id="updateCompilerSettingsBtn">Update compiler settings</button>
<script>
<script>
var paths = {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
'vs/language/typescript': '../release/dev',
'vs': '../node_modules/monaco-editor-core/dev/vs'
vs: '../node_modules/monaco-editor-core/dev/vs'
};
if (document.location.protocol === 'http:') {
// Add support for running local http server
@ -31,12 +43,12 @@
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 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>
function getDefaultCode() {
return [
'/* Game of Life',
@ -74,9 +86,9 @@
' constructor() {',
' this.gridSize = 50;',
' this.canvasSize = 600;',
' this.lineColor = \'#cdcdcd\';',
' this.liveColor = \'#666\';',
' this.deadColor = \'#eee\';',
" this.lineColor = '#cdcdcd';",
" this.liveColor = '#666';",
" this.deadColor = '#eee';",
' this.initialLifeProbability = 0.5;',
' this.animationRate = 60;',
' this.cellSize = 0;',
@ -149,57 +161,64 @@
' }',
'',
' public createDrawingContext() {',
' var canvas = <HTMLCanvasElement> document.getElementById(\'conway-canvas\');',
" var canvas = <HTMLCanvasElement> document.getElementById('conway-canvas');",
' if(canvas == null) {',
' canvas = document.createElement(\'canvas\');',
' canvas.id = \'conway-canvas\';',
" canvas = document.createElement('canvas');",
" canvas.id = 'conway-canvas';",
' canvas.width = this.canvasSize;',
' canvas.height = this.canvasSize;',
' document.body.appendChild(canvas);',
' }',
' return canvas.getContext(\'2d\');',
" return canvas.getContext('2d');",
' }',
' }',
'}',
'',
'var game = new Conway.GameOfLife();',
'var game = new Conway.GameOfLife();'
].join('\n');
}
function getDefaultComplierOpts() {
return { target: 99, jsx: 1, allowNonTsExtensions: true }
return { target: 99, jsx: 1, allowNonTsExtensions: true };
}
require([
'vs/basic-languages/monaco.contribution',
'vs/language/typescript/monaco.contribution'
], () => {
var editor = monaco.editor.create(document.getElementById('container'), {
value: localStorage.getItem("code") || getDefaultCode(),
var editor = monaco.editor.create(
document.getElementById('container'),
{
value: localStorage.getItem('code') || getDefaultCode(),
language: 'typescript',
lightbulb: { enabled: true }
});
}
);
editor.onDidChangeModelContent(() => {
const code = editor.getModel().getValue()
localStorage.setItem("code", code)
const code = editor.getModel().getValue();
localStorage.setItem('code', code);
});
document.getElementById('resetBtn').onclick = () => {
editor.setValue(getDefaultCode());
};
const optsString = localStorage.getItem("compiler-opts") || JSON.stringify(getDefaultComplierOpts(), null, 4)
document.getElementById("compilerOpts").textContent = optsString
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(JSON.parse(optsString))
const optsString =
localStorage.getItem('compiler-opts') ||
JSON.stringify(getDefaultComplierOpts(), null, 4);
document.getElementById('compilerOpts').textContent = optsString;
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
JSON.parse(optsString)
);
document.getElementById('updateCompilerSettingsBtn').onclick = () => {
const newOpts = document.getElementById('compilerOpts').value
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(JSON.parse(newOpts))
localStorage.setItem("compiler-opts", newOpts)
const newOpts = document.getElementById('compilerOpts').value;
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
JSON.parse(newOpts)
);
localStorage.setItem('compiler-opts', newOpts);
};
});
</script>
</body>
</script>
</body>
</html>