CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-ajalt--clikt-jvm

Multiplatform command line interface parsing for Kotlin

Pending
Overview
Eval results
Files

parameter-types.mddocs/

Parameter Types

Built-in type converters for common data types including numeric types, enums, choices, and platform-specific types like files and paths.

Capabilities

Numeric Types

Convert parameters to numeric types with optional range restrictions.

/** Convert to Int */
fun RawOption.int(): NullableOption<Int, Int>
fun RawArgument.int(): ProcessedArgument<Int, Int>

/** Convert to Long */
fun RawOption.long(): NullableOption<Long, Long>
fun RawArgument.long(): ProcessedArgument<Long, Long>

/** Convert to Float */
fun RawOption.float(): NullableOption<Float, Float>
fun RawArgument.float(): ProcessedArgument<Float, Float>

/** Convert to Double */
fun RawOption.double(): NullableOption<Double, Double>
fun RawArgument.double(): ProcessedArgument<Double, Double>

/** Convert to UInt (unsigned integer) */
fun RawOption.uint(): NullableOption<UInt, UInt>
fun RawArgument.uint(): ProcessedArgument<UInt, UInt>

/** Convert to ULong (unsigned long) */
fun RawOption.ulong(): NullableOption<ULong, ULong>
fun RawArgument.ulong(): ProcessedArgument<ULong, ULong>

Usage Examples:

class MyCommand : CliktCommand() {
    // Basic numeric options
    private val port by option("--port", help = "Port number").int().default(8080)
    private val timeout by option("--timeout", help = "Timeout in seconds").double()
    private val maxSize by option("--max-size", help = "Maximum size").ulong()
    
    // Numeric arguments
    private val count by argument(name = "COUNT", help = "Number of items").int()
    private val ratio by argument(name = "RATIO", help = "Ratio value").float()
    
    override fun run() {
        echo("Port: $port")
        echo("Timeout: ${timeout}s")
        echo("Max size: $maxSize bytes")
        echo("Count: $count")
        echo("Ratio: $ratio")
    }
}

Range Restrictions

Restrict numeric values to specific ranges.

/**
 * Restrict numeric value to a specific range
 * @param range Valid range for the value
 */
fun <T : Comparable<T>> NullableOption<T, T>.restrictTo(range: ClosedRange<T>): NullableOption<T, T>
fun <T : Comparable<T>> ProcessedArgument<T, T>.restrictTo(range: ClosedRange<T>): ProcessedArgument<T, T>

Usage Examples:

class MyCommand : CliktCommand() {
    // Port number between 1 and 65535
    private val port by option("--port", help = "Port number")
        .int().restrictTo(1..65535).default(8080)
    
    // Percentage between 0 and 100
    private val confidence by option("--confidence", help = "Confidence percentage")
        .double().restrictTo(0.0..100.0)
    
    // Thread count between 1 and available processors
    private val threads by argument(name = "THREADS", help = "Number of threads")
        .int().restrictTo(1..Runtime.getRuntime().availableProcessors())
}

Boolean Type

Convert parameters to boolean values.

/** Convert to Boolean */
fun RawOption.boolean(): NullableOption<Boolean, Boolean>
fun RawArgument.boolean(): ProcessedArgument<Boolean, Boolean>

Usage Examples:

class MyCommand : CliktCommand() {
    // Boolean option (requires explicit true/false value)
    private val enableFeature by option("--enable-feature", help = "Enable the feature")
        .boolean().default(false)
    
    // Boolean argument
    private val shouldProcess by argument(name = "PROCESS", help = "Whether to process (true/false)")
        .boolean()
    
    override fun run() {
        echo("Feature enabled: $enableFeature")
        echo("Should process: $shouldProcess")
    }
}

Enum Types

Convert parameters to enum values with case-insensitive matching.

/** Convert to Enum with case-insensitive matching */
inline fun <reified T : Enum<T>> RawOption.enum(
    ignoreCase: Boolean = true,
    key: (T) -> String = { it.name }
): NullableOption<T, T>

inline fun <reified T : Enum<T>> RawArgument.enum(
    ignoreCase: Boolean = true,
    key: (T) -> String = { it.name }
): ProcessedArgument<T, T>

Usage Examples:

class MyCommand : CliktCommand() {
    enum class LogLevel { DEBUG, INFO, WARN, ERROR }
    enum class OutputFormat { JSON, XML, YAML, CSV }
    
    // Enum option with default
    private val logLevel by option("--log-level", help = "Logging level")
        .enum<LogLevel>().default(LogLevel.INFO)
    
    // Enum argument
    private val format by argument(name = "FORMAT", help = "Output format")
        .enum<OutputFormat>()
    
    // Case-sensitive enum
    private val mode by option("--mode", help = "Processing mode")
        .enum<ProcessingMode>(ignoreCase = false)
    
    override fun run() {
        echo("Log level: $logLevel")
        echo("Format: $format")
        echo("Mode: $mode")
    }
}

Choice Types

Convert parameters to values from predefined choices.

/** Convert using choice map */
fun <T : Any> RawOption.choice(
    choices: Map<String, T>,
    metavar: String = choices.keys.joinToString("|", "(", ")"),
    ignoreCase: Boolean = false
): NullableOption<T, T>

fun <T : Any> RawArgument.choice(
    choices: Map<String, T>,
    ignoreCase: Boolean = false
): ProcessedArgument<T, T>

/** Convert using pair choices */
fun <T : Any> RawOption.choice(
    vararg choices: Pair<String, T>,
    metavar: String = choices.map { it.first }.joinToString("|", "(", ")"),
    ignoreCase: Boolean = false
): NullableOption<T, T>

fun <T : Any> RawArgument.choice(
    vararg choices: Pair<String, T>,
    ignoreCase: Boolean = false
): ProcessedArgument<T, T>

/** Convert using string choices */
fun RawOption.choice(
    vararg choices: String,
    metavar: String = choices.joinToString("|", "(", ")"),
    ignoreCase: Boolean = false
): NullableOption<String, String>

fun RawArgument.choice(
    vararg choices: String,
    ignoreCase: Boolean = false
): ProcessedArgument<String, String>

Usage Examples:

class MyCommand : CliktCommand() {
    // String choices
    private val compression by option("--compression", help = "Compression algorithm")
        .choice("none", "gzip", "bzip2", "xz").default("none")
    
    // Choice with custom values
    private val verbosity by option("-v", "--verbosity", help = "Verbosity level")
        .choice(mapOf(
            "quiet" to 0,
            "normal" to 1,
            "verbose" to 2,
            "debug" to 3
        )).default(1)
    
    // Case-insensitive choices
    private val protocol by argument(name = "PROTOCOL", help = "Network protocol")
        .choice("http", "https", "ftp", "sftp", ignoreCase = true)
    
    override fun run() {
        echo("Compression: $compression")
        echo("Verbosity: $verbosity")
        echo("Protocol: $protocol")
    }
}

File System Types (JVM Platform)

Convert parameters to file system objects (available on JVM platform only).

/** Convert to java.io.File */
fun RawOption.file(): NullableOption<File, File>
fun RawArgument.file(): ProcessedArgument<File, File>

/** Convert to java.nio.file.Path */
fun RawOption.path(): NullableOption<Path, Path>
fun RawArgument.path(): ProcessedArgument<Path, Path>

Usage Examples:

class MyCommand : CliktCommand() {
    // File options
    private val configFile by option("--config", help = "Configuration file")
        .file().default(File("config.properties"))
    
    private val outputDir by option("--output-dir", help = "Output directory")
        .path().default(Paths.get("output"))
    
    // File arguments
    private val inputFile by argument(name = "INPUT", help = "Input file to process").file()
    private val backupPath by argument(name = "BACKUP", help = "Backup location").path()
    
    override fun run() {
        echo("Config file: ${configFile.absolutePath}")
        echo("Output directory: ${outputDir.toAbsolutePath()}")
        echo("Input file: ${inputFile.name}")
        echo("Backup path: $backupPath")
    }
}

Stream Types (JVM Platform)

Convert parameters to input/output streams (available on JVM platform only).

/** Convert to InputStream */
fun RawOption.inputStream(): NullableOption<InputStream, InputStream>
fun RawArgument.inputStream(): ProcessedArgument<InputStream, InputStream>

