Skip to content

Commit f3b0a2d

Browse files
committed
Move the original location getter to ProjectService.
This is in anticipation of work needed to keep original projects alive
1 parent 1345a35 commit f3b0a2d

File tree

4 files changed

+56
-40
lines changed

4 files changed

+56
-40
lines changed

src/server/editorServices.ts

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,13 @@ namespace ts.server {
326326
syntaxOnly?: boolean;
327327
}
328328

329+
interface OriginalFileInfo { fileName: NormalizedPath; path: Path; }
330+
type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo;
331+
332+
function isOpenScriptInfo(infoOrFileName: OpenScriptInfoOrClosedFileInfo): infoOrFileName is ScriptInfo {
333+
return !!(infoOrFileName as ScriptInfo).containingProjects;
334+
}
335+
329336
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
330337
return `Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
331338
}
@@ -1044,12 +1051,12 @@ namespace ts.server {
10441051
}
10451052
}
10461053

1047-
private configFileExists(configFileName: NormalizedPath, canonicalConfigFilePath: string, info: ScriptInfo) {
1054+
private configFileExists(configFileName: NormalizedPath, canonicalConfigFilePath: string, info: OpenScriptInfoOrClosedFileInfo) {
10481055
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
10491056
if (configFileExistenceInfo) {
10501057
// By default the info would get impacted by presence of config file since its in the detection path
10511058
// Only adding the info as a root to inferred project will need the existence to be watched by file watcher
1052-
if (!configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
1059+
if (isOpenScriptInfo(info) && !configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
10531060
configFileExistenceInfo.openFilesImpactedByConfigFile.set(info.path, false);
10541061
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.OpenFilesImpactedByConfigFileAdd);
10551062
}
@@ -1066,9 +1073,11 @@ namespace ts.server {
10661073
// Or the whole chain of config files for the roots of the inferred projects
10671074

10681075
// Cache the host value of file exists and add the info to map of open files impacted by this config file
1069-
const openFilesImpactedByConfigFile = createMap<boolean>();
1070-
openFilesImpactedByConfigFile.set(info.path, false);
10711076
const exists = this.host.fileExists(configFileName);
1077+
const openFilesImpactedByConfigFile = createMap<boolean>();
1078+
if (isOpenScriptInfo(info)) {
1079+
openFilesImpactedByConfigFile.set(info.path, false);
1080+
}
10721081
configFileExistenceInfo = { exists, openFilesImpactedByConfigFile };
10731082
this.configFileExistenceInfoCache.set(canonicalConfigFilePath, configFileExistenceInfo);
10741083
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.OpenFilesImpactedByConfigFileAdd);
@@ -1180,7 +1189,7 @@ namespace ts.server {
11801189
*/
11811190
private stopWatchingConfigFilesForClosedScriptInfo(info: ScriptInfo) {
11821191
Debug.assert(!info.isScriptOpen());
1183-
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
1192+
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
11841193
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
11851194
if (configFileExistenceInfo) {
11861195
const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile.get(info.path);
@@ -1214,7 +1223,7 @@ namespace ts.server {
12141223
/* @internal */
12151224
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
12161225
Debug.assert(info.isScriptOpen());
1217-
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
1226+
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
12181227
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
12191228
if (!configFileExistenceInfo) {
12201229
// Create the cache
@@ -1242,7 +1251,7 @@ namespace ts.server {
12421251
*/
12431252
/* @internal */
12441253
stopWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
1245-
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
1254+
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
12461255
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
12471256
if (configFileExistenceInfo && configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
12481257
Debug.assert(info.isScriptOpen());
@@ -1265,12 +1274,12 @@ namespace ts.server {
12651274
* The server must start searching from the directory containing
12661275
* the newly opened file.
12671276
*/
1268-
private forEachConfigFileLocation(info: ScriptInfo, infoShouldBeOpen: boolean, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
1277+
private forEachConfigFileLocation(info: OpenScriptInfoOrClosedFileInfo, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
12691278
if (this.syntaxOnly) {
12701279
return undefined;
12711280
}
12721281

1273-
Debug.assert(!infoShouldBeOpen || this.openFiles.has(info.path));
1282+
Debug.assert(!isOpenScriptInfo(info) || this.openFiles.has(info.path));
12741283
const projectRootPath = this.openFiles.get(info.path);
12751284

12761285
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
@@ -1309,11 +1318,13 @@ namespace ts.server {
13091318
* current directory (the directory in which tsc was invoked).
13101319
* The server must start searching from the directory containing
13111320
* the newly opened file.
1321+
* If script info is passed in, it is asserted to be open script info
1322+
* otherwise just file name
13121323
*/
1313-
private getConfigFileNameForFile(info: ScriptInfo, infoShouldBeOpen: boolean) {
1314-
if (infoShouldBeOpen) Debug.assert(info.isScriptOpen());
1324+
private getConfigFileNameForFile(info: OpenScriptInfoOrClosedFileInfo) {
1325+
if (isOpenScriptInfo(info)) Debug.assert(info.isScriptOpen());
13151326
this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`);
1316-
const configFileName = this.forEachConfigFileLocation(info, infoShouldBeOpen, (configFileName, canonicalConfigFilePath) =>
1327+
const configFileName = this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) =>
13171328
this.configFileExists(configFileName, canonicalConfigFilePath, info));
13181329
if (configFileName) {
13191330
this.logger.info(`For info: ${info.fileName} :: Config file name: ${configFileName}`);
@@ -2005,7 +2016,7 @@ namespace ts.server {
20052016
// we first detect if there is already a configured project created for it: if so,
20062017
// we re- read the tsconfig file content and update the project only if we havent already done so
20072018
// otherwise we create a new one.
2008-
const configFileName = this.getConfigFileNameForFile(info, /*infoShouldBeOpen*/ true);
2019+
const configFileName = this.getConfigFileNameForFile(info);
20092020
if (configFileName) {
20102021
const project = this.findConfiguredProjectByProjectName(configFileName);
20112022
if (!project) {
@@ -2093,17 +2104,25 @@ namespace ts.server {
20932104
return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath ? toNormalizedPath(projectRootPath) : undefined);
20942105
}
20952106

2096-
/** @internal */
2097-
getProjectForFileWithoutOpening(fileName: NormalizedPath): { readonly scriptInfo: ScriptInfo, readonly projects: ReadonlyArray<Project> } | undefined {
2098-
const scriptInfo = this.filenameToScriptInfo.get(fileName) ||
2099-
this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName, this.currentDirectory, /*fileContent*/ undefined, /*scriptKind*/ undefined, /*hasMixedContent*/ undefined);
2100-
if (!scriptInfo) return undefined;
2101-
if (scriptInfo.containingProjects.length) {
2102-
return { scriptInfo, projects: scriptInfo.containingProjects };
2107+
/*@internal*/
2108+
getOriginalLocationEnsuringConfiguredProject(project: Project, location: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
2109+
const originalLocation = project.getSourceMapper().tryGetOriginalLocation(location);
2110+
if (!originalLocation) return undefined;
2111+
2112+
const { fileName } = originalLocation;
2113+
const originalScriptInfo = this.getScriptInfo(fileName);
2114+
if (originalScriptInfo && originalScriptInfo.containingProjects.length) {
2115+
return originalLocation;
21032116
}
2104-
const configFileName = this.getConfigFileNameForFile(scriptInfo, /*infoShouldBeOpen*/ false);
2105-
const project = configFileName === undefined ? undefined : this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
2106-
return project && project.containsScriptInfo(scriptInfo) ? { scriptInfo, projects: [project] } : undefined;
2117+
2118+
const info: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) };
2119+
const configFileName = this.getConfigFileNameForFile(info);
2120+
if (!configFileName) return undefined;
2121+
2122+
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
2123+
updateProjectIfDirty(configuredProject);
2124+
2125+
return configuredProject.containsFile(info.fileName) ? originalLocation : undefined;
21072126
}
21082127

21092128
/** @internal */
@@ -2128,7 +2147,7 @@ namespace ts.server {
21282147
this.openFiles.set(info.path, projectRootPath);
21292148
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
21302149
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
2131-
configFileName = this.getConfigFileNameForFile(info, /*infoShouldBeOpen*/ true);
2150+
configFileName = this.getConfigFileNameForFile(info);
21322151
if (configFileName) {
21332152
project = this.findConfiguredProjectByProjectName(configFileName);
21342153
if (!project) {

src/server/project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ namespace ts.server {
711711
}
712712

713713
containsFile(filename: NormalizedPath, requireOpen?: boolean): boolean {
714-
const info = this.projectService.getScriptInfoForPath(this.toPath(filename));
714+
const info = this.projectService.getScriptInfoForNormalizedPath(filename);
715715
if (info && (info.isScriptOpen() || !requireOpen)) {
716716
return this.containsScriptInfo(info);
717717
}

src/server/session.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -427,23 +427,20 @@ namespace ts.server {
427427
if (projectAndLocation.project.getCancellationToken().isCancellationRequested()) return undefined; // Skip rest of toDo if cancelled
428428
cb(projectAndLocation, (project, location) => {
429429
seenProjects.set(projectAndLocation.project.projectName, true);
430-
const originalLocation = project.getSourceMapper().tryGetOriginalLocation(location);
430+
const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject(project, location);
431431
if (!originalLocation) return false;
432-
const originalProjectAndScriptInfo = projectService.getProjectForFileWithoutOpening(toNormalizedPath(originalLocation.fileName));
433-
if (!originalProjectAndScriptInfo) return false;
434432

435-
if (originalProjectAndScriptInfo) {
436-
toDo = toDo || [];
433+
const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!;
434+
toDo = toDo || [];
437435

438-
for (const project of originalProjectAndScriptInfo.projects) {
439-
addToTodo({ project, location: originalLocation as TLocation }, toDo, seenProjects);
440-
}
441-
const symlinkedProjectsMap = projectService.getSymlinkedProjects(originalProjectAndScriptInfo.scriptInfo);
442-
if (symlinkedProjectsMap) {
443-
symlinkedProjectsMap.forEach((symlinkedProjects) => {
444-
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
445-
});
446-
}
436+
for (const project of originalScriptInfo.containingProjects) {
437+
addToTodo({ project, location: originalLocation as TLocation }, toDo, seenProjects);
438+
}
439+
const symlinkedProjectsMap = projectService.getSymlinkedProjects(originalScriptInfo);
440+
if (symlinkedProjectsMap) {
441+
symlinkedProjectsMap.forEach((symlinkedProjects) => {
442+
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
443+
});
447444
}
448445
return true;
449446
});

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9458,7 +9458,7 @@ export function Test2() {
94589458
});
94599459
});
94609460

9461-
describe("Untitled files", () => {
9461+
describe("tsserverProjectSystem Untitled files", () => {
94629462
it("Can convert positions to locations", () => {
94639463
const aTs: File = { path: "/proj/a.ts", content: "" };
94649464
const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" };

0 commit comments

Comments
 (0)