1namespace ts.projectSystem { 2 describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectSystem CachingFileSystemInformation", () => { 3 enum CalledMapsWithSingleArg { 4 fileExists = "fileExists", 5 directoryExists = "directoryExists", 6 getDirectories = "getDirectories", 7 readFile = "readFile" 8 } 9 enum CalledMapsWithFiveArgs { 10 readDirectory = "readDirectory" 11 } 12 type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs; 13 type CalledWithFiveArgs = [readonly string[], readonly string[], readonly string[], number]; 14 function createLoggerTrackingHostCalls(host: TestServerHost) { 15 const calledMaps: Record<CalledMapsWithSingleArg, MultiMap<string, true>> & Record<CalledMapsWithFiveArgs, MultiMap<string, CalledWithFiveArgs>> = { 16 fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists), 17 directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists), 18 getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories), 19 readFile: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.readFile), 20 readDirectory: setCallsTrackingWithFiveArgFn(CalledMapsWithFiveArgs.readDirectory) 21 }; 22 23 return logCacheAndClear; 24 25 function setCallsTrackingWithSingleArgFn(prop: CalledMapsWithSingleArg) { 26 const calledMap = createMultiMap<true>(); 27 const cb = (host as any)[prop].bind(host); 28 (host as any)[prop] = (f: string) => { 29 calledMap.add(f, /*value*/ true); 30 return cb(f); 31 }; 32 return calledMap; 33 } 34 35 function setCallsTrackingWithFiveArgFn<U, V, W, X>(prop: CalledMapsWithFiveArgs) { 36 const calledMap = createMultiMap<[U, V, W, X]>(); 37 const cb = (host as any)[prop].bind(host); 38 (host as any)[prop] = (f: string, arg1?: U, arg2?: V, arg3?: W, arg4?: X) => { 39 calledMap.add(f, [arg1!, arg2!, arg3!, arg4!]); // TODO: GH#18217 40 return cb(f, arg1, arg2, arg3, arg4); 41 }; 42 return calledMap; 43 } 44 45 function logCacheEntry(logger: Logger, callback: CalledMaps) { 46 const result = arrayFrom<[string, (true | CalledWithFiveArgs)[]], { key: string, count: number }>(calledMaps[callback].entries(), ([key, arr]) => ({ key, count: arr.length })); 47 logger.info(`${callback}:: ${JSON.stringify(result)}`); 48 calledMaps[callback].clear(); 49 } 50 51 function logCacheAndClear(logger: Logger) { 52 logCacheEntry(logger, CalledMapsWithSingleArg.fileExists); 53 logCacheEntry(logger, CalledMapsWithSingleArg.directoryExists); 54 logCacheEntry(logger, CalledMapsWithSingleArg.getDirectories); 55 logCacheEntry(logger, CalledMapsWithSingleArg.readFile); 56 logCacheEntry(logger, CalledMapsWithFiveArgs.readDirectory); 57 } 58 } 59 60 function logSemanticDiagnostics(projectService: server.ProjectService, project: server.Project, file: File) { 61 const diags = project.getLanguageService().getSemanticDiagnostics(file.path); 62 projectService.logger.info(`getSemanticDiagnostics:: ${file.path}:: ${diags.length}`); 63 diags.forEach(d => projectService.logger.info(formatDiagnostic(d, project))); 64 } 65 66 it("works using legacy resolution logic", () => { 67 let rootContent = `import {x} from "f1"`; 68 const root: File = { 69 path: "/c/d/f0.ts", 70 content: rootContent 71 }; 72 73 const imported: File = { 74 path: "/c/f1.ts", 75 content: `foo()` 76 }; 77 78 const host = createServerHost([root, imported]); 79 const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 80 projectService.setCompilerOptionsForInferredProjects({ module: ModuleKind.AMD, noLib: true }); 81 projectService.openClientFile(root.path); 82 const project = projectService.inferredProjects[0]; 83 const rootScriptInfo = project.getRootScriptInfos()[0]; 84 assert.equal(rootScriptInfo.fileName, root.path); 85 86 // ensure that imported file was found 87 logSemanticDiagnostics(projectService, project, imported); 88 89 const logCacheAndClear = createLoggerTrackingHostCalls(host); 90 91 // trigger synchronization to make sure that import will be fetched from the cache 92 // ensure file has correct number of errors after edit 93 editContent(`import {x} from "f1"; 94 var x: string = 1;`); 95 logSemanticDiagnostics(projectService, project, imported); 96 logCacheAndClear(projectService.logger); 97 98 // trigger synchronization to make sure that the host will try to find 'f2' module on disk 99 editContent(`import {x} from "f2"`); 100 try { 101 // trigger synchronization to make sure that the host will try to find 'f2' module on disk 102 logSemanticDiagnostics(projectService, project, imported); 103 } 104 catch (e) { 105 projectService.logger.info(e.message); 106 } 107 logCacheAndClear(projectService.logger); 108 109 editContent(`import {x} from "f1"`); 110 logSemanticDiagnostics(projectService, project, imported); 111 logCacheAndClear(projectService.logger); 112 113 // setting compiler options discards module resolution cache 114 projectService.setCompilerOptionsForInferredProjects({ module: ModuleKind.AMD, noLib: true, target: ScriptTarget.ES5 }); 115 logSemanticDiagnostics(projectService, project, imported); 116 logCacheAndClear(projectService.logger); 117 baselineTsserverLogs("cachingFileSystemInformation", "works using legacy resolution logic", projectService); 118 119 function editContent(newContent: string) { 120 rootScriptInfo.editContent(0, rootContent.length, newContent); 121 rootContent = newContent; 122 } 123 }); 124 125 it("loads missing files from disk", () => { 126 const root: File = { 127 path: "/c/foo.ts", 128 content: `import {y} from "bar"` 129 }; 130 131 const imported: File = { 132 path: "/c/bar.d.ts", 133 content: `export var y = 1` 134 }; 135 136 const host = createServerHost([root]); 137 const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 138 projectService.setCompilerOptionsForInferredProjects({ module: ModuleKind.AMD, noLib: true }); 139 const logCacheAndClear = createLoggerTrackingHostCalls(host); 140 projectService.openClientFile(root.path); 141 const project = projectService.inferredProjects[0]; 142 const rootScriptInfo = project.getRootScriptInfos()[0]; 143 assert.equal(rootScriptInfo.fileName, root.path); 144 145 logSemanticDiagnostics(projectService, project, root); 146 logCacheAndClear(projectService.logger); 147 148 host.writeFile(imported.path, imported.content); 149 host.runQueuedTimeoutCallbacks(); 150 logSemanticDiagnostics(projectService, project, root); 151 logCacheAndClear(projectService.logger); 152 baselineTsserverLogs("cachingFileSystemInformation", "loads missing files from disk", projectService); 153 }); 154 155 it("when calling goto definition of module", () => { 156 const clientFile: File = { 157 path: "/a/b/controllers/vessels/client.ts", 158 content: ` 159 import { Vessel } from '~/models/vessel'; 160 const v = new Vessel(); 161 ` 162 }; 163 const anotherModuleFile: File = { 164 path: "/a/b/utils/db.ts", 165 content: "export class Bookshelf { }" 166 }; 167 const moduleFile: File = { 168 path: "/a/b/models/vessel.ts", 169 content: ` 170 import { Bookshelf } from '~/utils/db'; 171 export class Vessel extends Bookshelf {} 172 ` 173 }; 174 const tsconfigFile: File = { 175 path: "/a/b/tsconfig.json", 176 content: JSON.stringify({ 177 compilerOptions: { 178 target: "es6", 179 module: "es6", 180 baseUrl: "./", // all paths are relative to the baseUrl 181 paths: { 182 "~/*": ["*"] // resolve any `~/foo/bar` to `<baseUrl>/foo/bar` 183 } 184 }, 185 exclude: [ 186 "api", 187 "build", 188 "node_modules", 189 "public", 190 "seeds", 191 "sql_updates", 192 "tests.build" 193 ] 194 }) 195 }; 196 const projectFiles = [clientFile, anotherModuleFile, moduleFile, tsconfigFile]; 197 const host = createServerHost(projectFiles); 198 const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); 199 openFilesForSession([clientFile], session); 200 const logCacheAndClear = createLoggerTrackingHostCalls(host); 201 202 // Get definitions shouldnt make host requests 203 const getDefinitionRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(protocol.CommandTypes.Definition, { 204 file: clientFile.path, 205 position: clientFile.content.indexOf("/vessel") + 1, 206 line: undefined!, // TODO: GH#18217 207 offset: undefined! // TODO: GH#18217 208 }); 209 session.executeCommand(getDefinitionRequest); 210 logCacheAndClear(session.logger); 211 212 // Open the file should call only file exists on module directory and use cached value for parental directory 213 openFilesForSession([moduleFile], session); 214 logCacheAndClear(session.logger); 215 216 baselineTsserverLogs("cachingFileSystemInformation", "when calling goto definition of module", session); 217 }); 218 219 describe("WatchDirectories for config file with", () => { 220 function verifyWatchDirectoriesCaseSensitivity(useCaseSensitiveFileNames: boolean) { 221 it(`watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, () => { 222 const frontendDir = "/Users/someuser/work/applications/frontend"; 223 const file1: File = { 224 path: `${frontendDir}/src/app/utils/Analytic.ts`, 225 content: "export class SomeClass { };" 226 }; 227 const file2: File = { 228 path: `${frontendDir}/src/app/redux/configureStore.ts`, 229 content: "export class configureStore { }" 230 }; 231 const file3: File = { 232 path: `${frontendDir}/src/app/utils/Cookie.ts`, 233 content: "export class Cookie { }" 234 }; 235 const es2016LibFile: File = { 236 path: "/a/lib/lib.es2016.full.d.ts", 237 content: libFile.content 238 }; 239 const typeRoots = ["types", "node_modules/@types"]; 240 const types = ["node", "jest"]; 241 const tsconfigFile: File = { 242 path: `${frontendDir}/tsconfig.json`, 243 content: JSON.stringify({ 244 compilerOptions: { 245 strict: true, 246 strictNullChecks: true, 247 target: "es2016", 248 module: "commonjs", 249 moduleResolution: "node", 250 sourceMap: true, 251 noEmitOnError: true, 252 experimentalDecorators: true, 253 emitDecoratorMetadata: true, 254 types, 255 noUnusedLocals: true, 256 outDir: "./compiled", 257 typeRoots, 258 baseUrl: ".", 259 paths: { 260 "*": [ 261 "types/*" 262 ] 263 } 264 }, 265 include: [ 266 "src/**/*" 267 ], 268 exclude: [ 269 "node_modules", 270 "compiled" 271 ] 272 }) 273 }; 274 const projectFiles = [file1, file2, es2016LibFile, tsconfigFile]; 275 const host = createServerHost(projectFiles, { useCaseSensitiveFileNames }); 276 const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 277 projectService.openClientFile(file1.path); 278 279 const logCacheAndClear = createLoggerTrackingHostCalls(host); 280 281 // Create file cookie.ts 282 host.writeFile(file3.path, file3.content); 283 host.runQueuedTimeoutCallbacks(); 284 logCacheAndClear(projectService.logger); 285 286 projectService.openClientFile(file3.path); 287 logCacheAndClear(projectService.logger); 288 baselineTsserverLogs("cachingFileSystemInformation", `watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, projectService); 289 }); 290 } 291 verifyWatchDirectoriesCaseSensitivity(/*useCaseSensitiveFileNames*/ false); 292 verifyWatchDirectoriesCaseSensitivity(/*useCaseSensitiveFileNames*/ true); 293 }); 294 295 describe("Subfolder invalidations correctly include parent folder failed lookup locations", () => { 296 function runFailedLookupTest(resolution: "Node" | "Classic") { 297 const projectLocation = "/proj"; 298 const file1: File = { 299 path: `${projectLocation}/foo/boo/app.ts`, 300 content: `import * as debug from "debug"` 301 }; 302 const file2: File = { 303 path: `${projectLocation}/foo/boo/moo/app.ts`, 304 content: `import * as debug from "debug"` 305 }; 306 const tsconfig: File = { 307 path: `${projectLocation}/tsconfig.json`, 308 content: JSON.stringify({ 309 files: ["foo/boo/app.ts", "foo/boo/moo/app.ts"], 310 moduleResolution: resolution 311 }) 312 }; 313 314 const files = [file1, file2, tsconfig, libFile]; 315 const host = createServerHost(files); 316 const service = createProjectService(host); 317 service.openClientFile(file1.path); 318 319 const project = service.configuredProjects.get(tsconfig.path)!; 320 checkProjectActualFiles(project, files.map(f => f.path)); 321 assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]); 322 assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]); 323 324 const debugTypesFile: File = { 325 path: `${projectLocation}/node_modules/debug/index.d.ts`, 326 content: "export {}" 327 }; 328 files.push(debugTypesFile); 329 host.writeFile(debugTypesFile.path, debugTypesFile.content); 330 host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions 331 host.runQueuedTimeoutCallbacks(); // Actual update 332 checkProjectActualFiles(project, files.map(f => f.path)); 333 assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), []); 334 assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file2.path).map(diag => diag.messageText), []); 335 } 336 337 it("Includes the parent folder FLLs in node module resolution mode", () => { 338 runFailedLookupTest("Node"); 339 }); 340 it("Includes the parent folder FLLs in classic module resolution mode", () => { 341 runFailedLookupTest("Classic"); 342 }); 343 }); 344 345 describe("Verify npm install in directory with tsconfig file works when", () => { 346 function verifyNpmInstall(timeoutDuringPartialInstallation: boolean) { 347 const root = "/user/username/rootfolder/otherfolder"; 348 const getRootedFileOrFolder = (fileOrFolder: File) => { 349 fileOrFolder.path = root + fileOrFolder.path; 350 return fileOrFolder; 351 }; 352 const app: File = getRootedFileOrFolder({ 353 path: "/a/b/app.ts", 354 content: "import _ from 'lodash';" 355 }); 356 const tsconfigJson: File = getRootedFileOrFolder({ 357 path: "/a/b/tsconfig.json", 358 content: '{ "compilerOptions": { } }' 359 }); 360 const packageJson: File = getRootedFileOrFolder({ 361 path: "/a/b/package.json", 362 content: ` 363{ 364 "name": "test", 365 "version": "1.0.0", 366 "description": "", 367 "main": "index.js", 368 "dependencies": { 369 "lodash", 370 "rxjs" 371 }, 372 "devDependencies": { 373 "@types/lodash", 374 "typescript" 375 }, 376 "scripts": { 377 "test": "echo \"Error: no test specified\" && exit 1" 378 }, 379 "keywords": [], 380 "author": "", 381 "license": "ISC" 382} 383` 384 }); 385 const host = createServerHost([app, libFile, tsconfigJson, packageJson]); 386 const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); 387 projectService.setHostConfiguration({ preferences: { includePackageJsonAutoImports: "off" } }); 388 projectService.openClientFile(app.path); 389 390 let npmInstallComplete = false; 391 392 // Simulate npm install 393 const filesAndFoldersToAdd: File[] = [ 394 { path: "/a/b/node_modules" }, 395 { path: "/a/b/node_modules/.staging/@types" }, 396 { path: "/a/b/node_modules/.staging/lodash-b0733faa" }, 397 { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7" }, 398 { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff" }, 399 { path: "/a/b/node_modules/.staging/rxjs-22375c61" }, 400 { path: "/a/b/node_modules/.staging/typescript-8493ea5d" }, 401 { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/package.json", content: "{\n \"name\": \"symbol-observable\",\n \"version\": \"1.0.4\",\n \"description\": \"Symbol.observable ponyfill\",\n \"license\": \"MIT\",\n \"repository\": \"blesh/symbol-observable\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"engines\": {\n \"node\": \">=0.10.0\"\n },\n \"scripts\": {\n \"test\": \"npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill\",\n \"build\": \"babel es --out-dir lib\",\n \"prepublish\": \"npm test\"\n },\n \"files\": [\n \"" }, 402 { path: "/a/b/node_modules/.staging/lodash-b0733faa/package.json", content: "{\n \"name\": \"lodash\",\n \"version\": \"4.17.4\",\n \"description\": \"Lodash modular utilities.\",\n \"keywords\": \"modules, stdlib, util\",\n \"homepage\": \"https://lodash.com/\",\n \"repository\": \"lodash/lodash\",\n \"icon\": \"https://lodash.com/icon.svg\",\n \"license\": \"MIT\",\n \"main\": \"lodash.js\",\n \"author\": \"John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)\",\n \"contributors\": [\n \"John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)\",\n \"Mathias Bynens <mathias@qiwi." }, 403 { path: "/a/b/node_modules/.staging/rxjs-22375c61/package.json", content: "{\n \"name\": \"rxjs\",\n \"version\": \"5.4.3\",\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"main\": \"Rx.js\",\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"eslint -c .eslintrc --ext .ts . --fix\",\n \"git add\"\n ]\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git@github.com:ReactiveX/RxJS.git\"\n },\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"author\": \"Ben Lesh <ben@benlesh.com>\",\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"eslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"typings\": \"Rx.d.ts\",\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n }\n}" }, 404 { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", content: "{\n \"name\": \"typescript\",\n \"author\": \"Microsoft Corp.\",\n \"homepage\": \"http://typescriptlang.org/\",\n \"version\": \"2.4.2\",\n \"license\": \"Apache-2.0\",\n \"description\": \"TypeScript is a language for application scale JavaScript development\",\n \"keywords\": [\n \"TypeScript\",\n \"Microsoft\",\n \"compiler\",\n \"language\",\n \"javascript\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/Microsoft/TypeScript/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/Microsoft/TypeScript.git\"\n },\n \"main\": \"./lib/typescript.js\",\n \"typings\": \"./lib/typescript.d.ts\",\n \"bin\": {\n \"tsc\": \"./bin/tsc\",\n \"tsserver\": \"./bin/tsserver\"\n },\n \"engines\": {\n \"node\": \">=4.2.0\"\n },\n \"devDependencies\": {\n \"@types/browserify\": \"latest\",\n \"@types/chai\": \"latest\",\n \"@types/convert-source-map\": \"latest\",\n \"@types/del\": \"latest\",\n \"@types/glob\": \"latest\",\n \"@types/gulp\": \"latest\",\n \"@types/gulp-concat\": \"latest\",\n \"@types/gulp-help\": \"latest\",\n \"@types/gulp-newer\": \"latest\",\n \"@types/gulp-sourcemaps\": \"latest\",\n \"@types/merge2\": \"latest\",\n \"@types/minimatch\": \"latest\",\n \"@types/minimist\": \"latest\",\n \"@types/mkdirp\": \"latest\",\n \"@types/mocha\": \"latest\",\n \"@types/node\": \"latest\",\n \"@types/q\": \"latest\",\n \"@types/run-sequence\": \"latest\",\n \"@types/through2\": \"latest\",\n \"browserify\": \"latest\",\n \"chai\": \"latest\",\n \"convert-source-map\": \"latest\",\n \"del\": \"latest\",\n \"gulp\": \"latest\",\n \"gulp-clone\": \"latest\",\n \"gulp-concat\": \"latest\",\n \"gulp-help\": \"latest\",\n \"gulp-insert\": \"latest\",\n \"gulp-newer\": \"latest\",\n \"gulp-sourcemaps\": \"latest\",\n \"gulp-typescript\": \"latest\",\n \"into-stream\": \"latest\",\n \"istanbul\": \"latest\",\n \"jake\": \"latest\",\n \"merge2\": \"latest\",\n \"minimist\": \"latest\",\n \"mkdirp\": \"latest\",\n \"mocha\": \"latest\",\n \"mocha-fivemat-progress-reporter\": \"latest\",\n \"q\": \"latest\",\n \"run-sequence\": \"latest\",\n \"sorcery\": \"latest\",\n \"through2\": \"latest\",\n \"travis-fold\": \"latest\",\n \"ts-node\": \"latest\",\n \"eslint\": \"5.16.0\",\n \"typescript\": \"^2.4\"\n },\n \"scripts\": {\n \"pretest\": \"jake tests\",\n \"test\": \"jake runtests-parallel\",\n \"build\": \"npm run build:compiler && npm run build:tests\",\n \"build:compiler\": \"jake local\",\n \"build:tests\": \"jake tests\",\n \"start\": \"node lib/tsc\",\n \"clean\": \"jake clean\",\n \"gulp\": \"gulp\",\n \"jake\": \"jake\",\n \"lint\": \"jake lint\",\n \"setup-hooks\": \"node scripts/link-hooks.js\"\n },\n \"browser\": {\n \"buffer\": false,\n \"fs\": false,\n \"os\": false,\n \"path\": false\n }\n}" }, 405 { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", content: "module.exports = require('./lib/index');\n" }, 406 { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", content: "declare const observableSymbol: symbol;\nexport default observableSymbol;\n" }, 407 { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib" }, 408 { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", content: "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;" }, 409 ].map(getRootedFileOrFolder); 410 verifyAfterPartialOrCompleteNpmInstall(2); 411 412 filesAndFoldersToAdd.push(...[ 413 { path: "/a/b/node_modules/.staging/typescript-8493ea5d/lib" }, 414 { path: "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" }, 415 { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", content: "{\n \"name\": \"@types/lodash\",\n \"version\": \"4.14.74\",\n \"description\": \"TypeScript definitions for Lo-Dash\",\n \"license\": \"MIT\",\n \"contributors\": [\n {\n \"name\": \"Brian Zengel\",\n \"url\": \"https://github.com/bczengel\"\n },\n {\n \"name\": \"Ilya Mochalov\",\n \"url\": \"https://github.com/chrootsu\"\n },\n {\n \"name\": \"Stepan Mikhaylyuk\",\n \"url\": \"https://github.com/stepancar\"\n },\n {\n \"name\": \"Eric L Anderson\",\n \"url\": \"https://github.com/ericanderson\"\n },\n {\n \"name\": \"AJ Richardson\",\n \"url\": \"https://github.com/aj-r\"\n },\n {\n \"name\": \"Junyoung Clare Jang\",\n \"url\": \"https://github.com/ailrun\"\n }\n ],\n \"main\": \"\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://www.github.com/DefinitelyTyped/DefinitelyTyped.git\"\n },\n \"scripts\": {},\n \"dependencies\": {},\n \"typesPublisherContentHash\": \"12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8\",\n \"typeScriptVersion\": \"2.2\"\n}" }, 416 { path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", content: "module.exports = require('./lodash');" }, 417 { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594", content: "" } 418 ].map(getRootedFileOrFolder)); 419 // Since we added/removed in .staging no timeout 420 verifyAfterPartialOrCompleteNpmInstall(0); 421 422 // Remove file "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594" 423 host.deleteFile(last(filesAndFoldersToAdd).path); 424 filesAndFoldersToAdd.length--; 425 verifyAfterPartialOrCompleteNpmInstall(0); 426 427 filesAndFoldersToAdd.push(...[ 428 { path: "/a/b/node_modules/.staging/rxjs-22375c61/bundles" }, 429 { path: "/a/b/node_modules/.staging/rxjs-22375c61/operator" }, 430 { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/add/observable/dom" }, 431 { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", content: "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}" } 432 ].map(getRootedFileOrFolder)); 433 verifyAfterPartialOrCompleteNpmInstall(0); 434 435 filesAndFoldersToAdd.push(...[ 436 { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/scheduler" }, 437 { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/util" }, 438 { path: "/a/b/node_modules/.staging/rxjs-22375c61/symbol" }, 439 { path: "/a/b/node_modules/.staging/rxjs-22375c61/testing" }, 440 { path: "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", content: "{\n \"_args\": [\n [\n {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\"\n ]\n ],\n \"_from\": \"rxjs@>=5.4.2 <6.0.0\",\n \"_id\": \"rxjs@5.4.3\",\n \"_inCache\": true,\n \"_location\": \"/rxjs\",\n \"_nodeVersion\": \"7.7.2\",\n \"_npmOperationalInternal\": {\n \"host\": \"s3://npm-registry-packages\",\n \"tmp\": \"tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167\"\n },\n \"_npmUser\": {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"_npmVersion\": \"5.3.0\",\n \"_phantomChildren\": {},\n \"_requested\": {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"_requiredBy\": [\n \"/\"\n ],\n \"_resolved\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\",\n \"_shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"_shrinkwrap\": null,\n \"_spec\": \"rxjs@^5.4.2\",\n \"_where\": \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n },\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"eslint\": \"^5.16.0\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"directories\": {},\n \"dist\": {\n \"integrity\": \"sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==\",\n \"shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"tarball\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"license\": \"Apache-2.0\",\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"eslint -c .eslintrc --ext .ts . --fix\",\n \"git add\"\n ]\n },\n \"main\": \"Rx.js\",\n \"maintainers\": [\n {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n }\n ],\n \"name\": \"rxjs\",\n \"optionalDependencies\": {},\n \"readme\": \"ERROR: No README data found!\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+ssh://git@github.com/ReactiveX/RxJS.git\"\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"typings\": \"Rx.d.ts\",\n \"version\": \"5.4.3\"\n}\n" } 441 ].map(getRootedFileOrFolder)); 442 verifyAfterPartialOrCompleteNpmInstall(0); 443 444 // remove /a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041 445 host.deleteFile(last(filesAndFoldersToAdd).path); 446 filesAndFoldersToAdd.length--; 447 // and add few more folders/files 448 filesAndFoldersToAdd.push(...[ 449 { path: "/a/b/node_modules/symbol-observable" }, 450 { path: "/a/b/node_modules/@types" }, 451 { path: "/a/b/node_modules/@types/lodash" }, 452 { path: "/a/b/node_modules/lodash" }, 453 { path: "/a/b/node_modules/rxjs" }, 454 { path: "/a/b/node_modules/typescript" }, 455 { path: "/a/b/node_modules/.bin" } 456 ].map(getRootedFileOrFolder)); 457 // From the type root update 458 verifyAfterPartialOrCompleteNpmInstall(2); 459 460 forEach(filesAndFoldersToAdd, f => { 461 f.path = f.path 462 .replace("/a/b/node_modules/.staging", "/a/b/node_modules") 463 .replace(/[\-\.][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w]/g, ""); 464 }); 465 466 host.deleteFolder(root + "/a/b/node_modules/.staging", /*recursive*/ true); 467 // npm installation complete, timeout after reload fs 468 npmInstallComplete = true; 469 verifyAfterPartialOrCompleteNpmInstall(2); 470 471 baselineTsserverLogs( 472 "cachingFileSystemInformation", 473 `npm install works when ${timeoutDuringPartialInstallation ? "timeout occurs inbetween installation" : "timeout occurs after installation"}`, 474 projectService 475 ); 476 477 function verifyAfterPartialOrCompleteNpmInstall(timeoutQueueLengthWhenRunningTimeouts: number) { 478 filesAndFoldersToAdd.forEach(f => host.ensureFileOrFolder(f)); 479 if (npmInstallComplete || timeoutDuringPartialInstallation) { 480 if (timeoutQueueLengthWhenRunningTimeouts) { 481 // Expected project update 482 host.checkTimeoutQueueLengthAndRun(timeoutQueueLengthWhenRunningTimeouts + 1); // Scheduled invalidation of resolutions 483 host.runQueuedTimeoutCallbacks(); // Actual update 484 } 485 else { 486 host.checkTimeoutQueueLengthAndRun(timeoutQueueLengthWhenRunningTimeouts); 487 } 488 } 489 else { 490 host.checkTimeoutQueueLength(3); 491 } 492 } 493 } 494 495 it("timeouts occur inbetween installation", () => { 496 verifyNpmInstall(/*timeoutDuringPartialInstallation*/ true); 497 }); 498 it("timeout occurs after installation", () => { 499 verifyNpmInstall(/*timeoutDuringPartialInstallation*/ false); 500 }); 501 }); 502 503 it("when node_modules dont receive event for the @types file addition", () => { 504 const projectLocation = "/user/username/folder/myproject"; 505 const app: File = { 506 path: `${projectLocation}/app.ts`, 507 content: `import * as debug from "debug"` 508 }; 509 const tsconfig: File = { 510 path: `${projectLocation}/tsconfig.json`, 511 content: "" 512 }; 513 514 const files = [app, tsconfig, libFile]; 515 const host = createServerHost(files); 516 const service = createProjectService(host); 517 service.openClientFile(app.path); 518 519 const project = service.configuredProjects.get(tsconfig.path)!; 520 checkProjectActualFiles(project, files.map(f => f.path)); 521 assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), ["Cannot find module 'debug' or its corresponding type declarations."]); 522 523 const debugTypesFile: File = { 524 path: `${projectLocation}/node_modules/@types/debug/index.d.ts`, 525 content: "export {}" 526 }; 527 files.push(debugTypesFile); 528 // Do not invoke recursive directory watcher for anything other than node_module/@types 529 const invoker = host.invokeFsWatchesRecursiveCallbacks; 530 host.invokeFsWatchesRecursiveCallbacks = (fullPath, eventName, entryFullPath) => { 531 if (fullPath.endsWith("@types")) { 532 invoker.call(host, fullPath, eventName, entryFullPath); 533 } 534 }; 535 host.writeFile(debugTypesFile.path, debugTypesFile.content); 536 host.runQueuedTimeoutCallbacks(); 537 checkProjectActualFiles(project, files.map(f => f.path)); 538 assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), []); 539 }); 540 541 it("when creating new file in symlinked folder", () => { 542 const module1: File = { 543 path: `${tscWatch.projectRoot}/client/folder1/module1.ts`, 544 content: `export class Module1Class { }` 545 }; 546 const module2: File = { 547 path: `${tscWatch.projectRoot}/folder2/module2.ts`, 548 content: `import * as M from "folder1/module1";` 549 }; 550 const symlink: SymLink = { 551 path: `${tscWatch.projectRoot}/client/linktofolder2`, 552 symLink: `${tscWatch.projectRoot}/folder2`, 553 }; 554 const config: File = { 555 path: `${tscWatch.projectRoot}/tsconfig.json`, 556 content: JSON.stringify({ 557 compilerOptions: { 558 baseUrl: "client", 559 paths: { "*": ["*"] }, 560 }, 561 include: ["client/**/*", "folder2"] 562 }) 563 }; 564 const host = createServerHost([module1, module2, symlink, config, libFile]); 565 const service = createProjectService(host); 566 service.openClientFile(`${symlink.path}/module2.ts`); 567 checkNumberOfProjects(service, { configuredProjects: 1 }); 568 const project = Debug.checkDefined(service.configuredProjects.get(config.path)); 569 checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, libFile.path]); 570 host.writeFile(`${symlink.path}/module3.ts`, `import * as M from "folder1/module1";`); 571 host.runQueuedTimeoutCallbacks(); 572 checkNumberOfProjects(service, { configuredProjects: 1 }); 573 checkProjectActualFiles(project, [module1.path, `${symlink.path}/module2.ts`, config.path, libFile.path, `${symlink.path}/module3.ts`]); 574 }); 575 }); 576} 577