• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.projectSystem {
2    describe("unittests:: tsserver:: Semantic operations on Syntax server", () => {
3        function setup() {
4            const file1: File = {
5                path: `${tscWatch.projectRoot}/a.ts`,
6                content: `import { y, cc } from "./b";
7import { something } from "something";
8class c { prop = "hello"; foo() { return this.prop; } }`
9            };
10            const file2: File = {
11                path: `${tscWatch.projectRoot}/b.ts`,
12                content: `export { cc } from "./c";
13import { something } from "something";
14                export const y = 10;`
15            };
16            const file3: File = {
17                path: `${tscWatch.projectRoot}/c.ts`,
18                content: `export const cc = 10;`
19            };
20            const something: File = {
21                path: `${tscWatch.projectRoot}/node_modules/something/index.d.ts`,
22                content: "export const something = 10;"
23            };
24            const configFile: File = {
25                path: `${tscWatch.projectRoot}/tsconfig.json`,
26                content: "{}"
27            };
28            const host = createServerHost([file1, file2, file3, something, libFile, configFile]);
29            const session = createSession(host, { syntaxOnly: true, useSingleInferredProject: true });
30            return { host, session, file1, file2, file3, something, configFile };
31        }
32
33        function verifySessionException<T extends server.protocol.Request>(session: TestSession, request: Partial<T>) {
34            let hasException = false;
35            try {
36                session.executeCommandSeq(request);
37            }
38            catch (e) {
39                assert.equal(e.message, `Request: ${request.command} not allowed in LanguageServiceMode.Syntactic`);
40                hasException = true;
41            }
42            assert.isTrue(hasException);
43        }
44
45        it("open files are added to inferred project even if config file is present and semantic operations fail", () => {
46            const { host, session, file1, file2, file3, something } = setup();
47            const service = session.getProjectService();
48            openFilesForSession([file1], session);
49            checkNumberOfProjects(service, { inferredProjects: 1 });
50            const project = service.inferredProjects[0];
51            checkProjectActualFiles(project, emptyArray);
52            verifyCompletions();
53            verifyGoToDefToB();
54
55            openFilesForSession([file2], session);
56            checkNumberOfProjects(service, { inferredProjects: 1 });
57            checkProjectActualFiles(project, emptyArray);
58            verifyCompletions();
59            verifyGoToDefToB();
60            verifyGoToDefToC();
61
62            openFilesForSession([file3], session);
63            checkNumberOfProjects(service, { inferredProjects: 1 });
64            checkProjectActualFiles(project, emptyArray);
65
66            openFilesForSession([something], session);
67            checkNumberOfProjects(service, { inferredProjects: 1 });
68            checkProjectActualFiles(project, emptyArray);
69
70            // Close open files and verify resolutions
71            closeFilesForSession([file3], session);
72            checkNumberOfProjects(service, { inferredProjects: 1 });
73            checkProjectActualFiles(project, emptyArray);
74
75            closeFilesForSession([file2], session);
76            checkNumberOfProjects(service, { inferredProjects: 1 });
77            checkProjectActualFiles(project, emptyArray);
78
79            function verifyCompletions() {
80                assert.isFalse(project.languageServiceEnabled);
81                checkWatchedFiles(host, emptyArray);
82                checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
83                checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
84                verifySessionException<protocol.CompletionsRequest>(session, {
85                    command: protocol.CommandTypes.Completions,
86                    arguments: protocolFileLocationFromSubstring(file1, "prop", { index: 1 })
87                });
88            }
89
90            function verifyGoToDefToB() {
91                verifySessionException<protocol.DefinitionAndBoundSpanRequest>(session, {
92                    command: protocol.CommandTypes.DefinitionAndBoundSpan,
93                    arguments: protocolFileLocationFromSubstring(file1, "y")
94                });
95            }
96
97            function verifyGoToDefToC() {
98                verifySessionException<protocol.DefinitionAndBoundSpanRequest>(session, {
99                    command: protocol.CommandTypes.DefinitionAndBoundSpan,
100                    arguments: protocolFileLocationFromSubstring(file1, "cc")
101                });
102            }
103        });
104
105        it("throws on unsupported commands", () => {
106            const { session, file1 } = setup();
107            const service = session.getProjectService();
108            openFilesForSession([file1], session);
109            verifySessionException<protocol.SemanticDiagnosticsSyncRequest>(session, {
110                type: "request",
111                seq: 1,
112                command: protocol.CommandTypes.SemanticDiagnosticsSync,
113                arguments: { file: file1.path }
114            });
115
116            let hasException = false;
117            const project = service.inferredProjects[0];
118            try {
119                project.getLanguageService().getSemanticDiagnostics(file1.path);
120            }
121            catch (e) {
122                assert.equal(e.message, `LanguageService Operation: getSemanticDiagnostics not allowed in LanguageServiceMode.Syntactic`);
123                hasException = true;
124            }
125            assert.isTrue(hasException);
126        });
127
128        it("should not include auto type reference directives", () => {
129            const { host, session, file1 } = setup();
130            const atTypes: File = {
131                path: `/node_modules/@types/somemodule/index.d.ts`,
132                content: "export const something = 10;"
133            };
134            host.ensureFileOrFolder(atTypes);
135            const service = session.getProjectService();
136            openFilesForSession([file1], session);
137            checkNumberOfProjects(service, { inferredProjects: 1 });
138            const project = service.inferredProjects[0];
139            checkProjectActualFiles(project, emptyArray); // Should not contain atTypes
140        });
141
142        it("should not include referenced files from unopened files", () => {
143            const file1: File = {
144                path: `${tscWatch.projectRoot}/a.ts`,
145                content: `///<reference path="b.ts"/>
146///<reference path="${tscWatch.projectRoot}/node_modules/something/index.d.ts"/>
147function fooA() { }`
148            };
149            const file2: File = {
150                path: `${tscWatch.projectRoot}/b.ts`,
151                content: `///<reference path="./c.ts"/>
152///<reference path="${tscWatch.projectRoot}/node_modules/something/index.d.ts"/>
153function fooB() { }`
154            };
155            const file3: File = {
156                path: `${tscWatch.projectRoot}/c.ts`,
157                content: `function fooC() { }`
158            };
159            const something: File = {
160                path: `${tscWatch.projectRoot}/node_modules/something/index.d.ts`,
161                content: "function something() {}"
162            };
163            const configFile: File = {
164                path: `${tscWatch.projectRoot}/tsconfig.json`,
165                content: "{}"
166            };
167            const host = createServerHost([file1, file2, file3, something, libFile, configFile]);
168            const session = createSession(host, { syntaxOnly: true, useSingleInferredProject: true });
169            const service = session.getProjectService();
170            openFilesForSession([file1], session);
171            checkNumberOfProjects(service, { inferredProjects: 1 });
172            const project = service.inferredProjects[0];
173            checkProjectActualFiles(project, emptyArray);
174
175            openFilesForSession([file2], session);
176            checkNumberOfProjects(service, { inferredProjects: 1 });
177            assert.isFalse(project.dirty);
178            project.updateGraph();
179            checkProjectActualFiles(project, emptyArray);
180
181            closeFilesForSession([file2], session);
182            checkNumberOfProjects(service, { inferredProjects: 1 });
183            assert.isTrue(project.dirty);
184            checkProjectActualFiles(project, emptyArray);
185        });
186    });
187}
188