Skip to content

Commit b2f76e9

Browse files
authored
Merge pull request #29240 from Microsoft/inferredProjectToExternalProject
The assert that cached value of config file existance is always correct, might not be true if file watcher is not invoked before creating configured project
2 parents 799656a + 24cc284 commit b2f76e9

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

src/server/editorServices.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,8 @@ namespace ts.server {
12771277
private setConfigFileExistenceByNewConfiguredProject(project: ConfiguredProject) {
12781278
const configFileExistenceInfo = this.getConfigFileExistenceInfo(project);
12791279
if (configFileExistenceInfo) {
1280-
Debug.assert(configFileExistenceInfo.exists);
1280+
// The existance might not be set if the file watcher is not invoked by the time config project is created by external project
1281+
configFileExistenceInfo.exists = true;
12811282
// close existing watcher
12821283
if (configFileExistenceInfo.configFileWatcherForRootOfInferredProject) {
12831284
const configFileName = project.getConfigFilePath();

src/testRunner/unittests/tsserver/externalProjects.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,5 +760,63 @@ namespace ts.projectSystem {
760760
assert.equal(project2.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
761761
checkProjectActualFiles(project2, [config.path, f1.path]);
762762
});
763+
764+
it("handles creation of external project with jsconfig before jsconfig creation watcher is invoked", () => {
765+
const projectLocation = `/user/username/projects/WebApplication36/WebApplication36`;
766+
const projectFileName = `${projectLocation}/WebApplication36.csproj`;
767+
const tsconfig: File = {
768+
path: `${projectLocation}/tsconfig.json`,
769+
content: "{}"
770+
};
771+
const files = [libFile, tsconfig];
772+
const host = createServerHost(files);
773+
const service = createProjectService(host);
774+
775+
// Create external project
776+
service.openExternalProjects([{
777+
projectFileName,
778+
rootFiles: [{ fileName: tsconfig.path }],
779+
options: { allowJs: false }
780+
}]);
781+
checkNumberOfProjects(service, { configuredProjects: 1 });
782+
const configProject = service.configuredProjects.get(tsconfig.path.toLowerCase())!;
783+
checkProjectActualFiles(configProject, [tsconfig.path]);
784+
785+
// write js file, open external project and open it for edit
786+
const jsFilePath = `${projectLocation}/javascript.js`;
787+
host.writeFile(jsFilePath, "");
788+
service.openExternalProjects([{
789+
projectFileName,
790+
rootFiles: [{ fileName: tsconfig.path }, { fileName: jsFilePath }],
791+
options: { allowJs: false }
792+
}]);
793+
service.applyChangesInOpenFiles([
794+
{ fileName: jsFilePath, scriptKind: ScriptKind.JS, content: "" }
795+
], /*changedFiles*/ undefined, /*closedFiles*/ undefined);
796+
checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
797+
checkProjectActualFiles(configProject, [tsconfig.path]);
798+
const inferredProject = service.inferredProjects[0];
799+
checkProjectActualFiles(inferredProject, [libFile.path, jsFilePath]);
800+
801+
// write jsconfig file
802+
const jsConfig: File = {
803+
path: `${projectLocation}/jsconfig.json`,
804+
content: "{}"
805+
};
806+
// Dont invoke file creation watchers as the repro suggests
807+
host.ensureFileOrFolder(jsConfig, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true);
808+
809+
// Open external project
810+
service.openExternalProjects([{
811+
projectFileName,
812+
rootFiles: [{ fileName: jsConfig.path }, { fileName: tsconfig.path }, { fileName: jsFilePath }],
813+
options: { allowJs: false }
814+
}]);
815+
checkNumberOfProjects(service, { configuredProjects: 2, inferredProjects: 1 });
816+
checkProjectActualFiles(configProject, [tsconfig.path]);
817+
assert.isTrue(inferredProject.isOrphan());
818+
const jsConfigProject = service.configuredProjects.get(jsConfig.path.toLowerCase())!;
819+
checkProjectActualFiles(jsConfigProject, [jsConfig.path, jsFilePath, libFile.path]);
820+
});
763821
});
764822
}

src/testRunner/unittests/tsserver/helpers.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ namespace ts.projectSystem {
5757

5858
export const nullLogger: server.Logger = {
5959
close: noop,
60-
hasLevel: () => false,
61-
loggingEnabled: () => false,
60+
hasLevel: returnFalse,
61+
loggingEnabled: returnFalse,
6262
perftrc: noop,
6363
info: noop,
6464
msg: noop,
@@ -80,6 +80,21 @@ namespace ts.projectSystem {
8080
return { logger, hasErrorMsg: () => hasErrorMsg };
8181
}
8282

83+
export function createLoggerWritingToConsole(): server.Logger {
84+
const { close, startGroup, endGroup, getLogFileName } = nullLogger;
85+
return {
86+
close,
87+
hasLevel: returnTrue,
88+
loggingEnabled: returnTrue,
89+
perftrc: s => console.log(s),
90+
info: s => console.log(s),
91+
msg: (s, type) => console.log(`${type}:: ${s}`),
92+
startGroup,
93+
endGroup,
94+
getLogFileName
95+
};
96+
}
97+
8398
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
8499
protected projectService!: server.ProjectService;
85100
constructor(

0 commit comments

Comments
 (0)