typescript-language-server
Advanced tools
Comparing version 0.2.0 to 0.3.0-dev.ceb1d15
#!/usr/bin/env node | ||
export {}; | ||
//# sourceMappingURL=cli.d.ts.map |
@@ -0,12 +1,26 @@ | ||
/// <reference path="../../node_modules/@types/lodash/common/common.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/array.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/collection.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/date.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/function.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/lang.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/math.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/number.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/object.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/seq.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/string.d.ts" /> | ||
/// <reference path="../../node_modules/@types/lodash/common/util.d.ts" /> | ||
import * as tsp from 'typescript/lib/protocol'; | ||
import * as lsp from 'vscode-languageserver'; | ||
import { Logger } from './logger'; | ||
import { EventTypes } from './tsp-command-types'; | ||
export declare class DiagnosticEventQueue { | ||
protected publicDiagnostics: (params: lsp.PublishDiagnosticsParams) => void; | ||
protected logger: Logger; | ||
protected readonly diagnostics: Map<string, Map<EventTypes, lsp.Diagnostic[]>>; | ||
constructor(publicDiagnostics: (params: lsp.PublishDiagnosticsParams) => void, logger: Logger); | ||
pendingSyntaxDiagnostics: Map<string, tsp.DiagnosticEvent>; | ||
addSyntacticDiagnostic(event: tsp.DiagnosticEvent): void; | ||
private key; | ||
addSemanticDiagnostic(event: tsp.DiagnosticEvent): void; | ||
updateDiagnostics(kind: EventTypes, event: tsp.DiagnosticEvent): void; | ||
protected firePublishDiagnostics: ((file: string) => void) & import("_").Cancelable; | ||
protected getDiagnostics(file: string): lsp.Diagnostic[]; | ||
} | ||
//# sourceMappingURL=diagnostic-queue.d.ts.map |
@@ -10,2 +10,3 @@ "use strict"; | ||
const protocol_translation_1 = require("./protocol-translation"); | ||
const debounce = require("lodash.debounce"); | ||
class DiagnosticEventQueue { | ||
@@ -15,37 +16,30 @@ constructor(publicDiagnostics, logger) { | ||
this.logger = logger; | ||
this.pendingSyntaxDiagnostics = new Map(); | ||
this.diagnostics = new Map(); | ||
this.firePublishDiagnostics = debounce((file) => { | ||
const uri = protocol_translation_1.pathToUri(file); | ||
const diagnostics = this.getDiagnostics(file); | ||
this.publicDiagnostics({ uri, diagnostics }); | ||
}, 50); | ||
} | ||
addSyntacticDiagnostic(event) { | ||
updateDiagnostics(kind, event) { | ||
if (!event.body) { | ||
this.logger.error("Received empty syntactic diagnostics."); | ||
this.logger.error(`Received empty ${event.event} diagnostics.`); | ||
return; | ||
} | ||
this.pendingSyntaxDiagnostics.set(this.key(event), event); | ||
const { file } = event.body; | ||
const diagnostics = this.diagnostics.get(file) || new Map(); | ||
diagnostics.set(kind, event.body.diagnostics.map(protocol_translation_1.toDiagnostic)); | ||
this.diagnostics.set(file, diagnostics); | ||
this.firePublishDiagnostics(file); | ||
} | ||
key(event) { | ||
return event.seq + event.body.file; | ||
} | ||
addSemanticDiagnostic(event) { | ||
const syntax = this.pendingSyntaxDiagnostics.get(this.key(event)); | ||
if (!event.body) { | ||
this.logger.error("Received empty semantic diagnostics."); | ||
return; | ||
getDiagnostics(file) { | ||
const diagnostics = this.diagnostics.get(file); | ||
if (!diagnostics) { | ||
return []; | ||
} | ||
if (!syntax) { | ||
this.logger.error("Received semantic diagnostics without previsou syntactic ones, for file : " + event.body.file); | ||
return; | ||
const result = []; | ||
for (const value of diagnostics.values()) { | ||
result.push(...value); | ||
} | ||
this.pendingSyntaxDiagnostics.delete(this.key(event)); | ||
const diagnostics = []; | ||
for (const d of syntax.body.diagnostics) { | ||
diagnostics.push(protocol_translation_1.toDiagnostic(d)); | ||
} | ||
for (const d of event.body.diagnostics) { | ||
diagnostics.push(protocol_translation_1.toDiagnostic(d)); | ||
} | ||
const result = { | ||
uri: protocol_translation_1.pathToUri(event.body.file), | ||
diagnostics | ||
}; | ||
this.publicDiagnostics(result); | ||
return result; | ||
} | ||
@@ -52,0 +46,0 @@ } |
@@ -20,1 +20,2 @@ import * as lsp from 'vscode-languageserver'; | ||
} | ||
//# sourceMappingURL=document.d.ts.map |
export {}; | ||
//# sourceMappingURL=file-lsp-server.spec.d.ts.map |
@@ -40,1 +40,2 @@ import { LspClient } from './lsp-client'; | ||
} | ||
//# sourceMappingURL=logger.d.ts.map |
@@ -8,2 +8,3 @@ import * as lsp from 'vscode-languageserver'; | ||
telemetry(args: any): void; | ||
rename(args: lsp.TextDocumentPositionParams): Promise<any>; | ||
} | ||
@@ -18,2 +19,4 @@ export declare class LspClientImpl implements LspClient { | ||
applyWorkspaceEdit(args: lsp.ApplyWorkspaceEditParams): Promise<lsp.ApplyWorkspaceEditResponse>; | ||
rename(args: lsp.TextDocumentPositionParams): Promise<any>; | ||
} | ||
//# sourceMappingURL=lsp-client.d.ts.map |
@@ -18,2 +18,3 @@ "use strict"; | ||
const lsp = require("vscode-languageserver"); | ||
const commands_1 = require("./commands"); | ||
class LspClientImpl { | ||
@@ -40,4 +41,9 @@ constructor(connection) { | ||
} | ||
rename(args) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.connection.sendRequest(commands_1.TypeScriptRenameRequest.type, args); | ||
}); | ||
} | ||
} | ||
exports.LspClientImpl = LspClientImpl; | ||
//# sourceMappingURL=lsp-client.js.map |
@@ -9,1 +9,2 @@ import * as lsp from 'vscode-languageserver'; | ||
export declare function createLspConnection(options: IServerOptions): lsp.IConnection; | ||
//# sourceMappingURL=lsp-connection.d.ts.map |
@@ -6,2 +6,3 @@ import * as lsp from 'vscode-languageserver'; | ||
import { LspDocument } from './document'; | ||
import { TSCompletionItem } from './completion'; | ||
export interface IServerOptions { | ||
@@ -14,3 +15,2 @@ logger: Logger; | ||
} | ||
export declare const WORKSPACE_EDIT_COMMAND = "workspace-edit"; | ||
export declare class LspServer { | ||
@@ -28,3 +28,6 @@ private options; | ||
initialize(params: lsp.InitializeParams): Promise<lsp.InitializeResult>; | ||
protected diagnosticsTokenSource: lsp.CancellationTokenSource | undefined; | ||
protected interuptDiagnostics<R>(f: () => R): R; | ||
requestDiagnostics(): Promise<tsp.RequestCompletedEvent>; | ||
protected cancelDiagnostics(): void; | ||
didOpenTextDocument(params: lsp.DidOpenTextDocumentParams): void; | ||
@@ -43,11 +46,18 @@ protected getScriptKindName(languageId: string): tsp.ScriptKindName | undefined; | ||
documentSymbol(params: lsp.TextDocumentPositionParams): Promise<lsp.SymbolInformation[]>; | ||
completion(params: lsp.TextDocumentPositionParams): Promise<lsp.CompletionList>; | ||
completionResolve(item: lsp.CompletionItem): Promise<lsp.CompletionItem>; | ||
completion(params: lsp.CompletionParams): Promise<TSCompletionItem[]>; | ||
completionResolve(item: TSCompletionItem): Promise<lsp.CompletionItem>; | ||
hover(params: lsp.TextDocumentPositionParams): Promise<lsp.Hover>; | ||
rename(params: lsp.RenameParams): Promise<lsp.WorkspaceEdit>; | ||
protected getQuickInfo(file: string, position: lsp.Position): Promise<tsp.QuickInfoResponse | undefined>; | ||
rename(params: lsp.RenameParams): Promise<lsp.WorkspaceEdit | undefined>; | ||
references(params: lsp.TextDocumentPositionParams): Promise<lsp.Location[]>; | ||
documentFormatting(params: lsp.DocumentFormattingParams): Promise<lsp.TextEdit[]>; | ||
signatureHelp(params: lsp.TextDocumentPositionParams): Promise<lsp.SignatureHelp>; | ||
codeAction(arg: lsp.CodeActionParams): Promise<lsp.Command[]>; | ||
executeCommand(arg: lsp.ExecuteCommandParams): void; | ||
signatureHelp(params: lsp.TextDocumentPositionParams): Promise<lsp.SignatureHelp | undefined>; | ||
protected getSignatureHelp(file: string, position: lsp.Position): Promise<tsp.SignatureHelpResponse | undefined>; | ||
codeAction(params: lsp.CodeActionParams): Promise<(lsp.Command | lsp.CodeAction)[]>; | ||
protected getCodeFixes(args: tsp.CodeFixRequestArgs): Promise<tsp.GetCodeFixesResponse | undefined>; | ||
protected getRefactors(args: tsp.GetApplicableRefactorsRequestArgs): Promise<tsp.GetApplicableRefactorsResponse | undefined>; | ||
executeCommand(arg: lsp.ExecuteCommandParams): Promise<void>; | ||
protected applyFileCodeEdits(edits: ReadonlyArray<tsp.FileCodeEdits>): Promise<boolean>; | ||
protected applyRenameFile(sourceUri: string, targetUri: string): Promise<void>; | ||
protected getEditsForFileRename(sourceUri: string, targetUri: string): Promise<ReadonlyArray<tsp.FileCodeEdits>>; | ||
documentHighlight(arg: lsp.TextDocumentPositionParams): Promise<lsp.DocumentHighlight[]>; | ||
@@ -62,5 +72,5 @@ private rootPath; | ||
protected asFoldingRange(span: tsp.OutliningSpan, document: LspDocument): lsp.FoldingRange | undefined; | ||
protected asRange(span: tsp.TextSpan): lsp.Range; | ||
protected asFoldingRangeKind(span: tsp.OutliningSpan): lsp.FoldingRangeKind | undefined; | ||
protected onTsEvent(event: protocol.Event): void; | ||
} | ||
//# sourceMappingURL=lsp-server.d.ts.map |
@@ -18,3 +18,3 @@ "use strict"; | ||
const lsp = require("vscode-languageserver"); | ||
const fs = require("fs"); | ||
const fs = require("fs-extra"); | ||
const commandExists = require("command-exists"); | ||
@@ -26,6 +26,10 @@ const logger_1 = require("./logger"); | ||
const protocol_translation_1 = require("./protocol-translation"); | ||
const protocol_translation_2 = require("./protocol-translation"); | ||
const utils_1 = require("./utils"); | ||
const document_1 = require("./document"); | ||
exports.WORKSPACE_EDIT_COMMAND = "workspace-edit"; | ||
const completion_1 = require("./completion"); | ||
const hover_1 = require("./hover"); | ||
const commands_1 = require("./commands"); | ||
const quickfix_1 = require("./quickfix"); | ||
const refactor_1 = require("./refactor"); | ||
const organize_imports_1 = require("./organize-imports"); | ||
class LspServer { | ||
@@ -83,2 +87,7 @@ constructor(options) { | ||
this.tspClient.start(); | ||
this.tspClient.request("configure" /* Configure */, { | ||
preferences: { | ||
allowTextChangesInNewFiles: true | ||
} | ||
}); | ||
this.initializeResult = { | ||
@@ -88,3 +97,3 @@ capabilities: { | ||
completionProvider: { | ||
triggerCharacters: ['.'], | ||
triggerCharacters: ['.', '"', '\'', '/', '@', '<'], | ||
resolveProvider: true | ||
@@ -98,3 +107,9 @@ }, | ||
executeCommandProvider: { | ||
commands: [exports.WORKSPACE_EDIT_COMMAND] | ||
commands: [ | ||
commands_1.Commands.APPLY_WORKSPACE_EDIT, | ||
commands_1.Commands.APPLY_CODE_ACTION, | ||
commands_1.Commands.APPLY_REFACTORING, | ||
commands_1.Commands.ORGANIZE_IMPORTS, | ||
commands_1.Commands.APPLY_RENAME_FILE | ||
] | ||
}, | ||
@@ -105,3 +120,3 @@ hoverProvider: true, | ||
signatureHelpProvider: { | ||
triggerCharacters: ['(', ','] | ||
triggerCharacters: ['(', ',', '<'] | ||
}, | ||
@@ -118,18 +133,48 @@ workspaceSymbolProvider: true, | ||
} | ||
interuptDiagnostics(f) { | ||
if (!this.diagnosticsTokenSource) { | ||
return f(); | ||
} | ||
this.cancelDiagnostics(); | ||
const result = f(); | ||
this.requestDiagnostics(); | ||
return result; | ||
} | ||
requestDiagnostics() { | ||
const files = []; | ||
// sort by least recently usage | ||
const orderedUris = [...this.openedDocumentUris.entries()].sort((a, b) => a[1].lastAccessed - b[1].lastAccessed).map(e => e[0]); | ||
for (const uri of orderedUris) { | ||
files.push(protocol_translation_2.uriToPath(uri)); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.cancelDiagnostics(); | ||
const geterrTokenSource = new lsp.CancellationTokenSource(); | ||
this.diagnosticsTokenSource = geterrTokenSource; | ||
const files = []; | ||
// sort by least recently usage | ||
const orderedUris = [...this.openedDocumentUris.entries()].sort((a, b) => a[1].lastAccessed - b[1].lastAccessed).map(e => e[0]); | ||
for (const uri of orderedUris) { | ||
files.push(protocol_translation_1.uriToPath(uri)); | ||
} | ||
const args = { | ||
delay: 0, | ||
files: files | ||
}; | ||
try { | ||
return yield this.tspClient.request("geterr" /* Geterr */, args, this.diagnosticsTokenSource.token); | ||
} | ||
finally { | ||
if (this.diagnosticsTokenSource === geterrTokenSource) { | ||
this.diagnosticsTokenSource = undefined; | ||
} | ||
} | ||
}); | ||
} | ||
cancelDiagnostics() { | ||
if (this.diagnosticsTokenSource) { | ||
this.diagnosticsTokenSource.cancel(); | ||
this.diagnosticsTokenSource = undefined; | ||
} | ||
const args = { | ||
delay: 0, | ||
files: files | ||
}; | ||
return this.tspClient.request("geterr" /* Geterr */, args); | ||
} | ||
didOpenTextDocument(params) { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('onDidOpenTextDocument', params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('onDidOpenTextDocument', params, file); | ||
if (!file) { | ||
return; | ||
} | ||
if (this.openedDocumentUris.get(params.textDocument.uri) !== undefined) { | ||
@@ -148,3 +193,3 @@ this.logger.log(`Cannot open already opened doc '${params.textDocument.uri}'.`); | ||
this.tspClient.notify("open" /* Open */, { | ||
file: path, | ||
file, | ||
fileContent: params.textDocument.text, | ||
@@ -168,5 +213,8 @@ scriptKindName: this.getScriptKindName(params.textDocument.languageId), | ||
didCloseTextDocument(params) { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('onDidCloseTextDocument', params, path); | ||
this.tspClient.notify("close" /* Close */, { file: path }); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('onDidCloseTextDocument', params, file); | ||
if (!file) { | ||
return; | ||
} | ||
this.tspClient.notify("close" /* Close */, { file }); | ||
this.openedDocumentUris.delete(params.textDocument.uri); | ||
@@ -181,4 +229,7 @@ // We won't be updating diagnostics anymore for that file, so clear them | ||
didChangeTextDocument(params) { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('onDidChangeTextDocument', params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('onDidChangeTextDocument', params, file); | ||
if (!file) { | ||
return; | ||
} | ||
const document = this.openedDocumentUris.get(params.textDocument.uri); | ||
@@ -206,3 +257,3 @@ if (!document) { | ||
this.tspClient.notify("change" /* Change */, { | ||
file: path, | ||
file, | ||
line, | ||
@@ -247,10 +298,13 @@ offset, | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log(type, params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log(type, params, file); | ||
if (!file) { | ||
return []; | ||
} | ||
const result = yield this.tspClient.request(type, { | ||
file: path, | ||
file, | ||
line: params.position.line + 1, | ||
offset: params.position.character + 1 | ||
}); | ||
return result.body ? result.body.map(fileSpan => protocol_translation_2.toLocation(fileSpan)) : []; | ||
return result.body ? result.body.map(fileSpan => protocol_translation_1.toLocation(fileSpan)) : []; | ||
}); | ||
@@ -260,6 +314,9 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('symbol', params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('symbol', params, file); | ||
if (!file) { | ||
return []; | ||
} | ||
const response = yield this.tspClient.request("navtree" /* NavTree */, { | ||
file: path | ||
file | ||
}); | ||
@@ -274,3 +331,3 @@ if (!response.body) { | ||
if (start && end) { | ||
const symbol = lsp.SymbolInformation.create(element.text, protocol_translation_2.toSymbolKind(element.kind), { start: protocol_translation_2.toPosition(start.start), end: protocol_translation_2.toPosition(end.end) }, params.textDocument.uri, parent); | ||
const symbol = lsp.SymbolInformation.create(element.text, protocol_translation_1.toSymbolKind(element.kind), { start: protocol_translation_1.toPosition(start.start), end: protocol_translation_1.toPosition(end.end) }, params.textDocument.uri, parent); | ||
acceptor(symbol); | ||
@@ -288,30 +345,26 @@ } | ||
} | ||
/* | ||
* implemented based on | ||
* https://github.com/Microsoft/vscode/blob/master/extensions/typescript-language-features/src/features/completions.ts | ||
*/ | ||
completion(params) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('completion', params, path); | ||
const result = yield this.tspClient.request("completions" /* Completions */, { | ||
file: path, | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('completion', params, file); | ||
if (!file) { | ||
return []; | ||
} | ||
const document = this.openedDocumentUris.get(params.textDocument.uri); | ||
if (!document) { | ||
throw new Error("The document should be opened for completion, file: " + file); | ||
} | ||
const result = yield this.interuptDiagnostics(() => this.tspClient.request("completions" /* Completions */, { | ||
file, | ||
line: params.position.line + 1, | ||
offset: params.position.character + 1, | ||
prefix: '', | ||
includeExternalModuleExports: true, | ||
includeInsertTextCompletions: true | ||
}); | ||
return { | ||
isIncomplete: false, | ||
items: result.body ? result.body | ||
.map(item => { | ||
return { | ||
label: item.name, | ||
kind: protocol_translation_2.completionKindsMapping[item.kind], | ||
// store information for resolve | ||
data: { | ||
file: path, | ||
line: params.position.line + 1, | ||
offset: params.position.character + 1 | ||
} | ||
}; | ||
}) : [] | ||
}; | ||
})); | ||
const body = result.body || []; | ||
return body.map(entry => completion_1.asCompletionItem(entry, file, params.position, document)); | ||
}); | ||
@@ -322,15 +375,8 @@ } | ||
this.logger.log('completion/resolve', item); | ||
const result = yield this.tspClient.request("completionEntryDetails" /* CompletionDetails */, { | ||
entryNames: [item.label], | ||
file: item.data.file, | ||
line: item.data.line, | ||
offset: item.data.offset, | ||
}); | ||
if (!result.body) { | ||
const { body } = yield this.interuptDiagnostics(() => this.tspClient.request("completionEntryDetails" /* CompletionDetails */, item.data)); | ||
const details = body && body.length && body[0]; | ||
if (!details) { | ||
return item; | ||
} | ||
if (result.body[0] && result.body[0].documentation) { | ||
item.documentation = result.body[0].documentation.map(i => i.text).join('\n'); | ||
} | ||
return item; | ||
return completion_1.asResolvedCompletionItem(item, details); | ||
}); | ||
@@ -340,32 +386,17 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('hover', params, path); | ||
let result; | ||
try { | ||
result = yield this.tspClient.request("quickinfo" /* Quickinfo */, { | ||
file: path, | ||
line: params.position.line + 1, | ||
offset: params.position.character + 1 | ||
}); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('hover', params, file); | ||
if (!file) { | ||
return { contents: [] }; | ||
} | ||
catch (err) { | ||
return { | ||
contents: [] | ||
}; | ||
const result = yield this.interuptDiagnostics(() => this.getQuickInfo(file, params.position)); | ||
if (!result || !result.body) { | ||
return { contents: [] }; | ||
} | ||
if (!result.body) { | ||
return { | ||
contents: [] | ||
}; | ||
} | ||
const range = { | ||
start: protocol_translation_2.toPosition(result.body.start), | ||
end: protocol_translation_2.toPosition(result.body.end) | ||
}; | ||
const range = protocol_translation_1.asRange(result.body); | ||
const contents = [ | ||
{ language: 'typescript', value: result.body.displayString } | ||
]; | ||
if (result.body.documentation) { | ||
contents.push(result.body.documentation); | ||
} | ||
const tags = protocol_translation_1.asTagsDocumentation(result.body.tags); | ||
contents.push(result.body.documentation + (tags ? '\n\n' + tags : '')); | ||
return { | ||
@@ -377,20 +408,37 @@ contents, | ||
} | ||
getQuickInfo(file, position) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
return yield this.tspClient.request("quickinfo" /* Quickinfo */, { | ||
file, | ||
line: position.line + 1, | ||
offset: position.character + 1 | ||
}); | ||
} | ||
catch (err) { | ||
return undefined; | ||
} | ||
}); | ||
} | ||
rename(params) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('onRename', params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('onRename', params, file); | ||
if (!file) { | ||
return undefined; | ||
} | ||
const result = yield this.tspClient.request("rename" /* Rename */, { | ||
file: path, | ||
file, | ||
line: params.position.line + 1, | ||
offset: params.position.character + 1 | ||
}); | ||
if (!result.body || !result.body.info.canRename || result.body.locs.length === 0) { | ||
return undefined; | ||
} | ||
const workspaceEdit = { | ||
changes: {} | ||
}; | ||
if (!result.body || !result.body.info.canRename || result.body.locs.length === 0) { | ||
return workspaceEdit; | ||
} | ||
result.body.locs | ||
.forEach((spanGroup) => { | ||
const uri = protocol_translation_2.pathToUri(spanGroup.file), textEdits = workspaceEdit.changes[uri] || (workspaceEdit.changes[uri] = []); | ||
const uri = protocol_translation_1.pathToUri(spanGroup.file), textEdits = workspaceEdit.changes[uri] || (workspaceEdit.changes[uri] = []); | ||
spanGroup.locs.forEach((textSpan) => { | ||
@@ -400,4 +448,4 @@ textEdits.push({ | ||
range: { | ||
start: protocol_translation_2.toPosition(textSpan.start), | ||
end: protocol_translation_2.toPosition(textSpan.end) | ||
start: protocol_translation_1.toPosition(textSpan.start), | ||
end: protocol_translation_1.toPosition(textSpan.end) | ||
} | ||
@@ -412,6 +460,9 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('onReferences', params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('onReferences', params, file); | ||
if (!file) { | ||
return []; | ||
} | ||
const result = yield this.tspClient.request("references" /* References */, { | ||
file: path, | ||
file, | ||
line: params.position.line + 1, | ||
@@ -424,3 +475,3 @@ offset: params.position.character + 1 | ||
return result.body.refs | ||
.map(fileSpan => protocol_translation_2.toLocation(fileSpan)); | ||
.map(fileSpan => protocol_translation_1.toLocation(fileSpan)); | ||
}); | ||
@@ -430,4 +481,7 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('documentFormatting', params, path); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('documentFormatting', params, file); | ||
if (!file) { | ||
return []; | ||
} | ||
let opts = Object.assign({}, params.options); | ||
@@ -452,3 +506,3 @@ // translate | ||
const response = yield this.tspClient.request("format" /* Format */, { | ||
file: path, | ||
file, | ||
line: 1, | ||
@@ -461,3 +515,3 @@ offset: 1, | ||
if (response.body) { | ||
return response.body.map(e => protocol_translation_2.toTextEdit(e)); | ||
return response.body.map(e => protocol_translation_1.toTextEdit(e)); | ||
} | ||
@@ -469,103 +523,177 @@ return []; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const path = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
this.logger.log('signatureHelp', params, path); | ||
const response = yield this.tspClient.request("signatureHelp" /* SignatureHelp */, { | ||
file: path, | ||
line: params.position.line + 1, | ||
offset: params.position.character + 1 | ||
}); | ||
if (!response.body) { | ||
return { | ||
signatures: [], | ||
activeSignature: null, | ||
activeParameter: null | ||
}; | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('signatureHelp', params, file); | ||
if (!file) { | ||
return undefined; | ||
} | ||
const response = yield yield this.interuptDiagnostics(() => this.getSignatureHelp(file, params.position)); | ||
if (!response || !response.body) { | ||
return undefined; | ||
} | ||
const info = response.body; | ||
const signatures = []; | ||
let activeSignature = response.body.selectedItemIndex; | ||
let activeParameter = response.body.argumentIndex; | ||
response.body.items.forEach((item, i) => { | ||
// keep active parameter in bounds | ||
if (i === info.selectedItemIndex && item.isVariadic) { | ||
activeParameter = Math.min(info.argumentIndex, item.parameters.length - 1); | ||
} | ||
let label = protocol_translation_2.toPlainText(item.prefixDisplayParts); | ||
const parameters = []; | ||
item.parameters.forEach((p, i, a) => { | ||
const parameter = lsp.ParameterInformation.create(protocol_translation_2.toPlainText(p.displayParts), protocol_translation_2.toPlainText(p.documentation)); | ||
label += parameter.label; | ||
parameters.push(parameter); | ||
if (i < a.length - 1) { | ||
label += protocol_translation_2.toPlainText(item.separatorDisplayParts); | ||
} | ||
}); | ||
label += protocol_translation_2.toPlainText(item.suffixDisplayParts); | ||
const documentation = protocol_translation_2.toMarkDown(item.documentation, item.tags); | ||
signatures.push({ | ||
label, | ||
documentation, | ||
parameters | ||
}); | ||
}); | ||
return { | ||
signatures, | ||
activeSignature, | ||
activeParameter | ||
}; | ||
return hover_1.asSignatureHelp(response.body); | ||
}); | ||
} | ||
codeAction(arg) { | ||
getSignatureHelp(file, position) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.logger.log('codeAction', arg); | ||
let response; | ||
try { | ||
response = yield this.tspClient.request("getCodeFixes" /* GetCodeFixes */, { | ||
file: protocol_translation_2.uriToPath(arg.textDocument.uri), | ||
startLine: arg.range.start.line + 1, | ||
startOffset: arg.range.start.character + 1, | ||
endLine: arg.range.end.line + 1, | ||
endOffset: arg.range.end.character + 1, | ||
errorCodes: arg.context.diagnostics.map(d => d.code) | ||
return yield this.tspClient.request("signatureHelp" /* SignatureHelp */, { | ||
file, | ||
line: position.line + 1, | ||
offset: position.character + 1 | ||
}); | ||
} | ||
catch (err) { | ||
return []; | ||
return undefined; | ||
} | ||
if (!response.body) { | ||
}); | ||
} | ||
codeAction(params) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('codeAction', params, file); | ||
if (!file) { | ||
return []; | ||
} | ||
const result = []; | ||
for (const fix of response.body) { | ||
result.push({ | ||
title: fix.description, | ||
command: exports.WORKSPACE_EDIT_COMMAND, | ||
arguments: [{ | ||
documentChanges: fix.changes.map(c => protocol_translation_2.toTextDocumentEdit(c)) | ||
}] | ||
const args = protocol_translation_1.toFileRangeRequestArgs(file, params.range); | ||
const codeActions = []; | ||
const errorCodes = params.context.diagnostics.map(diagnostic => Number(diagnostic.code)); | ||
quickfix_1.provideQuickFix(yield this.getCodeFixes(Object.assign({}, args, { errorCodes })), codeActions); | ||
refactor_1.provideRefactors(yield this.getRefactors(args), codeActions, args); | ||
organize_imports_1.provideOrganizeImports(file, params.context, codeActions); | ||
return codeActions; | ||
}); | ||
} | ||
getCodeFixes(args) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
return yield this.tspClient.request("getCodeFixes" /* GetCodeFixes */, args); | ||
} | ||
catch (err) { | ||
return undefined; | ||
} | ||
}); | ||
} | ||
getRefactors(args) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
return yield this.tspClient.request("getApplicableRefactors" /* GetApplicableRefactors */, args); | ||
} | ||
catch (err) { | ||
return undefined; | ||
} | ||
}); | ||
} | ||
executeCommand(arg) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.logger.log('executeCommand', arg); | ||
if (arg.command === commands_1.Commands.APPLY_WORKSPACE_EDIT && arg.arguments) { | ||
const edit = arg.arguments[0]; | ||
yield this.options.lspClient.applyWorkspaceEdit({ | ||
edit | ||
}); | ||
} | ||
return result; | ||
else if (arg.command === commands_1.Commands.APPLY_CODE_ACTION && arg.arguments) { | ||
const codeAction = arg.arguments[0]; | ||
if (!(yield this.applyFileCodeEdits(codeAction.changes))) { | ||
return; | ||
} | ||
if (codeAction.commands && codeAction.commands.length) { | ||
for (const command of codeAction.commands) { | ||
yield this.tspClient.request("applyCodeActionCommand" /* ApplyCodeActionCommand */, { command }); | ||
} | ||
} | ||
} | ||
else if (arg.command === commands_1.Commands.APPLY_REFACTORING && arg.arguments) { | ||
const args = arg.arguments[0]; | ||
const { body } = yield this.tspClient.request("getEditsForRefactor" /* GetEditsForRefactor */, args); | ||
if (!body || !body.edits.length) { | ||
return; | ||
} | ||
for (const edit of body.edits) { | ||
yield fs.ensureFile(edit.fileName); | ||
} | ||
if (!(yield this.applyFileCodeEdits(body.edits))) { | ||
return; | ||
} | ||
const renameLocation = body.renameLocation; | ||
if (renameLocation) { | ||
yield this.options.lspClient.rename({ | ||
textDocument: { | ||
uri: protocol_translation_1.pathToUri(args.file) | ||
}, | ||
position: protocol_translation_1.toPosition(renameLocation) | ||
}); | ||
} | ||
} | ||
else if (arg.command === commands_1.Commands.ORGANIZE_IMPORTS && arg.arguments) { | ||
const file = arg.arguments[0]; | ||
const { body } = yield this.tspClient.request("organizeImports" /* OrganizeImports */, { | ||
scope: { | ||
type: 'file', | ||
args: { file } | ||
} | ||
}); | ||
yield this.applyFileCodeEdits(body); | ||
} | ||
if (arg.command === commands_1.Commands.APPLY_RENAME_FILE && arg.arguments) { | ||
const { sourceUri, targetUri } = arg.arguments[0]; | ||
this.applyRenameFile(sourceUri, targetUri); | ||
} | ||
else { | ||
this.logger.error(`Unknown command ${arg.command}.`); | ||
} | ||
}); | ||
} | ||
executeCommand(arg) { | ||
this.logger.log('executeCommand', arg); | ||
if (arg.command === exports.WORKSPACE_EDIT_COMMAND && arg.arguments) { | ||
const edit = arg.arguments[0]; | ||
this.options.lspClient.applyWorkspaceEdit({ | ||
edit | ||
applyFileCodeEdits(edits) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!edits.length) { | ||
return false; | ||
} | ||
const changes = {}; | ||
for (const edit of edits) { | ||
changes[protocol_translation_1.pathToUri(edit.fileName)] = edit.textChanges.map(protocol_translation_1.toTextEdit); | ||
} | ||
const { applied } = yield this.options.lspClient.applyWorkspaceEdit({ | ||
edit: { changes } | ||
}); | ||
} | ||
else { | ||
this.logger.error(`Unknown command ${arg.command}.`); | ||
} | ||
return applied; | ||
}); | ||
} | ||
applyRenameFile(sourceUri, targetUri) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const edits = yield this.getEditsForFileRename(sourceUri, targetUri); | ||
this.applyFileCodeEdits(edits); | ||
}); | ||
} | ||
getEditsForFileRename(sourceUri, targetUri) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const newFilePath = protocol_translation_1.uriToPath(targetUri); | ||
const oldFilePath = protocol_translation_1.uriToPath(sourceUri); | ||
if (!newFilePath || !oldFilePath) { | ||
return []; | ||
} | ||
try { | ||
const { body } = yield this.tspClient.request("getEditsForFileRename" /* GetEditsForFileRename */, { | ||
oldFilePath, | ||
newFilePath | ||
}); | ||
return body; | ||
} | ||
catch (err) { | ||
return []; | ||
} | ||
}); | ||
} | ||
documentHighlight(arg) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.logger.log('documentHighlight', arg); | ||
const file = protocol_translation_1.uriToPath(arg.textDocument.uri); | ||
this.logger.log('documentHighlight', arg, file); | ||
if (!file) { | ||
return []; | ||
} | ||
let response; | ||
const file = protocol_translation_2.uriToPath(arg.textDocument.uri); | ||
try { | ||
response = yield this.tspClient.request("documentHighlights" /* DocumentHighlights */, { | ||
file: file, | ||
file, | ||
line: arg.position.line + 1, | ||
@@ -593,7 +721,7 @@ offset: arg.position.character + 1, | ||
rootPath() { | ||
return this.initializeParams.rootUri ? protocol_translation_2.uriToPath(this.initializeParams.rootUri) : this.initializeParams.rootPath; | ||
return this.initializeParams.rootUri ? protocol_translation_1.uriToPath(this.initializeParams.rootUri) : this.initializeParams.rootPath; | ||
} | ||
lastFileOrDummy() { | ||
for (const uri of this.openedDocumentUris.keys()) { | ||
return protocol_translation_2.uriToPath(uri); | ||
return protocol_translation_1.uriToPath(uri); | ||
} | ||
@@ -614,9 +742,9 @@ return this.rootPath(); | ||
location: { | ||
uri: protocol_translation_2.pathToUri(item.file), | ||
uri: protocol_translation_1.pathToUri(item.file), | ||
range: { | ||
start: protocol_translation_2.toPosition(item.start), | ||
end: protocol_translation_2.toPosition(item.end) | ||
start: protocol_translation_1.toPosition(item.start), | ||
end: protocol_translation_1.toPosition(item.end) | ||
} | ||
}, | ||
kind: protocol_translation_2.toSymbolKind(item.kind), | ||
kind: protocol_translation_1.toSymbolKind(item.kind), | ||
name: item.name | ||
@@ -632,4 +760,7 @@ }; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const file = protocol_translation_2.uriToPath(params.textDocument.uri); | ||
const file = protocol_translation_1.uriToPath(params.textDocument.uri); | ||
this.logger.log('foldingRanges', params, file); | ||
if (!file) { | ||
return undefined; | ||
} | ||
const document = this.openedDocumentUris.get(params.textDocument.uri); | ||
@@ -654,3 +785,3 @@ if (!document) { | ||
asFoldingRange(span, document) { | ||
const range = this.asRange(span.textSpan); | ||
const range = protocol_translation_1.asRange(span.textSpan); | ||
const kind = this.asFoldingRangeKind(span); | ||
@@ -673,5 +804,2 @@ // workaround for https://github.com/Microsoft/vscode/issues/49904 | ||
} | ||
asRange(span) { | ||
return lsp.Range.create(Math.max(0, span.start.line - 1), Math.max(span.start.offset - 1, 0), Math.max(0, span.end.line - 1), Math.max(0, span.end.offset - 1)); | ||
} | ||
asFoldingRangeKind(span) { | ||
@@ -687,8 +815,7 @@ switch (span.kind) { | ||
onTsEvent(event) { | ||
if (event.event === "semanticDiag" /* SementicDiag */) { | ||
this.diagnosticQueue.addSemanticDiagnostic(event); | ||
if (event.event === "semanticDiag" /* SementicDiag */ || | ||
event.event === "syntaxDiag" /* SyntaxDiag */ || | ||
event.event === "suggestionDiag" /* SuggestionDiag */) { | ||
this.diagnosticQueue.updateDiagnostics(event.event, event); | ||
} | ||
else if (event.event === "syntaxDiag" /* SyntaxDiag */) { | ||
this.diagnosticQueue.addSyntacticDiagnostic(event); | ||
} | ||
else { | ||
@@ -695,0 +822,0 @@ this.logger.log("Ignored event", { |
export {}; | ||
//# sourceMappingURL=lsp-server.spec.d.ts.map |
@@ -53,6 +53,6 @@ "use strict"; | ||
}); | ||
assert.isTrue(proposals.items.length > 800); | ||
const item = proposals.items.filter(i => i.label === 'addEventListener')[0]; | ||
assert.isTrue(proposals.length > 800, String(proposals.length)); | ||
const item = proposals.filter(i => i.label === 'addEventListener')[0]; | ||
const resolvedItem = yield server.completionResolve(item); | ||
assert.isTrue(resolvedItem.documentation !== undefined); | ||
assert.isTrue(resolvedItem.detail !== undefined, JSON.stringify(resolvedItem, undefined, 2)); | ||
server.didCloseTextDocument({ | ||
@@ -80,2 +80,3 @@ textDocument: doc | ||
yield server.requestDiagnostics(); | ||
yield new Promise(resolve => setTimeout(resolve, 200)); | ||
const diags = diagnostics.diagnostics; | ||
@@ -142,2 +143,3 @@ assert.equal(1, diags.length); | ||
yield server.requestDiagnostics(); | ||
yield new Promise(resolve => setTimeout(resolve, 200)); | ||
const diags = diagnostics.diagnostics; | ||
@@ -215,11 +217,11 @@ assert.isTrue(diags.length >= 1, diags.map(d => d.message).join(',')); | ||
}); | ||
let result = yield server.signatureHelp({ | ||
let result = (yield server.signatureHelp({ | ||
textDocument: doc, | ||
position: test_utils_1.position(doc, 'param1') | ||
}); | ||
})); | ||
assert.equal('bar: string', result.signatures[result.activeSignature].parameters[result.activeParameter].label); | ||
result = yield server.signatureHelp({ | ||
result = (yield server.signatureHelp({ | ||
textDocument: doc, | ||
position: test_utils_1.position(doc, 'param2') | ||
}); | ||
})); | ||
assert.equal('baz?: boolean', result.signatures[result.activeSignature].parameters[result.activeParameter].label); | ||
@@ -226,0 +228,0 @@ })).timeout(10000); |
export declare function findPathToModule(dir: string, moduleName: string): string | undefined; | ||
//# sourceMappingURL=modules-resolver.d.ts.map |
export {}; | ||
//# sourceMappingURL=modules-resolver.spec.d.ts.map |
@@ -15,5 +15,5 @@ "use strict"; | ||
const tsserverPath = modules_resolver_1.findPathToModule(__dirname, 'typescript/bin/tsserver'); | ||
chai.assert.equal(path.resolve(__dirname, '../node_modules/typescript/bin/tsserver'), tsserverPath); | ||
chai.assert.equal(path.resolve(__dirname, '../../node_modules/typescript/bin/tsserver'), tsserverPath); | ||
}); | ||
}); | ||
//# sourceMappingURL=modules-resolver.spec.js.map |
import * as lsp from 'vscode-languageserver'; | ||
import * as tsp from 'typescript/lib/protocol'; | ||
export declare function uriToPath(stringUri: string): string; | ||
export declare function uriToPath(stringUri: string): string | undefined; | ||
export declare function pathToUri(p: string): string; | ||
export declare function toPosition(location: tsp.Location): lsp.Position; | ||
export declare function toLocation(fileSpan: tsp.FileSpan): lsp.Location; | ||
export declare const completionKindsMapping: { | ||
[name: string]: lsp.CompletionItemKind; | ||
}; | ||
export declare function toFileRangeRequestArgs(file: string, range: lsp.Range): tsp.FileRangeRequestArgs; | ||
export declare function toSymbolKind(tspKind: string): lsp.SymbolKind; | ||
export declare function toDiagnosticSeverity(category: string): lsp.DiagnosticSeverity; | ||
export declare function toDiagnostic(tspDiag: tsp.Diagnostic): lsp.Diagnostic; | ||
export declare function toDiagnostic(diagnostic: tsp.Diagnostic): lsp.Diagnostic; | ||
export declare function asRelatedInformation(info: tsp.DiagnosticRelatedInformation[] | undefined): lsp.DiagnosticRelatedInformation[] | undefined; | ||
export declare function toTextEdit(edit: tsp.CodeEdit): lsp.TextEdit; | ||
export declare function toPlainText(parts: tsp.SymbolDisplayPart[]): string; | ||
export declare function toMarkDown(documentation: tsp.SymbolDisplayPart[], tags: tsp.JSDocTagInfo[]): string; | ||
export declare function toTextDocumentEdit(change: tsp.FileCodeEdits): lsp.TextDocumentEdit; | ||
export declare function toDocumentHighlight(item: tsp.DocumentHighlightsItem): lsp.DocumentHighlight[]; | ||
export declare function asRange(span: tsp.TextSpan): lsp.Range; | ||
export declare function asDocumentation(data: { | ||
documentation?: tsp.SymbolDisplayPart[]; | ||
tags?: tsp.JSDocTagInfo[]; | ||
}): lsp.MarkupContent | undefined; | ||
export declare function asTagsDocumentation(tags: tsp.JSDocTagInfo[]): string; | ||
export declare function asTagDocumentation(tag: tsp.JSDocTagInfo): string; | ||
export declare function asTagBodyText(tag: tsp.JSDocTagInfo): string | undefined; | ||
export declare function asPlainText(parts: undefined): undefined; | ||
export declare function asPlainText(parts: tsp.SymbolDisplayPart[]): string; | ||
export declare function asPlainText(parts: tsp.SymbolDisplayPart[] | undefined): string | undefined; | ||
//# sourceMappingURL=protocol-translation.d.ts.map |
@@ -15,3 +15,3 @@ "use strict"; | ||
if (uri.scheme !== 'file') { | ||
throw new Error(`The Typescript Language Server only supports file-scheme URIs. Received "${stringUri}"`); | ||
return undefined; | ||
} | ||
@@ -42,21 +42,13 @@ return uri.fsPath; | ||
exports.toLocation = toLocation; | ||
exports.completionKindsMapping = { | ||
class: lsp.CompletionItemKind.Class, | ||
constructor: lsp.CompletionItemKind.Constructor, | ||
enum: lsp.CompletionItemKind.Enum, | ||
field: lsp.CompletionItemKind.Field, | ||
file: lsp.CompletionItemKind.File, | ||
function: lsp.CompletionItemKind.Function, | ||
interface: lsp.CompletionItemKind.Interface, | ||
keyword: lsp.CompletionItemKind.Keyword, | ||
method: lsp.CompletionItemKind.Method, | ||
module: lsp.CompletionItemKind.Module, | ||
property: lsp.CompletionItemKind.Property, | ||
reference: lsp.CompletionItemKind.Reference, | ||
snippet: lsp.CompletionItemKind.Snippet, | ||
text: lsp.CompletionItemKind.Text, | ||
unit: lsp.CompletionItemKind.Unit, | ||
value: lsp.CompletionItemKind.Value, | ||
variable: lsp.CompletionItemKind.Variable | ||
}; | ||
function toFileRangeRequestArgs(file, range) { | ||
return { | ||
file, | ||
startLine: range.start.line + 1, | ||
startOffset: range.start.character + 1, | ||
endLine: range.end.line + 1, | ||
endOffset: range.end.character + 1 | ||
}; | ||
} | ||
exports.toFileRangeRequestArgs = toFileRangeRequestArgs; | ||
; | ||
const symbolKindsMapping = { | ||
@@ -95,19 +87,35 @@ 'enum member': lsp.SymbolKind.Constant, | ||
case 'warning': return lsp.DiagnosticSeverity.Warning; | ||
default: return lsp.DiagnosticSeverity.Information; | ||
case 'suggestion': return lsp.DiagnosticSeverity.Hint; | ||
default: return lsp.DiagnosticSeverity.Error; | ||
} | ||
} | ||
exports.toDiagnosticSeverity = toDiagnosticSeverity; | ||
function toDiagnostic(tspDiag) { | ||
function toDiagnostic(diagnostic) { | ||
return { | ||
range: { | ||
start: toPosition(tspDiag.start), | ||
end: toPosition(tspDiag.end) | ||
start: toPosition(diagnostic.start), | ||
end: toPosition(diagnostic.end) | ||
}, | ||
message: tspDiag.text, | ||
severity: toDiagnosticSeverity(tspDiag.category), | ||
code: tspDiag.code, | ||
source: 'typescript' | ||
message: diagnostic.text, | ||
severity: toDiagnosticSeverity(diagnostic.category), | ||
code: diagnostic.code, | ||
source: diagnostic.source || 'typescript', | ||
relatedInformation: asRelatedInformation(diagnostic.relatedInformation) | ||
}; | ||
} | ||
exports.toDiagnostic = toDiagnostic; | ||
function asRelatedInformation(info) { | ||
if (!info) { | ||
return undefined; | ||
} | ||
const result = []; | ||
for (const item of info) { | ||
const span = item.span; | ||
if (span) { | ||
result.push(lsp.DiagnosticRelatedInformation.create(toLocation(span), item.message)); | ||
} | ||
} | ||
return result; | ||
} | ||
exports.asRelatedInformation = asRelatedInformation; | ||
function toTextEdit(edit) { | ||
@@ -123,6 +131,2 @@ return { | ||
exports.toTextEdit = toTextEdit; | ||
function toPlainText(parts) { | ||
return parts.map(part => part.text).join(''); | ||
} | ||
exports.toPlainText = toPlainText; | ||
function tagsMarkdownPreview(tags) { | ||
@@ -141,3 +145,3 @@ return (tags || []) | ||
let result = ""; | ||
result += toPlainText(documentation); | ||
result += asPlainText(documentation); | ||
const tagsPreview = tagsMarkdownPreview(tags); | ||
@@ -188,2 +192,74 @@ if (tagsPreview) { | ||
} | ||
function asRange(span) { | ||
return lsp.Range.create(Math.max(0, span.start.line - 1), Math.max(span.start.offset - 1, 0), Math.max(0, span.end.line - 1), Math.max(0, span.end.offset - 1)); | ||
} | ||
exports.asRange = asRange; | ||
function asDocumentation(data) { | ||
let value = ''; | ||
const documentation = asPlainText(data.documentation); | ||
if (documentation) { | ||
value += documentation; | ||
} | ||
if (data.tags) { | ||
const tagsDocumentation = asTagsDocumentation(data.tags); | ||
if (tagsDocumentation) { | ||
value += '\n\n' + tagsDocumentation; | ||
} | ||
} | ||
return value.length ? { | ||
kind: lsp.MarkupKind.Markdown, | ||
value | ||
} : undefined; | ||
} | ||
exports.asDocumentation = asDocumentation; | ||
function asTagsDocumentation(tags) { | ||
return tags.map(asTagDocumentation).join(' \n\n'); | ||
} | ||
exports.asTagsDocumentation = asTagsDocumentation; | ||
function asTagDocumentation(tag) { | ||
switch (tag.name) { | ||
case 'param': | ||
const body = (tag.text || '').split(/^([\w\.]+)\s*-?\s*/); | ||
if (body && body.length === 3) { | ||
const param = body[1]; | ||
const doc = body[2]; | ||
const label = `*@${tag.name}* \`${param}\``; | ||
if (!doc) { | ||
return label; | ||
} | ||
return label + (doc.match(/\r\n|\n/g) ? ' \n' + doc : ` — ${doc}`); | ||
} | ||
} | ||
// Generic tag | ||
const label = `*@${tag.name}*`; | ||
const text = asTagBodyText(tag); | ||
if (!text) { | ||
return label; | ||
} | ||
return label + (text.match(/\r\n|\n/g) ? ' \n' + text : ` — ${text}`); | ||
} | ||
exports.asTagDocumentation = asTagDocumentation; | ||
function asTagBodyText(tag) { | ||
if (!tag.text) { | ||
return undefined; | ||
} | ||
switch (tag.name) { | ||
case 'example': | ||
case 'default': | ||
// Convert to markdown code block if it not already one | ||
if (tag.text.match(/^\s*[~`]{3}/g)) { | ||
return tag.text; | ||
} | ||
return '```\n' + tag.text + '\n```'; | ||
} | ||
return tag.text; | ||
} | ||
exports.asTagBodyText = asTagBodyText; | ||
function asPlainText(parts) { | ||
if (!parts) { | ||
return undefined; | ||
} | ||
return parts.map(part => part.text).join(''); | ||
} | ||
exports.asPlainText = asPlainText; | ||
//# sourceMappingURL=protocol-translation.js.map |
@@ -14,1 +14,2 @@ import * as lsp from 'vscode-languageserver'; | ||
}): Promise<LspServer>; | ||
//# sourceMappingURL=test-utils.d.ts.map |
@@ -72,7 +72,4 @@ "use strict"; | ||
}, | ||
applyWorkspaceEdit(args) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
throw new Error('unsupported'); | ||
}); | ||
} | ||
applyWorkspaceEdit: () => Promise.reject(new Error('unsupported')), | ||
rename: () => Promise.reject(new Error('unsupported')) | ||
}, | ||
@@ -79,0 +76,0 @@ }); |
import * as protocol from 'typescript/lib/protocol'; | ||
import { CommandTypes } from './tsp-command-types'; | ||
import { Logger } from './logger'; | ||
import { CancellationToken } from 'vscode-jsonrpc'; | ||
export interface TspClientOptions { | ||
@@ -11,2 +12,35 @@ logger: Logger; | ||
} | ||
interface TypeScriptRequestTypes { | ||
'geterr': [protocol.GeterrRequestArgs, any]; | ||
'documentHighlights': [protocol.DocumentHighlightsRequestArgs, protocol.DocumentHighlightsResponse]; | ||
'applyCodeActionCommand': [protocol.ApplyCodeActionCommandRequestArgs, protocol.ApplyCodeActionCommandResponse]; | ||
'completionEntryDetails': [protocol.CompletionDetailsRequestArgs, protocol.CompletionDetailsResponse]; | ||
'completionInfo': [protocol.CompletionsRequestArgs, protocol.CompletionInfoResponse]; | ||
'completions': [protocol.CompletionsRequestArgs, protocol.CompletionsResponse]; | ||
'configure': [protocol.ConfigureRequestArguments, protocol.ConfigureResponse]; | ||
'definition': [protocol.FileLocationRequestArgs, protocol.DefinitionResponse]; | ||
'definitionAndBoundSpan': [protocol.FileLocationRequestArgs, protocol.DefinitionInfoAndBoundSpanReponse]; | ||
'docCommentTemplate': [protocol.FileLocationRequestArgs, protocol.DocCommandTemplateResponse]; | ||
'format': [protocol.FormatRequestArgs, protocol.FormatResponse]; | ||
'formatonkey': [protocol.FormatOnKeyRequestArgs, protocol.FormatResponse]; | ||
'getApplicableRefactors': [protocol.GetApplicableRefactorsRequestArgs, protocol.GetApplicableRefactorsResponse]; | ||
'getCodeFixes': [protocol.CodeFixRequestArgs, protocol.GetCodeFixesResponse]; | ||
'getCombinedCodeFix': [protocol.GetCombinedCodeFixRequestArgs, protocol.GetCombinedCodeFixResponse]; | ||
'getEditsForFileRename': [protocol.GetEditsForFileRenameRequestArgs, protocol.GetEditsForFileRenameResponse]; | ||
'getEditsForRefactor': [protocol.GetEditsForRefactorRequestArgs, protocol.GetEditsForRefactorResponse]; | ||
'getOutliningSpans': [protocol.FileRequestArgs, protocol.OutliningSpansResponse]; | ||
'getSupportedCodeFixes': [null, protocol.GetSupportedCodeFixesResponse]; | ||
'implementation': [protocol.FileLocationRequestArgs, protocol.ImplementationResponse]; | ||
'jsxClosingTag': [protocol.JsxClosingTagRequestArgs, protocol.JsxClosingTagResponse]; | ||
'navto': [protocol.NavtoRequestArgs, protocol.NavtoResponse]; | ||
'navtree': [protocol.FileRequestArgs, protocol.NavTreeResponse]; | ||
'occurrences': [protocol.FileLocationRequestArgs, protocol.OccurrencesResponse]; | ||
'organizeImports': [protocol.OrganizeImportsRequestArgs, protocol.OrganizeImportsResponse]; | ||
'projectInfo': [protocol.ProjectInfoRequestArgs, protocol.ProjectInfoResponse]; | ||
'quickinfo': [protocol.FileLocationRequestArgs, protocol.QuickInfoResponse]; | ||
'references': [protocol.FileLocationRequestArgs, protocol.ReferencesResponse]; | ||
'rename': [protocol.RenameRequestArgs, protocol.RenameResponse]; | ||
'signatureHelp': [protocol.SignatureHelpRequestArgs, protocol.SignatureHelpResponse]; | ||
'typeDefinition': [protocol.FileLocationRequestArgs, protocol.TypeDefinitionResponse]; | ||
} | ||
export declare class TspClient { | ||
@@ -22,2 +56,3 @@ private options; | ||
private tsserverLogger; | ||
private cancellationPipeName; | ||
constructor(options: TspClientOptions); | ||
@@ -29,22 +64,4 @@ start(): void; | ||
notify(command: CommandTypes.Change, args: protocol.ChangeRequestArgs): any; | ||
request(command: CommandTypes.Configure, args: protocol.ConfigureRequestArguments): Promise<protocol.ConfigureResponse>; | ||
request(command: CommandTypes.Definition, args: protocol.FileLocationRequestArgs): Promise<protocol.DefinitionResponse>; | ||
request(command: CommandTypes.Implementation, args: protocol.FileLocationRequestArgs): Promise<protocol.ImplementationResponse>; | ||
request(command: CommandTypes.TypeDefinition, args: protocol.FileLocationRequestArgs): Promise<protocol.TypeDefinitionResponse>; | ||
request(command: CommandTypes.Format, args: protocol.FormatRequestArgs): Promise<protocol.FormatResponse>; | ||
request(command: CommandTypes.GetApplicableRefactors, args: protocol.CodeFixRequestArgs): Promise<protocol.GetCodeFixesResponse>; | ||
request(command: CommandTypes.GetCodeFixes, args: protocol.CodeFixRequestArgs): Promise<protocol.GetCodeFixesResponse>; | ||
request(command: CommandTypes.Geterr, args: protocol.GeterrRequestArgs): Promise<protocol.RequestCompletedEvent>; | ||
request(command: CommandTypes.GeterrForProject, args: protocol.GeterrForProjectRequestArgs): Promise<protocol.RequestCompletedEvent>; | ||
request(command: CommandTypes.Navto, args: protocol.NavtoRequestArgs): Promise<protocol.NavtoResponse>; | ||
request(command: CommandTypes.NavTree, args: protocol.FileRequestArgs): Promise<protocol.NavTreeResponse>; | ||
request(command: CommandTypes.Completions, args: protocol.CompletionsRequestArgs): Promise<protocol.CompletionsResponse>; | ||
request(command: CommandTypes.CompletionDetails, args: protocol.CompletionDetailsRequestArgs): Promise<protocol.CompletionDetailsResponse>; | ||
request(command: CommandTypes.DocumentHighlights, args: protocol.DocumentHighlightsRequestArgs): Promise<protocol.DocumentHighlightsResponse>; | ||
request(command: CommandTypes.Quickinfo, args: protocol.FileLocationRequestArgs): Promise<protocol.QuickInfoResponse>; | ||
request(command: CommandTypes.Rename, args: protocol.RenameRequestArgs): Promise<protocol.RenameResponse>; | ||
request(command: CommandTypes.References, args: protocol.FileLocationRequestArgs): Promise<protocol.ReferencesResponse>; | ||
request(command: CommandTypes.SignatureHelp, args: protocol.SignatureHelpRequestArgs): Promise<protocol.SignatureHelpResponse>; | ||
request(command: CommandTypes.GetOutliningSpans, args: protocol.FileRequestArgs): Promise<protocol.OutliningSpansResponse>; | ||
protected sendMessage(command: string, notification: boolean, args?: any): Promise<any> | undefined; | ||
request<K extends keyof TypeScriptRequestTypes>(command: K, args: TypeScriptRequestTypes[K][0], token?: CancellationToken): Promise<TypeScriptRequestTypes[K][1]>; | ||
protected sendMessage(command: string, notification: boolean, args?: any): void; | ||
protected processMessage(untrimmedMessageString: string): void; | ||
@@ -56,1 +73,3 @@ private resolveResponse; | ||
} | ||
export {}; | ||
//# sourceMappingURL=tsp-client.d.ts.map |
@@ -9,5 +9,7 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs = require("fs"); | ||
const cp = require("child_process"); | ||
const readline = require("readline"); | ||
const decoder = require("string_decoder"); | ||
const tempy = require("tempy"); | ||
const logger_1 = require("./logger"); | ||
@@ -37,2 +39,4 @@ const utils_1 = require("./utils"); | ||
} | ||
this.cancellationPipeName = tempy.file({ name: 'tscancellation' }); | ||
args.push('--cancellationPipeName', this.cancellationPipeName + '*'); | ||
this.logger.info(`Starting tsserver : '${this.options.tsserverPath} ${args.join(' ')}'`); | ||
@@ -56,4 +60,20 @@ this.tsserverProc = cp.spawn(this.options.tsserverPath, args); | ||
} | ||
request(command, args) { | ||
return this.sendMessage(command, false, args); | ||
request(command, args, token) { | ||
this.sendMessage(command, false, args); | ||
const seq = this.seq; | ||
const request = (this.deferreds[seq] = new utils_1.Deferred(command)).promise; | ||
if (token) { | ||
const onCancelled = token.onCancellationRequested(() => { | ||
onCancelled.dispose(); | ||
if (this.cancellationPipeName) { | ||
const requestCancellationPipeName = this.cancellationPipeName + seq; | ||
fs.writeFile(requestCancellationPipeName, '', err => { | ||
if (!err) { | ||
request.then(() => fs.unlink(requestCancellationPipeName, () => { })); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
return request; | ||
} | ||
@@ -72,10 +92,3 @@ sendMessage(command, notification, args) { | ||
this.tsserverProc.stdin.write(serializedRequest); | ||
if (notification) { | ||
this.logger.log("notify", request); | ||
return; | ||
} | ||
else { | ||
this.logger.log("request", request); | ||
return (this.deferreds[this.seq] = new utils_1.Deferred(command)).promise; | ||
} | ||
this.logger.log(notification ? "notify" : "request", request); | ||
} | ||
@@ -82,0 +95,0 @@ processMessage(untrimmedMessageString) { |
export {}; | ||
//# sourceMappingURL=tsp-client.spec.d.ts.map |
@@ -81,3 +81,74 @@ /** | ||
SementicDiag = "semanticDiag", | ||
SuggestionDiag = "suggestionDiag", | ||
Telemetry = "telemetry" | ||
} | ||
export declare enum ScriptElementKind { | ||
unknown = "", | ||
warning = "warning", | ||
/** predefined type (void) or keyword (class) */ | ||
keyword = "keyword", | ||
/** top level script node */ | ||
scriptElement = "script", | ||
/** module foo {} */ | ||
moduleElement = "module", | ||
/** class X {} */ | ||
classElement = "class", | ||
/** var x = class X {} */ | ||
localClassElement = "local class", | ||
/** interface Y {} */ | ||
interfaceElement = "interface", | ||
/** type T = ... */ | ||
typeElement = "type", | ||
/** enum E */ | ||
enumElement = "enum", | ||
enumMemberElement = "enum member", | ||
/** | ||
* Inside module and script only | ||
* const v = .. | ||
*/ | ||
variableElement = "var", | ||
/** Inside function */ | ||
localVariableElement = "local var", | ||
/** | ||
* Inside module and script only | ||
* function f() { } | ||
*/ | ||
functionElement = "function", | ||
/** Inside function */ | ||
localFunctionElement = "local function", | ||
/** class X { [public|private]* foo() {} } */ | ||
memberFunctionElement = "method", | ||
/** class X { [public|private]* [get|set] foo:number; } */ | ||
memberGetAccessorElement = "getter", | ||
memberSetAccessorElement = "setter", | ||
/** | ||
* class X { [public|private]* foo:number; } | ||
* interface Y { foo:number; } | ||
*/ | ||
memberVariableElement = "property", | ||
/** class X { constructor() { } } */ | ||
constructorImplementationElement = "constructor", | ||
/** interface Y { ():number; } */ | ||
callSignatureElement = "call", | ||
/** interface Y { []:number; } */ | ||
indexSignatureElement = "index", | ||
/** interface Y { new():Y; } */ | ||
constructSignatureElement = "construct", | ||
/** function foo(*Y*: string) */ | ||
parameterElement = "parameter", | ||
typeParameterElement = "type parameter", | ||
primitiveType = "primitive type", | ||
label = "label", | ||
alias = "alias", | ||
constElement = "const", | ||
letElement = "let", | ||
directory = "directory", | ||
externalModuleName = "external module name", | ||
/** | ||
* <JsxTagName attribute1 attribute2={0} /> | ||
*/ | ||
jsxAttribute = "JSX attribute", | ||
/** String literal */ | ||
string = "string" | ||
} | ||
//# sourceMappingURL=tsp-command-types.d.ts.map |
@@ -6,2 +6,72 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ScriptElementKind; | ||
(function (ScriptElementKind) { | ||
ScriptElementKind["unknown"] = ""; | ||
ScriptElementKind["warning"] = "warning"; | ||
/** predefined type (void) or keyword (class) */ | ||
ScriptElementKind["keyword"] = "keyword"; | ||
/** top level script node */ | ||
ScriptElementKind["scriptElement"] = "script"; | ||
/** module foo {} */ | ||
ScriptElementKind["moduleElement"] = "module"; | ||
/** class X {} */ | ||
ScriptElementKind["classElement"] = "class"; | ||
/** var x = class X {} */ | ||
ScriptElementKind["localClassElement"] = "local class"; | ||
/** interface Y {} */ | ||
ScriptElementKind["interfaceElement"] = "interface"; | ||
/** type T = ... */ | ||
ScriptElementKind["typeElement"] = "type"; | ||
/** enum E */ | ||
ScriptElementKind["enumElement"] = "enum"; | ||
ScriptElementKind["enumMemberElement"] = "enum member"; | ||
/** | ||
* Inside module and script only | ||
* const v = .. | ||
*/ | ||
ScriptElementKind["variableElement"] = "var"; | ||
/** Inside function */ | ||
ScriptElementKind["localVariableElement"] = "local var"; | ||
/** | ||
* Inside module and script only | ||
* function f() { } | ||
*/ | ||
ScriptElementKind["functionElement"] = "function"; | ||
/** Inside function */ | ||
ScriptElementKind["localFunctionElement"] = "local function"; | ||
/** class X { [public|private]* foo() {} } */ | ||
ScriptElementKind["memberFunctionElement"] = "method"; | ||
/** class X { [public|private]* [get|set] foo:number; } */ | ||
ScriptElementKind["memberGetAccessorElement"] = "getter"; | ||
ScriptElementKind["memberSetAccessorElement"] = "setter"; | ||
/** | ||
* class X { [public|private]* foo:number; } | ||
* interface Y { foo:number; } | ||
*/ | ||
ScriptElementKind["memberVariableElement"] = "property"; | ||
/** class X { constructor() { } } */ | ||
ScriptElementKind["constructorImplementationElement"] = "constructor"; | ||
/** interface Y { ():number; } */ | ||
ScriptElementKind["callSignatureElement"] = "call"; | ||
/** interface Y { []:number; } */ | ||
ScriptElementKind["indexSignatureElement"] = "index"; | ||
/** interface Y { new():Y; } */ | ||
ScriptElementKind["constructSignatureElement"] = "construct"; | ||
/** function foo(*Y*: string) */ | ||
ScriptElementKind["parameterElement"] = "parameter"; | ||
ScriptElementKind["typeParameterElement"] = "type parameter"; | ||
ScriptElementKind["primitiveType"] = "primitive type"; | ||
ScriptElementKind["label"] = "label"; | ||
ScriptElementKind["alias"] = "alias"; | ||
ScriptElementKind["constElement"] = "const"; | ||
ScriptElementKind["letElement"] = "let"; | ||
ScriptElementKind["directory"] = "directory"; | ||
ScriptElementKind["externalModuleName"] = "external module name"; | ||
/** | ||
* <JsxTagName attribute1 attribute2={0} /> | ||
*/ | ||
ScriptElementKind["jsxAttribute"] = "JSX attribute"; | ||
/** String literal */ | ||
ScriptElementKind["string"] = "string"; | ||
})(ScriptElementKind = exports.ScriptElementKind || (exports.ScriptElementKind = {})); | ||
//# sourceMappingURL=tsp-command-types.js.map |
@@ -11,1 +11,2 @@ export declare class Deferred<T> { | ||
export declare function isWindows(): boolean; | ||
//# sourceMappingURL=utils.d.ts.map |
{ | ||
"name": "typescript-language-server", | ||
"version": "0.2.0", | ||
"version": "0.3.0-dev.ceb1d15", | ||
"description": "Language Server Protocol (LSP) implementation for TypeScript using tsserver", | ||
"author": "TypeFox and others", | ||
"license": "Apache-2.0", | ||
"repository": { | ||
@@ -9,29 +11,7 @@ "type": "git", | ||
}, | ||
"scripts": { | ||
"prepare": "yarn run build", | ||
"build": "tsc && tslint --project .", | ||
"clean": "rimraf lib", | ||
"watch": "tsc --watch", | ||
"test": "mocha --exit --reporter spec \"./lib/**/*.spec.js\"" | ||
}, | ||
"bin": { | ||
"typescript-language-server": "./lib/cli.js" | ||
}, | ||
"files": [ | ||
"lib" | ||
], | ||
"author": "TypeFox and others", | ||
"license": "Apache-2.0", | ||
"devDependencies": { | ||
"@types/chai": "^4.0.4", | ||
"@types/commander": "^2.9.2", | ||
"@types/mocha": "^2.2.43", | ||
"@types/node": "^8.0.31", | ||
"chai": "^4.1.2", | ||
"mocha": "5.2.0", | ||
"rimraf": "^2.6.2", | ||
"source-map-support": "^0.4.18", | ||
"ts-node": "^5.0.0", | ||
"tslint": "^5.8.0", | ||
"typescript": "2.9.1" | ||
"bin": { | ||
"typescript-language-server": "./lib/cli.js" | ||
}, | ||
@@ -41,5 +21,20 @@ "dependencies": { | ||
"commander": "^2.11.0", | ||
"fs-extra": "^7.0.0", | ||
"lodash.debounce": "^4.0.8", | ||
"tempy": "^0.2.1", | ||
"vscode-languageserver": "^4.4.0", | ||
"vscode-uri": "^1.0.5" | ||
} | ||
}, | ||
"scripts": { | ||
"prepare": "echo 'skip'", | ||
"clean": "rimraf lib", | ||
"test": "mocha --exit --reporter spec \"./lib/**/*.spec.js\"", | ||
"lint": "tslint -c ../tslint.json --project ." | ||
}, | ||
"devDependencies": { | ||
"@types/fs-extra": "^5.0.4", | ||
"@types/lodash.debounce": "^4.0.4", | ||
"@types/tempy": "^0.1.0" | ||
}, | ||
"gitHead": "ceb1d15faf64a133a2dcfca696cdd666d5432b9a" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
233607
3
94
2999
7
1
0
4
+ Addedfs-extra@^7.0.0
+ Addedlodash.debounce@^4.0.8
+ Addedtempy@^0.2.1
+ Addedcrypto-random-string@1.0.0(transitive)
+ Addedfs-extra@7.0.1(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedjsonfile@4.0.0(transitive)
+ Addedlodash.debounce@4.0.8(transitive)
+ Addedtemp-dir@1.0.0(transitive)
+ Addedtempy@0.2.1(transitive)
+ Addedunique-string@1.0.0(transitive)
+ Addeduniversalify@0.1.2(transitive)