Skip to content

Commit caa9b70

Browse files
committed
Continue looking for tsconfig if found project isnt default project for script info
1 parent 5fae043 commit caa9b70

File tree

120 files changed

+8476
-3987
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+8476
-3987
lines changed

src/server/editorServices.ts

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
DocumentRegistry,
3232
DocumentRegistryBucketKeyWithMode,
3333
emptyOptions,
34+
endsWith,
3435
ensureTrailingDirectorySeparator,
3536
ExtendedConfigCacheEntry,
3637
FileExtensionInfo,
@@ -633,10 +634,37 @@ export interface ProjectServiceOptions {
633634
*/
634635
export type ConfigFileName = NormalizedPath | false;
635636

637+
/**
638+
* Stores cached config file name for info as well as ancestor so is a map
639+
* Key is false for Open ScriptInfo
640+
* Key is NormalizedPath for Config file name
641+
* @internal
642+
*/
643+
export type ConfigFileMapForOpenFile = Map<ConfigFileName, ConfigFileName>;
644+
645+
/**
646+
* The cache for open script info will have
647+
* ConfigFileName or false if ancestors are not looked up
648+
* Map if ancestors are looked up
649+
* @internal
650+
*/
651+
export type ConfigFileForOpenFile = ConfigFileName | ConfigFileMapForOpenFile;
652+
636653
/** Gets cached value of config file name based on open script info or ancestor script info */
637-
function getConfigFileNameFromCache(info: OpenScriptInfoOrClosedOrConfigFileInfo, cache: Map<Path, ConfigFileName> | undefined): ConfigFileName | undefined {
638-
if (!cache || isAncestorConfigFileInfo(info)) return undefined;
639-
return cache.get(info.path);
654+
function getConfigFileNameFromCache(info: OpenScriptInfoOrClosedOrConfigFileInfo, cache: Map<Path, ConfigFileForOpenFile> | undefined): ConfigFileName | undefined {
655+
if (!cache) return undefined;
656+
const configFileForOpenFile = cache.get(info.path);
657+
if (configFileForOpenFile === undefined) return undefined;
658+
if (!isAncestorConfigFileInfo(info)) {
659+
return isString(configFileForOpenFile) || !configFileForOpenFile ?
660+
configFileForOpenFile : // direct result
661+
configFileForOpenFile.get(/*key*/ false); // Its a map, use false as the key for the info's config file name
662+
}
663+
else {
664+
return configFileForOpenFile && !isString(configFileForOpenFile) ? // Map with fileName as key
665+
configFileForOpenFile.get(info.fileName) :
666+
undefined; // No result for the config file name
667+
}
640668
}
641669

642670
/** @internal */
@@ -651,6 +679,7 @@ export interface AncestorConfigFileInfo {
651679
/** path of open file so we can look at correct root */
652680
path: Path;
653681
configFileInfo: true;
682+
isForDefaultProject: boolean;
654683
}
655684
/** @internal */
656685
export type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo;
@@ -699,6 +728,8 @@ function forEachAncestorProject<T>(
699728
allowDeferredClosed: boolean | undefined,
700729
/** Used with ConfiguredProjectLoadKind.Reload to check if this project was already reloaded */
701730
reloadedProjects: Set<ConfiguredProject> | undefined,
731+
/** true means we are looking for solution, so we can stop if found project is not composite to go into parent solution */
732+
searchOnlyPotentialSolution: boolean,
702733
/** Used with ConfiguredProjectLoadKind.Reload to specify delay reload, and also a set of configured projects already marked for delay load */
703734
delayReloadedConfiguredProjects?: Set<ConfiguredProject>,
704735
): T | undefined {
@@ -708,7 +739,8 @@ function forEachAncestorProject<T>(
708739
if (
709740
!project.isInitialLoadPending() &&
710741
(
711-
!project.getCompilerOptions().composite ||
742+
(searchOnlyPotentialSolution && !project.getCompilerOptions().composite) ||
743+
// TODO: Should this flag be shared between trying to load solution for find all references vs trying to find default project
712744
project.getCompilerOptions().disableSolutionSearching
713745
)
714746
) return;
@@ -718,6 +750,7 @@ function forEachAncestorProject<T>(
718750
fileName: project.getConfigFilePath(),
719751
path: info.path,
720752
configFileInfo: true,
753+
isForDefaultProject: !searchOnlyPotentialSolution,
721754
}, kind === ConfiguredProjectLoadKind.Find);
722755
if (!configFileName) return;
723756

@@ -727,9 +760,9 @@ function forEachAncestorProject<T>(
727760
kind,
728761
reason,
729762
allowDeferredClosed,
730-
/*triggerFile*/ undefined,
763+
!searchOnlyPotentialSolution ? info.fileName : undefined, // Config Diag event for project if its for default project
731764
reloadedProjects,
732-
/*delayLoad*/ true,
765+
searchOnlyPotentialSolution, // Delay load if we are searching for solution
733766
delayReloadedConfiguredProjects,
734767
);
735768
if (!ancestor) return;
@@ -1195,7 +1228,7 @@ export class ProjectService {
11951228
*/
11961229
readonly openFiles: Map<Path, NormalizedPath | undefined> = new Map<Path, NormalizedPath | undefined>();
11971230
/** Config files looked up and cached config files for open script info */
1198-
private readonly configFileForOpenFiles = new Map<Path, ConfigFileName>();
1231+
private readonly configFileForOpenFiles = new Map<Path, ConfigFileForOpenFile>();
11991232
/** Set of open script infos that are root of inferred project */
12001233
private rootOfInferredProjects = new Set<ScriptInfo>();
12011234
/**
@@ -1234,7 +1267,7 @@ export class ProjectService {
12341267
* All the open script info that needs recalculation of the default project,
12351268
* this also caches config file info before config file change was detected to use it in case projects are not updated yet
12361269
*/
1237-
private pendingOpenFileProjectUpdates?: Map<Path, ConfigFileName>;
1270+
private pendingOpenFileProjectUpdates?: Map<Path, ConfigFileForOpenFile>;
12381271
/** @internal */
12391272
pendingEnsureProjectForOpenFiles = false;
12401273

@@ -2222,7 +2255,7 @@ export class ProjectService {
22222255
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
22232256

22242257
let openFilesImpactedByConfigFile: Set<Path> | undefined;
2225-
if (this.openFiles.has(info.path) && !isAncestorConfigFileInfo(info)) {
2258+
if (this.openFiles.has(info.path) && (!isAncestorConfigFileInfo(info) || info.isForDefaultProject)) {
22262259
// By default the info would get impacted by presence of config file since its in the detection path
22272260
// Only adding the info as a root to inferred project will need the existence to be watched by file watcher
22282261
if (configFileExistenceInfo) (configFileExistenceInfo.openFilesImpactedByConfigFile ??= new Set()).add(info.path);
@@ -2416,31 +2449,39 @@ export class ProjectService {
24162449

24172450
// If projectRootPath doesn't contain info.path, then do normal search for config file
24182451
const anySearchPathOk = !projectRootPath || !isSearchPathInProjectRoot();
2419-
// For ancestor of config file always ignore its own directory since its going to result in itself
2420-
let searchInDirectory = !isAncestorConfigFileInfo(info);
2452+
2453+
let searchTsconfig = true;
2454+
let searchJsconfig = true;
2455+
if (isAncestorConfigFileInfo(info)) {
2456+
// For ancestor of config file always ignore itself
2457+
if (endsWith(info.fileName, "tsconfig.json")) searchTsconfig = false;
2458+
else searchTsconfig = searchJsconfig = false;
2459+
}
24212460
do {
2422-
if (searchInDirectory) {
2423-
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
2461+
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
2462+
if (searchTsconfig) {
24242463
const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json"));
2425-
let result = action(combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, tsconfigFileName);
2464+
const result = action(combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, tsconfigFileName);
24262465
if (result) return tsconfigFileName;
2466+
}
24272467

2468+
if (searchJsconfig) {
24282469
const jsconfigFileName = asNormalizedPath(combinePaths(searchPath, "jsconfig.json"));
2429-
result = action(combinePaths(canonicalSearchPath, "jsconfig.json") as NormalizedPath, jsconfigFileName);
2470+
const result = action(combinePaths(canonicalSearchPath, "jsconfig.json") as NormalizedPath, jsconfigFileName);
24302471
if (result) return jsconfigFileName;
2472+
}
24312473

2432-
// If we started within node_modules, don't look outside node_modules.
2433-
// Otherwise, we might pick up a very large project and pull in the world,
2434-
// causing an editor delay.
2435-
if (isNodeModulesDirectory(canonicalSearchPath)) {
2436-
break;
2437-
}
2474+
// If we started within node_modules, don't look outside node_modules.
2475+
// Otherwise, we might pick up a very large project and pull in the world,
2476+
// causing an editor delay.
2477+
if (isNodeModulesDirectory(canonicalSearchPath)) {
2478+
break;
24382479
}
24392480

24402481
const parentPath = asNormalizedPath(getDirectoryPath(searchPath));
24412482
if (parentPath === searchPath) break;
24422483
searchPath = parentPath;
2443-
searchInDirectory = true;
2484+
searchTsconfig = searchJsconfig = true;
24442485
}
24452486
while (anySearchPathOk || isSearchPathInProjectRoot());
24462487

@@ -2475,8 +2516,24 @@ export class ProjectService {
24752516
configFileName: NormalizedPath | undefined,
24762517
) {
24772518
if (!this.openFiles.has(info.path)) return; // Dont cache for closed script infos
2478-
if (isAncestorConfigFileInfo(info)) return; // Dont cache for ancestors
2479-
this.configFileForOpenFiles.set(info.path, configFileName || false);
2519+
const config = configFileName || false;
2520+
if (!isAncestorConfigFileInfo(info)) {
2521+
// Set value for open script info
2522+
this.configFileForOpenFiles.set(info.path, config);
2523+
}
2524+
else {
2525+
// Need to set value for ancestor in ConfigFileMapForOpenFile
2526+
let configFileForOpenFile = this.configFileForOpenFiles.get(info.path)!;
2527+
if (!configFileForOpenFile || isString(configFileForOpenFile)) {
2528+
// We have value for open script info in cache, make a map with that as false key and set new vlaue
2529+
this.configFileForOpenFiles.set(
2530+
info.path,
2531+
configFileForOpenFile = new Map().set(false, configFileForOpenFile),
2532+
);
2533+
}
2534+
// Set value of for ancestor in the map
2535+
configFileForOpenFile.set(info.fileName, config);
2536+
}
24802537
}
24812538

24822539
/**
@@ -4191,7 +4248,8 @@ export class ProjectService {
41914248
function tryFindDefaultConfiguredProject(project: ConfiguredProject): ConfiguredProject | undefined {
41924249
return isDefaultProject(project) ?
41934250
defaultProject :
4194-
tryFindDefaultConfiguredProjectFromReferences(project);
4251+
(tryFindDefaultConfiguredProjectFromReferences(project) ??
4252+
tryFindDefaultConfiguredProjectFromAncestor(project));
41954253
}
41964254

41974255
function isDefaultProject(project: ConfiguredProject): ConfiguredProject | undefined {
@@ -4221,6 +4279,19 @@ export class ProjectService {
42214279
reloadedProjects,
42224280
);
42234281
}
4282+
4283+
function tryFindDefaultConfiguredProjectFromAncestor(project: ConfiguredProject) {
4284+
return forEachAncestorProject( // If not in referenced projects, try ancestors and its references
4285+
info,
4286+
project,
4287+
tryFindDefaultConfiguredProject,
4288+
kind,
4289+
`Creating possible configured project for ${info.fileName} to open`,
4290+
allowDeferredClosed,
4291+
reloadedProjects,
4292+
/*searchOnlyPotentialSolution*/ false,
4293+
);
4294+
}
42244295
}
42254296

42264297
/**
@@ -4265,6 +4336,7 @@ export class ProjectService {
42654336
`Creating project possibly referencing default composite project ${defaultProject.getProjectName()} of open file ${info.fileName}`,
42664337
allowDeferredClosed,
42674338
reloadedProjects,
4339+
/*searchOnlyPotentialSolution*/ true,
42684340
delayReloadedConfiguredProjects,
42694341
);
42704342
}

tests/baselines/reference/tsserver/configuredProjects/Open-ref-of-configured-project-when-open-file-gets-added-to-the-project-as-part-of-configured-file-update-buts-its-open-file-references-are-all-closed-when-the-update-happens.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ Info seq [hh:mm:ss:mss] request:
226226
"type": "request"
227227
}
228228
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /a/b/src/file2.ts ProjectRootPath: undefined:: Result: /a/b/tsconfig.json
229+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /a/b/tsconfig.json ProjectRootPath: undefined:: Result: undefined
229230
Info seq [hh:mm:ss:mss] event:
230231
{
231232
"seq": 0,

tests/baselines/reference/tsserver/configuredProjects/Open-ref-of-configured-project-when-open-file-gets-added-to-the-project-as-part-of-configured-file-update.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ Info seq [hh:mm:ss:mss] request:
226226
"type": "request"
227227
}
228228
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /a/b/src/file2.ts ProjectRootPath: undefined:: Result: /a/b/tsconfig.json
229+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /a/b/tsconfig.json ProjectRootPath: undefined:: Result: undefined
229230
Info seq [hh:mm:ss:mss] event:
230231
{
231232
"seq": 0,

tests/baselines/reference/tsserver/configuredProjects/add-and-then-remove-a-config-file-in-a-folder-with-loose-files.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile
340340
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json
341341
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile2.ts ProjectRootPath: undefined
342342
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject2*
343+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/myproject/tsconfig.json ProjectRootPath: undefined:: Result: undefined
343344
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
344345
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 2 projectProgramVersion: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
345346
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
@@ -631,6 +632,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile
631632
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*,/user/username/projects/myproject/tsconfig.json
632633
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile2.ts ProjectRootPath: undefined
633634
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject2*
635+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/myproject/tsconfig.json ProjectRootPath: undefined:: Result: undefined
634636
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
635637
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 4 projectProgramVersion: 3 structureChanged: true structureIsReused:: Not Elapsed:: *ms
636638
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
@@ -1536,6 +1538,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile
15361538
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json
15371539
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile2.ts ProjectRootPath: undefined
15381540
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject4*
1541+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/myproject/tsconfig.json ProjectRootPath: undefined:: Result: undefined
15391542
Info seq [hh:mm:ss:mss] After ensureProjectForOpenFiles:
15401543
Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured)
15411544
Info seq [hh:mm:ss:mss] Files (2)

0 commit comments

Comments
 (0)