-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/* | ||
rule = SeparateEachFileWarn | ||
*/ | ||
package fix | ||
|
||
trait SeparateEachFileWarnTest // assert: SeparateEachFileWarn | ||
class SeparateEachFileWarnTest1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
rule = SeparateEachFileWarn | ||
SeparateEachFileWarn.limit = 5 | ||
*/ | ||
package fix | ||
|
||
trait SeparateEachFileWarnTest2_1 | ||
trait SeparateEachFileWarnTest2_2 | ||
trait SeparateEachFileWarnTest2_3 | ||
trait SeparateEachFileWarnTest2_4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package fix | ||
|
||
trait SeparateEachFileWarnTest | ||
class SeparateEachFileWarnTest1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package fix | ||
|
||
trait SeparateEachFileWarnTest2_1 | ||
trait SeparateEachFileWarnTest2_2 | ||
trait SeparateEachFileWarnTest2_3 | ||
trait SeparateEachFileWarnTest2_4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package fix | ||
|
||
import scalafix.lint.LintSeverity | ||
import java.util.Locale | ||
import metaconfig.ConfDecoder | ||
import metaconfig.generic.Surface | ||
|
||
case class SeparateEachFileConfig( | ||
limit: Int, | ||
severity: LintSeverity | ||
) | ||
|
||
object SeparateEachFileConfig { | ||
|
||
val default: SeparateEachFileConfig = SeparateEachFileConfig( | ||
limit = 2, | ||
severity = LintSeverity.Warning, | ||
) | ||
|
||
implicit val surface: Surface[SeparateEachFileConfig] = | ||
metaconfig.generic.deriveSurface[SeparateEachFileConfig] | ||
|
||
private implicit val lintSeverityDecoderInstance: ConfDecoder[LintSeverity] = { conf => | ||
conf.as[String].map(_.toUpperCase(Locale.ROOT)).map { | ||
case "ERROR" => | ||
LintSeverity.Error | ||
case "INFO" => | ||
LintSeverity.Info | ||
case _ => | ||
LintSeverity.Warning | ||
} | ||
} | ||
|
||
implicit val decoder: ConfDecoder[SeparateEachFileConfig] = | ||
metaconfig.generic.deriveDecoder(default) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package fix | ||
|
||
import metaconfig.Configured | ||
import scala.meta._ | ||
import scalafix.v1._ | ||
import java.io.File | ||
import java.nio.file.Files | ||
import scala.meta.inputs.Input | ||
|
||
class SeparateEachFileRewrite(config: SeparateEachFileConfig) extends SyntacticRule("SeparateEachFileRewrite") { | ||
|
||
def this() = this(SeparateEachFileConfig.default) | ||
|
||
override def withConfiguration(config: Configuration): Configured[Rule] = | ||
config.conf | ||
.getOrElse("SeparateEachFileRewrite")(this.config) | ||
.map(newConfig => new SeparateEachFileRewrite(newConfig)) | ||
|
||
private def maxOption[A: Ordering](xs: Seq[A]): Option[A] = | ||
if (xs.isEmpty) None else Option(xs.max) | ||
|
||
override def fix(implicit doc: SyntacticDocument): Patch = { | ||
PartialFunction | ||
.condOpt(doc.input) { | ||
case f: Input.File => | ||
f.path.toFile | ||
case f: Input.VirtualFile => | ||
new File(f.path) | ||
} | ||
.foreach { input => | ||
val topLevelValues = doc.tree.collect { | ||
case t: (Stat.WithTemplate & Member & Stat.WithMods) | ||
if isTopLevel(t) && t.templ.inits.isEmpty && !t.is[Defn.Object] => | ||
t | ||
} | ||
|
||
if ( | ||
(topLevelValues.lengthCompare(config.limit) >= 0) && topLevelValues.forall(_.mods.forall(!_.is[Mod.Sealed])) | ||
) { | ||
val headerLastPos = { | ||
maxOption( | ||
doc.tree.collect { | ||
case i: Import if isTopLevel(i) => i.pos.end | ||
} | ||
).orElse( | ||
maxOption( | ||
doc.tree.collect { case p: Pkg => | ||
p.ref.pos.end | ||
} | ||
) | ||
).getOrElse(0) | ||
} | ||
val header = doc.input.text.take(headerLastPos) | ||
|
||
assert(input.delete()) | ||
|
||
val xs = doc.tree.collect { | ||
case t: (Stat.WithTemplate & Member) if isTopLevel(t) => | ||
t | ||
}.groupBy(_.name.value) | ||
|
||
xs.foreach { case (k, v) => | ||
Files.writeString( | ||
new File( | ||
input.getParentFile, | ||
s"${k}.scala" | ||
).toPath, | ||
header + "\n\n" + v | ||
.sortBy(_.getClass.getName) | ||
.map { x => | ||
(doc.comments.leading(x).toSeq.sortBy(_.pos.start).map(_.toString) :+ x.toString).mkString("\n") | ||
} | ||
.mkString("\n", "\n\n", "\n") | ||
) | ||
} | ||
} | ||
} | ||
|
||
Patch.empty | ||
} | ||
|
||
private def isTopLevel(t: Tree): Boolean = t.parent.forall(_.is[Pkg]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package fix | ||
|
||
import metaconfig.Configured | ||
import scala.meta._ | ||
import scalafix.v1._ | ||
|
||
class SeparateEachFileWarn(config: SeparateEachFileConfig) extends SyntacticRule("SeparateEachFileWarn") { | ||
|
||
def this() = this(SeparateEachFileConfig.default) | ||
|
||
override def withConfiguration(config: Configuration): Configured[Rule] = | ||
config.conf.getOrElse("SeparateEachFileWarn")(this.config).map(newConfig => new SeparateEachFileWarn(newConfig)) | ||
|
||
override def fix(implicit doc: SyntacticDocument): Patch = { | ||
val topLevelValues = doc.tree.collect { | ||
case t: (Stat.WithTemplate & Stat.WithMods & Member) | ||
if t.parent.forall(_.is[Pkg]) && t.templ.inits.isEmpty && !t.is[Defn.Object] => | ||
t | ||
} | ||
|
||
if ((topLevelValues.lengthCompare(config.limit) >= 0) && topLevelValues.forall(_.mods.forall(!_.is[Mod.Sealed]))) { | ||
Patch.lint( | ||
Diagnostic( | ||
id = "", | ||
message = Seq( | ||
s"too many top level classes. please separate file. ${topLevelValues.size} ", | ||
topLevelValues.map(_.name.value).mkString("[", ", ", "]") | ||
).mkString(""), | ||
position = topLevelValues.head.pos, | ||
severity = config.severity | ||
) | ||
) | ||
} else { | ||
Patch.empty | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
ThisBuild / scalafixDependencies += "com.github.xuwei-k" %% "scalafix-rules" % sys.props("scalafix-rules.version") | ||
|
||
scalaVersion := "3.3.3" | ||
|
||
TaskKey[Unit]("check") := { | ||
val names = Set("X1.scala", "X2.scala", "A.scala") | ||
val actualNames = file("src/main/scala/foo").listFiles().map(_.getName).toSet | ||
assert(actualNames == names, actualNames) | ||
names.foreach { | ||
f => | ||
val actual = IO.read(file(s"src/main/scala/foo/${f}")) | ||
val expect = IO.read(file(s"expect/${f}")) | ||
sys.process.Process(Seq("diff", s"src/main/scala/foo/${f}", s"expect/${f}")).! | ||
assert(actual == expect, actual) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package foo | ||
|
||
import scala.util.Try | ||
|
||
|
||
object A |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package foo | ||
|
||
import scala.util.Try | ||
|
||
|
||
/** | ||
* x1 | ||
*/ | ||
trait X1 { | ||
def y: Try[Int] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package foo | ||
|
||
import scala.util.Try | ||
|
||
|
||
// x2 class | ||
class X2 | ||
|
||
/** | ||
* x2 object | ||
*/ | ||
object X2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % sys.props("scalafix.version")) |
20 changes: 20 additions & 0 deletions
20
sbt-test/SeparateEachFileRewrite/test-1/src/main/scala/foo/A.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package foo | ||
|
||
import scala.util.Try | ||
|
||
/** | ||
* x2 object | ||
*/ | ||
object X2 | ||
|
||
/** | ||
* x1 | ||
*/ | ||
trait X1 { | ||
def y: Try[Int] | ||
} | ||
|
||
// x2 class | ||
class X2 | ||
|
||
object A |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
> scalafix SeparateEachFileRewrite | ||
> check |