
scalafix.internal.reflect.ScalafixCompilerDecoder.scala Maven / Gradle / Ivy
package scalafix.internal.reflect
import java.io.File
import java.io.FileNotFoundException
import java.net.URL
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import scala.meta.Input
import scalafix.rule.Rule
import scalafix.internal.config.LazySemanticdbIndex
import scalafix.internal.config.ScalafixMetaconfigReaders.UriRule
import scalafix.internal.util.FileOps
import metaconfig.Conf
import metaconfig.ConfDecoder
import metaconfig.ConfError
import metaconfig.Configured
import metaconfig.Configured.NotOk
import metaconfig.Configured.Ok
import org.langmeta.io.AbsolutePath
object ScalafixCompilerDecoder {
def baseCompilerDecoder(index: LazySemanticdbIndex): ConfDecoder[Rule] = {
implicit val cwd: AbsolutePath = index.workingDirectory
ConfDecoder.instance[Rule] {
case FromSourceRule(rule) =>
rule match {
case Ok(code) => ScalafixToolbox.getRule(code, index)
case err @ NotOk(_) => err
}
}
}
object UrlRule {
def unapply(arg: Conf.Str): Option[Configured[URL]] = arg match {
case UriRule("http" | "https", uri) if uri.isAbsolute =>
Option(Ok(uri.toURL))
case GitHubUrlRule(url) => Option(url)
case _ => None
}
}
object GitHubUrlRule {
private[this] val GitHubShorthand =
"""github:([^\/]+)\/([^\/]+)\/([^\/]+)""".r
private[this] val GitHubShorthandWithSha =
"""github:([^\/]+)\/([^\/]+)\/([^\/]+)\?sha=(.+)""".r
private[this] val GitHubFallback =
"""github:(.*)""".r
private[this] val alphanumerical = "[^a-zA-Z0-9]"
// approximates the "format=Camel" formatter in giter8.
// http://www.foundweekends.org/giter8/Combined+Pages.html#Formatting+template+fields
private[this] def CamelCase(string: String): String =
string.split(alphanumerical).mkString.capitalize
// approximates the "format=Snake" formatter in giter8.
private[this] def SnakeCase(string: String): String =
string.split(alphanumerical).map(_.toLowerCase).mkString("_")
private[this] def expandGitHubURL(
org: String,
repo: String,
version: String,
sha: String): URL = {
val fileName = s"${CamelCase(repo)}_${SnakeCase(version)}.scala"
new URL(
s"https://raw.githubusercontent.com/$org/$repo/$sha/scalafix/rules/src/main/scala/fix/$fileName")
}
def unapply(arg: Conf.Str): Option[Configured[URL]] = arg.value match {
case GitHubShorthandWithSha(org, repo, version, sha) =>
Option(Ok(expandGitHubURL(org, repo, version, sha)))
case GitHubShorthand(org, repo, version) =>
Option(Ok(expandGitHubURL(org, repo, version, "master")))
case GitHubFallback(invalid) =>
Some(
ConfError
.msg(s"""Invalid url 'github:$invalid'. Valid formats are:
|- github:org/repo/version
|- github:org/repo/version?sha=branch""".stripMargin)
.notOk)
case _ => None
}
}
object FileRule {
def unapply(arg: Conf.Str)(
implicit cwd: AbsolutePath): Option[AbsolutePath] =
arg match {
case UriRule("file", uri) =>
val path = AbsolutePath(Paths.get(uri.getSchemeSpecificPart))
Option(path)
case _ => None
}
}
object FromSourceRule {
private val scalafixRoot = Files.createTempDirectory("scalafix")
scalafixRoot.toFile.deleteOnExit()
private val fileCache = scala.collection.concurrent.TrieMap.empty[Int, Path]
private def getTempFile(url: URL, code: String): Path =
fileCache.getOrElseUpdate(
code.hashCode, {
val filename = Paths.get(url.getPath).getFileName.toString
val tmp = Files.createTempFile(scalafixRoot, filename, ".scala")
Files.write(tmp, code.getBytes)
tmp
}
)
def unapply(arg: Conf.Str)(
implicit cwd: AbsolutePath): Option[Configured[Input]] = arg match {
case FileRule(file) =>
// NOgg
Option(Ok(Input.File(file)))
case UrlRule(Ok(url)) =>
try {
val code = FileOps.readURL(url)
val file = getTempFile(url, code)
Option(Ok(Input.File(file)))
} catch {
case e: FileNotFoundException =>
Option(Configured.error(s"404 - not found $url"))
}
case _ => None
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy