Skip to content

Commit 6714998

Browse files
committed
Auto-include types for the jsx import source in the new jsx transforms
1 parent 6bde4b5 commit 6714998

19 files changed

+955
-18
lines changed

src/compiler/checker.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25132,14 +25132,42 @@ namespace ts {
2513225132
return links.resolvedSymbol;
2513325133
}
2513425134

25135+
function getJsxNamespaceContainerForImplicitImport(location: Node | undefined): Symbol | undefined {
25136+
const file = location && getSourceFileOfNode(location);
25137+
const links = file && getNodeLinks(file);
25138+
if (links && links.jsxImplicitImportContainer === false) {
25139+
return undefined;
25140+
}
25141+
if (links && links.jsxImplicitImportContainer) {
25142+
return links.jsxImplicitImportContainer;
25143+
}
25144+
const runtimeImportSpecifier = getJSXRuntimeImport(getJSXImplicitImportBase(compilerOptions, file), compilerOptions);
25145+
if (!runtimeImportSpecifier) {
25146+
return undefined;
25147+
}
25148+
const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic;
25149+
const errorMessage = isClassic
25150+
? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option
25151+
: Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations;
25152+
const mod = resolveExternalModule(location!, runtimeImportSpecifier, errorMessage, location!);
25153+
const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined;
25154+
if (links) {
25155+
links.jsxImplicitImportContainer = result || false;
25156+
}
25157+
return result;
25158+
}
25159+
2513525160
function getJsxNamespaceAt(location: Node | undefined): Symbol {
2513625161
const links = location && getNodeLinks(location);
2513725162
if (links && links.jsxNamespace) {
2513825163
return links.jsxNamespace;
2513925164
}
2514025165
if (!links || links.jsxNamespace !== false) {
2514125166
const namespaceName = getJsxNamespace(location);
25142-
const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
25167+
let resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
25168+
if (!resolvedNamespace || resolvedNamespace === unknownSymbol) {
25169+
resolvedNamespace = getJsxNamespaceContainerForImplicitImport(location);
25170+
}
2514325171
if (resolvedNamespace) {
2514425172
const candidate = resolveSymbol(getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace));
2514525173
if (candidate && candidate !== unknownSymbol) {
@@ -25148,9 +25176,9 @@ namespace ts {
2514825176
}
2514925177
return candidate;
2515025178
}
25151-
if (links) {
25152-
links.jsxNamespace = false;
25153-
}
25179+
}
25180+
if (links) {
25181+
links.jsxNamespace = false;
2515425182
}
2515525183
}
2515625184
// JSX global fallback

src/compiler/moduleNameResolver.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,10 @@ namespace ts {
402402
*/
403403
export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: ModuleResolutionHost): string[] {
404404
// Use explicit type list from tsconfig.json
405+
// jsxImportSource, if present and in use, creates implicit imports
406+
const implicitImport = getJSXRuntimeImport(getJSXImplicitImportBase(options), options);
405407
if (options.types) {
406-
return options.types;
408+
return [...options.types, ...(implicitImport ? [implicitImport] : [])];
407409
}
408410

409411
// Walk the primary type lookup locations
@@ -434,6 +436,9 @@ namespace ts {
434436
}
435437
}
436438
}
439+
if (implicitImport) {
440+
result.push(implicitImport);
441+
}
437442
return result;
438443
}
439444

src/compiler/program.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,7 @@ namespace ts {
14941494
}
14951495
// try to verify results of module resolution
14961496
for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
1497-
const moduleNames = getModuleNames(newSourceFile);
1497+
const moduleNames = getModuleNames(newSourceFile, options);
14981498
const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile);
14991499
// ensure that module resolution results are still correct
15001500
const resolutionsChanged = hasChangesInResolutions(moduleNames, resolutions, oldSourceFile.resolvedModules, moduleResolutionIsEqualTo);
@@ -2840,11 +2840,16 @@ namespace ts {
28402840
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
28412841
}
28422842
else {
2843-
fileProcessingDiagnostics.add(createRefFileDiagnostic(
2844-
refFile,
2845-
Diagnostics.Cannot_find_type_definition_file_for_0,
2846-
typeReferenceDirective
2847-
));
2843+
// Don't issue an error when auto-inclusion lookup fails for the jsxImportSource (at this point)
2844+
// It may be provided by an ambient module in the compilation, instead.
2845+
// A usage of a JSX tag later should report that the module couldn't be resolved if it is not supplied.
2846+
if (refFile || typeReferenceDirective !== getJSXRuntimeImport(getJSXImplicitImportBase(options), options)) {
2847+
fileProcessingDiagnostics.add(createRefFileDiagnostic(
2848+
refFile,
2849+
Diagnostics.Cannot_find_type_definition_file_for_0,
2850+
typeReferenceDirective
2851+
));
2852+
}
28482853
}
28492854

