blob: 66ded62a67f1f94ca926787fe73e12fc532a18ec [file] [log] [blame]
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}").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(name)
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) }
}
}
fun DocumentationNode.classNodeNameWithOuterClass(): String {
assert(kind in NodeKind.classLike)
return path.dropWhile { it.kind == NodeKind.Package || it.kind == NodeKind.Module }.joinToString(separator = ".") { it.name }
}