85 lines
2.3 KiB
Go
85 lines
2.3 KiB
Go
package commandkit
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// Register adds a batch of declarations to the application. The complete batch
|
|
// is validated before registry mutation; on error the registry and its derived
|
|
// command metadata remain unchanged. A successful nonempty batch becomes
|
|
// visible to later invocations. Declarations remain reusable.
|
|
func (a *App) Register(declarations ...Declaration) error {
|
|
return a.installBatch(declarations...)
|
|
}
|
|
|
|
func (a *App) installBatch(declarations ...Declaration) error {
|
|
if a == nil {
|
|
return fmt.Errorf("cannot register commands on a nil app")
|
|
}
|
|
commands := make([]Command, 0, len(declarations))
|
|
rules := make([]RoutingRule, 0)
|
|
for _, declaration := range declarations {
|
|
switch value := declaration.(type) {
|
|
case Command:
|
|
commands = append(commands, value)
|
|
case *Command:
|
|
if value == nil {
|
|
return fmt.Errorf("nil *Command declaration")
|
|
}
|
|
commands = append(commands, *value)
|
|
case RoutingRule:
|
|
rules = append(rules, value)
|
|
case *RoutingRule:
|
|
if value == nil {
|
|
return fmt.Errorf("nil *RoutingRule declaration")
|
|
}
|
|
rules = append(rules, *value)
|
|
case nil:
|
|
return fmt.Errorf("nil declaration")
|
|
default:
|
|
return fmt.Errorf("unsupported declaration type %T", declaration)
|
|
}
|
|
}
|
|
|
|
pending := make(map[string]*commandNode, len(commands))
|
|
for _, command := range commands {
|
|
if err := validateCommandPlacement(command); err != nil {
|
|
return err
|
|
}
|
|
if command.record.absent {
|
|
continue
|
|
}
|
|
name := command.record.name
|
|
if _, exists := a.commands[name]; exists {
|
|
return fmt.Errorf("command path %q is already registered", name)
|
|
}
|
|
if _, exists := pending[name]; exists {
|
|
return fmt.Errorf("command path %q is already registered", name)
|
|
}
|
|
pending[name] = &commandNode{command: command}
|
|
}
|
|
for _, rule := range rules {
|
|
if rule.record == nil {
|
|
return fmt.Errorf("invalid zero routing rule declaration")
|
|
}
|
|
if len(rule.record.issues) > 0 {
|
|
return fmt.Errorf("routing rule: %w", errors.Join(rule.record.issues...))
|
|
}
|
|
}
|
|
if len(pending) == 0 && len(rules) == 0 {
|
|
return nil
|
|
}
|
|
if a.commands == nil {
|
|
a.commands = make(map[string]*commandNode, len(pending))
|
|
}
|
|
for name, node := range pending {
|
|
a.commands[name] = node
|
|
}
|
|
a.routingRules = append(a.routingRules, rules...)
|
|
if len(pending) > 0 {
|
|
a.snapshot = nil
|
|
}
|
|
return nil
|
|
}
|