blob: 5c740eb98b7074bcb166614dac029dbb29a71658 [file] [log] [blame]
Simon Ogorodnik4256adf2017-12-28 21:23:27 +03001package org.jetbrains.dokka.Formats
2
3import org.jetbrains.dokka.DocumentationModule
4import org.jetbrains.dokka.ExternalDocumentationLinkResolver.Companion.DOKKA_PARAM_PREFIX
Simon Ogorodnik46414702018-02-01 19:02:33 +03005import org.jetbrains.dokka.InboundExternalLinkResolutionService
Simon Ogorodnik4256adf2017-12-28 21:23:27 +03006import org.jetbrains.dokka.NodeKind
7import org.jetbrains.dokka.PackageListService
Simon Ogorodnik46414702018-02-01 19:02:33 +03008import org.jetbrains.kotlin.descriptors.*
9import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
10import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
11import org.jetbrains.kotlin.types.KotlinType
Simon Ogorodnik4256adf2017-12-28 21:23:27 +030012
Simon Ogorodnik66ca7712018-01-06 02:15:05 +030013class JavaLayoutHtmlPackageListService : PackageListService {
Simon Ogorodnik4256adf2017-12-28 21:23:27 +030014
15 private fun StringBuilder.appendParam(name: String, value: String) {
16 append(DOKKA_PARAM_PREFIX)
17 append(name)
18 append(":")
19 appendln(value)
20 }
21
22 override fun formatPackageList(module: DocumentationModule): String {
23 val packages = module.members(NodeKind.Package).map { it.name }
24
25 return buildString {
26 appendParam("format", "java-layout-html")
Simon Ogorodnik46414702018-02-01 19:02:33 +030027 appendParam("mode", "kotlin")
Simon Ogorodnik4256adf2017-12-28 21:23:27 +030028 for (p in packages) {
29 appendln(p)
30 }
31 }
32 }
33
Simon Ogorodnik46414702018-02-01 19:02:33 +030034}
35
36class JavaLayoutHtmlInboundLinkResolutionService(private val paramMap: Map<String, List<String>>) : InboundExternalLinkResolutionService {
37 private fun getContainerPath(symbol: DeclarationDescriptor): String? {
38 return when (symbol) {
39 is PackageFragmentDescriptor -> symbol.fqName.asString() + "/"
40 is ClassifierDescriptor -> getContainerPath(symbol.findPackage()) + symbol.nameWithOuter() + ".html"
41 else -> null
42 }
43 }
44
45 private fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor =
46 generateSequence(this) { it.containingDeclaration }.filterIsInstance<PackageFragmentDescriptor>().first()
47
48 private fun ClassifierDescriptor.nameWithOuter(): String =
49 generateSequence(this) { it.containingDeclaration as? ClassifierDescriptor }
50 .toList().asReversed().joinToString(".") { it.name.asString() }
51
52 private fun getPagePath(symbol: DeclarationDescriptor): String? {
53 return when (symbol) {
54 is PackageFragmentDescriptor -> getContainerPath(symbol) + "package-summary.html"
55 is ClassifierDescriptor -> getContainerPath(symbol) + "#"
56 is FunctionDescriptor, is PropertyDescriptor -> getContainerPath(symbol.containingDeclaration!!) + "#" + symbol.signatureForAnchorUrlEncoded()
57 else -> null
58 }
59 }
60
61 private fun DeclarationDescriptor.signatureForAnchor(): String? {
62
63 fun ReceiverParameterDescriptor.extractReceiverName(): String {
64 var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
65 if (receiverClass.isCompanionObject()) {
66 receiverClass = receiverClass.containingDeclaration!!
67 } else if (receiverClass is TypeParameterDescriptor) {
68 val upperBoundClass = receiverClass.upperBounds.singleOrNull()?.constructor?.declarationDescriptor
69 if (upperBoundClass != null) {
70 receiverClass = upperBoundClass
71 }
72 }
73
74 return receiverClass.name.asString()
75 }
76
77 fun KotlinType.qualifiedNameForSignature(): String {
78 val desc = constructor.declarationDescriptor
79 return desc?.fqNameUnsafe?.asString() ?: "<ERROR TYPE NAME>"
80 }
81
82 fun StringBuilder.appendReceiverAndCompanion(desc: CallableDescriptor) {
83 if (desc.containingDeclaration.isCompanionObject()) {
84 append("Companion.")
85 }
86 desc.extensionReceiverParameter?.let {
87 append("(")
88 append(it.extractReceiverName())
89 append(").")
90 }
91 }
92
93 return when(this) {
94 is FunctionDescriptor -> buildString {
95 appendReceiverAndCompanion(this@signatureForAnchor)
96 append(name.asString())
97 valueParameters.joinTo(this, prefix = "(", postfix = ")") {
98 it.type.qualifiedNameForSignature()
99 }
100 }
101 is PropertyDescriptor -> buildString {
102 appendReceiverAndCompanion(this@signatureForAnchor)
103 append(name.asString())
104 append(":")
105 append(returnType?.qualifiedNameForSignature())
106 }
107 else -> null
108 }
109 }
110
111 private fun DeclarationDescriptor.signatureForAnchorUrlEncoded(): String? = signatureForAnchor()?.urlEncoded()
112
113 override fun getPath(symbol: DeclarationDescriptor) = getPagePath(symbol)
Simon Ogorodnik4256adf2017-12-28 21:23:27 +0300114}