All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fix.SyntacticOrganizeImports.scala Maven / Gradle / Ivy

The newest version!
package fix

import scala.annotation.tailrec
import scala.meta.Import
import scala.meta.Importer
import scala.meta.Pkg
import scala.meta.XtensionClassifiable
import scala.meta.XtensionCollectionLikeUI
import scala.meta.inputs.Position
import scalafix.Patch
import scalafix.lint.Diagnostic
import scalafix.lint.LintSeverity
import scalafix.v1.SyntacticDocument
import scalafix.v1.SyntacticRule
import scalafix.v1.XtensionOptionPatch
import scalafix.v1.XtensionSeqPatch

class SyntacticOrganizeImports extends SyntacticRule("SyntacticOrganizeImports") {

  private def collectWhile[A, B](list: List[A])(f: PartialFunction[A, B]): List[B] = {
    @tailrec
    def loop(values: List[A], acc: List[B]): List[B] = {
      values match {
        case x :: xs if f.isDefinedAt(x) =>
          loop(xs, f(x) :: acc)
        case _ =>
          acc
      }
    }
    loop(list, Nil).reverse
  }

  private def importToString(importer: Importer): String = {
    importer.pos.text
  }

  override def fix(implicit doc: SyntacticDocument): Patch = {
    doc.tree.collect { case p: Pkg =>
      // find top-level imports
      val imports = collectWhile(p.body.stats.dropWhile(!_.is[Import])) { case i: Import => i }.sortBy(_.pos.startLine)
      val importers = imports.map(_.importers).collect { case i :: Nil => i }
      if (imports.nonEmpty && (imports.lengthCompare(importers.size) == 0)) {
        val start = imports.map(_.pos.startLine).min
        val end = imports.map(_.pos.endLine).max

        Seq(
          doc.input.text.linesIterator.zipWithIndex
            .slice(start, end + 1)
            .filter(_._1.trim.isEmpty)
            .map { case (_, emptyLineNumber) =>
              Patch.lint(
                SyntacticOrganizeImportsWarn(
                  Position.Range(
                    input = doc.input,
                    startLine = emptyLineNumber,
                    startColumn = 0,
                    endLine = emptyLineNumber + 1,
                    endColumn = 0
                  ),
                  "there is empty line in top level imports"
                )
              )
            }
            .toList
            .asPatch,
          importers
            .sortBy(importToString)
            .zip(importers)
            .find { case (x1, x2) =>
              importToString(x1) != importToString(x2)
            }
            .map { case (_, value) =>
              Patch.lint(
                SyntacticOrganizeImportsWarn(
                  value.pos,
                  "does not sorted imports"
                )
              )
            }
            .asPatch
        ).asPatch
      } else {
        Patch.empty
      }
    }.asPatch
  }
}

case class SyntacticOrganizeImportsWarn(
  override val position: Position,
  override val message: String
) extends Diagnostic {
  override def severity: LintSeverity = LintSeverity.Warning
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy