Skip to content

Commit 432772e

Browse files
authored
Merge pull request #28417 from Microsoft/relativeFilesThroughDynamicFile
Allow creation of relative path file infos only for open script infos and dynamic file
2 parents 89fda5c + 8dd05d5 commit 432772e

File tree

4 files changed

+153
-65
lines changed

4 files changed

+153
-65
lines changed

src/server/editorServices.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -835,9 +835,9 @@ namespace ts.server {
835835

836836
/* @internal */
837837
private forEachProject(cb: (project: Project) => void) {
838-
this.inferredProjects.forEach(cb);
839-
this.configuredProjects.forEach(cb);
840838
this.externalProjects.forEach(cb);
839+
this.configuredProjects.forEach(cb);
840+
this.inferredProjects.forEach(cb);
841841
}
842842

843843
/* @internal */
@@ -1037,7 +1037,8 @@ namespace ts.server {
10371037
}
10381038

10391039
private removeProject(project: Project) {
1040-
this.logger.info(`remove project: ${project.getRootFiles().toString()}`);
1040+
this.logger.info("`remove Project::");
1041+
project.print();
10411042

10421043
project.close();
10431044
if (Debug.shouldAssert(AssertionLevel.Normal)) {
@@ -1477,19 +1478,9 @@ namespace ts.server {
14771478

14781479
const writeProjectFileNames = this.logger.hasLevel(LogLevel.verbose);
14791480
this.logger.startGroup();
1480-
let counter = 0;
1481-
const printProjects = (projects: Project[], counter: number): number => {
1482-
for (const project of projects) {
1483-
this.logger.info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
1484-
this.logger.info(project.filesToString(writeProjectFileNames));
1485-
this.logger.info("-----------------------------------------------");
1486-
counter++;
1487-
}
1488-
return counter;
1489-
};
1490-
counter = printProjects(this.externalProjects, counter);
1491-
counter = printProjects(arrayFrom(this.configuredProjects.values()), counter);
1492-
printProjects(this.inferredProjects, counter);
1481+
let counter = printProjectsWithCounter(this.externalProjects, 0);
1482+
counter = printProjectsWithCounter(arrayFrom(this.configuredProjects.values()), counter);
1483+
printProjectsWithCounter(this.inferredProjects, counter);
14931484

14941485
this.logger.info("Open files: ");
14951486
this.openFiles.forEach((projectRootPath, path) => {
@@ -2118,7 +2109,20 @@ namespace ts.server {
21182109
}
21192110

21202111
private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) {
2121-
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
2112+
if (isRootedDiskPath(fileName) || isDynamicFileName(fileName)) {
2113+
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
2114+
}
2115+
2116+
// This is non rooted path with different current directory than project service current directory
2117+
// Only paths recognized are open relative file paths
2118+
const info = this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName));
2119+
if (info) {
2120+
return info;
2121+
}
2122+
2123+
// This means triple slash references wont be resolved in dynamic and unsaved files
2124+
// which is intentional since we dont know what it means to be relative to non disk files
2125+
return undefined;
21222126
}
21232127

21242128
private getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) {
@@ -2135,7 +2139,7 @@ namespace ts.server {
21352139
let info = this.getScriptInfoForPath(path);
21362140
if (!info) {
21372141
const isDynamic = isDynamicFileName(fileName);
2138-
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info`);
2142+
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`);
21392143
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`);
21402144
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always have current directory context since containing external project name will always match the script info name.`);
21412145
// If the file is not opened by client and the file doesnot exist on the disk, return
@@ -2148,7 +2152,7 @@ namespace ts.server {
21482152
if (!openedByClient) {
21492153
this.watchClosedScriptInfo(info);
21502154
}
2151-
else if (!isRootedDiskPath(fileName) && currentDirectory !== this.currentDirectory) {
2155+
else if (!isRootedDiskPath(fileName) && !isDynamic) {
21522156
// File that is opened by user but isn't rooted disk path
21532157
this.openFilesWithNonRootedDiskPath.set(this.toCanonicalFileName(fileName), info);
21542158
}
@@ -2909,4 +2913,12 @@ namespace ts.server {
29092913
export function isConfigFile(config: ScriptInfoOrConfig): config is TsConfigSourceFile {
29102914
return (config as TsConfigSourceFile).kind !== undefined;
29112915
}
2916+
2917+
function printProjectsWithCounter(projects: Project[], counter: number) {
2918+
for (const project of projects) {
2919+
project.print(counter);
2920+
counter++;
2921+
}
2922+
return counter;
2923+
}
29122924
}

src/server/project.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,13 @@ namespace ts.server {
995995
return strBuilder;
996996
}
997997

998+
/*@internal*/
999+
print(counter?: number) {
1000+
this.writeLog(`Project '${this.projectName}' (${ProjectKind[this.projectKind]}) ${counter === undefined ? "" : counter}`);
1001+
this.writeLog(this.filesToString(this.projectService.logger.hasLevel(LogLevel.verbose)));
1002+
this.writeLog("-----------------------------------------------");
1003+
}
1004+
9981005
setCompilerOptions(compilerOptions: CompilerOptions) {
9991006
if (compilerOptions) {
10001007
compilerOptions.allowNonTsExtensions = true;

src/server/session.ts

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,6 @@ namespace ts.server {
289289
function combineProjectOutputWhileOpeningReferencedProjects<T>(
290290
projects: Projects,
291291
defaultProject: Project,
292-
projectService: ProjectService,
293292
action: (project: Project) => ReadonlyArray<T>,
294293
getLocation: (t: T) => sourcemaps.SourceMappableLocation,
295294
resultsEqual: (a: T, b: T) => boolean,
@@ -299,7 +298,6 @@ namespace ts.server {
299298
projects,
300299
defaultProject,
301300
/*initialLocation*/ undefined,
302-
projectService,
303301
({ project }, tryAddToTodo) => {
304302
for (const output of action(project)) {
305303
if (!contains(outputs, output, resultsEqual) && !tryAddToTodo(project, getLocation(output))) {
@@ -312,17 +310,27 @@ namespace ts.server {
312310
}
313311

314312
function combineProjectOutputForRenameLocations(
315-
projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService, findInStrings: boolean, findInComments: boolean
313+
projects: Projects,
314+
defaultProject: Project,
315+
initialLocation: sourcemaps.SourceMappableLocation,
316+
findInStrings: boolean,
317+
findInComments: boolean
316318
): ReadonlyArray<RenameLocation> {
317319
const outputs: RenameLocation[] = [];
318320

319-
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
320-
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.position, findInStrings, findInComments) || emptyArray) {
321-
if (!contains(outputs, output, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(output))) {
322-
outputs.push(output);
321+
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(
322+
projects,
323+
defaultProject,
324+
initialLocation,
325+
({ project, location }, tryAddToTodo) => {
326+
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.position, findInStrings, findInComments) || emptyArray) {
327+
if (!contains(outputs, output, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(output))) {
328+
outputs.push(output);
329+
}
323330
}
324-
}
325-
}, () => getDefinitionLocation(defaultProject, initialLocation));
331+
},
332+
() => getDefinitionLocation(defaultProject, initialLocation)
333+
);
326334

327335
return outputs;
328336
}
@@ -333,31 +341,41 @@ namespace ts.server {
333341
return info && { fileName: info.fileName, position: info.textSpan.start };
334342
}
335343

336-
function combineProjectOutputForReferences(projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
344+
function combineProjectOutputForReferences(
345+
projects: Projects,
346+
defaultProject: Project,
347+
initialLocation: sourcemaps.SourceMappableLocation
348+
): ReadonlyArray<ReferencedSymbol> {
337349
const outputs: ReferencedSymbol[] = [];
338350

339-
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, getMappedLocation) => {
340-
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
341-
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
342-
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
343-
...outputReferencedSymbol.definition,
344-
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
345-
fileName: mappedDefinitionFile.fileName,
346-
};
347-
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
348-
if (!symbolToAddTo) {
349-
symbolToAddTo = { definition, references: [] };
350-
outputs.push(symbolToAddTo);
351-
}
351+
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(
352+
projects,
353+
defaultProject,
354+
initialLocation,
355+
({ project, location }, getMappedLocation) => {
356+
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
357+
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
358+
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
359+
...outputReferencedSymbol.definition,
360+
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
361+
fileName: mappedDefinitionFile.fileName,
362+
};
363+
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
364+
if (!symbolToAddTo) {
365+
symbolToAddTo = { definition, references: [] };
366+
outputs.push(symbolToAddTo);
367+
}
352368

353-
for (const ref of outputReferencedSymbol.references) {
354-
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
355-
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
356-
symbolToAddTo.references.push(ref);
369+
for (const ref of outputReferencedSymbol.references) {
370+
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
371+
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
372+
symbolToAddTo.references.push(ref);
373+
}
357374
}
358375
}
359-
}
360-
}, () => getDefinitionLocation(defaultProject, initialLocation));
376+
},
377+
() => getDefinitionLocation(defaultProject, initialLocation)
378+
);
361379

362380
return outputs.filter(o => o.references.length !== 0);
363381
}
@@ -389,10 +407,10 @@ namespace ts.server {
389407
projects: Projects,
390408
defaultProject: Project,
391409
initialLocation: TLocation,
392-
projectService: ProjectService,
393410
cb: CombineProjectOutputCallback<TLocation>,
394411
getDefinition: (() => sourcemaps.SourceMappableLocation | undefined) | undefined,
395412
): void {
413+
const projectService = defaultProject.projectService;
396414
let toDo: ProjectAndLocation<TLocation>[] | undefined;
397415
const seenProjects = createMap<true>();
398416
forEachProjectInProjects(projects, initialLocation && initialLocation.fileName, (project, path) => {
@@ -1208,7 +1226,13 @@ namespace ts.server {
12081226
const position = this.getPositionInFile(args, file);
12091227
const projects = this.getProjects(args);
12101228

1211-
const locations = combineProjectOutputForRenameLocations(projects, this.getDefaultProject(args), { fileName: args.file, position }, this.projectService, !!args.findInStrings, !!args.findInComments);
1229+
const locations = combineProjectOutputForRenameLocations(
1230+
projects,
1231+
this.getDefaultProject(args),
1232+
{ fileName: args.file, position },
1233+
!!args.findInStrings,
1234+
!!args.findInComments
1235+
);
12121236
if (!simplifiedResult) return locations;
12131237

12141238
const defaultProject = this.getDefaultProject(args);
@@ -1242,7 +1266,11 @@ namespace ts.server {
12421266
const file = toNormalizedPath(args.file);
12431267
const projects = this.getProjects(args);
12441268
const position = this.getPositionInFile(args, file);
1245-
const references = combineProjectOutputForReferences(projects, this.getDefaultProject(args), { fileName: args.file, position }, this.projectService);
1269+
const references = combineProjectOutputForReferences(
1270+
projects,
1271+
this.getDefaultProject(args),
1272+
{ fileName: args.file, position },
1273+
);
12461274

12471275
if (simplifiedResult) {
12481276
const defaultProject = this.getDefaultProject(args);
@@ -1749,7 +1777,6 @@ namespace ts.server {
17491777
return combineProjectOutputWhileOpeningReferencedProjects<NavigateToItem>(
17501778
this.getProjects(args),
17511779
this.getDefaultProject(args),
1752-
this.projectService,
17531780
project =>
17541781
project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject()),
17551782
documentSpanLocation,

0 commit comments

Comments
 (0)