I’ve been using the JLLeitschuh/ktlint-gradle Grad...
# ktlint
c
I’ve been using the JLLeitschuh/ktlint-gradle Gradle plugin and have been ignoring the
disabledRules
and
additionalEditorconfigFile
deprecation for a while now, but I’m trying to get it fixed. However, it’s not clear to me what the replacement is supposed to be. I’m trying to configure Ktlint in an included build so I don’t have to redefine the disabled rules in each project’s default
.editorconfig
v
c
That’s incredibly disappointing. I really hate the idea of having to add so much extra boilerplate to each project. I’m using an included build specifically to avoid doing that. Can custom rulesets or other extension allow me to disable rules globally? Sure there must be some mechanism available to globally disable rules, considering there’s apparently a CLI flag for it
p
See ktlint documentation for use of
editorConfigOverride
. Consulting the changelog files would have been an other good option to discover how to migrate whenever functionality is removed.
w
I would like to expose editorConfigOverride via the plugin, but the API uses classes/objects defined in ktlint as well as rule sets, which are not on the buildscript classpath, so I am not sure how to approach it
as a workaround, you could have your included build / plugin append the excluded rule lines to the .editorconfig file I suppose
p
I would like to expose editorConfigOverride via the plugin, but the API uses classes/objects defined in ktlint as well as rule sets, which are not on the buildscript classpath, so I am not sure how to approach it
I am happy to investigate whether ktlint can support this case. But for that, I need more clarity about the problem so that we can think of a possible future. It would be great to start with an example project that demonstrates the problem.
w
TBH, i'm not sure a sample project will really show the issue. what it comes down to is
EditorConfigOverride.from
accepts
EditorConfigProperty
in its API. that class comes from ktlint-rule-engine-core, but instances of that class are defined in various rule set libraries. ktlint-gradle has classpath separation between the gradle configuration (where you configure ktlint-gradle) and the task worker (which actually executes ktlint). we don'tput any ktlint dependencies on the buildscript classpath. this is how we able to provide compatibility with multiple versions of ktlint
p
Ok, I see.
EditorConfigOverride.from
enforces compile time that the EditorConfigOverride is configured with valid
EditorConfigProperty
. This is very convenient from ktlint perspective. For this use case you would like to have an API like
from(vararg properties: Pair<String, String>): EditorConfigOverride
. Most likely it is possible to match the keys of this map with the properties that are used by the rules that are provided to the
KtlintRuleEngine
. Properties which can not be matched with a property can be ignored silently (but with a log warning). Properties which can be matched but have an invalid value according to the
EditorConfigProperty
definition will throw an exception before files are processed. I you think this will resolve the problem, I can give it a try.
w
yeah, I think that would work perfectly from our end
p
It turns out that it is not needed to provide a new API. In https://github.com/pinterest/ktlint/pull/2194 I have extended the example ktlint-api-consumer to proof that the
EditorConfigOverride
can be defined for properties that are provided via rulesets that are loaded dynamically. Do you still think that this should be provided by ktlint? I have the feeling that this more specific to
ktlint-gradle
due to dynamic loading of rulesets.
w
ooo this looks good.
do you know of an easy way to read an editorconfig file into a Map?
b/c if i can do that, I can make this work with the exisitng plugin configuration of additionalEditorconfigFile
but I at least can allow the Map to be build on the ktlint extension itself
p
There is no ‘easy’ way of reading the
.editorconfig
file. Ktlint contains quite some logic for this and it is kept internal for reasons. There should also be no need for an API consumer to read that
.editorconfig
in order to call
KtlintRuleEngine
as the rule engine will read it for you. You have two ways to influence the
.editorconfig
without reading/parsing it yourself. • `editorConfigDefaults`: This contains the default values for
.editorconfig
properties which are not set explicitly in any ‘.editorconfig’ file located on the path of the file which is processed with the
KtLintRuleEngine
. If a property is set in
editorConfigDefaults
this takes precedence above the default values defined in definition of the
EditorConfigProperty
. • `editorConfigOverride`: Override values for
.editorconfig
properties. If a property is set in
editorConfigOverride
it takes precedence above the same property being set in any other way. Please clarify what reason you would have to read/parse
.editorconfig
if above does not suffice.
w
the plugin used to have a config for pointing to a different file location for editorconfig. I was thinking I could still support that, but instead of passing it into ktlint, parse out the properties and pass them in as overrides
its not a feature I use, but for the sake of backward compatibility, it would be nice
but its NBD if not
i am adding a new config to set a Map<String, String> for overrides to pass in
i tried this, passing in
Copy code
"ktlint_standard_no-multi-spaces", "disabled"
and using that code in the sample, but it didnt work. I got
Copy code
Property with name 'ktlint_standard_no-multi-spaces' is not found in any of given rules. Available properties:
     	- ij_kotlin_allow_trailing_comma
     	- ij_kotlin_allow_trailing_comma_on_call_site
     	- ij_kotlin_imports_layout
     	- ij_kotlin_packages_to_use_import_on_demand
     	- indent_size
     	- indent_style
     	- insert_final_newline
     	- ktlint_code_style
     	- ktlint_function_signature_body_expression_wrapping
     	- ktlint_function_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than
     	- ktlint_ignore_back_ticked_identifier
     	- max_line_length
