aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt9
-rw-r--r--core/src/main/kotlin/Formats/GFMFormatService.kt21
-rw-r--r--core/src/main/kotlin/Formats/HtmlFormatService.kt9
-rw-r--r--core/src/main/kotlin/Formats/JekyllFormatService.kt18
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt28
-rw-r--r--core/src/main/kotlin/Formats/MarkdownFormatService.kt15
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt55
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt76
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt4
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt7
-rw-r--r--core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt2
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt227
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt4
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt4
-rw-r--r--core/src/main/kotlin/Model/DocumentationReference.kt23
-rw-r--r--core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt7
-rw-r--r--core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt14
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt (renamed from core/src/main/kotlin/Utilities/DokkaModule.kt)60
-rw-r--r--core/src/test/kotlin/TestAPI.kt61
-rw-r--r--core/src/test/kotlin/format/GFMFormatTest.kt2
-rw-r--r--core/src/test/kotlin/format/HtmlFormatTest.kt6
-rw-r--r--core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt2
-rw-r--r--core/src/test/kotlin/format/KotlinWebSiteRunnableSamplesFormatTest.kt6
-rw-r--r--core/src/test/kotlin/format/MarkdownFormatTest.kt69
-rw-r--r--core/src/test/kotlin/model/ClassTest.kt12
-rw-r--r--core/src/test/kotlin/model/CommentTest.kt3
-rw-r--r--core/src/test/kotlin/model/FunctionTest.kt12
-rw-r--r--core/src/test/kotlin/model/PropertyTest.kt12
-rw-r--r--core/src/test/kotlin/model/TypeAliasTest.kt9
-rw-r--r--core/testdata/classes/sinceKotlin.kt5
-rw-r--r--core/testdata/format/dynamicExtension.kt3
-rw-r--r--core/testdata/format/dynamicExtension.md10
-rw-r--r--core/testdata/format/dynamicType.kt2
-rw-r--r--core/testdata/format/dynamicType.md5
-rw-r--r--core/testdata/format/memberExtension.kt8
-rw-r--r--core/testdata/format/memberExtension.md10
-rw-r--r--core/testdata/format/multiplatform/js.kt7
-rw-r--r--core/testdata/format/multiplatform/jvm.kt8
-rw-r--r--core/testdata/format/multiplatform/multiplatform.package.md9
-rw-r--r--core/testdata/format/multiplatformImplied/foo.md24
-rw-r--r--core/testdata/format/multiplatformImplied/js.kt16
-rw-r--r--core/testdata/format/multiplatformImplied/jvm.kt16
-rw-r--r--core/testdata/format/multiplatformMerge/js.kt7
-rw-r--r--core/testdata/format/multiplatformMerge/jvm.kt8
-rw-r--r--core/testdata/format/multiplatformMerge/multiplatform.package.md8
-rw-r--r--core/testdata/format/multiplatformMergeMembers/foo.md26
-rw-r--r--core/testdata/format/multiplatformMergeMembers/js.kt16
-rw-r--r--core/testdata/format/multiplatformMergeMembers/jvm.kt16
-rw-r--r--core/testdata/format/multiplatformOmitRedundant/foo.md22
-rw-r--r--core/testdata/format/multiplatformOmitRedundant/js.kt2
-rw-r--r--core/testdata/format/multiplatformOmitRedundant/jvm.kt11
-rw-r--r--core/testdata/format/sinceKotlin.html27
-rw-r--r--core/testdata/format/sinceKotlin.kt5
-rw-r--r--core/testdata/format/sinceKotlin.md14
-rw-r--r--core/testdata/format/sinceKotlin.package.md8
-rw-r--r--core/testdata/format/website-samples/dropImport.md1
-rw-r--r--core/testdata/format/website-samples/newLinesInSamples.kt19
-rw-r--r--core/testdata/format/website-samples/newLinesInSamples.md31
-rw-r--r--core/testdata/format/website-samples/sample.md1
-rw-r--r--core/testdata/format/website-samples/sampleWithAsserts.md1
-rw-r--r--core/testdata/functions/sinceKotlin.kt5
-rw-r--r--core/testdata/properties/sinceKotlin.kt5
-rw-r--r--core/testdata/typealias/sinceKotlin.kt5
-rw-r--r--integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt1
-rw-r--r--runners/ant/src/main/kotlin/ant/dokka.kt24
-rw-r--r--runners/cli/src/main/kotlin/cli/main.kt8
-rw-r--r--runners/gradle-plugin/src/main/kotlin/main.kt1
-rw-r--r--runners/maven-plugin/src/main/kotlin/DokkaMojo.kt9
69 files changed, 963 insertions, 220 deletions
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt
index eb2b2a65..8038089f 100644
--- a/core/src/main/kotlin/DokkaBootstrapImpl.kt
+++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt
@@ -10,6 +10,11 @@ fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition {
urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it })
}
+fun parseSourceRoot(sourceRoot: String): SourceRoot {
+ val components = sourceRoot.split("::", limit = 2)
+ return SourceRoot(components.last(), if (components.size == 1) listOf() else components[0].split(','))
+}
+
class DokkaBootstrapImpl : DokkaBootstrap {
class DokkaProxyLogger(val consumer: BiConsumer<String, String>) : DokkaLogger {
@@ -37,6 +42,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
outputDir: String,
format: String,
includeNonPublic: Boolean,
+ includeRootPackage: Boolean,
reportUndocumented: Boolean,
skipEmptyPackages: Boolean,
skipDeprecated: Boolean,
@@ -46,7 +52,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
generator = DokkaGenerator(
DokkaProxyLogger(logger),
classpath,
- sources,
+ sources.map(::parseSourceRoot),
samples,
includes,
moduleName,
@@ -54,6 +60,7 @@ class DokkaBootstrapImpl : DokkaBootstrap {
outputDir,
format,
includeNonPublic,
+ includeRootPackage,
reportUndocumented,
skipEmptyPackages,
skipDeprecated,
diff --git a/core/src/main/kotlin/Formats/GFMFormatService.kt b/core/src/main/kotlin/Formats/GFMFormatService.kt
index cfb7fc03..cb31a1d3 100644
--- a/core/src/main/kotlin/Formats/GFMFormatService.kt
+++ b/core/src/main/kotlin/Formats/GFMFormatService.kt
@@ -3,11 +3,12 @@ package org.jetbrains.dokka
import com.google.inject.Inject
open class GFMOutputBuilder(to: StringBuilder,
- location: Location,
- locationService: LocationService,
- languageService: LanguageService,
- extension: String)
- : MarkdownOutputBuilder(to, location, locationService, languageService, extension)
+ location: Location,
+ locationService: LocationService,
+ languageService: LanguageService,
+ extension: String,
+ impliedPlatforms: List<String>)
+ : MarkdownOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
override fun appendTable(vararg columns: String, body: () -> Unit) {
to.appendln(columns.joinToString(" | ", "| ", " |"))
@@ -45,12 +46,14 @@ open class GFMOutputBuilder(to: StringBuilder,
open class GFMFormatService(locationService: LocationService,
signatureGenerator: LanguageService,
- linkExtension: String)
-: MarkdownFormatService(locationService, signatureGenerator, linkExtension) {
+ linkExtension: String,
+ impliedPlatforms: List<String>)
+: MarkdownFormatService(locationService, signatureGenerator, linkExtension, impliedPlatforms) {
@Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService) : this(locationService, signatureGenerator, "md")
+ signatureGenerator: LanguageService,
+ impliedPlatforms: List<String>) : this(locationService, signatureGenerator, "md", impliedPlatforms)
override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- GFMOutputBuilder(to, location, locationService, languageService, extension)
+ GFMOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/HtmlFormatService.kt b/core/src/main/kotlin/Formats/HtmlFormatService.kt
index d73e4e62..6819e652 100644
--- a/core/src/main/kotlin/Formats/HtmlFormatService.kt
+++ b/core/src/main/kotlin/Formats/HtmlFormatService.kt
@@ -2,6 +2,7 @@ package org.jetbrains.dokka
import com.google.inject.Inject
import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
@@ -11,8 +12,9 @@ open class HtmlOutputBuilder(to: StringBuilder,
locationService: LocationService,
languageService: LanguageService,
extension: String,
+ impliedPlatforms: List<String>,
val templateService: HtmlTemplateService)
- : StructuredOutputBuilder(to, location, locationService, languageService, extension)
+ : StructuredOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
override fun appendText(text: String) {
to.append(text.htmlEscape())
@@ -95,7 +97,8 @@ open class HtmlOutputBuilder(to: StringBuilder,
open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService,
signatureGenerator: LanguageService,
- val templateService: HtmlTemplateService)
+ val templateService: HtmlTemplateService,
+ @Named(impliedPlatformsName) val impliedPlatforms: List<String>)
: StructuredFormatService(locationService, signatureGenerator, "html"), OutlineFormatService {
override fun enumerateSupportFiles(callback: (String, String) -> Unit) {
@@ -103,7 +106,7 @@ open class HtmlFormatService @Inject constructor(@Named("folders") locationServi
}
override fun createOutputBuilder(to: StringBuilder, location: Location) =
- HtmlOutputBuilder(to, location, locationService, languageService, extension, templateService)
+ HtmlOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms, templateService)
override fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
templateService.appendHeader(to, "Module Contents", locationService.calcPathToRoot(location))
diff --git a/core/src/main/kotlin/Formats/JekyllFormatService.kt b/core/src/main/kotlin/Formats/JekyllFormatService.kt
index bab73379..d217bf38 100644
--- a/core/src/main/kotlin/Formats/JekyllFormatService.kt
+++ b/core/src/main/kotlin/Formats/JekyllFormatService.kt
@@ -1,13 +1,16 @@
package org.jetbrains.dokka
import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
open class JekyllOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : MarkdownOutputBuilder(to, location, locationService, languageService, extension)
+ extension: String,
+ impliedPlatforms: List<String>)
+ : MarkdownOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
override fun appendNodes(nodes: Iterable<DocumentationNode>) {
to.appendln("---")
@@ -25,14 +28,15 @@ open class JekyllOutputBuilder(to: StringBuilder,
open class JekyllFormatService(locationService: LocationService,
signatureGenerator: LanguageService,
- linkExtension: String)
-: MarkdownFormatService(locationService, signatureGenerator, linkExtension) {
+ linkExtension: String,
+ impliedPlatforms: List<String>)
+: MarkdownFormatService(locationService, signatureGenerator, linkExtension, impliedPlatforms) {
@Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService): this(locationService, signatureGenerator, "md") {
- }
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>): this(locationService, signatureGenerator, "md", impliedPlatforms)
override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- JekyllOutputBuilder(to, location, locationService, languageService, extension)
+ JekyllOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
index 007e9353..7ebc5f09 100644
--- a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
+++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
@@ -1,14 +1,17 @@
package org.jetbrains.dokka
import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
open class KotlinWebsiteOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : JekyllOutputBuilder(to, location, locationService, languageService, extension)
+ extension: String,
+ impliedPlatforms: List<String>)
+ : JekyllOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
private var needHardLineBreaks = false
private var insideDiv = 0
@@ -145,11 +148,12 @@ open class KotlinWebsiteOutputBuilder(to: StringBuilder,
}
class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService)
- : JekyllFormatService(locationService, signatureGenerator, "html")
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>)
+ : JekyllFormatService(locationService, signatureGenerator, "html", impliedPlatforms)
{
override fun createOutputBuilder(to: StringBuilder, location: Location) =
- KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension)
+ KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
@@ -157,14 +161,15 @@ class KotlinWebsiteRunnableSamplesOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension) {
+ extension: String,
+ impliedPlatforms: List<String>)
+ : KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms) {
override fun appendSampleBlockCode(language: String, imports: () -> Unit, body: () -> Unit) {
div(to, "sample", true) {
appendBlockCode(language) {
imports()
- wrap("\nfun main(args: Array<String>) {", "}") {
+ wrap("\n\nfun main(args: Array<String>) {", "}") {
wrap("\n//sampleStart\n", "\n//sampleEnd\n", body)
}
}
@@ -173,9 +178,10 @@ class KotlinWebsiteRunnableSamplesOutputBuilder(to: StringBuilder,
}
class KotlinWebsiteRunnableSamplesFormatService @Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService)
- : JekyllFormatService(locationService, signatureGenerator, "html") {
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>)
+ : JekyllFormatService(locationService, signatureGenerator, "html", impliedPlatforms) {
override fun createOutputBuilder(to: StringBuilder, location: Location) =
- KotlinWebsiteRunnableSamplesOutputBuilder(to, location, locationService, languageService, extension)
+ KotlinWebsiteRunnableSamplesOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/MarkdownFormatService.kt b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
index fc63b2f2..b9c9c04f 100644
--- a/core/src/main/kotlin/Formats/MarkdownFormatService.kt
+++ b/core/src/main/kotlin/Formats/MarkdownFormatService.kt
@@ -1,6 +1,8 @@
package org.jetbrains.dokka
import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.Utilities.impliedPlatformsName
import java.util.*
enum class ListKind {
@@ -14,8 +16,9 @@ open class MarkdownOutputBuilder(to: StringBuilder,
location: Location,
locationService: LocationService,
languageService: LanguageService,
- extension: String)
- : StructuredOutputBuilder(to, location, locationService, languageService, extension)
+ extension: String,
+ impliedPlatforms: List<String>)
+ : StructuredOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
{
private val listKindStack = Stack<ListKind>()
protected var inTableCell = false
@@ -211,11 +214,13 @@ open class MarkdownOutputBuilder(to: StringBuilder,
open class MarkdownFormatService(locationService: LocationService,
signatureGenerator: LanguageService,
- linkExtension: String)
+ linkExtension: String,
+ val impliedPlatforms: List<String>)
: StructuredFormatService(locationService, signatureGenerator, "md", linkExtension) {
@Inject constructor(locationService: LocationService,
- signatureGenerator: LanguageService): this(locationService, signatureGenerator, "md")
+ signatureGenerator: LanguageService,
+ @Named(impliedPlatformsName) impliedPlatforms: List<String>): this(locationService, signatureGenerator, "md", impliedPlatforms)
override fun createOutputBuilder(to: StringBuilder, location: Location): FormattedOutputBuilder =
- MarkdownOutputBuilder(to, location, locationService, languageService, extension)
+ MarkdownOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms)
}
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
index 0e2085c9..6e887c05 100644
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt
@@ -1,6 +1,7 @@
package org.jetbrains.dokka
import org.jetbrains.dokka.LanguageService.RenderMode
+import org.jetbrains.kotlin.utils.ifEmpty
import java.util.*
data class FormatLink(val text: String, val href: String)
@@ -9,7 +10,8 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
val location: Location,
val locationService: LocationService,
val languageService: LanguageService,
- val extension: String) : FormattedOutputBuilder {
+ val extension: String,
+ val impliedPlatforms: List<String>) : FormattedOutputBuilder {
protected fun wrap(prefix: String, suffix: String, body: () -> Unit) {
to.append(prefix)
@@ -59,6 +61,13 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
abstract fun appendText(text: String)
+ open fun appendSinceKotlin(version: String) {
+ appendParagraph {
+ appendText("Available since Kotlin: ")
+ appendCode { appendText(version) }
+ }
+ }
+
open fun appendSymbol(text: String) {
appendText(text)
}
@@ -281,12 +290,14 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
item.appendOverrides()
item.appendDeprecation()
+ item.appendPlatforms()
}
// All items have exactly the same documentation, so we can use any item to render it
val item = items.first()
item.details(NodeKind.OverloadGroupNote).forEach {
appendContent(it.content)
}
+
appendContent(item.content.summary)
item.appendDescription()
}
@@ -331,6 +342,17 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
+ private fun DocumentationNode.appendPlatforms() {
+ val platforms = platformsToShow.ifEmpty { return }
+ appendParagraph {
+ appendStrong { to.append("Platform and version requirements:") }
+ to.append(" " + platforms.joinToString())
+ }
+ }
+
+ val DocumentationNode.platformsToShow: List<String>
+ get() = platforms.let { if (it.containsAll(impliedPlatforms)) it - impliedPlatforms else it }
+
private fun DocumentationNode.appendDescription() {
if (content.description != ContentEmpty) {
appendContent(content.description)
@@ -381,15 +403,15 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendSection("Exceptions", node.members(NodeKind.Exception))
appendSection("Type Aliases", node.members(NodeKind.TypeAlias))
appendSection("Extensions for External Classes", node.members(NodeKind.ExternalClass))
- appendSection("Enum Values", node.members(NodeKind.EnumItem), sortMembers = false)
- appendSection("Constructors", node.members(NodeKind.Constructor))
- appendSection("Properties", node.members(NodeKind.Property))
+ appendSection("Enum Values", node.members(NodeKind.EnumItem), sortMembers = false, omitSamePlatforms = true)
+ appendSection("Constructors", node.members(NodeKind.Constructor), omitSamePlatforms = true)
+ appendSection("Properties", node.members(NodeKind.Property), omitSamePlatforms = true)
appendSection("Inherited Properties", node.inheritedMembers(NodeKind.Property))
- appendSection("Functions", node.members(NodeKind.Function))
+ appendSection("Functions", node.members(NodeKind.Function), omitSamePlatforms = true)
appendSection("Inherited Functions", node.inheritedMembers(NodeKind.Function))
- appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty))
+ appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
appendSection("Inherited Companion Object Properties", node.inheritedCompanionObjectMembers(NodeKind.Property))
- appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction))
+ appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction), omitSamePlatforms = true)
appendSection("Inherited Companion Object Functions", node.inheritedCompanionObjectMembers(NodeKind.Function))
appendSection("Other members", node.members.filter {
it.kind !in setOf(
@@ -428,7 +450,9 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
- private fun appendSection(caption: String, members: List<DocumentationNode>, sortMembers: Boolean = true) {
+ private fun appendSection(caption: String, members: List<DocumentationNode>,
+ sortMembers: Boolean = true,
+ omitSamePlatforms: Boolean = false) {
if (members.isEmpty()) return
appendHeader(3) { appendText(caption) }
@@ -437,11 +461,12 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
val membersMap = children.groupBy { link(node, it) }
appendTable("Name", "Summary") {
- appendTableBody() {
+ appendTableBody {
for ((memberLocation, members) in membersMap) {
- appendTableRow() {
+ appendTableRow {
appendTableCell {
appendLink(memberLocation)
+ appendPlatforms(members, omitSamePlatforms)
}
appendTableCell {
val breakdownBySummary = members.groupBy { it.summary }
@@ -475,6 +500,16 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
renderedSignatures.last().appendSignature()
}
}
+
+ private fun appendPlatforms(items: List<DocumentationNode>, omitSamePlatforms: Boolean) {
+ val platforms = items.foldRight(items.first().platformsToShow.toSet()) {
+ node, platforms -> platforms.intersect(node.platformsToShow)
+ }
+ if (platforms.isNotEmpty() && (platforms != node.platformsToShow.toSet() || !omitSamePlatforms)) {
+ appendLine()
+ to.append("(${platforms.joinToString()})")
+ }
+ }
}
inner class AllTypesNodeBuilder(val node: DocumentationNode)
diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt
index 360965d5..6b5df7c9 100644
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt
@@ -7,7 +7,8 @@ import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
-import org.jetbrains.dokka.Utilities.DokkaModule
+import org.jetbrains.dokka.Utilities.DokkaAnalysisModule
+import org.jetbrains.dokka.Utilities.DokkaOutputModule
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
@@ -15,47 +16,76 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.config.JVMConfigurationKeys
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import kotlin.system.measureTimeMillis
+class SourceRoot(path: String, val defaultPlatforms: List<String> = emptyList()) {
+ val path: String = File(path).absolutePath
+}
+
class DokkaGenerator(val logger: DokkaLogger,
val classpath: List<String>,
- val sources: List<String>,
+ val sources: List<SourceRoot>,
val samples: List<String>,
val includes: List<String>,
val moduleName: String,
val options: DocumentationOptions) {
+
+ private val documentationModule = DocumentationModule(moduleName)
+
fun generate() {
- val environment = createAnalysisEnvironment()
+ val sourcesGroupedByPlatform = sources.groupBy { it.defaultPlatforms.firstOrNull() }
+ for ((platform, roots) in sourcesGroupedByPlatform) {
+ appendSourceModule(platform, roots)
+ }
+ documentationModule.prepareForGeneration(options)
+
+ val timeBuild = measureTimeMillis {
+ logger.info("Generating pages... ")
+ val outputInjector = Guice.createInjector(DokkaOutputModule(options, logger))
+ outputInjector.getInstance(Generator::class.java).buildAll(documentationModule)
+ }
+ logger.info("done in ${timeBuild / 1000} secs")
+ }
+
+ private fun appendSourceModule(defaultPlatform: String?, sourceRoots: List<SourceRoot>) {
+ val sourcePaths = sourceRoots.map { it.path }
+ val environment = createAnalysisEnvironment(sourcePaths)
logger.info("Module: $moduleName")
logger.info("Output: ${File(options.outputDir)}")
- logger.info("Sources: ${environment.sources.joinToString()}")
+ logger.info("Sources: ${sourcePaths.joinToString()}")
logger.info("Classpath: ${environment.classpath.joinToString()}")
logger.info("Analysing sources and libraries... ")
val startAnalyse = System.currentTimeMillis()
- val injector = Guice.createInjector(DokkaModule(environment, options, logger))
+ val defaultPlatformAsList = defaultPlatform?.let { listOf(it) }.orEmpty()
+ val defaultPlatformsProvider = object : DefaultPlatformsProvider {
+ override fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String> {
+ val containingFilePath = descriptor.sourcePsi()?.containingFile?.virtualFile?.canonicalPath
+ ?.let { File(it).absolutePath }
+ val sourceRoot = containingFilePath?.let { path -> sourceRoots.find { path.startsWith(it.path) } }
+ return sourceRoot?.defaultPlatforms ?: defaultPlatformAsList
+ }
+ }
+
+ val injector = Guice.createInjector(
+ DokkaAnalysisModule(environment, options, defaultPlatformsProvider, documentationModule.nodeRefGraph, logger))
- val documentation = buildDocumentationModule(injector, moduleName, { isSample(it) }, includes)
+ buildDocumentationModule(injector, documentationModule, { isNotSample(it) }, includes)
val timeAnalyse = System.currentTimeMillis() - startAnalyse
logger.info("done in ${timeAnalyse / 1000} secs")
- val timeBuild = measureTimeMillis {
- logger.info("Generating pages... ")
- injector.getInstance(Generator::class.java).buildAll(documentation)
- }
- logger.info("done in ${timeBuild / 1000} secs")
-
Disposer.dispose(environment)
}
- fun createAnalysisEnvironment(): AnalysisEnvironment {
+ fun createAnalysisEnvironment(sourcePaths: List<String>): AnalysisEnvironment {
val environment = AnalysisEnvironment(DokkaMessageCollector(logger))
environment.apply {
@@ -65,14 +95,14 @@ class DokkaGenerator(val logger: DokkaLogger,
addClasspath(File(element))
}
- addSources(this@DokkaGenerator.sources)
+ addSources(sourcePaths)
addSources(this@DokkaGenerator.samples)
}
return environment
}
- fun isSample(file: PsiFile): Boolean {
+ fun isNotSample(file: PsiFile): Boolean {
val sourceFile = File(file.virtualFile!!.path)
return samples.none { sample ->
val canonicalSample = File(sample).canonicalPath
@@ -100,9 +130,9 @@ class DokkaMessageCollector(val logger: DokkaLogger): MessageCollector {
}
fun buildDocumentationModule(injector: Injector,
- moduleName: String,
+ documentationModule: DocumentationModule,
filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true },
- includes: List<String> = listOf()): DocumentationModule {
+ includes: List<String> = listOf()) {
val coreEnvironment = injector.getInstance(KotlinCoreEnvironment::class.java)
val fragmentFiles = coreEnvironment.getSourceFiles().filter(filesToDocumentFilter)
@@ -120,7 +150,13 @@ fun buildDocumentationModule(injector: Injector,
for (include in includes) {
packageDocs.parse(include, fragments.firstOrNull())
}
- val documentationModule = DocumentationModule(moduleName, packageDocs.moduleContent)
+ if (documentationModule.content.isEmpty()) {
+ documentationModule.updateContent {
+ for (node in packageDocs.moduleContent.children) {
+ append(node)
+ }
+ }
+ }
with(injector.getInstance(DocumentationBuilder::class.java)) {
documentationModule.appendFragments(fragments, packageDocs.packageContent,
@@ -131,10 +167,6 @@ fun buildDocumentationModule(injector: Injector,
with(injector.getInstance(JavaDocumentationBuilder::class.java)) {
javaFiles.map { appendFile(it, documentationModule, packageDocs.packageContent) }
}
-
- injector.getInstance(NodeReferenceGraph::class.java).resolveReferences()
-
- return documentationModule
}
diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
index 806e9f92..b2f4aeaf 100644
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
@@ -44,10 +44,10 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
private val refGraph: NodeReferenceGraph
private val docParser: JavaDocumentationParser
- @Inject constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph) {
+ @Inject constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, logger: DokkaLogger) {
this.options = options
this.refGraph = refGraph
- this.docParser = JavadocParser(refGraph)
+ this.docParser = JavadocParser(refGraph, logger)
}
constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt
index 0fb98230..af45f150 100644
--- a/core/src/main/kotlin/Java/JavadocParser.kt
+++ b/core/src/main/kotlin/Java/JavadocParser.kt
@@ -20,7 +20,8 @@ interface JavaDocumentationParser {
fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
}
-class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentationParser {
+class JavadocParser(private val refGraph: NodeReferenceGraph,
+ private val logger: DokkaLogger) : JavaDocumentationParser {
override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
val docComment = (element as? PsiDocCommentOwner)?.docComment
if (docComment == null) return JavadocParseResult.Empty
@@ -99,7 +100,7 @@ class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentatio
private fun createLink(element: Element): ContentBlock {
val docref = element.attr("docref")
if (docref != null) {
- return ContentNodeLazyLink(docref, { -> refGraph.lookup(docref)})
+ return ContentNodeLazyLink(docref, { -> refGraph.lookupOrWarn(docref, logger)})
}
val href = element.attr("href")
if (href != null) {
@@ -118,7 +119,7 @@ class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentatio
val linkSignature = resolveLink(linkElement)
val text = ContentText(linkElement.text)
if (linkSignature != null) {
- val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookup(linkSignature)})
+ val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookupOrWarn(linkSignature, logger)})
linkNode.append(text)
seeSection.append(linkNode)
} else {
diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
index 4c46f7d6..71b636bf 100644
--- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt
@@ -31,7 +31,7 @@ class DeclarationLinkResolver
if (jdkHref != null) {
return ContentExternalLink(jdkHref)
}
- return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) })
+ return ContentNodeLazyLink(href, { -> refGraph.lookupOrWarn(symbol.signature(), logger) })
}
if ("/" in href) {
return ContentExternalLink(href)
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
index d1f64eeb..06acf2e6 100644
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
@@ -116,7 +116,7 @@ class DescriptorDocumentationParser
fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> {
val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
if (psi is PsiDocCommentOwner) {
- val parseResult = JavadocParser(refGraph).parseDocumentation(psi as PsiNamedElement)
+ val parseResult = JavadocParser(refGraph, logger).parseDocumentation(psi as PsiNamedElement)
return parseResult.content to { node ->
parseResult.deprecatedContent?.let {
val deprecationNode = DocumentationNode("", it, NodeKind.Modifier)
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index afb95fe6..2ab43fa1 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -28,16 +28,19 @@ import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.supertypes
+import com.google.inject.name.Named as GuiceNamed
data class DocumentationOptions(val outputDir: String,
val outputFormat: String,
val includeNonPublic: Boolean = false,
+ val includeRootPackage: Boolean = false,
val reportUndocumented: Boolean = true,
val skipEmptyPackages: Boolean = true,
val skipDeprecated: Boolean = false,
val jdkVersion: Int = 6,
val generateIndexPages: Boolean = true,
- val sourceLinks: List<SourceLinkDefinition>)
+ val sourceLinks: List<SourceLinkDefinition> = emptyList(),
+ val impliedPlatforms: List<String> = emptyList())
private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor,
extensionReceiverDescriptor: DeclarationDescriptor,
@@ -57,13 +60,19 @@ interface PackageDocumentationBuilder {
allFqNames: Collection<FqName>)
}
+interface DefaultPlatformsProvider {
+ fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String>
+}
+
class DocumentationBuilder
@Inject constructor(val resolutionFacade: DokkaResolutionFacade,
val descriptorDocumentationParser: DescriptorDocumentationParser,
val options: DocumentationOptions,
val refGraph: NodeReferenceGraph,
+ val platformNodeRegistry: PlatformNodeRegistry,
val logger: DokkaLogger,
- val linkResolver: DeclarationLinkResolver) {
+ val linkResolver: DeclarationLinkResolver,
+ val defaultPlatformsProvider: DefaultPlatformsProvider) {
val boringBuiltinClasses = setOf(
"kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
"kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
@@ -156,6 +165,11 @@ class DocumentationBuilder
return appendType(it.abbreviation)
}
+ if (kotlinType.isDynamic()) {
+ append(DocumentationNode("dynamic", Content.Empty, kind), RefKind.Detail)
+ return
+ }
+
val classifierDescriptor = kotlinType.constructor.declarationDescriptor
val name = when (classifierDescriptor) {
is ClassDescriptor -> {
@@ -199,17 +213,34 @@ class DocumentationBuilder
fun DocumentationNode.appendAnnotations(annotated: Annotated) {
annotated.annotations.forEach {
it.build()?.let { annotationNode ->
- val refKind = when {
- it.isDocumented() && annotationNode.isDeprecation() -> RefKind.Deprecation
- it.isDocumented() -> RefKind.Annotation
- it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation
- else -> return@forEach
+ if (annotationNode.isSinceKotlin()) {
+ appendSinceKotlin(annotationNode)
}
- append(annotationNode, refKind)
+ else {
+ val refKind = when {
+ it.isDocumented() ->
+ when {
+ annotationNode.isDeprecation() -> RefKind.Deprecation
+ else -> RefKind.Annotation
+ }
+ it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation
+ else -> return@forEach
+ }
+ append(annotationNode, refKind)
+ }
+
}
}
}
+ fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) {
+ var kotlinVersion = annotation.detail(NodeKind.Parameter).detail(NodeKind.Value).name
+ if (kotlinVersion.startsWith('\"') && kotlinVersion.endsWith('\"')) {
+ kotlinVersion = kotlinVersion.substring(1..kotlinVersion.length-2)
+ }
+ append(platformNodeRegistry["Kotlin " + kotlinVersion], RefKind.Platform)
+ }
+
fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
@@ -219,8 +250,16 @@ class DocumentationBuilder
}
}
+ fun DocumentationNode.appendDefaultPlatforms(descriptor: DeclarationDescriptor) {
+ for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor)) {
+ append(platformNodeRegistry[platform], RefKind.Platform)
+ }
+ }
+
fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
+ fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation
+
fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
}
@@ -230,11 +269,7 @@ class DocumentationBuilder
}
fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? {
- // do not include generated code
- if (descriptor is CallableMemberDescriptor && descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION)
- return null
-
- if (descriptor.isDocumented(options)) {
+ if (!descriptor.isGenerated() && descriptor.isDocumented(options)) {
val node = descriptor.build()
append(node, kind)
return node
@@ -242,21 +277,57 @@ class DocumentationBuilder
return null
}
- fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>,
- inheritedLinkKind: RefKind = RefKind.InheritedMember): List<DocumentationNode> {
- val nodes = descriptors.map { descriptor ->
- if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
- if (baseDescriptor != null) {
- link(this, baseDescriptor, inheritedLinkKind)
+ fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) {
+ if (descriptor.isGenerated() || !descriptor.isDocumented(options)) return
+
+ val existingNode = refGraph.lookup(descriptor.signature())
+ if (existingNode != null) {
+ existingNode.updatePlatforms(descriptor)
+
+ if (descriptor is ClassDescriptor) {
+ val membersToDocument = descriptor.collectMembersToDocument()
+ for ((memberDescriptor, inheritedLinkKind, extraModifier) in membersToDocument) {
+ if (memberDescriptor is ClassDescriptor) {
+ existingNode.appendOrUpdateMember(memberDescriptor) // recurse into nested classes
+ }
+ else {
+ val existingMemberNode = refGraph.lookup(memberDescriptor.signature())
+ if (existingMemberNode != null) {
+ existingMemberNode.updatePlatforms(memberDescriptor)
+ }
+ else {
+ existingNode.appendClassMember(memberDescriptor, inheritedLinkKind, extraModifier)
+ }
+ }
}
- null
- } else {
- val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
- appendChild(descriptorToUse, RefKind.Member)
}
}
- return nodes.filterNotNull()
+ else {
+ appendChild(descriptor, RefKind.Member)
+ }
+ }
+
+ private fun DocumentationNode.updatePlatforms(descriptor: DeclarationDescriptor) {
+ for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor) - platforms) {
+ append(platformNodeRegistry[platform], RefKind.Platform)
+ }
+ }
+
+ fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor,
+ inheritedLinkKind: RefKind = RefKind.InheritedMember,
+ extraModifier: String?) {
+ if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
+ val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
+ if (baseDescriptor != null) {
+ link(this, baseDescriptor, inheritedLinkKind)
+ }
+ } else {
+ val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
+ val child = appendChild(descriptorToUse, RefKind.Member)
+ if (extraModifier != null) {
+ child?.appendTextNode("static", NodeKind.Modifier)
+ }
+ }
}
fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) {
@@ -272,6 +343,7 @@ class DocumentationBuilder
val allFqNames = fragments.map { it.fqName }.distinct()
for (packageName in allFqNames) {
+ if (packageName.isRoot && !options.includeRootPackage) continue
val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() }
if (options.skipEmptyPackages && declarations.none { it.isDocumented(options) }) continue
@@ -282,9 +354,6 @@ class DocumentationBuilder
}
propagateExtensionFunctionsToSubclasses(fragments)
- if (options.generateIndexPages) {
- generateAllTypesNode()
- }
}
private fun propagateExtensionFunctionsToSubclasses(fragments: Collection<PackageFragmentDescriptor>) {
@@ -297,13 +366,15 @@ class DocumentationBuilder
.filter { it.extensionReceiverParameter != null }
val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name }
- allExtensionFunctions.forEach { extensionFunction ->
+ for (extensionFunction in allExtensionFunctions) {
+ if (extensionFunction.dispatchReceiverParameter != null) continue
val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name]
?.filter { fn -> fn.canShadow(extensionFunction) }
?: emptyList()
- val classDescriptor = extensionFunction.getExtensionClassDescriptor() ?: return@forEach
- val subclasses = classHierarchy[classDescriptor] ?: return@forEach
+ if (extensionFunction.extensionReceiverParameter?.type?.isDynamic() == true) continue
+ val classDescriptor = extensionFunction.getExtensionClassDescriptor() ?: continue
+ val subclasses = classHierarchy[classDescriptor] ?: continue
subclasses.forEach { subclass ->
if (subclass.isExtensionApplicable(extensionFunction) &&
possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) {
@@ -357,19 +428,6 @@ class DocumentationBuilder
return false
}
- private fun DocumentationNode.generateAllTypesNode() {
- val allTypes = members(NodeKind.Package)
- .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
- .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.') else it.name }
-
- val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
- for (typeNode in allTypes) {
- allTypesNode.addReferenceTo(typeNode, RefKind.Member)
- }
-
- append(allTypesNode, RefKind.Member)
- }
-
fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
is ClassDescriptor -> build()
is ConstructorDescriptor -> build()
@@ -392,6 +450,7 @@ class DocumentationBuilder
node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType)
node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
register(this, node)
return node
@@ -413,28 +472,48 @@ class DocumentationBuilder
}
if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
- val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS)
+ }
+ for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
+ node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
+ }
+ node.appendAnnotations(this)
+ node.appendModifiers(this)
+ node.appendSourceLink(source)
+ node.appendDefaultPlatforms(this)
+ register(this, node)
+ return node
+ }
+
+ data class ClassMember(val descriptor: DeclarationDescriptor,
+ val inheritedLinkKind: RefKind = RefKind.InheritedMember,
+ val extraModifier: String? = null)
+
+ fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> {
+ val result = arrayListOf<ClassMember>()
+ if (kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) {
+ val constructorsToDocument = if (kind == ClassKind.ENUM_CLASS)
constructors.filter { it.valueParameters.size > 0 }
else
constructors
- node.appendMembers(constructorsToDocument)
- }
- val members = defaultType.memberScope.getContributedDescriptors().filter { it != companionObjectDescriptor }
- node.appendMembers(members)
- node.appendMembers(staticScope.getContributedDescriptors()).forEach {
- it.appendTextNode("static", NodeKind.Modifier)
+ constructorsToDocument.mapTo(result) { ClassMember(it) }
}
+
+ defaultType.memberScope.getContributedDescriptors()
+ .filter { it != companionObjectDescriptor }
+ .mapTo(result) { ClassMember(it) }
+
+ staticScope.getContributedDescriptors()
+ .mapTo(result) { ClassMember(it, extraModifier = "static") }
+
val companionObjectDescriptor = companionObjectDescriptor
if (companionObjectDescriptor != null) {
val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()
val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() }
- node.appendMembers(descriptorsToDocument, RefKind.InheritedCompanionObjectMember)
+ descriptorsToDocument.mapTo(result) {
+ ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember)
+ }
}
- node.appendAnnotations(this)
- node.appendModifiers(this)
- node.appendSourceLink(source)
- register(this, node)
- return node
+ return result
}
fun CallableDescriptor.isInheritedFromAny(): Boolean {
@@ -449,6 +528,7 @@ class DocumentationBuilder
fun ConstructorDescriptor.build(): DocumentationNode {
val node = nodeForDescriptor(this, NodeKind.Constructor)
node.appendInPageChildren(valueParameters, RefKind.Detail)
+ node.appendDefaultPlatforms(this)
register(this, node)
return node
}
@@ -477,6 +557,7 @@ class DocumentationBuilder
node.appendModifiers(this)
node.appendSourceLink(source)
node.appendSignature(this)
+ node.appendDefaultPlatforms(this)
overriddenDescriptors.forEach {
addOverrideLink(it, this)
@@ -523,6 +604,7 @@ class DocumentationBuilder
overriddenDescriptors.forEach {
addOverrideLink(it, this)
}
+ node.appendDefaultPlatforms(this)
register(this, node)
return node
@@ -596,9 +678,10 @@ class DocumentationBuilder
receiverClass = upperBoundClass
}
}
- link(receiverClass,
- containingDeclaration,
- RefKind.Extension)
+
+ if ((containingDeclaration as? FunctionDescriptor)?.dispatchReceiverParameter == null) {
+ link(receiverClass, containingDeclaration, RefKind.Extension)
+ }
val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver)
node.appendType(type)
@@ -646,6 +729,8 @@ fun DeclarationDescriptor.isDocumented(options: DocumentationOptions): Boolean {
(!options.skipDeprecated || !isDeprecated())
}
+private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
+
class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
packageName: FqName,
@@ -657,7 +742,7 @@ class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
with(documentationBuilder) {
if (descriptor.isDocumented(options)) {
val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes, allFqNames)
- parent.appendChild(descriptor, RefKind.Member)
+ parent.appendOrUpdateMember(descriptor)
}
}
}
@@ -819,3 +904,23 @@ fun DeclarationDescriptor.sourceLocation(): String? {
}
return null
}
+
+fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
+ if (options.generateIndexPages) {
+ generateAllTypesNode()
+ }
+ nodeRefGraph.resolveReferences()
+}
+
+fun DocumentationNode.generateAllTypesNode() {
+ val allTypes = members(NodeKind.Package)
+ .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
+ .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.') else it.name }
+
+ val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
+ for (typeNode in allTypes) {
+ allTypesNode.addReferenceTo(typeNode, RefKind.Member)
+ }
+
+ append(allTypesNode, RefKind.Member)
+}
diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
index faac9f7d..e54772b3 100644
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
@@ -186,6 +186,10 @@ class KotlinLanguageService : LanguageService {
}
private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
+ if (node.name == "dynamic") {
+ keyword("dynamic")
+ return
+ }
if (node.isFunctionalType()) {
renderFunctionalType(node, renderMode)
return
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index def0f626..caacac14 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -48,6 +48,7 @@ enum class NodeKind {
Signature,
ExternalLink,
+ Platform,
AllTypes,
@@ -97,6 +98,8 @@ open class DocumentationNode(val name: String,
get() = references(RefKind.Annotation).map { it.to }
val deprecation: DocumentationNode?
get() = references(RefKind.Deprecation).singleOrNull()?.to
+ val platforms: List<String>
+ get() = references(RefKind.Platform).map { it.to.name }
// TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice
fun addReferenceTo(to: DocumentationNode, kind: RefKind) {
@@ -135,6 +138,7 @@ open class DocumentationNode(val name: String,
class DocumentationModule(name: String, content: Content = Content.Empty)
: DocumentationNode(name, content, NodeKind.Module) {
+ val nodeRefGraph = NodeReferenceGraph()
}
val DocumentationNode.path: List<DocumentationNode>
diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt
index 0165b567..a968f400 100644
--- a/core/src/main/kotlin/Model/DocumentationReference.kt
+++ b/core/src/main/kotlin/Model/DocumentationReference.kt
@@ -1,6 +1,5 @@
package org.jetbrains.dokka
-import com.google.inject.Inject
import com.google.inject.Singleton
enum class RefKind {
@@ -18,7 +17,8 @@ enum class RefKind {
Annotation,
HiddenAnnotation,
Deprecation,
- TopLevelPage
+ TopLevelPage,
+ Platform
}
data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) {
@@ -36,9 +36,7 @@ class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
}
}
-@Singleton
-class NodeReferenceGraph
- @Inject constructor(val logger: DokkaLogger) {
+class NodeReferenceGraph() {
private val nodeMap = hashMapOf<String, DocumentationNode>()
val references = arrayListOf<PendingDocumentationReference>()
@@ -58,7 +56,9 @@ class NodeReferenceGraph
references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> nodeMap[toSignature]}, kind))
}
- fun lookup(signature: String): DocumentationNode? {
+ fun lookup(signature: String) = nodeMap[signature]
+
+ fun lookupOrWarn(signature: String, logger: DokkaLogger): DocumentationNode? {
val result = nodeMap[signature]
if (result == null) {
logger.warn("Can't find node by signature $signature")
@@ -70,3 +70,14 @@ class NodeReferenceGraph
references.forEach { it.resolve() }
}
}
+
+@Singleton
+class PlatformNodeRegistry {
+ private val platformNodes = hashMapOf<String, DocumentationNode>()
+
+ operator fun get(platform: String): DocumentationNode {
+ return platformNodes.getOrPut(platform) {
+ DocumentationNode(platform, Content.Empty, NodeKind.Platform)
+ }
+ }
+}
diff --git a/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt b/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
index e6539135..1eb0c114 100644
--- a/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
+++ b/core/src/main/kotlin/Samples/DefaultSampleProcessingService.kt
@@ -42,10 +42,9 @@ open class DefaultSampleProcessingService
return ContentBlockSampleCode().apply { append(ContentText("//Source not found: $functionName")) }
}
- val text = processSampleBody(psiElement)
-
- val lines = text.trimEnd().split("\n".toRegex()).toTypedArray().filterNot(String::isEmpty)
- val indent = lines.map { it.takeWhile(Char::isWhitespace).count() }.min() ?: 0
+ val text = processSampleBody(psiElement).trim { it == '\n' || it == '\r' }.trimEnd()
+ val lines = text.split("\n")
+ val indent = lines.filter(String::isNotBlank).map { it.takeWhile(Char::isWhitespace).count() }.min() ?: 0
val finalText = lines.map { it.drop(indent) }.joinToString("\n")
return ContentBlockSampleCode(importsBlock = processImports(psiElement)).apply { append(ContentText(finalText)) }
diff --git a/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt b/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
index ffc5c9c7..ca857aaa 100644
--- a/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
+++ b/core/src/main/kotlin/Samples/KotlinWebsiteSampleProcessingService.kt
@@ -2,6 +2,7 @@ package org.jetbrains.dokka.Samples
import com.google.inject.Inject
import com.intellij.psi.PsiElement
+import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.dokka.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ImportPath
@@ -12,7 +13,7 @@ open class KotlinWebsiteSampleProcessingService
resolutionFacade: DokkaResolutionFacade)
: DefaultSampleProcessingService(options, logger, resolutionFacade) {
- private class SampleBuilder() : KtVisitorVoid() {
+ private class SampleBuilder : KtTreeVisitorVoid() {
val builder = StringBuilder()
val text: String
get() = builder.toString()
@@ -48,13 +49,10 @@ open class KotlinWebsiteSampleProcessingService
}
}
- override fun visitElement(element: PsiElement?) {
- if (element != null) {
- if (element.children.isEmpty())
- builder.append(element.text)
- else
- element.acceptChildren(this)
- }
+ override fun visitElement(element: PsiElement) {
+ if (element is LeafPsiElement)
+ builder.append(element.text)
+ super.visitElement(element)
}
}
diff --git a/core/src/main/kotlin/Utilities/DokkaModule.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt
index e1ae829a..5982d7dd 100644
--- a/core/src/main/kotlin/Utilities/DokkaModule.kt
+++ b/core/src/main/kotlin/Utilities/DokkaModules.kt
@@ -3,6 +3,7 @@ package org.jetbrains.dokka.Utilities
import com.google.inject.Binder
import com.google.inject.Module
import com.google.inject.Provider
+import com.google.inject.TypeLiteral
import com.google.inject.name.Names
import org.jetbrains.dokka.*
import org.jetbrains.dokka.Formats.FormatDescriptor
@@ -10,10 +11,47 @@ import org.jetbrains.dokka.Samples.SampleProcessingService
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import java.io.File
-class DokkaModule(val environment: AnalysisEnvironment,
- val options: DocumentationOptions,
- val logger: DokkaLogger) : Module {
+const val impliedPlatformsName = "impliedPlatforms"
+
+class DokkaAnalysisModule(val environment: AnalysisEnvironment,
+ val options: DocumentationOptions,
+ val defaultPlatformsProvider: DefaultPlatformsProvider,
+ val nodeReferenceGraph: NodeReferenceGraph,
+ val logger: DokkaLogger) : Module {
+ override fun configure(binder: Binder) {
+ val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", options.outputFormat)
+
+ binder.registerCategory<LanguageService>("language")
+ binder.bind<PackageDocumentationBuilder>().to(descriptor.packageDocumentationBuilderClass.java)
+ binder.bind<JavaDocumentationBuilder>().to(descriptor.javaDocumentationBuilderClass.java)
+ binder.bind<SampleProcessingService>().to(descriptor.sampleProcessingService.java)
+
+ val coreEnvironment = environment.createCoreEnvironment()
+ binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
+
+ val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
+ binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
+
+ binder.bind<DocumentationOptions>().toInstance(options)
+ binder.bind<DokkaLogger>().toInstance(logger)
+
+ binder.bind<DefaultPlatformsProvider>().toInstance(defaultPlatformsProvider)
+
+ binder.bind<NodeReferenceGraph>().toInstance(nodeReferenceGraph)
+ }
+}
+
+object StringListType : TypeLiteral<@JvmSuppressWildcards List<String>>()
+
+class DokkaOutputModule(val options: DocumentationOptions,
+ val logger: DokkaLogger) : Module {
override fun configure(binder: Binder) {
+ binder.bind(LanguageService::class.java).to(KotlinLanguageService::class.java)
+
+ binder.bind(HtmlTemplateService::class.java).toProvider(object : Provider<HtmlTemplateService> {
+ override fun get(): HtmlTemplateService = HtmlTemplateService.default("style.css")
+ })
+
binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(options.outputDir))
binder.bindNameAnnotated<LocationService, SingleFolderLocationService>("singleFolder")
@@ -24,13 +62,7 @@ class DokkaModule(val environment: AnalysisEnvironment,
// defaults
binder.bind(LocationService::class.java).to(FoldersLocationService::class.java)
binder.bind(FileLocationService::class.java).to(FoldersLocationService::class.java)
- binder.bind(LanguageService::class.java).to(KotlinLanguageService::class.java)
-
- binder.bind(HtmlTemplateService::class.java).toProvider(object : Provider<HtmlTemplateService> {
- override fun get(): HtmlTemplateService = HtmlTemplateService.default("style.css")
- })
- binder.registerCategory<LanguageService>("language")
binder.registerCategory<OutlineFormatService>("outline")
binder.registerCategory<FormatService>("format")
binder.registerCategory<Generator>("generator")
@@ -43,20 +75,12 @@ class DokkaModule(val environment: AnalysisEnvironment,
descriptor.formatServiceClass?.let { clazz ->
binder.bind(FormatService::class.java).to(clazz.java)
}
- binder.bind<PackageDocumentationBuilder>().to(descriptor.packageDocumentationBuilderClass.java)
- binder.bind<JavaDocumentationBuilder>().to(descriptor.javaDocumentationBuilderClass.java)
- binder.bind<SampleProcessingService>().to(descriptor.sampleProcessingService.java)
binder.bind<Generator>().to(descriptor.generatorServiceClass.java)
- val coreEnvironment = environment.createCoreEnvironment()
- binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
-
- val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
- binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
-
binder.bind<DocumentationOptions>().toInstance(options)
binder.bind<DokkaLogger>().toInstance(logger)
+ binder.bind(StringListType).annotatedWith(Names.named(impliedPlatformsName)).toInstance(options.impliedPlatforms)
}
}
diff --git a/core/src/test/kotlin/TestAPI.kt b/core/src/test/kotlin/TestAPI.kt
index 7197d2c4..09a346cf 100644
--- a/core/src/test/kotlin/TestAPI.kt
+++ b/core/src/test/kotlin/TestAPI.kt
@@ -5,13 +5,14 @@ import com.intellij.openapi.application.PathManager
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Utilities.DokkaModule
+import org.jetbrains.dokka.Utilities.DokkaAnalysisModule
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.config.ContentRoot
import org.jetbrains.kotlin.config.KotlinSourceRoot
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.junit.Assert
import org.junit.Assert.fail
import java.io.File
@@ -22,6 +23,30 @@ fun verifyModel(vararg roots: ContentRoot,
format: String = "html",
includeNonPublic: Boolean = true,
verifier: (DocumentationModule) -> Unit) {
+ val documentation = DocumentationModule("test")
+
+ val options = DocumentationOptions("", format,
+ includeNonPublic = includeNonPublic,
+ skipEmptyPackages = false,
+ includeRootPackage = true,
+ sourceLinks = listOf<SourceLinkDefinition>(),
+ generateIndexPages = false)
+
+ appendDocumentation(documentation, *roots,
+ withJdk = withJdk,
+ withKotlinRuntime = withKotlinRuntime,
+ options = options)
+ documentation.prepareForGeneration(options)
+
+ verifier(documentation)
+}
+
+fun appendDocumentation(documentation: DocumentationModule,
+ vararg roots: ContentRoot,
+ withJdk: Boolean = false,
+ withKotlinRuntime: Boolean = false,
+ options: DocumentationOptions,
+ defaultPlatforms: List<String> = emptyList()) {
val messageCollector = object : MessageCollector {
override fun clear() {
@@ -60,14 +85,12 @@ fun verifyModel(vararg roots: ContentRoot,
}
addRoots(roots.toList())
}
- val options = DocumentationOptions("", format,
- includeNonPublic = includeNonPublic,
- skipEmptyPackages = false,
- sourceLinks = listOf<SourceLinkDefinition>(),
- generateIndexPages = false)
- val injector = Guice.createInjector(DokkaModule(environment, options, DokkaConsoleLogger))
- val documentation = buildDocumentationModule(injector, "test")
- verifier(documentation)
+ val defaultPlatformsProvider = object : DefaultPlatformsProvider {
+ override fun getDefaultPlatforms(descriptor: DeclarationDescriptor) = defaultPlatforms
+ }
+ val injector = Guice.createInjector(
+ DokkaAnalysisModule(environment, options, defaultPlatformsProvider, documentation.nodeRefGraph, DokkaConsoleLogger))
+ buildDocumentationModule(injector, documentation)
Disposer.dispose(environment)
}
@@ -128,19 +151,23 @@ fun verifyOutput(roots: Array<ContentRoot>,
format: String = "html",
outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
verifyModel(*roots, withJdk = withJdk, withKotlinRuntime = withKotlinRuntime, format = format) {
- verifyModelOutput(it, outputExtension, outputGenerator, roots.first().path)
+ verifyModelOutput(it, outputExtension, roots.first().path, outputGenerator)
}
}
-private fun verifyModelOutput(it: DocumentationModule,
- outputExtension: String,
- outputGenerator: (DocumentationModule, StringBuilder) -> Unit,
- sourcePath: String) {
+fun verifyModelOutput(it: DocumentationModule,
+ outputExtension: String,
+ sourcePath: String,
+ outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
val output = StringBuilder()
outputGenerator(it, output)
val ext = outputExtension.removePrefix(".")
- val path = sourcePath
- val expectedOutput = File(path.replaceAfterLast(".", ext, path + "." + ext)).readText()
+ val expectedFileContent = File(sourcePath.replaceAfterLast(".", ext, sourcePath + "." + ext)).readText()
+ val expectedOutput =
+ if (ext.equals("html", true))
+ expectedFileContent.lines().joinToString(separator = "\n", transform = String::trim)
+ else
+ expectedFileContent
assertEqualsIgnoringSeparators(expectedOutput, output.toString())
}
@@ -158,7 +185,7 @@ fun verifyJavaOutput(path: String,
withKotlinRuntime: Boolean = false,
outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
verifyJavaModel(path, withKotlinRuntime) { model ->
- verifyModelOutput(model, outputExtension, outputGenerator, path)
+ verifyModelOutput(model, outputExtension, path, outputGenerator)
}
}
diff --git a/core/src/test/kotlin/format/GFMFormatTest.kt b/core/src/test/kotlin/format/GFMFormatTest.kt
index 5327c9dc..c097c5c8 100644
--- a/core/src/test/kotlin/format/GFMFormatTest.kt
+++ b/core/src/test/kotlin/format/GFMFormatTest.kt
@@ -5,7 +5,7 @@ import org.jetbrains.dokka.KotlinLanguageService
import org.junit.Test
class GFMFormatTest {
- private val gfmService = GFMFormatService(InMemoryLocationService, KotlinLanguageService())
+ private val gfmService = GFMFormatService(InMemoryLocationService, KotlinLanguageService(), listOf())
@Test fun sample() {
verifyGFMNodeByName("sample", "Foo")
diff --git a/core/src/test/kotlin/format/HtmlFormatTest.kt b/core/src/test/kotlin/format/HtmlFormatTest.kt
index f2b8624d..cbea3209 100644
--- a/core/src/test/kotlin/format/HtmlFormatTest.kt
+++ b/core/src/test/kotlin/format/HtmlFormatTest.kt
@@ -7,7 +7,7 @@ import org.junit.Test
import java.io.File
class HtmlFormatTest {
- private val htmlService = HtmlFormatService(InMemoryLocationService, KotlinLanguageService(), HtmlTemplateService.default())
+ private val htmlService = HtmlFormatService(InMemoryLocationService, KotlinLanguageService(), HtmlTemplateService.default(), listOf())
@Test fun classWithCompanionObject() {
verifyHtmlNode("classWithCompanionObject")
@@ -138,6 +138,10 @@ class HtmlFormatTest {
verifyHtmlNode("functionalTypeWithNamedParameters")
}
+ @Test fun sinceKotlin() {
+ verifyHtmlNode("sinceKotlin")
+ }
+
@Test fun blankLineInsideCodeBlock() {
verifyHtmlNode("blankLineInsideCodeBlock")
}
diff --git a/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt b/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
index 3363b0a3..27c84aca 100644
--- a/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
+++ b/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
@@ -5,7 +5,7 @@ import org.jetbrains.dokka.KotlinWebsiteFormatService
import org.junit.Test
class KotlinWebSiteFormatTest {
- private val kwsService = KotlinWebsiteFormatService(InMemoryLocationService, KotlinLanguageService())
+ private val kwsService = KotlinWebsiteFormatService(InMemoryLocationService, KotlinLanguageService(), listOf())
@Test fun sample() {
verifyKWSNodeByName("sample", "foo")
diff --git a/core/src/test/kotlin/format/KotlinWebSiteRunnableSamplesFormatTest.kt b/core/src/test/kotlin/format/KotlinWebSiteRunnableSamplesFormatTest.kt
index 742d2908..3e46ead7 100644
--- a/core/src/test/kotlin/format/KotlinWebSiteRunnableSamplesFormatTest.kt
+++ b/core/src/test/kotlin/format/KotlinWebSiteRunnableSamplesFormatTest.kt
@@ -5,7 +5,7 @@ import org.jetbrains.dokka.KotlinWebsiteRunnableSamplesFormatService
import org.junit.Test
class KotlinWebSiteRunnableSamplesFormatTest {
- private val kwsService = KotlinWebsiteRunnableSamplesFormatService(InMemoryLocationService, KotlinLanguageService())
+ private val kwsService = KotlinWebsiteRunnableSamplesFormatService(InMemoryLocationService, KotlinLanguageService(), listOf())
@Test fun dropImport() {
@@ -20,6 +20,10 @@ class KotlinWebSiteRunnableSamplesFormatTest {
verifyKWSNodeByName("sampleWithAsserts", "a")
}
+ @Test fun newLinesInSamples() {
+ verifyKWSNodeByName("newLinesInSamples", "foo")
+ }
+
private fun verifyKWSNodeByName(fileName: String, name: String) {
verifyOutput("testdata/format/website-samples/$fileName.kt", ".md", format = "kotlin-website-samples") { model, output ->
kwsService.createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members.filter { it.name == name })
diff --git a/core/src/test/kotlin/format/MarkdownFormatTest.kt b/core/src/test/kotlin/format/MarkdownFormatTest.kt
index d788c84d..4830d760 100644
--- a/core/src/test/kotlin/format/MarkdownFormatTest.kt
+++ b/core/src/test/kotlin/format/MarkdownFormatTest.kt
@@ -1,14 +1,10 @@
package org.jetbrains.dokka.tests
-import org.jetbrains.dokka.DocumentationModule
-import org.jetbrains.dokka.DocumentationNode
-import org.jetbrains.dokka.KotlinLanguageService
-import org.jetbrains.dokka.MarkdownFormatService
-import org.junit.Ignore
+import org.jetbrains.dokka.*
import org.junit.Test
class MarkdownFormatTest {
- private val markdownService = MarkdownFormatService(InMemoryLocationService, KotlinLanguageService())
+ private val markdownService = MarkdownFormatService(InMemoryLocationService, KotlinLanguageService(), listOf())
@Test fun emptyDescription() {
verifyMarkdownNode("emptyDescription")
@@ -241,6 +237,67 @@ class MarkdownFormatTest {
verifyMarkdownPackage("suspendParam")
}
+ @Test fun sinceKotlin() {
+ verifyMarkdownNode("sinceKotlin")
+ verifyMarkdownPackage("sinceKotlin")
+ }
+
+ @Test fun dynamicType() {
+ verifyMarkdownNode("dynamicType")
+ }
+
+ @Test fun dynamicExtension() {
+ verifyMarkdownNodes("dynamicExtension") { model -> model.members.single().members.filter { it.name == "Foo" } }
+ }
+
+ @Test fun memberExtension() {
+ verifyMarkdownNodes("memberExtension") { model -> model.members.single().members.filter { it.name == "Foo" } }
+ }
+
+ @Test fun multiplePlatforms() {
+ verifyMultiplatformPackage(buildMultiplePlatforms("multiplatform"), "multiplatform")
+ }
+
+ @Test fun multiplePlatformsMerge() {
+ verifyMultiplatformPackage(buildMultiplePlatforms("multiplatformMerge"), "multiplatformMerge")
+ }
+
+ @Test fun multiplePlatformsMergeMembers() {
+ val module = buildMultiplePlatforms("multiplatformMergeMembers")
+ verifyModelOutput(module, ".md", "testdata/format/multiplatformMergeMembers/foo.kt") { model, output ->
+ markdownService.createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members)
+ }
+ }
+
+ @Test fun multiplePlatformsOmitRedundant() {
+ val module = buildMultiplePlatforms("multiplatformOmitRedundant")
+ verifyModelOutput(module, ".md", "testdata/format/multiplatformOmitRedundant/foo.kt") { model, output ->
+ markdownService.createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members)
+ }
+ }
+
+ @Test fun multiplePlatformsImplied() {
+ val module = buildMultiplePlatforms("multiplatformImplied")
+ verifyModelOutput(module, ".md", "testdata/format/multiplatformImplied/foo.kt") { model, output ->
+ MarkdownFormatService(InMemoryLocationService, KotlinLanguageService(), listOf("JVM", "JS"))
+ .createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members)
+ }
+ }
+
+ private fun buildMultiplePlatforms(path: String): DocumentationModule {
+ val module = DocumentationModule("test")
+ val options = DocumentationOptions("", "html", generateIndexPages = false)
+ appendDocumentation(module, contentRootFromPath("testdata/format/$path/jvm.kt"), defaultPlatforms = listOf("JVM"), options = options)
+ appendDocumentation(module, contentRootFromPath("testdata/format/$path/js.kt"), defaultPlatforms = listOf("JS"), options = options)
+ return module
+ }
+
+ private fun verifyMultiplatformPackage(module: DocumentationModule, path: String) {
+ verifyModelOutput(module, ".package.md", "testdata/format/$path/multiplatform.kt") { model, output ->
+ markdownService.createOutputBuilder(output, tempLocation).appendNodes(model.members)
+ }
+ }
+
@Test fun blankLineInsideCodeBlock() {
verifyMarkdownNode("blankLineInsideCodeBlock")
}
diff --git a/core/src/test/kotlin/model/ClassTest.kt b/core/src/test/kotlin/model/ClassTest.kt
index d50a3624..fb225728 100644
--- a/core/src/test/kotlin/model/ClassTest.kt
+++ b/core/src/test/kotlin/model/ClassTest.kt
@@ -3,11 +3,11 @@ package org.jetbrains.dokka.tests
import org.jetbrains.dokka.Content
import org.jetbrains.dokka.NodeKind
import org.jetbrains.dokka.RefKind
-import org.junit.Test
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
+import org.junit.Test
-public class ClassTest {
+class ClassTest {
@Test fun emptyClass() {
verifyModel("testdata/classes/emptyClass.kt") { model ->
with(model.members.single().members.single()) {
@@ -272,4 +272,12 @@ public class ClassTest {
}
}
}
+
+ @Test fun sinceKotlin() {
+ verifyModel("testdata/classes/sinceKotlin.kt") { model ->
+ with(model.members.single().members.single()) {
+ assertEquals(listOf("Kotlin 1.1"), platforms)
+ }
+ }
+ }
}
diff --git a/core/src/test/kotlin/model/CommentTest.kt b/core/src/test/kotlin/model/CommentTest.kt
index 2b2bc87e..3752bb8c 100644
--- a/core/src/test/kotlin/model/CommentTest.kt
+++ b/core/src/test/kotlin/model/CommentTest.kt
@@ -157,7 +157,8 @@ line two""", toTestString())
with(model.members.single().members.first()) {
assertEquals("Summary", content.summary.toTestString())
with (content.description) {
- assertEqualsIgnoringSeparators("""[code lang=kotlin]
+ assertEqualsIgnoringSeparators("""
+ |[code lang=kotlin]
|if (true) {
| println(property)
|}
diff --git a/core/src/test/kotlin/model/FunctionTest.kt b/core/src/test/kotlin/model/FunctionTest.kt
index 4cced562..ddd33941 100644
--- a/core/src/test/kotlin/model/FunctionTest.kt
+++ b/core/src/test/kotlin/model/FunctionTest.kt
@@ -2,11 +2,11 @@ package org.jetbrains.dokka.tests
import org.jetbrains.dokka.Content
import org.jetbrains.dokka.NodeKind
-import org.junit.Test
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
+import org.junit.Test
-public class FunctionTest {
+class FunctionTest {
@Test fun function() {
verifyModel("testdata/functions/function.kt") { model ->
with(model.members.single().members.single()) {
@@ -224,4 +224,12 @@ Documentation""", content.description.toTestString())
}
}
}
+
+ @Test fun sinceKotlin() {
+ verifyModel("testdata/functions/sinceKotlin.kt") { model ->
+ with(model.members.single().members.single()) {
+ assertEquals(listOf("Kotlin 1.1"), platforms)
+ }
+ }
+ }
}
diff --git a/core/src/test/kotlin/model/PropertyTest.kt b/core/src/test/kotlin/model/PropertyTest.kt
index cdf44c03..0ee0e0f5 100644
--- a/core/src/test/kotlin/model/PropertyTest.kt
+++ b/core/src/test/kotlin/model/PropertyTest.kt
@@ -3,11 +3,11 @@ package org.jetbrains.dokka.tests
import org.jetbrains.dokka.Content
import org.jetbrains.dokka.NodeKind
import org.jetbrains.dokka.RefKind
-import org.junit.Test
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
+import org.junit.Test
-public class PropertyTest {
+class PropertyTest {
@Test fun valueProperty() {
verifyModel("testdata/properties/valueProperty.kt") { model ->
with(model.members.single().members.single()) {
@@ -100,4 +100,12 @@ public class PropertyTest {
}
}
}
+
+ @Test fun sinceKotlin() {
+ verifyModel("testdata/properties/sinceKotlin.kt") { model ->
+ with(model.members.single().members.single()) {
+ assertEquals(listOf("Kotlin 1.1"), platforms)
+ }
+ }
+ }
}
diff --git a/core/src/test/kotlin/model/TypeAliasTest.kt b/core/src/test/kotlin/model/TypeAliasTest.kt
index 812fd9dc..c653ac83 100644
--- a/core/src/test/kotlin/model/TypeAliasTest.kt
+++ b/core/src/test/kotlin/model/TypeAliasTest.kt
@@ -120,4 +120,13 @@ class TypeAliasTest {
}
}
}
+
+ @Test
+ fun sinceKotlin() {
+ verifyModel("testdata/typealias/sinceKotlin.kt") { model ->
+ with(model.members.single().members.single()) {
+ assertEquals(listOf("Kotlin 1.1"), platforms)
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/core/testdata/classes/sinceKotlin.kt b/core/testdata/classes/sinceKotlin.kt
new file mode 100644
index 00000000..1025cf0d
--- /dev/null
+++ b/core/testdata/classes/sinceKotlin.kt
@@ -0,0 +1,5 @@
+/**
+ * Useful
+ */
+@SinceKotlin("1.1")
+class `Since1.1` \ No newline at end of file
diff --git a/core/testdata/format/dynamicExtension.kt b/core/testdata/format/dynamicExtension.kt
new file mode 100644
index 00000000..5c83bf22
--- /dev/null
+++ b/core/testdata/format/dynamicExtension.kt
@@ -0,0 +1,3 @@
+class Foo
+
+fun dynamic.bar() {}
diff --git a/core/testdata/format/dynamicExtension.md b/core/testdata/format/dynamicExtension.md
new file mode 100644
index 00000000..2fd928f6
--- /dev/null
+++ b/core/testdata/format/dynamicExtension.md
@@ -0,0 +1,10 @@
+[test](test/index) / [Foo](test/-foo/index)
+
+# Foo
+
+`class Foo`
+
+### Constructors
+
+| [&lt;init&gt;](test/-foo/-init-) | `Foo()` |
+
diff --git a/core/testdata/format/dynamicType.kt b/core/testdata/format/dynamicType.kt
new file mode 100644
index 00000000..9d557ac0
--- /dev/null
+++ b/core/testdata/format/dynamicType.kt
@@ -0,0 +1,2 @@
+fun foo(): dynamic = ""
+
diff --git a/core/testdata/format/dynamicType.md b/core/testdata/format/dynamicType.md
new file mode 100644
index 00000000..a3d6696b
--- /dev/null
+++ b/core/testdata/format/dynamicType.md
@@ -0,0 +1,5 @@
+[test](test/index) / [foo](test/foo)
+
+# foo
+
+`fun foo(): dynamic` \ No newline at end of file
diff --git a/core/testdata/format/memberExtension.kt b/core/testdata/format/memberExtension.kt
new file mode 100644
index 00000000..955794d1
--- /dev/null
+++ b/core/testdata/format/memberExtension.kt
@@ -0,0 +1,8 @@
+open class X
+
+class Foo : X
+
+class Bar {
+ fun X.y() = ""
+ fun Foo.x() = ""
+}
diff --git a/core/testdata/format/memberExtension.md b/core/testdata/format/memberExtension.md
new file mode 100644
index 00000000..b9db4e3d
--- /dev/null
+++ b/core/testdata/format/memberExtension.md
@@ -0,0 +1,10 @@
+[test](test/index) / [Foo](test/-foo/index)
+
+# Foo
+
+`class Foo : `[`X`](test/-x/index)
+
+### Constructors
+
+| [&lt;init&gt;](test/-foo/-init-) | `Foo()` |
+
diff --git a/core/testdata/format/multiplatform/js.kt b/core/testdata/format/multiplatform/js.kt
new file mode 100644
index 00000000..e6d66ffd
--- /dev/null
+++ b/core/testdata/format/multiplatform/js.kt
@@ -0,0 +1,7 @@
+package foo
+
+/**
+ * This is a bar.
+ */
+class Bar {
+}
diff --git a/core/testdata/format/multiplatform/jvm.kt b/core/testdata/format/multiplatform/jvm.kt
new file mode 100644
index 00000000..cb77273f
--- /dev/null
+++ b/core/testdata/format/multiplatform/jvm.kt
@@ -0,0 +1,8 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+
+}
diff --git a/core/testdata/format/multiplatform/multiplatform.package.md b/core/testdata/format/multiplatform/multiplatform.package.md
new file mode 100644
index 00000000..3574942c
--- /dev/null
+++ b/core/testdata/format/multiplatform/multiplatform.package.md
@@ -0,0 +1,9 @@
+[test](test/index) / [foo](test/foo/index)
+
+## Package foo
+
+### Types
+
+| [Bar](test/foo/-bar/index)<br>(JS) | `class Bar`<br>This is a bar. |
+| [Foo](test/foo/-foo/index)<br>(JVM) | `class Foo`<br>This is a foo. |
+
diff --git a/core/testdata/format/multiplatformImplied/foo.md b/core/testdata/format/multiplatformImplied/foo.md
new file mode 100644
index 00000000..c615dd8e
--- /dev/null
+++ b/core/testdata/format/multiplatformImplied/foo.md
@@ -0,0 +1,24 @@
+[test](test/index) / [foo](test/foo/index) / [Foo](test/foo/-foo/index)
+
+# Foo
+
+`class Foo`
+
+This is a foo.
+
+### Constructors
+
+| [&lt;init&gt;](test/foo/-foo/-init-) | `Foo()`<br>This is a foo. |
+
+### Properties
+
+| [propJs](test/foo/-foo/prop-js)<br>(JS) | `val propJs: String` |
+| [propJvm](test/foo/-foo/prop-jvm)<br>(JVM) | `val propJvm: String` |
+| [propJvmAndJs](test/foo/-foo/prop-jvm-and-js) | `val propJvmAndJs: Int` |
+
+### Functions
+
+| [bothJvmAndJs](test/foo/-foo/both-jvm-and-js) | `fun bothJvmAndJs(): Unit` |
+| [js](test/foo/-foo/js)<br>(JS) | `fun js(): Unit` |
+| [jvm](test/foo/-foo/jvm)<br>(JVM) | `fun jvm(): Unit` |
+
diff --git a/core/testdata/format/multiplatformImplied/js.kt b/core/testdata/format/multiplatformImplied/js.kt
new file mode 100644
index 00000000..dd2de5bc
--- /dev/null
+++ b/core/testdata/format/multiplatformImplied/js.kt
@@ -0,0 +1,16 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+ fun bothJvmAndJs() {
+ }
+
+ fun js() {
+ }
+
+ val propJvmAndJs = 0
+
+ val propJs = "abc"
+}
diff --git a/core/testdata/format/multiplatformImplied/jvm.kt b/core/testdata/format/multiplatformImplied/jvm.kt
new file mode 100644
index 00000000..8d73ce25
--- /dev/null
+++ b/core/testdata/format/multiplatformImplied/jvm.kt
@@ -0,0 +1,16 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+ fun bothJvmAndJs() {
+ }
+
+ fun jvm() {
+ }
+
+ val propJvmAndJs = 0
+
+ val propJvm = "abc"
+}
diff --git a/core/testdata/format/multiplatformMerge/js.kt b/core/testdata/format/multiplatformMerge/js.kt
new file mode 100644
index 00000000..bbf1dd7c
--- /dev/null
+++ b/core/testdata/format/multiplatformMerge/js.kt
@@ -0,0 +1,7 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+}
diff --git a/core/testdata/format/multiplatformMerge/jvm.kt b/core/testdata/format/multiplatformMerge/jvm.kt
new file mode 100644
index 00000000..cb77273f
--- /dev/null
+++ b/core/testdata/format/multiplatformMerge/jvm.kt
@@ -0,0 +1,8 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+
+}
diff --git a/core/testdata/format/multiplatformMerge/multiplatform.package.md b/core/testdata/format/multiplatformMerge/multiplatform.package.md
new file mode 100644
index 00000000..a423f603
--- /dev/null
+++ b/core/testdata/format/multiplatformMerge/multiplatform.package.md
@@ -0,0 +1,8 @@
+[test](test/index) / [foo](test/foo/index)
+
+## Package foo
+
+### Types
+
+| [Foo](test/foo/-foo/index)<br>(JVM, JS) | `class Foo`<br>This is a foo. |
+
diff --git a/core/testdata/format/multiplatformMergeMembers/foo.md b/core/testdata/format/multiplatformMergeMembers/foo.md
new file mode 100644
index 00000000..7490c878
--- /dev/null
+++ b/core/testdata/format/multiplatformMergeMembers/foo.md
@@ -0,0 +1,26 @@
+[test](test/index) / [foo](test/foo/index) / [Foo](test/foo/-foo/index)
+
+# Foo
+
+`class Foo`
+
+**Platform and version requirements:** JVM, JS
+
+This is a foo.
+
+### Constructors
+
+| [&lt;init&gt;](test/foo/-foo/-init-) | `Foo()`<br>This is a foo. |
+
+### Properties
+
+| [propJs](test/foo/-foo/prop-js)<br>(JS) | `val propJs: String` |
+| [propJvm](test/foo/-foo/prop-jvm)<br>(JVM) | `val propJvm: String` |
+| [propJvmAndJs](test/foo/-foo/prop-jvm-and-js) | `val propJvmAndJs: Int` |
+
+### Functions
+
+| [bothJvmAndJs](test/foo/-foo/both-jvm-and-js) | `fun bothJvmAndJs(): Unit` |
+| [js](test/foo/-foo/js)<br>(JS) | `fun js(): Unit` |
+| [jvm](test/foo/-foo/jvm)<br>(JVM) | `fun jvm(): Unit` |
+
diff --git a/core/testdata/format/multiplatformMergeMembers/js.kt b/core/testdata/format/multiplatformMergeMembers/js.kt
new file mode 100644
index 00000000..dd2de5bc
--- /dev/null
+++ b/core/testdata/format/multiplatformMergeMembers/js.kt
@@ -0,0 +1,16 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+ fun bothJvmAndJs() {
+ }
+
+ fun js() {
+ }
+
+ val propJvmAndJs = 0
+
+ val propJs = "abc"
+}
diff --git a/core/testdata/format/multiplatformMergeMembers/jvm.kt b/core/testdata/format/multiplatformMergeMembers/jvm.kt
new file mode 100644
index 00000000..8d73ce25
--- /dev/null
+++ b/core/testdata/format/multiplatformMergeMembers/jvm.kt
@@ -0,0 +1,16 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+ fun bothJvmAndJs() {
+ }
+
+ fun jvm() {
+ }
+
+ val propJvmAndJs = 0
+
+ val propJvm = "abc"
+}
diff --git a/core/testdata/format/multiplatformOmitRedundant/foo.md b/core/testdata/format/multiplatformOmitRedundant/foo.md
new file mode 100644
index 00000000..088ced2c
--- /dev/null
+++ b/core/testdata/format/multiplatformOmitRedundant/foo.md
@@ -0,0 +1,22 @@
+[test](test/index) / [foo](test/foo/index) / [Foo](test/foo/-foo/index)
+
+# Foo
+
+`class Foo`
+
+**Platform and version requirements:** JVM
+
+This is a foo.
+
+### Constructors
+
+| [&lt;init&gt;](test/foo/-foo/-init-) | `Foo()`<br>This is a foo. |
+
+### Properties
+
+| [propJvm](test/foo/-foo/prop-jvm) | `val propJvm: String` |
+
+### Functions
+
+| [jvm](test/foo/-foo/jvm) | `fun jvm(): Unit` |
+
diff --git a/core/testdata/format/multiplatformOmitRedundant/js.kt b/core/testdata/format/multiplatformOmitRedundant/js.kt
new file mode 100644
index 00000000..d1b1429c
--- /dev/null
+++ b/core/testdata/format/multiplatformOmitRedundant/js.kt
@@ -0,0 +1,2 @@
+package foo
+
diff --git a/core/testdata/format/multiplatformOmitRedundant/jvm.kt b/core/testdata/format/multiplatformOmitRedundant/jvm.kt
new file mode 100644
index 00000000..35e3c08d
--- /dev/null
+++ b/core/testdata/format/multiplatformOmitRedundant/jvm.kt
@@ -0,0 +1,11 @@
+package foo
+
+/**
+ * This is a foo.
+ */
+class Foo {
+ fun jvm() {
+ }
+
+ val propJvm = "abc"
+}
diff --git a/core/testdata/format/sinceKotlin.html b/core/testdata/format/sinceKotlin.html
new file mode 100644
index 00000000..eef5ca66
--- /dev/null
+++ b/core/testdata/format/sinceKotlin.html
@@ -0,0 +1,27 @@
+<HTML>
+<HEAD>
+ <meta charset="UTF-8">
+ <title>Since1.1 - test</title>
+</HEAD>
+<BODY>
+<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/-since1.1/index">Since1.1</a><br/>
+<br/>
+<h1>Since1.1</h1>
+<code><span class="keyword">class </span><span class="identifier">Since1.1</span></code>
+<p><strong>Platform and version requirements:</strong> Kotlin 1.1</p>
+<p>Useful</p>
+<h3>Constructors</h3>
+<table>
+ <tbody>
+ <tr>
+ <td>
+ <a href="test/-since1.1/-init-">&lt;init&gt;</a></td>
+ <td>
+ <code><span class="identifier">Since1.1</span><span class="symbol">(</span><span class="symbol">)</span></code>
+ <p>Useful</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+</BODY>
+</HTML>
diff --git a/core/testdata/format/sinceKotlin.kt b/core/testdata/format/sinceKotlin.kt
new file mode 100644
index 00000000..1025cf0d
--- /dev/null
+++ b/core/testdata/format/sinceKotlin.kt
@@ -0,0 +1,5 @@
+/**
+ * Useful
+ */
+@SinceKotlin("1.1")
+class `Since1.1` \ No newline at end of file
diff --git a/core/testdata/format/sinceKotlin.md b/core/testdata/format/sinceKotlin.md
new file mode 100644
index 00000000..a1abe5fd
--- /dev/null
+++ b/core/testdata/format/sinceKotlin.md
@@ -0,0 +1,14 @@
+[test](test/index) / [Since1.1](test/-since1.1/index)
+
+# Since1.1
+
+`class Since1.1`
+
+**Platform and version requirements:** Kotlin 1.1
+
+Useful
+
+### Constructors
+
+| [&lt;init&gt;](test/-since1.1/-init-) | `Since1.1()`<br>Useful |
+
diff --git a/core/testdata/format/sinceKotlin.package.md b/core/testdata/format/sinceKotlin.package.md
new file mode 100644
index 00000000..2af0c9ee
--- /dev/null
+++ b/core/testdata/format/sinceKotlin.package.md
@@ -0,0 +1,8 @@
+[test](test/index)
+
+## Package &lt;root&gt;
+
+### Types
+
+| [Since1.1](test/-since1.1/index)<br>(Kotlin 1.1) | `class Since1.1`<br>Useful |
+
diff --git a/core/testdata/format/website-samples/dropImport.md b/core/testdata/format/website-samples/dropImport.md
index 13c8fb79..1e05678b 100644
--- a/core/testdata/format/website-samples/dropImport.md
+++ b/core/testdata/format/website-samples/dropImport.md
@@ -12,6 +12,7 @@ layout: api
``` kotlin
import some.*
+
fun main(args: Array<String>) {
//sampleStart
diff --git a/core/testdata/format/website-samples/newLinesInSamples.kt b/core/testdata/format/website-samples/newLinesInSamples.kt
new file mode 100644
index 00000000..ee49aefc
--- /dev/null
+++ b/core/testdata/format/website-samples/newLinesInSamples.kt
@@ -0,0 +1,19 @@
+fun groupBySample() {
+ val words = listOf("a", "abc", "ab", "def", "abcd")
+ val byLength = words.groupBy { it.length }
+
+ assertPrints(byLength.keys, "[1, 3, 2, 4]")
+ assertPrints(byLength.values, "[[a], [abc, def], [ab], [abcd]]")
+
+ val mutableByLength: MutableMap<Int, MutableList<String>> = words.groupByTo(mutableMapOf()) { it.length }
+ // same content as in byLength map, but the map is mutable
+ assertTrue(mutableByLength == byLength)
+}
+
+
+/**
+ * @sample groupBySample
+ */
+fun foo() {
+
+} \ No newline at end of file
diff --git a/core/testdata/format/website-samples/newLinesInSamples.md b/core/testdata/format/website-samples/newLinesInSamples.md
new file mode 100644
index 00000000..5344b983
--- /dev/null
+++ b/core/testdata/format/website-samples/newLinesInSamples.md
@@ -0,0 +1,31 @@
+---
+title: foo - test
+layout: api
+---
+
+<div class='api-docs-breadcrumbs'><a href="test/index">test</a> / <a href="test/foo">foo</a></div>
+
+# foo
+
+<div class="signature"><code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code></div>
+<div class="sample" markdown="1">
+
+``` kotlin
+
+
+fun main(args: Array<String>) {
+//sampleStart
+val words = listOf("a", "abc", "ab", "def", "abcd")
+val byLength = words.groupBy { it.length }
+
+println(byLength.keys) // [1, 3, 2, 4]
+println(byLength.values) // [[a], [abc, def], [ab], [abcd]]
+
+val mutableByLength: MutableMap<Int, MutableList<String>> = words.groupByTo(mutableMapOf()) { it.length }
+// same content as in byLength map, but the map is mutable
+println("mutableByLength == byLength is ${mutableByLength == byLength}") // true
+//sampleEnd
+}
+```
+
+</div>
diff --git a/core/testdata/format/website-samples/sample.md b/core/testdata/format/website-samples/sample.md
index 203f1b02..b29075a7 100644
--- a/core/testdata/format/website-samples/sample.md
+++ b/core/testdata/format/website-samples/sample.md
@@ -18,6 +18,7 @@ applied to each element and returns a map where each group key is associated wit
``` kotlin
+
fun main(args: Array<String>) {
//sampleStart
if (true) {
diff --git a/core/testdata/format/website-samples/sampleWithAsserts.md b/core/testdata/format/website-samples/sampleWithAsserts.md
index 98d7df33..c114468a 100644
--- a/core/testdata/format/website-samples/sampleWithAsserts.md
+++ b/core/testdata/format/website-samples/sampleWithAsserts.md
@@ -12,6 +12,7 @@ layout: api
``` kotlin
+
fun main(args: Array<String>) {
//sampleStart
println(a()) // Hello, Work
diff --git a/core/testdata/functions/sinceKotlin.kt b/core/testdata/functions/sinceKotlin.kt
new file mode 100644
index 00000000..cdcd3357
--- /dev/null
+++ b/core/testdata/functions/sinceKotlin.kt
@@ -0,0 +1,5 @@
+/**
+ * Quite useful [String]
+ */
+@SinceKotlin("1.1")
+fun `availableSince1.1`(): String = "1.1 rulezz" \ No newline at end of file
diff --git a/core/testdata/properties/sinceKotlin.kt b/core/testdata/properties/sinceKotlin.kt
new file mode 100644
index 00000000..e96f2349
--- /dev/null
+++ b/core/testdata/properties/sinceKotlin.kt
@@ -0,0 +1,5 @@
+/**
+ * Quite useful [String]
+ */
+@SinceKotlin("1.1")
+val `availableSince1.1`: String = "1.1 rulezz" \ No newline at end of file
diff --git a/core/testdata/typealias/sinceKotlin.kt b/core/testdata/typealias/sinceKotlin.kt
new file mode 100644
index 00000000..5b76f63a
--- /dev/null
+++ b/core/testdata/typealias/sinceKotlin.kt
@@ -0,0 +1,5 @@
+/**
+ * Documentation
+ */
+@SinceKotlin("1.1")
+typealias `Since 1.1` = String \ No newline at end of file
diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt
index 50e8fb8d..845f86a6 100644
--- a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt
+++ b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt
@@ -13,6 +13,7 @@ interface DokkaBootstrap {
outputDir: String,
format: String,
includeNonPublic: Boolean,
+ includeRootPackage: Boolean,
reportUndocumented: Boolean,
skipEmptyPackages: Boolean,
skipDeprecated: Boolean,
diff --git a/runners/ant/src/main/kotlin/ant/dokka.kt b/runners/ant/src/main/kotlin/ant/dokka.kt
index 38dc543b..e9cb35a2 100644
--- a/runners/ant/src/main/kotlin/ant/dokka.kt
+++ b/runners/ant/src/main/kotlin/ant/dokka.kt
@@ -5,10 +5,7 @@ import org.apache.tools.ant.Project
import org.apache.tools.ant.Task
import org.apache.tools.ant.types.Path
import org.apache.tools.ant.types.Reference
-import org.jetbrains.dokka.DocumentationOptions
-import org.jetbrains.dokka.DokkaGenerator
-import org.jetbrains.dokka.DokkaLogger
-import org.jetbrains.dokka.SourceLinkDefinition
+import org.jetbrains.dokka.*
import java.io.File
class AntLogger(val task: Task): DokkaLogger {
@@ -19,10 +16,17 @@ class AntLogger(val task: Task): DokkaLogger {
class AntSourceLinkDefinition(var path: String? = null, var url: String? = null, var lineSuffix: String? = null)
-class DokkaAntTask(): Task() {
+class AntSourceRoot(var path: String? = null, var platforms: String? = null)
+
+fun AntSourceRoot.toSourceRoot(): SourceRoot? = path?.let {
+ path -> SourceRoot(path, platforms?.split(',').orEmpty())
+}
+
+class DokkaAntTask: Task() {
var moduleName: String? = null
var outputDir: String? = null
var outputFormat: String = "html"
+ var impliedPlatforms: String = ""
var jdkVersion: Int = 6
var skipDeprecated: Boolean = false
@@ -33,6 +37,7 @@ class DokkaAntTask(): Task() {
val includesPath: Path by lazy { Path(getProject()) }
val antSourceLinks: MutableList<AntSourceLinkDefinition> = arrayListOf()
+ val antSourceRoots: MutableList<AntSourceRoot> = arrayListOf()
fun setClasspath(classpath: Path) {
compileClasspath.append(classpath)
@@ -68,8 +73,10 @@ class DokkaAntTask(): Task() {
return def
}
+ fun createSourceRoot(): AntSourceRoot = AntSourceRoot().apply { antSourceRoots.add(this) }
+
override fun execute() {
- if (sourcePath.list().size == 0) {
+ if (sourcePath.list().isEmpty() && antSourceRoots.isEmpty()) {
throw BuildException("At least one source path needs to be specified")
}
if (moduleName == null) {
@@ -87,14 +94,15 @@ class DokkaAntTask(): Task() {
val generator = DokkaGenerator(
AntLogger(this),
compileClasspath.list().toList(),
- sourcePath.list().toList(),
+ sourcePath.list().map { SourceRoot(it) } + antSourceRoots.mapNotNull { it.toSourceRoot() },
samplesPath.list().toList(),
includesPath.list().toList(),
moduleName!!,
DocumentationOptions(outputDir!!, outputFormat,
skipDeprecated = skipDeprecated,
sourceLinks = sourceLinks,
- jdkVersion = jdkVersion)
+ jdkVersion = jdkVersion,
+ impliedPlatforms = impliedPlatforms.split(','))
)
generator.generate()
}
diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt
index afc67e45..58bca522 100644
--- a/runners/cli/src/main/kotlin/cli/main.kt
+++ b/runners/cli/src/main/kotlin/cli/main.kt
@@ -44,6 +44,9 @@ class DokkaArguments {
@set:Argument(value = "jdkVersion", description = "Version of JDK to use for linking to JDK JavaDoc")
var jdkVersion: Int = 6
+
+ @set:Argument(value = "impliedPlatforms", description = "List of implied platforms (comma-separated)")
+ var impliedPlatforms: String = ""
}
@@ -72,13 +75,14 @@ object MainKt {
arguments.outputDir.let { if (it.endsWith('/')) it else it + '/' },
arguments.outputFormat,
skipDeprecated = arguments.nodeprecated,
- sourceLinks = sourceLinks
+ sourceLinks = sourceLinks,
+ impliedPlatforms = arguments.impliedPlatforms.split(',')
)
val generator = DokkaGenerator(
DokkaConsoleLogger,
classPath,
- sources,
+ sources.map(::parseSourceRoot),
samples,
includes,
arguments.moduleName,
diff --git a/runners/gradle-plugin/src/main/kotlin/main.kt b/runners/gradle-plugin/src/main/kotlin/main.kt
index 7ed83473..3a78080c 100644
--- a/runners/gradle-plugin/src/main/kotlin/main.kt
+++ b/runners/gradle-plugin/src/main/kotlin/main.kt
@@ -159,6 +159,7 @@ open class DokkaTask : DefaultTask() {
outputDirectory,
outputFormat,
false,
+ false,
reportNotDocumented,
skipEmptyPackages,
skipDeprecated,
diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt
index 899d2dde..c3cf7509 100644
--- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt
+++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt
@@ -7,11 +7,12 @@ import org.apache.maven.plugin.AbstractMojo
import org.apache.maven.plugins.annotations.*
import org.apache.maven.project.MavenProject
import org.apache.maven.project.MavenProjectHelper
-import org.jetbrains.dokka.DokkaGenerator
-import org.jetbrains.dokka.SourceLinkDefinition
-import org.jetbrains.dokka.DocumentationOptions
import org.codehaus.plexus.archiver.Archiver
import org.codehaus.plexus.archiver.jar.JarArchiver
+import org.jetbrains.dokka.DocumentationOptions
+import org.jetbrains.dokka.DokkaGenerator
+import org.jetbrains.dokka.SourceLinkDefinition
+import org.jetbrains.dokka.SourceRoot
import java.io.File
class SourceLinkMapItem {
@@ -66,7 +67,7 @@ abstract class AbstractDokkaMojo : AbstractMojo() {
val gen = DokkaGenerator(
MavenDokkaLogger(log),
classpath,
- sourceDirectories,
+ sourceDirectories.map { SourceRoot(it) },
samplesDirs,
includeDirs + includes,
moduleName,