1namespace ts.projectSystem { 2 describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem extra resolution pass in server host", () => { 3 it("can load typings that are proper modules", () => { 4 const file1 = { 5 path: "/a/b/app.js", 6 content: `var x = require("lib")` 7 }; 8 const lib = { 9 path: "/a/cache/node_modules/@types/lib/index.d.ts", 10 content: "export let x = 1" 11 }; 12 const host: TestServerHost & ModuleResolutionHost = createServerHost([file1, lib]); 13 const projectService = createProjectService(host, { 14 typingsInstaller: new TestTypingsInstaller("/a/cache", /*throttleLimit*/5, host), 15 logger: createLoggerWithInMemoryLogs(host) 16 }); 17 18 projectService.setCompilerOptionsForInferredProjects({ traceResolution: true, allowJs: true }); 19 projectService.openClientFile(file1.path); 20 baselineTsserverLogs("resolutionCache", "can load typings that are proper modules", projectService); 21 }); 22 }); 23 24 describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem watching @types", () => { 25 it("works correctly when typings are added or removed", () => { 26 const f1 = { 27 path: "/a/b/app.ts", 28 content: "let x = 1;" 29 }; 30 const t1 = { 31 path: "/a/b/node_modules/@types/lib1/index.d.ts", 32 content: "export let a: number" 33 }; 34 const t2 = { 35 path: "/a/b/node_modules/@types/lib2/index.d.ts", 36 content: "export let b: number" 37 }; 38 const tsconfig = { 39 path: "/a/b/tsconfig.json", 40 content: JSON.stringify({ 41 compilerOptions: {}, 42 exclude: ["node_modules"] 43 }) 44 }; 45 const host = createServerHost([f1, t1, tsconfig]); 46 const projectService = createProjectService(host); 47 48 projectService.openClientFile(f1.path); 49 projectService.checkNumberOfProjects({ configuredProjects: 1 }); 50 checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, t1.path, tsconfig.path]); 51 52 // delete t1 53 host.deleteFile(t1.path); 54 // run throttled operation 55 host.runQueuedTimeoutCallbacks(); 56 57 projectService.checkNumberOfProjects({ configuredProjects: 1 }); 58 checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]); 59 60 // create t2 61 host.writeFile(t2.path, t2.content); 62 // run throttled operation 63 host.runQueuedTimeoutCallbacks(); 64 65 projectService.checkNumberOfProjects({ configuredProjects: 1 }); 66 checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, t2.path, tsconfig.path]); 67 }); 68 }); 69 70 describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem add the missing module file for inferred project", () => { 71 it("should remove the `module not found` error", () => { 72 const moduleFile = { 73 path: "/a/b/moduleFile.ts", 74 content: "export function bar() { };" 75 }; 76 const file1 = { 77 path: "/a/b/file1.ts", 78 content: "import * as T from './moduleFile'; T.bar();" 79 }; 80 const host = createServerHost([file1]); 81 const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); 82 openFilesForSession([file1], session); 83 const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>( 84 server.CommandNames.SemanticDiagnosticsSync, 85 { file: file1.path } 86 ); 87 session.executeCommand(getErrRequest); 88 89 host.writeFile(moduleFile.path, moduleFile.content); 90 host.runQueuedTimeoutCallbacks(); 91 92 // Make a change to trigger the program rebuild 93 const changeRequest = makeSessionRequest<server.protocol.ChangeRequestArgs>( 94 server.CommandNames.Change, 95 { file: file1.path, line: 1, offset: 44, endLine: 1, endOffset: 44, insertString: "\n" } 96 ); 97 session.executeCommand(changeRequest); 98 99 // Recheck 100 session.executeCommand(getErrRequest); 101 baselineTsserverLogs("resolutionCache", "should remove the module not found error", session); 102 }); 103 104 it("npm install @types works", () => { 105 const folderPath = "/a/b/projects/temp"; 106 const file1: File = { 107 path: `${folderPath}/a.ts`, 108 content: 'import f = require("pad"); f;' 109 }; 110 const host = createServerHost([file1, libFile]); 111 const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); 112 session.executeCommandSeq<protocol.OpenRequest>({ 113 command: server.CommandNames.Open, 114 arguments: { 115 file: file1.path, 116 fileContent: file1.content, 117 scriptKindName: "TS", 118 projectRootPath: folderPath 119 } 120 }); 121 122 verifyGetErrRequest({ session, host, files: [file1] }); 123 124 const padIndex: File = { 125 path: `${folderPath}/node_modules/@types/pad/index.d.ts`, 126 content: "export = pad;declare function pad(length: number, text: string, char ?: string): string;" 127 }; 128 host.ensureFileOrFolder(padIndex, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); 129 host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions 130 host.runQueuedTimeoutCallbacks(); // Actual update 131 host.runQueuedTimeoutCallbacks(); 132 host.runQueuedImmediateCallbacks(); 133 baselineTsserverLogs("resolutionCache", `npm install @types works`, session); 134 }); 135 136 it("suggestion diagnostics", () => { 137 const file: File = { 138 path: "/a.js", 139 content: "function f(p) {}", 140 }; 141 142 const host = createServerHost([file]); 143 const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); 144 145 session.executeCommandSeq<protocol.OpenRequest>({ 146 command: server.CommandNames.Open, 147 arguments: { file: file.path, fileContent: file.content }, 148 }); 149 150 host.checkTimeoutQueueLength(0); 151 verifyGetErrRequest({ session, host, files: [file] }); 152 baselineTsserverLogs("resolutionCache", `suggestion diagnostics`, session); 153 }); 154 155 it("disable suggestion diagnostics", () => { 156 const file: File = { 157 path: "/a.js", 158 content: 'require("b")', 159 }; 160 161 const host = createServerHost([file]); 162 const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); 163 164 session.executeCommandSeq<protocol.OpenRequest>({ 165 command: server.CommandNames.Open, 166 arguments: { file: file.path, fileContent: file.content }, 167 }); 168 169 session.executeCommandSeq<protocol.ConfigureRequest>({ 170 command: server.CommandNames.Configure, 171 arguments: { 172 preferences: { disableSuggestions: true } 173 }, 174 }); 175 176 host.checkTimeoutQueueLength(0); 177 verifyGetErrRequest({ session, host, files: [file], skip: [{ suggestion: true }] }); 178 baselineTsserverLogs("resolutionCache", `disable suggestion diagnostics`, session); 179 }); 180 181 it("suppressed diagnostic events", () => { 182 const file: File = { 183 path: "/a.ts", 184 content: "1 = 2;", 185 }; 186 187 const host = createServerHost([file]); 188 const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: createLoggerWithInMemoryLogs(host) }); 189 190 session.executeCommandSeq<protocol.OpenRequest>({ 191 command: server.CommandNames.Open, 192 arguments: { file: file.path, fileContent: file.content }, 193 }); 194 195 host.checkTimeoutQueueLength(0); 196 session.executeCommandSeq<protocol.GeterrRequest>({ 197 command: server.CommandNames.Geterr, 198 arguments: { 199 delay: 0, 200 files: [file.path], 201 } 202 }); 203 204 host.checkTimeoutQueueLength(0); 205 session.executeCommandSeq<protocol.GeterrForProjectRequest>({ 206 command: server.CommandNames.Geterr, 207 arguments: { 208 delay: 0, 209 file: file.path, 210 } 211 }); 212 213 host.checkTimeoutQueueLength(0); 214 baselineTsserverLogs("resolutionCache", "suppressed diagnostic events", session); 215 }); 216 }); 217 218 describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem rename a module file and rename back", () => { 219 it("should restore the states for inferred projects", () => { 220 const moduleFile = { 221 path: "/a/b/moduleFile.ts", 222 content: "export function bar() { };" 223 }; 224 const file1 = { 225 path: "/a/b/file1.ts", 226 content: "import * as T from './moduleFile'; T.bar();" 227 }; 228 const host = createServerHost([moduleFile, file1]); 229 const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); 230 231 openFilesForSession([file1], session); 232 const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>( 233 server.CommandNames.SemanticDiagnosticsSync, 234 { file: file1.path } 235 ); 236 session.executeCommand(getErrRequest); 237 238 const moduleFileNewPath = "/a/b/moduleFile1.ts"; 239 host.renameFile(moduleFile.path, moduleFileNewPath); 240 host.runQueuedTimeoutCallbacks(); 241 session.executeCommand(getErrRequest); 242 243 host.renameFile(moduleFileNewPath, moduleFile.path); 244 host.runQueuedTimeoutCallbacks(); 245 246 // Make a change to trigger the program rebuild 247 const changeRequest = makeSessionRequest<server.protocol.ChangeRequestArgs>( 248 server.CommandNames.Change, 249 { file: file1.path, line: 1, offset: 44, endLine: 1, endOffset: 44, insertString: "\n" } 250 ); 251 session.executeCommand(changeRequest); 252 host.runQueuedTimeoutCallbacks(); 253 254 session.executeCommand(getErrRequest); 255 baselineTsserverLogs("resolutionCache", "renaming module should restore the states for inferred projects", session); 256 }); 257 258 it("should restore the states for configured projects", () => { 259 const moduleFile = { 260 path: "/a/b/moduleFile.ts", 261 content: "export function bar() { };" 262 }; 263 const file1 = { 264 path: "/a/b/file1.ts", 265 content: "import * as T from './moduleFile'; T.bar();" 266 }; 267 const configFile = { 268 path: "/a/b/tsconfig.json", 269 content: `{}` 270 }; 271 const host = createServerHost([moduleFile, file1, configFile]); 272 const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); 273 274 openFilesForSession([file1], session); 275 const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>( 276 server.CommandNames.SemanticDiagnosticsSync, 277 { file: file1.path } 278 ); 279 session.executeCommand(getErrRequest); 280 281 const moduleFileNewPath = "/a/b/moduleFile1.ts"; 282 host.renameFile(moduleFile.path, moduleFileNewPath); 283 host.runQueuedTimeoutCallbacks(); 284 session.executeCommand(getErrRequest); 285 286 host.renameFile(moduleFileNewPath, moduleFile.path); 287 host.runQueuedTimeoutCallbacks(); 288 session.executeCommand(getErrRequest); 289 baselineTsserverLogs("resolutionCache", "renaming module should restore the states for configured projects", session); 290 }); 291 292 it("should property handle missing config files", () => { 293 const f1 = { 294 path: "/a/b/app.ts", 295 content: "let x = 1" 296 }; 297 const config = { 298 path: "/a/b/tsconfig.json", 299 content: "{}" 300 }; 301 const projectName = "project1"; 302 const host = createServerHost([f1]); 303 const projectService = createProjectService(host); 304 projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName }); 305 306 // should have one external project since config file is missing 307 projectService.checkNumberOfProjects({ externalProjects: 1 }); 308 309 host.writeFile(config.path, config.content); 310 projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName }); 311 projectService.checkNumberOfProjects({ configuredProjects: 1 }); 312 }); 313 314 it("types should load from config file path if config exists", () => { 315 const f1 = { 316 path: "/a/b/app.ts", 317 content: "let x = 1" 318 }; 319 const config = { 320 path: "/a/b/tsconfig.json", 321 content: JSON.stringify({ compilerOptions: { types: ["node"], typeRoots: [] } }) 322 }; 323 const node = { 324 path: "/a/b/node_modules/@types/node/index.d.ts", 325 content: "declare var process: any" 326 }; 327 const cwd = { 328 path: "/a/c" 329 }; 330 const host = createServerHost([f1, config, node, cwd], { currentDirectory: cwd.path }); 331 const projectService = createProjectService(host); 332 projectService.openClientFile(f1.path); 333 projectService.checkNumberOfProjects({ configuredProjects: 1 }); 334 checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, node.path, config.path]); 335 }); 336 }); 337 338 describe("unittests:: tsserver:: resolutionCache:: tsserverProjectSystem module resolution caching", () => { 339 const configFile: File = { 340 path: `${tscWatch.projectRoot}/tsconfig.json`, 341 content: JSON.stringify({ compilerOptions: { traceResolution: true } }) 342 }; 343 344 function getModules(module1Path: string, module2Path: string) { 345 const module1: File = { 346 path: module1Path, 347 content: `export function module1() {}` 348 }; 349 const module2: File = { 350 path: module2Path, 351 content: `export function module2() {}` 352 }; 353 return { module1, module2 }; 354 } 355 356 describe("from files in same folder", () => { 357 function getFiles(fileContent: string) { 358 const file1: File = { 359 path: `${tscWatch.projectRoot}/src/file1.ts`, 360 content: fileContent 361 }; 362 const file2: File = { 363 path: `${tscWatch.projectRoot}/src/file2.ts`, 364 content: fileContent 365 }; 366 return { file1, file2 }; 367 } 368 369 it("relative module name", () => { 370 const fileContent = `import { module1 } from "./module1";import { module2 } from "../module2";`; 371 const { file1, file2 } = getFiles(fileContent); 372 const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/module1.ts`, `${tscWatch.projectRoot}/module2.ts`); 373 const files = [module1, module2, file1, file2, configFile, libFile]; 374 const host = createServerHost(files); 375 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 376 service.openClientFile(file1.path); 377 378 host.writeFile(file1.path, file1.content + fileContent); 379 host.writeFile(file2.path, file2.content + fileContent); 380 host.runQueuedTimeoutCallbacks(); 381 382 baselineTsserverLogs("resolutionCache", "relative module name from files in same folder", service); 383 }); 384 385 it("non relative module name", () => { 386 const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`; 387 const { file1, file2 } = getFiles(fileContent); 388 const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); 389 const files = [module1, module2, file1, file2, configFile, libFile]; 390 const host = createServerHost(files); 391 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 392 service.openClientFile(file1.path); 393 394 host.writeFile(file1.path, file1.content + fileContent); 395 host.writeFile(file2.path, file2.content + fileContent); 396 host.runQueuedTimeoutCallbacks(); 397 baselineTsserverLogs("resolutionCache", "non relative module name from files in same folder", service); 398 }); 399 }); 400 401 describe("from files in different folders", () => { 402 function getFiles(fileContent1: string, fileContent2 = fileContent1, fileContent3 = fileContent1, fileContent4 = fileContent1) { 403 const file1: File = { 404 path: `${tscWatch.projectRoot}/product/src/file1.ts`, 405 content: fileContent1 406 }; 407 const file2: File = { 408 path: `${tscWatch.projectRoot}/product/src/feature/file2.ts`, 409 content: fileContent2 410 }; 411 const file3: File = { 412 path: `${tscWatch.projectRoot}/product/test/src/file3.ts`, 413 content: fileContent3 414 }; 415 const file4: File = { 416 path: `${tscWatch.projectRoot}/product/test/file4.ts`, 417 content: fileContent4 418 }; 419 return { file1, file2, file3, file4 }; 420 } 421 422 it("relative module name", () => { 423 const fileContent1 = `import { module1 } from "./module1";import { module2 } from "../module2";`; 424 const fileContent2 = `import { module1 } from "../module1";import { module2 } from "../../module2";`; 425 const fileContent3 = `import { module1 } from "../../src/module1";import { module2 } from "../../module2";`; 426 const fileContent4 = `import { module1 } from "../src/module1}";import { module2 } from "../module2";`; 427 const { file1, file2, file3, file4 } = getFiles(fileContent1, fileContent2, fileContent3, fileContent4); 428 const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/src/module1.ts`, `${tscWatch.projectRoot}/product/module2.ts`); 429 const files = [module1, module2, file1, file2, file3, file4, configFile, libFile]; 430 const host = createServerHost(files); 431 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 432 service.openClientFile(file1.path); 433 434 host.writeFile(file1.path, file1.content + fileContent1); 435 host.writeFile(file2.path, file2.content + fileContent2); 436 host.writeFile(file3.path, file3.content + fileContent3); 437 host.writeFile(file4.path, file4.content + fileContent4); 438 host.runQueuedTimeoutCallbacks(); 439 baselineTsserverLogs("resolutionCache", "relative module name from files in different folders", service); 440 }); 441 442 it("non relative module name", () => { 443 const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`; 444 const { file1, file2, file3, file4 } = getFiles(fileContent); 445 const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); 446 const files = [module1, module2, file1, file2, file3, file4, configFile, libFile]; 447 const host = createServerHost(files); 448 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 449 service.openClientFile(file1.path); 450 451 host.writeFile(file1.path, file1.content + fileContent); 452 host.writeFile(file2.path, file2.content + fileContent); 453 host.writeFile(file3.path, file3.content + fileContent); 454 host.writeFile(file4.path, file4.content + fileContent); 455 host.runQueuedTimeoutCallbacks(); 456 baselineTsserverLogs("resolutionCache", "non relative module name from files in different folders", service); 457 }); 458 459 it("non relative module name from inferred project", () => { 460 const module1Name = "module1"; 461 const module2Name = "module2"; 462 const file2Name = "./feature/file2"; 463 const file3Name = "../test/src/file3"; 464 const file4Name = "../test/file4"; 465 const importModuleContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; 466 const { file1, file2, file3, file4 } = getFiles(`import "${file2Name}"; import "${file4Name}"; import "${file3Name}"; ${importModuleContent}`, importModuleContent, importModuleContent, importModuleContent); 467 const { module1, module2 } = getModules(`${tscWatch.projectRoot}/product/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); 468 const files = [module1, module2, file1, file2, file3, file4, libFile]; 469 const host = createServerHost(files); 470 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 471 service.setCompilerOptionsForInferredProjects({ traceResolution: true }); 472 service.openClientFile(file1.path); 473 host.writeFile(file1.path, file1.content + importModuleContent); 474 host.writeFile(file2.path, file2.content + importModuleContent); 475 host.writeFile(file3.path, file3.content + importModuleContent); 476 host.writeFile(file4.path, file4.content + importModuleContent); 477 host.runQueuedTimeoutCallbacks(); 478 baselineTsserverLogs("resolutionCache", "non relative module name from inferred project", service); 479 }); 480 }); 481 482 describe("when watching directories for failed lookup locations in amd resolution", () => { 483 function verifyModuleResolution(scenario: string, useNodeFile: boolean) { 484 it(scenario, () => { 485 const nodeFile: File = { 486 path: `${tscWatch.projectRoot}/src/typings/node.d.ts`, 487 content: ` 488declare module "fs" { 489 export interface something { 490 } 491}` 492 }; 493 const electronFile: File = { 494 path: `${tscWatch.projectRoot}/src/typings/electron.d.ts`, 495 content: ` 496declare module 'original-fs' { 497 import * as fs from 'fs'; 498 export = fs; 499}` 500 }; 501 const srcFile: File = { 502 path: `${tscWatch.projectRoot}/src/somefolder/srcfile.ts`, 503 content: ` 504import { x } from "somefolder/module1"; 505import { x } from "somefolder/module2"; 506const y = x;` 507 }; 508 const moduleFile: File = { 509 path: `${tscWatch.projectRoot}/src/somefolder/module1.ts`, 510 content: ` 511export const x = 10;` 512 }; 513 const configFile: File = { 514 path: `${tscWatch.projectRoot}/src/tsconfig.json`, 515 content: JSON.stringify({ 516 compilerOptions: { 517 module: "amd", 518 moduleResolution: "classic", 519 target: "es5", 520 outDir: "../out", 521 baseUrl: "./", 522 typeRoots: ["typings"] 523 } 524 }) 525 }; 526 527 const files = [...(useNodeFile ? [nodeFile] : []), electronFile, srcFile, moduleFile, configFile, libFile]; 528 const host = createServerHost(files); 529 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 530 service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, tscWatch.projectRoot); 531 baselineTsserverLogs("resolutionCache", scenario, service); 532 }); 533 } 534 verifyModuleResolution("when resolves to ambient module", /*useNodeFile*/ true); 535 verifyModuleResolution("when resolution fails", /*useNodeFile*/ false); 536 }); 537 538 describe("ignores files/folder changes in node_modules that start with '.'", () => { 539 const npmCacheFile: File = { 540 path: `${tscWatch.projectRoot}/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`, 541 content: JSON.stringify({ something: 10 }) 542 }; 543 const file1: File = { 544 path: `${tscWatch.projectRoot}/test.ts`, 545 content: `import { x } from "somemodule";` 546 }; 547 const file2: File = { 548 path: `${tscWatch.projectRoot}/node_modules/somemodule/index.d.ts`, 549 content: `export const x = 10;` 550 }; 551 it("when watching node_modules in inferred project for failed lookup/closed script infos", () => { 552 const files = [libFile, file1, file2]; 553 const host = createServerHost(files); 554 const service = createProjectService(host); 555 service.openClientFile(file1.path); 556 checkNumberOfProjects(service, { inferredProjects: 1 }); 557 const project = service.inferredProjects[0]; 558 checkProjectActualFiles(project, files.map(f => f.path)); 559 host.checkTimeoutQueueLength(0); 560 561 host.ensureFileOrFolder(npmCacheFile); 562 host.checkTimeoutQueueLength(0); 563 }); 564 it("when watching node_modules as part of wild card directories in config project", () => { 565 const config: File = { 566 path: `${tscWatch.projectRoot}/tsconfig.json`, 567 content: "{}" 568 }; 569 const files = [libFile, file1, file2, config]; 570 const host = createServerHost(files); 571 const service = createProjectService(host); 572 service.openClientFile(file1.path); 573 checkNumberOfProjects(service, { configuredProjects: 1 }); 574 const project = Debug.checkDefined(service.configuredProjects.get(config.path)); 575 checkProjectActualFiles(project, files.map(f => f.path)); 576 host.checkTimeoutQueueLength(0); 577 578 host.ensureFileOrFolder(npmCacheFile); 579 host.checkTimeoutQueueLength(0); 580 }); 581 }); 582 583 describe("avoid unnecessary invalidation", () => { 584 it("unnecessary lookup invalidation on save", () => { 585 const fileContent = `import { module1 } from "module1";import { module2 } from "module2";`; 586 const file1: File = { 587 path: `${tscWatch.projectRoot}/src/file1.ts`, 588 content: fileContent 589 }; 590 const { module1, module2 } = getModules(`${tscWatch.projectRoot}/src/node_modules/module1/index.ts`, `${tscWatch.projectRoot}/node_modules/module2/index.ts`); 591 const files = [module1, module2, file1, configFile, libFile]; 592 const host = createServerHost(files); 593 const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 594 service.openClientFile(file1.path); 595 596 // invoke callback to simulate saving 597 host.modifyFile(file1.path, file1.content, { invokeFileDeleteCreateAsPartInsteadOfChange: true }); 598 host.checkTimeoutQueueLengthAndRun(0); 599 baselineTsserverLogs("resolutionCache", "avoid unnecessary lookup invalidation on save", service); 600 }); 601 }); 602 }); 603} 604