Структура каталогов Autofix на основе пакета в scala
У меня есть файл src/main/scala/foo.scala
который должен быть внутри упаковки bar
. В идеале файл должен быть внутриsrc/main/scala/bar/foo.scala
.
// src/main/scala/foo.scala
package bar
// ...
Как я могу автоматически исправить эту проблему во всем моем проекте, чтобы структура папок соответствовала структуре пакета?
Есть ли какой-либо плагин SBT и т. Д., Который может помочь мне решить эту проблему?
2 ответа
Насколько мне известно, таких инструментов нет, хотя AFAIR IntelliJ может предупреждать о несовпадении пакета и каталога.
Лучшее, что я могу подумать, если это настраиваемое правило scalafix (https://scalacenter.github.io/scalafix/) - scalafix/scalameta будет использоваться для проверки фактического пакета файла, перевода его в ожидаемый каталог и, если они отличаются, переместить файл.
Я предлагаю scalafix / scalameta, потому что есть такие угловые случаи, как:
вам разрешено писать свои пакеты, например:
package a package b package c
и это почти как
package a.b.c
за исключением того, что он автоматически импортирует все изa
а такжеb
вы можете иметь
package object
в вашем файле, а затем, если у вас есть
package a.b
package object c
этот файл должен быть в a/b/c
каталог
поэтому я бы предпочел проверить, не попадает ли файл под какой-либо из существующих инструментов.
Если вы уверены, что таких случаев у вас нет (я бы не стал без проверки), вы можете:
- сопоставьте первую строку с регулярным выражением (
^package (.*)
) - перевести
a.b.c
вa/b/c
(matched.split('.').map(_.trim).mkString(File.separator)
) - сравнить сгенерированное местоположение с фактическим местоположением (я предлагаю разрешить абсолютное местоположение файлов)
- при необходимости переместить файл
Если есть возможность иметь более сложный случай, я мог бы заменить первый шаг запросом утилит scalafix / scalameta.
Вот плагин sbt, обеспечивающий packageStructureToDirectoryStructure
задача, которая читает операторы пакета из исходных файлов, создает соответствующие каталоги, а затем перемещает в них файлы
import sbt._
import sbt.Keys._
import better.files._
object PackagesToDirectories extends AutoPlugin {
object autoImport {
val packageStructureToDirectoryStructure = taskKey[Unit]("Make directory structure match package structure")
}
import autoImport._
override def trigger = allRequirements
override lazy val projectSettings = Seq(
packageStructureToDirectoryStructure := {
val log = streams.value.log
log.info(s"Refactoring directory structure to match package structure...")
val sourceFiles = (Compile / sources).value
val sourceBase = (Compile / scalaSource).value
def packageStructure(lines: Traversable[String]): String = {
val packageObjectRegex = """package object\s(.+)\s\{""".r
val packageNestingRegex = """package\s(.+)\s\{""".r
val packageRegex = """package\s(.+)""".r
lines
.collect {
case packageObjectRegex(name) => name
case packageNestingRegex(name) => name
case packageRegex(name) => name
}
.flatMap(_.split('.'))
.mkString("/")
}
sourceFiles.foreach { sourceFile =>
val packagePath = packageStructure(sourceFile.toScala.lines)
val destination = file"$sourceBase/$packagePath"
destination.createDirectoryIfNotExists(createParents = true)
val result = sourceFile.toScala.moveToDirectory(destination)
log.info(s"$sourceFile moved to $result")
}
}
)
}
ВНИМАНИЕ! Обязательно сделайте резервную копию проекта перед его запуском.