Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Define EditorConfigOverride for dynamically loaded ruleset #2194

Merged
merged 5 commits into from
Aug 28, 2023

Conversation

paul-dingemans
Copy link
Collaborator

Description

Extend API Consumer example to showcase how EditorConfigOverride can be defined with dynamically loaded rulesets

Closes #2190

Checklist

Before submitting the PR, please check following (checks which are not relevant may be ignored):

  • Commit message are well written. In addition to a short title, the commit message also explain why a change is made.
  • At least one commit message contains a reference Closes #<xxx> or Fixes #<xxx> (replace<xxx> with issue number)
  • Tests are added
  • KtLint format has been applied on source code itself and violations are fixed
  • CHANGELOG.md is updated
  • PR description added

Documentation is updated. See difference between snapshot and release documentation

…be defined with dynamically loaded rulesets

Closes #2190
@paul-dingemans
Copy link
Collaborator Author

The EditorConfigOverride is defined as:

    val editorConfigOverride =
        EditorConfigOverride
            .from(
                // Property types provided by ktlint-rule-engine-core
                INDENT_STYLE_PROPERTY to 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
            ).plus(
                // 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",
                // In case an unknown property would be provided, an exception is thrown by the helper method
                // ruleProviders.findEditorConfigProperty("unknown_property") to "some-value",
            )

The helper method ruleProviders.findEditorConfigProperty(...) is defined in the ApiConsumer as:

private fun Set<RuleProvider>.findEditorConfigProperty(propertyName: String): EditorConfigProperty<*> {
    val properties =
        map { it.createNewRuleInstance() }
            .flatMap { it.usesEditorConfigProperties }
            .distinct()
    return properties
        .find { it.type.name == propertyName }
        ?: throw EditorConfigPropertyNotFoundException(
            properties
                .map { it.type.name }
                .sorted()
                .joinToString(
                    prefix = "Property with name '$propertyName' is not found in any of given rules. Available properties:\n\t",
                    separator = "\n\t",
                ) { "- $it" },
        )
}

When running the main method in the KtlintApiConsumer the following is logged.

Both the statically typed properties as well as the property from a dynamically loaded ruleset are recognized by ktlint:

[main] DEBUG com.pinterest.ktlint.rule.engine.internal.EditorConfigLoader - Effective editorconfig properties for file 'ktlint-api-consumer/src/main/kotlin/com/example/ktlint/api/consumer/KtlintApiConsumer.kt':
	tab_width: 4
	indent_style: SPACE
	indent_size: 4
	ktlint_experimental: enabled
	ktlint_function_signature_body_expression_wrapping: alwaysx

The invalid value for the property of a dynamically loaded ruleset is reported in same way as for static properties:

[main] WARN com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfig - Editorconfig property 'ktlint_function_signature_body_expression_wrapping' contains an invalid value 'alwaysx'. The default value 'default' is used instead.

@paul-dingemans
Copy link
Collaborator Author

New API EditorConfigPropertyRegistry is added. It can be used as follows to initialized the EditorConfigOverride in case rule sets are available at runtime only:

    val editorConfigPropertyRegistry = EditorConfigPropertyRegistry(ruleProviders)

    // Providing rule dependencies at compile time has the advantage that properties defined in those rules can be used to build the
    // EditorConfigOverride using static types. However, providing the rule dependencies at runtime can offer flexibility to the API
    // Consumer. It comes with the cost that the EditorConfigOverride can not be build with static types.
    val editorConfigOverride =
        EditorConfigOverride
            .from(
                // Properties provided by ktlint-rule-engine-core are best to be loaded statically as they are available at compile time as
                // they are provided by the ktlint-rule-engine-core module.
                INDENT_STYLE_PROPERTY to IndentConfig.IndentStyle.SPACE,
                INDENT_SIZE_PROPERTY to 4,
                EXPERIMENTAL_RULES_EXECUTION_PROPERTY to RuleExecution.enabled,
                //
                // Properties defined in the ktlint-ruleset-standard can only be loaded statically when that dependency is provided at
                // compile time. In this example project this ruleset is loaded at runtime, so following decommenting next line results in
                // a compilation error:
                // 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. As the property is not available at compile time, the value has to be
                // specified as a String (exactly as would be done in the `.editorconfig` file).
                // In case the property value is invalid, the KtlintRuleEngine logs a warning.
                editorConfigPropertyRegistry.find("ktlint_function_signature_body_expression_wrapping") to "always",
                //
                // The properties for enabling/disabling a rule or entire rule set can be set as well. Note that the values of this
                // property can be set via the `RuleExecution` enum which is available at compile time as it is provided by the
                // ktlint-rule-engine-core module.
                editorConfigPropertyRegistry.find("ktlint_standard_function-signature") to RuleExecution.disabled,
                editorConfigPropertyRegistry.find("ktlint_standard") to RuleExecution.disabled,
                //
                // In case an unknown property is provided, an exception is thrown:
                // ruleProviders.findEditorConfigProperty("unknown_property") to "some-value",
            )

@paul-dingemans paul-dingemans merged commit 9e0aadf into master Aug 28, 2023
@paul-dingemans paul-dingemans deleted the 2190-editorconfigoverride branch August 28, 2023 18:47
wakingrufus added a commit to JLLeitschuh/ktlint-gradle that referenced this pull request Sep 14, 2023
Allow editorconfig overrides in ktlint 0.49+ (fixes #707) using pinterest/ktlint#2194
wakingrufus added a commit to JLLeitschuh/ktlint-gradle that referenced this pull request Sep 14, 2023
Allow editorconfig overrides in ktlint 0.49+ (fixes #707) using pinterest/ktlint#2194
wakingrufus added a commit to JLLeitschuh/ktlint-gradle that referenced this pull request Sep 14, 2023
Allow editorconfig overrides in ktlint 0.49+ (fixes #707) using pinterest/ktlint#2194
wakingrufus added a commit to JLLeitschuh/ktlint-gradle that referenced this pull request Sep 18, 2023
Allow editorconfig overrides in ktlint 0.49+ (fixes #707) using pinterest/ktlint#2194
wakingrufus added a commit to JLLeitschuh/ktlint-gradle that referenced this pull request Sep 18, 2023
Allow editorconfig overrides in ktlint 0.49+ (fixes #707) using pinterest/ktlint#2194
wakingrufus added a commit to JLLeitschuh/ktlint-gradle that referenced this pull request Sep 18, 2023
Allow editorconfig overrides in ktlint 0.49+ (fixes #707) using pinterest/ktlint#2194
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide EditorConfigOverride API which can be defined at runtime
1 participant