Skip to content

Commit d27a1eb

Browse files
committed
Properly track whether break/continue apply to an inner switch or loop (closes #49)
1 parent 65791b9 commit d27a1eb

File tree

6 files changed

+77
-17
lines changed

6 files changed

+77
-17
lines changed

async-to-promises.ts

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ interface BreakContinueItem {
288288
identifier: Identifier;
289289
name?: string;
290290
path: NodePath<Statement>;
291+
isAsync: boolean;
291292
}
292293

293294
interface ForToIdentifier {
@@ -2800,6 +2801,7 @@ export default function ({
28002801
exitIdentifier?: Identifier;
28012802
breakIdentifiers: BreakContinueItem[];
28022803
usedIdentifiers: BreakContinueItem[];
2804+
switchCount: number;
28032805
}> = {
28042806
Function: skipNode,
28052807
ReturnStatement(path) {
@@ -2846,32 +2848,62 @@ export default function ({
28462848
}
28472849
}
28482850
},
2851+
SwitchStatement: {
2852+
enter() {
2853+
this.switchCount++;
2854+
},
2855+
exit() {
2856+
this.switchCount--;
2857+
},
2858+
},
2859+
Loop: {
2860+
enter(path) {
2861+
const parent = path.parentPath;
2862+
this.breakIdentifiers.unshift({
2863+
identifier: types.identifier("break"),
2864+
path,
2865+
name: parent.isLabeledStatement() ? parent.node.label.name : undefined,
2866+
isAsync: false,
2867+
});
2868+
},
2869+
exit() {
2870+
this.breakIdentifiers.shift();
2871+
},
2872+
},
28492873
BreakStatement(path) {
2850-
const replace = returnStatement(undefined, path.node);
28512874
const label = path.node.label;
2852-
const index = label
2853-
? this.breakIdentifiers.findIndex((breakIdentifier) => breakIdentifier.name === label.name)
2854-
: 0;
2855-
if (index !== -1 && this.breakIdentifiers.length) {
2856-
const used = this.breakIdentifiers.slice(0, index + 1);
2857-
if (used.length) {
2858-
pushMissing(this.usedIdentifiers, used);
2859-
path.replaceWithMultiple([
2860-
types.expressionStatement(setBreakIdentifiers(used, this.pluginState)),
2861-
replace,
2862-
]);
2863-
return;
2875+
if (label || this.switchCount === 0) {
2876+
const index = label
2877+
? this.breakIdentifiers.findIndex((breakIdentifier) => breakIdentifier.name === label.name)
2878+
: 0;
2879+
const replace = returnStatement(undefined, path.node);
2880+
if (index !== -1 && this.breakIdentifiers.length) {
2881+
if (!this.breakIdentifiers[index].isAsync) {
2882+
return;
2883+
}
2884+
const used = this.breakIdentifiers.slice(0, index + 1);
2885+
if (used.length) {
2886+
pushMissing(this.usedIdentifiers, used);
2887+
path.replaceWithMultiple([
2888+
types.expressionStatement(setBreakIdentifiers(used, this.pluginState)),
2889+
replace,
2890+
]);
2891+
return;
2892+
}
28642893
}
2894+
path.replaceWith(replace);
28652895
}
2866-
path.replaceWith(replace);
28672896
},
28682897
ContinueStatement(path) {
2869-
const replace = returnStatement(undefined, path.node);
28702898
const label = path.node.label;
28712899
const index = label
28722900
? this.breakIdentifiers.findIndex((breakIdentifier) => breakIdentifier.name === label.name)
28732901
: 0;
2902+
const replace = returnStatement(undefined, path.node);
28742903
if (index !== -1 && this.breakIdentifiers.length) {
2904+
if (!this.breakIdentifiers[index].isAsync) {
2905+
return;
2906+
}
28752907
const used = this.breakIdentifiers.slice(0, index);
28762908
if (used.length) {
28772909
pushMissing(this.usedIdentifiers, used);
@@ -2912,6 +2944,7 @@ export default function ({
29122944
exitIdentifier,
29132945
breakIdentifiers: breakContinueStackForPath(path),
29142946
usedIdentifiers,
2947+
switchCount: 0,
29152948
};
29162949
path.traverse(replaceReturnsAndBreaksVisitor, state);
29172950
// Add declarations for any new identifiers
@@ -3014,9 +3047,9 @@ export default function ({
30143047
}
30153048

30163049
// Build the break/continue stack for a path
3017-
function breakContinueStackForPath(path: NodePath) {
3050+
function breakContinueStackForPath(path: NodePath): BreakContinueItem[] {
30183051
let current: NodePath | null = path;
3019-
const result = [];
3052+
const result = [] as BreakContinueItem[];
30203053
while (current && !current.isFunction()) {
30213054
if (current.isLoop() || current.isSwitchStatement()) {
30223055
const breaks = pathsBreak(current);
@@ -3029,13 +3062,15 @@ export default function ({
30293062
identifier: breakIdentifierForPath(current),
30303063
name: current.parentPath.node.label.name,
30313064
path: current.parentPath,
3065+
isAsync: true,
30323066
});
30333067
}
30343068
current = current.parentPath;
30353069
} else if (simpleReferences.length) {
30363070
result.push({
30373071
identifier: breakIdentifierForPath(current),
30383072
path: current,
3073+
isAsync: true,
30393074
});
30403075
}
30413076
}
@@ -3046,6 +3081,7 @@ export default function ({
30463081
identifier: breakIdentifierForPath(current.get("body")),
30473082
name: current.node.label.name,
30483083
path: current,
3084+
isAsync: true,
30493085
});
30503086
}
30513087
}

tests/break in switch statement/hoisted.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/break in switch statement/inlined.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
async function() {
2+
await sleep(1000)
3+
const errorCode = 2;
4+
5+
let message = 'Something wrong';
6+
7+
switch (errorCode) {
8+
case 2:
9+
message = "Error 2";
10+
break;
11+
}
12+
13+
for (;;) {
14+
break;
15+
}
16+
17+
alert(message);
18+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"supportedBabels": ["babel 7"]
3+
}

tests/break in switch statement/output.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)