Skip to content

Commit

Permalink
Ensure expressions wrapped in parens
Browse files Browse the repository at this point in the history
Fix for #12055.
  • Loading branch information
overlookmotel committed Sep 19, 2020
1 parent 18d13d0 commit dd04ef5
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/babel-generator/src/node/parentheses.js
Expand Up @@ -293,7 +293,7 @@ function isFirstInStatement(
let node = printStack[i];
i--;
let parent = printStack[i];
while (i > 0) {
while (i >= 0) {
if (
t.isExpressionStatement(parent, { expression: node }) ||
(considerDefaultExports &&
Expand Down
Expand Up @@ -3,3 +3,5 @@ var foo = arr.map(v => ({
y: v.bar*2
}));
var fn = () => ({}).key;
var fn2 = () => ({});
var fn3 = () => ({a} = {});
Expand Up @@ -3,4 +3,10 @@ var foo = arr.map(v => ({
y: v.bar * 2
}));

var fn = () => ({}).key;
var fn = () => ({}).key;

var fn2 = () => ({});

var fn3 = () => ({
a
} = {});
Expand Up @@ -4,3 +4,4 @@ a = a || (a = {});

(a = b)();
(a = b)?.();
({a} = {});
Expand Up @@ -2,4 +2,7 @@
1 + (a += 2);
a = a || (a = {});
(a = b)();
(a = b)?.();
(a = b)?.();
({
a
} = {});
163 changes: 163 additions & 0 deletions packages/babel-generator/test/index.js
Expand Up @@ -494,6 +494,169 @@ describe("programmatic generation", function () {
expect(output).toBe("(number & boolean)?");
});
});

describe("object expressions", () => {
it("not wrapped in parentheses when standalone", () => {
const objectExpression = t.objectExpression([]);
const output = generate(objectExpression).code;
expect(output).toBe("{}");
});

it("wrapped in parentheses in expression statement", () => {
const expressionStatement = t.expressionStatement(t.objectExpression([]));
const output = generate(expressionStatement).code;
expect(output).toBe("({});");
});

it("wrapped in parentheses in arrow function", () => {
const arrowFunctionExpression = t.arrowFunctionExpression(
[],
t.objectExpression([]),
);
const output = generate(arrowFunctionExpression).code;
expect(output).toBe("() => ({})");
});

it("not wrapped in parentheses in conditional", () => {
const conditionalExpression = t.conditionalExpression(
t.objectExpression([]),
t.booleanLiteral(true),
t.booleanLiteral(false),
);
const output = generate(conditionalExpression).code;
expect(output).toBe("{} ? true : false");
});

it("wrapped in parentheses in conditional in expression statement", () => {
const expressionStatement = t.expressionStatement(
t.conditionalExpression(
t.objectExpression([]),
t.booleanLiteral(true),
t.booleanLiteral(false),
),
);
const output = generate(expressionStatement).code;
expect(output).toBe("({}) ? true : false;");
});

it("wrapped in parentheses in conditional in arrow function", () => {
const arrowFunctionExpression = t.arrowFunctionExpression(
[],
t.conditionalExpression(
t.objectExpression([]),
t.booleanLiteral(true),
t.booleanLiteral(false),
),
);
const output = generate(arrowFunctionExpression).code;
expect(output).toBe("() => ({}) ? true : false");
});

it("not wrapped in parentheses in binary expression", () => {
const binaryExpression = t.binaryExpression(
"+",
t.objectExpression([]),
t.numericLiteral(1),
);
const output = generate(binaryExpression).code;
expect(output).toBe("{} + 1");
});

it("wrapped in parentheses in binary expression in expression statement", () => {
const expressionStatement = t.expressionStatement(
t.binaryExpression("+", t.objectExpression([]), t.numericLiteral(1)),
);
const output = generate(expressionStatement).code;
expect(output).toBe("({}) + 1;");
});

it("wrapped in parentheses in binary expression in arrow function", () => {
const arrowFunctionExpression = t.arrowFunctionExpression(
[],
t.binaryExpression("+", t.objectExpression([]), t.numericLiteral(1)),
);
const output = generate(arrowFunctionExpression).code;
expect(output).toBe("() => ({}) + 1");
});

it("not wrapped in parentheses in sequence expression", () => {
const sequenceExpression = t.sequenceExpression([
t.objectExpression([]),
t.numericLiteral(1),
]);
const output = generate(sequenceExpression).code;
expect(output).toBe("{}, 1");
});

it("wrapped in parentheses in sequence expression in expression statement", () => {
const expressionStatement = t.expressionStatement(
t.sequenceExpression([t.objectExpression([]), t.numericLiteral(1)]),
);
const output = generate(expressionStatement).code;
expect(output).toBe("({}), 1;");
});

it("wrapped in parentheses in sequence expression in arrow function", () => {
const arrowFunctionExpression = t.arrowFunctionExpression(
[],
t.sequenceExpression([t.objectExpression([]), t.numericLiteral(1)]),
);
const output = generate(arrowFunctionExpression).code;
expect(output).toBe("() => (({}), 1)");
});
});

describe("function expressions", () => {
it("not wrapped in parentheses when standalone", () => {
const functionExpression = t.functionExpression(
null,
[],
t.blockStatement([]),
);
const output = generate(functionExpression).code;
expect(output).toBe("function () {}");
});

it("wrapped in parentheses in expression statement", () => {
const expressionStatement = t.expressionStatement(
t.functionExpression(null, [], t.blockStatement([])),
);
const output = generate(expressionStatement).code;
expect(output).toBe("(function () {});");
});

it("wrapped in parentheses in export default declaration", () => {
const exportDefaultDeclaration = t.exportDefaultDeclaration(
t.functionExpression(null, [], t.blockStatement([])),
);
const output = generate(exportDefaultDeclaration).code;
expect(output).toBe("export default (function () {});");
});
});

describe("class expressions", () => {
it("not wrapped in parentheses when standalone", () => {
const classExpression = t.classExpression(null, null, t.classBody([]));
const output = generate(classExpression).code;
expect(output).toBe("class {}");
});

it("wrapped in parentheses in expression statement", () => {
const expressionStatement = t.expressionStatement(
t.classExpression(null, null, t.classBody([])),
);
const output = generate(expressionStatement).code;
expect(output).toBe("(class {});");
});

it("wrapped in parentheses in export default declaration", () => {
const exportDefaultDeclaration = t.exportDefaultDeclaration(
t.classExpression(null, null, t.classBody([])),
);
const output = generate(exportDefaultDeclaration).code;
expect(output).toBe("export default (class {});");
});
});
});

describe("CodeGenerator", function () {
Expand Down

0 comments on commit dd04ef5

Please sign in to comment.