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() toType generatorServiceClass bind() toType languageServiceClass bind() toType templateServiceClass bind() toType generatorServiceClass lazyBind() toOptional outlineFactoryClass bind() toType packageListServiceClass bind() toType outputBuilderFactoryClass } val generatorServiceClass = JavaLayoutHtmlFormatGenerator::class abstract val languageServiceClass: KClass abstract val templateServiceClass: KClass abstract val outlineFactoryClass: KClass? abstract val packageListServiceClass: KClass abstract val outputBuilderFactoryClass: KClass } class JavaLayoutHtmlFormatDescriptor : JavaLayoutHtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsKotlin { override val outputBuilderFactoryClass: KClass = JavaLayoutHtmlFormatOutputBuilderFactoryImpl::class override val packageListServiceClass: KClass = 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 = JavaLayoutHtmlFormatOutputBuilderFactoryImpl::class override val packageListServiceClass: KClass = 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) } 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, headContent: HEAD.() -> Unit, bodyContent: BODY.() -> Unit ) class Default : JavaLayoutHtmlTemplateService { override fun composePage( page: JavaLayoutHtmlFormatOutputBuilder.Page, tagConsumer: TagConsumer, 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) } } }