mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(formatter): print decorators on rest parameters (#28731)
oxfmt deletes a decorator on a rest parameter. This happens with the
default settings, and oxfmt reports no error.
```ts
class C {
m(@Dec() ...args: string[]) {}
}
// before
class C {
m(...args: string[]) {}
}
```
The parser and codegen support these decorators (#18938, #20132), but
the formatter printed only the rest element and its type annotation.
This PR prints the decorators in the same way as for `FormalParameter`.
The new fixture `ts/parameters/rest-decorators.ts` covers single and
multiple decorators, `@(await p)`, a decorator after another parameter,
and long parameter lists. The output matches Prettier 3.9.10 for every
case.
---
AI assistance was used for this change. I reviewed and tested it.
---------
Co-authored-by: leaysgur <6259812+leaysgur@users.noreply.github.com>
This commit is contained in:
1 parent
8432de6b27
commit
b8ba9ae45f
4 files changed
+154
-3
No files matched your search
@@ -35,7 +35,7 @@ impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'_, 'a, ArenaVec<'a, Decora
|
||||
);
|
||||
}
|
||||
// Parameter decorators
|
||||
AstNodes::FormalParameter(_) => {
|
||||
AstNodes::FormalParameter(_) | AstNodes::FormalParameterRest(_) => {
|
||||
write!(f, should_expand_decorators(self, f).then_some(expand_parent()));
|
||||
}
|
||||
AstNodes::ExportDeclaration(_) | AstNodes::ExportDefaultDeclaration(_) => {
|
||||
|
||||
@@ -1103,8 +1103,17 @@ impl<'a> FormatWrite<'a> for AstNode<'_, 'a, BindingPattern<'a>> {
|
||||
|
||||
impl<'a> FormatWrite<'a> for AstNode<'_, 'a, FormalParameterRest<'a>> {
|
||||
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
|
||||
write!(f, [self.rest()]);
|
||||
write!(f, self.type_annotation());
|
||||
let content = format_with(|f| {
|
||||
write!(f, [self.rest()]);
|
||||
write!(f, self.type_annotation());
|
||||
});
|
||||
// Decorators are laid out as on `FormalParameter`, an undecorated rest parameter stays ungrouped
|
||||
let decorators = self.decorators();
|
||||
if decorators.is_empty() {
|
||||
write!(f, [content]);
|
||||
} else {
|
||||
write!(f, [group(&decorators), group(&content)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Decorators on a rest parameter are printed like those on other parameters
|
||||
class C { m(@d ...args: unknown[]) {} }
|
||||
class C2 { constructor(@Inject(TOKEN) ...deps: any[]) {} }
|
||||
class C3 { m(@d x, @e ...rest) {} }
|
||||
class C4 { async rest(@(await p) ...args: unknown[]) {} }
|
||||
class C5 { m(@d @e ...args) {} }
|
||||
class C6 {
|
||||
constructor(
|
||||
@Inject(VERY_LONG_TOKEN_NAME_FOR_DEPENDENCY_INJECTION) private readonly a: A,
|
||||
@Inject(ANOTHER_VERY_LONG_TOKEN_NAME) ...rest: unknown[]
|
||||
) {}
|
||||
}
|
||||
class C7 { m(@d
|
||||
...args) {} }
|
||||
// Comments around the decorator keep their place
|
||||
class C8 { m(@d /* c */ ...args) {} }
|
||||
class C9 { m(@d // c
|
||||
...args) {} }
|
||||
class C10 { m(@d ...args // c
|
||||
) {} }
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
source: crates/oxc_formatter/tests/fixtures/mod.rs
|
||||
---
|
||||
==================== Input ====================
|
||||
// Decorators on a rest parameter are printed like those on other parameters
|
||||
class C { m(@d ...args: unknown[]) {} }
|
||||
class C2 { constructor(@Inject(TOKEN) ...deps: any[]) {} }
|
||||
class C3 { m(@d x, @e ...rest) {} }
|
||||
class C4 { async rest(@(await p) ...args: unknown[]) {} }
|
||||
class C5 { m(@d @e ...args) {} }
|
||||
class C6 {
|
||||
constructor(
|
||||
@Inject(VERY_LONG_TOKEN_NAME_FOR_DEPENDENCY_INJECTION) private readonly a: A,
|
||||
@Inject(ANOTHER_VERY_LONG_TOKEN_NAME) ...rest: unknown[]
|
||||
) {}
|
||||
}
|
||||
class C7 { m(@d
|
||||
...args) {} }
|
||||
// Comments around the decorator keep their place
|
||||
class C8 { m(@d /* c */ ...args) {} }
|
||||
class C9 { m(@d // c
|
||||
...args) {} }
|
||||
class C10 { m(@d ...args // c
|
||||
) {} }
|
||||
|
||||
==================== Output ====================
|
||||
------------------
|
||||
{ printWidth: 80 }
|
||||
------------------
|
||||
// Decorators on a rest parameter are printed like those on other parameters
|
||||
class C {
|
||||
m(@d ...args: unknown[]) {}
|
||||
}
|
||||
class C2 {
|
||||
constructor(@Inject(TOKEN) ...deps: any[]) {}
|
||||
}
|
||||
class C3 {
|
||||
m(@d x, @e ...rest) {}
|
||||
}
|
||||
class C4 {
|
||||
async rest(@(await p) ...args: unknown[]) {}
|
||||
}
|
||||
class C5 {
|
||||
m(@d @e ...args) {}
|
||||
}
|
||||
class C6 {
|
||||
constructor(
|
||||
@Inject(VERY_LONG_TOKEN_NAME_FOR_DEPENDENCY_INJECTION)
|
||||
private readonly a: A,
|
||||
@Inject(ANOTHER_VERY_LONG_TOKEN_NAME) ...rest: unknown[]
|
||||
) {}
|
||||
}
|
||||
class C7 {
|
||||
m(
|
||||
@d
|
||||
...args
|
||||
) {}
|
||||
}
|
||||
// Comments around the decorator keep their place
|
||||
class C8 {
|
||||
m(@d /* c */ ...args) {}
|
||||
}
|
||||
class C9 {
|
||||
m(
|
||||
@d // c
|
||||
...args
|
||||
) {}
|
||||
}
|
||||
class C10 {
|
||||
m(
|
||||
@d ...args // c
|
||||
) {}
|
||||
}
|
||||
|
||||
-------------------
|
||||
{ printWidth: 100 }
|
||||
-------------------
|
||||
// Decorators on a rest parameter are printed like those on other parameters
|
||||
class C {
|
||||
m(@d ...args: unknown[]) {}
|
||||
}
|
||||
class C2 {
|
||||
constructor(@Inject(TOKEN) ...deps: any[]) {}
|
||||
}
|
||||
class C3 {
|
||||
m(@d x, @e ...rest) {}
|
||||
}
|
||||
class C4 {
|
||||
async rest(@(await p) ...args: unknown[]) {}
|
||||
}
|
||||
class C5 {
|
||||
m(@d @e ...args) {}
|
||||
}
|
||||
class C6 {
|
||||
constructor(
|
||||
@Inject(VERY_LONG_TOKEN_NAME_FOR_DEPENDENCY_INJECTION) private readonly a: A,
|
||||
@Inject(ANOTHER_VERY_LONG_TOKEN_NAME) ...rest: unknown[]
|
||||
) {}
|
||||
}
|
||||
class C7 {
|
||||
m(
|
||||
@d
|
||||
...args
|
||||
) {}
|
||||
}
|
||||
// Comments around the decorator keep their place
|
||||
class C8 {
|
||||
m(@d /* c */ ...args) {}
|
||||
}
|
||||
class C9 {
|
||||
m(
|
||||
@d // c
|
||||
...args
|
||||
) {}
|
||||
}
|
||||
class C10 {
|
||||
m(
|
||||
@d ...args // c
|
||||
) {}
|
||||
}
|
||||
|
||||
===================== End =====================
|
||||
Reference in new issue
Block a user