@@ -2,15 +2,13 @@ import jsx from "@babel/plugin-syntax-jsx";
22import { declare } from "@babel/helper-plugin-utils" ;
33import { types as t } from "@babel/core" ;
44import type { PluginPass } from "@babel/core" ;
5- import type { NodePath , Visitor } from "@babel/traverse" ;
5+ import type { NodePath , Scope , Visitor } from "@babel/traverse" ;
66import { addNamed , addNamespace , isModule } from "@babel/helper-module-imports" ;
77import annotateAsPure from "@babel/helper-annotate-as-pure" ;
88import type {
9- ArrowFunctionExpression ,
109 CallExpression ,
1110 Class ,
1211 Expression ,
13- FunctionParent ,
1412 Identifier ,
1513 JSXAttribute ,
1614 JSXElement ,
@@ -22,8 +20,6 @@ import type {
2220 Program ,
2321} from "@babel/types" ;
2422
25- type Diff < T , U > = T extends U ? never : T ;
26-
2723const DEFAULT = {
2824 importSource : "react" ,
2925 runtime : "automatic" ,
@@ -116,7 +112,7 @@ export default function createPlugin({ name, development }) {
116112 const injectMetaPropertiesVisitor : Visitor < PluginPass > = {
117113 JSXOpeningElement ( path , state ) {
118114 const attributes = [ ] ;
119- if ( isThisAllowed ( path ) ) {
115+ if ( isThisAllowed ( path . scope ) ) {
120116 attributes . push (
121117 t . jsxAttribute (
122118 t . jsxIdentifier ( "__self" ) ,
@@ -295,52 +291,36 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
295291 } as Visitor < PluginPass > ,
296292 } ;
297293
298- // Finds the closest parent function that provides `this`. Specifically, this looks for
299- // the first parent function that isn't an arrow function.
300- //
301- // Derived from `Scope#getFunctionParent`
302- function getThisFunctionParent (
303- path : NodePath ,
304- ) : NodePath < Diff < FunctionParent , ArrowFunctionExpression > > | null {
305- let scope = path . scope ;
306- do {
307- if (
308- scope . path . isFunctionParent ( ) &&
309- ! scope . path . isArrowFunctionExpression ( )
310- ) {
311- // @ts -expect-error ts can not infer scope.path is Diff<FunctionParent, ArrowFunctionExpression>
312- return scope . path ;
313- }
314- } while ( ( scope = scope . parent ) ) ;
315- return null ;
316- }
317-
318294 // Returns whether the class has specified a superclass.
319295 function isDerivedClass ( classPath : NodePath < Class > ) {
320296 return classPath . node . superClass !== null ;
321297 }
322298
323- // Returns whether `this` is allowed at given path .
324- function isThisAllowed ( path : NodePath < JSXOpeningElement > ) {
299+ // Returns whether `this` is allowed at given scope .
300+ function isThisAllowed ( scope : Scope ) {
325301 // This specifically skips arrow functions as they do not rewrite `this`.
326- const parentMethodOrFunction = getThisFunctionParent ( path ) ;
327- if ( parentMethodOrFunction === null ) {
328- // We are not in a method or function. It is fine to use `this`.
329- return true ;
330- }
331- if ( ! parentMethodOrFunction . isMethod ( ) ) {
332- // If the closest parent is a regular function, `this` will be rebound, therefore it is fine to use `this`.
333- return true ;
334- }
335- // Current node is within a method, so we need to check if the method is a constructor.
336- if ( parentMethodOrFunction . node . kind !== "constructor" ) {
337- // We are not in a constructor, therefore it is always fine to use `this`.
338- return true ;
339- }
340- // Now we are in a constructor. If it is a derived class, we do not reference `this`.
341- return ! isDerivedClass (
342- parentMethodOrFunction . parentPath . parentPath as NodePath < Class > ,
343- ) ;
302+ do {
303+ const { path } = scope ;
304+ if ( path . isFunctionParent ( ) && ! path . isArrowFunctionExpression ( ) ) {
305+ if ( ! path . isMethod ( ) ) {
306+ // If the closest parent is a regular function, `this` will be rebound, therefore it is fine to use `this`.
307+ return true ;
308+ }
309+ // Current node is within a method, so we need to check if the method is a constructor.
310+ if ( path . node . kind !== "constructor" ) {
311+ // We are not in a constructor, therefore it is always fine to use `this`.
312+ return true ;
313+ }
314+ // Now we are in a constructor. If it is a derived class, we do not reference `this`.
315+ return ! isDerivedClass ( path . parentPath . parentPath as NodePath < Class > ) ;
316+ }
317+ if ( path . isTSModuleBlock ( ) ) {
318+ // If the closeset parent is a TS Module block, `this` will not be allowed.
319+ return false ;
320+ }
321+ } while ( ( scope = scope . parent ) ) ;
322+ // We are not in a method or function. It is fine to use `this`.
323+ return true ;
344324 }
345325
346326 function call (
0 commit comments