diff --git a/packages/babel-helper-create-class-features-plugin/src/index.js b/packages/babel-helper-create-class-features-plugin/src/index.js index 5aa2db723519..19da30a62e03 100644 --- a/packages/babel-helper-create-class-features-plugin/src/index.js +++ b/packages/babel-helper-create-class-features-plugin/src/index.js @@ -20,7 +20,7 @@ import { isLoose, } from "./features"; -export { FEATURES, injectInitialization }; +export { FEATURES, enableFeature, injectInitialization }; // Note: Versions are represented as an integer. e.g. 7.1.5 is represented // as 70000100005. This method is easier than using a semver-parsing 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..464b0c27620d 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/package.json +++ b/packages/babel-plugin-proposal-private-property-in-object/package.json @@ -17,8 +17,10 @@ "babel-plugin" ], "dependencies": { + "@babel/helper-compilation-targets": "workspace:^7.12.17", "@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..2beb98dae688 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 @@ -1,23 +1,158 @@ -/* eslint-disable @babel/development/plugin-name */ - import { declare } from "@babel/helper-plugin-utils"; +import syntaxPlugin from "@babel/plugin-syntax-private-property-in-object"; import { - createClassFeaturePlugin, + enableFeature, FEATURES, + injectInitialization as injectConstructorInit, } from "@babel/helper-create-class-features-plugin"; -export default declare((api, options) => { - api.assertVersion(7); +export default declare(({ assertVersion, types: t, template }, { loose }) => { + assertVersion(7); + + // NOTE: When using the class fields or private methods plugins, + // they will also take care of '#priv in obj' checks when visiting + // the ClassExpression or ClassDeclaration nodes. + // The visitor of this plugin is only effective when not compiling + // private fields and methods. + + const classWeakSets = new WeakMap(); + const fieldsWeakSets = new WeakMap(); + + function unshadow(name, targetScope, scope) { + while (scope !== targetScope) { + if (scope.hasOwnBinding(name)) scope.rename(name); + scope = scope.parent; + } + } + + function injectToFieldInit(fieldPath, expr, before = false) { + if (fieldPath.node.value) { + if (before) { + fieldPath.get("value").insertBefore(expr); + } else { + fieldPath.get("value").insertAfter(expr); + } + } else { + fieldPath.set("value", t.unaryExpression("void", expr)); + } + } + + function injectInitialization(classPath, init) { + let firstFieldPath; + let consturctorPath; + + for (const el of classPath.get("body.body")) { + if ( + (el.isClassProperty() || el.isClassPrivateProperty()) && + !el.node.static + ) { + firstFieldPath = el; + break; + } + if (!consturctorPath && el.isClassMethod({ kind: "constructor" })) { + consturctorPath = el; + } + } + + if (firstFieldPath) { + injectToFieldInit(firstFieldPath, init, true); + } else { + injectConstructorInit(classPath, consturctorPath, [ + t.expressionStatement(init), + ]); + } + } + + function getWeakSetId(weakSets, outerClass, reference, name = "", inject) { + let id = classWeakSets.get(reference.node); + + if (!id) { + id = outerClass.scope.generateUidIdentifier(`${name || ""} brandCheck`); + classWeakSets.set(reference.node, id); + + inject(reference, template.expression.ast`${t.cloneNode(id)}.add(this)`); + + outerClass.insertBefore(template.ast`var ${id} = new WeakSet()`); + } + + return t.cloneNode(id); + } + + return { + name: "proposal-private-property-in-object", + inherits: syntaxPlugin, + pre() { + // Enable this in @babel/helper-create-class-features-plugin, so that it + // can be handled by the private fields and methods transform. + enableFeature(this.file, FEATURES.privateIn, loose); + }, + visitor: { + BinaryExpression(path) { + const { node } = path; + if (node.operator !== "in") return; + if (!t.isPrivateName(node.left)) return; + + const { name } = node.left.id; + + let privateElement; + const outerClass = path.findParent(path => { + if (!path.isClass()) return false; + + privateElement = path + .get("body.body") + .find(({ node }) => t.isPrivate(node) && node.key.id.name === name); + + return !!privateElement; + }); + + if (outerClass.parentPath.scope.path.isPattern()) { + outerClass.replaceWith(template.ast`(() => ${outerClass.node})()`); + // The injected class will be queued and eventually transformed when visited + return; + } + + if (privateElement.isMethod()) { + if (privateElement.node.static) { + if (outerClass.node.id) { + unshadow(outerClass.node.id.name, outerClass.scope, path.scope); + } else { + outerClass.set("id", path.scope.generateUidIdentifier("class")); + } + path.replaceWith( + template.expression.ast` + ${t.cloneNode(outerClass.node.id)} === ${path.node.right} + `, + ); + } else { + const id = getWeakSetId( + classWeakSets, + outerClass, + outerClass, + outerClass.node.id?.name, + injectInitialization, + ); - return createClassFeaturePlugin({ - name: "proposal-class-properties", + path.replaceWith( + template.expression.ast`${id}.has(${path.node.right})`, + ); + } + } else { + // Private fields might not all be initialized: see the 'halfConstructed' + // example at https://v8.dev/features/private-brand-checks. - api, - feature: FEATURES.privateIn, - loose: options.loose, + const id = getWeakSetId( + fieldsWeakSets, + outerClass, + privateElement, + privateElement.node.key.id.name, + injectToFieldInit, + ); - manipulateOptions(opts, parserOpts) { - parserOpts.plugins.push("privateIn"); + path.replaceWith( + template.expression.ast`${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-in-default-param/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-in-default-param/input.js new file mode 100644 index 000000000000..e7f65a90b196 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-in-default-param/input.js @@ -0,0 +1,4 @@ +(x = class { + #foo; + test(other) { return #foo in other } +}) => {} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-in-default-param/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-in-default-param/output.js new file mode 100644 index 000000000000..5289f0c5e834 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-in-default-param/output.js @@ -0,0 +1,12 @@ +(x = (() => { + var _fooBrandCheck; + + return _fooBrandCheck = new WeakSet(), class { + #foo = void _fooBrandCheck.add(this); + + 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..495153fae073 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-instance/output.js @@ -0,0 +1,12 @@ +function fn() { + var _privBrandCheck; + + return new (_privBrandCheck = new WeakSet(), class { + #priv = void _privBrandCheck.add(this); + + method(obj) { + return _privBrandCheck.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..39716aed530a --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/class-expression-static/output.js @@ -0,0 +1,12 @@ +function fn() { + var _privBrandCheck; + + return new (_privBrandCheck = new WeakSet(), class { + static #priv = void _privBrandCheck.add(this); + + method(obj) { + return _privBrandCheck.has(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..7ff1de3959f6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/field/output.js @@ -0,0 +1,12 @@ +var _temp; + +var _fooBrandCheck = new WeakSet(); + +class Foo { + #foo = (_temp = 1, _fooBrandCheck.add(this), _temp); + + test(other) { + return _fooBrandCheck.has(other); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/exec.js new file mode 100644 index 000000000000..733062328585 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/exec.js @@ -0,0 +1,28 @@ +let hasW, hasX, hasY, hasZ; +let halfConstructed; + +class F { + m() { + hasW = #w in this; + hasX = #x in this; + hasY = #y in this; + hasZ = #z in this; + } + get #w() {} + #x = 0; + #y = (() => { + halfConstructed = this; + throw "error"; + })(); + #z() {} +} + +try { + new F(); +} catch {} +halfConstructed.m(); + +expect(hasW).toBe(true); +expect(hasX).toBe(true); +expect(hasY).toBe(false); +expect(hasZ).toBe(true); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/input.js new file mode 100644 index 000000000000..048cedcd5bf4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/input.js @@ -0,0 +1,14 @@ +class F { + m() { + #w in this; + #x in this; + #y in this; + #z in this; + } + get #w() {} + #x = 0; + #y = (() => { + throw 'error'; + })(); + #z() {} +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/options.json new file mode 100644 index 000000000000..1655c55f42cc --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.0.0" +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/output.js new file mode 100644 index 000000000000..4d8bbd2a8b80 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-instance/output.js @@ -0,0 +1,29 @@ +var _temp, _temp2; + +var _FBrandCheck = new WeakSet(); + +var _xBrandCheck = new WeakSet(); + +var _yBrandCheck = new WeakSet(); + +class F { + m() { + _FBrandCheck.has(this); + + _xBrandCheck.has(this); + + _yBrandCheck.has(this); + + _FBrandCheck.has(this); + } + + get #w() {} + + #x = (_temp = (_FBrandCheck.add(this), 0), _xBrandCheck.add(this), _temp); + #y = (_temp2 = (() => { + throw 'error'; + })(), _yBrandCheck.add(this), _temp2); + + #z() {} + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/exec.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/exec.js new file mode 100644 index 000000000000..f60e0b24fde7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/exec.js @@ -0,0 +1,27 @@ +let hasW, hasX, hasY, hasZ; +let halfConstructed; + +try { + class F { + static m() { + hasW = #w in this; + hasX = #x in this; + hasY = #y in this; + hasZ = #z in this; + } + static get #w() {} + static #x = 0; + static #y = (() => { + halfConstructed = this; + throw "error"; + })(); + static #z() {} + } +} catch {} + +halfConstructed.m(); + +expect(hasW).toBe(true); +expect(hasX).toBe(true); +expect(hasY).toBe(false); +expect(hasZ).toBe(true); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/input.js new file mode 100644 index 000000000000..9b6ff923f33a --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/input.js @@ -0,0 +1,12 @@ +class F { + static m() { + #x in this; + #y in this; + #z in this; + } + static #x = 0; + static #y = (() => { + throw 'error'; + })(); + static #z() {} +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/options.json new file mode 100644 index 000000000000..1655c55f42cc --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "14.0.0" +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/output.js new file mode 100644 index 000000000000..e0ebbc3e2758 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/half-constructed-static/output.js @@ -0,0 +1,23 @@ +var _temp, _temp2; + +var _xBrandCheck = new WeakSet(); + +var _yBrandCheck = new WeakSet(); + +class F { + static m() { + _xBrandCheck.has(this); + + _yBrandCheck.has(this); + + F === this; + } + + static #x = (_temp = 0, _xBrandCheck.add(this), _temp); + static #y = (_temp2 = (() => { + throw 'error'; + })(), _yBrandCheck.add(this), _temp2); + + static #z() {} + +} 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/multiple-checks/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/multiple-checks/input.js new file mode 100644 index 000000000000..bb22d4fbdb0e --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/multiple-checks/input.js @@ -0,0 +1,11 @@ +class A { + #x; + #m() {} + + test() { + #x in this; + #m in this; + #x in this; + #m in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/multiple-checks/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/multiple-checks/output.js new file mode 100644 index 000000000000..98dc5cd7d891 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/multiple-checks/output.js @@ -0,0 +1,20 @@ +var _xBrandCheck = new WeakSet(); + +var _ABrandCheck = new WeakSet(); + +class A { + #x = (_ABrandCheck.add(this), void _xBrandCheck.add(this)); + + #m() {} + + test() { + _xBrandCheck.has(this); + + _ABrandCheck.has(this); + + _xBrandCheck.has(this); + + _ABrandCheck.has(this); + } + +} 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..2f11e248f111 --- /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,32 @@ +var _temp, _temp3; + +var _fooBrandCheck = new WeakSet(); + +var _barBrandCheck2 = new WeakSet(); + +class Foo { + #foo = (_temp = 1, _fooBrandCheck.add(this), _temp); + #bar = (_temp3 = 1, _barBrandCheck2.add(this), _temp3); + + test() { + var _temp2; + + var _barBrandCheck = new WeakSet(); + + class Nested { + #bar = (_temp2 = 2, _barBrandCheck.add(this), _temp2); + + test() { + _fooBrandCheck.has(this); + + _barBrandCheck.has(this); + } + + } + + _fooBrandCheck.has(this); + + _barBrandCheck2.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..87094388d2ab --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class-redeclared/output.js @@ -0,0 +1,25 @@ +var _temp2; + +var _fooBrandCheck2 = new WeakSet(); + +class Foo { + #foo = (_temp2 = 1, _fooBrandCheck2.add(this), _temp2); + + test() { + var _temp; + + var _fooBrandCheck = new WeakSet(); + + class Nested { + #foo = (_temp = 2, _fooBrandCheck.add(this), _temp); + + test() { + _fooBrandCheck.has(this); + } + + } + + _fooBrandCheck2.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..c897b8d6c8e1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/nested-class/output.js @@ -0,0 +1,19 @@ +var _temp; + +var _fooBrandCheck = new WeakSet(); + +class Foo { + #foo = (_temp = 1, _fooBrandCheck.add(this), _temp); + + 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..6a19479b9c2b --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-private-property-in-object", "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..ceadc64ac495 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-field/output.js @@ -0,0 +1,12 @@ +var _temp; + +var _fooBrandCheck = new WeakSet(); + +class Foo { + static #foo = (_temp = 1, _fooBrandCheck.add(this), _temp); + + test(other) { + return _fooBrandCheck.has(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-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadowed-binding/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadowed-binding/input.js new file mode 100644 index 000000000000..67206379b189 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadowed-binding/input.js @@ -0,0 +1,9 @@ +class A { + static #foo; + + test() { + let A = function fn(A) { + return #foo in A; + }; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadowed-binding/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadowed-binding/output.js new file mode 100644 index 000000000000..b89f6ea5a3cb --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/to-native-fields/static-shadowed-binding/output.js @@ -0,0 +1,12 @@ +var _fooBrandCheck = new WeakSet(); + +class A { + static #foo = void _fooBrandCheck.add(this); + + test() { + let A = function fn(A) { + return _fooBrandCheck.has(A); + }; + } + +} 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 dab65b379707..cf71ba6c9b3f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -393,7 +393,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@workspace:^7.13.13, @babel/helper-compilation-targets@workspace:^7.13.16, @babel/helper-compilation-targets@workspace:^7.13.8, @babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets": +"@babel/helper-compilation-targets@workspace:^7.12.17, @babel/helper-compilation-targets@workspace:^7.13.13, @babel/helper-compilation-targets@workspace:^7.13.16, @babel/helper-compilation-targets@workspace:^7.13.8, @babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets": version: 0.0.0-use.local resolution: "@babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets" dependencies: @@ -1439,9 +1439,11 @@ __metadata: resolution: "@babel/plugin-proposal-private-property-in-object@workspace:packages/babel-plugin-proposal-private-property-in-object" dependencies: "@babel/core": "workspace:*" + "@babel/helper-compilation-targets": "workspace:^7.12.17" "@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 @@ -1816,6 +1818,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"