Merge branch 'master' into watchOptions

This commit is contained in:
Sheetal Nandi
2018-03-03 10:51:59 -08:00
1306 changed files with 29122 additions and 28522 deletions

View File

@@ -71,11 +71,11 @@ namespace ts.server {
};
}
private convertCodeEditsToTextChange(fileName: string, codeEdit: protocol.CodeEdit): ts.TextChange {
private convertCodeEditsToTextChange(fileName: string, codeEdit: protocol.CodeEdit): TextChange {
return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText };
}
private processRequest<T extends protocol.Request>(command: string, args?: any): T {
private processRequest<T extends protocol.Request>(command: string, args?: T["arguments"]): T {
const request: protocol.Request = {
seq: this.sequence,
type: "request",
@@ -229,7 +229,7 @@ namespace ts.server {
}));
}
getFormattingEditsForRange(file: string, start: number, end: number, _options: FormatCodeOptions): ts.TextChange[] {
getFormattingEditsForRange(file: string, start: number, end: number, _options: FormatCodeOptions): TextChange[] {
const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset(file, start, end);
@@ -240,11 +240,11 @@ namespace ts.server {
return response.body.map(entry => this.convertCodeEditsToTextChange(file, entry));
}
getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): ts.TextChange[] {
getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] {
return this.getFormattingEditsForRange(fileName, 0, this.host.getScriptSnapshot(fileName).getLength(), options);
}
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, _options: FormatCodeOptions): ts.TextChange[] {
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, _options: FormatCodeOptions): TextChange[] {
const args: protocol.FormatOnKeyRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), key };
// TODO: handle FormatCodeOptions
@@ -343,41 +343,31 @@ namespace ts.server {
}
getSyntacticDiagnostics(file: string): Diagnostic[] {
const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true };
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest>(CommandNames.SyntacticDiagnosticsSync, args);
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => this.convertDiagnostic(entry, file));
return this.getDiagnostics(file, CommandNames.SyntacticDiagnosticsSync);
}
getSemanticDiagnostics(file: string): Diagnostic[] {
const args: protocol.SemanticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true };
const request = this.processRequest<protocol.SemanticDiagnosticsSyncRequest>(CommandNames.SemanticDiagnosticsSync, args);
const response = this.processResponse<protocol.SemanticDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => this.convertDiagnostic(entry, file));
return this.getDiagnostics(file, CommandNames.SemanticDiagnosticsSync);
}
getSuggestionDiagnostics(file: string): Diagnostic[] {
return this.getDiagnostics(file, CommandNames.SuggestionDiagnosticsSync);
}
convertDiagnostic(entry: protocol.DiagnosticWithLinePosition, _fileName: string): Diagnostic {
let category: DiagnosticCategory;
for (const id in DiagnosticCategory) {
if (isString(id) && entry.category === id.toLowerCase()) {
category = (<any>DiagnosticCategory)[id];
}
}
private getDiagnostics(file: string, command: CommandNames) {
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest | protocol.SemanticDiagnosticsSyncRequest | protocol.SuggestionDiagnosticsSyncRequest>(command, { file, includeLinePosition: true });
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse | protocol.SemanticDiagnosticsSyncResponse | protocol.SuggestionDiagnosticsSyncResponse>(request);
Debug.assert(category !== undefined, "convertDiagnostic: category should not be undefined");
return {
file: undefined,
start: entry.start,
length: entry.length,
messageText: entry.message,
category,
code: entry.code
};
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => {
const category = firstDefined(Object.keys(DiagnosticCategory), id =>
isString(id) && entry.category === id.toLowerCase() ? (<any>DiagnosticCategory)[id] : undefined);
return {
file: undefined,
start: entry.start,
length: entry.length,
messageText: entry.message,
category: Debug.assertDefined(category, "convertDiagnostic: category should not be undefined"),
code: entry.code
};
});
}
getCompilerOptionsDiagnostics(): Diagnostic[] {
@@ -650,7 +640,7 @@ namespace ts.server {
}));
}
convertTextChangeToCodeEdit(change: protocol.CodeEdit, fileName: string): ts.TextChange {
convertTextChangeToCodeEdit(change: protocol.CodeEdit, fileName: string): TextChange {
return {
span: this.decodeSpan(change, fileName),
newText: change.newText ? change.newText : ""

View File

@@ -1393,7 +1393,7 @@ namespace ts.server {
return project;
}
private sendProjectTelemetry(projectKey: string, project: server.ExternalProject | server.ConfiguredProject, projectOptions?: ProjectOptions): void {
private sendProjectTelemetry(projectKey: string, project: ExternalProject | ConfiguredProject, projectOptions?: ProjectOptions): void {
if (this.seenProjects.has(projectKey)) {
return;
}
@@ -1414,18 +1414,18 @@ namespace ts.server {
exclude: projectOptions && projectOptions.configHasExcludeProperty,
compileOnSave: project.compileOnSaveEnabled,
configFileName: configFileName(),
projectType: project instanceof server.ExternalProject ? "external" : "configured",
projectType: project instanceof ExternalProject ? "external" : "configured",
languageServiceEnabled: project.languageServiceEnabled,
version,
};
this.eventHandler({ eventName: ProjectInfoTelemetryEvent, data });
function configFileName(): ProjectInfoTelemetryEventData["configFileName"] {
if (!(project instanceof server.ConfiguredProject)) {
if (!(project instanceof ConfiguredProject)) {
return "other";
}
const configFilePath = project instanceof server.ConfiguredProject && project.getConfigFilePath();
const configFilePath = project instanceof ConfiguredProject && project.getConfigFilePath();
return getBaseConfigFileName(configFilePath) || "other";
}
@@ -2240,7 +2240,7 @@ namespace ts.server {
}
const excludeRegexes = excludeRules.map(e => new RegExp(e, "i"));
const filesToKeep: ts.server.protocol.ExternalFile[] = [];
const filesToKeep: protocol.ExternalFile[] = [];
for (let i = 0; i < proj.rootFiles.length; i++) {
if (excludeRegexes.some(re => re.test(normalizedNames[i]))) {
excludedFiles.push(normalizedNames[i]);

View File

@@ -210,6 +210,9 @@ namespace ts.server {
/*@internal*/
public directoryStructureHost: DirectoryStructureHost;
/*@internal*/
public readonly getCanonicalFileName: GetCanonicalFileName;
/*@internal*/
constructor(
/*@internal*/readonly projectName: string,
@@ -224,6 +227,7 @@ namespace ts.server {
currentDirectory: string | undefined) {
this.directoryStructureHost = directoryStructureHost;
this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || "");
this.getCanonicalFileName = this.projectService.toCanonicalFileName;
this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds);
if (!this.compilerOptions) {
@@ -238,7 +242,10 @@ namespace ts.server {
this.setInternalCompilerOptionsForEmittingJsFiles();
const host = this.projectService.host;
if (host.trace) {
if (this.projectService.logger.loggingEnabled()) {
this.trace = s => this.writeLog(s);
}
else if (host.trace) {
this.trace = s => host.trace(s);
}
@@ -853,7 +860,7 @@ namespace ts.server {
}
protected removeExistingTypings(include: string[]): string[] {
const existing = ts.getAutomaticTypeDirectiveNames(this.getCompilerOptions(), this.directoryStructureHost);
const existing = getAutomaticTypeDirectiveNames(this.getCompilerOptions(), this.directoryStructureHost);
return include.filter(i => existing.indexOf(i) < 0);
}

View File

@@ -1,3 +1,5 @@
// tslint:disable no-unnecessary-qualifier
/**
* Declaration module describing the TypeScript Server protocol
*/
@@ -42,6 +44,7 @@ namespace ts.server.protocol {
GeterrForProject = "geterrForProject",
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
SuggestionDiagnosticsSync = "suggestionDiagnosticsSync",
NavBar = "navbar",
/* @internal */
NavBarFull = "navbar-full",
@@ -2010,6 +2013,14 @@ namespace ts.server.protocol {
body?: Diagnostic[] | DiagnosticWithLinePosition[];
}
export interface SuggestionDiagnosticsSyncRequest extends FileRequest {
command: CommandTypes.SuggestionDiagnosticsSync;
arguments: SuggestionDiagnosticsSyncRequestArgs;
}
export type SuggestionDiagnosticsSyncRequestArgs = SemanticDiagnosticsSyncRequestArgs;
export type SuggestionDiagnosticsSyncResponse = SemanticDiagnosticsSyncResponse;
/**
* Synchronous request for syntactic diagnostics of one file.
*/
@@ -2121,7 +2132,7 @@ namespace ts.server.protocol {
text: string;
/**
* The category of the diagnostic message, e.g. "error" vs. "warning"
* The category of the diagnostic message, e.g. "error", "warning", or "suggestion".
*/
category: string;
@@ -2155,8 +2166,10 @@ namespace ts.server.protocol {
diagnostics: Diagnostic[];
}
export type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag";
/**
* Event message for "syntaxDiag" and "semanticDiag" event types.
* Event message for DiagnosticEventKind event types.
* These events provide syntactic and semantic errors for a file.
*/
export interface DiagnosticEvent extends Event {

View File

@@ -176,8 +176,13 @@ namespace ts.server {
return this.switchToScriptVersionCache();
}
// Else if the svc is uptodate with the text, we are good
return !this.pendingReloadFromDisk && this.svc;
// If there is pending reload from the disk then, reload the text
if (this.pendingReloadFromDisk) {
this.reloadWithFileText();
}
// At this point if svc is present its valid
return this.svc;
}
private getOrLoadText() {

View File

@@ -142,7 +142,7 @@ namespace ts.server {
terminal: false,
});
class Logger implements server.Logger {
class Logger implements server.Logger { // tslint:disable-line no-unnecessary-qualifier
private fd = -1;
private seq = 0;
private inGroup = false;
@@ -266,7 +266,7 @@ namespace ts.server {
constructor(
private readonly telemetryEnabled: boolean,
private readonly logger: server.Logger,
private readonly logger: Logger,
private readonly host: ServerHost,
readonly globalTypingsCacheLocation: string,
readonly typingSafeListLocation: string,
@@ -391,7 +391,7 @@ namespace ts.server {
switch (response.kind) {
case EventTypesRegistry:
this.typesRegistryCache = ts.createMapFromTemplate(response.typesRegistry);
this.typesRegistryCache = createMapFromTemplate(response.typesRegistry);
break;
case ActionPackageInstalled: {
const { success, message } = response;

View File

@@ -79,7 +79,7 @@ namespace ts.server {
end: scriptInfo.positionToLineOffset(diag.start + diag.length),
text: flattenDiagnosticMessageText(diag.messageText, "\n"),
code: diag.code,
category: DiagnosticCategory[diag.category].toLowerCase(),
category: diagnosticCategoryName(diag),
source: diag.source
};
}
@@ -95,7 +95,7 @@ namespace ts.server {
const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = flattenDiagnosticMessageText(diag.messageText, "\n");
const { code, source } = diag;
const category = DiagnosticCategory[diag.category].toLowerCase();
const category = diagnosticCategoryName(diag);
return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } :
{ start, end, text, code, category, source };
}
@@ -105,7 +105,7 @@ namespace ts.server {
project: Project;
}
function allEditsBeforePos(edits: ts.TextChange[], pos: number) {
function allEditsBeforePos(edits: TextChange[], pos: number) {
for (const edit of edits) {
if (textSpanEnd(edit.span) >= pos) {
return false;
@@ -122,7 +122,7 @@ namespace ts.server {
export type CommandNames = protocol.CommandTypes;
export const CommandNames = (<any>protocol).CommandTypes; // tslint:disable-line variable-name
export function formatMessage<T extends protocol.Message>(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string {
export function formatMessage<T extends protocol.Message>(msg: T, logger: Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string {
const verboseLogging = logger.hasLevel(LogLevel.verbose);
const json = JSON.stringify(msg);
@@ -466,30 +466,26 @@ namespace ts.server {
}
private semanticCheck(file: NormalizedPath, project: Project) {
try {
let diags: ReadonlyArray<Diagnostic> = emptyArray;
if (!isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) {
diags = project.getLanguageService().getSemanticDiagnostics(file);
}
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: bakedDiags }, "semanticDiag");
}
catch (err) {
this.logError(err, "semantic check");
}
const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file)
? emptyArray
: project.getLanguageService().getSemanticDiagnostics(file);
this.sendDiagnosticsEvent(file, project, diags, "semanticDiag");
}
private syntacticCheck(file: NormalizedPath, project: Project) {
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag");
}
private infoCheck(file: NormalizedPath, project: Project) {
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag");
}
private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: ReadonlyArray<Diagnostic>, kind: protocol.DiagnosticEventKind): void {
try {
const diags = project.getLanguageService().getSyntacticDiagnostics(file);
if (diags) {
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: bakedDiags }, "syntaxDiag");
}
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)) }, kind);
}
catch (err) {
this.logError(err, "syntactic check");
this.logError(err, kind);
}
}
@@ -499,21 +495,34 @@ namespace ts.server {
let index = 0;
const checkOne = () => {
if (this.changeSeq === seq) {
const checkSpec = checkList[index];
index++;
if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) {
this.syntacticCheck(checkSpec.fileName, checkSpec.project);
if (this.changeSeq === seq) {
next.immediate(() => {
this.semanticCheck(checkSpec.fileName, checkSpec.project);
if (checkList.length > index) {
next.delay(followMs, checkOne);
}
});
}
}
if (this.changeSeq !== seq) {
return;
}
const { fileName, project } = checkList[index];
index++;
if (!project.containsFile(fileName, requireOpen)) {
return;
}
this.syntacticCheck(fileName, project);
if (this.changeSeq !== seq) {
return;
}
next.immediate(() => {
this.semanticCheck(fileName, project);
if (this.changeSeq !== seq) {
return;
}
next.immediate(() => {
this.infoCheck(fileName, project);
if (checkList.length > index) {
next.delay(followMs, checkOne);
}
});
});
};
if (checkList.length > index && this.changeSeq === seq) {
@@ -580,7 +589,7 @@ namespace ts.server {
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
category: diagnosticCategoryName(d),
code: d.code,
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
@@ -606,7 +615,7 @@ namespace ts.server {
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
category: diagnosticCategoryName(d),
code: d.code,
source: d.source,
startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start),
@@ -756,6 +765,16 @@ namespace ts.server {
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition);
}
private getSuggestionDiagnosticsSync(args: protocol.SuggestionDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
const { configFile } = this.getConfigFileAndProject(args);
if (configFile) {
// Currently there are no info diagnostics for config files.
return emptyArray;
}
// isSemantic because we don't want to info diagnostics in declaration files for JS-only users
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), args.includeLinePosition);
}
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.DocumentHighlightsItem> | ReadonlyArray<DocumentHighlights> {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -1694,7 +1713,7 @@ namespace ts.server {
};
}
private convertTextChangeToCodeEdit(change: ts.TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
return {
start: scriptInfo.positionToLineOffset(change.span.start),
end: scriptInfo.positionToLineOffset(change.span.start + change.span.length),
@@ -1953,6 +1972,9 @@ namespace ts.server {
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.SyntacticDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
},
[CommandNames.SuggestionDiagnosticsSync]: (request: protocol.SuggestionDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSuggestionDiagnosticsSync(request.arguments));
},
[CommandNames.Geterr]: (request: protocol.GeterrRequest) => {
this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files));
return this.notRequired();

View File

@@ -221,11 +221,11 @@ namespace ts.server.typingsInstaller {
});
}
const logFilePath = findArgument(server.Arguments.LogFile);
const globalTypingsCacheLocation = findArgument(server.Arguments.GlobalCacheLocation);
const typingSafeListLocation = findArgument(server.Arguments.TypingSafeListLocation);
const typesMapLocation = findArgument(server.Arguments.TypesMapLocation);
const npmLocation = findArgument(server.Arguments.NpmLocation);
const logFilePath = findArgument(Arguments.LogFile);
const globalTypingsCacheLocation = findArgument(Arguments.GlobalCacheLocation);
const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation);
const typesMapLocation = findArgument(Arguments.TypesMapLocation);
const npmLocation = findArgument(Arguments.NpmLocation);
const log = new FileLog(logFilePath);
if (log.isEnabled()) {

View File

@@ -277,7 +277,7 @@ namespace ts.server.typingsInstaller {
this.sendResponse(<BeginInstallTypes>{
kind: EventBeginInstallTypes,
eventId: requestId,
typingsInstallerVersion: ts.version, // qualified explicitly to prevent occasional shadowing
typingsInstallerVersion: ts.version, // tslint:disable-line no-unnecessary-qualifier (qualified explicitly to prevent occasional shadowing)
projectName: req.projectName
});
@@ -308,7 +308,7 @@ namespace ts.server.typingsInstaller {
// packageName is guaranteed to exist in typesRegistry by filterTypings
const distTags = this.typesRegistry.get(packageName);
const newVersion = Semver.parse(distTags[`ts${ts.versionMajorMinor}`] || distTags[latestDistTag]);
const newVersion = Semver.parse(distTags[`ts${versionMajorMinor}`] || distTags[latestDistTag]);
const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: newVersion };
this.packageNameToTypingLocation.set(packageName, newTyping);
installedTypingFiles.push(typingFile);
@@ -326,7 +326,7 @@ namespace ts.server.typingsInstaller {
projectName: req.projectName,
packagesToInstall: scopedTypings,
installSuccess: ok,
typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing
typingsInstallerVersion: ts.version // tslint:disable-line no-unnecessary-qualifier (qualified explicitly to prevent occasional shadowing)
};
this.sendResponse(response);
}
@@ -359,7 +359,7 @@ namespace ts.server.typingsInstaller {
this.log.writeLine(`Got FS notification for ${f}, handler is already invoked '${isInvoked}'`);
}
if (!isInvoked) {
this.sendResponse({ projectName, kind: server.ActionInvalidate });
this.sendResponse({ projectName, kind: ActionInvalidate });
isInvoked = true;
}
}, /*pollingInterval*/ 2000);

View File

@@ -83,7 +83,7 @@ namespace ts.server {
};
}
export function mergeMapLikes(target: MapLike<any>, source: MapLike<any>): void {
export function mergeMapLikes<T extends object>(target: T, source: Partial<T>): void {
for (const key in source) {
if (hasProperty(source, key)) {
target[key] = source[key];