Skip to content

sorting fixes #215

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

Merged
merged 2 commits into from
Oct 13, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import modulecheck.api.Finding
import modulecheck.api.Finding.Position
import modulecheck.api.Fixable
import modulecheck.core.parse
import modulecheck.parsing.DependenciesBlock
import modulecheck.parsing.DependencyBlockParser
import modulecheck.parsing.DependencyDeclaration
import java.io.File

class SortDependenciesFinding(
Expand All @@ -41,9 +41,7 @@ class SortDependenciesFinding(
.parse(buildFile)
.forEach { block ->

val sorted = block.sortedDeclarations(comparator)

fileText = fileText.replace(block.contentString, sorted)
fileText = sortedDependenciesFileText(block, fileText, comparator)
}

buildFile.writeText(fileText)
Expand All @@ -52,13 +50,25 @@ class SortDependenciesFinding(
}
}

fun List<DependencyDeclaration>.grouped(
internal fun sortedDependenciesFileText(
block: DependenciesBlock,
fileText: String,
comparator: Comparator<String>
) = groupBy {
it.declarationText
.split("[(.]".toRegex())
.take(2)
.joinToString("-")
): String {
val sorted = block.sortedDeclarations(comparator)

val trimmedContent = block.contentString
.trimStart('\n')
.trimEnd()

val escapedContent = Regex.escape(trimmedContent)

val blockRegex = "$escapedContent[\\n\\r]*(\\s*)}".toRegex()

return fileText.replace(blockRegex) { mr ->

val whitespaceBeforeBrace = mr.destructured.component1()

"$sorted$whitespaceBeforeBrace}"
}
}
.toSortedMap(comparator)
.map { it.value }
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import modulecheck.core.parse
import modulecheck.core.rule.ModuleCheckRule
import modulecheck.parsing.DependenciesBlock
import modulecheck.parsing.DependencyBlockParser
import modulecheck.parsing.DependencyDeclaration
import org.jetbrains.kotlin.util.suffixIfNot
import java.util.*

class SortDependenciesRule(
Expand Down Expand Up @@ -53,7 +55,11 @@ class SortDependenciesRule(
.parse(project.buildFile)
.all { block ->

block.contentString == block.sortedDeclarations(comparator)
if (block.contentString.isBlank()) return@all true

val fileText = project.buildFile.readText()

fileText == sortedDependenciesFileText(block, fileText, comparator)
}

return if (allSorted) {
Expand All @@ -64,6 +70,18 @@ class SortDependenciesRule(
}
}

fun List<DependencyDeclaration>.grouped(
comparator: Comparator<String>
) = groupBy {
it.declarationText
.split("[^a-zA-Z-]".toRegex())
.filterNot { it.isEmpty() }
.take(2)
.joinToString("-")
}
.toSortedMap(comparator)
.map { it.value }

internal fun DependenciesBlock.sortedDeclarations(
comparator: Comparator<String>
): String {
Expand All @@ -77,6 +95,13 @@ internal fun DependenciesBlock.sortedDeclarations(
@Suppress("DEPRECATION")
declaration.declarationText.toLowerCase(Locale.US)
}
.joinToString("\n") { it.statementWithSurroundingText }
.joinToString("\n") {
it.statementWithSurroundingText
.trimStart('\n')
.trimEnd()
.lines()
.joinToString("\n")
}
}
.suffixIfNot("\n")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 Rick Busarow
* 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 modulecheck.parsing.groovy.antlr

import groovyjarjarantlr4.v4.runtime.tree.ParseTree
import groovyjarjarantlr4.v4.runtime.tree.RuleNode
import org.apache.groovy.parser.antlr4.GroovyParser
import org.apache.groovy.parser.antlr4.GroovyParserBaseVisitor

internal class EverythingPrinter : GroovyParserBaseVisitor<Unit>() {
override fun visit(tree: ParseTree) {
super.visit(tree)

println(
""" ------------------------------------------------------------ ${tree::class.java.simpleName}
|
|`${tree.text}`
|
""".trimMargin()
)
}

override fun visitChildren(node: RuleNode) {
super.visitChildren(node)
println(
""" ------------------------------------------------------------ ${node::class.java.simpleName}
|
|`${node.text}`
|
""".trimMargin()
)
}

override fun visitExpression(ctx: GroovyParser.ExpressionContext) {
super.visitExpression(ctx)
println(
""" ------------------------------------------------------------ ${ctx::class.java.simpleName}
|
|`${ctx.text}`
|
""".trimMargin()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,9 @@ class GroovyDependenciesBlock(
override fun originalLineMatchesParsed(
originalLine: String,
parsedString: String
) = originalLine.collapseBlockComments()
.trimEachLineStart()
.trimLinesLikeAntlr()
.lines()
.any { str ->

str.startsWith(parsedString)
}
): Boolean {
return originalLine.contains(parsedString)
}

override fun toString(): String {
return "GroovyDependenciesBlock(\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

package modulecheck.parsing.groovy.antlr

import groovyjarjarantlr4.v4.runtime.CharStreams
import groovyjarjarantlr4.v4.runtime.CommonTokenStream
import groovyjarjarantlr4.v4.runtime.*
import groovyjarjarantlr4.v4.runtime.misc.Interval
import groovyjarjarantlr4.v4.runtime.tree.RuleNode
import modulecheck.parsing.MavenCoordinates
import org.apache.groovy.parser.antlr4.GroovyLangLexer
Expand All @@ -34,10 +34,9 @@ class GroovyDependencyBlockParser {
fun parse(file: String): List<GroovyDependenciesBlock> {
val dependenciesBlocks = mutableListOf<GroovyDependenciesBlock>()

val flattened = file.collapseBlockComments()
.trimEachLineStart()
val stream = CharStreams.fromString(file)

val lexer = GroovyLangLexer(CharStreams.fromString(flattened))
val lexer = GroovyLangLexer(stream)
val tokens = CommonTokenStream(lexer)

val rawModuleNameVisitor = object : GroovyParserBaseVisitor<String?>() {
Expand All @@ -48,7 +47,7 @@ class GroovyDependencyBlockParser {
): Boolean = currentResult == null

override fun visitStringLiteral(ctx: StringLiteralContext?): String? {
return ctx?.text?.replace("""["']""".toRegex(), "")
return ctx?.originalText(stream)?.replace("""["']""".toRegex(), "")
}
}

Expand All @@ -62,7 +61,7 @@ class GroovyDependencyBlockParser {
override fun visitPostfixExpression(ctx: PostfixExpressionContext?): String? {
return visitChildren(ctx) ?: when (ctx?.start?.text) {
"projects" -> {
ctx.text.removePrefix("projects.")
ctx.originalText(stream).removePrefix("projects.")
}
"project" -> {
ctx.accept(rawModuleNameVisitor)
Expand All @@ -77,14 +76,18 @@ class GroovyDependencyBlockParser {
val visitor = object : GroovyParserBaseVisitor<Unit>() {

override fun visitScriptStatement(ctx: ScriptStatementContext?) {
super.visitScriptStatement(ctx)

val statement = ctx?.statement()

if (statement?.start?.text == "dependencies") {
val blockBodyReg = """dependencies\s*\{([\s\S]*)\}""".toRegex()

val blockBody = blockBodyReg.find(file)
super.visitScriptStatement(ctx)

val originalBlockBody = statement.parentOfType<ScriptStatementContext>()
?.originalText(stream)
?: return

val blockBody = BLOCK_BODY_REGEX.find(originalBlockBody)
?.groupValues
?.get(1)
?.removePrefix("\n")
Expand All @@ -104,7 +107,7 @@ class GroovyDependencyBlockParser {
dependenciesBlock.addModuleStatement(
moduleRef = moduleRef,
configName = config,
parsedString = ctx.text
parsedString = ctx.originalText(stream)
)
return
}
Expand All @@ -115,13 +118,13 @@ class GroovyDependencyBlockParser {
if (mavenCoordinates != null) {
dependenciesBlock.addNonModuleStatement(
configName = config,
parsedString = ctx.text,
parsedString = ctx.originalText(stream),
coordinates = mavenCoordinates
)
return
}

dependenciesBlock.addUnknownStatement(config, ctx.text)
dependenciesBlock.addUnknownStatement(config, ctx.originalText(stream))
}
}

Expand All @@ -138,4 +141,28 @@ class GroovyDependencyBlockParser {

return dependenciesBlocks
}

companion object {
val BLOCK_BODY_REGEX = """dependencies\s*\{([\s\S]*)\}""".toRegex()
}
}

inline fun <reified T> RuleContext.parentOfType(): T? {
return generateSequence(this as? RuleContext?) { it.parent }
.filterIsInstance<T>()
.firstOrNull()
}

fun ParserRuleContext.originalText(stream: CharStream): String {
return stream.getText(Interval(start.startIndex, stop.stopIndex))
}

inline fun blockStatementVisitor(
crossinline action: (BlockStatementContext) -> Unit
): GroovyParserBaseVisitor<Unit> {
return object : GroovyParserBaseVisitor<Unit>() {
override fun visitBlockStatement(ctx: BlockStatementContext) {
action(ctx)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ class GroovyPluginsBlock(

override fun findOriginalStringIndex(parsedString: String) = originalLines
.indexOfFirst { originalLine ->
originalLine.collapseBlockComments()
.trimEachLineStart()
.trimLinesLikeAntlr()
.lines()
.any { it.startsWith(parsedString) }

originalLine.trimStart().contains(parsedString)
}

override fun toString(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import org.apache.groovy.parser.antlr4.GroovyParserBaseVisitor
class GroovyPluginsBlockParser {

fun parse(file: String): GroovyPluginsBlock? {
val flattened = file.collapseBlockComments()
.trimEachLineStart()

val lexer = GroovyLangLexer(CharStreams.fromString(flattened))
val stream = CharStreams.fromString(file)

val lexer = GroovyLangLexer(stream)
val tokens = CommonTokenStream(lexer)

var block: GroovyPluginsBlock? = null
Expand Down Expand Up @@ -57,7 +57,7 @@ class GroovyPluginsBlockParser {
super.visitBlockStatement(ctx)

pluginsBlock.addStatement(
parsedString = ctx.text
parsedString = ctx.originalText(stream)
)
}
}
Expand Down
Loading