-
Notifications
You must be signed in to change notification settings - Fork 666
feat(rome_analyze): add a fix argument to rome check
command CLI and LSP
#2615
Conversation
Deploying with Cloudflare Pages
|
root: JsAnyRoot::unwrap_cast( | ||
root.into_syntax() | ||
.replace_child(prev_parent.into(), next_parent.into())?, | ||
), | ||
}) | ||
} |
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.
Would be possible to write some unit tests for each rule? Sometimes is not clear what the rule is flagging or doing.
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.
There are snapshots tests for each rules under crates/rome_analyze/tests/specs
. I went with snapshots since it captures the diagnostic or code action diff in a readable form close to what the end user will actually see on the CLI, rather than running individual asserts on things like the syntax tree resulting from a refactor since I found it to be easily unclear.
@@ -17,7 +19,7 @@ pub use crate::signals::{AnalyzerAction, AnalyzerSignal}; | |||
|
|||
/// Allows filtering the list of rules that will be executed in a run of the analyzer, | |||
/// and at what source code range signals (diagnostics or actions) may be raised | |||
#[derive(Default)] | |||
#[derive(Default, Clone, Copy)] |
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.
Why does it need to be Copy
? It means we cannot filter using a string, like "filter by name".
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.
It is currently possible to filter rules by name (that's used for the snapshot tests to enable only the rule being tested for instance), but since the name of each rules are statically known they can be represented with &'static str
string slices that implement Copy
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.
Sorry to interject your PR but I am a little confused about where we are headed with the commands.
I would like to understand the requirements first (is there been a discussion?). Could you please create an issue or a discussion first?
The reason why I am concerned is because I don't have any idea of how the final commands will look like. I don't know if this will be final design, or temporary design because of how things are (with a plan to reach the final design).
In Rome classic we had:
rome ci
, in line with the rewriterome format
, in line with the rewriterome check
, not in line with the rewrite. The former command applied linting and formatting.--apply
was the argument to have safe fixed and formatting applied. Like--write
in the currentrome format --write
We now adding a rome fix
command, which is "different" from the most popular tools I am aware about. For example, eslint
uses the --fix
argument, not a command. Classic rome
had the --apply
argument. Should we follow the same trend?
/// This should eventually get replaced with the `!` type when it gets stabilized | ||
pub enum Never {} | ||
|
||
/// Type alias of [ops::ControlFlow] with the `B` generic type defaulting to [Never] |
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.
Why do we default to Never
?. It might make sense to explain it in the doc
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.
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.
By default the analysis loop never breaks, so it behaves mostly like let b = loop {};
and has a "break type" of !
(the !
type isn't stable yet so I'm using an empty enum instead but they're identical for this purpose)
In practice it's not really a loop
but a for
because it's iterating on all nodes in the syntax tree, so when it reaches the end of the iterator the loop will exit but without producing a value of type B
: for this reason the analyze
function returns an Option<B>
that's set to Some(B)
if the callback did break, and None
if the analysis reached the end of the file.
Most consumers of the analyzer will want to analyze the entire file at once and never break, so using Never
as the type of B
in this case lets the compiler know the ControlFlow::Break
branch will never be taken and can be optimized out, as well as completely remove the return Some
case (Option<Never>
has a size of 0 and can be elided, while Option<()>
has a size of 1 as it still need to store a discriminant)
crates/rome_analyze/src/lib.rs
Outdated
file_id: FileId, | ||
root: &JsAnyRoot, | ||
filter: AnalysisFilter, | ||
mut callback: impl FnMut(&dyn AnalyzerSignal) -> ControlFlow<B>, |
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 we move the first three arguments into a struct
? (I presume it's not possible to have the callback
inside the struct)
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.
Most of the arguments for the analysis have already been pushed into the AnalysisFilter
struct, and I don't expect to add many more arguments to the analyze
function at this stage except an eventual &mut self
to let the analyzer keep some state / cache between runs, along some global-level settings
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.
It may make sense to define a type alias for the Callback
type and copy some of the explanations you gave in the other comments into its documentation so that future me will know what I need to return in the control flow.
crates/rome_cli/src/commands/fix.rs
Outdated
CliSession, Termination, | ||
}; | ||
|
||
/// Handler for the "fix" command of the Rome CLI |
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.
Why the fix
is a command and not an argument of check
command?
In rome classic we called it --apply
and it was an argument of the command rome check
. That's because check
wasn't just about "fixing" the code, but also apply formatting.
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.
Having two different commands was mostly because the check and fix commands had mostly different backing implementations, but I could as well change it to have the fix behavior be implemented by the check
command with an --apply
flag instead to be consistent with how the CLI worked in Rome JS
crates/rome_analyze/src/lib.rs
Outdated
file_id: FileId, | ||
root: &JsAnyRoot, | ||
filter: AnalysisFilter, | ||
mut callback: impl FnMut(&dyn AnalyzerSignal) -> ControlFlow<B>, |
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.
It may make sense to define a type alias for the Callback
type and copy some of the explanations you gave in the other comments into its documentation so that future me will know what I need to return in the control flow.
crates/rome_analyze/src/registry.rs
Outdated
&self, | ||
file_id: FileId, | ||
root: &JsAnyRoot, | ||
node: JsSyntaxNode, | ||
callback: &mut impl FnMut(&dyn AnalyzerSignal), | ||
) { | ||
callback: &mut impl FnMut(&dyn AnalyzerSignal) -> ControlFlow<B>, |
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.
Nit: Use the type alias here too?
crates/rome_analyze/src/registry.rs
Outdated
&self, | ||
file_id: FileId, | ||
root: &JsAnyRoot, | ||
node: JsSyntaxNode, | ||
callback: &mut impl FnMut(&dyn AnalyzerSignal), | ||
) { | ||
callback: &mut impl FnMut(&dyn AnalyzerSignal) -> ControlFlow<B>, |
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.
Nit: Use the type alias here too?
Unfortunately it's not possible to move that declaration in a type alias since |
rome check
command CLI and LSP
Maybe we should wait to merge this PR until we do the release next week? |
Parser conformance results on ubuntu-latestjs/262
jsx/babel
symbols/microsoft
ts/babel
ts/microsoft
|
Summary
This PR adds a new auto-fix workflow to the analysis toolchain, with the following changes:
analyze
entrypoint function for the analyzer now returns anstd::ops::ControlFlow
enum. This lets the callback interrupt the analysis process by returningControlFlow::Break(value)
, with the value being returned by the analyze function as anOption
Workspace
now has afix_file
method that applies all safe fixes to a given file and returns the resulting code. This is implemented by repeatedly calling intoanalyze
and breaking for each emitted action signal withApplicability::Always
to mutate the syntax tree with the code action, then restart the analysis until no more code actions are emittedcheck
command of the CLI now has an--apply
argument reusing the same traversal infrastructure, and callingfix_file
on each processed file then writing the resulting code back to the diskTextEdit
backing this action is also generated from the result offix_file
useSingleVarDeclarator
rule has been marked as "always applicable", and the implementation of the fix has been changed to support variable statements inJsModuleItemList
as well asJsStatementList
Test Plan
New tests have been added to the CLI test suite to check the
rome check --apply
command