feat: Begins vault commands, adds nodes for rendering discussion documentation.
This commit is contained in:
108
Sources/hpa/Internal/CommandConfigurationExtensions.swift
Normal file
108
Sources/hpa/Internal/CommandConfigurationExtensions.swift
Normal file
@@ -0,0 +1,108 @@
|
||||
import ArgumentParser
|
||||
import Rainbow
|
||||
|
||||
extension CommandConfiguration {
|
||||
|
||||
static func create(
|
||||
commandName: String,
|
||||
abstract: String,
|
||||
usesExtraArgs: Bool = true,
|
||||
discussion nodes: [Node]
|
||||
) -> Self {
|
||||
.init(
|
||||
commandName: commandName,
|
||||
abstract: createAbstract(abstract),
|
||||
discussion: Discussion(nodes: nodes, usesExtraArgs: usesExtraArgs).render()
|
||||
)
|
||||
}
|
||||
|
||||
static func playbook(
|
||||
commandName: String,
|
||||
abstract: String,
|
||||
parentCommand: String? = nil,
|
||||
examples: (label: String, example: String)...
|
||||
) -> Self {
|
||||
.create(
|
||||
commandName: commandName,
|
||||
abstract: abstract,
|
||||
discussion: [.note(label: "Most options are not required if you have a configuration file setup.")]
|
||||
+ examples.nodes(parentCommand)
|
||||
+ [.seeAlso(label: "Ansible playbook options.", command: "ansible-playbook")]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func createAbstract(_ string: String) -> String {
|
||||
"\(string.blue)"
|
||||
}
|
||||
|
||||
struct Discussion {
|
||||
var nodes: [Node]
|
||||
|
||||
init(usesExtraArgs: Bool = true, _ nodes: Node...) {
|
||||
self.init(nodes: nodes, usesExtraArgs: usesExtraArgs)
|
||||
}
|
||||
|
||||
init(nodes: [Node], usesExtraArgs: Bool = true) {
|
||||
var nodes = nodes
|
||||
|
||||
if let firstExampleIndex = nodes.firstIndex(where: \.isExampleNode) {
|
||||
nodes.insert(.exampleHeading, at: firstExampleIndex)
|
||||
}
|
||||
|
||||
if usesExtraArgs {
|
||||
if let lastExampleIndex = nodes.lastIndex(where: \.isExampleNode) {
|
||||
let last = nodes[lastExampleIndex]
|
||||
if case let .example(_, example, parent) = last {
|
||||
nodes.insert(
|
||||
.example(label: "Passing extra args.", example: example, parentCommand: parent),
|
||||
at: nodes.index(after: lastExampleIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.nodes = nodes
|
||||
}
|
||||
|
||||
func render() -> String {
|
||||
nodes.map { $0.render() }.joined(separator: "\n")
|
||||
}
|
||||
}
|
||||
|
||||
enum Node: Equatable {
|
||||
case note(header: String = "NOTE:", label: String, appendNewLine: Bool = true)
|
||||
case example(label: String, example: String, parentCommand: String?)
|
||||
case seeAlso(label: String, command: String, appendHelpToCommand: Bool = true)
|
||||
|
||||
static var exampleHeading: Self { .note(header: "Examples:", label: "Some common examples.", appendNewLine: false) }
|
||||
|
||||
var isExampleNode: Bool {
|
||||
if case .example = self { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
func render() -> String {
|
||||
switch self {
|
||||
case let .note(header, note, appendNewLine):
|
||||
return "\(header.yellow) \(note.italic)\(appendNewLine ? "\n" : "")"
|
||||
case let .example(label: label, example: example, parentCommand: parent):
|
||||
return """
|
||||
\(label.green.italic)
|
||||
$ \(Constants.appName) \(parent ?? "")\(parent != nil ? " \(example)" : example)
|
||||
|
||||
"""
|
||||
case let .seeAlso(label: label, command: command, appendHelpToCommand: appendHelp):
|
||||
return """
|
||||
\("See Also:".yellow) \(label.italic)
|
||||
$ \(command)\(appendHelp ? " --help" : "")
|
||||
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension Array where Element == (label: String, example: String) {
|
||||
func nodes(_ parentCommand: String?) -> [Node] {
|
||||
map { .example(label: $0.label, example: $0.example, parentCommand: parentCommand) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user