From 9637ec0747815181d56fa53419d4f6c56705752b Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Tue, 12 May 2020 15:19:53 +0200 Subject: Refactor CLI --- .../src/main/kotlin/cli/DokkaArgumentsParser.kt | 185 ------- runners/cli/src/main/kotlin/cli/main.kt | 584 +++++++++++---------- 2 files changed, 300 insertions(+), 469 deletions(-) delete mode 100644 runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt (limited to 'runners/cli/src/main/kotlin') 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, (String) -> Unit>() - private val flagActions = mutableMapOf, () -> Unit>() - - fun registerFlagAction( - keys: List, - help: String, - property: KProperty<*>, - invoke: () -> Unit - ) { - if (property !in flagActions.keys) { - cli.flagAction(keys, help) { - flagActions[property]!!() - } - } - flagActions[property] = invoke - - } - - fun registerSingleOption( - keys: List, - 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, - 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) { - cli.parseArgs(*args) - } - -} - -fun CommandLineInterface.singleAction( - keys: List, - help: String, - invoke: (String) -> Unit -) = registerAction( - object : FlagActionBase(keys, help) { - override fun invoke(arguments: ListIterator) { - if (arguments.hasNext()) { - val msg = arguments.next() - invoke(msg) - } - } - - override fun invoke() { - error("should be never called") - } - } -) - -fun CommandLineInterface.repeatingAction( - keys: List, - help: String, - invoke: (String) -> Unit -) = registerAction( - object : FlagActionBase(keys, help) { - override fun invoke(arguments: ListIterator) { - 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, val parseContext: ParseContext) { - class OptionDelegate( - var value: T, - private val action: (delegate: OptionDelegate, property: KProperty<*>) -> Unit - ) { - operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value - operator fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate { - action(this, property) - return this - } - } - - fun parseInto(dest: T): T { - // TODO: constructor: (DokkaArgumentsParser) -> T - parseContext.parse(args) - return dest - } - - fun repeatableOption( - keys: List, - help: String, - transform: (String) -> T - ) = OptionDelegate(mutableListOf()) { delegate, property -> - parseContext.registerRepeatableOption(keys, help, property) { - delegate.value.add(transform(it)) - } - } - - fun repeatableOption( - keys: List, - help: String - ) = repeatableOption(keys, help) { it as T } - - fun repeatableFlag( - keys: List, - help: String, - initElement: (ParseContext) -> T - ) = OptionDelegate(mutableListOf()) { delegate, property -> - parseContext.registerFlagAction(keys, help, property) { - delegate.value.add(initElement(parseContext)) - } - } - - fun singleFlag( - keys: List, - help: String, - initElement: (ParseContext) -> T, - transform: () -> T - ) = OptionDelegate(initElement(parseContext)) { delegate, property -> - parseContext.registerFlagAction(keys, help, property) { - delegate.value = transform() - } - } - - fun singleFlag( - keys: List, - help: String - ) = singleFlag(keys, help, { false }, { true }) - - fun stringOption( - keys: List, - help: String, - defaultValue: T - ) = singleOption(keys, help, { it as T }, { defaultValue }) - - fun singleOption( - keys: List, - 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 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) : 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 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 = emptyList() + override val outputDir by parser.option(ArgType.String, description = "Output directory path") + .default("./dokka") - override val pluginsConfiguration: Map = 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 by parser.repeatableOption( - listOf("-classpath"), - "Classpath for symbol resolution" - ) - - override val sourceRoots: List 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 by parser.repeatableOption( - listOf("-dependentSets"), - "Names of dependent source sets" - ) - - override val samples: List by parser.repeatableOption( - listOf("-sample"), - "Source root for samples" - ) - override val includes: List by parser.repeatableOption( - 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 = 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>() + .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>().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>() + .add(SourceLinkDefinitionImpl.parseSourceLinkDefinition(it)) + } + else { + DokkaConsoleLogger.warn("Invalid -srcLink syntax. Expected: =[#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>().addAll(defaultLinks(it)) + } + } +} - override val noJdkLink: Boolean by parser.singleFlag( - listOf("-noJdkLink"), - "Disable documentation link to JDK" +fun passArguments(args: Array): 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 by parser.repeatableOption( - 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 = 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(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(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 by parser.singleOption( - listOf("-packageOptions"), - "List of package passConfiguration in format \"prefix,-deprecated,-privateApi,+reportUndocumented,+suppress;...\" ", - { parsePerPackageOptions(it).toMutableList() }, - { mutableListOf() } - ) +object ArgTypePlugin : ArgType>(true) { + override fun convert(value: kotlin.String, name: kotlin.String): Map = + value.split("^^").map { + it.split("=").let { + it[0] to it[1] + } + }.toMap() - override val externalDocumentationLinks: MutableList 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 by parser.repeatableOption( - 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(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: =[#lineSuffix]. No source links will be generated.") } - } -} -object MainKt { - fun defaultLinks(config: DokkaConfiguration.PassConfiguration): MutableList = - mutableListOf().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 { - 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(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(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 = + mutableListOf().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): 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: =[#lineSuffix]. No source links will be generated.") - } - listOf() +private fun String.toAbsolutePath() = Paths.get(this).toAbsolutePath().toString() + +fun parseLinks(links: List): List { + 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) { - val configuration = createConfiguration(args) - - if (configuration.format.toLowerCase() == "javadoc") - startWithToolsJar(configuration) - else - entry(configuration) - } } - - +fun main(args: Array) { + 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 -- cgit