You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I want to create custom rule (to indent the content of multiline raw string literals) that only should be executed after the 'indent' rule has been executed. Reason for this is that I do no want to add logic to my custom rule for which the indentation rule is responsible.
KtLint currently offers the Rule.Modifier below:
Modifier {
/**
* Any rule implementing this interface will be given root ([FileASTNode]) node only
* (in other words, [visit] will be called on [FileASTNode] but not on [FileASTNode] children).
*/
interface RestrictToRoot
/**
* Marker interface to indicate that rule must be executed after all other rules (order among multiple
* [RestrictToRootLast] rules is not defined and should be assumed to be random).
*
* Note that [RestrictToRootLast] implements [RestrictToRoot].
*/
interface RestrictToRootLast : RestrictToRoot
interface Last
}
I could create my custom rule without this PR. Due to the current implementation of KtLint this rule would always be run after the standard indent rule. I consider this however to be a bad approach because my rule would not work correctly if the KtLint implementation would change the order in which the rule sets are loaded.
Also internally in KtLint standard rules, it could be beneficial if rule can depend on other rules being executed before. For example the current indentation rule could be split into two distinct rules. A new rule could be created to rearrange the nodes (i.e. insert new lines when needed) while the current indentation rule would only change the indentation of line. For this it needs to be guaranteed that the rearrange rule is executed before the indentation rule.
Currently, each rule in KtLint extends the abstract class Rule and optionally implements a marker interface like shown below:
// Current situation: it is not possible to specify that rule1 has to be executed after the 'indent' rule.
class Rule1 :
Rule("rule-1"),
Rule.Modifier.RestrictToRootLast {
// implementation omitted for brevity
}
It is not possible to pass down information via the Rule.Modifier interfaces. Neither can those interfaces be changed to a normal class as it would result in multiple parent classes for the rule. It is possible to add an additional parameter in the Rule class to pass down some information. This has some disadvantages though:
It violates the Single Responsibility Principle because a Rule should not have any knowledge about the order in which rules are executed.
From a maintainability perspective it is difficult to design the structure of this parameter with respect to future wishes regarding rule order execution.
A better approach would be to use annotations on a rule class to define the rule order execution rules. This approach is based on the way that the order of AutoConfiguration classes in Spring Boot can optionally be altered using annotations. In example below, two annotations are used for this. The @RestrictToRootLast has the same meaning as the Rule.Modifier.RestrictToRootLast interface. The @RunAfterRule annotation defines that 'rule-3' should run after the 'standard:indent' rule has been executed. The annotations will be parsed whenever the visitor for a file is being created.
@RunAfterRule(ruleId = "standard:indent")
@RestrictToRootLast
class Rule: Rule("rule-3") {
// implementation omitted for brevity
}
I have implemented the @RunAfterRule in a Proof Of Concept and verified that when the visitor is created in class KtLint, that I am able to check whether my rule class is annotated with @RunAfterRule and what the specific ruleId is that is specified in the annotation. So it is possible to change the ordering of the rules based on the annotations. More work is needed to verify that the rule being referred to does exist and no cycles in the rules have been created.
@romtsn@shashachu@Tapchicoma Would you please let me know whether you are willing to support something like this in KtLint? I am open to answer questions or discuss any concerns regarding this enhancement. Also I can file a PR with the current POC if that is helpful.
The text was updated successfully, but these errors were encountered:
Also internally in KtLint standard rules, it could be beneficial if rule can depend on other rules being executed before.
In the ktlint rule sets currently three rules exist which implement the Rule.Modifier.Last interface directly or indirectly:
The standard IndentationRule implementing Rule.Modifier.RestrictToRootLast
The standard MaxLineLengthRule implementing Rule.Modifier.Last
The indentation rule is run before the two other rules because it implements Rule.Modifier.RestrictToRootLast instead of Rule.Modifier.Last. According to a comment in the MaxLineLengthRule it should run after all other rules. This however is not true because the standard rules which implement Rule.Modifier.Last are executed before the experimental rules implementing that same interface.
When developers are using custom rule sets in which the interfaces Rule.Modifier.RestrictToRootLast and Rule.Modifier.Last the results become even more unpredictable.
I want to create custom rule (to indent the content of multiline raw string literals) that only should be executed after the 'indent' rule has been executed. Reason for this is that I do no want to add logic to my custom rule for which the indentation rule is responsible.
KtLint currently offers the Rule.Modifier below:
I could create my custom rule without this PR. Due to the current implementation of KtLint this rule would always be run after the standard indent rule. I consider this however to be a bad approach because my rule would not work correctly if the KtLint implementation would change the order in which the rule sets are loaded.
Also internally in KtLint standard rules, it could be beneficial if rule can depend on other rules being executed before. For example the current indentation rule could be split into two distinct rules. A new rule could be created to rearrange the nodes (i.e. insert new lines when needed) while the current indentation rule would only change the indentation of line. For this it needs to be guaranteed that the rearrange rule is executed before the indentation rule.
Currently, each rule in KtLint extends the abstract class Rule and optionally implements a marker interface like shown below:
It is not possible to pass down information via the Rule.Modifier interfaces. Neither can those interfaces be changed to a normal class as it would result in multiple parent classes for the rule. It is possible to add an additional parameter in the Rule class to pass down some information. This has some disadvantages though:
A better approach would be to use annotations on a rule class to define the rule order execution rules. This approach is based on the way that the order of AutoConfiguration classes in Spring Boot can optionally be altered using annotations. In example below, two annotations are used for this. The
@RestrictToRootLast
has the same meaning as the Rule.Modifier.RestrictToRootLast interface. The@RunAfterRule
annotation defines that 'rule-3' should run after the 'standard:indent' rule has been executed. The annotations will be parsed whenever the visitor for a file is being created.I have implemented the
@RunAfterRule
in a Proof Of Concept and verified that when the visitor is created in class KtLint, that I am able to check whether my rule class is annotated with@RunAfterRule
and what the specific ruleId is that is specified in the annotation. So it is possible to change the ordering of the rules based on the annotations. More work is needed to verify that the rule being referred to does exist and no cycles in the rules have been created.@romtsn @shashachu @Tapchicoma Would you please let me know whether you are willing to support something like this in KtLint? I am open to answer questions or discuss any concerns regarding this enhancement. Also I can file a PR with the current POC if that is helpful.
The text was updated successfully, but these errors were encountered: