diff --git a/packages/babel-plugin-proposal-class-static-block/src/index.js b/packages/babel-plugin-proposal-class-static-block/src/index.js index 2ff1361c289a..a6c7ac71d783 100644 --- a/packages/babel-plugin-proposal-class-static-block/src/index.js +++ b/packages/babel-plugin-proposal-class-static-block/src/index.js @@ -1,6 +1,40 @@ import { declare } from "@babel/helper-plugin-utils"; import syntaxClassStaticBlock from "@babel/plugin-syntax-class-static-block"; +/** + * Generate a uid that is not in `denyList` + * + * @param {*} scope + * @param {Set} privateNames + * @returns + */ +function generateUid(scope, denyList: Set) { + const name = ""; + let uid; + let i = 0; + do { + uid = scope._generateUid(name, i); + i++; + } while (denyList.has(uid)); + return uid; +} + +/** + * Get private names defined in current class body + * + * @param {NodePath} classBody + * @returns {Set} A set of defined private names + */ +function getPrivateNames(classBody: NodePath): Set { + const privateNames = new Set(); + for (const path of classBody.get("body")) { + if (path.isPrivate()) { + privateNames.add(path.get("key.id").node.name); + } + } + return privateNames; +} + export default declare(({ types: t, template, assertVersion }) => { // todo remove this check after Babel 7.12.0 is published if (process.env.NODE_ENV !== "test") { @@ -11,13 +45,15 @@ export default declare(({ types: t, template, assertVersion }) => { name: "proposal-class-static-block", inherits: syntaxClassStaticBlock, visitor: { - StaticBlock(path) { - const staticBlockRef = path.scope.generateUidIdentifier(""); - const classBody = path.parentPath; + StaticBlock(path: NodePath) { + const { parentPath: classBody, scope } = path; + const staticBlockRef = t.privateName( + t.identifier(generateUid(scope, getPrivateNames(classBody))), + ); classBody.pushContainer( "body", t.classPrivateProperty( - t.privateName(staticBlockRef), + staticBlockRef, template.expression.ast`(() => { ${path.node.body} })()`, [], /* static */ true, diff --git a/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/in-class-heritage/output.js b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/in-class-heritage/output.js index 256b0f546814..ef844d07c994 100644 --- a/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/in-class-heritage/output.js +++ b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/in-class-heritage/output.js @@ -1,9 +1,9 @@ class Foo extends class extends class Base { - static #_3 = (() => { + static #_ = (() => { this.qux = 21; })(); } { - static #_2 = (() => { + static #_ = (() => { this.bar = 21; })(); } { diff --git a/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/exec.js b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/exec.js new file mode 100644 index 000000000000..0de932f8d73a --- /dev/null +++ b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/exec.js @@ -0,0 +1,8 @@ +class Foo { + static #_ = 42; + // static block can not be tranformed as `#_` here + static { + this.foo = this.#_; + } +} +expect(Foo.foo).toBe(42); diff --git a/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/input.js b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/input.js new file mode 100644 index 000000000000..0de932f8d73a --- /dev/null +++ b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/input.js @@ -0,0 +1,8 @@ +class Foo { + static #_ = 42; + // static block can not be tranformed as `#_` here + static { + this.foo = this.#_; + } +} +expect(Foo.foo).toBe(42); diff --git a/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/output.js b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/output.js new file mode 100644 index 000000000000..9f73880d1fc7 --- /dev/null +++ b/packages/babel-plugin-proposal-class-static-block/test/fixtures/class-static-block/name-conflict/output.js @@ -0,0 +1,9 @@ +class Foo { + static #_ = 42; // static block can not be tranformed as `#_` here + + static #_2 = (() => { + this.foo = this.#_; + })(); +} + +expect(Foo.foo).toBe(42);