diff --git a/packages/babel-plugin-proposal-private-property-in-object/package.json b/packages/babel-plugin-proposal-private-property-in-object/package.json index 385e50f0436d..c66badfdb787 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/package.json +++ b/packages/babel-plugin-proposal-private-property-in-object/package.json @@ -18,7 +18,8 @@ ], "dependencies": { "@babel/helper-create-class-features-plugin": "workspace:^7.13.0", - "@babel/helper-plugin-utils": "workspace:^7.13.0" + "@babel/helper-plugin-utils": "workspace:^7.13.0", + "@babel/plugin-syntax-private-property-in-object": "workspace:^7.13.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" diff --git a/packages/babel-plugin-proposal-private-property-in-object/src/index.js b/packages/babel-plugin-proposal-private-property-in-object/src/index.js index c8c5c7bddcc0..f0c1ad5e43f9 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/src/index.js +++ b/packages/babel-plugin-proposal-private-property-in-object/src/index.js @@ -6,15 +6,21 @@ import { FEATURES, } from "@babel/helper-create-class-features-plugin"; +import pluginPrivateIn from "./native-private-fields"; + export default declare((api, options) => { api.assertVersion(7); + const { loose, nativePrivateFields } = options; + + if (nativePrivateFields) return pluginPrivateIn(api); + return createClassFeaturePlugin({ name: "proposal-class-properties", api, feature: FEATURES.privateIn, - loose: options.loose, + loose, manipulateOptions(opts, parserOpts) { parserOpts.plugins.push("privateIn"); diff --git a/packages/babel-plugin-proposal-private-property-in-object/src/native-private-fields.js b/packages/babel-plugin-proposal-private-property-in-object/src/native-private-fields.js new file mode 100644 index 000000000000..686eab8cdc7c --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/src/native-private-fields.js @@ -0,0 +1,67 @@ +import syntaxPlugin from "@babel/plugin-syntax-private-property-in-object"; +import { injectInitialization } from "@babel/helper-create-class-features-plugin"; + +export default function pluginPrivateIn({ types: t, template }) { + const ids = new WeakMap(); + + return { + name: "proposal-private-property-in-object", + inherits: syntaxPlugin, + visitor: { + BinaryExpression(path) { + const { node } = path; + if (node.operator !== "in") return; + if (!t.isPrivateName(node.left)) return; + + const { name } = node.left.id; + + let isStatic; + const outerClass = path.findParent(path => { + if (!path.isClass()) return false; + + const privateElement = path.node.body.body.find( + node => t.isPrivate(node) && node.key.id.name === name, + ); + if (!privateElement) return false; + + isStatic = privateElement.static; + return true; + }); + + if (isStatic) { + if (!outerClass.node.id) { + outerClass.set("id", path.scope.generateUidIdentifier("class")); + } + path.replaceWith( + template.expression.ast` + ${t.cloneNode(outerClass.node.id)} === ${path.node.right} + `, + ); + return; + } + + let id = ids.get(outerClass.node); + if (!id) { + id = outerClass.scope.generateUidIdentifier( + `${outerClass.node.id?.name || ""} brandCheck`, + ); + ids.set(outerClass.node, id); + + const constructor = outerClass + .get("body.body") + .find(el => el.isClassMethod({ kind: "constructor" })); + + injectInitialization(outerClass, constructor, [ + template.ast`${t.cloneNode(id)}.add(this)`, + ]); + + outerClass.insertBefore(template.ast`var ${id} = new WeakSet()`); + } + + path.replaceWith( + template.ast`${t.cloneNode(id)}.has(${path.node.right})`, + ); + }, + }, + }; +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/accessor/input.js new file mode 100644 index 000000000000..c0e9000615fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/accessor/output.js new file mode 100644 index 000000000000..7a64679f5a1a --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/accessor/output.js @@ -0,0 +1,14 @@ +var _FooBrandCheck = new WeakSet(); + +class Foo { + constructor() { + _FooBrandCheck.add(this); + } + + get #foo() {} + + test(other) { + return _FooBrandCheck.has(other); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/input.js new file mode 100644 index 000000000000..3d817b01b547 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/input.js @@ -0,0 +1,9 @@ +function fn() { + return new class { + #priv; + + method(obj) { + return #priv in obj; + } + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/output.js new file mode 100644 index 000000000000..b52693938314 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/output.js @@ -0,0 +1,16 @@ +function fn() { + var _brandCheck; + + return new (_brandCheck = new WeakSet(), class { + constructor() { + _brandCheck.add(this); + } + + #priv; + + method(obj) { + return _brandCheck.has(obj); + } + + })(); +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/input.js new file mode 100644 index 000000000000..8f394f3d4c76 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/input.js @@ -0,0 +1,9 @@ +function fn() { + return new class { + static #priv; + + method(obj) { + return #priv in obj; + } + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/output.js new file mode 100644 index 000000000000..20a1dff648cf --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/output.js @@ -0,0 +1,10 @@ +function fn() { + return new class _class { + static #priv; + + method(obj) { + return _class === obj; + } + + }(); +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/input.js new file mode 100644 index 000000000000..a682a1a15c5b --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/output.js new file mode 100644 index 000000000000..06c9ccc921e6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/output.js @@ -0,0 +1,14 @@ +var _FooBrandCheck = new WeakSet(); + +class Foo { + constructor() { + _FooBrandCheck.add(this); + } + + #foo = 1; + + test(other) { + return _FooBrandCheck.has(other); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/method/input.js new file mode 100644 index 000000000000..365843c59708 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/method/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/method/output.js new file mode 100644 index 000000000000..59a6fb1062f8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/method/output.js @@ -0,0 +1,14 @@ +var _FooBrandCheck = new WeakSet(); + +class Foo { + constructor() { + _FooBrandCheck.add(this); + } + + #foo() {} + + test(other) { + return _FooBrandCheck.has(other); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-other-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-other-redeclared/input.js new file mode 100644 index 000000000000..a084dd06afd6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-other-redeclared/input.js @@ -0,0 +1,18 @@ +class Foo { + #foo = 1; + #bar = 1; + + test() { + class Nested { + #bar = 2; + + test() { + #foo in this; + #bar in this; + } + } + + #foo in this; + #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-other-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-other-redeclared/output.js new file mode 100644 index 000000000000..881b784ec5b5 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-other-redeclared/output.js @@ -0,0 +1,34 @@ +var _FooBrandCheck = new WeakSet(); + +class Foo { + constructor() { + _FooBrandCheck.add(this); + } + + #foo = 1; + #bar = 1; + + test() { + var _NestedBrandCheck = new WeakSet(); + + class Nested { + constructor() { + _NestedBrandCheck.add(this); + } + + #bar = 2; + + test() { + _FooBrandCheck.has(this); + + _NestedBrandCheck.has(this); + } + + } + + _FooBrandCheck.has(this); + + _FooBrandCheck.has(this); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/input.js new file mode 100644 index 000000000000..2258be35c5fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/input.js @@ -0,0 +1,15 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + #foo = 2; + + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/output.js new file mode 100644 index 000000000000..a761903ba09a --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/output.js @@ -0,0 +1,29 @@ +var _FooBrandCheck = new WeakSet(); + +class Foo { + constructor() { + _FooBrandCheck.add(this); + } + + #foo = 1; + + test() { + var _NestedBrandCheck = new WeakSet(); + + class Nested { + constructor() { + _NestedBrandCheck.add(this); + } + + #foo = 2; + + test() { + _NestedBrandCheck.has(this); + } + + } + + _FooBrandCheck.has(this); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/input.js new file mode 100644 index 000000000000..e17e438b314d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/input.js @@ -0,0 +1,13 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/output.js new file mode 100644 index 000000000000..ab0ea8eebfef --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/output.js @@ -0,0 +1,21 @@ +var _FooBrandCheck = new WeakSet(); + +class Foo { + constructor() { + _FooBrandCheck.add(this); + } + + #foo = 1; + + test() { + class Nested { + test() { + _FooBrandCheck.has(this); + } + + } + + _FooBrandCheck.has(this); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/options.json new file mode 100644 index 000000000000..1727d6dba8e5 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + ["proposal-private-property-in-object", { "nativePrivateFields": true }], + "syntax-class-properties" + ] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-accessor/input.js new file mode 100644 index 000000000000..e74333f2055f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + static get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-accessor/output.js new file mode 100644 index 000000000000..cdec0d002314 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-accessor/output.js @@ -0,0 +1,8 @@ +class Foo { + static get #foo() {} + + test(other) { + return Foo === other; + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/input.js new file mode 100644 index 000000000000..a4f771844fe9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/output.js new file mode 100644 index 000000000000..823c53b802cf --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/output.js @@ -0,0 +1,8 @@ +class Foo { + static #foo = 1; + + test(other) { + return Foo === other; + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-method/input.js new file mode 100644 index 000000000000..9fffe7a01622 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-method/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-method/output.js new file mode 100644 index 000000000000..bb657d68eb23 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-method/output.js @@ -0,0 +1,8 @@ +class Foo { + static #foo() {} + + test(other) { + return Foo === other; + } + +} diff --git a/packages/babel-plugin-syntax-private-property-in-object/.npmignore b/packages/babel-plugin-syntax-private-property-in-object/.npmignore new file mode 100644 index 000000000000..f9806945836e --- /dev/null +++ b/packages/babel-plugin-syntax-private-property-in-object/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-syntax-private-property-in-object/README.md b/packages/babel-plugin-syntax-private-property-in-object/README.md new file mode 100644 index 000000000000..8dd2f6b32cb2 --- /dev/null +++ b/packages/babel-plugin-syntax-private-property-in-object/README.md @@ -0,0 +1,19 @@ +# @babel/plugin-syntax-class-static-block + +> Allow parsing of class static blocks + +See our website [@babel/plugin-syntax-class-static-block](https://babeljs.io/docs/en/babel-plugin-syntax-class-static-block) for more information. + +## Install + +Using npm: + +```sh +npm install --save-dev @babel/plugin-syntax-class-static-block +``` + +or using yarn: + +```sh +yarn add @babel/plugin-syntax-class-static-block --dev +``` diff --git a/packages/babel-plugin-syntax-private-property-in-object/package.json b/packages/babel-plugin-syntax-private-property-in-object/package.json new file mode 100644 index 000000000000..544e52ee4bea --- /dev/null +++ b/packages/babel-plugin-syntax-private-property-in-object/package.json @@ -0,0 +1,28 @@ +{ + "name": "@babel/plugin-syntax-private-property-in-object", + "version": "7.13.0", + "description": "Allow parsing of '#foo in obj' brand checks", + "repository": { + "type": "git", + "url": "https://github.com/babel/babel.git", + "directory": "packages/babel-plugin-syntax-private-property-in-object" + }, + "homepage": "https://babel.dev/docs/en/next/babel-plugin-syntax-private-property-in-object", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "./lib/index.js", + "exports": { + ".": "./lib/index.js" + }, + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-plugin-utils": "workspace:^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } +} diff --git a/packages/babel-plugin-syntax-private-property-in-object/src/index.js b/packages/babel-plugin-syntax-private-property-in-object/src/index.js new file mode 100644 index 000000000000..a716fe39e301 --- /dev/null +++ b/packages/babel-plugin-syntax-private-property-in-object/src/index.js @@ -0,0 +1,13 @@ +import { declare } from "@babel/helper-plugin-utils"; + +export default declare(api => { + api.assertVersion(7); + + return { + name: "syntax-private-property-in-object", + + manipulateOptions(opts, parserOpts) { + parserOpts.plugins.push("privateIn"); + }, + }; +}); diff --git a/yarn.lock b/yarn.lock index a22617a45714..f611585368d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1447,6 +1447,7 @@ __metadata: "@babel/helper-create-class-features-plugin": "workspace:^7.13.0" "@babel/helper-plugin-test-runner": "workspace:*" "@babel/helper-plugin-utils": "workspace:^7.13.0" + "@babel/plugin-syntax-private-property-in-object": "workspace:^7.13.0" peerDependencies: "@babel/core": ^7.0.0-0 languageName: unknown @@ -1821,6 +1822,16 @@ __metadata: languageName: unknown linkType: soft +"@babel/plugin-syntax-private-property-in-object@workspace:^7.13.0, @babel/plugin-syntax-private-property-in-object@workspace:packages/babel-plugin-syntax-private-property-in-object": + version: 0.0.0-use.local + resolution: "@babel/plugin-syntax-private-property-in-object@workspace:packages/babel-plugin-syntax-private-property-in-object" + dependencies: + "@babel/helper-plugin-utils": "workspace:^7.12.13" + peerDependencies: + "@babel/core": ^7.0.0-0 + languageName: unknown + linkType: soft + "@babel/plugin-syntax-record-and-tuple@workspace:*, @babel/plugin-syntax-record-and-tuple@workspace:^7.12.1, @babel/plugin-syntax-record-and-tuple@workspace:packages/babel-plugin-syntax-record-and-tuple": version: 0.0.0-use.local resolution: "@babel/plugin-syntax-record-and-tuple@workspace:packages/babel-plugin-syntax-record-and-tuple"