Skip to content

Commit c61fc0f

Browse files
authored
Fix AsyncParseableCommand hierarchy (apple#436)
1 parent 48a799e commit c61fc0f

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

Sources/ArgumentParser/Parsable Types/AsyncParsableCommand.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,3 @@ extension AsyncMainProtocol {
7373
}
7474
}
7575
}
76-

Sources/ArgumentParser/Parsable Types/ParsableCommand.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ extension ParsableCommand {
8484
public static func helpMessage(
8585
for subcommand: ParsableCommand.Type,
8686
columns: Int? = nil
87-
) -> String {
87+
) -> String {
8888
helpMessage(for: subcommand, includeHidden: false, columns: columns)
8989
}
9090

@@ -124,6 +124,13 @@ extension ParsableCommand {
124124
/// - Parameter arguments: An array of arguments to use for parsing. If
125125
/// `arguments` is `nil`, this uses the program's command-line arguments.
126126
public static func main(_ arguments: [String]?) {
127+
128+
#if DEBUG
129+
if #available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *) {
130+
checkAsyncHierarchy(self, root: "\(self)")
131+
}
132+
#endif
133+
127134
do {
128135
var command = try parseAsRoot(arguments)
129136
try command.run()
@@ -164,4 +171,28 @@ extension ParsableCommand {
164171
internal static var defaultIncludesUnconditionalArguments: Bool {
165172
configuration.defaultSubcommand?.includesUnconditionalArguments == true
166173
}
174+
175+
#if DEBUG
176+
@available(macOS 10.15, macCatalyst 13, iOS 13, tvOS 13, watchOS 6, *)
177+
internal static func checkAsyncHierarchy(_ command: ParsableCommand.Type, root: String) {
178+
for sub in command.configuration.subcommands {
179+
checkAsyncHierarchy(sub, root: root)
180+
181+
guard sub.configuration.subcommands.isEmpty else { continue }
182+
guard sub is AsyncParsableCommand.Type else { continue }
183+
184+
fatalError("""
185+
186+
--------------------------------------------------------------------
187+
Asynchronous subcommand of a synchronous root.
188+
189+
The asynchronous command `\(sub)` is declared as a subcommand of the synchronous root command `\(root)`.
190+
191+
With this configuration, your asynchronous `run()` method will not be called. To fix this issue, change `\(root)`'s `ParsableCommand` conformance to `AsyncParsableCommand`.
192+
--------------------------------------------------------------------
193+
194+
""".wrapped(to: 70))
195+
}
196+
}
197+
#endif
167198
}

0 commit comments

Comments
 (0)