Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support Diktat 2.0.0 #1972

Merged
merged 15 commits into from
Jan 14, 2024
13 changes: 11 additions & 2 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ versionCompatibility {
]
targetSourceSetName = 'ktlint'
}
namespaces.register('Diktat') {
versions = [
'1.2.5',
'2.0.0',
]
targetSourceSetName = 'diktat'
}
}
}

Expand All @@ -76,8 +83,10 @@ dependencies {
String VER_CLEANTHAT='2.17'
cleanthatCompileOnly "io.github.solven-eu.cleanthat:java:$VER_CLEANTHAT"
compatCleanthat2Dot1CompileAndTestOnly "io.github.solven-eu.cleanthat:java:$VER_CLEANTHAT"
// diktat
diktatCompileOnly 'org.cqfn.diktat:diktat-rules:1.2.5'
// diktat old supported version 1.x
compatDiktat1Dot2Dot5CompileOnly "org.cqfn.diktat:diktat-rules:1.2.5"
// diktat latest supported version 2.x
compatDiktat2Dot0Dot0CompileOnly "com.saveourtool.diktat:diktat-runner:2.0.0"
// flexmark
flexmarkCompileOnly 'com.vladsch.flexmark:flexmark-all:0.64.0'
// gherkin
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2023 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.diktat.compat;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nullable;

import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider;

import com.pinterest.ktlint.core.KtLint;
import com.pinterest.ktlint.core.LintError;
import com.pinterest.ktlint.core.RuleSet;
import com.pinterest.ktlint.core.api.EditorConfigOverride;

import kotlin.Unit;
import kotlin.jvm.functions.Function2;

public class DiktatCompat1Dot2Dot5Adapter implements DiktatCompatAdapter {
private final List<RuleSet> ruleSets;
private final Function2<? super LintError, ? super Boolean, Unit> formatterCallback;
private final ArrayList<LintError> errors = new ArrayList<>();

public DiktatCompat1Dot2Dot5Adapter(@Nullable File configFile) {
if (configFile != null) {
System.setProperty("diktat.config.path", configFile.getAbsolutePath());
}
this.ruleSets = Collections.singletonList(new DiktatRuleSetProvider().get());
this.formatterCallback = new FormatterCallback(errors);
}

static class FormatterCallback implements Function2<LintError, Boolean, Unit> {
private final ArrayList<LintError> errors;

FormatterCallback(ArrayList<LintError> errors) {
this.errors = errors;
}

@Override
public Unit invoke(LintError lintError, Boolean corrected) {
if (!corrected) {
errors.add(lintError);
}
return null;
}
}

@Override
public String format(final File file, final String content, final boolean isScript) {
errors.clear();
String result = KtLint.INSTANCE.format(new KtLint.ExperimentalParams(
// Unlike Ktlint, Diktat requires full path to the file.
// See https://github.com/diffplug/spotless/issues/1189, https://github.com/analysis-dev/diktat/issues/1202
file.getAbsolutePath(),
content,
ruleSets,
Collections.emptyMap(),
formatterCallback,
isScript,
null,
false,
new EditorConfigOverride(),
false));

DiktatReporting.reportIfRequired(errors, LintError::getLine, LintError::getCol, LintError::getDetail);

return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2023 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.diktat.compat;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.saveourtool.diktat.DiktatFactoriesKt;
import com.saveourtool.diktat.DiktatProcessor;
import com.saveourtool.diktat.api.DiktatCallback;
import com.saveourtool.diktat.api.DiktatError;
import com.saveourtool.diktat.api.DiktatRuleConfig;
import com.saveourtool.diktat.api.DiktatRuleSet;

import kotlin.Unit;

public class DiktatCompat2Dot0Dot0Adapter implements DiktatCompatAdapter {
private final DiktatProcessor processor;
private final DiktatCallback formatterCallback;
private final ArrayList<DiktatError> errors = new ArrayList<>();

public DiktatCompat2Dot0Dot0Adapter(@Nullable File configFile) {
this.processor = getDiktatReporter(configFile);
this.formatterCallback = new FormatterCallback(errors);
}

@Override
public String format(File file, String content, boolean isScript) {
errors.clear();
String result = processor.fix(content, file.toPath(), formatterCallback);
DiktatReporting.reportIfRequired(errors, DiktatError::getLine, DiktatError::getCol, DiktatError::getDetail);
return result;
}

private static class FormatterCallback implements DiktatCallback {
private final ArrayList<DiktatError> errors;

FormatterCallback(ArrayList<DiktatError> errors) {
this.errors = errors;
}

@Override
public Unit invoke(DiktatError diktatError, Boolean corrected) {
doInvoke(diktatError, corrected);
return Unit.INSTANCE;
}

@Override
public void invoke(@NotNull DiktatError diktatError, boolean corrected) {
doInvoke(diktatError, corrected);
}

private void doInvoke(@NotNull DiktatError diktatError, boolean corrected) {
if (!corrected) {
errors.add(diktatError);
}
}
}

private static DiktatProcessor getDiktatReporter(File configFile) {
final DiktatRuleSet ruleSet = DiktatFactoriesKt.getDiktatRuleSetFactory().invoke(readRuleConfigs(configFile));
return DiktatFactoriesKt.getDiktatProcessorFactory().invoke(ruleSet);
}

private static List<DiktatRuleConfig> readRuleConfigs(File configFile) {
if (configFile == null) {
return Collections.emptyList();
}
try (final InputStream configInputStream = new FileInputStream(configFile)) {
return DiktatFactoriesKt.getDiktatRuleConfigReader().invoke(configInputStream);
} catch (IOException e) {
throw new IllegalArgumentException("Fail to read configFile", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2023 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.diktat.compat;

import java.io.File;

public interface DiktatCompatAdapter {
String format(File file, String content, boolean isScript);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2023 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.diktat.compat;

import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;

interface DiktatReporting {
static <T> void reportIfRequired(
List<T> errors,
ToIntFunction<T> lineGetter,
ToIntFunction<T> columnGetter,
Function<T, String> detailGetter) {
if (!errors.isEmpty()) {
StringBuilder error = new StringBuilder();
error.append("There are ").append(errors.size()).append(" unfixed errors:");
for (T er : errors) {
error.append(System.lineSeparator())
.append("Error on line: ").append(lineGetter.applyAsInt(er))
.append(", column: ").append(columnGetter.applyAsInt(er))
.append(" cannot be fixed automatically")
.append(System.lineSeparator())
.append(detailGetter.apply(er));
}
throw new AssertionError(error);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2022 DiffPlug
* Copyright 2021-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,81 +16,30 @@
package com.diffplug.spotless.glue.diktat;

import java.io.File;
import java.util.*;

import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider;

import com.pinterest.ktlint.core.KtLint;
import com.pinterest.ktlint.core.LintError;
import com.pinterest.ktlint.core.RuleSet;
import com.pinterest.ktlint.core.api.EditorConfigOverride;

import com.diffplug.spotless.FormatterFunc;

import kotlin.Unit;
import kotlin.jvm.functions.Function2;
import com.diffplug.spotless.glue.diktat.compat.DiktatCompat1Dot2Dot5Adapter;
import com.diffplug.spotless.glue.diktat.compat.DiktatCompat2Dot0Dot0Adapter;
import com.diffplug.spotless.glue.diktat.compat.DiktatCompatAdapter;

public class DiktatFormatterFunc implements FormatterFunc.NeedsFile {

private final List<RuleSet> rulesets;
private final Function2<? super LintError, ? super Boolean, Unit> formatterCallback;
private final DiktatCompatAdapter adapter;
private final boolean isScript;

private final ArrayList<LintError> errors = new ArrayList<>();

public DiktatFormatterFunc(boolean isScript) {
rulesets = Collections.singletonList(new DiktatRuleSetProvider().get());
this.formatterCallback = new FormatterCallback(errors);
this.isScript = isScript;
}

static class FormatterCallback implements Function2<LintError, Boolean, Unit> {
private final ArrayList<LintError> errors;

FormatterCallback(ArrayList<LintError> errors) {
this.errors = errors;
}

@Override
public Unit invoke(LintError lintError, Boolean corrected) {
if (!corrected) {
errors.add(lintError);
}
return null;
public DiktatFormatterFunc(
String version,
File configFile,
boolean isScript) {
if (version.startsWith("1.")) {
this.adapter = new DiktatCompat1Dot2Dot5Adapter(configFile);
} else {
this.adapter = new DiktatCompat2Dot0Dot0Adapter(configFile);
}
this.isScript = isScript;
}

@Override
public String applyWithFile(String unix, File file) throws Exception {
errors.clear();
String result = KtLint.INSTANCE.format(new KtLint.ExperimentalParams(
// Unlike Ktlint, Diktat requires full path to the file.
// See https://github.com/diffplug/spotless/issues/1189, https://github.com/analysis-dev/diktat/issues/1202
file.getAbsolutePath(),
unix,
rulesets,
Collections.emptyMap(),
formatterCallback,
isScript,
null,
false,
new EditorConfigOverride(),
false));

if (!errors.isEmpty()) {
StringBuilder error = new StringBuilder();
error.append("There are ").append(errors.size()).append(" unfixed errors:");
for (LintError er : errors) {
error.append(System.lineSeparator())
.append("Error on line: ").append(er.getLine())
.append(", column: ").append(er.getCol())
.append(" cannot be fixed automatically")
.append(System.lineSeparator())
.append(er.getDetail());
}
throw new AssertionError(error);
}

return result;
public String applyWithFile(String unix, File file) {
return adapter.format(file, unix, isScript);
}
}
Loading
Loading