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, logger: createLoggerWithInMemoryLogs(host) }); 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 try { 35 session.executeCommandSeq(request); 36 } 37 catch (e) { 38 session.logger.info(e.message); 39 } 40 } 41 42 it("open files are added to inferred project even if config file is present and semantic operations fail", () => { 43 const { session, file1, file2, file3, something } = setup(); 44 openFilesForSession([file1], session); 45 verifyCompletions(); 46 verifyGoToDefToB(); 47 48 openFilesForSession([file2], session); 49 verifyCompletions(); 50 verifyGoToDefToB(); 51 verifyGoToDefToC(); 52 53 openFilesForSession([file3], session); 54 openFilesForSession([something], session); 55 56 // Close open files and verify resolutions 57 closeFilesForSession([file3], session); 58 closeFilesForSession([file2], session); 59 60 baselineTsserverLogs("syntacticServer", "files go to inferred project and semantic operations fail", session); 61 62 function verifyCompletions() { 63 verifySessionException<protocol.CompletionsRequest>(session, { 64 command: protocol.CommandTypes.Completions, 65 arguments: protocolFileLocationFromSubstring(file1, "prop", { index: 1 }) 66 }); 67 } 68 69 function verifyGoToDefToB() { 70 verifySessionException<protocol.DefinitionAndBoundSpanRequest>(session, { 71 command: protocol.CommandTypes.DefinitionAndBoundSpan, 72 arguments: protocolFileLocationFromSubstring(file1, "y") 73 }); 74 } 75 76 function verifyGoToDefToC() { 77 verifySessionException<protocol.DefinitionAndBoundSpanRequest>(session, { 78 command: protocol.CommandTypes.DefinitionAndBoundSpan, 79 arguments: protocolFileLocationFromSubstring(file1, "cc") 80 }); 81 } 82 }); 83 84 it("throws on unsupported commands", () => { 85 const { session, file1 } = setup(); 86 const service = session.getProjectService(); 87 openFilesForSession([file1], session); 88 verifySessionException<protocol.SemanticDiagnosticsSyncRequest>(session, { 89 type: "request", 90 seq: 1, 91 command: protocol.CommandTypes.SemanticDiagnosticsSync, 92 arguments: { file: file1.path } 93 }); 94 95 const project = service.inferredProjects[0]; 96 try { 97 project.getLanguageService().getSemanticDiagnostics(file1.path); 98 } 99 catch (e) { 100 session.logger.info(e.message); 101 } 102 baselineTsserverLogs("syntacticServer", "throws on unsupported commands", session); 103 }); 104 105 it("should not include auto type reference directives", () => { 106 const { host, session, file1 } = setup(); 107 const atTypes: File = { 108 path: `/node_modules/@types/somemodule/index.d.ts`, 109 content: "export const something = 10;" 110 }; 111 host.ensureFileOrFolder(atTypes); 112 openFilesForSession([file1], session); 113 baselineTsserverLogs("syntacticServer", "should not include auto type reference directives", session); 114 }); 115 116 it("should not include referenced files from unopened files", () => { 117 const file1: File = { 118 path: `${tscWatch.projectRoot}/a.ts`, 119 content: `///<reference path="b.ts"/> 120///<reference path="${tscWatch.projectRoot}/node_modules/something/index.d.ts"/> 121function fooA() { }` 122 }; 123 const file2: File = { 124 path: `${tscWatch.projectRoot}/b.ts`, 125 content: `///<reference path="./c.ts"/> 126///<reference path="${tscWatch.projectRoot}/node_modules/something/index.d.ts"/> 127function fooB() { }` 128 }; 129 const file3: File = { 130 path: `${tscWatch.projectRoot}/c.ts`, 131 content: `function fooC() { }` 132 }; 133 const something: File = { 134 path: `${tscWatch.projectRoot}/node_modules/something/index.d.ts`, 135 content: "function something() {}" 136 }; 137 const configFile: File = { 138 path: `${tscWatch.projectRoot}/tsconfig.json`, 139 content: "{}" 140 }; 141 const host = createServerHost([file1, file2, file3, something, libFile, configFile]); 142 const session = createSession(host, { syntaxOnly: true, useSingleInferredProject: true }); 143 const service = session.getProjectService(); 144 openFilesForSession([file1], session); 145 checkNumberOfProjects(service, { inferredProjects: 1 }); 146 const project = service.inferredProjects[0]; 147 checkProjectActualFiles(project, emptyArray); 148 149 openFilesForSession([file2], session); 150 checkNumberOfProjects(service, { inferredProjects: 1 }); 151 assert.isFalse(project.dirty); 152 project.updateGraph(); 153 checkProjectActualFiles(project, emptyArray); 154 155 closeFilesForSession([file2], session); 156 checkNumberOfProjects(service, { inferredProjects: 1 }); 157 assert.isTrue(project.dirty); 158 checkProjectActualFiles(project, emptyArray); 159 }); 160 }); 161} 162