28502855
if (saveResolution) {
@@ -2891,9 +2896,9 @@ namespace ts {
28912896

28922897
function processImportedModules(file: SourceFile) {
28932898
collectExternalModuleReferences(file);
2894-
if (file.imports.length || file.moduleAugmentations.length) {
2899+
if (file.imports.length || file.moduleAugmentations.length || getJSXImplicitImportBase(options, file)) {
28952900
// Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
2896-
const moduleNames = getModuleNames(file);
2901+
const moduleNames = getModuleNames(file, options);
28972902
const resolutions = resolveModuleNamesReusingOldState(moduleNames, file);
28982903
Debug.assert(resolutions.length === moduleNames.length);
28992904
for (let i = 0; i < moduleNames.length; i++) {
@@ -3882,14 +3887,19 @@ namespace ts {
38823887
}
38833888
}
38843889

3885-
function getModuleNames({ imports, moduleAugmentations }: SourceFile): string[] {
3890+
function getModuleNames(file: SourceFile, options: CompilerOptions): string[] {
3891+
const { imports, moduleAugmentations } = file;
38863892
const res = imports.map(i => i.text);
38873893
for (const aug of moduleAugmentations) {
38883894
if (aug.kind === SyntaxKind.StringLiteral) {
38893895
res.push(aug.text);
38903896
}
38913897
// Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
38923898
}
3899+
const jsxRuntimeImport = getJSXRuntimeImport(getJSXImplicitImportBase(options, file), options);
3900+
if (jsxRuntimeImport) {
3901+
res.push(jsxRuntimeImport);
3902+
}
38933903
return res;
38943904
}
38953905
}

src/compiler/transformers/jsx.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace ts {
4242
function getImplicitImportForName(name: string) {
4343
const importSource = name === "createElement"
4444
? currentFileState.importSpecifier!
45-
: `${currentFileState.importSpecifier}/${compilerOptions.jsx === JsxEmit.ReactJSXDev ? "jsx-dev-runtime" : "jsx-runtime"}`;
45+
: getJSXRuntimeImport(currentFileState.importSpecifier, compilerOptions)!;
4646
const existing = currentFileState.utilizedImplicitRuntimeImports?.get(importSource)?.get(name);
4747
if (existing) {
4848
return existing.name;

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4843,6 +4843,7 @@ namespace ts {
48434843
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
48444844
switchTypes?: Type[]; // Cached array of switch case expression types
48454845
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
4846+
jsxImplicitImportContainer?: Symbol | false; // Resolved module symbol the implicit jsx import of this file should refer to
48464847
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
48474848
deferredNodes?: ESMap<NodeId, Node>; // Set of nodes whose checking has been deferred
48484849
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement

src/compiler/utilities.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6009,8 +6009,8 @@ namespace ts {
60096009
return jsx === JsxEmit.React || jsx === JsxEmit.ReactJSX || jsx === JsxEmit.ReactJSXDev;
60106010
}
60116011

6012-
export function getJSXImplicitImportBase(compilerOptions: CompilerOptions, file: SourceFile): string | undefined {
6013-
const jsxImportSourcePragmas = file.pragmas.get("jsximportsource");
6012+
export function getJSXImplicitImportBase(compilerOptions: CompilerOptions, file?: SourceFile): string | undefined {
6013+
const jsxImportSourcePragmas = file?.pragmas.get("jsximportsource");
60146014
const jsxImportSourcePragma = isArray(jsxImportSourcePragmas) ? jsxImportSourcePragmas[0] : jsxImportSourcePragmas;
60156015
return compilerOptions.jsx === JsxEmit.ReactJSX ||
60166016
compilerOptions.jsx === JsxEmit.ReactJSXDev ||
@@ -6020,6 +6020,10 @@ namespace ts {
60206020
undefined;
60216021
}
60226022

6023+
export function getJSXRuntimeImport(base: string | undefined, options: CompilerOptions) {
6024+
return base ? `${base}/${options.jsx === JsxEmit.ReactJSXDev ? "jsx-dev-runtime" : "jsx-runtime"}` : undefined;
6025+
}
6026+
60236027
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
60246028
let seenAsterisk = false;
60256029
for (let i = 0; i < str.length; i++) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx (1 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
const a = <>
7+
~~
8+
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
9+
<p></p>
10+
text
11+
<div className="foo"></div>
12+
</>
13+
14+
export {};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx (1 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
const a = <>
7+
~~
8+
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
9+
<p></p>
10+
text
11+
<div className="foo"></div>
12+
</>
13+
14+
export {};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
tests/cases/conformance/jsx/jsxs/preact.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
/* @jsxImportSource react */
7+
import "./preact";
8+
const a = <>
9+
<p></p>
10+
text
11+
<div className="foo"></div>
12+
</>
13+
14+
export {};
15+
==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
16+
/// <reference path="/.lib/react16.d.ts" />
17+
/* @jsxImportSource preact */
18+
const a = <>
19+
~~
20+
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
21+
<p></p>
22+
text
23+
<div className="foo"></div>
24+
</>
25+
26+
export {};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
tests/cases/conformance/jsx/jsxs/preact.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
/* @jsxImportSource react */
7+
import "./preact";
8+
const a = <>
9+
<p></p>
10+
text
11+
<div className="foo"></div>
12+
</>
13+
14+
export {};
15+
==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
16+
/// <reference path="/.lib/react16.d.ts" />
17+
/* @jsxImportSource preact */
18+
const a = <>
19+
~~
20+
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
21+
<p></p>
22+
text
23+
<div className="foo"></div>
24+
</>
25+
26+
export {};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx (1 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
const props = { answer: 42 }
7+
const a = <div key="foo" {...props}>text</div>;
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
10+
const b = <div {...props} key="bar">text</div>;
11+
12+
export {};
13+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx (1 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
const props = { answer: 42 }
7+
const a = <div key="foo" {...props}>text</div>;
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
10+
const b = <div {...props} key="bar">text</div>;
11+
12+
export {};
13+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
tests/cases/conformance/jsx/jsxs/preact.tsx(4,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
/* @jsxImportSource react */
7+
import "./preact";
8+
const props2 = { answer: 42 }
9+
const a2 = <div key="foo" {...props2}>text</div>;
10+
const b2 = <div {...props2} key="bar">text</div>;
11+
12+
export {};
13+
14+
==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
15+
/// <reference path="/.lib/react16.d.ts" />
16+
/* @jsxImportSource preact */
17+
const props = { answer: 42 }
18+
const a = <div key="foo" {...props}>text</div>;
19+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
21+
const b = <div {...props} key="bar">text</div>;
22+
23+
export {};
24+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
tests/cases/conformance/jsx/jsxs/preact.tsx(4,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
2+
3+
4+
==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
5+
/// <reference path="/.lib/react16.d.ts" />
6+
/* @jsxImportSource react */
7+
import "./preact";
8+
const props2 = { answer: 42 }
9+
const a2 = <div key="foo" {...props2}>text</div>;
10+
const b2 = <div {...props2} key="bar">text</div>;
11+
12+
export {};
13+
14+
==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
15+
/// <reference path="/.lib/react16.d.ts" />
16+
/* @jsxImportSource preact */
17+
const props = { answer: 42 }
18+
const a = <div key="foo" {...props}>text</div>;
19+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
21+
const b = <div {...props} key="bar">text</div>;
22+
23+
export {};
24+

0 commit comments

Comments
 (0)