mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Handle watches of missing directories and make project the module resolution host
This commit is contained in:
1 parent
5aafd3f06c
commit
17565d8407
17 files changed
+586
-531
No files matched your search
@@ -3,7 +3,6 @@
|
||||
/// <reference path="utilities.ts" />
|
||||
/// <reference path="session.ts" />
|
||||
/// <reference path="scriptVersionCache.ts"/>
|
||||
/// <reference path="lsHost.ts"/>
|
||||
/// <reference path="project.ts"/>
|
||||
/// <reference path="typingsCache.ts"/>
|
||||
|
||||
@@ -476,7 +475,6 @@ namespace ts.server {
|
||||
this.typingsCache.deleteTypingsForProject(response.projectName);
|
||||
break;
|
||||
}
|
||||
project.markAsDirty();
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
}
|
||||
|
||||
@@ -528,6 +526,7 @@ namespace ts.server {
|
||||
|
||||
/* @internal */
|
||||
delayUpdateProjectGraphAndInferredProjectsRefresh(project: Project) {
|
||||
project.markAsDirty();
|
||||
this.delayUpdateProjectGraph(project);
|
||||
this.delayInferredProjectsRefresh();
|
||||
}
|
||||
@@ -712,36 +711,56 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
onTypeRootFileChanged(project: ConfiguredProject, fileOrFolder: string) {
|
||||
project.getCachedPartialSystem().addOrDeleteFileOrFolder(fileOrFolder, this.toPath(fileOrFolder));
|
||||
project.updateTypes();
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
/*@internal*/
|
||||
watchTypeRootDirectory(root: Path, project: ConfiguredProject) {
|
||||
// TODO: This is not needed anymore with watches for failed lookup locations?
|
||||
return this.watchDirectory(
|
||||
this.host,
|
||||
root,
|
||||
fileOrFolder => {
|
||||
project.getCachedPartialSystem().addOrDeleteFileOrFolder(fileOrFolder, this.toPath(fileOrFolder));
|
||||
project.updateTypes();
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
},
|
||||
WatchDirectoryFlags.None,
|
||||
WatchType.TypeRoot,
|
||||
project
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the callback function when a watched directory has added or removed source code files.
|
||||
* @param project the project that associates with this directory watcher
|
||||
* @param fileName the absolute file name that changed in watched directory
|
||||
* This is to watch whenever files are added or removed to the wildcard directories
|
||||
*/
|
||||
/* @internal */
|
||||
onFileAddOrRemoveInWatchedDirectoryOfProject(project: ConfiguredProject, fileOrFolder: string) {
|
||||
project.getCachedPartialSystem().addOrDeleteFileOrFolder(fileOrFolder, this.toPath(fileOrFolder));
|
||||
const configFilename = project.getConfigFilePath();
|
||||
/*@internal*/
|
||||
watchWildcardDirectory(directory: Path, flags: WatchDirectoryFlags, project: ConfiguredProject) {
|
||||
return this.watchDirectory(
|
||||
this.host,
|
||||
directory,
|
||||
fileOrFolder => {
|
||||
const fileOrFolderPath = this.toPath(fileOrFolder);
|
||||
project.getCachedPartialSystem().addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath);
|
||||
const configFilename = project.getConfigFilePath();
|
||||
|
||||
// If a change was made inside "folder/file", node will trigger the callback twice:
|
||||
// one with the fileName being "folder/file", and the other one with "folder".
|
||||
// We don't respond to the second one.
|
||||
if (fileOrFolder && !isSupportedSourceFileName(fileOrFolder, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) {
|
||||
this.logger.info(`Project: ${configFilename} Detected file add/remove of non supported extension: ${fileOrFolder}`);
|
||||
return;
|
||||
}
|
||||
// If the the added or created file or folder is not supported file name, ignore the file
|
||||
// But when watched directory is added/removed, we need to reload the file list
|
||||
if (fileOrFolderPath !== directory && !isSupportedSourceFileName(fileOrFolder, project.getCompilationSettings(), this.hostConfiguration.extraFileExtensions)) {
|
||||
this.logger.info(`Project: ${configFilename} Detected file add/remove of non supported extension: ${fileOrFolder}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const configFileSpecs = project.configFileSpecs;
|
||||
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFilename), project.getCompilerOptions(), project.getCachedPartialSystem(), this.hostConfiguration.extraFileExtensions);
|
||||
project.updateErrorOnNoInputFiles(result.fileNames.length !== 0);
|
||||
this.updateNonInferredProjectFiles(project, result.fileNames, fileNamePropertyReader, /*clientFileName*/ undefined);
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
// Reload is pending, do the reload
|
||||
if (!project.pendingReload) {
|
||||
const configFileSpecs = project.configFileSpecs;
|
||||
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFilename), project.getCompilationSettings(), project.getCachedPartialSystem(), this.hostConfiguration.extraFileExtensions);
|
||||
project.updateErrorOnNoInputFiles(result.fileNames.length !== 0);
|
||||
this.updateNonInferredProjectFiles(project, result.fileNames, fileNamePropertyReader, /*clientFileName*/ undefined);
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
}
|
||||
},
|
||||
flags,
|
||||
WatchType.WildcardDirectories,
|
||||
project
|
||||
);
|
||||
}
|
||||
|
||||
private onConfigChangedForConfiguredProject(project: ConfiguredProject, eventKind: FileWatcherEventKind) {
|
||||
@@ -1253,7 +1272,7 @@ namespace ts.server {
|
||||
return findProjectByName(projectFileName, this.externalProjects);
|
||||
}
|
||||
|
||||
private convertConfigFileContentToProjectOptions(configFilename: string, cachedServerHost: PartialSystem) {
|
||||
private convertConfigFileContentToProjectOptions(configFilename: string, cachedPartialSystem: CachedPartialSystem) {
|
||||
configFilename = normalizePath(configFilename);
|
||||
|
||||
const configFileContent = this.host.readFile(configFilename);
|
||||
@@ -1265,7 +1284,7 @@ namespace ts.server {
|
||||
const errors = result.parseDiagnostics;
|
||||
const parsedCommandLine = parseJsonSourceFileConfigFileContent(
|
||||
result,
|
||||
cachedServerHost,
|
||||
cachedPartialSystem,
|
||||
getDirectoryPath(configFilename),
|
||||
/*existingOptions*/ {},
|
||||
configFilename,
|
||||
@@ -1350,7 +1369,7 @@ namespace ts.server {
|
||||
const data: ProjectInfoTelemetryEventData = {
|
||||
projectId: this.host.createHash(projectKey),
|
||||
fileStats: countEachFileTypes(project.getScriptInfos()),
|
||||
compilerOptions: convertCompilerOptionsForTelemetry(project.getCompilerOptions()),
|
||||
compilerOptions: convertCompilerOptionsForTelemetry(project.getCompilationSettings()),
|
||||
typeAcquisition: convertTypeAcquisition(project.getTypeAcquisition()),
|
||||
extends: projectOptions && projectOptions.configHasExtendsProperty,
|
||||
files: projectOptions && projectOptions.configHasFilesProperty,
|
||||
@@ -1435,8 +1454,8 @@ namespace ts.server {
|
||||
const normalizedPath = toNormalizedPath(newRootFile);
|
||||
let scriptInfo: ScriptInfo | NormalizedPath;
|
||||
let path: Path;
|
||||
// Use the project's lsHost so that it can use caching instead of reaching to disk for the query
|
||||
if (!project.lsHost.fileExists(newRootFile)) {
|
||||
// Use the project's fileExists so that it can use caching instead of reaching to disk for the query
|
||||
if (!project.fileExists(newRootFile)) {
|
||||
path = normalizedPathToPath(normalizedPath, this.currentDirectory, this.toCanonicalFileName);
|
||||
const existingValue = projectRootFilesMap.get(path);
|
||||
if (isScriptInfo(existingValue)) {
|
||||
@@ -1448,7 +1467,7 @@ namespace ts.server {
|
||||
else {
|
||||
const scriptKind = propertyReader.getScriptKind(f);
|
||||
const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.extraFileExtensions);
|
||||
scriptInfo = this.getOrCreateScriptInfoForNormalizedPath(normalizedPath, /*openedByClient*/ clientFileName === newRootFile, /*fileContent*/ undefined, scriptKind, hasMixedContent, project.lsHost.host);
|
||||
scriptInfo = this.getOrCreateScriptInfoForNormalizedPath(normalizedPath, /*openedByClient*/ clientFileName === newRootFile, /*fileContent*/ undefined, scriptKind, hasMixedContent, project.partialSystem);
|
||||
path = scriptInfo.path;
|
||||
// If this script info is not already a root add it
|
||||
if (!project.isRoot(scriptInfo)) {
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="utilities.ts" />
|
||||
/// <reference path="scriptInfo.ts" />
|
||||
/// <reference path="..\compiler\resolutionCache.ts" />
|
||||
|
||||
namespace ts.server {
|
||||
export class LSHost implements LanguageServiceHost, ModuleResolutionHost {
|
||||
/*@internal*/
|
||||
compilationSettings: CompilerOptions;
|
||||
|
||||
readonly trace: (s: string) => void;
|
||||
readonly realpath?: (path: string) => string;
|
||||
|
||||
/*@internal*/
|
||||
hasInvalidatedResolution: HasInvalidatedResolution;
|
||||
|
||||
/**
|
||||
* This is the host that is associated with the project. This is normally same as projectService's host
|
||||
* except in Configured projects where it is CachedServerHost so that we can cache the results of the
|
||||
* file system entries as we would anyways be watching files in the project (so safe to cache)
|
||||
*/
|
||||
/*@internal*/
|
||||
host: PartialSystem;
|
||||
|
||||
constructor(host: PartialSystem, private project: Project, private readonly cancellationToken: HostCancellationToken) {
|
||||
this.host = host;
|
||||
this.cancellationToken = new ThrottledCancellationToken(cancellationToken, project.projectService.throttleWaitMilliseconds);
|
||||
|
||||
const serverHost = this.getServerHost();
|
||||
if (serverHost.trace) {
|
||||
this.trace = s => serverHost.trace(s);
|
||||
}
|
||||
|
||||
if (serverHost.realpath) {
|
||||
this.realpath = path => serverHost.realpath(path);
|
||||
}
|
||||
}
|
||||
|
||||
private getServerHost() {
|
||||
return this.project.projectService.host;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.project = undefined;
|
||||
this.host = undefined;
|
||||
}
|
||||
|
||||
getNewLine() {
|
||||
return this.host.newLine;
|
||||
}
|
||||
|
||||
getProjectVersion() {
|
||||
return this.project.getProjectVersion();
|
||||
}
|
||||
|
||||
getCompilationSettings() {
|
||||
return this.compilationSettings;
|
||||
}
|
||||
|
||||
useCaseSensitiveFileNames() {
|
||||
return this.host.useCaseSensitiveFileNames;
|
||||
}
|
||||
|
||||
getCancellationToken() {
|
||||
return this.cancellationToken;
|
||||
}
|
||||
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
|
||||
return this.project.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
|
||||
}
|
||||
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModuleFull[] {
|
||||
return this.project.resolutionCache.resolveModuleNames(moduleNames, containingFile, /*logChanges*/ true);
|
||||
}
|
||||
|
||||
getDefaultLibFileName() {
|
||||
const nodeModuleBinDir = getDirectoryPath(normalizePath(this.getServerHost().getExecutingFilePath()));
|
||||
return combinePaths(nodeModuleBinDir, getDefaultLibFileName(this.compilationSettings));
|
||||
}
|
||||
|
||||
getScriptSnapshot(filename: string): IScriptSnapshot {
|
||||
const scriptInfo = this.project.getScriptInfoLSHost(filename);
|
||||
if (scriptInfo) {
|
||||
return scriptInfo.getSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
getScriptFileNames() {
|
||||
return this.project.getRootFilesLSHost();
|
||||
}
|
||||
|
||||
getTypeRootsVersion() {
|
||||
return this.project.typesVersion;
|
||||
}
|
||||
|
||||
getScriptKind(fileName: string) {
|
||||
const info = this.project.getScriptInfoLSHost(fileName);
|
||||
return info && info.scriptKind;
|
||||
}
|
||||
|
||||
getScriptVersion(filename: string) {
|
||||
const info = this.project.getScriptInfoLSHost(filename);
|
||||
return info && info.getLatestVersion();
|
||||
}
|
||||
|
||||
getCurrentDirectory(): string {
|
||||
return this.host.getCurrentDirectory();
|
||||
}
|
||||
|
||||
resolvePath(path: string): string {
|
||||
return this.getServerHost().resolvePath(path);
|
||||
}
|
||||
|
||||
fileExists(file: string): boolean {
|
||||
// As an optimization, don't hit the disks for files we already know don't exist
|
||||
// (because we're watching for their creation).
|
||||
const path = this.project.projectService.toPath(file);
|
||||
return !this.project.isWatchedMissingFile(path) && this.host.fileExists(file);
|
||||
}
|
||||
|
||||
readFile(fileName: string): string | undefined {
|
||||
return this.host.readFile(fileName);
|
||||
}
|
||||
|
||||
directoryExists(path: string): boolean {
|
||||
return this.host.directoryExists(path);
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return this.host.readDirectory(path, extensions, exclude, include, depth);
|
||||
}
|
||||
|
||||
getDirectories(path: string): string[] {
|
||||
return this.host.getDirectories(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
+165
-112
@@ -1,7 +1,7 @@
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="utilities.ts"/>
|
||||
/// <reference path="scriptInfo.ts"/>
|
||||
/// <reference path="lsHost.ts"/>
|
||||
/// <reference path="..\compiler\resolutionCache.ts"/>
|
||||
/// <reference path="typingsCache.ts"/>
|
||||
/// <reference path="..\compiler\builder.ts"/>
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace ts.server {
|
||||
return value instanceof ScriptInfo;
|
||||
}
|
||||
|
||||
export abstract class Project {
|
||||
export abstract class Project implements LanguageServiceHost, ModuleResolutionHost {
|
||||
private rootFiles: ScriptInfo[] = [];
|
||||
private rootFilesMap: Map<ProjectRoot> = createMap<ProjectRoot>();
|
||||
private program: Program;
|
||||
@@ -127,11 +127,14 @@ namespace ts.server {
|
||||
|
||||
public languageServiceEnabled = true;
|
||||
|
||||
/*@internal*/
|
||||
resolutionCache: ResolutionCache;
|
||||
readonly trace?: (s: string) => void;
|
||||
readonly realpath?: (path: string) => string;
|
||||
|
||||
/*@internal*/
|
||||
lsHost: LSHost;
|
||||
hasInvalidatedResolution: HasInvalidatedResolution;
|
||||
|
||||
/*@internal*/
|
||||
resolutionCache: ResolutionCache;
|
||||
|
||||
private builder: Builder;
|
||||
/**
|
||||
@@ -161,7 +164,7 @@ namespace ts.server {
|
||||
|
||||
private typingFiles: SortedReadonlyArray<string>;
|
||||
|
||||
public typesVersion = 0;
|
||||
private typesVersion = 0;
|
||||
|
||||
public isNonTsProject() {
|
||||
this.updateGraph();
|
||||
@@ -190,7 +193,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly projectName: string,
|
||||
/*@internal*/readonly projectName: string,
|
||||
readonly projectKind: ProjectKind,
|
||||
readonly projectService: ProjectService,
|
||||
private documentRegistry: DocumentRegistry,
|
||||
@@ -198,7 +201,7 @@ namespace ts.server {
|
||||
languageServiceEnabled: boolean,
|
||||
private compilerOptions: CompilerOptions,
|
||||
public compileOnSaveEnabled: boolean,
|
||||
host: PartialSystem) {
|
||||
/*@internal*/public partialSystem: PartialSystem) {
|
||||
|
||||
if (!this.compilerOptions) {
|
||||
this.compilerOptions = getDefaultCompilerOptions();
|
||||
@@ -211,52 +214,162 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
this.setInternalCompilerOptionsForEmittingJsFiles();
|
||||
const host = this.projectService.host;
|
||||
if (host.trace) {
|
||||
this.trace = s => host.trace(s);
|
||||
}
|
||||
|
||||
this.lsHost = new LSHost(host, this, this.projectService.cancellationToken);
|
||||
this.resolutionCache = createResolutionCache(
|
||||
fileName => this.projectService.toPath(fileName),
|
||||
() => this.compilerOptions,
|
||||
directory => this.watchDirectoryOfFailedLookup(directory),
|
||||
s => this.projectService.logger.info(s),
|
||||
this.getProjectName(),
|
||||
() => this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined
|
||||
);
|
||||
this.lsHost.compilationSettings = this.compilerOptions;
|
||||
this.resolutionCache.setModuleResolutionHost(this.lsHost);
|
||||
|
||||
this.languageService = createLanguageService(this.lsHost, this.documentRegistry);
|
||||
if (host.realpath) {
|
||||
this.realpath = path => host.realpath(path);
|
||||
}
|
||||
|
||||
this.languageService = createLanguageService(this, this.documentRegistry);
|
||||
if (!languageServiceEnabled) {
|
||||
this.disableLanguageService();
|
||||
}
|
||||
|
||||
this.resolutionCache = createResolutionCache(this);
|
||||
this.markAsDirty();
|
||||
}
|
||||
|
||||
private watchDirectoryOfFailedLookup(directory: string) {
|
||||
getCompilationSettings() {
|
||||
return this.compilerOptions;
|
||||
}
|
||||
|
||||
getNewLine() {
|
||||
return this.partialSystem.newLine;
|
||||
}
|
||||
|
||||
getProjectVersion() {
|
||||
return this.projectStateVersion.toString();
|
||||
}
|
||||
|
||||
getScriptFileNames() {
|
||||
const result: string[] = [];
|
||||
if (this.rootFiles) {
|
||||
this.rootFilesMap.forEach((value, _path) => {
|
||||
const f: ScriptInfo = isScriptInfo(value) && value;
|
||||
if (this.languageServiceEnabled || (f && f.isScriptOpen())) {
|
||||
// if language service is disabled - process only files that are open
|
||||
result.push(f ? f.fileName : value as NormalizedPath);
|
||||
}
|
||||
});
|
||||
if (this.typingFiles) {
|
||||
for (const f of this.typingFiles) {
|
||||
result.push(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private getScriptInfoLSHost(fileName: string) {
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfo(fileName, /*openedByClient*/ false, this.partialSystem);
|
||||
if (scriptInfo) {
|
||||
const existingValue = this.rootFilesMap.get(scriptInfo.path);
|
||||
if (existingValue !== undefined && existingValue !== scriptInfo) {
|
||||
// This was missing path earlier but now the file exists. Update the root
|
||||
this.rootFiles.push(scriptInfo);
|
||||
this.rootFilesMap.set(scriptInfo.path, scriptInfo);
|
||||
}
|
||||
scriptInfo.attachToProject(this);
|
||||
}
|
||||
return scriptInfo;
|
||||
}
|
||||
|
||||
getScriptKind(fileName: string) {
|
||||
const info = this.getScriptInfoLSHost(fileName);
|
||||
return info && info.scriptKind;
|
||||
}
|
||||
|
||||
getScriptVersion(filename: string) {
|
||||
const info = this.getScriptInfoLSHost(filename);
|
||||
return info && info.getLatestVersion();
|
||||
}
|
||||
|
||||
getScriptSnapshot(filename: string): IScriptSnapshot {
|
||||
const scriptInfo = this.getScriptInfoLSHost(filename);
|
||||
if (scriptInfo) {
|
||||
return scriptInfo.getSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
getCancellationToken() {
|
||||
return this.projectService.cancellationToken;
|
||||
}
|
||||
|
||||
getCurrentDirectory(): string {
|
||||
return this.partialSystem.getCurrentDirectory();
|
||||
}
|
||||
|
||||
getDefaultLibFileName() {
|
||||
const nodeModuleBinDir = getDirectoryPath(normalizePath(this.projectService.host.getExecutingFilePath()));
|
||||
return combinePaths(nodeModuleBinDir, getDefaultLibFileName(this.compilerOptions));
|
||||
}
|
||||
|
||||
useCaseSensitiveFileNames() {
|
||||
return this.partialSystem.useCaseSensitiveFileNames;
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return this.partialSystem.readDirectory(path, extensions, exclude, include, depth);
|
||||
}
|
||||
|
||||
readFile(fileName: string): string | undefined {
|
||||
return this.partialSystem.readFile(fileName);
|
||||
}
|
||||
|
||||
fileExists(file: string): boolean {
|
||||
// As an optimization, don't hit the disks for files we already know don't exist
|
||||
// (because we're watching for their creation).
|
||||
const path = this.toPath(file);
|
||||
return !this.isWatchedMissingFile(path) && this.partialSystem.fileExists(file);
|
||||
}
|
||||
|
||||
getTypeRootsVersion() {
|
||||
return this.typesVersion;
|
||||
}
|
||||
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModuleFull[] {
|
||||
return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, /*logChanges*/ true);
|
||||
}
|
||||
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
|
||||
return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
|
||||
}
|
||||
|
||||
directoryExists(path: string): boolean {
|
||||
return this.partialSystem.directoryExists(path);
|
||||
}
|
||||
|
||||
getDirectories(path: string): string[] {
|
||||
return this.partialSystem.getDirectories(path);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
toPath(fileName: string) {
|
||||
return this.projectService.toPath(fileName);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback) {
|
||||
return this.projectService.watchDirectory(
|
||||
this.projectService.host,
|
||||
directory,
|
||||
fileOrFolder => this.onFileAddOrRemoveInDirectoryOfFailedLookup(fileOrFolder),
|
||||
cb,
|
||||
WatchDirectoryFlags.None,
|
||||
WatchType.FailedLookupLocation,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
private onFileAddOrRemoveInDirectoryOfFailedLookup(fileOrFolder: string) {
|
||||
const fileOrFolderPath = this.projectService.toPath(fileOrFolder);
|
||||
/*@internal*/
|
||||
onInvalidatedResolution() {
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
}
|
||||
|
||||
// There is some kind of change in the failed lookup location, update the program
|
||||
if (this.projectKind === ProjectKind.Configured) {
|
||||
(this.lsHost.host as CachedPartialSystem).addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath);
|
||||
}
|
||||
|
||||
// If the location results in update to failed lookup, schedule program update
|
||||
if (this.resolutionCache.onFileAddOrRemoveInDirectoryOfFailedLookup(fileOrFolderPath)) {
|
||||
this.markAsDirty();
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
}
|
||||
/*@internal*/
|
||||
getGlobalCache() {
|
||||
return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined;
|
||||
}
|
||||
|
||||
private setInternalCompilerOptionsForEmittingJsFiles() {
|
||||
@@ -326,10 +439,6 @@ namespace ts.server {
|
||||
return this.builder.getChangedProgramFiles(this.program);
|
||||
}
|
||||
|
||||
getProjectVersion() {
|
||||
return this.projectStateVersion.toString();
|
||||
}
|
||||
|
||||
enableLanguageService() {
|
||||
if (this.languageServiceEnabled) {
|
||||
return;
|
||||
@@ -366,7 +475,6 @@ namespace ts.server {
|
||||
|
||||
updateTypes() {
|
||||
this.typesVersion++;
|
||||
this.markAsDirty();
|
||||
}
|
||||
|
||||
close() {
|
||||
@@ -395,8 +503,7 @@ namespace ts.server {
|
||||
this.resolutionCache.clear();
|
||||
this.resolutionCache = undefined;
|
||||
this.cachedUnresolvedImportsPerFile = undefined;
|
||||
this.lsHost.dispose();
|
||||
this.lsHost = undefined;
|
||||
this.partialSystem = undefined;
|
||||
|
||||
// Clean up file watchers waiting for missing files
|
||||
if (this.missingFilesMap) {
|
||||
@@ -410,11 +517,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
isClosed() {
|
||||
return this.lsHost === undefined;
|
||||
}
|
||||
|
||||
getCompilerOptions() {
|
||||
return this.compilerOptions;
|
||||
return this.rootFiles === undefined;
|
||||
}
|
||||
|
||||
hasRoots() {
|
||||
@@ -425,25 +528,6 @@ namespace ts.server {
|
||||
return this.rootFiles && this.rootFiles.map(info => info.fileName);
|
||||
}
|
||||
|
||||
getRootFilesLSHost() {
|
||||
const result: string[] = [];
|
||||
if (this.rootFiles) {
|
||||
this.rootFilesMap.forEach((value, _path) => {
|
||||
const f: ScriptInfo = isScriptInfo(value) && value;
|
||||
if (this.languageServiceEnabled || (f && f.isScriptOpen())) {
|
||||
// if language service is disabled - process only files that are open
|
||||
result.push(f ? f.fileName : value as NormalizedPath);
|
||||
}
|
||||
});
|
||||
if (this.typingFiles) {
|
||||
for (const f of this.typingFiles) {
|
||||
result.push(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getRootFilesMap() {
|
||||
return this.rootFilesMap;
|
||||
@@ -622,7 +706,7 @@ namespace ts.server {
|
||||
*/
|
||||
updateGraph(): boolean {
|
||||
this.resolutionCache.startRecordingFilesWithChangedResolutions();
|
||||
this.lsHost.hasInvalidatedResolution = this.resolutionCache.createHasInvalidatedResolution();
|
||||
this.hasInvalidatedResolution = this.resolutionCache.createHasInvalidatedResolution();
|
||||
|
||||
let hasChanges = this.updateGraphWorker();
|
||||
|
||||
@@ -659,7 +743,7 @@ namespace ts.server {
|
||||
// Note we are retaining builder so we can send events for project change
|
||||
if (this.builder) {
|
||||
if (this.languageServiceEnabled) {
|
||||
this.builder.onProgramUpdateGraph(this.program, this.lsHost.hasInvalidatedResolution);
|
||||
this.builder.onProgramUpdateGraph(this.program, this.hasInvalidatedResolution);
|
||||
}
|
||||
else {
|
||||
this.builder.clear();
|
||||
@@ -720,7 +804,7 @@ namespace ts.server {
|
||||
// by the LSHost for files in the program when the program is retrieved above but
|
||||
// the program doesn't contain external files so this must be done explicitly.
|
||||
inserted => {
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfo(inserted, /*openedByClient*/ false, this.lsHost.host);
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfo(inserted, /*openedByClient*/ false, this.partialSystem);
|
||||
scriptInfo.attachToProject(this);
|
||||
},
|
||||
removed => {
|
||||
@@ -739,7 +823,7 @@ namespace ts.server {
|
||||
missingFilePath,
|
||||
(fileName, eventKind) => {
|
||||
if (this.projectKind === ProjectKind.Configured) {
|
||||
(this.lsHost.host as CachedPartialSystem).addOrDeleteFile(fileName, missingFilePath, eventKind);
|
||||
(this.partialSystem as CachedPartialSystem).addOrDeleteFile(fileName, missingFilePath, eventKind);
|
||||
}
|
||||
|
||||
if (eventKind === FileWatcherEventKind.Created && this.missingFilesMap.has(missingFilePath)) {
|
||||
@@ -747,7 +831,6 @@ namespace ts.server {
|
||||
fileWatcher.close();
|
||||
|
||||
// When a missing file is created, we should update the graph.
|
||||
this.markAsDirty();
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
}
|
||||
},
|
||||
@@ -757,28 +840,14 @@ namespace ts.server {
|
||||
return fileWatcher;
|
||||
}
|
||||
|
||||
isWatchedMissingFile(path: Path) {
|
||||
private isWatchedMissingFile(path: Path) {
|
||||
return this.missingFilesMap && this.missingFilesMap.has(path);
|
||||
}
|
||||
|
||||
getScriptInfoLSHost(fileName: string) {
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfo(fileName, /*openedByClient*/ false, this.lsHost.host);
|
||||
if (scriptInfo) {
|
||||
const existingValue = this.rootFilesMap.get(scriptInfo.path);
|
||||
if (existingValue !== undefined && existingValue !== scriptInfo) {
|
||||
// This was missing path earlier but now the file exists. Update the root
|
||||
this.rootFiles.push(scriptInfo);
|
||||
this.rootFilesMap.set(scriptInfo.path, scriptInfo);
|
||||
}
|
||||
scriptInfo.attachToProject(this);
|
||||
}
|
||||
return scriptInfo;
|
||||
}
|
||||
|
||||
getScriptInfoForNormalizedPath(fileName: NormalizedPath) {
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfoForNormalizedPath(
|
||||
fileName, /*openedByClient*/ false, /*fileContent*/ undefined,
|
||||
/*scriptKind*/ undefined, /*hasMixedContent*/ undefined, this.lsHost.host
|
||||
/*scriptKind*/ undefined, /*hasMixedContent*/ undefined, this.partialSystem
|
||||
);
|
||||
if (scriptInfo && !scriptInfo.isAttached(this)) {
|
||||
return Errors.ThrowProjectDoesNotContainDocument(fileName, this);
|
||||
@@ -815,8 +884,6 @@ namespace ts.server {
|
||||
if (changesAffectModuleResolution(oldOptions, compilerOptions)) {
|
||||
this.resolutionCache.clear();
|
||||
}
|
||||
this.lsHost.compilationSettings = this.compilerOptions;
|
||||
|
||||
this.markAsDirty();
|
||||
}
|
||||
}
|
||||
@@ -839,7 +906,7 @@ namespace ts.server {
|
||||
projectName: this.getProjectName(),
|
||||
version: this.projectStructureVersion,
|
||||
isInferred: this.projectKind === ProjectKind.Inferred,
|
||||
options: this.getCompilerOptions(),
|
||||
options: this.getCompilationSettings(),
|
||||
languageServiceDisabled: !this.languageServiceEnabled
|
||||
};
|
||||
const updatedFileNames = this.updatedFileNames;
|
||||
@@ -913,7 +980,7 @@ namespace ts.server {
|
||||
|
||||
setCompilerOptions(options?: CompilerOptions) {
|
||||
// Avoid manipulating the given options directly
|
||||
const newOptions = options ? cloneCompilerOptions(options) : this.getCompilerOptions();
|
||||
const newOptions = options ? cloneCompilerOptions(options) : this.getCompilationSettings();
|
||||
if (!newOptions) {
|
||||
return;
|
||||
}
|
||||
@@ -1042,7 +1109,7 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
getCachedPartialSystem() {
|
||||
return this.lsHost.host as CachedPartialSystem;
|
||||
return this.partialSystem as CachedPartialSystem;
|
||||
}
|
||||
|
||||
getConfigFilePath() {
|
||||
@@ -1051,7 +1118,7 @@ namespace ts.server {
|
||||
|
||||
enablePlugins() {
|
||||
const host = this.projectService.host;
|
||||
const options = this.getCompilerOptions();
|
||||
const options = this.getCompilationSettings();
|
||||
|
||||
if (!host.require) {
|
||||
this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded");
|
||||
@@ -1113,7 +1180,7 @@ namespace ts.server {
|
||||
config: configEntry,
|
||||
project: this,
|
||||
languageService: this.languageService,
|
||||
languageServiceHost: this.lsHost,
|
||||
languageServiceHost: this,
|
||||
serverHost: this.projectService.host
|
||||
};
|
||||
|
||||
@@ -1174,14 +1241,7 @@ namespace ts.server {
|
||||
this.directoriesWatchedForWildcards || (this.directoriesWatchedForWildcards = createMap()),
|
||||
wildcardDirectories,
|
||||
// Create new directory watcher
|
||||
(directory, flags) => this.projectService.watchDirectory(
|
||||
this.projectService.host,
|
||||
directory,
|
||||
path => this.projectService.onFileAddOrRemoveInWatchedDirectoryOfProject(this, path),
|
||||
flags,
|
||||
WatchType.WildcardDirectories,
|
||||
this
|
||||
)
|
||||
(directory, flags) => this.projectService.watchWildcardDirectory(directory as Path, flags, this),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1201,14 +1261,7 @@ namespace ts.server {
|
||||
newTypeRoots,
|
||||
{
|
||||
// Create new watch
|
||||
createNewValue: root => this.projectService.watchDirectory(
|
||||
this.projectService.host,
|
||||
root,
|
||||
path => this.projectService.onTypeRootFileChanged(this, path),
|
||||
WatchDirectoryFlags.None,
|
||||
WatchType.TypeRoot,
|
||||
this
|
||||
),
|
||||
createNewValue: root => this.projectService.watchTypeRootDirectory(root as Path, this),
|
||||
// Close existing watch thats not needed any more
|
||||
onDeleteValue: closeFileWatcher
|
||||
}
|
||||
@@ -1245,7 +1298,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getEffectiveTypeRoots() {
|
||||
return getEffectiveTypeRoots(this.getCompilerOptions(), this.lsHost.host) || [];
|
||||
return getEffectiveTypeRoots(this.getCompilationSettings(), this.partialSystem) || [];
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
|
||||
@@ -237,7 +237,7 @@ namespace ts.server {
|
||||
detachAllProjects() {
|
||||
for (const p of this.containingProjects) {
|
||||
if (p.projectKind === ProjectKind.Configured) {
|
||||
(p.lsHost.host as CachedPartialSystem).addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted);
|
||||
(p.partialSystem as CachedPartialSystem).addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted);
|
||||
}
|
||||
const isInfoRoot = p.isRoot(this);
|
||||
// detach is unnecessary since we'll clean the list of containing projects anyways
|
||||
|
||||
@@ -1218,7 +1218,7 @@ namespace ts.server {
|
||||
result.push({
|
||||
projectFileName: project.getProjectName(),
|
||||
fileNames: project.getCompileOnSaveAffectedFileList(info),
|
||||
projectUsesOutFile: !!project.getCompilerOptions().outFile || !!project.getCompilerOptions().out
|
||||
projectUsesOutFile: !!project.getCompilationSettings().outFile || !!project.getCompilationSettings().out
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"utilities.ts",
|
||||
"scriptVersionCache.ts",
|
||||
"scriptInfo.ts",
|
||||
"lsHost.ts",
|
||||
"typingsCache.ts",
|
||||
"project.ts",
|
||||
"editorServices.ts",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
},
|
||||
"files": [
|
||||
"editorServices.ts",
|
||||
"lsHost.ts",
|
||||
"project.ts",
|
||||
"protocol.ts",
|
||||
"scriptInfo.ts",
|
||||
|
||||
@@ -89,12 +89,12 @@ namespace ts.server {
|
||||
if (forceRefresh ||
|
||||
!entry ||
|
||||
typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) ||
|
||||
compilerOptionsChanged(project.getCompilerOptions(), entry.compilerOptions) ||
|
||||
compilerOptionsChanged(project.getCompilationSettings(), entry.compilerOptions) ||
|
||||
unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports)) {
|
||||
// Note: entry is now poisoned since it does not really contain typings for a given combination of compiler options\typings options.
|
||||
// instead it acts as a placeholder to prevent issuing multiple requests
|
||||
this.perProjectCache.set(project.getProjectName(), {
|
||||
compilerOptions: project.getCompilerOptions(),
|
||||
compilerOptions: project.getCompilationSettings(),
|
||||
typeAcquisition,
|
||||
typings: result,
|
||||
unresolvedImports,
|
||||
@@ -125,4 +125,4 @@ namespace ts.server {
|
||||
this.installer.onProjectClosed(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace ts.server {
|
||||
return {
|
||||
projectName: project.getProjectName(),
|
||||
fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true, /*excludeConfigFiles*/ true),
|
||||
compilerOptions: project.getCompilerOptions(),
|
||||
compilerOptions: project.getCompilationSettings(),
|
||||
typeAcquisition,
|
||||
unresolvedImports,
|
||||
projectRootPath: getProjectRootPath(project),
|
||||
|
||||
Reference in new issue
Block a user