Skip to content

Commit 3307cff

Browse files
committed
Fix crash on attempting to suggest a ts import for a synthetic js resolution
1 parent abf4b63 commit 3307cff

File tree

5 files changed

+268
-0
lines changed

5 files changed

+268
-0
lines changed

src/compiler/checker.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,16 @@ namespace ts {
10911091
}
10921092
}
10931093
function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void {
1094+
if (location.pos < 0 || location.end < 0) {
1095+
// Psuedo-synthesized input node
1096+
if (!isError) {
1097+
return; // Drop suggestions (we have no span to suggest on)
1098+
}
1099+
// Issue errors globally
1100+
const file = getSourceFileOfNode(location);
1101+
addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, arg0, arg1, arg2, arg3) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line no-in-operator
1102+
return;
1103+
}
10941104
addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); // eslint-disable-line no-in-operator
10951105
}
10961106

src/compiler/utilities.ts

+12
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,18 @@ namespace ts {
989989
};
990990
}
991991

992+
export function createDiagnosticForFileFromMessageChain(sourceFile: SourceFile, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation {
993+
return {
994+
file: sourceFile,
995+
start: 0,
996+
length: 0,
997+
code: messageChain.code,
998+
category: messageChain.category,
999+
messageText: messageChain.next ? messageChain : messageChain.messageText,
1000+
relatedInformation
1001+
};
1002+
}
1003+
9921004
export function createDiagnosticForRange(sourceFile: SourceFile, range: TextRange, message: DiagnosticMessage): DiagnosticWithLocation {
9931005
return {
9941006
file: sourceFile,

src/testRunner/unittests/tsc/incremental.ts

+37
Original file line numberDiff line numberDiff line change
@@ -235,5 +235,42 @@ const a: string = 10;`, "utf-8"),
235235
}
236236
}
237237
});
238+
239+
const jsxLibraryContent = `
240+
export {};
241+
declare global {
242+
namespace JSX {
243+
interface Element {}
244+
interface IntrinsicElements {
245+
div: {
246+
propA?: boolean;
247+
};
248+
}
249+
}
250+
}`;
251+
252+
verifyTsc({
253+
scenario: "react-jsx-emit-mode",
254+
subScenario: "with no backing types found doesn't crash",
255+
fs: () => loadProjectFromFiles({
256+
"/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result
257+
"/src/project/node_modules/@types/react/index.d.ts": jsxLibraryContent, // doesn't contain a jsx-runtime definition
258+
"/src/project/src/index.tsx": `export const App = () => <div propA={true}></div>;`,
259+
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" } })
260+
}),
261+
commandLineArgs: ["--p", "src/project"]
262+
});
263+
264+
verifyTsc({
265+
scenario: "react-jsx-emit-mode",
266+
subScenario: "with no backing types found doesn't crash under --strict",
267+
fs: () => loadProjectFromFiles({
268+
"/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result
269+
"/src/project/node_modules/@types/react/index.d.ts": jsxLibraryContent, // doesn't contain a jsx-runtime definition
270+
"/src/project/src/index.tsx": `export const App = () => <div propA={true}></div>;`,
271+
"/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" } })
272+
}),
273+
commandLineArgs: ["--p", "src/project", "--strict"]
274+
});
238275
});
239276
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
Input::
2+
//// [/lib/lib.d.ts]
3+
/// <reference no-default-lib="true"/>
4+
interface Boolean {}
5+
interface Function {}
6+
interface CallableFunction {}
7+
interface NewableFunction {}
8+
interface IArguments {}
9+
interface Number { toExponential: any; }
10+
interface Object {}
11+
interface RegExp {}
12+
interface String { charAt: any; }
13+
interface Array<T> { length: number; [n: number]: T; }
14+
interface ReadonlyArray<T> {}
15+
declare const console: { log(msg: any): void; };
16+
17+
//// [/src/project/node_modules/@types/react/index.d.ts]
18+
19+
export {};
20+
declare global {
21+
namespace JSX {
22+
interface Element {}
23+
interface IntrinsicElements {
24+
div: {
25+
propA?: boolean;
26+
};
27+
}
28+
}
29+
}
30+
31+
//// [/src/project/node_modules/react/jsx-runtime.js]
32+
33+
34+
//// [/src/project/src/index.tsx]
35+
export const App = () => <div propA={true}></div>;
36+
37+
//// [/src/project/tsconfig.json]
38+
{"compilerOptions":{"module":"commonjs","jsx":"react-jsx","incremental":true,"jsxImportSource":"react"}}
39+
40+
41+
42+
Output::
43+
/lib/tsc --p src/project --strict
44+
src/project/src/index.tsx:1:26 - error TS7016: Could not find a declaration file for module 'react/jsx-runtime'. '/src/project/node_modules/react/jsx-runtime.js' implicitly has an 'any' type.
45+
46+
1 export const App = () => <div propA={true}></div>;
47+
   ~~~~~~~~~~~~~~~~~~~~~~~~
48+
49+
50+
Found 1 error.
51+
52+
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
53+
54+
55+
//// [/src/project/src/index.js]
56+
"use strict";
57+
exports.__esModule = true;
58+
exports.App = void 0;
59+
var jsx_runtime_1 = require("react/jsx-runtime");
60+
var App = function () { return jsx_runtime_1.jsx("div", { propA: true }, void 0); };
61+
exports.App = App;
62+
63+
64+
//// [/src/project/tsconfig.tsbuildinfo]
65+
{
66+
"program": {
67+
"fileInfos": {
68+
"../../lib/lib.d.ts": {
69+
"version": "3858781397-/// <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; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
70+
"signature": "3858781397-/// <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; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
71+
"affectsGlobalScope": true
72+
},
73+
"./src/index.tsx": {
74+
"version": "-14760199789-export const App = () => <div propA={true}></div>;",
75+
"signature": "-8716173275-/// <reference types=\"react\" />\r\nexport declare const App: () => JSX.Element;\r\n",
76+
"affectsGlobalScope": false
77+
},
78+
"./node_modules/@types/react/index.d.ts": {
79+
"version": "-16587767667-\nexport {};\ndeclare global {\n namespace JSX {\n interface Element {}\n interface IntrinsicElements {\n div: {\n propA?: boolean;\n };\n }\n }\n}",
80+
"signature": "-16587767667-\nexport {};\ndeclare global {\n namespace JSX {\n interface Element {}\n interface IntrinsicElements {\n div: {\n propA?: boolean;\n };\n }\n }\n}",
81+
"affectsGlobalScope": true
82+
}
83+
},
84+
"options": {
85+
"module": 1,
86+
"jsx": 4,
87+
"incremental": true,
88+
"jsxImportSource": "react",
89+
"project": "./",
90+
"strict": true,
91+
"configFilePath": "./tsconfig.json"
92+
},
93+
"referencedMap": {},
94+
"exportedModulesMap": {},
95+
"semanticDiagnosticsPerFile": [
96+
"../../lib/lib.d.ts",
97+
"./node_modules/@types/react/index.d.ts",
98+
[
99+
"./src/index.tsx",
100+
[
101+
{
102+
"file": "./src/index.tsx",
103+
"start": 25,
104+
"length": 24,
105+
"code": 7016,
106+
"category": 1,
107+
"messageText": "Could not find a declaration file for module 'react/jsx-runtime'. '/src/project/node_modules/react/jsx-runtime.js' implicitly has an 'any' type."
108+
}
109+
]
110+
]
111+
]
112+
},
113+
"version": "FakeTSVersion"
114+
}
115+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
Input::
2+
//// [/lib/lib.d.ts]
3+
/// <reference no-default-lib="true"/>
4+
interface Boolean {}
5+
interface Function {}
6+
interface CallableFunction {}
7+
interface NewableFunction {}
8+
interface IArguments {}
9+
interface Number { toExponential: any; }
10+
interface Object {}
11+
interface RegExp {}
12+
interface String { charAt: any; }
13+
interface Array<T> { length: number; [n: number]: T; }
14+
interface ReadonlyArray<T> {}
15+
declare const console: { log(msg: any): void; };
16+
17+
//// [/src/project/node_modules/@types/react/index.d.ts]
18+
19+
export {};
20+
declare global {
21+
namespace JSX {
22+
interface Element {}
23+
interface IntrinsicElements {
24+
div: {
25+
propA?: boolean;
26+
};
27+
}
28+
}
29+
}
30+
31+
//// [/src/project/node_modules/react/jsx-runtime.js]
32+
33+
34+
//// [/src/project/src/index.tsx]
35+
export const App = () => <div propA={true}></div>;
36+
37+
//// [/src/project/tsconfig.json]
38+
{"compilerOptions":{"module":"commonjs","jsx":"react-jsx","incremental":true,"jsxImportSource":"react"}}
39+
40+
41+
42+
Output::
43+
/lib/tsc --p src/project
44+
exitCode:: ExitStatus.Success
45+
46+
47+
//// [/src/project/src/index.js]
48+
"use strict";
49+
exports.__esModule = true;
50+
exports.App = void 0;
51+
var jsx_runtime_1 = require("react/jsx-runtime");
52+
var App = function () { return jsx_runtime_1.jsx("div", { propA: true }, void 0); };
53+
exports.App = App;
54+
55+
56+
//// [/src/project/tsconfig.tsbuildinfo]
57+
{
58+
"program": {
59+
"fileInfos": {
60+
"../../lib/lib.d.ts": {
61+
"version": "3858781397-/// <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; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
62+
"signature": "3858781397-/// <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; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
63+
"affectsGlobalScope": true
64+
},
65+
"./src/index.tsx": {
66+
"version": "-14760199789-export const App = () => <div propA={true}></div>;",
67+
"signature": "-8716173275-/// <reference types=\"react\" />\r\nexport declare const App: () => JSX.Element;\r\n",
68+
"affectsGlobalScope": false
69+
},
70+
"./node_modules/@types/react/index.d.ts": {
71+
"version": "-16587767667-\nexport {};\ndeclare global {\n namespace JSX {\n interface Element {}\n interface IntrinsicElements {\n div: {\n propA?: boolean;\n };\n }\n }\n}",
72+
"signature": "-16587767667-\nexport {};\ndeclare global {\n namespace JSX {\n interface Element {}\n interface IntrinsicElements {\n div: {\n propA?: boolean;\n };\n }\n }\n}",
73+
"affectsGlobalScope": true
74+
}
75+
},
76+
"options": {
77+
"module": 1,
78+
"jsx": 4,
79+
"incremental": true,
80+
"jsxImportSource": "react",
81+
"project": "./",
82+
"configFilePath": "./tsconfig.json"
83+
},
84+
"referencedMap": {},
85+
"exportedModulesMap": {},
86+
"semanticDiagnosticsPerFile": [
87+
"../../lib/lib.d.ts",
88+
"./node_modules/@types/react/index.d.ts",
89+
"./src/index.tsx"
90+
]
91+
},
92+
"version": "FakeTSVersion"
93+
}
94+

0 commit comments

Comments
 (0)