Repository: swc-project/swc (rust)

Issue:
Parser bugs
### Describe the bug

Seems like we are eating too much modifiers in https://github.com/swc-project/swc/blob/3e32fdcdd22a46aa3305663eb1f2d00d4e9e3719/crates/swc_ecma_parser/src/parser/class_and_fn.rs#L528-L529

### Input code

```typescript
class A {
  static abstract<T>{}

}
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2018",
    "loose": false,
    "minify": {
      "compress": false,
      "mangle": false
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link

https://play.swc.rs/?version=1.2.160&code=H4sIAAAAAAAAA0vOSSwuVnBUqOZSUCguSSzJTFZITCouKUpMLrEJsauu5eKqBQBwosTTIwAAAA%3D%3D&config=H4sIAAAAAAAAA0WNSwrDMAxE76J1Fm0XpeQOPYRxleDgHxoFGozvXju4ZCfNPD0V2mBpLpSNgKVPOKKaL82kR2ZYcVlpIkWLFuPBtS1GVtaGMB63%2B6vVPiXwACYKLrrl6DKbQhYGrsrE1f%2FJ2lwhffYelPPf6XxSvRzjzuE9QJWd6w%2B6QIF4uAAAAA%3D%3D

### Expected behavior

It should be parsed

### Actual behavior

_No response_

### Version

1.2.160

### Additional context

_No response_

Pull request description:
fix(es/parser): align `ts_next_token_can_follow_modifier` to the Babel/TS implementation
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #4132 

Patch:
diff --git a/crates/swc_ecma_parser/src/parser/macros.rs b/crates/swc_ecma_parser/src/parser/macros.rs
index 2c066abaaa..a25445b52d 100644
--- a/crates/swc_ecma_parser/src/parser/macros.rs
+++ b/crates/swc_ecma_parser/src/parser/macros.rs
@@ -53,6 +53,13 @@ macro_rules! is {
         }
     }};
 
+    ($p:expr,BigInt) => {{
+        match cur!($p, false) {
+            Ok(&Token::BigInt { .. }) => true,
+            _ => false,
+        }
+    }};
+
     ($p:expr,';') => {{
         match $p.input.cur() {
             Some(&Token::Semi) | None | Some(&tok!('}')) => true,
diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs
index f4e1cfd190..e7688556e8 100644
--- a/crates/swc_ecma_parser/src/parser/typescript.rs
+++ b/crates/swc_ecma_parser/src/parser/typescript.rs
@@ -17,7 +17,7 @@ impl<I: Tokens> Parser<I> {
         // hasLineBreakUpNext() method...
         bump!(self);
         Ok(!self.input.had_line_break_before_cur()
-            && !is_one_of!(self, '(', ')', ':', '=', '?', '!', ',', '>', "extends"))
+            && is_one_of!(self, '[', '{', '*', "...", '#', IdentName, Str, Num, BigInt))
     }
 
     /// Parses a modifier matching one the given modifier names.


Test patch:
diff --git a/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es2015.1.normal.js b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es2015.1.normal.js
new file mode 100644
index 0000000000..1c4384f37d
--- /dev/null
+++ b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es2015.1.normal.js
@@ -0,0 +1,79 @@
+class C {
+}
+var c;
+var r1 = c.abstract;
+var r2 = c.as;
+var i;
+var r3 = i.abstract;
+var r4 = i.as;
+var a;
+var r5 = a.abstract;
+var r6 = a.as;
+var E;
+(function(E) {
+    E[E["abstract"] = 0] = "abstract";
+    E[E["as"] = 1] = "as";
+    E[E["boolean"] = 2] = "boolean";
+    E[E["break"] = 3] = "break";
+    E[E["byte"] = 4] = "byte";
+    E[E["case"] = 5] = "case";
+    E[E["catch"] = 6] = "catch";
+    E[E["char"] = 7] = "char";
+    E[E["class"] = 8] = "class";
+    E[E["continue"] = 9] = "continue";
+    E[E["const"] = 10] = "const";
+    E[E["debugger"] = 11] = "debugger";
+    E[E["default"] = 12] = "default";
+    E[E["delete"] = 13] = "delete";
+    E[E["do"] = 14] = "do";
+    E[E["double"] = 15] = "double";
+    E[E["else"] = 16] = "else";
+    E[E["enum"] = 17] = "enum";
+    E[E["export"] = 18] = "export";
+    E[E["extends"] = 19] = "extends";
+    E[E["false"] = 20] = "false";
+    E[E["final"] = 21] = "final";
+    E[E["finally"] = 22] = "finally";
+    E[E["float"] = 23] = "float";
+    E[E["for"] = 24] = "for";
+    E[E["function"] = 25] = "function";
+    E[E["goto"] = 26] = "goto";
+    E[E["if"] = 27] = "if";
+    E[E["implements"] = 28] = "implements";
+    E[E["import"] = 29] = "import";
+    E[E["in"] = 30] = "in";
+    E[E["instanceof"] = 31] = "instanceof";
+    E[E["int"] = 32] = "int";
+    E[E["interface"] = 33] = "interface";
+    E[E["is"] = 34] = "is";
+    E[E["long"] = 35] = "long";
+    E[E["namespace"] = 36] = "namespace";
+    E[E["native"] = 37] = "native";
+    E[E["new"] = 38] = "new";
+    E[E["null"] = 39] = "null";
+    E[E["package"] = 40] = "package";
+    E[E["private"] = 41] = "private";
+    E[E["protected"] = 42] = "protected";
+    E[E["public"] = 43] = "public";
+    E[E["return"] = 44] = "return";
+    E[E["short"] = 45] = "short";
+    E[E["static"] = 46] = "static";
+    E[E["super"] = 47] = "super";
+    E[E["switch"] = 48] = "switch";
+    E[E["synchronized"] = 49] = "synchronized";
+    E[E["this"] = 50] = "this";
+    E[E["throw"] = 51] = "throw";
+    E[E["throws"] = 52] = "throws";
+    E[E["transient"] = 53] = "transient";
+    E[E["true"] = 54] = "true";
+    E[E["try"] = 55] = "try";
+    E[E["typeof"] = 56] = "typeof";
+    E[E["use"] = 57] = "use";
+    E[E["var"] = 58] = "var";
+    E[E["void"] = 59] = "void";
+    E[E["volatile"] = 60] = "volatile";
+    E[E["while"] = 61] = "while";
+    E[E["with"] = 62] = "with";
+})(E || (E = {}));
+var r7 = E.abstract;
+var r8 = E.as;
diff --git a/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es2015.2.minified.js b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es2015.2.minified.js
new file mode 100644
index 0000000000..e7d7091942
--- /dev/null
+++ b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es2015.2.minified.js
@@ -0,0 +1,4 @@
+var c, i, a, E;
+c.abstract, c.as, i.abstract, i.as, a.abstract, a.as, function(E) {
+    E[E.abstract = 0] = "abstract", E[E.as = 1] = "as", E[E.boolean = 2] = "boolean", E[E.break = 3] = "break", E[E.byte = 4] = "byte", E[E.case = 5] = "case", E[E.catch = 6] = "catch", E[E.char = 7] = "char", E[E.class = 8] = "class", E[E.continue = 9] = "continue", E[E.const = 10] = "const", E[E.debugger = 11] = "debugger", E[E.default = 12] = "default", E[E.delete = 13] = "delete", E[E.do = 14] = "do", E[E.double = 15] = "double", E[E.else = 16] = "else", E[E.enum = 17] = "enum", E[E.export = 18] = "export", E[E.extends = 19] = "extends", E[E.false = 20] = "false", E[E.final = 21] = "final", E[E.finally = 22] = "finally", E[E.float = 23] = "float", E[E.for = 24] = "for", E[E.function = 25] = "function", E[E.goto = 26] = "goto", E[E.if = 27] = "if", E[E.implements = 28] = "implements", E[E.import = 29] = "import", E[E.in = 30] = "in", E[E.instanceof = 31] = "instanceof", E[E.int = 32] = "int", E[E.interface = 33] = "interface", E[E.is = 34] = "is", E[E.long = 35] = "long", E[E.namespace = 36] = "namespace", E[E.native = 37] = "native", E[E.new = 38] = "new", E[E.null = 39] = "null", E[E.package = 40] = "package", E[E.private = 41] = "private", E[E.protected = 42] = "protected", E[E.public = 43] = "public", E[E.return = 44] = "return", E[E.short = 45] = "short", E[E.static = 46] = "static", E[E.super = 47] = "super", E[E.switch = 48] = "switch", E[E.synchronized = 49] = "synchronized", E[E.this = 50] = "this", E[E.throw = 51] = "throw", E[E.throws = 52] = "throws", E[E.transient = 53] = "transient", E[E.true = 54] = "true", E[E.try = 55] = "try", E[E.typeof = 56] = "typeof", E[E.use = 57] = "use", E[E.var = 58] = "var", E[E.void = 59] = "void", E[E.volatile = 60] = "volatile", E[E.while = 61] = "while", E[E.with = 62] = "with";
+}(E || (E = {})), E.abstract, E.as;
diff --git a/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es5.1.normal.js b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es5.1.normal.js
new file mode 100644
index 0000000000..b875ba065e
--- /dev/null
+++ b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es5.1.normal.js
@@ -0,0 +1,82 @@
+import * as swcHelpers from "@swc/helpers";
+var C = function C() {
+    "use strict";
+    swcHelpers.classCallCheck(this, C);
+};
+var c;
+var r1 = c.abstract;
+var r2 = c.as;
+var i;
+var r3 = i.abstract;
+var r4 = i.as;
+var a;
+var r5 = a.abstract;
+var r6 = a.as;
+var E;
+(function(E) {
+    E[E["abstract"] = 0] = "abstract";
+    E[E["as"] = 1] = "as";
+    E[E["boolean"] = 2] = "boolean";
+    E[E["break"] = 3] = "break";
+    E[E["byte"] = 4] = "byte";
+    E[E["case"] = 5] = "case";
+    E[E["catch"] = 6] = "catch";
+    E[E["char"] = 7] = "char";
+    E[E["class"] = 8] = "class";
+    E[E["continue"] = 9] = "continue";
+    E[E["const"] = 10] = "const";
+    E[E["debugger"] = 11] = "debugger";
+    E[E["default"] = 12] = "default";
+    E[E["delete"] = 13] = "delete";
+    E[E["do"] = 14] = "do";
+    E[E["double"] = 15] = "double";
+    E[E["else"] = 16] = "else";
+    E[E["enum"] = 17] = "enum";
+    E[E["export"] = 18] = "export";
+    E[E["extends"] = 19] = "extends";
+    E[E["false"] = 20] = "false";
+    E[E["final"] = 21] = "final";
+    E[E["finally"] = 22] = "finally";
+    E[E["float"] = 23] = "float";
+    E[E["for"] = 24] = "for";
+    E[E["function"] = 25] = "function";
+    E[E["goto"] = 26] = "goto";
+    E[E["if"] = 27] = "if";
+    E[E["implements"] = 28] = "implements";
+    E[E["import"] = 29] = "import";
+    E[E["in"] = 30] = "in";
+    E[E["instanceof"] = 31] = "instanceof";
+    E[E["int"] = 32] = "int";
+    E[E["interface"] = 33] = "interface";
+    E[E["is"] = 34] = "is";
+    E[E["long"] = 35] = "long";
+    E[E["namespace"] = 36] = "namespace";
+    E[E["native"] = 37] = "native";
+    E[E["new"] = 38] = "new";
+    E[E["null"] = 39] = "null";
+    E[E["package"] = 40] = "package";
+    E[E["private"] = 41] = "private";
+    E[E["protected"] = 42] = "protected";
+    E[E["public"] = 43] = "public";
+    E[E["return"] = 44] = "return";
+    E[E["short"] = 45] = "short";
+    E[E["static"] = 46] = "static";
+    E[E["super"] = 47] = "super";
+    E[E["switch"] = 48] = "switch";
+    E[E["synchronized"] = 49] = "synchronized";
+    E[E["this"] = 50] = "this";
+    E[E["throw"] = 51] = "throw";
+    E[E["throws"] = 52] = "throws";
+    E[E["transient"] = 53] = "transient";
+    E[E["true"] = 54] = "true";
+    E[E["try"] = 55] = "try";
+    E[E["typeof"] = 56] = "typeof";
+    E[E["use"] = 57] = "use";
+    E[E["var"] = 58] = "var";
+    E[E["void"] = 59] = "void";
+    E[E["volatile"] = 60] = "volatile";
+    E[E["while"] = 61] = "while";
+    E[E["with"] = 62] = "with";
+})(E || (E = {}));
+var r7 = E.abstract;
+var r8 = E.as;
diff --git a/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es5.2.minified.js b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es5.2.minified.js
new file mode 100644
index 0000000000..c08ed29043
--- /dev/null
+++ b/crates/swc/tests/tsc-references/propertyNamesOfReservedWords_es5.2.minified.js
@@ -0,0 +1,8 @@
+import * as swcHelpers from "@swc/helpers";
+var c, i, a, E, C = function() {
+    "use strict";
+    swcHelpers.classCallCheck(this, C);
+};
+c.abstract, c.as, i.abstract, i.as, a.abstract, a.as, function(E) {
+    E[E.abstract = 0] = "abstract", E[E.as = 1] = "as", E[E.boolean = 2] = "boolean", E[E.break = 3] = "break", E[E.byte = 4] = "byte", E[E.case = 5] = "case", E[E.catch = 6] = "catch", E[E.char = 7] = "char", E[E.class = 8] = "class", E[E.continue = 9] = "continue", E[E.const = 10] = "const", E[E.debugger = 11] = "debugger", E[E.default = 12] = "default", E[E.delete = 13] = "delete", E[E.do = 14] = "do", E[E.double = 15] = "double", E[E.else = 16] = "else", E[E.enum = 17] = "enum", E[E.export = 18] = "export", E[E.extends = 19] = "extends", E[E.false = 20] = "false", E[E.final = 21] = "final", E[E.finally = 22] = "finally", E[E.float = 23] = "float", E[E.for = 24] = "for", E[E.function = 25] = "function", E[E.goto = 26] = "goto", E[E.if = 27] = "if", E[E.implements = 28] = "implements", E[E.import = 29] = "import", E[E.in = 30] = "in", E[E.instanceof = 31] = "instanceof", E[E.int = 32] = "int", E[E.interface = 33] = "interface", E[E.is = 34] = "is", E[E.long = 35] = "long", E[E.namespace = 36] = "namespace", E[E.native = 37] = "native", E[E.new = 38] = "new", E[E.null = 39] = "null", E[E.package = 40] = "package", E[E.private = 41] = "private", E[E.protected = 42] = "protected", E[E.public = 43] = "public", E[E.return = 44] = "return", E[E.short = 45] = "short", E[E.static = 46] = "static", E[E.super = 47] = "super", E[E.switch = 48] = "switch", E[E.synchronized = 49] = "synchronized", E[E.this = 50] = "this", E[E.throw = 51] = "throw", E[E.throws = 52] = "throws", E[E.transient = 53] = "transient", E[E.true = 54] = "true", E[E.try = 55] = "try", E[E.typeof = 56] = "typeof", E[E.use = 57] = "use", E[E.var = 58] = "var", E[E.void = 59] = "void", E[E.volatile = 60] = "volatile", E[E.while = 61] = "while", E[E.with = 62] = "with";
+}(E || (E = {})), E.abstract, E.as;
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-4132/index.ts b/crates/swc_ecma_parser/tests/typescript/issue-4132/index.ts
new file mode 100644
index 0000000000..70828c9bd1
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-4132/index.ts
@@ -0,0 +1,3 @@
+class A {
+    static abstract<T>() {}
+}
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-4132/index.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-4132/index.ts.json
new file mode 100644
index 0000000000..78e387b8f3
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-4132/index.ts.json
@@ -0,0 +1,115 @@
+{
+  "type": "Script",
+  "span": {
+    "start": 0,
+    "end": 39,
+    "ctxt": 0
+  },
+  "body": [
+    {
+      "type": "ClassDeclaration",
+      "identifier": {
+        "type": "Identifier",
+        "span": {
+          "start": 6,
+          "end": 7,
+          "ctxt": 0
+        },
+        "value": "A",
+        "optional": false
+      },
+      "declare": false,
+      "span": {
+        "start": 0,
+        "end": 39,
+        "ctxt": 0
+      },
+      "decorators": [],
+      "body": [
+        {
+          "type": "ClassMethod",
+          "span": {
+            "start": 14,
+            "end": 37,
+            "ctxt": 0
+          },
+          "key": {
+            "type": "Identifier",
+            "span": {
+              "start": 21,
+              "end": 29,
+              "ctxt": 0
+            },
+            "value": "abstract",
+            "optional": false
+          },
+          "function": {
+            "params": [],
+            "decorators": [],
+            "span": {
+              "start": 14,
+              "end": 37,
+              "ctxt": 0
+            },
+            "body": {
+              "type": "BlockStatement",
+              "span": {
+                "start": 35,
+                "end": 37,
+                "ctxt": 0
+              },
+              "stmts": []
+            },
+            "generator": false,
+            "async": false,
+            "typeParameters": {
+              "type": "TsTypeParameterDeclaration",
+              "span": {
+                "start": 29,
+                "end": 32,
+                "ctxt": 0
+              },
+              "parameters": [
+                {
+                  "type": "TsTypeParameter",
+                  "span": {
+                    "start": 30,
+                    "end": 31,
+                    "ctxt": 0
+                  },
+                  "name": {
+                    "type": "Identifier",
+                    "span": {
+                      "start": 30,
+                      "end": 31,
+                      "ctxt": 0
+                    },
+                    "value": "T",
+                    "optional": false
+                  },
+                  "in": false,
+                  "out": false,
+                  "constraint": null,
+                  "default": null
+                }
+              ]
+            },
+            "returnType": null
+          },
+          "kind": "method",
+          "isStatic": true,
+          "accessibility": null,
+          "isAbstract": false,
+          "isOptional": false,
+          "isOverride": false
+        }
+      ],
+      "superClass": null,
+      "isAbstract": false,
+      "typeParams": null,
+      "superTypeParams": null,
+      "implements": []
+    }
+  ],
+  "interpreter": null
+}