Skip to content

Commit

Permalink
Don't substitute namespace exported names in JSX intrinsic tag names
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Dec 26, 2024
1 parent 56a0825 commit 0bc569a
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 9 deletions.
8 changes: 1 addition & 7 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ import {
isJsxCallLike,
isJsxElement,
isJsxFragment,
isJsxIntrinsicTagName,
isJsxNamespacedName,
isJsxOpeningElement,
isJsxOpeningFragment,
Expand Down Expand Up @@ -33099,13 +33100,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return (name as string).includes("-");
}

/**
* Returns true iff React would emit this tag name as a string rather than an identifier or qualified name
*/
function isJsxIntrinsicTagName(tagName: Node): tagName is Identifier | JsxNamespacedName {
return isIdentifier(tagName) && isIntrinsicJsxName(tagName.escapedText) || isJsxNamespacedName(tagName);
}

function checkJsxAttribute(node: JsxAttribute, checkMode?: CheckMode) {
return node.initializer
? checkExpressionForMutableLocation(node.initializer, checkMode)
Expand Down
7 changes: 5 additions & 2 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ import {
isInstantiatedModule,
isJsonSourceFile,
isJsxAttributes,
isJsxIntrinsicTagName,
isJSXTagName,
isJsxTagNameExpression,
isLeftHandSideExpression,
isLocalName,
Expand Down Expand Up @@ -2688,8 +2690,9 @@ export function transformTypeScript(context: TransformationContext): Transformer
// an identifier that is exported from a merged namespace.
const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false);
if (container && container.kind !== SyntaxKind.SourceFile) {
const substitute = (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
(applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration);
const substitute = ((applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
(applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration)) &&
(!isJSXTagName(node) || !isJsxIntrinsicTagName(node));
if (substitute) {
return setTextRange(
factory.createPropertyAccessExpression(factory.getGeneratedNameForNode(container), node),
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3549,6 +3549,14 @@ export function isJSXTagName(node: Node): boolean {
return false;
}

/**
* @internal
* Returns true if React would emit this tag name as a string rather than an identifier or qualified name
*/
export function isJsxIntrinsicTagName(tagName: Node): tagName is Identifier | JsxNamespacedName {
return isIdentifier(tagName) && isIntrinsicJsxName(tagName.escapedText) || isJsxNamespacedName(tagName);
}

/** @internal */
export function isExpressionNode(node: Node): boolean {
switch (node.kind) {
Expand Down
27 changes: 27 additions & 0 deletions tests/baselines/reference/namespaceJsxPreserve1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//// [tests/cases/compiler/namespaceJsxPreserve1.tsx] ////

//// [namespaceJsxPreserve1.tsx]
/// <reference path="/.lib/react16.d.ts" />

export namespace form {
export const input = null;

export const HiddenInput = () => null;

export const test1 = <input />;
export const test2 = <HiddenInput />;
}


//// [namespaceJsxPreserve1.jsx]
"use strict";
/// <reference path="react16.d.ts" />
Object.defineProperty(exports, "__esModule", { value: true });
exports.form = void 0;
var form;
(function (form) {
form.input = null;
form.HiddenInput = function () { return null; };
form.test1 = <input />;
form.test2 = <form.HiddenInput />;
})(form || (exports.form = form = {}));
23 changes: 23 additions & 0 deletions tests/baselines/reference/namespaceJsxPreserve1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//// [tests/cases/compiler/namespaceJsxPreserve1.tsx] ////

=== namespaceJsxPreserve1.tsx ===
/// <reference path="react16.d.ts" />

export namespace form {
>form : Symbol(form, Decl(namespaceJsxPreserve1.tsx, 0, 0))

export const input = null;
>input : Symbol(input, Decl(namespaceJsxPreserve1.tsx, 3, 14))

export const HiddenInput = () => null;
>HiddenInput : Symbol(HiddenInput, Decl(namespaceJsxPreserve1.tsx, 5, 14))

export const test1 = <input />;
>test1 : Symbol(test1, Decl(namespaceJsxPreserve1.tsx, 7, 14))
>input : Symbol(JSX.IntrinsicElements.input, Decl(react16.d.ts, 2570, 106))

export const test2 = <HiddenInput />;
>test2 : Symbol(test2, Decl(namespaceJsxPreserve1.tsx, 8, 14))
>HiddenInput : Symbol(HiddenInput, Decl(namespaceJsxPreserve1.tsx, 5, 14))
}

42 changes: 42 additions & 0 deletions tests/baselines/reference/namespaceJsxPreserve1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//// [tests/cases/compiler/namespaceJsxPreserve1.tsx] ////

=== Performance Stats ===
Assignability cache: 2,500
Type Count: 10,000
Instantiation count: 100,000
Symbol count: 50,000

=== namespaceJsxPreserve1.tsx ===
/// <reference path="react16.d.ts" />

export namespace form {
>form : typeof form
> : ^^^^^^^^^^^

export const input = null;
>input : null
> : ^^^^

export const HiddenInput = () => null;
>HiddenInput : () => null
> : ^^^^^^^^^^
>() => null : () => null
> : ^^^^^^^^^^

export const test1 = <input />;
>test1 : JSX.Element
> : ^^^^^^^^^^^
><input /> : JSX.Element
> : ^^^^^^^^^^^
>input : null
> : ^^^^

export const test2 = <HiddenInput />;
>test2 : JSX.Element
> : ^^^^^^^^^^^
><HiddenInput /> : JSX.Element
> : ^^^^^^^^^^^
>HiddenInput : () => null
> : ^^^^^^^^^^
}

13 changes: 13 additions & 0 deletions tests/cases/compiler/namespaceJsxPreserve1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @strict: true
// @jsx: preserve

/// <reference path="/.lib/react16.d.ts" />

export namespace form {
export const input = null;

export const HiddenInput = () => null;

export const test1 = <input />;
export const test2 = <HiddenInput />;
}

0 comments on commit 0bc569a

Please sign in to comment.