Skip to content

Commit 5c3645b

Browse files
committed
fix(formatter): handle decorators correctly for class expressions in export (#13845)
The decorators of class expressions should be printed on the class expression itself; otherwise, the parentheses wouldn't wrap the decorators, which would cause a syntax error. Input: ```ts export default (@dec class {}) {}; ``` Output before: ```ts export default @dec ( class {} ) { } ``` Output after: ```ts export default (@dec class {}) {}
1 parent 3cf1a41 commit 5c3645b

File tree

3 files changed

+8
-9
lines changed

3 files changed

+8
-9
lines changed

crates/oxc_formatter/src/write/class.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,12 @@ impl<'a> Format<'a> for FormatClass<'a, '_> {
259259
// Decorators are handled differently depending on the parent context
260260
// When the class is exported, the export statement handles decorator formatting
261261
// to ensure proper placement relative to the export keyword
262-
if !matches!(
263-
self.parent,
264-
AstNodes::ExportNamedDeclaration(_) | AstNodes::ExportDefaultDeclaration(_)
265-
) {
262+
if self.is_expression()
263+
|| !matches!(
264+
self.parent,
265+
AstNodes::ExportNamedDeclaration(_) | AstNodes::ExportDefaultDeclaration(_)
266+
)
267+
{
266268
write!(f, decorators)?;
267269
}
268270

crates/oxc_formatter/src/write/export_declarations.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ fn format_export_keyword_with_class_decorators<'a>(
3333

3434
if let AstNodes::Class(class) = declaration
3535
&& !class.decorators.is_empty()
36+
&& !class.is_expression()
3637
{
3738
// `@decorator export class Cls {}`
3839
// decorators are placed before the export keyword

tasks/coverage/snapshots/formatter_typescript.snap

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ commit: 261630d6
22

33
formatter_typescript Summary:
44
AST Parsed : 8816/8816 (100.00%)
5-
Positive Passed: 8785/8816 (99.65%)
5+
Positive Passed: 8787/8816 (99.67%)
66
Mismatch: tasks/coverage/typescript/tests/cases/compiler/amdLikeInputDeclarationEmit.ts
77

88
Expect to Parse: tasks/coverage/typescript/tests/cases/compiler/arrayFromAsync.ts
@@ -45,10 +45,6 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/classes/prope
4545
Classes may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototypeClasses may not have a static property named prototype
4646
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/controlFlow/controlFlowAssignmentPatternOrder.ts
4747
An implementation cannot be declared in ambient contexts.
48-
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/esDecorators/classExpression/esDecorators-classExpression-missingEmitHelpers-classDecorator.3.ts
49-
Decorators are not valid here.Unexpected token
50-
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/esDecorators/classExpression/namedEvaluation/esDecorators-classExpression-namedEvaluation.8.ts
51-
Decorators are not valid here.Unexpected token
5248
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/expressions/elementAccess/letIdentifierInElementAccess01.ts
5349
Unexpected token
5450
Mismatch: tasks/coverage/typescript/tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts

0 commit comments

Comments
 (0)