Merge pull request #64 from microsoft/let_ts_resolve_libs

pull/2748/head
Alexandru Dima 5 years ago committed by GitHub
commit 6d0fbd443f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -105,110 +105,43 @@ export = ts;
})();
function importLibs() {
function getFileName(name) {
return (name === '' ? 'lib.d.ts' : `lib.${name}.d.ts`);
}
function getVariableName(name) {
return (name === '' ? 'lib_dts' : `lib_${name.replace(/\./g, '_')}_dts`);
}
function readLibFile(name) {
var srcPath = path.join(TYPESCRIPT_LIB_SOURCE, getFileName(name));
var srcPath = path.join(TYPESCRIPT_LIB_SOURCE, name);
return fs.readFileSync(srcPath).toString();
}
var queue = [];
var in_queue = {};
var enqueue = function (name) {
if (in_queue[name]) {
return;
}
in_queue[name] = true;
queue.push(name);
};
enqueue('');
enqueue('es2015');
var result = [];
while (queue.length > 0) {
var name = queue.shift();
var contents = readLibFile(name);
var lines = contents.split(/\r\n|\r|\n/);
var output = '';
var writeOutput = function (text) {
if (output.length === 0) {
output = text;
} else {
output += ` + ${text}`;
}
};
var outputLines = [];
var flushOutputLines = function () {
writeOutput(`"${escapeText(outputLines.join('\n'))}"`);
outputLines = [];
};
var deps = [];
for (let i = 0; i < lines.length; i++) {
let m = lines[i].match(/\/\/\/\s*<reference\s*lib="([^"]+)"/);
if (m) {
flushOutputLines();
writeOutput(getVariableName(m[1]));
deps.push(getVariableName(m[1]));
enqueue(m[1]);
continue;
}
outputLines.push(lines[i]);
}
flushOutputLines();
result.push({
name: getVariableName(name),
deps: deps,
output: output
});
}
var strResult = `/*---------------------------------------------------------------------------------------------
var strLibResult = `/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
${generatedNote}`;
// Do a topological sort
while (result.length > 0) {
for (let i = result.length - 1; i >= 0; i--) {
if (result[i].deps.length === 0) {
// emit this node
strResult += `\nexport const ${result[i].name}: string = ${result[i].output};\n`;
// mark dep as resolved
for (let j = 0; j < result.length; j++) {
for (let k = 0; k < result[j].deps.length; k++) {
if (result[j].deps[k] === result[i].name) {
result[j].deps.splice(k, 1);
break;
}
}
}
${generatedNote}
// remove from result
result.splice(i, 1);
break;
}
}
}
/** Contains all the lib files */
export const libFileMap: Record<string, string> = {}
`
;
strResult += `
/** This is the DTS which is used when the target is ES6 or below */
export const lib_es5_bundled_dts = lib_dts;
var strIndexResult = `/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
${generatedNote}
/** This is the DTS which is used by default in monaco-typescript, and when the target is 2015 or above */
export const lib_es2015_bundled_dts = lib_es2015_dts + "" + lib_dom_dts + "" + lib_webworker_importscripts_dts + "" + lib_scripthost_dts + "";
/** Contains all the lib files */
export const libFileSet: Record<string, boolean> = {}
`
;
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');
strLibResult += `libFileMap['${name}'] = "${escapeText(output)}";\n`;
strIndexResult += `libFileSet['${name}'] = true;\n`;
}
var dstPath = path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts');
fs.writeFileSync(dstPath, strResult);
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.ts'), strLibResult);
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'lib.index.ts'), strIndexResult);
}
/**

@ -7,6 +7,7 @@
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import * as ts from './lib/typescriptServices';
import { TypeScriptWorker } from './tsWorker';
import { libFileSet } from "./lib/lib.index"
import Uri = monaco.Uri;
import Position = monaco.Position;
@ -58,7 +59,7 @@ function displayPartsToString(displayParts: ts.SymbolDisplayPart[] | undefined):
export abstract class Adapter {
constructor(protected _worker: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>) {
constructor(protected _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>) {
}
// protected _positionToOffset(model: monaco.editor.ITextModel, position: monaco.IPosition): number {
@ -78,6 +79,75 @@ export abstract class Adapter {
}
}
// --- lib files
export class LibFiles {
private _libFiles: Record<string, string>;
private _hasFetchedLibFiles: boolean;
private _fetchLibFilesPromise: Promise<void> | null;
constructor(
private readonly _worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
) {
this._libFiles = {};
this._hasFetchedLibFiles = false;
this._fetchLibFilesPromise = null;
}
public isLibFile(uri: Uri | null): boolean {
if (!uri) {
return false;
}
if (uri.path.indexOf("/lib.") === 0) {
return !!libFileSet[uri.path.slice(1)];
}
return false;
}
public getOrCreateModel(uri: Uri): monaco.editor.ITextModel | null {
const model = monaco.editor.getModel(uri);
if (model) {
return model;
}
if (this.isLibFile(uri) && this._hasFetchedLibFiles) {
return monaco.editor.createModel(this._libFiles[uri.path.slice(1)], "javascript", uri);
}
return null;
}
private _containsLibFile(uris: (Uri | null)[]): boolean {
for (let uri of uris) {
if (this.isLibFile(uri)) {
return true;
}
}
return false;
}
public async fetchLibFilesIfNecessary(uris: (Uri | null)[]): Promise<void> {
if (!this._containsLibFile(uris)) {
// no lib files necessary
return;
}
await this._fetchLibFiles();
}
private _fetchLibFiles(): Promise<void> {
if (!this._fetchLibFilesPromise) {
this._fetchLibFilesPromise = (
this._worker()
.then(w => w.getLibFiles())
.then((libFiles) => {
this._hasFetchedLibFiles = true;
this._libFiles = libFiles;
})
);
}
return this._fetchLibFilesPromise;
}
}
// --- diagnostics --- ---
enum DiagnosticCategory {
@ -92,8 +162,11 @@ export class DiagnosticsAdapter extends Adapter {
private _disposables: IDisposable[] = [];
private _listener: { [uri: string]: IDisposable } = Object.create(null);
constructor(private _defaults: LanguageServiceDefaultsImpl, private _selector: string,
worker: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>
constructor(
private readonly _libFiles: LibFiles,
private _defaults: LanguageServiceDefaultsImpl,
private _selector: string,
worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
) {
super(worker);
@ -180,19 +253,31 @@ export class DiagnosticsAdapter extends Adapter {
promises.push(worker.getSuggestionDiagnostics(model.uri.toString()));
}
const diagnostics = await Promise.all(promises);
const allDiagnostics = await Promise.all(promises);
if (!diagnostics || model.isDisposed()) {
if (!allDiagnostics || model.isDisposed()) {
// model was disposed in the meantime
return;
}
const markers = diagnostics
const diagnostics = allDiagnostics
.reduce((p, c) => c.concat(p), [])
.filter(d => (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === -1)
.map(d => this._convertDiagnostics(model, d));
.filter(d => (this._defaults.getDiagnosticsOptions().diagnosticCodesToIgnore || []).indexOf(d.code) === -1);
monaco.editor.setModelMarkers(model, this._selector, markers);
// Fetch lib files if necessary
const relatedUris = diagnostics
.map(d => d.relatedInformation || [])
.reduce((p, c) => c.concat(p), [])
.map(relatedInformation => relatedInformation.file ? monaco.Uri.parse(relatedInformation.file.fileName) : null);
await this._libFiles.fetchLibFilesIfNecessary(relatedUris);
if (model.isDisposed()) {
// model was disposed in the meantime
return;
}
monaco.editor.setModelMarkers(model, this._selector, diagnostics.map(d => this._convertDiagnostics(model, d)));
}
private _convertDiagnostics(model: monaco.editor.ITextModel, diag: ts.Diagnostic): monaco.editor.IMarkerData {
@ -224,7 +309,7 @@ export class DiagnosticsAdapter extends Adapter {
let relatedResource: monaco.editor.ITextModel | null = model;
if (info.file) {
const relatedResourceUri = monaco.Uri.parse(info.file.fileName);
relatedResource = monaco.editor.getModel(relatedResourceUri);
relatedResource = this._libFiles.getOrCreateModel(relatedResourceUri);
}
if (!relatedResource) {
@ -479,6 +564,13 @@ export class OccurrencesAdapter extends Adapter implements monaco.languages.Docu
export class DefinitionAdapter extends Adapter {
constructor(
private readonly _libFiles: LibFiles,
worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
) {
super(worker);
}
public async provideDefinition(model: monaco.editor.ITextModel, position: Position, token: CancellationToken): Promise<monaco.languages.Definition | undefined> {
const resource = model.uri;
const offset = model.getOffsetAt(position);
@ -489,10 +581,17 @@ export class DefinitionAdapter extends Adapter {
return;
}
// Fetch lib files if necessary
await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName)));
if (model.isDisposed()) {
return;
}
const result: monaco.languages.Location[] = [];
for (let entry of entries) {
const uri = Uri.parse(entry.fileName);
const refModel = monaco.editor.getModel(uri);
const refModel = this._libFiles.getOrCreateModel(uri);
if (refModel) {
result.push({
uri: uri,
@ -508,6 +607,13 @@ export class DefinitionAdapter extends Adapter {
export class ReferenceAdapter extends Adapter implements monaco.languages.ReferenceProvider {
constructor(
private readonly _libFiles: LibFiles,
worker: (...uris: Uri[]) => Promise<TypeScriptWorker>
) {
super(worker);
}
public async provideReferences(model: monaco.editor.ITextModel, position: Position, context: monaco.languages.ReferenceContext, token: CancellationToken): Promise<monaco.languages.Location[] | undefined> {
const resource = model.uri;
const offset = model.getOffsetAt(position);
@ -518,10 +624,17 @@ export class ReferenceAdapter extends Adapter implements monaco.languages.Refere
return;
}
// Fetch lib files if necessary
await this._libFiles.fetchLibFilesIfNecessary(entries.map(entry => Uri.parse(entry.fileName)));
if (model.isDisposed()) {
return;
}
const result: monaco.languages.Location[] = [];
for (let entry of entries) {
const uri = Uri.parse(entry.fileName);
const refModel = monaco.editor.getModel(uri);
const refModel = this._libFiles.getOrCreateModel(uri);
if (refModel) {
result.push({
uri: uri,
@ -701,7 +814,7 @@ export class CodeActionAdaptor extends FormatHelper implements monaco.languages.
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 => {

@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//
// **NOTE**: Do not edit directly! This file is generated using `npm run import-typescript`
//
/** Contains all the lib files */
export const libFileSet: Record<string, boolean> = {}
libFileSet['lib.d.ts'] = true;
libFileSet['lib.dom.d.ts'] = true;
libFileSet['lib.dom.iterable.d.ts'] = true;
libFileSet['lib.es2015.collection.d.ts'] = true;
libFileSet['lib.es2015.core.d.ts'] = true;
libFileSet['lib.es2015.d.ts'] = true;
libFileSet['lib.es2015.generator.d.ts'] = true;
libFileSet['lib.es2015.iterable.d.ts'] = true;
libFileSet['lib.es2015.promise.d.ts'] = true;
libFileSet['lib.es2015.proxy.d.ts'] = true;
libFileSet['lib.es2015.reflect.d.ts'] = true;
libFileSet['lib.es2015.symbol.d.ts'] = true;
libFileSet['lib.es2015.symbol.wellknown.d.ts'] = true;
libFileSet['lib.es2016.array.include.d.ts'] = true;
libFileSet['lib.es2016.d.ts'] = true;
libFileSet['lib.es2016.full.d.ts'] = true;
libFileSet['lib.es2017.d.ts'] = true;
libFileSet['lib.es2017.full.d.ts'] = true;
libFileSet['lib.es2017.intl.d.ts'] = true;
libFileSet['lib.es2017.object.d.ts'] = true;
libFileSet['lib.es2017.sharedmemory.d.ts'] = true;
libFileSet['lib.es2017.string.d.ts'] = true;
libFileSet['lib.es2017.typedarrays.d.ts'] = true;
libFileSet['lib.es2018.asyncgenerator.d.ts'] = true;
libFileSet['lib.es2018.asynciterable.d.ts'] = true;
libFileSet['lib.es2018.d.ts'] = true;
libFileSet['lib.es2018.full.d.ts'] = true;
libFileSet['lib.es2018.intl.d.ts'] = true;
libFileSet['lib.es2018.promise.d.ts'] = true;
libFileSet['lib.es2018.regexp.d.ts'] = true;
libFileSet['lib.es2019.array.d.ts'] = true;
libFileSet['lib.es2019.d.ts'] = true;
libFileSet['lib.es2019.full.d.ts'] = true;
libFileSet['lib.es2019.object.d.ts'] = true;
libFileSet['lib.es2019.string.d.ts'] = true;
libFileSet['lib.es2019.symbol.d.ts'] = true;
libFileSet['lib.es2020.bigint.d.ts'] = true;
libFileSet['lib.es2020.d.ts'] = true;
libFileSet['lib.es2020.full.d.ts'] = true;
libFileSet['lib.es2020.promise.d.ts'] = true;
libFileSet['lib.es2020.string.d.ts'] = true;
libFileSet['lib.es2020.symbol.wellknown.d.ts'] = true;
libFileSet['lib.es5.d.ts'] = true;
libFileSet['lib.es6.d.ts'] = true;
libFileSet['lib.esnext.array.d.ts'] = true;
libFileSet['lib.esnext.asynciterable.d.ts'] = true;
libFileSet['lib.esnext.bigint.d.ts'] = true;
libFileSet['lib.esnext.d.ts'] = true;
libFileSet['lib.esnext.full.d.ts'] = true;
libFileSet['lib.esnext.intl.d.ts'] = true;
libFileSet['lib.esnext.symbol.d.ts'] = true;
libFileSet['lib.scripthost.d.ts'] = true;
libFileSet['lib.webworker.d.ts'] = true;
libFileSet['lib.webworker.importscripts.d.ts'] = true;

File diff suppressed because one or more lines are too long

@ -55,18 +55,20 @@ function setupMode(defaults: LanguageServiceDefaultsImpl, modeId: string): (...u
return client.getLanguageServiceWorker(...uris);
};
const libFiles = new languageFeatures.LibFiles(worker);
monaco.languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker));
monaco.languages.registerSignatureHelpProvider(modeId, new languageFeatures.SignatureHelpAdapter(worker));
monaco.languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker));
monaco.languages.registerDocumentHighlightProvider(modeId, new languageFeatures.OccurrencesAdapter(worker));
monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(worker));
monaco.languages.registerReferenceProvider(modeId, new languageFeatures.ReferenceAdapter(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(defaults, modeId, worker);
new languageFeatures.DiagnosticsAdapter(libFiles, defaults, modeId, worker);
return worker;
}

@ -5,21 +5,11 @@
'use strict';
import * as ts from './lib/typescriptServices';
import { lib_es5_dts, lib_es2015_bundled_dts } from './lib/lib';
import { libFileMap } from './lib/lib';
import { IExtraLibs } from './monaco.contribution';
import IWorkerContext = monaco.worker.IWorkerContext;
const DEFAULT_ES5_LIB = {
NAME: 'defaultLib:lib.d.ts',
CONTENTS: lib_es5_dts
};
const ES2015_LIB = {
NAME: 'defaultLib:lib.es2015.d.ts',
CONTENTS: lib_es2015_bundled_dts
};
export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.languages.typescript.TypeScriptWorker {
// --- model sync -----------------------
@ -79,15 +69,12 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
if (model) {
// a true editor model
text = model.getValue();
} else if (fileName in libFileMap) {
text = libFileMap[fileName];
} else if (fileName in this._extraLibs) {
// extra lib
text = this._extraLibs[fileName].content;
} else if (fileName === DEFAULT_ES5_LIB.NAME) {
text = DEFAULT_ES5_LIB.CONTENTS;
} else if (fileName === ES2015_LIB.NAME) {
text = ES2015_LIB.CONTENTS;
} else {
return;
}
@ -126,14 +113,42 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, monaco.language
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
// TODO@joh support lib.es7.d.ts
return (options.target || ts.ScriptTarget.ES2015) < ts.ScriptTarget.ES2015 ? DEFAULT_ES5_LIB.NAME : ES2015_LIB.NAME;
switch (options.target) {
case 99 /* ESNext */:
const esnext = "lib.esnext.full.d.ts";
if (esnext in libFileMap || esnext in this._extraLibs) return esnext
case 7 /* ES2020 */:
case 6 /* ES2019 */:
case 5 /* ES2018 */:
case 4 /* ES2017 */:
case 3 /* ES2016 */:
case 2 /* ES2015 */:
default:
// Support a dynamic lookup for the ES20XX version based on the target
// which is safe unless TC39 changes their numbering system
const eslib = `lib.es${2013 + (options.target || 99)}.full.d.ts`;
// Note: This also looks in _extraLibs, If you want
// to add support for additional target options, you will need to
// add the extra dts files to _extraLibs via the API.
if (eslib in libFileMap || eslib in this._extraLibs) {
return eslib;
}
return "lib.es6.d.ts"; // We don't use lib.es2015.full.d.ts due to breaking change.
case 1:
case 0:
return "lib.d.ts";
}
}
isDefaultLibFileName(fileName: string): boolean {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
}
getLibFiles(): Promise<Record<string, string>> {
return Promise.resolve(libFileMap);
}
// --- language features
private static clearFiles(diagnostics: ts.Diagnostic[]): monaco.languages.typescript.Diagnostic[] {

Loading…
Cancel
Save