aboutsummaryrefslogtreecommitdiff
path: root/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala
blob: 11e2faeef06683244cbfb6c811824a73655f0f24 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package dotty.tools
package dottydoc
package staticsite

import _root_.java.io.{ File => JFile }
import dotc.config.Printers.dottydoc
import dotc.core.Contexts.Context
import scala.io.Source

class Site(val root: JFile) {

  /** If, for some reason, the supplied default files cannot be found - this
    * exception will be thrown in `layouts`.
    */
  final case class ResourceNotFoundException(message: String) extends Exception(message)

  /** Files that define a layout then referred to by `layout: filename-no-ext`
    * in yaml front-matter.
    *
    * The compiler will look in two locations, `<root>/_layouts/` and
    * in the bundled jar file's resources `/_layouts`.
    *
    * If the user supplies a layout that has the same name as one of the
    * defaults, the user-defined one will take precedence.
    */
  val layouts: Map[String, String] = {
    def collectLayouts(dir: JFile): Map[String, String] =
      dir
      .listFiles
      .filter(f => f.getName.endsWith(".md") || f.getName.endsWith(".html"))
      .map { f =>
        (f.getName.substring(0, f.getName.lastIndexOf('.')), Source.fromFile(f).mkString)
      }
      .toMap

    val userDefinedLayouts =
      root
      .listFiles.find(d => d.getName == "_layouts" && d.isDirectory)
      .map(collectLayouts)
      .getOrElse(Map.empty)

    val defaultLayouts: Map[String, String] = Map(
      "main" -> "/_layouts/main.html",
      "index" -> "/_layouts/index.html"
    ).mapValues(getResource)

    defaultLayouts ++ userDefinedLayouts
  }

  private def getResource(r: String): String =
    Option(getClass.getResourceAsStream(r)).map(scala.io.Source.fromInputStream)
      .map(_.mkString)
      .getOrElse(throw ResourceNotFoundException(r))

  def render(page: Page, params: Map[String, AnyRef])(implicit ctx: Context): String = {
    page.yaml.get("layout").flatMap(layouts.get(_)) match {
      case None =>
        page.html
      case Some(layout) =>
        val expandedTemplate = new HtmlPage(layout, Map("content" -> page.html) ++ params)
        render(expandedTemplate, params)
    }
  }
}