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

Replace editorconfig parser to ec4j. #561

Merged
merged 3 commits into from
Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ext.deps = [
'compiler': "org.jetbrains.kotlin:kotlin-compiler-embeddable:${versions.kotlin}"
],
'klob' : 'com.github.shyiko.klob:klob:0.2.1',
ec4j : 'org.ec4j.core:ec4j-core:0.2.0',
'aether' : [
'api' : "org.eclipse.aether:aether-api:${versions.aether}",
'spi' : "org.eclipse.aether:aether-spi:${versions.aether}",
Expand Down
1 change: 1 addition & 0 deletions ktlint-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ plugins {
dependencies {
implementation deps.kotlin.stdlib
implementation deps.kotlin.compiler
implementation deps.ec4j

testImplementation deps.junit
testImplementation deps.assertj
Expand Down
5 changes: 5 additions & 0 deletions ktlint-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
<artifactId>kotlin-compiler-embeddable</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.ec4j.core</groupId>
<artifactId>ec4j-core</artifactId>
<version>${ec4j.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,10 @@ object KtLint {
node.putUserData(FILE_PATH_USER_DATA_KEY, userData["file_path"])
node.putUserData(EDITOR_CONFIG_USER_DATA_KEY, EditorConfig.fromMap(editorConfigMap - "android" - "file_path"))
node.putUserData(ANDROID_USER_DATA_KEY, android)
node.putUserData(DISABLED_RULES, userData["disabled_rules"]?.split(",")?.toSet() ?: emptySet())
node.putUserData(
DISABLED_RULES,
userData["disabled_rules"]?.split(",")?.map { it.trim() }?.toSet() ?: emptySet()
)
}

private fun visitor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package com.pinterest.ktlint.core.internal

import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.Properties
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
import org.ec4j.core.PropertyTypeRegistry
import org.ec4j.core.Resource
import org.ec4j.core.model.EditorConfig
import org.ec4j.core.model.Version
import org.ec4j.core.parser.EditorConfigModelHandler
import org.ec4j.core.parser.EditorConfigParser
import org.ec4j.core.parser.ErrorHandler

/**
* This class handles traversing the filetree and parsing and merging the contents of any discovered .editorconfig files
Expand All @@ -18,11 +24,10 @@ class EditorConfigInternal private constructor (
) : Map<String, String> by data {

companion object : EditorConfigLookup {

override fun of(dir: String) = of(Paths.get(dir))
override fun of(dir: Path) =
generateSequence(locate(dir)) { seed -> locate(seed.parent.parent) } // seed.parent == .editorconfig dir
.map { it to lazy { load(it) } }
.map { it to lazy { loadEditorconfigFile(it) } }
.let { seq ->
// stop when .editorconfig with "root = true" is found, go deeper otherwise
var prev: Pair<Path, Lazy<Map<String, Map<String, String>>>>? = null
Expand Down Expand Up @@ -64,7 +69,7 @@ class EditorConfigInternal private constructor (
(
parent?.data
?: emptyMap()
) + flatten(load(editorConfigPath))
) + flatten(loadEditorconfigFile(editorConfigPath))
)
} else {
parent
Expand All @@ -91,15 +96,15 @@ class EditorConfigInternal private constructor (
}
}

private fun flatten(data: LinkedHashMap<String, Map<String, String>>): Map<String, String> {
private fun flatten(data: Map<String, Map<String, String>>): Map<String, String> {
val map = mutableMapOf<String, String>()
val patternsToSearchFor = arrayOf("*", "*.kt", "*.kts")
for ((sectionName, section) in data) {
if (sectionName == "") {
continue
}
val patterns = try {
parseSection(sectionName.substring(1, sectionName.length - 1))
parseSection(sectionName)
} catch (e: Exception) {
throw RuntimeException(
"ktlint failed to parse .editorconfig section \"$sectionName\"" +
Expand All @@ -114,26 +119,37 @@ class EditorConfigInternal private constructor (
return map.toSortedMap()
}

private fun load(path: Path) =
linkedMapOf<String, Map<String, String>>().also { map ->
object : Properties() {
private var section: MutableMap<String, String>? = null
private fun parseEditorconfigFile(path: Path): EditorConfig {
val parser = EditorConfigParser.builder().build()
val handler = EditorConfigModelHandler(PropertyTypeRegistry.default_(), Version.CURRENT)

override fun put(key: Any, value: Any): Any? {
val sectionName = (key as String).trim()
if (sectionName.startsWith('[') && sectionName.endsWith(']') && value == "") {
section = mutableMapOf<String, String>().also { map.put(sectionName, it) }
} else {
val section =
section
?: mutableMapOf<String, String>().also { section = it; map.put("", it) }
section[key] = value.toString()
parser.parse(
Resource.Resources.ofPath(path, StandardCharsets.UTF_8),
handler,
ErrorHandler.THROW_SYNTAX_ERRORS_IGNORE_OTHERS
)
return handler.editorConfig
}

private fun loadEditorconfigFile(editorConfigFile: Path): Map<String, Map<String, String>> {
val editorConfig = parseEditorconfigFile(editorConfigFile)

var mapRepresentation = editorConfig.sections
.associate { section ->
section.glob.toString() to section
.properties
.mapValues { entry ->
entry.value.sourceValue
}
return null
}
}.load(ByteArrayInputStream(Files.readAllBytes(path)))
}

if (editorConfig.isRoot) {
mapRepresentation = mapRepresentation + ("" to mapOf("root" to true.toString()))
}

return mapRepresentation
}

internal fun parseSection(sectionName: String): List<String> {
val result = mutableListOf<String>()
fun List<List<String>>.collect0(i: Int = 0, str: Array<String?>, acc: MutableList<String>) {
Expand Down
Loading