package com.infendro.cli.command import com.infendro.cli.argument.Argument import com.infendro.cli.exception.CliException import com.infendro.cli.exception.build.* import com.infendro.cli.exception.run.UnknownCommandException import com.infendro.cli.util.Regex.ARGUMENT_NAME import com.infendro.cli.util.Regex.COMMAND_NAME class Command private constructor( val name: String?, val commands: List, val arguments: List>, private val block: Execution.() -> Unit, ) { fun run(args: Array) = try { val index = args.withIndex() .firstOrNull { (_, value) -> value.startsWith("-") } ?.index ?: args.size val cmd = args.slice(0..() private val arguments = mutableListOf>() private lateinit var block: Execution.() -> Unit private val nextIndex: Int get() = index + 1 fun command(name: String? = null, block: Builder.(Key) -> Unit) { if (name != null && !name.matches(COMMAND_NAME)) throw IllegalCommandNameException(name) if (commands.any { it.name == name }) throw DuplicateCommandException(name) val builder = Builder(nextIndex, name) val key = Key(nextIndex) builder.block(key) val command = builder.build() commands.add(command) } fun argument(argument: Argument<*>) { for (name in argument.names) { if (!name.matches(ARGUMENT_NAME)) throw IllegalArgumentNameException(name) if (arguments.any { name in it.names }) throw DuplicateArgumentException(name) } arguments.add(argument) } fun arguments(vararg arguments: Argument<*>) = arguments.forEach(::argument) fun execute(block: Execution.() -> Unit) { if (this::block.isInitialized) throw DuplicateExecuteException() this.block = block } fun build(): Command { if (!this::block.isInitialized) throw NoExecuteException() return Command(name, commands, arguments, block) } } class Key internal constructor( internal val index: Int, ) } fun cli( block: Command.Builder.() -> Unit, ): Command { val builder = Command.Builder(-1, null) builder.block() return builder.build() }