diff --git a/documentation/release-latest/docs/api/custom-integration.md b/documentation/release-latest/docs/api/custom-integration.md index 51049a1578..668e35f5fa 100644 --- a/documentation/release-latest/docs/api/custom-integration.md +++ b/documentation/release-latest/docs/api/custom-integration.md @@ -4,26 +4,26 @@ The `Ktlint Rule Engine` is the central entry point for custom integrations with the `Ktlint API`. See [basic API Consumer](https://github.com/pinterest/ktlint/blob/master/ktlint-api-consumer/src/main/kotlin/com/example/ktlint/api/consumer/KtlintApiConsumer.kt) for a basic example on how to invoke the `Ktlint Rule Engine`. This example also explains how the logging of the `Ktlint Rule Engine` can be configured to your needs. -The `KtLintRuleEngine` instance only needs to be created once for the entire lifetime of your application. Reusing the same instance results in better performance due to caching. +The `KtLintRuleEngine` instance only needs to be created once for the entire lifetime of your application. Reusing the same instance results in better performance due to caching. ```kotlin title="Creating the KtLintRuleEngine" val ktLintRuleEngine = - KtLintRuleEngine( - ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, - ) + KtLintRuleEngine( + ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, + ) ``` ### Rule provider -The `KtLintRuleEngine` must be configured with at least one `RuleProvider`. A `RuleProvider` is a lambda which upon request of the `KtLintRuleEngine` provides a new instance of a specific rule. You can either provide any of the standard rules provided by KtLint or with your own custom rules, or with a combination of both. +The `KtLintRuleEngine` must be configured with at least one `RuleProvider`. A `RuleProvider` is a lambda which upon request of the `KtLintRuleEngine` provides a new instance of a specific rule. You can either provide any of the standard rules provided by KtLint, or your own custom rules, or a combination of both. ```kotlin title="Creating a set of RuleProviders" val KTLINT_API_CONSUMER_RULE_PROVIDERS = - setOf( - // Can provide custom rules - RuleProvider { NoVarRule() }, - // but also reuse rules from KtLint rulesets - RuleProvider { IndentationRule() }, - ) + setOf( + // Can provide custom rules + RuleProvider { NoVarRule() }, + // but also reuse rules from KtLint rulesets + RuleProvider { IndentationRule() }, + ) ``` ### Editor config: defaults & overrides @@ -32,29 +32,29 @@ When linting and formatting files, the `KtlintRuleEngine` takes the `.editorconf ```kotlin title="Specifying the editorConfigOverride" val ktLintRuleEngine = - KtLintRuleEngine( - ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, - editorConfigOverride = EditorConfigOverride.from( - INDENT_STYLE_PROPERTY to IndentConfig.IndentStyle.SPACE, - INDENT_SIZE_PROPERTY to 4 - ) + KtLintRuleEngine( + ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, + editorConfigOverride = EditorConfigOverride.from( + INDENT_STYLE_PROPERTY to IndentConfig.IndentStyle.SPACE, + INDENT_SIZE_PROPERTY to 4 ) + ) ``` The `editorConfigOverride` property takes an `EditorConfigProperty` as key. KtLint defines several such properties, but they can also be defined as part of a custom rule. The `editorConfigDefaults` property is more cumbersome to define as it is based directly on the data format of the `ec4j` library which is used for parsing the `.editorconfig` file. -The defaults can be loaded from a path or a directory. If a path to a file is specified, the name of the file does not necessarily have to end with `.editorconfig`. If a path to a directory is specified, the directory should contain a file with name `.editorconfig`. Note that the `propertyTypes` have to be derived from the same collection of rule providers that are specified in the `ruleProviders` property of the `KtLintRuleEngine`. +The defaults can be loaded from a path or a directory. If a path to a file is specified, the name of the file does not necessarily have to end with `.editorconfig`. If a path to a directory is specified, the directory should contain a file with name `.editorconfig`. Note that the `propertyTypes` have to be derived from the same collection of rule providers that are specified in the `ruleProviders` property of the `KtLintRuleEngine`. ```kotlin title="Specifying the editorConfigDefaults using an '.editorconfig' file" val ktLintRuleEngine = - KtLintRuleEngine( - ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, - editorConfigDefaults = EditorConfigDefaults.load( - path = Paths.get("/some/path/to/editorconfig/file/or/directory"), - propertyTypes = KTLINT_API_CONSUMER_RULE_PROVIDERS.propertyTypes(), - ) + KtLintRuleEngine( + ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, + editorConfigDefaults = EditorConfigDefaults.load( + path = Paths.get("/some/path/to/editorconfig/file/or/directory"), + propertyTypes = KTLINT_API_CONSUMER_RULE_PROVIDERS.propertyTypes(), + ) ) ``` If you want to include all RuleProviders of the Ktlint project than you can easily retrieve the collection using `StandardRuleSetProvider().getRuleProviders()`. @@ -63,20 +63,20 @@ The `EditorConfigDefaults` property can also be specified programmatically as is ```kotlin title="Specifying the editorConfigDefaults programmatically" val ktLintRuleEngine = - KtLintRuleEngine( - ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, - editorConfigDefaults = EditorConfigDefaults( - org.ec4j.core.model.EditorConfig - .builder() - // .. add relevant properties - .build() - ) + KtLintRuleEngine( + ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, + editorConfigDefaults = EditorConfigDefaults( + org.ec4j.core.model.EditorConfig + .builder() + // .. add relevant properties + .build() ) + ) ``` ### Lint & format -Once the `KtLintRuleEngine` has been defined, it is ready to be invoked for each file or code snippet that has to be linted or formatted. The the `lint` and `format` functions take a `Code` instance as parameter. Such an instance can either be created from a file +Once the `KtLintRuleEngine` has been defined, it is ready to be invoked for code that has to be linted or formatted. The `lint` and `format` functions take a `Code` instance as parameter. Such an instance can either be created from a file ```kotlin title="Code from file" val code = Code.fromFile( File("/some/path/to/file") @@ -91,23 +91,107 @@ val code = Code.fromSnippet( ) ``` -The `lint` function is invoked with a lambda which is called each time a `LintError` is found and does not return a result. -```kotlin title="Specifying the editorConfigDefaults programmatically" +The `lint` function is invoked with an optional lambda. Once linting is complete, the lambda will be called for each `LintError` which is found. +```kotlin title="Invoking lint" ktLintRuleEngine - .lint(codeFile) { lintError -> - // handle - } + .lint(code) { lintError -> + // handle + } ``` -The `format` function is invoked with a lambda which is called each time a `LintError` is found and returns the formatted code as result. Note that the `LintError` should be inspected for errors that could not be autocorrected. -```kotlin title="Specifying the editorConfigDefaults programmatically" +The `format` function is invoked with a lambda. The lambda is called for each `LintError` which is found. If the `LintError` can be autocorrected, the return value of the lambda instructs the rule whether this specific `LintError` is to be autocorrected, or not. If the `LintError` can not be autocorrected, the return result of the lambda is ignored. The formatted code is returned as result of the function. + +The new `format` function allows the API Consumer to decide which LintError is to be autocorrected, or not. This is most interesting for API Consumers that let their user interactively decide per `LintError` how it has to be handled. For example see the `ktlint-intellij-plugin` which in 'manual' mode displays all lint violations, which allows the user to decide which `LintError` is to be autocorrected. + +!!! note + The difference with the legacy version of the `format` is subtle. It takes two parameters (a `LintError` and `Boolean` denoting whether the `LintError` is corrected), and it does not return a value. + +```kotlin title="Invoke format (preferred, starting from Ktlint 1.3)" +val formattedCode = + ktLintRuleEngine + .format(code) { lintError -> + if (lintError.canBeAutoCorrected) { + // Return AutocorrectDecision.ALLOW_AUTOCORRECT to execute the autocorrect of this lintError if this is supported by the rule. + // Return AutocorrectDecision.NO_AUTOCORRECT if the LintError should not be corrected even if is supported by the rule. + } else { + // In case the LintError can not be autocorrected, the return value of the lambda will be ignored. + // For clarity reasons it is advised to return AutocorrectDecision.NO_AUTOCORRECT in case the LintError can not be autocorrected. + AutocorrectDecision.NO_AUTOCORRECT + } + } +``` + +!!! warning + Rules need to implement the interface `RuleAutocorrectApproveHandler` in order to let the API Consumer decide whether a `LintError` is to be autocorrected, or not. This interface is implemented for all rules provided via the Ktlint project starting from version 1.3. However, external rulesets may not have implemented this interface on their rulesets though. Contact the maintainer of such a ruleset to implement this interface. + +The (legacy) `format` function is invoked with an optional lambda. Once formatting is complete, the lambda will be called for each `LintError` which is found. The (legacy) `format` function fixes all `LintErrors` for which an autocorrect is available. The formatted code is returned as result of the function. + +```kotlin title="Invoke format (deprecated as of Ktlint 1.3, will be removed in Ktlint 2.0)" +// Up until Ktlint 1.2.1 the format was invoked with a lambda having two parameters and not returning a result. This function will be removed in Ktlint 2.0 val formattedCode = ktLintRuleEngine - .format(codeFile) { lintError -> - // handle + .format(code) { lintError, corrected -> + // handle } ``` +### Rule & RuleAutocorrectApproveHandler + +!!! note + Providers of custom rules are strongly encouraged to implement `RuleAutocorrectApproveHandler` interface as described below. The `ktlint-intellij-plugin`, which will be updated soon after the 1.3 release of Ktlint, make use of this new functionality. If your ruleset is used by users of the plugin, it is very likely that they want to be able to autocorrect individual `LintErrors` or to format a block of code (e.g. a selection) in a file. This functionality will only be available for rules that have implemented this interface. + +In Ktlint 1.3 the `RuleAutocorrectApproveHandler` interface is added. This interface adds the ability that the API Consumer decides per `LintError` whether it needs to autocorrected, or not. In Ktlint 2.0 the methods `beforeVisitChildNodes` and `afterVisitChildNodes` of the `Rule` class will be replaced with the new versions which are now added to the `RuleAutocorrectApproveHandler` interface as is shown below (the signature for `afterVisitChildNodes` is changed similarly): + + + + + + +
+ +```kotlin title="Deprecated signature in `Rule` class" +public open fun beforeVisitChildNodes( + node: ASTNode, + autoCorrect: Boolean, + emit: ( + offset: Int, + errorMessage: String, + canBeAutoCorrected: Boolean + ) -> Unit, +) +``` + + + +```kotlin title="New signature in `RuleAutocorrectApproveHandler` interface" +public fun beforeVisitChildNodes( + node: ASTNode, + emit: ( + offset: Int, + errorMessage: String, + canBeAutoCorrected: Boolean + ) -> AutocorrectDecision, +) +``` + +
+ +The `autoCorrect` parameter is no longer passed to the method. Instead, the `emit` lambda now returns the value `AutocorrectDecision.ALLOW_AUTOCORRECT` or `AutocorrectDecision.NO_AUTOCORRECT`. + +In case a `LintError` is detected, and can be autocorrected, the `LintError` can be processed as shown below: + +```kotlin +emit(node.startOffset, "some detail message", true) + .ifAutocorrectAllowed { + // Autocorrect the LintError + } +``` + +In case the `LintError` can not be autocorrected, if suffices to emit the violation only: +```kotlin +emit(node.startOffset, "some detail message", false) +``` + ## Logging Ktlint uses the `io.github.oshai:kotlin-logging` which is a `slf4j` wrapper. As API consumer you can choose which logging framework you want to use and configure that framework to your exact needs. The [basic API Consumer](https://github.com/pinterest/ktlint/blob/master/ktlint-api-consumer/src/main/kotlin/com/example/ktlint/api/consumer/KtlintApiConsumer.kt) contains an example with `org.slf4j:slf4j-simple` as logging provider and a customized configuration which shows logging at `DEBUG` level for all classes except one specific class which only displays logging at `WARN` level. diff --git a/documentation/release-latest/docs/install/cli.md b/documentation/release-latest/docs/install/cli.md index 9cbfe32e1c..36443fb7e7 100644 --- a/documentation/release-latest/docs/install/cli.md +++ b/documentation/release-latest/docs/install/cli.md @@ -12,7 +12,7 @@ All releases of `ktlint` can be downloaded from the [releases](https://github.co A particular version of `ktlint` can be downloaded with next command which also changes the file to an executable in directory `/usr/local/bin`: ```sh title="Download" -curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.2.1/ktlint && chmod a+x ktlint && sudo mv ktlint /usr/local/bin/ +curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint && chmod a+x ktlint && sudo mv ktlint /usr/local/bin/ ``` !!! tip "Curl not installed or behind proxy" @@ -209,6 +209,6 @@ Options `--stdin` and `--patterns-from-stdin` are mutually exclusive, only one o Microsoft Windows is not able to run the `ktlint` command directly. Ktlint can be run in following ways on Microsoft Windows: -1. Use the `ktlint.bat` batch file provided as part of the [release](https://github.com/pinterest/ktlint/releases/tag/1.2.1). Add the batch file to your `%PATH%` environment variable for easy access +1. Use the `ktlint.bat` batch file provided as part of the [release](https://github.com/pinterest/ktlint/releases/tag/1.3.0). Add the batch file to your `%PATH%` environment variable for easy access 2. Run `ktlint` using Git Bash 3. Run as `java -jar ktlint` diff --git a/documentation/release-latest/docs/install/integrations.md b/documentation/release-latest/docs/install/integrations.md index de5a02d75e..657128a283 100644 --- a/documentation/release-latest/docs/install/integrations.md +++ b/documentation/release-latest/docs/install/integrations.md @@ -56,7 +56,7 @@ See [cli usage](../cli) for arguments that can be supplied to `ktlint`. com.pinterest.ktlint ktlint-cli - 1.2.1 + 1.3.0 @@ -117,7 +117,7 @@ configurations { } dependencies { - ktlint("com.pinterest.ktlint:ktlint-cli:1.2.1") { + ktlint("com.pinterest.ktlint:ktlint-cli:1.3.0") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) } @@ -167,7 +167,7 @@ The configuration below, defines following task: val ktlint by configurations.creating dependencies { - ktlint("com.pinterest.ktlint:ktlint-cli:1.2.1") { + ktlint("com.pinterest.ktlint:ktlint-cli:1.3.0") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) } diff --git a/documentation/release-latest/docs/rules/configuration-intellij-idea.md b/documentation/release-latest/docs/rules/configuration-intellij-idea.md index d465d63584..e877b5592b 100644 --- a/documentation/release-latest/docs/rules/configuration-intellij-idea.md +++ b/documentation/release-latest/docs/rules/configuration-intellij-idea.md @@ -21,7 +21,7 @@ ij_kotlin_packages_to_use_import_on_demand = unset ``` Conflicts between `ktlint` and IDEA formatting can also be resolved by using the [ktlint-intellij-plugin](https://plugins.jetbrains.com/plugin/15057-ktlint) (or install via Intellij IDEA plugin marketplace) in `distract free` mode. In this mode, the plugin formats your code with `ktlint` while you're editing the code. - + # Cleaning up old XML configuration settings Projects which have been created with (old)er versions of Intellij IDEA might still contain XML configuration regarding code styling. It is advised to remove the directory `.idea/codeStyles` whenever it still exists in your project directory. diff --git a/documentation/release-latest/docs/rules/experimental.md b/documentation/release-latest/docs/rules/experimental.md index c3c661f887..98817733be 100644 --- a/documentation/release-latest/docs/rules/experimental.md +++ b/documentation/release-latest/docs/rules/experimental.md @@ -8,73 +8,6 @@ ktlint_experimental=enabled ``` Also see [enable/disable specific rules](../configuration-ktlint/#disabled-rules). -### Backing property naming - -Allows property names to start with `_` in case the property is a backing property. `ktlint_official` and `android_studio` code styles require the correlated property/function to be defined as `public`. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - class Bar { - // Backing property - private val _elementList = mutableListOf() - val elementList: List - get() = _elementList - } - ``` -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - class Bar { - // Incomplete backing property as public property 'elementList1' is missing - private val _elementList1 = mutableListOf() - - // Invalid backing property as '_elementList2' is not a private property - val _elementList2 = mutableListOf() - val elementList2: List - get() = _elementList2 - } - ``` - -Rule id: `backing-property-naming` (`standard` rule set) - -## Binary expression wrapping - -Wraps binary expression at the operator reference whenever the binary expression does not fit on the line. In case the binary expression is nested, the expression is evaluated from outside to inside. If the left and right hand sides of the binary expression, after wrapping, fit on a single line then the inner binary expressions will not be wrapped. If one or both inner binary expression still do not fit on a single after wrapping of the outer binary expression, then each of those inner binary expressions will be wrapped. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - fun foo() { - // Assume that the last allowed character is - // at the X character on the right X - if ((leftHandSideExpression && rightHandSideExpression) || - ( - leftHandSideLongExpression && - rightHandSideExpression - ) - ) { - // do something - } - } - ``` - -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - fun foo() { - // Assume that the last allowed character is - // at the X character on the right X - if ((leftHandSideExpression && rightHandSideExpression) || - (leftHandSideLongExpression && rightHandSideExpression) - ) { - // do something - } - } - ``` - -Rule id: `binary-expression-wrapping` (`standard` rule set) - ## Blank lines between when-conditions Consistently add or remove blank lines between when-conditions in a when-statement. A blank line is only added between when-conditions if the when-statement contains at lease one multiline when-condition. If a when-statement only contains single line when-conditions, then the blank lines between the when-conditions are removed. @@ -176,508 +109,12 @@ Consistently add or remove blank lines between when-conditions in a when-stateme Rule id: `blank-lines-between-when-conditions` (`standard` rule set) -## Chain method continuation - -In a multiline method chain, the chain operators (`.` or `?.`) have to be aligned with each other. - -Multiple chained methods on a single line are allowed as long as the maximum line length, and the maximum number of chain operators are not exceeded. Under certain conditions, it is allowed that the expression before the first and/or the expression after the last chain operator is a multiline expression. - -The `.` in `java.class` is ignored when wrapping on chain operators. - -This rule can be configured with `.editorconfig` property [`ktlint_chain_method_rule_force_multiline_when_chain_operator_count_greater_or_equal_than`](../configuration-ktlint/#force-multiline-chained-methods-based-on-number-of-chain-operators). - -!!! warning - Binary expression for which the left and/or right operand consist of method chain are currently being ignored by this rule. Please reach out, if you can help to determine what the best strategy is to deal with such kind of expressions. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - val foo1 = - listOf(1, 2, 3) - .filter { it > 2 }!! - .takeIf { it > 2 } - .map { - it * it - }?.map { - it * it - } - val foo2 = - listOf(1, 2, 3) - .filter { - it > 2 - }.map { - 2 * it - }?.map { - 2 * it - } - val foo3 = - foo().bar().map { - it.foobar() - } - val foo4 = - """ - Some text - """.trimIndent().foo().bar() - ``` - -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - val foo1 = - listOf(1, 2, 3). - filter { it > 2 }!!. - takeIf { it > 2 }. - map { - it * it - }?. - map { - it * it - } - val foo2 = - listOf(1, 2, 3) - .filter { - it > 2 - } - .map { - 2 * it - } - ?.map { - 2 * it - } - val foo3 = - foo() - .bar().map { - it.foobar() - } - val foo4 = - """ - Some text - """.trimIndent().foo() - .bar() - ``` - -| Configuration setting | ktlint_official | intellij_idea | android_studio | -|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------:|:-------------:|:--------------:| -| `ktlint_chain_method_rule_force_multiline_when_chain_operator_count_greater_or_equal_than`
Force wrapping of chained methods in case an expression contains at least the specified number of chain operators. If a chained method contains nested expressions, the chain operators of the inner expression are not taken into account. Use value `unset` (default) to disable this setting. | 4 | 4 | 4 | - - -Rule id: `chain-method-continuation` (`standard` rule set) - -!!! Note - This rule is only run when `ktlint_code_style` is set to `ktlint_official` or when the rule is enabled explicitly. - -## Class signature - -Rewrites the class signature to a consistent format respecting the `.editorconfig` property `max_line_length` if set. In the `ktlint_official` code style all class parameters are wrapped by default. Set `.editorconfig` property `ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than` to a value greater than 1 to allow class with a few parameters to be placed on a single line. -The other code styles allow an infinite amount of parameters on the same line (as long as the `max_line_length` is not exceeded) unless `.editorconfig` property `ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than` is set explicitly. - -=== "[:material-heart:](#) Ktlint (ktlint_official)" - - ```kotlin - // Assume that max_line_length is not exceeded when written as single line - class Foo0 - - class Foo1( - a: Any, - ) - - class Foo2( - a: Any, - b: Any, - ) - - class Foo3( - @Foo a: Any, - b: Any, - c: Any, - ) - - class Foo4( - a: Any, - b: Any, - c: Any, - ) : FooBar(a, c) - - class Foo5 : - FooBar( - "bar1", - "bar2", - ) { - // body - } - - class Foo6( - val bar1: Bar, - val bar2: Bar, - ) : FooBar( - bar1, - bar2, - ) { - // body - } - - class Foo7( - val bar1: Bar, - val bar2: Bar, - ) : FooBar( - bar1, - bar2, - ), - BarFoo1, - BarFoo2 { - // body - } - - class Foo8 - constructor( - val bar1: Bar, - val bar2: Bar, - ) : FooBar(bar1, bar2), - BarFoo1, - BarFoo2 { - // body - } - ``` - -=== "[:material-heart-off-outline:](#) Disallowed (ktlint_official)" - - ```kotlin - // Assume that max_line_length is not exceeded when written as single line - class Foo0() - - class Foo1(a: Any) - - class Foo2(a: Any, b: Any) - - class Foo3(@Foo a: Any, b: Any, c: Any) - - class Foo4(a: Any, b: Any, c: Any) : FooBar(a, c) - - class Foo5 : FooBar( - "bar1", - "bar2", - ) { - // body - } - - class Foo6( - val bar1: Bar, - val bar2: Bar, - ) : FooBar( - bar1, - bar2, - ) { - // body - } - - class Foo7( - val bar1: Bar, - val bar2: Bar, - ) : FooBar( - bar1, - bar2, - ), - BarFoo1, - BarFoo2 { - // body - } - - class Foo8 - constructor( - val bar1: Bar, - val bar2: Bar, - ) : FooBar(bar1, bar2), - BarFoo1, - BarFoo2 { - // body - } - ``` - -=== "[:material-heart:](#) Ktlint (non ktlint_official)" - - ```kotlin - // Assume that the last allowed character is - // at the X character on the right X - class Foo0 - - class Foo1( - a: Any, - ) - - class Foo2(a: Any) - - class Foo3( - a: Any, - b: Any, - ) - - class Foo4(a: Any, b: Any) - - class Foo5(@Foo a: Any, b: Any, c: Any) - - class Foo6(a: Any, b: Any, c: Any) : - FooBar(a, c) - - class Foo7 : FooBar( - "bar1", - "bar2", - ) { - // body - } - class Foo8( - val bar1: Bar, - val bar2: Bar, - ) : FooBar( - bar1, - bar2 - ) { - // body - } - - class Foo9( - val bar1: Bar, - val bar2: Bar, - ) : FooBar( - bar1, - bar2 - ), - BarFoo1, - BarFoo2 { - // body - } - - class Foo10 - constructor( - val bar1: Bar, - val bar2: Bar, - ) : FooBar(bar1, bar2), - BarFoo1, - BarFoo2 { - // body - } - ``` - -=== "[:material-heart-off-outline:](#) Disallowed (non ktlint_official)" - - ```kotlin - // Assume that the last allowed character is - // at the X character on the right X - class Foo0() - - class Foo6(a: Any, b: Any, c: Any) : FooBar(a, c) - ``` - -| Configuration setting | ktlint_official | intellij_idea | android_studio | -|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------:|:-------------:|:--------------:| -| `ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than`
Force wrapping of the parameters of the class signature in case it contains at least the specified number of parameters, even in case the entire class signature would fit on a single line. Use value `unset` to disable this setting. | 1 | `unset` | `unset` | - -Rule id: `class-signature` (`standard` rule set) - -## Condition wrapping - -Wraps each operand in a multiline condition to a separate line. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - val foo = bar || baz - if (bar1 || - bar2 || - baz1 || - (baz2 && baz3) - ) { - // do something - } - ``` - -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - val foo = - multiLineOperand( - "bar" - ) || baz - if (bar1 || bar2 || - baz1 || (baz2 && baz3) - ) { - // do something - } - ``` - -Rule id: `condition-wrapping` (`standard` rule set) - -## Function expression body - -Rewrites a function body only containing a `return` or `throw` expression to an expression body. - -!!! note - If the function body contains a comment, it is not rewritten to an expression body. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - fun foo1() = "foo" - - fun foo2(): String = "foo" - - fun foo3(): Unit = throw IllegalArgumentException("some message") - - fun foo4(): Foo = throw IllegalArgumentException("some message") - - fun foo5() { - return "foo" // some comment - } - - fun foo6(): String { - /* some comment */ - return "foo" - } - - fun foo7() { - throw IllegalArgumentException("some message") - /* some comment */ - } - - fun foo8(): Foo { - throw IllegalArgumentException("some message") - // some comment - } - ``` -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - fun foo1() { - return "foo" - } - - fun foo2(): String { - return "foo" - } - - fun foo3() { - throw IllegalArgumentException("some message") - } - - fun foo4(): Foo { - throw IllegalArgumentException("some message") - } - ``` - -Rule id: `function-expression-body` (`standard` rule set) - -## Function literal - -Enforces the parameters of a function literal and the arrow to be written on the same line as the opening brace if the maximum line length is not exceeded. In case the parameters are wrapped to multiple lines then this is respected. - -If the function literal contains multiple parameter and at least one parameter other than the first parameter starts on a new line than all parameters and the arrow are wrapped to separate lines. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - val foobar1 = { foo + bar } - val foobar2 = - { - foo + bar - } - val foobar3 = - { foo: Foo -> - foo.repeat(2) - } - val foobar4 = - { foo: Foo, bar: Bar -> - foo + bar - } - val foobar5 = { foo: Foo, bar: Bar -> foo + bar } - val foobar6 = - { - foo: Foo, - bar: Bar, - -> - foo + bar - } - - // Assume that the last allowed character is - // at the X character on the right X - val foobar7 = - barrrrrrrrrrrrrr { - fooooooooooooooo: Foo - -> - foo.repeat(2) - } - ``` - -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - val foobar3 = - { - foo: Foo -> - foo.repeat(2) - } - val foobar6 = - { foo: Foo, - bar: Bar -> - foo + bar - } - // Assume that the last allowed character is - // at the X character on the right X - val foobar7 = - barrrrrrrrrrrrrr { fooooooooooooooo: Foo -> - foo.repeat(2) - } - ``` - -Rule id: `function-literal` (`standard` rule set) - -## Function type modifier spacing - -Enforce a single whitespace between the modifier list and the function type. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - val foo: suspend () -> Unit = {} - - suspend fun bar(baz: suspend () -> Unit) = baz() - ``` - -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - val foo: suspend() -> Unit = {} - - suspend fun bar(baz: suspend () -> Unit) = baz() - ``` - -Rule id: `function-type-modifier-spacing` (`standard` rule set) - -## Mixed condition operators - -Conditions should not use a both `&&` and `||` operators between operators at the same level. By using parenthesis the expression is to be clarified. - -=== "[:material-heart:](#) Ktlint" - - ```kotlin - val foo = bar1 && (bar2 || bar3) && bar4 - ``` - -=== "[:material-heart-off-outline:](#) Disallowed" - - ```kotlin - val foo = bar1 && - bar2 || - bar3 - val foo = bar1 && (bar2 || bar3 && bar4) && bar5 - ``` - -Rule id: `mixed-condition-operators` (`standard` rule set) - ## KDoc KDoc's should only be used on elements for which KDoc is to be transformed to documentation. Normal block comments should be used in other cases. !!! note: - Access modifiers are ignored. Strictly speaking, one could argue that private declarations should not have a KDoc as no documentation will be generated for it. However, for internal use of developers the KDoc still serves documentation purposes. +Access modifiers are ignored. Strictly speaking, one could argue that private declarations should not have a KDoc as no documentation will be generated for it. However, for internal use of developers the KDoc still serves documentation purposes. === "[:material-heart:](#) Ktlint" @@ -729,26 +166,26 @@ KDoc's should only be used on elements for which KDoc is to be transformed to do Rule id: `kdoc` (`standard` rule set) -## Multiline loop +## Mixed condition operators -Braces required for multiline for, while, and do statements. +Conditions should not use a both `&&` and `||` operators between operators at the same level. By using parenthesis the expression is to be clarified. === "[:material-heart:](#) Ktlint" ```kotlin - for (i in 1..10) { - println(i) - } + val foo = bar1 && (bar2 || bar3) && bar4 ``` === "[:material-heart-off-outline:](#) Disallowed" ```kotlin - for (i in 1..10) - println(i) + val foo = bar1 && + bar2 || + bar3 + val foo = bar1 && (bar2 || bar3 && bar4) && bar5 ``` -Rule id: `multiline-loop` (`standard` rule set) +Rule id: `mixed-condition-operators` (`standard` rule set) ## Square brackets spacing diff --git a/documentation/release-latest/docs/rules/standard.md b/documentation/release-latest/docs/rules/standard.md index 7fe5915aa4..0b5689d685 100644 --- a/documentation/release-latest/docs/rules/standard.md +++ b/documentation/release-latest/docs/rules/standard.md @@ -52,6 +52,43 @@ Multiple annotations should be on a separate line than the annotated declaration Rule-id: `annotation` (`standard` rule set) +## Binary expression wrapping + +Wraps binary expression at the operator reference whenever the binary expression does not fit on the line. In case the binary expression is nested, the expression is evaluated from outside to inside. If the left and right hand sides of the binary expression, after wrapping, fit on a single line then the inner binary expressions will not be wrapped. If one or both inner binary expression still do not fit on a single after wrapping of the outer binary expression, then each of those inner binary expressions will be wrapped. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + fun foo() { + // Assume that the last allowed character is + // at the X character on the right X + if ((leftHandSideExpression && rightHandSideExpression) || + ( + leftHandSideLongExpression && + rightHandSideExpression + ) + ) { + // do something + } + } + ``` + +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + fun foo() { + // Assume that the last allowed character is + // at the X character on the right X + if ((leftHandSideExpression && rightHandSideExpression) || + (leftHandSideLongExpression && rightHandSideExpression) + ) { + // do something + } + } + ``` + +Rule id: `binary-expression-wrapping` (`standard` rule set) + ## Blank line before declarations Requires a blank line before any class or function declaration. No blank line is required between the class signature and the first declaration in the class. In a similar way, a blank line is required before any list of top level or class properties. No blank line is required before local properties or between consecutive properties. @@ -124,6 +161,301 @@ Lines in a block comment which (exclusive the indentation) start with a `*` shou Rule id: `block-comment-initial-star-alignment` (`standard` rule set) +## Chain method continuation + +In a multiline method chain, the chain operators (`.` or `?.`) have to be aligned with each other. + +Multiple chained methods on a single line are allowed as long as the maximum line length, and the maximum number of chain operators are not exceeded. Under certain conditions, it is allowed that the expression before the first and/or the expression after the last chain operator is a multiline expression. + +The `.` in `java.class` is ignored when wrapping on chain operators. + +!!! warning + A binary expression for which the left and/or right operand consist of a method chain are currently being ignored by this rule. Please reach out, if you can help to determine what the best strategy is to deal with such kind of expressions. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + val foo1 = + listOf(1, 2, 3) + .filter { it > 2 }!! + .takeIf { it > 2 } + .map { + it * it + }?.map { + it * it + } + val foo2 = + listOf(1, 2, 3) + .filter { + it > 2 + }.map { + 2 * it + }?.map { + 2 * it + } + val foo3 = + foo().bar().map { + it.foobar() + } + val foo4 = + """ + Some text + """.trimIndent().foo().bar() + ``` + +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + val foo1 = + listOf(1, 2, 3). + filter { it > 2 }!!. + takeIf { it > 2 }. + map { + it * it + }?. + map { + it * it + } + val foo2 = + listOf(1, 2, 3) + .filter { + it > 2 + } + .map { + 2 * it + } + ?.map { + 2 * it + } + val foo3 = + foo() + .bar().map { + it.foobar() + } + val foo4 = + """ + Some text + """.trimIndent().foo() + .bar() + ``` + +| Configuration setting | ktlint_official | intellij_idea | android_studio | +|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------:|:-------------:|:--------------:| +| `ktlint_chain_method_rule_force_multiline_when_chain_operator_count_greater_or_equal_than`
Force wrapping of chained methods in case an expression contains at least the specified number of chain operators. If a chained method contains nested expressions, the chain operators of the inner expression are not taken into account. Use value `unset` (default) to disable this setting. | 4 | 4 | 4 | + + +Rule id: `chain-method-continuation` (`standard` rule set) + +!!! Note + This rule is only run when `ktlint_code_style` is set to `ktlint_official` or when the rule is enabled explicitly. + +## Class signature + +Rewrites the class signature to a consistent format respecting the `.editorconfig` property `max_line_length` if set. In the `ktlint_official` code style all class parameters are wrapped by default. Set `.editorconfig` property `ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than` to a value greater than 1 to allow classes with a few parameters to be placed on a single line. +The other code styles allow an infinite amount of parameters on the same line (as long as the `max_line_length` is not exceeded) unless `.editorconfig` property `ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than` is set explicitly. + +=== "[:material-heart:](#) Ktlint (ktlint_official)" + + ```kotlin + // Assume that max_line_length is not exceeded when written as single line + class Foo0 + + class Foo1( + a: Any, + ) + + class Foo2( + a: Any, + b: Any, + ) + + class Foo3( + @Foo a: Any, + b: Any, + c: Any, + ) + + class Foo4( + a: Any, + b: Any, + c: Any, + ) : FooBar(a, c) + + class Foo5 : + FooBar( + "bar1", + "bar2", + ) { + // body + } + + class Foo6( + val bar1: Bar, + val bar2: Bar, + ) : FooBar( + bar1, + bar2, + ) { + // body + } + + class Foo7( + val bar1: Bar, + val bar2: Bar, + ) : FooBar( + bar1, + bar2, + ), + BarFoo1, + BarFoo2 { + // body + } + + class Foo8 + constructor( + val bar1: Bar, + val bar2: Bar, + ) : FooBar(bar1, bar2), + BarFoo1, + BarFoo2 { + // body + } + ``` + +=== "[:material-heart-off-outline:](#) Disallowed (ktlint_official)" + + ```kotlin + // Assume that max_line_length is not exceeded when written as single line + class Foo0() + + class Foo1(a: Any) + + class Foo2(a: Any, b: Any) + + class Foo3(@Foo a: Any, b: Any, c: Any) + + class Foo4(a: Any, b: Any, c: Any) : FooBar(a, c) + + class Foo5 : FooBar( + "bar1", + "bar2", + ) { + // body + } + + class Foo6( + val bar1: Bar, + val bar2: Bar, + ) : FooBar( + bar1, + bar2, + ) { + // body + } + + class Foo7( + val bar1: Bar, + val bar2: Bar, + ) : FooBar( + bar1, + bar2, + ), + BarFoo1, + BarFoo2 { + // body + } + + class Foo8 + constructor( + val bar1: Bar, + val bar2: Bar, + ) : FooBar(bar1, bar2), + BarFoo1, + BarFoo2 { + // body + } + ``` + +=== "[:material-heart:](#) Ktlint (non ktlint_official)" + + ```kotlin + // Assume that the last allowed character is + // at the X character on the right X + class Foo0 + + class Foo1( + a: Any, + ) + + class Foo2(a: Any) + + class Foo3( + a: Any, + b: Any, + ) + + class Foo4(a: Any, b: Any) + + class Foo5(@Foo a: Any, b: Any, c: Any) + + class Foo6(a: Any, b: Any, c: Any) : + FooBar(a, c) + + class Foo7 : FooBar( + "bar1", + "bar2", + ) { + // body + } + class Foo8( + val bar1: Bar, + val bar2: Bar, + ) : FooBar( + bar1, + bar2 + ) { + // body + } + + class Foo9( + val bar1: Bar, + val bar2: Bar, + ) : FooBar( + bar1, + bar2 + ), + BarFoo1, + BarFoo2 { + // body + } + + class Foo10 + constructor( + val bar1: Bar, + val bar2: Bar, + ) : FooBar(bar1, bar2), + BarFoo1, + BarFoo2 { + // body + } + ``` + +=== "[:material-heart-off-outline:](#) Disallowed (non ktlint_official)" + + ```kotlin + // Assume that the last allowed character is + // at the X character on the right X + class Foo0() + + class Foo6(a: Any, b: Any, c: Any) : FooBar(a, c) + ``` + +| Configuration setting | ktlint_official | intellij_idea | android_studio | +|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------:|:-------------:|:--------------:| +| `ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than`
Force wrapping of the parameters of the class signature in case it contains at least the specified number of parameters, even in case the entire class signature would fit on a single line. Use value `unset` to disable this setting. | 1 | `unset` | `unset` | + +Rule id: `class-signature` (`standard` rule set) + ## Enum entry Enum entry names should be uppercase underscore-separated or upper camel-case separated. @@ -166,6 +498,129 @@ Ensures consistent usage of a newline at the end of each file. Rule id: `final-newline` (`standard` rule set) +## Function expression body + +Rewrites a function body only containing a `return` or `throw` expression to an expression body. + +!!! note + If the function body contains a comment, it is not rewritten to an expression body. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + fun foo1() = "foo" + + fun foo2(): String = "foo" + + fun foo3(): Unit = throw IllegalArgumentException("some message") + + fun foo4(): Foo = throw IllegalArgumentException("some message") + + fun foo5() { + return "foo" // some comment + } + + fun foo6(): String { + /* some comment */ + return "foo" + } + + fun foo7() { + throw IllegalArgumentException("some message") + /* some comment */ + } + + fun foo8(): Foo { + throw IllegalArgumentException("some message") + // some comment + } + ``` +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + fun foo1() { + return "foo" + } + + fun foo2(): String { + return "foo" + } + + fun foo3() { + throw IllegalArgumentException("some message") + } + + fun foo4(): Foo { + throw IllegalArgumentException("some message") + } + ``` + +Rule id: `function-expression-body` (`standard` rule set) + +## Function literal + +Enforces the parameters of a function literal and the arrow to be written on the same line as the opening brace if the maximum line length is not exceeded. In case the parameters are wrapped to multiple lines then this is respected. + +If the function literal contains multiple parameters and at least one parameter other than the first parameter starts on a new line than all parameters and the arrow are wrapped to separate lines. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + val foobar1 = { foo + bar } + val foobar2 = + { + foo + bar + } + val foobar3 = + { foo: Foo -> + foo.repeat(2) + } + val foobar4 = + { foo: Foo, bar: Bar -> + foo + bar + } + val foobar5 = { foo: Foo, bar: Bar -> foo + bar } + val foobar6 = + { + foo: Foo, + bar: Bar, + -> + foo + bar + } + + // Assume that the last allowed character is + // at the X character on the right X + val foobar7 = + barrrrrrrrrrrrrr { + fooooooooooooooo: Foo + -> + foo.repeat(2) + } + ``` + +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + val foobar3 = + { + foo: Foo -> + foo.repeat(2) + } + val foobar6 = + { foo: Foo, + bar: Bar -> + foo + bar + } + // Assume that the last allowed character is + // at the X character on the right X + val foobar7 = + barrrrrrrrrrrrrr { fooooooooooooooo: Foo -> + foo.repeat(2) + } + ``` + +Rule id: `function-literal` (`standard` rule set) + ## Function signature Rewrites the function signature to a single line when possible (e.g. when not exceeding the `max_line_length` property) or a multiline signature otherwise. @@ -320,6 +775,28 @@ Rewrites the function signature to a single line when possible (e.g. when not ex Rule id: `function-signature` (`standard` rule set) +## Function type modifier spacing + +Enforce a single whitespace between the modifier list and the function type. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + val foo: suspend () -> Unit = {} + + suspend fun bar(baz: suspend () -> Unit) = baz() + ``` + +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + val foo: suspend() -> Unit = {} + + suspend fun bar(baz: suspend () -> Unit) = baz() + ``` + +Rule id: `function-type-modifier-spacing` (`standard` rule set) + ## If else bracing If at least one branch of an if-else statement or an if-else-if statement is wrapped between curly braces then all branches should be wrapped between braces. @@ -418,6 +895,36 @@ Rule id: `indent` (`standard` rule set) ## Naming +### Backing property naming + +Allows property names to start with `_` in case the property is a backing property. `ktlint_official` and `android_studio` code styles require the correlated property/function to be defined as `public`. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + class Bar { + // Backing property + private val _elementList = mutableListOf() + val elementList: List + get() = _elementList + } + ``` +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + class Bar { + // Incomplete backing property as public property 'elementList1' is missing + private val _elementList1 = mutableListOf() + + // Invalid backing property as '_elementList2' is not a private property + val _elementList2 = mutableListOf() + val elementList2: List + get() = _elementList2 + } + ``` + +Rule id: `backing-property-naming` (`standard` rule set) + ### Class naming Enforce naming of class and objects. @@ -582,7 +1089,7 @@ Enforce naming of property. } ``` -This rule can also be suppressed with the IntelliJ IDEA inspection suppression `PropertyName` or `ConstPropertyName`. +This rule is suppressed whenever the IntelliJ IDEA inspection suppression `PropertyName`, `ConstPropertyName`, `ObjectPropertyName` or `PrivatePropertyName` is used. Rule id: `property-naming` (`standard` rule set) @@ -999,6 +1506,27 @@ Braces required for multiline if/else statements. Rule id: `multiline-if-else` (`standard` rule set) +## Multiline loop + +Braces required for multiline for, while, and do statements. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + for (i in 1..10) { + println(i) + } + ``` + +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + for (i in 1..10) + println(i) + ``` + +Rule id: `multiline-loop` (`standard` rule set) + ## No blank lines before `}` No blank lines before `}`. @@ -1277,7 +1805,7 @@ No wildcard imports except whitelisted imports. import foobar.* ``` -| Configuration setting | ktlint_official | intellij_idea | android_studio | +| Configuration setting | ktlint_official | intellij_idea | android_studio | |:--------------------------------------------------------------------------------------------------------------------|:---------------:|:------------------------------------------:|:-----------------------------------------------:| | `ij_kotlin_packages_to_use_import_on_demand`
Defines allowed wildcard imports as a comma separated list. | - | `java.util.*,`
`kotlinx.android.synthetic.**` | `java.util.*,`
`kotlinx.android.synthetic.**` | @@ -2364,6 +2892,39 @@ A block comment should start and end on a line that does not contain any other e Rule id: `comment-wrapping` (`standard` rule set) +### Condition wrapping + +Wraps each operand in a multiline condition to a separate line. + +=== "[:material-heart:](#) Ktlint" + + ```kotlin + val foo = bar || baz + if (bar1 || + bar2 || + baz1 || + (baz2 && baz3) + ) { + // do something + } + ``` + +=== "[:material-heart-off-outline:](#) Disallowed" + + ```kotlin + val foo = + multiLineOperand( + "bar" + ) || baz + if (bar1 || bar2 || + baz1 || (baz2 && baz3) + ) { + // do something + } + ``` + +Rule id: `condition-wrapping` (`standard` rule set) + ### Content receiver wrapping Wraps the content receiver list to a separate line regardless of maximum line length. If the maximum line length is configured and is exceeded, wrap the context receivers and if needed its projection types to separate lines. diff --git a/documentation/snapshot/docs/install/cli.md b/documentation/snapshot/docs/install/cli.md index 9cbfe32e1c..36443fb7e7 100644 --- a/documentation/snapshot/docs/install/cli.md +++ b/documentation/snapshot/docs/install/cli.md @@ -12,7 +12,7 @@ All releases of `ktlint` can be downloaded from the [releases](https://github.co A particular version of `ktlint` can be downloaded with next command which also changes the file to an executable in directory `/usr/local/bin`: ```sh title="Download" -curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.2.1/ktlint && chmod a+x ktlint && sudo mv ktlint /usr/local/bin/ +curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint && chmod a+x ktlint && sudo mv ktlint /usr/local/bin/ ``` !!! tip "Curl not installed or behind proxy" @@ -209,6 +209,6 @@ Options `--stdin` and `--patterns-from-stdin` are mutually exclusive, only one o Microsoft Windows is not able to run the `ktlint` command directly. Ktlint can be run in following ways on Microsoft Windows: -1. Use the `ktlint.bat` batch file provided as part of the [release](https://github.com/pinterest/ktlint/releases/tag/1.2.1). Add the batch file to your `%PATH%` environment variable for easy access +1. Use the `ktlint.bat` batch file provided as part of the [release](https://github.com/pinterest/ktlint/releases/tag/1.3.0). Add the batch file to your `%PATH%` environment variable for easy access 2. Run `ktlint` using Git Bash 3. Run as `java -jar ktlint` diff --git a/documentation/snapshot/docs/install/integrations.md b/documentation/snapshot/docs/install/integrations.md index de5a02d75e..657128a283 100644 --- a/documentation/snapshot/docs/install/integrations.md +++ b/documentation/snapshot/docs/install/integrations.md @@ -56,7 +56,7 @@ See [cli usage](../cli) for arguments that can be supplied to `ktlint`. com.pinterest.ktlint ktlint-cli - 1.2.1 + 1.3.0 @@ -117,7 +117,7 @@ configurations { } dependencies { - ktlint("com.pinterest.ktlint:ktlint-cli:1.2.1") { + ktlint("com.pinterest.ktlint:ktlint-cli:1.3.0") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) } @@ -167,7 +167,7 @@ The configuration below, defines following task: val ktlint by configurations.creating dependencies { - ktlint("com.pinterest.ktlint:ktlint-cli:1.2.1") { + ktlint("com.pinterest.ktlint:ktlint-cli:1.3.0") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) }