-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhelp.ts
131 lines (117 loc) · 4.13 KB
/
help.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import * as Discord from '../Discord';
import Command from '../Command';
import CommandOption from '../CommandOption';
import { bold, pluralize } from '../format';
import SubCommand from '../SubCommand';
import {
ctxCanRunCommand,
countCtxAccessibleSubCommands,
convertCommandListToOptionsList,
checkCtxPermissions,
} from './_utils';
import commandList from './commands';
const help = new Command({
name: 'help',
displayName: 'Help',
description: 'Displays usage information about HooskBot’s available commands',
options: [
new CommandOption({
name: 'command',
description: 'Get information about a specific command',
required: false,
choices: convertCommandListToOptionsList(commandList),
type: Discord.CommandOptionType.STRING,
}),
],
handler: async ctx => {
const chosenCommand = ctx.getArgument<string>('command')?.trim();
if (chosenCommand) {
const sections: { name: string; description: string }[] = [];
let heading = '';
// Find the command with the given name.
const command =
commandList.find(element => element.name === chosenCommand) ??
commandList[0];
const subCommands = Object.values(command.subCommands);
if (subCommands.length > 0 && subCommands[0] instanceof SubCommand) {
heading = '\n\nSubcommands:';
for (const sub of subCommands) {
// Make sure we only count subcommands.
if (!(sub instanceof SubCommand)) continue;
if (checkCtxPermissions(ctx, sub.requiredPerms)[1]) {
sections.push({
name: `/${command.name} ` + sub.name,
description: sub.props.description,
});
}
}
} else if ((command.props.options ?? []).length > 0) {
// If the command has no subcommands but it has parameters, then list
// the parameters.
heading = '\n\nCommand parameters:';
for (const option of command.props.options ?? []) {
let name = option.name;
if (!option.props.required) {
name += ' (optional)';
}
sections.push({
name: name,
description: option.props.description,
});
}
}
// Map section groups to Discord embed fields
const fields: Discord.EmbedField[] = sections.map(sec => ({
name: sec.name, // The section name
value: sec.description, // The section description
}));
return ctx.interactionApi.respondSilentlyWithEmbed({
type: Discord.EmbedType.RICH,
title: `Usage information for ${bold('/' + command.name)}`,
description: command.props.description + (heading && bold(heading)),
fields,
});
}
// No specific command was chosen, so output entire command list.
const displayedCmds: {
name: string;
description: string;
subCommands: string;
}[] = [];
// Sort the commands in alphabetical order of name. The spread operator makes
// a shallow copy of the command list.
const sortedCmdList = [...commandList].sort((a, b) =>
a.name.localeCompare(b.name),
);
for (const cmd of sortedCmdList) {
if (ctxCanRunCommand(ctx, cmd)) {
let subCommands = '';
const subCommandCount = countCtxAccessibleSubCommands(ctx, cmd);
if (subCommandCount > 0) {
subCommands = ` (${subCommandCount} ${pluralize(
'subcommand',
subCommandCount,
)})`;
}
displayedCmds.push({
name: cmd.name,
description: cmd.props.description,
subCommands: subCommands,
});
}
}
// Map commands to Discord embed fields
const fields: Discord.EmbedField[] = displayedCmds.map(cmd => ({
name: '/' + cmd.name, // The command name
value: cmd.description + cmd.subCommands, // The command description
}));
return await ctx.interactionApi.respondSilentlyWithEmbed({
type: Discord.EmbedType.RICH,
title: 'Command List',
description:
'Run `/help [command]` to view more information about a specific command.',
fields,
});
},
});
export default help;