Refactoring, kleine Verbesserungen, Aufräumarbeiten

This commit is contained in:
Hartmut Bauer committed 2026-01-19 22:16:01 +01:00
1 parent 66244db097
commit 561fe601a9
16 files changed
+255 -142

No files matched your search

+18 -4
View File
@@ -1,5 +1,19 @@
# Ignore Gradle project-specific cache directory *.iml
.kotlin
.gradle .gradle
**/build/
# Ignore Gradle build output directory xcuserdata
build !src/**/build/
local.properties
.idea
.DS_Store
captures
.externalNativeBuild
.cxx
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
node_modules/
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-js-0.3.0-beta.11">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-js-0.3.0-beta.11.jar">
<element id="module-output" name="util.jsMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-js-0.3.0-beta.8">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-js-0.3.0-beta.8.jar">
<element id="module-output" name="util.jsMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-jvm-0.3.0-beta.11">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-jvm-0.3.0-beta.11.jar">
<element id="module-output" name="util.jvmMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-jvm-0.3.0-beta.8">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-jvm-0.3.0-beta.8.jar">
<element id="module-output" name="util.jvmMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-wasm-js-0.3.0-beta.11">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-wasm-js-0.3.0-beta.11.jar">
<element id="module-output" name="util.wasmJsMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-wasm-js-0.3.0-beta.8">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-wasm-js-0.3.0-beta.8.jar">
<element id="module-output" name="util.wasmJsMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-wasm-wasi-0.3.0-beta.11">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-wasm-wasi-0.3.0-beta.11.jar">
<element id="module-output" name="util.wasmWasiMain" />
</root>
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="util-wasm-wasi-0.3.0-beta.8">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="util-wasm-wasi-0.3.0-beta.8.jar">
<element id="module-output" name="util.wasmWasiMain" />
</root>
</artifact>
</component>
+2 -2
View File
@@ -1,3 +1,3 @@
#auto generated #auto generated
#Mon Jan 19 01:08:01 CET 2026 #Mon Jan 19 21:39:57 CET 2026
build.number=117 build.number=129
+6 -1
View File
@@ -1,3 +1,8 @@
#Kotlin
kotlin.code.style=official kotlin.code.style=official
org.gradle.configuration-cache=true kotlin.daemon.jvmargs=-Xmx3072M
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
#Gradle
org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8
org.gradle.configuration-cache=true
org.gradle.caching=true
+1 -1
View File
@@ -19,7 +19,7 @@ dependencyResolutionManagement {
versionCatalogs { versionCatalogs {
create("masterLibs") { create("masterLibs") {
// from(files("gradle/masterlibs.versions.toml")) // from(files("gradle/masterlibs.versions.toml"))
from("net.keinekekse:version-catalog:116") from("net.keinekekse:version-catalog:127")
} }
} }
} }
+155 -103
View File
@@ -32,13 +32,13 @@ class VerifyParameterException(message: String) : RuntimeException(message)
* This function is used to signal that there was an error during argument parsing. * This function is used to signal that there was an error during argument parsing.
* *
* For use in the application. The exception will be caught by the command-line parser * For use in the application. The exception will be caught by the command-line parser
* and displayed to the user via showHelp(). * and displayed to the user together with the help information.
* *
* @param msg The error message to include in the exception. * @param msg The error message to include in the exception.
* @throws VerifyParameterException with the provided error message. * @throws VerifyParameterException with the provided error message.
*/ */
fun showParsingError(msg: String): Nothing { fun showParsingError(msg: String): Nothing {
throw VerifyParameterException("*** ERROR parsing arguments: $msg") throw VerifyParameterException(msg)
} }
/** /**
@@ -117,37 +117,44 @@ class SubCommand private constructor(
description: String, description: String,
isMandatory: Boolean, isMandatory: Boolean,
): ParameterValue<T> { ): ParameterValue<T> {
val result = runCatching { val processedLong = long.handleCase(ignoreCase)
val long = long.handleCase(ignoreCase) val processedShort = short?.toString()?.handleCase(ignoreCase)
val short = short?.toString()?.handleCase(ignoreCase)
type.createOption(long, short, description, isMandatory).apply {
verifyParameter(this)
@Suppress("UNCHECKED_CAST") return runCatching {
obj.params[long] = this as ParameterData<Any> type.createOption(processedLong, processedShort, description, isMandatory).apply {
short?.let { verifyParameter(this)
obj.params[it] = this registerParameter(this, processedLong, processedShort)
}
}.prop }.prop
} }.getOrElse { showDefiningError(it.message ?: "") }
return result.getOrElse { showDefiningError(it.message ?: "") } }
private fun registerParameter(parameter: ParameterData<*>, long: String, short: String?) {
@Suppress("UNCHECKED_CAST")
val data = parameter as ParameterData<Any>
obj.params[long] = data
short?.let { obj.params[it] = data }
} }
private fun verifyParameter(parameter: ParameterData<*>) { private fun verifyParameter(parameter: ParameterData<*>) {
if (!NAME_PATTERN.matches(parameter.long)) throw ArgumentParserException.invalidName( val longName = parameter.long
parameter.long if (!NAME_PATTERN.matches(longName)) {
) throw ArgumentParserException.invalidName(longName)
if (obj.params.containsKey(parameter.long)) throw ArgumentParserException.optionExists(
parameter.long
)
parameter.short?.let {
if (!SHORT_NAME_PATTERN.matches(it)) {
throw ArgumentParserException.invalidShortName(it)
}
if (obj.params.containsKey(it)) throw ArgumentParserException.optionExists(it)
} }
val n = parameter.long.lowercase() if (obj.params.containsKey(longName)) {
if (n == "help" || n == "version") { throw ArgumentParserException.optionExists(longName)
}
parameter.short?.let { shortName ->
if (!SHORT_NAME_PATTERN.matches(shortName)) {
throw ArgumentParserException.invalidShortName(shortName)
}
if (obj.params.containsKey(shortName)) {
throw ArgumentParserException.optionExists(shortName)
}
}
val lowerLong = longName.lowercase()
if (lowerLong == "help" || lowerLong == "version") {
throw ArgumentParserException.noHelpOrVersion() throw ArgumentParserException.noHelpOrVersion()
} }
@@ -166,12 +173,60 @@ class SubCommand private constructor(
* @param programVersion The version information of the program, including display name and copyright. * @param programVersion The version information of the program, including display name and copyright.
* @param ignoreCase Determines whether the parsing should ignore case sensitivity for commands and parameters. * @param ignoreCase Determines whether the parsing should ignore case sensitivity for commands and parameters.
* @param remainingDescription The description for remaining command-line arguments, or null if no arguments are allowed. * @param remainingDescription The description for remaining command-line arguments, or null if no arguments are allowed.
* @param emptyCommandLineAllowed Indicates whether the parser should allow an empty command line to be parsed. Defaults to false.
*
* ```
* // global parameters
*
* val commandLine = CommandLine(
* programVersion = VERSION,
* remainingDescription = "EPUB-Dateien",
* ignoreCase = true,
* )
*
* val param1 by commandLine.addStringParameter(
* long = "param",
* short = 'P',
* description = "parameter description"
* )
* // more global parameters
*
* commandLine.setExecution { additionalParameters: List<String> ->
* // called when no subcommand is specified
* }
*
* // subcommand
*
* val commandSubCommand = commandLine.addSubCommand(
* "command",
* "My custom command",
* listOf("cmd") // aliases
* )
*
* val par1 by commandSubCommand.addStringParameter(
* long = "par1",
* description = "Parameter Par1 ",
* isMandatory = true
* )
* // more parameters
*
* commandSubCommand.setExecution { additionalParameters ->
* // called when this subcommand is found in the command line
* }
*
* // more subcommands
*
* // start program
* commandLine.parseAndRun(*args)
* ```
*/ */
class CommandLine( class CommandLine(
val programVersion: Version, val programVersion: Version,
val ignoreCase: Boolean = false, val ignoreCase: Boolean = false,
val remainingDescription: String? = null, // null -> no remaining allowed val remainingDescription: String? = null, // null -> no remaining allowed
val emptyCommandLineAllowed: Boolean = false,
) : AddParameter { ) : AddParameter {
private var hasRun = false
private val globalSubCommand = SubCommand.create(SubCommandData(), ignoreCase) private val globalSubCommand = SubCommand.create(SubCommandData(), ignoreCase)
private var subCommands = mutableMapOf<String, SubCommandData>() private var subCommands = mutableMapOf<String, SubCommandData>()
@@ -210,68 +265,68 @@ class CommandLine(
name: String, name: String,
description: String, description: String,
aliases: List<String> = emptyList(), aliases: List<String> = emptyList(),
): SubCommand { ): SubCommand = runCatching {
val result = runCatching { val normalizedName = normalizeAndVerifySubCommand(name, ignoreCase)
val name = verifySubCommand(name, ignoreCase) val subData = SubCommandData(normalizedName, description, aliases)
val subData = SubCommandData(name, description, aliases) subCommands[normalizedName] = subData
subCommands[name] = subData aliases.forEach { alias ->
aliases.forEach { alias -> val alias = normalizeAndVerifySubCommand(alias, ignoreCase)
val alias = verifySubCommand(alias, ignoreCase) subCommands[alias] = subData
subCommands[alias] = subData
}
SubCommand.create(subData, ignoreCase)
} }
return result.getOrElse { showDefiningError(it.message ?: "") } SubCommand.create(subData, ignoreCase)
} }.getOrElse { showDefiningError(it.message ?: "") }
fun parseAndRun(vararg args: String) { fun parseAndRun(vararg args: String) {
val result = runCatching { runCatching {
val selectedSubCommand = parse(args.toList()) val selectedSubCommand = parse(args.toList())
selectedSubCommand.execute(selectedSubCommand.additionalParameters) selectedSubCommand.execute(selectedSubCommand.additionalParameters)
}.onFailure { exception ->
handleErrorAndShowHelp(exception as Exception)
} }
result.exceptionOrNull()?.let { showHelp(it as Exception) }
} }
private fun verifySubCommand(cmd: String, ignoreCase: Boolean): String { private fun normalizeAndVerifySubCommand(cmd: String, ignoreCase: Boolean): String {
val cmd = cmd.handleCase(ignoreCase) val normalized = cmd.handleCase(ignoreCase)
if (!matchSubCommand(cmd)) throw ArgumentParserException.invalidCommand(cmd) if (!matchSubCommand(normalized)) throw ArgumentParserException.invalidCommand(normalized)
return cmd return normalized
} }
private fun parse(args: List<String>): SubCommandData { private fun parse(args: List<String>): SubCommandData {
if (args.isEmpty()) { if (hasRun) throw ArgumentParserException.noMoreParsing()
throw ArgumentParserException.commandRequired() hasRun = true
} if (args.isEmpty() && !emptyCommandLineAllowed) throw ArgumentParserException.commandRequired()
checkExecutors() checkExecutors()
val remaining = parseParameters(args, globalSubCommand.obj) val remainingAfterGlobal = parseParameters(args, globalSubCommand.obj)
validateMandatoryParameters(globalSubCommand.obj) validateMandatoryParameters(globalSubCommand.obj)
val resultSubCommand = parseSubCommand(remaining) val resultSubCommand = parseSubCommand(remainingAfterGlobal)
validateMandatoryParameters(resultSubCommand) validateMandatoryParameters(resultSubCommand)
if (remainingDescription != null) { if (remainingDescription != null) {
val additionalFromPipe = getRemainingParametersFromPipe() resultSubCommand.additionalParameters += resolveRemainingFromPipe()
if (additionalFromPipe.isNotEmpty()) {
resultSubCommand.additionalParameters += additionalFromPipe
}
} else if (resultSubCommand.additionalParameters.isNotEmpty()) { } else if (resultSubCommand.additionalParameters.isNotEmpty()) {
throw ArgumentParserException.noMoreOptions() throw ArgumentParserException.noMoreOptions()
} }
return resultSubCommand return resultSubCommand
} }
private fun resolveRemainingFromPipe(): List<String> {
return if (isStdInputReady()) getRemainingParametersFromPipe() else emptyList()
}
private fun parseSubCommand(args: List<String>): SubCommandData { private fun parseSubCommand(args: List<String>): SubCommandData {
val sub = args.firstOrNull()?.handleCase(ignoreCase)?.let { subCommands[it] } val firstArg = args.firstOrNull()?.handleCase(ignoreCase)
?: return globalSubCommand.obj.apply { additionalParameters = args } val sub = subCommands[firstArg] ?: return globalSubCommand.obj.apply {
additionalParameters = args
}
return sub.apply { additionalParameters = parseParameters(args.drop(1), this) } return sub.apply { additionalParameters = parseParameters(args.drop(1), this) }
} }
private fun validateMandatoryParameters(subCommand: SubCommandData) { private fun validateMandatoryParameters(subCommand: SubCommandData) {
subCommand.params.forEach { (_, parameter) -> subCommand.params.filter { it.key == it.value.long }.forEach { (_, parameter) ->
if (parameter.isMandatory && parameter.prop.value == null) { if (parameter.isMandatory && parameter.prop.value == null) {
throw ArgumentParserException.optionRequiresValue(parameter.long) throw ArgumentParserException.optionRequired(parameter.long)
} }
} }
} }
@@ -279,17 +334,23 @@ class CommandLine(
private fun parseParameters(args: List<String>, subCommand: SubCommandData): List<String> { private fun parseParameters(args: List<String>, subCommand: SubCommandData): List<String> {
var index = 0 var index = 0
while (index < args.size) { while (index < args.size) {
val parseResult = matchArgument(args[index]) ?: return args.drop(index) val (key, inlineValue) = matchArgument(args[index]) ?: return args.drop(index)
var (key, inlineValue) = parseResult
checkForHelpOrVersion(key) checkForHelpOrVersion(key)
key = key.handleCase(ignoreCase) val normalizedKey = key.handleCase(ignoreCase)
val param =
subCommand.params[normalizedKey] ?: throw ArgumentParserException.unknownOption(
normalizedKey
)
val param = subCommand.params[key] ?: throw ArgumentParserException.unknownOption(key) val (value, consumedExtra) = resolveParameterValue(
args,
val (value, consumedExtra) = resolveParameterValue(args, index, key, inlineValue, param) index,
normalizedKey,
inlineValue,
param
)
param.type.convertAndSet(value, param.prop) param.type.convertAndSet(value, param.prop)
index += 1 + consumedExtra index += 1 + consumedExtra
} }
return emptyList() return emptyList()
@@ -312,7 +373,9 @@ class CommandLine(
inlineValue.isNotBlank() -> inlineValue to 0 inlineValue.isNotBlank() -> inlineValue to 0
// --name --irgendwas ist nicht OK // --name --irgendwas ist nicht OK
currentIndex < args.size - 1 && !ARGUMENT_PATTERN.matches(args[currentIndex + 1]) -> { currentIndex < args.size - 1
&& !ARGUMENT_PATTERN.matches(args[currentIndex + 1])
&& args[currentIndex + 1].isNotBlank() -> {
args[currentIndex + 1] to 1 args[currentIndex + 1] to 1
} }
@@ -322,12 +385,11 @@ class CommandLine(
private fun getRemainingParametersFromPipe(): List<String> { private fun getRemainingParametersFromPipe(): List<String> {
if (isStdInputReady()) { if (isStdInputReady()) {
var input: String?
val pipe = mutableListOf<String>() val pipe = mutableListOf<String>()
do { while (true) {
input = readlnOrNull() val input = readlnOrNull() ?: break
input?.let { pipe.add(it) } pipe.add(input)
} while (!input.isNullOrEmpty()) }
return pipe return pipe
} }
return emptyList() return emptyList()
@@ -347,37 +409,28 @@ class CommandLine(
} }
} }
private fun showHelp( private fun handleErrorAndShowHelp(
e: Exception?, e: Exception?,
): Nothing { ): Nothing {
val sub = !subCommands.isEmpty() val hasSubCommands = subCommands.isNotEmpty()
val globalParam = globalSubCommand.obj.params.isNotEmpty() val hasGlobalParams = globalSubCommand.obj.params.isNotEmpty()
val remain = remainingDescription != null val allowsRemaining = remainingDescription != null
println("\n${programVersion.displayName} ${programVersion.version} ${programVersion.copyright}\n") println("\n${programVersion.displayName} ${programVersion.version} ${programVersion.copyright}\n")
println(programVersion.description) println("${programVersion.description}\n")
println()
println( val usagePrefix = "usage: ${programVersion.name}"
"usage: ${programVersion.name} ${ val globalPart =
if (sub) if (hasGlobalParams) "[${if (hasSubCommands) "GLOBAL " else ""}PARAMETER]" else ""
if (globalParam) { val subPart = if (hasSubCommands) " subcommand [PARAMETER]" else ""
"[GLOBAL PARAMETER]" val remainPart = if (allowsRemaining) " <$remainingDescription>" else ""
} else {
"" println("$usagePrefix $globalPart$subPart$remainPart\n")
} + " subcommand [PARAMETER]" if (hasGlobalParams) {
else "[PARAMETER]" println("${if (hasSubCommands) "Global " else ""}Parameters:")
} ${if (remain) "<$remainingDescription>" else ""}"
)
println()
if (globalParam) {
if (sub) {
println("Global Parameters:")
} else {
println("Parameters:")
}
} }
showParameters(globalSubCommand.obj.params) showParameters(globalSubCommand.obj.params)
if (sub) { if (hasSubCommands) {
println() println()
println("Subcommands:") println("Subcommands:")
showSubcommands(subCommands) showSubcommands(subCommands)
@@ -400,21 +453,20 @@ class CommandLine(
println("$INDENT${param.name}$aliases ${param.description}") println("$INDENT${param.name}$aliases ${param.description}")
showParameters(param.params) showParameters(param.params)
println() println()
} }
} }
private fun showParameters(parameters: MutableMap<String, ParameterData<Any>>) { private fun showParameters(parameters: MutableMap<String, ParameterData<Any>>) {
var len = 0 var len = 0
parameters.filter { it.key == it.value.long }.map { (_, param) -> parameters.filter { it.key == it.value.long }.map { (_, param) ->
len = maxOf(len, param.long.length + INDENT.length * 2 + 4 + 2) val parmStr = INDENT + INDENT +
Pair(INDENT + INDENT + (param.short?.let { "-$it, " } ?: " ") + "--${param.long}", (param.short?.let { "-$it, " } ?: " ") +
"${param.description} ${if (param.isMandatory) "*" else ""}") "--${param.long}" + if (param.type != ParameterType.BOOLEAN) " <...>" else ""
len = maxOf(len, parmStr.length)
Pair(parmStr, "${param.description} ${if (param.isMandatory) "*" else ""}")
}.forEach { }.forEach {
println(it.first.padEnd(len + 3) + it.second) println(it.first.padEnd(len + 3) + it.second)
} }
} }
private fun showVersion(): Nothing { private fun showVersion(): Nothing {
@@ -157,42 +157,23 @@ internal class ArgumentParserException(message: String?) : RuntimeException(mess
fun noHelpOrVersion() = fun noHelpOrVersion() =
ArgumentParserException("Option 'help' and option 'version' are not allowed.") ArgumentParserException("Option 'help' and option 'version' are not allowed.")
fun noParametersDefined() = ArgumentParserException("No parameters found for command line.")
fun noExecutorDefinedGlobal() = ArgumentParserException("No lambda found for command line.")
fun noExecutorDefined(name: String?) = fun noExecutorDefined(name: String?) =
ArgumentParserException("No lambda found for '$name'.") ArgumentParserException("No lambda found for '$name'.")
fun optionExists(name: String) = ArgumentParserException("Option '$name' already exists.") fun optionExists(name: String) = ArgumentParserException("Option '$name' already exists.")
fun invalidAnnotationTargetParameter(name: String) =
ArgumentParserException("Annotation @CmdLineParameter can only be used on mutable properties, '$name' isn't a mutable property.")
fun notNullableAnnotationTargetParameter(name: String) =
ArgumentParserException("Annotation @CmdLineParameter can only be used on nullable properties, '$name' isn't a nullable property.")
fun invalidAnnotationTargetOption() =
ArgumentParserException("Annotation @CmdLineOption can only be used on CommandLine Objects.")
fun optionNameRequired() = ArgumentParserException("Option name is required.")
fun unknownOption(name: String) = ArgumentParserException("Unknown option '$name'.") fun unknownOption(name: String) = ArgumentParserException("Unknown option '$name'.")
fun unknownCommand(name: String) = ArgumentParserException("Unknown command '$name'.")
fun optionRequiresValue(name: String) = fun optionRequiresValue(name: String) =
ArgumentParserException("Option '$name' requires a value.") ArgumentParserException("Option '$name' requires a value.")
fun optionNoValue(name: String) = fun optionNoValue(name: String) =
ArgumentParserException("Option '$name' does not accept a value.") ArgumentParserException("Option '$name' does not accept a value.")
fun booleanNotMandatory(name: String) =
ArgumentParserException("Boolean option '$name' can not be mandatory.")
fun optionRequired(name: String) = ArgumentParserException("Option '$name' is required.") fun optionRequired(name: String) = ArgumentParserException("Option '$name' is required.")
fun commandRequired() = ArgumentParserException("At least one command is required.") fun commandRequired() = ArgumentParserException("At least one command is required.")
fun invalidLongValue(value: String) = fun invalidLongValue(value: String) =
ArgumentParserException("Value '$value' is not a long integer.") ArgumentParserException("Value '$value' is not a long integer.")
fun invalidType(name: String, type: String) =
ArgumentParserException("Unsupported parameter type: ${type} for parameter $name")
fun invalidShortName(name: String) = fun invalidShortName(name: String) =
ArgumentParserException("Option short name '$name' is invalid.") ArgumentParserException("Option short name '$name' is invalid.")
@@ -210,7 +191,7 @@ internal const val TRUE = "true"
internal const val NAME = """[a-zA-Z][\w-]+""" internal const val NAME = """[a-zA-Z][\w-]+"""
internal const val SHORT_NAME = """[a-zA-Z]""" internal const val SHORT_NAME = """[a-zA-Z]"""
internal val ARGUMENT_PATTERN = """^(?:-(${SHORT_NAME})|--(${NAME}))(?:=(.+)|$)$""".toRegex() internal val ARGUMENT_PATTERN = """^(?:-(${SHORT_NAME})|--(${NAME}))(?:[=:](.*)|$)$""".toRegex()
internal val NAME_PATTERN = """^${NAME}$""".toRegex() internal val NAME_PATTERN = """^${NAME}$""".toRegex()
internal val SHORT_NAME_PATTERN = """^${SHORT_NAME}$""".toRegex() internal val SHORT_NAME_PATTERN = """^${SHORT_NAME}$""".toRegex()
@@ -3,14 +3,14 @@ package net.keinekekse.util
import net.keinekekse.version.Version import net.keinekekse.version.Version
object VERSION: Version { object VERSION: Version {
override val version = "0.3.0-beta.8+build.117" override val version = "0.3.0-beta.19+build.129"
override val fullVersion = "0.3.0-beta.8+build.117" override val fullVersion = "0.3.0-beta.19+build.129"
override val major = 0 override val major = 0
override val minor = 3 override val minor = 3
override val patch = 0 override val patch = 0
override val preRelease = "beta.8" override val preRelease = "beta.19"
override val buildMetadata = "build.117" override val buildMetadata = "build.129"
override val buildDate = "2026-01-19T00:08:01.397532Z" override val buildDate = "2026-01-19T20:39:57.564140Z"
override val displayName = "Utility Library" override val displayName = "Utility Library"
override val copyright = "Copyright (c) 2025-2026 Hartmut Bauer" override val copyright = "Copyright (c) 2025-2026 Hartmut Bauer"
override val name = "util" override val name = "util"
@@ -386,19 +386,16 @@ private fun resolveParameterValue(
args: List<String>, args: List<String>,
currentIndex: Int, currentIndex: Int,
key: String, key: String,
inlineValue: String, parameterValue: String,
param: CmdParameter, param: CmdParameter,
): Pair<String, Int> { ): Pair<String, Int> {
return when { return when {
param.type == ParameterType.BOOLEAN -> { param.type == ParameterType.BOOLEAN -> {
if (inlineValue.isNotBlank()) throw ArgumentParserException.optionNoValue(key) if (parameterValue.isNotBlank()) throw ArgumentParserException.optionNoValue(key)
TRUE to 0 TRUE to 0
} }
// --name=--irgendwas ist OK parameterValue.isNotBlank() -> parameterValue to 0
inlineValue.isNotBlank() -> inlineValue to 0
// --name --irgendwas ist nicht OK
currentIndex < args.size - 1 && !ARGUMENT_PATTERN.matches(args[currentIndex + 1]) -> { currentIndex < args.size - 1 && !ARGUMENT_PATTERN.matches(args[currentIndex + 1]) -> {
args[currentIndex + 1] to 1 args[currentIndex + 1] to 1
} }