diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index 908d0b133062..29e94d746ef9 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -669,6 +669,17 @@ const thisContextVisitor = traverse.visitors.merge([ environmentVisitor, ]); +const innerReferencesVisitor = { + ReferencedIdentifier(path, state) { + if ( + path.scope.bindingIdentifierEquals(path.node.name, state.innerBinding) + ) { + state.needsClassRef = true; + path.node.name = state.classRef.name; + } + }, +}; + function replaceThisContext( path, ref, @@ -676,8 +687,13 @@ function replaceThisContext( file, isStaticBlock, constantSuper, + innerBindingRef, ) { - const state = { classRef: ref, needsClassRef: false }; + const state = { + classRef: ref, + needsClassRef: false, + innerBinding: innerBindingRef, + }; const replacer = new ReplaceSupers({ methodPath: path, @@ -696,6 +712,11 @@ function replaceThisContext( if (isStaticBlock || path.isProperty()) { path.traverse(thisContextVisitor, state); } + + if (state.classRef?.name && state.classRef.name !== innerBindingRef?.name) { + path.traverse(innerReferencesVisitor, state); + } + return state.needsClassRef; } @@ -708,6 +729,7 @@ export function buildFieldsInitNodes( setPublicClassFields, privateFieldsAsProperties, constantSuper, + innerBindingRef, ) { let needsClassRef = false; let injectSuperRef; @@ -743,6 +765,7 @@ export function buildFieldsInitNodes( state, isStaticBlock, constantSuper, + innerBindingRef, ); needsClassRef = needsClassRef || replaced; } diff --git a/packages/babel-helper-create-class-features-plugin/src/index.ts b/packages/babel-helper-create-class-features-plugin/src/index.ts index e071aa2845c9..359085b52b2b 100644 --- a/packages/babel-helper-create-class-features-plugin/src/index.ts +++ b/packages/babel-helper-create-class-features-plugin/src/index.ts @@ -168,9 +168,9 @@ export function createClassFeaturePlugin({ if (!props.length && !isDecorated) return; + const innerBinding = path.node.id; let ref; - - if (path.isClassExpression() || !path.node.id) { + if (!innerBinding || path.isClassExpression()) { nameFunction(path); ref = path.scope.generateUidIdentifier("class"); } else { @@ -220,6 +220,7 @@ export function createClassFeaturePlugin({ setPublicClassFields ?? loose, privateFieldsAsProperties ?? loose, constantSuper ?? loose, + innerBinding, )); } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/exec.js new file mode 100644 index 000000000000..388fed537f7d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/exec.js @@ -0,0 +1,15 @@ +const f = class Foo { + static #x = Foo; + static y = Foo; + + static extract() { + return { + x: Foo.#x, + y: Foo.y, + } + } +}; + +const { x, y } = f.extract(); +expect(x).toBe(f) +expect(y).toBe(f) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/input.js new file mode 100644 index 000000000000..24e0bf9e918d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/input.js @@ -0,0 +1,4 @@ +const f = class Foo { + static #x = Foo; + static y = Foo; +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/options.json new file mode 100644 index 000000000000..c13414457ab2 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties", "transform-block-scoping"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/output.js new file mode 100644 index 000000000000..e24d4e7024e4 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-field/output.js @@ -0,0 +1,6 @@ +var _class, _temp, _x; + +var f = (_temp = _class = class Foo {}, _x = { + writable: true, + value: _class +}, babelHelpers.defineProperty(_class, "y", _class), _temp); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/exec.js new file mode 100644 index 000000000000..09bb2297db3c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/exec.js @@ -0,0 +1,31 @@ +const f = class Foo { + static #bar() { + return Foo; + } + + static #method() { + return function inner() { + return Foo; + }; + } + static #method_shadowed() { + new Foo(); + return function inner() { + let Foo = 3; + return Foo; + } + } + + static extract() { + return { + bar: Foo.#bar, + method: Foo.#method, + method_shadowed: Foo.#method_shadowed + } + } +}; + +const { bar, method, method_shadowed } = f.extract(); +expect(bar()).toBe(f) +expect(method()()).toBe(f) +expect(method_shadowed()()).toBe(3) diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/input.js new file mode 100644 index 000000000000..a8c80e401bef --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/input.js @@ -0,0 +1,18 @@ +const f = class Foo { + static #bar() { + return Foo; + } + + static #method() { + return function inner() { + return Foo; + }; + } + static #method_shadowed() { + new Foo(); + return function inner() { + let Foo = 3; + return Foo; + } + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/options.json new file mode 100644 index 000000000000..c13414457ab2 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-class-properties", "transform-block-scoping"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/output.js new file mode 100644 index 000000000000..b3f7c4cf2a5b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/static-self-method/output.js @@ -0,0 +1,21 @@ +var _class; + +var f = _class = class Foo {}; + +function _bar() { + return _class; +} + +function _method() { + return function inner() { + return _class; + }; +} + +function _method_shadowed() { + new _class(); + return function inner() { + var Foo = 3; + return Foo; + }; +}