feat(commands): improve discovery and normalize parameters

This commit is contained in:
tiennm99 committed 2026-07-21 11:45:20 +07:00
1 parent 3316eec74c
commit f5ba9d4032
31 files changed
+479 -56

No files matched your search

+6
View File
@@ -87,6 +87,12 @@ func TestHelp_RendersHTML(t *testing.T) {
if !strings.Contains(got.Text(), "<b>util</b>") {
t.Errorf("/help body missing util section; got %q", got.Text())
}
if !strings.Contains(got.Text(), "/help. Show all available commands.") {
t.Errorf("/help body missing formatted command summary; got %q", got.Text())
}
if !strings.Contains(got.Text(), "<pre>/help</pre>") {
t.Errorf("/help body missing copyable example; got %q", got.Text())
}
}
func TestStickerID_NoReply_ShowsUsage(t *testing.T) {
+7 -10
View File
@@ -32,16 +32,10 @@ func RenderHelp(reg *modules.Registry) string {
return "no commands registered\n\n" + supportFooter
}
type entry struct {
name string
description string
}
byModule := make(map[string][]entry, len(reg.Modules))
byModule := make(map[string][]modules.Command, len(reg.Modules))
for _, c := range reg.PublicCommands() {
byModule[ownerOf(reg, c.Name)] = append(byModule[ownerOf(reg, c.Name)], entry{
name: c.Name, description: c.Description,
})
byModule[ownerOf(reg, c.Name)] = append(byModule[ownerOf(reg, c.Name)], c)
}
var sections []string
@@ -52,8 +46,11 @@ func RenderHelp(reg *modules.Registry) string {
}
var sb strings.Builder
fmt.Fprintf(&sb, "<b>%s</b>", html.EscapeString(mod.Name))
for _, e := range es {
fmt.Fprintf(&sb, "\n/%s — %s", e.name, html.EscapeString(e.description))
for _, command := range es {
fmt.Fprintf(&sb, "\n%s %s\n<pre>%s</pre>",
html.EscapeString(command.InvocationSentence()),
html.EscapeString(command.SummarySentence()),
html.EscapeString(command.ExampleInvocation()))
}
sections = append(sections, sb.String())
}
+30 -1
View File
@@ -51,7 +51,8 @@ func TestRenderHelp_GroupsByModuleAndSkipsNonPublic(t *testing.T) {
for _, want := range []string{
"<b>alpha</b>",
"<b>beta</b>",
"/a_pub — alpha public",
"/a_pub. alpha public.",
"<pre>/a_pub</pre>",
// HTML in user descriptions must be escaped.
"beta &lt;i&gt;desc&lt;/i&gt;",
// Locks html.EscapeString contract: & → &amp;, " → &#34;.
@@ -71,6 +72,34 @@ func TestRenderHelp_GroupsByModuleAndSkipsNonPublic(t *testing.T) {
}
}
func TestRenderHelp_ShowsParametersAndCopyableExample(t *testing.T) {
command := modules.Command{
Name: "buy",
Visibility: modules.VisibilityPublic,
Description: "Buy & hold",
Parameters: "<quantity> <ticker>",
Example: "/buy 100 TCB",
Handler: helpTestNoop,
}
reg, err := modules.Build(
[]string{"stock"},
map[string]modules.Factory{"stock": fakeFactory("stock", []modules.Command{command})},
storage.NewMemoryProvider(),
modules.BuildOptions{},
)
if err != nil {
t.Fatalf("Build: %v", err)
}
out := util.RenderHelp(reg)
if !strings.Contains(out, "/buy &lt;quantity&gt; &lt;ticker&gt;. Buy &amp; hold.") {
t.Fatalf("help missing formatted invocation and summary:\n%s", out)
}
if !strings.Contains(out, "<pre>/buy 100 TCB</pre>") {
t.Fatalf("help missing copyable example:\n%s", out)
}
}
func TestRenderHelp_ModuleOrderMatchesEnvOrder(t *testing.T) {
cmd := func(name string) modules.Command {
return modules.Command{Name: name, Visibility: modules.VisibilityPublic, Description: name, Handler: helpTestNoop}