diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index 9a575f933a81..93251aa48ef3 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -600,25 +600,21 @@ helpers.classPrivateFieldKey = () => template.program.ast` } `; -helpers.classPrivateFieldGet = () => template.program.ast` - export default function _classPrivateFieldGet(receiver, privateMap) { - if (!privateMap.has(receiver)) { - throw new TypeError("attempted to get private field on non-instance"); +helpers.classPrivateFieldBase = () => template.program.ast` + export default function _classPrivateFieldBase(receiver, privateKey) { + if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { + throw new TypeError("attempted to use private field on non-instance"); } - return privateMap.get(receiver); + return receiver; } `; -helpers.classPrivateFieldGetStatic = () => template.program.ast` +helpers.classPrivateFieldGet = () => template.program.ast` export default function _classPrivateFieldGet(receiver, privateMap) { - while (receiver && !privateMap.has(receiver)) { - receiver = Object.getPrototypeOf(receiver); - } - if (receiver) { - return privateMap.get(receiver); - } else { + if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } + return privateMap.get(receiver); } `; @@ -632,20 +628,6 @@ helpers.classPrivateFieldPut = () => template.program.ast` } `; -helpers.classPrivateFieldPutStatic = () => template.program.ast` - export default function _classPrivateFieldPutStatic(receiver, privateMap, value) { - while (receiver && !privateMap.has(receiver)) { - receiver = Object.getPrototypeOf(receiver); - } - if (receiver) { - privateMap.set(receiver, value); - return value; - } else { - throw new TypeError("attempted to set private field on non-instance"); - } - } -`; - helpers.set = () => template.program.ast` export default function _set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); diff --git a/packages/babel-plugin-transform-class-properties/src/index.js b/packages/babel-plugin-transform-class-properties/src/index.js index 4024482a08af..48f646334d32 100644 --- a/packages/babel-plugin-transform-class-properties/src/index.js +++ b/packages/babel-plugin-transform-class-properties/src/index.js @@ -200,8 +200,13 @@ export default function({ types: t }) { } if (!parentPath.isMemberExpression()) return; + const object = parentPath.get("object"); + + object.replaceWith( + t.callExpression(this.base, [object.node, this.privateKey]), + ); parentPath.node.computed = true; - path.replaceWith(this.privateName); + path.replaceWith(this.privateKey); }, ClassBody(path) { @@ -247,13 +252,7 @@ export default function({ types: t }) { ); } - function buildPrivateClassPropertySpec( - ref, - prop, - classBody, - nodes, - isStatic = false, - ) { + function buildPrivateClassPropertySpec(ref, prop, classBody, nodes) { const { node } = prop; const { name } = node.key.id; const { file } = classBody.hub; @@ -262,8 +261,8 @@ export default function({ types: t }) { classBody.traverse(privateNameRemapper, { name, privateMap, - get: file.addHelper(`classPrivateFieldGet${isStatic ? "Static" : ""}`), - put: file.addHelper(`classPrivateFieldPut${isStatic ? "Static" : ""}`), + get: file.addHelper("classPrivateFieldGet"), + put: file.addHelper("classPrivateFieldPut"), }); nodes.push( @@ -288,15 +287,19 @@ export default function({ types: t }) { const { key, value } = prop.node; const { name } = key.id; const { file } = classBody.hub; - const privateName = classBody.scope.generateDeclaredUidIdentifier(name); + const privateKey = classBody.scope.generateDeclaredUidIdentifier(name); - classBody.traverse(privateNameRemapperLoose, { name, privateName }); + classBody.traverse(privateNameRemapperLoose, { + name, + privateKey, + base: file.addHelper("classPrivateFieldBase"), + }); nodes.push( t.expressionStatement( t.assignmentExpression( "=", - privateName, + privateKey, t.callExpression(file.addHelper("classPrivateFieldKey"), [ t.stringLiteral(name), ]), @@ -306,7 +309,7 @@ export default function({ types: t }) { return buildPrivateProperty({ REF: ref, - KEY: privateName, + KEY: privateKey, VALUE: value || prop.scope.buildUndefinedNode(), }); } @@ -356,7 +359,7 @@ export default function({ types: t }) { for (const prop of staticProps) { if (prop.isClassPrivateProperty()) { - nodes.push(buildPrivateClassProperty(ref, prop, body, nodes, true)); + nodes.push(buildPrivateClassProperty(ref, prop, body, nodes)); } else { nodes.push(buildPublicClassProperty(ref, prop)); } diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/exec.js b/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/exec.js index a5616114f741..d158c9bb6dcc 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/exec.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/exec.js @@ -1,13 +1,21 @@ class Base { static #foo = 1; - static m() { + static getThis() { return this.#foo; } - static update(val) { + static updateThis(val) { return this.#foo = val; } + + static getClass() { + return Base.#foo; + } + + static updateClass(val) { + return Base.#foo = val; + } } class Sub1 extends Base { @@ -21,21 +29,42 @@ class Sub1 extends Base { class Sub2 extends Base { } -assert.equal(Base.m(), 1); -assert.equal(Sub1.m(), 1); -assert.equal(Sub2.m(), 1); +assert.equal(Base.getThis(), 1); +assert.equal(Base.getClass(), 1); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 1); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 1); assert.equal(Sub1.update(3), 3); -assert.equal(Base.m(), 1); -assert.equal(Sub1.m(), 1); -assert.equal(Sub2.m(), 1); - -assert.equal(Base.update(4), 4); -assert.equal(Base.m(), 4); -assert.equal(Sub1.m(), 4); -assert.equal(Sub2.m(), 4); - -assert.equal(Sub2.update(5), 5); -assert.equal(Base.m(), 5); -assert.equal(Sub1.m(), 5); -assert.equal(Sub2.m(), 5); +assert.equal(Base.getThis(), 1); +assert.equal(Base.getClass(), 1); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 1); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 1); + +assert.equal(Base.updateThis(4), 4); +assert.equal(Base.getThis(), 4); +assert.equal(Base.getClass(), 4); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 4); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 4); + +assert.equal(Base.updateClass(5), 5); +assert.equal(Base.getThis(), 5); +assert.equal(Base.getClass(), 5); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 5); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 5); + +assert.throws(() => Sub2.updateThis(6)); +assert.equal(Sub2.updateClass(7), 7); +assert.equal(Base.getThis(), 7); +assert.equal(Base.getClass(), 7); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 7); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 7); diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/expected.js index 8926f3da9b50..e197f50f0cae 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static-inherited/expected.js @@ -8,7 +8,7 @@ var Base = function () { babelHelpers.createClass(Base, null, [{ key: "m", value: function m() { - return babelHelpers.classPrivateFieldGetStatic(this, _foo); + return babelHelpers.classPrivateFieldGet(this, _foo); } }]); return Base; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static/expected.js index d62504f46b0d..7b2c29d70277 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/general-private/static/expected.js @@ -8,12 +8,12 @@ var Foo = function () { babelHelpers.createClass(Foo, [{ key: "test", value: function test() { - return babelHelpers.classPrivateFieldGetStatic(Foo, _bar); + return babelHelpers.classPrivateFieldGet(Foo, _bar); } }], [{ key: "test", value: function test() { - return babelHelpers.classPrivateFieldGetStatic(Foo, _bar); + return babelHelpers.classPrivateFieldGet(Foo, _bar); } }]); return Foo; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/assignment/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/assignment/expected.js index 14d774a546c5..67cbebd15f6e 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/assignment/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/assignment/expected.js @@ -12,10 +12,10 @@ var Foo = function () { babelHelpers.createClass(Foo, [{ key: "test", value: function test(other) { - this[_foo] += 1; - this[_foo] = 2; - other.obj[_foo] += 1; - other.obj[_foo] = 2; + babelHelpers.classPrivateFieldBase(this, _foo)[_foo] += 1; + babelHelpers.classPrivateFieldBase(this, _foo)[_foo] = 2; + babelHelpers.classPrivateFieldBase(other.obj, _foo)[_foo] += 1; + babelHelpers.classPrivateFieldBase(other.obj, _foo)[_foo] = 2; } }]); return Foo; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/call/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/call/expected.js index 428da116aa12..bebbd23e857d 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/call/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/call/expected.js @@ -14,9 +14,9 @@ var Foo = function () { babelHelpers.createClass(Foo, [{ key: "test", value: function test(other) { - this[_foo](); + babelHelpers.classPrivateFieldBase(this, _foo)[_foo](); - other.obj[_foo](); + babelHelpers.classPrivateFieldBase(other.obj, _foo)[_foo](); } }]); return Foo; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/canonical/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/canonical/expected.js index bfd48872b51f..0521226ba4b8 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/canonical/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/canonical/expected.js @@ -11,35 +11,35 @@ var Point = function () { writable: true, value: void 0 }); - this[_x] = +x; - this[_y] = +y; + babelHelpers.classPrivateFieldBase(this, _x)[_x] = +x; + babelHelpers.classPrivateFieldBase(this, _y)[_y] = +y; } babelHelpers.createClass(Point, [{ key: "equals", value: function equals(p) { - return this[_x] === p[_x] && this[_y] === p[_y]; + return babelHelpers.classPrivateFieldBase(this, _x)[_x] === babelHelpers.classPrivateFieldBase(p, _x)[_x] && babelHelpers.classPrivateFieldBase(this, _y)[_y] === babelHelpers.classPrivateFieldBase(p, _y)[_y]; } }, { key: "toString", value: function toString() { - return `Point<${this[_x]},${this[_y]}>`; + return `Point<${babelHelpers.classPrivateFieldBase(this, _x)[_x]},${babelHelpers.classPrivateFieldBase(this, _y)[_y]}>`; } }, { key: "x", get: function () { - return this[_x]; + return babelHelpers.classPrivateFieldBase(this, _x)[_x]; }, set: function (value) { - this[_x] = +value; + babelHelpers.classPrivateFieldBase(this, _x)[_x] = +value; } }, { key: "y", get: function () { - return this[_y]; + return babelHelpers.classPrivateFieldBase(this, _y)[_y]; }, set: function (value) { - this[_y] = +value; + babelHelpers.classPrivateFieldBase(this, _y)[_y] = +value; } }]); return Point; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/multiple/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/multiple/expected.js index faecd01af41a..43db28c51d3c 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/multiple/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/multiple/expected.js @@ -8,7 +8,7 @@ var Foo = function Foo() { }); Object.defineProperty(this, _y, { writable: true, - value: this[_x] + value: babelHelpers.classPrivateFieldBase(this, _x)[_x] }); }; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/private-in-derived/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/private-in-derived/expected.js index 84b913ee6dbc..94787b50a7c2 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/private-in-derived/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/private-in-derived/expected.js @@ -7,8 +7,8 @@ var Outer = function Outer() { value: void 0 }); - var Test = function (_this$_outer) { - babelHelpers.inherits(Test, _this$_outer); + var Test = function (_babelHelpers$classPr) { + babelHelpers.inherits(Test, _babelHelpers$classPr); function Test() { babelHelpers.classCallCheck(this, Test); @@ -16,7 +16,7 @@ var Outer = function Outer() { } return Test; - }(this[_outer]); + }(babelHelpers.classPrivateFieldBase(this, _outer)[_outer]); }; _outer = babelHelpers.classPrivateFieldKey("outer"); diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/reevaluated/exec.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/reevaluated/exec.js index 179dec9918b2..0bf3f73d3aa2 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/reevaluated/exec.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/reevaluated/exec.js @@ -37,7 +37,7 @@ assert.equal(Foo1.static(), "bar"); assert.equal(Foo2.instance(f2), "foo"); assert.equal(Foo2.static(), "bar"); -assert.equal(f1.instance.call(f2), undefined); -assert.equal(f2.instance.call(f1), undefined); -assert.equal(Foo1.instance(f2), undefined); -assert.equal(Foo2.instance(f1), undefined); +assert.throws(() => f1.instance.call(f2)); +assert.throws(() => f2.instance.call(f1)); +assert.throws(() => Foo1.instance(f2)); +assert.throws(() => Foo2.instance(f1)); diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/exec.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/exec.js index 09854b24bde1..d158c9bb6dcc 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/exec.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/exec.js @@ -1,18 +1,70 @@ class Base { static #foo = 1; - static m() { + static getThis() { return this.#foo; } + + static updateThis(val) { + return this.#foo = val; + } + + static getClass() { + return Base.#foo; + } + + static updateClass(val) { + return Base.#foo = val; + } } class Sub1 extends Base { static #foo = 2; + + static update(val) { + return this.#foo = val; + } } class Sub2 extends Base { } -assert.equal(Base.m(), 1); -assert.equal(Sub1.m(), 1); -assert.equal(Sub2.m(), 1); +assert.equal(Base.getThis(), 1); +assert.equal(Base.getClass(), 1); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 1); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 1); + +assert.equal(Sub1.update(3), 3); +assert.equal(Base.getThis(), 1); +assert.equal(Base.getClass(), 1); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 1); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 1); + +assert.equal(Base.updateThis(4), 4); +assert.equal(Base.getThis(), 4); +assert.equal(Base.getClass(), 4); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 4); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 4); + +assert.equal(Base.updateClass(5), 5); +assert.equal(Base.getThis(), 5); +assert.equal(Base.getClass(), 5); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 5); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 5); + +assert.throws(() => Sub2.updateThis(6)); +assert.equal(Sub2.updateClass(7), 7); +assert.equal(Base.getThis(), 7); +assert.equal(Base.getClass(), 7); +assert.throws(() => Sub1.getThis()); +assert.equal(Sub1.getClass(), 7); +assert.throws(() => Sub2.getThis()); +assert.equal(Sub2.getClass(), 7); diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/expected.js index 30a86f9a000e..1895cbc4c3e4 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static-inherited/expected.js @@ -8,7 +8,7 @@ var Base = function () { babelHelpers.createClass(Base, null, [{ key: "m", value: function m() { - return this[_foo]; + return babelHelpers.classPrivateFieldBase(this, _foo)[_foo]; } }]); return Base; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static/expected.js index f5ef462ab335..798fd2218ad8 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/static/expected.js @@ -8,12 +8,12 @@ var Foo = function () { babelHelpers.createClass(Foo, [{ key: "test", value: function test() { - return Foo[_bar]; + return babelHelpers.classPrivateFieldBase(Foo, _bar)[_bar]; } }], [{ key: "test", value: function test() { - return Foo[_bar]; + return babelHelpers.classPrivateFieldBase(Foo, _bar)[_bar]; } }]); return Foo; diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/update/expected.js b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/update/expected.js index 7019b68e5d1e..b38acf94365e 100644 --- a/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/update/expected.js +++ b/packages/babel-plugin-transform-class-properties/test/fixtures/loose-private/update/expected.js @@ -12,10 +12,10 @@ var Foo = function () { babelHelpers.createClass(Foo, [{ key: "test", value: function test(other) { - this[_foo]++; - ++this[_foo]; - other.obj[_foo]++; - ++other.obj[_foo]; + babelHelpers.classPrivateFieldBase(this, _foo)[_foo]++; + ++babelHelpers.classPrivateFieldBase(this, _foo)[_foo]; + babelHelpers.classPrivateFieldBase(other.obj, _foo)[_foo]++; + ++babelHelpers.classPrivateFieldBase(other.obj, _foo)[_foo]; } }]); return Foo;