diff --git a/.editorconfig b/.editorconfig index 3902112c..43deb257 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,4 +6,4 @@ indent_size = 4 insert_final_newline = true ij_kotlin_allow_trailing_comma = true ij_kotlin_allow_trailing_comma_on_call_site = true -ktlint_disabled_rules = filename +ktlint_standard_filename = disabled diff --git a/build.gradle.kts b/build.gradle.kts index 0bbc820c..a764cc8f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ description = projectDescription object Versions { const val androidTools = "7.3.1" const val junit = "5.9.1" - const val ktlint = "0.47.1" + const val ktlint = "0.48.0" const val mockitoKotlin = "4.1.0" } diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt index a415f1cb..2f95a0cf 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/support/EditorConfigUtils.kt @@ -1,8 +1,11 @@ package org.jmailen.gradle.kotlinter.support -import com.pinterest.ktlint.core.KtLint -import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties +import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.api.EditorConfigOverride +import com.pinterest.ktlint.core.api.EditorConfigOverride.Companion.EMPTY_EDITOR_CONFIG_OVERRIDE +import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import org.ec4j.core.model.PropertyType +import org.ec4j.core.model.PropertyType.PropertyValueParser.IDENTITY_VALUE_PARSER import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ProjectLayout import org.gradle.api.logging.Logger @@ -12,20 +15,39 @@ internal fun editorConfigOverride(ktLintParams: KtLintParams): EditorConfigOverr val rules = ktLintParams.disabledRules return if (rules.isEmpty()) { - EditorConfigOverride.emptyEditorConfigOverride + EMPTY_EDITOR_CONFIG_OVERRIDE } else { - EditorConfigOverride.from(DefaultEditorConfigProperties.ktlintDisabledRulesProperty to rules.joinToString(separator = ",")) + rules + .asSequence() + .map(::getDisabledRulePropertyName) + .map { propertyName -> + EditorConfigProperty( + type = PropertyType(propertyName, "Rule to be disabled", IDENTITY_VALUE_PARSER), + defaultValue = "disabled", + ) + } + .map { it to "disabled" } + .toList() + .toTypedArray() + .let { EditorConfigOverride.from(*it) } } } -internal fun resetEditorconfigCacheIfNeeded( +private fun getDisabledRulePropertyName(it: String) = + if (it.contains(':')) { // Rule from a custom source set + "ktlint_${it.replace(':', '_')}" + } else { + "ktlint_standard_$it" + } + +internal fun KtLintRuleEngine.resetEditorconfigCacheIfNeeded( changedEditorconfigFiles: ConfigurableFileCollection, logger: Logger, ) { val changedFiles = changedEditorconfigFiles.files if (changedFiles.any()) { logger.info("Editorconfig changed, resetting KtLint caches") - changedFiles.map(File::toPath).forEach(KtLint::reloadEditorConfigFile) + changedFiles.map(File::toPath).forEach(::reloadEditorConfigFile) } } diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt index ba03305b..f294144b 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/LintTask.kt @@ -52,7 +52,7 @@ open class LintTask @Inject constructor( p.projectDirectory.set(projectLayout.projectDirectory.asFile) p.reporters.putAll(reports) p.ktLintParams.set(getKtLintParams()) - p.changedEditorconfigFiles.from(getChangedEditorconfigFiles(inputChanges)) + p.changedEditorConfigFiles.from(getChangedEditorconfigFiles(inputChanges)) } runCatching { await() } } diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt index 5b411fa6..1d502305 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/format/FormatWorkerAction.kt @@ -1,8 +1,6 @@ package org.jmailen.gradle.kotlinter.tasks.format -import com.pinterest.ktlint.core.KtLint -import com.pinterest.ktlint.core.LintError -import com.pinterest.ktlint.core.RuleProvider +import com.pinterest.ktlint.core.KtLintRuleEngine import org.gradle.api.logging.LogLevel import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging @@ -26,7 +24,12 @@ abstract class FormatWorkerAction : WorkAction { private val output: File? = parameters.output.asFile.orNull override fun execute() { - resetEditorconfigCacheIfNeeded( + val ktLintEngine = KtLintRuleEngine( + ruleProviders = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules), + editorConfigOverride = editorConfigOverride(ktLintParams), + ) + + ktLintEngine.resetEditorconfigCacheIfNeeded( changedEditorconfigFiles = parameters.changedEditorConfigFiles, logger = logger, ) @@ -34,32 +37,27 @@ abstract class FormatWorkerAction : WorkAction { val fixes = mutableListOf() try { files.forEach { file -> - val ruleSets = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules) val sourceText = file.readText() val relativePath = file.toRelativeString(projectDirectory) logger.log(LogLevel.DEBUG, "$name checking format: $relativePath") - when (file.extension) { - "kt" -> this::formatKt - "kts" -> this::formatKts - else -> { - logger.log(LogLevel.DEBUG, "$name ignoring non Kotlin file: $relativePath") - null - } - }?.let { formatFunc -> - val formattedText = formatFunc.invoke(file, ruleSets) { error, corrected -> - val msg = when (corrected) { - true -> "${file.path}:${error.line}:${error.col}: Format fixed > [${error.ruleId}] ${error.detail}" - false -> "${file.path}:${error.line}:${error.col}: Format could not fix > [${error.ruleId}] ${error.detail}" - } - logger.log(LogLevel.QUIET, msg) - fixes.add(msg) - } - if (!formattedText.contentEquals(sourceText)) { - logger.log(LogLevel.QUIET, "${file.path}: Format fixed") - file.writeText(formattedText) + if (file.extension !in supportedExtensions) { + logger.log(LogLevel.DEBUG, "$name ignoring non Kotlin file: $relativePath") + return@forEach + } + + val formattedText = ktLintEngine.format(file.toPath()) { error, corrected -> + val msg = when (corrected) { + true -> "${file.path}:${error.line}:${error.col}: Format fixed > [${error.ruleId}] ${error.detail}" + false -> "${file.path}:${error.line}:${error.col}: Format could not fix > [${error.ruleId}] ${error.detail}" } + logger.log(LogLevel.QUIET, msg) + fixes.add(msg) + } + if (!formattedText.contentEquals(sourceText)) { + logger.log(LogLevel.QUIET, "${file.path}: Format fixed") + file.writeText(formattedText) } } } catch (t: Throwable) { @@ -73,27 +71,6 @@ abstract class FormatWorkerAction : WorkAction { }, ) } - - private fun formatKt(file: File, ruleSets: Set, onError: ErrorHandler) = - format(file, ruleSets, onError, false) - - private fun formatKts(file: File, ruleSets: Set, onError: ErrorHandler) = - format(file, ruleSets, onError, true) - - private fun format(file: File, ruleProviders: Set, onError: ErrorHandler, script: Boolean): String { - return KtLint.format( - KtLint.ExperimentalParams( - fileName = file.path, - text = file.readText(), - ruleProviders = ruleProviders, - script = script, - editorConfigOverride = editorConfigOverride(ktLintParams), - cb = { error, corrected -> - onError(error, corrected) - }, - ), - ) - } } -typealias ErrorHandler = (error: LintError, corrected: Boolean) -> Unit +private val supportedExtensions = setOf("kt", "kts") diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt index 914792a0..82d363c6 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerAction.kt @@ -1,9 +1,7 @@ package org.jmailen.gradle.kotlinter.tasks.lint -import com.pinterest.ktlint.core.KtLint -import com.pinterest.ktlint.core.LintError +import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.Reporter -import com.pinterest.ktlint.core.RuleProvider import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.gradle.internal.logging.slf4j.DefaultContextAwareTaskLogger @@ -31,8 +29,13 @@ abstract class LintWorkerAction : WorkAction { private val ktLintParams: KtLintParams = parameters.ktLintParams.get() override fun execute() { - resetEditorconfigCacheIfNeeded( - changedEditorconfigFiles = parameters.changedEditorconfigFiles, + val ktLintEngine = KtLintRuleEngine( + ruleProviders = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules), + editorConfigOverride = editorConfigOverride(ktLintParams), + ) + + ktLintEngine.resetEditorconfigCacheIfNeeded( + changedEditorconfigFiles = parameters.changedEditorConfigFiles, logger = logger, ) var hasError = false @@ -40,19 +43,16 @@ abstract class LintWorkerAction : WorkAction { try { reporters.onEach { it.beforeAll() } files.forEach { file -> - val ruleSets = resolveRuleProviders(defaultRuleSetProviders, ktLintParams.experimentalRules) val relativePath = file.toRelativeString(projectDirectory) reporters.onEach { it.before(relativePath) } logger.debug("$name linting: $relativePath") - val lintFunc = when (file.extension) { - "kt" -> ::lintKt - "kts" -> ::lintKts - else -> { - logger.debug("$name ignoring non Kotlin file: $relativePath") - null - } + + if (file.extension !in supportedExtensions) { + logger.debug("$name ignoring non Kotlin file: $relativePath") + return@forEach } - lintFunc?.invoke(file, ruleSets) { error -> + + ktLintEngine.lint(file.toPath()) { error -> hasError = true reporters.onEach { reporter -> // some reporters want relative paths, some want absolute @@ -72,24 +72,6 @@ abstract class LintWorkerAction : WorkAction { throw LintFailure("kotlin source failed lint check") } } - - private fun lintKt(file: File, ruleSets: Set, onError: (error: LintError) -> Unit) = - lint(file, ruleSets, onError, false) - - private fun lintKts(file: File, ruleSets: Set, onError: (error: LintError) -> Unit) = - lint(file, ruleSets, onError, true) - - private fun lint(file: File, ruleProviders: Set, onError: ErrorHandler, script: Boolean) = - KtLint.lint( - KtLint.ExperimentalParams( - fileName = file.path, - text = file.readText(), - ruleProviders = ruleProviders, - script = script, - editorConfigOverride = editorConfigOverride(ktLintParams), - cb = { error, _ -> onError(error) }, - ), - ) } -typealias ErrorHandler = (error: LintError) -> Unit +private val supportedExtensions = setOf("kt", "kts") diff --git a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt index 82b375b8..f060af66 100644 --- a/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt +++ b/src/main/kotlin/org/jmailen/gradle/kotlinter/tasks/lint/LintWorkerParameters.kt @@ -10,7 +10,7 @@ import java.io.File interface LintWorkerParameters : WorkParameters { val name: Property - val changedEditorconfigFiles: ConfigurableFileCollection + val changedEditorConfigFiles: ConfigurableFileCollection val files: ConfigurableFileCollection val projectDirectory: RegularFileProperty val reporters: MapProperty diff --git a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt index 7e96c657..97912817 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/functional/EditorConfigTest.kt @@ -60,7 +60,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { // language=editorconfig """ [*.{kt,kts}] - ktlint_disabled_rules = filename + ktlint_standard_filename = disabled """.trimIndent(), ) } @@ -111,7 +111,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { // language=editorconfig """ [*.{kt,kts}] - ktlint_disabled_rules = filename + ktlint_standard_filename = disabled """.trimIndent(), ) } @@ -164,7 +164,7 @@ internal class EditorConfigTest : WithGradleTest.Kotlin() { // language=editorconfig """ [*.{kt,kts}] - ktlint_disabled_rules = filename + ktlint_standard_filename = disabled """.trimIndent(), ) } diff --git a/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt b/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt index 033989d3..c4123834 100644 --- a/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt +++ b/src/test/kotlin/org/jmailen/gradle/kotlinter/support/RuleSetsTest.kt @@ -1,12 +1,13 @@ package org.jmailen.gradle.kotlinter.support -import com.pinterest.ktlint.core.KtLint +import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.RuleProvider import com.pinterest.ktlint.core.RuleSetProviderV2 import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test +import java.io.File class RuleSetsTest { @@ -34,10 +35,11 @@ class RuleSetsTest { @Test fun `test compatibility`() { - KtLint.lint( - KtLint.ExperimentalParams( - fileName = "/tmp/src/test/KotlinClass.kt", - text = """ + KtLintRuleEngine( + resolveRuleProviders(defaultRuleSetProviders), + ).lint( + filePath = File("/tmp/src/test/KotlinClass.kt").toPath(), + code = """ package test class KotlinClass { @@ -46,10 +48,8 @@ class RuleSetsTest { } } - """.trimIndent(), - ruleProviders = resolveRuleProviders(defaultRuleSetProviders), - cb = { _, _ -> }, - ), + """.trimIndent(), + callback = { _ -> }, ) } }