Skip to content
Permalink
Browse files

Began work on new TemplateGenerator tool to allow generation of Scala…

… code at compile time based on an existing HTML template
  • Loading branch information
darkfrog26 committed Feb 5, 2020
1 parent 420e335 commit 6e7b4d19d9424bc8414764490b8165ce3f1bc5f9
@@ -140,7 +140,11 @@ lazy val spatialJVM = spatial.jvm

lazy val stream = project.in(file("stream"))
.settings(
name := "youi-stream"
name := "youi-stream",
libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest" % scalaTestVersion % "test",
"org.scalacheck" %%% "scalacheck" % scalaCheckVersion % "test"
)
)
.dependsOn(coreJVM)

@@ -2,4 +2,5 @@ package io.youi.stream

case class CachedInformation(byId: Map[String, Tag.Open],
byClass: Map[String, Set[Tag.Open]],
byTag: Map[String, Set[Tag.Open]])
byTag: Map[String, Set[Tag.Open]],
byAttribute: Map[String, Set[Tag.Open]])
@@ -5,7 +5,6 @@ import java.net.URL
import java.util.concurrent.ConcurrentHashMap

import io.youi.http.content._
import io.youi.stream._

import scala.annotation.tailrec
import scala.jdk.CollectionConverters._
@@ -24,9 +23,9 @@ object HTMLParser {
/**
* The set of attributes to limit to if filterAttributes is set to true.
*
* Defaults to "id" and "class".
* Defaults to "id", "class", and "data-youi".
*/
var validAttributes: Set[String] = Set("id", "class")
var validAttributes: Set[String] = Set("id", "class", "data-youi", "data-youi-class")

private val parsers = new ConcurrentHashMap[File, StreamableHTML]().asScala

@@ -53,7 +52,7 @@ object HTMLParser {
}

def apply(file: File): StreamableHTML = {
val cacheBuilder = new CacheBuilder {
val cacheBuilder: CacheBuilder = new CacheBuilder {
private var lastModified: Long = 0L

override def isStale: Boolean = lastModified != file.lastModified()
@@ -66,6 +65,7 @@ object HTMLParser {
var byId = Map.empty[String, Tag.Open]
var byClass = Map.empty[String, Set[Tag.Open]]
var byTag = Map.empty[String, Set[Tag.Open]]
var byAttribute = Map.empty[String, Set[Tag.Open]]
tags.foreach { tag =>
if (tag.attributes.contains("id")) {
byId += tag.attributes("id") -> tag
@@ -78,12 +78,17 @@ object HTMLParser {
byClass += cn -> classTags
}
}
tag.attributes.keys.foreach { attributeName =>
var attributeNameTags = byAttribute.getOrElse(attributeName, Set.empty[Tag.Open])
attributeNameTags += tag
byAttribute += attributeName -> attributeNameTags
}
var tagsByName = byTag.getOrElse(tag.tagName, Set.empty[Tag.Open])
tagsByName += tag
byTag += tag.tagName -> tagsByName
}
lastModified = file.lastModified()
CachedInformation(byId, byClass, byTag)
CachedInformation(byId, byClass, byTag, byAttribute)
} catch {
case throwable: Throwable => throw new RuntimeException(s"Error parsing ${file.getAbsolutePath}", throwable)
} finally {
@@ -17,6 +17,10 @@ object Selector {
override def lookup(streamable: StreamableHTML): Set[Tag.Open] = streamable.byTag.getOrElse(tagName, Set.empty)
}

case class HasAtribute(attributeName: String) extends Selector {
override def lookup(streamable: StreamableHTML): Set[Tag.Open] = streamable.byAttribute.getOrElse(attributeName, Set.empty)
}

case class ByMultiple(selectors: Selector*) extends Selector {
override def lookup(streamable: StreamableHTML): Set[Tag.Open] = selectors.flatMap(_.lookup(streamable)).toSet
}
@@ -12,6 +12,7 @@ class StreamableHTML(file: File, cacheBuilder: CacheBuilder) {
def byId: Map[String, Tag.Open] = cache.byId
def byClass: Map[String, Set[Tag.Open]] = cache.byClass
def byTag: Map[String, Set[Tag.Open]] = cache.byTag
def byAttribute: Map[String, Set[Tag.Open]] = cache.byAttribute

def stream(deltas: List[Delta],
selector: Option[Selector] = None,
@@ -0,0 +1,40 @@
package spec

import io.youi.stream.{HTMLParser, Selector}
import io.youi.stream.delta.Delta
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.Matchers

class TemplateGeneratorSpec extends AnyWordSpec with Matchers {
"TemplateGenerator" should {
"generate source from a simple HTML file" in {
val html = HTMLParser.cache(
"""<html>
|<head>
|</head>
|<body>
|<h1 data-youi="object" id="heading">Heading</h1>
|<ul>
| <li data-youi="class" data-youi-class="listItem" id="entry">Entry</li>
|</ul>
|</body>
|</html>""".stripMargin)
val result = html.stream(deltas = List(
Delta.Process(
selector = Selector.HasAtribute("data-youi"),
replace = true,
onlyOpenTag = false,
processor = (tag, content) => {
val `type` = tag.attributes("data-youi")
val id = tag.attributes.getOrElse("id", throw new RuntimeException(s"No id defined for: $content"))
val className = tag.attributes.getOrElse("data-youi-class", id)
println(s"Tag: $tag, Content: $content, Type: ${`type`}, Class: $className")
"REPLACED"
},
closeTagProcessor = None
)
))
println(result)
}
}
}

0 comments on commit 6e7b4d1

Please sign in to comment.
You can’t perform that action at this time.