Skip to content

Commit 712d77a

Browse files
committed
Merge ../spotless into typeAnnotations
2 parents 42edcb1 + 753f8f7 commit 712d77a

File tree

21 files changed

+167
-288
lines changed

21 files changed

+167
-288
lines changed

CHANGES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1313
### Added
1414
* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275))
1515

16+
## [2.29.0] - 2022-08-23
17+
### Added
18+
* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact ([#1283](https://github.com/diffplug/spotless/pull/1283))
19+
* Converted `scalafmt` integration to use a compile-only source set (fixes [#524](https://github.com/diffplug/spotless/issues/524))
20+
### Changes
21+
* Add the `ktlint` rule in error messages when `ktlint` fails to apply a fix ([#1279](https://github.com/diffplug/spotless/pull/1279))
22+
* Bump default `scalafmt` to latest `3.0.8` -> `3.5.9` (removed support for pre-`3.0.0`) ([#1283](https://github.com/diffplug/spotless/pull/1283))
23+
1624
## [2.28.1] - 2022-08-10
1725
### Fixed
1826
* Fix Clang not knowing the filename and changing the format ([#1268](https://github.com/diffplug/spotless/pull/1268) fixes [#1267](https://github.com/diffplug/spotless/issues/1267)).

lib/build.gradle

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ def NEEDS_GLUE = [
1212
'ktfmt',
1313
'ktlint',
1414
'flexmark',
15-
'diktat'
15+
'diktat',
16+
'scalafmt'
1617
]
1718
for (glue in NEEDS_GLUE) {
1819
sourceSets.register(glue) {
@@ -23,7 +24,7 @@ for (glue in NEEDS_GLUE) {
2324
}
2425

2526
dependencies {
26-
compileOnly 'org.slf4j:slf4j-api:1.7.36'
27+
compileOnly 'org.slf4j:slf4j-api:2.0.0'
2728
// zero runtime reqs is a hard requirements for spotless-lib
2829
// if you need a dep, put it in lib-extra
2930
testImplementation "org.junit.jupiter:junit-jupiter:$VER_JUNIT"
@@ -32,7 +33,7 @@ dependencies {
3233

3334
// used for pom sorting
3435
sortPomCompileOnly 'com.github.ekryd.sortpom:sortpom-sorter:3.0.0'
35-
sortPomCompileOnly 'org.slf4j:slf4j-api:1.7.35'
36+
sortPomCompileOnly 'org.slf4j:slf4j-api:2.0.0'
3637

3738
palantirJavaFormatCompileOnly 'com.palantir.javaformat:palantir-java-format:1.1.0'
3839

@@ -51,6 +52,9 @@ dependencies {
5152
ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-experimental:$VER_KTLINT"
5253
ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-standard:$VER_KTLINT"
5354

55+
String VER_SCALAFMT="3.5.9"
56+
scalafmtCompileOnly "org.scalameta:scalafmt-core_2.13:$VER_SCALAFMT"
57+
5458
String VER_DIKTAT = "1.2.3"
5559
diktatCompileOnly "org.cqfn.diktat:diktat-rules:$VER_DIKTAT"
5660

lib/src/ktlint/java/com/diffplug/spotless/glue/ktlint/KtlintFormatterFunc.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ static class FormatterCallback implements Function2<LintError, Boolean, Unit> {
111111
@Override
112112
public Unit invoke(LintError lint, Boolean corrected) {
113113
if (!corrected) {
114-
throw new AssertionError("Error on line: " + lint.getLine() + ", column: " + lint.getCol() + "\n" + lint.getDetail());
114+
throw new AssertionError("Error on line: " + lint.getLine() + ", column: " + lint.getCol() + "\nrule: " + lint.getRuleId() + "\n" + lint.getDetail());
115115
}
116116
return null;
117117
}
Lines changed: 24 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2022 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,13 +18,8 @@
1818
import java.io.File;
1919
import java.io.IOException;
2020
import java.io.Serializable;
21-
import java.lang.reflect.Method;
22-
import java.nio.charset.StandardCharsets;
23-
import java.nio.file.Files;
21+
import java.lang.reflect.Constructor;
2422
import java.util.Collections;
25-
import java.util.Objects;
26-
import java.util.regex.Matcher;
27-
import java.util.regex.Pattern;
2823

2924
import javax.annotation.Nullable;
3025

@@ -39,108 +34,52 @@ public class ScalaFmtStep {
3934
// prevent direct instantiation
4035
private ScalaFmtStep() {}
4136

42-
private static final Pattern VERSION_PRE_2_0 = Pattern.compile("[10]\\.(\\d+)\\.\\d+");
43-
private static final Pattern VERSION_PRE_3_0 = Pattern.compile("2\\.(\\d+)\\.\\d+");
44-
private static final String DEFAULT_VERSION = "3.0.8";
37+
private static final String DEFAULT_VERSION = "3.5.9";
38+
39+
private static final String DEFAULT_SCALA_MAJOR_VERSION = "2.13";
4540
static final String NAME = "scalafmt";
46-
static final String MAVEN_COORDINATE_PRE_2_0 = "com.geirsson:scalafmt-core_2.11:";
47-
static final String MAVEN_COORDINATE_PRE_3_0 = "org.scalameta:scalafmt-core_2.11:";
48-
static final String MAVEN_COORDINATE = "org.scalameta:scalafmt-core_2.13:";
41+
static final String MAVEN_COORDINATE = "org.scalameta:scalafmt-core_";
4942

5043
public static FormatterStep create(Provisioner provisioner) {
51-
return create(defaultVersion(), provisioner, null);
44+
return create(defaultVersion(), defaultScalaMajorVersion(), provisioner, null);
5245
}
5346

5447
public static FormatterStep create(String version, Provisioner provisioner, @Nullable File configFile) {
55-
Objects.requireNonNull(version, "version");
56-
Objects.requireNonNull(provisioner, "provisioner");
48+
return create(version, defaultScalaMajorVersion(), provisioner, configFile);
49+
}
50+
51+
public static FormatterStep create(String version, @Nullable String scalaMajorVersion, Provisioner provisioner, @Nullable File configFile) {
52+
String finalScalaMajorVersion = scalaMajorVersion == null ? DEFAULT_SCALA_MAJOR_VERSION : scalaMajorVersion;
53+
5754
return FormatterStep.createLazy(NAME,
58-
() -> new State(version, provisioner, configFile),
55+
() -> new State(JarState.from(MAVEN_COORDINATE + finalScalaMajorVersion + ":" + version, provisioner), configFile),
5956
State::createFormat);
6057
}
6158

6259
public static String defaultVersion() {
6360
return DEFAULT_VERSION;
6461
}
6562

63+
public static String defaultScalaMajorVersion() {
64+
return DEFAULT_SCALA_MAJOR_VERSION;
65+
}
66+
6667
static final class State implements Serializable {
6768
private static final long serialVersionUID = 1L;
6869

6970
final JarState jarState;
7071
final FileSignature configSignature;
7172

72-
State(String version, Provisioner provisioner, @Nullable File configFile) throws IOException {
73-
String mavenCoordinate;
74-
Matcher versionMatcher;
75-
if ((versionMatcher = VERSION_PRE_2_0.matcher(version)).matches()) {
76-
mavenCoordinate = MAVEN_COORDINATE_PRE_2_0;
77-
} else if ((versionMatcher = VERSION_PRE_3_0.matcher(version)).matches()) {
78-
mavenCoordinate = MAVEN_COORDINATE_PRE_3_0;
79-
} else {
80-
mavenCoordinate = MAVEN_COORDINATE;
81-
}
82-
83-
this.jarState = JarState.from(mavenCoordinate + version, provisioner);
73+
State(JarState jarState, @Nullable File configFile) throws IOException {
74+
this.jarState = jarState;
8475
this.configSignature = FileSignature.signAsList(configFile == null ? Collections.emptySet() : Collections.singleton(configFile));
8576
}
8677

8778
FormatterFunc createFormat() throws Exception {
88-
ClassLoader classLoader = jarState.getClassLoader();
89-
90-
// scalafmt returns instances of formatted, we get result by calling get()
91-
Class<?> formatted = classLoader.loadClass("org.scalafmt.Formatted");
92-
Method formattedGet = formatted.getMethod("get");
93-
94-
// this is how we actually do a format
95-
Class<?> scalafmt = classLoader.loadClass("org.scalafmt.Scalafmt");
96-
Class<?> scalaSet = classLoader.loadClass("scala.collection.immutable.Set");
97-
98-
Object defaultScalaFmtConfig = scalafmt.getMethod("format$default$2").invoke(null);
99-
Object emptyRange = scalafmt.getMethod("format$default$3").invoke(null);
100-
Method formatMethod = scalafmt.getMethod("format", String.class, defaultScalaFmtConfig.getClass(), scalaSet);
101-
102-
// now we just need to parse the config, if any
103-
Object config;
104-
if (configSignature.files().isEmpty()) {
105-
config = defaultScalaFmtConfig;
106-
} else {
107-
File file = configSignature.getOnlyFile();
108-
109-
Class<?> optionCls = classLoader.loadClass("scala.Option");
110-
Class<?> configCls = classLoader.loadClass("org.scalafmt.config.Config");
111-
Class<?> scalafmtCls = classLoader.loadClass("org.scalafmt.Scalafmt");
112-
113-
Object configured;
114-
115-
try {
116-
// scalafmt >= 1.6.0
117-
Method parseHoconConfig = scalafmtCls.getMethod("parseHoconConfig", String.class);
118-
119-
String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
120-
121-
configured = parseHoconConfig.invoke(null, configStr);
122-
} catch (NoSuchMethodException e) {
123-
// scalafmt >= v0.7.0-RC1 && scalafmt < 1.6.0
124-
Method fromHocon = configCls.getMethod("fromHoconString", String.class, optionCls);
125-
Object fromHoconEmptyPath = configCls.getMethod("fromHoconString$default$2").invoke(null);
126-
127-
String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
128-
129-
configured = fromHocon.invoke(null, configStr, fromHoconEmptyPath);
130-
}
131-
132-
config = invokeNoArg(configured, "get");
133-
}
134-
return input -> {
135-
Object resultInsideFormatted = formatMethod.invoke(null, input, config, emptyRange);
136-
return (String) formattedGet.invoke(resultInsideFormatted);
137-
};
79+
final ClassLoader classLoader = jarState.getClassLoader();
80+
final Class<?> formatterFunc = classLoader.loadClass("com.diffplug.spotless.glue.scalafmt.ScalafmtFormatterFunc");
81+
final Constructor<?> constructor = formatterFunc.getConstructor(FileSignature.class);
82+
return (FormatterFunc) constructor.newInstance(this.configSignature);
13883
}
13984
}
140-
141-
private static Object invokeNoArg(Object obj, String toInvoke) throws Exception {
142-
Class<?> clazz = obj.getClass();
143-
Method method = clazz.getMethod(toInvoke);
144-
return method.invoke(obj);
145-
}
14685
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2022 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.glue.scalafmt;
17+
18+
import java.io.File;
19+
import java.lang.reflect.Method;
20+
import java.nio.charset.StandardCharsets;
21+
import java.nio.file.Files;
22+
23+
import org.scalafmt.Scalafmt;
24+
import org.scalafmt.config.ScalafmtConfig;
25+
import org.scalafmt.config.ScalafmtConfig$;
26+
27+
import com.diffplug.spotless.FileSignature;
28+
import com.diffplug.spotless.FormatterFunc;
29+
30+
import scala.collection.immutable.Set$;
31+
32+
public class ScalafmtFormatterFunc implements FormatterFunc {
33+
private final ScalafmtConfig config;
34+
35+
public ScalafmtFormatterFunc(FileSignature configSignature) throws Exception {
36+
if (configSignature.files().isEmpty()) {
37+
// Note that reflection is used here only because Scalafmt has a method called
38+
// default which happens to be a reserved Java keyword. The only way to call
39+
// such methods is by reflection, see
40+
// https://vlkan.com/blog/post/2015/11/20/scala-method-with-java-reserved-keyword/
41+
Method method = ScalafmtConfig$.MODULE$.getClass().getDeclaredMethod("default");
42+
config = (ScalafmtConfig) method.invoke(ScalafmtConfig$.MODULE$);
43+
} else {
44+
File file = configSignature.getOnlyFile();
45+
String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
46+
config = Scalafmt.parseHoconConfig(configStr).get();
47+
}
48+
}
49+
50+
@Override
51+
public String apply(String input) {
52+
return Scalafmt.format(input, config, Set$.MODULE$.empty()).get();
53+
}
54+
}

plugin-gradle/CHANGES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
66
### Added
77
* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275))
88

9+
## [6.10.0] - 2022-08-23
10+
### Added
11+
* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact ([#1283](https://github.com/diffplug/spotless/pull/1283))
12+
### Changes
13+
* Add the `ktlint` rule in error messages when `ktlint` fails to apply a fix ([#1279](https://github.com/diffplug/spotless/pull/1279))
14+
* Bump default `scalafmt` to latest `3.0.8` -> `3.5.9` (removed support for pre-`3.0.0`) ([#1283](https://github.com/diffplug/spotless/pull/1283))
15+
916
## [6.9.1] - 2022-08-10
1017
### Fixed
1118
* Fix Clang not knowing the filename and changing the format ([#1268](https://github.com/diffplug/spotless/pull/1268) fixes [#1267](https://github.com/diffplug/spotless/issues/1267)).

0 commit comments

Comments
 (0)