fix(rslint_parser): Static `constructor` member
Static methods called `constructor` are valid JS, thus, these methods can be generators or async.
MODIFY
crates/rslint_parser/src/syntax/class.rs
crates/rslint_parser/src/syntax/class.rs
@@ -383,7 +383,6 @@ fn parse_class_member_impl(
if p.at(T![*]) {
p.bump_any(); // bump * token
- let is_constructor = p.cur_src() == "constructor";
if let Some(range) = modifiers.get_range(ModifierKind::Readonly) {
let err = p
.err_builder("class methods cannot be readonly")
@@ -392,7 +391,7 @@ fn parse_class_member_impl(
p.error(err);
}
- if is_constructor {
+ if is_at_constructor(p, &modifiers) {
let err = p
.err_builder("constructors can't be generators")
.primary(generator_range, "");
@@ -422,7 +421,7 @@ fn parse_class_member_impl(
flags |= SignatureFlags::GENERATOR;
}
- if p.cur_src() == "constructor" {
+ if is_at_constructor(p, &modifiers) {
let err = p
.err_builder("constructors cannot be async")
.primary(async_range, "");
@@ -441,11 +440,7 @@ fn parse_class_member_impl(
return Present(parse_method_class_member(p, member_marker, flags));
}
- let member_name = p.cur_src();
- let is_constructor = matches!(
- member_name,
- "constructor" | "\"constructor\"" | "'constructor'"
- ) && modifiers.get_range(ModifierKind::Static).is_none();
+ let is_constructor = is_at_constructor(p, &modifiers);
let member_name =
parse_class_member_name(p).or_add_diagnostic(p, js_parse_error::expected_class_member_name);
@@ -666,7 +661,7 @@ fn parse_class_member_impl(
//
// test_err class_declare_member
// class B { declare foo }
- let property = if modifiers.get_range(ModifierKind::Declare).is_some() {
+ let property = if modifiers.has(ModifierKind::Declare) {
property_declaration_class_member_body(p, member_marker, member_name.kind())
} else {
parse_property_class_member_body(p, member_marker)
@@ -1058,6 +1053,19 @@ fn is_at_modifier(p: &Parser, offset: usize) -> bool {
) || is_at_class_member_name(p, offset)
}
+// test static_generator_constructor_method
+// class A {
+// static async * constructor() {}
+// static * constructor() {}
+// }
+fn is_at_constructor(p: &Parser, modifiers: &ClassMemberModifiers) -> bool {
+ !modifiers.has(ModifierKind::Static)
+ && matches!(
+ p.cur_src(),
+ "constructor" | "\"constructor\"" | "'constructor'"
+ )
+}
+
// test_err class_invalid_modifiers
// class A { public foo() {} }
// class B { static static foo() {} }
@@ -1227,4 +1235,8 @@ impl ClassMemberModifiers {
fn set_range(&mut self, modifier: Modifier) {
self.modifiers[modifier.kind as usize] = Some(modifier.range);
}
+
+ fn has(&self, kind: ModifierKind) -> bool {
+ self.modifiers[kind as usize].is_some()
+ }
}

ADD
crates/rslint_parser/test_data/inline/ok/static_generator_constructor_method.js
+class A {
+ static async * constructor() {}
+ static * constructor() {}
+}

ADD
crates/rslint_parser/test_data/inline/ok/static_generator_constructor_method.rast
+JsModule {
+ interpreter_token: missing (optional),
+ directives: JsDirectiveList [],
+ items: JsModuleItemList [
+ JsClassStatement {
+ class_token: CLASS_KW@0..6 "class" [] [Whitespace(" ")],
+ id: JsIdentifierBinding {
+ name_token: IDENT@6..8 "A" [] [Whitespace(" ")],
+ },
+ extends_clause: missing (optional),
+ implements_clause: missing (optional),
+ l_curly_token: L_CURLY@8..9 "{" [] [],
+ members: JsClassMemberList [
+ JsMethodClassMember {
+ access_modifier: missing (optional),
+ static_token: STATIC_KW@9..18 "static" [Newline("\n"), Whitespace("\t")] [Whitespace(" ")],
+ abstract_token: missing (optional),
+ async_token: ASYNC_KW@18..24 "async" [] [Whitespace(" ")],
+ star_token: STAR@24..26 "*" [] [Whitespace(" ")],
+ name: JsLiteralMemberName {
+ value: IDENT@26..37 "constructor" [] [],
+ },
+ type_parameters: missing (optional),
+ parameters: JsParameters {
+ l_paren_token: L_PAREN@37..38 "(" [] [],
+ items: JsParameterList [],
+ r_paren_token: R_PAREN@38..40 ")" [] [Whitespace(" ")],
+ },
+ return_type: missing (optional),
+ body: JsFunctionBody {
+ l_curly_token: L_CURLY@40..41 "{" [] [],
+ directives: JsDirectiveList [],
+ statements: JsStatementList [],
+ r_curly_token: R_CURLY@41..42 "}" [] [],
+ },
+ },
+ JsMethodClassMember {
+ access_modifier: missing (optional),
+ static_token: STATIC_KW@42..51 "static" [Newline("\n"), Whitespace("\t")] [Whitespace(" ")],
+ abstract_token: missing (optional),
+ async_token: missing (optional),
+ star_token: STAR@51..53 "*" [] [Whitespace(" ")],
+ name: JsLiteralMemberName {
+ value: IDENT@53..64 "constructor" [] [],
+ },
+ type_parameters: missing (optional),
+ parameters: JsParameters {
+ l_paren_token: L_PAREN@64..65 "(" [] [],
+ items: JsParameterList [],
+ r_paren_token: R_PAREN@65..67 ")" [] [Whitespace(" ")],
+ },
+ return_type: missing (optional),
+ body: JsFunctionBody {
+ l_curly_token: L_CURLY@67..68 "{" [] [],
+ directives: JsDirectiveList [],
+ statements: JsStatementList [],
+ r_curly_token: R_CURLY@68..69 "}" [] [],
+ },
+ },
+ ],
+ r_curly_token: R_CURLY@69..71 "}" [Newline("\n")] [],
+ },
+ ],
+ eof_token: EOF@71..72 "" [Newline("\n")] [],
+}
+
+0: JS_MODULE@0..72
+ 0: (empty)
+ 1: JS_DIRECTIVE_LIST@0..0
+ 2: JS_MODULE_ITEM_LIST@0..71
+ 0: JS_CLASS_STATEMENT@0..71
+ 0: CLASS_KW@0..6 "class" [] [Whitespace(" ")]
+ 1: JS_IDENTIFIER_BINDING@6..8
+ 0: IDENT@6..8 "A" [] [Whitespace(" ")]
+ 2: (empty)
+ 3: (empty)
+ 4: L_CURLY@8..9 "{" [] []
+ 5: JS_CLASS_MEMBER_LIST@9..69
+ 0: JS_METHOD_CLASS_MEMBER@9..42
+ 0: (empty)
+ 1: STATIC_KW@9..18 "static" [Newline("\n"), Whitespace("\t")] [Whitespace(" ")]
+ 2: (empty)
+ 3: ASYNC_KW@18..24 "async" [] [Whitespace(" ")]
+ 4: STAR@24..26 "*" [] [Whitespace(" ")]
+ 5: JS_LITERAL_MEMBER_NAME@26..37
+ 0: IDENT@26..37 "constructor" [] []
+ 6: (empty)
+ 7: JS_PARAMETERS@37..40
+ 0: L_PAREN@37..38 "(" [] []
+ 1: JS_PARAMETER_LIST@38..38
+ 2: R_PAREN@38..40 ")" [] [Whitespace(" ")]
+ 8: (empty)
+ 9: JS_FUNCTION_BODY@40..42
+ 0: L_CURLY@40..41 "{" [] []
+ 1: JS_DIRECTIVE_LIST@41..41
+ 2: JS_STATEMENT_LIST@41..41
+ 3: R_CURLY@41..42 "}" [] []
+ 1: JS_METHOD_CLASS_MEMBER@42..69
+ 0: (empty)
+ 1: STATIC_KW@42..51 "static" [Newline("\n"), Whitespace("\t")] [Whitespace(" ")]
+ 2: (empty)
+ 3: (empty)
+ 4: STAR@51..53 "*" [] [Whitespace(" ")]
+ 5: JS_LITERAL_MEMBER_NAME@53..64
+ 0: IDENT@53..64 "constructor" [] []
+ 6: (empty)
+ 7: JS_PARAMETERS@64..67
+ 0: L_PAREN@64..65 "(" [] []
+ 1: JS_PARAMETER_LIST@65..65
+ 2: R_PAREN@65..67 ")" [] [Whitespace(" ")]
+ 8: (empty)
+ 9: JS_FUNCTION_BODY@67..69
+ 0: L_CURLY@67..68 "{" [] []
+ 1: JS_DIRECTIVE_LIST@68..68
+ 2: JS_STATEMENT_LIST@68..68
+ 3: R_CURLY@68..69 "}" [] []
+ 6: R_CURLY@69..71 "}" [Newline("\n")] []
+ 3: EOF@71..72 "" [Newline("\n")] []

fix(rslint_parser): Static `constructor` member (#1955)

Static methods called `constructor` are valid JS, thus, these methods can be generators or async.