mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-21 00:59:03 +01:00
Use Strict Null Checks In TS Extension (#16244)
* Use Strict Null Checks In TS Extension Updates the Ts extension to use strict null checks. * Throw instead of returning undefined in some linkedmap cases * fix small null check in buffersync * Fix for request item null
This commit is contained in:
@@ -167,7 +167,10 @@ export default class BufferSyncSupport {
|
||||
|
||||
public dispose(): void {
|
||||
while (this.disposables.length) {
|
||||
this.disposables.pop().dispose();
|
||||
const obj = this.disposables.pop();
|
||||
if (obj) {
|
||||
obj.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +194,7 @@ export default class BufferSyncSupport {
|
||||
}
|
||||
|
||||
private onDidCloseTextDocument(document: TextDocument): void {
|
||||
let filepath: string = this.client.asAbsolutePath(document.uri);
|
||||
let filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
@@ -208,7 +211,7 @@ export default class BufferSyncSupport {
|
||||
}
|
||||
|
||||
private onDidChangeTextDocument(e: TextDocumentChangeEvent): void {
|
||||
let filepath: string = this.client.asAbsolutePath(e.document.uri);
|
||||
let filepath = this.client.asAbsolutePath(e.document.uri);
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
@@ -220,7 +223,7 @@ export default class BufferSyncSupport {
|
||||
}
|
||||
|
||||
private onDidSaveTextDocument(document: TextDocument): void {
|
||||
let filepath: string = this.client.asAbsolutePath(document.uri);
|
||||
let filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
@@ -312,7 +315,7 @@ export default class BufferSyncSupport {
|
||||
return cp.exec(cmd + ' ' + url);
|
||||
}
|
||||
|
||||
let tscVersion: string = undefined;
|
||||
let tscVersion: string | undefined = undefined;
|
||||
try {
|
||||
let out = cp.execSync('tsc --version', { encoding: 'utf8' });
|
||||
if (out) {
|
||||
|
||||
@@ -92,6 +92,9 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
||||
|
||||
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise<CompletionItem[]> {
|
||||
let filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve<CompletionItem[]>([]);
|
||||
}
|
||||
let args: CompletionsRequestArgs = {
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
@@ -120,14 +123,15 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
||||
|
||||
let completionItems: CompletionItem[] = [];
|
||||
let body = msg.body;
|
||||
if (body) {
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
let element = body[i];
|
||||
let item = new MyCompletionItem(element);
|
||||
item.document = document;
|
||||
item.position = position;
|
||||
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
let element = body[i];
|
||||
let item = new MyCompletionItem(element);
|
||||
item.document = document;
|
||||
item.position = position;
|
||||
|
||||
completionItems.push(item);
|
||||
completionItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return completionItems;
|
||||
@@ -139,16 +143,19 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
||||
|
||||
public resolveCompletionItem(item: CompletionItem, token: CancellationToken): any | Thenable<any> {
|
||||
if (item instanceof MyCompletionItem) {
|
||||
|
||||
const filepath = this.client.asAbsolutePath(item.document.uri);
|
||||
if (!filepath) {
|
||||
return null;
|
||||
}
|
||||
let args: CompletionDetailsRequestArgs = {
|
||||
file: this.client.asAbsolutePath(item.document.uri),
|
||||
file: filepath,
|
||||
line: item.position.line + 1,
|
||||
offset: item.position.character + 1,
|
||||
entryNames: [item.label]
|
||||
};
|
||||
return this.client.execute('completionEntryDetails', args, token).then((response) => {
|
||||
let details = response.body;
|
||||
let detail: CompletionEntryDetails = null;
|
||||
let detail: CompletionEntryDetails | null = null;
|
||||
if (details && details.length > 0) {
|
||||
detail = details[0];
|
||||
item.documentation = Previewer.plain(detail.documentation);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { DefinitionProvider, TextDocument, Position, Range, CancellationToken, Location } from 'vscode';
|
||||
import { DefinitionProvider, TextDocument, Position, Range, CancellationToken, Definition, Location } from 'vscode';
|
||||
|
||||
import * as Proto from '../protocol';
|
||||
import { ITypescriptServiceClient } from '../typescriptService';
|
||||
@@ -20,19 +20,23 @@ export default class TypeScriptDefinitionProvider implements DefinitionProvider
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise<Location> {
|
||||
public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise<Definition | null> {
|
||||
const filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
let args: Proto.FileLocationRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1
|
||||
};
|
||||
if (!args.file) {
|
||||
return Promise.resolve<Location>(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return this.client.execute('definition', args, token).then(response => {
|
||||
let locations: Proto.FileSpan[] = response.body;
|
||||
let locations: Proto.FileSpan[] = response.body || [];
|
||||
if (!locations || locations.length === 0) {
|
||||
return null;
|
||||
return [] as Definition;
|
||||
}
|
||||
return locations.map(location => {
|
||||
let resource = this.client.asUrl(location.file);
|
||||
@@ -41,10 +45,10 @@ export default class TypeScriptDefinitionProvider implements DefinitionProvider
|
||||
} else {
|
||||
return new Location(resource, new Range(location.start.line - 1, location.start.offset - 1, location.end.line - 1, location.end.offset - 1));
|
||||
}
|
||||
});
|
||||
}).filter(x => x !== null) as Location[];
|
||||
}, (error) => {
|
||||
this.client.error(`'definition' request failed with error.`, error);
|
||||
return null;
|
||||
return [] as Definition;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,12 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh
|
||||
}
|
||||
|
||||
public provideDocumentHighlights(resource: TextDocument, position: Position, token: CancellationToken): Promise<DocumentHighlight[]> {
|
||||
const filepath = this.client.asAbsolutePath(resource.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve<DocumentHighlight[]>([]);
|
||||
}
|
||||
let args: Proto.FileLocationRequestArgs = {
|
||||
file: this.client.asAbsolutePath(resource.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1
|
||||
};
|
||||
@@ -36,6 +40,7 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh
|
||||
item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read);
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}, (err) => {
|
||||
this.client.error(`'occurrences' request failed with error.`, err);
|
||||
return [];
|
||||
|
||||
@@ -40,8 +40,12 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP
|
||||
}
|
||||
|
||||
public provideDocumentSymbols(resource: TextDocument, token: CancellationToken): Promise<SymbolInformation[]> {
|
||||
const filepath = this.client.asAbsolutePath(resource.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve<SymbolInformation[]>([]);
|
||||
}
|
||||
let args: Proto.FileRequestArgs = {
|
||||
file: this.client.asAbsolutePath(resource.uri)
|
||||
file: filepath
|
||||
};
|
||||
if (!args.file) {
|
||||
return Promise.resolve<SymbolInformation[]>([]);
|
||||
@@ -53,7 +57,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP
|
||||
if (realIndent !== 0 && !foldingMap[key]) {
|
||||
let result = new SymbolInformation(item.text,
|
||||
outlineTypeTable[item.kind] || SymbolKind.Variable,
|
||||
containerLabel,
|
||||
'' + containerLabel,
|
||||
new Location(resource.uri, textSpan2Range(item.spans[0])));
|
||||
foldingMap[key] = result;
|
||||
bucket.push(result);
|
||||
@@ -68,7 +72,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP
|
||||
function convertNavTree(bucket: SymbolInformation[], item: Proto.NavigationTree, containerLabel?: string): void {
|
||||
let result = new SymbolInformation(item.text,
|
||||
outlineTypeTable[item.kind] || SymbolKind.Variable,
|
||||
containerLabel,
|
||||
'' + containerLabel,
|
||||
new Location(resource.uri, textSpan2Range(item.spans[0]))
|
||||
);
|
||||
if (item.childItems && item.childItems.length > 0) {
|
||||
|
||||
@@ -71,7 +71,7 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
||||
|
||||
private client: ITypescriptServiceClient;
|
||||
private config: Configuration;
|
||||
private formatOptions: { [key: string]: Proto.FormatCodeSettings; };
|
||||
private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; };
|
||||
|
||||
public constructor(client: ITypescriptServiceClient) {
|
||||
this.client = client;
|
||||
@@ -106,8 +106,12 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
||||
if (currentOptions && currentOptions.tabSize === options.tabSize && currentOptions.indentSize === options.tabSize && currentOptions.convertTabsToSpaces === options.insertSpaces) {
|
||||
return Promise.resolve(currentOptions);
|
||||
} else {
|
||||
const absPath = this.client.asAbsolutePath(document.uri);
|
||||
if (!absPath) {
|
||||
return Promise.resolve(Object.create(null));
|
||||
}
|
||||
let args: Proto.ConfigureRequestArguments = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: absPath,
|
||||
formatOptions: this.getFormatOptions(options)
|
||||
};
|
||||
return this.client.execute('configure', args, token).then((response) => {
|
||||
@@ -120,7 +124,11 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
||||
private doFormat(document: TextDocument, options: FormattingOptions, args: Proto.FormatRequestArgs, token: CancellationToken): Promise<TextEdit[]> {
|
||||
return this.ensureFormatOptions(document, options, token).then(() => {
|
||||
return this.client.execute('format', args, token).then((response): TextEdit[] => {
|
||||
return response.body.map(this.codeEdit2SingleEditOperation);
|
||||
if (response.body) {
|
||||
return response.body.map(this.codeEdit2SingleEditOperation);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}, (err: any) => {
|
||||
this.client.error(`'format' request failed with error.`, err);
|
||||
return [];
|
||||
@@ -129,8 +137,12 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
||||
}
|
||||
|
||||
public provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): Promise<TextEdit[]> {
|
||||
const absPath = this.client.asAbsolutePath(document.uri);
|
||||
if (!absPath) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
let args: Proto.FormatRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: absPath,
|
||||
line: range.start.line + 1,
|
||||
offset: range.start.character + 1,
|
||||
endLine: range.end.line + 1,
|
||||
@@ -140,8 +152,12 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
||||
}
|
||||
|
||||
public provideOnTypeFormattingEdits(document: TextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): Promise<TextEdit[]> {
|
||||
const filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
let args: Proto.FormatOnKeyRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1,
|
||||
key: ch
|
||||
@@ -151,6 +167,9 @@ export default class TypeScriptFormattingProvider implements DocumentRangeFormat
|
||||
return this.client.execute('formatonkey', args, token).then((response): TextEdit[] => {
|
||||
let edits = response.body;
|
||||
let result: TextEdit[] = [];
|
||||
if (!edits) {
|
||||
return result;
|
||||
}
|
||||
for (let edit of edits) {
|
||||
let textEdit = this.codeEdit2SingleEditOperation(edit);
|
||||
let range = textEdit.range;
|
||||
|
||||
@@ -18,16 +18,20 @@ export default class TypeScriptHoverProvider implements HoverProvider {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public provideHover(document: TextDocument, position: Position, token: CancellationToken): Promise<Hover> {
|
||||
public provideHover(document: TextDocument, position: Position, token: CancellationToken): Promise<Hover | undefined | null> {
|
||||
const filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
let args: Proto.FileLocationRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1
|
||||
};
|
||||
if (!args.file) {
|
||||
return Promise.resolve<Hover>(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return this.client.execute('quickinfo', args, token).then((response): Hover => {
|
||||
return this.client.execute('quickinfo', args, token).then((response): Hover | undefined => {
|
||||
let data = response.body;
|
||||
if (data) {
|
||||
return new Hover(
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
interface Item<T> {
|
||||
previous: Item<T>;
|
||||
next: Item<T>;
|
||||
previous: Item<T> | undefined;
|
||||
next: Item<T> | undefined;
|
||||
key: string;
|
||||
value: T;
|
||||
}
|
||||
@@ -13,8 +13,8 @@ interface Item<T> {
|
||||
export default class LinkedMap<T> {
|
||||
|
||||
private map: Map<Item<T>>;
|
||||
private head: Item<T>;
|
||||
private tail: Item<T>;
|
||||
private head: Item<T> | undefined;
|
||||
private tail: Item<T> | undefined;
|
||||
private _length: number;
|
||||
|
||||
constructor() {
|
||||
@@ -32,7 +32,7 @@ export default class LinkedMap<T> {
|
||||
return this._length;
|
||||
}
|
||||
|
||||
public get(key: string): T {
|
||||
public get(key: string): T | undefined {
|
||||
const item = this.map[key];
|
||||
if (!item) {
|
||||
return undefined;
|
||||
@@ -61,7 +61,7 @@ export default class LinkedMap<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public remove(key: string): T {
|
||||
public remove(key: string): T | undefined {
|
||||
const item = this.map[key];
|
||||
if (!item) {
|
||||
return undefined;
|
||||
@@ -72,10 +72,13 @@ export default class LinkedMap<T> {
|
||||
return item.value;
|
||||
}
|
||||
|
||||
public shift(): T {
|
||||
public shift(): T | undefined {
|
||||
if (!this.head && !this.tail) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this.head || !this.tail) {
|
||||
throw new Error('Invalid list');
|
||||
}
|
||||
const item = this.head;
|
||||
delete this.map[item.key];
|
||||
this.removeItem(item);
|
||||
@@ -87,8 +90,9 @@ export default class LinkedMap<T> {
|
||||
// First time Insert
|
||||
if (!this.head && !this.tail) {
|
||||
this.tail = item;
|
||||
}
|
||||
else {
|
||||
} else if (!this.head) {
|
||||
throw new Error('Invalid list');
|
||||
} else {
|
||||
item.next = this.head;
|
||||
this.head.previous = item;
|
||||
}
|
||||
@@ -99,8 +103,9 @@ export default class LinkedMap<T> {
|
||||
// First time Insert
|
||||
if (!this.head && !this.tail) {
|
||||
this.head = item;
|
||||
}
|
||||
else {
|
||||
} else if (!this.tail) {
|
||||
throw new Error('Invalid list');
|
||||
} else {
|
||||
item.previous = this.tail;
|
||||
this.tail.next = item;
|
||||
}
|
||||
@@ -121,6 +126,9 @@ export default class LinkedMap<T> {
|
||||
else {
|
||||
const next = item.next;
|
||||
const previous = item.previous;
|
||||
if (!next || !previous) {
|
||||
throw new Error('Invalid list');
|
||||
}
|
||||
next.previous = previous;
|
||||
previous.next = next;
|
||||
}
|
||||
@@ -140,13 +148,20 @@ export default class LinkedMap<T> {
|
||||
}
|
||||
else {
|
||||
// Both next and previous are not null since item was neither head nor tail.
|
||||
next.previous = previous;
|
||||
previous.next = next;
|
||||
if (next) {
|
||||
next.previous = previous;
|
||||
}
|
||||
if (previous) {
|
||||
previous.next = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the node at head
|
||||
item.previous = undefined;
|
||||
item.next = this.head;
|
||||
if (!this.head) {
|
||||
throw new Error('Invalid list');
|
||||
}
|
||||
this.head.previous = item;
|
||||
this.head = item;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,12 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider {
|
||||
}
|
||||
|
||||
public provideReferences(document: TextDocument, position: Position, options: { includeDeclaration: boolean }, token: CancellationToken): Promise<Location[]> {
|
||||
const filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve<Location[]>([]);
|
||||
}
|
||||
let args: Proto.FileLocationRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1
|
||||
};
|
||||
@@ -32,6 +36,9 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider {
|
||||
const apiVersion = this.client.apiVersion;
|
||||
return this.client.execute('references', args, token).then((msg) => {
|
||||
let result: Location[] = [];
|
||||
if (!msg.body) {
|
||||
return result;
|
||||
}
|
||||
let refs = msg.body.refs;
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
let ref = refs[i];
|
||||
|
||||
@@ -20,20 +20,27 @@ export default class TypeScriptRenameProvider implements RenameProvider {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): Promise<WorkspaceEdit> {
|
||||
public provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): Promise<WorkspaceEdit | undefined | null> {
|
||||
const filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
let args: Proto.RenameRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1,
|
||||
findInStrings: false,
|
||||
findInComments: false
|
||||
};
|
||||
if (!args.file) {
|
||||
return Promise.resolve<WorkspaceEdit>(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return this.client.execute('rename', args, token).then((response) => {
|
||||
let renameResponse = response.body;
|
||||
if (!renameResponse) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
let renameInfo = renameResponse.info;
|
||||
let result = new WorkspaceEdit();
|
||||
|
||||
|
||||
@@ -19,14 +19,18 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise<SignatureHelp> {
|
||||
public provideSignatureHelp(document: TextDocument, position: Position, token: CancellationToken): Promise<SignatureHelp | undefined | null> {
|
||||
const filepath = this.client.asAbsolutePath(document.uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
let args: Proto.SignatureHelpRequestArgs = {
|
||||
file: this.client.asAbsolutePath(document.uri),
|
||||
file: filepath,
|
||||
line: position.line + 1,
|
||||
offset: position.character + 1
|
||||
};
|
||||
if (!args.file) {
|
||||
return Promise.resolve<SignatureHelp>(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return this.client.execute('signatureHelp', args, token).then((response) => {
|
||||
let info = response.body;
|
||||
@@ -42,6 +46,9 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro
|
||||
}
|
||||
|
||||
info.items.forEach((item, i) => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
// keep active parameter in bounds
|
||||
if (i === info.selectedItemIndex && item.isVariadic) {
|
||||
|
||||
@@ -32,7 +32,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo
|
||||
// typescript wants to have a resource even when asking
|
||||
// general questions so we check the active editor. If this
|
||||
// doesn't match we take the first TS document.
|
||||
let uri: Uri;
|
||||
let uri: Uri | undefined = undefined;
|
||||
let editor = window.activeTextEditor;
|
||||
if (editor) {
|
||||
let document = editor.document;
|
||||
@@ -54,8 +54,12 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo
|
||||
return Promise.resolve<SymbolInformation[]>([]);
|
||||
}
|
||||
|
||||
const filepath = this.client.asAbsolutePath(uri);
|
||||
if (!filepath) {
|
||||
return Promise.resolve<SymbolInformation[]>([]);
|
||||
}
|
||||
let args: Proto.NavtoRequestArgs = {
|
||||
file: this.client.asAbsolutePath(uri),
|
||||
file: filepath,
|
||||
searchValue: search
|
||||
};
|
||||
if (!args.file) {
|
||||
@@ -74,7 +78,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo
|
||||
if (item.kind === 'method' || item.kind === 'function') {
|
||||
label += '()';
|
||||
}
|
||||
result.push(new SymbolInformation(label, _kindMapping[item.kind], item.containerName,
|
||||
result.push(new SymbolInformation(label, _kindMapping[item.kind], '' + item.containerName,
|
||||
new Location(this.client.asUrl(item.file), range)));
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -103,7 +103,7 @@ class LanguageProvider {
|
||||
|
||||
private completionItemProvider: CompletionItemProvider;
|
||||
private formattingProvider: FormattingProvider;
|
||||
private formattingProviderRegistration: Disposable;
|
||||
private formattingProviderRegistration: Disposable | null;
|
||||
|
||||
private _validate: boolean;
|
||||
|
||||
@@ -214,7 +214,7 @@ class LanguageProvider {
|
||||
this.formattingProvider.updateConfiguration(config);
|
||||
if (!this.formattingProvider.isEnabled() && this.formattingProviderRegistration) {
|
||||
this.formattingProviderRegistration.dispose();
|
||||
this.formattingProviderRegistration = undefined;
|
||||
this.formattingProviderRegistration = null;
|
||||
|
||||
} else if (this.formattingProvider.isEnabled() && !this.formattingProviderRegistration) {
|
||||
this.formattingProviderRegistration = languages.registerDocumentRangeFormattingEditProvider(this.description.modeIds, this.formattingProvider);
|
||||
@@ -228,7 +228,7 @@ class LanguageProvider {
|
||||
return true;
|
||||
}
|
||||
let basename = path.basename(file);
|
||||
return basename && basename === this.description.configFile;
|
||||
return !!basename && basename === this.description.configFile;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
@@ -325,7 +325,7 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
|
||||
return !!this.findLanguage(file);
|
||||
}
|
||||
|
||||
private findLanguage(file: string): LanguageProvider {
|
||||
private findLanguage(file: string): LanguageProvider | null {
|
||||
for (let i = 0; i < this.languages.length; i++) {
|
||||
let language = this.languages[i];
|
||||
if (language.handles(file)) {
|
||||
@@ -348,7 +348,7 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
|
||||
|
||||
/* internal */ syntaxDiagnosticsReceived(event: Proto.DiagnosticEvent): void {
|
||||
let body = event.body;
|
||||
if (body.diagnostics) {
|
||||
if (body && body.diagnostics) {
|
||||
let language = this.findLanguage(body.file);
|
||||
if (language) {
|
||||
language.syntaxDiagnosticsReceived(body.file, this.createMarkerDatas(body.diagnostics, language.diagnosticSource));
|
||||
@@ -358,7 +358,7 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
|
||||
|
||||
/* internal */ semanticDiagnosticsReceived(event: Proto.DiagnosticEvent): void {
|
||||
let body = event.body;
|
||||
if (body.diagnostics) {
|
||||
if (body && body.diagnostics) {
|
||||
let language = this.findLanguage(body.file);
|
||||
if (language) {
|
||||
language.semanticDiagnosticsReceived(body.file, this.createMarkerDatas(body.diagnostics, language.diagnosticSource));
|
||||
|
||||
@@ -56,7 +56,7 @@ export class API {
|
||||
}
|
||||
|
||||
export interface ITypescriptServiceClient {
|
||||
asAbsolutePath(resource: Uri): string;
|
||||
asAbsolutePath(resource: Uri): string | null;
|
||||
asUrl(filepath: string): Uri;
|
||||
|
||||
info(message: string, data?: any): void;
|
||||
|
||||
@@ -36,8 +36,8 @@ interface CallbackMap {
|
||||
|
||||
interface RequestItem {
|
||||
request: Proto.Request;
|
||||
promise: Promise<any>;
|
||||
callbacks: CallbackItem;
|
||||
promise: Promise<any> | null;
|
||||
callbacks: CallbackItem | null;
|
||||
}
|
||||
|
||||
interface IPackageInfo {
|
||||
@@ -85,13 +85,13 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
private pathSeparator: string;
|
||||
|
||||
private _onReady: { promise: Promise<void>; resolve: () => void; reject: () => void; };
|
||||
private tsdk: string;
|
||||
private tsdk: string | null;
|
||||
private _checkGlobalTSCVersion: boolean;
|
||||
private _experimentalAutoBuild: boolean;
|
||||
private trace: Trace;
|
||||
private _output: OutputChannel;
|
||||
private servicePromise: Promise<cp.ChildProcess>;
|
||||
private lastError: Error;
|
||||
private servicePromise: Promise<cp.ChildProcess> | null;
|
||||
private lastError: Error | null;
|
||||
private reader: Reader<Proto.Response>;
|
||||
private sequenceNumber: number;
|
||||
private exitRequested: boolean;
|
||||
@@ -103,7 +103,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
private pendingResponses: number;
|
||||
private callbacks: CallbackMap;
|
||||
|
||||
private _packageInfo: IPackageInfo;
|
||||
private _packageInfo: IPackageInfo | null;
|
||||
private _apiVersion: API;
|
||||
private telemetryReporter: TelemetryReporter;
|
||||
|
||||
@@ -114,7 +114,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
this.pathSeparator = path.sep;
|
||||
|
||||
let p = new Promise<void>((resolve, reject) => {
|
||||
this._onReady = { promise: null, resolve, reject };
|
||||
this._onReady = { promise: Promise.reject<void>(null), resolve, reject };
|
||||
});
|
||||
this._onReady.promise = p;
|
||||
|
||||
@@ -129,7 +129,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
this.pendingResponses = 0;
|
||||
this.callbacks = Object.create(null);
|
||||
const configuration = workspace.getConfiguration();
|
||||
this.tsdk = configuration.get<string>('typescript.tsdk', null);
|
||||
this.tsdk = configuration.get<string | null>('typescript.tsdk', null);
|
||||
this._experimentalAutoBuild = false; // configuration.get<boolean>('typescript.tsserver.experimentalAutoBuild', false);
|
||||
this._apiVersion = new API('1.0.0');
|
||||
this._checkGlobalTSCVersion = true;
|
||||
@@ -137,7 +137,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
workspace.onDidChangeConfiguration(() => {
|
||||
this.trace = this.readTrace();
|
||||
let oldTsdk = this.tsdk;
|
||||
this.tsdk = workspace.getConfiguration().get<string>('typescript.tsdk', null);
|
||||
this.tsdk = workspace.getConfiguration().get<string | null>('typescript.tsdk', null);
|
||||
if (this.servicePromise === null && oldTsdk !== this.tsdk) {
|
||||
this.startService();
|
||||
}
|
||||
@@ -230,7 +230,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
// this.output.show(true);
|
||||
}
|
||||
|
||||
private get packageInfo(): IPackageInfo {
|
||||
private get packageInfo(): IPackageInfo | null {
|
||||
|
||||
if (this._packageInfo !== undefined) {
|
||||
return this._packageInfo;
|
||||
@@ -264,7 +264,10 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
return Promise.reject<cp.ChildProcess>(this.lastError);
|
||||
}
|
||||
this.startService();
|
||||
return this.servicePromise;
|
||||
if (this.servicePromise) {
|
||||
return this.servicePromise;
|
||||
}
|
||||
return Promise.reject<cp.ChildProcess>(new Error('Could not create TS service'));
|
||||
}
|
||||
|
||||
private startService(resendModels: boolean = false): void {
|
||||
@@ -362,7 +365,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
|
||||
let version = this.getTypeScriptVersion(modulePath);
|
||||
if (!version) {
|
||||
version = workspace.getConfiguration().get<string>('typescript.tsdk_version', undefined);
|
||||
version = workspace.getConfiguration().get<string | undefined>('typescript.tsdk_version', undefined);
|
||||
}
|
||||
if (version) {
|
||||
this._apiVersion = new API(version);
|
||||
@@ -469,7 +472,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
let args: Proto.SetCompilerOptionsForInferredProjectsArgs = {
|
||||
options: compilerOptions
|
||||
};
|
||||
this.execute('compilerOptionsForInferredProjects', args).then(null, (err) => {
|
||||
this.execute('compilerOptionsForInferredProjects', args, true).catch((err) => {
|
||||
this.error(`'compilerOptionsForInferredProjects' request failed with error.`, err);
|
||||
});
|
||||
}
|
||||
@@ -479,7 +482,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
}
|
||||
}
|
||||
|
||||
private getTypeScriptVersion(serverPath: string): string {
|
||||
private getTypeScriptVersion(serverPath: string): string | undefined {
|
||||
let p = serverPath.split(path.sep);
|
||||
if (p.length <= 2) {
|
||||
return undefined;
|
||||
@@ -491,13 +494,13 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
return undefined;
|
||||
}
|
||||
let contents = fs.readFileSync(fileName).toString();
|
||||
let desc = null;
|
||||
let desc: any = null;
|
||||
try {
|
||||
desc = JSON.parse(contents);
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
if (!desc.version) {
|
||||
if (!desc || !desc.version) {
|
||||
return undefined;
|
||||
}
|
||||
return desc.version;
|
||||
@@ -528,7 +531,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
}
|
||||
}
|
||||
|
||||
public asAbsolutePath(resource: Uri): string {
|
||||
public asAbsolutePath(resource: Uri): string | null {
|
||||
if (resource.scheme !== 'file') {
|
||||
return null;
|
||||
}
|
||||
@@ -563,7 +566,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
promise: null,
|
||||
callbacks: null
|
||||
};
|
||||
let result: Promise<any> = null;
|
||||
let result: Promise<any> = Promise.resolve(null);
|
||||
if (expectsResult) {
|
||||
result = new Promise<any>((resolve, reject) => {
|
||||
requestInfo.callbacks = { c: resolve, e: reject, start: Date.now() };
|
||||
@@ -584,7 +587,10 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
|
||||
private sendNextRequests(): void {
|
||||
while (this.pendingResponses === 0 && this.requestQueue.length > 0) {
|
||||
this.sendRequest(this.requestQueue.shift());
|
||||
const item = this.requestQueue.shift();
|
||||
if (item) {
|
||||
this.sendRequest(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,9 +697,9 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
if (this.trace === Trace.Off) {
|
||||
return;
|
||||
}
|
||||
let data: string = undefined;
|
||||
let data: string | undefined = undefined;
|
||||
if (this.trace === Trace.Verbose && request.arguments) {
|
||||
data = `Arguments: ${JSON.stringify(request.arguments, null, 4)}`;
|
||||
data = `Arguments: ${JSON.stringify(request.arguments, [], 4)}`;
|
||||
}
|
||||
this.logTrace(`Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${this.requestQueue.length}`, data);
|
||||
}
|
||||
@@ -702,9 +708,9 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
if (this.trace === Trace.Off) {
|
||||
return;
|
||||
}
|
||||
let data: string = undefined;
|
||||
let data: string | undefined = undefined;
|
||||
if (this.trace === Trace.Verbose && response.body) {
|
||||
data = `Result: ${JSON.stringify(response.body, null, 4)}`;
|
||||
data = `Result: ${JSON.stringify(response.body, [], 4)}`;
|
||||
}
|
||||
this.logTrace(`Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data);
|
||||
}
|
||||
@@ -713,9 +719,9 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient
|
||||
if (this.trace === Trace.Off) {
|
||||
return;
|
||||
}
|
||||
let data: string = undefined;
|
||||
let data: string | undefined = undefined;
|
||||
if (this.trace === Trace.Verbose && event.body) {
|
||||
data = `Data: ${JSON.stringify(event.body, null, 4)}`;
|
||||
data = `Data: ${JSON.stringify(event.body, [], 4)}`;
|
||||
}
|
||||
this.logTrace(`Event received: ${event.event} (${event.seq}).`, data);
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ export class Delayer<T> {
|
||||
|
||||
public defaultDelay: number;
|
||||
private timeout: any; // Timer
|
||||
private completionPromise: Promise<T>;
|
||||
private onSuccess: (value?: T | Thenable<T>) => void;
|
||||
private task: ITask<T>;
|
||||
private completionPromise: Promise<T> | null;
|
||||
private onSuccess: ((value?: T | Thenable<T>) => void) | null;
|
||||
private task: ITask<T> | null;
|
||||
|
||||
constructor(defaultDelay: number) {
|
||||
this.defaultDelay = defaultDelay;
|
||||
@@ -37,7 +37,7 @@ export class Delayer<T> {
|
||||
}).then(() => {
|
||||
this.completionPromise = null;
|
||||
this.onSuccess = null;
|
||||
var result = this.task();
|
||||
var result = this.task && this.task();
|
||||
this.task = null;
|
||||
return result;
|
||||
});
|
||||
@@ -46,20 +46,24 @@ export class Delayer<T> {
|
||||
if (delay >= 0 || this.timeout === null) {
|
||||
this.timeout = setTimeout(() => {
|
||||
this.timeout = null;
|
||||
this.onSuccess(null);
|
||||
if (this.onSuccess) {
|
||||
this.onSuccess(undefined);
|
||||
}
|
||||
}, delay >= 0 ? delay : this.defaultDelay);
|
||||
}
|
||||
|
||||
return this.completionPromise;
|
||||
}
|
||||
|
||||
public forceDelivery(): Promise<T> {
|
||||
public forceDelivery(): Promise<T> | null {
|
||||
if (!this.completionPromise) {
|
||||
return null;
|
||||
}
|
||||
this.cancelTimeout();
|
||||
let result = this.completionPromise;
|
||||
this.onSuccess(null);
|
||||
if (this.onSuccess) {
|
||||
this.onSuccess(undefined);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ function generatePatchedEnv(env: any, stdInPipeName: string, stdOutPipeName: str
|
||||
return newEnv;
|
||||
}
|
||||
|
||||
export function fork(modulePath: string, args: string[], options: IForkOptions, callback: (error: any, cp: cp.ChildProcess) => void): void {
|
||||
export function fork(modulePath: string, args: string[], options: IForkOptions, callback: (error: any, cp: cp.ChildProcess | null) => void): void {
|
||||
|
||||
var callbackCalled = false;
|
||||
var resolve = (result: cp.ChildProcess) => {
|
||||
|
||||
@@ -31,8 +31,8 @@ export function create(client: ITypescriptServiceClient, isOpen: (path: string)
|
||||
|
||||
const projectHintIgnoreList = memento.get<string[]>('projectHintIgnoreList', []);
|
||||
for (let path of projectHintIgnoreList) {
|
||||
if (path === null) {
|
||||
path = undefined;
|
||||
if (!path) {
|
||||
path = 'undefined';
|
||||
}
|
||||
projectHinted[path] = true;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export function create(client: ITypescriptServiceClient, isOpen: (path: string)
|
||||
delete projectHinted[e.document.fileName];
|
||||
}));
|
||||
|
||||
function onEditor(editor: vscode.TextEditor): void {
|
||||
function onEditor(editor: vscode.TextEditor | undefined): void {
|
||||
if (!editor
|
||||
|| !vscode.languages.match(selector, editor.document)
|
||||
|| !client.asAbsolutePath(editor.document.uri)) {
|
||||
@@ -63,20 +63,26 @@ export function create(client: ITypescriptServiceClient, isOpen: (path: string)
|
||||
}
|
||||
|
||||
const file = client.asAbsolutePath(editor.document.uri);
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
isOpen(file).then(value => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
return client.execute('projectInfo', { file, needFileNameList: true }).then(res => {
|
||||
|
||||
if (!res.body) {
|
||||
return;
|
||||
}
|
||||
let {configFileName, fileNames} = res.body;
|
||||
|
||||
if (projectHinted[configFileName] === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileNames.length > fileLimit) {
|
||||
if (fileNames && fileNames.length > fileLimit) {
|
||||
let largeRoots = computeLargeRoots(configFileName, fileNames).map(f => `'/${f}/'`).join(', ');
|
||||
|
||||
currentHint = {
|
||||
@@ -91,10 +97,11 @@ export function create(client: ITypescriptServiceClient, isOpen: (path: string)
|
||||
item.hide();
|
||||
|
||||
let configFileUri: vscode.Uri;
|
||||
if (dirname(configFileName).indexOf(vscode.workspace.rootPath) === 0) {
|
||||
let rootPath = vscode.workspace.rootPath;
|
||||
if (rootPath && dirname(configFileName).indexOf('' + rootPath) === 0) {
|
||||
configFileUri = vscode.Uri.file(configFileName);
|
||||
} else {
|
||||
configFileUri = vscode.Uri.parse('untitled://' + join(vscode.workspace.rootPath, 'jsconfig.json'));
|
||||
configFileUri = vscode.Uri.parse('untitled://' + join(rootPath, 'jsconfig.json'));
|
||||
}
|
||||
|
||||
return vscode.workspace.openTextDocument(configFileUri)
|
||||
|
||||
@@ -25,7 +25,7 @@ class ProtocolBuffer {
|
||||
}
|
||||
|
||||
public append(data: string | Buffer): void {
|
||||
let toAppend: Buffer = null;
|
||||
let toAppend: Buffer | null = null;
|
||||
if (Buffer.isBuffer(data)) {
|
||||
toAppend = <Buffer>data;
|
||||
} else {
|
||||
@@ -70,7 +70,7 @@ class ProtocolBuffer {
|
||||
return result;
|
||||
}
|
||||
|
||||
public tryReadContent(length: number): string {
|
||||
public tryReadContent(length: number): string | null {
|
||||
if (this.index < length) {
|
||||
return null;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ class ProtocolBuffer {
|
||||
return result;
|
||||
}
|
||||
|
||||
public tryReadLine(): string {
|
||||
public tryReadLine(): string | null {
|
||||
let end: number = 0;
|
||||
while (end < this.index && this.buffer[end] !== BackslashR && this.buffer[end] !== BackslashN) {
|
||||
end++;
|
||||
|
||||
Reference in New Issue
Block a user