Skip to content

Commit

Permalink
Update dokka to 1.4.10.2
Browse files Browse the repository at this point in the history
Fix location provider and provide nice paths.

Change the way how we restructure pages structure so search bar also works with documentation pages
  • Loading branch information
romanowski committed Oct 21, 2020
1 parent a678eef commit 0b3d947
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 206 deletions.
7 changes: 6 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ val dokka_version: String by project

dependencies {
compileOnly("org.jetbrains.dokka:dokka-core:$dokka_version")

// Expose dependency to dokka in .pom file
apiElements("org.jetbrains.dokka:dokka-core:$dokka_version")
apiElements("org.jetbrains.dokka:dokka-base:$dokka_version")

implementation("org.jetbrains.dokka:dokka-base:$dokka_version")
implementation("com.vladsch.flexmark:flexmark-all:0.42.12")
implementation("nl.big-o:liqp:0.6.7")
Expand Down Expand Up @@ -119,5 +123,6 @@ publishing {

// Configure dokka
tasks.dokkaHtml {
pluginsConfiguration.put("ExternalDocsTooKey", "documentation")
// TODO (#37): use pluginConfiguration
pluginsMapConfiguration.put("ExternalDocsTooKey", "documentation")
}
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
kotlin.code.style=official

kotlin_version=1.4.0
dokka_version=1.4.0
kotlin_version=1.4.10
dokka_version=1.4.10.2

language_version=1.4
143 changes: 143 additions & 0 deletions src/main/kotlin/com/virtuslab/dokka/site/StaticSiteContext.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.virtuslab.dokka.site

import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.doc.DocTag
import org.jetbrains.dokka.model.doc.Text
import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.model.toDisplaySourceSet
import org.jetbrains.dokka.pages.ContentKind
import org.jetbrains.dokka.pages.ContentNode
import org.jetbrains.dokka.pages.DCI
import org.jetbrains.dokka.pages.PageNode
import org.jetbrains.dokka.plugability.DokkaContext
import java.io.File

class StaticSiteContext(val root: File, cxt: DokkaContext){
val docsFile = File(root, "docs")

fun indexPage(): BaseStaticSiteProcessor.StaticPageNode? {
val files = listOf(File(root, "index.html"), File(root, "index.md")).filter { it.exists() }
if (files.size > 1) println("ERROR: Multiple root index pages found: ${files.map { it.absolutePath }}") // TODO (#14): provide proper error handling
return loadFiles(files).firstOrNull()
}

private val mySourceSet = cxt.configuration.sourceSets.toSet()
private val myDisplaySourceSet = mySourceSet.map { it.toDisplaySourceSet() }.toSet()

private val layouts: Map<String, TemplateFile> by lazy {
val layoutRoot = File(root, "_layouts")
val dirs: Array<File> = layoutRoot.listFiles() ?: emptyArray()
dirs.map { loadTemplateFile(it) }.map { it.name() to it }.toMap()
}


private fun isValidTemplate(file: File): Boolean =
(file.isDirectory && !file.name.startsWith("_")) ||
file.name.endsWith(".md") ||
file.name.endsWith(".html")


private fun loadTemplate(from: File): BaseStaticSiteProcessor.LoadedTemplate? =
if (!isValidTemplate(from)) null else try {
val (indexes, children) = (from.listFiles()?.mapNotNull { loadTemplate(it) }
?: emptyList()).partition { it.isIndexPage() }
if (indexes.size > 1)
println("ERROR: Multiple index pages for $from found in ${indexes.map { it.file }}") // TODO (#14): provide proper error handling

fun loadIndexPage(): TemplateFile {
val indexFiles = from.listFiles { file -> file.name == "index.md" || file.name == "index.html" }
return when (indexFiles.size) {
0 -> emptyTemplate(from)
1 -> loadTemplateFile(indexFiles.first()).copy(file = from)
else -> throw java.lang.RuntimeException("ERROR: Multiple index pages found under ${from.path}")
}
}

val templateFile = if (from.isDirectory) loadIndexPage() else loadTemplateFile(from)

BaseStaticSiteProcessor.LoadedTemplate(templateFile, children, from)

} catch (e: RuntimeException) {
e.printStackTrace() // TODO (#14): provide proper error handling
null
}

private fun parseMarkdown(page: PreResolvedPage, dri: DRI, allDRIs: Map<String, DRI>): ContentNode {
val nodes = if (page.hasMarkdown) {
val parser = ExtendableMarkdownParser(page.code) { link ->
val driKey = if (link.startsWith("/")) {
// handle root related links
link.replace('/', '.').removePrefix(".")
} else {
val unSuffixedDri = dri.packageName!!.removeSuffix(".html").removeSuffix(".md")
val parentDri = unSuffixedDri.take(unSuffixedDri.indexOfLast('.'::equals)).removePrefix("_.")
"${parentDri}.${link.replace('/', '.')}"
}
allDRIs[driKey]
}

val docTag = try {
parser.parse()
} catch (e: Throwable) {
val msg = "Error rendering (dri = $dri): ${e.message}"
println("ERROR: $msg") // TODO (#14): provide proper error handling
Text(msg, emptyList())
}

asContent(docTag, dri)
} else emptyList()
return PartiallyRenderedContent(
page,
nodes,
DCI(setOf(dri), ContentKind.Empty),
myDisplaySourceSet,
emptySet(),
PropertyContainer.empty()
)
}

fun asContent(d: DocTag, dri: DRI) = DocTagToContentConverter().buildContent(
d,
DCI(setOf(dri), ContentKind.Empty),
mySourceSet,
emptySet(),
PropertyContainer.empty()
)

fun loadFiles(files: List<File>, customChildren: List<PageNode> = emptyList()): List<BaseStaticSiteProcessor.StaticPageNode> {
val all = files.mapNotNull { loadTemplate(it) }
fun flatten(it: BaseStaticSiteProcessor.LoadedTemplate): List<String> =
listOf(it.relativePath(root)) + it.children.flatMap { flatten(it) }

fun pathToDri(path: String) = DRI("_.$path")

val driMap = all.flatMap { flatten(it) }.map { it to pathToDri(it) }.toMap()

fun templateToPage(myTemplate: BaseStaticSiteProcessor.LoadedTemplate): BaseStaticSiteProcessor.StaticPageNode {
val dri = pathToDri(myTemplate.relativePath(root))
val page = try {
val properties = myTemplate.templateFile.layout()
?.let { mapOf("content" to myTemplate.templateFile.rawCode) } ?: emptyMap()

myTemplate.templateFile.resolveMarkdown(RenderingContext(properties, layouts))
} catch (e: Throwable) {
val msg = "Error rendering $myTemplate: ${e.message}"
println("ERROR: $msg") // TODO (#14): provide proper error handling
PreResolvedPage("", null, true)
}
val content = parseMarkdown(page, dri, driMap)
val children = myTemplate.children.map { templateToPage(it) }
return BaseStaticSiteProcessor.StaticPageNode(
myTemplate.templateFile.title(),
children + customChildren,
myTemplate,
setOf(dri),
emptyList(),
content
)
}
return all.map { templateToPage(it) }
}
}

29 changes: 25 additions & 4 deletions src/main/kotlin/com/virtuslab/dokka/site/StaticSitePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,47 @@ package com.virtuslab.dokka.site

import org.jetbrains.dokka.CoreExtensions
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.DokkaPlugin
import java.io.File

class StaticSitePlugin : DokkaPlugin() {
private val dokkaBase by lazy { plugin<DokkaBase>() }

private fun loadStaticSiteContext(cxt: DokkaContext): StaticSiteContext? =
cxt.configuration.pluginsConfiguration
.filter { it.fqPluginName == ExternalDocsTooKey }
.map { StaticSiteContext(File(it.values), cxt) }
.firstOrNull()

val customDocumentationProvider by extending {
dokkaBase.htmlPreprocessors providing { ctx ->
SitePagesCreator(ctx)
SitePagesCreator(loadStaticSiteContext(ctx))
} order {
before(dokkaBase.navigationPageInstaller)
before(dokkaBase.scriptsInstaller)
before(dokkaBase.stylesInstaller)
before(dokkaBase.packageListCreator)
}
}

val customIndexRootProvider by extending {
dokkaBase.htmlPreprocessors providing { ctx ->
RootIndexPageCreator(loadStaticSiteContext(ctx))
} order {
after(dokkaBase.navigationPageInstaller)
before(dokkaBase.styleAndScriptsAppender)
before(dokkaBase.scriptsInstaller)
before(dokkaBase.stylesInstaller)
}
}

val customDocumentationResources by extending {
dokkaBase.htmlPreprocessors providing { ctx ->
SiteResourceManager(ctx)
SiteResourceManager(loadStaticSiteContext(ctx))
} order {
// We want our css and scripts after default ones
after(dokkaBase.styleAndScriptsAppender)
after(dokkaBase.scriptsInstaller)
before(dokkaBase.stylesInstaller)
}
}

Expand Down
33 changes: 33 additions & 0 deletions src/main/kotlin/com/virtuslab/dokka/site/compat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.virtuslab.dokka.site

import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.model.DModule
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.Extension
import org.jetbrains.dokka.plugability.ExtensionBuilder
import org.jetbrains.dokka.plugability.OrderingKind
import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator


// TODO (#39): investigate if scala3doc can live without it
data class SourceSetWrapper(val sourceSet: DokkaConfiguration.DokkaSourceSet) {
fun toSet(): Set<DokkaConfiguration.DokkaSourceSet> = setOf(sourceSet)
fun <T> asMap(value: T): Map<DokkaConfiguration.DokkaSourceSet, T> = mapOf(sourceSet to value)
}

// TODO (#39): add fixes to in dokka
abstract class JavaSourceToDocumentableTranslator: SourceToDocumentableTranslator {
override suspend fun invoke(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): DModule =
process(sourceSet, context)

abstract fun process(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): DModule
}

// TODO (#39): fix that in dokka
class ExtensionBuilderEx {
fun <T: Any> newOrdering(old: ExtensionBuilder<T>, before: Array<Extension<*, *, *>>, after: Array<Extension<*, *, *>>) =
old.copy(ordering = OrderingKind.ByDsl {
before(*before)
after(*after)
})
}
27 changes: 15 additions & 12 deletions src/main/kotlin/com/virtuslab/dokka/site/locationProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.virtuslab.dokka.site
import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider
import org.jetbrains.dokka.base.resolvers.local.LocationProvider
import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory
import org.jetbrains.dokka.pages.ContentPage
import org.jetbrains.dokka.pages.PageNode
import org.jetbrains.dokka.pages.RootPageNode
import org.jetbrains.dokka.plugability.DokkaContext
Expand All @@ -14,16 +15,18 @@ class StaticSiteLocationProviderFactory(private val ctx: DokkaContext) : Locatio
}

class StaticSiteLocationProvider(ctx: DokkaContext, pageNode: RootPageNode) : DokkaLocationProvider(pageNode, ctx) {
override fun pathTo(node: PageNode, context: PageNode?): String =
if (node is BaseStaticSiteProcessor.StaticPageNode)
if (node.dri.contains(docsRootDRI)) "index"
else {
// replace title with original markdown file name
val original = super.pathTo(node, context)
val paths = original.split("/")
val fileName = node.loadedTemplate.file.name
(paths.dropLast(1) + listOf(fileName)).joinToString("/")
}
else
super.pathTo(node, context)
private fun updatePageEntry(path: List<String>, page: PageNode): List<String> =
if (page is BaseStaticSiteProcessor.StaticPageNode){
if (page.dri.contains(docsRootDRI)) listOf("index")
else {
val start = if (path[0] == "--root--") listOf("docs") else path.take(1)
start + path.drop(1).dropLast(1) + listOf(page.loadedTemplate.file.nameWithoutExtension)
}
}
else if (page is ContentPage && page.dri.contains(docsDRI)) listOf("docs")
else if (page is ContentPage && page.dri.contains(apiPageDRI)) listOf("api", "index")
else if (path.size > 1 && path[0] == "--root--" && path[1] == "-a-p-i") listOf("api") + path.drop(2)
else path

override val pathsIndex: Map<PageNode, List<String>> = super.pathsIndex.mapValues { updatePageEntry(it.value, it.key) }
}
Loading

0 comments on commit 0b3d947

Please sign in to comment.