Skip to content
This repository was archived by the owner on Jun 10, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
30539a5
Bump commons-io:commons-io from 2.18.0 to 2.19.0 in /gradle-twirl
dependabot[bot] Apr 14, 2025
066bd30
Bump com.diffplug.spotless from 7.0.2 to 7.0.3 in /gradle-twirl
dependabot[bot] Apr 14, 2025
d25a0af
Merge pull request #927 from playframework/dependabot/gradle/gradle-t…
mkurz Apr 14, 2025
2651bb5
Merge pull request #926 from playframework/dependabot/gradle/gradle-t…
mkurz Apr 14, 2025
5bf3cf6
Update `gradle` to `v8.14` (was `8.13`)
renovate[bot] Apr 25, 2025
7a54f1d
Merge pull request #929 from playframework/renovate/main-gradle-8.x
ihostage Apr 25, 2025
38b571a
Update `gradle` to `v8.14.1` (was `8.14`)
renovate[bot] May 22, 2025
19be388
Merge pull request #934 from playframework/renovate/main-gradle-8.x
mkurz May 22, 2025
edf3732
Bump com.diffplug.spotless from 7.0.3 to 7.0.4 in /gradle-twirl
dependabot[bot] Jun 2, 2025
65db0fc
Merge pull request #940 from playframework/dependabot/gradle/gradle-t…
mkurz Jun 2, 2025
6957b6b
scala-xml 2.4.0
mkurz Jun 3, 2025
10e7997
sbt-scalajs 1.19.0
mkurz Jun 3, 2025
0d6cfd7
Merge pull request #941 from mkurz/scala-xml-2.4.0
mkurz Jun 3, 2025
a13af96
Update `gradle` to `v8.14.2` (was `8.14.1`)
renovate[bot] Jun 5, 2025
aa94803
Merge pull request #942 from playframework/renovate/main-gradle-8.x
mkurz Jun 5, 2025
e1bc654
add -Xsource:3 option
xuwei-k Jun 15, 2025
a49273f
[Gradle Plugin] Support Configuration Cache
ihostage Jun 25, 2025
14777a6
Merge pull request #952 from ihostage/issue/948
ihostage Jun 25, 2025
6dc4c8d
prepend "using" at the callsite if the definition site includes an im…
ajafri2001 May 11, 2025
fadcc1c
Only prepend "using" if on scala3
ajafri2001 May 12, 2025
80184c1
accomodate review comments
ajafri2001 Jun 17, 2025
177f33c
using is valid in twirlTemplate
ajafri2001 Jun 23, 2025
0a0a711
updated test
ajafri2001 Jun 23, 2025
00bb87a
remove zipWithIndex
ajafri2001 Jun 24, 2025
5d2ba6b
cleanerCode - added usingSyntax to ScalaCompat
ajafri2001 Jun 25, 2025
d25ff89
Run using.scala.html only for scala3
ajafri2001 Jun 28, 2025
070c1e4
Merge pull request #933 from ajafri2001/issue-894
mkurz Jun 30, 2025
bd3612d
Merge pull request #947 from xuwei-k/X-source-3
mkurz Jun 30, 2025
44c80b4
sbt, scripted-plugin 1.11.2 (was 1.10.11)
mkurz Jun 30, 2025
9938bbc
sbt-bloop 2.0.10 (was 2.0.8)
mkurz Jun 30, 2025
4b8fb11
scala3-compiler 3.3.6 (was 3.3.5)
mkurz Jun 30, 2025
7ce4015
scala3-library 3.3.6 (was 3.3.5)
mkurz Jun 30, 2025
82ead3b
parsers 4.13.8 (was 4.13.4)
mkurz Jun 30, 2025
5ee98c1
sbt-scalafmt 2.5.5 (was 2.5.4)
mkurz Jun 30, 2025
ddf7043
scalafmt-core 3.9.8 (was 3.9.1)
mkurz Jun 30, 2025
e316169
Reformat with scalafmt 3.9.8
mkurz Jun 30, 2025
a5d7147
Add 'Reformat with scalafmt 3.9.8' to .git-blame-ignore-revs
mkurz Jun 30, 2025
c5e1445
Merge pull request #965 from playframework/update/patches
mkurz Jun 30, 2025
3c1ed2d
Merge pull request #964 from playframework/update/sbt-1.11.2
mkurz Jun 30, 2025
22f86b1
Fix Gradle Publishing to Central Portal
mkurz Jul 1, 2025
2be111a
Merge pull request #966 from mkurz/fix_gradle_publishing
mkurz Jul 1, 2025
af926b4
Remove dead code
mkurz Jul 3, 2025
b810258
Merge pull request #968 from mkurz/rm_dead-code
mkurz Jul 3, 2025
cdd042b
Update `gradle` to `v8.14.3` (was `8.14.2`)
renovate[bot] Jul 4, 2025
d68b809
Merge pull request #971 from playframework/renovate/main-gradle-8.x
mergify[bot] Jul 4, 2025
1fe1b87
sbt-ci-release 1.11.1 (was 1.9.3)
mkurz Jun 30, 2025
0bc8452
Remove sonatypeProfileName
mkurz Jul 4, 2025
ed4fb96
Update README
mkurz Jul 4, 2025
5a4752d
Formatting
mkurz Jul 4, 2025
af9363b
Merge pull request #962 from playframework/update/sbt-ci-release-1.11.1
mkurz Jul 4, 2025
3b3682e
play-docs 3.0.8 (was 3.0.7)
mkurz Jul 4, 2025
98a0db8
Merge pull request #973 from playframework/update/patches
mkurz Jul 5, 2025
b7d879c
sbt 1.11.3 (was 1.11.2)
mkurz Jul 6, 2025
e8f7692
Merge pull request #976 from playframework/update/patches
mkurz Jul 6, 2025
2bc744f
Bump org.apache.commons:commons-lang3 in /gradle-twirl
dependabot[bot] Jul 14, 2025
d157922
Bump com.diffplug.spotless from 7.0.4 to 7.1.0 in /gradle-twirl
dependabot[bot] Jul 14, 2025
ebb1750
Merge pull request #983 from playframework/dependabot/gradle/gradle-t…
mkurz Jul 14, 2025
04d8ad0
Merge pull request #982 from playframework/dependabot/gradle/gradle-t…
mkurz Jul 14, 2025
014310b
Bump commons-io:commons-io from 2.19.0 to 2.20.0 in /gradle-twirl
dependabot[bot] Jul 21, 2025
3a3e426
Bump com.diffplug.spotless from 7.1.0 to 7.2.0 in /gradle-twirl
dependabot[bot] Jul 21, 2025
d8f02f7
Merge pull request #989 from playframework/dependabot/gradle/gradle-t…
mkurz Jul 21, 2025
9edb52b
Merge pull request #988 from playframework/dependabot/gradle/gradle-t…
mkurz Jul 21, 2025
6849bf3
Bump com.diffplug.spotless from 7.2.0 to 7.2.1 in /gradle-twirl
dependabot[bot] Jul 28, 2025
af2dffe
Merge pull request #990 from playframework/dependabot/gradle/gradle-t…
ihostage Jul 29, 2025
42423d6
Bump org.assertj:assertj-core from 3.27.3 to 3.27.4 in /gradle-twirl
dependabot[bot] Aug 11, 2025
4b73721
Merge pull request #999 from playframework/dependabot/gradle/gradle-t…
mkurz Aug 11, 2025
c62046f
sbt 2.0.0-RC3
xuwei-k Aug 17, 2025
b7b56d9
Bump actions/checkout from 4 to 5
dependabot[bot] Aug 18, 2025
4616e86
Merge pull request #1005 from playframework/dependabot/github_actions…
mkurz Aug 19, 2025
d55d603
Merge pull request #1002 from xuwei-k/sbt-2-RC
mkurz Aug 19, 2025
a4dd5a8
Update sbt version in `docs` project
xuwei-k Aug 24, 2025
2f48772
Merge pull request #1008 from xuwei-k/patch-1
mkurz Aug 24, 2025
af0dea6
Bump com.gradle.plugin-publish from 1.3.1 to 2.0.0 in /gradle-twirl
dependabot[bot] Sep 8, 2025
7a6fe43
Merge pull request #1014 from playframework/dependabot/gradle/gradle-…
mkurz Sep 8, 2025
bca6c85
sbt-scalajs, scalajs-compiler, ... 1.20.1 (was 1.19.0)
mkurz Sep 9, 2025
c80959a
sbt-bloop 2.0.13 (was 2.0.10)
mkurz Sep 9, 2025
572f805
sbt-ci-release 1.11.2 (was 1.11.1)
mkurz Sep 9, 2025
740d545
sbt 1.11.6 (was 1.11.4)
mkurz Sep 9, 2025
2583ad4
parsers 4.13.9 (was 4.13.8)
mkurz Sep 9, 2025
e7a123f
scalafmt-core 3.9.9 (was 3.9.8)
mkurz Sep 9, 2025
006b4de
Merge pull request #1016 from playframework/update/patches
mkurz Sep 9, 2025
a15bfae
Merge pull request #1015 from playframework/update/sbt-scalajs-1.20.1
mkurz Sep 9, 2025
4dc780d
Bump org.assertj:assertj-core from 3.27.4 to 3.27.5 in /gradle-twirl
dependabot[bot] Sep 22, 2025
ba7d488
Merge pull request #1023 from playframework/dependabot/gradle/gradle-…
ihostage Sep 23, 2025
f9fa035
Bump com.diffplug.spotless from 7.2.1 to 8.0.0 in /gradle-twirl
dependabot[bot] Sep 29, 2025
6633dcb
Bump org.apache.commons:commons-lang3 in /gradle-twirl
dependabot[bot] Sep 29, 2025
419a0a0
Merge pull request #1028 from playframework/dependabot/gradle/gradle-…
mkurz Sep 29, 2025
a6eb0f6
Merge pull request #1030 from playframework/dependabot/gradle/gradle-…
mkurz Sep 29, 2025
69a9687
Bump org.assertj:assertj-core from 3.27.5 to 3.27.6 in /gradle-twirl
dependabot[bot] Sep 29, 2025
bdd6973
Merge pull request #1027 from playframework/dependabot/gradle/gradle-…
mkurz Sep 29, 2025
2162cfe
Merge branch 'main' of github.com:playframework/twirl into merge-upst…
mrdziuban Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ c3b04b90d9863ca2c7b7e56bc0bda148ce392642

# Scala Steward: Reformat with scalafmt 3.8.1
cb6d4261c6253f685d50b24177064616e5d22143

# Scala Steward: Reformat with scalafmt 3.9.8
e316169276b40dbdc76142d03895233ba103f417
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = 3.9.1
version = 3.9.9

project.layout=StandardConvention

Expand Down
10 changes: 5 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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",
Expand All @@ -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,
Expand Down
78 changes: 40 additions & 38 deletions compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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(
Expand All @@ -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)
}

Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/test/resources/using.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@*******************************************************************************************************************************************************************
* Copyright (C) from 2025 BondLink, 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com> *
*******************************************************************************************************************************************************************@

@(x: String)(using y: String)
@x @y
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -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,
Expand Down Expand Up @@ -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")
}
Expand Down
Loading
Loading