Fixed computed keys for class expression (#10029)
* test case for insertBefore for jsx * fix unshiftContainer and insertBefore * use path.scope.push * add test making sure computedKeys var declaration at the right block * add comment * nit [skip ci]
This commit is contained in:
parent
a596da2822
commit
b4c9cb0222
@ -98,10 +98,16 @@ export function extractComputedKeys(ref, path, computedPaths, file) {
|
|||||||
const ident = path.scope.generateUidIdentifierBasedOnNode(
|
const ident = path.scope.generateUidIdentifierBasedOnNode(
|
||||||
computedNode.key,
|
computedNode.key,
|
||||||
);
|
);
|
||||||
|
// Declaring in the same block scope
|
||||||
|
// Ref: https://github.com/babel/babel/pull/10029/files#diff-fbbdd83e7a9c998721c1484529c2ce92
|
||||||
|
path.scope.push({
|
||||||
|
id: ident,
|
||||||
|
kind: "let",
|
||||||
|
});
|
||||||
declarations.push(
|
declarations.push(
|
||||||
t.variableDeclaration("var", [
|
t.expressionStatement(
|
||||||
t.variableDeclarator(ident, computedNode.key),
|
t.assignmentExpression("=", t.cloneNode(ident), computedNode.key),
|
||||||
]),
|
),
|
||||||
);
|
);
|
||||||
computedNode.key = t.cloneNode(ident);
|
computedNode.key = t.cloneNode(ident);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,12 @@ function (_Hello) {
|
|||||||
babelHelpers.inherits(Outer, _Hello);
|
babelHelpers.inherits(Outer, _Hello);
|
||||||
|
|
||||||
function Outer() {
|
function Outer() {
|
||||||
|
let _this2;
|
||||||
|
|
||||||
var _this;
|
var _this;
|
||||||
|
|
||||||
babelHelpers.classCallCheck(this, Outer);
|
babelHelpers.classCallCheck(this, Outer);
|
||||||
|
_this2 = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this));
|
||||||
var _this2 = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this));
|
|
||||||
|
|
||||||
let Inner = function Inner() {
|
let Inner = function Inner() {
|
||||||
babelHelpers.classCallCheck(this, Inner);
|
babelHelpers.classCallCheck(this, Inner);
|
||||||
|
|||||||
@ -22,12 +22,13 @@ function (_Hello) {
|
|||||||
babelHelpers.inherits(Outer, _Hello);
|
babelHelpers.inherits(Outer, _Hello);
|
||||||
|
|
||||||
function Outer() {
|
function Outer() {
|
||||||
|
let _babelHelpers$get$cal;
|
||||||
|
|
||||||
var _this;
|
var _this;
|
||||||
|
|
||||||
babelHelpers.classCallCheck(this, Outer);
|
babelHelpers.classCallCheck(this, Outer);
|
||||||
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this));
|
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Outer).call(this));
|
||||||
|
_babelHelpers$get$cal = babelHelpers.get(babelHelpers.getPrototypeOf(Outer.prototype), "toString", babelHelpers.assertThisInitialized(_this)).call(babelHelpers.assertThisInitialized(_this));
|
||||||
var _babelHelpers$get$cal = babelHelpers.get(babelHelpers.getPrototypeOf(Outer.prototype), "toString", babelHelpers.assertThisInitialized(_this)).call(babelHelpers.assertThisInitialized(_this));
|
|
||||||
|
|
||||||
let Inner = function Inner() {
|
let Inner = function Inner() {
|
||||||
babelHelpers.classCallCheck(this, Inner);
|
babelHelpers.classCallCheck(this, Inner);
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
|
var _one, _ref, _undefined, _computed, _computed2, _ref2, _ref3, _baz, _ref4;
|
||||||
|
|
||||||
var foo = "foo";
|
var foo = "foo";
|
||||||
|
|
||||||
var bar = () => {};
|
var bar = () => {};
|
||||||
|
|
||||||
var four = 4;
|
var four = 4;
|
||||||
|
_one = one();
|
||||||
var _one = one();
|
_ref = 2 * four + seven;
|
||||||
|
_undefined = undefined;
|
||||||
var _ref = 2 * four + seven;
|
_computed = computed();
|
||||||
|
_computed2 = computed();
|
||||||
var _undefined = undefined;
|
_ref2 = "test" + one;
|
||||||
|
_ref3 = /regex/;
|
||||||
var _computed = computed();
|
_baz = baz;
|
||||||
|
_ref4 = `template${expression}`;
|
||||||
var _computed2 = computed();
|
|
||||||
|
|
||||||
var _ref2 = "test" + one;
|
|
||||||
|
|
||||||
var _ref3 = /regex/;
|
|
||||||
var _baz = baz;
|
|
||||||
var _ref4 = `template${expression}`;
|
|
||||||
|
|
||||||
var MyClass =
|
var MyClass =
|
||||||
/*#__PURE__*/
|
/*#__PURE__*/
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
function test(x) {
|
function test(x) {
|
||||||
var _x = x;
|
var _x;
|
||||||
|
|
||||||
|
_x = x;
|
||||||
|
|
||||||
var F = function F() {
|
var F = function F() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
const createClass = (k) => class { [k()] = 2 };
|
||||||
|
|
||||||
|
const clazz = createClass(() => 'foo');
|
||||||
|
const instance = new clazz();
|
||||||
|
expect(instance.foo).toBe(2);
|
||||||
@ -0,0 +1 @@
|
|||||||
|
const createClass = (k) => class { [k()] = 2 };
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
var createClass = k => {
|
||||||
|
var _temp;
|
||||||
|
|
||||||
|
var _k;
|
||||||
|
|
||||||
|
return _temp = (_k = k(),
|
||||||
|
/*#__PURE__*/
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function _class2() {
|
||||||
|
babelHelpers.classCallCheck(this, _class2);
|
||||||
|
babelHelpers.defineProperty(this, _k, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _class2;
|
||||||
|
}()), _temp;
|
||||||
|
};
|
||||||
@ -1,24 +1,19 @@
|
|||||||
|
var _one, _ref, _undefined, _computed, _computed2, _ref2, _ref3, _baz, _ref4;
|
||||||
|
|
||||||
var foo = "foo";
|
var foo = "foo";
|
||||||
|
|
||||||
var bar = () => {};
|
var bar = () => {};
|
||||||
|
|
||||||
var four = 4;
|
var four = 4;
|
||||||
|
_one = one();
|
||||||
var _one = one();
|
_ref = 2 * four + seven;
|
||||||
|
_undefined = undefined;
|
||||||
var _ref = 2 * four + seven;
|
_computed = computed();
|
||||||
|
_computed2 = computed();
|
||||||
var _undefined = undefined;
|
_ref2 = "test" + one;
|
||||||
|
_ref3 = /regex/;
|
||||||
var _computed = computed();
|
_baz = baz;
|
||||||
|
_ref4 = `template${expression}`;
|
||||||
var _computed2 = computed();
|
|
||||||
|
|
||||||
var _ref2 = "test" + one;
|
|
||||||
|
|
||||||
var _ref3 = /regex/;
|
|
||||||
var _baz = baz;
|
|
||||||
var _ref4 = `template${expression}`;
|
|
||||||
|
|
||||||
var MyClass =
|
var MyClass =
|
||||||
/*#__PURE__*/
|
/*#__PURE__*/
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
function test(x) {
|
function test(x) {
|
||||||
var _x = x;
|
var _x;
|
||||||
|
|
||||||
|
_x = x;
|
||||||
|
|
||||||
var F = function F() {
|
var F = function F() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|||||||
@ -75,9 +75,11 @@ new ComputedMethod(); // ensure ComputedKey Field is still transformed
|
|||||||
|
|
||||||
class ComputedField extends Obj {
|
class ComputedField extends Obj {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
let _ref;
|
||||||
|
|
||||||
var _temp3;
|
var _temp3;
|
||||||
|
|
||||||
var _ref = (_temp3 = super(), babelHelpers.defineProperty(this, "field", 1), _temp3);
|
_ref = (_temp3 = super(), babelHelpers.defineProperty(this, "field", 1), _temp3);
|
||||||
|
|
||||||
class B extends Obj {
|
class B extends Obj {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
23
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/exec.js
vendored
Normal file
23
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/exec.js
vendored
Normal file
@ -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);
|
||||||
|
}
|
||||||
13
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/input.js
vendored
Normal file
13
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/input.js
vendored
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
3
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/options.json
vendored
Normal file
3
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["external-helpers", "proposal-class-properties"]
|
||||||
|
}
|
||||||
23
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/output.js
vendored
Normal file
23
packages/babel-plugin-proposal-class-properties/test/fixtures/regression/8882/output.js
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
const classes = [];
|
||||||
|
|
||||||
|
for (let i = 0; i <= 10; ++i) {
|
||||||
|
var _class, _temp, _bar;
|
||||||
|
|
||||||
|
let _i;
|
||||||
|
|
||||||
|
classes.push((_temp = (_i = i, _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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}), _bar = new WeakMap(), babelHelpers.defineProperty(_class, "foo", `static field ${i}`), _temp));
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
var _class, _descriptor, _Symbol$search, _temp;
|
let _Symbol$search;
|
||||||
|
|
||||||
|
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 }); }
|
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 }); }
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
let _x$x;
|
||||||
|
|
||||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||||
|
|
||||||
function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); }
|
function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); }
|
||||||
|
|
||||||
var _x$x = {
|
_x$x = {
|
||||||
x: (_classNameTDZError("A"), A) || 0
|
x: (_classNameTDZError("A"), A) || 0
|
||||||
}.x;
|
}.x;
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
let _ref;
|
||||||
|
|
||||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||||
|
|
||||||
function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); }
|
function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); }
|
||||||
|
|
||||||
var _ref = (_classNameTDZError("C"), C) + 3;
|
_ref = (_classNameTDZError("C"), C) + 3;
|
||||||
|
|
||||||
let C = function C() {
|
let C = function C() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
let _ref;
|
||||||
|
|
||||||
function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); }
|
function _classNameTDZError(name) { throw new Error("Class \"" + name + "\" cannot be referenced in computed property keys."); }
|
||||||
|
|
||||||
var _ref = (_classNameTDZError("C"), C) + 3;
|
_ref = (_classNameTDZError("C"), C) + 3;
|
||||||
|
|
||||||
class C {}
|
class C {}
|
||||||
|
|
||||||
|
|||||||
@ -24,9 +24,7 @@ export function insertBefore(nodes) {
|
|||||||
) {
|
) {
|
||||||
return parentPath.insertBefore(nodes);
|
return parentPath.insertBefore(nodes);
|
||||||
} else if (
|
} else if (
|
||||||
(this.isNodeType("Expression") &&
|
(this.isNodeType("Expression") && !this.isJSXElement()) ||
|
||||||
this.listKey !== "params" &&
|
|
||||||
this.listKey !== "arguments") ||
|
|
||||||
(parentPath.isForStatement() && this.key === "init")
|
(parentPath.isForStatement() && this.key === "init")
|
||||||
) {
|
) {
|
||||||
if (this.node) nodes.push(this.node);
|
if (this.node) nodes.push(this.node);
|
||||||
@ -220,7 +218,7 @@ export function unshiftContainer(listKey, nodes) {
|
|||||||
key: 0,
|
key: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
return path.insertBefore(nodes);
|
return path._containerInsertBefore(nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pushContainer(listKey, nodes) {
|
export function pushContainer(listKey, nodes) {
|
||||||
|
|||||||
@ -36,6 +36,19 @@ describe("modification", function() {
|
|||||||
|
|
||||||
expect(generateCode(rootPath)).toBe("function test(a) {\n b;\n}");
|
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() {
|
describe("unshiftContainer", function() {
|
||||||
it("unshifts identifier into params", function() {
|
it("unshifts identifier into params", function() {
|
||||||
@ -116,6 +129,32 @@ describe("modification", function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("returns inserted path with nested JSXElement", function() {
|
||||||
|
const ast = parse("<div><span>foo</span></div>", {
|
||||||
|
plugins: ["jsx"],
|
||||||
|
});
|
||||||
|
let path;
|
||||||
|
traverse(ast, {
|
||||||
|
Program: function(_path) {
|
||||||
|
path = _path.get("body.0");
|
||||||
|
},
|
||||||
|
JSXElement: function(path) {
|
||||||
|
const tagName = path.node.openingElement.name.name;
|
||||||
|
if (tagName !== "span") return;
|
||||||
|
path.insertBefore(
|
||||||
|
t.JSXElement(
|
||||||
|
t.JSXOpeningElement(t.JSXIdentifier("div"), [], false),
|
||||||
|
t.JSXClosingElement(t.JSXIdentifier("div")),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(generateCode(path)).toBe(
|
||||||
|
"<div><div></div><span>foo</span></div>;",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe("when the parent is an export declaration inserts the node before", function() {
|
describe("when the parent is an export declaration inserts the node before", function() {
|
||||||
it("the ExportNamedDeclaration", function() {
|
it("the ExportNamedDeclaration", function() {
|
||||||
const bodyPath = getPath("export function a() {}", {
|
const bodyPath = getPath("export function a() {}", {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user