diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index e15649f47b622..bea1f32648d72 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -497,7 +497,7 @@ namespace ts { /*@internal*/ export interface CacheWithRedirects { - ownMap: ESMap; + getOwnMap: () => ESMap; redirectsMap: ESMap>; getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): ESMap; clear(): void; @@ -510,7 +510,7 @@ namespace ts { let ownMap: ESMap = new Map(); const redirectsMap = new Map>(); return { - ownMap, + getOwnMap, redirectsMap, getOrCreateMapOfCacheRedirects, clear, @@ -518,6 +518,10 @@ namespace ts { setOwnMap }; + function getOwnMap() { + return ownMap; + } + function setOwnOptions(newOptions: CompilerOptions) { options = newOptions; } @@ -579,10 +583,10 @@ namespace ts { if (directoryToModuleNameMap.redirectsMap.size === 0) { // The own map will be for projectCompilerOptions Debug.assert(!moduleNameToDirectoryMap || moduleNameToDirectoryMap.redirectsMap.size === 0); - Debug.assert(directoryToModuleNameMap.ownMap.size === 0); - Debug.assert(!moduleNameToDirectoryMap || moduleNameToDirectoryMap.ownMap.size === 0); - directoryToModuleNameMap.redirectsMap.set(options.configFile.path, directoryToModuleNameMap.ownMap); - moduleNameToDirectoryMap?.redirectsMap.set(options.configFile.path, moduleNameToDirectoryMap.ownMap); + Debug.assert(directoryToModuleNameMap.getOwnMap().size === 0); + Debug.assert(!moduleNameToDirectoryMap || moduleNameToDirectoryMap.getOwnMap().size === 0); + directoryToModuleNameMap.redirectsMap.set(options.configFile.path, directoryToModuleNameMap.getOwnMap()); + moduleNameToDirectoryMap?.redirectsMap.set(options.configFile.path, moduleNameToDirectoryMap.getOwnMap()); } else { // Set correct own map diff --git a/src/testRunner/unittests/tsbuild/watchMode.ts b/src/testRunner/unittests/tsbuild/watchMode.ts index 5e0d0932f502d..65880a0c69c39 100644 --- a/src/testRunner/unittests/tsbuild/watchMode.ts +++ b/src/testRunner/unittests/tsbuild/watchMode.ts @@ -1020,4 +1020,59 @@ const a: string = "hello";`), ] }); }); + + describe("unittests:: tsbuild:: watchMode:: module resolution different in referenced project", () => { + verifyTscWatch({ + scenario: "moduleResolutionCache", + subScenario: "handles the cache correctly when two projects use different module resolution settings", + sys: () => createWatchedSystem( + [ + { path: `${projectRoot}/project1/index.ts`, content: `import { foo } from "file";` }, + { path: `${projectRoot}/project1/node_modules/file/index.d.ts`, content: "export const foo = 10;" }, + { + path: `${projectRoot}/project1/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { composite: true, types: ["foo", "bar"] }, + files: ["index.ts"] + }) + }, + { path: `${projectRoot}/project2/index.ts`, content: `import { foo } from "file";` }, + { path: `${projectRoot}/project2/file.d.ts`, content: "export const foo = 10;" }, + { + path: `${projectRoot}/project2/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { composite: true, types: ["foo"], moduleResolution: "classic" }, + files: ["index.ts"] + }) + }, + { path: `${projectRoot}/node_modules/@types/foo/index.d.ts`, content: "export const foo = 10;" }, + { path: `${projectRoot}/node_modules/@types/bar/index.d.ts`, content: "export const bar = 10;" }, + { + path: `${projectRoot}/tsconfig.json`, + content: JSON.stringify({ + files: [], + references: [ + { path: "./project1" }, + { path: "./project2" } + ] + }) + }, + libFile + ], + { currentDirectory: projectRoot } + ), + commandLineArgs: ["--b", "-w", "-v"], + changes: [ + { + caption: "Append text", + change: sys => sys.appendFile(`${projectRoot}/project1/index.ts`, "const bar = 10;"), + timeouts: sys => { + sys.checkTimeoutQueueLengthAndRun(1); // build project1 + sys.checkTimeoutQueueLengthAndRun(1); // Solution + sys.checkTimeoutQueueLength(0); + } + }, + ] + }); + }); } diff --git a/tests/baselines/reference/tsbuild/watchMode/moduleResolutionCache/handles-the-cache-correctly-when-two-projects-use-different-module-resolution-settings.js b/tests/baselines/reference/tsbuild/watchMode/moduleResolutionCache/handles-the-cache-correctly-when-two-projects-use-different-module-resolution-settings.js new file mode 100644 index 0000000000000..d59269e3e201d --- /dev/null +++ b/tests/baselines/reference/tsbuild/watchMode/moduleResolutionCache/handles-the-cache-correctly-when-two-projects-use-different-module-resolution-settings.js @@ -0,0 +1,378 @@ +Input:: +//// [/user/username/projects/myproject/project1/index.ts] +import { foo } from "file"; + +//// [/user/username/projects/myproject/project1/node_modules/file/index.d.ts] +export const foo = 10; + +//// [/user/username/projects/myproject/project1/tsconfig.json] +{"compilerOptions":{"composite":true,"types":["foo","bar"]},"files":["index.ts"]} + +//// [/user/username/projects/myproject/project2/index.ts] +import { foo } from "file"; + +//// [/user/username/projects/myproject/project2/file.d.ts] +export const foo = 10; + +//// [/user/username/projects/myproject/project2/tsconfig.json] +{"compilerOptions":{"composite":true,"types":["foo"],"moduleResolution":"classic"},"files":["index.ts"]} + +//// [/user/username/projects/myproject/node_modules/@types/foo/index.d.ts] +export const foo = 10; + +//// [/user/username/projects/myproject/node_modules/@types/bar/index.d.ts] +export const bar = 10; + +//// [/user/username/projects/myproject/tsconfig.json] +{"files":[],"references":[{"path":"./project1"},{"path":"./project2"}]} + +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +/a/lib/tsc.js --b -w -v +Output:: +>> Screen clear +[12:00:51 AM] Starting compilation in watch mode... + +[12:00:52 AM] Projects in this build: + * project1/tsconfig.json + * project2/tsconfig.json + * tsconfig.json + +[12:00:53 AM] Project 'project1/tsconfig.json' is out of date because output file 'project1/index.js' does not exist + +[12:00:54 AM] Building project '/user/username/projects/myproject/project1/tsconfig.json'... + +[12:01:03 AM] Project 'project2/tsconfig.json' is out of date because output file 'project2/index.js' does not exist + +[12:01:04 AM] Building project '/user/username/projects/myproject/project2/tsconfig.json'... + +[12:01:13 AM] Found 0 errors. Watching for file changes. + + + +Program root files: ["/user/username/projects/myproject/project1/index.ts"] +Program options: {"composite":true,"types":["foo","bar"],"watch":true,"configFilePath":"/user/username/projects/myproject/project1/tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/project1/node_modules/file/index.d.ts +/user/username/projects/myproject/project1/index.ts +/user/username/projects/myproject/node_modules/@types/foo/index.d.ts +/user/username/projects/myproject/node_modules/@types/bar/index.d.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/user/username/projects/myproject/project1/node_modules/file/index.d.ts +/user/username/projects/myproject/project1/index.ts +/user/username/projects/myproject/node_modules/@types/foo/index.d.ts +/user/username/projects/myproject/node_modules/@types/bar/index.d.ts + +Program root files: ["/user/username/projects/myproject/project2/index.ts"] +Program options: {"composite":true,"types":["foo"],"moduleResolution":1,"watch":true,"configFilePath":"/user/username/projects/myproject/project2/tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/project2/file.d.ts +/user/username/projects/myproject/project2/index.ts +/user/username/projects/myproject/node_modules/@types/foo/index.d.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/user/username/projects/myproject/project2/file.d.ts +/user/username/projects/myproject/project2/index.ts +/user/username/projects/myproject/node_modules/@types/foo/index.d.ts + +WatchedFiles:: +/user/username/projects/myproject/project1/tsconfig.json: + {"fileName":"/user/username/projects/myproject/project1/tsconfig.json","pollingInterval":250} +/user/username/projects/myproject/project1/index.ts: + {"fileName":"/user/username/projects/myproject/project1/index.ts","pollingInterval":250} +/user/username/projects/myproject/project2/tsconfig.json: + {"fileName":"/user/username/projects/myproject/project2/tsconfig.json","pollingInterval":250} +/user/username/projects/myproject/project2/index.ts: + {"fileName":"/user/username/projects/myproject/project2/index.ts","pollingInterval":250} +/user/username/projects/myproject/tsconfig.json: + {"fileName":"/user/username/projects/myproject/tsconfig.json","pollingInterval":250} + +FsWatches:: + +FsWatchesRecursive:: + +exitCode:: ExitStatus.undefined + +//// [/user/username/projects/myproject/project1/index.js] +"use strict"; +exports.__esModule = true; + + +//// [/user/username/projects/myproject/project1/index.d.ts] +export {}; + + +//// [/user/username/projects/myproject/project1/tsconfig.tsbuildinfo] +{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","./node_modules/file/index.d.ts","./index.ts","../node_modules/@types/foo/index.d.ts","../node_modules/@types/bar/index.d.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true},"-12737086933-export const foo = 10;","-4708082513-import { foo } from \"file\";","-12737086933-export const foo = 10;","-12042713060-export const bar = 10;"],"options":{"composite":true},"fileIdsList":[[2]],"referencedMap":[[3,1]],"exportedModulesMap":[[3,1]],"semanticDiagnosticsPerFile":[1,5,4,3,2]},"version":"FakeTSVersion"} + +//// [/user/username/projects/myproject/project1/tsconfig.tsbuildinfo.readable.baseline.txt] +{ + "program": { + "fileNames": [ + "../../../../../a/lib/lib.d.ts", + "./node_modules/file/index.d.ts", + "./index.ts", + "../node_modules/@types/foo/index.d.ts", + "../node_modules/@types/bar/index.d.ts" + ], + "fileNamesList": [ + [ + "./node_modules/file/index.d.ts" + ] + ], + "fileInfos": { + "../../../../../a/lib/lib.d.ts": { + "version": "-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }", + "signature": "-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }", + "affectsGlobalScope": true + }, + "./node_modules/file/index.d.ts": { + "version": "-12737086933-export const foo = 10;", + "signature": "-12737086933-export const foo = 10;" + }, + "./index.ts": { + "version": "-4708082513-import { foo } from \"file\";", + "signature": "-4708082513-import { foo } from \"file\";" + }, + "../node_modules/@types/foo/index.d.ts": { + "version": "-12737086933-export const foo = 10;", + "signature": "-12737086933-export const foo = 10;" + }, + "../node_modules/@types/bar/index.d.ts": { + "version": "-12042713060-export const bar = 10;", + "signature": "-12042713060-export const bar = 10;" + } + }, + "options": { + "composite": true + }, + "referencedMap": { + "./index.ts": [ + "./node_modules/file/index.d.ts" + ] + }, + "exportedModulesMap": { + "./index.ts": [ + "./node_modules/file/index.d.ts" + ] + }, + "semanticDiagnosticsPerFile": [ + "../../../../../a/lib/lib.d.ts", + "../node_modules/@types/bar/index.d.ts", + "../node_modules/@types/foo/index.d.ts", + "./index.ts", + "./node_modules/file/index.d.ts" + ] + }, + "version": "FakeTSVersion", + "size": 925 +} + +//// [/user/username/projects/myproject/project2/index.js] +"use strict"; +exports.__esModule = true; + + +//// [/user/username/projects/myproject/project2/index.d.ts] +export {}; + + +//// [/user/username/projects/myproject/project2/tsconfig.tsbuildinfo] +{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","./file.d.ts","./index.ts","../node_modules/@types/foo/index.d.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true},"-12737086933-export const foo = 10;","-4708082513-import { foo } from \"file\";","-12737086933-export const foo = 10;"],"options":{"composite":true},"fileIdsList":[[2]],"referencedMap":[[3,1]],"exportedModulesMap":[[3,1]],"semanticDiagnosticsPerFile":[1,4,2,3]},"version":"FakeTSVersion"} + +//// [/user/username/projects/myproject/project2/tsconfig.tsbuildinfo.readable.baseline.txt] +{ + "program": { + "fileNames": [ + "../../../../../a/lib/lib.d.ts", + "./file.d.ts", + "./index.ts", + "../node_modules/@types/foo/index.d.ts" + ], + "fileNamesList": [ + [ + "./file.d.ts" + ] + ], + "fileInfos": { + "../../../../../a/lib/lib.d.ts": { + "version": "-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }", + "signature": "-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }", + "affectsGlobalScope": true + }, + "./file.d.ts": { + "version": "-12737086933-export const foo = 10;", + "signature": "-12737086933-export const foo = 10;" + }, + "./index.ts": { + "version": "-4708082513-import { foo } from \"file\";", + "signature": "-4708082513-import { foo } from \"file\";" + }, + "../node_modules/@types/foo/index.d.ts": { + "version": "-12737086933-export const foo = 10;", + "signature": "-12737086933-export const foo = 10;" + } + }, + "options": { + "composite": true + }, + "referencedMap": { + "./index.ts": [ + "./file.d.ts" + ] + }, + "exportedModulesMap": { + "./index.ts": [ + "./file.d.ts" + ] + }, + "semanticDiagnosticsPerFile": [ + "../../../../../a/lib/lib.d.ts", + "../node_modules/@types/foo/index.d.ts", + "./file.d.ts", + "./index.ts" + ] + }, + "version": "FakeTSVersion", + "size": 826 +} + + +Change:: Append text + +Input:: +//// [/user/username/projects/myproject/project1/index.ts] +import { foo } from "file";const bar = 10; + + +Output:: +>> Screen clear +[12:01:16 AM] File change detected. Starting incremental compilation... + +[12:01:17 AM] Project 'project1/tsconfig.json' is out of date because oldest output 'project1/index.js' is older than newest input 'project1/index.ts' + +[12:01:18 AM] Building project '/user/username/projects/myproject/project1/tsconfig.json'... + +[12:01:31 AM] Found 0 errors. Watching for file changes. + + + +Program root files: ["/user/username/projects/myproject/project1/index.ts"] +Program options: {"composite":true,"types":["foo","bar"],"watch":true,"configFilePath":"/user/username/projects/myproject/project1/tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/project1/node_modules/file/index.d.ts +/user/username/projects/myproject/project1/index.ts +/user/username/projects/myproject/node_modules/@types/foo/index.d.ts +/user/username/projects/myproject/node_modules/@types/bar/index.d.ts + +Semantic diagnostics in builder refreshed for:: +/user/username/projects/myproject/project1/index.ts + +WatchedFiles:: +/user/username/projects/myproject/project1/tsconfig.json: + {"fileName":"/user/username/projects/myproject/project1/tsconfig.json","pollingInterval":250} +/user/username/projects/myproject/project1/index.ts: + {"fileName":"/user/username/projects/myproject/project1/index.ts","pollingInterval":250} +/user/username/projects/myproject/project2/tsconfig.json: + {"fileName":"/user/username/projects/myproject/project2/tsconfig.json","pollingInterval":250} +/user/username/projects/myproject/project2/index.ts: + {"fileName":"/user/username/projects/myproject/project2/index.ts","pollingInterval":250} +/user/username/projects/myproject/tsconfig.json: + {"fileName":"/user/username/projects/myproject/tsconfig.json","pollingInterval":250} + +FsWatches:: + +FsWatchesRecursive:: + +exitCode:: ExitStatus.undefined + +//// [/user/username/projects/myproject/project1/index.js] +"use strict"; +exports.__esModule = true; +var bar = 10; + + +//// [/user/username/projects/myproject/project1/index.d.ts] file written with same contents +//// [/user/username/projects/myproject/project1/tsconfig.tsbuildinfo] +{"program":{"fileNames":["../../../../../a/lib/lib.d.ts","./node_modules/file/index.d.ts","./index.ts","../node_modules/@types/foo/index.d.ts","../node_modules/@types/bar/index.d.ts"],"fileInfos":[{"version":"-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }","affectsGlobalScope":true},"-12737086933-export const foo = 10;",{"version":"-7561100220-import { foo } from \"file\";const bar = 10;","signature":"-3531856636-export {};\n"},"-12737086933-export const foo = 10;","-12042713060-export const bar = 10;"],"options":{"composite":true},"fileIdsList":[[2]],"referencedMap":[[3,1]],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,5,4,3,2]},"version":"FakeTSVersion"} + +//// [/user/username/projects/myproject/project1/tsconfig.tsbuildinfo.readable.baseline.txt] +{ + "program": { + "fileNames": [ + "../../../../../a/lib/lib.d.ts", + "./node_modules/file/index.d.ts", + "./index.ts", + "../node_modules/@types/foo/index.d.ts", + "../node_modules/@types/bar/index.d.ts" + ], + "fileNamesList": [ + [ + "./node_modules/file/index.d.ts" + ] + ], + "fileInfos": { + "../../../../../a/lib/lib.d.ts": { + "version": "-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }", + "signature": "-7698705165-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }", + "affectsGlobalScope": true + }, + "./node_modules/file/index.d.ts": { + "version": "-12737086933-export const foo = 10;", + "signature": "-12737086933-export const foo = 10;" + }, + "./index.ts": { + "version": "-7561100220-import { foo } from \"file\";const bar = 10;", + "signature": "-3531856636-export {};\n" + }, + "../node_modules/@types/foo/index.d.ts": { + "version": "-12737086933-export const foo = 10;", + "signature": "-12737086933-export const foo = 10;" + }, + "../node_modules/@types/bar/index.d.ts": { + "version": "-12042713060-export const bar = 10;", + "signature": "-12042713060-export const bar = 10;" + } + }, + "options": { + "composite": true + }, + "referencedMap": { + "./index.ts": [ + "./node_modules/file/index.d.ts" + ] + }, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "../../../../../a/lib/lib.d.ts", + "../node_modules/@types/bar/index.d.ts", + "../node_modules/@types/foo/index.d.ts", + "./index.ts", + "./node_modules/file/index.d.ts" + ] + }, + "version": "FakeTSVersion", + "size": 986 +} +