diff --git a/CHANGELOG.md b/CHANGELOG.md index a64418037974..0d1a8e644279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,23 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom ### Parser +#### Bug fixes +- Fix [#1728](https://github.com/biomejs/biome/issues/1728). Correctly parse the global declaration when the `{` token is on the line following the `global` keyword. + + Now the following code is correctly parsed: + + ```ts + declare global + { } + + declare module foo { + global + { } + } + ``` + + Contributed by @ah-yu + ## 1.5.3 (2024-01-22) ### LSP diff --git a/crates/biome_js_parser/src/syntax/auxiliary.rs b/crates/biome_js_parser/src/syntax/auxiliary.rs index d269518da7b8..3f3d2b2e3073 100644 --- a/crates/biome_js_parser/src/syntax/auxiliary.rs +++ b/crates/biome_js_parser/src/syntax/auxiliary.rs @@ -47,6 +47,10 @@ pub(crate) fn is_nth_at_declaration_clause(p: &mut JsParser, n: usize) -> bool { return true; } + if is_nth_at_any_ts_namespace_declaration(p, n) { + return true; + } + if p.has_nth_preceding_line_break(n + 1) { return false; } @@ -63,10 +67,6 @@ pub(crate) fn is_nth_at_declaration_clause(p: &mut JsParser, n: usize) -> bool { return true; } - if is_nth_at_any_ts_namespace_declaration(p, n) { - return true; - } - if p.nth_at(n, T![abstract]) && p.nth_at(n + 1, T![class]) { return true; } diff --git a/crates/biome_js_parser/src/syntax/stmt.rs b/crates/biome_js_parser/src/syntax/stmt.rs index 86b2e18485d5..6564d93d3e25 100644 --- a/crates/biome_js_parser/src/syntax/stmt.rs +++ b/crates/biome_js_parser/src/syntax/stmt.rs @@ -359,7 +359,7 @@ pub(crate) fn parse_statement(p: &mut JsParser, context: StatementContext) -> Pa T![async] if is_at_async_function(p, LineBreak::DoNotCheck) => { parse_function_declaration(p, context) } - T![module] | T![namespace] | T![global] if is_at_any_ts_namespace_declaration(p) => { + T![module] | T![namespace] | T![global] if is_nth_at_any_ts_namespace_declaration(p, 0) => { let name = p.cur_range(); TypeScript.parse_exclusive_syntax( p, diff --git a/crates/biome_js_parser/src/syntax/typescript/statement.rs b/crates/biome_js_parser/src/syntax/typescript/statement.rs index 293d39261ab7..7d94f3620776 100644 --- a/crates/biome_js_parser/src/syntax/typescript/statement.rs +++ b/crates/biome_js_parser/src/syntax/typescript/statement.rs @@ -375,24 +375,11 @@ fn parse_ts_extends_clause(p: &mut JsParser) -> ParsedSyntax { } #[inline] -pub(crate) fn is_at_any_ts_namespace_declaration(p: &mut JsParser) -> bool { - if p.has_nth_preceding_line_break(1) { - return false; - } - - if matches!(p.cur(), T![namespace] | T![module]) { - return is_nth_at_identifier(p, 1) || p.nth_at(1, JS_STRING_LITERAL); - } - - if p.at(T![global]) { - return p.nth_at(1, T!['{']); +pub(crate) fn is_nth_at_any_ts_namespace_declaration(p: &mut JsParser, n: usize) -> bool { + if p.nth_at(n, T![global]) { + return p.nth_at(n + 1, T!['{']); } - false -} - -#[inline] -pub(crate) fn is_nth_at_any_ts_namespace_declaration(p: &mut JsParser, n: usize) -> bool { if p.has_nth_preceding_line_break(n + 1) { return false; } @@ -401,10 +388,6 @@ pub(crate) fn is_nth_at_any_ts_namespace_declaration(p: &mut JsParser, n: usize) return is_nth_at_identifier(p, n + 1) || p.nth_at(n + 1, JS_STRING_LITERAL); } - if p.nth_at(n, T![global]) { - return p.nth_at(n + 1, T!['{']); - } - false } @@ -521,6 +504,13 @@ fn parse_ts_module_block(p: &mut JsParser) -> ParsedSyntax { // let VERSION: string; // } // } +// declare module "foo" { +// global +// { } +// } +// declare global {} +// declare global +// { } // // test ts ts_global_variable // let global; diff --git a/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.rast b/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.rast index 09a91fe73069..2de4e95dd2c3 100644 --- a/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.rast +++ b/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.rast @@ -48,15 +48,60 @@ JsModule { }, }, }, + TsDeclareStatement { + declare_token: DECLARE_KW@66..75 "declare" [Newline("\n")] [Whitespace(" ")], + declaration: TsExternalModuleDeclaration { + module_token: MODULE_KW@75..82 "module" [] [Whitespace(" ")], + source: JsModuleSource { + value_token: JS_STRING_LITERAL@82..88 "\"foo\"" [] [Whitespace(" ")], + }, + body: TsModuleBlock { + l_curly_token: L_CURLY@88..89 "{" [] [], + items: JsModuleItemList [ + TsGlobalDeclaration { + global_token: GLOBAL_KW@89..97 "global" [Newline("\n"), Whitespace(" ")] [], + body: TsModuleBlock { + l_curly_token: L_CURLY@97..101 "{" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + items: JsModuleItemList [], + r_curly_token: R_CURLY@101..102 "}" [] [], + }, + }, + ], + r_curly_token: R_CURLY@102..104 "}" [Newline("\n")] [], + }, + }, + }, + TsDeclareStatement { + declare_token: DECLARE_KW@104..113 "declare" [Newline("\n")] [Whitespace(" ")], + declaration: TsGlobalDeclaration { + global_token: GLOBAL_KW@113..120 "global" [] [Whitespace(" ")], + body: TsModuleBlock { + l_curly_token: L_CURLY@120..121 "{" [] [], + items: JsModuleItemList [], + r_curly_token: R_CURLY@121..122 "}" [] [], + }, + }, + }, + TsDeclareStatement { + declare_token: DECLARE_KW@122..131 "declare" [Newline("\n")] [Whitespace(" ")], + declaration: TsGlobalDeclaration { + global_token: GLOBAL_KW@131..137 "global" [] [], + body: TsModuleBlock { + l_curly_token: L_CURLY@137..140 "{" [Newline("\n")] [Whitespace(" ")], + items: JsModuleItemList [], + r_curly_token: R_CURLY@140..141 "}" [] [], + }, + }, + }, ], - eof_token: EOF@66..67 "" [Newline("\n")] [], + eof_token: EOF@141..142 "" [Newline("\n")] [], } -0: JS_MODULE@0..67 +0: JS_MODULE@0..142 0: (empty) 1: (empty) 2: JS_DIRECTIVE_LIST@0..0 - 3: JS_MODULE_ITEM_LIST@0..66 + 3: JS_MODULE_ITEM_LIST@0..141 0: TS_DECLARE_STATEMENT@0..66 0: DECLARE_KW@0..8 "declare" [] [Whitespace(" ")] 1: TS_EXTERNAL_MODULE_DECLARATION@8..66 @@ -87,4 +132,36 @@ JsModule { 1: SEMICOLON@60..61 ";" [] [] 2: R_CURLY@61..64 "}" [Newline("\n"), Whitespace(" ")] [] 2: R_CURLY@64..66 "}" [Newline("\n")] [] - 4: EOF@66..67 "" [Newline("\n")] [] + 1: TS_DECLARE_STATEMENT@66..104 + 0: DECLARE_KW@66..75 "declare" [Newline("\n")] [Whitespace(" ")] + 1: TS_EXTERNAL_MODULE_DECLARATION@75..104 + 0: MODULE_KW@75..82 "module" [] [Whitespace(" ")] + 1: JS_MODULE_SOURCE@82..88 + 0: JS_STRING_LITERAL@82..88 "\"foo\"" [] [Whitespace(" ")] + 2: TS_MODULE_BLOCK@88..104 + 0: L_CURLY@88..89 "{" [] [] + 1: JS_MODULE_ITEM_LIST@89..102 + 0: TS_GLOBAL_DECLARATION@89..102 + 0: GLOBAL_KW@89..97 "global" [Newline("\n"), Whitespace(" ")] [] + 1: TS_MODULE_BLOCK@97..102 + 0: L_CURLY@97..101 "{" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 1: JS_MODULE_ITEM_LIST@101..101 + 2: R_CURLY@101..102 "}" [] [] + 2: R_CURLY@102..104 "}" [Newline("\n")] [] + 2: TS_DECLARE_STATEMENT@104..122 + 0: DECLARE_KW@104..113 "declare" [Newline("\n")] [Whitespace(" ")] + 1: TS_GLOBAL_DECLARATION@113..122 + 0: GLOBAL_KW@113..120 "global" [] [Whitespace(" ")] + 1: TS_MODULE_BLOCK@120..122 + 0: L_CURLY@120..121 "{" [] [] + 1: JS_MODULE_ITEM_LIST@121..121 + 2: R_CURLY@121..122 "}" [] [] + 3: TS_DECLARE_STATEMENT@122..141 + 0: DECLARE_KW@122..131 "declare" [Newline("\n")] [Whitespace(" ")] + 1: TS_GLOBAL_DECLARATION@131..141 + 0: GLOBAL_KW@131..137 "global" [] [] + 1: TS_MODULE_BLOCK@137..141 + 0: L_CURLY@137..140 "{" [Newline("\n")] [Whitespace(" ")] + 1: JS_MODULE_ITEM_LIST@140..140 + 2: R_CURLY@140..141 "}" [] [] + 4: EOF@141..142 "" [Newline("\n")] [] diff --git a/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.ts b/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.ts index ad8f633057ba..677350e709e8 100644 --- a/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.ts +++ b/crates/biome_js_parser/test_data/inline/ok/ts_global_declaration.ts @@ -3,3 +3,10 @@ declare module "./test" { let VERSION: string; } } +declare module "foo" { + global + { } +} +declare global {} +declare global +{ } diff --git a/website/src/content/docs/internals/changelog.mdx b/website/src/content/docs/internals/changelog.mdx index 4259c82bbc05..0e215a6a2ddc 100644 --- a/website/src/content/docs/internals/changelog.mdx +++ b/website/src/content/docs/internals/changelog.mdx @@ -136,6 +136,23 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom ### Parser +#### Bug fixes +- Fix [#1728](https://github.com/biomejs/biome/issues/1728). Correctly parse the global declaration when the `{` token is on the line following the `global` keyword. + + Now the following code is correctly parsed: + + ```ts + declare global + { } + + declare module foo { + global + { } + } + ``` + + Contributed by @ah-yu + ## 1.5.3 (2024-01-22) ### LSP