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)
+ assert(packages != null || classes != null)
+ }
+
+ private val documentables = root.children.filterIsInstance<ContentPage>().flatMap { node ->
+ getDocumentableEntries(node)
+ }.groupBy({ it.first }) { it.second }.map { (l, r) -> l to r.first() }.toMap()
+
+ private val descriptorMap = getDescriptorMap(root)
+ private val inheritanceTuple = generateInheritanceTree()
+ private val classGraph = inheritanceTuple.first
+ private val interfaceGraph = inheritanceTuple.second
+
+ override val children: List<PageNode> = emptyList()
+
+ override val contentMap: Map<String, Any?> = mapOf(
+ "title" to (when (documentable) {
+ is DPackage -> "$name Class Hierarchy"
+ else -> "All packages"
+ }),
+ "name" to name,
+ "kind" to (when (documentable) {
+ is DPackage -> "package"
+ else -> "main"
+ }),
+ "list" to packages.orEmpty() + classes.orEmpty(),
+ "classGraph" to classGraph,
+ "interfaceGraph" to interfaceGraph
+ )
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ dri: Set<DRI>,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): ContentPage =
+ TreeViewPage(
+ name,
+ packages = children.filterIsInstance<JavadocPackagePageNode>().takeIf { it.isNotEmpty() },
+ classes = children.filterIsInstance<JavadocClasslikePageNode>().takeIf { it.isNotEmpty() },
+ dri = dri,
+ documentable = documentable,
+ root = root
+ )
+
+ override fun modified(name: String, children: List<PageNode>): PageNode =
+ TreeViewPage(
+ name,
+ packages = children.filterIsInstance<JavadocPackagePageNode>().takeIf { it.isNotEmpty() },
+ classes = children.filterIsInstance<JavadocClasslikePageNode>().takeIf { it.isNotEmpty() },
+ dri = dri,
+ documentable = documentable,
+ root = root
+ )
+
+ override val embeddedResources: List<String> = emptyList()
+
+ override val content: ContentNode = EmptyNode(
+ DRI.topLevel,
+ ContentKind.Classlikes,
+ emptySet()
+ )
+
+ private fun generateInheritanceTree(): Pair<InheritanceNode, InheritanceNode> {
+ val mergeMap = mutableMapOf<DRI, InheritanceNode>()
+
+ fun addToMap(info: InheritanceNode, map: MutableMap<DRI, InheritanceNode>) {
+ if (map.containsKey(info.dri))
+ map.computeIfPresent(info.dri) { _, info2 ->
+ info.copy(children = (info.children + info2.children).distinct())
+ }!!.children.forEach { addToMap(it, map) }
+ else
+ map[info.dri] = info
+ }
+
+ fun collect(dri: DRI): InheritanceNode =
+ InheritanceNode(
+ dri,
+ mergeMap[dri]?.children.orEmpty().map { collect(it.dri) },
+ mergeMap[dri]?.interfaces.orEmpty(),
+ mergeMap[dri]?.isInterface ?: false
+ )
+
+ fun classTreeRec(node: InheritanceNode): List<InheritanceNode> = if (node.isInterface) {
+ node.children.flatMap (::classTreeRec)
+ }
+ else {
+ listOf(node.copy(children = node.children.flatMap (::classTreeRec)))
+ }
+ fun classTree(node: InheritanceNode) = classTreeRec(node).single()
+
+ fun interfaceTreeRec(node: InheritanceNode): List<InheritanceNode> = if (node.isInterface) {
+ listOf(node.copy(children = node.children.filter { it.isInterface }))
+ }
+ else {
+ node.children.flatMap(::interfaceTreeRec)
+ }
+
+ fun interfaceTree(node: InheritanceNode) = interfaceTreeRec(node).first() // TODO.single()
+
+ fun gatherPsiClasses(psi: PsiType): List<Pair<PsiType, List<PsiType>>> = psi.superTypes.toList().let { l ->
+ listOf(psi to l) + l.flatMap { gatherPsiClasses(it) }
+ }
+
+ fun gatherPsiClasses(psi: PsiClass): List<Pair<PsiType, List<PsiType>>> =
+ psi.superTypes.flatMap(::gatherPsiClasses)
+
+ val psiClasses = documentables.flatMap { (_, v) -> (v as? WithExpectActual)?.sources?.values.orEmpty() }
+ .filterIsInstance<PsiDocumentableSource>().mapNotNull { it.psi as? PsiClass }.flatMap(::gatherPsiClasses)
+ .groupBy({ it.first }) { it.second }
+ .map { (k, v) -> k to v.flatten().distinct() }.toMap()
+
+ val s1 = descriptorMap.flatMap { (k, v) ->
+ v.typeConstructor.supertypes.map { getClassDescriptorForType(it) }.map { it to listOf(v) }
+ }.let { it + it.flatMap { e -> e.second.map { it to emptyList<ClassDescriptor>() } } }
+ .groupBy({ it.first }) { it.second }
+ .map { (k, v) ->
+ InheritanceNode(
+ DRI.from(k),
+ v.flatten().map { InheritanceNode(DRI.from(it)) },
+ k.typeConstructor.supertypes.map { getClassDescriptorForType(it) }
+ .mapNotNull { cd -> cd.takeIf { it.kind == ClassKind.INTERFACE }?.let { DRI.from(it) } },
+ isInterface = k.kind == ClassKind.INTERFACE
+ )
+ }
+ s1.forEach { addToMap(it, mergeMap) }
+ val g = mergeMap.entries.find { it.key.classNames == "Any" }?.value?.dri?.let(::collect)
+
+ return g?.let{classTree(it) to interfaceTree(it)} ?: run { throw IllegalStateException("Building inheritance tree failed") }
+ }
+
+ private fun generateInterfaceGraph() {
+ documentables.values.filterIsInstance<DInterface>()
+ }
+
+ private fun getDocumentableEntries(node: ContentPage): List<Pair<DRI, Documentable>> =
+ listOfNotNull(node.documentable?.let { it.dri to it }) +
+ node.children.filterIsInstance<ContentPage>().flatMap(::getDocumentableEntries)
+
+ private fun getDescriptorMap(root: RootPageNode): Map<DRI, ClassDescriptor> {
+ val map: MutableMap<DRI, ClassDescriptor> = mutableMapOf()
+ documentables
+ .mapNotNull { (k, v) ->
+ v.descriptorForPlatform()?.let { k to it }?.also { (k, v) -> map[k] = v }
+ }.map { it.second }.forEach { gatherSupertypes(it, map) }
+
+ return map.toMap()
+ }
+
+ private fun gatherSupertypes(descriptor: ClassDescriptor, map: MutableMap<DRI, ClassDescriptor>) {
+ map.putIfAbsent(DRI.from(descriptor), descriptor)
+ descriptor.typeConstructor.supertypes.map { getClassDescriptorForType(it) }
+ .forEach { gatherSupertypes(it, map) }
+ }
+
+ private fun Documentable?.descriptorForPlatform(platform: Platform = Platform.jvm) =
+ (this as? WithExpectActual).descriptorForPlatform(platform)
+
+ private fun WithExpectActual?.descriptorForPlatform(platform: Platform = Platform.jvm) = this?.let {
+ it.sources.entries.find { it.key.platform == platform }?.value?.let { it as? DescriptorDocumentableSource }?.descriptor as? ClassDescriptor
+ }
+
+ data class InheritanceNode(
+ val dri: DRI,
+ val children: List<InheritanceNode> = emptyList(),
+ val interfaces: List<DRI> = emptyList(),
+ val isInterface: Boolean = false
+ ) {
+ override fun equals(other: Any?): Boolean = other is InheritanceNode && other.dri == dri
+ override fun hashCode(): Int = dri.hashCode()
+ }
+}
+
+interface ContentValue
+data class StringValue(val text: String) : ContentValue
+data class ListValue(val list: List<String>) : ContentValue \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt
new file mode 100644
index 00000000..ae573007
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt
@@ -0,0 +1,161 @@
+package javadoc.pages
+
+import java.time.LocalDate
+
+internal fun overviewSummary(title: String, version: String) = """
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!-- NewPage -->
+<html lang="en">
+<head>
+<title>Overview ($title $version API)</title>
+<meta name="date" content="${LocalDate.now()}">
+<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+</head>
+<body>
+<script type="text/javascript"><!--
+ try {
+ if (location.href.indexOf('is-external=true') == -1) {
+ parent.document.title="Overview ($title $version API)";
+ }
+ }
+ catch(err) {
+ }
+//-->
+</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+<!-- ========= START OF TOP NAVBAR ======= -->
+<div class="topNav"><a name="navbar.top">
+<!-- -->
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a name="navbar.top.firstrow">
+<!-- -->
+</a>
+<ul class="navList" title="Navigation">
+<li class="navBarCell1Rev">Overview</li>
+<li>Package</li>
+<li>Class</li>
+<li><a href="overview-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
+<li><a href="index-all.html">Index</a></li>
+<li><a href="help-doc.html">Help</a></li>
+</ul>
+</div>
+<div class="subNav">
+<ul class="navList">
+<li>Prev</li>
+<li>Next</li>
+</ul>
+<ul class="navList">
+<li><a href="index.html?overview-summary.html" target="_top">Frames</a></li>
+<li><a href="overview-summary.html" target="_top">No&nbsp;Frames</a></li>
+</ul>
+<ul class="navList" id="allclasses_navbar_top">
+<li><a href="allclasses-noframe.html">All&nbsp;Classes</a></li>
+</ul>
+<div>
+<script type="text/javascript"><!--
+ allClassesLink = document.getElementById("allclasses_navbar_top");
+ if(window==top) {
+ allClassesLink.style.display = "block";
+ }
+ else {
+ allClassesLink.style.display = "none";
+ }
+ //-->
+</script>
+</div>
+<a name="skip.navbar.top">
+<!-- -->
+</a></div>
+<!-- ========= END OF TOP NAVBAR ========= -->
+<div class="header">
+<h1 class="title">terrain-generator 0.0.1 API</h1>
+</div>
+<div class="contentContainer">
+<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Packages table, listing packages, and an explanation">
+<caption><span>Packages</span><span class="tabEnd">&nbsp;</span></caption>
+<tr>
+<th class="colFirst" scope="col">Package</th>
+<th class="colLast" scope="col">Description</th>
+</tr>
+<tbody>
+<tr class="altColor">
+<td class="colFirst"><a href="adaptation/package-summary.html">adaptation</a></td>
+<td class="colLast">&nbsp;</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a href="app/package-summary.html">app</a></td>
+<td class="colLast">&nbsp;</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a href="common/package-summary.html">common</a></td>
+<td class="colLast">&nbsp;</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a href="model/package-summary.html">model</a></td>
+<td class="colLast">&nbsp;</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a href="processor/package-summary.html">processor</a></td>
+<td class="colLast">&nbsp;</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a href="transformation/package-summary.html">transformation</a></td>
+<td class="colLast">&nbsp;</td>
+</tr>
+</tbody>
+</table>
+</div>
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<div class="bottomNav"><a name="navbar.bottom">
+<!-- -->
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a name="navbar.bottom.firstrow">
+<!-- -->
+</a>
+<ul class="navList" title="Navigation">
+<li class="navBarCell1Rev">Overview</li>
+<li>Package</li>
+<li>Class</li>
+<li><a href="overview-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
+<li><a href="index-all.html">Index</a></li>
+<li><a href="help-doc.html">Help</a></li>
+</ul>
+</div>
+<div class="subNav">
+<ul class="navList">
+<li>Prev</li>
+<li>Next</li>
+</ul>
+<ul class="navList">
+<li><a href="index.html?overview-summary.html" target="_top">Frames</a></li>
+<li><a href="overview-summary.html" target="_top">No&nbsp;Frames</a></li>
+</ul>
+<ul class="navList" id="allclasses_navbar_bottom">
+<li><a href="allclasses-noframe.html">All&nbsp;Classes</a></li>
+</ul>
+<div>
+<script type="text/javascript"><!--
+ allClassesLink = document.getElementById("allclasses_navbar_bottom");
+ if(window==top) {
+ allClassesLink.style.display = "block";
+ }
+ else {
+ allClassesLink.style.display = "none";
+ }
+ //-->
+</script>
+</div>
+<a name="skip.navbar.bottom">
+<!-- -->
+</a></div>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+</body>
+</html>
+""" \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt
new file mode 100644
index 00000000..98aa2344
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt
@@ -0,0 +1,391 @@
+package javadoc.pages
+
+import kotlinx.html.html
+import kotlinx.html.stream.createHTML
+import org.jetbrains.dokka.pages.ClasslikePageNode
+import org.jetbrains.dokka.pages.ModulePageNode
+import org.jetbrains.dokka.pages.PackagePageNode
+import org.jetbrains.dokka.pages.PageNode
+import java.time.LocalDate
+
+class NavbarGenerator(val page: PageNode) {
+ val activeClass = "navBarCell1Rev"
+ fun pathToRoot() = "???" // TODO
+ val navItems = listOf("Overview", "Package", "Class", "Tree", "Deprecated", "Index", "Help")
+
+ // private fun items = navItems.map {itemLink}
+// fun navItemLink()
+ val x = createHTML().html {}
+
+ private fun navList(content: String) = """<ul class="navList" title="Navigation">
+ $content
+ </ul>
+ """.trimIndent()
+
+// private fun navList(): String {
+// when (page) {
+// is PackagePageNode ->
+// }
+// """
+//<li><a href="../index.html">Overview</a></li>
+//<li><a href="package-summary.html">Package</a></li>
+//<li class="navBarCell1Rev">Class</li>
+//"""
+// val classItem = if (page is ClasslikePageNode) {
+// "Class".wrapInTag("li", mapOf("class" to activeClass))
+// }
+// val treeItem = if (page is ModulePageNode) {
+// "<li><a href=\"overview-tree.html\">Tree</a></li>\n"
+// } else {
+// "<li><a href=\"package-tree.html\">Tree</a></li>\n"
+// }
+//
+// val navListEnd = """
+//<li><a href="${pathToRoot()}deprecated-list.html">Deprecated</a></li>
+//<li><a href="${pathToRoot()}index-all.html">Index</a></li>
+//<li><a href="${pathToRoot()}help-doc.html">Help</a></li>
+//""".trimIndent()
+// }
+
+ private fun bottomNavbar(page: PageNode): String =
+ """
+ |<nav role="navigation">
+ |<!-- ======= START OF BOTTOM NAVBAR ====== -->
+ |<div class="bottomNav"><a id="navbar.bottom">
+ |<!-- -->
+ |</a>
+ |<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+ |<a id="navbar.bottom.firstrow">
+ |<!-- -->
+ |</a>
+ ${navList("????")}
+ |</div>
+ |<div class="subNav">
+ |<div>
+ |<ul class="subNavList">
+ |<li>Summary:&nbsp;</li>
+ |<li>Nested&nbsp;|&nbsp;</li>
+ |<li>Field&nbsp;|&nbsp;</li>
+ |<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+ |<li><a href="#method.summary">Method</a></li>
+ |</ul>
+ |<ul class="subNavList">
+ |<li>Detail:&nbsp;</li>
+ |<li>Field&nbsp;|&nbsp;</li>
+ |<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+ |<li><a href="#method.detail">Method</a></li>
+ |</ul>
+ |</div>
+ |</div>
+ |<a id="skip.navbar.bottom">
+ |<!-- -->
+ |</a>
+ |<!-- ======== END OF BOTTOM NAVBAR ======= -->
+ |</nav>"""
+}
+
+internal fun pageStart(title: String, version: String, documentTitle: String, pathToRoot: String) = """
+ |<!DOCTYPE HTML>
+ |<!-- NewPage -->
+ |<html lang="en">
+ |<head>
+ |<title>$documentTitle ($title $version API)</title>
+ |<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ |<meta name="dc.created" content="${LocalDate.now()}">
+ |<link rel="stylesheet" type="text/css" href="${pathToRoot}stylesheet.css" title="Style">
+ |<link rel="stylesheet" type="text/css" href="${pathToRoot}jquery/jquery-ui.css" title="Style">
+ |<script type="text/javascript" src="${pathToRoot}script.js"></script>
+ |<script type="text/javascript" src="${pathToRoot}jquery/jszip/dist/jszip.min.js"></script>
+ |<script type="text/javascript" src="${pathToRoot}jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+ |<!--[if IE]>
+ |<script type="text/javascript" src="${pathToRoot}jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+ |<![endif]-->
+ |<script type="text/javascript" src="${pathToRoot}jquery/jquery-$jQueryVersion.js"></script>
+ |<script type="text/javascript" src="${pathToRoot}jquery/jquery-migrate-$jQueryMigrateVersion.js"></script>
+ |<script type="text/javascript" src="${pathToRoot}jquery/jquery-ui.js"></script>
+ |</head>
+ |<body>
+ |<script type="text/javascript"><!--
+ | try {
+ | if (location.href.indexOf('is-external=true') == -1) {
+ | parent.document.title="$documentTitle ($title $version API)";
+ | }
+ | }
+ | catch(err) {
+ | }
+ |//-->
+ |var pathtoroot = "$pathToRoot";
+ |var useModuleDirectories = true;
+ |loadScripts(document, 'script');</script>
+ |<noscript>
+ |<div>JavaScript is disabled on your browser.</div>
+ |</noscript>
+ |<header role="banner">
+ |<nav role="navigation">
+ |<div class="fixedNav">""".trimMargin("|")
+
+internal fun topNavbar(page: PageNode, pathToRoot: String): String = """
+ |<!-- ========= START OF TOP NAVBAR ======= -->
+ |<div class="topNav"><a id="navbar.top">
+ |<!-- -->
+ |</a>
+ |<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+ |<a id="navbar.top.firstrow">
+ |<!-- -->
+ |</a>
+ |<ul class="navList" title="Navigation">
+ ${/*if ((page is JavadocPageNode) && page.pageType == PageType.Class)
+ "<li><a href=\"${pathToRoot}index.html\">Overview</a></li>"
+ else if (page is RootIndexPage)
+ "<li class=\"navBarCell1Rev\">Overview</li>"
+ else
+ "<li><a href=\"package-summary.html\">Package</a></li>\n"}
+ ${if ((page is JavadocPageNode) && page.pageType == PageType.Package)
+ "<li class=\"navBarCell1Rev\">Package</li>"
+ else
+ "<li>Package</li>"*/ ""}
+ |<li navBarCell1Rev>Class</li>
+ |<li><a href="overview-tree.html">Tree</a></li>
+ |<li><a href="${pathToRoot}deprecated-list.html">Deprecated</a></li>
+ |<li><a href="${pathToRoot}index-all.html">Index</a></li>
+ |<li><a href="${pathToRoot}help-doc.html">Help</a></li>
+ |</ul>
+ |</div>
+ |<div class="subNav">
+ |<ul class="navListSearch">
+ |<li><label for="search">SEARCH:</label>
+ |<input type="text" id="search" value="search" disabled="disabled">
+ |<input type="reset" id="reset" value="reset" disabled="disabled">
+ |</li>
+ |</ul>
+ |</div>
+ |<a id="skip.navbar.top">
+ |<!-- -->
+ |</a>
+ |<!-- ========= END OF TOP NAVBAR ========= -->""".trimMargin("|")
+
+internal fun indexPage(title: String, version: String, tabTitle: String, colTitle: String, packages: List<PageNode>) = """
+ |</div>
+ |<div class="navPadding">&nbsp;</div>
+ |<script type="text/javascript"><!--
+ |${'$'}('.navPadding').css('padding-top', ${'$'}('.fixedNav').css("height"));
+ |//-->
+ |</script>
+ |</nav>
+ |</header>
+ |<main role="main">
+ |<div class="header">
+ |<h1 class="title">$title $version API</h1>
+ |</div>
+ |<div class="contentContainer">
+ |<div class="overviewSummary">
+ |<table>
+ |<caption><span>$tabTitle</span><span class="tabEnd">&nbsp;</span></caption>
+ |<tr>
+ |<th class="colFirst" scope="col">$colTitle</th>
+ |<th class="colLast" scope="col">Description</th>
+ |</tr>
+ |<tbody>
+ ${packages.mapIndexed { i, e -> e.generateLink(i) }.joinToString("\n")}
+ |</tbody>
+ |</table>
+ |</div>
+ |</div>
+ |</main>
+ |<footer role="contentinfo">
+ |<nav role="navigation">
+ |<!-- ======= START OF BOTTOM NAVBAR ====== -->
+ |<div class="bottomNav"><a id="navbar.bottom">
+ |<!-- -->
+ |</a>
+ |<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+ |<a id="navbar.bottom.firstrow">
+ |<!-- -->
+ |</a>
+ |<ul class="navList" title="Navigation">
+ |<li class="navBarCell1Rev">Overview</li>
+ |<li>Package</li>
+ |<li>Class</li>
+ |<li><a href="overview-tree.html">Tree</a></li>
+ |<li><a href="deprecated-list.html">Deprecated</a></li>
+ |<li><a href="index-all.html">Index</a></li>
+ |<li><a href="help-doc.html">Help</a></li>
+ |</ul>
+ |</div>
+ |<a id="skip.navbar.bottom">
+ |<!-- -->
+ |</a>
+ |<!-- ======== END OF BOTTOM NAVBAR ======= -->
+ |</nav>
+ |</footer>
+ |</body>
+ |</html>
+ |""".trimMargin("|")
+
+fun classData(name: String, extends: String) = """
+ |<!-- ======== START OF CLASS DATA ======== -->
+ |<div class="header">
+ |<div class="subTitle">adaptation</div>
+ |<h2 title="Class $name" class="title">Class $name</h2>
+ |</div>
+ |<div class="contentContainer">
+ ${classInheritance()}
+ |<div class="description">
+ |<ul class="blockList">
+ |<li class="blockList">
+ |<hr>
+ |<br>
+ |<pre>public class <span class="typeNameLabel">$name</span>
+ |extends $name</pre>
+ |</li>
+ |</ul>
+ |</div>
+ |<div class="summary">
+ |<ul class="blockList">
+ |<li class="blockList">
+ |<!-- ======== NESTED CLASS SUMMARY ======== -->
+ |<ul class="blockList">
+ |<li class="blockList"><a name="nested.class.summary">
+ |<!-- -->
+ |</a>
+ |<h3>Nested Class Summary</h3>
+ |<table class="memberSummary" border="0" cellpadding="3" cellspacing="0" summary="Nested Class Summary table, listing nested classes, and an explanation">
+ |<caption><span>Nested Classes</span><span class="tabEnd">&nbsp;</span></caption>
+ |<tr>
+ |<th class="colFirst" scope="col">Modifier and Type</th>
+ |<th class="colLast" scope="col">Class and Description</th>
+ |</tr>
+ |<tr class="altColor">
+ |<td class="colFirst"><code>class&nbsp;</code></td>
+ |<td class="colLast"><code><span class="memberNameLink"><a href="../adaptation/Adaptation.AdaptationInternalClass.html" title="class in adaptation">Adaptation.AdaptationInternalClass</a></span></code>&nbsp;</td>
+ |</tr>
+ |<tr class="rowColor">
+ |<td class="colFirst"><code>static class&nbsp;</code></td>
+ |<td class="colLast"><code><span class="memberNameLink"><a href="../adaptation/Adaptation.AdaptationInternalStaticClass.html" title="class in adaptation">Adaptation.AdaptationInternalStaticClass</a></span></code>&nbsp;</td>
+ |</tr>
+ |</table>
+ |</li>
+ |</ul>
+ |<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+ |<ul class="blockList">
+ |<li class="blockList"><a name="constructor.summary">
+ |<!-- -->
+ |</a>
+ |<h3>Constructor Summary</h3>
+ |<table class="memberSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+ |<caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
+ |<tr>
+ |<th class="colOne" scope="col">Constructor and Description</th>
+ |</tr>
+ |<tr class="altColor">
+ |<td class="colOne"><code><span class="memberNameLink"><a href="../adaptation/Adaptation.html#Adaptation--">Adaptation</a></span>()</code>&nbsp;</td>
+ |</tr>
+ |</table>
+ |</li>
+ |</ul>
+ |<!-- ========== METHOD SUMMARY =========== -->
+ |<ul class="blockList">
+ |<li class="blockList"><a name="method.summary">
+ |<!-- -->
+ |</a>
+ |<h3>Method Summary</h3>
+ |<table class="memberSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
+ |<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t1" class="tableTab"><span><a href="javascript:show(1);">Static Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
+ |<tr>
+ |<th class="colFirst" scope="col">Modifier and Type</th>
+ |<th class="colLast" scope="col">Method and Description</th>
+ |</tr>
+ |<tr id="i0" class="altColor">
+ |<td class="colFirst"><code>static org.javatuples.Pair&lt;<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a>,java.lang.Boolean&gt;</code></td>
+ |<td class="colLast"><code><span class="memberNameLink"><a href="../adaptation/Adaptation.html#transform-model.ModelGraph-transformation.Transformation-">transform</a></span>(<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a>&nbsp;graph,
+ | <a href="../transformation/Transformation.html" title="interface in transformation">Transformation</a>&nbsp;transformation)</code>&nbsp;</td>
+ |</tr>
+ |</table>
+ |<ul class="blockList">
+ |<li class="blockList"><a name="methods.inherited.from.class.java.lang.Object">
+ |<!-- -->
+ |</a>
+ |<h3>Methods inherited from class&nbsp;java.lang.Object</h3>
+ |<code>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</code></li>
+ |</ul>
+ |</li>
+ |</ul>
+ |</li>
+ |</ul>
+ |</div>
+ |<div class="details">
+ |<ul class="blockList">
+ |<li class="blockList">
+ |<!-- ========= CONSTRUCTOR DETAIL ======== -->
+ |<ul class="blockList">
+ |<li class="blockList"><a name="constructor.detail">
+ |<!-- -->
+ |</a>
+ |<h3>Constructor Detail</h3>
+ |<a name="Adaptation--">
+ |<!-- -->
+ |</a>
+ |<ul class="blockListLast">
+ |<li class="blockList">
+ |<h4>Adaptation</h4>
+ |<pre>public&nbsp;Adaptation()</pre>
+ |</li>
+ |</ul>
+ |</li>
+ |</ul>
+ |<!-- ============ METHOD DETAIL ========== -->
+ |<ul class="blockList">
+ |<li class="blockList"><a name="method.detail">
+ |<!-- -->
+ |</a>
+ |<h3>Method Detail</h3>
+ |<a name="transform-model.ModelGraph-transformation.Transformation-">
+ |<!-- -->
+ |</a>
+ |<ul class="blockListLast">
+ |<li class="blockList">
+ |<h4>transform</h4>
+ |<pre>public static&nbsp;org.javatuples.Pair&lt;<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a>,java.lang.Boolean&gt;&nbsp;transform(<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a>&nbsp;graph,
+ | <a href="../transformation/Transformation.html" title="interface in transformation">Transformation</a>&nbsp;transformation)</pre>
+ |</li>
+ |</ul>
+ |</li>
+ |</ul>
+ |</li>
+ |</ul>
+ |</div>
+ |</div>
+ |<!-- ========= END OF CLASS DATA ========= -->
+""".trimIndent()
+
+fun classInheritance() = """
+ |<ul class="inheritance">
+ |<li>java.lang.Object</li>
+ |<li>
+ |<ul class="inheritance">
+ |<li>adaptation.Adaptation</li>
+ |</ul>
+ |</li>
+ |</ul>
+ """
+
+internal fun String.wrapInTag(tag: String, options: Map<String, String>) =
+ "<$tag ${options.map { it.key + "=\"" + it.value + '"' }.joinToString(" ")}>$this</$tag>"
+
+fun PageNode.generateLink(i: Int) = "\n<tr class=\"altColor\" id=\"i$i\">\n" + run {
+ val path = /*if (this is JavadocPageNode && this.pageType != PageType.Package) "$filename.html" else*/ "$name/package-summary.html"
+
+ name.wrapInTag("a", mapOf("href" to path))
+ .wrapInTag(
+ "th",
+ mapOf("class" to "colFirst", "scope" to "row")
+ ) + "<td class=\"colLast\">&nbsp;</td>\n</tr>"
+}
+
+internal enum class NavigableType {
+ Overview, Package, Class, Tree, Deprecated, Index, Help
+}
+
+internal interface Navigable {
+ val type: NavigableType
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt
new file mode 100644
index 00000000..fc0771e7
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt
@@ -0,0 +1,63 @@
+package javadoc.pages
+
+import org.jetbrains.dokka.pages.*
+import org.jetbrains.dokka.transformers.pages.PageTransformer
+
+val preprocessors = listOf(ResourcesInstaller, TreeViewInstaller, AllClassesPageInstaller)
+
+object ResourcesInstaller : PageTransformer {
+ override fun invoke(input: RootPageNode): RootPageNode = input.modified(
+ children = input.children +
+ RendererSpecificResourcePage(
+ "resourcePack",
+ emptyList(),
+ RenderingStrategy.Copy("/static_res")
+ )
+ )
+}
+
+object TreeViewInstaller : PageTransformer {
+ override fun invoke(input: RootPageNode): RootPageNode = install(input, input) as RootPageNode
+
+ private fun install(node: PageNode, root: RootPageNode): PageNode = when (node) {
+ is JavadocModulePageNode -> installOverviewTreeNode(node, root)
+ is JavadocPackagePageNode -> installPackageTreeNode(node, root)
+ else -> node
+ }
+
+ private fun installOverviewTreeNode(node: JavadocModulePageNode, root: RootPageNode): JavadocModulePageNode {
+ val overviewTree = TreeViewPage(
+ name = "Class Hierarchy",
+ packages = node.children<JavadocPackagePageNode>().map { installPackageTreeNode(it, root) },
+ classes = null,
+ dri = node.dri,
+ documentable = null,
+ root = root
+ )
+
+ return node.modified(ch = node.children.map { node -> install(node, root) } + overviewTree) as JavadocModulePageNode
+ }
+
+ private fun installPackageTreeNode(node: JavadocPackagePageNode, root: RootPageNode): JavadocPackagePageNode {
+ val packageTree = TreeViewPage(
+ name = "${node.name}",
+ packages = null,
+ classes = node.children.filterIsInstance<JavadocClasslikePageNode>(),
+ dri = node.dri,
+ documentable = node.documentable,
+ root = root
+ )
+
+ return node.modified(ch = node.children + packageTree) as JavadocPackagePageNode
+ }
+}
+
+object AllClassesPageInstaller : PageTransformer {
+ override fun invoke(input: RootPageNode): RootPageNode {
+ val classes = (input as JavadocModulePageNode).children.filterIsInstance<JavadocPackagePageNode>().flatMap {
+ it.children.filterIsInstance<JavadocClasslikePageNode>()
+ }
+
+ return input.modified(children = input.children + AllClassesPage(classes))
+ }
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/pages.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/pages.kt
new file mode 100644
index 00000000..0486369a
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/pages.kt
@@ -0,0 +1,17 @@
+package javadoc.pages
+
+internal const val jQueryVersion = "3.3.1"
+internal const val jQueryMigrateVersion = "3.0.1"
+
+//class PackageSummary(val page: PageNode) : RendererSpecificPage {
+// override val name = "package-summary"
+// override val children = emptyList<PageNode>()
+// override fun modified(name: String, children: List<PageNode>) = this
+//
+// override val strategy = RenderingStrategy.Write(content())
+//
+// private fun content(): String = pageStart(page.name, "0.0.1", page.name, "../") + // TODO
+// topNavbar(page, "???")
+//
+//}
+