Separate validation into a distinct step.
This allows help to be called even when the parse trace is invalid. Without this, the command-line would have to be valid in order to use help at all, which defeats the purpose.
This commit is contained in:
committed by
Gerald Kaszuba
parent
afbb431641
commit
fdc7230e22
@@ -1,27 +1,70 @@
|
||||
package kong
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
Node
|
||||
HelpFlag *Flag
|
||||
}
|
||||
|
||||
// A Branch is a command or positional argument that results in a branch in the command tree.
|
||||
type Branch struct {
|
||||
Command *Command
|
||||
Argument *Argument
|
||||
// Leaves returns the leaf commands/arguments in the command-line grammar.
|
||||
func (a *Application) Leaves() (out []*Node) {
|
||||
var walk func(n *Node)
|
||||
walk = func(n *Node) {
|
||||
if len(n.Children) == 0 {
|
||||
out = append(out, n)
|
||||
}
|
||||
for _, child := range n.Children {
|
||||
if child.Type == CommandNode || child.Type == ArgumentNode {
|
||||
walk(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(&a.Node)
|
||||
return
|
||||
}
|
||||
|
||||
type Argument = Node
|
||||
|
||||
type Command = Node
|
||||
|
||||
type NodeType int
|
||||
|
||||
const (
|
||||
ApplicationNode NodeType = iota
|
||||
CommandNode
|
||||
ArgumentNode
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Type NodeType
|
||||
Parent *Node
|
||||
Name string
|
||||
Help string
|
||||
Flags []*Flag
|
||||
Positional []*Value
|
||||
Children []*Branch
|
||||
Target reflect.Value
|
||||
Positional []*Positional
|
||||
Children []*Node
|
||||
Target reflect.Value // Pointer to the value in the grammar that this Node is associated with.
|
||||
|
||||
Argument *Value // Populated when Type is ArgumentNode.
|
||||
}
|
||||
|
||||
// Path through ancestors to this Node.
|
||||
func (n *Node) Path() (out string) {
|
||||
if n.Parent != nil {
|
||||
out += " " + n.Parent.Path()
|
||||
}
|
||||
switch n.Type {
|
||||
case ApplicationNode, CommandNode:
|
||||
out += " " + n.Name
|
||||
case ArgumentNode:
|
||||
out += " " + "<" + n.Name + ">"
|
||||
}
|
||||
return strings.TrimSpace(out)
|
||||
}
|
||||
|
||||
// A Value is either a flag or a variable positional argument.
|
||||
@@ -36,6 +79,11 @@ type Value struct {
|
||||
Required bool
|
||||
Set bool // Used with Required to test if a value has been given.
|
||||
Format string // Formatting directive, if applicable.
|
||||
Position int // Position (for positional arguments).
|
||||
}
|
||||
|
||||
func (v *Value) IsBool() bool {
|
||||
return v.Value.Kind() == reflect.Bool
|
||||
}
|
||||
|
||||
// Parse tokens into value, parse, and validate, but do not write to the field.
|
||||
@@ -69,14 +117,28 @@ func (v *Value) Reset() error {
|
||||
|
||||
type Positional = Value
|
||||
|
||||
type Argument struct {
|
||||
Node
|
||||
Argument *Value
|
||||
}
|
||||
|
||||
type Flag struct {
|
||||
Value
|
||||
Placeholder string
|
||||
PlaceHolder string
|
||||
Env string
|
||||
Short rune
|
||||
Hidden bool
|
||||
}
|
||||
|
||||
func (f *Flag) FormatPlaceHolder() string {
|
||||
if f.PlaceHolder != "" {
|
||||
return f.PlaceHolder
|
||||
}
|
||||
if f.Default != "" {
|
||||
ellipsis := ""
|
||||
if len(f.Default) > 1 {
|
||||
ellipsis = "..."
|
||||
}
|
||||
|
||||
if f.Value.Value.Kind() == reflect.String {
|
||||
return strconv.Quote(f.Default) + ellipsis
|
||||
}
|
||||
return f.Default + ellipsis
|
||||
}
|
||||
return strings.ToUpper(f.Name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user