/** Convert to OutputStream */
fun RawOption.outputStream(): NullableOption<OutputStream, OutputStream>
fun RawArgument.outputStream(): ProcessedArgument<OutputStream, OutputStream>

Usage Examples:

class MyCommand : CliktCommand() {
    // Stream options (stdin/stdout supported with "-")
    private val input by option("--input", help = "Input stream (use '-' for stdin)")
        .inputStream().default(System.`in`)
    
    private val output by option("--output", help = "Output stream (use '-' for stdout)")
        .outputStream().default(System.out)
    
    override fun run() {
        input.use { inputStream ->
            output.use { outputStream ->
                inputStream.copyTo(outputStream)
            }
        }
    }
}

Custom Type Conversion

Create custom type converters for domain-specific types.

/**
 * Convert using custom conversion function
 * @param metavar Placeholder for help text
 * @param conversion Custom conversion function
 */
fun <T : Any> RawOption.convert(
    metavar: String,
    conversion: ValueConverter<String, T>
): NullableOption<T, T>

fun <T : Any> RawArgument.convert(
    conversion: ArgValueConverter<String, T>
): ProcessedArgument<T, T>

Usage Examples:

import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.regex.Pattern

class MyCommand : CliktCommand() {
    // Date conversion
    private val startDate by option("--start-date", help = "Start date (YYYY-MM-DD)")
        .convert("DATE") { LocalDate.parse(it) }
    
    // DateTime conversion
    private val timestamp by option("--timestamp", help = "Timestamp (ISO format)")
        .convert("DATETIME") { 
            LocalDateTime.parse(it, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        }
    
    // URL conversion
    private val apiEndpoint by option("--api-endpoint", help = "API endpoint URL")
        .convert("URL") { 
            require(it.startsWith("http")) { "URL must start with http or https" }
            java.net.URL(it)
        }
    
    // Regex pattern conversion
    private val pattern by argument(name = "PATTERN", help = "Regular expression pattern")
        .convert { Pattern.compile(it) }
    
    // Custom data class conversion
    data class Coordinate(val lat: Double, val lon: Double)
    
    private val location by option("--location", help = "Location as 'lat,lon'")
        .convert("LAT,LON") {
            val parts = it.split(",")
            require(parts.size == 2) { "Location must be in format 'lat,lon'" }
            Coordinate(parts[0].toDouble(), parts[1].toDouble())
        }
    
    override fun run() {
        echo("Start date: $startDate")
        echo("Timestamp: $timestamp")
        echo("API endpoint: $apiEndpoint")
        echo("Pattern: ${pattern.pattern()}")
        echo("Location: $location")
    }
}

Type Conversion Context

Type conversion functions receive a context object with useful properties and methods.

/**
 * Context for option type conversion
 */
interface OptionTransformContext {
    val context: Context
    val option: Option
    val name: String
    
    /** Throw conversion error */
    fun fail(message: String): Nothing
}

/**
 * Context for argument type conversion
 */
interface ArgumentTransformContext {
    val context: Context
    val argument: Argument
    val name: String
    
    /** Throw conversion error */
    fun fail(message: String): Nothing
}

Usage Examples:

class MyCommand : CliktCommand() {
    // Using context in conversion
    private val positiveInt by option("--count", help = "Positive integer")
        .convert("INT") { value ->
            val parsed = value.toIntOrNull() 
                ?: fail("'$value' is not a valid integer")
            
            if (parsed <= 0) {
                fail("Value must be positive, got $parsed")
            }
            
            parsed
        }
    
    // Access option name in conversion
    private val percentage by option("--percentage", help = "Percentage value")
        .convert("PERCENT") { value ->
            val parsed = value.toDoubleOrNull()
                ?: fail("Option $name requires a number, got '$value'")
            
            if (parsed !in 0.0..100.0) {
                fail("Option $name must be between 0 and 100, got $parsed")
            }
            
            parsed
        }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-github-ajalt--clikt-jvm

docs

arguments.md

configuration-sources.md

core-commands.md

exceptions.md

index.md

options.md

parameter-groups.md

parameter-types.md

shell-completion.md

testing-utilities.md

tile.json