aboutsummaryrefslogtreecommitdiff
path: root/doc-tool
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-01-12 18:37:49 +0100
committerFelix Mulder <felix.mulder@gmail.com>2017-01-31 14:31:07 +0100
commitbe9c3799aad4c5712f85948e0e4c29321bdcb9a4 (patch)
tree4e9d78f0e50d6c1af0ff478d08ba47d0d53c6f1e /doc-tool
parent3e16bfd9c32d965820121abc0083e8db94537821 (diff)
downloaddotty-be9c3799aad4c5712f85948e0e4c29321bdcb9a4.tar.gz
dotty-be9c3799aad4c5712f85948e0e4c29321bdcb9a4.tar.bz2
dotty-be9c3799aad4c5712f85948e0e4c29321bdcb9a4.zip
Add basic API generation from templates
Diffstat (limited to 'doc-tool')
-rw-r--r--doc-tool/resources/_layouts/api-page.html70
-rw-r--r--doc-tool/resources/_layouts/doc.html6
-rw-r--r--doc-tool/resources/css/api-page.css61
-rw-r--r--doc-tool/resources/css/dottydoc.css6
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/DocDriver.scala3
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/model/java.scala10
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala15
-rw-r--r--doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala105
-rw-r--r--doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala10
9 files changed, 238 insertions, 48 deletions
diff --git a/doc-tool/resources/_layouts/api-page.html b/doc-tool/resources/_layouts/api-page.html
new file mode 100644
index 000000000..41daf6c47
--- /dev/null
+++ b/doc-tool/resources/_layouts/api-page.html
@@ -0,0 +1,70 @@
+---
+layout: doc
+extraCSS:
+ - css/api-page.css
+---
+
+<div id="entity-container">
+ <div id="entity-title">
+ <span id="entity-modifiers">
+ {{ entity.modifiers | join: " " }}
+ </span>
+ <span id="entity-kind">
+ {{ entity.kind }}
+ </span>
+ <span id="entity-name">
+ {{ entity.name }}
+ </span>
+ </div>
+
+ {% if entity.comment.body %}
+ <div id="entity-body" class="entity-section">
+ {{ entity.comment.body }}
+ </div>
+ {% endif %}
+
+ <h1 class="section">Members</h1>
+
+ <div id="entity-members" class="entity-section">
+ {% for member in entity.members %}
+ <div class="member">
+ <div class="member-title">
+ <span class="member-modifiers">
+ {{ member.modifiers | join: " " }}
+ </span>
+ <span class="member-kind">
+ {{ member.kind }}
+ </span>
+ <span class="member-name">
+ {{ member.name }}
+ </span>
+
+ {% if member.kind == "def" and member.paramLists.size > 0 %}
+ {% for plist in member.paramLists %}
+ <span class="no-left">(</span>
+ {% if plist.isImplicit %}
+ <span class="no-left keyword">implicit</span>
+ {% endif %}
+ {% for ref in plist.list %}
+ {% if forloop.last %}
+ <span class="no-left">{{ ref.title }}</span>
+ {% else %}
+ <span class="no-left">{{ ref.title }}, </span>
+ {% endif %}
+ {% endfor %}
+ <span class="no-left">)</span>
+ {% endfor %}
+ {% endif %}
+
+ {% if member.returnValue %}
+ <span class="no-left">: {{ member.returnValue.title }}</span>
+ {% endif %}
+ </div><!-- end member-title -->
+
+ <div class="member-body">
+ {{ member.comment.short }}
+ </div>
+ </div><!-- end member -->
+ {% endfor %}
+ </div>
+</div><!-- end entity-container -->
diff --git a/doc-tool/resources/_layouts/doc.html b/doc-tool/resources/_layouts/doc.html
index 78fc2b116..4fd615d23 100644
--- a/doc-tool/resources/_layouts/doc.html
+++ b/doc-tool/resources/_layouts/doc.html
@@ -8,17 +8,17 @@ layout: main
<ul class="index-entities">
{% if docs.size > 0 %}
<li class="index-title">
- <a href="{{ site.baseurl }}/api/index.html">API</a>
+ <span>API</span>
</li>
{% endif %}
{% for pkg in docs %}
<li class="index-entity entity-package">
- <a href="#">{{ pkg.name }}</a>
+ <a href="{{ site.baseurl }}/api/{{ pkg.path | join: "/" }}/index.html">{{ pkg.name }}</a>
</li>
{% for member in pkg.members %}
{% if member.kind != "package" %}
<li class="index-entity">
- <a href="#">{{ member.kind }} {{ member.name }}</a>
+ <a href="{{ site.baseurl }}/api/{{ member.path | join: "/" }}.html">{{ member.kind }} {{ member.name }}</a>
</li>
{% endif %}
{% endfor %}
diff --git a/doc-tool/resources/css/api-page.css b/doc-tool/resources/css/api-page.css
new file mode 100644
index 000000000..47f88ed6c
--- /dev/null
+++ b/doc-tool/resources/css/api-page.css
@@ -0,0 +1,61 @@
+/** Fonts */
+@import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700,600);
+
+div#entity-container {
+ margin-top: 10px;
+ padding: 0 20px 20px;
+}
+
+div#entity-title {
+ color: #34495e;
+ font-family: "Helvetica","Arial",sans-serif;
+ font-weight: 400;
+ margin-bottom: 30px;
+ font-size: 2.5rem;
+}
+
+div#entity-title > span#entity-modifiers,
+div#entity-title > span#entity-kind {
+ font-weight: 100;
+}
+
+div.entity-section {
+ background-color: #fff;
+ border-radius: 4px;
+ margin: 0;
+ padding: 30px;
+}
+
+div.entity-section *:last-child {
+ margin-bottom: 0px;
+}
+
+h1.section {
+ margin: 30px 0;
+}
+
+div#entity-members > div.member {
+ margin-bottom: 30px;
+}
+
+div#entity-members > div.member:last-child {
+ margin-bottom: 0px;
+}
+
+div#entity-members > div.member > div.member-title {
+ font-family: "Source Code Pro", sans-serif;
+}
+
+div#entity-members > div.member > div.member-title > span.member-name {
+ color: #458;
+ font-weight: 600;
+}
+
+div#entity-members > div.member > div.member-title span.keyword {
+ font-weight: 600;
+ margin-right: 11px;
+}
+
+div#entity-members > div.member > div.member-title span.no-left {
+ margin-left: -11px;
+}
diff --git a/doc-tool/resources/css/dottydoc.css b/doc-tool/resources/css/dottydoc.css
index a40ee6a4d..754d3b3f7 100644
--- a/doc-tool/resources/css/dottydoc.css
+++ b/doc-tool/resources/css/dottydoc.css
@@ -59,6 +59,7 @@ ul.toc {
ul.toc > li.toc-title > a {
font-size: 16px;
font-weight: bold;
+ margin-top: 1rem;
}
ul.toc > li > a#home-button,
@@ -101,10 +102,11 @@ ul.toc > li > ul.hide {
display: none;
}
-ul.index-entities > li.index-title > a {
+ul.index-entities > li.index-title > span {
font-size: 16px;
font-weight: bold;
- color: rgba(0,0,0,.87)
+ color: rgba(0,0,0,.87);
+ padding: 0 24px;
}
li.index-entity > a:focus {
diff --git a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala
index 84eb04779..228366431 100644
--- a/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala
+++ b/doc-tool/src/dotty/tools/dottydoc/DocDriver.scala
@@ -56,13 +56,14 @@ class DocDriver extends Driver {
implicit val (filesToDocument, ctx) = setup(args, initCtx.fresh)
doCompile(newCompiler(ctx), filesToDocument)(ctx)
- val docs = ctx.docbase.packages.toJavaList
+ val docs = ctx.docbase.packages
val siteRoot = new java.io.File(ctx.settings.siteRoot.value)
if (!siteRoot.exists || !siteRoot.isDirectory)
ctx.error(s"Site root does not exist: $siteRoot")
else {
Site(siteRoot, docs)
+ .generateApiDocs()
.copyStaticFiles()
.generateHtmlFiles()
.generateBlog()
diff --git a/doc-tool/src/dotty/tools/dottydoc/model/java.scala b/doc-tool/src/dotty/tools/dottydoc/model/java.scala
index 30e884ce3..01dac2685 100644
--- a/doc-tool/src/dotty/tools/dottydoc/model/java.scala
+++ b/doc-tool/src/dotty/tools/dottydoc/model/java.scala
@@ -11,9 +11,12 @@ object java {
import scala.collection.JavaConverters._
import _root_.java.util.{ Optional => JOptional, Map => JMap }
- implicit class JavaOption[A](val opt: Option[A]) extends AnyVal {
- def asJava: JOptional[A] =
- opt.map(a => JOptional.of(a)).getOrElse(JOptional.empty[A])
+ implicit class OptStr(val opt: Option[String]) extends AnyVal {
+ def asJava = opt.getOrElse(null)
+ }
+
+ implicit class OptMap(val opt: Option[JMap[String, _]]) extends AnyVal {
+ def asJava = opt.getOrElse(Map.empty.asJava)
}
implicit class JavaComment(val cmt: Comment) extends AnyVal {
@@ -222,6 +225,7 @@ object java {
case ent: Object => ent.asJava(extras)
case ent: Def => ent.asJava
case ent: Val => ent.asJava
+ case _ => Map.empty.asJava
}
implicit class JavaMap(val map: collection.Map[String, Package]) extends AnyVal {
diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala
index d0f49100c..ce57dc805 100644
--- a/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala
+++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala
@@ -3,24 +3,31 @@ package dottydoc
package staticsite
import java.util.{ List => JList }
+import model.{ Entity, NonEntity }
case class DefaultParams(
docs: JList[_],
page: PageInfo,
- site: SiteInfo
+ site: SiteInfo,
+ entity: Entity = NonEntity
) {
-
+ import model.java._
import scala.collection.JavaConverters._
+
def toMap: Map[String, AnyRef] = Map(
"docs" -> docs,
+
"page" -> Map(
"url" -> page.url,
"path" -> page.path
),
+
"site" -> Map(
"baseurl" -> site.baseurl,
"posts" -> site.posts.map(_.toMap)
- ).asJava
+ ).asJava,
+
+ "entity" -> entity.asJava()
)
def withPosts(posts: Array[BlogPost]): DefaultParams =
@@ -28,6 +35,8 @@ case class DefaultParams(
def withUrl(url: String): DefaultParams =
copy(page = PageInfo(url))
+
+ def withEntity(e: model.Entity) = copy(entity = e)
}
case class PageInfo(url: String) {
diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala
index 7c9dc00fe..ecc076ba3 100644
--- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala
+++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala
@@ -18,10 +18,17 @@ import com.vladsch.flexmark.util.options.{ DataHolder, MutableDataSet }
import dotc.config.Printers.dottydoc
import dotc.core.Contexts.Context
+import model.Package
import scala.io.Source
import scala.collection.mutable.ArrayBuffer
-case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder {
+case class Site(val root: JFile, val documentation: Map[String, Package]) extends ResourceFinder {
+ /** Documentation serialized to java maps */
+ private val docs: JList[_] = {
+ import model.java._
+ documentation.toJavaList
+ }
+
/** All files that are considered static in this context, this can be
* anything from CSS, JS to images and other files.
*
@@ -87,6 +94,7 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder {
// Copy statics included in resources
Map(
+ "css/api-page.css" -> "/css/api-page.css",
"css/dottydoc.css" -> "/css/dottydoc.css",
"css/color-brewer.css" -> "/css/color-brewer.css",
"js/highlight.pack.js" -> "/js/highlight.pack.js"
@@ -113,41 +121,73 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder {
DefaultParams(docs, PageInfo(pathFromRoot), SiteInfo(baseUrl, Array()))
}
- /** Generate HTML files from markdown and .html sources */
- def generateHtmlFiles(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type = {
+ private def createOutput(outDir: JFile)(op: => Unit): this.type = {
if (!outDir.isDirectory) outDir.mkdirs()
if (!outDir.isDirectory) /*dottydoc.*/println(s"couldn't create output folder: $outDir")
- else compilableFiles.foreach { asset =>
- val pathFromRoot = stripRoot(asset)
- val fileContents = Source.fromFile(asset).mkString
- val params = defaultParams(asset).withPosts(blogInfo).toMap
- val page =
- if (asset.getName.endsWith(".md")) new MarkdownPage(fileContents, params, includes)
- else new HtmlPage(fileContents, params, includes)
-
- val renderedPage = render(page)
- val source = new ByteArrayInputStream(renderedPage.getBytes(StandardCharsets.UTF_8))
- val target = pathFromRoot.splitAt(pathFromRoot.lastIndexOf('.'))._1 + ".html"
- val htmlTarget = mkdirs(fs.getPath(outDir.getAbsolutePath, target))
- Files.copy(source, htmlTarget, REPLACE_EXISTING)
- }
+ else op
this
}
- def generateBlog(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): Unit = {
- blogposts.foreach { file =>
- val BlogPost.extract(year, month, day, name, ext) = file.getName
- val fileContents = Source.fromFile(file).mkString
- val params = defaultParams(file, 2).withPosts(blogInfo).toMap
- val page =
- if (ext == "md") new MarkdownPage(fileContents, params, includes)
- else new HtmlPage(fileContents, params, includes)
+ /** Generate HTML for the API documentation */
+ def generateApiDocs(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type =
+ createOutput(outDir) {
+ def genDoc(e: model.Entity) = {
+ // Suffix is index.html for packages and therefore the additional depth
+ // is increased by 1
+ val (suffix, offset) =
+ if (e.kind == "package") ("/index.html", -1)
+ else (".html", 0)
+
+ val target = mkdirs(fs.getPath(outDir.getAbsolutePath + "/api/" + e.path.mkString("/") + suffix))
+ val params = defaultParams(target.toFile, -1).withPosts(blogInfo).withEntity(e)
+ val page = new HtmlPage(layouts("api-page"), params.toMap, includes)
+
+ val rendered = render(page)
+ val source = new ByteArrayInputStream(rendered.getBytes(StandardCharsets.UTF_8))
- val source = new ByteArrayInputStream(render(page).getBytes(StandardCharsets.UTF_8))
- val target = mkdirs(fs.getPath(outDir.getAbsolutePath, "blog", year, month, day, name + ".html"))
- Files.copy(source, target, REPLACE_EXISTING)
+ Files.copy(source, target, REPLACE_EXISTING)
+ }
+
+ documentation.values.foreach { pkg =>
+ genDoc(pkg)
+ pkg.members.filterNot(_.kind == "package").map(genDoc)
+ }
+ }
+
+ /** Generate HTML files from markdown and .html sources */
+ def generateHtmlFiles(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type =
+ createOutput(outDir) {
+ compilableFiles.foreach { asset =>
+ val pathFromRoot = stripRoot(asset)
+ val fileContents = Source.fromFile(asset).mkString
+ val params = defaultParams(asset).withPosts(blogInfo).toMap
+ val page =
+ if (asset.getName.endsWith(".md")) new MarkdownPage(fileContents, params, includes)
+ else new HtmlPage(fileContents, params, includes)
+
+ val renderedPage = render(page)
+ val source = new ByteArrayInputStream(renderedPage.getBytes(StandardCharsets.UTF_8))
+ val target = pathFromRoot.splitAt(pathFromRoot.lastIndexOf('.'))._1 + ".html"
+ val htmlTarget = mkdirs(fs.getPath(outDir.getAbsolutePath, target))
+ Files.copy(source, htmlTarget, REPLACE_EXISTING)
+ }
+ }
+
+ def generateBlog(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): this.type =
+ createOutput(outDir) {
+ blogposts.foreach { file =>
+ val BlogPost.extract(year, month, day, name, ext) = file.getName
+ val fileContents = Source.fromFile(file).mkString
+ val params = defaultParams(file, 2).withPosts(blogInfo).toMap
+ val page =
+ if (ext == "md") new MarkdownPage(fileContents, params, includes)
+ else new HtmlPage(fileContents, params, includes)
+
+ val source = new ByteArrayInputStream(render(page).getBytes(StandardCharsets.UTF_8))
+ val target = mkdirs(fs.getPath(outDir.getAbsolutePath, "blog", year, month, day, name + ".html"))
+ Files.copy(source, target, REPLACE_EXISTING)
+ }
}
- }
private def mkdirs(path: Path): path.type = {
val parent = path.getParent.toFile
@@ -181,7 +221,11 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder {
def splitFiles(f: JFile, assets: ArrayBuffer[JFile], comp: ArrayBuffer[JFile]): Unit = {
val name = f.getName
if (f.isDirectory) {
- if (!f.getName.startsWith("_")) f.listFiles.foreach(splitFiles(_, assets, comp))
+ val name = f.getName
+ if (!name.startsWith("_") && name != "api") f.listFiles.foreach(splitFiles(_, assets, comp))
+ if (f.getName == "api") dottydoc.println {
+ "the specified `/api` directory will not be used since it is needed for the api documentation"
+ }
}
else if (name.endsWith(".md") || name.endsWith(".html")) comp.append(f)
else assets.append(f)
@@ -230,6 +274,7 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder {
"main" -> "/_layouts/main.html",
"doc" -> "/_layouts/doc.html",
"doc-page" -> "/_layouts/doc-page.html",
+ "api-page" -> "/_layouts/api-page.html",
"blog" -> "/_layouts/blog.html",
"index" -> "/_layouts/index.html"
).mapValues(getResource)
diff --git a/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala b/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala
index d72299e84..11a1da818 100644
--- a/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala
+++ b/doc-tool/test/dotty/tools/dottydoc/staticsite/SiteTests.scala
@@ -7,7 +7,7 @@ import org.junit.Assert._
class SiteTests extends DottyDocTest {
import scala.collection.JavaConverters._
- val site = new Site(new java.io.File("../doc-tool/resources/"), List.empty.asJava)
+ val site = new Site(new java.io.File("../doc-tool/resources/"), Map.empty)
private def html(
str: String,
@@ -19,7 +19,7 @@ class SiteTests extends DottyDocTest {
assert(site.root.exists && site.root.isDirectory,
s"'${site.root.getName}' is not a directory")
- val expectedLayouts = Set("main", "index", "blog", "doc", "doc-page")
+ val expectedLayouts = Set("main", "index", "blog", "doc", "doc-page", "api-page")
assert(site.layouts.keys == expectedLayouts,
s"Incorrect layouts in: ${site.layouts.keys}, expected: $expectedLayouts")
}
@@ -91,16 +91,14 @@ class SiteTests extends DottyDocTest {
val compd = site.compilableFiles.map(site.stripRoot).toSet
val expectedAssets = Set(
+ "css/api-page.css",
"css/dottydoc.css",
"css/color-brewer.css",
"js/highlight.pack.js"
)
val expectedCompd = Set(
- "index.md"
// Directories starting in `_` are not included in compilable files
- //"_includes/header.html",
- //"_layouts/index.html",
- //"_layouts/main.html"
+ "index.md"
)
assert(expectedAssets == assets,