Repository: alangpierce/sucrase
Pull request #708 (2022-06-24 23:56:40)

Implement parsing for flow enums
Progress toward #701

This is based largely off of the Babel implementation, and handles various cases
with ellipses, `of` declarations, assignments, and enums as part of named and
default exports.

I also changed the token test to make it easier to copy and paste the error
output to get a starting point for the tokens.

codecov[bot]: # [Codecov](https://codecov.io/gh/alangpierce/sucrase/pull/708?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) Report
> Merging [#708](https://codecov.io/gh/alangpierce/sucrase/pull/708?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) (56e8298) into [main](https://codecov.io/gh/alangpierce/sucrase/commit/210bee9f0694a963f8d0e993f9884f23202b7e30?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) (210bee9) will **increase** coverage by `0.04%`.
> The diff coverage is `90.32%`.

```diff
@@            Coverage Diff             @@
##             main     #708      +/-   ##
==========================================
+ Coverage   84.73%   84.77%   +0.04%     
==========================================
  Files          54       54              
  Lines        5771     5801      +30     
  Branches     1314     1323       +9     
==========================================
+ Hits         4890     4918      +28     
- Misses        597      598       +1     
- Partials      284      285       +1     
```


| [Impacted Files](https://codecov.io/gh/alangpierce/sucrase/pull/708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) | Coverage Δ | |
|---|---|---|
| [src/parser/tokenizer/readWordTree.ts](https://codecov.io/gh/alangpierce/sucrase/pull/708/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci90b2tlbml6ZXIvcmVhZFdvcmRUcmVlLnRz) | `100.00% <ø> (ø)` | |
| [src/parser/traverser/statement.ts](https://codecov.io/gh/alangpierce/sucrase/pull/708/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci90cmF2ZXJzZXIvc3RhdGVtZW50LnRz) | `82.48% <66.66%> (-0.09%)` | :arrow_down: |
| [src/parser/plugins/flow.ts](https://codecov.io/gh/alangpierce/sucrase/pull/708/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci9wbHVnaW5zL2Zsb3cudHM=) | `65.41% <92.59%> (+1.49%)` | :arrow_up: |
| [src/parser/tokenizer/keywords.ts](https://codecov.io/gh/alangpierce/sucrase/pull/708/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci90b2tlbml6ZXIva2V5d29yZHMudHM=) | `100.00% <100.00%> (ø)` | |

:mega: Codecov can now indicate which changes are the most critical in Pull Requests. [Learn more](https://about.codecov.io/product/feature/runtime-insights/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce)

github-actions[bot]: ## Benchmark results
**Before this PR:** 284.9 thousand lines per second
**After this PR:**  281 thousand lines per second

**Measured change:** 1.34% slower (2.96% slower to 0.29% faster)
**Summary:** Likely no significant difference

Patch:
diff --git a/generator/generateReadWordTree.ts b/generator/generateReadWordTree.ts
index 191bfcf..c785104 100644
--- a/generator/generateReadWordTree.ts
+++ b/generator/generateReadWordTree.ts
@@ -73,6 +73,7 @@ const CONTEXTUAL_KEYWORDS = [
   "require",
   "set",
   "static",
+  "symbol",
   "type",
   "unique",
 ];
diff --git a/src/parser/plugins/flow.ts b/src/parser/plugins/flow.ts
index 834bcf5..b69dad4 100644
--- a/src/parser/plugins/flow.ts
+++ b/src/parser/plugins/flow.ts
@@ -769,9 +769,19 @@ export function flowTryParseStatement(): boolean {
     flowParseInterface();
     popTypeContext(oldIsType);
     return true;
-  } else {
-    return false;
+  } else if (isContextual(ContextualKeyword._enum)) {
+    flowParseEnumDeclaration();
+    return true;
+  }
+  return false;
+}
+
+export function flowTryParseExportDefaultExpression(): boolean {
+  if (isContextual(ContextualKeyword._enum)) {
+    flowParseEnumDeclaration();
+    return true;
   }
+  return false;
 }
 
 // declares, interfaces and type aliases
@@ -811,7 +821,8 @@ export function flowShouldParseExportDeclaration(): boolean {
   return (
     isContextual(ContextualKeyword._type) ||
     isContextual(ContextualKeyword._interface) ||
-    isContextual(ContextualKeyword._opaque)
+    isContextual(ContextualKeyword._opaque) ||
+    isContextual(ContextualKeyword._enum)
   );
 }
 
@@ -820,7 +831,8 @@ export function flowShouldDisallowExportDefaultSpecifier(): boolean {
     match(tt.name) &&
     (state.contextualKeyword === ContextualKeyword._type ||
       state.contextualKeyword === ContextualKeyword._interface ||
-      state.contextualKeyword === ContextualKeyword._opaque)
+      state.contextualKeyword === ContextualKeyword._opaque ||
+      state.contextualKeyword === ContextualKeyword._enum)
   );
 }
 
@@ -1055,3 +1067,39 @@ function parseAsyncArrowWithTypeParameters(): boolean {
   parseArrowExpression(startTokenIndex);
   return true;
 }
+
+function flowParseEnumDeclaration(): void {
+  expectContextual(ContextualKeyword._enum);
+  state.tokens[state.tokens.length - 1].type = tt._enum;
+  parseIdentifier();
+  flowParseEnumBody();
+}
+
+function flowParseEnumBody(): void {
+  if (eatContextual(ContextualKeyword._of)) {
+    next();
+  }
+  expect(tt.braceL);
+  flowParseEnumMembers();
+  expect(tt.braceR);
+}
+
+function flowParseEnumMembers(): void {
+  while (!match(tt.braceR) && !state.error) {
+    if (eat(tt.ellipsis)) {
+      break;
+    }
+    flowParseEnumMember();
+    if (!match(tt.braceR)) {
+      expect(tt.comma);
+    }
+  }
+}
+
+function flowParseEnumMember(): void {
+  parseIdentifier();
+  if (eat(tt.eq)) {
+    // Flow enum values are always just one token (a string, number, or boolean literal).
+    next();
+  }
+}
diff --git a/src/parser/tokenizer/keywords.ts b/src/parser/tokenizer/keywords.ts
index 8a52a26..5dd5e8a 100644
--- a/src/parser/tokenizer/keywords.ts
+++ b/src/parser/tokenizer/keywords.ts
@@ -32,6 +32,7 @@ export enum ContextualKeyword {
   _require,
   _set,
   _static,
+  _symbol,
   _type,
   _unique,
 }
diff --git a/src/parser/tokenizer/readWordTree.ts b/src/parser/tokenizer/readWordTree.ts
index d0f00b4..0b00915 100644
--- a/src/parser/tokenizer/readWordTree.ts
+++ b/src/parser/tokenizer/readWordTree.ts
@@ -5,7 +5,7 @@ import {TokenType as tt} from "./types";
 // prettier-ignore
 export const READ_WORD_TREE = new Int32Array([
   // ""
-  -1, 27, 594, 729, 1566, 2187, 2673, 3294, -1, 3510, -1, 4428, 4563, 4644, 4941, 5319, 5697, -1, 6237, 6696, 7155, 7587, 7749, 7911, -1, 8127, -1,
+  -1, 27, 594, 729, 1566, 2187, 2673, 3294, -1, 3510, -1, 4428, 4563, 4644, 4941, 5319, 5697, -1, 6237, 6696, 7290, 7722, 7884, 8046, -1, 8262, -1,
   // "a"
   -1, -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 243, -1, -1, -1, 486, -1, -1, -1,
   // "ab"
@@ -501,7 +501,7 @@ export const READ_WORD_TREE = new Int32Array([
   // "return"
   (tt._return << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "s"
-  -1, -1, -1, -1, -1, 6723, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6777, 6912, -1, 7020, -1, -1, -1,
+  -1, -1, -1, -1, -1, 6723, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6777, 6912, -1, 7020, -1, 7155, -1,
   // "se"
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6750, -1, -1, -1, -1, -1, -1,
   // "set"
@@ -534,86 +534,96 @@ export const READ_WORD_TREE = new Int32Array([
   -1, -1, -1, -1, -1, -1, -1, -1, 7128, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "switch"
   (tt._switch << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  // "sy"
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7182, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  // "sym"
+  -1, -1, 7209, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  // "symb"
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7236, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  // "symbo"
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7263, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  // "symbol"
+  ContextualKeyword._symbol << 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "t"
-  -1, -1, -1, -1, -1, -1, -1, -1, 7182, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7344, -1, -1, -1, -1, -1, -1, 7452, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, 7317, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7479, -1, -1, -1, -1, -1, -1, 7587, -1,
   // "th"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7209, -1, -1, -1, -1, -1, -1, -1, -1, 7263, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7344, -1, -1, -1, -1, -1, -1, -1, -1, 7398, -1, -1, -1, -1, -1, -1, -1, -1,
   // "thi"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7236, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7371, -1, -1, -1, -1, -1, -1, -1,
   // "this"
   (tt._this << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "thr"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7425, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "thro"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7317, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7452, -1, -1, -1,
   // "throw"
   (tt._throw << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "tr"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7371, -1, -1, -1, 7425, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7506, -1, -1, -1, 7560, -1,
   // "tru"
-  -1, -1, -1, -1, -1, 7398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, 7533, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "true"
   (tt._true << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "try"
   (tt._try << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "ty"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7479, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7614, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "typ"
-  -1, -1, -1, -1, -1, 7506, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, 7641, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "type"
-  ContextualKeyword._type << 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7533, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  ContextualKeyword._type << 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7668, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "typeo"
-  -1, -1, -1, -1, -1, -1, 7560, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, 7695, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "typeof"
   (tt._typeof << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "u"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7614, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7749, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "un"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7641, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7776, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "uni"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7668, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7803, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "uniq"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7695, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7830, -1, -1, -1, -1, -1,
   // "uniqu"
-  -1, -1, -1, -1, -1, 7722, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, 7857, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "unique"
   ContextualKeyword._unique << 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "v"
-  -1, 7776, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7830, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, 7911, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7965, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "va"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7803, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7938, -1, -1, -1, -1, -1, -1, -1, -1,
   // "var"
   (tt._var << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "vo"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7857, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7992, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "voi"
-  -1, -1, -1, -1, 7884, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 8019, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "void"
   (tt._void << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "w"
-  -1, -1, -1, -1, -1, -1, -1, -1, 7938, 8046, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, 8073, 8181, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "wh"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 7965, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 8100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "whi"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7992, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8127, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "whil"
-  -1, -1, -1, -1, -1, 8019, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, 8154, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "while"
   (tt._while << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "wi"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8073, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8208, -1, -1, -1, -1, -1, -1,
   // "wit"
-  -1, -1, -1, -1, -1, -1, -1, -1, 8100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, 8235, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "with"
   (tt._with << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "y"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 8154, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 8289, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "yi"
-  -1, -1, -1, -1, -1, 8181, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, 8316, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "yie"
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8343, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "yiel"
-  -1, -1, -1, -1, 8235, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 8370, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   // "yield"
   (tt._yield << 1) + 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 ]);
diff --git a/src/parser/traverser/statement.ts b/src/parser/traverser/statement.ts
index 4b7adac..929b554 100644
--- a/src/parser/traverser/statement.ts
+++ b/src/parser/traverser/statement.ts
@@ -15,6 +15,7 @@ import {
   flowShouldParseExportStar,
   flowStartParseFunctionParams,
   flowStartParseImportSpecifiers,
+  flowTryParseExportDefaultExpression,
   flowTryParseStatement,
 } from "../plugins/flow";
 import {
@@ -918,6 +919,11 @@ function parseExportDefaultExpression(): void {
       return;
     }
   }
+  if (isFlowEnabled) {
+    if (flowTryParseExportDefaultExpression()) {
+      return;
+    }
+  }
   const functionStart = state.start;
   if (eat(tt._function)) {
     parseFunction(functionStart, true, true);


Test patch:
diff --git a/test/flow-test.ts b/test/flow-test.ts
index 71a655f..b7d48c3 100644
--- a/test/flow-test.ts
+++ b/test/flow-test.ts
@@ -1,7 +1,7 @@
 import {throws} from "assert";
 
 import {transform, Options} from "../src";
-import {IMPORT_DEFAULT_PREFIX} from "./prefixes";
+import {ESMODULE_PREFIX, IMPORT_DEFAULT_PREFIX} from "./prefixes";
 import {assertResult} from "./util";
 
 function assertFlowResult(
@@ -154,6 +154,17 @@ describe("transform flow", () => {
     );
   });
 
+  it("handles plain default exports when parsing flow", () => {
+    assertFlowResult(
+      `
+      export default 3;
+    `,
+      `"use strict";${ESMODULE_PREFIX}
+      exports. default = 3;
+    `,
+    );
+  });
+
   it("properly parses import aliases with the flow parser", () => {
     assertFlowResult(
       `
diff --git a/test/tokens-test.ts b/test/tokens-test.ts
index 44c1e98..57bc8bb 100644
--- a/test/tokens-test.ts
+++ b/test/tokens-test.ts
@@ -2,14 +2,22 @@ import * as assert from "assert";
 
 import {parse} from "../src/parser";
 import {IdentifierRole, Token} from "../src/parser/tokenizer";
+import {ContextualKeyword} from "../src/parser/tokenizer/keywords";
 import {TokenType as tt} from "../src/parser/tokenizer/types";
 
 type SimpleToken = Token & {label?: string};
 type TokenExpectation = {[K in keyof SimpleToken]?: SimpleToken[K]};
 
-function assertTokens(code: string, expectedTokens: Array<TokenExpectation>): void {
-  const tokens: Array<SimpleToken> = parse(code, true, true, false).tokens;
-  assert.strictEqual(tokens.length, expectedTokens.length);
+function assertTokens(
+  code: string,
+  expectedTokens: Array<TokenExpectation>,
+  {isFlow = false}: {isFlow?: boolean} = {},
+): void {
+  const tokens: Array<SimpleToken> = parse(code, true, !isFlow, isFlow).tokens;
+  const helpMessage = `Tokens did not match. Starting point with just token types: [${tokens
+    .map((t) => `{type: tt.${tt[t.type]}}`)
+    .join(", ")}]`;
+  assert.strictEqual(tokens.length, expectedTokens.length, helpMessage);
   const projectedTokens = tokens.map((token, i) => {
     const result = {};
     for (const key of Object.keys(expectedTokens[i])) {
@@ -18,7 +26,7 @@ function assertTokens(code: string, expectedTokens: Array<TokenExpectation>): vo
     }
     return result;
   });
-  assert.deepStrictEqual(projectedTokens, expectedTokens);
+  assert.deepStrictEqual(projectedTokens, expectedTokens, helpMessage);
 }
 
 describe("tokens", () => {
@@ -367,4 +375,127 @@ describe("tokens", () => {
       ],
     );
   });
+
+  it("parses simple flow enums", () => {
+    assertTokens(
+      `
+      enum E {
+        A,
+        B,
+        ...
+      }
+    `,
+      [
+        {type: tt._enum},
+        {type: tt.name},
+        {type: tt.braceL},
+        {type: tt.name},
+        {type: tt.comma},
+        {type: tt.name},
+        {type: tt.comma},
+        {type: tt.ellipsis},
+        {type: tt.braceR},
+        {type: tt.eof},
+      ],
+      {isFlow: true},
+    );
+  });
+
+  it("parses flow enums with assignments", () => {
+    assertTokens(
+      `
+      enum E {
+        A = 1,
+        B = 2,
+      }
+    `,
+      [
+        {type: tt._enum},
+        {type: tt.name},
+        {type: tt.braceL},
+        {type: tt.name},
+        {type: tt.eq},
+        {type: tt.num},
+        {type: tt.comma},
+        {type: tt.name},
+        {type: tt.eq},
+        {type: tt.num},
+        {type: tt.comma},
+        {type: tt.braceR},
+        {type: tt.eof},
+      ],
+      {isFlow: true},
+    );
+  });
+
+  it("parses flow symbol enums", () => {
+    assertTokens(
+      `
+      enum E of symbol {
+        A,
+        B
+      }
+    `,
+      [
+        {type: tt._enum},
+        {type: tt.name},
+        {type: tt.name, contextualKeyword: ContextualKeyword._of},
+        {type: tt.name, contextualKeyword: ContextualKeyword._symbol},
+        {type: tt.braceL},
+        {type: tt.name},
+        {type: tt.comma},
+        {type: tt.name},
+        {type: tt.braceR},
+        {type: tt.eof},
+      ],
+      {isFlow: true},
+    );
+  });
+
+  it("parses flow named export enums", () => {
+    assertTokens(
+      `
+      export enum E {
+        A,
+        B
+      }
+    `,
+      [
+        {type: tt._export},
+        {type: tt._enum},
+        {type: tt.name},
+        {type: tt.braceL},
+        {type: tt.name},
+        {type: tt.comma},
+        {type: tt.name},
+        {type: tt.braceR},
+        {type: tt.eof},
+      ],
+      {isFlow: true},
+    );
+  });
+
+  it("parses flow default export enums", () => {
+    assertTokens(
+      `
+      export default enum E {
+        A,
+        B
+      }
+    `,
+      [
+        {type: tt._export},
+        {type: tt._default},
+        {type: tt._enum},
+        {type: tt.name},
+        {type: tt.braceL},
+        {type: tt.name},
+        {type: tt.comma},
+        {type: tt.name},
+        {type: tt.braceR},
+        {type: tt.eof},
+      ],
+      {isFlow: true},
+    );
+  });
 });