Skip to content

Commit

Permalink
Replace editorconfig parser to ec4j. (pinterest#561)
Browse files Browse the repository at this point in the history
* Change editorconfig parser.

Replaced custom parser, that is hard to maintain and not working well,
with https://github.com/ec4j/ec4j parser.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>

* Trim whitespaces in parsed disabled rules values.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>

* Add ec4j dependency to maven.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
  • Loading branch information
Tapchicoma authored and sowmyav24 committed Aug 31, 2019
1 parent d6cb03a commit 5224a52
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 89 deletions.
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

0 comments on commit 5224a52

Please sign in to comment.