mirror of
https://github.com/apple/swift-argument-parser.git
synced 2026-06-06 20:18:23 +00:00
87 lines
3.0 KiB
Swift
87 lines
3.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift Argument Parser open source project
|
|
//
|
|
// Copyright (c) 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A validator for positional argument arrays.
|
|
///
|
|
/// For positional arguments to be valid, there must be at most one
|
|
/// positional array argument, and it must be the last positional argument
|
|
/// in the argument list. Any other configuration leads to ambiguity in
|
|
/// parsing the arguments.
|
|
struct PositionalArgumentsValidator: ParsableArgumentsValidator {
|
|
struct Error: ParsableArgumentsValidatorError, CustomStringConvertible {
|
|
let repeatedPositionalArgument: String
|
|
|
|
let positionalArgumentFollowingRepeated: String
|
|
|
|
var description: String {
|
|
"""
|
|
Can't have a positional argument \
|
|
`\(positionalArgumentFollowingRepeated)` following an array of \
|
|
positional arguments `\(repeatedPositionalArgument)`.
|
|
"""
|
|
}
|
|
|
|
var kind: ValidatorErrorKind { .failure }
|
|
}
|
|
|
|
static func validate(
|
|
_ type: ParsableArguments.Type, parent: InputKey?
|
|
) -> ParsableArgumentsValidatorError? {
|
|
let sets: [ArgumentSet] = Mirror(reflecting: type.init())
|
|
.children
|
|
.compactMap { child in
|
|
guard
|
|
let codingKey = child.label,
|
|
let parsed = child.value as? ArgumentSetProvider
|
|
else { return nil }
|
|
|
|
let key = InputKey(name: codingKey, parent: parent)
|
|
return parsed.argumentSet(for: key)
|
|
}
|
|
|
|
guard
|
|
let repeatedPositional = sets.firstIndex(where: {
|
|
$0.firstRepeatedPositionalArgument != nil
|
|
})
|
|
else { return nil }
|
|
guard
|
|
let positionalFollowingRepeated = sets[repeatedPositional...]
|
|
.dropFirst()
|
|
.first(where: { $0.firstPositionalArgument != nil })
|
|
else { return nil }
|
|
|
|
// swift-format-ignore: NeverForceUnwrap
|
|
// We know these are non-nil because of the guard statements above.
|
|
let firstRepeatedPositionalArgument: ArgumentDefinition = sets[
|
|
repeatedPositional
|
|
].firstRepeatedPositionalArgument!
|
|
// swift-format-ignore: NeverForceUnwrap
|
|
let positionalFollowingRepeatedArgument: ArgumentDefinition =
|
|
positionalFollowingRepeated.firstPositionalArgument!
|
|
// swift-format-ignore: NeverForceUnwrap
|
|
return Error(
|
|
repeatedPositionalArgument: firstRepeatedPositionalArgument.help.keys
|
|
.first!.name,
|
|
positionalArgumentFollowingRepeated: positionalFollowingRepeatedArgument
|
|
.help.keys.first!.name)
|
|
}
|
|
}
|
|
|
|
extension ArgumentSet {
|
|
fileprivate var firstPositionalArgument: ArgumentDefinition? {
|
|
content.first(where: { $0.isPositional })
|
|
}
|
|
|
|
fileprivate var firstRepeatedPositionalArgument: ArgumentDefinition? {
|
|
content.first(where: { $0.isRepeatingPositional })
|
|
}
|
|
}
|