Skip to content

Commit

Permalink
special handling for classExpression
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau committed May 26, 2019
1 parent 7fd8eb5 commit e9cdda3
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 24 deletions.
29 changes: 27 additions & 2 deletions 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 {
Expand Down Expand Up @@ -58,6 +59,7 @@ export function createClassFeaturePlugin({

let constructor;
let isDecorated = hasOwnDecorators(path.node);
const isClassExpression = path.isClassExpression();
const props = [];
const elements = [];
const computedPaths = [];
Expand Down Expand Up @@ -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) {
Expand Down
Expand Up @@ -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),
]),
);
Expand Down
Expand Up @@ -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);
Expand Down
Expand Up @@ -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);
Expand Down
Expand Up @@ -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() {
Expand Down
@@ -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);
}
@@ -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;
}
}
);
}
@@ -0,0 +1,3 @@
{
"plugins": ["external-helpers", "proposal-class-properties"]
}
@@ -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;
}());
}
@@ -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 }); }

Expand All @@ -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,
Expand Down
Expand Up @@ -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;

Expand Down
Expand Up @@ -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";
Expand Down
@@ -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 {}

Expand Down
13 changes: 13 additions & 0 deletions packages/babel-traverse/test/modification.js
Expand Up @@ -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() {
Expand Down

0 comments on commit e9cdda3

Please sign in to comment.