mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Introduce a --syntaxOnly server mode
1. Disable the LS in all projects 2. Don't create Program objects 3. Ignore config files
This commit is contained in:
parent
e2bd282414
commit
855171bde5
@ -1314,6 +1314,109 @@ namespace ts.projectSystem {
|
||||
|
||||
});
|
||||
|
||||
describe("ignoreConfigFiles", () => {
|
||||
it("external project including config file", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/f1.ts",
|
||||
content: "let x =1;"
|
||||
};
|
||||
const config1 = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify(
|
||||
{
|
||||
compilerOptions: {},
|
||||
files: ["f1.ts"]
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
const externalProjectName = "externalproject";
|
||||
const host = createServerHost([file1, config1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
projectService.openExternalProject({
|
||||
rootFiles: toExternalFiles([file1.path, config1.path]),
|
||||
options: {},
|
||||
projectFileName: externalProjectName
|
||||
});
|
||||
|
||||
checkNumberOfProjects(projectService, { externalProjects: 1 });
|
||||
const proj = projectService.externalProjects[0];
|
||||
assert.isDefined(proj);
|
||||
|
||||
assert.isTrue(proj.fileExists(file1.path));
|
||||
});
|
||||
|
||||
it("loose file included in config file (openClientFile)", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/f1.ts",
|
||||
content: "let x =1;"
|
||||
};
|
||||
const config1 = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify(
|
||||
{
|
||||
compilerOptions: {},
|
||||
files: ["f1.ts"]
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, config1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
projectService.openClientFile(file1.path, file1.content);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const proj = projectService.inferredProjects[0];
|
||||
assert.isDefined(proj);
|
||||
|
||||
assert.isTrue(proj.fileExists(file1.path));
|
||||
});
|
||||
|
||||
it("loose file included in config file (applyCodeChanges)", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/f1.ts",
|
||||
content: "let x =1;"
|
||||
};
|
||||
const config1 = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: JSON.stringify(
|
||||
{
|
||||
compilerOptions: {},
|
||||
files: ["f1.ts"]
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, config1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
projectService.applyChangesInOpenFiles([{ fileName: file1.path, content: file1.content }], [], []);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const proj = projectService.inferredProjects[0];
|
||||
assert.isDefined(proj);
|
||||
|
||||
assert.isTrue(proj.fileExists(file1.path));
|
||||
});
|
||||
});
|
||||
|
||||
it("disable inferred project", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/f1.ts",
|
||||
content: "let x =1;"
|
||||
};
|
||||
|
||||
const host = createServerHost([file1]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true }, { syntaxOnly: true });
|
||||
|
||||
projectService.openClientFile(file1.path, file1.content);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const proj = projectService.inferredProjects[0];
|
||||
assert.isDefined(proj);
|
||||
|
||||
assert.isFalse(proj.languageServiceEnabled);
|
||||
});
|
||||
|
||||
it("reload regular file after closing", () => {
|
||||
const f1 = {
|
||||
path: "/a/b/app.ts",
|
||||
|
||||
@ -311,6 +311,7 @@ namespace ts.server {
|
||||
pluginProbeLocations?: ReadonlyArray<string>;
|
||||
allowLocalPluginLoads?: boolean;
|
||||
typesMapLocation?: string;
|
||||
syntaxOnly?: boolean;
|
||||
}
|
||||
|
||||
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
|
||||
@ -400,6 +401,8 @@ namespace ts.server {
|
||||
public readonly allowLocalPluginLoads: boolean;
|
||||
public readonly typesMapLocation: string | undefined;
|
||||
|
||||
public readonly syntaxOnly?: boolean;
|
||||
|
||||
/** Tracks projects that we have already sent telemetry for. */
|
||||
private readonly seenProjects = createMap<true>();
|
||||
|
||||
@ -420,6 +423,7 @@ namespace ts.server {
|
||||
this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray;
|
||||
this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads;
|
||||
this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(this.getExecutingFilePath(), "../typesMap.json") : opts.typesMapLocation;
|
||||
this.syntaxOnly = opts.syntaxOnly;
|
||||
|
||||
Debug.assert(!!this.host.createHash, "'ServerHost.createHash' is required for ProjectService");
|
||||
if (this.host.realpath) {
|
||||
@ -1197,6 +1201,11 @@ namespace ts.server {
|
||||
private forEachConfigFileLocation(info: ScriptInfo,
|
||||
action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void,
|
||||
projectRootPath?: NormalizedPath) {
|
||||
|
||||
if (this.syntaxOnly) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
|
||||
|
||||
while (!projectRootPath || containsPath(projectRootPath, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames)) {
|
||||
@ -2004,7 +2013,7 @@ namespace ts.server {
|
||||
|
||||
const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent);
|
||||
let project: ConfiguredProject | ExternalProject = this.findExternalProjetContainingOpenScriptInfo(info);
|
||||
if (!project) {
|
||||
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
|
||||
configFileName = this.getConfigFileNameForFile(info, projectRootPath);
|
||||
if (configFileName) {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
@ -2309,7 +2318,7 @@ namespace ts.server {
|
||||
for (const file of proj.rootFiles) {
|
||||
const normalized = toNormalizedPath(file.fileName);
|
||||
if (getBaseConfigFileName(normalized)) {
|
||||
if (this.host.fileExists(normalized)) {
|
||||
if (!this.syntaxOnly && this.host.fileExists(normalized)) {
|
||||
(tsConfigFiles || (tsConfigFiles = [])).push(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ namespace ts.server {
|
||||
// wrapper over the real language service that will suppress all semantic operations
|
||||
protected languageService: LanguageService;
|
||||
|
||||
public languageServiceEnabled = true;
|
||||
public languageServiceEnabled: boolean;
|
||||
|
||||
readonly trace?: (s: string) => void;
|
||||
readonly realpath?: (path: string) => string;
|
||||
@ -240,6 +240,8 @@ namespace ts.server {
|
||||
this.compilerOptions.allowNonTsExtensions = true;
|
||||
}
|
||||
|
||||
this.languageServiceEnabled = !projectService.syntaxOnly;
|
||||
|
||||
this.setInternalCompilerOptionsForEmittingJsFiles();
|
||||
const host = this.projectService.host;
|
||||
if (this.projectService.logger.loggingEnabled()) {
|
||||
@ -255,7 +257,7 @@ namespace ts.server {
|
||||
|
||||
// Use the current directory as resolution root only if the project created using current directory string
|
||||
this.resolutionCache = createResolutionCache(this, currentDirectory && this.currentDirectory, /*logChangesWhenResolvingModule*/ true);
|
||||
this.languageService = createLanguageService(this, this.documentRegistry);
|
||||
this.languageService = createLanguageService(this, this.documentRegistry, projectService.syntaxOnly);
|
||||
if (lastFileExceededProgramSize) {
|
||||
this.disableLanguageService(lastFileExceededProgramSize);
|
||||
}
|
||||
@ -506,7 +508,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
enableLanguageService() {
|
||||
if (this.languageServiceEnabled) {
|
||||
if (this.languageServiceEnabled || this.projectService.syntaxOnly) {
|
||||
return;
|
||||
}
|
||||
this.languageServiceEnabled = true;
|
||||
@ -518,6 +520,7 @@ namespace ts.server {
|
||||
if (!this.languageServiceEnabled) {
|
||||
return;
|
||||
}
|
||||
Debug.assert(!this.projectService.syntaxOnly);
|
||||
this.languageService.cleanupSemanticCache();
|
||||
this.languageServiceEnabled = false;
|
||||
this.lastFileExceededProgramSize = lastFileExceededProgramSize;
|
||||
@ -875,10 +878,12 @@ namespace ts.server {
|
||||
this.dirty = false;
|
||||
this.resolutionCache.finishCachingPerDirectoryResolution();
|
||||
|
||||
Debug.assert(oldProgram === undefined || this.program !== undefined);
|
||||
|
||||
// bump up the version if
|
||||
// - oldProgram is not set - this is a first time updateGraph is called
|
||||
// - newProgram is different from the old program and structure of the old program was not reused.
|
||||
const hasChanges = !oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused & StructureIsReused.Completely));
|
||||
const hasChanges = this.program && (!oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused & StructureIsReused.Completely)));
|
||||
this.hasChangedAutomaticTypeDirectiveNames = false;
|
||||
if (hasChanges) {
|
||||
if (oldProgram) {
|
||||
|
||||
@ -513,6 +513,7 @@ namespace ts.server {
|
||||
logger,
|
||||
canUseEvents: true,
|
||||
suppressDiagnosticEvents,
|
||||
syntaxOnly,
|
||||
globalPlugins,
|
||||
pluginProbeLocations,
|
||||
allowLocalPluginLoads,
|
||||
@ -945,6 +946,7 @@ namespace ts.server {
|
||||
const useInferredProjectPerProjectRoot = hasArgument("--useInferredProjectPerProjectRoot");
|
||||
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
|
||||
const suppressDiagnosticEvents = hasArgument("--suppressDiagnosticEvents");
|
||||
const syntaxOnly = hasArgument("--syntaxOnly");
|
||||
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);
|
||||
|
||||
logger.info(`Starting TS Server`);
|
||||
|
||||
@ -297,6 +297,7 @@ namespace ts.server {
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
/** Has no effect if eventHandler is also specified. */
|
||||
suppressDiagnosticEvents?: boolean;
|
||||
syntaxOnly?: boolean;
|
||||
throttleWaitMilliseconds?: number;
|
||||
|
||||
globalPlugins?: ReadonlyArray<string>;
|
||||
@ -359,7 +360,8 @@ namespace ts.server {
|
||||
suppressDiagnosticEvents: this.suppressDiagnosticEvents,
|
||||
globalPlugins: opts.globalPlugins,
|
||||
pluginProbeLocations: opts.pluginProbeLocations,
|
||||
allowLocalPluginLoads: opts.allowLocalPluginLoads
|
||||
allowLocalPluginLoads: opts.allowLocalPluginLoads,
|
||||
syntaxOnly: opts.syntaxOnly,
|
||||
};
|
||||
this.projectService = new ProjectService(settings);
|
||||
this.gcTimer = new GcTimer(this.host, /*delay*/ 7000, this.logger);
|
||||
|
||||
@ -1152,8 +1152,10 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function createLanguageService(host: LanguageServiceHost,
|
||||
documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService {
|
||||
export function createLanguageService(
|
||||
host: LanguageServiceHost,
|
||||
documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory()),
|
||||
syntaxOnly = false): LanguageService {
|
||||
|
||||
const syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
|
||||
let program: Program;
|
||||
@ -1188,6 +1190,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function synchronizeHostData(): void {
|
||||
Debug.assert(!syntaxOnly);
|
||||
|
||||
// perform fast check if host supports it
|
||||
if (host.getProjectVersion) {
|
||||
const hostProjectVersion = host.getProjectVersion();
|
||||
@ -1363,6 +1367,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getProgram(): Program {
|
||||
if (syntaxOnly) {
|
||||
Debug.assert(program === undefined);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
synchronizeHostData();
|
||||
|
||||
return program;
|
||||
|
||||
@ -1197,7 +1197,7 @@ namespace ts {
|
||||
this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory());
|
||||
}
|
||||
const hostAdapter = new LanguageServiceShimHostAdapter(host);
|
||||
const languageService = createLanguageService(hostAdapter, this.documentRegistry);
|
||||
const languageService = createLanguageService(hostAdapter, this.documentRegistry, /*syntaxOnly*/ false);
|
||||
return new LanguageServiceShimObject(this, host, languageService);
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
@ -4867,7 +4867,7 @@ declare namespace ts {
|
||||
function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean, scriptKind?: ScriptKind): SourceFile;
|
||||
let disableIncrementalParsing: boolean;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry, syntaxOnly?: boolean): LanguageService;
|
||||
/**
|
||||
* Get the path of the default library files (lib.d.ts) as distributed with the typescript
|
||||
* node package.
|
||||
@ -7295,6 +7295,7 @@ declare namespace ts.server {
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
/** Has no effect if eventHandler is also specified. */
|
||||
suppressDiagnosticEvents?: boolean;
|
||||
syntaxOnly?: boolean;
|
||||
throttleWaitMilliseconds?: number;
|
||||
globalPlugins?: ReadonlyArray<string>;
|
||||
pluginProbeLocations?: ReadonlyArray<string>;
|
||||
@ -7864,6 +7865,7 @@ declare namespace ts.server {
|
||||
pluginProbeLocations?: ReadonlyArray<string>;
|
||||
allowLocalPluginLoads?: boolean;
|
||||
typesMapLocation?: string;
|
||||
syntaxOnly?: boolean;
|
||||
}
|
||||
class ProjectService {
|
||||
readonly typingsCache: TypingsCache;
|
||||
@ -7930,6 +7932,7 @@ declare namespace ts.server {
|
||||
readonly pluginProbeLocations: ReadonlyArray<string>;
|
||||
readonly allowLocalPluginLoads: boolean;
|
||||
readonly typesMapLocation: string | undefined;
|
||||
readonly syntaxOnly?: boolean;
|
||||
/** Tracks projects that we have already sent telemetry for. */
|
||||
private readonly seenProjects;
|
||||
constructor(opts: ProjectServiceOptions);
|
||||
|
||||
@ -5120,7 +5120,7 @@ declare namespace ts {
|
||||
function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean, scriptKind?: ScriptKind): SourceFile;
|
||||
let disableIncrementalParsing: boolean;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry, syntaxOnly?: boolean): LanguageService;
|
||||
/**
|
||||
* Get the path of the default library files (lib.d.ts) as distributed with the typescript
|
||||
* node package.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user