-
Notifications
You must be signed in to change notification settings - Fork 666
refactor(rome_js_formatter): Support FormatRule
s with options
#2757
Conversation
Deploying with Cloudflare Pages
|
impl FormatRule<JsArrayElementList> for FormatJsArrayElementList { | ||
type Context = JsFormatContext; | ||
#[derive(Debug, Clone, Default)] | ||
pub struct FormatJsArrayElementList { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Format rule with custom options
let elements = format_with(|f| { | ||
FormatJsArrayElementList::format_with_group_id(&elements, f, Some(group_id)) | ||
}); | ||
let elements = elements.format().with_options(Some(group_id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usage of the new API
e704c4f
to
95d3e99
Compare
!bench_formatter |
Formatter Benchmark Results
|
This is interesting. I also noticed that the
@leops @xunilrj do you have any idea where this regression might be coming from? |
95d3e99
to
18c8f7c
Compare
!bench_formatter |
Formatter Benchmark Results
|
I noticed that you force pushed and the benchmarker is now in a decent shape. What did you change between the two benchs? |
impl FormatNodeFields<TsVoidType> for FormatNodeRule<TsVoidType> { | ||
fn fmt_fields(node: &TsVoidType, f: &mut JsFormatter) -> FormatResult<()> { | ||
#[derive(Debug, Clone, Default)] | ||
pub struct FormatTsVoidType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should everything be pub
? Isn't pub(crate)
enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used pub(crate)
first with the same motivation you just mentioned but the problem is that the types are used as associated types in AsFormat
and IntoFormat
error[E0446]: crate-private type `FormatJsScript` in public interface
--> crates/rome_js_formatter/src/generated.rs:12:5
|
12 | / type Format = FormatRefWithRule<
13 | | 'a,
14 | | rome_js_syntax::JsScript,
15 | | crate::js::auxiliary::script::FormatJsScript,
16 | | >;
| |______^ can't leak crate-private type
|
::: crates/rome_js_formatter/src/js/auxiliary/script.rs:9:1
|
9 | pub(crate) struct FormatJsScript;
| --------------------------------- `FormatJsScript` declared as crate-private
impl FormatNodeFields<JsExportDefaultExpressionClause> for FormatNodeRule<JsExportDefaultExpressionClause> { | ||
fn fmt_fields(node: &JsExportDefaultExpressionClause, f: &mut JsFormatter) -> FormatResult<()> { | ||
#[derive(Debug, Clone, Default)] | ||
pub struct FormatJsExportDefaultExpressionClause; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So now the structs are created inside the single file and in the generated.rs
we have only the implementation of the traits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's correct. The definition in the implementation file is necessary so that you can customise the rules fields without the codegen overriding it.
I added an |
Summary
To this point, it hasn't been possible to customize the formatting of a
FormatRule
. The only way to pass additional data has been by creating an additional method on the struct that takes additional parameters and call that method instead. Doing so comes with the risk that this will accidentally by-pass the node's suppression check.This PR adds a way to
FormatRule
s to be parametrized by options which can be useful to e.g. pass a group id from one rule to another. I did so byfmt
signature ofFormatRule
to takeself
by reference (so that the rule is able to access the options)FormatRuleWithOptions
trait that rules with options can implement and thatFormatOwnedWithRule
andFormatRefWithRule
automatically implement if the inner rule supports options. This makes it possible to do writeelements.format().with_options(options)
rather than usingformat_with(|f| MyFormatRule::new(options).fmt(elements, f))
FormatNodeRule
to a trait so that each rule has its own struct that can have additional optionsAlternatives
An alternative to the design I implemented in this PR is to extend
FormatContext
orFormatState
to store additional data, either as a bag of values or using static values. Storing the data on the context would have the added benefit that it becomes possible to pass data arbitrarily deep but comes at the cost that the data needs to be part of the snapshot and tracking where the data gets written and read becomes more difficult.The main reasons why I didn't go for that approach is that it isn't needed today and that the data is part of the state and needs to support snapshots, as well as nested calls. Supporting snapshots can be as straightforward as copying the data (comes at a cost) and recurring can be supported in a similar way as we support it in the parser by storing the old value on the stack and putting it back into place if the inner formatting exits.
Test Plan
cargo test
FormatJsArrayElementList
now uses the new options infrastructure.