Skip to content
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