Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-include types for the jsx import source in the new jsx transforms #41330

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 32 additions & 4 deletions src/compiler/checker.ts
Expand Up @@ -25132,14 +25132,42 @@ namespace ts {
return links.resolvedSymbol;
}

function getJsxNamespaceContainerForImplicitImport(location: Node | undefined): Symbol | undefined {
const file = location && getSourceFileOfNode(location);
const links = file && getNodeLinks(file);
if (links && links.jsxImplicitImportContainer === false) {
return undefined;
}
if (links && links.jsxImplicitImportContainer) {
return links.jsxImplicitImportContainer;
}
const runtimeImportSpecifier = getJSXRuntimeImport(getJSXImplicitImportBase(compilerOptions, file), compilerOptions);
if (!runtimeImportSpecifier) {
return undefined;
}
const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic;
const errorMessage = isClassic
? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option
: Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations;
const mod = resolveExternalModule(location!, runtimeImportSpecifier, errorMessage, location!);
const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined;
if (links) {
links.jsxImplicitImportContainer = result || false;
}
return result;
}

function getJsxNamespaceAt(location: Node | undefined): Symbol {
const links = location && getNodeLinks(location);
if (links && links.jsxNamespace) {
return links.jsxNamespace;
}
if (!links || links.jsxNamespace !== false) {
const namespaceName = getJsxNamespace(location);
const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
let resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
if (!resolvedNamespace || resolvedNamespace === unknownSymbol) {
resolvedNamespace = getJsxNamespaceContainerForImplicitImport(location);
}
if (resolvedNamespace) {
const candidate = resolveSymbol(getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace));
if (candidate && candidate !== unknownSymbol) {
Expand All @@ -25148,9 +25176,9 @@ namespace ts {
}
return candidate;
}
if (links) {
links.jsxNamespace = false;
}
}
if (links) {
links.jsxNamespace = false;
}
}
// JSX global fallback
Expand Down
7 changes: 6 additions & 1 deletion src/compiler/moduleNameResolver.ts
Expand Up @@ -402,8 +402,10 @@ namespace ts {
*/
export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: ModuleResolutionHost): string[] {
// Use explicit type list from tsconfig.json
// jsxImportSource, if present and in use, creates implicit imports
const implicitImport = getJSXRuntimeImport(getJSXImplicitImportBase(options), options);
weswigham marked this conversation as resolved.
Show resolved Hide resolved
if (options.types) {
return options.types;
return [...options.types, ...(implicitImport ? [implicitImport] : [])];
}

// Walk the primary type lookup locations
Expand Down Expand Up @@ -434,6 +436,9 @@ namespace ts {
}
}
}
if (implicitImport) {
result.push(implicitImport);
}
return result;
}

Expand Down
28 changes: 19 additions & 9 deletions src/compiler/program.ts
Expand Up @@ -1494,7 +1494,7 @@ namespace ts {
}
// try to verify results of module resolution
for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
const moduleNames = getModuleNames(newSourceFile);
const moduleNames = getModuleNames(newSourceFile, options);
const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile);
// ensure that module resolution results are still correct
const resolutionsChanged = hasChangesInResolutions(moduleNames, resolutions, oldSourceFile.resolvedModules, moduleResolutionIsEqualTo);
Expand Down Expand Up @@ -2840,11 +2840,16 @@ namespace ts {
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
}
else {
fileProcessingDiagnostics.add(createRefFileDiagnostic(
refFile,
Diagnostics.Cannot_find_type_definition_file_for_0,
typeReferenceDirective
));
// Don't issue an error when auto-inclusion lookup fails for the jsxImportSource (at this point)
// It may be provided by an ambient module in the compilation, instead.
// A usage of a JSX tag later should report that the module couldn't be resolved if it is not supplied.
if (refFile || typeReferenceDirective !== getJSXRuntimeImport(getJSXImplicitImportBase(options), options)) {
fileProcessingDiagnostics.add(createRefFileDiagnostic(
refFile,
Diagnostics.Cannot_find_type_definition_file_for_0,
typeReferenceDirective
));
}
}

