aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
blob: b94886693707330c7e1e0a9764e6208aad6b62e1 (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package org.jetbrains.dokka.Formats

import com.google.inject.Binder
import kotlinx.html.*
import org.jetbrains.dokka.*
import org.jetbrains.dokka.Utilities.bind
import org.jetbrains.dokka.Utilities.lazyBind
import org.jetbrains.dokka.Utilities.toOptional
import org.jetbrains.dokka.Utilities.toType
import java.net.URI
import kotlin.reflect.KClass


abstract class JavaLayoutHtmlFormatDescriptorBase : FormatDescriptor, DefaultAnalysisComponent {

    override fun configureOutput(binder: Binder): Unit = with(binder) {
        bind<Generator>() toType generatorServiceClass
        bind<LanguageService>() toType languageServiceClass
        bind<JavaLayoutHtmlTemplateService>() toType templateServiceClass
        bind<JavaLayoutHtmlUriProvider>() toType generatorServiceClass
        lazyBind<JavaLayoutHtmlFormatOutlineFactoryService>() toOptional outlineFactoryClass
        bind<PackageListService>() toType packageListServiceClass
        bind<JavaLayoutHtmlFormatOutputBuilderFactory>() toType outputBuilderFactoryClass
    }

    val generatorServiceClass = JavaLayoutHtmlFormatGenerator::class
    abstract val languageServiceClass: KClass<out LanguageService>
    abstract val templateServiceClass: KClass<out JavaLayoutHtmlTemplateService>
    abstract val outlineFactoryClass: KClass<out JavaLayoutHtmlFormatOutlineFactoryService>?
    abstract val packageListServiceClass: KClass<out PackageListService>
    abstract val outputBuilderFactoryClass: KClass<out JavaLayoutHtmlFormatOutputBuilderFactory>
}

class JavaLayoutHtmlFormatDescriptor : JavaLayoutHtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsKotlin {
    override val outputBuilderFactoryClass: KClass<out JavaLayoutHtmlFormatOutputBuilderFactory> = JavaLayoutHtmlFormatOutputBuilderFactoryImpl::class
    override val packageListServiceClass: KClass<out PackageListService> = JavaLayoutHtmlPackageListService::class
    override val languageServiceClass = KotlinLanguageService::class
    override val templateServiceClass = JavaLayoutHtmlTemplateService.Default::class
    override val outlineFactoryClass = null
}

class JavaLayoutHtmlAsJavaFormatDescriptor : JavaLayoutHtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsJava {
    override val outputBuilderFactoryClass: KClass<out JavaLayoutHtmlFormatOutputBuilderFactory> = JavaLayoutHtmlFormatOutputBuilderFactoryImpl::class
    override val packageListServiceClass: KClass<out PackageListService> = JavaLayoutHtmlPackageListService::class
    override val languageServiceClass = NewJavaLanguageService::class
    override val templateServiceClass = JavaLayoutHtmlTemplateService.Default::class
    override val outlineFactoryClass = null
}

interface JavaLayoutHtmlFormatOutlineFactoryService {
    fun generateOutlines(outputProvider: (URI) -> Appendable, nodes: Iterable<DocumentationNode>)
}


interface JavaLayoutHtmlUriProvider {
    fun tryGetContainerUri(node: DocumentationNode): URI?
    fun tryGetMainUri(node: DocumentationNode): URI?
    fun tryGetOutlineRootUri(node: DocumentationNode): URI?
    fun containerUri(node: DocumentationNode): URI = tryGetContainerUri(node) ?: error("Unsupported ${node.kind}")
    fun mainUri(node: DocumentationNode): URI = tryGetMainUri(node) ?: error("Unsupported ${node.kind}")
    fun outlineRootUri(node: DocumentationNode): URI = tryGetOutlineRootUri(node) ?: error("Unsupported ${node.kind}")


    fun linkTo(to: DocumentationNode, from: URI): String {
        return mainUri(to).relativeTo(from).toString()
    }

    fun linkToFromOutline(to: DocumentationNode, from: URI): String {
        return outlineRootUri(to).relativeTo(from).toString()
    }

    fun mainUriOrWarn(node: DocumentationNode): URI? = tryGetMainUri(node) ?: (null).also {
        AssertionError("Not implemented mainUri for ${node.kind} (${node})").printStackTrace()
    }
}


interface JavaLayoutHtmlTemplateService {
    fun composePage(
            page: JavaLayoutHtmlFormatOutputBuilder.Page,
            tagConsumer: TagConsumer<Appendable>,
            headContent: HEAD.() -> Unit,
            bodyContent: BODY.() -> Unit
    )

    class Default : JavaLayoutHtmlTemplateService {
        override fun composePage(
                page: JavaLayoutHtmlFormatOutputBuilder.Page,
                tagConsumer: TagConsumer<Appendable>,
                headContent: HEAD.() -> Unit,
                bodyContent: BODY.() -> Unit
        ) {
            tagConsumer.html {
                head {
                    meta(charset = "UTF-8")
                    headContent()
                }
                body(block = bodyContent)
            }
        }
    }
}

val DocumentationNode.companion get() = members(NodeKind.Object).find { it.details(NodeKind.Modifier).any { it.name == "companion" } }

fun DocumentationNode.signatureForAnchor(logger: DokkaLogger): String {

    fun StringBuilder.appendReceiverIfSo() {
        detailOrNull(NodeKind.Receiver)?.let {
            append("(")
            append(it.detail(NodeKind.Type).qualifiedNameFromType())
            append(").")
        }
    }

    return when (kind) {
        NodeKind.Function, NodeKind.Constructor, NodeKind.CompanionObjectFunction -> buildString {
            if (kind == NodeKind.CompanionObjectFunction) {
                append("Companion.")
            }
            appendReceiverIfSo()
            append(prettyName)
            details(NodeKind.Parameter).joinTo(this, prefix = "(", postfix = ")") { it.detail(NodeKind.Type).qualifiedNameFromType() }
        }
        NodeKind.Property, NodeKind.CompanionObjectProperty -> buildString {
            if (kind == NodeKind.CompanionObjectProperty) {
                append("Companion.")
            }
            appendReceiverIfSo()
            append(name)
            append(":")
            append(detail(NodeKind.Type).qualifiedNameFromType())
        }
        NodeKind.TypeParameter, NodeKind.Parameter -> this.detail(NodeKind.Signature).name // Todo Why not signatureForAnchor
        NodeKind.Field -> name
        NodeKind.EnumItem -> "ENUM_VALUE:$name"
        NodeKind.Attribute -> "attr_$name"
        else -> "Not implemented signatureForAnchor $this".also { logger.warn(it) }
    }
}