does that imply the standard ruleset is missing from the classpath?
no i dont think so. it is on the classpath
i think its a problem with the standard rules? they have an empty
usesEditorConfigProperties
but shouldnt they have
"ktlint_${RuleSetId.STANDARD.value}_$id"
in that Set?
p
The rule execution property which is used for enabling/disabling rules is a special property type which does not need to be defined in the rule. As of that, it is not found by the helper-function. I will have to check how we can make that work. For testing purposes, you can use the properties mentioned in logging above.
w
ktlint-gradle has config for disabled rules and overriding editor config, both of which could now be covered by this feature, but disabling rules is by far the more popular one. so i'd want to work out the path forward for making that work before continuing on with this, otherwise it will cause confusion and ill be answering 100 github issues on it 😕
p
Ow, I just meant for next couple of days. It won’t be something that I can not fix easily. Just need a couple of hours for it.
w
Ok sounds good. Thanks! I wasn't trying to be aggressive, I just meant that I'd rather wait for that fix, I'll pause my work on this for now. Thanks again!
p
No worries. I didn't take it as aggressive. Next to that you're also actually working on making stuff better.
It turns out that
ktlint-rule-engine-core
already has some extension functions that you can use to enable/disable rules and rule sets.
Copy code
EditorConfigOverride
            .from(
                // Property types provided by ktlint-rule-engine-core
                INDENT_STYLE_PROPERTY to <http://IndentConfig.IndentStyle.SPACE|IndentConfig.IndentStyle.SPACE>,
                INDENT_SIZE_PROPERTY to 4,
                EXPERIMENTAL_RULES_EXECUTION_PROPERTY to RuleExecution.enabled,
                // Properties defines in the ktlint-ruleset-standard can only be used statically when that dependency is provided at compile
                // time.
                // FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY to always
                // For properties that are defined in rules for which the dependency is provided at runtime only, the property name can be
                // provided as String and the value as Any type. In case the property value is invalid, the KtlintRuleEngine logs a warning.
                ruleProviders.findEditorConfigProperty("ktlint_function_signature_body_expression_wrapping") to "alwaysx",
                RuleId("standard:function-signature").createRuleExecutionEditorConfigProperty() to RuleExecution.disabled,
                RuleSetId("some-custom-ruleset").createRuleSetExecutionEditorConfigProperty() to RuleExecution.enabled,
                // In case an unknown property would be provided, an exception is thrown by the helper method
                // ruleProviders.findEditorConfigProperty("unknown_property") to "some-value",
            )
I am not yet very satisfied with the different ways how to derive the editor config property in example above. I have an idea about the new API that I want to offer for that. Basically it would boil down to:
Copy code
val editorConfigPropertyRegistry = EditorConfigPropertyRegistry(ruleProviders)

    val editorConfigOverride =
        EditorConfigOverride
            .from(
                // Property types provided by ktlint-rule-engine-core
                INDENT_STYLE_PROPERTY to <http://IndentConfig.IndentStyle.SPACE|IndentConfig.IndentStyle.SPACE>,
                INDENT_SIZE_PROPERTY to 4,
                EXPERIMENTAL_RULES_EXECUTION_PROPERTY to RuleExecution.enabled,
                // Properties defines in the ktlint-ruleset-standard can only be used statically when that dependency is provided at compile
                // time.
                // FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY to always
                // For properties that are defined in rules for which the dependency is provided at runtime only, the property name can be
                // provided as String and the value as Any type. In case the property value is invalid, the KtlintRuleEngine logs a warning.
                editorConfigPropertyRegistry.find("ktlint_function_signature_body_expression_wrapping") to "alwaysx",
                editorConfigPropertyRegistry.find("ktlint_standard_function-signature") to RuleExecution.disabled,
                editorConfigPropertyRegistry.find("ktlint_some-custom-ruleset") to RuleExecution.enabled,
                // In case an unknown property would be provided, an exception is thrown by the helper method
                // ruleProviders.findEditorConfigProperty("unknown_property") to "some-value",
            )
I think that I will be able to finish it tomorrow.
w
ooo, that looks nice
p
I am glad you like it. The change is merged. You can test it using the ktlint snapshot build.
w
Thanks! 👀
p
@wakingrufus Were you able to confirm with the snapshot build that this approach works and solves the issue?
w
Sorry, I did not get a chance. Things have been hectic for me. I see that 1.0 is out! nice work! Ill start working this as soon as I can, but it probably won't be until late next week
p
No worries. As you noticed, I did not wait for a reply with the release.
w
ok I finally got everything working with 1.0, except is still get an error like
Copy code
> Property with name 'ktlint_standard_no-multi-spaces' is not found in any of given rules. Available properties:
     	- ij_kotlin_allow_trailing_comma
     	- ij_kotlin_allow_trailing_comma_on_call_site
     	- ij_kotlin_imports_layout
     	- ij_kotlin_packages_to_use_import_on_demand
     	- indent_size
     	- indent_style
     	- insert_final_newline
     	- ktlint_chain_method_rule_force_multiline_when_chain_operator_count_greater_or_equal_than
     	- ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than
     	- ktlint_code_style
     	- ktlint_function_signature_body_expression_wrapping
     	- ktlint_function_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than
     	- ktlint_ignore_back_ticked_identifier
     	- max_line_length
my code looks like
Copy code
KtLintRuleEngine(
                    ruleProviders = ruleProviders,
                    editorConfigOverride = EditorConfigOverride.from(*editorConfigOverrides
                        .mapKeys { editorConfigPropertyRegistry.find(it.key) }
                        .entries
                        .map { it.key to it.value }
                        .toTypedArray())
                )
oh wait nvm
it was a bug on my end
it works
p
Ah cool. I was staring at the code and could spot a problem yet.
w
i am now trying to find a rule that is not loaded at runtime that i can test to see if it will work in 0.49 and 0.50
ij_kotlin_allow_trailing_comma doesnt seem to have an effect
maybe max_line_length ?
310 Views