Argument.swift 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  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 positional command-line argument.
  12. ///
  13. /// Use the `@Argument` wrapper to define a property of your custom command as
  14. /// a positional argument. A *positional argument* for a command-line tool is
  15. /// specified without a label and must appear in declaration order. `@Argument`
  16. /// properties with `Optional` type or a default value are optional for the user
  17. /// of your command-line tool.
  18. ///
  19. /// For example, the following program has two positional arguments. The `name`
  20. /// argument is required, while `greeting` is optional because it has a default
  21. /// value.
  22. ///
  23. /// ```swift
  24. /// @main
  25. /// struct Greet: ParsableCommand {
  26. /// @Argument var name: String
  27. /// @Argument var greeting: String = "Hello"
  28. ///
  29. /// mutating func run() {
  30. /// print("\(greeting) \(name)!")
  31. /// }
  32. /// }
  33. /// ```
  34. ///
  35. /// You can call this program with just a name or with a name and a
  36. /// greeting. When you supply both arguments, the first argument is always
  37. /// treated as the name, due to the order of the property declarations.
  38. ///
  39. /// $ greet Nadia
  40. /// Hello Nadia!
  41. /// $ greet Tamara Hi
  42. /// Hi Tamara!
  43. @propertyWrapper
  44. public struct Argument<Value>:
  45. Decodable, ParsedWrapper
  46. {
  47. internal var _parsedValue: Parsed<Value>
  48. internal init(_parsedValue: Parsed<Value>) {
  49. self._parsedValue = _parsedValue
  50. }
  51. public init(from _decoder: Decoder) throws {
  52. try self.init(_decoder: _decoder)
  53. }
  54. /// This initializer works around a quirk of property wrappers, where the
  55. /// compiler will not see no-argument initializers in extensions.
  56. ///
  57. /// Explicitly marking this initializer unavailable means that when `Value`
  58. /// conforms to `ExpressibleByArgument`, that overload will be selected
  59. /// instead.
  60. ///
  61. /// ```swift
  62. /// @Argument() var foo: String // Syntax without this initializer
  63. /// @Argument var foo: String // Syntax with this initializer
  64. /// ```
  65. @available(
  66. *, unavailable,
  67. message:
  68. "A default value must be provided unless the value type conforms to ExpressibleByArgument."
  69. )
  70. public init() {
  71. fatalError("unavailable")
  72. }
  73. /// The value presented by this property wrapper.
  74. public var wrappedValue: Value {
  75. get {
  76. switch _parsedValue {
  77. case .value(let v):
  78. return v
  79. case .definition:
  80. configurationFailure(directlyInitializedError)
  81. }
  82. }
  83. set {
  84. _parsedValue = .value(newValue)
  85. }
  86. }
  87. }
  88. extension Argument: CustomStringConvertible {
  89. public var description: String {
  90. switch _parsedValue {
  91. case .value(let v):
  92. return String(describing: v)
  93. case .definition:
  94. return "Argument(*definition*)"
  95. }
  96. }
  97. }
  98. extension Argument: Sendable where Value: Sendable {}
  99. extension Argument: DecodableParsedWrapper where Value: Decodable {}
  100. /// The strategy to use when parsing multiple values from positional arguments
  101. /// into an array.
  102. public struct ArgumentArrayParsingStrategy: Hashable {
  103. internal var base: ArgumentDefinition.ParsingStrategy
  104. /// Parse only unprefixed values from the command-line input, ignoring
  105. /// any inputs that have a dash prefix; this is the default strategy.
  106. ///
  107. /// `remaining` is the default parsing strategy for argument arrays.
  108. ///
  109. /// For example, the `Example` command defined below has a `words` array that
  110. /// uses the `remaining` parsing strategy:
  111. ///
  112. /// @main
  113. /// struct Example: ParsableCommand {
  114. /// @Flag var verbose = false
  115. ///
  116. /// @Argument(parsing: .remaining)
  117. /// var words: [String]
  118. ///
  119. /// func run() {
  120. /// print(words.joined(separator: "\n"))
  121. /// }
  122. /// }
  123. ///
  124. /// Any non-dash-prefixed inputs will be captured in the `words` array.
  125. ///
  126. /// ```
  127. /// $ example --verbose one two
  128. /// one
  129. /// two
  130. /// $ example one two --verbose
  131. /// one
  132. /// two
  133. /// $ example one two --other
  134. /// Error: Unknown option '--other'
  135. /// ```
  136. ///
  137. /// If a user uses the `--` terminator in their input, all following inputs
  138. /// will be captured in `words`.
  139. ///
  140. /// ```
  141. /// $ example one two -- --verbose --other
  142. /// one
  143. /// two
  144. /// --verbose
  145. /// --other
  146. /// ```
  147. public static var remaining: ArgumentArrayParsingStrategy {
  148. self.init(base: .default)
  149. }
  150. /// After parsing, capture all unrecognized inputs in this argument array.
  151. ///
  152. /// You can use the `allUnrecognized` parsing strategy to suppress
  153. /// "unexpected argument" errors or to capture unrecognized inputs for further
  154. /// processing.
  155. ///
  156. /// For example, the `Example` command defined below has an `other` array that
  157. /// uses the `allUnrecognized` parsing strategy:
  158. ///
  159. /// @main
  160. /// struct Example: ParsableCommand {
  161. /// @Flag var verbose = false
  162. /// @Argument var name: String
  163. ///
  164. /// @Argument(parsing: .allUnrecognized)
  165. /// var other: [String]
  166. ///
  167. /// func run() {
  168. /// print(other.joined(separator: "\n"))
  169. /// }
  170. /// }
  171. ///
  172. /// After parsing the `--verbose` flag and `<name>` argument, any remaining
  173. /// input is captured in the `other` array.
  174. ///
  175. /// ```
  176. /// $ example --verbose Negin one two
  177. /// one
  178. /// two
  179. /// $ example Asa --verbose --other -zzz
  180. /// --other
  181. /// -zzz
  182. /// ```
  183. public static var allUnrecognized: ArgumentArrayParsingStrategy {
  184. self.init(base: .allUnrecognized)
  185. }
  186. // swift-format-ignore: BeginDocumentationCommentWithOneLineSummary
  187. // https://github.com/swiftlang/swift-format/issues/924
  188. /// Before parsing arguments, capture all inputs that follow the `--`
  189. /// terminator in this argument array.
  190. ///
  191. /// For example, the `Example` command defined below has a `words` array that
  192. /// uses the `postTerminator` parsing strategy:
  193. ///
  194. /// @main
  195. /// struct Example: ParsableCommand {
  196. /// @Flag var verbose = false
  197. /// @Argument var name = ""
  198. ///
  199. /// @Argument(parsing: .postTerminator)
  200. /// var words: [String]
  201. ///
  202. /// func run() {
  203. /// print(words.joined(separator: "\n"))
  204. /// }
  205. /// }
  206. ///
  207. /// Before looking for the `--verbose` flag and `<name>` argument, any inputs
  208. /// after the `--` terminator are captured into the `words` array.
  209. ///
  210. /// ```
  211. /// $ example --verbose Asa -- one two --other
  212. /// one
  213. /// two
  214. /// --other
  215. /// $ example Asa Extra -- one two --other
  216. /// Error: Unexpected argument 'Extra'
  217. /// ```
  218. ///
  219. /// Because options are parsed before arguments, an option that consumes or
  220. /// suppresses the `--` terminator can prevent a `postTerminator` argument
  221. /// array from capturing any input. In particular, the
  222. /// ``SingleValueParsingStrategy/unconditional``,
  223. /// ``ArrayParsingStrategy/unconditionalSingleValue``, and
  224. /// ``ArrayParsingStrategy/remaining`` parsing strategies can all consume
  225. /// the terminator as part of their values.
  226. ///
  227. /// - Note: This parsing strategy can be surprising for users, since it
  228. /// changes the behavior of the `--` terminator. Prefer ``remaining``
  229. /// whenever possible.
  230. public static var postTerminator: ArgumentArrayParsingStrategy {
  231. self.init(base: .postTerminator)
  232. }
  233. // swift-format-ignore: BeginDocumentationCommentWithOneLineSummary
  234. // https://github.com/swiftlang/swift-format/issues/924
  235. /// Parse all remaining inputs after parsing any known options or flags,
  236. /// including dash-prefixed inputs and the `--` terminator.
  237. ///
  238. /// You can use the `captureForPassthrough` parsing strategy if you need to
  239. /// capture a user's input to manually pass it unchanged to another command.
  240. ///
  241. /// When you use this parsing strategy, the parser stops parsing flags and
  242. /// options as soon as it encounters a positional argument or an unrecognized
  243. /// flag, and captures all remaining inputs in the array argument.
  244. ///
  245. /// For example, the `Example` command defined below has an `words` array that
  246. /// uses the `captureForPassthrough` parsing strategy:
  247. ///
  248. /// @main
  249. /// struct Example: ParsableCommand {
  250. /// @Flag var verbose = false
  251. ///
  252. /// @Argument(parsing: .captureForPassthrough)
  253. /// var words: [String] = []
  254. ///
  255. /// func run() {
  256. /// print(words.joined(separator: "\n"))
  257. /// }
  258. /// }
  259. ///
  260. /// Any values after the first unrecognized input are captured in the `words`
  261. /// array.
  262. ///
  263. /// ```
  264. /// $ example --verbose one two --other
  265. /// one
  266. /// two
  267. /// --other
  268. /// $ example one two --verbose
  269. /// one
  270. /// two
  271. /// --verbose
  272. /// ```
  273. ///
  274. /// With the `captureForPassthrough` parsing strategy, the `--` terminator
  275. /// is included in the captured values.
  276. ///
  277. /// ```
  278. /// $ example --verbose one two -- --other
  279. /// one
  280. /// two
  281. /// --
  282. /// --other
  283. /// ```
  284. ///
  285. /// - Note: This parsing strategy can be surprising for users, particularly
  286. /// when combined with options and flags. Prefer ``remaining`` or
  287. /// ``allUnrecognized`` whenever possible, since users can always terminate
  288. /// options and flags with the `--` terminator. With the `remaining`
  289. /// parsing strategy, the input `--verbose -- one two --other` would have
  290. /// the same result as the first example above.
  291. public static var captureForPassthrough: ArgumentArrayParsingStrategy {
  292. self.init(base: .allRemainingInput)
  293. }
  294. @available(*, deprecated, renamed: "captureForPassthrough")
  295. public static var unconditionalRemaining: ArgumentArrayParsingStrategy {
  296. .captureForPassthrough
  297. }
  298. }
  299. extension ArgumentArrayParsingStrategy: Sendable {}
  300. // MARK: - @Argument T: ExpressibleByArgument Initializers
  301. extension Argument where Value: ExpressibleByArgument {
  302. /// Creates a property with a default value provided by standard Swift default
  303. /// value syntax.
  304. ///
  305. /// This method is called to initialize an `Argument` with a default value
  306. /// such as:
  307. /// ```swift
  308. /// @Argument var foo: String = "bar"
  309. /// ```
  310. ///
  311. /// - Parameters:
  312. /// - wrappedValue: A default value to use for this property, provided
  313. /// implicitly by the compiler during property wrapper initialization.
  314. /// - help: Information about how to use this argument.
  315. /// - completion: Kind of completion provided to the user for this option.
  316. public init(
  317. wrappedValue: Value,
  318. help: ArgumentHelp? = nil,
  319. completion: CompletionKind? = nil
  320. ) {
  321. self.init(
  322. _parsedValue: .init { key in
  323. let arg = ArgumentDefinition(
  324. container: Bare<Value>.self,
  325. key: key,
  326. kind: .positional,
  327. help: help,
  328. parsingStrategy: .default,
  329. initial: wrappedValue,
  330. completion: completion)
  331. return ArgumentSet(arg)
  332. })
  333. }
  334. /// Creates a property with no default value.
  335. ///
  336. /// This method is called to initialize an `Argument` without a default value
  337. /// such as:
  338. /// ```swift
  339. /// @Argument var foo: String
  340. /// ```
  341. ///
  342. /// - Parameters:
  343. /// - help: Information about how to use this argument.
  344. /// - completion: Kind of completion provided to the user for this option.
  345. public init(
  346. help: ArgumentHelp? = nil,
  347. completion: CompletionKind? = nil
  348. ) {
  349. self.init(
  350. _parsedValue: .init { key in
  351. let arg = ArgumentDefinition(
  352. container: Bare<Value>.self,
  353. key: key,
  354. kind: .positional,
  355. help: help,
  356. parsingStrategy: .default,
  357. initial: nil,
  358. completion: completion)
  359. return ArgumentSet(arg)
  360. })
  361. }
  362. }
  363. // MARK: - @Argument T Initializers
  364. extension Argument {
  365. /// Creates a property with a default value provided by standard Swift default
  366. /// value syntax, parsing with the given closure.
  367. ///
  368. /// This method is called to initialize an `Argument` with a default value
  369. /// such as:
  370. /// ```swift
  371. /// @Argument(transform: baz)
  372. /// var foo: String = "bar"
  373. /// ```
  374. ///
  375. /// - Parameters:
  376. /// - wrappedValue: A default value to use for this property, provided
  377. /// implicitly by the compiler during property wrapper initialization.
  378. /// - help: Information about how to use this argument.
  379. /// - completion: Kind of completion provided to the user for this option.
  380. /// - transform: A closure that converts a string into this property's type
  381. /// or throws an error.
  382. @preconcurrency
  383. public init(
  384. wrappedValue: Value,
  385. help: ArgumentHelp? = nil,
  386. completion: CompletionKind? = nil,
  387. transform: @Sendable @escaping (String) throws -> Value
  388. ) {
  389. self.init(
  390. _parsedValue: .init { key in
  391. let arg = ArgumentDefinition(
  392. container: Bare<Value>.self,
  393. key: key,
  394. kind: .positional,
  395. help: help,
  396. parsingStrategy: .default,
  397. transform: transform,
  398. initial: wrappedValue,
  399. completion: completion)
  400. return ArgumentSet(arg)
  401. })
  402. }
  403. /// Creates a property with no default value, parsing with the given closure.
  404. ///
  405. /// This method is called to initialize an `Argument` with no default value such as:
  406. /// ```swift
  407. /// @Argument(transform: baz)
  408. /// var foo: String
  409. /// ```
  410. ///
  411. /// - Parameters:
  412. /// - help: Information about how to use this argument.
  413. /// - completion: Kind of completion provided to the user for this option.
  414. /// - transform: A closure that converts a string into this property's
  415. /// element type or throws an error.
  416. @preconcurrency
  417. @_disfavoredOverload
  418. public init(
  419. help: ArgumentHelp? = nil,
  420. completion: CompletionKind? = nil,
  421. transform: @Sendable @escaping (String) throws -> Value
  422. ) {
  423. self.init(
  424. _parsedValue: .init { key in
  425. let arg = ArgumentDefinition(
  426. container: Bare<Value>.self,
  427. key: key,
  428. kind: .positional,
  429. help: help,
  430. parsingStrategy: .default,
  431. transform: transform,
  432. initial: nil,
  433. completion: completion)
  434. return ArgumentSet(arg)
  435. })
  436. }
  437. }
  438. // MARK: - @Argument Optional<T: ExpressibleByArgument> Initializers
  439. extension Argument {
  440. /// This initializer allows a user to provide a `nil` default value for an
  441. /// optional `@Argument`-marked property without allowing a non-`nil` default
  442. /// value.
  443. ///
  444. /// - Parameters:
  445. /// - wrappedValue: A default value to use for this property, provided
  446. /// implicitly by the compiler during property wrapper initialization.
  447. /// - help: Information about how to use this argument.
  448. /// - completion: Kind of completion provided to the user for this option.
  449. public init<T>(
  450. wrappedValue: _OptionalNilComparisonType,
  451. help: ArgumentHelp? = nil,
  452. completion: CompletionKind? = nil
  453. ) where T: ExpressibleByArgument, Value == T? {
  454. self.init(
  455. _parsedValue: .init { key in
  456. let arg = ArgumentDefinition(
  457. container: Optional<T>.self,
  458. key: key,
  459. kind: .positional,
  460. help: help,
  461. parsingStrategy: .default,
  462. initial: nil,
  463. completion: completion)
  464. return ArgumentSet(arg)
  465. })
  466. }
  467. @available(
  468. *, deprecated,
  469. message: """
  470. Optional @Arguments with default values should be declared as non-Optional.
  471. """
  472. )
  473. @_disfavoredOverload
  474. public init<T>(
  475. wrappedValue _wrappedValue: T?,
  476. help: ArgumentHelp? = nil,
  477. completion: CompletionKind? = nil
  478. ) where T: ExpressibleByArgument, Value == T? {
  479. self.init(
  480. _parsedValue: .init { key in
  481. let arg = ArgumentDefinition(
  482. container: Optional<T>.self,
  483. key: key,
  484. kind: .positional,
  485. help: help,
  486. parsingStrategy: .default,
  487. initial: _wrappedValue,
  488. completion: completion)
  489. return ArgumentSet(arg)
  490. })
  491. }
  492. /// Creates an optional property that reads its value from an argument.
  493. ///
  494. /// The argument is optional for the caller of the command and defaults to
  495. /// `nil`.
  496. ///
  497. /// - Parameters:
  498. /// - help: Information about how to use this argument.
  499. /// - completion: Kind of completion provided to the user for this option.
  500. public init<T>(
  501. help: ArgumentHelp? = nil,
  502. completion: CompletionKind? = nil
  503. ) where T: ExpressibleByArgument, Value == T? {
  504. self.init(
  505. _parsedValue: .init { key in
  506. let arg = ArgumentDefinition(
  507. container: Optional<T>.self,
  508. key: key,
  509. kind: .positional,
  510. help: help,
  511. parsingStrategy: .default,
  512. initial: nil,
  513. completion: completion)
  514. return ArgumentSet(arg)
  515. })
  516. }
  517. }
  518. // MARK: - @Argument Optional<T> Initializers
  519. extension Argument {
  520. /// This initializer allows a user to provide a `nil` default value for an
  521. /// optional `@Argument`-marked property without allowing a non-`nil` default
  522. /// value.
  523. ///
  524. /// - Parameters:
  525. /// - wrappedValue: A default value to use for this property, provided
  526. /// implicitly by the compiler during property wrapper initialization.
  527. /// - help: Information about how to use this argument.
  528. /// - completion: Kind of completion provided to the user for this option.
  529. /// - transform: A closure that converts a string into this property's
  530. /// element type or throws an error.
  531. @preconcurrency
  532. public init<T>(
  533. wrappedValue: _OptionalNilComparisonType,
  534. help: ArgumentHelp? = nil,
  535. completion: CompletionKind? = nil,
  536. transform: @Sendable @escaping (String) throws -> T
  537. ) where Value == T? {
  538. self.init(
  539. _parsedValue: .init { key in
  540. let arg = ArgumentDefinition(
  541. container: Optional<T>.self,
  542. key: key,
  543. kind: .positional,
  544. help: help,
  545. parsingStrategy: .default,
  546. transform: transform,
  547. initial: nil,
  548. completion: completion)
  549. return ArgumentSet(arg)
  550. })
  551. }
  552. @available(
  553. *, deprecated,
  554. message: """
  555. Optional @Arguments with default values should be declared as non-Optional.
  556. """
  557. )
  558. @_disfavoredOverload
  559. @preconcurrency
  560. public init<T>(
  561. wrappedValue _wrappedValue: T?,
  562. help: ArgumentHelp? = nil,
  563. completion: CompletionKind? = nil,
  564. transform: @Sendable @escaping (String) throws -> T
  565. ) where Value == T? {
  566. self.init(
  567. _parsedValue: .init { key in
  568. let arg = ArgumentDefinition(
  569. container: Optional<T>.self,
  570. key: key,
  571. kind: .positional,
  572. help: help,
  573. parsingStrategy: .default,
  574. transform: transform,
  575. initial: _wrappedValue,
  576. completion: completion)
  577. return ArgumentSet(arg)
  578. })
  579. }
  580. /// Creates an optional property that reads its value from an argument.
  581. ///
  582. /// The argument is optional for the caller of the command and defaults to
  583. /// `nil`.
  584. ///
  585. /// - Parameters:
  586. /// - help: Information about how to use this argument.
  587. /// - completion: Kind of completion provided to the user for this option.
  588. /// - transform: A closure that converts a string into this property's
  589. /// element type or throws an error.
  590. @preconcurrency
  591. public init<T>(
  592. help: ArgumentHelp? = nil,
  593. completion: CompletionKind? = nil,
  594. transform: @Sendable @escaping (String) throws -> T
  595. ) where Value == T? {
  596. self.init(
  597. _parsedValue: .init { key in
  598. let arg = ArgumentDefinition(
  599. container: Optional<T>.self,
  600. key: key,
  601. kind: .positional,
  602. help: help,
  603. parsingStrategy: .default,
  604. transform: transform,
  605. initial: nil,
  606. completion: completion)
  607. return ArgumentSet(arg)
  608. })
  609. }
  610. }
  611. // MARK: - @Argument Array<T: ExpressibleByArgument> Initializers
  612. extension Argument {
  613. /// Creates a property that reads an array from zero or more arguments.
  614. ///
  615. /// - Parameters:
  616. /// - wrappedValue: A default value to use for this property.
  617. /// - parsingStrategy: The behavior to use when parsing multiple values from
  618. /// the command-line arguments.
  619. /// - help: Information about how to use this argument.
  620. /// - completion: Kind of completion provided to the user for this option.
  621. public init<T>(
  622. wrappedValue: [T],
  623. parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
  624. help: ArgumentHelp? = nil,
  625. completion: CompletionKind? = nil
  626. ) where T: ExpressibleByArgument, Value == [T] {
  627. self.init(
  628. _parsedValue: .init { key in
  629. let arg = ArgumentDefinition(
  630. container: Array<T>.self,
  631. key: key,
  632. kind: .positional,
  633. help: help,
  634. parsingStrategy: parsingStrategy.base,
  635. initial: wrappedValue,
  636. completion: completion)
  637. return ArgumentSet(arg)
  638. })
  639. }
  640. /// Creates a property with no default value that reads an array from zero or
  641. /// more arguments.
  642. ///
  643. /// This method is called to initialize an array `Argument` with no default
  644. /// value such as:
  645. /// ```swift
  646. /// @Argument()
  647. /// var foo: [String]
  648. /// ```
  649. ///
  650. /// - Parameters:
  651. /// - parsingStrategy: The behavior to use when parsing multiple values from
  652. /// the command-line arguments.
  653. /// - help: Information about how to use this argument.
  654. /// - completion: Kind of completion provided to the user for this option.
  655. public init<T>(
  656. parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
  657. help: ArgumentHelp? = nil,
  658. completion: CompletionKind? = nil
  659. ) where T: ExpressibleByArgument, Value == [T] {
  660. self.init(
  661. _parsedValue: .init { key in
  662. let arg = ArgumentDefinition(
  663. container: Array<T>.self,
  664. key: key,
  665. kind: .positional,
  666. help: help,
  667. parsingStrategy: parsingStrategy.base,
  668. initial: nil,
  669. completion: completion)
  670. return ArgumentSet(arg)
  671. })
  672. }
  673. }
  674. // MARK: - @Argument Array<T> Initializers
  675. extension Argument {
  676. /// Creates a property that reads an array from zero or more arguments,
  677. /// parsing each element with the given closure.
  678. ///
  679. /// - Parameters:
  680. /// - wrappedValue: A default value to use for this property.
  681. /// - parsingStrategy: The behavior to use when parsing multiple values from
  682. /// the command-line arguments.
  683. /// - help: Information about how to use this argument.
  684. /// - completion: Kind of completion provided to the user for this option.
  685. /// - transform: A closure that converts a string into this property's
  686. /// element type or throws an error.
  687. @preconcurrency
  688. public init<T>(
  689. wrappedValue: [T],
  690. parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
  691. help: ArgumentHelp? = nil,
  692. completion: CompletionKind? = nil,
  693. transform: @Sendable @escaping (String) throws -> T
  694. ) where Value == [T] {
  695. self.init(
  696. _parsedValue: .init { key in
  697. let arg = ArgumentDefinition(
  698. container: Array<T>.self,
  699. key: key,
  700. kind: .positional,
  701. help: help,
  702. parsingStrategy: parsingStrategy.base,
  703. transform: transform,
  704. initial: wrappedValue,
  705. completion: completion)
  706. return ArgumentSet(arg)
  707. })
  708. }
  709. /// Creates a property with no default value that reads an array from zero or
  710. /// more arguments, parsing each element with the given closure.
  711. ///
  712. /// This method is called to initialize an array `Argument` with no default
  713. /// value such as:
  714. /// ```swift
  715. /// @Argument(transform: baz)
  716. /// var foo: [String]
  717. /// ```
  718. ///
  719. /// - Parameters:
  720. /// - parsingStrategy: The behavior to use when parsing multiple values from
  721. /// the command-line arguments.
  722. /// - help: Information about how to use this argument.
  723. /// - completion: Kind of completion provided to the user for this option.
  724. /// - transform: A closure that converts a string into this property's
  725. /// element type or throws an error.
  726. @preconcurrency
  727. public init<T>(
  728. parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
  729. help: ArgumentHelp? = nil,
  730. completion: CompletionKind? = nil,
  731. transform: @Sendable @escaping (String) throws -> T
  732. ) where Value == [T] {
  733. self.init(
  734. _parsedValue: .init { key in
  735. let arg = ArgumentDefinition(
  736. container: Array<T>.self,
  737. key: key,
  738. kind: .positional,
  739. help: help,
  740. parsingStrategy: parsingStrategy.base,
  741. transform: transform,
  742. initial: nil,
  743. completion: completion)
  744. return ArgumentSet(arg)
  745. })
  746. }
  747. }