ToolInfo.swift 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. extension Collection {
  12. /// - returns: A non-empty collection or `nil`.
  13. fileprivate var nonEmpty: Self? { isEmpty ? nil : self }
  14. }
  15. /// Header used to validate serialization version of an encoded ToolInfo struct.
  16. public struct ToolInfoHeader: Decodable {
  17. /// A sentinel value indicating the version of the ToolInfo struct used to
  18. /// generate the serialized form.
  19. public var serializationVersion: Int
  20. public init(serializationVersion: Int) {
  21. self.serializationVersion = serializationVersion
  22. }
  23. }
  24. /// Top-level structure containing serialization version and information for all
  25. /// commands in a tool.
  26. public struct ToolInfoV0: Codable, Hashable {
  27. /// A sentinel value indicating the version of the ToolInfo struct used to
  28. /// generate the serialized form.
  29. public var serializationVersion = 0
  30. /// Root command of the tool.
  31. public var command: CommandInfoV0
  32. public init(command: CommandInfoV0) {
  33. self.command = command
  34. }
  35. }
  36. /// All information about a particular command, including arguments and
  37. /// subcommands.
  38. public struct CommandInfoV0: Codable, Hashable {
  39. /// Super commands and tools.
  40. public var superCommands: [String]?
  41. /// Command should appear in help displays.
  42. public var shouldDisplay: Bool = true
  43. /// Name used to invoke the command.
  44. public var commandName: String
  45. /// List of command aliases.
  46. public var aliases: [String]?
  47. /// Short description of the command's functionality.
  48. public var abstract: String?
  49. /// Extended description of the command's functionality.
  50. public var discussion: String?
  51. /// Optional name of the subcommand invoked when the command is invoked with
  52. /// no arguments.
  53. public var defaultSubcommand: String?
  54. /// List of nested commands.
  55. public var subcommands: [CommandInfoV0]?
  56. /// List of supported arguments.
  57. public var arguments: [ArgumentInfoV0]?
  58. public init(
  59. superCommands: [String],
  60. shouldDisplay: Bool,
  61. commandName: String,
  62. aliases: [String]?,
  63. abstract: String,
  64. discussion: String,
  65. defaultSubcommand: String?,
  66. subcommands: [CommandInfoV0],
  67. arguments: [ArgumentInfoV0]
  68. ) {
  69. self.superCommands = superCommands.nonEmpty
  70. self.shouldDisplay = shouldDisplay
  71. self.commandName = commandName
  72. self.aliases = aliases?.nonEmpty
  73. self.abstract = abstract.nonEmpty
  74. self.discussion = discussion.nonEmpty
  75. self.defaultSubcommand = defaultSubcommand?.nonEmpty
  76. self.subcommands = subcommands.nonEmpty
  77. self.arguments = arguments.nonEmpty
  78. }
  79. public init(from decoder: any Decoder) throws {
  80. let container = try decoder.container(keyedBy: CodingKeys.self)
  81. self.superCommands = try container.decodeIfPresent(
  82. [String].self, forKey: .superCommands)
  83. self.commandName = try container.decode(String.self, forKey: .commandName)
  84. self.aliases = try container.decodeIfPresent(
  85. [String].self, forKey: .aliases)
  86. self.abstract = try container.decodeIfPresent(
  87. String.self, forKey: .abstract)
  88. self.discussion = try container.decodeIfPresent(
  89. String.self, forKey: .discussion)
  90. self.shouldDisplay =
  91. try container.decodeIfPresent(Bool.self, forKey: .shouldDisplay) ?? true
  92. self.defaultSubcommand = try container.decodeIfPresent(
  93. String.self, forKey: .defaultSubcommand)
  94. self.subcommands = try container.decodeIfPresent(
  95. [CommandInfoV0].self, forKey: .subcommands)
  96. self.arguments = try container.decodeIfPresent(
  97. [ArgumentInfoV0].self, forKey: .arguments)
  98. }
  99. }
  100. /// All information about a particular argument, including display names and
  101. /// options.
  102. public struct ArgumentInfoV0: Codable, Hashable {
  103. /// Information about an argument's name.
  104. public struct NameInfoV0: Codable, Hashable {
  105. /// Kind of prefix of an argument's name.
  106. public enum KindV0: String, Codable, Hashable {
  107. /// A multi-character name preceded by two dashes.
  108. case long
  109. /// A single character name preceded by a single dash.
  110. case short
  111. /// A multi-character name preceded by a single dash.
  112. case longWithSingleDash
  113. }
  114. /// Kind of prefix the NameInfoV0 describes.
  115. public var kind: KindV0
  116. /// Single or multi-character name of the argument.
  117. public var name: String
  118. public init(kind: NameInfoV0.KindV0, name: String) {
  119. self.kind = kind
  120. self.name = name
  121. }
  122. }
  123. /// Kind of argument.
  124. public enum KindV0: String, Codable, Hashable {
  125. /// Argument specified as a bare value on the command line.
  126. case positional
  127. /// Argument specified as a value prefixed by a `--flag` on the command line.
  128. case option
  129. /// Argument specified only as a `--flag` on the command line.
  130. case flag
  131. }
  132. public enum ParsingStrategyV0: String, Codable, Hashable {
  133. /// Expect the next `SplitArguments.Element` to be a value and parse it.
  134. /// Will fail if the next input is an option.
  135. case `default`
  136. /// Parse the next `SplitArguments.Element.value`
  137. case scanningForValue
  138. /// Parse the next `SplitArguments.Element` as a value, regardless of its type.
  139. case unconditional
  140. /// Parse multiple `SplitArguments.Element.value` up to the next non-`.value`
  141. case upToNextOption
  142. /// Parse all remaining `SplitArguments.Element` as values, regardless of its type.
  143. case allRemainingInput
  144. /// Collect all the elements after the terminator, preventing them from
  145. /// appearing in any other position.
  146. case postTerminator
  147. /// Collect all unused inputs once recognized arguments/options/flags have
  148. /// been parsed.
  149. case allUnrecognized
  150. }
  151. public enum CompletionKindV0: Codable, Hashable {
  152. /// Use the specified list of completion strings.
  153. case list(values: [String])
  154. /// Complete file names with the specified extensions.
  155. case file(extensions: [String])
  156. /// Complete directory names that match the specified pattern.
  157. case directory
  158. /// Call the given shell command to generate completions.
  159. case shellCommand(command: String)
  160. /// Generate completions using the given three-parameter closure.
  161. case custom
  162. /// Generate completions using the given async three-parameter closure.
  163. case customAsync
  164. /// Generate completions using the given one-parameter closure.
  165. @available(*, deprecated, message: "Use custom instead.")
  166. case customDeprecated
  167. }
  168. /// Kind of argument the ArgumentInfo describes.
  169. public var kind: KindV0
  170. /// Argument should appear in help displays.
  171. public var shouldDisplay: Bool
  172. /// Custom name of argument's section.
  173. public var sectionTitle: String?
  174. /// Argument can be omitted.
  175. public var isOptional: Bool
  176. /// Argument can be specified multiple times.
  177. public var isRepeating: Bool
  178. /// Parsing strategy of the ArgumentInfo.
  179. public var parsingStrategy: ParsingStrategyV0
  180. /// All names of the argument.
  181. public var names: [NameInfoV0]?
  182. /// The best name to use when referring to the argument in help displays.
  183. public var preferredName: NameInfoV0?
  184. /// Name of argument's value.
  185. public var valueName: String?
  186. /// Default value of the argument is none is specified on the command line.
  187. public var defaultValue: String?
  188. // NOTE: this property will not be renamed to 'allValueStrings' to avoid
  189. // breaking compatibility with the current serialized format.
  190. //
  191. // This property is effectively deprecated.
  192. /// List of all valid values.
  193. public var allValues: [String]?
  194. /// List of all valid values.
  195. public var allValueStrings: [String]? {
  196. get { self.allValues }
  197. set { self.allValues = newValue }
  198. }
  199. /// Mapping of valid values to descriptions of the value.
  200. public var allValueDescriptions: [String: String]?
  201. /// The type of completion to use for an argument or an option value.
  202. ///
  203. /// `nil` if the tool uses the default completion kind.
  204. public var completionKind: CompletionKindV0?
  205. /// Short description of the argument's functionality.
  206. public var abstract: String?
  207. /// Extended description of the argument's functionality.
  208. public var discussion: String?
  209. public init(
  210. kind: KindV0,
  211. shouldDisplay: Bool,
  212. sectionTitle: String?,
  213. isOptional: Bool,
  214. isRepeating: Bool,
  215. parsingStrategy: ParsingStrategyV0,
  216. names: [NameInfoV0]?,
  217. preferredName: NameInfoV0?,
  218. valueName: String?,
  219. defaultValue: String?,
  220. allValueStrings: [String]?,
  221. allValueDescriptions: [String: String]?,
  222. completionKind: CompletionKindV0?,
  223. abstract: String?,
  224. discussion: String?
  225. ) {
  226. self.kind = kind
  227. self.shouldDisplay = shouldDisplay
  228. self.sectionTitle = sectionTitle
  229. self.isOptional = isOptional
  230. self.isRepeating = isRepeating
  231. self.parsingStrategy = parsingStrategy
  232. self.names = names?.nonEmpty
  233. self.preferredName = preferredName
  234. self.valueName = valueName?.nonEmpty
  235. self.defaultValue = defaultValue?.nonEmpty
  236. self.allValueStrings = allValueStrings?.nonEmpty
  237. self.allValueDescriptions = allValueDescriptions?.nonEmpty
  238. self.completionKind = completionKind
  239. self.abstract = abstract?.nonEmpty
  240. self.discussion = discussion?.nonEmpty
  241. }
  242. }