diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/input.ts b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/input.ts
new file mode 100644
index 000000000000..26edcac0b890
--- /dev/null
+++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/input.ts
@@ -0,0 +1,5 @@
+export namespace Namespaced {
+ export const Component = () => (
+
Hello, world!
+ );
+}
diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/options.json b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/options.json
new file mode 100644
index 000000000000..3c8e6aa49b85
--- /dev/null
+++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/options.json
@@ -0,0 +1,8 @@
+{
+ "plugins": [
+ "transform-react-jsx-development",
+ ["syntax-typescript", { "isTSX": true }]
+ ],
+ "sourceType": "module",
+ "os": ["linux", "darwin"]
+}
diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/output.mjs b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/output.mjs
new file mode 100644
index 000000000000..9090c80cb91c
--- /dev/null
+++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/output.mjs
@@ -0,0 +1,11 @@
+var _jsxFileName = "/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/within-ts-module-block/input.ts";
+import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
+export namespace Namespaced {
+ export const Component = () => /*#__PURE__*/_jsxDEV("div", {
+ children: "Hello, world!"
+ }, void 0, false, {
+ fileName: _jsxFileName,
+ lineNumber: 3,
+ columnNumber: 3
+ }, void 0);
+}
diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/input.ts b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/input.ts
new file mode 100644
index 000000000000..26edcac0b890
--- /dev/null
+++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/input.ts
@@ -0,0 +1,5 @@
+export namespace Namespaced {
+ export const Component = () => (
+ Hello, world!
+ );
+}
diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/options.json b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/options.json
new file mode 100644
index 000000000000..1fb16caa5bff
--- /dev/null
+++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/options.json
@@ -0,0 +1,8 @@
+{
+ "plugins": [
+ "transform-react-jsx-development",
+ ["syntax-typescript", { "isTSX": true }]
+ ],
+ "sourceType": "module",
+ "os": ["win32"]
+}
diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/output.mjs b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/output.mjs
new file mode 100644
index 000000000000..efb871f367af
--- /dev/null
+++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/within-ts-module-block/output.mjs
@@ -0,0 +1,11 @@
+var _jsxFileName = "\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\within-ts-module-block\\input.ts";
+import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
+export namespace Namespaced {
+ export const Component = () => /*#__PURE__*/_jsxDEV("div", {
+ children: "Hello, world!"
+ }, void 0, false, {
+ fileName: _jsxFileName,
+ lineNumber: 3,
+ columnNumber: 3
+ }, void 0);
+}
diff --git a/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts b/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts
index 982083f1671e..b7a7530f084e 100644
--- a/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts
+++ b/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts
@@ -2,15 +2,13 @@ import jsx from "@babel/plugin-syntax-jsx";
import { declare } from "@babel/helper-plugin-utils";
import { types as t } from "@babel/core";
import type { PluginPass } from "@babel/core";
-import type { NodePath, Visitor } from "@babel/traverse";
+import type { NodePath, Scope, Visitor } from "@babel/traverse";
import { addNamed, addNamespace, isModule } from "@babel/helper-module-imports";
import annotateAsPure from "@babel/helper-annotate-as-pure";
import type {
- ArrowFunctionExpression,
CallExpression,
Class,
Expression,
- FunctionParent,
Identifier,
JSXAttribute,
JSXElement,
@@ -22,8 +20,6 @@ import type {
Program,
} from "@babel/types";
-type Diff = T extends U ? never : T;
-
const DEFAULT = {
importSource: "react",
runtime: "automatic",
@@ -116,7 +112,7 @@ export default function createPlugin({ name, development }) {
const injectMetaPropertiesVisitor: Visitor = {
JSXOpeningElement(path, state) {
const attributes = [];
- if (isThisAllowed(path)) {
+ if (isThisAllowed(path.scope)) {
attributes.push(
t.jsxAttribute(
t.jsxIdentifier("__self"),
@@ -295,52 +291,36 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
} as Visitor,
};
- // Finds the closest parent function that provides `this`. Specifically, this looks for
- // the first parent function that isn't an arrow function.
- //
- // Derived from `Scope#getFunctionParent`
- function getThisFunctionParent(
- path: NodePath,
- ): NodePath> | null {
- let scope = path.scope;
- do {
- if (
- scope.path.isFunctionParent() &&
- !scope.path.isArrowFunctionExpression()
- ) {
- // @ts-expect-error ts can not infer scope.path is Diff
- return scope.path;
- }
- } while ((scope = scope.parent));
- return null;
- }
-
// Returns whether the class has specified a superclass.
function isDerivedClass(classPath: NodePath) {
return classPath.node.superClass !== null;
}
- // Returns whether `this` is allowed at given path.
- function isThisAllowed(path: NodePath) {
+ // Returns whether `this` is allowed at given scope.
+ function isThisAllowed(scope: Scope) {
// This specifically skips arrow functions as they do not rewrite `this`.
- const parentMethodOrFunction = getThisFunctionParent(path);
- if (parentMethodOrFunction === null) {
- // We are not in a method or function. It is fine to use `this`.
- return true;
- }
- if (!parentMethodOrFunction.isMethod()) {
- // If the closest parent is a regular function, `this` will be rebound, therefore it is fine to use `this`.
- return true;
- }
- // Current node is within a method, so we need to check if the method is a constructor.
- if (parentMethodOrFunction.node.kind !== "constructor") {
- // We are not in a constructor, therefore it is always fine to use `this`.
- return true;
- }
- // Now we are in a constructor. If it is a derived class, we do not reference `this`.
- return !isDerivedClass(
- parentMethodOrFunction.parentPath.parentPath as NodePath,
- );
+ do {
+ const { path } = scope;
+ if (path.isFunctionParent() && !path.isArrowFunctionExpression()) {
+ if (!path.isMethod()) {
+ // If the closest parent is a regular function, `this` will be rebound, therefore it is fine to use `this`.
+ return true;
+ }
+ // Current node is within a method, so we need to check if the method is a constructor.
+ if (path.node.kind !== "constructor") {
+ // We are not in a constructor, therefore it is always fine to use `this`.
+ return true;
+ }
+ // Now we are in a constructor. If it is a derived class, we do not reference `this`.
+ return !isDerivedClass(path.parentPath.parentPath as NodePath);
+ }
+ if (path.isTSModuleBlock()) {
+ // If the closeset parent is a TS Module block, `this` will not be allowed.
+ return false;
+ }
+ } while ((scope = scope.parent));
+ // We are not in a method or function. It is fine to use `this`.
+ return true;
}
function call(