diff --git a/CHANGES.md b/CHANGES.md index 6bcae24245..873dcdcf52 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changes * Extend minimum supported version for `ktlint` to `0.31.0` ([#xxx](https://github.com/diffplug/spotless/pull/xxx)). +* Support `ktlint` version 0.47.0 ([#xxx](https://github.com/diffplug/spotless/pull/xxx)) fixes [#1281](https://github.com/diffplug/spotless/issues/1281). ## [2.29.0] - 2022-08-23 ### Added diff --git a/lib/build.gradle b/lib/build.gradle index 1a5fbf9c64..5983e4479a 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -33,6 +33,7 @@ versionCompatibility { '0.34.2', '0.45.2', '0.46.0', + '0.47.0', ] targetSourceSetName = 'ktlint' } @@ -86,6 +87,9 @@ dependencies { compatKtLint0Dot46Dot0CompileOnly 'com.pinterest.ktlint:ktlint-core:0.46.0' compatKtLint0Dot46Dot0CompileOnly 'com.pinterest.ktlint:ktlint-ruleset-experimental:0.46.0' compatKtLint0Dot46Dot0CompileOnly 'com.pinterest.ktlint:ktlint-ruleset-standard:0.46.0' + compatKtLint0Dot47Dot0CompileOnly 'com.pinterest.ktlint:ktlint-core:0.47.0' + compatKtLint0Dot47Dot0CompileOnly 'com.pinterest.ktlint:ktlint-ruleset-experimental:0.47.0' + compatKtLint0Dot47Dot0CompileOnly 'com.pinterest.ktlint:ktlint-ruleset-standard:0.47.0' String VER_SCALAFMT="3.5.9" scalafmtCompileOnly "org.scalameta:scalafmt-core_2.13:$VER_SCALAFMT" diff --git a/lib/src/compatKtLint0Dot47Dot0/java/com/diffplug/spotless/glue/ktlint/compat/KtLintCompat0Dot47Dot0Adapter.java b/lib/src/compatKtLint0Dot47Dot0/java/com/diffplug/spotless/glue/ktlint/compat/KtLintCompat0Dot47Dot0Adapter.java new file mode 100644 index 0000000000..842294a5cc --- /dev/null +++ b/lib/src/compatKtLint0Dot47Dot0/java/com/diffplug/spotless/glue/ktlint/compat/KtLintCompat0Dot47Dot0Adapter.java @@ -0,0 +1,125 @@ +/* + * Copyright 2022 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.glue.ktlint.compat; + +import static java.util.Collections.emptySet; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.pinterest.ktlint.core.KtLint; +import com.pinterest.ktlint.core.LintError; +import com.pinterest.ktlint.core.Rule; +import com.pinterest.ktlint.core.RuleProvider; +import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties; +import com.pinterest.ktlint.core.api.EditorConfigDefaults; +import com.pinterest.ktlint.core.api.EditorConfigOverride; +import com.pinterest.ktlint.core.api.UsesEditorConfigProperties; +import com.pinterest.ktlint.ruleset.experimental.ExperimentalRuleSetProvider; +import com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider; + +import kotlin.Pair; +import kotlin.Unit; +import kotlin.jvm.functions.Function2; + +public class KtLintCompat0Dot47Dot0Adapter implements KtLintCompatAdapter { + + static class FormatterCallback implements Function2 { + @Override + public Unit invoke(LintError lint, Boolean corrected) { + if (!corrected) { + KtLintCompatReporting.report(lint.getLine(), lint.getCol(), lint.getRuleId(), lint.getDetail()); + } + return null; + } + } + + @Override + public String format(final String text, final String name, final boolean isScript, + final boolean useExperimental, + final Map userData, + final Map editorConfigOverrideMap) { + final FormatterCallback formatterCallback = new FormatterCallback(); + + Set allRuleProviders = new LinkedHashSet<>( + new StandardRuleSetProvider().getRuleProviders()); + if (useExperimental) { + allRuleProviders.addAll(new ExperimentalRuleSetProvider().getRuleProviders()); + } + + EditorConfigOverride editorConfigOverride; + if (editorConfigOverrideMap.isEmpty()) { + editorConfigOverride = EditorConfigOverride.Companion.getEmptyEditorConfigOverride(); + } else { + editorConfigOverride = createEditorConfigOverride(allRuleProviders.stream().map( + RuleProvider::createNewRuleInstance).collect( + Collectors.toList()), + editorConfigOverrideMap); + } + + return KtLint.INSTANCE.format(new KtLint.ExperimentalParams( + name, + text, + emptySet(), + allRuleProviders, + userData, + formatterCallback, + isScript, + null, + false, + EditorConfigDefaults.Companion.getEmptyEditorConfigDefaults(), + editorConfigOverride, + false)); + } + + /** + * Create EditorConfigOverride from user provided parameters. + * Calling this method requires KtLint 0.45.2. + */ + private static EditorConfigOverride createEditorConfigOverride(final List rules, Map editorConfigOverrideMap) { + // Get properties from rules in the rule sets + Stream> ruleProperties = rules.stream() + .filter(rule -> rule instanceof UsesEditorConfigProperties) + .flatMap(rule -> ((UsesEditorConfigProperties) rule).getEditorConfigProperties().stream()); + + // Create a mapping of properties to their names based on rule properties and default properties + Map> supportedProperties = Stream + .concat(ruleProperties, DefaultEditorConfigProperties.INSTANCE.getEditorConfigProperties().stream()) + .distinct() + .collect(Collectors.toMap(property -> property.getType().getName(), property -> property)); + + // Create config properties based on provided property names and values + @SuppressWarnings("unchecked") + Pair, ?>[] properties = editorConfigOverrideMap.entrySet().stream() + .map(entry -> { + UsesEditorConfigProperties.EditorConfigProperty property = supportedProperties.get(entry.getKey()); + if (property != null) { + return new Pair<>(property, entry.getValue()); + } else { + return null; + } + }) + .filter(Objects::nonNull) + .toArray(Pair[]::new); + + return EditorConfigOverride.Companion.from(properties); + } +} diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 2e7d5cf34b..5273e9c9c3 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changes * Extend minimum supported version for `ktlint` to `0.31.0` ([#xxx](https://github.com/diffplug/spotless/pull/xxx)). +* Support `ktlint` version 0.47.0 ([#xxx](https://github.com/diffplug/spotless/pull/xxx)) fixes [#1281](https://github.com/diffplug/spotless/issues/1281). ## [6.10.0] - 2022-08-23 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index b1fd561786..1f0eb90069 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ### Changes * Extend minimum supported version for `ktlint` to `0.31.0` ([#xxx](https://github.com/diffplug/spotless/pull/xxx)). +* Support `ktlint` version 0.47.0 ([#xxx](https://github.com/diffplug/spotless/pull/xxx)) fixes [#1281](https://github.com/diffplug/spotless/issues/1281). ## [2.25.0] - 2022-08-23 ### Added diff --git a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtLintStepTest.java b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtLintStepTest.java index 96c2ab885a..f82d61c078 100644 --- a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtLintStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtLintStepTest.java @@ -118,6 +118,19 @@ void works0_46_0() throws Exception { }); } + @Test + void works0_47_0() throws Exception { + FormatterStep step = KtLintStep.create("0.47.0", TestProvisioner.mavenCentral()); + StepHarness.forStep(step) + .testResource("kotlin/ktlint/basic.dirty", "kotlin/ktlint/basic.clean") + .testResourceException("kotlin/ktlint/unsolvable.dirty", assertion -> { + assertion.isInstanceOf(AssertionError.class); + assertion.hasMessage("Error on line: 1, column: 1\n" + + "rule: no-wildcard-imports\n" + + "Wildcard import"); + }); + } + @Test void equality() throws Exception { new SerializableEqualityTester() {