diff options
-rw-r--r-- | runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt | 226 | ||||
-rw-r--r-- | runners/cli/src/main/kotlin/cli/main.kt | 376 |
2 files changed, 363 insertions, 239 deletions
diff --git a/runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt b/runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt new file mode 100644 index 00000000..dd4d6377 --- /dev/null +++ b/runners/cli/src/main/kotlin/cli/DokkaArgumentsParser.kt @@ -0,0 +1,226 @@ +package org.jetbrains.dokka + +import kotlinx.cli.* +import kotlin.reflect.KProperty +class ParseContext(val cli: CommandLineInterface = CommandLineInterface("dokka")) { + private val map = mutableMapOf<KProperty<*>, (String) -> Unit>() + private val flagActions = mutableMapOf<KProperty<*>, () -> Unit>() + + fun registerFlagAction( + keys: List<String>, + help: String, + invoke: () -> Unit, + property: KProperty<*> + ) { + if (property !in flagActions.keys) { + cli.flagAction(keys, help) { + flagActions[property]!!() + } + } + flagActions[property] = invoke + + } + + fun registerSingleAction( + keys: List<String>, + help: String, + invoke: (String) -> Unit, + property: KProperty<*> + ) { + if (property !in map.keys) { + cli.singleAction(keys, help) { + map[property]!!(it) + } + } + map[property] = invoke + } + + fun registerRepeatableAction( + keys: List<String>, + help: String, + invoke: (String) -> Unit, + property: KProperty<*> + ) { + if (property !in map.keys) { + cli.repeatingAction(keys, help) { + map[property]!!(it) + } + } + map[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) { + fun <T> parseInto(constructor: (parseContext: DokkaArgumentsParser) -> T): T { + val res = constructor(this) + parseContext.parse(args) + return res + } + + fun <T> repeatableOption( + keys: List<String>, + help: String, + transform: (String) -> T + ): OptionDelegate<MutableList<T>> { + val list = mutableListOf<T>() + return object : OptionDelegate<MutableList<T>>(list) { + override fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate<MutableList<T>> { + parseContext.registerRepeatableAction( + keys, + help, + { + list.add(transform(it)) + }, + property + + ) + return this + } + } + } + + fun <T> repeatableFlag( + keys: List<String>, + help: String, + initElement: (ParseContext) -> T + ): OptionDelegate<MutableList<T>> { + val list = mutableListOf<T>() + return object : OptionDelegate<MutableList<T>>(list) { + override fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate<MutableList<T>> { + parseContext.registerFlagAction( + keys, + help, + { + list.add(initElement(parseContext)) + }, + property + + ) + return this + } + } + } + + fun <T> singleFlag( + keys: List<String>, + help: String, + initElement: (ParseContext) -> T, + transform: () -> T + ): OptionDelegate<T> { + val element = initElement(parseContext) + return object : OptionDelegate<T>(element) { + override fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate<T> { + parseContext.registerFlagAction( + keys, + help, + { + value = transform() + }, + property + ) + + return this + } + } + + } + + fun <T> singleOption( + keys: List<String>, + help: String, + transform: ((String) -> T)? = null, + initElement: (ParseContext) -> T + ): OptionDelegate<T> { + val element: T = initElement(parseContext) + return object : OptionDelegate<T>(element) { + + override fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate<T> { + parseContext.registerSingleAction( + keys, + help, + { + val toAdd = if (transform != null) { + transform(it) + } else { + it as T + } + value = toAdd + }, + property + ) + + return this + } + } + } + + fun singleBooleanFlag( + keys: List<String>, + help: String + ) = singleFlag(keys, help, { false }, { true }) + + fun <T> defaultSingleOption( + keys: List<String>, + help: String, + defaultValue: T + ) = singleOption( + keys, + help, + { it as T }, + { defaultValue } + ) +} + +abstract class OptionDelegate<T>(var value: T) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value + abstract operator fun provideDelegate(thisRef: Any, property: KProperty<*>): OptionDelegate<T> +} diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 85826fe0..34d86257 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -1,6 +1,5 @@ package org.jetbrains.dokka -import kotlinx.cli.* import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink import java.io.File @@ -8,247 +7,144 @@ import java.net.MalformedURLException import java.net.URL import java.net.URLClassLoader -data class Arguments( - override var moduleName: String = "", - override var classpath: MutableList<String> = mutableListOf(), - override var sourceRoots: MutableList<DokkaConfiguration.SourceRoot> = mutableListOf(), - override var samples: MutableList<String> = mutableListOf(), - override var includes: MutableList<String> = mutableListOf(), - override var includeNonPublic: Boolean = false, - override var includeRootPackage: Boolean = false, - override var reportUndocumented: Boolean = false, - override var skipEmptyPackages: Boolean = false, - override var skipDeprecated: Boolean = false, - override var jdkVersion: Int = 6, - override var sourceLinks: List<DokkaConfiguration.SourceLinkDefinition> = listOf(), - override var perPackageOptions: List<DokkaConfiguration.PackageOptions> = listOf(), - override var externalDocumentationLinks: List<DokkaConfiguration.ExternalDocumentationLink> = listOf(), - override var languageVersion: String? = "", - override var apiVersion: String? = "", - override var noStdlibLink: Boolean = false, - override var noJdkLink: Boolean = false, - override var suppressedFiles: MutableList<String> = mutableListOf(), - override var collectInheritedExtensionsFromLibraries: Boolean = false, - override var analysisPlatform: Platform = Platform.DEFAULT, - override var targets: MutableList<String> = mutableListOf(), - var rawPerPackageOptions: MutableList<String> = mutableListOf() -) : DokkaConfiguration.PassConfiguration - - -data class GlobalArguments( - override var outputDir: String = "", - override var format: String = "", - override var generateIndexPages: Boolean = false, - override var cacheRoot: String? = null, - override var passesConfigurations: List<Arguments> = listOf(), - override var impliedPlatforms: MutableList<String> = mutableListOf() -) : DokkaConfiguration - -class DokkaArgumentsParser { - companion object { - fun CommandLineInterface.registerSingleAction( - 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.registerRepeatingAction( - 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@registerRepeatingAction.getFlagAction(message) != null) { - arguments.previous() - break - } - invoke(message) - } - - } - - override fun invoke() { - error("should be never called") - } - } - - ) - - } - - val cli = CommandLineInterface("dokka") - val globalArguments = GlobalArguments() - - init { - cli.flagAction( - listOf("-pass"), - "Single dokka pass" - ) { - globalArguments.passesConfigurations += Arguments() - } - - cli.registerRepeatingAction( - listOf("-src"), - "Source file or directory (allows many paths separated by the system path separator)" - ) { - globalArguments.passesConfigurations.last().sourceRoots.add(SourceRootImpl.parseSourceRoot(it)) - } - - cli.registerRepeatingAction( - listOf("-srcLink"), - "Mapping between a source directory and a Web site for browsing the code" - ) { - println(it) - } - - cli.registerRepeatingAction( - listOf("-include"), - "Markdown files to load (allows many paths separated by the system path separator)" - ) { - globalArguments.passesConfigurations.last().includes.add(it) - } - - cli.registerRepeatingAction( - listOf("-samples"), - "Source root for samples" - ) { - globalArguments.passesConfigurations.last().samples.add(it) - } - - cli.registerSingleAction( - listOf("-output"), - "Output directory path" - ) { - globalArguments.outputDir = it - } - - cli.registerSingleAction( - listOf("-format"), - "Output format (text, html, markdown, jekyll, kotlin-website)" - ) { - globalArguments.format = it - } - - cli.registerSingleAction( - listOf("-module"), - "Name of the documentation module" - ) { - globalArguments.passesConfigurations.last().moduleName = it - } - - cli.registerRepeatingAction( - listOf("-classpath"), - "Classpath for symbol resolution" - ) { - globalArguments.passesConfigurations.last().classpath.add(it) - } - - cli.flagAction( - listOf("-nodeprecacted"), - "Exclude deprecated members from documentation" - ) { - globalArguments.passesConfigurations.last().skipDeprecated = true - } - - cli.registerSingleAction( - listOf("jdkVersion"), - "Version of JDK to use for linking to JDK JavaDoc" - ) { - globalArguments.passesConfigurations.last().jdkVersion = Integer.parseInt(it) - } - - cli.registerRepeatingAction( - listOf("-impliedPlatforms"), - "List of implied platforms (comma-separated)" - ) { - globalArguments.impliedPlatforms.add(it) - } - - cli.registerSingleAction( - listOf("-pckageOptions"), - "List of package passConfiguration in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" " - ) { - globalArguments.passesConfigurations.last().perPackageOptions = parsePerPackageOptions(it) - } - - cli.registerSingleAction( - listOf("links"), - "External documentation links in format url^packageListUrl^^url2..." - ) { - globalArguments.passesConfigurations.last().externalDocumentationLinks = MainKt.parseLinks(it) - } - - cli.flagAction( - listOf("-noStdlibLink"), - "Disable documentation link to stdlib" - ) { - globalArguments.passesConfigurations.last().noStdlibLink = true - } - - cli.flagAction( - listOf("-noJdkLink"), - "Disable documentation link to jdk" - ) { - globalArguments.passesConfigurations.last().noJdkLink = true - } - - cli.registerSingleAction( - listOf("-cacheRoot"), - "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled" - ) { - globalArguments.cacheRoot = it - } - - cli.registerSingleAction( - listOf("-languageVersion"), - "Language Version to pass to Kotlin Analysis" - ) { - globalArguments.passesConfigurations.last().languageVersion = it - } - - cli.registerSingleAction( - listOf("-apiVesion"), - "Kotlin Api Version to pass to Kotlin Analysis" - ) { - globalArguments.passesConfigurations.last().apiVersion = it - } - - cli.flagAction( - listOf("-collectInheritedExtensionsFromLibraries"), - "Search for applicable extensions in libraries" - ) { - globalArguments.passesConfigurations.last().collectInheritedExtensionsFromLibraries = true - } - +open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { + override val outputDir: String by parser.defaultSingleOption( + listOf("-output"), + "Output directory path", + "") + + override val format: String by parser.defaultSingleOption( + listOf("-format"), + "Output format (text, html, markdown, jekyll, kotlin-website)", + "") + + override val generateIndexPages: Boolean by parser.singleBooleanFlag( + listOf("-generateIndexPages"), + "Generate index page" + ) + + override val cacheRoot: String? by parser.defaultSingleOption( + listOf("-cacheRoot"), + "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled", + null) + + override val impliedPlatforms: List<String> by parser.repeatableOption( + listOf("-impliedPlatforms"), + "List of implied platforms (comma-separated)" + ) { it } + + override val passesConfigurations: List<Arguments> by parser.repeatableFlag( + listOf("-pass"), + "Single dokka pass" + ) { + Arguments(parser) } +} - fun parse(args: Array<String>): DokkaConfiguration { - cli.parseArgs(*args) - - return globalArguments - } +class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfiguration { + override val moduleName: String by parser.defaultSingleOption( + listOf("-module"), + "Name of the documentation module", + "") + + override val classpath: List<String> by parser.repeatableOption( + listOf("-classpath"), + "Classpath for symbol resolution" + ) { it } + + 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.parseSourceRoot(it) } + + override val samples: List<String> by parser.repeatableOption( + listOf("-samples"), + "Source root for samples" + ) { it } + + override val includes: List<String> by parser.repeatableOption( + listOf("-include"), + "Markdown files to load (allows many paths separated by the system path separator)" + ) { it } + + override val includeNonPublic: Boolean by parser.singleBooleanFlag( + listOf("-includeNonPublic"), + "Include non public") + + override val includeRootPackage: Boolean by parser.singleBooleanFlag( + listOf("-includeRootPackage"), + "Include non public") + + override val reportUndocumented: Boolean by parser.singleBooleanFlag( + listOf("-reportUndocumented"), + "Include non public") + + override val skipEmptyPackages: Boolean by parser.singleBooleanFlag( + listOf("-skipEmptyPackages"), + "Include non public") + + override val skipDeprecated: Boolean by parser.singleBooleanFlag( + listOf("-skipDeprecated"), + "Include non public") + + override val jdkVersion: Int by parser.singleOption( + listOf("jdkVersion"), + "Version of JDK to use for linking to JDK JavaDoc", + { it.toInt() }, + { 6 } + ) + + override val languageVersion: String? by parser.defaultSingleOption( + listOf("-languageVersion"), + "Language Version to pass to Kotlin Analysis", + null) + + override val apiVersion: String? by parser.defaultSingleOption( + listOf("-apiVesion"), + "Kotlin Api Version to pass to Kotlin Analysis", + null + ) + + override val noStdlibLink: Boolean by parser.singleBooleanFlag( + listOf("-noStdlibLink"), + "Disable documentation link to stdlib") + + override val noJdkLink: Boolean by parser.singleBooleanFlag( + listOf("-noJdkLink"), + "Disable documentation link to stdlib") + + override val suppressedFiles: List<String> by parser.repeatableOption( + listOf("-suppresedFiles"), + "", + { it } + ) + + override val collectInheritedExtensionsFromLibraries: Boolean by parser.singleBooleanFlag( + listOf("-collectInheritedExtensionsFromLibraries"), + "Search for applicable extensions in libraries") + + override val analysisPlatform: Platform by parser.singleOption( + listOf("-analysisPlatform"), + "Platform for analysis", + { Platform.fromString(it) }, + { Platform.DEFAULT } + ) + + override val targets: List<String> by parser.repeatableOption( + listOf("-targets"), + "Generation targets", + { it } + ) + + override val sourceLinks: List<DokkaConfiguration.SourceLinkDefinition> + get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + override val perPackageOptions: List<DokkaConfiguration.PackageOptions> + get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + override val externalDocumentationLinks: List<DokkaConfiguration.ExternalDocumentationLink> + get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. } object MainKt { - fun parseLinks(links: String): List<ExternalDocumentationLink> { val (parsedLinks, parsedOfflineLinks) = links.split("^^") .map { it.split("^").map { it.trim() }.filter { it.isNotBlank() } } @@ -312,8 +208,10 @@ object MainKt { fun main(args: Array<String>) { - val dokkaArgumentsParser = DokkaArgumentsParser() - val configuration = dokkaArgumentsParser.parse(args) + val parser = DokkaArgumentsParser(args, ParseContext()) + val parseContext = parser.parseInto(::GlobalArguments) + + val configuration = parseContext if (configuration.format == "javadoc") startWithToolsJar(configuration) |