feat: Allow configuring global hooks via Kong's functional options (#511)

Lets you pass `kong.WithBeforeApply` along with a function that supports dynamic bindings to register a `BeforeApply` hook without tying it directly to a node in the schema.

Co-authored-by: Sutina Wipawiwat <swipawiwat@squareup.com>
This commit is contained in:
Bob Lail
2025-03-21 20:04:20 -07:00
committed by GitHub
parent 1edf069f4a
commit 78d4066dab
5 changed files with 127 additions and 5 deletions
+14 -1
View File
@@ -71,6 +71,8 @@ type Kong struct {
postBuildOptions []Option
embedded []embedded
dynamicCommands []*dynamicCommand
hooks map[string][]reflect.Value
}
// New creates a new Kong parser on grammar.
@@ -84,6 +86,7 @@ func New(grammar any, options ...Option) (*Kong, error) {
registry: NewRegistry().RegisterDefaults(),
vars: Vars{},
bindings: bindings{},
hooks: make(map[string][]reflect.Value),
helpFormatter: DefaultHelpValueFormatter,
ignoreFields: make([]*regexp.Regexp, 0),
flagNamer: func(s string) string {
@@ -366,7 +369,7 @@ func (k *Kong) applyHook(ctx *Context, name string) error {
default:
panic("unsupported Path")
}
for _, method := range getMethods(value, name) {
for _, method := range k.getMethods(value, name) {
binds := k.bindings.clone()
binds.add(ctx, trace)
binds.add(trace.Node().Vars().CloneWith(k.vars))
@@ -380,6 +383,16 @@ func (k *Kong) applyHook(ctx *Context, name string) error {
return k.applyHookToDefaultFlags(ctx, ctx.Path[0].Node(), name)
}
func (k *Kong) getMethods(value reflect.Value, name string) []reflect.Value {
return append(
// Identify callbacks by reflecting on value
getMethods(value, name),
// Identify callbacks that were registered with a kong.Option
k.hooks[name]...,
)
}
// Call hook on any unset flags with default values.
func (k *Kong) applyHookToDefaultFlags(ctx *Context, node *Node, name string) error {
if node == nil {