diff --git a/CHANGES.md b/CHANGES.md
index 81e67e1416..68764ad9bf 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -12,6 +12,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Changes
* Bump default `ktlint` version to latest `1.2.1` -> `1.3.0`. ([#2165](https://github.com/diffplug/spotless/pull/2165))
+* Bump default `ktfmt` version to latest `0.49` -> `0.51`. ([#2172](https://github.com/diffplug/spotless/pull/2172))
+* Renamed property `ktfmt` option `removeUnusedImport` -> `removeUnusedImports` to match `ktfmt`. ([#2172](https://github.com/diffplug/spotless/pull/2172))
+### Fixed
+* Fix compatibility issue introduced by `ktfmt` `0.51`. ([#2172](https://github.com/diffplug/spotless/issues/2172))
## [3.0.0.BETA1] - 2024-06-04
### Added
diff --git a/lib/build.gradle b/lib/build.gradle
index c82c648e07..24dddfe396 100644
--- a/lib/build.gradle
+++ b/lib/build.gradle
@@ -101,7 +101,7 @@ dependencies {
jacksonCompileOnly "com.fasterxml.jackson.core:jackson-databind:$VER_JACKSON"
jacksonCompileOnly "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$VER_JACKSON"
// ktfmt
- ktfmtCompileOnly "com.facebook:ktfmt:0.49"
+ ktfmtCompileOnly "com.facebook:ktfmt:0.51"
ktfmtCompileOnly("com.google.googlejavaformat:google-java-format") {
version {
strictly '1.7' // for JDK 8 compatibility
diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java
index 1d191c05d5..50925a5a5d 100644
--- a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java
+++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtFormatterFunc.java
@@ -15,8 +15,6 @@
*/
package com.diffplug.spotless.glue.ktfmt;
-import java.lang.reflect.Method;
-
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -34,7 +32,7 @@ public final class KtfmtFormatterFunc implements FormatterFunc {
private final KtfmtFormattingOptions ktfmtFormattingOptions;
public KtfmtFormatterFunc() {
- this(KtfmtStyle.DEFAULT, null);
+ this(KtfmtStyle.META, null);
}
public KtfmtFormatterFunc(@Nonnull KtfmtStyle style) {
@@ -42,7 +40,7 @@ public KtfmtFormatterFunc(@Nonnull KtfmtStyle style) {
}
public KtfmtFormatterFunc(@Nullable KtfmtFormattingOptions ktfmtFormattingOptions) {
- this(KtfmtStyle.DEFAULT, ktfmtFormattingOptions);
+ this(KtfmtStyle.META, ktfmtFormattingOptions);
}
public KtfmtFormatterFunc(@Nonnull KtfmtStyle style, @Nullable KtfmtFormattingOptions ktfmtFormattingOptions) {
@@ -59,11 +57,8 @@ public String apply(@Nonnull String input) throws Exception {
private FormattingOptions createFormattingOptions() throws Exception {
FormattingOptions formattingOptions;
switch (style) {
- case DEFAULT:
- formattingOptions = new FormattingOptions();
- break;
- case DROPBOX:
- formattingOptions = Formatter.DROPBOX_FORMAT;
+ case META:
+ formattingOptions = Formatter.META_FORMAT;
break;
case GOOGLE:
formattingOptions = Formatter.GOOGLE_FORMAT;
@@ -72,30 +67,17 @@ private FormattingOptions createFormattingOptions() throws Exception {
formattingOptions = Formatter.KOTLINLANG_FORMAT;
break;
default:
- throw new IllegalStateException("Unknown formatting option");
+ throw new IllegalStateException("Unknown formatting option " + style);
}
if (ktfmtFormattingOptions != null) {
- try {
- formattingOptions = formattingOptions.copy(
- formattingOptions.getStyle(),
- ktfmtFormattingOptions.getMaxWidth().orElse(formattingOptions.getMaxWidth()),
- ktfmtFormattingOptions.getBlockIndent().orElse(formattingOptions.getBlockIndent()),
- ktfmtFormattingOptions.getContinuationIndent().orElse(formattingOptions.getContinuationIndent()),
- ktfmtFormattingOptions.getRemoveUnusedImport().orElse(formattingOptions.getRemoveUnusedImports()),
- formattingOptions.getDebuggingPrintOpsAfterFormatting(),
- formattingOptions.getManageTrailingCommas());
- } catch (NoSuchMethodError e) {
- //noinspection JavaReflectionMemberAccess, ABI change from ktfmt 0.47
- Method copyMethod = formattingOptions.getClass().getMethod("copy", FormattingOptions.Style.class, int.class, int.class, int.class, boolean.class, boolean.class);
- formattingOptions = (FormattingOptions) copyMethod.invoke(formattingOptions,
- formattingOptions.getStyle(),
- ktfmtFormattingOptions.getMaxWidth().orElse(formattingOptions.getMaxWidth()),
- ktfmtFormattingOptions.getBlockIndent().orElse(formattingOptions.getBlockIndent()),
- ktfmtFormattingOptions.getContinuationIndent().orElse(formattingOptions.getContinuationIndent()),
- ktfmtFormattingOptions.getRemoveUnusedImport().orElse(formattingOptions.getRemoveUnusedImports()),
- formattingOptions.getDebuggingPrintOpsAfterFormatting());
- }
+ formattingOptions = formattingOptions.copy(
+ ktfmtFormattingOptions.getMaxWidth().orElse(formattingOptions.getMaxWidth()),
+ ktfmtFormattingOptions.getBlockIndent().orElse(formattingOptions.getBlockIndent()),
+ ktfmtFormattingOptions.getContinuationIndent().orElse(formattingOptions.getContinuationIndent()),
+ formattingOptions.getManageTrailingCommas(),
+ ktfmtFormattingOptions.getRemoveUnusedImport().orElse(formattingOptions.getRemoveUnusedImports()),
+ formattingOptions.getDebuggingPrintOpsAfterFormatting());
}
return formattingOptions;
diff --git a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java
index 34b81175ec..47aea7eedd 100644
--- a/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java
+++ b/lib/src/ktfmt/java/com/diffplug/spotless/glue/ktfmt/KtfmtStyle.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 DiffPlug
+ * Copyright 2022-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,5 +16,5 @@
package com.diffplug.spotless.glue.ktfmt;
public enum KtfmtStyle {
- DEFAULT, DROPBOX, GOOGLE, KOTLIN_LANG
+ META, GOOGLE, KOTLIN_LANG
}
diff --git a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java
index cf76d5f8ae..5e1cd7f00a 100644
--- a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java
+++ b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java
@@ -16,12 +16,15 @@
package com.diffplug.spotless.kotlin;
import static com.diffplug.spotless.kotlin.KtfmtStep.Style.DEFAULT;
+import static com.diffplug.spotless.kotlin.KtfmtStep.Style.DROPBOX;
+import static com.diffplug.spotless.kotlin.KtfmtStep.Style.META;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
+import java.util.Optional;
import javax.annotation.Nullable;
@@ -32,11 +35,11 @@
import com.diffplug.spotless.ThrowingEx;
/**
- * Wraps up ktfmt as a FormatterStep.
+ * Wraps up ktfmt as a FormatterStep.
*/
public class KtfmtStep implements Serializable {
private static final long serialVersionUID = 1L;
- private static final String DEFAULT_VERSION = "0.49";
+ private static final String DEFAULT_VERSION = "0.51";
private static final String NAME = "ktfmt";
private static final String MAVEN_COORDINATE = "com.facebook:ktfmt:";
@@ -64,17 +67,32 @@ private KtfmtStep(String version,
/**
* Used to allow multiple style option through formatting options and since when is each of them available.
*
- * @see ktfmt source
+ * @see ktfmt source
*/
public enum Style {
- DEFAULT("DEFAULT_FORMAT", "0.0"), DROPBOX("DROPBOX_FORMAT", "0.11"), GOOGLE("GOOGLE_FORMAT", "0.21"), KOTLINLANG("KOTLINLANG_FORMAT", "0.21");
+ // @formatter:off
+ DEFAULT("DEFAULT_FORMAT", "0.0", "0.50"),
+ META("META_FORMAT", "0.51"),
+ DROPBOX("DROPBOX_FORMAT", "0.16", "0.50"),
+ GOOGLE("GOOGLE_FORMAT", "0.19"),
+ KOTLINLANG("KOTLINLANG_FORMAT", "0.21"),
+ ;
+ // @formatter:on
final private String format;
final private String since;
+ final private @Nullable String until;
Style(String format, String since) {
this.format = format;
this.since = since;
+ this.until = null;
+ }
+
+ Style(String format, String since, @Nullable String until) {
+ this.format = format;
+ this.since = since;
+ this.until = until;
}
String getFormat() {
@@ -84,6 +102,12 @@ String getFormat() {
String getSince() {
return since;
}
+
+ /** Last version (inclusive) that supports this style */
+ @Nullable
+ String getUntil() {
+ return until;
+ }
}
public static class KtfmtFormattingOptions implements Serializable {
@@ -100,7 +124,7 @@ public static class KtfmtFormattingOptions implements Serializable {
private Integer continuationIndent = null;
@Nullable
- private Boolean removeUnusedImport = null;
+ private Boolean removeUnusedImports = null;
public KtfmtFormattingOptions() {}
@@ -108,11 +132,11 @@ public KtfmtFormattingOptions(
@Nullable Integer maxWidth,
@Nullable Integer blockIndent,
@Nullable Integer continuationIndent,
- @Nullable Boolean removeUnusedImport) {
+ @Nullable Boolean removeUnusedImports) {
this.maxWidth = maxWidth;
this.blockIndent = blockIndent;
this.continuationIndent = continuationIndent;
- this.removeUnusedImport = removeUnusedImport;
+ this.removeUnusedImports = removeUnusedImports;
}
public void setMaxWidth(int maxWidth) {
@@ -127,18 +151,11 @@ public void setContinuationIndent(int continuationIndent) {
this.continuationIndent = continuationIndent;
}
- public void setRemoveUnusedImport(boolean removeUnusedImport) {
- this.removeUnusedImport = removeUnusedImport;
+ public void setRemoveUnusedImports(boolean removeUnusedImports) {
+ this.removeUnusedImports = removeUnusedImports;
}
}
- /**
- * The format
method is available in the link below.
- *
- * @see ktfmt source
- */
- static final String FORMATTER_METHOD = "format";
-
/** Creates a step which formats everything - code, import order, and unused imports. */
public static FormatterStep create(Provisioner provisioner) {
return create(defaultVersion(), provisioner);
@@ -169,7 +186,6 @@ private State equalityState() {
private static final class State implements Serializable {
private static final long serialVersionUID = 1L;
- private static final String PACKAGE = "com.facebook.ktfmt";
private final String version;
@Nullable
private final Style style;
@@ -185,16 +201,15 @@ private static final class State implements Serializable {
this.options = options;
this.style = style;
this.jarState = jarState;
+ validateStyle();
+ validateOptions();
}
FormatterFunc createFormat() throws Exception {
final ClassLoader classLoader = jarState.getClassLoader();
- if (BadSemver.version(version) < BadSemver.version(0, 32)) {
- if (options != null) {
- throw new IllegalStateException("Ktfmt formatting options supported for version 0.32 and later");
- }
- return getFormatterFuncFallback(style != null ? style : DEFAULT, classLoader);
+ if (BadSemver.version(version) < BadSemver.version(0, 51)) {
+ return new KtfmtFormatterFuncCompat(version, style, options, classLoader).getFormatterFunc();
}
final Class> formatterFuncClass = classLoader.loadClass("com.diffplug.spotless.glue.ktfmt.KtfmtFormatterFunc");
@@ -215,7 +230,7 @@ FormatterFunc createFormat() throws Exception {
final Constructor> optionsConstructor = ktfmtFormattingOptionsClass.getConstructor(
Integer.class, Integer.class, Integer.class, Boolean.class);
final Object ktfmtFormattingOptions = optionsConstructor.newInstance(
- options.maxWidth, options.blockIndent, options.continuationIndent, options.removeUnusedImport);
+ options.maxWidth, options.blockIndent, options.continuationIndent, options.removeUnusedImports);
if (style == null) {
final Constructor> constructor = formatterFuncClass.getConstructor(ktfmtFormattingOptionsClass);
return (FormatterFunc) constructor.newInstance(ktfmtFormattingOptions);
@@ -225,16 +240,42 @@ FormatterFunc createFormat() throws Exception {
return (FormatterFunc) constructor.newInstance(ktfmtStyle, ktfmtFormattingOptions);
}
+ private void validateOptions() {
+ if (BadSemver.version(version) < BadSemver.version(0, 11)) {
+ if (options != null) {
+ throw new IllegalStateException("Ktfmt formatting options supported for version 0.11 and later");
+ }
+ return;
+ }
+
+ if (BadSemver.version(version) < BadSemver.version(0, 17)) {
+ if (options != null && options.removeUnusedImports != null) {
+ throw new IllegalStateException("Ktfmt formatting option `removeUnusedImports` supported for version 0.17 and later");
+ }
+ }
+ }
+
+ private void validateStyle() {
+ if (style == null) {
+ return;
+ }
+
+ if (BadSemver.version(version) < BadSemver.version(style.since)) {
+ throw new IllegalStateException(String.format("The style %s is available from version %s (current version: %s)", style.name(), style.since, version));
+ }
+ if (style.until != null && BadSemver.version(version) > BadSemver.version(style.until)) {
+ throw new IllegalStateException(String.format("The style %s is no longer available from version %s (current version: %s)", style.name(), style.until, version));
+ }
+ }
+
/**
* @param style
* @return com.diffplug.spotless.glue.ktfmt.KtfmtStyle enum value name
*/
private String getKtfmtStyleOption(Style style) {
switch (style) {
- case DEFAULT:
- return "DEFAULT";
- case DROPBOX:
- return "DROPBOX";
+ case META:
+ return "META";
case GOOGLE:
return "GOOGLE";
case KOTLINLANG:
@@ -243,48 +284,117 @@ private String getKtfmtStyleOption(Style style) {
throw new IllegalStateException("Unsupported style: " + style);
}
}
+ }
+
+ private static final class KtfmtFormatterFuncCompat {
+ private static final String PACKAGE = "com.facebook.ktfmt";
+
+ /**
+ * The format
method is available in the link below.
+ *
+ * @see ktfmt source
+ */
+ static final String FORMATTER_METHOD = "format";
+
+ private final String version;
+ private final Style style;
+ private final KtfmtFormattingOptions options;
+ private final ClassLoader classLoader;
+
+ public KtfmtFormatterFuncCompat(String currentVersion, @Nullable Style style, @Nullable KtfmtFormattingOptions options, ClassLoader classLoader) {
+ this.version = currentVersion;
+ this.style = style;
+ this.options = options;
+ this.classLoader = classLoader;
+ }
- private FormatterFunc getFormatterFuncFallback(Style style, ClassLoader classLoader) {
+ public FormatterFunc getFormatterFunc() {
return input -> {
try {
- if (style == DEFAULT) {
- Method formatterMethod = getFormatterClazz(classLoader).getMethod(FORMATTER_METHOD, String.class);
- return (String) formatterMethod.invoke(getFormatterClazz(classLoader), input);
- } else {
- Method formatterMethod = getFormatterClazz(classLoader).getMethod(FORMATTER_METHOD,
- getFormattingOptionsClazz(classLoader),
- String.class);
- Object formattingOptions = getCustomFormattingOptions(classLoader, style);
- return (String) formatterMethod.invoke(getFormatterClazz(classLoader), formattingOptions, input);
- }
+ return applyFormat(input);
} catch (InvocationTargetException e) {
throw ThrowingEx.unwrapCause(e);
}
};
}
- private Object getCustomFormattingOptions(ClassLoader classLoader, Style style) throws Exception {
- if (BadSemver.version(version) < BadSemver.version(style.since)) {
- throw new IllegalStateException(String.format("The style %s is available from version %s (current version: %s)", style.name(), style.since, version));
+ protected String applyFormat(String input) throws Exception {
+ Class> formatterClass = getFormatterClazz();
+ if (style == null && options == null || style == DEFAULT) {
+ Method formatterMethod = formatterClass.getMethod(FORMATTER_METHOD, String.class);
+ return (String) formatterMethod.invoke(formatterClass, input);
+ } else {
+ Method formatterMethod = formatterClass.getMethod(FORMATTER_METHOD, getFormattingOptionsClazz(), String.class);
+ Object formattingOptions = getCustomFormattingOptions(formatterClass);
+ return (String) formatterMethod.invoke(formatterClass, formattingOptions, input);
+ }
+ }
+
+ private Object getCustomFormattingOptions(Class> formatterClass) throws Exception {
+ Object formattingOptions = getFormattingOptionsFromStyle(formatterClass);
+ Class> formattingOptionsClass = formattingOptions.getClass();
+
+ if (options != null) {
+ if (BadSemver.version(version) < BadSemver.version(0, 17)) {
+ formattingOptions = formattingOptions.getClass().getConstructor(int.class, int.class, int.class).newInstance(
+ /* maxWidth = */ Optional.ofNullable(options.maxWidth).orElse((Integer) formattingOptionsClass.getMethod("getMaxWidth").invoke(formattingOptions)),
+ /* blockIndent = */ Optional.ofNullable(options.blockIndent).orElse((Integer) formattingOptionsClass.getMethod("getBlockIndent").invoke(formattingOptions)),
+ /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)));
+ } else if (BadSemver.version(version) < BadSemver.version(0, 19)) {
+ formattingOptions = formattingOptions.getClass().getConstructor(int.class, int.class, int.class, boolean.class, boolean.class).newInstance(
+ /* maxWidth = */ Optional.ofNullable(options.maxWidth).orElse((Integer) formattingOptionsClass.getMethod("getMaxWidth").invoke(formattingOptions)),
+ /* blockIndent = */ Optional.ofNullable(options.blockIndent).orElse((Integer) formattingOptionsClass.getMethod("getBlockIndent").invoke(formattingOptions)),
+ /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)),
+ /* removeUnusedImports = */ Optional.ofNullable(options.removeUnusedImports).orElse((Boolean) formattingOptionsClass.getMethod("getRemoveUnusedImports").invoke(formattingOptions)),
+ /* debuggingPrintOpsAfterFormatting = */ (Boolean) formattingOptionsClass.getMethod("getDebuggingPrintOpsAfterFormatting").invoke(formattingOptions));
+ } else if (BadSemver.version(version) < BadSemver.version(0, 47)) {
+ Class> styleClass = classLoader.loadClass(formattingOptionsClass.getName() + "$Style");
+ formattingOptions = formattingOptions.getClass().getConstructor(styleClass, int.class, int.class, int.class, boolean.class, boolean.class).newInstance(
+ /* style = */ formattingOptionsClass.getMethod("getStyle").invoke(formattingOptions),
+ /* maxWidth = */ Optional.ofNullable(options.maxWidth).orElse((Integer) formattingOptionsClass.getMethod("getMaxWidth").invoke(formattingOptions)),
+ /* blockIndent = */ Optional.ofNullable(options.blockIndent).orElse((Integer) formattingOptionsClass.getMethod("getBlockIndent").invoke(formattingOptions)),
+ /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)),
+ /* removeUnusedImports = */ Optional.ofNullable(options.removeUnusedImports).orElse((Boolean) formattingOptionsClass.getMethod("getRemoveUnusedImports").invoke(formattingOptions)),
+ /* debuggingPrintOpsAfterFormatting = */ (Boolean) formattingOptionsClass.getMethod("getDebuggingPrintOpsAfterFormatting").invoke(formattingOptions));
+ } else {
+ Class> styleClass = classLoader.loadClass(formattingOptionsClass.getName() + "$Style");
+ formattingOptions = formattingOptions.getClass().getConstructor(styleClass, int.class, int.class, int.class, boolean.class, boolean.class, boolean.class).newInstance(
+ /* style = */ formattingOptionsClass.getMethod("getStyle").invoke(formattingOptions),
+ /* maxWidth = */ Optional.ofNullable(options.maxWidth).orElse((Integer) formattingOptionsClass.getMethod("getMaxWidth").invoke(formattingOptions)),
+ /* blockIndent = */ Optional.ofNullable(options.blockIndent).orElse((Integer) formattingOptionsClass.getMethod("getBlockIndent").invoke(formattingOptions)),
+ /* continuationIndent = */ Optional.ofNullable(options.continuationIndent).orElse((Integer) formattingOptionsClass.getMethod("getContinuationIndent").invoke(formattingOptions)),
+ /* removeUnusedImports = */ Optional.ofNullable(options.removeUnusedImports).orElse((Boolean) formattingOptionsClass.getMethod("getRemoveUnusedImports").invoke(formattingOptions)),
+ /* debuggingPrintOpsAfterFormatting = */ (Boolean) formattingOptionsClass.getMethod("getDebuggingPrintOpsAfterFormatting").invoke(formattingOptions),
+ /* manageTrailingCommas */ (Boolean) formattingOptionsClass.getMethod("getManageTrailingCommas").invoke(formattingOptions));
+ }
}
- try {
- // ktfmt v0.19 and later
- return getFormatterClazz(classLoader).getField(style.getFormat()).get(null);
- } catch (NoSuchFieldException ignored) {}
+ return formattingOptions;
+ }
- // fallback to old, pre-0.19 ktfmt interface.
- if (style == Style.DEFAULT || style == Style.DROPBOX) {
+ private Object getFormattingOptionsFromStyle(Class> formatterClass) throws Exception {
+ Style style = this.style;
+ if (style == null) {
+ if (BadSemver.version(version) < BadSemver.version(0, 51)) {
+ style = DEFAULT;
+ } else {
+ style = META;
+ }
+ }
+ if (BadSemver.version(version) < BadSemver.version(0, 19)) {
+ if (style != DROPBOX) {
+ throw new IllegalStateException("Invalid style " + style + " for version " + version);
+ }
Class> formattingOptionsCompanionClazz = classLoader.loadClass(PACKAGE + ".FormattingOptions$Companion");
Object companion = formattingOptionsCompanionClazz.getConstructors()[0].newInstance((Object) null);
Method formattingOptionsMethod = formattingOptionsCompanionClazz.getDeclaredMethod("dropboxStyle");
return formattingOptionsMethod.invoke(companion);
} else {
- throw new IllegalStateException("Versions pre-0.19 can only use Default and Dropbox styles");
+ return formatterClass.getField(style.getFormat()).get(null);
}
}
- private Class> getFormatterClazz(ClassLoader classLoader) throws Exception {
+ private Class> getFormatterClazz() throws Exception {
Class> formatterClazz;
if (BadSemver.version(version) >= BadSemver.version(0, 31)) {
formatterClazz = classLoader.loadClass(PACKAGE + ".format.Formatter");
@@ -294,7 +404,7 @@ private Class> getFormatterClazz(ClassLoader classLoader) throws Exception {
return formatterClazz;
}
- private Class> getFormattingOptionsClazz(ClassLoader classLoader) throws Exception {
+ private Class> getFormattingOptionsClazz() throws Exception {
Class> formattingOptionsClazz;
if (BadSemver.version(version) >= BadSemver.version(0, 31)) {
formattingOptionsClazz = classLoader.loadClass(PACKAGE + ".format.FormattingOptions");
diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md
index b09160fd73..2968e11403 100644
--- a/plugin-gradle/CHANGES.md
+++ b/plugin-gradle/CHANGES.md
@@ -5,6 +5,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Changes
* Bump default `ktlint` version to latest `1.2.1` -> `1.3.0`. ([#2165](https://github.com/diffplug/spotless/pull/2165))
+* Bump default `ktfmt` version to latest `0.49` -> `0.51`. ([#2172](https://github.com/diffplug/spotless/pull/2172))
+* Renamed property `ktfmt` option `removeUnusedImport` -> `removeUnusedImports` to match `ktfmt`. ([#2172](https://github.com/diffplug/spotless/pull/2172))
+### Fixed
+* Fix compatibility issue introduced by `ktfmt` `0.51`. ([#2172](https://github.com/diffplug/spotless/issues/2172))
## [7.0.0.BETA1] - 2024-06-04
### Added
diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md
index 117974ba10..e10a333e8c 100644
--- a/plugin-gradle/README.md
+++ b/plugin-gradle/README.md
@@ -388,12 +388,20 @@ spotless { // if you are using build.gradle.kts, instead of 'spotless {' use:
### ktfmt
-[homepage](https://github.com/facebookincubator/ktfmt). [changelog](https://github.com/facebookincubator/ktfmt/releases).
+[homepage](https://github.com/facebook/ktfmt). [changelog](https://github.com/facebook/ktfmt/releases).
```kotlin
spotless {
kotlin {
- ktfmt('0.30').dropboxStyle() // version and dropbox style are optional
+ // version, style and all configurations here are optional
+ ktfmt("0.51").googleStyle().configure {
+ it.setMaxWidth(80)
+ it.setBlockIndent(4)
+ it.setContinuationIndent(4)
+ it.setRemoveUnusedImports(false)
+ }
+ }
+}
```
diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java
index 4be814a470..8d9a36c804 100644
--- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java
+++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 DiffPlug
+ * Copyright 2023-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,13 +56,13 @@ public KtlintConfig ktlint(String version) throws IOException {
return new KtlintConfig(version, Collections.emptyMap(), Collections.emptyList());
}
- /** Uses the ktfmt jar to format source code. */
+ /** Uses the ktfmt jar to format source code. */
public KtfmtConfig ktfmt() {
return ktfmt(KtfmtStep.defaultVersion());
}
/**
- * Uses the given version of ktfmt and applies the dropbox style
+ * Uses the given version of ktfmt and applies the dropbox style
* option to format source code.
*/
public KtfmtConfig ktfmt(String version) {
@@ -109,6 +109,10 @@ private KtfmtConfig(String version) {
addStep(createStep());
}
+ public ConfigurableStyle metaStyle() {
+ return style(KtfmtStep.Style.META);
+ }
+
public ConfigurableStyle dropboxStyle() {
return style(KtfmtStep.Style.DROPBOX);
}
diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java
index 9720276e15..c2293ab76d 100644
--- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java
+++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java
@@ -54,11 +54,11 @@ void integrationKtfmtDropboxStyleWithPublicApi() throws IOException {
"repositories { mavenCentral() }",
"spotless {",
" kotlin {",
- " ktfmt().dropboxStyle().configure {",
+ " ktfmt(\"0.50\").dropboxStyle().configure {",
" it.setMaxWidth(4)",
" it.setBlockIndent(4)",
" it.setContinuationIndent(4)",
- " it.setRemoveUnusedImport(false)",
+ " it.setRemoveUnusedImports(false)",
" }",
" }",
"}");
diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md
index 886dfdf753..d5b511d4c3 100644
--- a/plugin-maven/CHANGES.md
+++ b/plugin-maven/CHANGES.md
@@ -5,6 +5,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Changes
* Bump default `ktlint` version to latest `1.2.1` -> `1.3.0`. ([#2165](https://github.com/diffplug/spotless/pull/2165))
+* Bump default `ktfmt` version to latest `0.49` -> `0.51`. ([#2172](https://github.com/diffplug/spotless/pull/2172))
+* Renamed property `ktfmt` option `removeUnusedImport` -> `removeUnusedImports` to match `ktfmt`. ([#2172](https://github.com/diffplug/spotless/pull/2172))
+### Fixed
+* Fix compatibility issue introduced by `ktfmt` `0.51`. ([#2172](https://github.com/diffplug/spotless/issues/2172))
## [2.44.0.BETA1] - 2024-06-04
### Added
diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index 12efe3d5bd..5ba1ae7db8 100644
--- a/plugin-maven/README.md
+++ b/plugin-maven/README.md
@@ -392,12 +392,16 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T
### ktfmt
-[homepage](https://github.com/facebookincubator/ktfmt). [changelog](https://github.com/facebookincubator/ktfmt/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java).
+[homepage](https://github.com/facebook/ktfmt). [changelog](https://github.com/facebook/ktfmt/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java).
```xml
- 0.39
-
+ 0.51
+
+ 120
+ 4
+ 8
+ false
```
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java
index b917d33a44..7bd420f1ee 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2022 DiffPlug
+ * Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,13 +42,13 @@ public class Ktfmt implements FormatterStepFactory {
private Integer continuationIndent;
@Parameter
- private Boolean removeUnusedImport;
+ private Boolean removeUnusedImports;
@Override
public FormatterStep newFormatterStep(FormatterStepConfig config) {
String version = this.version != null ? this.version : KtfmtStep.defaultVersion();
Style style = this.style != null ? Style.valueOf(this.style) : null;
- KtfmtFormattingOptions options = new KtfmtFormattingOptions(maxWidth, blockIndent, continuationIndent, removeUnusedImport);
+ KtfmtFormattingOptions options = new KtfmtFormattingOptions(maxWidth, blockIndent, continuationIndent, removeUnusedImports);
return KtfmtStep.create(version, config.getProvisioner(), style, options);
}
}
diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java
index e452c5d56b..48b43bfcb1 100644
--- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java
+++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2023 DiffPlug
+ * Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ void testContinuation() throws Exception {
@Test
void testKtfmtStyle() throws Exception {
- writePomWithKotlinSteps("");
+ writePomWithKotlinSteps("0.50");
setFile("src/main/kotlin/main.kt").toResource("kotlin/ktfmt/basic.dirty");
mavenRunner().withArguments("spotless:apply").runNoError();
@@ -65,7 +65,7 @@ void testKtfmtWithMaxWidthOption() throws Exception {
@Test
void testKtfmtStyleWithMaxWidthOption() throws Exception {
- writePomWithKotlinSteps("120");
+ writePomWithKotlinSteps("0.17120");
setFile("src/main/kotlin/main.kt").toResource("kotlin/ktfmt/max-width.dirty");
mavenRunner().withArguments("spotless:apply").runNoError();
diff --git a/testlib/build.gradle b/testlib/build.gradle
index 38e598369e..08e735bced 100644
--- a/testlib/build.gradle
+++ b/testlib/build.gradle
@@ -30,9 +30,10 @@ spotbugs {
apply from: rootProject.file('gradle/special-tests.gradle')
tasks.withType(Test).configureEach {
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
- // for Antlr4FormatterStepTest and KtLintStepTest
+ // for Antlr4FormatterStepTest, KtfmtStepTest, and KtLintStepTest
def args = [
- '--add-opens=java.base/java.lang=ALL-UNNAMED'
+ '--add-opens=java.base/java.lang=ALL-UNNAMED',
+ '--add-opens=java.base/java.util=ALL-UNNAMED',
]
jvmArgs args
}
diff --git a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java
index e9458c9d39..f4f6e0b651 100644
--- a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java
+++ b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java
@@ -34,9 +34,31 @@ void behaviorWithOptions() {
StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic.clean");
}
+ @Test
+ void dropboxStyle_0_16() throws Exception {
+ KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions();
+ FormatterStep step = KtfmtStep.create("0.16", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, options);
+ StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic-dropboxstyle.clean");
+ }
+
@Test
void dropboxStyle_0_18() throws Exception {
- FormatterStep step = KtfmtStep.create("0.18", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, null);
+ KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions();
+ FormatterStep step = KtfmtStep.create("0.18", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, options);
+ StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic-dropboxstyle.clean");
+ }
+
+ @Test
+ void dropboxStyle_0_22() throws Exception {
+ KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions();
+ FormatterStep step = KtfmtStep.create("0.22", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, options);
+ StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic-dropboxstyle.clean");
+ }
+
+ @Test
+ void dropboxStyle_0_50() throws Exception {
+ KtfmtStep.KtfmtFormattingOptions options = new KtfmtStep.KtfmtFormattingOptions();
+ FormatterStep step = KtfmtStep.create("0.50", TestProvisioner.mavenCentral(), KtfmtStep.Style.DROPBOX, options);
StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic-dropboxstyle.clean");
}