Simon Ogorodnik | 4256adf | 2017-12-28 21:23:27 +0300 | [diff] [blame] | 1 | package org.jetbrains.dokka.Formats |
| 2 | |
| 3 | import org.jetbrains.dokka.DocumentationModule |
| 4 | import org.jetbrains.dokka.ExternalDocumentationLinkResolver.Companion.DOKKA_PARAM_PREFIX |
Simon Ogorodnik | 4641470 | 2018-02-01 19:02:33 +0300 | [diff] [blame^] | 5 | import org.jetbrains.dokka.InboundExternalLinkResolutionService |
Simon Ogorodnik | 4256adf | 2017-12-28 21:23:27 +0300 | [diff] [blame] | 6 | import org.jetbrains.dokka.NodeKind |
| 7 | import org.jetbrains.dokka.PackageListService |
Simon Ogorodnik | 4641470 | 2018-02-01 19:02:33 +0300 | [diff] [blame^] | 8 | import org.jetbrains.kotlin.descriptors.* |
| 9 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe |
| 10 | import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject |
| 11 | import org.jetbrains.kotlin.types.KotlinType |
Simon Ogorodnik | 4256adf | 2017-12-28 21:23:27 +0300 | [diff] [blame] | 12 | |
Simon Ogorodnik | 66ca771 | 2018-01-06 02:15:05 +0300 | [diff] [blame] | 13 | class JavaLayoutHtmlPackageListService : PackageListService { |
Simon Ogorodnik | 4256adf | 2017-12-28 21:23:27 +0300 | [diff] [blame] | 14 | |
| 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 Ogorodnik | 4641470 | 2018-02-01 19:02:33 +0300 | [diff] [blame^] | 27 | appendParam("mode", "kotlin") |
Simon Ogorodnik | 4256adf | 2017-12-28 21:23:27 +0300 | [diff] [blame] | 28 | for (p in packages) { |
| 29 | appendln(p) |
| 30 | } |
| 31 | } |
| 32 | } |
| 33 | |
Simon Ogorodnik | 4641470 | 2018-02-01 19:02:33 +0300 | [diff] [blame^] | 34 | } |
| 35 | |
| 36 | class 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 Ogorodnik | 4256adf | 2017-12-28 21:23:27 +0300 | [diff] [blame] | 114 | } |