1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package org.jetbrains.dokka.base.renderers
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.local.LocationProvider
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.querySingle
import org.jetbrains.dokka.renderers.Renderer
import org.jetbrains.dokka.transformers.pages.PageTransformer
abstract class DefaultRenderer<T>(
protected val context: DokkaContext
) : Renderer {
protected val outputWriter = context.plugin<DokkaBase>().querySingle { outputWriter }
protected lateinit var locationProvider: LocationProvider
private set
protected open val preprocessors: Iterable<PageTransformer> = emptyList()
abstract fun T.buildHeader(level: Int, content: T.() -> Unit)
abstract fun T.buildLink(address: String, content: T.() -> Unit)
abstract fun T.buildList(node: ContentList, pageContext: ContentPage, platformRestriction: PlatformData? = null)
abstract fun T.buildNewLine()
abstract fun T.buildResource(node: ContentEmbeddedResource, pageContext: ContentPage)
abstract fun T.buildTable(node: ContentTable, pageContext: ContentPage, platformRestriction: PlatformData? = null)
abstract fun T.buildText(textNode: ContentText)
abstract fun T.buildNavigation(page: PageNode)
abstract fun buildPage(page: ContentPage, content: (T, ContentPage) -> Unit): String
abstract fun buildError(node: ContentNode)
open fun T.buildPlatformDependent(content: PlatformHintedContent, pageContext: ContentPage) =
buildContentNode(content.inner, pageContext)
open fun T.buildGroup(node: ContentGroup, pageContext: ContentPage, platformRestriction: PlatformData? = null) =
wrapGroup(node, pageContext) { node.children.forEach { it.build(this, pageContext, platformRestriction) } }
open fun T.wrapGroup(node: ContentGroup, pageContext: ContentPage, childrenCallback: T.() -> Unit) =
childrenCallback()
open fun T.buildLinkText(
nodes: List<ContentNode>,
pageContext: ContentPage,
platformRestriction: PlatformData? = null
) {
nodes.forEach { it.build(this, pageContext, platformRestriction) }
}
open fun T.buildCode(code: List<ContentNode>, language: String, pageContext: ContentPage) {
code.forEach { it.build(this, pageContext) }
}
open fun T.buildHeader(node: ContentHeader, pageContext: ContentPage, platformRestriction: PlatformData? = null) {
buildHeader(node.level) { node.children.forEach { it.build(this, pageContext, platformRestriction) } }
}
open fun ContentNode.build(builder: T, pageContext: ContentPage, platformRestriction: PlatformData? = null) =
builder.buildContentNode(this, pageContext, platformRestriction)
open fun T.buildContentNode(
node: ContentNode,
pageContext: ContentPage,
platformRestriction: PlatformData? = null
) {
if (platformRestriction == null || platformRestriction in node.platforms) {
when (node) {
is ContentText -> buildText(node)
is ContentHeader -> buildHeader(node, pageContext, platformRestriction)
is ContentCode -> buildCode(node.children, node.language, pageContext)
is ContentDRILink ->
buildLink(locationProvider.resolve(node.address, node.platforms.toList(), pageContext)) {
buildLinkText(node.children, pageContext, platformRestriction)
}
is ContentResolvedLink -> buildLink(node.address) {
buildLinkText(node.children, pageContext, platformRestriction)
}
is ContentEmbeddedResource -> buildResource(node, pageContext)
is ContentList -> buildList(node, pageContext, platformRestriction)
is ContentTable -> buildTable(node, pageContext, platformRestriction)
is ContentGroup -> buildGroup(node, pageContext, platformRestriction)
is ContentBreakLine -> buildNewLine()
is PlatformHintedContent -> buildPlatformDependent(node, pageContext)
else -> buildError(node)
}
}
}
open fun buildPageContent(context: T, page: ContentPage) {
context.buildNavigation(page)
page.content.build(context, page)
}
open fun renderPage(page: PageNode) {
val path by lazy { locationProvider.resolve(page, skipExtension = true) }
when (page) {
is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> buildPageContent(c, p) }, ".html")
is RendererSpecificPage -> when (val strategy = page.strategy) {
is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, path)
is RenderingStrategy.Write -> outputWriter.write(path, strategy.text, "")
is RenderingStrategy.Callback -> outputWriter.write(path, strategy.instructions(this, page), ".html")
RenderingStrategy.DoNothing -> Unit
}
else -> throw AssertionError(
"Page ${page.name} cannot be rendered by renderer as it is not renderer specific nor contains content"
)
}
}
open fun renderPages(root: PageNode) {
renderPage(root)
root.children.forEach { renderPages(it) }
}
override fun render(root: RootPageNode) {
val newRoot = preprocessors.fold(root) { acc, t -> t(acc) }
locationProvider =
context.plugin<DokkaBase>().querySingle { locationProviderFactory }.getLocationProvider(newRoot)
renderPages(newRoot)
}
}
fun ContentPage.platforms() = this.content.platforms.toList()
|