From e9cdda30300a6ed51d8eb69016db4b18a6fd05ba Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sun, 26 May 2019 21:52:03 +0800 Subject: [PATCH] special handling for classExpression --- .../src/index.js | 29 +++++++++++++-- .../src/misc.js | 2 +- .../nested-class/super-call-in-key/output.js | 2 +- .../super-property-in-key/output.js | 2 +- .../test/fixtures/regression/7371/output.js | 2 +- .../test/fixtures/regression/8882/exec.js | 23 ++++++++++++ .../test/fixtures/regression/8882/input.js | 13 +++++++ .../fixtures/regression/8882/options.json | 3 ++ .../test/fixtures/regression/8882/output.js | 32 +++++++++++++++++ .../decorator-interop/output.js | 36 +++++++++++-------- .../static-property-tdz/edgest-case/output.js | 2 +- .../static-property-tdz/general/output.js | 2 +- .../static-property-tdz/loose/output.js | 2 +- packages/babel-traverse/test/modification.js | 13 +++++++ 14 files changed, 139 insertions(+), 24 deletions(-) create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/exec.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/input.js create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/options.json create mode 100644 packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/output.js 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 dc6300736b3a..0f12432dd2d1 100644 --- a/packages/babel-helper-create-class-features-plugin/src/index.js +++ b/packages/babel-helper-create-class-features-plugin/src/index.js @@ -1,3 +1,4 @@ +import { types as t } from "@babel/core"; import nameFunction from "@babel/helper-function-name"; import splitExportDeclaration from "@babel/helper-split-export-declaration"; import { @@ -58,6 +59,7 @@ export function createClassFeaturePlugin({ let constructor; let isDecorated = hasOwnDecorators(path.node); + const isClassExpression = path.isClassExpression(); const props = []; const elements = []; const computedPaths = []; @@ -181,8 +183,31 @@ export function createClassFeaturePlugin({ } path = wrapClass(path); - path.insertBefore(keysNodes); - path.insertAfter([...privateNamesNodes, ...staticNodes]); + + // insertBefore does not work well with class expression + if (isClassExpression && keysNodes.length) { + let { scope } = path; + + // Inserting after the computed key of a method should insert the + // temporary binding in the method's parent's scope. + if (path.parentPath.isMethod({ computed: true, key: this.node })) { + scope = scope.parent; + } + const temp = scope.generateDeclaredUidIdentifier(); + + path.replaceExpressionWithStatements([ + ...keysNodes, + t.expressionStatement( + t.assignmentExpression("=", t.cloneNode(temp), path.node), + ), + ...privateNamesNodes, + ...staticNodes, + t.expressionStatement(t.cloneNode(temp)), + ]); + } else { + path.insertBefore(keysNodes); + path.insertAfter([...privateNamesNodes, ...staticNodes]); + } }, PrivateName(path) { diff --git a/packages/babel-helper-create-class-features-plugin/src/misc.js b/packages/babel-helper-create-class-features-plugin/src/misc.js index 2468167fe940..62d5d3136537 100644 --- a/packages/babel-helper-create-class-features-plugin/src/misc.js +++ b/packages/babel-helper-create-class-features-plugin/src/misc.js @@ -99,7 +99,7 @@ export function extractComputedKeys(ref, path, computedPaths, file) { computedNode.key, ); declarations.push( - t.variableDeclaration("var", [ + t.variableDeclaration("const", [ t.variableDeclarator(ident, computedNode.key), ]), ); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-call-in-key/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-call-in-key/output.js index 2ded153f1e81..330cc3512fe1 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-call-in-key/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-call-in-key/output.js @@ -20,7 +20,7 @@ function (_Hello) { babelHelpers.classCallCheck(this, Outer); - var _this2 = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this)); + const _this2 = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this)); let Inner = function Inner() { babelHelpers.classCallCheck(this, Inner); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-property-in-key/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-property-in-key/output.js index 6df7880cd395..bc8724d6a203 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-property-in-key/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/super-property-in-key/output.js @@ -27,7 +27,7 @@ function (_Hello) { babelHelpers.classCallCheck(this, Outer); _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this)); - var _babelHelpers$get$cal = babelHelpers.get(babelHelpers.getPrototypeOf(Outer.prototype), "toString", babelHelpers.assertThisInitialized(_this)).call(babelHelpers.assertThisInitialized(_this)); + const _babelHelpers$get$cal = babelHelpers.get(babelHelpers.getPrototypeOf(Outer.prototype), "toString", babelHelpers.assertThisInitialized(_this)).call(babelHelpers.assertThisInitialized(_this)); let Inner = function Inner() { babelHelpers.classCallCheck(this, Inner); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/7371/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/7371/output.js index 5c6ac57eeba1..7ab422a7ac8c 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/7371/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/7371/output.js @@ -77,7 +77,7 @@ class ComputedField extends Obj { constructor() { var _temp3; - var _ref = (_temp3 = super(), babelHelpers.defineProperty(this, "field", 1), _temp3); + const _ref = (_temp3 = super(), babelHelpers.defineProperty(this, "field", 1), _temp3); class B extends Obj { constructor() { diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/exec.js new file mode 100644 index 000000000000..a16b8048dcaf --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/exec.js @@ -0,0 +1,23 @@ +const classes = []; +for (let i = 0; i <= 10; ++i) { + classes.push( + class A { + [i] = `computed field ${i}`; + static foo = `static field ${i}`; + #bar = `private field ${i}`; + getBar() { + return this.#bar; + } + } + ); +} + +for(let i=0; i<= 10; ++i) { + const clazz = classes[i]; + expect(clazz.foo).toBe('static field ' + i); + + const instance = new clazz(); + expect(Object.getOwnPropertyNames(instance)).toEqual([String(i)]) + expect(instance[i]).toBe('computed field ' + i); + expect(instance.getBar()).toBe('private field ' + i); +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/input.js new file mode 100644 index 000000000000..f7ca46cc407d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/input.js @@ -0,0 +1,13 @@ +const classes = []; +for (let i = 0; i <= 10; ++i) { + classes.push( + class A { + [i] = `computed field ${i}`; + static foo = `static field ${i}`; + #bar = `private field ${i}`; + getBar() { + return this.#bar; + } + } + ); +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/options.json new file mode 100644 index 000000000000..9d30185b9bff --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["external-helpers", "proposal-class-properties"] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/output.js new file mode 100644 index 000000000000..c6d0b0c7cf0f --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/output.js @@ -0,0 +1,32 @@ +const classes = []; + +for (let i = 0; i <= 10; ++i) { + var _class, _temp; + + classes.push(function () { + var _ret; + + const _i = i; + _temp = _class = class A { + constructor() { + babelHelpers.defineProperty(this, _i, `computed field ${i}`); + + _bar.set(this, { + writable: true, + value: `private field ${i}` + }); + } + + getBar() { + return babelHelpers.classPrivateFieldGet(this, _bar); + } + + }; + + var _bar = new WeakMap(); + + babelHelpers.defineProperty(_class, "foo", `static field ${i}`); + _ret = _temp; + return _ret; + }()); +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/decorator-interop/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/decorator-interop/output.js index 8f3aff871cf0..4a12bd063a9b 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/decorator-interop/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/decorator-interop/output.js @@ -1,4 +1,4 @@ -var _class, _descriptor, _Symbol$search, _temp; +var _class, _descriptor, _temp; function _initializerDefineProperty(target, property, descriptor, context) { if (!descriptor) return; Object.defineProperty(target, property, { enumerable: descriptor.enumerable, configurable: descriptor.configurable, writable: descriptor.writable, value: descriptor.initializer ? descriptor.initializer.call(context) : void 0 }); } @@ -14,24 +14,30 @@ function _initializerWarningHelper(descriptor, context) { throw new Error('Decor function dec() {} -let A = (_class = (_temp = (_Symbol$search = Symbol.search, -/*#__PURE__*/ -function () { - "use strict"; +let A = (_class = function () { + const _Symbol$search = Symbol.search; - function A() { - _classCallCheck(this, A); + _temp = + /*#__PURE__*/ + function () { + "use strict"; - _initializerDefineProperty(this, "a", _descriptor, this); - } + function A() { + _classCallCheck(this, A); - _createClass(A, [{ - key: _Symbol$search, - value: function () {} - }]); + _initializerDefineProperty(this, "a", _descriptor, this); + } - return A; -}()), _temp), (_descriptor = _applyDecoratedDescriptor(_class.prototype, "a", [dec], { + _createClass(A, [{ + key: _Symbol$search, + value: function () {} + }]); + + return A; + }(); + + return _temp; +}(), (_descriptor = _applyDecoratedDescriptor(_class.prototype, "a", [dec], { configurable: true, enumerable: true, writable: true, diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js index c3fc9ecd57e0..4dcf48ea1cac 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/edgest-case/output.js @@ -4,7 +4,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); } -var _x$x = { +const _x$x = { x: (_classNameTDZError("A"), A) || 0 }.x; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js index 21c823a89aae..aa9ea74fdc20 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/general/output.js @@ -4,7 +4,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); } -var _ref = (_classNameTDZError("C"), C) + 3; +const _ref = (_classNameTDZError("C"), C) + 3; let C = function C() { "use strict"; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js index a6acc92159f9..e4d284f143fa 100644 --- a/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/static-property-tdz/loose/output.js @@ -1,6 +1,6 @@ function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); } -var _ref = (_classNameTDZError("C"), C) + 3; +const _ref = (_classNameTDZError("C"), C) + 3; class C {} diff --git a/packages/babel-traverse/test/modification.js b/packages/babel-traverse/test/modification.js index 027b71945723..a4ccc90823ab 100644 --- a/packages/babel-traverse/test/modification.js +++ b/packages/babel-traverse/test/modification.js @@ -36,6 +36,19 @@ describe("modification", function() { expect(generateCode(rootPath)).toBe("function test(a) {\n b;\n}"); }); + + it("properly handles more than one arguments", function() { + const code = "foo(a, b);"; + const ast = parse(code); + traverse(ast, { + CallExpression: function(path) { + path.pushContainer("arguments", t.identifier("d")); + expect(generateCode(path)).toBe("foo(a, b, d);"); + path.pushContainer("arguments", t.stringLiteral("s")); + expect(generateCode(path)).toBe(`foo(a, b, d, "s");`); + }, + }); + }); }); describe("unshiftContainer", function() { it("unshifts identifier into params", function() {