| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- //===----------------------------------------------------------------------===//
- //
- // This source file is part of the Swift Argument Parser open source project
- //
- // Copyright (c) 2020 Apple Inc. and the Swift project authors
- // Licensed under Apache License v2.0 with Runtime Library Exception
- //
- // See https://swift.org/LICENSE.txt for license information
- //
- //===----------------------------------------------------------------------===//
- #if compiler(>=6.0)
- // import ArgumentParserToolInfo
- #else
- // import ArgumentParserToolInfo
- #endif
- internal struct DumpHelpGenerator {
- private var toolInfo: ToolInfoV0
- init(_ type: ParsableArguments.Type) {
- self.init(commandStack: [type.asCommand])
- }
- init(commandStack: [ParsableCommand.Type]) {
- self.toolInfo = ToolInfoV0(commandStack: commandStack)
- }
- func rendered() -> String {
- return ArgParserJSONEncoder.encode(self.toolInfo)
- }
- }
- extension BidirectionalCollection where Element == ParsableCommand.Type {
- /// Returns the ArgumentSet for the last command in this stack, including
- /// help and version flags, when appropriate.
- fileprivate func allArguments() -> ArgumentSet {
- guard
- var arguments = self.last.map({
- ArgumentSet($0, visibility: .private, parent: nil)
- })
- else { return ArgumentSet() }
- self.versionArgumentDefinition().map { arguments.append($0) }
- self.helpArgumentDefinition().map { arguments.append($0) }
- return arguments
- }
- }
- extension ToolInfoV0 {
- init(commandStack: [ParsableCommand.Type]) {
- self.init(command: CommandInfoV0(commandStack: commandStack))
- // FIXME: This is a hack to inject the help command into the tool info
- // instead we should try to lift this into the parseable command tree
- self.command.subcommands =
- (self.command.subcommands ?? []) + [
- CommandInfoV0(commandStack: commandStack + [HelpCommand.self])
- ]
- }
- }
- extension CommandInfoV0 {
- fileprivate init(commandStack: [ParsableCommand.Type]) {
- guard let command = commandStack.last else {
- preconditionFailure("commandStack must not be empty")
- }
- let parents = commandStack.dropLast()
- var superCommands = parents.map { $0._commandName }
- if let superName = parents.first?.configuration._superCommandName {
- superCommands.insert(superName, at: 0)
- }
- let defaultSubcommand = command.configuration.defaultSubcommand?
- .configuration.commandName
- let subcommands = command.configuration.subcommands
- .map { subcommand -> CommandInfoV0 in
- var commandStack = commandStack
- commandStack.append(subcommand)
- return CommandInfoV0(commandStack: commandStack)
- }
- let arguments =
- commandStack
- .allArguments()
- .compactMap(ArgumentInfoV0.init)
- self = CommandInfoV0(
- superCommands: superCommands,
- shouldDisplay: command.configuration.shouldDisplay,
- commandName: command._commandName,
- aliases: command.configuration.aliases,
- abstract: command.configuration.abstract,
- discussion: command.configuration.discussion,
- defaultSubcommand: defaultSubcommand,
- subcommands: subcommands,
- arguments: arguments)
- }
- }
- extension ArgumentInfoV0 {
- fileprivate init?(argument: ArgumentDefinition) {
- guard let kind = ArgumentInfoV0.KindV0(argument: argument) else {
- return nil
- }
- let discussion: String?
- let allValueDescriptions: [String: String]?
- switch argument.help.discussion {
- case .none:
- discussion = nil
- allValueDescriptions = nil
- case .staticText(let _discussion):
- discussion = _discussion
- allValueDescriptions = nil
- case .enumerated(let _discussion, let options):
- discussion = _discussion
- allValueDescriptions = options.allValueDescriptions
- }
- self.init(
- kind: kind,
- shouldDisplay: argument.help.visibility.base == .default,
- sectionTitle: argument.help.parentTitle.nonEmpty,
- isOptional: argument.help.options.contains(.isOptional),
- isRepeating: argument.help.options.contains(.isRepeating),
- parsingStrategy: ArgumentInfoV0.ParsingStrategyV0(argument: argument),
- names: argument.names.map(ArgumentInfoV0.NameInfoV0.init),
- preferredName: argument.names.preferredName.map(
- ArgumentInfoV0.NameInfoV0.init),
- valueName: argument.valueName,
- defaultValue: argument.help.defaultValue,
- allValueStrings: argument.help.allValueStrings,
- allValueDescriptions: allValueDescriptions,
- completionKind: ArgumentInfoV0.CompletionKindV0(
- completion: argument.completion),
- abstract: argument.help.abstract,
- discussion: discussion)
- }
- }
- extension ArgumentInfoV0.KindV0 {
- fileprivate init?(argument: ArgumentDefinition) {
- switch argument.kind {
- case .named:
- switch argument.update {
- case .nullary:
- self = .flag
- case .unary:
- self = .option
- }
- case .positional:
- self = .positional
- case .default:
- return nil
- }
- }
- }
- extension ArgumentInfoV0.ParsingStrategyV0 {
- fileprivate init(argument: ArgumentDefinition) {
- switch argument.parsingStrategy {
- case .`default`:
- self = .default
- case .scanningForValue:
- self = .scanningForValue
- case .unconditional:
- self = .unconditional
- case .upToNextOption:
- self = .upToNextOption
- case .allRemainingInput:
- self = .allRemainingInput
- case .postTerminator:
- self = .postTerminator
- case .allUnrecognized:
- self = .allUnrecognized
- }
- }
- }
- extension ArgumentInfoV0.NameInfoV0 {
- fileprivate init(name: Name) {
- switch name {
- case .long(let n):
- self.init(kind: .long, name: n)
- case .short(let n, _):
- self.init(kind: .short, name: String(n))
- case .longWithSingleDash(let n):
- self.init(kind: .longWithSingleDash, name: n)
- }
- }
- }
- extension ArgumentInfoV0.CompletionKindV0 {
- fileprivate init?(completion: CompletionKind) {
- switch completion.kind {
- case .`default`:
- return nil
- case .list(let values):
- self = .list(values: values)
- case .file(let extensions):
- self = .file(extensions: extensions)
- case .directory:
- self = .directory
- case .shellCommand(let command):
- self = .shellCommand(command: command)
- case .custom(_):
- self = .custom
- case .customAsync(_):
- self = .customAsync
- case .customDeprecated(_):
- self = .customDeprecated
- }
- }
- }
|