Option.swift 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  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 property wrapper that represents a command-line option.
  12. ///
  13. /// Use the `@Option` wrapper to define a property of your custom command as a
  14. /// command-line option. An *option* is a named value passed to a command-line
  15. /// tool, like `--configuration debug`. Options can be specified in any order.
  16. ///
  17. /// An option can have a default value specified as part of its
  18. /// declaration; options with optional `Value` types implicitly have `nil` as
  19. /// their default value. Options that are neither declared as `Optional` nor
  20. /// given a default value are required for users of your command-line tool.
  21. ///
  22. /// For example, the following program defines three options:
  23. ///
  24. /// ```swift
  25. /// @main
  26. /// struct Greet: ParsableCommand {
  27. /// @Option var greeting = "Hello"
  28. /// @Option var age: Int? = nil
  29. /// @Option var name: String
  30. ///
  31. /// mutating func run() {
  32. /// print("\(greeting) \(name)!")
  33. /// if let age {
  34. /// print("Congrats on making it to the ripe old age of \(age)!")
  35. /// }
  36. /// }
  37. /// }
  38. /// ```
  39. ///
  40. /// `greeting` has a default value of `"Hello"`, which can be overridden by
  41. /// providing a different string as an argument, while `age` defaults to `nil`.
  42. /// `name` is a required option because it is non-`nil` and has no default
  43. /// value.
  44. ///
  45. /// $ greet --name Alicia
  46. /// Hello Alicia!
  47. /// $ greet --age 28 --name Seungchin --greeting Hi
  48. /// Hi Seungchin!
  49. /// Congrats on making it to the ripe old age of 28!
  50. @propertyWrapper
  51. public struct Option<Value>: Decodable, ParsedWrapper {
  52. internal var _parsedValue: Parsed<Value>
  53. internal init(_parsedValue: Parsed<Value>) {
  54. self._parsedValue = _parsedValue
  55. }
  56. public init(from _decoder: Decoder) throws {
  57. try self.init(_decoder: _decoder)
  58. }
  59. /// This initializer works around a quirk of property wrappers, where the
  60. /// compiler will not see no-argument initializers in extensions.
  61. ///
  62. /// Explicitly marking this initializer unavailable means that when `Value`
  63. /// conforms to `ExpressibleByArgument`, that overload will be selected
  64. /// instead.
  65. ///
  66. /// ```swift
  67. /// @Option() var foo: String // Syntax without this initializer
  68. /// @Option var foo: String // Syntax with this initializer
  69. /// ```
  70. @available(
  71. *, unavailable,
  72. message:
  73. "A default value must be provided unless the value type conforms to ExpressibleByArgument."
  74. )
  75. public init() {
  76. fatalError("unavailable")
  77. }
  78. /// The value presented by this property wrapper.
  79. public var wrappedValue: Value {
  80. get {
  81. switch _parsedValue {
  82. case .value(let v):
  83. return v
  84. case .definition:
  85. configurationFailure(directlyInitializedError)
  86. }
  87. }
  88. set {
  89. _parsedValue = .value(newValue)
  90. }
  91. }
  92. }
  93. extension Option: CustomStringConvertible {
  94. public var description: String {
  95. switch _parsedValue {
  96. case .value(let v):
  97. return String(describing: v)
  98. case .definition:
  99. return "Option(*definition*)"
  100. }
  101. }
  102. }
  103. extension Option: Sendable where Value: Sendable {}
  104. extension Option: DecodableParsedWrapper where Value: Decodable {}
  105. /// The strategy to use when parsing a single value from `@Option` arguments.
  106. ///
  107. /// - SeeAlso: ``ArrayParsingStrategy``
  108. public struct SingleValueParsingStrategy: Hashable {
  109. internal var base: ArgumentDefinition.ParsingStrategy
  110. /// Parse the input after the option and expect it to be a value.
  111. ///
  112. /// For inputs such as `--foo foo`, this would parse `foo` as the
  113. /// value. However, the input `--foo --bar foo bar` would
  114. /// result in an error. Even though two values are provided, they don’t
  115. /// succeed each option. Parsing would result in an error such as the following:
  116. ///
  117. /// Error: Missing value for '--foo <foo>'
  118. /// Usage: command [--foo <foo>]
  119. ///
  120. /// This is the **default behavior** for `@Option`-wrapped properties.
  121. public static var next: SingleValueParsingStrategy {
  122. self.init(base: .default)
  123. }
  124. /// Parse the next input, even if it could be interpreted as an option or
  125. /// flag.
  126. ///
  127. /// For inputs such as `--foo --bar baz`, if `.unconditional` is used for `foo`,
  128. /// this would read `--bar` as the value for `foo` and would use `baz` as
  129. /// the next positional argument.
  130. ///
  131. /// This allows reading negative numeric values or capturing flags to be
  132. /// passed through to another program since the leading hyphen is normally
  133. /// interpreted as the start of another option.
  134. ///
  135. /// - Note: This is usually *not* what users would expect. Use with caution.
  136. public static var unconditional: SingleValueParsingStrategy {
  137. self.init(base: .unconditional)
  138. }
  139. /// Parse the next input, as long as that input can't be interpreted as
  140. /// an option or flag.
  141. ///
  142. /// - Note: This will skip other options and _read ahead_ in the input
  143. /// to find the next available value. This may be *unexpected* for users.
  144. /// Use with caution.
  145. ///
  146. /// For example, if `--foo` takes a value, then the input `--foo --bar bar`
  147. /// would be parsed such that the value `bar` is used for `--foo`.
  148. public static var scanningForValue: SingleValueParsingStrategy {
  149. self.init(base: .scanningForValue)
  150. }
  151. }
  152. extension SingleValueParsingStrategy: Sendable {}
  153. /// The strategy to use when parsing multiple values from `@Option` arguments into an
  154. /// array.
  155. public struct ArrayParsingStrategy: Hashable {
  156. internal var base: ArgumentDefinition.ParsingStrategy
  157. /// Parse one value per option, joining multiple into an array.
  158. ///
  159. /// For example, for a parsable type with a property defined as
  160. /// `@Option(parsing: .singleValue) var read: [String]`,
  161. /// the input `--read foo --read bar` would result in the array
  162. /// `["foo", "bar"]`. The same would be true for the input
  163. /// `--read=foo --read=bar`.
  164. ///
  165. /// - Note: This follows the default behavior of differentiating between values and options. As
  166. /// such, the value for this option will be the next value (non-option) in the input. For the
  167. /// above example, the input `--read --name Foo Bar` would parse `Foo` into
  168. /// `read` (and `Bar` into `name`).
  169. public static var singleValue: ArrayParsingStrategy {
  170. self.init(base: .default)
  171. }
  172. /// Parse the value immediately after the option while allowing repeating options, joining multiple into an array.
  173. ///
  174. /// This is identical to `.singleValue` except that the value will be read
  175. /// from the input immediately after the option, even if it could be interpreted as an option.
  176. ///
  177. /// For example, for a parsable type with a property defined as
  178. /// `@Option(parsing: .unconditionalSingleValue) var read: [String]`,
  179. /// the input `--read foo --read bar` would result in the array
  180. /// `["foo", "bar"]` -- just as it would have been the case for `.singleValue`.
  181. ///
  182. /// - Note: However, the input `--read --name Foo Bar --read baz` would result in
  183. /// `read` being set to the array `["--name", "baz"]`. This is usually *not* what users
  184. /// would expect. Use with caution.
  185. public static var unconditionalSingleValue: ArrayParsingStrategy {
  186. self.init(base: .unconditional)
  187. }
  188. /// Parse all values up to the next option.
  189. ///
  190. /// For example, for a parsable type with a property defined as
  191. /// `@Option(parsing: .upToNextOption) var files: [String]`,
  192. /// the input `--files foo bar` would result in the array
  193. /// `["foo", "bar"]`.
  194. ///
  195. /// Parsing stops as soon as there’s another option in the input such that
  196. /// `--files foo bar --verbose` would also set `files` to the array
  197. /// `["foo", "bar"]`.
  198. public static var upToNextOption: ArrayParsingStrategy {
  199. self.init(base: .upToNextOption)
  200. }
  201. /// Parse all remaining arguments into an array.
  202. ///
  203. /// `.remaining` can be used for capturing pass-through flags. For example, for
  204. /// a parsable type defined as
  205. /// `@Option(parsing: .remaining) var passthrough: [String]`:
  206. ///
  207. /// $ cmd --passthrough --foo 1 --bar 2 -xvf
  208. /// ------------
  209. /// options.passthrough == ["--foo", "1", "--bar", "2", "-xvf"]
  210. ///
  211. /// - Note: This will read all inputs following the option without attempting to do any parsing. This is
  212. /// usually *not* what users would expect. Use with caution.
  213. ///
  214. /// Consider using a trailing `@Argument` instead and letting users explicitly turn off parsing
  215. /// through the terminator `--`. That is the more common approach. For example:
  216. /// ```swift
  217. /// struct Options: ParsableArguments {
  218. /// @Option var title: String
  219. /// @Argument var remainder: [String]
  220. /// }
  221. /// ```
  222. /// would parse the input `--title Foo -- Bar --baz` such that the `remainder`
  223. /// would hold the value `["Bar", "--baz"]`.
  224. public static var remaining: ArrayParsingStrategy {
  225. self.init(base: .allRemainingInput)
  226. }
  227. }
  228. extension ArrayParsingStrategy: Sendable {}
  229. // MARK: - @Option T: ExpressibleByArgument Initializers
  230. extension Option where Value: ExpressibleByArgument {
  231. /// Creates a property with a default value that reads its value from a
  232. /// labeled option.
  233. ///
  234. /// This initializer is used when you declare an `@Option`-attributed property
  235. /// that has an `ExpressibleByArgument` type, providing a default value:
  236. ///
  237. /// ```swift
  238. /// @Option var title: String = "<Title>"
  239. /// ```
  240. ///
  241. /// - Parameters:
  242. /// - wrappedValue: A default value to use for this property, provided
  243. /// implicitly by the compiler during property wrapper initialization.
  244. /// - name: A specification for what names are allowed for this option.
  245. /// - parsingStrategy: The behavior to use when looking for this option's
  246. /// value.
  247. /// - help: Information about how to use this option.
  248. /// - completion: The type of command-line completion provided for this
  249. /// option.
  250. public init(
  251. wrappedValue: Value,
  252. name: NameSpecification = .long,
  253. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  254. help: ArgumentHelp? = nil,
  255. completion: CompletionKind? = nil
  256. ) {
  257. self.init(
  258. _parsedValue: .init { key in
  259. let arg = ArgumentDefinition(
  260. container: Bare<Value>.self,
  261. key: key,
  262. kind: .name(key: key, specification: name),
  263. help: .init(
  264. help?.abstract ?? "",
  265. discussion: help?.discussion,
  266. valueName: help?.valueName,
  267. visibility: help?.visibility ?? .default,
  268. argumentType: Value.self
  269. ),
  270. parsingStrategy: parsingStrategy.base,
  271. initial: wrappedValue,
  272. completion: completion)
  273. return ArgumentSet(arg)
  274. })
  275. }
  276. @available(
  277. *, deprecated,
  278. message: """
  279. Swap the order of the 'help' and 'completion' arguments.
  280. """
  281. )
  282. public init(
  283. wrappedValue _wrappedValue: Value,
  284. name: NameSpecification = .long,
  285. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  286. completion: CompletionKind?,
  287. help: ArgumentHelp?
  288. ) {
  289. self.init(
  290. wrappedValue: _wrappedValue,
  291. name: name,
  292. parsing: parsingStrategy,
  293. help: help,
  294. completion: completion)
  295. }
  296. /// Creates a required property that reads its value from a labeled option.
  297. ///
  298. /// This initializer is used when you declare an `@Option`-attributed property
  299. /// that has an `ExpressibleByArgument` type, but without a default value:
  300. ///
  301. /// ```swift
  302. /// @Option var title: String
  303. /// ```
  304. ///
  305. /// - Parameters:
  306. /// - name: A specification for what names are allowed for this option.
  307. /// - parsingStrategy: The behavior to use when looking for this option's
  308. /// value.
  309. /// - help: Information about how to use this option.
  310. /// - completion: The type of command-line completion provided for this
  311. /// option.
  312. public init(
  313. name: NameSpecification = .long,
  314. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  315. help: ArgumentHelp? = nil,
  316. completion: CompletionKind? = nil
  317. ) {
  318. self.init(
  319. _parsedValue: .init { key in
  320. let arg = ArgumentDefinition(
  321. container: Bare<Value>.self,
  322. key: key,
  323. kind: .name(key: key, specification: name),
  324. help: .init(
  325. help?.abstract ?? "",
  326. discussion: help?.discussion,
  327. valueName: help?.valueName,
  328. visibility: help?.visibility ?? .default,
  329. argumentType: Value.self
  330. ),
  331. parsingStrategy: parsingStrategy.base,
  332. initial: nil,
  333. completion: completion)
  334. return ArgumentSet(arg)
  335. })
  336. }
  337. }
  338. // MARK: - @Option T Initializers
  339. extension Option {
  340. /// Creates a property with a default value that reads its value from a
  341. /// labeled option, parsing with the given closure.
  342. ///
  343. /// This initializer is used when you declare an `@Option`-attributed property
  344. /// with a transform closure and a default value:
  345. ///
  346. /// ```swift
  347. /// @Option(transform: { $0.first ?? " " })
  348. /// var char: Character = "_"
  349. /// ```
  350. ///
  351. /// - Parameters:
  352. /// - wrappedValue: The default value to use for this property, provided
  353. /// implicitly by the compiler during property wrapper initialization.
  354. /// - name: A specification for what names are allowed for this option.
  355. /// - parsingStrategy: The behavior to use when looking for this option's
  356. /// value.
  357. /// - help: Information about how to use this option.
  358. /// - completion: The type of command-line completion provided for this
  359. /// option.
  360. /// - transform: A closure that converts a string into this property's
  361. /// type, or else throws an error.
  362. @preconcurrency
  363. public init(
  364. wrappedValue: Value,
  365. name: NameSpecification = .long,
  366. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  367. help: ArgumentHelp? = nil,
  368. completion: CompletionKind? = nil,
  369. transform: @Sendable @escaping (String) throws -> Value
  370. ) {
  371. self.init(
  372. _parsedValue: .init { key in
  373. let arg = ArgumentDefinition(
  374. container: Bare<Value>.self,
  375. key: key,
  376. kind: .name(key: key, specification: name),
  377. help: help,
  378. parsingStrategy: parsingStrategy.base,
  379. transform: transform,
  380. initial: wrappedValue,
  381. completion: completion)
  382. return ArgumentSet(arg)
  383. })
  384. }
  385. /// Creates a required property that reads its value from a labeled option,
  386. /// parsing with the given closure.
  387. ///
  388. /// This initializer is used when you declare an `@Option`-attributed property
  389. /// with a transform closure and without a default value:
  390. ///
  391. /// ```swift
  392. /// @Option(transform: { $0.first ?? " " })
  393. /// var char: Character
  394. /// ```
  395. ///
  396. /// - Parameters:
  397. /// - name: A specification for what names are allowed for this option.
  398. /// - parsingStrategy: The behavior to use when looking for this option's
  399. /// value.
  400. /// - help: Information about how to use this option.
  401. /// - completion: The type of command-line completion provided for this
  402. /// option.
  403. /// - transform: A closure that converts a string into this property's
  404. /// type, or else throws an error.
  405. @preconcurrency
  406. @_disfavoredOverload
  407. public init(
  408. name: NameSpecification = .long,
  409. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  410. help: ArgumentHelp? = nil,
  411. completion: CompletionKind? = nil,
  412. transform: @Sendable @escaping (String) throws -> Value
  413. ) {
  414. self.init(
  415. _parsedValue: .init { key in
  416. let arg = ArgumentDefinition(
  417. container: Bare<Value>.self,
  418. key: key,
  419. kind: .name(key: key, specification: name),
  420. help: help,
  421. parsingStrategy: parsingStrategy.base,
  422. transform: transform,
  423. initial: nil,
  424. completion: completion)
  425. return ArgumentSet(arg)
  426. })
  427. }
  428. }
  429. // MARK: - @Option Optional<T: ExpressibleByArgument> Initializers
  430. extension Option {
  431. /// Creates an optional property that reads its value from a labeled option,
  432. /// with an explicit `nil` default.
  433. ///
  434. /// This initializer allows a user to provide a `nil` default value for an
  435. /// optional `@Option`-marked property:
  436. ///
  437. /// ```swift
  438. /// @Option var count: Int? = nil
  439. /// ```
  440. ///
  441. /// - Parameters:
  442. /// - wrappedValue: A default value to use for this property, provided
  443. /// implicitly by the compiler during property wrapper initialization.
  444. /// - name: A specification for what names are allowed for this option.
  445. /// - parsingStrategy: The behavior to use when looking for this option's
  446. /// value.
  447. /// - help: Information about how to use this option.
  448. /// - completion: The type of command-line completion provided for this
  449. /// option.
  450. public init<T>(
  451. wrappedValue: _OptionalNilComparisonType,
  452. name: NameSpecification = .long,
  453. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  454. help: ArgumentHelp? = nil,
  455. completion: CompletionKind? = nil
  456. ) where T: ExpressibleByArgument, Value == T? {
  457. self.init(
  458. _parsedValue: .init { key in
  459. let arg = ArgumentDefinition(
  460. container: Optional<T>.self,
  461. key: key,
  462. kind: .name(key: key, specification: name),
  463. help: .init(
  464. help?.abstract ?? "",
  465. discussion: help?.discussion,
  466. valueName: help?.valueName,
  467. visibility: help?.visibility ?? .default,
  468. argumentType: T.self
  469. ),
  470. parsingStrategy: parsingStrategy.base,
  471. initial: nil,
  472. completion: completion)
  473. return ArgumentSet(arg)
  474. })
  475. }
  476. @available(
  477. *, deprecated,
  478. message: """
  479. Optional @Options with default values should be declared as non-Optional.
  480. """
  481. )
  482. @_disfavoredOverload
  483. public init<T>(
  484. wrappedValue _wrappedValue: T?,
  485. name: NameSpecification = .long,
  486. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  487. help: ArgumentHelp? = nil,
  488. completion: CompletionKind? = nil
  489. ) where T: ExpressibleByArgument, Value == T? {
  490. self.init(
  491. _parsedValue: .init { key in
  492. let arg = ArgumentDefinition(
  493. container: Optional<T>.self,
  494. key: key,
  495. kind: .name(key: key, specification: name),
  496. help: .init(
  497. help?.abstract ?? "",
  498. discussion: help?.discussion,
  499. valueName: help?.valueName,
  500. visibility: help?.visibility ?? .default,
  501. argumentType: T.self
  502. ),
  503. parsingStrategy: parsingStrategy.base,
  504. initial: _wrappedValue,
  505. completion: completion)
  506. return ArgumentSet(arg)
  507. })
  508. }
  509. /// Creates an optional property that reads its value from a labeled option.
  510. ///
  511. /// This initializer is used when you declare an `@Option`-attributed property
  512. /// with an optional type and no default value:
  513. ///
  514. /// ```swift
  515. /// @Option var count: Int?
  516. /// ```
  517. ///
  518. /// - Parameters:
  519. /// - name: A specification for what names are allowed for this option.
  520. /// - parsingStrategy: The behavior to use when looking for this option's
  521. /// value.
  522. /// - help: Information about how to use this option.
  523. /// - completion: The type of command-line completion provided for this
  524. /// option.
  525. public init<T>(
  526. name: NameSpecification = .long,
  527. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  528. help: ArgumentHelp? = nil,
  529. completion: CompletionKind? = nil
  530. ) where T: ExpressibleByArgument, Value == T? {
  531. self.init(
  532. _parsedValue: .init { key in
  533. let arg = ArgumentDefinition(
  534. container: Optional<T>.self,
  535. key: key,
  536. kind: .name(key: key, specification: name),
  537. help: .init(
  538. help?.abstract ?? "",
  539. discussion: help?.discussion,
  540. valueName: help?.valueName,
  541. visibility: help?.visibility ?? .default,
  542. argumentType: T.self
  543. ),
  544. parsingStrategy: parsingStrategy.base,
  545. initial: nil,
  546. completion: completion)
  547. return ArgumentSet(arg)
  548. })
  549. }
  550. }
  551. // MARK: - @Option Optional<T> Initializers
  552. extension Option {
  553. /// Creates an optional property that reads its value from a labeled option,
  554. /// parsing with the given closure, with an explicit `nil` default.
  555. ///
  556. /// This initializer is used when you declare an `@Option`-attributed property
  557. /// with a transform closure and with a default value of `nil`:
  558. ///
  559. /// ```swift
  560. /// @Option(transform: { $0.first ?? " " })
  561. /// var char: Character? = nil
  562. /// ```
  563. ///
  564. /// - Parameters:
  565. /// - wrappedValue: A default value to use for this property, provided
  566. /// implicitly by the compiler during property wrapper initialization.
  567. /// - name: A specification for what names are allowed for this option.
  568. /// - parsingStrategy: The behavior to use when looking for this option's
  569. /// value.
  570. /// - help: Information about how to use this option.
  571. /// - completion: The type of command-line completion provided for this
  572. /// option.
  573. /// - transform: A closure that converts a string into this property's
  574. /// type, or else throws an error.
  575. @preconcurrency
  576. public init<T>(
  577. wrappedValue: _OptionalNilComparisonType,
  578. name: NameSpecification = .long,
  579. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  580. help: ArgumentHelp? = nil,
  581. completion: CompletionKind? = nil,
  582. transform: @Sendable @escaping (String) throws -> T
  583. ) where Value == T? {
  584. self.init(
  585. _parsedValue: .init { key in
  586. let arg = ArgumentDefinition(
  587. container: Optional<T>.self,
  588. key: key,
  589. kind: .name(key: key, specification: name),
  590. help: help,
  591. parsingStrategy: parsingStrategy.base,
  592. transform: transform,
  593. initial: nil,
  594. completion: completion)
  595. return ArgumentSet(arg)
  596. })
  597. }
  598. @available(
  599. *, deprecated,
  600. message: """
  601. Optional @Options with default values should be declared as non-Optional.
  602. """
  603. )
  604. @_disfavoredOverload
  605. @preconcurrency
  606. public init<T>(
  607. wrappedValue _wrappedValue: T?,
  608. name: NameSpecification = .long,
  609. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  610. help: ArgumentHelp? = nil,
  611. completion: CompletionKind? = nil,
  612. transform: @Sendable @escaping (String) throws -> T
  613. ) where Value == T? {
  614. self.init(
  615. _parsedValue: .init { key in
  616. let arg = ArgumentDefinition(
  617. container: Optional<T>.self,
  618. key: key,
  619. kind: .name(key: key, specification: name),
  620. help: help,
  621. parsingStrategy: parsingStrategy.base,
  622. transform: transform,
  623. initial: _wrappedValue,
  624. completion: completion)
  625. return ArgumentSet(arg)
  626. })
  627. }
  628. /// Creates an optional property that reads its value from a labeled option,
  629. /// parsing with the given closure.
  630. ///
  631. /// This initializer is used when you declare an `@Option`-attributed property
  632. /// with a transform closure and without a default value:
  633. ///
  634. /// ```swift
  635. /// @Option(transform: { $0.first ?? " " })
  636. /// var char: Character?
  637. /// ```
  638. ///
  639. /// - Parameters:
  640. /// - name: A specification for what names are allowed for this option.
  641. /// - parsingStrategy: The behavior to use when looking for this option's
  642. /// value.
  643. /// - help: Information about how to use this option.
  644. /// - completion: The type of command-line completion provided for this
  645. /// option.
  646. /// - transform: A closure that converts a string into this property's
  647. /// type, or else throws an error.
  648. @preconcurrency
  649. public init<T>(
  650. name: NameSpecification = .long,
  651. parsing parsingStrategy: SingleValueParsingStrategy = .next,
  652. help: ArgumentHelp? = nil,
  653. completion: CompletionKind? = nil,
  654. transform: @Sendable @escaping (String) throws -> T
  655. ) where Value == T? {
  656. self.init(
  657. _parsedValue: .init { key in
  658. let arg = ArgumentDefinition(
  659. container: Optional<T>.self,
  660. key: key,
  661. kind: .name(key: key, specification: name),
  662. help: help,
  663. parsingStrategy: parsingStrategy.base,
  664. transform: transform,
  665. initial: nil,
  666. completion: completion)
  667. return ArgumentSet(arg)
  668. })
  669. }
  670. }
  671. // MARK: - @Option Array<T: ExpressibleByArgument> Initializers
  672. extension Option {
  673. /// Creates an array property that reads its values from zero or
  674. /// more labeled options.
  675. ///
  676. /// This initializer is used when you declare an `@Option`-attributed array
  677. /// property with a default value:
  678. ///
  679. /// ```swift
  680. /// @Option(name: .customLong("char"))
  681. /// var chars: [Character] = []
  682. /// ```
  683. ///
  684. /// If the element type conforms to `ExpressibleByArgument` and has enumerable
  685. /// value descriptions (via `defaultValueDescription`), the help output will
  686. /// display each possible value with its description, similar to single
  687. /// enumerable options.
  688. ///
  689. /// - Parameters:
  690. /// - wrappedValue: A default value to use for this property, provided
  691. /// implicitly by the compiler during property wrapper initialization.
  692. /// If this initial value is non-empty, elements passed from the command
  693. /// line are appended to the original contents.
  694. /// - name: A specification for what names are allowed for this option.
  695. /// - parsingStrategy: The behavior to use when parsing the elements for
  696. /// this option.
  697. /// - help: Information about how to use this option.
  698. /// - completion: The type of command-line completion provided for this
  699. /// option.
  700. public init<T>(
  701. wrappedValue: [T],
  702. name: NameSpecification = .long,
  703. parsing parsingStrategy: ArrayParsingStrategy = .singleValue,
  704. help: ArgumentHelp? = nil,
  705. completion: CompletionKind? = nil
  706. ) where T: ExpressibleByArgument, Value == [T] {
  707. self.init(
  708. _parsedValue: .init { key in
  709. let arg = ArgumentDefinition(
  710. container: Array<T>.self,
  711. key: key,
  712. kind: .name(key: key, specification: name),
  713. help: .init(
  714. help?.abstract ?? "",
  715. discussion: help?.discussion,
  716. valueName: help?.valueName,
  717. visibility: help?.visibility ?? .default,
  718. argumentType: T.self
  719. ),
  720. parsingStrategy: parsingStrategy.base,
  721. initial: wrappedValue,
  722. completion: completion)
  723. return ArgumentSet(arg)
  724. })
  725. }
  726. /// Creates a required array property that reads its values from zero or
  727. /// more labeled options.
  728. ///
  729. /// This initializer is used when you declare an `@Option`-attributed array
  730. /// property without a default value:
  731. ///
  732. /// ```swift
  733. /// @Option(name: .customLong("char"))
  734. /// var chars: [Character]
  735. /// ```
  736. ///
  737. /// If the element type conforms to `ExpressibleByArgument` and has enumerable
  738. /// value descriptions (via `defaultValueDescription`), the help output will
  739. /// display each possible value with its description, similar to single
  740. /// enumerable options.
  741. ///
  742. /// - Parameters:
  743. /// - name: A specification for what names are allowed for this option.
  744. /// - parsingStrategy: The behavior to use when parsing the elements for
  745. /// this option.
  746. /// - help: Information about how to use this option.
  747. /// - completion: The type of command-line completion provided for this
  748. /// option.
  749. public init<T>(
  750. name: NameSpecification = .long,
  751. parsing parsingStrategy: ArrayParsingStrategy = .singleValue,
  752. help: ArgumentHelp? = nil,
  753. completion: CompletionKind? = nil
  754. ) where T: ExpressibleByArgument, Value == [T] {
  755. self.init(
  756. _parsedValue: .init { key in
  757. let arg = ArgumentDefinition(
  758. container: Array<T>.self,
  759. key: key,
  760. kind: .name(key: key, specification: name),
  761. help: .init(
  762. help?.abstract ?? "",
  763. discussion: help?.discussion,
  764. valueName: help?.valueName,
  765. visibility: help?.visibility ?? .default,
  766. argumentType: T.self
  767. ),
  768. parsingStrategy: parsingStrategy.base,
  769. initial: nil,
  770. completion: completion)
  771. return ArgumentSet(arg)
  772. })
  773. }
  774. }
  775. // MARK: - @Option Array<T> Initializers
  776. extension Option {
  777. /// Creates an array property that reads its values from zero or
  778. /// more labeled options, parsing each element with the given closure.
  779. ///
  780. /// This initializer is used when you declare an `@Option`-attributed array
  781. /// property with a transform closure and a default value:
  782. ///
  783. /// ```swift
  784. /// @Option(name: .customLong("char"), transform: { $0.first ?? " " })
  785. /// var chars: [Character] = []
  786. /// ```
  787. ///
  788. /// - Parameters:
  789. /// - wrappedValue: A default value to use for this property, provided
  790. /// implicitly by the compiler during property wrapper initialization.
  791. /// If this initial value is non-empty, elements passed from the command
  792. /// line are appended to the original contents.
  793. /// - name: A specification for what names are allowed for this option.
  794. /// - parsingStrategy: The behavior to use when parsing the elements for
  795. /// this option.
  796. /// - help: Information about how to use this option.
  797. /// - completion: The type of command-line completion provided for this
  798. /// option.
  799. /// - transform: A closure that converts a string into this property's
  800. /// element type, or else throws an error.
  801. @preconcurrency
  802. public init<T>(
  803. wrappedValue: [T],
  804. name: NameSpecification = .long,
  805. parsing parsingStrategy: ArrayParsingStrategy = .singleValue,
  806. help: ArgumentHelp? = nil,
  807. completion: CompletionKind? = nil,
  808. transform: @Sendable @escaping (String) throws -> T
  809. ) where Value == [T] {
  810. self.init(
  811. _parsedValue: .init { key in
  812. let arg = ArgumentDefinition(
  813. container: Array<T>.self,
  814. key: key,
  815. kind: .name(key: key, specification: name),
  816. help: help,
  817. parsingStrategy: parsingStrategy.base,
  818. transform: transform,
  819. initial: wrappedValue,
  820. completion: completion)
  821. return ArgumentSet(arg)
  822. })
  823. }
  824. /// Creates a required array property that reads its values from zero or
  825. /// more labeled options, parsing each element with the given closure.
  826. ///
  827. /// This initializer is used when you declare an `@Option`-attributed array
  828. /// property with a transform closure and without a default value:
  829. ///
  830. /// ```swift
  831. /// @Option(name: .customLong("char"), transform: { $0.first ?? " " })
  832. /// var chars: [Character]
  833. /// ```
  834. ///
  835. /// - Parameters:
  836. /// - name: A specification for what names are allowed for this option.
  837. /// - parsingStrategy: The behavior to use when parsing the elements for
  838. /// this option.
  839. /// - help: Information about how to use this option.
  840. /// - completion: The type of command-line completion provided for this
  841. /// option.
  842. /// - transform: A closure that converts a string into this property's
  843. /// element type, or else throws an error.
  844. @preconcurrency
  845. public init<T>(
  846. name: NameSpecification = .long,
  847. parsing parsingStrategy: ArrayParsingStrategy = .singleValue,
  848. help: ArgumentHelp? = nil,
  849. completion: CompletionKind? = nil,
  850. transform: @Sendable @escaping (String) throws -> T
  851. ) where Value == [T] {
  852. self.init(
  853. _parsedValue: .init { key in
  854. let arg = ArgumentDefinition(
  855. container: Array<T>.self,
  856. key: key,
  857. kind: .name(key: key, specification: name),
  858. help: help,
  859. parsingStrategy: parsingStrategy.base,
  860. transform: transform,
  861. initial: nil,
  862. completion: completion)
  863. return ArgumentSet(arg)
  864. })
  865. }
  866. }