Skip to content

Commit 95d23ca

Browse files
authored
Treat the input file name from referenced project as "ts" rather than file extension it is when determining eliding file for program construction (#58308)
1 parent c92bd16 commit 95d23ca

File tree

4 files changed

+595
-1
lines changed

4 files changed

+595
-1
lines changed

src/compiler/program.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4106,7 +4106,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
41064106
}
41074107

41084108
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
4109-
const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
4109+
// If this is js file source of project reference, dont treat it as js file but as d.ts
4110+
const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension) && !getProjectReferenceRedirectProject(resolution.resolvedFileName);
41104111
const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile && (!resolution.originalPath || pathContainsNodeModules(resolution.resolvedFileName));
41114112
const resolvedFileName = resolution.resolvedFileName;
41124113

src/testRunner/unittests/tsbuild/moduleResolution.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as ts from "../../_namespaces/ts";
22
import * as Utils from "../../_namespaces/Utils";
3+
import { Symlink } from "../../_namespaces/vfs";
34
import { jsonToReadableText } from "../helpers";
45
import {
56
noChangeOnlyRuns,
@@ -131,3 +132,69 @@ describe("unittests:: tsbuild:: moduleResolution:: impliedNodeFormat differs bet
131132
edits: noChangeOnlyRuns,
132133
});
133134
});
135+
136+
describe("unittests:: tsbuild:: moduleResolution:: resolution sharing", () => {
137+
function fs() {
138+
return loadProjectFromFiles({
139+
"/src/projects/project/packages/a/index.js": `export const a = 'a';`,
140+
"/src/projects/project/packages/a/test/index.js": `import 'a';`,
141+
"/src/projects/project/packages/a/tsconfig.json": jsonToReadableText({
142+
compilerOptions: {
143+
checkJs: true,
144+
composite: true,
145+
declaration: true,
146+
emitDeclarationOnly: true,
147+
module: "nodenext",
148+
outDir: "types",
149+
},
150+
}),
151+
"/src/projects/project/packages/a/package.json": jsonToReadableText({
152+
name: "a",
153+
version: "0.0.0",
154+
type: "module",
155+
exports: {
156+
".": {
157+
types: "./types/index.d.ts",
158+
default: "./index.js",
159+
},
160+
},
161+
}),
162+
"/src/projects/project/packages/b/index.js": `export { a } from 'a';`,
163+
"/src/projects/project/packages/b/tsconfig.json": jsonToReadableText({
164+
references: [{ path: "../a" }],
165+
compilerOptions: {
166+
checkJs: true,
167+
module: "nodenext",
168+
noEmit: true,
169+
noImplicitAny: true,
170+
},
171+
}),
172+
"/src/projects/project/packages/b/package.json": jsonToReadableText({
173+
name: "b",
174+
version: "0.0.0",
175+
type: "module",
176+
}),
177+
"/src/projects/project/node_modules/a": new Symlink("/src/projects/project/packages/a"),
178+
"/lib/lib.esnext.full.d.ts": libFile.content,
179+
}, { cwd: "/src/projects/project" });
180+
}
181+
182+
verifyTsc({
183+
scenario: "moduleResolution",
184+
subScenario: "shared resolution should not report error",
185+
fs,
186+
commandLineArgs: ["-b", "packages/b", "--verbose", "--traceResolution", "--explainFiles"],
187+
});
188+
189+
verifyTsc({
190+
scenario: "moduleResolution",
191+
subScenario: "when resolution is not shared",
192+
fs,
193+
commandLineArgs: ["-b", "packages/a", "--verbose", "--traceResolution", "--explainFiles"],
194+
edits: [{
195+
caption: "build b",
196+
edit: ts.noop,
197+
commandLineArgs: ["-b", "packages/b", "--verbose", "--traceResolution", "--explainFiles"],
198+
}],
199+
});
200+
});
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
currentDirectory:: /src/projects/project useCaseSensitiveFileNames: false
2+
Input::
3+
//// [/lib/lib.d.ts]
4+
/// <reference no-default-lib="true"/>
5+
interface Boolean {}
6+
interface Function {}
7+
interface CallableFunction {}
8+
interface NewableFunction {}
9+
interface IArguments {}
10+
interface Number { toExponential: any; }
11+
interface Object {}
12+
interface RegExp {}
13+
interface String { charAt: any; }
14+
interface Array<T> { length: number; [n: number]: T; }
15+
interface ReadonlyArray<T> {}
16+
declare const console: { log(msg: any): void; };
17+
18+
//// [/lib/lib.esnext.full.d.ts]
19+
/// <reference no-default-lib="true"/>
20+
interface Boolean {}
21+
interface Function {}
22+
interface CallableFunction {}
23+
interface NewableFunction {}
24+
interface IArguments {}
25+
interface Number { toExponential: any; }
26+
interface Object {}
27+
interface RegExp {}
28+
interface String { charAt: any; }
29+
interface Array<T> { length: number; [n: number]: T; }
30+
31+
//// [/src/projects/project/node_modules/a] symlink(/src/projects/project/packages/a)
32+
//// [/src/projects/project/packages/a/index.js]
33+
export const a = 'a';
34+
35+
//// [/src/projects/project/packages/a/package.json]
36+
{
37+
"name": "a",
38+
"version": "0.0.0",
39+
"type": "module",
40+
"exports": {
41+
".": {
42+
"types": "./types/index.d.ts",
43+
"default": "./index.js"
44+
}
45+
}
46+
}
47+
48+
//// [/src/projects/project/packages/a/test/index.js]
49+
import 'a';
50+
51+
//// [/src/projects/project/packages/a/tsconfig.json]
52+
{
53+
"compilerOptions": {
54+
"checkJs": true,
55+
"composite": true,
56+
"declaration": true,
57+
"emitDeclarationOnly": true,
58+
"module": "nodenext",
59+
"outDir": "types"
60+
}
61+
}
62+
63+
//// [/src/projects/project/packages/b/index.js]
64+
export { a } from 'a';
65+
66+
//// [/src/projects/project/packages/b/package.json]
67+
{
68+
"name": "b",
69+
"version": "0.0.0",
70+
"type": "module"
71+
}
72+
73+
//// [/src/projects/project/packages/b/tsconfig.json]
74+
{
75+
"references": [
76+
{
77+
"path": "../a"
78+
}
79+
],
80+
"compilerOptions": {
81+
"checkJs": true,
82+
"module": "nodenext",
83+
"noEmit": true,
84+
"noImplicitAny": true
85+
}
86+
}
87+
88+
89+
90+
Output::
91+
/lib/tsc -b packages/b --verbose --traceResolution --explainFiles
92+
[12:00:22 AM] Projects in this build:
93+
* packages/a/tsconfig.json
94+
* packages/b/tsconfig.json
95+
96+
[12:00:23 AM] Project 'packages/a/tsconfig.json' is out of date because output file 'packages/a/types/tsconfig.tsbuildinfo' does not exist
97+
98+
[12:00:24 AM] Building project '/src/projects/project/packages/a/tsconfig.json'...
99+
100+
Found 'package.json' at '/src/projects/project/packages/a/package.json'.
101+
File '/src/projects/project/packages/a/test/package.json' does not exist.
102+
File '/src/projects/project/packages/a/package.json' exists according to earlier cached lookups.
103+
======== Resolving module 'a' from '/src/projects/project/packages/a/test/index.js'. ========
104+
Module resolution kind is not specified, using 'NodeNext'.
105+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
106+
File '/src/projects/project/packages/a/test/package.json' does not exist according to earlier cached lookups.
107+
File '/src/projects/project/packages/a/package.json' exists according to earlier cached lookups.
108+
Entering conditional exports.
109+
Matched 'exports' condition 'types'.
110+
Using 'exports' subpath '.' with target './types/index.d.ts'.
111+
File name '/src/projects/project/packages/a/index.js' has a '.js' extension - stripping it.
112+
File '/src/projects/project/packages/a/index.ts' does not exist.
113+
File '/src/projects/project/packages/a/index.tsx' does not exist.
114+
File '/src/projects/project/packages/a/index.d.ts' does not exist.
115+
File '/src/projects/project/packages/a/index.js' exists - use it as a name resolution result.
116+
'package.json' does not have a 'peerDependencies' field.
117+
Resolved under condition 'types'.
118+
Exiting conditional exports.
119+
Resolving real path for '/src/projects/project/packages/a/index.js', result '/src/projects/project/packages/a/index.js'.
120+
======== Module name 'a' was successfully resolved to '/src/projects/project/packages/a/index.js' with Package ID 'a/[email protected]'. ========
121+
File '/lib/package.json' does not exist.
122+
File '/package.json' does not exist.
123+
../../../lib/lib.esnext.full.d.ts
124+
Default library for target 'esnext'
125+
packages/a/index.js
126+
Matched by default include pattern '**/*'
127+
File is ECMAScript module because 'packages/a/package.json' has field "type" with value "module"
128+
packages/a/test/index.js
129+
Matched by default include pattern '**/*'
130+
File is ECMAScript module because 'packages/a/package.json' has field "type" with value "module"
131+
[12:00:32 AM] Project 'packages/b/tsconfig.json' is out of date because output 'packages/b/index.js' is older than input 'packages/a'
132+
133+
[12:00:33 AM] Building project '/src/projects/project/packages/b/tsconfig.json'...
134+
135+
Found 'package.json' at '/src/projects/project/packages/b/package.json'.
136+
======== Resolving module 'a' from '/src/projects/project/packages/b/index.js'. ========
137+
Module resolution kind is not specified, using 'NodeNext'.
138+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
139+
File '/src/projects/project/packages/b/package.json' exists according to earlier cached lookups.
140+
Loading module 'a' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration.
141+
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
142+
Directory '/src/projects/project/packages/b/node_modules' does not exist, skipping all lookups in it.
143+
Resolution for module 'a' was found in cache from location '/src/projects/project/packages'.
144+
======== Module name 'a' was successfully resolved to '/src/projects/project/packages/a/index.js' with Package ID 'a/[email protected]'. ========
145+
File '/src/projects/project/packages/a/types/package.json' does not exist.
146+
File '/src/projects/project/packages/a/package.json' exists according to earlier cached lookups.
147+
File '/lib/package.json' does not exist according to earlier cached lookups.
148+
File '/package.json' does not exist according to earlier cached lookups.
149+
../../../lib/lib.esnext.full.d.ts
150+
Default library for target 'esnext'
151+
packages/a/types/index.d.ts
152+
Imported via 'a' from file 'packages/b/index.js' with packageId 'a/[email protected]'
153+
File is output of project reference source 'packages/a/index.js'
154+
File is ECMAScript module because 'packages/a/package.json' has field "type" with value "module"
155+
packages/b/index.js
156+
Matched by default include pattern '**/*'
157+
File is ECMAScript module because 'packages/b/package.json' has field "type" with value "module"
158+
exitCode:: ExitStatus.Success
159+
160+
161+
//// [/src/projects/project/packages/a/types/index.d.ts]
162+
export const a: "a";
163+
164+
165+
//// [/src/projects/project/packages/a/types/test/index.d.ts]
166+
export {};
167+
168+
169+
//// [/src/projects/project/packages/a/types/tsconfig.tsbuildinfo]
170+
{"program":{"fileNames":["../../../../../../lib/lib.esnext.full.d.ts","../index.js","../test/index.js"],"fileInfos":[{"version":"-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"-15642581130-export const a = 'a';","signature":"-13259723213-export const a: \"a\";\n","impliedFormat":99},{"version":"-3920874422-import 'a';","signature":"-3531856636-export {};\n","impliedFormat":99}],"root":[2,3],"options":{"checkJs":true,"composite":true,"declaration":true,"emitDeclarationOnly":true,"module":199,"outDir":"./"},"fileIdsList":[[2]],"referencedMap":[[3,1]],"semanticDiagnosticsPerFile":[1,2,3],"latestChangedDtsFile":"./test/index.d.ts"},"version":"FakeTSVersion"}
171+
172+
//// [/src/projects/project/packages/a/types/tsconfig.tsbuildinfo.readable.baseline.txt]
173+
{
174+
"program": {
175+
"fileNames": [
176+
"../../../../../../lib/lib.esnext.full.d.ts",
177+
"../index.js",
178+
"../test/index.js"
179+
],
180+
"fileNamesList": [
181+
[
182+
"../index.js"
183+
]
184+
],
185+
"fileInfos": {
186+
"../../../../../../lib/lib.esnext.full.d.ts": {
187+
"original": {
188+
"version": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
189+
"affectsGlobalScope": true,
190+
"impliedFormat": 1
191+
},
192+
"version": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
193+
"signature": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
194+
"affectsGlobalScope": true,
195+
"impliedFormat": "commonjs"
196+
},
197+
"../index.js": {
198+
"original": {
199+
"version": "-15642581130-export const a = 'a';",
200+
"signature": "-13259723213-export const a: \"a\";\n",
201+
"impliedFormat": 99
202+
},
203+
"version": "-15642581130-export const a = 'a';",
204+
"signature": "-13259723213-export const a: \"a\";\n",
205+
"impliedFormat": "esnext"
206+
},
207+
"../test/index.js": {
208+
"original": {
209+
"version": "-3920874422-import 'a';",
210+
"signature": "-3531856636-export {};\n",
211+
"impliedFormat": 99
212+
},
213+
"version": "-3920874422-import 'a';",
214+
"signature": "-3531856636-export {};\n",
215+
"impliedFormat": "esnext"
216+
}
217+
},
218+
"root": [
219+
[
220+
2,
221+
"../index.js"
222+
],
223+
[
224+
3,
225+
"../test/index.js"
226+
]
227+
],
228+
"options": {
229+
"checkJs": true,
230+
"composite": true,
231+
"declaration": true,
232+
"emitDeclarationOnly": true,
233+
"module": 199,
234+
"outDir": "./"
235+
},
236+
"referencedMap": {
237+
"../test/index.js": [
238+
"../index.js"
239+
]
240+
},
241+
"semanticDiagnosticsPerFile": [
242+
"../../../../../../lib/lib.esnext.full.d.ts",
243+
"../index.js",
244+
"../test/index.js"
245+
],
246+
"latestChangedDtsFile": "./test/index.d.ts"
247+
},
248+
"version": "FakeTSVersion",
249+
"size": 1032
250+
}
251+

0 commit comments

Comments
 (0)