Some CLI tools need multiple different option names whose values are collected into a single ordered array — where the relative ordering across different flags matters.
Motivating example
Consider an image processing pipeline where transformations must be applied in the order the user specifies:
./image-tool input.png \
--resize 50% \
--blur 3 \
--crop 100x100 \
--rotate 90 \
--blur 1
The order matters: --resize then --crop produces a different result than --crop then --resize. Tools like ImageMagick and ffmpeg have this pattern.
Current state
Today, you can declare separate @Option var resize: [String] and @Option var crop: [String] arrays, which each preserve their own insertion order — but there's no way to know the relative ordering across different option names.
The parser already tracks this information internally. In ArgumentDefinition.swift, the Update.Unary closure receives the matched Name?:
typealias Unary = (InputOrigin, Name?, String, inout ParsedValues) throws -> Void
And when building the update closure, name is available but not passed through to user code:
update: .unary({ (origin, name, valueString, parsedValues) in
let value = try parser(key, origin, name, valueString) // name available here
Container.update(
parsedValues: &parsedValues,
value: value,
key: key,
origin: origin) // ...but not passed to the container
})
The public transform closure only receives the value string, discarding the name.
Proposed solution
Add @Option initialiser overloads where the transform closure receives the matched option name as a string, in addition to the value:
@Option(
name: [.customLong("resize"), .customLong("blur"), .customLong("crop"), .customLong("rotate")],
transform: { optionName, value in
switch optionName {
case "resize": return .resize(value)
case "blur": return .blur(Double(value)!)
case "crop": return .crop(value)
case "rotate": return .rotate(Double(value)!)
default: fatalError()
}
}
) var operations: [Operation]
This would allow:
enum Operation {
case resize(String)
case blur(Double)
case crop(String)
case rotate(Double)
}
struct ImageTool: ParsableCommand {
@Argument var input: String
@Option(
name: [.customLong("resize"), .customLong("blur"), .customLong("crop"), .customLong("rotate")],
transform: { optionName, value in
switch optionName {
case "resize": return .resize(value)
case "blur": return .blur(Double(value)!)
case "crop": return .crop(value)
case "rotate": return .rotate(Double(value)!)
default: fatalError()
}
}
) var operations: [Operation] = []
func run() {
for op in operations {
print(op) // Printed in the order the user specified
}
}
}
Some CLI tools need multiple different option names whose values are collected into a single ordered array — where the relative ordering across different flags matters.
Motivating example
Consider an image processing pipeline where transformations must be applied in the order the user specifies:
The order matters:
--resizethen--cropproduces a different result than--cropthen--resize. Tools like ImageMagick and ffmpeg have this pattern.Current state
Today, you can declare separate
@Option var resize: [String]and@Option var crop: [String]arrays, which each preserve their own insertion order — but there's no way to know the relative ordering across different option names.The parser already tracks this information internally. In
ArgumentDefinition.swift, theUpdate.Unaryclosure receives the matchedName?:And when building the update closure, name is available but not passed through to user code:
The public transform closure only receives the
valuestring, discarding thename.Proposed solution
Add
@Optioninitialiser overloads where the transform closure receives the matched option name as a string, in addition to the value:This would allow: