NonsenseFlagsValidator.swift 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  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 prevents declaring flags that can't be turned off.
  12. struct NonsenseFlagsValidator: ParsableArgumentsValidator {
  13. struct Error: ParsableArgumentsValidatorError, CustomStringConvertible {
  14. var names: [String]
  15. var description: String {
  16. """
  17. One or more Boolean flags is declared with an initial value of `true`. \
  18. This results in the flag always being `true`, no matter whether the user \
  19. specifies the flag or not.
  20. To resolve this error, change the default to `false`, provide a value \
  21. for the `inversion:` parameter, or remove the `@Flag` property wrapper \
  22. altogether.
  23. Affected flag(s):
  24. \(names.joined(separator: "\n"))
  25. """
  26. }
  27. var kind: ValidatorErrorKind { .warning }
  28. }
  29. static func validate(_ type: ParsableArguments.Type, parent: InputKey?)
  30. -> ParsableArgumentsValidatorError?
  31. {
  32. let argSets: [ArgumentSet] = Mirror(reflecting: type.init())
  33. .children
  34. .compactMap { child in
  35. guard
  36. let codingKey = child.label,
  37. let parsed = child.value as? ArgumentSetProvider
  38. else { return nil }
  39. let key = InputKey(name: codingKey, parent: parent)
  40. return parsed.argumentSet(for: key)
  41. }
  42. let nonsenseFlags: [String] = argSets.flatMap { args -> [String] in
  43. args.compactMap { def in
  44. if case .nullary = def.update,
  45. !def.help.isComposite,
  46. def.help.options.contains(.isOptional),
  47. def.help.defaultValue == "true"
  48. {
  49. return def.unadornedSynopsis
  50. } else {
  51. return nil
  52. }
  53. }
  54. }
  55. return nonsenseFlags.isEmpty
  56. ? nil
  57. : Error(names: nonsenseFlags)
  58. }
  59. }