From 05d739be7e1345eb77cc5a2c6dcbc178b21d79bc Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 26 Sep 2022 15:35:18 -0700 Subject: [PATCH 1/7] Add test that fails --- src/harness/fakesHosts.ts | 1 + src/harness/virtualFileSystemWithWatch.ts | 1 + .../unittests/tsbuild/moduleResolution.ts | 34 ++- ...iffers-between-projects-for-shared-file.js | 196 ++++++++++++++++++ 4 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js diff --git a/src/harness/fakesHosts.ts b/src/harness/fakesHosts.ts index 1868561a34ccc..17fbc39833994 100644 --- a/src/harness/fakesHosts.ts +++ b/src/harness/fakesHosts.ts @@ -41,6 +41,7 @@ namespace fakes { } public write(message: string) { + if (ts.Debug.isDebugging) console.log(message); this.output.push(message); } diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 3006a3f1ffdb3..d8a30e66580d0 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -987,6 +987,7 @@ interface Array { length: number; [n: number]: T; }` } write(message: string) { + if (Debug.isDebugging) console.log(message); this.output.push(message); } diff --git a/src/testRunner/unittests/tsbuild/moduleResolution.ts b/src/testRunner/unittests/tsbuild/moduleResolution.ts index 487f83196c36e..772a30262a042 100644 --- a/src/testRunner/unittests/tsbuild/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuild/moduleResolution.ts @@ -86,4 +86,36 @@ namespace ts.tscWatch { commandLineArgs: ["-b", "/src/packages/pkg1.tsconfig.json", "/src/packages/pkg2.tsconfig.json", "--verbose", "--traceResolution"], }); }); -} + + describe("unittests:: tsbuild:: moduleResolution:: impliedNodeFormat differs between projects for shared file", () => { + verifyTscWithEdits({ + scenario: "moduleResolution", + subScenario: "impliedNodeFormat differs between projects for shared file", + fs: () => loadProjectFromFiles({ + "/src/projects/a/src/index.ts": "", + "/src/projects/a/tsconfig.json": JSON.stringify({ + compilerOptions: { strict: true } + }), + "/src/projects/b/src/index.ts": Utils.dedent` + import pg from "pg"; + pg.foo(); + `, + "/src/projects/b/tsconfig.json": JSON.stringify({ + compilerOptions: { strict: true, module: "node16" } + }), + "/src/projects/b/package.json": JSON.stringify({ + name: "b", + type: "module" + }), + "/src/projects/node_modules/@types/pg/index.d.ts": "export function foo(): void;", + "/src/projects/node_modules/@types/pg/package.json": JSON.stringify({ + name: "@types/pg", + types: "index.d.ts", + }), + }), + modifyFs: fs => fs.writeFileSync("/lib/lib.es2022.full.d.ts", libFile.content), + commandLineArgs: ["-b", "/src/projects/a", "/src/projects/b", "--verbose", "--traceResolution", "--explainFiles"], + edits: noChangeOnlyRuns + }); + }); +} \ No newline at end of file diff --git a/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js b/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js new file mode 100644 index 0000000000000..9d5759a45f983 --- /dev/null +++ b/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js @@ -0,0 +1,196 @@ +Input:: +//// [/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; } +interface ReadonlyArray {} +declare const console: { log(msg: any): void; }; + +//// [/lib/lib.es2022.full.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; } + +//// [/src/projects/a/src/index.ts] + + +//// [/src/projects/a/tsconfig.json] +{"compilerOptions":{"strict":true}} + +//// [/src/projects/b/package.json] +{"name":"b","type":"module"} + +//// [/src/projects/b/src/index.ts] +import pg from "pg"; +pg.foo(); + + +//// [/src/projects/b/tsconfig.json] +{"compilerOptions":{"strict":true,"module":"node16"}} + +//// [/src/projects/node_modules/@types/pg/index.d.ts] +export function foo(): void; + +//// [/src/projects/node_modules/@types/pg/package.json] +{"name":"@types/pg","types":"index.d.ts"} + + + +Output:: +/lib/tsc -b /src/projects/a /src/projects/b --verbose --traceResolution --explainFiles +[12:00:22 AM] Projects in this build: + * src/projects/a/tsconfig.json + * src/projects/b/tsconfig.json + +[12:00:23 AM] Project 'src/projects/a/tsconfig.json' is out of date because output file 'src/projects/a/src/index.js' does not exist + +[12:00:24 AM] Building project '/src/projects/a/tsconfig.json'... + +======== Resolving type reference directive 'pg', containing file '/src/projects/a/__inferred type names__.ts', root directory '/src/projects/node_modules/@types'. ======== +Resolving with primary search path '/src/projects/node_modules/@types'. +Found 'package.json' at '/src/projects/node_modules/@types/pg/package.json'. +'package.json' does not have a 'typesVersions' field. +'package.json' does not have a 'typings' field. +'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. +File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. +Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. +======== Type reference directive 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts', primary: true. ======== +lib/lib.d.ts + Default library for target 'es3' +src/projects/a/src/index.ts + Matched by default include pattern '**/*' +src/projects/node_modules/@types/pg/index.d.ts + Entry point for implicit type library 'pg' +[12:00:26 AM] Project 'src/projects/b/tsconfig.json' is out of date because output file 'src/projects/b/src/index.js' does not exist + +[12:00:27 AM] Building project '/src/projects/b/tsconfig.json'... + +File '/src/projects/b/src/package.json' does not exist. +Found 'package.json' at '/src/projects/b/package.json'. +'package.json' does not have a 'typesVersions' field. +======== Resolving module 'pg' from '/src/projects/b/src/index.ts'. ======== +Module resolution kind is not specified, using 'Node16'. +File '/src/projects/b/src/package.json' does not exist according to earlier cached lookups. +File '/src/projects/b/package.json' exists according to earlier cached lookups. +Loading module 'pg' from 'node_modules' folder, target file type 'TypeScript'. +Directory '/src/projects/b/src/node_modules' does not exist, skipping all lookups in it. +Directory '/src/projects/b/node_modules' does not exist, skipping all lookups in it. +File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. +'package.json' does not have a 'typings' field. +'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. +File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. +Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. +======== Module name 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts'. ======== +File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. +======== Resolving type reference directive 'pg', containing file '/src/projects/b/__inferred type names__.ts', root directory '/src/projects/node_modules/@types'. ======== +Resolving with primary search path '/src/projects/node_modules/@types'. +File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. +'package.json' does not have a 'typings' field. +'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. +File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. +Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. +======== Type reference directive 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts', primary: true. ======== +File '/lib/package.json' does not exist. +File '/package.json' does not exist. +src/projects/b/src/index.ts:1:8 - error TS1192: Module '"/src/projects/node_modules/@types/pg/index"' has no default export. + +1 import pg from "pg"; +   ~~ + +lib/lib.es2022.full.d.ts + Default library for target 'es2022' +src/projects/node_modules/@types/pg/index.d.ts + Imported via "pg" from file 'src/projects/b/src/index.ts' + Entry point for implicit type library 'pg' +src/projects/b/src/index.ts + Matched by default include pattern '**/*' + File is ECMAScript module because 'src/projects/b/package.json' has field "type" with value "module" + +Found 1 error. + +exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated + + +//// [/src/projects/a/src/index.js] +"use strict"; + + + + +Change:: no-change-run +Input:: + + +Output:: +/lib/tsc -b /src/projects/a /src/projects/b --verbose --traceResolution --explainFiles +[12:00:28 AM] Projects in this build: + * src/projects/a/tsconfig.json + * src/projects/b/tsconfig.json + +[12:00:29 AM] Project 'src/projects/a/tsconfig.json' is up to date because newest input 'src/projects/a/src/index.ts' is older than output 'src/projects/a/src/index.js' + +[12:00:30 AM] Project 'src/projects/b/tsconfig.json' is out of date because output file 'src/projects/b/src/index.js' does not exist + +[12:00:31 AM] Building project '/src/projects/b/tsconfig.json'... + +File '/src/projects/b/src/package.json' does not exist. +Found 'package.json' at '/src/projects/b/package.json'. +'package.json' does not have a 'typesVersions' field. +======== Resolving module 'pg' from '/src/projects/b/src/index.ts'. ======== +Module resolution kind is not specified, using 'Node16'. +File '/src/projects/b/src/package.json' does not exist according to earlier cached lookups. +File '/src/projects/b/package.json' exists according to earlier cached lookups. +Loading module 'pg' from 'node_modules' folder, target file type 'TypeScript'. +Directory '/src/projects/b/src/node_modules' does not exist, skipping all lookups in it. +Directory '/src/projects/b/node_modules' does not exist, skipping all lookups in it. +Found 'package.json' at '/src/projects/node_modules/@types/pg/package.json'. +'package.json' does not have a 'typesVersions' field. +'package.json' does not have a 'typings' field. +'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. +File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. +Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. +======== Module name 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts'. ======== +File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. +======== Resolving type reference directive 'pg', containing file '/src/projects/b/__inferred type names__.ts', root directory '/src/projects/node_modules/@types'. ======== +Resolving with primary search path '/src/projects/node_modules/@types'. +File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. +'package.json' does not have a 'typings' field. +'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. +File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. +Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. +======== Type reference directive 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts', primary: true. ======== +File '/lib/package.json' does not exist. +File '/package.json' does not exist. +lib/lib.es2022.full.d.ts + Default library for target 'es2022' +src/projects/node_modules/@types/pg/index.d.ts + Imported via "pg" from file 'src/projects/b/src/index.ts' + Entry point for implicit type library 'pg' + File is CommonJS module because 'src/projects/node_modules/@types/pg/package.json' does not have field "type" +src/projects/b/src/index.ts + Matched by default include pattern '**/*' + File is ECMAScript module because 'src/projects/b/package.json' has field "type" with value "module" +exitCode:: ExitStatus.Success + + +//// [/src/projects/b/src/index.js] +import pg from "pg"; +pg.foo(); + + From c8ebfb82979deefbbfda140aaf6f26ca08c365c1 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 27 Sep 2022 16:28:53 -0700 Subject: [PATCH 2/7] Handle impliedNodeFormat when handling sourceFileCache Fixes #50872 --- src/compiler/program.ts | 15 +++-- ...iffers-between-projects-for-shared-file.js | 66 +++---------------- 2 files changed, 19 insertions(+), 62 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 74abd84b43665..b6011e83185f5 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -171,7 +171,7 @@ namespace ts { const readFileCache = new Map(); const fileExistsCache = new Map(); const directoryExistsCache = new Map(); - const sourceFileCache = new Map(); + const sourceFileCache = new Map>(); const readFileWithCache = (fileName: string): string | undefined => { const key = toPath(fileName); @@ -196,14 +196,16 @@ namespace ts { return setReadFileCache(key, fileName); }; - const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { + const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { const key = toPath(fileName); - const value = sourceFileCache.get(key); + const impliedNodeFormat: SourceFile["impliedNodeFormat"] = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined; + const forPath = sourceFileCache.get(key); + const value = forPath?.get(impliedNodeFormat); if (value) return value; - const sourceFile = getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); + const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { - sourceFileCache.set(key, sourceFile); + sourceFileCache.set(key, (forPath || new Map()).set(impliedNodeFormat, sourceFile)); } return sourceFile; } : undefined; @@ -228,7 +230,8 @@ namespace ts { sourceFileCache.delete(key); } else if (getSourceFileWithCache) { - const sourceFile = sourceFileCache.get(key); + const sourceFileMap = sourceFileCache.get(key); + const sourceFile = sourceFileMap && firstDefinedIterator(sourceFileMap.values(), identity); if (sourceFile && sourceFile.text !== data) { sourceFileCache.delete(key); } diff --git a/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js b/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js index 9d5759a45f983..a2c1eb5d054eb 100644 --- a/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js +++ b/tests/baselines/reference/tsbuild/moduleResolution/impliedNodeFormat-differs-between-projects-for-shared-file.js @@ -108,29 +108,27 @@ Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', resul ======== Type reference directive 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts', primary: true. ======== File '/lib/package.json' does not exist. File '/package.json' does not exist. -src/projects/b/src/index.ts:1:8 - error TS1192: Module '"/src/projects/node_modules/@types/pg/index"' has no default export. - -1 import pg from "pg"; -   ~~ - lib/lib.es2022.full.d.ts Default library for target 'es2022' src/projects/node_modules/@types/pg/index.d.ts Imported via "pg" from file 'src/projects/b/src/index.ts' Entry point for implicit type library 'pg' + File is CommonJS module because 'src/projects/node_modules/@types/pg/package.json' does not have field "type" src/projects/b/src/index.ts Matched by default include pattern '**/*' File is ECMAScript module because 'src/projects/b/package.json' has field "type" with value "module" - -Found 1 error. - -exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated +exitCode:: ExitStatus.Success //// [/src/projects/a/src/index.js] "use strict"; +//// [/src/projects/b/src/index.js] +import pg from "pg"; +pg.foo(); + + Change:: no-change-run @@ -139,58 +137,14 @@ Input:: Output:: /lib/tsc -b /src/projects/a /src/projects/b --verbose --traceResolution --explainFiles -[12:00:28 AM] Projects in this build: +[12:00:29 AM] Projects in this build: * src/projects/a/tsconfig.json * src/projects/b/tsconfig.json -[12:00:29 AM] Project 'src/projects/a/tsconfig.json' is up to date because newest input 'src/projects/a/src/index.ts' is older than output 'src/projects/a/src/index.js' +[12:00:30 AM] Project 'src/projects/a/tsconfig.json' is up to date because newest input 'src/projects/a/src/index.ts' is older than output 'src/projects/a/src/index.js' -[12:00:30 AM] Project 'src/projects/b/tsconfig.json' is out of date because output file 'src/projects/b/src/index.js' does not exist +[12:00:31 AM] Project 'src/projects/b/tsconfig.json' is up to date because newest input 'src/projects/b/src/index.ts' is older than output 'src/projects/b/src/index.js' -[12:00:31 AM] Building project '/src/projects/b/tsconfig.json'... - -File '/src/projects/b/src/package.json' does not exist. -Found 'package.json' at '/src/projects/b/package.json'. -'package.json' does not have a 'typesVersions' field. -======== Resolving module 'pg' from '/src/projects/b/src/index.ts'. ======== -Module resolution kind is not specified, using 'Node16'. -File '/src/projects/b/src/package.json' does not exist according to earlier cached lookups. -File '/src/projects/b/package.json' exists according to earlier cached lookups. -Loading module 'pg' from 'node_modules' folder, target file type 'TypeScript'. -Directory '/src/projects/b/src/node_modules' does not exist, skipping all lookups in it. -Directory '/src/projects/b/node_modules' does not exist, skipping all lookups in it. -Found 'package.json' at '/src/projects/node_modules/@types/pg/package.json'. -'package.json' does not have a 'typesVersions' field. -'package.json' does not have a 'typings' field. -'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. -File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. -Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. -======== Module name 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts'. ======== -File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. -======== Resolving type reference directive 'pg', containing file '/src/projects/b/__inferred type names__.ts', root directory '/src/projects/node_modules/@types'. ======== -Resolving with primary search path '/src/projects/node_modules/@types'. -File '/src/projects/node_modules/@types/pg/package.json' exists according to earlier cached lookups. -'package.json' does not have a 'typings' field. -'package.json' has 'types' field 'index.d.ts' that references '/src/projects/node_modules/@types/pg/index.d.ts'. -File '/src/projects/node_modules/@types/pg/index.d.ts' exist - use it as a name resolution result. -Resolving real path for '/src/projects/node_modules/@types/pg/index.d.ts', result '/src/projects/node_modules/@types/pg/index.d.ts'. -======== Type reference directive 'pg' was successfully resolved to '/src/projects/node_modules/@types/pg/index.d.ts', primary: true. ======== -File '/lib/package.json' does not exist. -File '/package.json' does not exist. -lib/lib.es2022.full.d.ts - Default library for target 'es2022' -src/projects/node_modules/@types/pg/index.d.ts - Imported via "pg" from file 'src/projects/b/src/index.ts' - Entry point for implicit type library 'pg' - File is CommonJS module because 'src/projects/node_modules/@types/pg/package.json' does not have field "type" -src/projects/b/src/index.ts - Matched by default include pattern '**/*' - File is ECMAScript module because 'src/projects/b/package.json' has field "type" with value "module" exitCode:: ExitStatus.Success -//// [/src/projects/b/src/index.js] -import pg from "pg"; -pg.foo(); - - From 5c98b9cfc1f275877d8d57a60f8f28a5c8d08157 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 28 Sep 2022 10:04:51 -0700 Subject: [PATCH 3/7] Revert the fix --- src/compiler/program.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b6011e83185f5..74abd84b43665 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -171,7 +171,7 @@ namespace ts { const readFileCache = new Map(); const fileExistsCache = new Map(); const directoryExistsCache = new Map(); - const sourceFileCache = new Map>(); + const sourceFileCache = new Map(); const readFileWithCache = (fileName: string): string | undefined => { const key = toPath(fileName); @@ -196,16 +196,14 @@ namespace ts { return setReadFileCache(key, fileName); }; - const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { + const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { const key = toPath(fileName); - const impliedNodeFormat: SourceFile["impliedNodeFormat"] = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined; - const forPath = sourceFileCache.get(key); - const value = forPath?.get(impliedNodeFormat); + const value = sourceFileCache.get(key); if (value) return value; - const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); + const sourceFile = getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { - sourceFileCache.set(key, (forPath || new Map()).set(impliedNodeFormat, sourceFile)); + sourceFileCache.set(key, sourceFile); } return sourceFile; } : undefined; @@ -230,8 +228,7 @@ namespace ts { sourceFileCache.delete(key); } else if (getSourceFileWithCache) { - const sourceFileMap = sourceFileCache.get(key); - const sourceFile = sourceFileMap && firstDefinedIterator(sourceFileMap.values(), identity); + const sourceFile = sourceFileCache.get(key); if (sourceFile && sourceFile.text !== data) { sourceFileCache.delete(key); } From 651a47fdd6ea200e59fdf150dfa913230a86653a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 28 Sep 2022 10:09:45 -0700 Subject: [PATCH 4/7] Make sure impliedNodeFormat is set for the sourceFile --- src/compiler/program.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 74abd84b43665..e536111a48923 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1734,6 +1734,7 @@ namespace ts { if (!newSourceFile) { return StructureIsReused.Not; } + newSourceFile.impliedNodeFormat = sourceFileOptions.impliedNodeFormat; newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope; @@ -2968,6 +2969,7 @@ namespace ts { file.path = path; file.resolvedPath = toPath(fileName); file.originalFileName = originalFileName; + file.impliedNodeFormat = sourceFileOptions.impliedNodeFormat; file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; file.packageJsonScope = sourceFileOptions.packageJsonScope; addFileIncludeReason(file, reason); From 2c22989bd55498eac882548b254ea04f58baeac3 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 31 Oct 2022 10:22:35 -0700 Subject: [PATCH 5/7] Revert "Make sure impliedNodeFormat is set for the sourceFile" This reverts commit 651a47fdd6ea200e59fdf150dfa913230a86653a. --- src/compiler/program.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index e536111a48923..74abd84b43665 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1734,7 +1734,6 @@ namespace ts { if (!newSourceFile) { return StructureIsReused.Not; } - newSourceFile.impliedNodeFormat = sourceFileOptions.impliedNodeFormat; newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope; @@ -2969,7 +2968,6 @@ namespace ts { file.path = path; file.resolvedPath = toPath(fileName); file.originalFileName = originalFileName; - file.impliedNodeFormat = sourceFileOptions.impliedNodeFormat; file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; file.packageJsonScope = sourceFileOptions.packageJsonScope; addFileIncludeReason(file, reason); From 92bf32dcf5e0fd32fa0f3beae86e064b391a1aa3 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 31 Oct 2022 10:22:42 -0700 Subject: [PATCH 6/7] Revert "Revert the fix" This reverts commit 5c98b9cfc1f275877d8d57a60f8f28a5c8d08157. --- src/compiler/program.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 74abd84b43665..b6011e83185f5 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -171,7 +171,7 @@ namespace ts { const readFileCache = new Map(); const fileExistsCache = new Map(); const directoryExistsCache = new Map(); - const sourceFileCache = new Map(); + const sourceFileCache = new Map>(); const readFileWithCache = (fileName: string): string | undefined => { const key = toPath(fileName); @@ -196,14 +196,16 @@ namespace ts { return setReadFileCache(key, fileName); }; - const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersion, onError, shouldCreateNewSourceFile) => { + const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { const key = toPath(fileName); - const value = sourceFileCache.get(key); + const impliedNodeFormat: SourceFile["impliedNodeFormat"] = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined; + const forPath = sourceFileCache.get(key); + const value = forPath?.get(impliedNodeFormat); if (value) return value; - const sourceFile = getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile); + const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { - sourceFileCache.set(key, sourceFile); + sourceFileCache.set(key, (forPath || new Map()).set(impliedNodeFormat, sourceFile)); } return sourceFile; } : undefined; @@ -228,7 +230,8 @@ namespace ts { sourceFileCache.delete(key); } else if (getSourceFileWithCache) { - const sourceFile = sourceFileCache.get(key); + const sourceFileMap = sourceFileCache.get(key); + const sourceFile = sourceFileMap && firstDefinedIterator(sourceFileMap.values(), identity); if (sourceFile && sourceFile.text !== data) { sourceFileCache.delete(key); } From 4bd8b9b0e9ff0d9aa5d6eac23729fcefa7d5bfdb Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 31 Oct 2022 10:54:44 -0700 Subject: [PATCH 7/7] Swap the keys for map --- src/compiler/program.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b6011e83185f5..cc773c39f4bae 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -168,10 +168,10 @@ namespace ts { const originalDirectoryExists = host.directoryExists; const originalCreateDirectory = host.createDirectory; const originalWriteFile = host.writeFile; - const readFileCache = new Map(); - const fileExistsCache = new Map(); - const directoryExistsCache = new Map(); - const sourceFileCache = new Map>(); + const readFileCache = new Map(); + const fileExistsCache = new Map(); + const directoryExistsCache = new Map(); + const sourceFileCache = new Map>(); const readFileWithCache = (fileName: string): string | undefined => { const key = toPath(fileName); @@ -199,13 +199,13 @@ namespace ts { const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { const key = toPath(fileName); const impliedNodeFormat: SourceFile["impliedNodeFormat"] = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined; - const forPath = sourceFileCache.get(key); - const value = forPath?.get(impliedNodeFormat); + const forImpliedNodeFormat = sourceFileCache.get(impliedNodeFormat); + const value = forImpliedNodeFormat?.get(key); if (value) return value; const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { - sourceFileCache.set(key, (forPath || new Map()).set(impliedNodeFormat, sourceFile)); + sourceFileCache.set(impliedNodeFormat, (forImpliedNodeFormat || new Map()).set(key, sourceFile)); } return sourceFile; } : undefined; @@ -227,14 +227,15 @@ namespace ts { const value = readFileCache.get(key); if (value !== undefined && value !== data) { readFileCache.delete(key); - sourceFileCache.delete(key); + sourceFileCache.forEach(map => map.delete(key)); } else if (getSourceFileWithCache) { - const sourceFileMap = sourceFileCache.get(key); - const sourceFile = sourceFileMap && firstDefinedIterator(sourceFileMap.values(), identity); - if (sourceFile && sourceFile.text !== data) { - sourceFileCache.delete(key); - } + sourceFileCache.forEach(map => { + const sourceFile = map.get(key); + if (sourceFile && sourceFile.text !== data) { + map.delete(key); + } + }); } originalWriteFile.call(host, fileName, data, ...rest); };