mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 21:06:50 -05:00
Add separate flag serverMode for server mode (#39735)
* Add separate flag serverMode for server mode to allow back compatibility * Addressed code review feedback. Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
@@ -396,7 +396,9 @@ namespace ts.server {
|
||||
pluginProbeLocations?: readonly string[];
|
||||
allowLocalPluginLoads?: boolean;
|
||||
typesMapLocation?: string;
|
||||
/** @deprecated use serverMode instead */
|
||||
syntaxOnly?: boolean;
|
||||
serverMode?: LanguageServiceMode;
|
||||
}
|
||||
|
||||
interface OriginalFileInfo { fileName: NormalizedPath; path: Path; }
|
||||
@@ -683,7 +685,9 @@ namespace ts.server {
|
||||
|
||||
public readonly typesMapLocation: string | undefined;
|
||||
|
||||
public readonly syntaxOnly?: boolean;
|
||||
/** @deprecated use serverMode instead */
|
||||
public readonly syntaxOnly: boolean;
|
||||
public readonly serverMode: LanguageServiceMode;
|
||||
|
||||
/** Tracks projects that we have already sent telemetry for. */
|
||||
private readonly seenProjects = new Map<string, true>();
|
||||
@@ -713,7 +717,18 @@ namespace ts.server {
|
||||
this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray;
|
||||
this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads;
|
||||
this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation;
|
||||
this.syntaxOnly = opts.syntaxOnly;
|
||||
if (opts.serverMode !== undefined) {
|
||||
this.serverMode = opts.serverMode;
|
||||
this.syntaxOnly = this.serverMode === LanguageServiceMode.SyntaxOnly;
|
||||
}
|
||||
else if (opts.syntaxOnly) {
|
||||
this.serverMode = LanguageServiceMode.SyntaxOnly;
|
||||
this.syntaxOnly = true;
|
||||
}
|
||||
else {
|
||||
this.serverMode = LanguageServiceMode.Semantic;
|
||||
this.syntaxOnly = false;
|
||||
}
|
||||
|
||||
Debug.assert(!!this.host.createHash, "'ServerHost.createHash' is required for ProjectService");
|
||||
if (this.host.realpath) {
|
||||
@@ -749,7 +764,7 @@ namespace ts.server {
|
||||
this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None;
|
||||
const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop;
|
||||
this.packageJsonCache = createPackageJsonCache(this);
|
||||
this.watchFactory = this.syntaxOnly ?
|
||||
this.watchFactory = this.serverMode !== LanguageServiceMode.Semantic ?
|
||||
{
|
||||
watchFile: returnNoopFileWatcher,
|
||||
watchFilePath: returnNoopFileWatcher,
|
||||
@@ -1727,7 +1742,7 @@ namespace ts.server {
|
||||
* the newly opened file.
|
||||
*/
|
||||
private forEachConfigFileLocation(info: OpenScriptInfoOrClosedOrConfigFileInfo, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
|
||||
if (this.syntaxOnly) {
|
||||
if (this.serverMode !== LanguageServiceMode.Semantic) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -3014,7 +3029,7 @@ namespace ts.server {
|
||||
let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined;
|
||||
let projectForConfigFileDiag: ConfiguredProject | undefined;
|
||||
let defaultConfigProjectIsCreated = false;
|
||||
if (this.syntaxOnly) {
|
||||
if (this.serverMode === LanguageServiceMode.ApproximateSemanticOnly) {
|
||||
// Invalidate resolutions in the file since this file is now open
|
||||
info.containingProjects.forEach(project => {
|
||||
if (project.resolutionCache.removeRelativeNoResolveResolutionsOfFile(info.path)) {
|
||||
@@ -3022,7 +3037,7 @@ namespace ts.server {
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (!project) { // Checking syntaxOnly is an optimization
|
||||
else if (!project && this.serverMode === LanguageServiceMode.Semantic) { // Checking semantic mode is an optimization
|
||||
configFileName = this.getConfigFileNameForFile(info);
|
||||
if (configFileName) {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
@@ -3109,7 +3124,7 @@ namespace ts.server {
|
||||
Debug.assert(this.openFiles.has(info.path));
|
||||
this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path));
|
||||
}
|
||||
else if (this.syntaxOnly && info.cacheSourceFile?.sourceFile.referencedFiles.length) {
|
||||
else if (this.serverMode === LanguageServiceMode.ApproximateSemanticOnly && info.cacheSourceFile?.sourceFile.referencedFiles.length) {
|
||||
// This file was just opened and references in this file will previously not been resolved so schedule update
|
||||
info.containingProjects.forEach(project => project.markAsDirty());
|
||||
}
|
||||
@@ -3325,7 +3340,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private telemetryOnOpenFile(scriptInfo: ScriptInfo): void {
|
||||
if (this.syntaxOnly || !this.eventHandler || !scriptInfo.isJavaScript() || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path)) {
|
||||
if (this.serverMode !== LanguageServiceMode.Semantic || !this.eventHandler || !scriptInfo.isJavaScript() || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3637,7 +3652,7 @@ namespace ts.server {
|
||||
for (const file of proj.rootFiles) {
|
||||
const normalized = toNormalizedPath(file.fileName);
|
||||
if (getBaseConfigFileName(normalized)) {
|
||||
if (!this.syntaxOnly && this.host.fileExists(normalized)) {
|
||||
if (this.serverMode === LanguageServiceMode.Semantic && this.host.fileExists(normalized)) {
|
||||
(tsConfigFiles || (tsConfigFiles = [])).push(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,9 +279,21 @@ namespace ts.server {
|
||||
this.compilerOptions.allowNonTsExtensions = true;
|
||||
}
|
||||
|
||||
this.languageServiceEnabled = true;
|
||||
if (projectService.syntaxOnly) {
|
||||
this.compilerOptions.types = [];
|
||||
switch (projectService.serverMode) {
|
||||
case LanguageServiceMode.Semantic:
|
||||
this.languageServiceEnabled = true;
|
||||
break;
|
||||
case LanguageServiceMode.ApproximateSemanticOnly:
|
||||
this.languageServiceEnabled = true;
|
||||
this.compilerOptions.types = [];
|
||||
break;
|
||||
case LanguageServiceMode.SyntaxOnly:
|
||||
this.languageServiceEnabled = false;
|
||||
this.compilerOptions.noResolve = true;
|
||||
this.compilerOptions.types = [];
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(projectService.serverMode);
|
||||
}
|
||||
|
||||
this.setInternalCompilerOptionsForEmittingJsFiles();
|
||||
@@ -298,10 +310,10 @@ namespace ts.server {
|
||||
this.resolutionCache = createResolutionCache(
|
||||
this,
|
||||
currentDirectory && this.currentDirectory,
|
||||
projectService.syntaxOnly ? ResolutionKind.RelativeReferencesInOpenFileOnly : ResolutionKind.All,
|
||||
projectService.serverMode === LanguageServiceMode.Semantic ? ResolutionKind.All : ResolutionKind.RelativeReferencesInOpenFileOnly,
|
||||
/*logChangesWhenResolvingModule*/ true
|
||||
);
|
||||
this.languageService = createLanguageService(this, this.documentRegistry, this.projectService.syntaxOnly);
|
||||
this.languageService = createLanguageService(this, this.documentRegistry, this.projectService.serverMode);
|
||||
if (lastFileExceededProgramSize) {
|
||||
this.disableLanguageService(lastFileExceededProgramSize);
|
||||
}
|
||||
@@ -456,7 +468,16 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
includeTripleslashReferencesFrom(containingFile: string) {
|
||||
return !this.projectService.syntaxOnly || this.fileIsOpen(this.toPath(containingFile));
|
||||
switch (this.projectService.serverMode) {
|
||||
case LanguageServiceMode.Semantic:
|
||||
return true;
|
||||
case LanguageServiceMode.ApproximateSemanticOnly:
|
||||
return this.fileIsOpen(this.toPath(containingFile));
|
||||
case LanguageServiceMode.SyntaxOnly:
|
||||
return false;
|
||||
default:
|
||||
Debug.assertNever(this.projectService.serverMode);
|
||||
}
|
||||
}
|
||||
|
||||
directoryExists(path: string): boolean {
|
||||
@@ -656,7 +677,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
enableLanguageService() {
|
||||
if (this.languageServiceEnabled) {
|
||||
if (this.languageServiceEnabled || this.projectService.serverMode === LanguageServiceMode.SyntaxOnly) {
|
||||
return;
|
||||
}
|
||||
this.languageServiceEnabled = true;
|
||||
@@ -668,6 +689,7 @@ namespace ts.server {
|
||||
if (!this.languageServiceEnabled) {
|
||||
return;
|
||||
}
|
||||
Debug.assert(this.projectService.serverMode !== LanguageServiceMode.SyntaxOnly);
|
||||
this.languageService.cleanupSemanticCache();
|
||||
this.languageServiceEnabled = false;
|
||||
this.lastFileExceededProgramSize = lastFileExceededProgramSize;
|
||||
@@ -997,7 +1019,7 @@ namespace ts.server {
|
||||
|
||||
// update builder only if language service is enabled
|
||||
// otherwise tell it to drop its internal state
|
||||
if (this.languageServiceEnabled && !this.projectService.syntaxOnly) {
|
||||
if (this.languageServiceEnabled && this.projectService.serverMode === LanguageServiceMode.Semantic) {
|
||||
// 1. no changes in structure, no changes in unresolved imports - do nothing
|
||||
// 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files
|
||||
// (can reuse cached imports for files that were not changed)
|
||||
@@ -1128,7 +1150,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// Watch the type locations that would be added to program as part of automatic type resolutions
|
||||
if (this.languageServiceEnabled && !this.projectService.syntaxOnly) {
|
||||
if (this.languageServiceEnabled && this.projectService.serverMode === LanguageServiceMode.Semantic) {
|
||||
this.resolutionCache.updateTypeRootsWatch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ namespace ts.server {
|
||||
undefined;
|
||||
}
|
||||
|
||||
const invalidSyntaxOnlyCommands: readonly CommandNames[] = [
|
||||
const invalidApproximateSemanticOnlyCommands: readonly CommandNames[] = [
|
||||
CommandNames.OpenExternalProject,
|
||||
CommandNames.OpenExternalProjects,
|
||||
CommandNames.CloseExternalProject,
|
||||
@@ -621,6 +621,36 @@ namespace ts.server {
|
||||
CommandNames.ProvideCallHierarchyOutgoingCalls,
|
||||
];
|
||||
|
||||
const invalidSyntaxOnlyCommands: readonly CommandNames[] = [
|
||||
...invalidApproximateSemanticOnlyCommands,
|
||||
CommandNames.Definition,
|
||||
CommandNames.DefinitionFull,
|
||||
CommandNames.DefinitionAndBoundSpan,
|
||||
CommandNames.DefinitionAndBoundSpanFull,
|
||||
CommandNames.TypeDefinition,
|
||||
CommandNames.Implementation,
|
||||
CommandNames.ImplementationFull,
|
||||
CommandNames.References,
|
||||
CommandNames.ReferencesFull,
|
||||
CommandNames.Rename,
|
||||
CommandNames.RenameLocationsFull,
|
||||
CommandNames.RenameInfoFull,
|
||||
CommandNames.Quickinfo,
|
||||
CommandNames.QuickinfoFull,
|
||||
CommandNames.CompletionInfo,
|
||||
CommandNames.Completions,
|
||||
CommandNames.CompletionsFull,
|
||||
CommandNames.CompletionDetails,
|
||||
CommandNames.CompletionDetailsFull,
|
||||
CommandNames.SignatureHelp,
|
||||
CommandNames.SignatureHelpFull,
|
||||
CommandNames.Navto,
|
||||
CommandNames.NavtoFull,
|
||||
CommandNames.Occurrences,
|
||||
CommandNames.DocumentHighlights,
|
||||
CommandNames.DocumentHighlightsFull,
|
||||
];
|
||||
|
||||
export interface SessionOptions {
|
||||
host: ServerHost;
|
||||
cancellationToken: ServerCancellationToken;
|
||||
@@ -637,7 +667,9 @@ namespace ts.server {
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
/** Has no effect if eventHandler is also specified. */
|
||||
suppressDiagnosticEvents?: boolean;
|
||||
/** @deprecated use serverMode instead */
|
||||
syntaxOnly?: boolean;
|
||||
serverMode?: LanguageServiceMode;
|
||||
throttleWaitMilliseconds?: number;
|
||||
noGetErrOnBackgroundUpdate?: boolean;
|
||||
|
||||
@@ -709,18 +741,32 @@ namespace ts.server {
|
||||
allowLocalPluginLoads: opts.allowLocalPluginLoads,
|
||||
typesMapLocation: opts.typesMapLocation,
|
||||
syntaxOnly: opts.syntaxOnly,
|
||||
serverMode: opts.serverMode,
|
||||
};
|
||||
this.projectService = new ProjectService(settings);
|
||||
this.projectService.setPerformanceEventHandler(this.performanceEventHandler.bind(this));
|
||||
this.gcTimer = new GcTimer(this.host, /*delay*/ 7000, this.logger);
|
||||
|
||||
// Make sure to setup handlers to throw error for not allowed commands on syntax server;
|
||||
if (this.projectService.syntaxOnly) {
|
||||
invalidSyntaxOnlyCommands.forEach(commandName =>
|
||||
this.handlers.set(commandName, request => {
|
||||
throw new Error(`Request: ${request.command} not allowed on syntaxServer`);
|
||||
})
|
||||
);
|
||||
// Make sure to setup handlers to throw error for not allowed commands on syntax server
|
||||
switch (this.projectService.serverMode) {
|
||||
case LanguageServiceMode.Semantic:
|
||||
break;
|
||||
case LanguageServiceMode.ApproximateSemanticOnly:
|
||||
invalidApproximateSemanticOnlyCommands.forEach(commandName =>
|
||||
this.handlers.set(commandName, request => {
|
||||
throw new Error(`Request: ${request.command} not allowed on approximate semantic only server`);
|
||||
})
|
||||
);
|
||||
break;
|
||||
case LanguageServiceMode.SyntaxOnly:
|
||||
invalidSyntaxOnlyCommands.forEach(commandName =>
|
||||
this.handlers.set(commandName, request => {
|
||||
throw new Error(`Request: ${request.command} not allowed on syntax only server`);
|
||||
})
|
||||
);
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(this.projectService.serverMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user