diff options
author | Andrzej Ratajczak <andrzej.ratajczak98@gmail.com> | 2020-03-13 10:46:33 +0100 |
---|---|---|
committer | Błażej Kardyś <bkardys@virtuslab.com> | 2020-06-23 02:19:14 +0200 |
commit | 3940153fd08e0c0596ac289766d9ef2877b56591 (patch) | |
tree | ccf7bd66800c512a357ad0e31ca42f8cefcc0dcb /plugins/javadoc/src/main/kotlin | |
parent | f6530934d36fbb977c2b7c4eb3669a8f581dd9f5 (diff) | |
download | dokka-3940153fd08e0c0596ac289766d9ef2877b56591.tar.gz dokka-3940153fd08e0c0596ac289766d9ef2877b56591.tar.bz2 dokka-3940153fd08e0c0596ac289766d9ef2877b56591.zip |
First version of javadoc output generation
Diffstat (limited to 'plugins/javadoc/src/main/kotlin')
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 Frames</a></li> +</ul> +<ul class="navList" id="allclasses_navbar_top"> +<li><a href="allclasses-noframe.html">All 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"> </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"> </td> +</tr> +<tr class="rowColor"> +<td class="colFirst"><a href="app/package-summary.html">app</a></td> +<td class="colLast"> </td> +</tr> +<tr class="altColor"> +<td class="colFirst"><a href="common/package-summary.html">common</a></td> +<td class="colLast"> </td> +</tr> +<tr class="rowColor"> +<td class="colFirst"><a href="model/package-summary.html">model</a></td> +<td class="colLast"> </td> +</tr> +<tr class="altColor"> +<td class="colFirst"><a href="processor/package-summary.html">processor</a></td> +<td class="colLast"> </td> +</tr> +<tr class="rowColor"> +<td class="colFirst"><a href="transformation/package-summary.html">transformation</a></td> +<td class="colLast"> </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 Frames</a></li> +</ul> +<ul class="navList" id="allclasses_navbar_bottom"> +<li><a href="allclasses-noframe.html">All 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: </li> + |<li>Nested | </li> + |<li>Field | </li> + |<li><a href="#constructor.summary">Constr</a> | </li> + |<li><a href="#method.summary">Method</a></li> + |</ul> + |<ul class="subNavList"> + |<li>Detail: </li> + |<li>Field | </li> + |<li><a href="#constructor.detail">Constr</a> | </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"> </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"> </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"> </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 </code></td> + |<td class="colLast"><code><span class="memberNameLink"><a href="../adaptation/Adaptation.AdaptationInternalClass.html" title="class in adaptation">Adaptation.AdaptationInternalClass</a></span></code> </td> + |</tr> + |<tr class="rowColor"> + |<td class="colFirst"><code>static class </code></td> + |<td class="colLast"><code><span class="memberNameLink"><a href="../adaptation/Adaptation.AdaptationInternalStaticClass.html" title="class in adaptation">Adaptation.AdaptationInternalStaticClass</a></span></code> </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"> </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> </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"> </span></span><span id="t1" class="tableTab"><span><a href="javascript:show(1);">Static Methods</a></span><span class="tabEnd"> </span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd"> </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<<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a>,java.lang.Boolean></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> graph, + | <a href="../transformation/Transformation.html" title="interface in transformation">Transformation</a> transformation)</code> </td> + |</tr> + |</table> + |<ul class="blockList"> + |<li class="blockList"><a name="methods.inherited.from.class.java.lang.Object"> + |<!-- --> + |</a> + |<h3>Methods inherited from class 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 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 org.javatuples.Pair<<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a>,java.lang.Boolean> transform(<a href="../model/ModelGraph.html" title="class in model">ModelGraph</a> graph, + | <a href="../transformation/Transformation.html" title="interface in transformation">Transformation</a> 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\"> </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, "???") +// +//} + |