if (saveResolution) {
Expand Down Expand Up @@ -2891,9 +2896,9 @@ namespace ts {

function processImportedModules(file: SourceFile) {
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
if (file.imports.length || file.moduleAugmentations.length || getJSXImplicitImportBase(options, file)) {
// Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
const moduleNames = getModuleNames(file);
const moduleNames = getModuleNames(file, options);
const resolutions = resolveModuleNamesReusingOldState(moduleNames, file);
Debug.assert(resolutions.length === moduleNames.length);
for (let i = 0; i < moduleNames.length; i++) {
Expand Down Expand Up @@ -3882,14 +3887,19 @@ namespace ts {
}
}

function getModuleNames({ imports, moduleAugmentations }: SourceFile): string[] {
function getModuleNames(file: SourceFile, options: CompilerOptions): string[] {
const { imports, moduleAugmentations } = file;
const res = imports.map(i => i.text);
for (const aug of moduleAugmentations) {
if (aug.kind === SyntaxKind.StringLiteral) {
res.push(aug.text);
}
// Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`.
}
const jsxRuntimeImport = getJSXRuntimeImport(getJSXImplicitImportBase(options, file), options);
weswigham marked this conversation as resolved.
Show resolved Hide resolved
if (jsxRuntimeImport) {
res.push(jsxRuntimeImport);
}
return res;
}
}
2 changes: 1 addition & 1 deletion src/compiler/transformers/jsx.ts
Expand Up @@ -42,7 +42,7 @@ namespace ts {
function getImplicitImportForName(name: string) {
const importSource = name === "createElement"
? currentFileState.importSpecifier!
: `${currentFileState.importSpecifier}/${compilerOptions.jsx === JsxEmit.ReactJSXDev ? "jsx-dev-runtime" : "jsx-runtime"}`;
: getJSXRuntimeImport(currentFileState.importSpecifier, compilerOptions)!;
const existing = currentFileState.utilizedImplicitRuntimeImports?.get(importSource)?.get(name);
if (existing) {
return existing.name;
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Expand Up @@ -4843,6 +4843,7 @@ namespace ts {
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
switchTypes?: Type[]; // Cached array of switch case expression types
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
jsxImplicitImportContainer?: Symbol | false; // Resolved module symbol the implicit jsx import of this file should refer to
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
deferredNodes?: ESMap<NodeId, Node>; // Set of nodes whose checking has been deferred
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
Expand Down
8 changes: 6 additions & 2 deletions src/compiler/utilities.ts
Expand Up @@ -6009,8 +6009,8 @@ namespace ts {
return jsx === JsxEmit.React || jsx === JsxEmit.ReactJSX || jsx === JsxEmit.ReactJSXDev;
}

export function getJSXImplicitImportBase(compilerOptions: CompilerOptions, file: SourceFile): string | undefined {
const jsxImportSourcePragmas = file.pragmas.get("jsximportsource");
export function getJSXImplicitImportBase(compilerOptions: CompilerOptions, file?: SourceFile): string | undefined {
const jsxImportSourcePragmas = file?.pragmas.get("jsximportsource");
weswigham marked this conversation as resolved.
Show resolved Hide resolved
const jsxImportSourcePragma = isArray(jsxImportSourcePragmas) ? jsxImportSourcePragmas[0] : jsxImportSourcePragmas;
return compilerOptions.jsx === JsxEmit.ReactJSX ||
compilerOptions.jsx === JsxEmit.ReactJSXDev ||
Expand All @@ -6020,6 +6020,10 @@ namespace ts {
undefined;
}

export function getJSXRuntimeImport(base: string | undefined, options: CompilerOptions) {
return base ? `${base}/${options.jsx === JsxEmit.ReactJSXDev ? "jsx-dev-runtime" : "jsx-runtime"}` : undefined;
}

export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
let seenAsterisk = false;
for (let i = 0; i < str.length; i++) {
Expand Down
@@ -0,0 +1,14 @@
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
const a = <>
~~
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
<p></p>
text
<div className="foo"></div>
</>

export {};
@@ -0,0 +1,14 @@
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx(2,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformCustomImport.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
const a = <>
~~
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
<p></p>
text
<div className="foo"></div>
</>

export {};
@@ -0,0 +1,26 @@
tests/cases/conformance/jsx/jsxs/preact.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource react */
import "./preact";
const a = <>
<p></p>
text
<div className="foo"></div>
</>

export {};
==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource preact */
const a = <>
~~
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
<p></p>
text
<div className="foo"></div>
</>

export {};
@@ -0,0 +1,26 @@
tests/cases/conformance/jsx/jsxs/preact.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource react */
import "./preact";
const a = <>
<p></p>
text
<div className="foo"></div>
</>

export {};
==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource preact */
const a = <>
~~
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
<p></p>
text
<div className="foo"></div>
</>

export {};
@@ -0,0 +1,13 @@
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
const props = { answer: 42 }
const a = <div key="foo" {...props}>text</div>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
const b = <div {...props} key="bar">text</div>;

export {};

@@ -0,0 +1,13 @@
tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx(3,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/jsxJsxsCjsTransformKeyPropCustomImport.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
const props = { answer: 42 }
const a = <div key="foo" {...props}>text</div>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
const b = <div {...props} key="bar">text</div>;

export {};

@@ -0,0 +1,24 @@
tests/cases/conformance/jsx/jsxs/preact.tsx(4,11): error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource react */
import "./preact";
const props2 = { answer: 42 }
const a2 = <div key="foo" {...props2}>text</div>;
const b2 = <div {...props2} key="bar">text</div>;

export {};

==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource preact */
const props = { answer: 42 }
const a = <div key="foo" {...props}>text</div>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'preact/jsx-runtime' or its corresponding type declarations.
const b = <div {...props} key="bar">text</div>;

export {};

@@ -0,0 +1,24 @@
tests/cases/conformance/jsx/jsxs/preact.tsx(4,11): error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.


==== tests/cases/conformance/jsx/jsxs/react.tsx (0 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource react */
import "./preact";
const props2 = { answer: 42 }
const a2 = <div key="foo" {...props2}>text</div>;
const b2 = <div {...props2} key="bar">text</div>;

export {};

==== tests/cases/conformance/jsx/jsxs/preact.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
/* @jsxImportSource preact */
const props = { answer: 42 }
const a = <div key="foo" {...props}>text</div>;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'preact/jsx-dev-runtime' or its corresponding type declarations.
const b = <div {...props} key="bar">text</div>;

export {};