diff --git a/crates/biome_js_formatter/src/ts/expressions/as_expression.rs b/crates/biome_js_formatter/src/ts/expressions/as_expression.rs index 360b68e1606e..bf574e07893d 100644 --- a/crates/biome_js_formatter/src/ts/expressions/as_expression.rs +++ b/crates/biome_js_formatter/src/ts/expressions/as_expression.rs @@ -91,6 +91,20 @@ impl NeedsParentheses for TsAsOrSatisfiesExpression { match parent.kind() { JsSyntaxKind::JS_CONDITIONAL_EXPRESSION => true, + // `export default (function foo() {} as bar)` needs to be special + // cased. All other default-exported as expressions can be written + // without parentheses, but function expressions _without_ the + // parentheses because `JsExportDefaultFunctionDeclaration`s and + // the cast becomes invalid. + JsSyntaxKind::JS_EXPORT_DEFAULT_EXPRESSION_CLAUSE => { + self.expression().map_or(false, |expression| { + matches!( + expression.syntax().kind(), + JsSyntaxKind::JS_FUNCTION_EXPRESSION + ) + }) + } + _ => { type_cast_like_needs_parens(self.syntax(), parent) || is_binary_like_left_or_right(self.syntax(), parent) @@ -152,5 +166,14 @@ mod tests { assert_needs_parentheses!("(x as any) instanceof (y as any)", TsAsExpression[1]); assert_not_needs_parentheses!("x as number as string", TsAsExpression[1]); + + // default-exported function expressions require parentheses, otherwise + // the end of the function ends the export declaration, and the `as` + // gets treated as a new statement. + assert_needs_parentheses!( + "export default (function foo(){} as typeof console.log)", + TsAsExpression + ); + assert_not_needs_parentheses!("export default foo as bar", TsAsExpression); } } diff --git a/crates/biome_js_formatter/tests/quick_test.rs b/crates/biome_js_formatter/tests/quick_test.rs index e71fdc0ab672..ea8f6983cd8a 100644 --- a/crates/biome_js_formatter/tests/quick_test.rs +++ b/crates/biome_js_formatter/tests/quick_test.rs @@ -9,31 +9,20 @@ mod language { include!("language.rs"); } +#[ignore] #[test] // use this test check if your snippet prints as you wish, without using a snapshot fn quick_test() { let src = r#" - -const makeSomeFunction = -(services = {logger:null}) => - (a, b, c) => - services.logger(a,b,c) - -const makeSomeFunction2 = -(services = { - logger: null -}) => - (a, b, c) => - services.logger(a, b, c) - + export default foo as bar; "#; - let syntax = JsFileSource::tsx(); + let source_type = JsFileSource::tsx(); let tree = parse( src, - syntax, + source_type, JsParserOptions::default().with_parse_class_parameter_decorators(), ); - let options = JsFormatOptions::new(syntax) + let options = JsFormatOptions::new(source_type) .with_indent_style(IndentStyle::Space) .with_semicolons(Semicolons::Always) .with_quote_style(QuoteStyle::Double) @@ -42,7 +31,6 @@ const makeSomeFunction2 = let doc = format_node(options.clone(), &tree.syntax()).unwrap(); let result = doc.print().unwrap(); - let source_type = JsFileSource::js_module(); println!("{}", doc.into_document()); eprintln!("{}", result.as_code());