diff options
author | Andrzej Ratajczak <andrzej.ratajczak98@gmail.com> | 2020-05-12 15:19:53 +0200 |
---|---|---|
committer | Kamil Doległo <9080183+kamildoleglo@users.noreply.github.com> | 2020-06-16 11:42:11 +0200 |
commit | 9637ec0747815181d56fa53419d4f6c56705752b (patch) | |
tree | 8d5c151b13322224c1053c9710273be2cf9760bd | |
parent | d20cad929c4c095fbc8a94e4d41938fa3fc39a0c (diff) | |
download | dokka-9637ec0747815181d56fa53419d4f6c56705752b.tar.gz dokka-9637ec0747815181d56fa53419d4f6c56705752b.tar.bz2 dokka-9637ec0747815181d56fa53419d4f6c56705752b.zip |
Refactor CLI
-rw-r--r-- | core/src/main/kotlin/DokkaBootstrapImpl.kt | 41 | ||||
-rw-r--r-- | core/src/main/kotlin/utilities/DokkaLogging.kt | 4 | ||||
-rw-r--r-- | runners/cli/build.gradle.kts | 5 | ||||
-rw-r--r-- | runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt | 185 | ||||
-rw-r--r-- | runners/cli/src/main/kotlin/cli/main.kt | 584 |
5 files changed, 324 insertions, 495 deletions
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt index d39ee1d5..e0f014c8 100644 --- a/core/src/main/kotlin/DokkaBootstrapImpl.kt +++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt @@ -8,28 +8,25 @@ import org.jetbrains.dokka.utilities.DokkaLogger import java.util.function.BiConsumer -fun parsePerPackageOptions(arg: String): List<PackageOptions> { - if (arg.isBlank()) return emptyList() - - return arg.split(";").map { it.split(",") }.map { - val prefix = it.first() - if (prefix == "") - throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead") - val args = it.subList(1, it.size) - val deprecated = args.find { it.endsWith("deprecated") }?.startsWith("+") ?: true - val reportUndocumented = args.find { it.endsWith("reportUndocumented") }?.startsWith("+") ?: true - val privateApi = args.find { it.endsWith("privateApi") }?.startsWith("+") ?: false - val suppress = args.find { it.endsWith("suppress") }?.startsWith("+") ?: false - PackageOptionsImpl( - prefix, - includeNonPublic = privateApi, - reportUndocumented = reportUndocumented, - skipDeprecated = !deprecated, - suppress = suppress - ) - } +fun parsePerPackageOptions(args: List<String>): List<PackageOptions> = args.map { it.split(",") }.map { + val prefix = it.first() + if (prefix == "") + throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead") + val args = it.subList(1, it.size) + val deprecated = args.find { it.endsWith("deprecated") }?.startsWith("+") ?: true + val reportUndocumented = args.find { it.endsWith("reportUndocumented") }?.startsWith("+") ?: true + val privateApi = args.find { it.endsWith("privateApi") }?.startsWith("+") ?: false + val suppress = args.find { it.endsWith("suppress") }?.startsWith("+") ?: false + PackageOptionsImpl( + prefix, + includeNonPublic = privateApi, + reportUndocumented = reportUndocumented, + skipDeprecated = !deprecated, + suppress = suppress + ) } + class DokkaBootstrapImpl : DokkaBootstrap { class DokkaProxyLogger(val consumer: BiConsumer<String, String>) : DokkaLogger { @@ -60,9 +57,9 @@ class DokkaBootstrapImpl : DokkaBootstrap { if (warningsCount > 0 || errorsCount > 0) { println( "Generation completed with $warningsCount warning" + - (if (DokkaConsoleLogger.warningsCount == 1) "" else "s") + + (if (warningsCount == 1) "" else "s") + " and $errorsCount error" + - if (DokkaConsoleLogger.errorsCount == 1) "" else "s" + if (errorsCount == 1) "" else "s" ) } else { println("generation completed successfully") diff --git a/core/src/main/kotlin/utilities/DokkaLogging.kt b/core/src/main/kotlin/utilities/DokkaLogging.kt index 1c05c95d..4b671f7b 100644 --- a/core/src/main/kotlin/utilities/DokkaLogging.kt +++ b/core/src/main/kotlin/utilities/DokkaLogging.kt @@ -27,9 +27,9 @@ object DokkaConsoleLogger : DokkaLogger { override fun report() { if (warningsCount > 0 || errorsCount > 0) { - println("Generation completed with warningsCount warning" + + println("Generation completed with $warningsCount warning" + (if(warningsCount == 1) "" else "s") + - " and errorsCount error" + + " and $errorsCount error" + if(errorsCount == 1) "" else "s" ) } else { diff --git a/runners/cli/build.gradle.kts b/runners/cli/build.gradle.kts index 4b39d64c..6c3a4d7d 100644 --- a/runners/cli/build.gradle.kts +++ b/runners/cli/build.gradle.kts @@ -5,11 +5,12 @@ plugins { } repositories { - maven(url = "https://dl.bintray.com/orangy/maven") + maven(url = "https://dl.bintray.com/kotlin/kotlinx") } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-cli-jvm:0.1.0-dev-3") + implementation("org.jetbrains.kotlinx:kotlinx-cli-jvm:0.2.1") + implementation("com.google.code.gson:gson:2.8.5") implementation(project(":core")) } diff --git a/runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt b/runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt deleted file mode 100644 index 5d795da7..00000000 --- a/runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt +++ /dev/null @@ -1,185 +0,0 @@ -package org.jetbrains.dokka - -import kotlinx.cli.* -import kotlin.reflect.KProperty - -class ParseContext(val cli: CommandLineInterface = CommandLineInterface("dokka")) { - private val transformActions = mutableMapOf<KProperty<*>, (String) -> Unit>() - private val flagActions = mutableMapOf<KProperty<*>, () -> Unit>() - - fun registerFlagAction( - keys: List<String>, - help: String, - property: KProperty<*>, - invoke: () -> Unit - ) { - if (property !in flagActions.keys) { - cli.flagAction(keys, help) { - flagActions[property]!!() - } - } - flagActions[property] = invoke - - } - - fun registerSingleOption( - keys: List<String>, - help: String, - property: KProperty<*>, - invoke: (String) -> Unit - ) { - if (property !in transformActions.keys) { - cli.singleAction(keys, help) { - transformActions[property]!!(it) - } - } - transformActions[property] = invoke - } - - fun registerRepeatableOption( - keys: List<String>, - help: String, - property: KProperty<*>, - invoke: (String) -> Unit - ) { - if (property !in transformActions.keys) { - cli.repeatingAction(keys, help) { - transformActions[property]!!(it) - } - } - transformActions[property] = invoke - } - - fun parse(args: Array<String>) { - cli.parseArgs(*args) - } - -} - -fun CommandLineInterface.singleAction( - keys: List<String>, - help: String, - invoke: (String) -> Unit -) = registerAction( - object : FlagActionBase(keys, help) { - override fun invoke(arguments: ListIterator<String>) { - if (arguments.hasNext()) { - val msg = arguments.next() - invoke(msg) - } - } - - override fun invoke() { - error("should be never called") - } - } -) - -fun CommandLineInterface.repeatingAction( - keys: List<String>, - help: String, - invoke: (String) -> Unit -) = registerAction( - object : FlagActionBase(keys, help) { - override fun invoke(arguments: ListIterator<String>) { - while (arguments.hasNext()) { - val message = arguments.next() - - if (this@repeatingAction.getFlagAction(message) != null) { - arguments.previous() - break - } - invoke(message) - } - } - - override fun invoke() { - error("should be never called") - } - } - -) - - -class DokkaArgumentsParser(val args: Array<String>, val parseContext: ParseContext) { - class OptionDelegate<T>( - var value: T, - private val action: (delegate: OptionDelegate<T>, property: KProperty<*>) -> Unit - ) { - operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value - operator fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate<T> { - action(this, property) - return this - } - } - - fun <T> parseInto(dest: T): T { - // TODO: constructor: (DokkaArgumentsParser) -> T - parseContext.parse(args) - return dest - } - - fun <T> repeatableOption( - keys: List<String>, - help: String, - transform: (String) -> T - ) = OptionDelegate(mutableListOf<T>()) { delegate, property -> - parseContext.registerRepeatableOption(keys, help, property) { - delegate.value.add(transform(it)) - } - } - - fun <T : String?> repeatableOption( - keys: List<String>, - help: String - ) = repeatableOption(keys, help) { it as T } - - fun <T> repeatableFlag( - keys: List<String>, - help: String, - initElement: (ParseContext) -> T - ) = OptionDelegate(mutableListOf<T>()) { delegate, property -> - parseContext.registerFlagAction(keys, help, property) { - delegate.value.add(initElement(parseContext)) - } - } - - fun <T> singleFlag( - keys: List<String>, - help: String, - initElement: (ParseContext) -> T, - transform: () -> T - ) = OptionDelegate(initElement(parseContext)) { delegate, property -> - parseContext.registerFlagAction(keys, help, property) { - delegate.value = transform() - } - } - - fun singleFlag( - keys: List<String>, - help: String - ) = singleFlag(keys, help, { false }, { true }) - - fun <T : String?> stringOption( - keys: List<String>, - help: String, - defaultValue: T - ) = singleOption(keys, help, { it as T }, { defaultValue }) - - fun <T> singleOption( - keys: List<String>, - help: String, - transform: (String) -> T, - initElement: (ParseContext) -> T - ) = OptionDelegate(initElement(parseContext)) { delegate, property -> - parseContext.registerSingleOption(keys, help, property) { - val toAdd = transform(it) - delegate.value = toAdd - } - } -} - - -//`(-perPackage fqName [-include-non-public] [...other flags])*` (edited) -//`(-sourceLink dir url [-urlSuffix value])*` -//`(-extLink url [packageListUrl])*`
\ No newline at end of file diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 2ef08c2e..515f9bb0 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -1,335 +1,351 @@ package org.jetbrains.dokka +import com.google.gson.Gson +import kotlinx.cli.* import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink import org.jetbrains.dokka.utilities.DokkaConsoleLogger -import java.io.File -import java.io.FileNotFoundException +import org.jetbrains.kotlin.utils.addToStdlib.cast +import java.io.* import java.net.MalformedURLException import java.net.URL -import java.net.URLClassLoader import java.nio.file.Files import java.nio.file.Paths -open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { - override val outputDir: String by parser.stringOption( - listOf("-output"), - "Output directory path", - "" - ) - - override val format: String by parser.stringOption( - listOf("-format"), - "Output format (text, html, gfm, jekyll, kotlin-website)", - "" - ) - - override val pluginsClasspath: List<File> by parser.repeatableOption( - listOf("-dokkaPlugins"), - "List of jars with dokka plugins" - ) { - File(it) - }.also { - Paths.get("./dokka-base.jar").toAbsolutePath().normalize().run { - if (Files.exists(this)) it.value.add(this.toFile()) - else throw FileNotFoundException("Dokka base plugin is not found! Make sure you placed 'dokka-base.jar' containing base plugin along the cli jar file") - } - } - - override val cacheRoot: String? by parser.stringOption( - listOf("-cacheRoot"), - "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled", - null - ) - - override val offlineMode: Boolean by parser.singleFlag( - listOf("-offlineMode"), - "Offline mode (do not download package lists from the Internet)" - ) +class GlobalArguments(args: Array<String>) : DokkaConfiguration { - override val failOnWarning: Boolean by parser.singleFlag( - listOf("-failOnWarning"), "Fail dokka task if at least one warning was reported" - ) + val parser = ArgParser("globalArguments", prefixStyle = ArgParser.OptionPrefixStyle.JVM) - override val passesConfigurations: List<Arguments> by parser.repeatableFlag( - listOf("-pass"), - "Single dokka pass" - ) { - Arguments(parser).also { if (it.moduleName.isEmpty()) DokkaConsoleLogger.warn("Not specified module name. It can result in unexpected behaviour while including documentation for module") } - } + val json: String? by parser.argument(ArgType.String, description = "Json file name").optional() - override val modules: List<DokkaConfiguration.DokkaModuleDescription> = emptyList() + override val outputDir by parser.option(ArgType.String, description = "Output directory path") + .default("./dokka") - override val pluginsConfiguration: Map<String, String> = mutableMapOf() -} + override val format by parser.option( + ArgType.String, + description = "Output format (html, gfm, jekyll)" + ).default("html") -class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfiguration { - override val moduleName: String by parser.stringOption( - listOf("-module"), - "Name of the documentation module", - "" + override val cacheRoot by parser.option( + ArgType.String, + description = "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled" ) - override val displayName: String by parser.stringOption( - listOf("-displayName"), - "Name displayed in the generated documentation", - "" - ) + override val passesConfigurations by parser.option( + ArgTypeArgument, + description = "Single dokka pass", + fullName = "pass" + ).multiple() - override val sourceSetID: String by parser.stringOption( - listOf("-sourceSetID"), - "Source set ID used for declaring dependent source sets", - "main" - ) + override val pluginsConfiguration by parser.option( + ArgTypePlugin, + description = "Configuration for plugins in format fqPluginName=json^^fqPluginName=json..." + ).default(emptyMap()) - override val classpath: List<String> by parser.repeatableOption<String>( - listOf("-classpath"), - "Classpath for symbol resolution" - ) - - override val sourceRoots: List<DokkaConfiguration.SourceRoot> by parser.repeatableOption( - listOf("-src"), - "Source file or directory (allows many paths separated by the system path separator)" - ) { SourceRootImpl(it) } + override val pluginsClasspath by parser.option( + ArgTypeFile, + description = "List of jars with dokka plugins (allows many paths separated by the semicolon `;`)" + ).delimiter(";") - override val dependentSourceSets: List<String> by parser.repeatableOption<String>( - listOf("-dependentSets"), - "Names of dependent source sets" - ) - - override val samples: List<String> by parser.repeatableOption<String>( - listOf("-sample"), - "Source root for samples" - ) - override val includes: List<String> by parser.repeatableOption<String>( - listOf("-include"), - "Markdown files to load (allows many paths separated by the system path separator)" - ) - - override val includeNonPublic: Boolean by parser.singleFlag( - listOf("-includeNonPublic"), - "Include non public" - ) - - override val includeRootPackage: Boolean by parser.singleFlag( - listOf("-includeRootPackage"), - "Include root package" - ) - - override val reportUndocumented: Boolean by parser.singleFlag( - listOf("-reportUndocumented"), - "Report undocumented members" + override val offlineMode by parser.option( + ArgType.Boolean, + "Offline mode (do not download package lists from the Internet)" + ).default(false) + + override val failOnWarning by parser.option( + ArgType.Boolean, + "Throw an exception if the generation exited with warnings" + ).default(false) + + val globalPackageOptions by parser.option( + ArgType.String, + description = "List of package passConfiguration 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 helpPass by parser.option( + ArgTypeHelpPass, + description = "Prints help for single -pass" ) - override val skipEmptyPackages: Boolean by parser.singleFlag( - listOf("-skipEmptyPackages"), - "Do not create index pages for empty packages" - ) + override val modules: List<DokkaConfiguration.DokkaModuleDescription> = emptyList() - override val skipDeprecated: Boolean by parser.singleFlag( - listOf("-skipDeprecated"), - "Do not output deprecated members" - ) + init { + parser.parse(args) - override val jdkVersion: Int by parser.singleOption( - listOf("-jdkVersion"), - "Version of JDK to use for linking to JDK JavaDoc", - { it.toInt() }, - { 8 } - ) + passesConfigurations.all { + it.perPackageOptions.cast<MutableList<DokkaConfiguration.PackageOptions>>() + .addAll(parsePerPackageOptions(globalPackageOptions)) + } - override val languageVersion: String? by parser.stringOption( - listOf("-languageVersion"), - "Language Version to pass to Kotlin analysis", - null - ) + passesConfigurations.all { + it.externalDocumentationLinks.cast<MutableList<ExternalDocumentationLink>>().addAll(parseLinks(globalLinks)) + } - override val apiVersion: String? by parser.stringOption( - listOf("-apiVersion"), - "Kotlin Api Version to pass to Kotlin analysis", - null - ) + globalSrcLink.forEach { + if (it.isNotEmpty() && it.contains("=")) + passesConfigurations.all { pass -> + pass.sourceLinks.cast<MutableList<SourceLinkDefinitionImpl>>() + .add(SourceLinkDefinitionImpl.parseSourceLinkDefinition(it)) + } + else { + DokkaConsoleLogger.warn("Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") + } + } - override val noStdlibLink: Boolean by parser.singleFlag( - listOf("-noStdlibLink"), - "Disable documentation link to stdlib" - ) + passesConfigurations.forEach { + it.externalDocumentationLinks.cast<MutableList<ExternalDocumentationLink>>().addAll(defaultLinks(it)) + } + } +} - override val noJdkLink: Boolean by parser.singleFlag( - listOf("-noJdkLink"), - "Disable documentation link to JDK" +fun passArguments(args: Array<String>): DokkaConfiguration.PassConfiguration { + + val parser = ArgParser("passConfiguration", prefixStyle = ArgParser.OptionPrefixStyle.JVM) + + val moduleName by parser.option( + ArgType.String, + description = "Name of the documentation module", + fullName = "module" + ).required() + + val displayName by parser.option( + ArgType.String, + description = "Name of the source set" + ).default("JVM") + + val sourceSetID by parser.option( + ArgType.String, + description = "ID of the source set" + ).default("main") + + val classpath by parser.option( + ArgType.String, + description = "Classpath for symbol resolution (allows many paths separated by the semicolon `;`)" + ).delimiter(";") + + val sourceRoots by parser.option( + ArgType.String, + description = "Source file or directory (allows many paths separated by the semicolon `;`)", + fullName = "src" + ).delimiter(";") + + val dependentSourceRoots by parser.option( + ArgType.String, + description = "Source file or directory (allows many paths separated by the semicolon `;`)" + ).delimiter(";") + + val dependentSourceSets by parser.option( + ArgType.String, + description = "Names of dependent source sets (allows many paths separated by the semicolon `;`)" + ).delimiter(";") + + val samples by parser.option( + ArgType.String, + description = "Source root for samples (allows many paths separated by the semicolon `;`)" + ).delimiter(";") + + val includes by parser.option( + ArgType.String, + 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(false) + + val includeRootPackage by parser.option(ArgType.Boolean, description = "Include non public") + .default(false) + + val reportUndocumented by parser.option(ArgType.Boolean, description = "Report undocumented members") + .default(false) + + val skipEmptyPackages by parser.option( + ArgType.Boolean, + description = "Do not create index pages for empty packages" + ).default(false) + + val skipDeprecated by parser.option(ArgType.Boolean, description = "Do not output deprecated members") + .default(false) + + val jdkVersion by parser.option( + ArgType.Int, + description = "Version of JDK to use for linking to JDK JavaDoc" + ).default(8) + + val languageVersion by parser.option( + ArgType.String, + description = "Language Version to pass to Kotlin analysis" ) - override val suppressedFiles: List<String> by parser.repeatableOption<String>( - listOf("-suppressedFile"), - "" + 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(false) + + val noJdkLink by parser.option(ArgType.Boolean, description = "Disable documentation link to JDK") + .default(false) + + val suppressedFiles by parser.option( + ArgType.String, + 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(Platform.DEFAULT) + + val perPackageOptions by parser.option( + ArgType.String, + description = "List of package passConfiguration 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.PassConfiguration { + override val moduleName = moduleName + override val displayName = displayName + override val sourceSetID = sourceSetID + override val classpath = classpath + override val sourceRoots = sourceRoots.map { SourceRootImpl(it.toAbsolutePath()) } + override val dependentSourceSets: List<String> = dependentSourceSets + override val samples = samples.map { it.toAbsolutePath() } + override val includes = includes.map { it.toAbsolutePath() } + override val includeNonPublic = includeNonPublic + override val includeRootPackage = includeRootPackage + override val reportUndocumented = reportUndocumented + override val skipEmptyPackages = skipEmptyPackages + override val skipDeprecated = skipDeprecated + override val jdkVersion = jdkVersion + override val sourceLinks = sourceLinks + override val analysisPlatform = analysisPlatform + override val perPackageOptions = parsePerPackageOptions(perPackageOptions) + override val externalDocumentationLinks = parseLinks(externalDocumentationLinks) + override val languageVersion = languageVersion + override val apiVersion = apiVersion + override val noStdlibLink = noStdlibLink + override val noJdkLink = noJdkLink + override val suppressedFiles = suppressedFiles + } +} - override val analysisPlatform: Platform by parser.singleOption( - listOf("-analysisPlatform"), - "Platform for analysis", - { Platform.fromString(it) }, - { Platform.DEFAULT } - ) +object ArgTypeFile : ArgType<File>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): File = File(value) + 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 thar represents paltform }" +} - override val perPackageOptions: MutableList<DokkaConfiguration.PackageOptions> by parser.singleOption( - listOf("-packageOptions"), - "List of package passConfiguration in format \"prefix,-deprecated,-privateApi,+reportUndocumented,+suppress;...\" ", - { parsePerPackageOptions(it).toMutableList() }, - { mutableListOf() } - ) +object ArgTypePlugin : ArgType<Map<String, String>>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): Map<kotlin.String, kotlin.String> = + value.split("^^").map { + it.split("=").let { + it[0] to it[1] + } + }.toMap() - override val externalDocumentationLinks: MutableList<DokkaConfiguration.ExternalDocumentationLink> by parser.singleOption( - listOf("-links"), - "External documentation links in format url^packageListUrl^^url2...", - { MainKt.parseLinks(it).toMutableList() }, - { mutableListOf() } - ) + override val description: kotlin.String + get() = "{ String fqName=json, remember to escape `\"` inside json }" +} - override val sourceLinks: MutableList<DokkaConfiguration.SourceLinkDefinition> by parser.repeatableOption<DokkaConfiguration.SourceLinkDefinition>( - listOf("-srcLink"), - "Mapping between a source directory and a Web site for browsing the code" - ) { - if (it.isNotEmpty() && it.contains("=")) - SourceLinkDefinitionImpl.parseSourceLinkDefinition(it) +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.") } - } -} -object MainKt { - fun defaultLinks(config: DokkaConfiguration.PassConfiguration): MutableList<ExternalDocumentationLink> = - mutableListOf<ExternalDocumentationLink>().apply { - if (!config.noJdkLink) - this += DokkaConfiguration.ExternalDocumentationLink - .Builder("https://docs.oracle.com/javase/${config.jdkVersion}/docs/api/") - .build() - - if (!config.noStdlibLink) - this += DokkaConfiguration.ExternalDocumentationLink - .Builder("https://kotlinlang.org/api/latest/jvm/stdlib/") - .build() - } + override val description: kotlin.String + get() = "{ String that represent source links }" +} - fun parseLinks(links: String): List<ExternalDocumentationLink> { - val (parsedLinks, parsedOfflineLinks) = links.split("^^") - .map { it.split("^").map { it.trim() }.filter { it.isNotBlank() } } - .filter { it.isNotEmpty() } - .partition { it.size == 1 } - - return parsedLinks.map { (root) -> ExternalDocumentationLink.Builder(root).build() } + - parsedOfflineLinks.map { (root, packageList) -> - val rootUrl = URL(root) - val packageListUrl = - try { - URL(packageList) - } catch (ex: MalformedURLException) { - File(packageList).toURI().toURL() - } - ExternalDocumentationLink.Builder(rootUrl, packageListUrl).build() - } - } +object ArgTypeArgument : ArgType<DokkaConfiguration.PassConfiguration>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): DokkaConfiguration.PassConfiguration = + passArguments(value.split(" ").filter { it.isNotBlank() }.toTypedArray()) - @JvmStatic - fun entry(configuration: DokkaConfiguration) { - val generator = DokkaGenerator(configuration, DokkaConsoleLogger) - generator.generate() - DokkaConsoleLogger.report() - } + override val description: kotlin.String + get() = "" +} - fun findToolsJar(): File { - val javaHome = System.getProperty("java.home") - val default = File(javaHome, "../lib/tools.jar") - val mac = File(javaHome, "../Classes/classes.jar") - return when { - default.exists() -> default - mac.exists() -> mac - else -> { - throw Exception("tools.jar not found, please check it, also you can provide it manually, using -cp") - } - } - } +// Workaround for printing nested parsers help +object ArgTypeHelpPass : ArgType<Any>(false) { + override fun convert(value: kotlin.String, name: kotlin.String): Any = Any().also { passArguments(arrayOf("-h")) } - fun createClassLoaderWithTools(): ClassLoader { - val toolsJar = findToolsJar().canonicalFile.toURI().toURL() - val originalUrls = (javaClass.classLoader as? URLClassLoader)?.urLs - val dokkaJar = javaClass.protectionDomain.codeSource.location - val urls = if (originalUrls != null) arrayOf(toolsJar, *originalUrls) else arrayOf(toolsJar, dokkaJar) - return URLClassLoader(urls, ClassLoader.getSystemClassLoader().parent) - } + override val description: kotlin.String + get() = "" +} - fun startWithToolsJar(configuration: DokkaConfiguration) { - try { - javaClass.classLoader.loadClass("com.sun.tools.doclets.formats.html.HtmlDoclet") - entry(configuration) - } catch (e: ClassNotFoundException) { - val classLoader = createClassLoaderWithTools() - classLoader.loadClass("org.jetbrains.dokka.MainKt") - .methods.find { it.name == "entry" }!! - .invoke(null, configuration) - } +fun defaultLinks(config: DokkaConfiguration.PassConfiguration): MutableList<ExternalDocumentationLink> = + mutableListOf<ExternalDocumentationLink>().apply { + if (!config.noJdkLink) + this += DokkaConfiguration.ExternalDocumentationLink + .Builder("https://docs.oracle.com/javase/${config.jdkVersion}/docs/api/") + .build() + + if (!config.noStdlibLink) + this += ExternalDocumentationLink + .Builder("https://kotlinlang.org/api/latest/jvm/stdlib/") + .build() } - fun createConfiguration(args: Array<String>): GlobalArguments { - val parseContext = ParseContext() - val parser = DokkaArgumentsParser(args, parseContext) - val configuration = GlobalArguments(parser) - - parseContext.cli.singleAction( - listOf("-globalPackageOptions"), - "List of package passConfiguration in format \"prefix,-deprecated,-privateApi,+reportUndocumented,+suppress;...\" " - ) { link -> - configuration.passesConfigurations.all { - it.perPackageOptions.toMutableList().addAll(parsePerPackageOptions(link)) - } - } - - parseContext.cli.singleAction( - listOf("-globalLinks"), - "External documentation links in format url^packageListUrl^^url2..." - ) { link -> - configuration.passesConfigurations.all { - it.externalDocumentationLinks.toMutableList().addAll(parseLinks(link)) - } - } - - parseContext.cli.repeatingAction( - listOf("-globalSrcLink"), - "Mapping between a source directory and a Web site for browsing the code" - ) { - val newSourceLinks = if (it.isNotEmpty() && it.contains("=")) - listOf(SourceLinkDefinitionImpl.parseSourceLinkDefinition(it)) - else { - if (it.isNotEmpty()) { - DokkaConsoleLogger.warn("Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") - } - listOf() +private fun String.toAbsolutePath() = Paths.get(this).toAbsolutePath().toString() + +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.Builder(root).build() } + + parsedOfflineLinks.map { (root, packageList) -> + val rootUrl = URL(root) + val packageListUrl = + try { + URL(packageList) + } catch (ex: MalformedURLException) { + File(packageList).toURI().toURL() + } + ExternalDocumentationLink.Builder(rootUrl, packageListUrl).build() } - - configuration.passesConfigurations.all { - it.sourceLinks.toMutableList().addAll(newSourceLinks) - } - } - parser.parseInto(configuration) - configuration.passesConfigurations.forEach { - it.externalDocumentationLinks.addAll(defaultLinks(it)) - } - return configuration - } - - @JvmStatic - fun main(args: Array<String>) { - val configuration = createConfiguration(args) - - if (configuration.format.toLowerCase() == "javadoc") - startWithToolsJar(configuration) - else - entry(configuration) - } } - - +fun main(args: Array<String>) { + val globalArguments = GlobalArguments(args) + val configuration = if (globalArguments.json != null) + Gson().fromJson( + Paths.get(globalArguments.json).toFile().readText(), + DokkaConfigurationImpl::class.java + ) + else + globalArguments + DokkaGenerator(configuration, DokkaConsoleLogger).generate() +}
\ No newline at end of file |