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