Feature: Add check for overlapping xor and and groups (#443)
* Docs: Clean and group description * Feat: Add check for overlapping xor and and groups Co-authored-by: inful <jone.marius@vign.es> * Chore: Rewrite overlap err to avoid duplicated words --------- Co-authored-by: inful <jone.marius@vign.es>
This commit is contained in:
@@ -577,7 +577,7 @@ Both can coexist with standard Tag parsing.
|
|||||||
| `enum:"X,Y,..."` | Set of valid values allowed for this flag. An enum field must be `required` or have a valid `default`. |
|
| `enum:"X,Y,..."` | Set of valid values allowed for this flag. An enum field must be `required` or have a valid `default`. |
|
||||||
| `group:"X"` | Logical group for a flag or command. |
|
| `group:"X"` | Logical group for a flag or command. |
|
||||||
| `xor:"X,Y,..."` | Exclusive OR groups for flags. Only one flag in the group can be used which is restricted within the same command. When combined with `required`, at least one of the `xor` group will be required. |
|
| `xor:"X,Y,..."` | Exclusive OR groups for flags. Only one flag in the group can be used which is restricted within the same command. When combined with `required`, at least one of the `xor` group will be required. |
|
||||||
| `and:"X,Y,..."` | Exclusive AND groups for flags. All flags in the group must be used in the same command. When combined with `required`, all flags in the group will be required. |
|
| `and:"X,Y,..."` | AND groups for flags. All flags in the group must be used in the same command. When combined with `required`, all flags in the group will be required. |
|
||||||
| `prefix:"X"` | Prefix for all sub-flags. |
|
| `prefix:"X"` | Prefix for all sub-flags. |
|
||||||
| `envprefix:"X"` | Envar prefix for all sub-flags. |
|
| `envprefix:"X"` | Envar prefix for all sub-flags. |
|
||||||
| `set:"K=V"` | Set a variable for expansion by child elements. Multiples can occur. |
|
| `set:"K=V"` | Set a variable for expansion by child elements. Multiples can occur. |
|
||||||
|
|||||||
@@ -167,9 +167,42 @@ func New(grammar interface{}, options ...Option) (*Kong, error) {
|
|||||||
|
|
||||||
k.bindings.add(k.vars)
|
k.bindings.add(k.vars)
|
||||||
|
|
||||||
|
if err = checkOverlappingXorAnd(k); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return k, nil
|
return k, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkOverlappingXorAnd(k *Kong) error {
|
||||||
|
xorGroups := map[string][]string{}
|
||||||
|
andGroups := map[string][]string{}
|
||||||
|
for _, flag := range k.Model.Node.Flags {
|
||||||
|
for _, xor := range flag.Xor {
|
||||||
|
xorGroups[xor] = append(xorGroups[xor], flag.Name)
|
||||||
|
}
|
||||||
|
for _, and := range flag.And {
|
||||||
|
andGroups[and] = append(andGroups[and], flag.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for xor, xorSet := range xorGroups {
|
||||||
|
for and, andSet := range andGroups {
|
||||||
|
overlappingEntries := []string{}
|
||||||
|
for _, xorTag := range xorSet {
|
||||||
|
for _, andTag := range andSet {
|
||||||
|
if xorTag == andTag {
|
||||||
|
overlappingEntries = append(overlappingEntries, xorTag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(overlappingEntries) > 1 {
|
||||||
|
return fmt.Errorf("invalid xor and combination, %s and %s overlap with more than one: %s", xor, and, overlappingEntries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type varStack []Vars
|
type varStack []Vars
|
||||||
|
|
||||||
func (v *varStack) head() Vars { return (*v)[len(*v)-1] }
|
func (v *varStack) head() Vars { return (*v)[len(*v)-1] }
|
||||||
|
|||||||
@@ -1026,6 +1026,16 @@ func TestXorAnd(t *testing.T) {
|
|||||||
assert.EqualError(t, err, "--hello and --one can't be used together, --hello and --two must be used together")
|
assert.EqualError(t, err, "--hello and --one can't be used together, --hello and --two must be used together")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOverLappingXorAnd(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Hello bool `xor:"one" and:"two"`
|
||||||
|
One bool `xor:"one" and:"two"`
|
||||||
|
Two string `xor:"one" and:"two"`
|
||||||
|
}
|
||||||
|
_, err := kong.New(&cli)
|
||||||
|
assert.EqualError(t, err, "invalid xor and combination, one and two overlap with more than one: [hello one two]")
|
||||||
|
}
|
||||||
|
|
||||||
func TestXorRequired(t *testing.T) {
|
func TestXorRequired(t *testing.T) {
|
||||||
var cli struct {
|
var cli struct {
|
||||||
One bool `xor:"one,two" required:""`
|
One bool `xor:"one,two" required:""`
|
||||||
|
|||||||
Reference in New Issue
Block a user