Skip to content

Commit

Permalink
Prevent ASI errors for conditional expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Aug 7, 2019
1 parent 44a23bb commit 1059e99
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 10 deletions.
29 changes: 20 additions & 9 deletions src/ast/nodes/ConditionalExpression.ts
@@ -1,6 +1,7 @@
import MagicString from 'magic-string';
import { BLANK } from '../../utils/blank';
import {
findFirstLineBreakOutsideComment,
findFirstOccurrenceOutsideComment,
NodeRenderOptions,
RenderOptions
Expand Down Expand Up @@ -151,20 +152,30 @@ export default class ConditionalExpression extends NodeBase implements Deoptimiz
render(
code: MagicString,
options: RenderOptions,
{ renderedParentType, isCalleeOfRenderedParent }: NodeRenderOptions = BLANK
{ renderedParentType, isCalleeOfRenderedParent, preventASI }: NodeRenderOptions = BLANK
) {
if (!this.test.included) {
const colonPos = findFirstOccurrenceOutsideComment(code.original, ':', this.consequent.end);
const inclusionStart =
(this.consequent.included
? findFirstOccurrenceOutsideComment(code.original, '?', this.test.end)
: colonPos) + 1;
if (preventASI) {
const branchStart = (this.usedBranch as ExpressionNode).start;
let lineBreakPos = inclusionStart;
do {
lineBreakPos = findFirstLineBreakOutsideComment(code.original, lineBreakPos);
if (lineBreakPos >= 0 && lineBreakPos < branchStart) {
code.remove(lineBreakPos, lineBreakPos + 1);
lineBreakPos++;
} else {
lineBreakPos = -1;
}
} while (lineBreakPos >= 0);
}
code.remove(this.start, inclusionStart);
if (this.consequent.included) {
const questionmarkPos = findFirstOccurrenceOutsideComment(
code.original,
'?',
this.test.end
);
code.remove(this.start, questionmarkPos + 1);
code.remove(colonPos, this.end);
} else {
code.remove(this.start, colonPos + 1);
}
removeAnnotations(this, code);
(this.usedBranch as ExpressionNode).render(code, options, {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/ReturnStatement.ts
Expand Up @@ -22,7 +22,7 @@ export default class ReturnStatement extends StatementBase {

render(code: MagicString, options: RenderOptions) {
if (this.argument) {
this.argument.render(code, options);
this.argument.render(code, options, { preventASI: true });
if (this.argument.start === this.start + 6 /* 'return'.length */) {
code.prependLeft(this.start + 6, ' ');
}
Expand Down
1 change: 1 addition & 0 deletions src/utils/renderHelpers.ts
Expand Up @@ -17,6 +17,7 @@ export interface NodeRenderOptions {
isCalleeOfRenderedParent?: boolean;
isNoStatement?: boolean;
isShorthandProperty?: boolean;
preventASI?: boolean;
renderedParentType?: string; // also serves as a flag if the rendered parent is different from the actual parent
start?: number;
}
Expand Down
@@ -0,0 +1,4 @@
module.exports = {
description:
'always keep leading comments when tree-shaking and no automatic semicolons are inserted'
};
@@ -0,0 +1,7 @@
console.log(
/* keep me */
'expected');

console.log(
/* keep me */
'expected' );
9 changes: 9 additions & 0 deletions test/form/samples/keep-tree-shaking-comments-no-asi/main.js
@@ -0,0 +1,9 @@
console.log(false ?
'unexpected' :
/* keep me */
'expected');

console.log(true ?
/* keep me */
'expected' :
'unexpected');
9 changes: 9 additions & 0 deletions test/function/samples/prevent-tree-shaking-asi/_config.js
@@ -0,0 +1,9 @@
const assert = require('assert');

module.exports = {
description: 'prevent automatic semicolon insertion from changing behaviour when tree-shaking',
exports(exports) {
assert.strictEqual(exports.test1(), 'expected');
assert.strictEqual(exports.test2(), 'expected');
}
};
15 changes: 15 additions & 0 deletions test/function/samples/prevent-tree-shaking-asi/main.js
@@ -0,0 +1,15 @@
export function test1() {
return true ?


'expected' :
'unexpected';
}

export function test2() {
return false ?
'unexpected' :


'expected';
}

0 comments on commit 1059e99

Please sign in to comment.