diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index b421b877..20e9ea0e 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -15,3 +15,6 @@ c3b04b90d9863ca2c7b7e56bc0bda148ce392642 # Scala Steward: Reformat with scalafmt 3.8.1 cb6d4261c6253f685d50b24177064616e5d22143 + +# Scala Steward: Reformat with scalafmt 3.9.8 +e316169276b40dbdc76142d03895233ba103f417 diff --git a/.scalafmt.conf b/.scalafmt.conf index 29f85935..704cbf04 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.9.1 +version = 3.9.9 project.layout=StandardConvention diff --git a/build.sbt b/build.sbt index 04867c64..2e7bfa17 100644 --- a/build.sbt +++ b/build.sbt @@ -55,7 +55,7 @@ lazy val api = crossProject(JVMPlatform, JSPlatform) ) ), libraryDependencies ++= Seq( - "org.scala-lang.modules" %%% "scala-xml" % "2.3.0", + "org.scala-lang.modules" %%% "scala-xml" % "2.4.0", "org.scalatest" %%% "scalatest" % ScalaTestVersion % Test, ) ++ (scalaVersion.value match { case v @ (Scala212 | Scala213) => Seq("org.scala-lang" % "scala-reflect" % v % "provided") @@ -90,7 +90,7 @@ lazy val compiler = project } }, libraryDependencies += parserCombinators(scalaVersion.value), - libraryDependencies += "org.scalameta" %% "parsers" % "4.13.4", + libraryDependencies += "org.scalameta" %% "parsers" % "4.13.9", run / fork := true, buildInfoKeys := Seq[BuildInfoKey](scalaVersion), buildInfoPackage := "play.twirl.compiler", @@ -108,14 +108,14 @@ lazy val plugin = project name := "sbt-typed-twirl", organization := "bondlink", scalaVersion := Scala212, - crossScalaVersions := Seq(Scala212, Scala36), + crossScalaVersions := Seq(Scala212, Scala37), libraryDependencies += "org.scalatest" %%% "scalatest" % ScalaTestVersion % Test, - pluginCrossBuild / sbtVersion := { + pluginCrossBuild / sbtVersion := { scalaBinaryVersion.value match { case "2.12" => sbtVersion.value case _ => - "2.0.0-M4" + "2.0.0-RC6" } }, Compile / resourceGenerators += generateVersionFile.taskValue, diff --git a/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala b/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala index 91b9c051..3122a67e 100644 --- a/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala +++ b/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala @@ -7,6 +7,7 @@ package play.twirl.compiler import java.io.File import scala.annotation.tailrec import scala.io.Codec +import scala.meta.classifiers._ import play.twirl.parser.TwirlIO import play.twirl.parser.TwirlParser import scala.util.parsing.input.Position @@ -90,7 +91,7 @@ sealed trait AbstractGeneratedSource { def mapPosition(generatedPosition: Int): Int = { matrix.indexWhere(p => p._1 > generatedPosition) match { - case 0 => 0 + case 0 => 0 case i if i > 0 => { val pos = matrix(i - 1) pos._2 + (generatedPosition - pos._1) @@ -104,7 +105,7 @@ sealed trait AbstractGeneratedSource { def mapLine(generatedLine: Int): Int = { lines.indexWhere(p => p._1 > generatedLine) match { - case 0 => 0 + case 0 => 0 case i if i > 0 => { val line = lines(i - 1) line._2 + (generatedLine - line._1) @@ -153,7 +154,7 @@ case class GeneratedSource(file: File, codec: Codec = TwirlIO.defaultCodec) exte } case class GeneratedSourceVirtual(path: String) extends AbstractGeneratedSource { - var _content = "" + var _content = "" def setContent(newContent: String): Unit = { this._content = newContent } @@ -163,11 +164,13 @@ case class GeneratedSourceVirtual(path: String) extends AbstractGeneratedSource object TwirlCompiler { // For constants that depend on Scala 2 or 3 mode. - private[compiler] class ScalaCompat(emitScala3Sources: Boolean) { + private[compiler] class ScalaCompat(val emitScala3Sources: Boolean) { val varargSplicesSyntax: String = if (emitScala3Sources) "*" else ": _*" def valueOrEmptyIfScala3Exceeding22Params(params: Int, value: => String): String = if (emitScala3Sources && params > 22) "" else value + val usingSyntax: String = + if (emitScala3Sources) "using " else "" } private[compiler] object ScalaCompat { @@ -236,7 +239,7 @@ object TwirlCompiler { codec: Codec, inclusiveDot: Boolean ): Option[File] = { - val resultType = formatterType + ".Appendable" + val resultType = formatterType + ".Appendable" val (templateName, generatedSource) = generatedFile(source, codec, sourceDirectory, generatedDirectory, inclusiveDot) if (generatedSource.needRecompilation(additionalImports)) { @@ -297,7 +300,7 @@ object TwirlCompiler { ): GeneratedSourceVirtual = { val (templateName, generatedSource) = generatedFileVirtual(source, sourceDirectory, inclusiveDot) - val generated = parseAndGenerateCode( + val generated = parseAndGenerateCode( templateName, content.getBytes(codec.charSet), codec, @@ -462,7 +465,7 @@ object TwirlCompiler { // We need to double escape slashes, since it's a regex replacement private val escapedTripleQuote = "\\\"" * 3 private val doubleEscapedTripleQuote = "\\\\\"" * 3 - private val tripleQuoteReplacement = + private val tripleQuoteReplacement = escapedTripleQuote + " + \\\"" + doubleEscapedTripleQuote + "\\\" + " + escapedTripleQuote private def quoteAndEscape(text: String): collection.Seq[String] = { Seq(tripleQuote, text.replaceAll(tripleQuote, tripleQuoteReplacement), tripleQuote) @@ -691,7 +694,7 @@ package """ :+ packageName :+ """ val params: List[List[Term.Param]] = try { - val dialect = Dialect.current + val dialect = Dialect.current.withAllowGivenUsing(true) val input = Input.String(s"object FT { def signature$signature }") val obj = implicitly[Parse[Stat]].apply(input, dialect).get.asInstanceOf[Defn.Object] val templ = obj.templ @@ -715,6 +718,27 @@ package """ :+ packageName :+ """ ) .mkString(" => ") + " => " + returnType + ")" + val hasContextParameters = + params.flatten.exists(_.mods.exists(modifier => modifier.is[Mod.Implicit] || modifier.is[Mod.Using])) + + val applyArgs = { + params.map { group => + val groupStr = "(" + group + .map { p => + p.name.toString + Option(p.decltpe.get.toString) + .filter(_.endsWith("*")) + .map(_ => s".toIndexedSeq${sc.varargSplicesSyntax}") + .getOrElse("") + } + .mkString(",") + ")" + + // prepend "using" for Scala 3 context parameters on the last param + if (sc.emitScala3Sources && hasContextParameters && group == params.last) + groupStr.replace("(", s"(${sc.usingSyntax}") + else groupStr + }.mkString + } + val renderCall = "def render%s: %s = apply%s".format( "(" + params.flatten .map { @@ -723,18 +747,13 @@ package """ :+ packageName :+ """ } .mkString(",") + ")", returnType, - params - .map(group => - "(" + group - .map { p => - p.name.toString + Option(p.decltpe.get.toString) - .filter(_.endsWith("*")) - .map(_ => s".toIndexedSeq${sc.varargSplicesSyntax}") - .getOrElse("") - } - .mkString(",") + ")" - ) - .mkString + applyArgs + ) + + val f = "def f:%s = %s => apply%s".format( + functionType, + params.map(group => "(" + group.map(_.name.toString).mkString(",") + ")").mkString(" => "), + applyArgs ) val templateType = sc.valueOrEmptyIfScala3Exceeding22Params( @@ -751,23 +770,6 @@ package """ :+ packageName :+ """ ) ) - val f = "def f:%s = %s => apply%s".format( - functionType, - params.map(group => "(" + group.map(_.name.toString).mkString(",") + ")").mkString(" => "), - params - .map(group => - "(" + group - .map { p => - p.name.toString + Option(p.decltpe.get.toString) - .filter(_.endsWith("*")) - .map(_ => s".toIndexedSeq${sc.varargSplicesSyntax}") - .getOrElse("") - } - .mkString(",") + ")" - ) - .mkString - ) - (renderCall, f, templateType) } @@ -810,7 +812,7 @@ object Source { lines: ListBuffer[(Int, Int)] ): Unit = { parts.foreach { - case s: String => source.append(s) + case s: String => source.append(s) case Source(code, pos @ OffsetPosition(_, offset)) => { source.append("/*" + pos + "*/") positions += (source.length -> offset) diff --git a/compiler/src/test/resources/using.scala.html b/compiler/src/test/resources/using.scala.html new file mode 100644 index 00000000..575f5e11 --- /dev/null +++ b/compiler/src/test/resources/using.scala.html @@ -0,0 +1,6 @@ +@******************************************************************************************************************************************************************* + * Copyright (C) from 2025 BondLink, 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. * + *******************************************************************************************************************************************************************@ + +@(x: String)(using y: String) +@x @y diff --git a/compiler/src/test/scala-2/play/twirl/compiler/test/Helper.scala b/compiler/src/test/scala-2/play/twirl/compiler/test/Helper.scala index bb0364a8..aafaab87 100644 --- a/compiler/src/test/scala-2/play/twirl/compiler/test/Helper.scala +++ b/compiler/src/test/scala-2/play/twirl/compiler/test/Helper.scala @@ -82,7 +82,7 @@ object Helper { def inject(constructorArgs: Any*): T = { classloader.loadClass(className).getConstructors match { case Array(single) => getF(single.newInstance(constructorArgs.asInstanceOf[Seq[AnyRef]]: _*)) - case other => + case other => throw new IllegalStateException(className + " does not declare exactly one constructor: " + other) } } @@ -93,8 +93,8 @@ object Helper { className: String, additionalImports: Seq[String] = Nil ): CompiledTemplate[T] = { - val scalaVersion = play.twirl.compiler.BuildInfo.scalaVersion - val templateFile = new File(sourceDir, templateName) + val scalaVersion = play.twirl.compiler.BuildInfo.scalaVersion + val templateFile = new File(sourceDir, templateName) val Some(generated) = twirlCompiler.compile( templateFile, sourceDir, diff --git a/compiler/src/test/scala-3/play/twirl/compiler/test/Helper.scala b/compiler/src/test/scala-3/play/twirl/compiler/test/Helper.scala index 82a9d330..4e66e818 100644 --- a/compiler/src/test/scala-3/play/twirl/compiler/test/Helper.scala +++ b/compiler/src/test/scala-3/play/twirl/compiler/test/Helper.scala @@ -49,7 +49,7 @@ object Helper { def inject(constructorArgs: Any*): T = { classloader.loadClass(className).getConstructors match { case Array(single) => getF(single.newInstance(constructorArgs.asInstanceOf[Seq[AnyRef]]*)) - case other => + case other => throw new IllegalStateException(className + " does not declare exactly one constructor: " + other) } } @@ -60,8 +60,8 @@ object Helper { className: String, additionalImports: Seq[String] = Nil ): CompiledTemplate[T] = { - val scalaVersion = play.twirl.compiler.BuildInfo.scalaVersion - val templateFile = new File(sourceDir, templateName) + val scalaVersion = play.twirl.compiler.BuildInfo.scalaVersion + val templateFile = new File(sourceDir, templateName) val generatedOpt: Option[File] = twirlCompiler.compile( templateFile, sourceDir, @@ -104,7 +104,7 @@ object Helper { class TestDriver(outDir: Path, compilerArgs: Array[String], path: Path) extends Driver { def compile(): Reporter = { - val setupOpt = setup(compilerArgs :+ path.toAbsolutePath.toString, initCtx.fresh) + val setupOpt = setup(compilerArgs :+ path.toAbsolutePath.toString, initCtx.fresh) val (toCompile, rootCtx) = setupOpt.getOrElse { throw new Exception("Failed to initialize compiler") } diff --git a/compiler/src/test/scala/play/twirl/compiler/test/CompilerSpec.scala b/compiler/src/test/scala/play/twirl/compiler/test/CompilerSpec.scala index 2e1b4564..958d64f0 100644 --- a/compiler/src/test/scala/play/twirl/compiler/test/CompilerSpec.scala +++ b/compiler/src/test/scala/play/twirl/compiler/test/CompilerSpec.scala @@ -34,7 +34,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { testName should { "compile successfully (real)" in { val helper = newCompilerHelper - val tmpl = helper + val tmpl = helper .compile[((String, List[String]) => (Int) => Html)]("real.scala.html", "html.real") .static("World", List("A", "B"))(4) .toString @@ -77,7 +77,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile successfully (helloNull)" in { val helper = newCompilerHelper - val hello = + val hello = helper.compile[((String) => Html)]("helloNull.scala.html", "html.helloNull").static(null).toString.trim hello must be("

