• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.projectSystem {
2    describe("unittests:: tsserver:: searching for config file", () => {
3        it("should stop at projectRootPath if given", () => {
4            const f1 = {
5                path: "/a/file1.ts",
6                content: ""
7            };
8            const configFile = {
9                path: "/tsconfig.json",
10                content: "{}"
11            };
12            const host = createServerHost([f1, configFile]);
13            const service = createProjectService(host);
14            service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a");
15
16            checkNumberOfConfiguredProjects(service, 0);
17            checkNumberOfInferredProjects(service, 1);
18
19            service.closeClientFile(f1.path);
20            service.openClientFile(f1.path);
21            checkNumberOfConfiguredProjects(service, 1);
22            checkNumberOfInferredProjects(service, 0);
23        });
24
25        it("should use projectRootPath when searching for inferred project again", () => {
26            const projectDir = "/a/b/projects/project";
27            const configFileLocation = `${projectDir}/src`;
28            const f1 = {
29                path: `${configFileLocation}/file1.ts`,
30                content: ""
31            };
32            const configFile = {
33                path: `${configFileLocation}/tsconfig.json`,
34                content: "{}"
35            };
36            const configFile2 = {
37                path: "/a/b/projects/tsconfig.json",
38                content: "{}"
39            };
40            const host = createServerHost([f1, libFile, configFile, configFile2]);
41            const service = createProjectService(host);
42            service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir);
43            checkNumberOfProjects(service, { configuredProjects: 1 });
44            assert.isDefined(service.configuredProjects.get(configFile.path));
45            checkWatchedFiles(host, [libFile.path, configFile.path]);
46            checkWatchedDirectories(host, [], /*recursive*/ false);
47            const typeRootLocations = getTypeRootsFromLocation(configFileLocation);
48            checkWatchedDirectories(host, typeRootLocations.concat(configFileLocation), /*recursive*/ true);
49
50            // Delete config file - should create inferred project and not configured project
51            host.deleteFile(configFile.path);
52            host.runQueuedTimeoutCallbacks();
53            checkNumberOfProjects(service, { inferredProjects: 1 });
54            checkWatchedFiles(host, [libFile.path, configFile.path, `${configFileLocation}/jsconfig.json`, `${projectDir}/tsconfig.json`, `${projectDir}/jsconfig.json`]);
55            checkWatchedDirectories(host, [], /*recursive*/ false);
56            checkWatchedDirectories(host, typeRootLocations, /*recursive*/ true);
57        });
58
59        it("should use projectRootPath when searching for inferred project again 2", () => {
60            const projectDir = "/a/b/projects/project";
61            const configFileLocation = `${projectDir}/src`;
62            const f1 = {
63                path: `${configFileLocation}/file1.ts`,
64                content: ""
65            };
66            const configFile = {
67                path: `${configFileLocation}/tsconfig.json`,
68                content: "{}"
69            };
70            const configFile2 = {
71                path: "/a/b/projects/tsconfig.json",
72                content: "{}"
73            };
74            const host = createServerHost([f1, libFile, configFile, configFile2]);
75            const service = createProjectService(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true });
76            service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectDir);
77            checkNumberOfProjects(service, { configuredProjects: 1 });
78            assert.isDefined(service.configuredProjects.get(configFile.path));
79            checkWatchedFiles(host, [libFile.path, configFile.path]);
80            checkWatchedDirectories(host, [], /*recursive*/ false);
81            checkWatchedDirectories(host, getTypeRootsFromLocation(configFileLocation).concat(configFileLocation), /*recursive*/ true);
82
83            // Delete config file - should create inferred project with project root path set
84            host.deleteFile(configFile.path);
85            host.runQueuedTimeoutCallbacks();
86            checkNumberOfProjects(service, { inferredProjects: 1 });
87            assert.equal(service.inferredProjects[0].projectRootPath, projectDir);
88            checkWatchedFiles(host, [libFile.path, configFile.path, `${configFileLocation}/jsconfig.json`, `${projectDir}/tsconfig.json`, `${projectDir}/jsconfig.json`]);
89            checkWatchedDirectories(host, [], /*recursive*/ false);
90            checkWatchedDirectories(host, getTypeRootsFromLocation(projectDir), /*recursive*/ true);
91        });
92
93        describe("when the opened file is not from project root", () => {
94            const projectRoot = "/a/b/projects/project";
95            const file: File = {
96                path: `${projectRoot}/src/index.ts`,
97                content: "let y = 10"
98            };
99            const tsconfig: File = {
100                path: `${projectRoot}/tsconfig.json`,
101                content: "{}"
102            };
103            const dirOfFile = getDirectoryPath(file.path);
104
105            function openClientFile(files: File[]) {
106                const host = createServerHost(files);
107                const projectService = createProjectService(host);
108
109                projectService.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a/b/projects/proj");
110                return { host, projectService };
111            }
112
113            function verifyConfiguredProject(host: TestServerHost, projectService: TestProjectService, orphanInferredProject?: boolean) {
114                projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: orphanInferredProject ? 1 : 0 });
115                const project = Debug.checkDefined(projectService.configuredProjects.get(tsconfig.path));
116
117                if (orphanInferredProject) {
118                    const inferredProject = projectService.inferredProjects[0];
119                    assert.isTrue(inferredProject.isOrphan());
120                }
121
122                checkProjectActualFiles(project, [file.path, libFile.path, tsconfig.path]);
123                checkWatchedFiles(host, [libFile.path, tsconfig.path]);
124                checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
125                checkWatchedDirectories(host, (orphanInferredProject ? [projectRoot, `${dirOfFile}/node_modules/@types`] : [projectRoot]).concat(getTypeRootsFromLocation(projectRoot)), /*recursive*/ true);
126            }
127
128            function verifyInferredProject(host: TestServerHost, projectService: TestProjectService) {
129                projectService.checkNumberOfProjects({ inferredProjects: 1 });
130                const project = projectService.inferredProjects[0];
131                assert.isDefined(project);
132
133                const filesToWatch = [libFile.path, ...getConfigFilesToWatch(dirOfFile)];
134
135                checkProjectActualFiles(project, [file.path, libFile.path]);
136                checkWatchedFiles(host, filesToWatch);
137                checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
138                checkWatchedDirectories(host, getTypeRootsFromLocation(dirOfFile), /*recursive*/ true);
139            }
140
141            it("tsconfig for the file exists", () => {
142                const { host, projectService } = openClientFile([file, libFile, tsconfig]);
143                verifyConfiguredProject(host, projectService);
144
145                host.deleteFile(tsconfig.path);
146                host.runQueuedTimeoutCallbacks();
147                verifyInferredProject(host, projectService);
148
149                host.writeFile(tsconfig.path, tsconfig.content);
150                host.runQueuedTimeoutCallbacks();
151                verifyConfiguredProject(host, projectService, /*orphanInferredProject*/ true);
152            });
153
154            it("tsconfig for the file does not exist", () => {
155                const { host, projectService } = openClientFile([file, libFile]);
156                verifyInferredProject(host, projectService);
157
158                host.writeFile(tsconfig.path, tsconfig.content);
159                host.runQueuedTimeoutCallbacks();
160                verifyConfiguredProject(host, projectService, /*orphanInferredProject*/ true);
161
162                host.deleteFile(tsconfig.path);
163                host.runQueuedTimeoutCallbacks();
164                verifyInferredProject(host, projectService);
165            });
166        });
167
168        describe("should not search and watch config files from directories that cannot be watched", () => {
169            const root = "/root/teams/VSCode68/Shared Documents/General/jt-ts-test-workspace";
170            function verifyConfigFileWatch(projectRootPath: string | undefined) {
171                const path = `${root}/x.js`;
172                const host = createServerHost([libFile, { path, content: "const x = 10" }], { useCaseSensitiveFileNames: true });
173                const service = createProjectService(host);
174                service.openClientFile(path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRootPath);
175                checkNumberOfProjects(service, { inferredProjects: 1 });
176                checkProjectActualFiles(service.inferredProjects[0], [path, libFile.path]);
177                checkWatchedFilesDetailed(host, [libFile.path, ...getConfigFilesToWatch(root)], 1);
178            }
179
180            it("when projectRootPath is not present", () => {
181                verifyConfigFileWatch(/*projectRootPath*/ undefined);
182            });
183            it("when projectRootPath is present but file is not from project root", () => {
184                verifyConfigFileWatch("/a/b");
185            });
186        });
187    });
188}
189