cash.grammar.kotlindsl.utils.BlockRemover.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
A library for parsing, rewriting, and linting Kotlin source code
package cash.grammar.kotlindsl.utils
import cash.grammar.kotlindsl.model.RemovableBlock
import cash.grammar.kotlindsl.parse.BuildScriptParseException
import cash.grammar.kotlindsl.parse.Parser
import cash.grammar.kotlindsl.parse.Rewriter
import cash.grammar.kotlindsl.utils.Whitespace.trimGently
import cash.grammar.utils.ifNotEmpty
import com.squareup.cash.grammar.KotlinParser
import com.squareup.cash.grammar.KotlinParserBaseListener
import org.antlr.v4.runtime.CommonTokenStream
import java.io.InputStream
import java.nio.file.Path
/**
* A utility class for removing specified blocks from a Gradle Kotlin build script.
*
* @property tokens The token stream for the parser.
* @property errorListener The listener that collects parsing errors.
* @property blocksToRemove The set of [RemovableBlock]s to be removed from the build script
*/
public class BlockRemover private constructor(
private val tokens: CommonTokenStream,
private val errorListener: CollectingErrorListener,
private val blocksToRemove: Set
): KotlinParserBaseListener() {
private val rewriter = Rewriter(tokens)
private var terminalNewlines = 0
@Throws(BuildScriptParseException::class)
public fun rewritten(): String {
errorListener.getErrorMessages().ifNotEmpty {
throw BuildScriptParseException.withErrors(it)
}
return rewriter.text.trimGently(terminalNewlines)
}
override fun enterScript(ctx: KotlinParser.ScriptContext) {
terminalNewlines = Whitespace.countTerminalNewlines(ctx, tokens)
}
override fun exitNamedBlock(ctx: KotlinParser.NamedBlockContext) {
val simpleBlocks = blocksToRemove.filterIsInstance()
if (ctx.name().text in simpleBlocks.map { it.name }) {
// delete whole block and spaces around it
rewriter.delete(ctx.start, ctx.stop)
rewriter.deleteWhitespaceToLeft(ctx.start)
rewriter.deleteNewlineToRight(ctx.stop)
}
}
override fun exitPostfixUnaryExpression(ctx: KotlinParser.PostfixUnaryExpressionContext) {
val tasksWithTypeToRemove = blocksToRemove.filterIsInstance().map { it.type }.toSet()
val inTasksWithType = ctx.primaryExpression()?.simpleIdentifier()?.text == "tasks" && ctx.postfixUnarySuffix(0)?.navigationSuffix()?.simpleIdentifier()?.text == "withType"
if (inTasksWithType) {
removeWithType(ctx, tasksWithTypeToRemove)
}
}
private fun removeWithType(ctx: KotlinParser.PostfixUnaryExpressionContext, typeNames: Set) {
// tasks.withType
val kotlinDSLType = ctx.postfixUnarySuffix(1)?.typeArguments()?.typeProjection()?.singleOrNull()?.type()?.text
// tasks.withType(TypeName)
val groovyDSLType = ctx.postfixUnarySuffix(1)?.callSuffix()?.valueArguments()?.valueArgument()?.singleOrNull()?.text
if (kotlinDSLType in typeNames || groovyDSLType in typeNames) {
rewriter.delete(ctx.start, ctx.stop)
rewriter.deleteWhitespaceToLeft(ctx.start)
rewriter.deleteNewlineToRight(ctx.stop)
}
}
public companion object {
public fun of(
buildScript: Path,
blocksToRemove: Set
): BlockRemover {
return of(Parser.readOnlyInputStream(buildScript), blocksToRemove)
}
public fun of(
buildScript: String,
blocksToRemove: Set
): BlockRemover {
return of(buildScript.byteInputStream(), blocksToRemove)
}
private fun of(
buildScript: InputStream,
blocksToRemove: Set
): BlockRemover {
val errorListener = CollectingErrorListener()
return Parser(
file = buildScript,
errorListener = errorListener,
listenerFactory = { _, tokens, _ ->
BlockRemover(
tokens = tokens,
errorListener = errorListener,
blocksToRemove = blocksToRemove
)
}
).listener()
}
}
}