Hello !

") } @@ -95,7 +95,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile successfully (set)" in { val helper = newCompilerHelper - val set = helper + val set = helper .compile[((collection.immutable.Set[String]) => Html)]("set.scala.html", "html.set") .static(Set("first", "second", "third")) .toString @@ -146,7 +146,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile successfully (var args existential)" in { val helper = newCompilerHelper - val text = helper + val text = helper .compile[(Array[List[?]] => Html)]("varArgsExistential.scala.html", "html.varArgsExistential") .static(Array(List(1, 2, 3), List(4, 5, 6))) .toString @@ -160,9 +160,28 @@ class CompilerSpec extends AnyWordSpec with Matchers { text must be("123456") } - "compile successfully (call by name)" in { + "compile successfully (using)" in { + + assume(BuildInfo.scalaVersion.startsWith("3."), "This test is only supposed to run with scala3") val helper = newCompilerHelper + val text = helper + .compile[(String => String => Html)]("using.scala.html", "html.using") + .static("the using modifier")("should compile 😤") + .toString + .trim + + val compat = ScalaCompat(Option(BuildInfo.scalaVersion)) + val generatedFile = helper.generatedDir.toPath.resolve("html/using.template.scala").toFile + val generatedText = Source.fromFile(generatedFile).getLines().mkString("\n") + + generatedText must include(s"apply(x)(${compat.usingSyntax}y)") + text must be("the using modifier should compile 😤") + } + + "compile successfully (call by name)" in { + val helper = newCompilerHelper + val text = helper .compile[((=> String) => Html)]("callByName.scala.html", "html.callByName") .static("World") .toString @@ -191,7 +210,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile templates that have contiguous strings > than 64k" in { val helper = newCompilerHelper - val input = TwirlIO + val input = TwirlIO .readFileAsString(new File(sourceDir, "long.scala.html")) .replaceAll("(?s)@\\*(.*)\\*@(\n)*", "") // drop block comments val result = helper.compile[(() => Html)]("long.scala.html", "html.long").static().toString @@ -201,7 +220,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "allow rendering a template twice" in { val helper = newCompilerHelper - val inner = helper + val inner = helper .compile[((String, List[String]) => (Int) => Html)]("htmlInner.scala.html", "html.htmlInner") .static("World", List("A", "B"))(4) @@ -225,7 +244,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { } "with parameter groups" in { - val helper = newCompilerHelper + val helper = newCompilerHelper val template = helper .compile[String => Html]("injectParamGroups.scala.html", "html.injectParamGroups") .inject("Hello", 10, "my") @@ -233,7 +252,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { } "with comments" in { - val helper = newCompilerHelper + val helper = newCompilerHelper val template = helper.compile[String => Html]("injectComments.scala.html", "html.injectComments").inject("Hello", 10) template("world").body.trim mustBe "Hello 10 world" @@ -292,7 +311,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile successfully (complex if without brackets)" in { val helper = newCompilerHelper - val hello = + val hello = helper.compile[((String, String) => Html)]("ifWithoutBracketsComplex.scala.html", "html.ifWithoutBracketsComplex") hello.static("twirl", "play").toString.trim must include("""
""") hello.static("twirl", "something-else").toString.trim must include("""
""") @@ -300,7 +319,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile successfully (local definitions)" in { val helper = newCompilerHelper - val hello = + val hello = helper.compile[(() => Html)]("localDef.scala.html", "html.localDef") hello.static().toString.trim must be( "Play-Framework-Vienna-Austria-Europe-The High Velocity Web Framework For Java and Scala-2023" @@ -319,7 +338,7 @@ class CompilerSpec extends AnyWordSpec with Matchers { "compile successfully (block with nested tuples)" in { val helper = newCompilerHelper - val hello = + val hello = helper.compile[(Seq[(String, String)] => Html)]("blockWithNestedTuple.scala.html", "html.blockWithNestedTuple") val args = Seq[(String, String)]( diff --git a/parser/src/main/scala/play/twirl/parser/TwirlParser.scala b/parser/src/main/scala/play/twirl/parser/TwirlParser.scala index d1b0bfcb..240bb005 100644 --- a/parser/src/main/scala/play/twirl/parser/TwirlParser.scala +++ b/parser/src/main/scala/play/twirl/parser/TwirlParser.scala @@ -415,7 +415,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) { if (next == ":") { anyUntil(c => c != ' ' && c != '\t', inclusive = false) val resultTypePos = input.offset() - val rt = identifier() match { + val rt = identifier() match { case null => null case id => id } @@ -532,7 +532,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) { } def blockArgs(): PosString = { - def noCurlyBraces(result: String): Boolean = !result.contains("{") && !result.contains("}") + def noCurlyBraces(result: String): Boolean = !result.contains("{") && !result.contains("}") def noOpeningParenthesis(result: String): Boolean = { val noContainsOpenParenthesis = !result.contains("(") @@ -907,7 +907,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) { def templateDeclaration(): (PosString, PosString) = { if (check("@")) { val namepos = input.offset() - val name = identifier() match { + val name = identifier() match { case null => null case id => position(PosString(id), namepos) } @@ -1029,7 +1029,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) { input.reset(source) errorStack.clear() - val topImports = extraImports() + val topImports = extraImports() val (constructor, argsComment) = { val constructorComment = Option(lastComment()) whitespace() diff --git a/project/Common.scala b/project/Common.scala index 5e93d36e..46428625 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -27,6 +27,7 @@ object Common extends AutoPlugin { ) val scalacParameters = Seq( + "-release:17", "-deprecation", "-feature", "-unchecked", @@ -38,11 +39,7 @@ object Common extends AutoPlugin { CrossVersion.partialVersion(version) match { case Some((2, _)) => scalacParameters ++ Seq( - "-release:17", - "-Ywarn-unused:imports", - "-Xlint:nullary-unit", - "-Xlint", - "-Ywarn-dead-code" + "-Xsource:3" ) case Some((3, _)) => scalacParameters diff --git a/project/Dependencies.scala b/project/Dependencies.scala index cbf24254..daca59be 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -5,7 +5,7 @@ object Dependencies { val Scala212 = "2.12.20" val Scala213 = "2.13.16" - val Scala33 = "3.3.5" - val Scala36 = "3.6.4" + val Scala33 = "3.3.6" + val Scala37 = "3.7.3" val ScalaVersions = Seq(Scala212, Scala213, Scala33) } diff --git a/project/build.properties b/project/build.properties index 6b451e0b..d1e20439 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1,3 +1,3 @@ # Copyright (C) from 2025 BondLink, 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. -sbt.version=1.10.11 +sbt.version=1.11.6 diff --git a/project/plugins.sbt b/project/plugins.sbt index 398ef33f..85a4945b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,12 +1,12 @@ // Copyright (C) from 2025 BondLink, 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. // For the Cross Build -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.18.2") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.20.1") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2") addSbtPlugin("com.frugalmechanic" % "fm-sbt-s3-resolver" % "0.23.0") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.10.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.5") addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.8.0") -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.8") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.13") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1") diff --git a/sbt-twirl/src/main/scala-2/play/twirl/sbt/SbtTwirlCompat.scala b/sbt-twirl/src/main/scala-2/play/twirl/sbt/SbtTwirlCompat.scala new file mode 100644 index 00000000..871a6bf2 --- /dev/null +++ b/sbt-twirl/src/main/scala-2/play/twirl/sbt/SbtTwirlCompat.scala @@ -0,0 +1,11 @@ +/* + * Copyright (C) from 2025 BondLink, 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. + */ + +package play.twirl.sbt + +private[sbt] object SbtTwirlCompat { + implicit class DefOps(private val self: _root_.sbt.Def.type) extends AnyVal { + def uncached[A](a: A): A = a + } +} diff --git a/sbt-twirl/src/main/scala-3/play/twirl/sbt/SbtTwirlCompat.scala b/sbt-twirl/src/main/scala-3/play/twirl/sbt/SbtTwirlCompat.scala new file mode 100644 index 00000000..1f1a773c --- /dev/null +++ b/sbt-twirl/src/main/scala-3/play/twirl/sbt/SbtTwirlCompat.scala @@ -0,0 +1,7 @@ +/* + * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. + */ + +package play.twirl.sbt + +private[sbt] object SbtTwirlCompat diff --git a/sbt-twirl/src/main/scala/play/twirl/sbt/SbtTwirl.scala b/sbt-twirl/src/main/scala/play/twirl/sbt/SbtTwirl.scala index ed193b7f..83707537 100644 --- a/sbt-twirl/src/main/scala/play/twirl/sbt/SbtTwirl.scala +++ b/sbt-twirl/src/main/scala/play/twirl/sbt/SbtTwirl.scala @@ -5,6 +5,7 @@ package play.twirl.sbt import play.twirl.compiler.TwirlCompiler +import play.twirl.sbt.SbtTwirlCompat._ import sbt.Keys._ // format: off import sbt.{given, _} @@ -48,12 +49,13 @@ object SbtTwirl extends AutoPlugin { compileTemplates / includeFilter := "*.scala.*", compileTemplates / excludeFilter := HiddenFileFilter, (compileTemplates / sourceDirectories) := Seq(sourceDirectory.value / "twirl"), - (Defaults.ConfigZero / watchSources) += + (Defaults.ConfigZero / watchSources) += Def.uncached( WatchSource( (compileTemplates / sourceDirectory).value, (compileTemplates / includeFilter).value, (compileTemplates / excludeFilter).value - ), + ) + ), (compileTemplates / sources) := Defaults .collectFiles( compileTemplates / sourceDirectories, @@ -77,14 +79,14 @@ object SbtTwirl extends AutoPlugin { def positionSettings: Seq[Setting[?]] = Seq( - sourcePositionMappers += TemplateProblem.positionMapper(Codec(sourceEncoding.value)) + sourcePositionMappers += Def.uncached(TemplateProblem.positionMapper(Codec(sourceEncoding.value))) ) def dependencySettings = Def.settings( twirlVersion := readResourceProperty("twirl.version.properties", "twirl.api.version"), libraryDependencies += { - val crossVer = crossVersion.value + val crossVer = crossVersion.value val isScalaJS = CrossVersion(crossVer, scalaVersion.value, scalaBinaryVersion.value) match { case Some(f) => f("").contains("_sjs1") // detect ScalaJS CrossVersion case None => false diff --git a/sbt-twirl/src/sbt-test/twirl/compile-scala3/build.sbt b/sbt-twirl/src/sbt-test/twirl/compile-scala3/build.sbt index bd7e3dd3..d9733e7d 100644 --- a/sbt-twirl/src/sbt-test/twirl/compile-scala3/build.sbt +++ b/sbt-twirl/src/sbt-test/twirl/compile-scala3/build.sbt @@ -13,6 +13,6 @@ lazy val root = (project in file(".")) SbtTwirl } .settings( - scalaVersion := "3.3.5", + scalaVersion := "3.3.6", scalacOptions ++= Seq("-source:future", "-feature") ) diff --git a/sbt-twirl/src/sbt-test/twirl/scalajs-compile/project/plugins.sbt b/sbt-twirl/src/sbt-test/twirl/scalajs-compile/project/plugins.sbt index 3de419ef..f616c729 100644 --- a/sbt-twirl/src/sbt-test/twirl/scalajs-compile/project/plugins.sbt +++ b/sbt-twirl/src/sbt-test/twirl/scalajs-compile/project/plugins.sbt @@ -1,4 +1,4 @@ // Copyright (C) from 2025 BondLink, 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. addSbtPlugin("bondlink" % "sbt-typed-twirl" % sys.props("project.version")) -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.18.2") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.20.1")