aboutsummaryrefslogtreecommitdiff
path: root/plugins/javadoc/src/main/kotlin
diff options
context:
space:
mode:
authorAndrzej Ratajczak <andrzej.ratajczak98@gmail.com>2020-03-13 10:46:33 +0100
committerBłażej Kardyś <bkardys@virtuslab.com>2020-06-23 02:19:14 +0200
commit3940153fd08e0c0596ac289766d9ef2877b56591 (patch)
treeccf7bd66800c512a357ad0e31ca42f8cefcc0dcb /plugins/javadoc/src/main/kotlin
parentf6530934d36fbb977c2b7c4eb3669a8f581dd9f5 (diff)
downloaddokka-3940153fd08e0c0596ac289766d9ef2877b56591.tar.gz
dokka-3940153fd08e0c0596ac289766d9ef2877b56591.tar.bz2
dokka-3940153fd08e0c0596ac289766d9ef2877b56591.zip
First version of javadoc output generation
Diffstat (limited to 'plugins/javadoc/src/main/kotlin')
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt18
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt103
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt92
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt29
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocRenderer.kt28
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt193
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt163
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt328
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt161
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt391
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt63
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/pages.kt17
12 files changed, 1586 insertions, 0 deletions
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt
new file mode 100644
index 00000000..840bdc55
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt
@@ -0,0 +1,18 @@
+package javadoc
+
+import org.jetbrains.dokka.base.signatures.SignatureProvider
+import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.pages.ModulePageNode
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator
+import org.jetbrains.dokka.utilities.DokkaLogger
+
+class JavadocDocumentableToPageTranslator(
+ private val commentsToContentConverter: CommentsToContentConverter,
+ private val signatureProvider: SignatureProvider,
+ private val logger: DokkaLogger
+) : DocumentableToPageTranslator {
+ override fun invoke(module: DModule): RootPageNode =
+ JavadocPageCreator(commentsToContentConverter, signatureProvider, logger).pageForModule(module)
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt
new file mode 100644
index 00000000..520486f6
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt
@@ -0,0 +1,103 @@
+package javadoc
+
+import javadoc.pages.*
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.base.resolvers.local.LocationProvider
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.SourceSetData
+import org.jetbrains.dokka.pages.ContentPage
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.query
+import java.nio.file.Paths
+import java.util.*
+
+class JavadocLocationProvider(pageRoot: RootPageNode, private val context: DokkaContext) : LocationProvider {
+ private val externalLocationProviderFactories =
+ context.plugin<DokkaBase>().query { externalLocationProviderFactory }
+ private val externalLocationProvider =
+ externalLocationProviderFactories.asSequence().map { it.getExternalLocationProvider("javadoc10") }
+ .filterNotNull().take(1).firstOrNull()
+ private val externalDocumentationLinks by lazy {
+ context.configuration.passesConfigurations
+ .filter { passConfig -> passConfig.analysisPlatform == Platform.jvm }
+ .flatMap { it.externalDocumentationLinks }
+ .distinct()
+ }
+
+ private val pathIndex = IdentityHashMap<PageNode, List<String>>().apply {
+ fun registerPath(page: PageNode, prefix: List<String> = emptyList()) {
+ val newPrefix = prefix + page.takeIf { it is JavadocPackagePageNode }?.name.orEmpty()
+ val path = (prefix + when (page) {
+ is AllClassesPage -> listOf("allclasses")
+ is TreeViewPage -> if (page.classes == null)
+ listOf("overview-tree")
+ else
+ listOf("package-tree")
+ is ContentPage -> if (page.dri.isNotEmpty() && page.dri.first().classNames != null)
+ listOfNotNull(page.dri.first().classNames)
+ else if (page is JavadocPackagePageNode)
+ listOf(page.name, "package-summary")
+ else
+ listOf("index")
+ else -> emptyList()
+ }).filterNot { it.isEmpty() }
+
+ put(page, path)
+ page.children.forEach { registerPath(it, newPrefix) }
+
+ }
+ put(pageRoot, listOf("index"))
+ pageRoot.children.forEach { registerPath(it) }
+ }
+
+ private val nodeIndex = IdentityHashMap<DRI, PageNode>().apply {
+ fun registerNode(node: PageNode) {
+ if (node is ContentPage) put(node.dri.first(), node)
+
+ node.children.forEach(::registerNode)
+ }
+ registerNode(pageRoot)
+ }
+
+ private operator fun IdentityHashMap<PageNode, List<String>>.get(dri: DRI) = this[nodeIndex[dri]]
+
+ override fun resolve(dri: DRI, sourceSets: List<SourceSetData>, context: PageNode?): String =
+ context?.let { resolve(it, skipExtension = false) } ?: nodeIndex[dri]?.let {
+ resolve(it, skipExtension = true)
+ } ?: with(externalLocationProvider!!) {
+ dri.toLocation()
+ }
+
+ override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String =
+ pathIndex[node]?.joinToString("/")?.let {
+ if (skipExtension) it.removeSuffix(".html") else it
+ } ?: run {
+ throw IllegalStateException("Path for ${node::class.java.canonicalName}:${node.name} not found")
+ }
+
+ fun resolve(link: LinkJavadocListEntry, dir: String = "", skipExtension: Boolean = true) = pathIndex[link.dri.first()]?.let {
+ when (link.kind) {
+ JavadocContentKind.Class -> it
+ JavadocContentKind.OverviewSummary -> it.dropLast(1) + "index"
+ JavadocContentKind.PackageSummary -> it.dropLast(1) + "package-summary"
+ JavadocContentKind.AllClasses -> it.dropLast(1) + "allclasses"
+ JavadocContentKind.OverviewTree -> it.dropLast(1) + "overview-tree"
+ JavadocContentKind.PackageTree -> it.dropLast(1) + "package-tree"
+ else -> it
+ }
+ }?.joinToString("/")?.let {if (skipExtension) "$it.html" else it}?.let {
+ Paths.get(dir).relativize(Paths.get(it)).toString()
+ } ?: run {throw IllegalStateException("Page for ${link.name} not found")}
+
+ override fun resolveRoot(node: PageNode): String {
+ TODO("Not yet implemented")
+ }
+
+ override fun ancestors(node: PageNode): List<PageNode> {
+ TODO("Not yet implemented")
+ }
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
new file mode 100644
index 00000000..f5ca4bb3
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
@@ -0,0 +1,92 @@
+package javadoc
+
+import javadoc.pages.*
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.base.signatures.SignatureProvider
+import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.pages.ContentKind
+import org.jetbrains.dokka.utilities.DokkaLogger
+
+open class JavadocPageCreator(
+ commentsToContentConverter: CommentsToContentConverter,
+ signatureProvider: SignatureProvider,
+ val logger: DokkaLogger
+) {
+ fun pageForModule(m: DModule): JavadocModulePageNode =
+ JavadocModulePageNode(
+ m.name.ifEmpty { "root" },
+ contentForModule(m),
+ m.packages.map { pageForPackage(it) },
+ setOf(m.dri)
+ )
+
+ fun pageForPackage(p: DPackage) =
+ JavadocPackagePageNode(p.name, contentForPackage(p), setOf(p.dri), p,
+ p.classlikes.map { pageForClasslike(it) } // TODO: nested classlikes
+ ).also {
+ it
+ }
+
+ fun pageForClasslike(c: DClasslike): JavadocClasslikePageNode {
+ val constructors = when (c) {
+ is DClass -> c.constructors
+ is DEnum -> c.constructors
+ else -> emptyList()
+ }
+
+ return JavadocClasslikePageNode(c.name.orEmpty(), contentForClasslike(c), setOf(c.dri), c, emptyList())
+ }
+
+ fun contentForModule(m: DModule): JavadocContentNode =
+ JavadocContentGroup(
+ setOf(m.dri),
+ JavadocContentKind.OverviewSummary,
+ m.sourceSets.filter { it.platform == Platform.jvm }.toSet()
+ ) {
+ title(m.name, "0.0.1", dri = setOf(m.dri), kind = ContentKind.Main)
+ list("Packages", "Package", setOf(m.dri), ContentKind.Packages, m.packages.map { p ->
+ val doc = p.documentation.entries.find { (k, _) -> k.platform == Platform.jvm }?.value?.let {
+ it.children.joinToString("\n") { it.root.toString() }
+ }.orEmpty()
+ RowJavadocListEntry(
+ LinkJavadocListEntry(p.name, setOf(p.dri), JavadocContentKind.PackageSummary, sourceSets),
+ doc
+ )
+ })
+ }
+
+ fun contentForPackage(p: DPackage): JavadocContentNode =
+ JavadocContentGroup(
+ setOf(p.dri),
+ JavadocContentKind.PackageSummary,
+ p.sourceSets.filter { it.platform == Platform.jvm }.toSet()
+ ) {
+ title(p.name, "0.0.1", dri = setOf(p.dri), kind = ContentKind.Packages)
+ list("Packages", "Package", setOf(p.dri), ContentKind.Packages, p.classlikes.map { c ->
+ val doc = c.documentation.entries.find { (k, _) -> k.platform == Platform.jvm }?.value?.let {
+ it.children.joinToString("\n") { it.root.toString() }
+ }.orEmpty()
+ RowJavadocListEntry(
+ LinkJavadocListEntry(c.name.orEmpty(), setOf(c.dri), JavadocContentKind.Class, sourceSets),
+ doc
+ )
+ })
+ }
+
+ fun contentForClasslike(c: DClasslike): JavadocContentNode =
+ JavadocContentGroup(
+ setOf(c.dri),
+ JavadocContentKind.Class,
+ c.sourceSets.filter { it.platform == Platform.jvm }.toSet()
+ ) {
+ title(
+ c.name.orEmpty(),
+ "0.0.1",
+ parent = c.dri.packageName,
+ dri = setOf(c.dri),
+ kind = JavadocContentKind.Class
+ )
+ }
+}
+
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt
new file mode 100644
index 00000000..f58faa49
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt
@@ -0,0 +1,29 @@
+package org.jetbrains.dokka.javadoc
+
+import javadoc.JavadocDocumentableToPageTranslator
+import javadoc.KorteJavadocRenderer
+import org.jetbrains.dokka.CoreExtensions
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.querySingle
+
+class JavadocPlugin : DokkaPlugin() {
+ val dokkaJavadocPlugin by extending {
+ val dokkaBasePlugin = plugin<DokkaBase>()
+ CoreExtensions.renderer providing { ctx ->
+ KorteJavadocRenderer(dokkaBasePlugin.querySingle { outputWriter }, ctx, "views")
+ } applyIf { format == "javadoc" }
+ }
+
+ val pageTranslator by extending {
+ val dokkaBasePlugin = plugin<DokkaBase>()
+ CoreExtensions.documentableToPageTranslator providing { ctx ->
+ JavadocDocumentableToPageTranslator(
+ dokkaBasePlugin.querySingle { commentsToContentConverter },
+ dokkaBasePlugin.querySingle { signatureProvider },
+ ctx.logger
+ )
+ }
+ }
+}
+
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocRenderer.kt
new file mode 100644
index 00000000..588d89ba
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocRenderer.kt
@@ -0,0 +1,28 @@
+package org.jetbrains.dokka.javadoc
+
+//class JavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext) : Renderer {
+// override fun render(root: RootPageNode) {
+// val rootIndex = (root as RootIndexPage)
+// val instructions = (rootIndex.strategy as RenderingStrategy.Callback).instructions
+// outputWriter.writeHtml("index", instructions(this, rootIndex)) // TODO get version
+// rootIndex.children.forEach { renderPages(it) }
+// }
+//
+// private fun renderPages(node: PageNode, dir: String = "") {
+// val path = if (node is JavadocPageNode) node.fullPath else "$dir/${node.name}"
+// if (node is RendererSpecificPage) {
+// when (val strategy = node.strategy) {
+// is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "")
+// is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text)
+// is RenderingStrategy.Callback -> outputWriter.writeHtml(path, strategy.instructions(this, node))
+// RenderingStrategy.DoNothing -> Unit
+// }
+// }
+//// else
+//// throw IllegalStateException("${node.name} was not expected here")
+//
+// node.children.forEach { renderPages(it, path) }
+// }
+//
+// private fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, ".html")
+//} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt
new file mode 100644
index 00000000..ad83968e
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt
@@ -0,0 +1,193 @@
+package javadoc
+
+import com.soywiz.korte.*
+import javadoc.pages.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.jetbrains.dokka.base.renderers.OutputWriter
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.pages.RendererSpecificPage
+import org.jetbrains.dokka.pages.RenderingStrategy
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.renderers.Renderer
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.time.LocalDate
+
+class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext, val resourceDir: String) :
+ Renderer {
+ private lateinit var locationProvider: JavadocLocationProvider
+
+ override fun render(root: RootPageNode) = root.let { preprocessors.fold(root) { r, t -> t.invoke(r) } }.let { r ->
+ locationProvider = JavadocLocationProvider(r, context)
+ runBlocking(Dispatchers.IO) {
+ renderModulePageNode(r as JavadocModulePageNode)
+ }
+ }
+
+ private fun templateForNode(node: JavadocPageNode) = when (node) {
+ is JavadocClasslikePageNode -> "class.korte"
+ is JavadocPackagePageNode -> "tabPage.korte"
+ is JavadocModulePageNode -> "tabPage.korte"
+ is AllClassesPage -> "listPage.korte"
+ is TreeViewPage -> "treePage.korte"
+ else -> ""
+ }
+
+ private fun CoroutineScope.renderNode(node: PageNode, path: String = "") {
+ if (node is JavadocPageNode) {
+ renderJavadocNode(node)
+ } else if (node is RendererSpecificPage) {
+ renderSpecificPage(node, path)
+ }
+ }
+
+ private fun CoroutineScope.renderModulePageNode(node: JavadocModulePageNode) {
+ val link = "."
+ val name = "index"
+ val pathToRoot = ""
+
+ val contentMap = mapOf(
+ "docName" to "docName", // todo docname
+ "pathToRoot" to pathToRoot
+ ) + node.contentMap
+ writeFromTemplate(outputWriter, "$link/$name".toNormalized(), "tabPage.korte", contentMap.toList())
+ node.children.forEach { renderNode(it, link) }
+ }
+
+ private fun CoroutineScope.renderJavadocNode(node: JavadocPageNode) {
+ val link = locationProvider.resolve(node, skipExtension = true)
+ val dir = Paths.get(link).parent?.let { it.toNormalized() }.orEmpty()
+ val pathToRoot = dir.split("/").joinToString("/") { ".." }.let {
+ if (it.isNotEmpty()) "$it/" else it
+ }
+
+ val contentMap = mapOf(
+ "docName" to "docName", // todo docname
+ "pathToRoot" to pathToRoot,
+ "dir" to dir
+ ) + node.contentMap
+// DokkaConsoleLogger.info("${node::class.java.canonicalName}::${node.name} - $link")
+ writeFromTemplate(outputWriter, link, templateForNode(node), contentMap.toList())
+ node.children.forEach { renderNode(it, link.toNormalized()) }
+ }
+
+ fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch {
+ when (val strategy = node.strategy) {
+ is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "")
+ is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text)
+ is RenderingStrategy.Callback -> outputWriter.writeResources(
+ path,
+ strategy.instructions(this@KorteJavadocRenderer, node)
+ )
+ RenderingStrategy.DoNothing -> Unit
+ }
+ }
+
+ fun Pair<String, String>.pairToTag() = "\n<th class=\"colFirst\" scope=\"row\">${first}</th>\n<td class=\"colLast\">${second}</td>"
+
+ fun LinkJavadocListEntry.toLinkTag(parent: String? = null) =
+ createLinkTag(locationProvider.resolve(dri.first(), sourceSets.toList()).let {
+ if (parent != null) it.relativizePath(parent)
+ else it
+ }, name)
+
+ fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptyList(), context)
+
+ fun createLinkTag(address: String, name: String) =
+ address.let { if (it.endsWith(".html")) it else "$it.html" }.let {
+ """<a href="$it">$name</a>"""
+ }
+
+ private fun String.parent() = Paths.get(this).parent.toNormalized()
+ private fun Path.toNormalized() = this.normalize().toFile().toString()
+ private fun String.toNormalized() = Paths.get(this).toNormalized()
+ private fun String.relativizePath(parent: String) = Paths.get(parent).relativize(Paths.get(this)).toNormalized()
+
+ private suspend fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, ".html")
+ private fun CoroutineScope.writeFromTemplate(
+ writer: OutputWriter,
+ path: String,
+ template: String,
+ args: List<Pair<String, *>>
+ ) =
+ launch {
+ val tmp = templateRenderer.render(template, *(args.toTypedArray()))
+ writer.writeHtml(
+ path,
+ tmp
+ )
+ }
+
+ fun getTemplateConfig() = TemplateConfig().also { config ->
+ listOf(
+ TeFunction("curDate") { LocalDate.now() },
+ TeFunction("jQueryVersion") { "3.1" },
+ TeFunction("jQueryMigrateVersion") { "1.2.1" },
+ TeFunction("rowColor") { args -> if ((args.first() as Int) % 2 == 0) "altColor" else "rowColor" },
+ TeFunction("h1Title") { args -> if ((args.first() as? String) == "package") "title=\"Package\" " else "" },
+ TeFunction("createTabRow") { args ->
+ val (link, doc) = args.first() as RowJavadocListEntry
+ val dir = args[1] as String?
+ (createLinkTag(locationProvider.resolve(link, dir.orEmpty()), link.name) to doc).pairToTag().trim()
+ },
+ TeFunction("createListRow") { args ->
+ val link = args.first() as LinkJavadocListEntry
+ val dir = args[1] as String?
+// link.toLinkTag(dir)
+ createLinkTag(locationProvider.resolve(link, dir.orEmpty()), link.name)
+ },
+ TeFunction("createPackageHierarchy") { args ->
+ val list = args.first() as List<JavadocPackagePageNode>
+ list.mapIndexed { i, p ->
+ val content = if (i + 1 == list.size) "" else ", "
+ val name = p.name
+ "<li><a href=\"$name/package-tree.html\">$name</a>$content</li>"
+ }.joinToString("\n")
+ },
+ TeFunction("renderInheritanceGraph") { args ->
+ val node = args.first() as TreeViewPage.InheritanceNode
+
+ fun drawRec(node: TreeViewPage.InheritanceNode): String =
+ "<li class=\"circle\">" + node.dri.let { dri ->
+ listOfNotNull(
+ dri.packageName,
+ dri.classNames
+ ).joinToString(".") + node.interfaces.takeUnless { node.isInterface || it.isEmpty() }
+ ?.let {
+ " implements " + it.joinToString(", ") { n ->
+ listOfNotNull(
+ n.packageName,
+ createLinkTag(n.toLink(), n.classNames.orEmpty())
+ ).joinToString(".")
+ }
+ }.orEmpty()
+ } + node.children.filterNot { it.isInterface }.takeUnless { it.isEmpty() }?.let {
+ "<ul>" + it.joinToString("\n", transform = ::drawRec) + "</ul>"
+ }.orEmpty() + "</li>"
+
+ drawRec(node)
+ },
+ Filter("length") { subject.dynamicLength() }
+ ).forEach {
+ when (it) {
+ is TeFunction -> config.register(it)
+ is Filter -> config.register(it)
+ is Tag -> config.register(it)
+ }
+ }
+ }
+
+ val config = getTemplateConfig()
+ val templateRenderer = Templates(ResourceTemplateProvider(resourceDir), config = config, cache = true)
+
+ class ResourceTemplateProvider(val basePath: String) : TemplateProvider {
+ override suspend fun get(template: String): String =
+ javaClass.classLoader.getResourceAsStream("$basePath/$template")?.bufferedReader()?.lines()?.toArray()
+ ?.joinToString("\n") ?: throw IllegalStateException("Template not found: $basePath/$template")
+ }
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt
new file mode 100644
index 00000000..df026be3
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt
@@ -0,0 +1,163 @@
+package javadoc.pages
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.SourceSetData
+import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.pages.*
+
+enum class JavadocContentKind : Kind {
+ AllClasses, OverviewSummary, PackageSummary, Class, OverviewTree, PackageTree
+}
+
+abstract class JavadocContentNode(
+ dri: Set<DRI>,
+ kind: Kind,
+ override val sourceSets: Set<SourceSetData>
+) : ContentNode {
+ abstract val contentMap: Map<String, Any?>
+ override val dci: DCI = DCI(dri, kind)
+ override val style: Set<Style> = emptySet()
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode = this
+}
+
+interface JavadocListEntry {
+ val stringTag: String
+}
+
+class EmptyNode(
+ dri: DRI,
+ kind: Kind,
+ override val sourceSets: Set<SourceSetData>,
+ override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
+) : ContentNode {
+ override val dci: DCI = DCI(setOf(dri), kind)
+ override val style: Set<Style> = emptySet()
+
+ override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode =
+ EmptyNode(dci.dri.first(), dci.kind, sourceSets, newExtras)
+}
+
+class JavadocContentGroup(
+ val dri: Set<DRI>,
+ val kind: Kind,
+ sourceSets: Set<SourceSetData>,
+ val children: List<JavadocContentNode>
+) : JavadocContentNode(dri, kind, sourceSets) {
+ override val contentMap: Map<String, Any?> by lazy { children.fold(emptyMap<String, Any?>()) { m, cv -> m + cv.contentMap } }
+
+ companion object {
+ operator fun invoke(
+ dri: Set<DRI>,
+ kind: Kind,
+ sourceSets: Set<SourceSetData>,
+ block: JavaContentGroupBuilder.() -> Unit
+ ): JavadocContentGroup =
+ JavadocContentGroup(dri, kind, sourceSets, JavaContentGroupBuilder(sourceSets).apply(block).list)
+ }
+}
+
+class JavaContentGroupBuilder(val sourceSets: Set<SourceSetData>) {
+ val list = mutableListOf<JavadocContentNode>()
+}
+
+class TitleNode(
+ val title: String,
+ val version: String,
+ val parent: String?,
+ val dri: Set<DRI>,
+ val kind: Kind,
+ sourceSets: Set<SourceSetData>
+) : JavadocContentNode(dri, kind, sourceSets) {
+
+ override val contentMap: Map<String, Any?> by lazy {
+ mapOf(
+ "title" to title,
+ "version" to version,
+ "packageName" to parent
+ )
+ }
+
+// override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode = TODO()
+}
+
+fun JavaContentGroupBuilder.title(
+ title: String,
+ version: String,
+ parent: String? = null,
+ dri: Set<DRI>,
+ kind: Kind
+) {
+ list.add(TitleNode(title, version, parent, dri, kind, sourceSets))
+}
+
+class ListNode(
+ val tabTitle: String,
+ val colTitle: String,
+ val children: List<JavadocListEntry>,
+ val dri: Set<DRI>,
+ val kind: Kind,
+ sourceSets: Set<SourceSetData>
+) : JavadocContentNode(dri, kind, sourceSets) {
+ override val contentMap: Map<String, Any?> by lazy {
+ mapOf(
+ "tabTitle" to tabTitle,
+ "colTitle" to colTitle,
+ "list" to children
+ )
+ }
+}
+
+fun JavaContentGroupBuilder.list(
+ tabTitle: String,
+ colTitle: String,
+ dri: Set<DRI>,
+ kind: Kind,
+ children: List<JavadocListEntry>
+) {
+ list.add(ListNode(tabTitle, colTitle, children, dri, kind, sourceSets))
+}
+
+data class SimpleJavadocListEntry(val content: String) : JavadocListEntry {
+ override val stringTag: String = content
+}
+
+class LinkJavadocListEntry(
+ val name: String,
+ val dri: Set<DRI>,
+ val kind: Kind = ContentKind.Symbol,
+ val sourceSets: Set<SourceSetData>
+) :
+ JavadocListEntry {
+ override val stringTag: String
+ get() = if (builtString == null)
+ throw IllegalStateException("stringTag for LinkJavadocListEntry accessed before build() call")
+ else builtString!!
+
+ private var builtString: String? = null
+
+ fun build(body: (String, Set<DRI>, Kind, List<SourceSetData>) -> String) {
+ builtString = body(name, dri, kind, sourceSets.toList())
+ }
+}
+
+data class RowJavadocListEntry(val link: LinkJavadocListEntry, val doc: String) : JavadocListEntry {
+ override val stringTag: String = ""
+}
+
+data class CompoundJavadocListEntry(
+ val name: String,
+ val content: List<JavadocListEntry>
+) : JavadocListEntry {
+ override val stringTag: String
+ get() = if (builtString == null)
+ throw IllegalStateException("stringTag for CompoundJavadocListEntry accessed before build() call")
+ else builtString!!
+
+ private var builtString: String? = null
+
+ fun build(body: (List<JavadocListEntry>) -> String) {
+ builtString = body(content)
+ }
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt
new file mode 100644
index 00000000..b73b2b36
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt
@@ -0,0 +1,328 @@
+package javadoc.pages
+
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiType
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.base.renderers.platforms
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.pages.*
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType
+
+interface JavadocPageNode : ContentPage {
+ val contentMap: Map<String, Any?>
+}
+
+class JavadocModulePageNode(
+ override val name: String, override val content: JavadocContentNode, override val children: List<PageNode>,
+ override val dri: Set<DRI>
+) :
+ RootPageNode(),
+ JavadocPageNode {
+ override val contentMap: Map<String, Any?> by lazy { mapOf("kind" to "main") + content.contentMap }
+
+ val version: String = "0.0.1"
+ val pathToRoot: String = ""
+
+ override val documentable: Documentable? = null
+ override val embeddedResources: List<String> = emptyList()
+ override fun modified(name: String, ch: List<PageNode>): RootPageNode =
+ JavadocModulePageNode(name, content, ch, dri)
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ ch: List<PageNode>
+ ): ContentPage = JavadocModulePageNode(name, content as JavadocContentNode, ch, dri)
+}
+
+class JavadocPackagePageNode(
+ override val name: String,
+ override val content: JavadocContentNode,
+ override val dri: Set<DRI>,
+
+ override val documentable: Documentable? = null,
+ override val children: List<PageNode> = emptyList(),
+ override val embeddedResources: List<String> = listOf()
+) : JavadocPageNode {
+ override val contentMap: Map<String, Any?> by lazy { mapOf("kind" to "package") + content.contentMap }
+ override fun modified(
+ name: String,
+ ch: List<PageNode>
+ ): PageNode = JavadocPackagePageNode(
+ name,
+ content,
+ dri,
+ documentable,
+ ch,
+ embeddedResources
+ )
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ ch: List<PageNode>
+ ): ContentPage =
+ JavadocPackagePageNode(
+ name,
+ content as JavadocContentNode,
+ dri,
+ documentable,
+ ch,
+ embeddedResources
+ )
+}
+
+class JavadocClasslikePageNode(
+ override val name: String,
+ override val content: JavadocContentNode,
+ override val dri: Set<DRI>,
+
+ override val documentable: Documentable? = null,
+ override val children: List<PageNode> = emptyList(),
+ override val embeddedResources: List<String> = listOf()
+) : JavadocPageNode {
+ override val contentMap: Map<String, Any?> by lazy { mapOf("kind" to "class") + content.contentMap }
+ override fun modified(
+ name: String,
+ children: List<PageNode>
+ ): PageNode = JavadocClasslikePageNode(name, content, dri, documentable, children, embeddedResources)
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): ContentPage =
+ JavadocClasslikePageNode(name, content as JavadocContentNode, dri, documentable, children, embeddedResources)
+}
+
+class AllClassesPage(val classes: List<JavadocClasslikePageNode>) : JavadocPageNode {
+ val classEntries = classes.map { LinkJavadocListEntry(it.name, it.dri, ContentKind.Classlikes, it.platforms().toSet()) }
+
+ override val contentMap: Map<String, Any?> = mapOf(
+ "title" to "All Classes",
+ "list" to classEntries
+ )
+
+ override val name: String = "All Classes"
+ override val dri: Set<DRI> = setOf(DRI.topLevel)
+
+ override val documentable: Documentable? = null
+ override val embeddedResources: List<String> = emptyList()
+
+ override val content: ContentNode =
+ EmptyNode(
+ DRI.topLevel,
+ ContentKind.Classlikes,
+ classes.flatMap { it.platforms() }.toSet()
+ )
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): ContentPage = TODO()
+
+ override fun modified(name: String, children: List<PageNode>): PageNode =
+ TODO()
+
+ override val children: List<PageNode> = emptyList()
+
+}
+
+class TreeViewPage(
+ override val name: String,
+ val packages: List<JavadocPackagePageNode>?,
+ val classes: List<JavadocClasslikePageNode>?,
+ override val dri: Set<DRI>,
+ override val documentable: Documentable?,
+ val root: RootPageNode
+) : JavadocPageNode {
+ init {
+ assert(packages == null || classes == null)