diff --git a/.scalafmt.conf b/.scalafmt.conf
new file mode 100644
index 00000000..3c681f57
--- /dev/null
+++ b/.scalafmt.conf
@@ -0,0 +1,12 @@
+# Keep in sync with docs/.scalafmt.conf
+align = true
+assumeStandardLibraryStripMargin = true
+danglingParentheses = true
+docstrings = JavaDoc
+maxColumn = 120
+project.git = true
+rewrite.rules = [ AvoidInfix, ExpandImportSelectors, RedundantParens, SortModifiers, PreferCurlyFors ]
+rewrite.sortModifiers.order = [ "private", "protected", "final", "sealed", "abstract", "implicit", "override", "lazy" ]
+spaces.inImportCurlyBraces = true # more idiomatic to include whitepsace in import x.{ yyy }
+trailingCommas = preserve
+version = 2.0.0
diff --git a/.travis.yml b/.travis.yml
index b66d6249..3729acaa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,6 +12,7 @@ before_install: curl -Ls https://git.io/jabba | bash && . ~/.jabba/jabba.sh
install: jabba install "adopt@~1.$TRAVIS_JDK.0-0" && jabba use "$_" && java -Xmx32m -version
script:
+ - ./scripts/test-code.sh
- ./scripts/validate-code.sh
- ./scripts/validate-docs.sh
diff --git a/api/shared/src/main/scala/play/twirl/api/BaseScalaTemplate.scala b/api/shared/src/main/scala/play/twirl/api/BaseScalaTemplate.scala
index 94a3743c..60685755 100644
--- a/api/shared/src/main/scala/play/twirl/api/BaseScalaTemplate.scala
+++ b/api/shared/src/main/scala/play/twirl/api/BaseScalaTemplate.scala
@@ -13,32 +13,33 @@ case class BaseScalaTemplate[T <: Appendable[T], F <: Format[T]](format: F) {
// The overloaded methods are here for speed. The compiled templates
// can take advantage of them for a 12% performance boost
- def _display_(x: AnyVal): T = format.escape(x.toString)
- def _display_(x: String): T = if (x eq null) format.empty else format.escape(x)
- def _display_(x: Unit): T = format.empty
+ def _display_(x: AnyVal): T = format.escape(x.toString)
+ def _display_(x: String): T = if (x eq null) format.empty else format.escape(x)
+ def _display_(x: Unit): T = format.empty
def _display_(x: scala.xml.NodeSeq): T = if (x eq null) format.empty else format.raw(x.toString())
- def _display_(x: T): T = if (x eq null) format.empty else x
+ def _display_(x: T): T = if (x eq null) format.empty else x
def _display_(o: Any)(implicit m: ClassTag[T]): T = {
o match {
case escaped if escaped != null && escaped.getClass == m.runtimeClass => escaped.asInstanceOf[T]
- case () => format.empty
- case None => format.empty
- case Some(v) => _display_(v)
+ case () => format.empty
+ case None => format.empty
+ case Some(v) => _display_(v)
case key: Optional[_] =>
(if (key.isPresent) Some(key.get) else None) match {
- case None => format.empty
+ case None => format.empty
case Some(v) => _display_(v)
- case _ => format.empty
+ case _ => format.empty
}
- case xml: scala.xml.NodeSeq => format.raw(xml.toString())
- case escapeds: immutable.Seq[_] => format.fill(escapeds.map(_display_))
+ case xml: scala.xml.NodeSeq => format.raw(xml.toString())
+ case escapeds: immutable.Seq[_] => format.fill(escapeds.map(_display_))
case escapeds: TraversableOnce[_] => format.fill(escapeds.map(_display_).toList)
- case escapeds: Array[_] => format.fill(escapeds.view.map(_display_).toList)
- case escapeds: java.util.List[_] => format.fill(JavaConverters.collectionAsScalaIterableConverter(escapeds).asScala.map(_display_).toList)
+ case escapeds: Array[_] => format.fill(escapeds.view.map(_display_).toList)
+ case escapeds: java.util.List[_] =>
+ format.fill(JavaConverters.collectionAsScalaIterableConverter(escapeds).asScala.map(_display_).toList)
case string: String => format.escape(string)
case v if v != null => format.escape(v.toString)
- case _ => format.empty
+ case _ => format.empty
}
}
}
diff --git a/api/shared/src/main/scala/play/twirl/api/Content.scala b/api/shared/src/main/scala/play/twirl/api/Content.scala
index d4a2ca05..19c06d53 100644
--- a/api/shared/src/main/scala/play/twirl/api/Content.scala
+++ b/api/shared/src/main/scala/play/twirl/api/Content.scala
@@ -32,7 +32,11 @@ trait Content {
* @param text Formatted content
* @tparam A self-type
*/
-abstract class BufferedContent[A <: BufferedContent[A]](protected val elements: immutable.Seq[A], protected val text: String) extends Appendable[A] with Content { this: A =>
+abstract class BufferedContent[A <: BufferedContent[A]](
+ protected val elements: immutable.Seq[A],
+ protected val text: String
+) extends Appendable[A]
+ with Content { this: A =>
protected def buildString(builder: StringBuilder): Unit = {
if (!elements.isEmpty) {
elements.foreach { e =>
@@ -59,7 +63,7 @@ abstract class BufferedContent[A <: BufferedContent[A]](protected val elements:
override def equals(obj: Any): Boolean = obj match {
case other: BufferedContent[_] if this.getClass == other.getClass => body == other.body
- case _ => false
+ case _ => false
}
override def hashCode(): Int = this.getClass.hashCode() + body.hashCode()
diff --git a/api/shared/src/main/scala/play/twirl/api/Formats.scala b/api/shared/src/main/scala/play/twirl/api/Formats.scala
index 6c019103..6c3cc6b5 100644
--- a/api/shared/src/main/scala/play/twirl/api/Formats.scala
+++ b/api/shared/src/main/scala/play/twirl/api/Formats.scala
@@ -23,7 +23,8 @@ object Formats {
* This has 3 states, either it's a tree of elements, or a leaf, if it's a leaf, it's either safe text, or unsafe text
* that needs to be escaped when written out.
*/
-class Html private[api] (elements: immutable.Seq[Html], text: String, escape: Boolean) extends BufferedContent[Html](elements, text) {
+class Html private[api] (elements: immutable.Seq[Html], text: String, escape: Boolean)
+ extends BufferedContent[Html](elements, text) {
def this(text: String) = this(Nil, Formats.safe(text), false)
def this(elements: immutable.Seq[Html]) = this(elements, "", false)
@@ -36,7 +37,7 @@ class Html private[api] (elements: immutable.Seq[Html], text: String, escape: Bo
* of Strings, if it doesn't, performance actually goes down (measured 10%), due to the fact that the JVM can't
* optimise the invocation of buildString as well because there are two different possible implementations.
*/
- override protected def buildString(builder: StringBuilder): Unit = {
+ protected override def buildString(builder: StringBuilder): Unit = {
if (elements.nonEmpty) {
elements.foreach { e =>
e.buildString(builder)
@@ -47,12 +48,12 @@ class Html private[api] (elements: immutable.Seq[Html], text: String, escape: Bo
var i = 0
while (i < text.length) {
text.charAt(i) match {
- case '<' => builder.append("<")
- case '>' => builder.append(">")
- case '"' => builder.append(""")
+ case '<' => builder.append("<")
+ case '>' => builder.append(">")
+ case '"' => builder.append(""")
case '\'' => builder.append("'")
- case '&' => builder.append("&")
- case c => builder += c
+ case '&' => builder.append("&")
+ case c => builder += c
}
i += 1
}
@@ -80,8 +81,8 @@ object Html {
}
/**
- * Creates an HTML fragment with initial content specified. Uses an empty String if None is passed.
- */
+ * Creates an HTML fragment with initial content specified. Uses an empty String if None is passed.
+ */
def apply(text: Option[String]): Html = {
apply(text.getOrElse(""))
}
@@ -227,7 +228,8 @@ object XmlFormat extends Format[Xml] {
/**
* Type used in default JavaScript templates.
*/
-class JavaScript private (elements: immutable.Seq[JavaScript], text: String) extends BufferedContent[JavaScript](elements, text) {
+class JavaScript private (elements: immutable.Seq[JavaScript], text: String)
+ extends BufferedContent[JavaScript](elements, text) {
def this(text: String) = this(Nil, Formats.safe(text))
def this(elements: immutable.Seq[JavaScript]) = this(elements, "")
@@ -241,6 +243,7 @@ class JavaScript private (elements: immutable.Seq[JavaScript], text: String) ext
* Helper for JavaScript utility methods.
*/
object JavaScript {
+
/**
* Creates a JavaScript fragment with initial content specified
*/
@@ -253,6 +256,7 @@ object JavaScript {
* Formatter for JavaScript content.
*/
object JavaScriptFormat extends Format[JavaScript] {
+
/**
* Integrate `text` without performing any escaping process.
* @param text Text to integrate
diff --git a/api/shared/src/main/scala/play/twirl/api/Template.scala b/api/shared/src/main/scala/play/twirl/api/Template.scala
index 05d8fee6..0b5cdeb6 100644
--- a/api/shared/src/main/scala/play/twirl/api/Template.scala
+++ b/api/shared/src/main/scala/play/twirl/api/Template.scala
@@ -72,25 +72,113 @@ trait Template16[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Result] {
}
trait Template17[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, Result] {
- def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q): Result
+ def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q)
+ : Result
}
trait Template18[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, Result] {
- def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R): Result
+ def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R)
+ : Result
}
trait Template19[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, Result] {
- def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S): Result
+ def render(
+ a: A,
+ b: B,
+ c: C,
+ d: D,
+ e: E,
+ f: F,
+ g: G,
+ h: H,
+ i: I,
+ j: J,
+ k: K,
+ l: L,
+ m: M,
+ n: N,
+ o: O,
+ p: P,
+ q: Q,
+ r: R,
+ s: S
+ ): Result
}
trait Template20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, Result] {
- def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T): Result
+ def render(
+ a: A,
+ b: B,
+ c: C,
+ d: D,
+ e: E,
+ f: F,
+ g: G,
+ h: H,
+ i: I,
+ j: J,
+ k: K,
+ l: L,
+ m: M,
+ n: N,
+ o: O,
+ p: P,
+ q: Q,
+ r: R,
+ s: S,
+ t: T
+ ): Result
}
trait Template21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, Result] {
- def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U): Result
+ def render(
+ a: A,
+ b: B,
+ c: C,
+ d: D,
+ e: E,
+ f: F,
+ g: G,
+ h: H,
+ i: I,
+ j: J,
+ k: K,
+ l: L,
+ m: M,
+ n: N,
+ o: O,
+ p: P,
+ q: Q,
+ r: R,
+ s: S,
+ t: T,
+ u: U
+ ): Result
}
trait Template22[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, Result] {
- def render(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V): Result
+ def render(
+ a: A,
+ b: B,
+ c: C,
+ d: D,
+ e: E,
+ f: F,
+ g: G,
+ h: H,
+ i: I,
+ j: J,
+ k: K,
+ l: L,
+ m: M,
+ n: N,
+ o: O,
+ p: P,
+ q: Q,
+ r: R,
+ s: S,
+ t: T,
+ u: U,
+ v: V
+ ): Result
}
diff --git a/api/shared/src/main/scala/play/twirl/api/TemplateMagic.scala b/api/shared/src/main/scala/play/twirl/api/TemplateMagic.scala
index b6a71f00..3bbe71ed 100644
--- a/api/shared/src/main/scala/play/twirl/api/TemplateMagic.scala
+++ b/api/shared/src/main/scala/play/twirl/api/TemplateMagic.scala
@@ -19,8 +19,8 @@ object TemplateMagic {
// --- IF
implicit def iterableToBoolean(x: Iterable[_]) = x != null && !x.isEmpty
- implicit def optionToBoolean(x: Option[_]) = x != null && x.isDefined
- implicit def stringToBoolean(x: String) = x != null && !x.isEmpty
+ implicit def optionToBoolean(x: Option[_]) = x != null && x.isDefined
+ implicit def stringToBoolean(x: String) = x != null && !x.isEmpty
// --- JAVA
@@ -33,12 +33,12 @@ object TemplateMagic {
case class Default(default: Any) {
def ?:(x: Any) = x match {
- case "" => default
- case Nil => default
+ case "" => default
+ case Nil => default
case false => default
- case 0 => default
- case None => default
- case _ => x
+ case 0 => default
+ case None => default
+ case _ => x
}
}
@@ -62,7 +62,7 @@ object TemplateMagic {
def when(predicate: => Boolean) = {
predicate match {
- case true => string
+ case true => string
case false => ""
}
}
diff --git a/api/shared/src/main/scala/play/twirl/api/TwirlFeatureImports.scala b/api/shared/src/main/scala/play/twirl/api/TwirlFeatureImports.scala
index defd3a68..235fffe2 100644
--- a/api/shared/src/main/scala/play/twirl/api/TwirlFeatureImports.scala
+++ b/api/shared/src/main/scala/play/twirl/api/TwirlFeatureImports.scala
@@ -6,23 +6,23 @@ package play.twirl.api
import scala.language.implicitConversions
/**
- * Imports that provide Twirl language features.
- *
- * This includes:
- *
- * - @defining
- * - @using
- * - iterable/option/string as boolean for if statements
- * - default values (maybeFoo ? defaultFoo)
- */
+ * Imports that provide Twirl language features.
+ *
+ * This includes:
+ *
+ * - @defining
+ * - @using
+ * - iterable/option/string as boolean for if statements
+ * - default values (maybeFoo ? defaultFoo)
+ */
object TwirlFeatureImports {
/**
- * Provides the `@defining` language feature, that lets you set a local val that can be reused.
- *
- * @param t The defined val.
- * @param handler The block to handle it.
- */
+ * Provides the `@defining` language feature, that lets you set a local val that can be reused.
+ *
+ * @param t The defined val.
+ * @param handler The block to handle it.
+ */
def defining[T](t: T)(handler: T => Any): Any = {
handler(t)
}
@@ -32,23 +32,25 @@ object TwirlFeatureImports {
/** Adds "truthiness" to iterables, making them false if they are empty. */
implicit def twirlIterableToBoolean(x: Iterable[_]): Boolean = x != null && !x.isEmpty
+
/** Adds "truthiness" to options, making them false if they are empty. */
implicit def twirlOptionToBoolean(x: Option[_]): Boolean = x != null && x.isDefined
+
/** Adds "truthiness" to strings, making them false if they are empty. */
implicit def twirlStringToBoolean(x: String): Boolean = x != null && !x.isEmpty
/**
- * Provides default values, such that an empty sequence, string, option, false boolean, or null will render
- * the default value.
- */
+ * Provides default values, such that an empty sequence, string, option, false boolean, or null will render
+ * the default value.
+ */
implicit class TwirlDefaultValue(default: Any) {
def ?:(x: Any): Any = x match {
- case "" => default
- case Nil => default
+ case "" => default
+ case Nil => default
case false => default
- case 0 => default
- case None => default
- case _ => x
+ case 0 => default
+ case None => default
+ case _ => x
}
}
-}
\ No newline at end of file
+}
diff --git a/api/shared/src/main/scala/play/twirl/api/TwirlHelperImports.scala b/api/shared/src/main/scala/play/twirl/api/TwirlHelperImports.scala
index d366fe02..bdee1c68 100644
--- a/api/shared/src/main/scala/play/twirl/api/TwirlHelperImports.scala
+++ b/api/shared/src/main/scala/play/twirl/api/TwirlHelperImports.scala
@@ -6,8 +6,8 @@ package play.twirl.api
import scala.language.implicitConversions
/**
- * Imports for useful Twirl helpers.
- */
+ * Imports for useful Twirl helpers.
+ */
object TwirlHelperImports {
/** Allows Java collections to be used as if they were Scala collections. */
@@ -30,11 +30,11 @@ object TwirlHelperImports {
def when(predicate: => Boolean): String = {
predicate match {
- case true => string
+ case true => string
case false => ""
}
}
}
-}
\ No newline at end of file
+}
diff --git a/api/shared/src/main/scala/play/twirl/api/package.scala b/api/shared/src/main/scala/play/twirl/api/package.scala
index 5aa274be..89212565 100644
--- a/api/shared/src/main/scala/play/twirl/api/package.scala
+++ b/api/shared/src/main/scala/play/twirl/api/package.scala
@@ -22,17 +22,17 @@ package object api {
* Three interpolators are available: `html`, `xml` and `js`.
*/
implicit class StringInterpolation(val sc: StringContext) extends AnyVal {
-
+
def html(args: Any*): Html = interpolate(args, HtmlFormat)
-
+
def xml(args: Any*): Xml = interpolate(args, XmlFormat)
def js(args: Any*): JavaScript = interpolate(args, JavaScriptFormat)
- def interpolate[A <: Appendable[A] : ClassTag](args: Seq[Any], format: Format[A]): A = {
+ def interpolate[A <: Appendable[A]: ClassTag](args: Seq[Any], format: Format[A]): A = {
sc.checkLengths(args)
- val array = Array.ofDim[Any](args.size + sc.parts.size)
- val strings = sc.parts.iterator
+ val array = Array.ofDim[Any](args.size + sc.parts.size)
+ val strings = sc.parts.iterator
val expressions = args.iterator
array(0) = format.raw(strings.next())
var i = 1
@@ -43,7 +43,7 @@ package object api {
}
new BaseScalaTemplate[A, Format[A]](format)._display_(array)
}
-
+
}
}
diff --git a/api/shared/src/main/scala/play/twirl/api/utils/StringEscapeUtils.scala b/api/shared/src/main/scala/play/twirl/api/utils/StringEscapeUtils.scala
index 78441053..1ad4f157 100644
--- a/api/shared/src/main/scala/play/twirl/api/utils/StringEscapeUtils.scala
+++ b/api/shared/src/main/scala/play/twirl/api/utils/StringEscapeUtils.scala
@@ -6,7 +6,7 @@ package play.twirl.api.utils
object StringEscapeUtils {
def escapeEcmaScript(input: String): String = {
- val s = new StringBuilder()
+ val s = new StringBuilder()
val len = input.length
var pos = 0
while (pos < len) {
@@ -15,7 +15,7 @@ object StringEscapeUtils {
case '\'' => s.append("\\'")
case '\"' => s.append("\\\"")
case '\\' => s.append("\\\\")
- case '/' => s.append("\\/")
+ case '/' => s.append("\\/")
// JAVA_CTRL_CHARS
case '\b' => s.append("\\b")
case '\n' => s.append("\\n")
@@ -36,21 +36,21 @@ object StringEscapeUtils {
def escapeXml11(input: String): String = {
// Implemented per XML spec:
// http://www.w3.org/International/questions/qa-controls
- val s = new StringBuilder()
+ val s = new StringBuilder()
val len = input.length
var pos = 0
while (pos < len) {
input.charAt(pos) match {
- case '<' => s.append("<")
- case '>' => s.append(">")
- case '&' => s.append("&")
- case '"' => s.append(""")
- case '\n' => s.append('\n')
- case '\r' => s.append('\r')
- case '\t' => s.append('\t')
+ case '<' => s.append("<")
+ case '>' => s.append(">")
+ case '&' => s.append("&")
+ case '"' => s.append(""")
+ case '\n' => s.append('\n')
+ case '\r' => s.append('\r')
+ case '\t' => s.append('\t')
case c if c < ' ' =>
- case c => s.append(c)
+ case c => s.append(c)
}
pos += 1
}
diff --git a/api/shared/src/test/scala/play/twirl/api/test/BufferedContentSpec.scala b/api/shared/src/test/scala/play/twirl/api/test/BufferedContentSpec.scala
index bbd9eedd..c7ceb00d 100644
--- a/api/shared/src/test/scala/play/twirl/api/test/BufferedContentSpec.scala
+++ b/api/shared/src/test/scala/play/twirl/api/test/BufferedContentSpec.scala
@@ -3,7 +3,8 @@
*/
package play.twirl.api.test
-import org.scalatest.{ MustMatchers, WordSpec }
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
import play.twirl.api._
import scala.collection.immutable
@@ -19,11 +20,17 @@ class BufferedContentSpec extends WordSpec with MustMatchers {
}
"return false for BufferedContents with different bodies but the same implementations" in {
- HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar"))) must not be HtmlFormat.fill(immutable.Seq(Html("fizz"), Html("buzz")))
+ HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar"))) must not be HtmlFormat.fill(
+ immutable.Seq(Html("fizz"), Html("buzz"))
+ )
HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar"))) must not be Html("fizzbuzz")
- XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar"))) must not be XmlFormat.fill(immutable.Seq(Xml("fizz"), Xml("buzz")))
+ XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar"))) must not be XmlFormat.fill(
+ immutable.Seq(Xml("fizz"), Xml("buzz"))
+ )
XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar"))) must not be Xml("fizzbuzz")
- TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar"))) must not be TxtFormat.fill(immutable.Seq(Txt("fizz"), Txt("buzz")))
+ TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar"))) must not be TxtFormat.fill(
+ immutable.Seq(Txt("fizz"), Txt("buzz"))
+ )
TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar"))) must not be Txt("fizzbuzz")
Html("hello") must not be Html("boom")
Txt("hello") must not be Txt("boom")
@@ -31,11 +38,17 @@ class BufferedContentSpec extends WordSpec with MustMatchers {
}
"return true for BufferedContents with the same body and the same implementation" in {
- HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar"))) mustEqual HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar")))
+ HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar"))) mustEqual HtmlFormat.fill(
+ immutable.Seq(Html("foo"), Html("bar"))
+ )
HtmlFormat.fill(immutable.Seq(Html("foo"), Html("bar"))) mustEqual Html("foobar")
- XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar"))) mustEqual XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar")))
+ XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar"))) mustEqual XmlFormat.fill(
+ immutable.Seq(Xml("foo"), Xml("bar"))
+ )
XmlFormat.fill(immutable.Seq(Xml("foo"), Xml("bar"))) mustEqual Xml("foobar")
- TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar"))) mustEqual TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar")))
+ TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar"))) mustEqual TxtFormat.fill(
+ immutable.Seq(Txt("foo"), Txt("bar"))
+ )
TxtFormat.fill(immutable.Seq(Txt("foo"), Txt("bar"))) mustEqual Txt("foobar")
Html("hello") mustEqual Html("hello")
Txt("hello") mustEqual Txt("hello")
diff --git a/api/shared/src/test/scala/play/twirl/api/test/FormatSpec.scala b/api/shared/src/test/scala/play/twirl/api/test/FormatSpec.scala
index ae9ab1c6..6994545a 100644
--- a/api/shared/src/test/scala/play/twirl/api/test/FormatSpec.scala
+++ b/api/shared/src/test/scala/play/twirl/api/test/FormatSpec.scala
@@ -4,7 +4,8 @@
package play.twirl.api
package test
-import org.scalatest.{ MustMatchers, WordSpec }
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
class FormatSpec extends WordSpec with MustMatchers {
diff --git a/api/shared/src/test/scala/play/twirl/api/test/StringInterpolationSpec.scala b/api/shared/src/test/scala/play/twirl/api/test/StringInterpolationSpec.scala
index 090834a5..7a1417df 100644
--- a/api/shared/src/test/scala/play/twirl/api/test/StringInterpolationSpec.scala
+++ b/api/shared/src/test/scala/play/twirl/api/test/StringInterpolationSpec.scala
@@ -8,7 +8,8 @@ import java.util.ArrayList
import java.util.Optional
import java.util.{ List => JList }
-import org.scalatest.{ MustMatchers, WordSpec }
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
class StringInterpolationSpec extends WordSpec with MustMatchers {
@@ -19,11 +20,11 @@ class StringInterpolationSpec extends WordSpec with MustMatchers {
}
"escape interpolated arguments" in {
val arg = "<"
- val p = html"
$arg
"
+ val p = html"$arg
"
p.body mustBe "<
"
}
"leave nested templates untouched" in {
- val p = html""
+ val p = html""
val div = html"$p
"
div.body mustBe ""
}
@@ -38,4 +39,4 @@ class StringInterpolationSpec extends WordSpec with MustMatchers {
}
}
-}
\ No newline at end of file
+}
diff --git a/build.sbt b/build.sbt
index 762bc610..721e8adf 100644
--- a/build.sbt
+++ b/build.sbt
@@ -7,15 +7,18 @@ val previousVersion: Option[String] = None
def binaryCompatibilitySettings(org: String, moduleName: String, scalaBinVersion: String): Set[ModuleID] = {
if (scalaBinVersion.equals(scala213)) Set.empty
- else previousVersion match {
- case None => Set.empty
- case Some(pv) => Set(org % s"${moduleName}_${scalaBinVersion}" % pv)
- }
+ else
+ previousVersion match {
+ case None => Set.empty
+ case Some(pv) => Set(org % s"${moduleName}_${scalaBinVersion}" % pv)
+ }
}
val javacParameters = Seq(
- "-source", "1.8",
- "-target", "1.8",
+ "-source",
+ "1.8",
+ "-target",
+ "1.8",
"-Xlint:deprecation",
"-Xlint:unchecked"
)
@@ -27,7 +30,6 @@ val scalacBasicParams = Seq(
val scalacExtraParams = scalacBasicParams ++ Seq(
"-Ywarn-unused:imports",
"-Xlint:nullary-unit",
-
"-Xlint",
"-Ywarn-dead-code",
)
@@ -37,18 +39,21 @@ val javaCompilerSettings = Seq(
javacOptions in Test ++= javacParameters,
)
-def scalacCompilerSettings(scalaVer: String) = if (scalaVer.equals(scala210)) {
- scalacBasicParams
-} else {
- scalacExtraParams
-}
+def scalacCompilerSettings(scalaVer: String) =
+ if (scalaVer.equals(scala210)) {
+ scalacBasicParams
+ } else {
+ scalacExtraParams
+ }
val headerSettings = Seq(
headerLicense := {
val currentYear = java.time.Year.now(java.time.Clock.systemUTC).getValue
- Some(HeaderLicense.Custom(
- s"Copyright (C) 2009-$currentYear Lightbend Inc. "
- ))
+ Some(
+ HeaderLicense.Custom(
+ s"Copyright (C) 2009-$currentYear Lightbend Inc. "
+ )
+ )
},
headerEmptyLine := false
)
@@ -60,13 +65,15 @@ val commonSettings = javaCompilerSettings ++ headerSettings ++ Seq(
)
lazy val twirl = project
- .in(file("."))
- .enablePlugins(PlayRootProject)
- .settings(commonSettings)
- .settings(crossScalaVersions := Nil) // workaround so + uses project-defined variants
- .settings(releaseCrossBuild := false)
- .aggregate(apiJvm, apiJs, parser, compiler, plugin)
-
+ .in(file("."))
+ .enablePlugins(PlayRootProject)
+ .settings(commonSettings)
+ .settings(
+ crossScalaVersions := Nil, // workaround so + uses project-defined variants
+ releaseCrossBuild := false,
+ mimaFailOnNoPrevious := false
+ )
+ .aggregate(apiJvm, apiJs, parser, compiler, plugin)
lazy val nodeJs = {
if (System.getProperty("NODE_PATH") != null)
@@ -76,66 +83,79 @@ lazy val nodeJs = {
}
lazy val api = crossProject(JVMPlatform, JSPlatform)
- .in(file("api"))
- .enablePlugins(PlayLibrary, Playdoc)
- .configs(Docs)
- .settings(commonSettings)
- .settings(mimaPreviousArtifacts := binaryCompatibilitySettings(organization.value, moduleName.value, scalaBinaryVersion.value))
- .settings(
- name := "twirl-api",
- jsEnv := nodeJs,
- libraryDependencies ++= scalaXml.value,
- libraryDependencies += "org.scalatest" %%% "scalatest" % scalatest(scalaVersion.value) % "test"
- )
+ .in(file("api"))
+ .enablePlugins(PlayLibrary, Playdoc)
+ .configs(Docs)
+ .settings(commonSettings)
+ .settings(
+ name := "twirl-api",
+ jsEnv := nodeJs,
+ libraryDependencies ++= scalaXml.value,
+ libraryDependencies += "org.scalatest" %%% "scalatest" % scalatest(scalaVersion.value) % "test",
+ mimaPreviousArtifacts := binaryCompatibilitySettings(
+ organization.value,
+ moduleName.value,
+ scalaBinaryVersion.value
+ ),
+ )
lazy val apiJvm = api.jvm
-lazy val apiJs = api.js
+lazy val apiJs = api.js
lazy val parser = project
- .in(file("parser"))
- .enablePlugins(PlayLibrary)
- .settings(commonSettings)
- .settings(mimaPreviousArtifacts := binaryCompatibilitySettings(organization.value, moduleName.value, scalaBinaryVersion.value))
- .settings(
- name := "twirl-parser",
- libraryDependencies ++= scalaParserCombinators(scalaVersion.value),
- libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test",
- libraryDependencies += "org.scalatest" %%% "scalatest" % scalatest(scalaVersion.value) % "test"
- )
+ .in(file("parser"))
+ .enablePlugins(PlayLibrary)
+ .settings(commonSettings)
+ .settings(
+ name := "twirl-parser",
+ libraryDependencies ++= scalaParserCombinators(scalaVersion.value),
+ libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test",
+ libraryDependencies += "org.scalatest" %%% "scalatest" % scalatest(scalaVersion.value) % "test",
+ mimaPreviousArtifacts := binaryCompatibilitySettings(organization.value, moduleName.value, scalaBinaryVersion.value)
+ )
lazy val compiler = project
- .in(file("compiler"))
- .enablePlugins(PlayLibrary)
- .dependsOn(apiJvm, parser % "compile;test->test")
- .settings(commonSettings)
- .settings(mimaPreviousArtifacts := binaryCompatibilitySettings(organization.value, moduleName.value, scalaBinaryVersion.value))
- .settings(
- name := "twirl-compiler",
- libraryDependencies += scalaCompiler(scalaVersion.value),
- libraryDependencies ++= scalaParserCombinators(scalaVersion.value),
- fork in run := true
- )
+ .in(file("compiler"))
+ .enablePlugins(PlayLibrary)
+ .dependsOn(apiJvm, parser % "compile;test->test")
+ .settings(commonSettings)
+ .settings(
+ name := "twirl-compiler",
+ libraryDependencies += scalaCompiler(scalaVersion.value),
+ libraryDependencies ++= scalaParserCombinators(scalaVersion.value),
+ fork in run := true,
+ mimaPreviousArtifacts := binaryCompatibilitySettings(
+ organization.value,
+ moduleName.value,
+ scalaBinaryVersion.value
+ ),
+ )
lazy val plugin = project
- .in(file("sbt-twirl"))
- .enablePlugins(PlaySbtPlugin, SbtPlugin)
- .dependsOn(compiler)
- .settings(javaCompilerSettings)
- .settings(headerSettings)
- .settings(
- name := "sbt-twirl",
- organization := "com.typesafe.sbt",
- scalaVersion := scala212,
- libraryDependencies += "org.scalatest" %%% "scalatest" % scalatest(scalaVersion.value) % "test",
- resourceGenerators in Compile += generateVersionFile.taskValue,
- scriptedDependencies := {
- scriptedDependencies.value
- publishLocal.all(ScopeFilter(
- inDependencies(compiler)
- )).value
- },
- scalacOptions ++= scalacCompilerSettings(scalaVersion.value),
- )
+ .in(file("sbt-twirl"))
+ .enablePlugins(PlaySbtPlugin, SbtPlugin)
+ .dependsOn(compiler)
+ .settings(javaCompilerSettings)
+ .settings(headerSettings)
+ .settings(
+ name := "sbt-twirl",
+ organization := "com.typesafe.sbt",
+ scalaVersion := scala212,
+ libraryDependencies += "org.scalatest" %%% "scalatest" % scalatest(scalaVersion.value) % "test",
+ resourceGenerators in Compile += generateVersionFile.taskValue,
+ scriptedDependencies := {
+ scriptedDependencies.value
+ publishLocal
+ .all(
+ ScopeFilter(
+ inDependencies(compiler)
+ )
+ )
+ .value
+ },
+ scalacOptions ++= scalacCompilerSettings(scalaVersion.value),
+ mimaFailOnNoPrevious := false,
+ )
playBuildRepoName in ThisBuild := "twirl"
playBuildExtraTests := {
@@ -149,7 +169,7 @@ playBuildExtraPublish := {
def generateVersionFile = Def.task {
val version = (Keys.version in apiJvm).value
- val file = (resourceManaged in Compile).value / "twirl.version.properties"
+ val file = (resourceManaged in Compile).value / "twirl.version.properties"
val content = s"twirl.api.version=$version"
IO.write(file, content)
Seq(file)
@@ -165,9 +185,10 @@ def scalaCompiler(version: String) = "org.scala-lang" % "scala-compiler" % versi
def scalaParserCombinators(scalaVersion: String): Seq[ModuleID] = scalaVersion match {
case interplay.ScalaVersions.scala210 => Seq.empty
- case _ => Seq(
- "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2" % "optional"
- )
+ case _ =>
+ Seq(
+ "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2" % "optional"
+ )
}
def scalaXml = Def.setting {
@@ -179,4 +200,4 @@ def scalaXml = Def.setting {
}
}
-addCommandAlias("validateCode", ";headerCheck;test:headerCheck")
\ No newline at end of file
+addCommandAlias("validateCode", ";headerCheck;test:headerCheck;scalafmtCheckAll;scalafmtSbtCheck")
diff --git a/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala b/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala
index 77908178..f3001f75 100644
--- a/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala
+++ b/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala
@@ -9,7 +9,8 @@ import java.time.LocalDateTime
import scala.annotation.tailrec
import scala.io.Codec
import scala.reflect.internal.Flags
-import play.twirl.parser.{TwirlIO, TwirlParser}
+import play.twirl.parser.TwirlIO
+import play.twirl.parser.TwirlParser
object Hash {
@@ -24,7 +25,8 @@ object Hash {
}
-case class TemplateCompilationError(source: File, message: String, line: Int, column: Int) extends RuntimeException(message)
+case class TemplateCompilationError(source: File, message: String, line: Int, column: Int)
+ extends RuntimeException(message)
object MaybeGeneratedSource {
@@ -45,17 +47,22 @@ sealed trait AbstractGeneratedSource {
def content: String
lazy val meta: Map[String, String] = {
- val Meta = """([A-Z]+): (.*)""".r
+ val Meta = """([A-Z]+): (.*)""".r
val UndefinedMeta = """([A-Z]+):""".r
Map.empty[String, String] ++ {
try {
- content.split("-- GENERATED --")(1).trim.split('\n').map { m =>
- m.trim match {
- case Meta(key, value) => (key -> value)
- case UndefinedMeta(key) => (key -> "")
- case _ => ("UNDEFINED", "")
+ content
+ .split("-- GENERATED --")(1)
+ .trim
+ .split('\n')
+ .map { m =>
+ m.trim match {
+ case Meta(key, value) => (key -> value)
+ case UndefinedMeta(key) => (key -> "")
+ case _ => ("UNDEFINED", "")
+ }
}
- }.toMap
+ .toMap
} catch {
case _: Exception => Map.empty[String, String]
}
@@ -65,19 +72,19 @@ sealed trait AbstractGeneratedSource {
lazy val matrix: Seq[(Int, Int)] = {
for (pos <- meta("MATRIX").split('|'); c = pos.split("->"))
yield try {
- Integer.parseInt(c(0)) -> Integer.parseInt(c(1))
- } catch {
- case _: Exception => (0, 0) // Skip if MATRIX meta is corrupted
- }
+ Integer.parseInt(c(0)) -> Integer.parseInt(c(1))
+ } catch {
+ case _: Exception => (0, 0) // Skip if MATRIX meta is corrupted
+ }
}
lazy val lines: Seq[(Int, Int)] = {
for (pos <- meta("LINES").split('|'); c = pos.split("->"))
yield try {
- Integer.parseInt(c(0)) -> Integer.parseInt(c(1))
- } catch {
- case _: Exception => (0, 0) // Skip if LINES meta is corrupted
- }
+ Integer.parseInt(c(0)) -> Integer.parseInt(c(1))
+ } catch {
+ case _: Exception => (0, 0) // Skip if LINES meta is corrupted
+ }
}
def mapPosition(generatedPosition: Int): Int = {
@@ -113,15 +120,16 @@ case class GeneratedSource(file: File, codec: Codec = TwirlIO.defaultCodec) exte
def content = TwirlIO.readFileAsString(file, codec)
- def needRecompilation(imports: collection.Seq[String]): Boolean = !file.exists ||
- // A generated source already exist but
- source.isDefined && ((source.get.lastModified > file.lastModified) || // the source has been modified
- (meta("HASH") != Hash(TwirlIO.readFile(source.get), imports))) // or the hash don't match
+ def needRecompilation(imports: collection.Seq[String]): Boolean =
+ !file.exists ||
+ // A generated source already exist but
+ source.isDefined && ((source.get.lastModified > file.lastModified) || // the source has been modified
+ (meta("HASH") != Hash(TwirlIO.readFile(source.get), imports))) // or the hash don't match
def toSourcePosition(marker: Int): (Int, Int) = {
try {
val targetMarker = mapPosition(marker)
- val line = TwirlIO.readFileAsString(source.get, codec).substring(0, targetMarker).split('\n').size
+ val line = TwirlIO.readFileAsString(source.get, codec).substring(0, targetMarker).split('\n').size
(line, targetMarker)
} catch {
case _: Exception => (0, 0)
@@ -166,14 +174,31 @@ object TwirlCompiler {
import play.twirl.parser.TreeNodes._
- def compile(source: File, sourceDirectory: File, generatedDirectory: File, formatterType: String,
- additionalImports: collection.Seq[String] = Nil, constructorAnnotations: collection.Seq[String] = Nil, codec: Codec = TwirlIO.defaultCodec,
- inclusiveDot: Boolean = false) = {
+ def compile(
+ source: File,
+ sourceDirectory: File,
+ generatedDirectory: File,
+ formatterType: String,
+ additionalImports: collection.Seq[String] = Nil,
+ constructorAnnotations: collection.Seq[String] = Nil,
+ codec: Codec = TwirlIO.defaultCodec,
+ inclusiveDot: Boolean = false
+ ) = {
val resultType = formatterType + ".Appendable"
- val (templateName, generatedSource) = generatedFile(source, codec, sourceDirectory, generatedDirectory, inclusiveDot)
+ val (templateName, generatedSource) =
+ generatedFile(source, codec, sourceDirectory, generatedDirectory, inclusiveDot)
if (generatedSource.needRecompilation(additionalImports)) {
- val generated = parseAndGenerateCode(templateName, TwirlIO.readFile(source), codec, source.getAbsolutePath,
- resultType, formatterType, additionalImports, constructorAnnotations, inclusiveDot)
+ val generated = parseAndGenerateCode(
+ templateName,
+ TwirlIO.readFile(source),
+ codec,
+ source.getAbsolutePath,
+ resultType,
+ formatterType,
+ additionalImports,
+ constructorAnnotations,
+ inclusiveDot
+ )
TwirlIO.writeStringToFile(generatedSource.file, generated.toString, codec)
Some(generatedSource.file)
} else {
@@ -181,23 +206,49 @@ object TwirlCompiler {
}
}
- def compileVirtual(content: String, source: File, sourceDirectory: File, resultType: String, formatterType: String,
- additionalImports: collection.Seq[String] = Nil, constructorAnnotations: collection.Seq[String] = Nil,
- codec: Codec = TwirlIO.defaultCodec, inclusiveDot: Boolean = false) = {
+ def compileVirtual(
+ content: String,
+ source: File,
+ sourceDirectory: File,
+ resultType: String,
+ formatterType: String,
+ additionalImports: collection.Seq[String] = Nil,
+ constructorAnnotations: collection.Seq[String] = Nil,
+ codec: Codec = TwirlIO.defaultCodec,
+ inclusiveDot: Boolean = false
+ ) = {
val (templateName, generatedSource) = generatedFileVirtual(source, sourceDirectory, inclusiveDot)
- val generated = parseAndGenerateCode(templateName, content.getBytes(codec.charSet), codec, source.getAbsolutePath,
- resultType, formatterType, additionalImports, constructorAnnotations, inclusiveDot)
+ val generated = parseAndGenerateCode(
+ templateName,
+ content.getBytes(codec.charSet),
+ codec,
+ source.getAbsolutePath,
+ resultType,
+ formatterType,
+ additionalImports,
+ constructorAnnotations,
+ inclusiveDot
+ )
generatedSource.setContent(generated)
generatedSource
}
- def parseAndGenerateCode(templateName: Array[String], content: Array[Byte], codec: Codec, absolutePath: String,
- resultType: String, formatterType: String, additionalImports: collection.Seq[String], constructorAnnotations: collection.Seq[String],
- inclusiveDot: Boolean) = {
+ def parseAndGenerateCode(
+ templateName: Array[String],
+ content: Array[Byte],
+ codec: Codec,
+ absolutePath: String,
+ resultType: String,
+ formatterType: String,
+ additionalImports: collection.Seq[String],
+ constructorAnnotations: collection.Seq[String],
+ inclusiveDot: Boolean
+ ) = {
val templateParser = new TwirlParser(inclusiveDot)
templateParser.parse(new String(content, codec.charSet)) match {
case templateParser.Success(parsed: Template, rest) if rest.atEnd => {
- generateFinalTemplate(absolutePath,
+ generateFinalTemplate(
+ absolutePath,
content,
templateName.dropRight(1).mkString("."),
templateName.takeRight(1).mkString,
@@ -213,14 +264,26 @@ object TwirlCompiler {
}
case templateParser.Error(_, rest, errors) => {
val firstError = errors.head
- throw new TemplateCompilationError(new File(absolutePath), firstError.str, firstError.pos.line, firstError.pos.column)
+ throw new TemplateCompilationError(
+ new File(absolutePath),
+ firstError.str,
+ firstError.pos.line,
+ firstError.pos.column
+ )
}
}
}
- def generatedFile(template: File, codec: Codec, sourceDirectory: File, generatedDirectory: File, inclusiveDot: Boolean) = {
+ def generatedFile(
+ template: File,
+ codec: Codec,
+ sourceDirectory: File,
+ generatedDirectory: File,
+ inclusiveDot: Boolean
+ ) = {
val templateName = {
- val name = source2TemplateName(template, sourceDirectory, template.getName.split('.').takeRight(1).head).split('.')
+ val name =
+ source2TemplateName(template, sourceDirectory, template.getName.split('.').takeRight(1).head).split('.')
if (inclusiveDot) addInclusiveDotName(name) else name
}
templateName -> GeneratedSource(new File(generatedDirectory, templateName.mkString("/") + ".template.scala"), codec)
@@ -228,7 +291,8 @@ object TwirlCompiler {
def generatedFileVirtual(template: File, sourceDirectory: File, inclusiveDot: Boolean) = {
val templateName = {
- val name = source2TemplateName(template, sourceDirectory, template.getName.split('.').takeRight(1).head).split('.')
+ val name =
+ source2TemplateName(template, sourceDirectory, template.getName.split('.').takeRight(1).head).split('.')
if (inclusiveDot) addInclusiveDotName(name) else name
}
templateName -> GeneratedSourceVirtual(templateName.mkString("/") + ".template.scala")
@@ -242,19 +306,37 @@ object TwirlCompiler {
}
@tailrec
- def source2TemplateName(f: File, sourceDirectory: File, ext: String, suffix: String = "", topDirectory: String = "views", setExt: Boolean = true): String = {
+ def source2TemplateName(
+ f: File,
+ sourceDirectory: File,
+ ext: String,
+ suffix: String = "",
+ topDirectory: String = "views",
+ setExt: Boolean = true
+ ): String = {
val Name = """([a-zA-Z0-9_]+)[.]scala[.]([a-z]+)""".r
(f, f.getName) match {
case (f, _) if f == sourceDirectory => {
if (setExt) {
val parts = suffix.split('.')
- Option(parts.dropRight(1).mkString(".")).filterNot(_.isEmpty).map(_ + ".").getOrElse("") + ext + "." + parts.takeRight(1).mkString
+ Option(parts.dropRight(1).mkString(".")).filterNot(_.isEmpty).map(_ + ".").getOrElse("") + ext + "." + parts
+ .takeRight(1)
+ .mkString
} else suffix
}
- case (f, name) if name == topDirectory => source2TemplateName(f.getParentFile, sourceDirectory, ext, name + "." + ext + "." + suffix, topDirectory, false)
- case (f, Name(name, _)) if f.isFile => source2TemplateName(f.getParentFile, sourceDirectory, ext, name, topDirectory, setExt)
- case (f, name) if !f.isFile => source2TemplateName(f.getParentFile, sourceDirectory, ext, name + "." + suffix, topDirectory, setExt)
- case (f, name) => throw TemplateCompilationError(f, "Invalid template name [" + name + "], filenames must only consist of alphanumeric characters and underscores or periods.", 0, 0)
+ case (f, name) if name == topDirectory =>
+ source2TemplateName(f.getParentFile, sourceDirectory, ext, name + "." + ext + "." + suffix, topDirectory, false)
+ case (f, Name(name, _)) if f.isFile =>
+ source2TemplateName(f.getParentFile, sourceDirectory, ext, name, topDirectory, setExt)
+ case (f, name) if !f.isFile =>
+ source2TemplateName(f.getParentFile, sourceDirectory, ext, name + "." + suffix, topDirectory, setExt)
+ case (f, name) =>
+ throw TemplateCompilationError(
+ f,
+ "Invalid template name [" + name + "], filenames must only consist of alphanumeric characters and underscores or periods.",
+ 0,
+ 0
+ )
}
}
@@ -270,9 +352,9 @@ object TwirlCompiler {
// Scala doesn't offer a way to escape triple quoted strings inside triple quoted strings (to my knowledge), so we
// have to escape them in this rather crude way
// We need to double escape slashes, since it's a regex replacement
- private val escapedTripleQuote = "\\\"" * 3
+ private val escapedTripleQuote = "\\\"" * 3
private val doubleEscapedTripleQuote = "\\\\\"" * 3
- private val tripleQuoteReplacement = escapedTripleQuote + " + \\\"" + doubleEscapedTripleQuote + "\\\" + " + escapedTripleQuote
+ private val tripleQuoteReplacement = escapedTripleQuote + " + \\\"" + doubleEscapedTripleQuote + "\\\" + " + escapedTripleQuote
private def quoteAndEscape(text: String): collection.Seq[String] = {
Seq(tripleQuote, text.replaceAll(tripleQuote, tripleQuoteReplacement), tripleQuote)
}
@@ -280,24 +362,34 @@ object TwirlCompiler {
def visit(elem: collection.Seq[TemplateTree], previous: collection.Seq[Any]): collection.Seq[Any] = {
elem.toList match {
case head :: tail =>
- visit(tail, head match {
- case p @ Plain(text) =>
-
- // String literals may not be longer than 65536 bytes. They are encoded as UTF-8 in the classfile, each
- // UTF-16 2 byte char could end up becoming up to 3 bytes, so that puts an upper limit of somewhere
- // over 20000 characters. 20000 characters is a nice round number, use that.
- val grouped = StringGrouper(text, 20000)
- (if (previous.isEmpty) Nil else previous :+ ",") :+
- "format.raw" :+ Source("(", p.pos) :+ quoteAndEscape(grouped.head) :+ ")" :+
- grouped.tail.flatMap { t => Seq(",\nformat.raw(", quoteAndEscape(t), ")") }
- case Comment(msg) => previous
- case Display(exp) => (if (previous.isEmpty) Nil else previous :+ ",") :+ displayVisitedChildren(visit(Seq(exp), Nil))
- case ScalaExp(parts) => previous :+ parts.map {
- case s @ Simple(code) => Source(code, s.pos)
- case b @ Block(whitespace, args, content) if (content.forall(_.isInstanceOf[ScalaExp])) => Nil :+ Source(whitespace + "{" + args.getOrElse(""), b.pos) :+ visit(content, Nil) :+ "}"
- case b @ Block(whitespace, args, content) => Nil :+ Source(whitespace + "{" + args.getOrElse(""), b.pos) :+ displayVisitedChildren(visit(content, Nil)) :+ "}"
+ visit(
+ tail,
+ head match {
+ case p @ Plain(text) =>
+ // String literals may not be longer than 65536 bytes. They are encoded as UTF-8 in the classfile, each
+ // UTF-16 2 byte char could end up becoming up to 3 bytes, so that puts an upper limit of somewhere
+ // over 20000 characters. 20000 characters is a nice round number, use that.
+ val grouped = StringGrouper(text, 20000)
+ (if (previous.isEmpty) Nil else previous :+ ",") :+
+ "format.raw" :+ Source("(", p.pos) :+ quoteAndEscape(grouped.head) :+ ")" :+
+ grouped.tail.flatMap { t =>
+ Seq(",\nformat.raw(", quoteAndEscape(t), ")")
+ }
+ case Comment(msg) => previous
+ case Display(exp) =>
+ (if (previous.isEmpty) Nil else previous :+ ",") :+ displayVisitedChildren(visit(Seq(exp), Nil))
+ case ScalaExp(parts) =>
+ previous :+ parts.map {
+ case s @ Simple(code) => Source(code, s.pos)
+ case b @ Block(whitespace, args, content) if (content.forall(_.isInstanceOf[ScalaExp])) =>
+ Nil :+ Source(whitespace + "{" + args.getOrElse(""), b.pos) :+ visit(content, Nil) :+ "}"
+ case b @ Block(whitespace, args, content) =>
+ Nil :+ Source(whitespace + "{" + args.getOrElse(""), b.pos) :+ displayVisitedChildren(
+ visit(content, Nil)
+ ) :+ "}"
+ }
}
- })
+ )
case Nil => previous
}
}
@@ -307,10 +399,16 @@ object TwirlCompiler {
val defs = (template.sub ++ template.defs).map {
case t: Template if t.name.toString == "" => templateCode(t, resultType)
case t: Template => {
- Nil :+ (if (t.name.str.startsWith("implicit")) "implicit def " else "def ") :+ Source(t.name.str, t.name.pos) :+ Source(t.params.str, t.params.pos) :+ ":" :+ resultType :+ " = {_display_(" :+ templateCode(t, resultType) :+ ")};"
+ Nil :+ (if (t.name.str.startsWith("implicit")) "implicit def " else "def ") :+ Source(t.name.str, t.name.pos) :+ Source(
+ t.params.str,
+ t.params.pos
+ ) :+ ":" :+ resultType :+ " = {_display_(" :+ templateCode(t, resultType) :+ ")};"
}
case Def(name, params, block) => {
- Nil :+ (if (name.str.startsWith("implicit")) "implicit def " else "def ") :+ Source(name.str, name.pos) :+ Source(params.str, params.pos) :+ " = {" :+ block.code :+ "};"
+ Nil :+ (if (name.str.startsWith("implicit")) "implicit def " else "def ") :+ Source(name.str, name.pos) :+ Source(
+ params.str,
+ params.pos
+ ) :+ " = {" :+ block.code :+ "};"
}
}
@@ -319,15 +417,19 @@ object TwirlCompiler {
Nil :+ imports :+ "\n" :+ defs :+ "\n" :+ "Seq[Any](" :+ visit(template.content, Nil) :+ ")"
}
- def generateCode(packageName: String, name: String, root: Template, resultType: String, formatterType: String,
- additionalImports: collection.Seq[String], constructorAnnotations: collection.Seq[String]): collection.Seq[Any] = {
- val (renderCall, f, templateType) = TemplateAsFunctionCompiler.getFunctionMapping(
- root.params.str,
- resultType)
+ def generateCode(
+ packageName: String,
+ name: String,
+ root: Template,
+ resultType: String,
+ formatterType: String,
+ additionalImports: collection.Seq[String],
+ constructorAnnotations: collection.Seq[String]
+ ): collection.Seq[Any] = {
+ val (renderCall, f, templateType) = TemplateAsFunctionCompiler.getFunctionMapping(root.params.str, resultType)
// Get the imports that we need to include, filtering out empty imports
- val imports: Seq[Any] = Seq(additionalImports.map(i => Seq("import ", i, "\n")),
- formatImports(root.topImports))
+ val imports: Seq[Any] = Seq(additionalImports.map(i => Seq("import ", i, "\n")), formatImports(root.topImports))
val classDeclaration = root.constructor.fold[Seq[Any]](
Seq("object ", name)
@@ -370,11 +472,19 @@ package """ :+ packageName :+ """
imports.map(i => Seq(Source(i.code, i.pos), "\n"))
}
- def generateFinalTemplate(absolutePath: String, contents: Array[Byte], packageName: String, name: String,
- root: Template, resultType: String, formatterType: String, additionalImports: collection.Seq[String],
- constructorAnnotations: collection.Seq[String]): String = {
- val generated = generateCode(packageName, name, root, resultType, formatterType, additionalImports,
- constructorAnnotations)
+ def generateFinalTemplate(
+ absolutePath: String,
+ contents: Array[Byte],
+ packageName: String,
+ name: String,
+ root: Template,
+ resultType: String,
+ formatterType: String,
+ additionalImports: collection.Seq[String],
+ constructorAnnotations: collection.Seq[String]
+ ): String = {
+ val generated =
+ generateCode(packageName, name, root, resultType, formatterType, additionalImports, constructorAnnotations)
Source.finalSource(absolutePath, contents, generated, Hash(contents, additionalImports))
}
@@ -388,20 +498,23 @@ package """ :+ packageName :+ """
import java.io.File
import scala.tools.nsc.interactive.Global
- import scala.reflect.internal.util.{ SourceFile, Position, BatchSourceFile }
+ import scala.reflect.internal.util.SourceFile
+ import scala.reflect.internal.util.Position
+ import scala.reflect.internal.util.BatchSourceFile
import scala.tools.nsc.Settings
import scala.tools.nsc.reporters.ConsoleReporter
- type Tree = PresentationCompiler.global.Tree
- type DefDef = PresentationCompiler.global.DefDef
+ type Tree = PresentationCompiler.global.Tree
+ type DefDef = PresentationCompiler.global.DefDef
type TypeDef = PresentationCompiler.global.TypeDef
- type ValDef = PresentationCompiler.global.ValDef
+ type ValDef = PresentationCompiler.global.ValDef
// For some reason they got rid of mods.isByNameParam
object ByNameParam {
- def unapply(param: ValDef): Option[(String, String)] = if (param.mods.hasFlag(Flags.BYNAMEPARAM)) {
- Some((param.name.toString, param.tpt.children(1).toString))
- } else None
+ def unapply(param: ValDef): Option[(String, String)] =
+ if (param.mods.hasFlag(Flags.BYNAMEPARAM)) {
+ Some((param.name.toString, param.tpt.children(1).toString))
+ } else None
}
/** The maximum time in milliseconds to wait for a compiler response to finish. */
@@ -409,54 +522,89 @@ package """ :+ packageName :+ """
def getFunctionMapping(signature: String, returnType: String): (String, String, String) = synchronized {
- def filterType(t: String) = t
- .replace("_root_.scala.", "Array")
- .replace("", "")
+ def filterType(t: String) =
+ t.replace("_root_.scala.", "Array")
+ .replace("", "")
def findSignature(tree: Tree): Option[DefDef] = {
tree match {
case t: DefDef if t.name.toString == "signature" => Some(t)
- case t: Tree => t.children.flatMap(findSignature).headOption
+ case t: Tree => t.children.flatMap(findSignature).headOption
}
}
- val params = findSignature(
- PresentationCompiler.treeFrom("object FT { def signature" + signature + " }")).get.vparamss
-
- val resp = PresentationCompiler.global.askForResponse { () =>
-
- val functionType = "(" + params.map(group => "(" + group.map {
- case ByNameParam(_, paramType) => " => " + paramType
- case a => filterType(a.tpt.toString)
- }.mkString(",") + ")").mkString(" => ") + " => " + returnType + ")"
-
- val renderCall = "def render%s: %s = apply%s".format(
- "(" + params.flatten.map {
- case ByNameParam(name, paramType) => name + ":" + paramType
- case a => a.name.toString + ":" + filterType(a.tpt.toString)
- }.mkString(",") + ")",
- returnType,
- params.map(group => "(" + group.map { p =>
- p.name.toString + Option(p.tpt.toString).filter(_.startsWith("_root_.scala.")).map(_ => ":_*").getOrElse("")
- }.mkString(",") + ")").mkString)
-
- val templateType = "_root_.play.twirl.api.Template%s[%s%s]".format(
- params.flatten.size,
- params.flatten.map {
- case ByNameParam(_, paramType) => paramType
- case a => filterType(a.tpt.toString)
- }.mkString(","),
- (if (params.flatten.isEmpty) "" else ",") + returnType)
-
- 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.tpt.toString).filter(_.startsWith("_root_.scala.")).map(_ => ":_*").getOrElse("")
- }.mkString(",") + ")").mkString)
-
- (renderCall, f, templateType)
- }.get(Timeout)
+ val params =
+ findSignature(PresentationCompiler.treeFrom("object FT { def signature" + signature + " }")).get.vparamss
+
+ val resp = PresentationCompiler.global
+ .askForResponse { () =>
+ val functionType = "(" + params
+ .map(
+ group =>
+ "(" + group
+ .map {
+ case ByNameParam(_, paramType) => " => " + paramType
+ case a => filterType(a.tpt.toString)
+ }
+ .mkString(",") + ")"
+ )
+ .mkString(" => ") + " => " + returnType + ")"
+
+ val renderCall = "def render%s: %s = apply%s".format(
+ "(" + params.flatten
+ .map {
+ case ByNameParam(name, paramType) => name + ":" + paramType
+ case a => a.name.toString + ":" + filterType(a.tpt.toString)
+ }
+ .mkString(",") + ")",
+ returnType,
+ params
+ .map(
+ group =>
+ "(" + group
+ .map { p =>
+ p.name.toString + Option(p.tpt.toString)
+ .filter(_.startsWith("_root_.scala."))
+ .map(_ => ":_*")
+ .getOrElse("")
+ }
+ .mkString(",") + ")"
+ )
+ .mkString
+ )
+
+ val templateType = "_root_.play.twirl.api.Template%s[%s%s]".format(
+ params.flatten.size,
+ params.flatten
+ .map {
+ case ByNameParam(_, paramType) => paramType
+ case a => filterType(a.tpt.toString)
+ }
+ .mkString(","),
+ (if (params.flatten.isEmpty) "" else ",") + returnType
+ )
+
+ 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.tpt.toString)
+ .filter(_.startsWith("_root_.scala."))
+ .map(_ => ":_*")
+ .getOrElse("")
+ }
+ .mkString(",") + ")"
+ )
+ .mkString
+ )
+
+ (renderCall, f, templateType)
+ }
+ .get(Timeout)
resp match {
case None =>
@@ -487,20 +635,24 @@ package """ :+ packageName :+ """
if (scalaPredefSource != null) {
import java.net.URL
import java.security.CodeSource
- def urlToFile(url: URL): File = try {
- val file = new File(url.toURI)
- if (file.exists) file else new File(url.getPath) // assume malformed URL
- } catch {
- case _: java.net.URISyntaxException =>
- // malformed URL: fallback to using the URL path directly
- new File(url.getPath)
- }
+ def urlToFile(url: URL): File =
+ try {
+ val file = new File(url.toURI)
+ if (file.exists) file else new File(url.getPath) // assume malformed URL
+ } catch {
+ case _: java.net.URISyntaxException =>
+ // malformed URL: fallback to using the URL path directly
+ new File(url.getPath)
+ }
def toAbsolutePath(cs: CodeSource): String = urlToFile(cs.getLocation).getAbsolutePath
- val compilerPath = toAbsolutePath(Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource)
- val libPath = toAbsolutePath(scalaPredefSource)
- val pathList = List(compilerPath, libPath)
+ val compilerPath = toAbsolutePath(
+ Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource
+ )
+ val libPath = toAbsolutePath(scalaPredefSource)
+ val pathList = List(compilerPath, libPath)
val origBootclasspath = settings.bootclasspath.value
- settings.bootclasspath.value = ((origBootclasspath :: pathList) ::: additionalClassPathEntry.toList) mkString File.pathSeparator
+ settings.bootclasspath.value =
+ ((origBootclasspath :: pathList) ::: additionalClassPathEntry.toList).mkString(File.pathSeparator)
}
val compiler = new Global(settings, new ConsoleReporter(settings) {
@@ -558,7 +710,9 @@ package """ :+ packageName :+ """
/* ------- */
-import scala.util.parsing.input.{ Position, OffsetPosition, NoPosition }
+import scala.util.parsing.input.Position
+import scala.util.parsing.input.OffsetPosition
+import scala.util.parsing.input.NoPosition
case class Source(code: String, pos: Position = NoPosition)
@@ -566,10 +720,15 @@ object Source {
import scala.collection.mutable.ListBuffer
- def finalSource(absolutePath: String, contents: Array[Byte], generatedTokens: collection.Seq[Any], hash: String): String = {
+ def finalSource(
+ absolutePath: String,
+ contents: Array[Byte],
+ generatedTokens: collection.Seq[Any],
+ hash: String
+ ): String = {
val scalaCode = new StringBuilder
val positions = ListBuffer.empty[(Int, Int)]
- val lines = ListBuffer.empty[(Int, Int)]
+ val lines = ListBuffer.empty[(Int, Int)]
serialize(generatedTokens, scalaCode, positions, lines)
scalaCode.toString + s"""
/*
@@ -584,17 +743,22 @@ object Source {
"""
}
- private def serialize(parts: collection.Seq[Any], source: StringBuilder, positions: ListBuffer[(Int, Int)], lines: ListBuffer[(Int, Int)]): Unit = {
+ private def serialize(
+ parts: collection.Seq[Any],
+ source: StringBuilder,
+ positions: ListBuffer[(Int, Int)],
+ lines: ListBuffer[(Int, Int)]
+ ): Unit = {
parts.foreach {
case s: String => source.append(s)
case Source(code, pos @ OffsetPosition(_, offset)) => {
source.append("/*" + pos + "*/")
- positions += (source.length -> offset)
+ positions += (source.length -> offset)
lines += (source.toString.split('\n').size -> pos.line)
source.append(code)
}
case Source(code, NoPosition) => source.append(code)
- case s: collection.Seq[any] => serialize(s, source, positions, lines)
+ case s: collection.Seq[any] => serialize(s, source, positions, lines)
}
}
diff --git a/compiler/src/test/scala/play/twirl/compiler/test/Benchmark.scala b/compiler/src/test/scala/play/twirl/compiler/test/Benchmark.scala
index 5fcb2d7a..a61480b3 100644
--- a/compiler/src/test/scala/play/twirl/compiler/test/Benchmark.scala
+++ b/compiler/src/test/scala/play/twirl/compiler/test/Benchmark.scala
@@ -15,11 +15,10 @@ import play.twirl.parser.TwirlIO
*/
object Benchmark extends App {
- val sourceDir = new File("src/test/resources")
- val generatedDir = new File("target/test/benchmark-templates")
+ val sourceDir = new File("src/test/resources")
+ val generatedDir = new File("target/test/benchmark-templates")
val generatedClasses = new File("target/test/benchmark-classes")
-
TwirlIO.deleteRecursively(generatedDir)
TwirlIO.deleteRecursively(generatedClasses)
generatedClasses.mkdirs()
@@ -28,7 +27,7 @@ object Benchmark extends App {
println("Compiling template...")
val template = helper.compile[((String, List[String]) => (Int) => Html)]("real.scala.html", "html.real").static
- val input = (1 to 100).map(_.toString).toList
+ val input = (1 to 100).map(_.toString).toList
val text = "world " * 100
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 cc12d6b6..7bec582d 100644
--- a/compiler/src/test/scala/play/twirl/compiler/test/CompilerSpec.scala
+++ b/compiler/src/test/scala/play/twirl/compiler/test/CompilerSpec.scala
@@ -6,7 +6,8 @@ package test
import java.io._
-import org.scalatest.{ MustMatchers, WordSpec }
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
import play.twirl.api.Html
import play.twirl.parser.TwirlIO
@@ -19,8 +20,8 @@ class CompilerSpec extends WordSpec with MustMatchers {
val sourceDir = new File("compiler/src/test/resources")
def newCompilerHelper = {
- val dirName = "twirl-parser"
- val generatedDir = new File("compiler/target/test/" + dirName + "/generated-templates")
+ val dirName = "twirl-parser"
+ val generatedDir = new File("compiler/target/test/" + dirName + "/generated-templates")
val generatedClasses = new File("compiler/target/test/" + dirName + "/generated-classes")
TwirlIO.deleteRecursively(generatedDir)
TwirlIO.deleteRecursively(generatedClasses)
@@ -32,23 +33,30 @@ class CompilerSpec extends WordSpec with MustMatchers {
"compile successfully (real)" in {
val helper = newCompilerHelper
- val tmpl = helper.compile[((String, List[String]) => (Int) => Html)]("real.scala.html", "html.real")
- .static("World", List("A", "B"))(4).toString.trim
+ val tmpl = helper
+ .compile[((String, List[String]) => (Int) => Html)]("real.scala.html", "html.real")
+ .static("World", List("A", "B"))(4)
+ .toString
+ .trim
- tmpl must (include("Hello World
") and include("You have 2 items") and include("EA") and include("EB"))
+ tmpl must (include("Hello World
").and(include("You have 2 items")).and(include("EA")).and(include("EB")))
}
"compile successfully (static)" in {
val helper = newCompilerHelper
helper.compile[(() => Html)]("static.scala.html", "html.static").static().toString.trim must be(
- "It works
")
+ "It works
"
+ )
}
"compile successfully (patternMatching)" in {
val testParam = "12345"
- val helper = newCompilerHelper
- helper.compile[((String) => Html)]("patternMatching.scala.html", "html.patternMatching").static(testParam).toString.trim must be(
- """@test
+ val helper = newCompilerHelper
+ helper
+ .compile[((String) => Html)]("patternMatching.scala.html", "html.patternMatching")
+ .static(testParam)
+ .toString
+ .trim must be("""@test
@test.length
@test.length.toInt
@@ -62,81 +70,110 @@ class CompilerSpec extends WordSpec with MustMatchers {
"compile successfully (hello)" in {
val helper = newCompilerHelper
- val hello = helper.compile[((String) => Html)]("hello.scala.html", "html.hello").static("World").toString.trim
+ val hello = helper.compile[((String) => Html)]("hello.scala.html", "html.hello").static("World").toString.trim
hello must be("Hello World!
xml
")
}
"compile successfully (helloNull)" in {
val helper = newCompilerHelper
- val hello = helper.compile[((String) => Html)]("helloNull.scala.html", "html.helloNull").static(null).toString.trim
+ val hello =
+ helper.compile[((String) => Html)]("helloNull.scala.html", "html.helloNull").static(null).toString.trim
hello must be("Hello !
")
}
"compile successfully (zipWithIndex)" in {
val helper = newCompilerHelper
- val output = helper.compile[((Seq[String]) => Html)]("zipWithIndex.scala.html", "html.zipWithIndex").static(Seq("Alice", "Bob", "Charlie")).toString.trim.replace("\n", "")
+ val output = helper
+ .compile[((Seq[String]) => Html)]("zipWithIndex.scala.html", "html.zipWithIndex")
+ .static(Seq("Alice", "Bob", "Charlie"))
+ .toString
+ .trim
+ .replace("\n", "")
output must be("0 Hello Alice!
1 Hello Bob!
2 Hello Charlie!
")
}
"compile successfully (set)" in {
val helper = newCompilerHelper
- val set = helper.compile[((collection.immutable.Set[String]) => Html)]("set.scala.html", "html.set").static(Set("first", "second", "third")).toString.trim.replace("\n", "").replaceAll("\\s+", "")
+ val set = helper
+ .compile[((collection.immutable.Set[String]) => Html)]("set.scala.html", "html.set")
+ .static(Set("first", "second", "third"))
+ .toString
+ .trim
+ .replace("\n", "")
+ .replaceAll("\\s+", "")
set must be("firstsecondthird")
}
"compile successfully (arg imports)" in {
val helper = newCompilerHelper
- val result = helper.compile[((java.io.File, java.net.URL) => Html)]("argImports.scala.html", "html.argImports").static(new java.io.File("example"), new java.net.URL("http://example.org")).toString.trim
+ val result = helper
+ .compile[((java.io.File, java.net.URL) => Html)]("argImports.scala.html", "html.argImports")
+ .static(new java.io.File("example"), new java.net.URL("http://example.org"))
+ .toString
+ .trim
result must be("file: example, url: http://example.org
")
}
"compile successfully (default imports)" in {
val helper = newCompilerHelper
- val result = helper.compile[(() => Html)]("importsDefault.scala.html", "html.importsDefault").static().toString.trim
+ val result =
+ helper.compile[(() => Html)]("importsDefault.scala.html", "html.importsDefault").static().toString.trim
result must be("foo")
}
"compile successfully (escape closing brace)" in {
val helper = newCompilerHelper
- val result = helper.compile[(Option[String] => Html)]("escapebrace.scala.html", "html.escapebrace").static(Some("foo")).toString.trim
+ val result = helper
+ .compile[(Option[String] => Html)]("escapebrace.scala.html", "html.escapebrace")
+ .static(Some("foo"))
+ .toString
+ .trim
result must be("foo: }")
}
"compile successfully (utf8)" in {
val helper = newCompilerHelper
- val text = helper.compile[(() => Html)]("utf8.scala.html", "html.utf8").static().toString.trim
+ val text = helper.compile[(() => Html)]("utf8.scala.html", "html.utf8").static().toString.trim
text must be("€, ö, or ü")
}
"compile successfully (existential)" in {
val helper = newCompilerHelper
- val text = helper.compile[(List[_] => Html)]("existential.scala.html", "html.existential").static(List(1, 2, 3)).toString.trim
+ val text = helper
+ .compile[(List[_] => Html)]("existential.scala.html", "html.existential")
+ .static(List(1, 2, 3))
+ .toString
+ .trim
text must be("123")
}
"compile successfully (triple quotes)" in {
val helper = newCompilerHelper
- val out = helper.compile[(() => Html)]("triplequotes.scala.html", "html.triplequotes").static().toString.trim
+ val out = helper.compile[(() => Html)]("triplequotes.scala.html", "html.triplequotes").static().toString.trim
out must be("\"\"\"\n\n\"\"\"\"\"\n\n\"\"\"\"\"\"")
}
"compile successfully (var args existential)" in {
val helper = newCompilerHelper
- val text = helper.compile[(Array[List[_]] => Html)]("varArgsExistential.scala.html", "html.varArgsExistential").static(Array(List(1, 2, 3), List(4, 5, 6))).toString.trim
+ val text = helper
+ .compile[(Array[List[_]] => Html)]("varArgsExistential.scala.html", "html.varArgsExistential")
+ .static(Array(List(1, 2, 3), List(4, 5, 6)))
+ .toString
+ .trim
text must be("123456")
}
"fail compilation for error.scala.html" in {
val helper = newCompilerHelper
the[CompilationError] thrownBy helper.compile[(() => Html)]("error.scala.html", "html.error") must have(
- Symbol("line") (2),
- Symbol("column") (12)
+ Symbol("line")(2),
+ Symbol("column")(12)
)
}
"compile templates that have contiguous strings > than 64k" in {
val helper = newCompilerHelper
- val input = TwirlIO.readFileAsString(new File(sourceDir, "long.scala.html"))
+ val input = TwirlIO.readFileAsString(new File(sourceDir, "long.scala.html"))
val result = helper.compile[(() => Html)]("long.scala.html", "html.long").static().toString
result.length mustBe input.length
result mustBe input
@@ -144,7 +181,9 @@ class CompilerSpec extends WordSpec with MustMatchers {
"allow rendering a template twice" in {
val helper = newCompilerHelper
- val inner = helper.compile[((String, List[String]) => (Int) => Html)]("htmlInner.scala.html", "html.htmlInner").static("World", List("A", "B"))(4)
+ val inner = helper
+ .compile[((String, List[String]) => (Int) => Html)]("htmlInner.scala.html", "html.htmlInner")
+ .static("World", List("A", "B"))(4)
val outer = helper.compile[Html => Html]("htmlParam.scala.html", "html.htmlParam").static
@@ -155,30 +194,32 @@ class CompilerSpec extends WordSpec with MustMatchers {
"support injectable templates" when {
"plain injected template" in {
- val helper = newCompilerHelper
+ val helper = newCompilerHelper
val template = helper.compile[String => Html]("inject.scala.html", "html.inject").inject("Hello", 10)
template("world").body.trim mustBe "Hello 10 world"
}
"with no args" in {
- val helper = newCompilerHelper
+ val helper = newCompilerHelper
val template = helper.compile[String => Html]("injectNoArgs.scala.html", "html.injectNoArgs").inject()
template("Hello").body.trim mustBe "Hello"
}
"with parameter groups" in {
val helper = newCompilerHelper
- val template = helper.compile[String => Html]("injectParamGroups.scala.html", "html.injectParamGroups").inject("Hello", 10, "my")
+ val template = helper
+ .compile[String => Html]("injectParamGroups.scala.html", "html.injectParamGroups")
+ .inject("Hello", 10, "my")
template("world").body.trim mustBe "Hello 10 my world"
}
"with comments" in {
val helper = newCompilerHelper
- val template = helper.compile[String => Html]("injectComments.scala.html", "html.injectComments").inject("Hello", 10)
+ val template =
+ helper.compile[String => Html]("injectComments.scala.html", "html.injectComments").inject("Hello", 10)
template("world").body.trim mustBe "Hello 10 world"
}
-
}
}
@@ -187,53 +228,54 @@ class CompilerSpec extends WordSpec with MustMatchers {
val line = "abcde" + beer + "fg"
"split before a surrogate pair" in {
- StringGrouper(line, 5) must contain allOf ("abcde", beer + "fg")
+ (StringGrouper(line, 5) must contain).allOf("abcde", beer + "fg")
}
"not split a surrogate pair" in {
- StringGrouper(line, 6) must contain allOf("abcde" + beer, "fg")
+ (StringGrouper(line, 6) must contain).allOf("abcde" + beer, "fg")
}
"split after a surrogate pair" in {
- StringGrouper(line, 7) must contain allOf("abcde" + beer, "fg")
+ (StringGrouper(line, 7) must contain).allOf("abcde" + beer, "fg")
}
}
"compile successfully (elseIf)" when {
"input is in if clause" in {
val helper = newCompilerHelper
- val hello = helper.compile[((Int) => Html)]("elseIf.scala.html", "html.elseIf").static(0).toString.trim
+ val hello = helper.compile[((Int) => Html)]("elseIf.scala.html", "html.elseIf").static(0).toString.trim
hello must be("hello")
}
"input is in else if clause" in {
val helper = newCompilerHelper
- val hello = helper.compile[((Int) => Html)]("elseIf.scala.html", "html.elseIf").static(1).toString.trim
+ val hello = helper.compile[((Int) => Html)]("elseIf.scala.html", "html.elseIf").static(1).toString.trim
hello must be("world")
}
"input is in else clause" in {
val helper = newCompilerHelper
- val hello = helper.compile[((Int) => Html)]("elseIf.scala.html", "html.elseIf").static(25).toString.trim
+ val hello = helper.compile[((Int) => Html)]("elseIf.scala.html", "html.elseIf").static(25).toString.trim
hello must be("fail!")
}
}
"compile successfully (if without brackets)" in {
val helper = newCompilerHelper
- val hello = helper.compile[((String, String) => Html)]("ifWithoutBrackets.scala.html", "html.ifWithoutBrackets")
+ val hello = helper.compile[((String, String) => Html)]("ifWithoutBrackets.scala.html", "html.ifWithoutBrackets")
hello.static("twirl", "play").toString.trim must be("twirl-play")
hello.static("twirl", "something-else").toString.trim must be("twirl")
}
"compile successfully (complex if without brackets)" in {
val helper = newCompilerHelper
- val hello = helper.compile[((String, String) => Html)]("ifWithoutBracketsComplex.scala.html", "html.ifWithoutBracketsComplex")
+ 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("""""")
}
"compile successfully (block with tuple)" in {
val helper = newCompilerHelper
- val hello = helper.compile[(Seq[(String, String)] => Html)]("blockWithTuple.scala.html", "html.blockWithTuple")
+ val hello = helper.compile[(Seq[(String, String)] => Html)]("blockWithTuple.scala.html", "html.blockWithTuple")
val args = Seq[(String, String)](
"the-key" -> "the-value"
@@ -243,7 +285,8 @@ class CompilerSpec extends WordSpec with MustMatchers {
"compile successfully (block with nested tuples)" in {
val helper = newCompilerHelper
- val hello = helper.compile[(Seq[(String, String)] => Html)]("blockWithNestedTuple.scala.html", "html.blockWithNestedTuple")
+ val hello =
+ helper.compile[(Seq[(String, String)] => Html)]("blockWithNestedTuple.scala.html", "html.blockWithNestedTuple")
val args = Seq[(String, String)](
"the-key" -> "the-value"
@@ -264,30 +307,43 @@ object Helper {
import scala.collection.mutable
import scala.reflect.internal.util.Position
import scala.tools.nsc.reporters.ConsoleReporter
- import scala.tools.nsc.{ Global, Settings }
+ import scala.tools.nsc.Global
+ import scala.tools.nsc.Settings
val twirlCompiler = TwirlCompiler
- val classloader = new URLClassLoader(Array(generatedClasses.toURI.toURL), Class.forName("play.twirl.compiler.TwirlCompiler").getClassLoader)
+ val classloader = new URLClassLoader(
+ Array(generatedClasses.toURI.toURL),
+ Class.forName("play.twirl.compiler.TwirlCompiler").getClassLoader
+ )
// A list of the compile errors from the most recent compiler run
val compileErrors = new mutable.ListBuffer[CompilationError]
val compiler = {
- def additionalClassPathEntry: Option[String] = Some(
- Class.forName("play.twirl.compiler.TwirlCompiler").getClassLoader.asInstanceOf[URLClassLoader].getURLs.map(url => new File(url.toURI)).mkString(":"))
-
- val settings = new Settings
+ def additionalClassPathEntry: Option[String] =
+ Some(
+ Class
+ .forName("play.twirl.compiler.TwirlCompiler")
+ .getClassLoader
+ .asInstanceOf[URLClassLoader]
+ .getURLs
+ .map(url => new File(url.toURI))
+ .mkString(":")
+ )
+
+ val settings = new Settings
val scalaObjectSource = Class.forName("scala.Option").getProtectionDomain.getCodeSource
// is null in Eclipse/OSGI but luckily we don't need it there
if (scalaObjectSource != null) {
- val compilerPath = Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource.getLocation
- val libPath = scalaObjectSource.getLocation
- val pathList = List(compilerPath, libPath)
+ val compilerPath = Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource.getLocation
+ val libPath = scalaObjectSource.getLocation
+ val pathList = List(compilerPath, libPath)
val origBootclasspath = settings.bootclasspath.value
- settings.bootclasspath.value = ((origBootclasspath :: pathList) ::: additionalClassPathEntry.toList) mkString File.pathSeparator
+ settings.bootclasspath.value =
+ ((origBootclasspath :: pathList) ::: additionalClassPathEntry.toList).mkString(File.pathSeparator)
settings.outdir.value = generatedClasses.getAbsolutePath
}
@@ -295,7 +351,7 @@ object Helper {
override def display(pos: Position, msg: String, severity: Severity): Unit = {
pos match {
case scala.reflect.internal.util.NoPosition => // do nothing
- case _ => compileErrors.append(CompilationError(msg, pos.line, pos.point))
+ case _ => compileErrors.append(CompilationError(msg, pos.line, pos.point))
}
}
})
@@ -316,15 +372,25 @@ object Helper {
def inject(constructorArgs: Any*): T = {
classloader.loadClass(className).getConstructors match {
case Array(single) => getF(single.newInstance(constructorArgs.asInstanceOf[Seq[AnyRef]]: _*))
- case other => throw new IllegalStateException(className + " does not declare exactly one constructor: " + other)
+ case other =>
+ throw new IllegalStateException(className + " does not declare exactly one constructor: " + other)
}
}
}
- def compile[T](templateName: String, className: String, additionalImports: Seq[String] = Nil): CompiledTemplate[T] = {
+ def compile[T](
+ templateName: String,
+ className: String,
+ additionalImports: Seq[String] = Nil
+ ): CompiledTemplate[T] = {
val templateFile = new File(sourceDir, templateName)
- val Some(generated) = twirlCompiler.compile(templateFile, sourceDir, generatedDir, "play.twirl.api.HtmlFormat",
- additionalImports = TwirlCompiler.DefaultImports ++ additionalImports)
+ val Some(generated) = twirlCompiler.compile(
+ templateFile,
+ sourceDir,
+ generatedDir,
+ "play.twirl.api.HtmlFormat",
+ additionalImports = TwirlCompiler.DefaultImports ++ additionalImports
+ )
val mapper = GeneratedSource(generated)
diff --git a/compiler/src/test/scala/play/twirl/compiler/test/TemplateUtilsSpec.scala b/compiler/src/test/scala/play/twirl/compiler/test/TemplateUtilsSpec.scala
index d8ddb829..f06b8782 100644
--- a/compiler/src/test/scala/play/twirl/compiler/test/TemplateUtilsSpec.scala
+++ b/compiler/src/test/scala/play/twirl/compiler/test/TemplateUtilsSpec.scala
@@ -4,7 +4,8 @@
package play.twirl.compiler
package test
-import org.scalatest.{ MustMatchers, WordSpec }
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
import play.twirl.api._
import scala.collection.immutable
@@ -26,9 +27,9 @@ class TemplateUtilsSpec extends WordSpec with MustMatchers {
}
object HtmlFormat extends Format[Html] {
- def raw(text: String) = Html(text)
- def escape(text: String) = Html(text.replace("<", "<"))
- def empty = Html("")
+ def raw(text: String) = Html(text)
+ def escape(text: String) = Html(text.replace("<", "<"))
+ def empty = Html("")
def fill(elements: immutable.Seq[Html]) = Html("")
}
@@ -44,9 +45,9 @@ class TemplateUtilsSpec extends WordSpec with MustMatchers {
}
object TextFormat extends Format[Text] {
- def raw(text: String) = Text(text)
- def escape(text: String) = Text(text)
- def empty = Text("")
+ def raw(text: String) = Text(text)
+ def escape(text: String) = Text(text)
+ def empty = Text("")
def fill(elements: immutable.Seq[Text]) = Text("")
}
diff --git a/compiler/src/test/scala/play/twirl/compiler/test/imports/bar/Default.scala b/compiler/src/test/scala/play/twirl/compiler/test/imports/bar/Default.scala
index 9adb1ca6..040f5273 100644
--- a/compiler/src/test/scala/play/twirl/compiler/test/imports/bar/Default.scala
+++ b/compiler/src/test/scala/play/twirl/compiler/test/imports/bar/Default.scala
@@ -4,4 +4,4 @@
package play.twirl.compiler.test.imports.bar
// Used to test import priorities
-object Default
\ No newline at end of file
+object Default
diff --git a/compiler/src/test/scala/play/twirl/compiler/test/imports/foo/Default.scala b/compiler/src/test/scala/play/twirl/compiler/test/imports/foo/Default.scala
index 066c9108..e3e47842 100644
--- a/compiler/src/test/scala/play/twirl/compiler/test/imports/foo/Default.scala
+++ b/compiler/src/test/scala/play/twirl/compiler/test/imports/foo/Default.scala
@@ -4,4 +4,4 @@
package play.twirl.compiler.test.imports.foo
// Used to test import priorities
-object Default
\ No newline at end of file
+object Default
diff --git a/docs/build.sbt b/docs/build.sbt
index 0a3ed71b..4517ef02 100644
--- a/docs/build.sbt
+++ b/docs/build.sbt
@@ -7,30 +7,34 @@ lazy val docs = project
// use special snapshot play version for now
resolvers ++= DefaultOptions.resolvers(snapshot = true),
resolvers += Resolver.typesafeRepo("releases"),
- libraryDependencies += component("play-test") % "test",
+ libraryDependencies += component("play-test") % "test",
libraryDependencies += component("play-specs2") % "test",
PlayDocsKeys.javaManualSourceDirectories := (baseDirectory.value / "manual" / "working" / "javaGuide" ** "code").get,
PlayDocsKeys.scalaManualSourceDirectories := (baseDirectory.value / "manual" / "working" / "scalaGuide" ** "code").get,
headerLicense := {
val currentYear = java.time.Year.now(java.time.Clock.systemUTC).getValue
- Some(HeaderLicense.Custom(
- s"Copyright (C) 2009-$currentYear Lightbend Inc. "
- ))
+ Some(
+ HeaderLicense.Custom(
+ s"Copyright (C) 2009-$currentYear Lightbend Inc. "
+ )
+ )
},
headerEmptyLine := false
- ).settings(overrideTwirlSettings: _*)
+ )
+ .settings(overrideTwirlSettings: _*)
.dependsOn(twirlApi)
// The changes in Twirl imports cause a problem with the PlayDocsPlugin, which defines its own twirl compile tasks
// and doesn't use the default imports provided by Twirl but defines its own by scratch, and since the defaults
// have changed, this breaks. So, first we need to set all source generators in test to Nil, then we can redefine the
// twirl settings.
-def overrideTwirlSettings: Seq[Setting[_]] = Seq(
- sourceGenerators in Test := Nil
-) ++ inConfig(Test)(SbtTwirl.twirlSettings) ++ SbtTwirl.defaultSettings ++ SbtTwirl.positionSettings ++ Seq(
- sourceDirectories in (Test, TwirlKeys.compileTemplates) ++=
- (PlayDocsKeys.javaManualSourceDirectories.value ++ PlayDocsKeys.scalaManualSourceDirectories.value)
-)
+def overrideTwirlSettings: Seq[Setting[_]] =
+ Seq(
+ sourceGenerators in Test := Nil
+ ) ++ inConfig(Test)(SbtTwirl.twirlSettings) ++ SbtTwirl.defaultSettings ++ SbtTwirl.positionSettings ++ Seq(
+ sourceDirectories in (Test, TwirlKeys.compileTemplates) ++=
+ (PlayDocsKeys.javaManualSourceDirectories.value ++ PlayDocsKeys.scalaManualSourceDirectories.value)
+ )
// the twirl plugin automatically adds this dependency, but this overrides it so
// it can be an interproject dependency, rather than requiring it to be published
diff --git a/docs/manual/working/scalaGuide/main/templates/code/ScalaTemplates.scala b/docs/manual/working/scalaGuide/main/templates/code/ScalaTemplates.scala
index 3289a976..d8953422 100644
--- a/docs/manual/working/scalaGuide/main/templates/code/ScalaTemplates.scala
+++ b/docs/manual/working/scalaGuide/main/templates/code/ScalaTemplates.scala
@@ -33,8 +33,7 @@ package html.utils {
object ScalaTemplatesSpec extends Specification {
val customer = Customer("mr customer")
- val orders = List(Order("foo"), Order("bar"))
-
+ val orders = List(Order("foo"), Order("bar"))
"Scala templates" should {
"support an example template" in {
@@ -57,7 +56,7 @@ object ScalaTemplatesSpec extends Specification {
import play.twirl.api.StringInterpolation
val name = "Martin"
- val p = html"Hello $name
"
+ val p = html"Hello $name
"
//#string-interpolation
p.body must_== "Hello Martin
"
@@ -100,13 +99,17 @@ object ScalaTemplatesSpec extends Specification {
"allow comments on the first line" in {
val body = html.firstLineComment("blah").body
body must contain("blah")
- body must not contain("Home page")
+ body must not contain ("Home page")
}
{
val body = html.snippets(Seq(Product("p1", "1"), Product("p2", "2")), User("John", "Doe"), Article("")).body
def segment(name: String) = {
- body.linesIterator.dropWhile(_ != "").drop(1).takeWhile(_ != "").mkString("\n")
+ body.linesIterator
+ .dropWhile(_ != "")
+ .drop(1)
+ .takeWhile(_ != "")
+ .mkString("\n")
}
"allow escaping the @ character" in {
@@ -140,7 +143,7 @@ object ScalaTemplatesSpec extends Specification {
}
"allow comments" in {
- body must not contain("This is a comment")
+ body must not contain ("This is a comment")
}
"allow intering raw HTML" in {
@@ -153,10 +156,10 @@ object ScalaTemplatesSpec extends Specification {
body must contain("User(Foo,Bar)")
body must contain("value inside option")
- body must not contain("Option(value inside option)")
+ body must not contain ("Option(value inside option)")
body must contain("firstlast")
- body must not contain("List")
+ body must not contain ("List")
body must contain("helloUser(Foo,Bar)value inside optionfirstlast")
}
}
-}
\ No newline at end of file
+}
diff --git a/docs/project/plugins.sbt b/docs/project/plugins.sbt
index 870c912c..0d9c95ed 100644
--- a/docs/project/plugins.sbt
+++ b/docs/project/plugins.sbt
@@ -5,5 +5,5 @@ lazy val sbtTwirl = ProjectRef(Path.fileProperty("user.dir").getParentFile, "plu
resolvers ++= DefaultOptions.resolvers(snapshot = true)
addSbtPlugin("com.typesafe.play" % "play-docs-sbt-plugin" % sys.props.getOrElse("play.version", "2.8.0-M3"))
-
-addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0")
\ No newline at end of file
+addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0")
+addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0")
diff --git a/parser/src/main/scala/play/twirl/parser/TreeNodes.scala b/parser/src/main/scala/play/twirl/parser/TreeNodes.scala
index ebcfff0b..bdbe938d 100644
--- a/parser/src/main/scala/play/twirl/parser/TreeNodes.scala
+++ b/parser/src/main/scala/play/twirl/parser/TreeNodes.scala
@@ -11,17 +11,28 @@ object TreeNodes {
case class Params(code: String) extends Positional
case class Constructor(comment: Option[Comment], params: PosString)
- case class Template(name: PosString, constructor: Option[Constructor], comment: Option[Comment], params: PosString, topImports: collection.Seq[Simple],
- imports: collection.Seq[Simple], defs: collection.Seq[Def], sub: collection.Seq[Template], content: collection.Seq[TemplateTree]) extends Positional
+ case class Template(
+ name: PosString,
+ constructor: Option[Constructor],
+ comment: Option[Comment],
+ params: PosString,
+ topImports: collection.Seq[Simple],
+ imports: collection.Seq[Simple],
+ defs: collection.Seq[Def],
+ sub: collection.Seq[Template],
+ content: collection.Seq[TemplateTree]
+ ) extends Positional
case class PosString(str: String) extends Positional {
override def toString: String = str
}
case class Def(name: PosString, params: PosString, code: Simple) extends Positional
- case class Plain(text: String) extends TemplateTree with Positional
- case class Display(exp: ScalaExp) extends TemplateTree with Positional
- case class Comment(msg: String) extends TemplateTree with Positional
- case class ScalaExp(parts: collection.Seq[ScalaExpPart]) extends TemplateTree with Positional
- case class Simple(code: String) extends ScalaExpPart with Positional
- case class Block(whitespace: String, args: Option[PosString], content: collection.Seq[TemplateTree]) extends ScalaExpPart with Positional
+ case class Plain(text: String) extends TemplateTree with Positional
+ case class Display(exp: ScalaExp) extends TemplateTree with Positional
+ case class Comment(msg: String) extends TemplateTree with Positional
+ case class ScalaExp(parts: collection.Seq[ScalaExpPart]) extends TemplateTree with Positional
+ case class Simple(code: String) extends ScalaExpPart with Positional
+ case class Block(whitespace: String, args: Option[PosString], content: collection.Seq[TemplateTree])
+ extends ScalaExpPart
+ with Positional
case class Value(ident: PosString, block: Block) extends Positional
}
diff --git a/parser/src/main/scala/play/twirl/parser/TwirlIO.scala b/parser/src/main/scala/play/twirl/parser/TwirlIO.scala
index c12788dd..ba12aa8b 100644
--- a/parser/src/main/scala/play/twirl/parser/TwirlIO.scala
+++ b/parser/src/main/scala/play/twirl/parser/TwirlIO.scala
@@ -25,8 +25,8 @@ private[twirl] object TwirlIO {
*/
def readStream(stream: InputStream): Array[Byte] = {
val buffer = new Array[Byte](8192)
- var len = stream.read(buffer)
- val out = new ByteArrayOutputStream()
+ var len = stream.read(buffer)
+ val out = new ByteArrayOutputStream()
while (len != -1) {
out.write(buffer, 0, len)
len = stream.read(buffer)
diff --git a/parser/src/main/scala/play/twirl/parser/TwirlParser.scala b/parser/src/main/scala/play/twirl/parser/TwirlParser.scala
index ff5e5d00..663613e8 100644
--- a/parser/src/main/scala/play/twirl/parser/TwirlParser.scala
+++ b/parser/src/main/scala/play/twirl/parser/TwirlParser.scala
@@ -88,20 +88,19 @@ import scala.util.parsing.input.OffsetPosition
* - Missing blocks after case and match statements
* - Invalid ("alone") '@' symbols.
*/
-
class TwirlParser(val shouldParseInclusiveDot: Boolean) {
import play.twirl.parser.TreeNodes._
import scala.util.parsing.input.Positional
sealed abstract class ParseResult
- case class Success(template: Template, input: Input) extends ParseResult
+ case class Success(template: Template, input: Input) extends ParseResult
case class Error(template: Template, input: Input, errors: List[PosString]) extends ParseResult
case class Input() {
- private var offset_ = 0
- private var source_ = ""
- private var length_ = 1
+ private var offset_ = 0
+ private var source_ = ""
+ private var length_ = 1
val regressionStatistics = new collection.mutable.HashMap[String, (Int, Int)]
/** Peek at the current input. Does not check for EOF. */
@@ -137,7 +136,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
/** Backtrack to a known offset */
def regressTo(offset: Int): Unit = offset_ = offset
- def isPastEOF(len: Int): Boolean = (offset_ + len-1) >= length_
+ def isPastEOF(len: Int): Boolean = (offset_ + len - 1) >= length_
def isEOF: Boolean = isPastEOF(1)
@@ -158,7 +157,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
}
- private val input: Input = new Input
+ private val input: Input = new Input
private val errorStack: ListBuffer[PosString] = ListBuffer()
/**
@@ -197,7 +196,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
*/
def check(str: String): Boolean = {
val len = str.length
- if (!input.isPastEOF(len) && input.matches(str)){
+ if (!input.isPastEOF(len) && input.matches(str)) {
input.advance(len)
true
} else false
@@ -207,7 +206,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
errorStack += position(PosString(message), offset)
}
- /** Consume/Advance `length` characters, and return the consumed characters. Returns "" if at EOF. */
+ /** Consume/Advance `length` characters, and return the consumed characters. Returns "" if at EOF. */
def any(length: Int = 1): String = {
if (input.isEOF) {
error("Expected more input but found 'EOF'")
@@ -227,8 +226,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
*/
def anyUntil(stop: String, inclusive: Boolean): String = {
val sb = new StringBuilder
- while (!input.isPastEOF(stop.length) && !input.matches(stop))
- sb.append(any())
+ while (!input.isPastEOF(stop.length) && !input.matches(stop)) sb.append(any())
if (inclusive && !input.isPastEOF(stop.length))
sb.append(any(stop.length))
sb.toString()
@@ -242,8 +240,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
*/
def anyUntil(f: Char => Boolean, inclusive: Boolean): String = {
val sb = new StringBuilder
- while (!input.isEOF && !f(input()))
- sb.append(any())
+ while (!input.isEOF && !f(input())) sb.append(any())
if (inclusive && !input.isEOF)
sb.append(any())
sb.toString
@@ -263,7 +260,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def recursiveTag(prefix: String, suffix: String, allowStringLiterals: Boolean = false): String = {
if (check(prefix)) {
var stack = 1
- val sb = new StringBuffer
+ val sb = new StringBuffer
sb.append(prefix)
while (stack > 0) {
if (check(prefix)) {
@@ -278,7 +275,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
} else if (allowStringLiterals) {
stringLiteral("\"", "\\") match {
case null => sb.append(any())
- case s => sb.append(s)
+ case s => sb.append(s)
}
} else {
sb.append(any())
@@ -295,7 +292,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def stringLiteral(quote: String, escape: String): String = {
if (check(quote)) {
var within = true
- val sb = new StringBuffer
+ val sb = new StringBuffer
sb.append(quote)
while (within) {
if (check(quote)) { // end of string literal
@@ -320,8 +317,10 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
/** Match zero or more `parser` */
- def several[T, BufferType <: mutable.Buffer[T]](parser: () => T, provided: BufferType = null)(implicit manifest: Manifest[BufferType]): BufferType = {
- val ab = if (provided != null) provided else manifest.runtimeClass.newInstance().asInstanceOf[BufferType]
+ def several[T, BufferType <: mutable.Buffer[T]](parser: () => T, provided: BufferType = null)(
+ implicit manifest: Manifest[BufferType]
+ ): BufferType = {
+ val ab = if (provided != null) provided else manifest.runtimeClass.newInstance().asInstanceOf[BufferType]
var parsed = parser()
while (parsed != null) {
ab += parsed
@@ -349,8 +348,8 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
/**
- * Parse a comment.
- */
+ * Parse a comment.
+ */
def comment(): Comment = {
val pos = input.offset()
if (check("@*")) {
@@ -361,8 +360,8 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
/**
- * Parses comments and/or whitespace, ignoring both until the last comment is reached, and returning that (if found)
- */
+ * Parses comments and/or whitespace, ignoring both until the last comment is reached, and returning that (if found)
+ */
def lastComment(): Comment = {
@tailrec
def tryNext(last: Comment): Comment = {
@@ -380,14 +379,14 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def importExpression(): Simple = {
val p = input.offset()
if (check("@import "))
- position(Simple("import " + anyUntil("\n", inclusive = true).trim), p+1) // don't include position of @
+ position(Simple("import " + anyUntil("\n", inclusive = true).trim), p + 1) // don't include position of @
else null
}
def localDef(): Def = {
- var result: Def = null
+ var result: Def = null
val resetPosition = input.offset()
- val templDecl = templateDeclaration()
+ val templDecl = templateDeclaration()
if (templDecl != null) {
anyUntil(c => c != ' ' && c != '\t', inclusive = false)
if (check("=")) {
@@ -410,7 +409,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val p = input.offset()
brackets() match {
case null => null
- case b => position(Simple(b), p)
+ case b => position(Simple(b), p)
}
} else null
}
@@ -428,19 +427,23 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def opt1(): ListBuffer[TemplateTree] = {
val t =
comment() match {
- case null => scalaBlockDisplayed() match {
- case null => forExpression() match {
- case null => matchExpOrSafeExpOrExpr() match {
- case null => caseExpression() match {
- case null => plain()
+ case null =>
+ scalaBlockDisplayed() match {
+ case null =>
+ forExpression() match {
+ case null =>
+ matchExpOrSafeExpOrExpr() match {
+ case null =>
+ caseExpression() match {
+ case null => plain()
+ case x => x
+ }
+ case x => x
+ }
case x => x
}
- case x => x
- }
case x => x
}
- case x => x
- }
case x => x
}
if (t != null) ListBuffer(t)
@@ -453,7 +456,9 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
if (check("{")) {
var buffer = new ListBuffer[TemplateTree]
buffer += position(Plain("{"), lbracepos)
- for (m <- several[ListBuffer[TemplateTree], ListBuffer[ListBuffer[TemplateTree]]]{ () => mixed() })
+ for (m <- several[ListBuffer[TemplateTree], ListBuffer[ListBuffer[TemplateTree]]] { () =>
+ mixed()
+ })
buffer = buffer ++ m // creates a new object, but is constant in time, as opposed to buffer ++= m which is linear (proportional to size of m)
val rbracepos = input.offset()
if (check("}"))
@@ -466,7 +471,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
opt1() match {
case null => opt2()
- case x => x
+ case x => x
}
}
@@ -484,12 +489,12 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val noContainsOpenParenthesis = !result.contains("(")
val startsWithParenthesis = result.trim.startsWith("(") || result.trim.stripPrefix("case").trim.startsWith("(")
- val endsWithParenthesis = result.stripSuffix("=>").trim.endsWith(")")
+ val endsWithParenthesis = result.stripSuffix("=>").trim.endsWith(")")
noContainsOpenParenthesis || (startsWithParenthesis && endsWithParenthesis)
}
- val p = input.offset()
+ val p = input.offset()
val result = anyUntil("=>", inclusive = true)
if (result.endsWith("=>") && !result.contains("\n") && noCurlyBraces(result) && noOpeningParenthesis(result))
position(PosString(result), p)
@@ -501,11 +506,13 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def block(blockArgsAllowed: Boolean): Block = {
var result: Block = null
- val p = input.offset()
- val ws = whitespaceNoBreak()
+ val p = input.offset()
+ val ws = whitespaceNoBreak()
if (check("{")) {
- val blkArgs = if(blockArgsAllowed) Option(blockArgs()) else None
- val mixeds = several[ListBuffer[TemplateTree], ListBuffer[ListBuffer[TemplateTree]]] { () => mixed() }
+ val blkArgs = if (blockArgsAllowed) Option(blockArgs()) else None
+ val mixeds = several[ListBuffer[TemplateTree], ListBuffer[ListBuffer[TemplateTree]]] { () =>
+ mixed()
+ }
accept("}")
// TODO - not use flatten here (if it's a performance problem)
result = position(Block(ws, blkArgs, mixeds.flatten), p)
@@ -520,11 +527,11 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
var result: TemplateTree = null
val wspos = input.offset()
- val ws = whitespace()
- val p = input.offset()
+ val ws = whitespace()
+ val p = input.offset()
if (check("case ")) {
val pattern = position(Simple("case " + anyUntil("=>", inclusive = true)), p)
- val blk = block(blockArgsAllowed = true)
+ val blk = block(blockArgsAllowed = true)
if (blk != null) {
result = ScalaExp(ListBuffer(pattern, blk))
whitespace()
@@ -546,15 +553,15 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val result =
expression() match {
case null => safeExpression()
- case x => x
+ case x => x
}
if (result != null) {
val exprs = result.exp.parts.asInstanceOf[ListBuffer[ScalaExpPart]]
- val mpos = input.offset()
- val ws = whitespaceNoBreak()
+ val mpos = input.offset()
+ val ws = whitespaceNoBreak()
if (check("match")) {
- val m = position(Simple(ws + "match"), mpos)
+ val m = position(Simple(ws + "match"), mpos)
val blk = block(blockArgsAllowed = false)
if (blk != null) {
exprs.append(m)
@@ -573,13 +580,13 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def forExpression(): Display = {
var result: Display = null
- val p = input.offset()
+ val p = input.offset()
if (check("@for")) {
val parens = parentheses()
if (parens != null) {
val blk = block(blockArgsAllowed = true)
if (blk != null) {
- result = Display(ScalaExp(ListBuffer(position(Simple("for" + parens + " yield "), p+1), blk))) // don't include pos of @
+ result = Display(ScalaExp(ListBuffer(position(Simple("for" + parens + " yield "), p + 1), blk))) // don't include pos of @
}
}
}
@@ -605,9 +612,9 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
else if (!input.isEOF && input() != '@' && input() != '}' && input() != '{') any()
else null
}
- val p = input.offset()
+ val p = input.offset()
var result: Plain = null
- var part = single()
+ var part = single()
if (part != null) {
val sb = new StringBuffer
while (part != null) {
@@ -623,10 +630,12 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def expression(): Display = {
var result: Display = null
if (check("@")) {
- val pos = input.offset()
+ val pos = input.offset()
val code = methodCall()
if (code != null) {
- val parts = several[ScalaExpPart, ListBuffer[ScalaExpPart]] { () => expressionPart(blockArgsAllowed = true) }
+ val parts = several[ScalaExpPart, ListBuffer[ScalaExpPart]] { () =>
+ expressionPart(blockArgsAllowed = true)
+ }
parts.prepend(position(Simple(code), pos))
result = Display(ScalaExp(parts))
} else input.regressTo(pos - 1) // don't consume the @
@@ -639,15 +648,15 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val name = identifier()
if (name != null) {
val sb = new StringBuffer(name)
- sb.append(Option(squareBrackets()) getOrElse "")
- sb.append(Option(parentheses()) getOrElse "")
+ sb.append(Option(squareBrackets()).getOrElse(""))
+ sb.append(Option(parentheses()).getOrElse(""))
sb.toString
} else null
}
def expressionPart(blockArgsAllowed: Boolean): ScalaExpPart = {
def simpleParens() = {
- val p = input.offset()
+ val p = input.offset()
val parens = parentheses()
if (parens != null) position(Simple(parens), p)
else null
@@ -662,19 +671,23 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
chainedMethods() match {
- case null => block(blockArgsAllowed) match {
- case null => wsThenScalaBlockChained() match {
- case null => elseIfCall() match {
- case null => elseCall() match {
- case null =>simpleParens()
+ case null =>
+ block(blockArgsAllowed) match {
+ case null =>
+ wsThenScalaBlockChained() match {
+ case null =>
+ elseIfCall() match {
+ case null =>
+ elseCall() match {
+ case null => simpleParens()
+ case x => x
+ }
+ case x => x
+ }
case x => x
}
- case x => x
- }
case x => x
}
- case x => x
- }
case x => x
}
}
@@ -694,7 +707,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val sb = new StringBuffer(".")
// Simply alternate between matching a methodCall and a dot until one fails.
- var done = false
+ var done = false
var matchMethodCall = true // represent: "should I try to match a method call or a dot?
while (!done) {
if (matchMethodCall) {
@@ -717,20 +730,20 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
// We know we must start with a methodCall, so try to parse one.
// If it exceeds, enter a loop trying to parse a dot and methodcall in each iteration.
def exclusiveDot(): Simple = {
- val p = input.offset()
+ val p = input.offset()
var result: Simple = null
if (check(".")) {
val firstMethodCall = methodCall()
if (firstMethodCall != null) {
- val sb = new StringBuffer("." + firstMethodCall)
+ val sb = new StringBuffer("." + firstMethodCall)
var done = false
while (!done) {
- val reset = input.offset()
+ val reset = input.offset()
var nextLink: String = null
if (check(".")) {
methodCall() match {
case m: String => nextLink = m
- case _ =>
+ case _ =>
}
}
@@ -763,7 +776,9 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val p = input.offset()
if (check("else if")) {
whitespaceNoBreak()
- val args = several[String, ArrayBuffer[String]] { () => parentheses() }
+ val args = several[String, ArrayBuffer[String]] { () =>
+ parentheses()
+ }
position(Simple("else if" + args.mkString(",")), p)
} else {
input.regressTo(reset)
@@ -786,10 +801,10 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def template(): Template = {
var result: Template = null
- val resetPosition = input.offset()
- val templDecl = templateDeclaration()
+ val resetPosition = input.offset()
+ val templDecl = templateDeclaration()
if (templDecl != null) {
- anyUntil(c => c != ' ' && c != '\t', inclusive = false)
+ anyUntil(c => c != ' ' && c != '\t', inclusive = false)
if (check("=")) {
anyUntil(c => c != ' ' && c != '\t', inclusive = false)
if (check("{")) {
@@ -810,13 +825,15 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
val namepos = input.offset()
val name = identifier() match {
case null => null
- case id => position(PosString(id), namepos)
+ case id => position(PosString(id), namepos)
}
if (name != null) {
val paramspos = input.offset()
- val types = Option(squareBrackets()) getOrElse PosString("")
- val args = several[String, ArrayBuffer[String]] { () => parentheses() }
+ val types = Option(squareBrackets()).getOrElse(PosString(""))
+ val args = several[String, ArrayBuffer[String]] { () =>
+ parentheses()
+ }
val params = position(PosString(types.toString + args.mkString), paramspos)
if (params != null)
return (name, params)
@@ -826,11 +843,12 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
null
}
- def templateContent(): (collection.Seq[Simple], collection.Seq[Def], collection.Seq[Template], collection.Seq[TemplateTree]) = {
- val imports = new ArrayBuffer[Simple]
+ def templateContent()
+ : (collection.Seq[Simple], collection.Seq[Def], collection.Seq[Template], collection.Seq[TemplateTree]) = {
+ val imports = new ArrayBuffer[Simple]
val localDefs = new ArrayBuffer[Def]
val templates = new ArrayBuffer[Template]
- val mixeds = new ArrayBuffer[TemplateTree]
+ val mixeds = new ArrayBuffer[TemplateTree]
var done = false
while (!done) {
@@ -861,7 +879,7 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
def extraImports(): collection.Seq[Simple] = {
var resetPosition = input.offset()
- val imports = new ArrayBuffer[Simple]
+ val imports = new ArrayBuffer[Simple]
lastComment()
@@ -883,10 +901,12 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
/**
- * Parse the template arguments.
- */
+ * Parse the template arguments.
+ */
private def templateArgs(): String = {
- val result = several[String, ArrayBuffer[String]] { () => parentheses() }
+ val result = several[String, ArrayBuffer[String]] { () =>
+ parentheses()
+ }
if (result.nonEmpty)
result.mkString
else
@@ -894,12 +914,12 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
/**
- * Parse the template arguments, if they exist
- */
+ * Parse the template arguments, if they exist
+ */
private def maybeTemplateArgs(): Option[PosString] = {
if (check("@(")) {
input.regress(1)
- val p = input.offset()
+ val p = input.offset()
val args = templateArgs()
if (args != null) {
val result = position(PosString(args), p)
@@ -912,12 +932,12 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
}
/**
- * Parse the template arguments, if they exist
- */
+ * Parse the template arguments, if they exist
+ */
private def constructorArgs(): PosString = {
if (check("@this(")) {
input.regress(1)
- val p = input.offset()
+ val p = input.offset()
val args = templateArgs()
if (args != null) position(PosString(args), p)
else null
@@ -944,10 +964,20 @@ class TwirlParser(val shouldParseInclusiveDot: Boolean) {
(None, constructorComment)
}
}
- val args = maybeTemplateArgs()
+ val args = maybeTemplateArgs()
val (imports, localDefs, templates, mixeds) = templateContent()
- val template = Template(PosString(""), constructor, argsComment, args.getOrElse(PosString("()")), topImports, imports, localDefs, templates, mixeds)
+ val template = Template(
+ PosString(""),
+ constructor,
+ argsComment,
+ args.getOrElse(PosString("()")),
+ topImports,
+ imports,
+ localDefs,
+ templates,
+ mixeds
+ )
if (errorStack.isEmpty)
Success(template, input)
diff --git a/parser/src/test/scala/play/twirl/parser/test/ParserSpec.scala b/parser/src/test/scala/play/twirl/parser/test/ParserSpec.scala
index e3f645ec..3c2cdc7b 100644
--- a/parser/src/test/scala/play/twirl/parser/test/ParserSpec.scala
+++ b/parser/src/test/scala/play/twirl/parser/test/ParserSpec.scala
@@ -4,7 +4,9 @@
package play.twirl.parser
package test
-import org.scalatest.{Inside, MustMatchers, WordSpec}
+import org.scalatest.Inside
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
import play.twirl.parser.TreeNodes._
class ParserSpec extends WordSpec with MustMatchers with Inside {
@@ -70,23 +72,25 @@ class ParserSpec extends WordSpec with MustMatchers with Inside {
}
"elseIf.scala.html" in {
- val template = parseTemplate("elseIf.scala.html")
- val node = template.content(1)
+ val template = parseTemplate("elseIf.scala.html")
+ val node = template.content(1)
val expressions = node.asInstanceOf[Display].exp.parts
- expressions.head must be (Simple("if(input == 5)"))
+ expressions.head must be(Simple("if(input == 5)"))
expressions(1).asInstanceOf[Block]
- expressions(2) must be (Simple("else if(input == 6)"))
+ expressions(2) must be(Simple("else if(input == 6)"))
expressions(3).asInstanceOf[Block]
- expressions(4) must be (Simple("else if(input == 8)"))
+ expressions(4) must be(Simple("else if(input == 8)"))
expressions(5).asInstanceOf[Block]
- expressions(6) must be (Simple("else"))
+ expressions(6) must be(Simple("else"))
}
"imports.scala.html" in {
- parseTemplate("imports.scala.html").topImports must be (Seq(
- Simple("import java.io.File"),
- Simple("import java.net.URL")
- ))
+ parseTemplate("imports.scala.html").topImports must be(
+ Seq(
+ Simple("import java.io.File"),
+ Simple("import java.net.URL")
+ )
+ )
}
"case.scala.js" in {
@@ -94,48 +98,48 @@ class ParserSpec extends WordSpec with MustMatchers with Inside {
}
"import expressions" in {
- parseTemplateString("@import identifier").topImports must be (Seq(Simple("import identifier")))
+ parseTemplateString("@import identifier").topImports must be(Seq(Simple("import identifier")))
parseTemplateString("@importIdentifier").topImports mustBe empty
}
"code block containing => of another statement with curly braces in first line" in {
- val tmpl = parseTemplateString("""@if(attrs!=null){@attrs.map{ v => @v._1 }}""") // "@attrs.map{ v =>" should not be handled as block args
+ val tmpl = parseTemplateString("""@if(attrs!=null){@attrs.map{ v => @v._1 }}""") // "@attrs.map{ v =>" should not be handled as block args
val ifExpressions = tmpl.content(0).asInstanceOf[Display].exp.parts
- ifExpressions.head must be (Simple("if(attrs!=null)"))
+ ifExpressions.head must be(Simple("if(attrs!=null)"))
val ifBlockBody = ifExpressions(1).asInstanceOf[Block].content(0).asInstanceOf[Display].exp.parts
- ifBlockBody.head must be (Simple("attrs"))
- ifBlockBody(1) must be (Simple(".map"))
+ ifBlockBody.head must be(Simple("attrs"))
+ ifBlockBody(1) must be(Simple(".map"))
val mapBlock = ifBlockBody(2).asInstanceOf[Block]
mapBlock.args.map(_.toString) mustBe Some(" v =>")
val mapBlockBody = ifBlockBody(2).asInstanceOf[Block].content(1).asInstanceOf[Display].exp.parts
- mapBlockBody.head must be (Simple("v"))
- mapBlockBody(1) must be (Simple("._1"))
+ mapBlockBody.head must be(Simple("v"))
+ mapBlockBody(1) must be(Simple("._1"))
}
"code block containing => of another statement with parentheses in first line" in {
- val tmpl = parseTemplateString("""@if(attrs!=null){@attrs.map( v => @v._1 )}""") // "@attrs.map( v =>" should not be handled as block args
+ val tmpl = parseTemplateString("""@if(attrs!=null){@attrs.map( v => @v._1 )}""") // "@attrs.map( v =>" should not be handled as block args
val ifExpressions = tmpl.content(0).asInstanceOf[Display].exp.parts
- ifExpressions.head must be (Simple("if(attrs!=null)"))
+ ifExpressions.head must be(Simple("if(attrs!=null)"))
val ifBlockBody = ifExpressions(1).asInstanceOf[Block].content(0).asInstanceOf[Display].exp.parts
- ifBlockBody.head must be (Simple("attrs"))
- ifBlockBody(1) must be (Simple(".map( v => @v._1 )"))
+ ifBlockBody.head must be(Simple("attrs"))
+ ifBlockBody(1) must be(Simple(".map( v => @v._1 )"))
}
"code block containing (...) => in first line" in {
- val tmpl = parseTemplateString("""@if(attrs!=null){( arg1, arg2 ) => @arg1.toString }""") // "( arg1, arg2 ) =>" should be handled as block args
+ val tmpl = parseTemplateString("""@if(attrs!=null){( arg1, arg2 ) => @arg1.toString }""") // "( arg1, arg2 ) =>" should be handled as block args
val ifExpressions = tmpl.content(0).asInstanceOf[Display].exp.parts
- ifExpressions.head must be (Simple("if(attrs!=null)"))
+ ifExpressions.head must be(Simple("if(attrs!=null)"))
val ifBlock = ifExpressions(1).asInstanceOf[Block]
ifBlock.args.map(_.toString) mustBe Some("( arg1, arg2 ) =>")
val ifBlockBody = ifBlock.content(1).asInstanceOf[Display].exp.parts
- ifBlockBody.head must be (Simple("arg1"))
- ifBlockBody(1) must be (Simple(".toString"))
+ ifBlockBody.head must be(Simple("arg1"))
+ ifBlockBody(1) must be(Simple(".toString"))
}
"text outside of code block on same line containing =>" in {
- val tmpl = parseTemplateString("""@if(attrs!=null){blockbody}Some plain text with => inside""") // "blockbody}Some plain text with =>" should not be handled as block args
+ val tmpl = parseTemplateString("""@if(attrs!=null){blockbody}Some plain text with => inside""") // "blockbody}Some plain text with =>" should not be handled as block args
val ifExpressions = tmpl.content(0).asInstanceOf[Display].exp.parts
- ifExpressions.head must be (Simple("if(attrs!=null)"))
+ ifExpressions.head must be(Simple("if(attrs!=null)"))
val ifBlockBody = ifExpressions(1).asInstanceOf[Block].content(0).asInstanceOf[Plain]
ifBlockBody.text mustBe "blockbody"
val outsideIf = tmpl.content(1).asInstanceOf[Plain]
@@ -143,20 +147,22 @@ class ParserSpec extends WordSpec with MustMatchers with Inside {
}
"match statement not allowed to have block arguments" in {
- val tmpl = parseTemplateString("""@fooVariable match { case x: String => { Nice string } case _ => { Not a nice string } }""") // " case x: String =>" should not be handled as block args of the match block
+ val tmpl = parseTemplateString(
+ """@fooVariable match { case x: String => { Nice string } case _ => { Not a nice string } }"""
+ ) // " case x: String =>" should not be handled as block args of the match block
val matchExpressions = tmpl.content(0).asInstanceOf[Display].exp.parts
- matchExpressions.head must be (Simple("fooVariable"))
- matchExpressions(1) must be (Simple(" match"))
+ matchExpressions.head must be(Simple("fooVariable"))
+ matchExpressions(1) must be(Simple(" match"))
val matchBlock = matchExpressions(2).asInstanceOf[Block].content
val firstCaseBlock = matchBlock.head.asInstanceOf[ScalaExp].parts
- firstCaseBlock.head must be (Simple("case x: String =>"))
+ firstCaseBlock.head must be(Simple("case x: String =>"))
val firstCaseBlockBody = firstCaseBlock(1).asInstanceOf[Block]
firstCaseBlockBody.content(1).asInstanceOf[Plain].text mustBe "Nice string "
val secondCaseBlock = matchBlock(1).asInstanceOf[ScalaExp].parts
- secondCaseBlock.head must be (Simple("case _ =>"))
+ secondCaseBlock.head must be(Simple("case _ =>"))
val secondCaseBlockBody = secondCaseBlock(1).asInstanceOf[Block]
secondCaseBlockBody.content(1).asInstanceOf[Plain].text mustBe "Not a nice string "
}
@@ -197,4 +203,3 @@ class ParserSpec extends WordSpec with MustMatchers with Inside {
}
}
-
diff --git a/project/plugins.sbt b/project/plugins.sbt
index b4a1370a..9f67a8ab 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -5,5 +5,6 @@ addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.6.1")
-addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.5.0")
-addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0")
+addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.5.0")
+addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0")
+addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0")
diff --git a/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/SbtTwirlCompat.scala b/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/SbtTwirlCompat.scala
index be6962bf..453a7822 100644
--- a/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/SbtTwirlCompat.scala
+++ b/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/SbtTwirlCompat.scala
@@ -8,7 +8,7 @@ import sbt.Keys._
import play.twirl.sbt.Import.TwirlKeys._
object SbtTwirlCompat {
- def watchSourcesSettings: Seq[Setting[_]] = Seq(
+ def watchSourcesSettings: Seq[Setting[_]] = Seq(
watchSources in Defaults.ConfigGlobal +=
WatchSource(
(sourceDirectory in compileTemplates).value,
diff --git a/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateCompilerErrorHandler.scala b/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateCompilerErrorHandler.scala
index 0a129199..2ee7e27d 100644
--- a/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateCompilerErrorHandler.scala
+++ b/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateCompilerErrorHandler.scala
@@ -14,8 +14,10 @@ trait TemplateCompilerErrorHandler {
def handleError(log: Logger, codec: Codec): PartialFunction[Throwable, Nothing] = {
case TemplateCompilationError(source, message, line, column) =>
val exception = TemplateProblem.exception(source, codec, message, line, column)
- val reporter = new LoggedReporter(10, log)
- exception.problems foreach { p => reporter.log(p) }
+ val reporter = new LoggedReporter(10, log)
+ exception.problems.foreach { p =>
+ reporter.log(p)
+ }
throw exception
case e => throw e
}
diff --git a/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateProblem.scala b/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateProblem.scala
index 375676dd..4efd4be1 100644
--- a/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateProblem.scala
+++ b/sbt-twirl/src/main/scala-sbt-1.0/play/twirl/sbt/TemplateProblem.scala
@@ -3,34 +3,38 @@
*/
package play.twirl.sbt
-import play.twirl.compiler.{ GeneratedSource, MaybeGeneratedSource }
+import play.twirl.compiler.GeneratedSource
+import play.twirl.compiler.MaybeGeneratedSource
import play.twirl.parser.TwirlIO
import sbt._
-import xsbti.{ CompileFailed, Position, Problem, Severity }
+import xsbti.CompileFailed
+import xsbti.Position
+import xsbti.Problem
+import xsbti.Severity
import scala.io.Codec
object TemplateProblem {
def positionMapper(codec: Codec): Position => Option[Position] = position => {
- toScala(position.sourceFile).flatMap(f => MaybeGeneratedSource(f, codec)) map {
- generated => TemplatePosition(generated, position)
+ toScala(position.sourceFile).flatMap(f => MaybeGeneratedSource(f, codec)).map { generated =>
+ TemplatePosition(generated, position)
}
}
def exception(source: File, codec: Codec, message: String, line: Int, column: Int) = {
- val column0 = 0 max (column - 1) // convert to 0-based column
+ val column0 = 0.max(column - 1) // convert to 0-based column
new ProblemException(TemplateProblem(message, TemplatePosition(source, codec, line, column0)))
}
class ProblemException(issues: Problem*) extends CompileFailed with FeedbackProvidedException {
def arguments(): Array[String] = Array.empty
def problems(): Array[Problem] = issues.toArray
- override def toString = "Twirl compilation failed"
+ override def toString = "Twirl compilation failed"
}
case class TemplateProblem(message: String, position: Position) extends Problem {
- def category: String = "undefined"
+ def category: String = "undefined"
def severity: Severity = Severity.Error
}
@@ -41,28 +45,34 @@ object TemplateProblem {
}
def apply(generated: GeneratedSource, position: Position): TemplatePosition = {
- val offset = toScala(position.offset) map { o => generated.mapPosition(o) }
- val location = offset flatMap { o => TemplateMapping(generated.source, generated.codec).location(o) }
+ val offset = toScala(position.offset).map { o =>
+ generated.mapPosition(o)
+ }
+ val location = offset.flatMap { o =>
+ TemplateMapping(generated.source, generated.codec).location(o)
+ }
new TemplatePosition(generated.source, location)
}
}
class TemplatePosition(source: Option[File], location: Option[TemplateMapping.Location]) extends Position {
- val line: java.util.Optional[Integer] = toJava { location map (_.line) }
+ val line: java.util.Optional[Integer] = toJava { location.map(_.line) }
val lineContent: String = location.fold("")(_.content)
- val offset: java.util.Optional[Integer] = toJava { location map (_.offset) }
+ val offset: java.util.Optional[Integer] = toJava { location.map(_.offset) }
- val pointer: java.util.Optional[Integer] = toJava { location map (_.column) }
+ val pointer: java.util.Optional[Integer] = toJava { location.map(_.column) }
val pointerSpace: java.util.Optional[String] = toJava {
- location.map { l => lineContent.take(l.column) map { case '\t' => '\t'; case _ => ' ' } }
+ location.map { l =>
+ lineContent.take(l.column).map { case '\t' => '\t'; case _ => ' ' }
+ }
}
val sourceFile: java.util.Optional[File] = toJava(source)
- val sourcePath: java.util.Optional[String] = toJava { source map (_.getCanonicalPath) }
+ val sourcePath: java.util.Optional[String] = toJava { source.map(_.getCanonicalPath) }
override def toString: String = {
val stringBuilder = new StringBuilder
@@ -85,21 +95,21 @@ object TemplateProblem {
} else if (l > line) {
Location(line, content.length, end, content)
} else {
- val column = 0 max c min content.length
+ val column = 0.max(c).min(content.length)
val offset = start + column
Location(line, column, offset, content)
}
}
def location(o: Int): Location = {
- val offset = start max o min end
+ val offset = start.max(o).min(end)
val column = offset - start
Location(line, column, offset, content)
}
}
def apply(source: Option[File], codec: Codec): TemplateMapping = {
- val lines = source.toSeq flatMap { file =>
+ val lines = source.toSeq.flatMap { file =>
TwirlIO.readFileAsString(file, codec.charSet).stripSuffix("\n").split("\n")
}
TemplateMapping(lines)
@@ -107,17 +117,20 @@ object TemplateProblem {
}
case class TemplateMapping(sourceLines: Seq[String]) {
- import TemplateMapping.{Line, Location}
+ import TemplateMapping.Line
+ import TemplateMapping.Location
- val lines: Seq[Line] = sourceLines.scanLeft(Line(0, -1, -1, "")) { (previous, content) =>
- Line(previous.line + 1, previous.end + 1, previous.end + 1 + content.length, content.stripSuffix("\r"))
- }.drop(1)
+ val lines: Seq[Line] = sourceLines
+ .scanLeft(Line(0, -1, -1, "")) { (previous, content) =>
+ Line(previous.line + 1, previous.end + 1, previous.end + 1 + content.length, content.stripSuffix("\r"))
+ }
+ .drop(1)
def location(offset: Int): Option[Location] = {
if (lines.isEmpty) {
None
} else {
- val index = 0 max lines.lastIndexWhere(_.start <= offset)
+ val index = 0.max(lines.lastIndexWhere(_.start <= offset))
Some(lines(index).location(offset))
}
}
@@ -126,7 +139,7 @@ object TemplateProblem {
if (lines.isEmpty) {
None
} else {
- val index = 0 max (line - 1) min (lines.length - 1)
+ val index = 0.max(line - 1).min(lines.length - 1)
Some(lines(index).location(line, column))
}
}
@@ -134,7 +147,7 @@ object TemplateProblem {
def toJava[A](o: Option[A]): java.util.Optional[A] = o match {
case Some(v) => java.util.Optional.ofNullable(v)
- case None => java.util.Optional.empty()
+ case None => java.util.Optional.empty()
}
def toScala[A](o: java.util.Optional[A]): Option[A] = {
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 265ceaa4..af1df5cb 100644
--- a/sbt-twirl/src/main/scala/play/twirl/sbt/SbtTwirl.scala
+++ b/sbt-twirl/src/main/scala/play/twirl/sbt/SbtTwirl.scala
@@ -11,14 +11,19 @@ import scala.io.Codec
object Import {
object TwirlKeys {
- val twirlVersion = SettingKey[String]("twirl-version", "Twirl version used for twirl-api dependency")
+ val twirlVersion = SettingKey[String]("twirl-version", "Twirl version used for twirl-api dependency")
val templateFormats = SettingKey[Map[String, String]]("twirl-template-formats", "Defined twirl template formats")
val templateImports = SettingKey[Seq[String]]("twirl-template-imports", "Extra imports for twirl templates")
- val constructorAnnotations = SettingKey[Seq[String]]("twirl-constructor-annotations", "Annotations added to constructors in injectable templates")
+ val constructorAnnotations = SettingKey[Seq[String]](
+ "twirl-constructor-annotations",
+ "Annotations added to constructors in injectable templates"
+ )
@deprecated("No longer supported", "1.2.0")
val useOldParser = SettingKey[Boolean]("twirl-use-old-parser", "No longer supported")
- val sourceEncoding = TaskKey[String]("twirl-source-encoding", "Source encoding for template files and generated scala files")
- val compileTemplates = TaskKey[Seq[File]]("twirl-compile-templates", "Compile twirl templates into scala source files")
+ val sourceEncoding =
+ TaskKey[String]("twirl-source-encoding", "Source encoding for template files and generated scala files")
+ val compileTemplates =
+ TaskKey[Seq[File]]("twirl-compile-templates", "Compile twirl templates into scala source files")
}
}
@@ -34,26 +39,24 @@ object SbtTwirl extends AutoPlugin {
override def projectSettings: Seq[Setting[_]] =
inConfig(Compile)(twirlSettings) ++
- inConfig(Test)(twirlSettings) ++
- defaultSettings ++
- positionSettings ++
- dependencySettings
+ inConfig(Test)(twirlSettings) ++
+ defaultSettings ++
+ positionSettings ++
+ dependencySettings
def twirlSettings: Seq[Setting[_]] = SbtTwirlCompat.watchSourcesSettings ++ Seq(
includeFilter in compileTemplates := "*.scala.*",
excludeFilter in compileTemplates := HiddenFileFilter,
sourceDirectories in compileTemplates := Seq(sourceDirectory.value / "twirl"),
-
- sources in compileTemplates := Defaults.collectFiles(
- sourceDirectories in compileTemplates,
- includeFilter in compileTemplates,
- excludeFilter in compileTemplates
- ).value,
-
+ sources in compileTemplates := Defaults
+ .collectFiles(
+ sourceDirectories in compileTemplates,
+ includeFilter in compileTemplates,
+ excludeFilter in compileTemplates
+ )
+ .value,
target in compileTemplates := crossTarget.value / "twirl" / Defaults.nameForSrc(configuration.value.name),
-
compileTemplates := compileTemplatesTask.value,
-
sourceGenerators += compileTemplates.taskValue,
managedSourceDirectories += (target in compileTemplates).value
)
@@ -75,11 +78,11 @@ object SbtTwirl extends AutoPlugin {
val crossVer = crossVersion.value
val isScalaJS = CrossVersion(crossVer, scalaVersion.value, scalaBinaryVersion.value) match {
case Some(f) => f("").contains("_sjs0.6") // detect ScalaJS CrossVersion
- case None => false
+ case None => false
}
// TODO: use %%% from sbt-crossproject when we add support for scalajs 1.0
val baseModuleID = "com.typesafe.play" %% "twirl-api" % twirlVersion.value
- if (isScalaJS) baseModuleID cross crossVer else baseModuleID
+ if (isScalaJS) baseModuleID.cross(crossVer) else baseModuleID
}
)
@@ -90,9 +93,9 @@ object SbtTwirl extends AutoPlugin {
def defaultFormats = Map(
"html" -> "play.twirl.api.HtmlFormat",
- "txt" -> "play.twirl.api.TxtFormat",
- "xml" -> "play.twirl.api.XmlFormat",
- "js" -> "play.twirl.api.JavaScriptFormat"
+ "txt" -> "play.twirl.api.TxtFormat",
+ "xml" -> "play.twirl.api.XmlFormat",
+ "js" -> "play.twirl.api.JavaScriptFormat"
)
def compileTemplatesTask = Def.task {
@@ -110,15 +113,13 @@ object SbtTwirl extends AutoPlugin {
}
def readResourceProperty(resource: String, property: String): String = {
- val props = new java.util.Properties
+ val props = new java.util.Properties
val stream = getClass.getClassLoader.getResourceAsStream(resource)
try {
props.load(stream)
- }
- catch {
+ } catch {
case e: Exception =>
- }
- finally {
+ } finally {
if (stream ne null) stream.close
}
props.getProperty(property)
diff --git a/sbt-twirl/src/main/scala/play/twirl/sbt/TemplateCompiler.scala b/sbt-twirl/src/main/scala/play/twirl/sbt/TemplateCompiler.scala
index bfbca4c5..33ec45dc 100644
--- a/sbt-twirl/src/main/scala/play/twirl/sbt/TemplateCompiler.scala
+++ b/sbt-twirl/src/main/scala/play/twirl/sbt/TemplateCompiler.scala
@@ -10,36 +10,55 @@ import scala.io.Codec
object TemplateCompiler extends TemplateCompilerErrorHandler {
@deprecated("Use other compile method", "1.2.0")
def compile(
- sourceDirectories: Seq[File],
- targetDirectory: File,
- templateFormats: Map[String, String],
- templateImports: Seq[String],
- includeFilter: FileFilter,
- excludeFilter: FileFilter,
- codec: Codec,
- useOldParser: Boolean,
- log: Logger): Seq[File] =
- compile(sourceDirectories, targetDirectory, templateFormats, templateImports, Nil, includeFilter, excludeFilter,
- codec, log)
+ sourceDirectories: Seq[File],
+ targetDirectory: File,
+ templateFormats: Map[String, String],
+ templateImports: Seq[String],
+ includeFilter: FileFilter,
+ excludeFilter: FileFilter,
+ codec: Codec,
+ useOldParser: Boolean,
+ log: Logger
+ ): Seq[File] =
+ compile(
+ sourceDirectories,
+ targetDirectory,
+ templateFormats,
+ templateImports,
+ Nil,
+ includeFilter,
+ excludeFilter,
+ codec,
+ log
+ )
def compile(
- sourceDirectories: Seq[File],
- targetDirectory: File,
- templateFormats: Map[String, String],
- templateImports: Seq[String],
- constructorAnnotations: Seq[String],
- includeFilter: FileFilter,
- excludeFilter: FileFilter,
- codec: Codec,
- log: Logger): Seq[File] = {
+ sourceDirectories: Seq[File],
+ targetDirectory: File,
+ templateFormats: Map[String, String],
+ templateImports: Seq[String],
+ constructorAnnotations: Seq[String],
+ includeFilter: FileFilter,
+ excludeFilter: FileFilter,
+ codec: Codec,
+ log: Logger
+ ): Seq[File] = {
try {
syncGenerated(targetDirectory, codec)
val templates = collectTemplates(sourceDirectories, templateFormats, includeFilter, excludeFilter)
for ((template, sourceDirectory, extension, format) <- templates) {
val imports = formatImports(templateImports, extension)
- TwirlCompiler.compile(template, sourceDirectory, targetDirectory, format, imports, constructorAnnotations,
- codec, inclusiveDot = false)
+ TwirlCompiler.compile(
+ template,
+ sourceDirectory,
+ targetDirectory,
+ format,
+ imports,
+ constructorAnnotations,
+ codec,
+ inclusiveDot = false
+ )
}
generatedFiles(targetDirectory).map(_.getAbsoluteFile)
} catch handleError(log, codec)
@@ -53,9 +72,14 @@ object TemplateCompiler extends TemplateCompilerErrorHandler {
generatedFiles(targetDirectory).map(GeneratedSource(_, codec)).foreach(_.sync)
}
- def collectTemplates(sourceDirectories: Seq[File], templateFormats: Map[String, String], includeFilter: FileFilter, excludeFilter: FileFilter): Seq[(File, File, String, String)] = {
- sourceDirectories flatMap { sourceDirectory =>
- (sourceDirectory ** includeFilter).get flatMap { file =>
+ def collectTemplates(
+ sourceDirectories: Seq[File],
+ templateFormats: Map[String, String],
+ includeFilter: FileFilter,
+ excludeFilter: FileFilter
+ ): Seq[(File, File, String, String)] = {
+ sourceDirectories.flatMap { sourceDirectory =>
+ (sourceDirectory ** includeFilter).get.flatMap { file =>
val ext = file.name.split('.').last
if (!excludeFilter.accept(file) && templateFormats.contains(ext))
Some((file, sourceDirectory, ext, templateFormats(ext)))
diff --git a/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplateMappingSpec.scala b/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplateMappingSpec.scala
index 1ac396cb..bdfa91a6 100644
--- a/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplateMappingSpec.scala
+++ b/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplateMappingSpec.scala
@@ -4,7 +4,9 @@
package play.twirl.sbt
package test
-import org.scalatest.{ Inspectors, MustMatchers, WordSpec }
+import org.scalatest.Inspectors
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
import play.twirl.sbt.TemplateProblem.TemplateMapping
import play.twirl.sbt.TemplateProblem.TemplateMapping.Location
@@ -33,7 +35,7 @@ class TemplateMappingSpec extends WordSpec with MustMatchers with Inspectors {
Location(4, 1, 7, "d")
)
- forAll (testLocations) { location =>
+ forAll(testLocations) { location =>
mapping.location(location.offset) mustBe Some(location)
mapping.location(location.line, location.column) mustBe Some(location)
}
@@ -47,8 +49,9 @@ class TemplateMappingSpec extends WordSpec with MustMatchers with Inspectors {
10 -> Location(4, 1, 7, "d")
)
- forAll(testOffsets) { case (offset, location) =>
- mapping.location(offset) mustBe Some(location)
+ forAll(testOffsets) {
+ case (offset, location) =>
+ mapping.location(offset) mustBe Some(location)
}
val testPositions = Seq(
@@ -61,8 +64,9 @@ class TemplateMappingSpec extends WordSpec with MustMatchers with Inspectors {
(5, 0) -> Location(4, 1, 7, "d")
)
- forAll(testPositions) { case ((line, column), location) =>
- mapping.location(line, column) mustBe Some(location)
+ forAll(testPositions) {
+ case ((line, column), location) =>
+ mapping.location(line, column) mustBe Some(location)
}
}
}
diff --git a/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplatePositionSpec.scala b/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplatePositionSpec.scala
index e8f3aad0..ce5585db 100644
--- a/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplatePositionSpec.scala
+++ b/sbt-twirl/src/test/scala/play/twirl/sbt/test/TemplatePositionSpec.scala
@@ -5,8 +5,11 @@ package play.twirl.sbt.test
import java.io.File
-import play.twirl.sbt.TemplateProblem.{TemplateMapping, TemplatePosition}
-import org.scalatest.{Inspectors, MustMatchers, WordSpec}
+import play.twirl.sbt.TemplateProblem.TemplateMapping
+import play.twirl.sbt.TemplateProblem.TemplatePosition
+import org.scalatest.Inspectors
+import org.scalatest.MustMatchers
+import org.scalatest.WordSpec
class TemplatePositionSpec extends WordSpec with MustMatchers with Inspectors {
@@ -15,54 +18,54 @@ class TemplatePositionSpec extends WordSpec with MustMatchers with Inspectors {
"toString" should {
"have the source path" in {
- val file = new File("/some/path/file.scala.html")
+ val file = new File("/some/path/file.scala.html")
val location = TemplateMapping.Location(line = 10, column = 2, offset = 22, content = "some content")
- val tp = new TemplatePosition(Option(file), Option(location))
+ val tp = new TemplatePosition(Option(file), Option(location))
tp.toString mustBe "/some/path/file.scala.html:10\nsome content"
}
"not have the source path when it is empty" in {
val location = TemplateMapping.Location(line = 10, column = 2, offset = 22, content = "some content")
- val tp = new TemplatePosition(None, Option(location))
+ val tp = new TemplatePosition(None, Option(location))
tp.toString mustNot include("/some/path/file.scala.html")
}
"have line if present" in {
- val file = new File("/some/path/file.scala.html")
+ val file = new File("/some/path/file.scala.html")
val location = TemplateMapping.Location(line = 10, column = 2, offset = 22, content = "some content")
- val tp = new TemplatePosition(Option(file), Option(location))
+ val tp = new TemplatePosition(Option(file), Option(location))
tp.toString must include("10")
}
"not have line when it is empty" in {
val file = new File("/some/path/file.scala.html")
- val tp = new TemplatePosition(Option(file), None /* means no location for the error, then no line */)
+ val tp = new TemplatePosition(Option(file), None /* means no location for the error, then no line */ )
tp.toString mustBe "/some/path/file.scala.html"
}
"have line content if present" in {
- val file = new File("/some/path/file.scala.html")
+ val file = new File("/some/path/file.scala.html")
val location = TemplateMapping.Location(line = 10, column = 2, offset = 22, content = "some content")
- val tp = new TemplatePosition(Option(file), Option(location))
+ val tp = new TemplatePosition(Option(file), Option(location))
tp.toString must include("some content")
}
"not have line content when it is missing" in {
val file = new File("/some/path/file.scala.html")
- val tp = new TemplatePosition(Option(file), None /* means no location for the error, then no offset */)
+ val tp = new TemplatePosition(Option(file), None /* means no location for the error, then no offset */ )
tp.toString mustBe "/some/path/file.scala.html"
}
"not have line content when it is empty" in {
- val file = new File("/some/path/file.scala.html")
+ val file = new File("/some/path/file.scala.html")
val location = TemplateMapping.Location(line = 10, column = 2, offset = 22, content = "")
- val tp = new TemplatePosition(Option(file), Option(location))
+ val tp = new TemplatePosition(Option(file), Option(location))
tp.toString mustBe "/some/path/file.scala.html:10"
}
diff --git a/scripts/test-code.sh b/scripts/test-code.sh
new file mode 100755
index 00000000..f24fdb53
--- /dev/null
+++ b/scripts/test-code.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+sbt "++ $TRAVIS_SCALA_VERSION test" || travis_terminate 1
+sbt +publishLocal plugin/test plugin/scripted || travis_terminate 1
\ No newline at end of file
diff --git a/scripts/validate-code.sh b/scripts/validate-code.sh
index 749773d9..49e47eec 100755
--- a/scripts/validate-code.sh
+++ b/scripts/validate-code.sh
@@ -1,5 +1,4 @@
#!/usr/bin/env bash
-sbt ++$TRAVIS_SCALA_VERSION validateCode || travis_terminate 1
-sbt "++ $TRAVIS_SCALA_VERSION test" || travis_terminate 1
-sbt +publishLocal plugin/test plugin/scripted || travis_terminate 1
\ No newline at end of file
+sbt ++$TRAVIS_SCALA_VERSION validateCode || travis_terminate 1
+sbt "++$TRAVIS_SCALA_VERSION mimaReportBinaryIssues" || travis_terminate 1