diff options
Diffstat (limited to 'runners')
20 files changed, 1600 insertions, 549 deletions
diff --git a/runners/cli/api/cli.api b/runners/cli/api/cli.api index cdd051cc..74769272 100644 --- a/runners/cli/api/cli.api +++ b/runners/cli/api/cli.api @@ -62,7 +62,8 @@ public final class org/jetbrains/dokka/ArgTypeVisibility : kotlinx/cli/ArgType { public final class org/jetbrains/dokka/GlobalArguments : org/jetbrains/dokka/DokkaConfiguration { public fun <init> ([Ljava/lang/String;)V - public fun getCacheRoot ()Ljava/io/File; + public synthetic fun getCacheRoot ()Ljava/io/File; + public fun getCacheRoot ()Ljava/lang/Void; public fun getDelayTemplateSubstitution ()Z public fun getFailOnWarning ()Z public fun getFinalizeCoroutines ()Z @@ -88,10 +89,13 @@ public final class org/jetbrains/dokka/GlobalArguments : org/jetbrains/dokka/Dok public fun getSuppressObviousFunctions ()Z } -public final class org/jetbrains/dokka/MainKt { +public final class org/jetbrains/dokka/LinkMapperKt { public static final fun defaultLinks (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Ljava/util/List; + public static final fun parseLinks (Ljava/util/List;)Ljava/util/List; +} + +public final class org/jetbrains/dokka/MainKt { public static final fun initializeConfiguration (Lorg/jetbrains/dokka/GlobalArguments;)Lorg/jetbrains/dokka/DokkaConfiguration; public static final fun main ([Ljava/lang/String;)V - public static final fun parseLinks (Ljava/util/List;)Ljava/util/List; } diff --git a/runners/cli/src/main/kotlin/org/jetbrains/dokka/CliArgumentTypes.kt b/runners/cli/src/main/kotlin/org/jetbrains/dokka/CliArgumentTypes.kt new file mode 100644 index 00000000..f52f72fd --- /dev/null +++ b/runners/cli/src/main/kotlin/org/jetbrains/dokka/CliArgumentTypes.kt @@ -0,0 +1,91 @@ +package org.jetbrains.dokka + +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.CLIEntity +import org.jetbrains.dokka.utilities.LoggingLevel +import java.io.File +import java.nio.file.Paths + + +object ArgTypeFile : ArgType<File>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): File = Paths.get(value).toRealPath().toFile() + override val description: kotlin.String + get() = "{ String that represents a directory / file path }" +} + +object ArgTypePlatform : ArgType<Platform>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): Platform = Platform.fromString(value) + override val description: kotlin.String + get() = "{ String that represents a Kotlin platform. Possible values: jvm/js/native/common/android }" +} + +object ArgTypeVisibility : ArgType<DokkaConfiguration.Visibility>(true) { + override fun convert(value: kotlin.String, name: kotlin.String) = DokkaConfiguration.Visibility.fromString(value) + override val description: kotlin.String + get() = "{ String that represents a visibility modifier. Possible values: ${getPossibleVisibilityValues()}" + + private fun getPossibleVisibilityValues(): kotlin.String = + DokkaConfiguration.Visibility.values().joinToString(separator = ", ") +} + +object ArgTypePlugin : ArgType<DokkaConfiguration.PluginConfiguration>(true) { + override fun convert( + value: kotlin.String, + name: kotlin.String + ): DokkaConfiguration.PluginConfiguration { + return value.split("=").let { + PluginConfigurationImpl( + fqPluginName = it[0], + serializationFormat = DokkaConfiguration.SerializationFormat.JSON, + values = it[1] + ) + } + } + + override val description: kotlin.String + get() = "{ String that represents plugin configuration. " + + "Format is {fullyQualifiedPluginName}={jsonConfiguration}. " + + "Quotation marks (`\"`) inside json must be escaped. }" +} + +object ArgTypeSourceLinkDefinition : ArgType<DokkaConfiguration.SourceLinkDefinition>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): DokkaConfiguration.SourceLinkDefinition { + return if (value.isNotEmpty() && value.contains("=")) + SourceLinkDefinitionImpl.parseSourceLinkDefinition(value) + else { + throw IllegalArgumentException( + "Warning: Invalid -srcLink syntax. " + + "Expected: <path>=<url>[#lineSuffix]. No source links will be generated." + ) + } + } + + override val description: kotlin.String + get() = "{ String that represent source links. Format: {srcPath}={remotePath#lineSuffix} }" +} + +data class ArgTypeArgument(val moduleName: CLIEntity<kotlin.String>) : + ArgType<DokkaConfiguration.DokkaSourceSet>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): DokkaConfiguration.DokkaSourceSet = + (if (moduleName.valueOrigin != ArgParser.ValueOrigin.UNSET && moduleName.valueOrigin != ArgParser.ValueOrigin.UNDEFINED) { + moduleName.value + } else { + DokkaDefaults.moduleName + }).let { moduleNameOrDefault -> + parseSourceSet(moduleNameOrDefault, value.split(" ").filter { it.isNotBlank() }.toTypedArray()) + } + + override val description: kotlin.String + get() = "" +} + +// Workaround for printing nested parsers help +data class ArgTypeHelpSourceSet(val moduleName: CLIEntity<kotlin.String>) : ArgType<Any>(false) { + override fun convert(value: kotlin.String, name: kotlin.String): Any = Any().also { + parseSourceSet(moduleName.value, arrayOf("-h")) + } + + override val description: kotlin.String + get() = "" +} diff --git a/runners/cli/src/main/kotlin/org/jetbrains/dokka/GlobalArguments.kt b/runners/cli/src/main/kotlin/org/jetbrains/dokka/GlobalArguments.kt new file mode 100644 index 00000000..2bda8d79 --- /dev/null +++ b/runners/cli/src/main/kotlin/org/jetbrains/dokka/GlobalArguments.kt @@ -0,0 +1,164 @@ +package org.jetbrains.dokka + +import kotlinx.cli.* +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.dokka.utilities.LoggingLevel +import org.jetbrains.dokka.utilities.cast +import java.io.File + +class GlobalArguments(args: Array<String>) : DokkaConfiguration { + + val parser = ArgParser("dokka-cli", prefixStyle = ArgParser.OptionPrefixStyle.JVM) + + val json: String? by parser.argument(ArgType.String, description = "JSON configuration file path").optional() + + private val _moduleName = parser.option( + ArgType.String, + description = "Name of the project/module", + fullName = "moduleName" + ).default(DokkaDefaults.moduleName) + + override val moduleName: String by _moduleName + + override val moduleVersion by parser.option( + ArgType.String, + description = "Documented version", + fullName = "moduleVersion" + ) + + override val outputDir by parser.option(ArgTypeFile, description = "Output directory path, ./dokka by default") + .default(DokkaDefaults.outputDir) + + override val cacheRoot = null + + override val sourceSets by parser.option( + ArgTypeArgument(_moduleName), + description = "Configuration for a Dokka source set. Contains nested configuration.", + fullName = "sourceSet" + ).multiple() + + override val pluginsConfiguration by parser.option( + ArgTypePlugin, + description = "Configuration for Dokka plugins. Accepts multiple values separated by `^^`." + ).delimiter("^^") + + override val pluginsClasspath by parser.option( + ArgTypeFile, + fullName = "pluginsClasspath", + description = "List of jars with Dokka plugins and their dependencies. Accepts multiple paths separated by semicolons" + ).delimiter(";") + + override val offlineMode by parser.option( + ArgType.Boolean, + description = "Whether to resolve remote files/links over network" + ).default(DokkaDefaults.offlineMode) + + override val failOnWarning by parser.option( + ArgType.Boolean, + description = "Whether to fail documentation generation if Dokka has emitted a warning or an error" + ).default(DokkaDefaults.failOnWarning) + + override val delayTemplateSubstitution by parser.option( + ArgType.Boolean, + description = "Delay substitution of some elements. Used in incremental builds of multimodule projects" + ).default(DokkaDefaults.delayTemplateSubstitution) + + val noSuppressObviousFunctions: Boolean by parser.option( + ArgType.Boolean, + description = "Whether to suppress obvious functions such as inherited from `kotlin.Any` and `java.lang.Object`" + ).default(!DokkaDefaults.suppressObviousFunctions) + + override val suppressObviousFunctions: Boolean by lazy { !noSuppressObviousFunctions } + + private val _includes by parser.option( + ArgTypeFile, + fullName = "includes", + description = "Markdown files that contain module and package documentation. " + + "Accepts multiple values separated by semicolons" + ).delimiter(";") + + override val includes: Set<File> by lazy { _includes.toSet() } + + override val suppressInheritedMembers: Boolean by parser.option( + ArgType.Boolean, + description = "Whether to suppress inherited members that aren't explicitly overridden in a given class" + ).default(DokkaDefaults.suppressInheritedMembers) + + override val finalizeCoroutines: Boolean = true + + val globalPackageOptions by parser.option( + ArgType.String, + description = "Global list of package configurations in format " + + "\"matchingRegexp,-deprecated,-privateApi,+warnUndocumented,+suppress;...\". " + + "Accepts multiple values separated by semicolons. " + ).delimiter(";") + + val globalLinks by parser.option( + ArgType.String, + description = "Global external documentation links in format {url}^{packageListUrl}. " + + "Accepts multiple values separated by `^^`" + ).delimiter("^^") + + val globalSrcLink by parser.option( + ArgType.String, + description = "Global mapping between a source directory and a Web service for browsing the code. " + + "Accepts multiple paths separated by semicolons" + ).delimiter(";") + + val helpSourceSet by parser.option( + ArgTypeHelpSourceSet(_moduleName), + description = "Prints help for nested -sourceSet configuration" + ) + + val loggingLevel by parser.option( + ArgType.Choice(toVariant = { + when (it.toUpperCase().trim()) { + "DEBUG", "" -> LoggingLevel.DEBUG + "PROGRESS" -> LoggingLevel.PROGRESS + "INFO" -> LoggingLevel.INFO + "WARN" -> LoggingLevel.WARN + "ERROR" -> LoggingLevel.ERROR + else -> { + println("""Failed to deserialize logging level, got $it expected one of + |"DEBUG", "PROGRESS", "INFO", "WARN", "ERROR", falling back to DEBUG""".trimMargin()) + LoggingLevel.DEBUG + } + } + }, toString = { it.toString() } + )).default(LoggingLevel.DEBUG) + + override val modules: List<DokkaConfiguration.DokkaModuleDescription> = emptyList() + + val logger: DokkaLogger by lazy { + DokkaConsoleLogger(loggingLevel) + } + + init { + parser.parse(args) + + sourceSets.forEach { + it.perPackageOptions.cast<MutableList<DokkaConfiguration.PackageOptions>>() + .addAll(parsePerPackageOptions(globalPackageOptions)) + } + + sourceSets.forEach { + it.externalDocumentationLinks.cast<MutableSet<DokkaConfiguration.ExternalDocumentationLink>>().addAll(parseLinks(globalLinks)) + } + + globalSrcLink.forEach { + if (it.isNotEmpty() && it.contains("=")) + sourceSets.all { sourceSet -> + sourceSet.sourceLinks.cast<MutableSet<SourceLinkDefinitionImpl>>() + .add(SourceLinkDefinitionImpl.parseSourceLinkDefinition(it)) + } + else { + logger.warn("Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") + } + } + + sourceSets.forEach { + it.externalDocumentationLinks.cast<MutableSet<DokkaConfiguration.ExternalDocumentationLink>>().addAll(defaultLinks(it)) + } + } +} diff --git a/runners/cli/src/main/kotlin/org/jetbrains/dokka/LinkMapper.kt b/runners/cli/src/main/kotlin/org/jetbrains/dokka/LinkMapper.kt new file mode 100644 index 00000000..191d5067 --- /dev/null +++ b/runners/cli/src/main/kotlin/org/jetbrains/dokka/LinkMapper.kt @@ -0,0 +1,37 @@ +package org.jetbrains.dokka + +import java.io.File +import java.net.MalformedURLException +import java.net.URL + +@OptIn(ExperimentalStdlibApi::class) // for buildList +fun defaultLinks(config: DokkaConfiguration.DokkaSourceSet): MutableList<DokkaConfiguration.ExternalDocumentationLink> = + buildList<DokkaConfiguration.ExternalDocumentationLink> { + if (!config.noJdkLink) { + add(DokkaConfiguration.ExternalDocumentationLink.jdk(config.jdkVersion)) + } + + if (!config.noStdlibLink) { + add(DokkaConfiguration.ExternalDocumentationLink.kotlinStdlib()) + } + }.toMutableList() + + +fun parseLinks(links: List<String>): List<DokkaConfiguration.ExternalDocumentationLink> { + val (parsedLinks, parsedOfflineLinks) = links + .map { it.split("^").map { it.trim() }.filter { it.isNotBlank() } } + .filter { it.isNotEmpty() } + .partition { it.size == 1 } + + return parsedLinks.map { (root) -> ExternalDocumentationLink(root) } + + parsedOfflineLinks.map { (root, packageList) -> + val rootUrl = URL(root) + val packageListUrl = + try { + URL(packageList) + } catch (ex: MalformedURLException) { + File(packageList).toURI().toURL() + } + ExternalDocumentationLink(rootUrl, packageListUrl) + } +} diff --git a/runners/cli/src/main/kotlin/org/jetbrains/dokka/PackageOptionsParser.kt b/runners/cli/src/main/kotlin/org/jetbrains/dokka/PackageOptionsParser.kt new file mode 100644 index 00000000..1b9a3c56 --- /dev/null +++ b/runners/cli/src/main/kotlin/org/jetbrains/dokka/PackageOptionsParser.kt @@ -0,0 +1,34 @@ +package org.jetbrains.dokka + +internal fun parsePerPackageOptions(args: List<String>): List<DokkaConfiguration.PackageOptions> = args.map { it.split(",") }.map { + val matchingRegex = it.first() + + val options = it.subList(1, it.size) + + val deprecated = options.find { it.endsWith("skipDeprecated") }?.startsWith("+") + ?: DokkaDefaults.skipDeprecated + + val reportUndocumented = options.find { it.endsWith("reportUndocumented") }?.startsWith("+") + ?: DokkaDefaults.reportUndocumented + + val privateApi = options.find { it.endsWith("includeNonPublic") }?.startsWith("+") + ?: DokkaDefaults.includeNonPublic + + val suppress = options.find { it.endsWith("suppress") }?.startsWith("+") + ?: DokkaDefaults.suppress + + val documentedVisibilities = options + .filter { it.matches(Regex("\\+visibility:.+")) } // matches '+visibility:' with at least one symbol after the semicolon + .map { DokkaConfiguration.Visibility.fromString(it.split(":")[1]) } + .toSet() + .ifEmpty { DokkaDefaults.documentedVisibilities } + + PackageOptionsImpl( + matchingRegex, + includeNonPublic = privateApi, + documentedVisibilities = documentedVisibilities, + reportUndocumented = reportUndocumented, + skipDeprecated = !deprecated, + suppress = suppress + ) +} diff --git a/runners/cli/src/main/kotlin/org/jetbrains/dokka/SourceSetArgumentsParser.kt b/runners/cli/src/main/kotlin/org/jetbrains/dokka/SourceSetArgumentsParser.kt new file mode 100644 index 00000000..49e8f2ae --- /dev/null +++ b/runners/cli/src/main/kotlin/org/jetbrains/dokka/SourceSetArgumentsParser.kt @@ -0,0 +1,155 @@ +package org.jetbrains.dokka + +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.default +import kotlinx.cli.delimiter + +internal fun parseSourceSet(moduleName: String, args: Array<String>): DokkaConfiguration.DokkaSourceSet { + + val parser = ArgParser("sourceSet", prefixStyle = ArgParser.OptionPrefixStyle.JVM) + + val sourceSetName by parser.option( + ArgType.String, + description = "Name of the source set" + ).default("main") + + val displayName by parser.option( + ArgType.String, + description = "Display name of the source set, used both internally and externally" + ).default(DokkaDefaults.sourceSetDisplayName) + + val classpath by parser.option( + ArgTypeFile, + description = "Classpath for analysis and interactive samples. Accepts multiple paths separated by semicolons" + ).delimiter(";") + + val sourceRoots by parser.option( + ArgTypeFile, + description = "Source code roots to be analyzed and documented. Accepts multiple paths separated by semicolons", + fullName = "src" + ).delimiter(";") + + val dependentSourceSets by parser.option( + ArgType.String, + description = "Names of dependent source sets in format \"moduleName/sourceSetName\". " + + "Accepts multiple paths separated by semicolons" + ).delimiter(";") + + val samples by parser.option( + ArgTypeFile, + description = "List of directories or files that contain sample functions. " + + "Accepts multiple paths separated by semicolons" + ).delimiter(";") + + val includes by parser.option( + ArgTypeFile, + description = "Markdown files that contain module and package documentation. " + + "Accepts multiple paths separated by semicolons" + ).delimiter(";") + + val includeNonPublic: Boolean by parser.option( + ArgType.Boolean, + description = "Deprecated, use documentedVisibilities") + .default(DokkaDefaults.includeNonPublic) + + val documentedVisibilities by parser.option( + ArgTypeVisibility, + description = "Visibilities to be documented. Accepts multiple values separated by semicolons" + ).delimiter(";") + + val reportUndocumented by parser.option(ArgType.Boolean, description = "Whether to report undocumented declarations") + .default(DokkaDefaults.reportUndocumented) + + val noSkipEmptyPackages by parser.option( + ArgType.Boolean, + description = "Whether to create pages for empty packages" + ).default(!DokkaDefaults.skipEmptyPackages) + + val skipEmptyPackages by lazy { !noSkipEmptyPackages } + + val skipDeprecated by parser.option(ArgType.Boolean, description = "Whether to skip deprecated declarations") + .default(DokkaDefaults.skipDeprecated) + + val jdkVersion by parser.option( + ArgType.Int, + description = "Version of JDK to use for linking to JDK Javadocs" + ).default(DokkaDefaults.jdkVersion) + + val languageVersion by parser.option( + ArgType.String, + description = "Language version used for setting up analysis and samples" + ) + + val apiVersion by parser.option( + ArgType.String, + description = "Kotlin API version used for setting up analysis and samples" + ) + + val noStdlibLink by parser.option(ArgType.Boolean, description = "Whether to generate links to Standard library") + .default(DokkaDefaults.noStdlibLink) + + val noJdkLink by parser.option(ArgType.Boolean, description = "Whether to generate links to JDK Javadocs") + .default(DokkaDefaults.noJdkLink) + + val suppressedFiles by parser.option( + ArgTypeFile, + description = "Paths to files to be suppressed. Accepts multiple paths separated by semicolons." + ).delimiter(";") + + val analysisPlatform: Platform by parser.option( + ArgTypePlatform, + description = "Platform used for setting up analysis" + ).default(DokkaDefaults.analysisPlatform) + + val perPackageOptions by parser.option( + ArgType.String, + description = "List of package source set configuration in format " + + "\"matchingRegexp,-deprecated,-privateApi,+warnUndocumented,+suppress;...\". " + + "Accepts multiple values separated by semicolons. " + ).delimiter(";") + + val externalDocumentationLinks by parser.option( + ArgType.String, + description = "External documentation links in format {url}^{packageListUrl}. " + + "Accepts multiple values separated by `^^`" + ).delimiter("^^") + + val sourceLinks by parser.option( + ArgTypeSourceLinkDefinition, + description = "Mapping between a source directory and a Web service for browsing the code. " + + "Accepts multiple paths separated by semicolons", + fullName = "srcLink" + ).delimiter(";") + + parser.parse(args) + + return object : DokkaConfiguration.DokkaSourceSet { + override val displayName = displayName + override val sourceSetID = DokkaSourceSetID(moduleName, sourceSetName) + override val classpath = classpath.toMutableList() + override val sourceRoots = sourceRoots.toMutableSet() + override val dependentSourceSets = dependentSourceSets + .map { dependentSourceSetName -> dependentSourceSetName.split('/').let { DokkaSourceSetID(it[0], it[1]) } } + .toMutableSet() + override val samples = samples.toMutableSet() + override val includes = includes.toMutableSet() + @Deprecated("Use [documentedVisibilities] property for a more flexible control over documented visibilities") + override val includeNonPublic = includeNonPublic + override val reportUndocumented = reportUndocumented + override val skipEmptyPackages = skipEmptyPackages + override val skipDeprecated = skipDeprecated + override val jdkVersion = jdkVersion + override val sourceLinks = sourceLinks.toMutableSet() + override val analysisPlatform = analysisPlatform + override val perPackageOptions = parsePerPackageOptions(perPackageOptions).toMutableList() + override val externalDocumentationLinks = parseLinks(externalDocumentationLinks).toMutableSet() + override val languageVersion = languageVersion + override val apiVersion = apiVersion + override val noStdlibLink = noStdlibLink + override val noJdkLink = noJdkLink + override val suppressedFiles = suppressedFiles.toMutableSet() + override val documentedVisibilities: Set<DokkaConfiguration.Visibility> = documentedVisibilities.toSet() + .ifEmpty { DokkaDefaults.documentedVisibilities } + } +} diff --git a/runners/cli/src/main/kotlin/org/jetbrains/dokka/main.kt b/runners/cli/src/main/kotlin/org/jetbrains/dokka/main.kt index 7fe782a9..99813f62 100644 --- a/runners/cli/src/main/kotlin/org/jetbrains/dokka/main.kt +++ b/runners/cli/src/main/kotlin/org/jetbrains/dokka/main.kt @@ -1,429 +1,28 @@ package org.jetbrains.dokka -import kotlinx.cli.* import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink import org.jetbrains.dokka.utilities.* -import java.io.* -import java.net.MalformedURLException -import java.net.URL import java.nio.file.Paths -class GlobalArguments(args: Array<String>) : DokkaConfiguration { - - val parser = ArgParser("globalArguments", prefixStyle = ArgParser.OptionPrefixStyle.JVM) - - val json: String? by parser.argument(ArgType.String, description = "Json file name").optional() - - private val _moduleName = parser.option( - ArgType.String, - description = "Name of the documentation module", - fullName = "moduleName" - ).default(DokkaDefaults.moduleName) - - override val moduleName: String by _moduleName - - override val moduleVersion by parser.option( - ArgType.String, - description = "Documentation version", - fullName = "moduleVersion" - ) - - override val outputDir by parser.option(ArgTypeFile, description = "Output directory path") - .default(DokkaDefaults.outputDir) - - override val cacheRoot by parser.option( - ArgTypeFile, - description = "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled" - ) - - override val sourceSets by parser.option( - ArgTypeArgument(_moduleName), - description = "Single dokka source set", - fullName = "sourceSet" - ).multiple() - - override val pluginsConfiguration by parser.option( - ArgTypePlugin, - description = "Configuration for plugins in format fqPluginName=json^^fqPluginName=json..." - ).delimiter("^^") - - override val pluginsClasspath by parser.option( - ArgTypeFile, - fullName = "pluginsClasspath", - description = "List of jars with dokka plugins (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - override val offlineMode by parser.option( - ArgType.Boolean, - description = "Offline mode (do not download package lists from the Internet)" - ).default(DokkaDefaults.offlineMode) - - override val failOnWarning by parser.option( - ArgType.Boolean, - description = "Throw an exception if the generation exited with warnings" - ).default(DokkaDefaults.failOnWarning) - - override val delayTemplateSubstitution by parser.option( - ArgType.Boolean, - description = "Delay substitution of some elements (usefull for incremental builds of multimodule projects)" - ).default(DokkaDefaults.delayTemplateSubstitution) - - val noSuppressObviousFunctions: Boolean by parser.option( - ArgType.Boolean, - description = "Document generated or obvious functions like default `toString` or `equals`" - ).default(!DokkaDefaults.suppressObviousFunctions) - - override val suppressObviousFunctions: Boolean by lazy { !noSuppressObviousFunctions } - - private val _includes by parser.option( - ArgTypeFile, - fullName = "includes", - description = "Markdown files that would be displayed in multi-module page separated by the semicolon `;`)" - ).delimiter(";") - - override val includes: Set<File> by lazy { _includes.toSet() } - - override val suppressInheritedMembers: Boolean by parser.option( - ArgType.Boolean, - description = "Suppress members inherited from other classes" - ).default(DokkaDefaults.suppressInheritedMembers) - - override val finalizeCoroutines: Boolean = true - - val globalPackageOptions by parser.option( - ArgType.String, - description = "List of package source sets in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" " - ).delimiter(";") - - val globalLinks by parser.option( - ArgType.String, - description = "External documentation links in format url^packageListUrl^^url2..." - ).delimiter("^^") - - val globalSrcLink by parser.option( - ArgType.String, - description = "Mapping between a source directory and a Web site for browsing the code (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - val helpSourceSet by parser.option( - ArgTypeHelpSourceSet(_moduleName), - description = "Prints help for single -sourceSet" - ) - - val loggingLevel by parser.option( - ArgType.Choice(toVariant = { - when (it.toUpperCase().trim()) { - "DEBUG", "" -> LoggingLevel.DEBUG - "PROGRESS" -> LoggingLevel.PROGRESS - "INFO" -> LoggingLevel.INFO - "WARN" -> LoggingLevel.WARN - "ERROR" -> LoggingLevel.ERROR - else -> { - println("""Failed to deserialize logging level, got $it expected one of "DEBUG", "PROGRESS", "INFO", "WARN", "ERROR", falling back to DEBUG""") - LoggingLevel.DEBUG - } - } - }, toString = { it.toString() } - )).default(LoggingLevel.DEBUG) - - override val modules: List<DokkaConfiguration.DokkaModuleDescription> = emptyList() - - val logger: DokkaLogger by lazy { - DokkaConsoleLogger(loggingLevel) - } - - init { - parser.parse(args) - - sourceSets.forEach { - it.perPackageOptions.cast<MutableList<DokkaConfiguration.PackageOptions>>() - .addAll(parsePerPackageOptions(globalPackageOptions)) - } - - sourceSets.forEach { - it.externalDocumentationLinks.cast<MutableSet<ExternalDocumentationLink>>().addAll(parseLinks(globalLinks)) - } - - globalSrcLink.forEach { - if (it.isNotEmpty() && it.contains("=")) - sourceSets.all { sourceSet -> - sourceSet.sourceLinks.cast<MutableSet<SourceLinkDefinitionImpl>>() - .add(SourceLinkDefinitionImpl.parseSourceLinkDefinition(it)) - } - else { - logger.warn("Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") - } - } - - sourceSets.forEach { - it.externalDocumentationLinks.cast<MutableSet<ExternalDocumentationLink>>().addAll(defaultLinks(it)) - } - } -} - -private fun parseSourceSet(moduleName: String, args: Array<String>): DokkaConfiguration.DokkaSourceSet { - - val parser = ArgParser("sourceSet", prefixStyle = ArgParser.OptionPrefixStyle.JVM) - - val sourceSetName by parser.option( - ArgType.String, - description = "Name of the source set" - ).default("main") - - val displayName by parser.option( - ArgType.String, - description = "Displayed name of the source set" - ).default(DokkaDefaults.sourceSetDisplayName) - - val classpath by parser.option( - ArgTypeFile, - description = "Classpath for symbol resolution (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - val sourceRoots by parser.option( - ArgTypeFile, - description = "Source file or directory (allows many paths separated by the semicolon `;`)", - fullName = "src" - ).delimiter(";") - - val dependentSourceSets by parser.option( - ArgType.String, - description = "Names of dependent source sets in format \"moduleName/sourceSetName\" (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - val samples by parser.option( - ArgTypeFile, - description = "Source root for samples (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - val includes by parser.option( - ArgTypeFile, - description = "Markdown files to load (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - val includeNonPublic: Boolean by parser.option(ArgType.Boolean, description = "Include non public") - .default(DokkaDefaults.includeNonPublic) - - val documentedVisibilities by parser.option( - ArgTypeVisibility, - description = "Visibilities to be documented (allows multiple values separated by the semicolon `;`)" - ).delimiter(";") - - val reportUndocumented by parser.option(ArgType.Boolean, description = "Report undocumented members") - .default(DokkaDefaults.reportUndocumented) - - val noSkipEmptyPackages by parser.option( - ArgType.Boolean, - description = "Create index pages for empty packages" - ).default(!DokkaDefaults.skipEmptyPackages) - - val skipEmptyPackages by lazy { !noSkipEmptyPackages } - - val skipDeprecated by parser.option(ArgType.Boolean, description = "Do not output deprecated members") - .default(DokkaDefaults.skipDeprecated) - - val jdkVersion by parser.option( - ArgType.Int, - description = "Version of JDK to use for linking to JDK JavaDoc" - ).default(DokkaDefaults.jdkVersion) - - val languageVersion by parser.option( - ArgType.String, - description = "Language Version to pass to Kotlin analysis" - ) - - val apiVersion by parser.option( - ArgType.String, - description = "Kotlin Api Version to pass to Kotlin analysis" - ) - - val noStdlibLink by parser.option(ArgType.Boolean, description = "Disable documentation link to stdlib") - .default(DokkaDefaults.noStdlibLink) - - val noJdkLink by parser.option(ArgType.Boolean, description = "Disable documentation link to JDK") - .default(DokkaDefaults.noJdkLink) - - val suppressedFiles by parser.option( - ArgTypeFile, - description = "Paths to files to be suppressed (allows many paths separated by the semicolon `;`)" - ).delimiter(";") - - val analysisPlatform: Platform by parser.option( - ArgTypePlatform, - description = "Platform for analysis" - ).default(DokkaDefaults.analysisPlatform) - - val perPackageOptions by parser.option( - ArgType.String, - description = "List of package source set configuration in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" " - ).delimiter(";") - - val externalDocumentationLinks by parser.option( - ArgType.String, - description = "External documentation links in format url^packageListUrl^^url2..." - ).delimiter("^^") - - val sourceLinks by parser.option( - ArgTypeSourceLinkDefinition, - description = "Mapping between a source directory and a Web site for browsing the code (allows many paths separated by the semicolon `;`)", - fullName = "srcLink" - ).delimiter(";") - - parser.parse(args) - - return object : DokkaConfiguration.DokkaSourceSet { - override val displayName = displayName - override val sourceSetID = DokkaSourceSetID(moduleName, sourceSetName) - override val classpath = classpath.toMutableList() - override val sourceRoots = sourceRoots.toMutableSet() - override val dependentSourceSets = dependentSourceSets - .map { dependentSourceSetName -> dependentSourceSetName.split('/').let { DokkaSourceSetID(it[0], it[1]) } } - .toMutableSet() - override val samples = samples.toMutableSet() - override val includes = includes.toMutableSet() - @Deprecated("Use [documentedVisibilities] property for a more flexible control over documented visibilities") - override val includeNonPublic = includeNonPublic - override val reportUndocumented = reportUndocumented - override val skipEmptyPackages = skipEmptyPackages - override val skipDeprecated = skipDeprecated - override val jdkVersion = jdkVersion - override val sourceLinks = sourceLinks.toMutableSet() - override val analysisPlatform = analysisPlatform - override val perPackageOptions = parsePerPackageOptions(perPackageOptions).toMutableList() - override val externalDocumentationLinks = parseLinks(externalDocumentationLinks).toMutableSet() - override val languageVersion = languageVersion - override val apiVersion = apiVersion - override val noStdlibLink = noStdlibLink - override val noJdkLink = noJdkLink - override val suppressedFiles = suppressedFiles.toMutableSet() - override val documentedVisibilities: Set<DokkaConfiguration.Visibility> = documentedVisibilities.toSet() - .ifEmpty { DokkaDefaults.documentedVisibilities } - } -} - -object ArgTypeFile : ArgType<File>(true) { - override fun convert(value: kotlin.String, name: kotlin.String): File = Paths.get(value).toRealPath().toFile() - override val description: kotlin.String - get() = "{ String that points to file path }" -} - -object ArgTypePlatform : ArgType<Platform>(true) { - override fun convert(value: kotlin.String, name: kotlin.String): Platform = Platform.fromString(value) - override val description: kotlin.String - get() = "{ String that represents platform }" -} - -object ArgTypeVisibility : ArgType<DokkaConfiguration.Visibility>(true) { - override fun convert(value: kotlin.String, name: kotlin.String) = DokkaConfiguration.Visibility.fromString(value) - override val description: kotlin.String - get() = "{ String that represents a visibility modifier. " + - "Possible values: ${DokkaConfiguration.Visibility.values().joinToString(separator = ", ")} }" -} - -object ArgTypePlugin : ArgType<DokkaConfiguration.PluginConfiguration>(true) { - override fun convert( - value: kotlin.String, - name: kotlin.String - ): DokkaConfiguration.PluginConfiguration { - return value.split("=").let { - PluginConfigurationImpl( - fqPluginName = it[0], - serializationFormat = DokkaConfiguration.SerializationFormat.JSON, - values = it[1] - ) - } - } - - override val description: kotlin.String - get() = "{ String fqName=json, remember to escape `\"` inside json }" -} - -object ArgTypeSourceLinkDefinition : ArgType<DokkaConfiguration.SourceLinkDefinition>(true) { - override fun convert(value: kotlin.String, name: kotlin.String): DokkaConfiguration.SourceLinkDefinition = - if (value.isNotEmpty() && value.contains("=")) - SourceLinkDefinitionImpl.parseSourceLinkDefinition(value) - else { - throw IllegalArgumentException("Warning: Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") - } - - override val description: kotlin.String - get() = "{ String that represent source links }" -} - -data class ArgTypeArgument(val moduleName: CLIEntity<kotlin.String>) : - ArgType<DokkaConfiguration.DokkaSourceSet>(true) { - override fun convert(value: kotlin.String, name: kotlin.String): DokkaConfiguration.DokkaSourceSet = - (if (moduleName.valueOrigin != ArgParser.ValueOrigin.UNSET && moduleName.valueOrigin != ArgParser.ValueOrigin.UNDEFINED) { - moduleName.value - } else { - DokkaDefaults.moduleName - }).let { moduleNameOrDefault -> - parseSourceSet(moduleNameOrDefault, value.split(" ").filter { it.isNotBlank() }.toTypedArray()) - } - - override val description: kotlin.String - get() = "" -} - -// Workaround for printing nested parsers help -data class ArgTypeHelpSourceSet(val moduleName: CLIEntity<kotlin.String>) : ArgType<Any>(false) { - override fun convert(value: kotlin.String, name: kotlin.String): Any = Any().also { - parseSourceSet(moduleName.value, arrayOf("-h")) - } - - override val description: kotlin.String - get() = "" +fun main(args: Array<String>) { + val globalArguments = GlobalArguments(args) + val configuration = initializeConfiguration(globalArguments) + DokkaGenerator(configuration, globalArguments.logger).generate() } -@OptIn(ExperimentalStdlibApi::class) -fun defaultLinks(config: DokkaConfiguration.DokkaSourceSet): MutableList<ExternalDocumentationLink> = - buildList<ExternalDocumentationLink> { - if (!config.noJdkLink) { - add(ExternalDocumentationLink.jdk(config.jdkVersion)) - } +fun initializeConfiguration(globalArguments: GlobalArguments): DokkaConfiguration { + return if (globalArguments.json != null) { + val jsonContent = Paths.get(checkNotNull(globalArguments.json)).toFile().readText() + val globals = GlobalDokkaConfiguration(jsonContent) + val dokkaConfigurationImpl = DokkaConfigurationImpl(jsonContent) - if (!config.noStdlibLink) { - add(ExternalDocumentationLink.kotlinStdlib()) - } - }.toMutableList() - - -fun parseLinks(links: List<String>): List<ExternalDocumentationLink> { - val (parsedLinks, parsedOfflineLinks) = links - .map { it.split("^").map { it.trim() }.filter { it.isNotBlank() } } - .filter { it.isNotEmpty() } - .partition { it.size == 1 } - - return parsedLinks.map { (root) -> ExternalDocumentationLink(root) } + - parsedOfflineLinks.map { (root, packageList) -> - val rootUrl = URL(root) - val packageListUrl = - try { - URL(packageList) - } catch (ex: MalformedURLException) { - File(packageList).toURI().toURL() - } - ExternalDocumentationLink(rootUrl, packageListUrl) + dokkaConfigurationImpl.apply(globals).apply { + sourceSets.forEach { + it.externalDocumentationLinks.cast<MutableSet<ExternalDocumentationLink>>().addAll(defaultLinks(it)) } -} - -fun initializeConfiguration(globalArguments: GlobalArguments): DokkaConfiguration = if (globalArguments.json != null) { - val jsonContent = Paths.get(checkNotNull(globalArguments.json)).toFile().readText() - val globals = GlobalDokkaConfiguration(jsonContent) - val dokkaConfigurationImpl = DokkaConfigurationImpl(jsonContent) - - dokkaConfigurationImpl.apply(globals).apply { - sourceSets.forEach { - it.externalDocumentationLinks.cast<MutableSet<ExternalDocumentationLink>>().addAll(defaultLinks(it)) } + } else { + globalArguments } -} else { - globalArguments -} - -fun main(args: Array<String>) { - val globalArguments = GlobalArguments(args) - val configuration = initializeConfiguration(globalArguments) - DokkaGenerator(configuration, globalArguments.logger).generate() } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt index 2c761eef..0fb62b30 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt @@ -23,48 +23,160 @@ import kotlin.reflect.full.createInstance @DisableCachingByDefault(because = "Abstract super-class, not to be instantiated directly") abstract class AbstractDokkaTask : DefaultTask() { + /** + * Display name used to refer to the module. Used for ToC, navigation, logging, etc. + * + * If set for a single-project build or a MultiModule task, will be used as project name. + * + * Default is Gradle project name. + */ @Input val moduleName: Property<String> = project.objects.safeProperty<String>() .safeConvention(project.name) + /** + * Module version. + * + * If set for a single-project build or a MultiModule task, will be used + * as project version by the versioning plugin. + * + * Default is Gradle project version. + */ @Input val moduleVersion: Property<String> = project.objects.safeProperty<String>() .safeConvention(project.version.toString()) + /** + * Directory to which documentation will be generated, regardless of format. + * Can be set on per-task basis. + * + * Default is `project/buildDir/taskName.removePrefix("dokka").decapitalize()`, so + * for `dokkaHtmlMultiModule` task it will be `project/buildDir/htmlMultiModule` + */ @OutputDirectory val outputDirectory: Property<File> = project.objects.safeProperty<File>() .safeConvention(project.provider { defaultDokkaOutputDirectory() }) - @Optional - @InputDirectory - @PathSensitive(PathSensitivity.RELATIVE) - val cacheRoot: Property<File?> = project.objects.safeProperty() + /** + * Configuration for Dokka plugins. This property is not expected to be used directly - if possible, use + * [pluginConfiguration] blocks (preferred) or [pluginsMapConfiguration] instead. + */ + @Input + val pluginsConfiguration: ListProperty<in DokkaConfiguration.PluginConfiguration> = project.objects.listProperty() + /** + * JSON configuration of Dokka plugins. + * + * Key is fully qualified Dokka plugin name, value is its configuration in JSON. + * + * Example: + * + * ```kotlin + * tasks.dokkaHtml { + * val dokkaBaseConfiguration = """ + * { + * "customAssets": ["${file("assets/my-image.png")}"], + * "customStyleSheets": ["${file("assets/my-styles.css")}"], + * "footerMessage": "(c) 2022 MyOrg" + * } + * """ + * pluginsMapConfiguration.set( + * mapOf("org.jetbrains.dokka.base.DokkaBase" to dokkaBaseConfiguration) + * ) + * } + * ``` + */ @Input - val failOnWarning: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.failOnWarning) + val pluginsMapConfiguration: MapProperty<String, String> = project.objects.mapProperty() + /** + * Whether to suppress obvious functions. + * + * A function is considered to be obvious if it is: + * - Inherited from `kotlin.Any`, `Kotlin.Enum`, `java.lang.Object` or `java.lang.Enum`, + * such as `equals`, `hashCode`, `toString`. + * - Synthetic (generated by the compiler) and does not have any documentation, such as + * `dataClass.componentN` or `dataClass.copy`. + * + * Default is `true` + */ @Input val suppressObviousFunctions: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.suppressObviousFunctions) + /** + * Whether to suppress inherited members that aren't explicitly overridden in a given class. + * + * Note: this can suppress functions such as `equals`/`hashCode`/`toString`, but cannot suppress + * synthetic functions such as `dataClass.componentN` and `dataClass.copy`. Use [suppressObviousFunctions] + * for that. + * + * Default is `false`. + */ @Input val suppressInheritedMembers: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.suppressInheritedMembers) + /** + * Whether to resolve remote files/links over network. + * + * This includes package-lists used for generating external documentation links: + * for instance, to make classes from standard library clickable. + * + * Setting this to `true` can significantly speed up build times in certain cases, + * but can also worsen documentation quality and user experience, for instance by + * not resolving some dependency's class/member links. + * + * When using offline mode, you can cache fetched files locally and provide them to + * Dokka as local paths. For instance, see [GradleExternalDocumentationLinkBuilder]. + * + * Default is `false`. + */ @Input val offlineMode: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.offlineMode) - @Input - val pluginsConfiguration: ListProperty<in DokkaConfiguration.PluginConfiguration> = project.objects.listProperty() - /** - * Used to keep compatibility with gradle using Kotlin lower than 1.3.50 + * Whether to fail documentation generation if Dokka has emitted a warning or an error. + * Will wait until all errors and warnings have been emitted first. + * + * This setting works well with [GradleDokkaSourceSetBuilder.reportUndocumented] + * + * Default is `false`. */ @Input - val pluginsMapConfiguration: MapProperty<String, String> = project.objects.mapProperty() + val failOnWarning: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.failOnWarning) + @Optional + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) + val cacheRoot: Property<File?> = project.objects.safeProperty() + + /** + * Type-safe configuration for a Dokka plugin. + * + * Note: this is available in Kotlin DSL only, if Dokka Gradle plugin was applied through `plugins` block + * and the configured plugin can be found on classpath, which may require adding a classpath dependency + * to `buildscript` block in case of external plugins. Some Dokka plugins, such as + * [org.jetbrains.dokka.base.DokkaBase], are on classpath by default. + * + * Example: + * + * ```kotlin + * import org.jetbrains.dokka.base.DokkaBase + * import org.jetbrains.dokka.base.DokkaBaseConfiguration + * + * tasks.dokkaHtml { + * pluginConfiguration<DokkaBase, DokkaBaseConfiguration> { + * footerMessage = "Test" + * } + * } + * ``` + * + * @param P Plugin class that extends [DokkaPlugin] + * @param T Plugin configuration class that extends [ConfigurableBlock] + */ inline fun <reified P : DokkaPlugin, reified T : ConfigurableBlock> pluginConfiguration(block: T.() -> Unit) { val instance = T::class.createInstance().apply(block) val pluginConfiguration = PluginConfigurationImpl( diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt index 76213f14..c930bc50 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt @@ -16,6 +16,33 @@ private typealias TaskPath = String @CacheableTask abstract class DokkaMultiModuleTask : AbstractDokkaParentTask() { + + /** + * List of Markdown files that contain + * [module and package documentation](https://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation). + * + * Contents of specified files will be parsed and embedded into documentation as module and package descriptions. + * + * Example of such a file: + * + * ```markdown + * # Module kotlin-demo + * + * The module shows the Dokka usage. + * + * # Package org.jetbrains.kotlin.demo + * + * Contains assorted useful stuff. + * + * ## Level 2 heading + * + * Text after this heading is also part of documentation for `org.jetbrains.kotlin.demo` + * + * # Package org.jetbrains.kotlin.demo2 + * + * Useful stuff in another package. + * ``` + */ @InputFiles @Optional @PathSensitive(PathSensitivity.RELATIVE) diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaSourceSetMapper.kt index 56c3f071..56c3f071 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaSourceSetMapper.kt diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt index 717527d2..6390336a 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt @@ -13,6 +13,29 @@ import org.jetbrains.dokka.* import java.io.File import java.net.URL +/** + * [Source set](https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets) level configuration. + * + * Can be configured in the following way with Gradle Kotlin DSL: + * + * ```kotlin + * import org.jetbrains.dokka.gradle.DokkaTask + * + * tasks.dokkaHtml { + * dokkaSourceSets { + * // configure individual source set by name + * named("customSourceSet") { + * suppress.set(true) + * } + * + * // configure all source sets at once + * configureEach { + * reportUndocumented.set(true) + * } + * } + * } + * ``` + */ open class GradleDokkaSourceSetBuilder( @Transient @get:Input val name: String, @Transient @get:Internal internal val project: Project, @@ -22,177 +45,423 @@ open class GradleDokkaSourceSetBuilder( @Input val sourceSetID: DokkaSourceSetID = sourceSetIdFactory.create(name) + /** + * Whether this source set should be skipped when generating documentation. + * + * Default is `false`. + */ @Input val suppress: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(false) - @Classpath - @Optional - val classpath: ConfigurableFileCollection = project.files() - + /** + * Display name used to refer to the source set. + * + * The name will be used both externally (for example, source set name visible to documentation readers) and + * internally (for example, for logging messages of [reportUndocumented]). + * + * By default, the value is deduced from information provided by the Kotlin Gradle plugin. + */ @Input @Optional val displayName: Property<String?> = project.objects.safeProperty() + /** + * List of Markdown files that contain + * [module and package documentation](https://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation). + * + * Contents of specified files will be parsed and embedded into documentation as module and package descriptions. + * + * Example of such a file: + * + * ```markdown + * # Module kotlin-demo + * + * The module shows the Dokka usage. + * + * # Package org.jetbrains.kotlin.demo + * + * Contains assorted useful stuff. + * + * ## Level 2 heading + * + * Text after this heading is also part of documentation for `org.jetbrains.kotlin.demo` + * + * # Package org.jetbrains.kotlin.demo2 + * + * Useful stuff in another package. + * ``` + */ @InputFiles + @Optional @PathSensitive(PathSensitivity.RELATIVE) - val sourceRoots: ConfigurableFileCollection = project.objects.fileCollection() + val includes: ConfigurableFileCollection = project.files() + + /** + * Set of visibility modifiers that should be documented. + * + * This can be used if you want to document protected/internal/private declarations, + * as well as if you want to exclude public declarations and only document internal API. + * + * Can be configured on per-package basis, see [GradlePackageOptionsBuilder.documentedVisibilities]. + * + * Default is [DokkaConfiguration.Visibility.PUBLIC]. + */ + @Input + val documentedVisibilities: SetProperty<DokkaConfiguration.Visibility> = project.objects.setProperty<DokkaConfiguration.Visibility>() + .convention(DokkaDefaults.documentedVisibilities) + /** + * Specifies source sets that current source set depends on. + * + * Among other things, this information is needed to resolve + * [expect/actual](https://kotlinlang.org/docs/multiplatform-connect-to-apis.html) declarations. + * + * Prefer using [dependsOn] function to append dependent source sets to this list. + * + * By default, the values are deduced from information provided by the Kotlin Gradle plugin. + */ @Input val dependentSourceSets: SetProperty<DokkaSourceSetID> = project.objects.setProperty<DokkaSourceSetID>() .convention(emptySet()) - @InputFiles + /** + * Classpath for analysis and interactive samples. + * + * Useful if some types that come from dependencies are not resolved/picked up automatically. + * Property accepts both `.jar` and `.klib` files. + * + * By default, classpath is deduced from information provided by the Kotlin Gradle plugin. + */ + @Classpath @Optional + val classpath: ConfigurableFileCollection = project.files() + + /** + * Source code roots to be analyzed and documented. + * Accepts directories and individual `.kt` / `.java` files. + * + * Prefer using [sourceRoot] function to append source roots to this list. + * + * By default, source roots are deduced from information provided by the Kotlin Gradle plugin. + */ + @InputFiles @PathSensitive(PathSensitivity.RELATIVE) - val samples: ConfigurableFileCollection = project.files() + val sourceRoots: ConfigurableFileCollection = project.objects.fileCollection() + /** + * List of directories or files that contain sample functions which are referenced via + * [@sample](https://kotlinlang.org/docs/kotlin-doc.html#sample-identifier) KDoc tag. + */ @InputFiles @Optional @PathSensitive(PathSensitivity.RELATIVE) - val includes: ConfigurableFileCollection = project.files() - - @Input - val includeNonPublic: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.includeNonPublic) - - @Input - val documentedVisibilities: SetProperty<DokkaConfiguration.Visibility> = project.objects.setProperty<DokkaConfiguration.Visibility>() - .convention(DokkaDefaults.documentedVisibilities) + val samples: ConfigurableFileCollection = project.files() + /** + * Whether to emit warnings about visible undocumented declarations, that is declarations without KDocs + * after they have been filtered by [documentedVisibilities]. + * + * This setting works well with [AbstractDokkaTask.failOnWarning]. + * + * Can be overridden for a specific package by setting [GradlePackageOptionsBuilder.reportUndocumented]. + * + * Default is `false`. + */ @Input val reportUndocumented: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.reportUndocumented) - @Input - val skipEmptyPackages: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.skipEmptyPackages) - - @Input - val skipDeprecated: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.skipDeprecated) - - @Input - val suppressGeneratedFiles: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(true) - - @Input - val jdkVersion: Property<Int> = project.objects.safeProperty<Int>() - .safeConvention(DokkaDefaults.jdkVersion) - + /** + * Specifies the location of the project source code on the Web. If provided, Dokka generates + * "source" links for each declaration. See [GradleSourceLinkBuilder] for more details. + * + * Prefer using [sourceLink] action/closure for adding source links. + */ @Nested val sourceLinks: SetProperty<GradleSourceLinkBuilder> = project.objects.setProperty<GradleSourceLinkBuilder>() .convention(emptySet()) + /** + * Allows to customize documentation generation options on a per-package basis. + * + * @see GradlePackageOptionsBuilder for details + */ @Nested val perPackageOptions: ListProperty<GradlePackageOptionsBuilder> = project.objects.listProperty<GradlePackageOptionsBuilder>() .convention(emptyList()) + /** + * Allows linking to Dokka/Javadoc documentation of the project's dependencies. + * + * Prefer using [externalDocumentationLink] action/closure for adding links. + */ @Nested val externalDocumentationLinks: SetProperty<GradleExternalDocumentationLinkBuilder> = project.objects.setProperty<GradleExternalDocumentationLinkBuilder>() .convention(emptySet()) + /** + * Platform to be used for setting up code analysis and samples. + * + * The default value is deduced from information provided by the Kotlin Gradle plugin. + */ @Input @Optional - val languageVersion: Property<String?> = project.objects.safeProperty() + val platform: Property<Platform> = project.objects.safeProperty<Platform>() + .safeConvention(Platform.DEFAULT) + /** + * Whether to skip packages that contain no visible declarations after + * various filters have been applied. + * + * For instance, if [skipDeprecated] is set to `true` and your package contains only + * deprecated declarations, it will be considered to be empty. + * + * Default is `true`. + */ @Input - @Optional - val apiVersion: Property<String?> = project.objects.safeProperty() + val skipEmptyPackages: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.skipEmptyPackages) + /** + * Whether to document declarations annotated with [Deprecated]. + * + * Can be overridden on package level by setting [GradlePackageOptionsBuilder.skipDeprecated]. + * + * Default is `false`. + */ + @Input + val skipDeprecated: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.skipDeprecated) + + /** + * Directories or individual files that should be suppressed, meaning declarations from them + * will be not documented. + * + * Will be concatenated with generated files if [suppressGeneratedFiles] is set to `false`. + */ + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + val suppressedFiles: ConfigurableFileCollection = project.files() + + /** + * Whether to document/analyze generated files. + * + * Generated files are expected to be present under `{project}/{buildDir}/generated` directory. + * If set to `true`, it effectively adds all files from that directory to [suppressedFiles], so + * you can configure it manually. + * + * Default is `true`. + */ + @Input + val suppressGeneratedFiles: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.suppressGeneratedFiles) + + /** + * Whether to generate external documentation links that lead to API reference + * documentation for Kotlin's standard library when declarations from it are used. + * + * Default is `false`, meaning links will be generated. + */ @Input val noStdlibLink: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.noStdlibLink) + /** + * Whether to generate external documentation links to JDK's Javadocs + * when declarations from it are used. + * + * The version of JDK Javadocs is determined by [jdkVersion] property. + * + * Default is `false`, meaning links will be generated. + */ @Input val noJdkLink: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.noJdkLink) + /** + * Whether to generate external documentation links for Android SDK API reference + * when declarations from it are used. + * + * Only relevant in Android projects, ignored otherwise. + * + * Default is `false`, meaning links will be generated. + */ @Input val noAndroidSdkLink: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(false) - - @InputFiles - @PathSensitive(PathSensitivity.RELATIVE) - val suppressedFiles: ConfigurableFileCollection = project.files() + .safeConvention(DokkaDefaults.noAndroidSdkLink) + + /** + * [Kotlin language version](https://kotlinlang.org/docs/compatibility-modes.html) + * used for setting up analysis and [@sample](https://kotlinlang.org/docs/kotlin-doc.html#sample-identifier) + * environment. + * + * By default, the latest language version available to Dokka's embedded compiler will be used. + */ + @Input + @Optional + val languageVersion: Property<String?> = project.objects.safeProperty() + /** + * [Kotlin API version](https://kotlinlang.org/docs/compatibility-modes.html) + * used for setting up analysis and [@sample](https://kotlinlang.org/docs/kotlin-doc.html#sample-identifier) + * environment. + * + * By default, it will be deduced from [languageVersion]. + */ @Input @Optional - val platform: Property<Platform> = project.objects.safeProperty<Platform>() - .safeConvention(Platform.DEFAULT) + val apiVersion: Property<String?> = project.objects.safeProperty() + + /** + * JDK version to use when generating external documentation links for Java types. + * + * For instance, if you use [java.util.UUID] from JDK in some public declaration signature, + * and this property is set to `8`, Dokka will generate an external documentation link + * to [JDK 8 Javadocs](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html) for it. + * + * Default is JDK 8. + */ + @Input + val jdkVersion: Property<Int> = project.objects.safeProperty<Int>() + .safeConvention(DokkaDefaults.jdkVersion) + + /** + * Deprecated. Use [documentedVisibilities] instead. + */ + @Input + val includeNonPublic: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.includeNonPublic) fun DokkaSourceSetID(sourceSetName: String): DokkaSourceSetID = sourceSetIdFactory.create(sourceSetName) + /** + * Convenient override to **append** source sets to [dependentSourceSets] + */ fun dependsOn(sourceSet: SourceSet) { dependsOn(DokkaSourceSetID(sourceSet.name)) } + /** + * Convenient override to **append** source sets to [dependentSourceSets] + */ fun dependsOn(sourceSet: GradleDokkaSourceSetBuilder) { dependsOn(sourceSet.sourceSetID) } + /** + * Convenient override to **append** source sets to [dependentSourceSets] + */ fun dependsOn(sourceSet: DokkaConfiguration.DokkaSourceSet) { dependsOn(sourceSet.sourceSetID) } + /** + * Convenient override to **append** source sets to [dependentSourceSets] + */ fun dependsOn(sourceSetName: String) { dependsOn(DokkaSourceSetID(sourceSetName)) } + /** + * Convenient override to **append** source sets to [dependentSourceSets] + */ fun dependsOn(sourceSetID: DokkaSourceSetID) { dependentSourceSets.add(sourceSetID) } + /** + * Convenient override to **append** source roots to [sourceRoots] + */ fun sourceRoot(file: File) { sourceRoots.from(file) } + /** + * Convenient override to **append** source roots to [sourceRoots] + */ fun sourceRoot(path: String) { sourceRoot(project.file(path)) } + /** + * Closure for configuring source links, appending to [sourceLinks]. + * + * @see [GradleSourceLinkBuilder] for details. + */ @Suppress("DEPRECATION") // TODO [beresnev] ConfigureUtil will be removed in Gradle 8 fun sourceLink(c: Closure<in GradleSourceLinkBuilder>) { val configured = org.gradle.util.ConfigureUtil.configure(c, GradleSourceLinkBuilder(project)) sourceLinks.add(configured) } + /** + * Action for configuring source links, appending to [sourceLinks]. + * + * @see [GradleSourceLinkBuilder] for details. + */ fun sourceLink(action: Action<in GradleSourceLinkBuilder>) { val sourceLink = GradleSourceLinkBuilder(project) action.execute(sourceLink) sourceLinks.add(sourceLink) } + /** + * Closure for configuring package options, appending to [perPackageOptions]. + * + * @see [GradlePackageOptionsBuilder] for details. + */ @Suppress("DEPRECATION") // TODO [beresnev] ConfigureUtil will be removed in Gradle 8 fun perPackageOption(c: Closure<in GradlePackageOptionsBuilder>) { val configured = org.gradle.util.ConfigureUtil.configure(c, GradlePackageOptionsBuilder(project)) perPackageOptions.add(configured) } + /** + * Action for configuring package options, appending to [perPackageOptions]. + * + * @see [GradlePackageOptionsBuilder] for details. + */ fun perPackageOption(action: Action<in GradlePackageOptionsBuilder>) { val option = GradlePackageOptionsBuilder(project) action.execute(option) perPackageOptions.add(option) } + /** + * Closure for configuring external documentation links, appending to [externalDocumentationLinks]. + * + * @see [GradleExternalDocumentationLinkBuilder] for details. + */ @Suppress("DEPRECATION") // TODO [beresnev] ConfigureUtil will be removed in Gradle 8 fun externalDocumentationLink(c: Closure<in GradleExternalDocumentationLinkBuilder>) { val link = org.gradle.util.ConfigureUtil.configure(c, GradleExternalDocumentationLinkBuilder(project)) externalDocumentationLinks.add(link) } + /** + * Action for configuring external documentation links, appending to [externalDocumentationLinks]. + * + * See [GradleExternalDocumentationLinkBuilder] for details. + */ fun externalDocumentationLink(action: Action<in GradleExternalDocumentationLinkBuilder>) { val link = GradleExternalDocumentationLinkBuilder(project) action.execute(link) externalDocumentationLinks.add(link) } + /** + * Convenient override to **append** external documentation links to [externalDocumentationLinks]. + */ fun externalDocumentationLink(url: String, packageListUrl: String? = null) { externalDocumentationLink(URL(url), packageListUrl = packageListUrl?.let(::URL)) } + /** + * Convenient override to **append** external documentation links to [externalDocumentationLinks]. + */ fun externalDocumentationLink(url: URL, packageListUrl: URL? = null) { externalDocumentationLinks.add( GradleExternalDocumentationLinkBuilder(project).apply { diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt index c5c7428f..5c7c523b 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt @@ -3,14 +3,23 @@ package org.jetbrains.dokka.gradle import com.android.build.gradle.api.AndroidSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +/** + * Convenient override to **append** source sets to [GradleDokkaSourceSetBuilder.dependentSourceSets] + */ fun GradleDokkaSourceSetBuilder.dependsOn(sourceSet: KotlinSourceSet) { dependsOn(DokkaSourceSetID(sourceSet.name)) } +/** + * Convenient override to **append** source sets to [GradleDokkaSourceSetBuilder.dependentSourceSets] + */ fun GradleDokkaSourceSetBuilder.dependsOn(sourceSet: AndroidSourceSet) { dependsOn(DokkaSourceSetID(sourceSet.name)) } +/** + * Extension allowing configuration of Dokka source sets via Kotlin Gradle plugin source sets. + */ fun GradleDokkaSourceSetBuilder.kotlinSourceSet(kotlinSourceSet: KotlinSourceSet) { configureWithKotlinSourceSet(kotlinSourceSet) } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleExternalDocumentationLinkBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleExternalDocumentationLinkBuilder.kt index 19d150c3..36e4f81d 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleExternalDocumentationLinkBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleExternalDocumentationLinkBuilder.kt @@ -10,12 +10,60 @@ import org.jetbrains.dokka.ExternalDocumentationLink import org.jetbrains.dokka.ExternalDocumentationLinkImpl import java.net.URL +/** + * Configuration builder that allows creating links leading to externally hosted + * documentation of your dependencies. + * + * For instance, if you are using types from `kotlinx.serialization`, by default + * they will be unclickable in your documentation, as if unresolved. However, + * since API reference for `kotlinx.serialization` is also built by Dokka and is + * [published on kotlinlang.org](https://kotlinlang.org/api/kotlinx.serialization/), + * you can configure external documentation links for it, allowing Dokka to generate + * documentation links for used types, making them clickable and appear resolved. + * + * Example in Gradle Kotlin DSL: + * + * ```kotlin + * externalDocumentationLink { + * url.set(URL("https://kotlinlang.org/api/kotlinx.serialization/")) + * packageListUrl.set( + * rootProject.projectDir.resolve("serialization.package.list").toURL() + * ) + * } + * ``` + */ class GradleExternalDocumentationLinkBuilder( @Transient @get:Internal internal val project: Project ) : DokkaConfigurationBuilder<ExternalDocumentationLinkImpl> { + + /** + * Root URL of documentation to link with. **Must** contain a trailing slash. + * + * Dokka will do its best to automatically find `package-list` for the given URL, and link + * declarations together. + * + * It automatic resolution fails or if you want to use locally cached files instead, + * consider providing [packageListUrl]. + * + * Example: + * + * ```kotlin + * java.net.URL("https://kotlinlang.org/api/kotlinx.serialization/") + * ``` + */ @Input val url: Property<URL?> = project.objects.safeProperty() + /** + * Specifies the exact location of a `package-list` instead of relying on Dokka + * automatically resolving it. Can also be a locally cached file to avoid network calls. + * + * Example: + * + * ```kotlin + * rootProject.projectDir.resolve("serialization.package.list").toURL() + * ``` + */ @Optional @Input val packageListUrl: Property<URL?> = project.objects.safeProperty() diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradlePackageOptionsBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradlePackageOptionsBuilder.kt index f15a6462..4e53cf81 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradlePackageOptionsBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradlePackageOptionsBuilder.kt @@ -13,33 +13,91 @@ import org.jetbrains.dokka.DokkaConfigurationBuilder import org.jetbrains.dokka.DokkaDefaults import org.jetbrains.dokka.PackageOptionsImpl - +/** + * Configuration builder that allows setting some options for specific packages + * matched by [matchingRegex]. + * + * Example in Gradle Kotlin DSL: + * + * ```kotlin + * tasks.dokkaHtml { + * dokkaSourceSets.configureEach { + * perPackageOption { + * matchingRegex.set(".*internal.*") + * suppress.set(true) + * } + * } + * } + * ``` + */ class GradlePackageOptionsBuilder( @Transient @get:Internal internal val project: Project ) : DokkaConfigurationBuilder<PackageOptionsImpl> { + + /** + * Regular expression that is used to match the package. + * + * Default is any string: `.*`. + */ @Input val matchingRegex: Property<String> = project.objects.safeProperty<String>() .safeConvention(".*") + /** + * Whether this package should be skipped when generating documentation. + * + * Default is `false`. + */ @Input - val includeNonPublic: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.includeNonPublic) + val suppress: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.suppress) + /** + * Set of visibility modifiers that should be documented. + * + * This can be used if you want to document protected/internal/private declarations within a + * specific package, as well as if you want to exclude public declarations and only document internal API. + * + * Can be configured for a whole source set, see [GradleDokkaSourceSetBuilder.documentedVisibilities]. + * + * Default is [DokkaConfiguration.Visibility.PUBLIC]. + */ @Input val documentedVisibilities: SetProperty<DokkaConfiguration.Visibility> = project.objects.setProperty<DokkaConfiguration.Visibility>() .convention(DokkaDefaults.documentedVisibilities) + /** + * Whether to document declarations annotated with [Deprecated]. + * + * Can be overridden on source set level by setting [GradleDokkaSourceSetBuilder.skipDeprecated]. + * + * Default is `false`. + */ + @Input + val skipDeprecated: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.skipDeprecated) + + /** + * Whether to emit warnings about visible undocumented declarations, that is declarations from + * this package and without KDocs, after they have been filtered by [documentedVisibilities]. + * + * This setting works well with [AbstractDokkaTask.failOnWarning]. + * + * Can be overridden on source set level by setting [GradleDokkaSourceSetBuilder.reportUndocumented]. + * + * Default is `false`. + */ @Input val reportUndocumented: Property<Boolean> = project.objects.safeProperty<Boolean>() .safeConvention(DokkaDefaults.reportUndocumented) + /** + * Deprecated. Use [documentedVisibilities] instead. + */ @Input - val skipDeprecated: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.skipDeprecated) + val includeNonPublic: Property<Boolean> = project.objects.safeProperty<Boolean>() + .safeConvention(DokkaDefaults.includeNonPublic) - @Input - val suppress: Property<Boolean> = project.objects.safeProperty<Boolean>() - .safeConvention(DokkaDefaults.suppress) override fun build(): PackageOptionsImpl = PackageOptionsImpl( matchingRegex = checkNotNull(matchingRegex.getSafe()) { "prefix not specified" }, diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt index 2ddd8056..4a0c1333 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleSourceLinkBuilder.kt @@ -8,17 +8,67 @@ import org.jetbrains.dokka.SourceLinkDefinitionImpl import java.io.File import java.net.URL +/** + * Configuration builder that allows adding a `source` link to each signature + * which leads to [remoteUrl] with a specific line number (configurable by setting [remoteLineSuffix]), + * letting documentation readers find source code for each declaration. + * + * Example in Gradle Kotlin DSL: + * + * ```kotlin + * sourceLink { + * localDirectory.set(projectDir.resolve("src")) + * remoteUrl.set(URL("https://github.com/kotlin/dokka/tree/master/src")) + * remoteLineSuffix.set("#L") + * } + * ``` + */ class GradleSourceLinkBuilder( @Transient @get:Internal internal val project: Project ) : DokkaConfigurationBuilder<SourceLinkDefinitionImpl> { + /** + * Path to the local source directory. The path must be relative to the root of current project. + * + * Example: + * + * ```kotlin + * projectDir.resolve("src") + * ``` + */ @InputDirectory @PathSensitive(PathSensitivity.RELATIVE) val localDirectory: Property<File?> = project.objects.safeProperty() + /** + * URL of source code hosting service that can be accessed by documentation readers, + * like GitHub, GitLab, Bitbucket, etc. This URL will be used to generate + * source code links of declarations. + * + * Example: + * + * ```kotlin + * java.net.URL("https://github.com/username/projectname/tree/master/src")) + * ``` + */ @Input val remoteUrl: Property<URL?> = project.objects.safeProperty() + /** + * Suffix used to append source code line number to the URL. This will help readers navigate + * not only to the file, but to the specific line number of the declaration. + * + * The number itself will be appended to the specified suffix. For instance, + * if this property is set to `#L` and the line number is 10, resulting URL suffix + * will be `#L10` + * + * Suffixes used by popular services: + * - GitHub: `#L` + * - GitLab: `#L` + * - Bitbucket: `#lines-` + * + * Default is `#L`. + */ @Optional @Input val remoteLineSuffix: Property<String> = project.objects.safeProperty<String>() diff --git a/runners/maven-plugin/api/maven-plugin.api b/runners/maven-plugin/api/maven-plugin.api index 3b4ace56..28d96bd3 100644 --- a/runners/maven-plugin/api/maven-plugin.api +++ b/runners/maven-plugin/api/maven-plugin.api @@ -66,22 +66,6 @@ public abstract class org/jetbrains/dokka/maven/AbstractDokkaMojo : org/apache/m public final fun setSuppressedFiles (Ljava/util/List;)V } -public final class org/jetbrains/dokka/maven/AbstractDokkaMojo$PackageOptions : org/jetbrains/dokka/DokkaConfiguration$PackageOptions { - public fun <init> ()V - public fun getDocumentedVisibilities ()Ljava/util/Set; - public fun getIncludeNonPublic ()Z - public fun getMatchingRegex ()Ljava/lang/String; - public fun getReportUndocumented ()Ljava/lang/Boolean; - public fun getSkipDeprecated ()Z - public fun getSuppress ()Z - public fun setDocumentedVisibilities (Ljava/util/Set;)V - public fun setIncludeNonPublic (Z)V - public fun setMatchingRegex (Ljava/lang/String;)V - public fun setReportUndocumented (Z)V - public fun setSkipDeprecated (Z)V - public fun setSuppress (Z)V -} - public final class org/jetbrains/dokka/maven/DokkaJavadocJarMojo : org/jetbrains/dokka/maven/AbstractDokkaMojo { public fun <init> ()V public fun execute ()V @@ -124,6 +108,22 @@ public final class org/jetbrains/dokka/maven/MavenDokkaLogger : org/jetbrains/do public fun warn (Ljava/lang/String;)V } +public final class org/jetbrains/dokka/maven/PackageOptions : org/jetbrains/dokka/DokkaConfiguration$PackageOptions { + public fun <init> ()V + public fun getDocumentedVisibilities ()Ljava/util/Set; + public fun getIncludeNonPublic ()Z + public fun getMatchingRegex ()Ljava/lang/String; + public fun getReportUndocumented ()Ljava/lang/Boolean; + public fun getSkipDeprecated ()Z + public fun getSuppress ()Z + public fun setDocumentedVisibilities (Ljava/util/Set;)V + public fun setIncludeNonPublic (Z)V + public fun setMatchingRegex (Ljava/lang/String;)V + public fun setReportUndocumented (Z)V + public fun setSkipDeprecated (Z)V + public fun setSuppress (Z)V +} + public final class org/jetbrains/dokka/maven/SourceLinkMapItem { public fun <init> ()V public final fun getLineSuffix ()Ljava/lang/String; diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index 581d4c9e..92ab9754 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -24,28 +24,6 @@ import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink import java.io.File import java.net.URL -class SourceLinkMapItem { - @Parameter(name = "path", required = true) - var path: String = "" - - @Parameter(name = "url", required = true) - var url: String = "" - - @Parameter(name = "lineSuffix") - var lineSuffix: String? = null -} - -class ExternalDocumentationLinkBuilder { - - @Parameter(name = "url", required = true) - var url: URL? = null - - @Parameter(name = "packageListUrl", required = true) - var packageListUrl: URL? = null - - fun build() = ExternalDocumentationLink(url, packageListUrl) -} - abstract class AbstractDokkaMojo(private val defaultDokkaPlugins: List<Dependency>) : AbstractMojo() { @Parameter(defaultValue = "\${project}", readonly = true, required = true) @@ -64,118 +42,303 @@ abstract class AbstractDokkaMojo(private val defaultDokkaPlugins: List<Dependenc @Component private var resolutionErrorHandler: ResolutionErrorHandler? = null - class PackageOptions : DokkaConfiguration.PackageOptions { - @Parameter - override var matchingRegex: String = ".*" - - @Parameter - @Deprecated("Use [documentedVisibilities] property for a more flexible control over documented visibilities") - override var includeNonPublic: Boolean = DokkaDefaults.includeNonPublic - - @Parameter - override var reportUndocumented: Boolean = DokkaDefaults.reportUndocumented - - @Parameter - override var skipDeprecated: Boolean = DokkaDefaults.skipDeprecated - - @Parameter - override var suppress: Boolean = DokkaDefaults.suppress - - @Parameter(property = "visibility") - override var documentedVisibilities: Set<DokkaConfiguration.Visibility> = DokkaDefaults.documentedVisibilities - } + @Parameter(defaultValue = "JVM") + var displayName: String = "JVM" @Parameter var sourceSetName: String = "JVM" + /** + * Source code roots to be analyzed and documented. + * Accepts directories and individual `.kt` / `.java` files. + * + * Default is `{project.compileSourceRoots}`. + */ @Parameter(required = true, defaultValue = "\${project.compileSourceRoots}") var sourceDirectories: List<String> = emptyList() + /** + * List of directories or files that contain sample functions which are referenced via + * [@sample](https://kotlinlang.org/docs/kotlin-doc.html#sample-identifier) KDoc tag. + */ @Parameter var samples: List<String> = emptyList() + /** + * List of Markdown files that contain + * [module and package documentation](https://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation). + * + * Contents of specified files will be parsed and embedded into documentation as module and package descriptions. + * + * Example of such a file: + * + * ```markdown + * # Module kotlin-demo + * + * The module shows the Dokka usage. + * + * # Package org.jetbrains.kotlin.demo + * + * Contains assorted useful stuff. + * + * ## Level 2 heading + * + * Text after this heading is also part of documentation for `org.jetbrains.kotlin.demo` + * + * # Package org.jetbrains.kotlin.demo2 + * + * Useful stuff in another package. + * ``` + */ @Parameter var includes: List<String> = emptyList() + /** + * Classpath for analysis and interactive samples. + * + * Useful if some types that come from dependencies are not resolved/picked up automatically. + * Property accepts both `.jar` and `.klib` files. + * + * Default is `{project.compileClasspathElements}`. + */ @Parameter(required = true, defaultValue = "\${project.compileClasspathElements}") var classpath: List<String> = emptyList() + /** + * Specifies the location of the project source code on the Web. If provided, Dokka generates + * "source" links for each declaration. See [SourceLinkMapItem] for more details. + */ @Parameter var sourceLinks: List<SourceLinkMapItem> = emptyList() + /** + * Display name used to refer to the project/module. Used for ToC, navigation, logging, etc. + * + * Default is `{project.artifactId}`. + */ @Parameter(required = true, defaultValue = "\${project.artifactId}") var moduleName: String = "" + /** + * Whether to skip documentation generation. + * + * Default is `false`. + */ @Parameter(required = false, defaultValue = "false") var skip: Boolean = false + /** + * JDK version to use when generating external documentation links for Java types. + * + * For instance, if you use [java.util.UUID] from JDK in some public declaration signature, + * and this property is set to `8`, Dokka will generate an external documentation link + * to [JDK 8 Javadocs](https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html) for it. + * + * Default is JDK 8. + */ @Parameter(required = false, defaultValue = "${DokkaDefaults.jdkVersion}") var jdkVersion: Int = DokkaDefaults.jdkVersion + /** + * Whether to document declarations annotated with [Deprecated]. + * + * Can be overridden on package level by setting [PackageOptions.skipDeprecated]. + * + * Default is `false`. + */ @Parameter var skipDeprecated: Boolean = DokkaDefaults.skipDeprecated + /** + * Whether to skip packages that contain no visible declarations after + * various filters have been applied. + * + * For instance, if [skipDeprecated] is set to `true` and your package contains only + * deprecated declarations, it will be considered to be empty. + * + * Default is `true`. + */ @Parameter var skipEmptyPackages: Boolean = DokkaDefaults.skipEmptyPackages + /** + * Whether to emit warnings about visible undocumented declarations, that is declarations without KDocs + * after they have been filtered by [documentedVisibilities]. + * + * This setting works well with [failOnWarning]. + * + * Can be overridden for a specific package by setting [PackageOptions.reportUndocumented]. + * + * Default is `false`. + */ @Parameter var reportUndocumented: Boolean = DokkaDefaults.reportUndocumented + /** + * Allows to customize documentation generation options on a per-package basis. + * + * @see PackageOptions for details + */ @Parameter var perPackageOptions: List<PackageOptions> = emptyList() + /** + * Allows linking to Dokka/Javadoc documentation of the project's dependencies. + * + * @see ExternalDocumentationLinkBuilder for details + */ @Parameter var externalDocumentationLinks: List<ExternalDocumentationLinkBuilder> = emptyList() + /** + * Whether to generate external documentation links that lead to API reference + * documentation for Kotlin's standard library when declarations from it are used. + * + * Default is `false`, meaning links will be generated. + */ @Parameter(defaultValue = "${DokkaDefaults.noStdlibLink}") var noStdlibLink: Boolean = DokkaDefaults.noStdlibLink + /** + * Whether to generate external documentation links to JDK's Javadocs + * when declarations from it are used. + * + * The version of JDK Javadocs is determined by [jdkVersion] property. + * + * Default is `false`, meaning links will be generated. + */ @Parameter(defaultValue = "${DokkaDefaults.noJdkLink}") var noJdkLink: Boolean = DokkaDefaults.noJdkLink - @Parameter - var cacheRoot: String? = null - - @Parameter(defaultValue = "JVM") - var displayName: String = "JVM" - + /** + * Whether to resolve remote files/links over network. + * + * This includes package-lists used for generating external documentation links: + * for instance, to make classes from standard library clickable. + * + * Setting this to `true` can significantly speed up build times in certain cases, + * but can also worsen documentation quality and user experience, for instance by + * not resolving some dependency's class/member links. + * + * When using offline mode, you can cache fetched files locally and provide them to + * Dokka as local paths. For instance, see [ExternalDocumentationLinkBuilder]. + * + * Default is `false`. + */ @Parameter(defaultValue = "${DokkaDefaults.offlineMode}") var offlineMode: Boolean = DokkaDefaults.offlineMode + /** + * [Kotlin language version](https://kotlinlang.org/docs/compatibility-modes.html) + * used for setting up analysis and [@sample](https://kotlinlang.org/docs/kotlin-doc.html#sample-identifier) + * environment. + * + * By default, the latest language version available to Dokka's embedded compiler will be used. + */ @Parameter var languageVersion: String? = null + /** + * [Kotlin API version](https://kotlinlang.org/docs/compatibility-modes.html) + * used for setting up analysis and [@sample](https://kotlinlang.org/docs/kotlin-doc.html#sample-identifier) + * environment. + * + * By default, it will be deduced from [languageVersion]. + */ @Parameter var apiVersion: String? = null + /** + * Directories or individual files that should be suppressed, meaning declarations from them + * will be not documented. + */ @Parameter var suppressedFiles: List<String> = emptyList() - @Parameter - var platform: String = "" - - @Parameter - var includeNonPublic: Boolean = DokkaDefaults.includeNonPublic - + /** + * Set of visibility modifiers that should be documented. + * + * This can be used if you want to document protected/internal/private declarations, + * as well as if you want to exclude public declarations and only document internal API. + * + * Can be configured on per-package basis, see [PackageOptions.documentedVisibilities]. + * + * Default is [DokkaConfiguration.Visibility.PUBLIC]. + */ @Parameter(property = "visibility") var documentedVisibilities: Set<DokkaConfiguration.Visibility> = DokkaDefaults.documentedVisibilities // hack to set the default value for lists, didn't find any other safe way // maven seems to overwrite Kotlin's default initialization value, so it doesn't matter what you put there get() = field.ifEmpty { DokkaDefaults.documentedVisibilities } + /** + * Whether to fail documentation generation if Dokka has emitted a warning or an error. + * Will wait until all errors and warnings have been emitted first. + * + * This setting works well with [reportUndocumented] + * + * Default is `false`. + */ @Parameter var failOnWarning: Boolean = DokkaDefaults.failOnWarning + /** + * Whether to suppress obvious functions. + * + * A function is considered to be obvious if it is: + * - Inherited from `kotlin.Any`, `Kotlin.Enum`, `java.lang.Object` or `java.lang.Enum`, + * such as `equals`, `hashCode`, `toString`. + * - Synthetic (generated by the compiler) and does not have any documentation, such as + * `dataClass.componentN` or `dataClass.copy`. + * + * Default is `true` + */ @Parameter(defaultValue = "${DokkaDefaults.suppressObviousFunctions}") var suppressObviousFunctions: Boolean = DokkaDefaults.suppressObviousFunctions + /** + * Whether to suppress inherited members that aren't explicitly overridden in a given class. + * + * Note: this can suppress functions such as `equals`/`hashCode`/`toString`, but cannot suppress + * synthetic functions such as `dataClass.componentN` and `dataClass.copy`. Use [suppressObviousFunctions] + * for that. + * + * Default is `false`. + */ @Parameter(defaultValue = "${DokkaDefaults.suppressInheritedMembers}") var suppressInheritedMembers: Boolean = DokkaDefaults.suppressInheritedMembers + /** + * Dokka plugins to be using during documentation generation. + * + * Example: + * + * ```xml + * <dokkaPlugins> + * <plugin> + * <groupId>org.jetbrains.dokka</groupId> + * <artifactId>gfm-plugin</artifactId> + * <version>1.7.20</version> + * </plugin> + * </dokkaPlugins> + * ``` + */ @Parameter var dokkaPlugins: List<Dependency> = emptyList() get() = field + defaultDokkaPlugins + @Parameter + var cacheRoot: String? = null + + @Parameter + var platform: String = "" + + /** + * Deprecated. Use [documentedVisibilities] instead. + */ + @Parameter + var includeNonPublic: Boolean = DokkaDefaults.includeNonPublic + protected abstract fun getOutDir(): String override fun execute() { @@ -320,6 +483,12 @@ abstract class AbstractDokkaMojo(private val defaultDokkaPlugins: List<Dependenc requiresProject = true ) class DokkaMojo : AbstractDokkaMojo(emptyList()) { + + /** + * Directory to which documentation will be generated. + * + * Default is `{project.basedir}/target/dokka`. + */ @Parameter(required = true, defaultValue = "\${project.basedir}/target/dokka") var outputDir: String = "" @@ -334,6 +503,12 @@ class DokkaMojo : AbstractDokkaMojo(emptyList()) { requiresProject = true ) class DokkaJavadocMojo : AbstractDokkaMojo(listOf(javadocDependency)) { + + /** + * Directory to which documentation will be generated. + * + * Default is `{project.basedir}/target/dokkaJavadoc`. + */ @Parameter(required = true, defaultValue = "\${project.basedir}/target/dokkaJavadoc") var outputDir: String = "" @@ -348,6 +523,12 @@ class DokkaJavadocMojo : AbstractDokkaMojo(listOf(javadocDependency)) { requiresProject = true ) class DokkaJavadocJarMojo : AbstractDokkaMojo(listOf(javadocDependency)) { + + /** + * Directory to which documentation jar will be generated. + * + * Default is `{project.basedir}/target/dokkaJavadocJar`. + */ @Parameter(required = true, defaultValue = "\${project.basedir}/target/dokkaJavadocJar") var outputDir: String = "" diff --git a/runners/maven-plugin/src/main/kotlin/ExternalDocumentationLinkBuilder.kt b/runners/maven-plugin/src/main/kotlin/ExternalDocumentationLinkBuilder.kt new file mode 100644 index 00000000..8e145fd5 --- /dev/null +++ b/runners/maven-plugin/src/main/kotlin/ExternalDocumentationLinkBuilder.kt @@ -0,0 +1,63 @@ +package org.jetbrains.dokka.maven + +import org.apache.maven.plugins.annotations.Parameter +import org.jetbrains.dokka.ExternalDocumentationLink +import java.net.URL + +/** + * Configuration block that allows creating links leading to externally hosted + * documentation of your dependencies. + * + * For instance, if you are using types from `kotlinx.serialization`, by default + * they will be unclickable in your documentation, as if unresolved. However, + * since API reference for `kotlinx.serialization` is also built by Dokka and is + * [published on kotlinlang.org](https://kotlinlang.org/api/kotlinx.serialization/), + * you can configure external documentation links for it, allowing Dokka to generate + * documentation links for used types, making them clickable and appear resolved. + * + * Example: + * + * ```xml + * <externalDocumentationLinks> + * <link> + * <url>https://kotlinlang.org/api/latest/jvm/stdlib/</url> + * <packageListUrl>file:/${project.basedir}/stdlib.package.list</packageListUrl> + * </link> + * </externalDocumentationLinks> + * ``` + */ +class ExternalDocumentationLinkBuilder { + + /** + * Root URL of documentation to link with. **Must** contain a trailing slash. + * + * Dokka will do its best to automatically find `package-list` for the given URL, and link + * declarations together. + * + * It automatic resolution fails or if you want to use locally cached files instead, + * consider providing [packageListUrl]. + * + * Example: + * + * ```xml + * <url>https://kotlinlang.org/api/latest/jvm/stdlib/</url> + * ``` + */ + @Parameter(name = "url", required = true) + var url: URL? = null + + /** + * Specifies the exact location of a `package-list` instead of relying on Dokka + * automatically resolving it. Can also be a locally cached file to avoid network calls. + * + * Example: + * + * ```xml + * <packageListUrl>file:/${project.basedir}/stdlib.package.list</packageListUrl> + * ``` + */ + @Parameter(name = "packageListUrl", required = true) + var packageListUrl: URL? = null + + fun build() = ExternalDocumentationLink(url, packageListUrl) +} diff --git a/runners/maven-plugin/src/main/kotlin/PackageOptions.kt b/runners/maven-plugin/src/main/kotlin/PackageOptions.kt new file mode 100644 index 00000000..af678769 --- /dev/null +++ b/runners/maven-plugin/src/main/kotlin/PackageOptions.kt @@ -0,0 +1,85 @@ +package org.jetbrains.dokka.maven + +import org.apache.maven.plugins.annotations.Parameter +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaDefaults + +/** + * Configuration block that allows setting some options for specific packages + * matched by [matchingRegex]. + * + * Example: + * + * ```xml + * <configuration> + * <perPackageOptions> + * <packageOptions> + * <matchingRegex>.*api.*</matchingRegex> + * <suppress>false</suppress> + * <reportUndocumented>false</reportUndocumented> + * <skipDeprecated>false</skipDeprecated> + * <documentedVisibilities> + * <visibility>PUBLIC</visibility> + * <visibility>PROTECTED</visibility> + * </documentedVisibilities> + * </packageOptions> + * </perPackageOptions> + * </configuration> + * ``` + */ +class PackageOptions : DokkaConfiguration.PackageOptions { + + /** + * Regular expression that is used to match the package. + * + * If multiple packages match the same `matchingRegex`, the longest `matchingRegex` will be used. + * + * Default is any string: `.*`. + */ + @Parameter + override var matchingRegex: String = ".*" + + /** + * Whether this package should be skipped when generating documentation. + * + * Default is `false`. + */ + @Parameter + override var suppress: Boolean = DokkaDefaults.suppress + + /** + * List of visibility modifiers that should be documented. + * + * This can be used if you want to document protected/internal/private declarations within a + * specific package, as well as if you want to exclude public declarations and only document internal API. + * + * Default is [DokkaConfiguration.Visibility.PUBLIC]. + */ + @Parameter(property = "visibility") + override var documentedVisibilities: Set<DokkaConfiguration.Visibility> = DokkaDefaults.documentedVisibilities + + /** + * Whether to document declarations annotated with [Deprecated]. + * + * Can be set on project level with [AbstractDokkaMojo.skipDeprecated]. + * + * Default is `false`. + */ + @Parameter + override var skipDeprecated: Boolean = DokkaDefaults.skipDeprecated + + /** + * Whether to emit warnings about visible undocumented declarations, that is declarations from + * this package and without KDocs, after they have been filtered by [documentedVisibilities]. + * + * This setting works well with [AbstractDokkaMojo.failOnWarning]. + * + * Default is `false`. + */ + @Parameter + override var reportUndocumented: Boolean = DokkaDefaults.reportUndocumented + + @Parameter + @Deprecated("Use [documentedVisibilities] property for a more flexible control over documented visibilities") + override var includeNonPublic: Boolean = DokkaDefaults.includeNonPublic +} diff --git a/runners/maven-plugin/src/main/kotlin/SourceLinkMapItem.kt b/runners/maven-plugin/src/main/kotlin/SourceLinkMapItem.kt new file mode 100644 index 00000000..621b38d8 --- /dev/null +++ b/runners/maven-plugin/src/main/kotlin/SourceLinkMapItem.kt @@ -0,0 +1,65 @@ +package org.jetbrains.dokka.maven + +import org.apache.maven.plugins.annotations.Parameter + +/** + * Configuration block that allows adding a `source` link to each signature + * which leads to [path] with a specific line number (configurable by setting [lineSuffix]), + * letting documentation readers find source code for each declaration. + * + * Example: + * + * ```xml + * <sourceLinks> + * <link> + * <path>${project.basedir}/src</path> + * <url>https://github.com/kotlin/dokka/tree/master/src</url> + * <lineSuffix>#L</lineSuffix> + * </link> + * </sourceLinks> + * ``` + */ +class SourceLinkMapItem { + + /** + * Path to the local source directory. The path must be relative to the root of current project. + * + * Example: + * + * ```xml + * <path>${project.basedir}/src</path> + * ``` + */ + @Parameter(name = "path", required = true) + var path: String = "" + + /** + * URL of source code hosting service that can be accessed by documentation readers, + * like GitHub, GitLab, Bitbucket, etc. This URL will be used to generate + * source code links of declarations. + * + * Example: + * + * ```xml + * <url>https://github.com/username/projectname/tree/master/src</url> + * ``` + */ + @Parameter(name = "url", required = true) + var url: String = "" + + /** + * Suffix used to append source code line number to the URL. This will help readers navigate + * not only to the file, but to the specific line number of the declaration. + * + * The number itself will be appended to the specified suffix. For instance, + * if this property is set to `#L` and the line number is 10, resulting URL suffix + * will be `#L10` + * + * Suffixes used by popular services: + * - GitHub: `#L` + * - GitLab: `#L` + * - Bitbucket: `#lines-` + */ + @Parameter(name = "lineSuffix") + var lineSuffix: String? = null +} |