Do not prepend / append with a semicolon the only JSX element in a program (#3330)

* Do not prepend / append with a semicolon the only JSX element in a program

Fixes #3196

* Limit single JSX element without semicolon to Markdown only

* Fix tests
master
Artem Sapegin 2017-11-28 06:04:12 +01:00 committed by suchipi
parent f514d1e93f
commit 172d34e43d
5 changed files with 82 additions and 2 deletions

View File

@ -12,6 +12,7 @@ const concat = docBuilders.concat;
function printSubtree(subtreeParser, path, print, options) {
const next = Object.assign({}, { transformDoc: doc => doc }, subtreeParser);
next.options = Object.assign({}, options, next.options, {
parentParser: options.parser,
originalText: next.text
});
if (next.options.parser === "json") {

View File

@ -292,7 +292,11 @@ function genericPrintNoParens(path, options, print, args) {
if (n.directive) {
return concat([nodeStr(n.expression, options, true), semi]);
}
return concat([path.call(print, "expression"), semi]); // Babel extension.
// Do not append semicolon after the only JSX element in a program
return concat([
path.call(print, "expression"),
isTheOnlyJSXElementInMarkdown(options, path) ? "" : semi
]); // Babel extension.
case "ParenthesizedExpression":
return concat(["(", path.call(print, "expression"), ")"]);
case "AssignmentExpression":
@ -2864,7 +2868,13 @@ function printStatementSequence(path, options, print) {
const parts = [];
// in no-semi mode, prepend statement with semicolon if it might break ASI
if (!options.semi && !isClass && stmtNeedsASIProtection(stmtPath)) {
// don't prepend the only JSX element in a program with semicolon
if (
!options.semi &&
!isClass &&
!isTheOnlyJSXElementInMarkdown(options, stmtPath) &&
stmtNeedsASIProtection(stmtPath)
) {
if (stmt.comments && stmt.comments.some(comment => comment.leading)) {
// Note: stmtNeedsASIProtection requires stmtPath to already be printed
// as it reads needsParens which is mutated on the instance
@ -5047,4 +5057,20 @@ function printAstToDoc(ast, options, addAlignmentSize) {
return doc;
}
function isTheOnlyJSXElementInMarkdown(options, path) {
if (options.parentParser !== "markdown") {
return false;
}
const node = path.getNode();
if (!node.expression || node.expression.type !== "JSXElement") {
return false;
}
const parent = path.getParentNode();
return parent.type === "Program" && parent.body.length == 1;
}
module.exports = { printAstToDoc };

View File

@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`semi.md 1`] = `
\`\`\`jsx
<div>foo</div>
\`\`\`
\`\`\`jsx
const a = 1;
<div>foo</div>;
\`\`\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\`\`\`jsx
<div>foo</div>
\`\`\`
\`\`\`jsx
const a = 1;
<div>foo</div>;
\`\`\`
`;
exports[`semi.md 2`] = `
\`\`\`jsx
<div>foo</div>
\`\`\`
\`\`\`jsx
const a = 1;
<div>foo</div>;
\`\`\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\`\`\`jsx
<div>foo</div>
\`\`\`
\`\`\`jsx
const a = 1
;<div>foo</div>
\`\`\`
`;

View File

@ -0,0 +1,2 @@
run_spec(__dirname, { semi: true, parser: "markdown" });
run_spec(__dirname, { semi: false, parser: "markdown" });

View File

@ -0,0 +1,8 @@
```jsx
<div>foo</div>
```
```jsx
const a = 1;
<div>foo</div>;
```