diff --git a/build.sc b/build.sc index 811d015c4c..5c24f035ed 100644 --- a/build.sc +++ b/build.sc @@ -273,6 +273,13 @@ object dummy extends Module { Deps.scalaPy ) } + object scalafix extends ScalaModule with Bloop.Module { + def skipBloop = true + def scalaVersion = Scala.defaultInternal + def ivyDeps = Agg( + Deps.scalafixInterfaces + ) + } } trait BuildMacros extends ScalaCliCrossSbtModule @@ -527,6 +534,8 @@ trait Core extends ScalaCliCrossSbtModule | def mavenAppArtifactId = "${Deps.Versions.mavenAppArtifactId}" | def mavenAppGroupId = "${Deps.Versions.mavenAppGroupId}" | def mavenAppVersion = "${Deps.Versions.mavenAppVersion}" + | + | def scalafixVersion = "${Deps.Versions.scalafix}" |} |""".stripMargin if (!os.isFile(dest) || os.read(dest) != code) @@ -918,7 +927,8 @@ trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers Deps.scalaPackager.exclude("com.lihaoyi" -> "os-lib_2.13"), Deps.signingCli.exclude((organization, "config_2.13")), Deps.slf4jNop, // to silence jgit - Deps.sttp + Deps.sttp, + Deps.scalafixInterfaces ) def compileIvyDeps = super.compileIvyDeps() ++ Agg( Deps.jsoniterMacros, diff --git a/modules/build/src/main/scala/scala/build/ScalafixArtifacts.scala b/modules/build/src/main/scala/scala/build/ScalafixArtifacts.scala new file mode 100644 index 0000000000..a368a8d637 --- /dev/null +++ b/modules/build/src/main/scala/scala/build/ScalafixArtifacts.scala @@ -0,0 +1,157 @@ +package scala.build + +import coursier.cache.FileCache +import coursier.core.{Repository, Version} +import coursier.error.{CoursierError, ResolutionError} +import coursier.util.Task +import dependency.* +import org.apache.commons.compress.archivers.zip.ZipFile +import os.Path + +import java.io.ByteArrayInputStream +import java.util.Properties + +import scala.build.EitherCps.{either, value} +import scala.build.errors.{BuildException, FetchingDependenciesError} +import scala.build.internal.Constants +import scala.build.internal.CsLoggerUtil.* + +final case class ScalafixArtifacts( + scalafixJars: Seq[os.Path], + toolsJars: Seq[os.Path] +) + +object ScalafixArtifacts { + + def artifacts( + scalaVersion: String, + externalRulesDeps: Seq[Positioned[AnyDependency]], + extraRepositories: Seq[Repository], + logger: Logger, + cache: FileCache[Task] + ): Either[BuildException, ScalafixArtifacts] = + either { + val scalafixProperties = + value(fetchOrLoadScalafixProperties(extraRepositories, logger, cache)) + val key = + value(scalafixPropsKey(scalaVersion)) + val fetchScalaVersion = scalafixProperties.getProperty(key) + + val scalafixDeps = + Seq(dep"ch.epfl.scala:scalafix-cli_$fetchScalaVersion:${Constants.scalafixVersion}") + + val scalafix = + value( + Artifacts.artifacts( + scalafixDeps.map(Positioned.none), + extraRepositories, + None, + logger, + cache.withMessage(s"Downloading scalafix-cli ${Constants.scalafixVersion}") + ) + ) + + val scalaParameters = + // Scalafix for scala 3 uses 2.13-published community rules + // https://github.com/scalacenter/scalafix/issues/2041 + if (scalaVersion.startsWith("3")) ScalaParameters(Constants.defaultScala213Version) + else ScalaParameters(scalaVersion) + + val tools = + value( + Artifacts.artifacts( + externalRulesDeps, + extraRepositories, + Some(scalaParameters), + logger, + cache.withMessage(s"Downloading scalafix.deps") + ) + ) + + ScalafixArtifacts(scalafix.map(_._2), tools.map(_._2)) + } + + private def fetchOrLoadScalafixProperties( + extraRepositories: Seq[Repository], + logger: Logger, + cache: FileCache[Task] + ): Either[BuildException, Properties] = + either { + val cacheDir = Directories.directories.cacheDir / "scalafix-props-cache" + val cachePath = cacheDir / s"scalafix-interfaces-${Constants.scalafixVersion}.properties" + + val content = + if (!os.exists(cachePath)) { + val interfacesJar = value(fetchScalafixInterfaces(extraRepositories, logger, cache)) + val propsData = value(readScalafixProperties(interfacesJar)) + if (!os.exists(cacheDir)) os.makeDir(cacheDir) + os.write(cachePath, propsData) + propsData + } + else os.read(cachePath) + val props = new Properties() + val stream = new ByteArrayInputStream(content.getBytes()) + props.load(stream) + props + } + + private def fetchScalafixInterfaces( + extraRepositories: Seq[Repository], + logger: Logger, + cache: FileCache[Task] + ): Either[BuildException, Path] = + either { + val scalafixInterfaces = dep"ch.epfl.scala:scalafix-interfaces:${Constants.scalafixVersion}" + + val fetchResult = + value( + Artifacts.artifacts( + List(scalafixInterfaces).map(Positioned.none), + extraRepositories, + None, + logger, + cache.withMessage(s"Downloading scalafix-interfaces ${scalafixInterfaces.version}") + ) + ) + + val expectedJarName = s"scalafix-interfaces-${Constants.scalafixVersion}.jar" + val interfacesJar = fetchResult.collectFirst { + case (_, path) if path.last == expectedJarName => path + } + + value( + interfacesJar.toRight(new BuildException("Failed to found scalafix-interfaces jar") {}) + ) + } + + private def readScalafixProperties(jar: Path): Either[BuildException, String] = { + import scala.jdk.CollectionConverters.* + val zipFile = new ZipFile(jar.toNIO) + val entry = zipFile.getEntries().asScala.find(entry => + entry.getName() == "scalafix-interfaces.properties" + ) + val out = + entry.toRight(new BuildException("Failed to found scalafix properties") {}) + .map { entry => + val stream = zipFile.getInputStream(entry) + val bytes = stream.readAllBytes() + new String(bytes) + } + zipFile.close() + out + } + + private def scalafixPropsKey(scalaVersion: String): Either[BuildException, String] = { + val regex = "(\\d)\\.(\\d+).+".r + scalaVersion match { + case regex("2", "12") => Right("scala212") + case regex("2", "13") => Right("scala213") + case regex("3", x) if x.toInt <= 3 => Right("scala3LTS") + case regex("3", _) => Right("scala3Next") + case _ => + Left(new BuildException(s"Scalafix is not supported for Scala version: $scalaVersion") {}) + } + + } + +} diff --git a/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala b/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala index 59d57347b4..2ea06636f2 100644 --- a/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala +++ b/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala @@ -39,6 +39,7 @@ class ScalaCliCommands( export0.Export, fix.Fix, fmt.Fmt, + scalafix.Scalafix, new HelpCmd(help), installcompletions.InstallCompletions, installhome.InstallHome, diff --git a/modules/cli/src/main/scala/scala/cli/commands/scalafix/Scalafix.scala b/modules/cli/src/main/scala/scala/cli/commands/scalafix/Scalafix.scala new file mode 100644 index 0000000000..b8a9f1ea2e --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/commands/scalafix/Scalafix.scala @@ -0,0 +1,150 @@ +package scala.cli.commands.scalafix + +import caseapp.* +import caseapp.core.help.HelpFormat +import coursier.cache.FileCache +import dependency.* +import scalafix.interfaces.ScalafixError.* +import scalafix.interfaces.{ + Scalafix => ScalafixInterface, + ScalafixError, + ScalafixException, + ScalafixRule +} + +import java.io.File +import java.util.Optional + +import scala.build.EitherCps.{either, value} +import scala.build.input.{Inputs, Script, SourceScalaFile} +import scala.build.internal.{Constants, ExternalBinaryParams, FetchExternalBinary, Runner} +import scala.build.options.{BuildOptions, Scope} +import scala.build.{Artifacts, Build, BuildThreads, Logger, ScalafixArtifacts, Sources} +import scala.cli.CurrentParams +import scala.cli.commands.compile.Compile.buildOptionsOrExit +import scala.cli.commands.fmt.FmtUtil.* +import scala.cli.commands.shared.{HelpCommandGroup, HelpGroup, SharedOptions} +import scala.cli.commands.{ScalaCommand, SpecificationLevel, compile} +import scala.cli.config.Keys +import scala.cli.util.ArgHelpers.* +import scala.cli.util.ConfigDbUtils +import scala.collection.mutable +import scala.collection.mutable.Buffer +import scala.jdk.CollectionConverters.* +import scala.jdk.OptionConverters.* + +object Scalafix extends ScalaCommand[ScalafixOptions] { + override def group: String = HelpCommandGroup.Main.toString + override def sharedOptions(options: ScalafixOptions): Option[SharedOptions] = Some(options.shared) + override def scalaSpecificationLevel: SpecificationLevel = SpecificationLevel.EXPERIMENTAL + + val hiddenHelpGroups: Seq[HelpGroup] = + Seq( + HelpGroup.Scala, + HelpGroup.Java, + HelpGroup.Dependency, + HelpGroup.ScalaJs, + HelpGroup.ScalaNative, + HelpGroup.CompilationServer, + HelpGroup.Debug + ) + override def helpFormat: HelpFormat = super.helpFormat + .withHiddenGroups(hiddenHelpGroups) + .withHiddenGroupsWhenShowHidden(hiddenHelpGroups) + .withPrimaryGroup(HelpGroup.Format) + override def names: List[List[String]] = List( + List("scalafix") + ) + + override def runCommand(options: ScalafixOptions, args: RemainingArgs, logger: Logger): Unit = { + val buildOptions = buildOptionsOrExit(options) + val buildOptionsWithSemanticDb = buildOptions.copy(scalaOptions = + buildOptions.scalaOptions.copy(semanticDbOptions = + buildOptions.scalaOptions.semanticDbOptions.copy(generateSemanticDbs = Some(true)) + ) + ) + val inputs = options.shared.inputs(args.all).orExit(logger) + val threads = BuildThreads.create() + val compilerMaker = options.shared.compilerMaker(threads) + val configDb = ConfigDbUtils.configDb.orExit(logger) + val actionableDiagnostics = + options.shared.logging.verbosityOptions.actions.orElse( + configDb.get(Keys.actions).getOrElse(None) + ) + + val workspace = + if (args.all.isEmpty) os.pwd + else inputs.workspace + + val scalaVersion = + options.buildOptions.orExit(logger).scalaParams.orExit(logger).map(_.scalaVersion) + .getOrElse(Constants.defaultScalaVersion) + val scalaBinVersion = + options.buildOptions.orExit(logger).scalaParams.orExit(logger).map(_.scalaBinaryVersion) + + val configFilePathOpt = options.scalafixConf.map(os.Path(_, os.pwd)) + + val res = Build.build( + inputs, + buildOptionsWithSemanticDb, + compilerMaker, + None, + logger, + crossBuilds = false, + buildTests = false, + partial = None, + actionableDiagnostics = actionableDiagnostics + ) + val builds = res.orExit(logger) + + builds.get(Scope.Main).flatMap(_.successfulOpt) match + case None => sys.exit(1) + case Some(build) => + val classPaths = build.fullClassPath + + val scalacOptions = options.shared.scalac.scalacOption ++ + build.options.scalaOptions.scalacOptions.toSeq.map(_.value.value) + + either { + val artifacts = + value( + ScalafixArtifacts.artifacts( + scalaVersion, + build.options.classPathOptions.scalafixDependencies.values.flatten, + value(buildOptions.finalRepositories), + logger, + buildOptions.internal.cache.getOrElse(FileCache()) + ) + ) + + val scalafixOptions = + options.scalafixConf.toList.flatMap(scalafixConf => List("--config", scalafixConf)) ++ + Seq("--sourceroot", workspace.toString) ++ + Seq("--classpath", classPaths.mkString(java.io.File.pathSeparator)) ++ + Seq("--scala-version", scalaVersion) ++ + (if (options.check) Seq("--test") else Nil) ++ + (if (scalacOptions.nonEmpty) scalacOptions.flatMap(Seq("--scalac-options", _)) + else Nil) ++ + (if (artifacts.toolsJars.nonEmpty) + Seq("--tool-classpath", artifacts.toolsJars.mkString(java.io.File.pathSeparator)) + else Nil) ++ + options.rules.flatMap(Seq("-r", _)) + ++ options.scalafixArg + + val proc = Runner.runJvm( + buildOptions.javaHome().value.javaCommand, + buildOptions.javaOptions.javaOpts.toSeq.map(_.value.value), + artifacts.scalafixJars, + "scalafix.cli.Cli", + scalafixOptions, + logger, + cwd = Some(workspace), + allowExecve = true + ) + + sys.exit(proc.waitFor()) + } + + } + +} diff --git a/modules/cli/src/main/scala/scala/cli/commands/scalafix/ScalafixOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/scalafix/ScalafixOptions.scala new file mode 100644 index 0000000000..e666411ee9 --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/commands/scalafix/ScalafixOptions.scala @@ -0,0 +1,63 @@ +package scala.cli.commands.scalafix + +import caseapp.* +import coursier.core.Version + +import scala.build.EitherCps.{either, value} +import scala.build.errors.BuildException +import scala.build.internal.FetchExternalBinary +import scala.build.options.BuildOptions +import scala.cli.ScalaCli.fullRunnerName +import scala.cli.commands.shared.{HasSharedOptions, HelpGroup, HelpMessages, SharedOptions} +import scala.cli.commands.{Constants, tags} +import scala.util.Properties + +// format: off +@HelpMessage(ScalafixOptions.helpMessage, "", ScalafixOptions.detailedHelpMessage) +final case class ScalafixOptions( + @Recurse + shared: SharedOptions = SharedOptions(), + + @Group(HelpGroup.Format.toString) + @Tag(tags.experimental) + @HelpMessage("Custom path to the scalafix configuration file.") + @Tag(tags.inShortHelp) + scalafixConf: Option[String] = None, + + @Group(HelpGroup.Format.toString) + @Tag(tags.experimental) + @HelpMessage("Pass extra argument(s) to scalafix.") + @Tag(tags.inShortHelp) + scalafixArg: List[String] = Nil, + + @Group(HelpGroup.Format.toString) + @Tag(tags.experimental) + @HelpMessage("Run rule(s) explicitly, overriding the configuration file default.") + @Tag(tags.inShortHelp) + rules: List[String] = Nil, + + @Group(HelpGroup.Format.toString) + @Tag(tags.experimental) + @HelpMessage("Fail the invocation if rewrites are needed") + @Tag(tags.inShortHelp) + check: Boolean = false, +) extends HasSharedOptions { + def buildOptions: Either[BuildException, BuildOptions] = shared.buildOptions() + +} +object ScalafixOptions { + implicit lazy val parser: Parser[ScalafixOptions] = Parser.derive + implicit lazy val help: Help[ScalafixOptions] = Help.derive + + val cmdName = "scalafix" + private val helpHeader = "Run Scalafix rules to lint or rewrite Scala code." + val helpMessage: String = HelpMessages.shortHelpMessage(cmdName, helpHeader) + val detailedHelpMessage: String = + s"""$helpHeader + | + |`scalafix` is used to check project code or rewrite it under the hood with use of specified rules. + | + |All standard $fullRunnerName inputs are accepted, but only Scala sources will be refactored (.scala and .sc files). + | + |${HelpMessages.commandDocWebsiteReference(cmdName)}""".stripMargin +} diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala index 45234df10c..6c99e3c7a0 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Dependency.scala @@ -14,6 +14,7 @@ import scala.build.options.{ ShadowingSeq, WithBuildRequirements } +import scala.build.preprocessing.directives.Dependency.DependencyType import scala.build.preprocessing.directives.DirectiveUtil.* import scala.cli.commands.SpecificationLevel @@ -46,27 +47,48 @@ final case class Dependency( @DirectiveName("compileOnly.dep") @DirectiveName("compileOnly.deps") @DirectiveName("compileOnly.dependencies") - compileOnlyDependency: List[Positioned[String]] = Nil + compileOnlyDependency: List[Positioned[String]] = Nil, + @DirectiveName("scalafix.dep") + @DirectiveName("scalafix.deps") + @DirectiveName("scalafix.dependencies") + scalafixDependency: List[Positioned[String]] = Nil ) extends HasBuildOptionsWithRequirements { def buildOptionsList: List[Either[BuildException, WithBuildRequirements[BuildOptions]]] = List( - Dependency.buildOptions(dependency).map(_.withEmptyRequirements), - Dependency.buildOptions(testDependency).map(_.withScopeRequirement(Scope.Test)), - Dependency.buildOptions(compileOnlyDependency, isCompileOnly = true) + Dependency.buildOptions(dependency, DependencyType.Runtime).map(_.withEmptyRequirements), + Dependency.buildOptions(testDependency, DependencyType.Runtime).map( + _.withScopeRequirement(Scope.Test) + ), + Dependency.buildOptions(compileOnlyDependency, DependencyType.CompileOnly) + .map(_.withEmptyRequirements), + Dependency.buildOptions(scalafixDependency, DependencyType.Scalafix) .map(_.withEmptyRequirements) ) } object Dependency { val handler: DirectiveHandler[Dependency] = DirectiveHandler.derive + + sealed trait DependencyType + object DependencyType { + case object Runtime extends DependencyType + case object CompileOnly extends DependencyType + case object Scalafix extends DependencyType + } + def buildOptions( ds: List[Positioned[String]], - isCompileOnly: Boolean = false + tpe: DependencyType ): Either[BuildException, BuildOptions] = either { val dependencies: ShadowingSeq[Positioned[AnyDependency]] = value(ds.asDependencies.map(ShadowingSeq.from)) val classPathOptions = - if (isCompileOnly) ClassPathOptions(extraCompileOnlyDependencies = dependencies) - else ClassPathOptions(extraDependencies = dependencies) + tpe match { + case DependencyType.Runtime => ClassPathOptions(extraDependencies = dependencies) + case DependencyType.CompileOnly => + ClassPathOptions(extraCompileOnlyDependencies = dependencies) + case DependencyType.Scalafix => ClassPathOptions(scalafixDependencies = dependencies) + } + BuildOptions(classPathOptions = classPathOptions) } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/ScalafixTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTestDefinitions.scala new file mode 100644 index 0000000000..7d326b0bc4 --- /dev/null +++ b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTestDefinitions.scala @@ -0,0 +1,297 @@ +package scala.cli.integration + +import com.eed3si9n.expecty.Expecty.expect + +abstract class ScalafixTestDefinitions extends ScalaCliSuite with TestScalaVersionArgs { + _: TestScalaVersion => + override def group: ScalaCliSuite.TestGroup = ScalaCliSuite.TestGroup.First + + protected val confFileName: String = ".scalafix.conf" + + protected val unusedRuleOption: String + + protected def noCrLf(input: String): String = + input.replaceAll("\r\n", "\n") + + private val simpleInputsOriginalContent: String = + """package foo + | + |final object Hello { + | def main(args: Array[String]): Unit = { + | println("Hello") + | } + |} + |""".stripMargin + private val simpleInputs: TestInputs = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | RedundantSyntax + |] + |""".stripMargin, + os.rel / "Hello.scala" -> simpleInputsOriginalContent + ) + private val expectedContent: String = noCrLf { + """package foo + | + |object Hello { + | def main(args: Array[String]): Unit = { + | println("Hello") + | } + |} + |""".stripMargin + } + + test("simple") { + simpleInputs.fromRoot { root => + os.proc(TestUtil.cli, "scalafix", ".", "--power", scalaVersionArgs).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == expectedContent) + } + } + + test("with --check") { + simpleInputs.fromRoot { root => + val res = os.proc(TestUtil.cli, "scalafix", "--power", "--check", ".", scalaVersionArgs).call( + cwd = root, + check = false + ) + expect(res.exitCode != 0) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == noCrLf(simpleInputsOriginalContent)) + } + } + + test("semantic rule") { + val unusedValueInputsContent: String = + s"""//> using options $unusedRuleOption + |package foo + | + |object Hello { + | def main(args: Array[String]): Unit = { + | val name = "John" + | println("Hello") + | } + |} + |""".stripMargin + val semanticRuleInputs: TestInputs = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | RemoveUnused + |] + |""".stripMargin, + os.rel / "Hello.scala" -> unusedValueInputsContent + ) + val expectedContent: String = noCrLf { + s"""//> using options $unusedRuleOption + |package foo + | + |object Hello { + | def main(args: Array[String]): Unit = { + | + | println("Hello") + | } + |} + |""".stripMargin + } + + semanticRuleInputs.fromRoot { root => + os.proc(TestUtil.cli, "scalafix", "--power", ".", scalaVersionArgs).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == expectedContent) + } + } + + test("--rules args") { + val input = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | RemoveUnused, + | RedundantSyntax + |] + |""".stripMargin, + os.rel / "Hello.scala" -> + s"""|//> using options $unusedRuleOption + |package hello + | + |object Hello { + | def a = { + | val x = 1 // keep unused - exec only RedundantSyntax + | s"Foo" + | } + |} + |""".stripMargin + ) + + input.fromRoot { root => + os.proc( + TestUtil.cli, + "scalafix", + ".", + "--rules", + "RedundantSyntax", + "--power", + scalaVersionArgs + ).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + val expected = noCrLf { + s"""|//> using options $unusedRuleOption + |package hello + | + |object Hello { + | def a = { + | val x = 1 // keep unused - exec only RedundantSyntax + | "Foo" + | } + |} + |""".stripMargin + } + + expect(updatedContent == expected) + + } + } + + test("--scalafix-arg arg") { + val original: String = + """|package foo + | + |final object Hello { // keep `final` beucase of parameter finalObject=false + | s"Foo" + |} + |""".stripMargin + val inputs: TestInputs = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | RedundantSyntax + |] + |""".stripMargin, + os.rel / "Hello.scala" -> original + ) + val expectedContent: String = noCrLf { + """|package foo + | + |final object Hello { // keep `final` beucase of parameter finalObject=false + | "Foo" + |} + |""".stripMargin + } + + inputs.fromRoot { root => + os.proc( + TestUtil.cli, + "scalafix", + ".", + "--scalafix-arg=--settings.RedundantSyntax.finalObject=false", + "--power", + scalaVersionArgs + ).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == expectedContent) + } + } + + test("--scalafix-conf arg") { + val original: String = + """|package foo + | + |final object Hello { + | s"Foo" + |} + |""".stripMargin + + val confFileName = "unusual-scalafix-filename" + val inputs: TestInputs = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | RedundantSyntax + |] + |""".stripMargin, + os.rel / "Hello.scala" -> original + ) + val expectedContent: String = noCrLf { + """|package foo + | + |object Hello { + | "Foo" + |} + |""".stripMargin + } + + inputs.fromRoot { root => + os.proc( + TestUtil.cli, + "scalafix", + ".", + s"--scalafix-conf=$confFileName", + "--power", + scalaVersionArgs + ).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == expectedContent) + } + } + + test("external rule") { + val original: String = + """|//> using scalafix.dep "com.github.xuwei-k::scalafix-rules:0.5.1" + | + |object CollectHeadOptionTest { + | def x1: Option[String] = List(1, 2, 3).collect { case n if n % 2 == 0 => n.toString }.headOption + |} + |""".stripMargin + val inputs: TestInputs = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | CollectHeadOption + |] + |""".stripMargin, + os.rel / "Hello.scala" -> original + ) + val expectedContent: String = noCrLf { + """|//> using scalafix.dep "com.github.xuwei-k::scalafix-rules:0.5.1" + | + |object CollectHeadOptionTest { + | def x1: Option[String] = List(1, 2, 3).collectFirst{ case n if n % 2 == 0 => n.toString } + |} + |""".stripMargin + } + + inputs.fromRoot { root => + os.proc(TestUtil.cli, "scalafix", ".", "--power", scalaVersionArgs).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == expectedContent) + } + } + + test("explicit-result-types") { + val original: String = + """|package foo + | + |object Hello { + | def a(a: Int) = "asdasd" + a.toString + |} + |""".stripMargin + val inputs: TestInputs = TestInputs( + os.rel / confFileName -> + s"""|rules = [ + | ExplicitResultTypes + |] + |""".stripMargin, + os.rel / "Hello.scala" -> original + ) + val expectedContent: String = noCrLf { + """|package foo + | + |object Hello { + | def a(a: Int): String = "asdasd" + a.toString + |} + |""".stripMargin + } + + inputs.fromRoot { root => + os.proc(TestUtil.cli, "scalafix", ".", "--power", scalaVersionArgs).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Hello.scala")) + expect(updatedContent == expectedContent) + } + } +} diff --git a/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests212.scala b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests212.scala new file mode 100644 index 0000000000..3cdf25639f --- /dev/null +++ b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests212.scala @@ -0,0 +1,5 @@ +package scala.cli.integration + +class ScalafixTests212 extends ScalafixTestDefinitions with Test212 { + override val unusedRuleOption: String = "-Ywarn-unused" +} diff --git a/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests213.scala b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests213.scala new file mode 100644 index 0000000000..674fe16c88 --- /dev/null +++ b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests213.scala @@ -0,0 +1,6 @@ +package scala.cli.integration + +class ScalafixTests213 extends ScalafixTestDefinitions with Test213 { + override val unusedRuleOption: String = "-Wunused" + +} diff --git a/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests3.scala b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests3.scala new file mode 100644 index 0000000000..98e40540cf --- /dev/null +++ b/modules/integration/src/test/scala/scala/cli/integration/ScalafixTests3.scala @@ -0,0 +1,5 @@ +package scala.cli.integration + +class ScalafixTests3 extends ScalafixTestDefinitions with TestDefault { + override val unusedRuleOption: String = "-Wunused:all" +} diff --git a/modules/options/src/main/scala/scala/build/options/ClassPathOptions.scala b/modules/options/src/main/scala/scala/build/options/ClassPathOptions.scala index 76d886586d..10272c3ce3 100644 --- a/modules/options/src/main/scala/scala/build/options/ClassPathOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/ClassPathOptions.scala @@ -13,7 +13,8 @@ final case class ClassPathOptions( extraDependencies: ShadowingSeq[Positioned[AnyDependency]] = ShadowingSeq.empty, extraCompileOnlyDependencies: ShadowingSeq[Positioned[AnyDependency]] = ShadowingSeq.empty, resourcesDir: Seq[os.Path] = Nil, - resourcesVirtualDir: Seq[os.SubPath] = Nil + resourcesVirtualDir: Seq[os.SubPath] = Nil, + scalafixDependencies: ShadowingSeq[Positioned[AnyDependency]] = ShadowingSeq.empty ) { def allExtraDependencies: ShadowingSeq[Positioned[AnyDependency]] = extraDependencies ++ extraCompileOnlyDependencies.toSeq diff --git a/project/deps.sc b/project/deps.sc index 3c211e619d..517d2c46a6 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -131,6 +131,7 @@ object Deps { def mavenAppArtifactId = "maven-app" def mavenAppGroupId = "com.example" def mavenAppVersion = "0.1-SNAPSHOT" + def scalafix = "0.13.0" } // DO NOT hardcode a Scala version in this dependency string // This dependency is used to ensure that Ammonite is available for Scala versions @@ -247,7 +248,8 @@ object Deps { // This provides a ZipInputStream that doesn't verify CRC32 checksums, that users // can enable by setting SCALA_CLI_VENDORED_ZIS=true in the environment, to workaround // some bad GraalVM / zlib issues (see #828 and linked issues for more details). - def zipInputStream = ivy"org.virtuslab.scala-cli.zip-input-stream:zip-input-stream:0.1.2" + def zipInputStream = ivy"org.virtuslab.scala-cli.zip-input-stream:zip-input-stream:0.1.2" + def scalafixInterfaces = ivy"ch.epfl.scala:scalafix-interfaces:${Versions.scalafix}" } def graalVmVersion = "22.3.1" diff --git a/website/docs/commands/scalafix.md b/website/docs/commands/scalafix.md new file mode 100644 index 0000000000..f8864b5ea7 --- /dev/null +++ b/website/docs/commands/scalafix.md @@ -0,0 +1,45 @@ +--- +title: Scalafix ⚡️ +sidebar_position: 80 +--- + +:::caution +The Scalafix command is experimental and requires setting the `--power` option to be used. +You can pass it explicitly or set it globally by running: + + scala-cli config power true +::: + +Scala CLI runs [Scalafix](https://scalacenter.github.io/scalafix/) - Refactoring and Linting tool for Scala + +Before using this command you need to provide the configuration at `.scalafix.conf`. +For example: +``` text title=.scalafix.conf +// .scalafix.conf +rules = [ + DisableSyntax +] +``` + +Then you can run it: +```bash +scala-cli scalafix . --power +``` + +If you’re setting up a continuous integration (CI) server, Scala CLI also has you covered. +You can run linter using a `--check` flag: +```bash fail +scala-cli scalafix --check . --power +``` + +Read more about Scalafix: +- [Configuration](https://scalacenter.github.io/scalafix/docs/users/configuration.html) +- [Rules](https://scalacenter.github.io/scalafix/docs/rules/overview.html) + + +### Using external rules + +Adding an [external scalafix rule](https://scalacenter.github.io/scalafix/docs/rules/external-rules.html) to scala-cli might be done by declaring [`scalafix.dep`](./compile.md#compile-only-dependencies): +```scala title=externalRule.scala +//> using scalafix.dep "com.github.xuwei-k::scalafix-rules:0.5.1" +``` diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index b20e736750..088d05771d 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -46,7 +46,7 @@ are assumed to be Scala compiler options and will be propagated to Scala Compile Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -62,7 +62,7 @@ Set JMH version (default: 1.37) Available in commands: -[`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall) +[`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall) @@ -219,7 +219,7 @@ Force overwriting values for key Available in commands: -[`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall) +[`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall) @@ -258,7 +258,7 @@ Run given command against all provided Scala versions and/or platforms Available in commands: -[`bloop`](./commands.md#bloop), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bloop`](./commands.md#bloop), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -278,7 +278,7 @@ Debug mode (attach by default) Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -483,7 +483,7 @@ Pass scalafmt version before running it (3.8.3 by default). If passed, this over Available in commands: -[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) +[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) @@ -497,7 +497,7 @@ Suppress warnings about using experimental features Available in commands: -[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp create`](./commands.md#pgp-create), [`pgp key-id`](./commands.md#pgp-key-id), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`pgp sign`](./commands.md#pgp-sign), [`pgp verify`](./commands.md#pgp-verify), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) +[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp create`](./commands.md#pgp-create), [`pgp key-id`](./commands.md#pgp-key-id), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`pgp sign`](./commands.md#pgp-sign), [`pgp verify`](./commands.md#pgp-verify), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) @@ -521,7 +521,7 @@ Print help message, including hidden options, and exit Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -627,7 +627,7 @@ Add java properties. Note that options equal `-Dproperty=value` are assumed to b Available in commands: -[`bloop`](./commands.md#bloop), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bloop`](./commands.md#bloop), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -677,7 +677,7 @@ Port for BSP debugging Available in commands: -[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) +[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) @@ -715,7 +715,7 @@ List main classes available in the current context Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -974,7 +974,7 @@ Key server to push / pull keys from Available in commands: -[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) +[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) @@ -1176,7 +1176,7 @@ Dummy mode - don't upload any secret to GitHub Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1279,7 +1279,7 @@ Run Java commands using a manifest-based class path (shortens command length) Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1378,7 +1378,7 @@ Whether to run the Scala.js CLI on the JVM or using a native executable Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1444,7 +1444,7 @@ Enable/disable Scala Native multithreading support Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1462,7 +1462,7 @@ Add a `scalac` option. Note that options starting with `-g`, `-language`, `-opt` Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1478,6 +1478,30 @@ Aliases: `--verbose-scalac` Turn verbosity on for scalac. This is an alias for --scalac-option -verbose +## Scalafix options + +Available in commands: + +[`scalafix`](./commands.md#scalafix) + + + +### `--scalafix-conf` + +Custom path to the scalafix configuration file. + +### `--scalafix-arg` + +Pass extra argument(s) to scalafix. + +### `--rules` + +Run rule(s) explicitly, overriding the configuration file default. + +### `--check` + +Fail the invocation if rewrites are needed + ## Scope options Available in commands: @@ -1529,7 +1553,7 @@ Aliases: `-n` Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1625,7 +1649,7 @@ Force object wrapper for scripts Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1674,7 +1698,7 @@ A synonym to --markdown-snippet, which defaults the sub-command to `run` when no Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1688,7 +1712,7 @@ Generate BuildInfo for project Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -1809,7 +1833,7 @@ A github token used to access GitHub. Not needed in most cases. Available in commands: -[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) +[`add-path`](./commands.md#add-path), [`bloop`](./commands.md#bloop), [`bloop exit`](./commands.md#bloop-exit), [`bloop output`](./commands.md#bloop-output), [`bloop start`](./commands.md#bloop-start), [`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`config`](./commands.md#config), [`default-file`](./commands.md#default-file), [`dependency-update`](./commands.md#dependency-update), [`directories`](./commands.md#directories), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`help`](./commands.md#help), [`install completions` , `install-completions`](./commands.md#install-completions), [`install-home`](./commands.md#install-home), [`new`](./commands.md#new), [`package`](./commands.md#package), [`pgp pull`](./commands.md#pgp-pull), [`pgp push`](./commands.md#pgp-push), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`github secret create` , `gh secret create`](./commands.md#github-secret-create), [`github secret list` , `gh secret list`](./commands.md#github-secret-list), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`uninstall`](./commands.md#uninstall), [`uninstall completions` , `uninstall-completions`](./commands.md#uninstall-completions), [`update`](./commands.md#update), [`version`](./commands.md#version) @@ -1833,7 +1857,7 @@ Enable actionable diagnostics Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`version`](./commands.md#version) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test), [`version`](./commands.md#version) @@ -2005,7 +2029,7 @@ Force overwriting destination files Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -2224,7 +2248,7 @@ Time to wait between staging repository operation retries, in milliseconds. Available in commands: -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) @@ -2264,7 +2288,7 @@ Available in commands: Available in commands: -[`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) +[`bsp`](./commands.md#bsp), [`clean`](./commands.md#clean), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`publish setup`](./commands.md#publish-setup), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`scalafix`](./commands.md#scalafix), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) diff --git a/website/docs/reference/commands.md b/website/docs/reference/commands.md index 193dfbba8d..361a3281ee 100644 --- a/website/docs/reference/commands.md +++ b/website/docs/reference/commands.md @@ -156,6 +156,22 @@ For detailed documentation refer to our website: https://scala-cli.virtuslab.org Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +## scalafix + +Run Scalafix rules to lint or rewrite Scala code. + +`scalafix` is used to check project code or rewrite it under the hood with use of specified rules. + +All standard Scala CLI inputs are accepted, but only Scala sources will be refactored (.scala and .sc files). + +For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/scalafix + +The `scalafix` sub-command is experimental. +Please bear in mind that non-ideal user experience should be expected. +If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli + +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [Scalafix](./cli-options.md#scalafix-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) + ## help Print help message