Структура каталогов Autofix на основе пакета в scala - PullRequest
3 голосов
/ 09 мая 2020

У меня есть файл src/main/scala/foo.scala, который должен находиться внутри пакета bar. В идеале файл должен находиться внутри src/main/scala/bar/foo.scala.

// src/main/scala/foo.scala


package bar

// ... 

Как я могу автоматически исправить эту проблему во всем моем проекте, чтобы структура папок соответствовала структуре пакета?

Есть ли какие-либо SBT плагин et c, который может помочь мне решить эту проблему?

Ответы [ 2 ]

3 голосов
/ 09 мая 2020

Насколько мне известно, таких инструментов нет, хотя AFAIR IntelliJ может предупреждать о несоответствии между пакетом и каталогом. ) правило - 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 каталог

, поэтому я бы предпочел проверить, не попал ли файл под какие-либо из существующих инструментов.

Если вы уверены, что у вас нет таких случаев ( Я бы не стал без проверки) вы могли бы:

  • соответствовать первым t строка с регулярным выражением (^package (.*))
  • преобразовать a.b.c в a/b/c (matched.split('.').map(_.trim).mkString(File.separator))
  • сравнить сгенерированное местоположение с фактическим местоположением (я предлагаю разрешить абсолютное местоположение файлов)
  • при необходимости переместить файл

Если есть возможность иметь более сложный случай, я мог бы заменить первый шаг запросом утилит scalafix / scalameta.

2 голосов
/ 09 мая 2020

Вот плагин 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")
      }
    }
  )

}

ВНИМАНИЕ: обязательно сделайте резервную копию проекта перед запуском это.

...