Repository: swc-project/swc (rust)

Issue:
optional class properties with a name of `static` or `declare` are incorrectly disallowed
**Describe the bug**
`static? = 5` is allowed as a ts class property, however, swc does not allow it:
```
error: Unexpected token `?`. Expected identifier, string literal, numeric literal or [ for the computed key
 --> tests/main.ts:2:9
  |
2 |   static?() {}
  |         ^
```
```
error: `declare` modifier cannot appear on a class element
 --> tests/main.ts:2:3
  |
2 |   declare?() {}
  |   ^^^^^^^

error: Unexpected token `?`. Expected identifier, string literal, numeric literal or [ for the computed key
 --> tests/main.ts:2:10
  |
2 |   declare?() {}
  |          ^
```

**Input code**
```ts
class Foo {
  static? = 5;
  declare? = 5;
}
```

**Config**
None

**Expected behavior**
No parser errors


**Version**
The version of @swc/core: `1.2.37`

**Additional context**
It is caused by the [is_class_property](https://github.com/swc-project/swc/blob/master/ecmascript/parser/src/parser/class_and_fn.rs#L820) check, which wont work correctly if the current token is `?` when checking for `declare` and `static` tokens in class_member.


Pull request description:
fix(ecma/parser): allow static/declare to be optional class property 
fix #1219

Patch:
diff --git a/crates/swc_ecma_parser/src/parser/class_and_fn.rs b/crates/swc_ecma_parser/src/parser/class_and_fn.rs
index 98e0069192..8f3fc34414 100644
--- a/crates/swc_ecma_parser/src/parser/class_and_fn.rs
+++ b/crates/swc_ecma_parser/src/parser/class_and_fn.rs
@@ -343,7 +343,9 @@ impl<'a, I: Tokens> Parser<I> {
                         kind: MethodKind::Method,
                     },
                 );
-            } else if self.is_class_property(/* asi */ true) {
+            } else if self.is_class_property(/* asi */ true)
+                || (self.syntax().typescript() && is!(self, '?'))
+            {
                 // Property named `declare`
 
                 let key = Either::Right(PropName::Ident(Ident::new(
@@ -403,7 +405,9 @@ impl<'a, I: Tokens> Parser<I> {
                         kind: MethodKind::Method,
                     },
                 );
-            } else if self.is_class_property(/* asi */ true) {
+            } else if self.is_class_property(/* asi */ true)
+                || (self.syntax().typescript() && is!(self, '?'))
+            {
                 // Property named `static`
 
                 // Avoid to parse


Test patch:
diff --git a/crates/swc/tests/fixture/issue-1219/input/.swcrc b/crates/swc/tests/fixture/issue-1219/input/.swcrc
new file mode 100644
index 0000000000..77ae0f6af9
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-1219/input/.swcrc
@@ -0,0 +1,8 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "typescript"
+        },
+        "target": "es2015"
+    }
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issue-1219/input/index.ts b/crates/swc/tests/fixture/issue-1219/input/index.ts
new file mode 100644
index 0000000000..2c877d3e88
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-1219/input/index.ts
@@ -0,0 +1,4 @@
+class Foo {
+    static? = 5;
+    declare? = 5;
+}
diff --git a/crates/swc/tests/fixture/issue-1219/output/index.ts b/crates/swc/tests/fixture/issue-1219/output/index.ts
new file mode 100644
index 0000000000..03f5f5d4a3
--- /dev/null
+++ b/crates/swc/tests/fixture/issue-1219/output/index.ts
@@ -0,0 +1,6 @@
+class Foo {
+    constructor(){
+        this.static = 5;
+        this.declare = 5;
+    }
+}