UniqueNamesValidator.swift 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Argument Parser open source project
  4. //
  5. // Copyright (c) 2020 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See https://swift.org/LICENSE.txt for license information
  9. //
  10. //===----------------------------------------------------------------------===//
  11. /// A validator that ensures argument names are unique within a
  12. /// `ParsableArguments` or `ParsableCommand`.
  13. struct UniqueNamesValidator: ParsableArgumentsValidator {
  14. struct Error: ParsableArgumentsValidatorError, CustomStringConvertible {
  15. var duplicateNames: [String: Int] = [:]
  16. var description: String {
  17. duplicateNames.map { entry in
  18. """
  19. Multiple (\(entry.value)) `Option` or `Flag` arguments are named \
  20. "\(entry.key)".
  21. """
  22. }.joined(separator: "\n")
  23. }
  24. var kind: ValidatorErrorKind { .failure }
  25. }
  26. static func validate(_ type: ParsableArguments.Type, parent: InputKey?)
  27. -> ParsableArgumentsValidatorError?
  28. {
  29. let argSets: [ArgumentSet] = Mirror(reflecting: type.init())
  30. .children
  31. .compactMap { child in
  32. guard
  33. let codingKey = child.label,
  34. let parsed = child.value as? ArgumentSetProvider
  35. else { return nil }
  36. let key = InputKey(name: codingKey, parent: parent)
  37. return parsed.argumentSet(for: key)
  38. }
  39. let countedNames: [String: Int] = argSets.reduce(into: [:]) {
  40. countedNames, args in
  41. for name in args.content.flatMap({ $0.names }) {
  42. countedNames[name.synopsisString, default: 0] += 1
  43. }
  44. }
  45. let duplicateNames = countedNames.filter { $0.value > 1 }
  46. return duplicateNames.isEmpty
  47. ? nil
  48. : Error(duplicateNames: duplicateNames)
  49. }
  50. }