From 34ae2819b88bcc57b7eb5daa224afb4f08974582 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Sun, 16 Oct 2022 22:15:23 +0800 Subject: [PATCH] fix: preserve this for `super.*` template tags (#15043) --- .../class-arrow-super-tagged-expr/exec.js | 13 ++++++ .../class-arrow-super-tagged-expr/input.js | 16 ++++++++ .../options.json | 4 ++ .../class-arrow-super-tagged-expr/output.js | 40 +++++++++++++++++++ .../babel-traverse/src/path/conversion.ts | 13 ++++++ 5 files changed, 86 insertions(+) create mode 100644 packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/exec.js create mode 100644 packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/input.js create mode 100644 packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/options.json create mode 100644 packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/output.js diff --git a/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/exec.js b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/exec.js new file mode 100644 index 000000000000..3fde364ade29 --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/exec.js @@ -0,0 +1,13 @@ +async function test() { + class Foo { foo() { return this } } + class Bar extends Foo { + a = async () => super.foo`` + b = async () => super['foo']`` + c = async (foo) => super[foo]`` + } + const bar = new Bar + expect(await bar.a()).toEqual(bar); + expect(await bar.b()).toEqual(bar); + expect(await bar.c('foo')).toEqual(bar); +} +test() diff --git a/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/input.js b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/input.js new file mode 100644 index 000000000000..6f5cb4c36d59 --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/input.js @@ -0,0 +1,16 @@ +// This should print "true true true" +async function test() { + class Foo { foo() { return this } } + class Bar extends Foo { + a = async () => super.foo`` + b = async () => super['foo']`` + c = async (foo) => super[foo]`` + } + const bar = new Bar + console.log( + (await bar.a()) === bar, + (await bar.b()) === bar, + (await bar.c('foo')) === bar, + ) +} +test() diff --git a/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/options.json b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/options.json new file mode 100644 index 000000000000..dd93a82a5e65 --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/options.json @@ -0,0 +1,4 @@ +{ + "targets": "chrome 50", + "presets": ["env"] +} diff --git a/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/output.js b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/output.js new file mode 100644 index 000000000000..67934bba2b6e --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/plugins-integration/class-arrow-super-tagged-expr/output.js @@ -0,0 +1,40 @@ +// This should print "true true true" +function test() { + return _test.apply(this, arguments); +} +function _test() { + _test = babelHelpers.asyncToGenerator(function* () { + class Foo { + foo() { + return this; + } + } + class Bar extends Foo { + constructor(...args) { + var _superprop_getFoo = () => super.foo, + _this, + _superprop_get = _prop => super[_prop]; + super(...args); + _this = this; + babelHelpers.defineProperty(this, "a", /*#__PURE__*/babelHelpers.asyncToGenerator(function* () { + return _superprop_getFoo().bind(_this)``; + })); + babelHelpers.defineProperty(this, "b", /*#__PURE__*/babelHelpers.asyncToGenerator(function* () { + return _superprop_get('foo').bind(_this)``; + })); + babelHelpers.defineProperty(this, "c", /*#__PURE__*/function () { + var _ref3 = babelHelpers.asyncToGenerator(function* (foo) { + return _superprop_get(foo).bind(_this)``; + }); + return function (_x) { + return _ref3.apply(this, arguments); + }; + }()); + } + } + const bar = new Bar(); + console.log((yield bar.a()) === bar, (yield bar.b()) === bar, (yield bar.c('foo')) === bar); + }); + return _test.apply(this, arguments); +} +test(); diff --git a/packages/babel-traverse/src/path/conversion.ts b/packages/babel-traverse/src/path/conversion.ts index 1352f6a04c73..eecdf85af83a 100644 --- a/packages/babel-traverse/src/path/conversion.ts +++ b/packages/babel-traverse/src/path/conversion.ts @@ -368,6 +368,9 @@ function hoistFunctionEnvironment( const isCall = superParentPath.isCallExpression({ callee: superProp.node, }); + const isTaggedTemplate = superParentPath.isTaggedTemplateExpression({ + tag: superProp.node, + }); const superBinding = getSuperPropBinding(thisEnvFn, isAssignment, key); const args: t.Expression[] = []; @@ -393,6 +396,16 @@ function hoistFunctionEnvironment( } else if (isAssignment) { // Replace not only the super.prop, but the whole assignment superParentPath.replaceWith(call); + } else if (isTaggedTemplate) { + superProp.replaceWith( + callExpression(memberExpression(call, identifier("bind"), false), [ + thisExpression(), + ]), + ); + + thisPaths.push( + superProp.get("arguments.0") as NodePath, + ); } else { superProp.replaceWith(call); }