reciple 5.4.0 → 5.4.1-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/{bin.js → cjs/bin.js} +0 -0
- package/bin/{index.js → cjs/index.js} +0 -0
- package/bin/{reciple → cjs/reciple}/classes/CommandCooldownManager.js +0 -0
- package/bin/{reciple → cjs/reciple}/classes/MessageCommandOptionManager.js +0 -0
- package/bin/{reciple → cjs/reciple}/classes/RecipleClient.js +0 -0
- package/bin/{reciple → cjs/reciple}/classes/RecipleConfig.js +0 -0
- package/bin/{reciple → cjs/reciple}/classes/builders/MessageCommandBuilder.js +0 -0
- package/bin/{reciple → cjs/reciple}/classes/builders/MessageCommandOptionBuilder.js +0 -0
- package/bin/{reciple → cjs/reciple}/classes/builders/SlashCommandBuilder.js +0 -0
- package/bin/{reciple → cjs/reciple}/flags.js +0 -0
- package/bin/{reciple → cjs/reciple}/logger.js +0 -0
- package/bin/{reciple → cjs/reciple}/modules.js +0 -0
- package/bin/{reciple → cjs/reciple}/permissions.js +0 -0
- package/bin/{reciple → cjs/reciple}/registerApplicationCommands.js +0 -0
- package/bin/{reciple → cjs/reciple}/types/builders.js +0 -0
- package/bin/{reciple → cjs/reciple}/types/commands.js +0 -0
- package/bin/{reciple → cjs/reciple}/types/paramOptions.js +0 -0
- package/bin/{reciple → cjs/reciple}/util.js +0 -0
- package/bin/{reciple → cjs/reciple}/version.js +0 -0
- package/bin/mjs/bin.js +46 -0
- package/bin/{index.d.ts → mjs/index.js} +0 -0
- package/bin/mjs/reciple/classes/CommandCooldownManager.js +87 -0
- package/bin/mjs/reciple/classes/MessageCommandOptionManager.js +21 -0
- package/bin/mjs/reciple/classes/RecipleClient.js +363 -0
- package/bin/mjs/reciple/classes/RecipleConfig.js +92 -0
- package/bin/mjs/reciple/classes/builders/MessageCommandBuilder.js +218 -0
- package/bin/mjs/reciple/classes/builders/MessageCommandOptionBuilder.js +67 -0
- package/bin/mjs/reciple/classes/builders/SlashCommandBuilder.js +204 -0
- package/bin/mjs/reciple/flags.js +28 -0
- package/bin/mjs/reciple/logger.js +28 -0
- package/bin/mjs/reciple/modules.js +81 -0
- package/bin/mjs/reciple/permissions.js +23 -0
- package/bin/mjs/reciple/registerApplicationCommands.js +47 -0
- package/bin/mjs/reciple/types/builders.js +8 -0
- package/bin/mjs/reciple/types/commands.js +12 -0
- package/bin/mjs/reciple/types/paramOptions.js +1 -0
- package/bin/mjs/reciple/util.js +7 -0
- package/bin/mjs/reciple/version.js +38 -0
- package/bin/{bin.d.ts → types/bin.d.ts} +0 -0
- package/bin/types/index.d.ts +17 -0
- package/bin/{reciple → types/reciple}/classes/CommandCooldownManager.d.ts +0 -0
- package/bin/{reciple → types/reciple}/classes/MessageCommandOptionManager.d.ts +0 -0
- package/bin/{reciple → types/reciple}/classes/RecipleClient.d.ts +0 -0
- package/bin/{reciple → types/reciple}/classes/RecipleConfig.d.ts +0 -0
- package/bin/{reciple → types/reciple}/classes/builders/MessageCommandBuilder.d.ts +0 -0
- package/bin/{reciple → types/reciple}/classes/builders/MessageCommandOptionBuilder.d.ts +0 -0
- package/bin/{reciple → types/reciple}/classes/builders/SlashCommandBuilder.d.ts +0 -0
- package/bin/{reciple → types/reciple}/flags.d.ts +0 -0
- package/bin/{reciple → types/reciple}/logger.d.ts +0 -0
- package/bin/{reciple → types/reciple}/modules.d.ts +0 -0
- package/bin/{reciple → types/reciple}/permissions.d.ts +0 -0
- package/bin/{reciple → types/reciple}/registerApplicationCommands.d.ts +0 -0
- package/bin/{reciple → types/reciple}/types/builders.d.ts +1 -1
- package/bin/{reciple → types/reciple}/types/commands.d.ts +0 -0
- package/bin/{reciple → types/reciple}/types/paramOptions.d.ts +0 -0
- package/bin/{reciple → types/reciple}/util.d.ts +0 -0
- package/bin/{reciple → types/reciple}/version.d.ts +0 -0
- package/package.json +13 -8
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { CommandBuilderType } from '../../types/builders';
|
|
2
|
+
import { normalizeArray } from 'discord.js';
|
|
3
|
+
import { MessageCommandOptionManager } from '../MessageCommandOptionManager';
|
|
4
|
+
import { MessageCommandOptionBuilder } from './MessageCommandOptionBuilder';
|
|
5
|
+
/**
|
|
6
|
+
* Reciple builder for message command
|
|
7
|
+
*/
|
|
8
|
+
export class MessageCommandBuilder {
|
|
9
|
+
type = CommandBuilderType.MessageCommand;
|
|
10
|
+
name = '';
|
|
11
|
+
description = '';
|
|
12
|
+
cooldown = 0;
|
|
13
|
+
aliases = [];
|
|
14
|
+
validateOptions = false;
|
|
15
|
+
options = [];
|
|
16
|
+
requiredBotPermissions = [];
|
|
17
|
+
requiredMemberPermissions = [];
|
|
18
|
+
allowExecuteInDM = true;
|
|
19
|
+
allowExecuteByBots = false;
|
|
20
|
+
halt;
|
|
21
|
+
execute = () => { };
|
|
22
|
+
constructor(data) {
|
|
23
|
+
if (data?.name !== undefined)
|
|
24
|
+
this.setName(data.name);
|
|
25
|
+
if (data?.description !== undefined)
|
|
26
|
+
this.setDescription(data.description);
|
|
27
|
+
if (data?.cooldown !== undefined)
|
|
28
|
+
this.setCooldown(Number(data?.cooldown));
|
|
29
|
+
if (data?.requiredBotPermissions !== undefined)
|
|
30
|
+
this.setRequiredBotPermissions(data.requiredBotPermissions);
|
|
31
|
+
if (data?.requiredMemberPermissions !== undefined)
|
|
32
|
+
this.setRequiredMemberPermissions(data.requiredMemberPermissions);
|
|
33
|
+
if (data?.halt !== undefined)
|
|
34
|
+
this.setHalt(this.halt);
|
|
35
|
+
if (data?.execute !== undefined)
|
|
36
|
+
this.setExecute(data.execute);
|
|
37
|
+
if (data?.aliases !== undefined)
|
|
38
|
+
this.addAliases(data.aliases);
|
|
39
|
+
if (data?.allowExecuteByBots)
|
|
40
|
+
this.setAllowExecuteByBots(true);
|
|
41
|
+
if (data?.allowExecuteInDM)
|
|
42
|
+
this.setAllowExecuteInDM(true);
|
|
43
|
+
if (data?.validateOptions)
|
|
44
|
+
this.setValidateOptions(true);
|
|
45
|
+
if (data?.options !== undefined)
|
|
46
|
+
this.options = data.options.map(o => o instanceof MessageCommandOptionBuilder ? o : new MessageCommandOptionBuilder(o));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Sets the command name
|
|
50
|
+
* @param name Command name
|
|
51
|
+
*/
|
|
52
|
+
setName(name) {
|
|
53
|
+
if (!name || typeof name !== 'string' || !name.match(/^[\w-]{1,32}$/))
|
|
54
|
+
throw new TypeError('name must be a string and match the regex /^[\\w-]{1,32}$/');
|
|
55
|
+
this.name = name;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Sets the command description
|
|
60
|
+
* @param description Command description
|
|
61
|
+
*/
|
|
62
|
+
setDescription(description) {
|
|
63
|
+
if (!description || typeof description !== 'string')
|
|
64
|
+
throw new TypeError('description must be a string.');
|
|
65
|
+
this.description = description;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Add aliases to the command
|
|
70
|
+
* @param aliases Command aliases
|
|
71
|
+
*/
|
|
72
|
+
addAliases(...aliases) {
|
|
73
|
+
aliases = normalizeArray(aliases);
|
|
74
|
+
if (!aliases.length)
|
|
75
|
+
throw new TypeError('Provide atleast one alias');
|
|
76
|
+
if (aliases.some(a => !a || typeof a !== 'string' || a.match(/^\s+$/)))
|
|
77
|
+
throw new TypeError('aliases must be strings and should not contain whitespaces');
|
|
78
|
+
if (this.name && aliases.some(a => a == this.name))
|
|
79
|
+
throw new TypeError('alias cannot have same name to its real command name');
|
|
80
|
+
this.aliases = [...new Set(aliases.map(s => s.toLowerCase()))];
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Set if command can be executed in dms
|
|
85
|
+
* @param allowExecuteInDM `true` if the command can execute in DMs
|
|
86
|
+
*/
|
|
87
|
+
setAllowExecuteInDM(allowExecuteInDM) {
|
|
88
|
+
if (typeof allowExecuteInDM !== 'boolean')
|
|
89
|
+
throw new TypeError('allowExecuteInDM must be a boolean.');
|
|
90
|
+
this.allowExecuteInDM = allowExecuteInDM;
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Allow command to be executed by bots
|
|
95
|
+
* @param allowExecuteByBots `true` if the command can be executed by bots
|
|
96
|
+
*/
|
|
97
|
+
setAllowExecuteByBots(allowExecuteByBots) {
|
|
98
|
+
if (typeof allowExecuteByBots !== 'boolean')
|
|
99
|
+
throw new TypeError('allowExecuteByBots must be a boolean.');
|
|
100
|
+
this.allowExecuteByBots = allowExecuteByBots;
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Add option to the command
|
|
105
|
+
* @param option Message option builder
|
|
106
|
+
*/
|
|
107
|
+
addOption(option) {
|
|
108
|
+
if (!option)
|
|
109
|
+
throw new TypeError('option must be a MessageOption.');
|
|
110
|
+
option = typeof option === 'function' ? option(new MessageCommandOptionBuilder()) : option;
|
|
111
|
+
if (this.options.find(o => o.name === option.name))
|
|
112
|
+
throw new TypeError('option with name "' + option.name + '" already exists.');
|
|
113
|
+
if (this.options.length > 0 && !this.options[this.options.length - 1 < 0 ? 0 : this.options.length - 1].required && option.required)
|
|
114
|
+
throw new TypeError('All required options must be before optional options.');
|
|
115
|
+
this.options = [...this.options, option];
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Validate options before executing
|
|
120
|
+
* @param validateOptions `true` if the command options needs to be validated before executing
|
|
121
|
+
*/
|
|
122
|
+
setValidateOptions(validateOptions) {
|
|
123
|
+
if (typeof validateOptions !== 'boolean')
|
|
124
|
+
throw new TypeError('validateOptions must be a boolean.');
|
|
125
|
+
this.validateOptions = validateOptions;
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
setCooldown(cooldown) {
|
|
129
|
+
this.cooldown = cooldown;
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
setRequiredBotPermissions(...permissions) {
|
|
133
|
+
this.requiredBotPermissions = normalizeArray(permissions);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
setRequiredMemberPermissions(...permissions) {
|
|
137
|
+
this.requiredMemberPermissions = normalizeArray(permissions);
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
setHalt(halt) {
|
|
141
|
+
this.halt = halt ?? undefined;
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
setExecute(execute) {
|
|
145
|
+
if (!execute || typeof execute !== 'function')
|
|
146
|
+
throw new TypeError('execute must be a function.');
|
|
147
|
+
this.execute = execute;
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns JSON object of this builder
|
|
152
|
+
*/
|
|
153
|
+
toJSON() {
|
|
154
|
+
return {
|
|
155
|
+
type: this.type,
|
|
156
|
+
name: this.name,
|
|
157
|
+
description: this.description,
|
|
158
|
+
aliases: this.aliases,
|
|
159
|
+
cooldown: this.cooldown,
|
|
160
|
+
requiredBotPermissions: this.requiredBotPermissions,
|
|
161
|
+
requiredMemberPermissions: this.requiredMemberPermissions,
|
|
162
|
+
halt: this.halt,
|
|
163
|
+
execute: this.execute,
|
|
164
|
+
allowExecuteByBots: this.allowExecuteByBots,
|
|
165
|
+
allowExecuteInDM: this.allowExecuteInDM,
|
|
166
|
+
validateOptions: this.validateOptions,
|
|
167
|
+
options: this.options.map(o => o.toJSON()),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
static resolveMessageCommand(commandData) {
|
|
171
|
+
return this.isMessageCommandBuilder(commandData) ? commandData : new MessageCommandBuilder(commandData);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Is a message command builder
|
|
175
|
+
*/
|
|
176
|
+
static isMessageCommandBuilder(builder) {
|
|
177
|
+
return builder instanceof MessageCommandBuilder;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Is a message command execute data
|
|
181
|
+
*/
|
|
182
|
+
static isMessageCommandExecuteData(executeData) {
|
|
183
|
+
return executeData.builder !== undefined && this.isMessageCommandBuilder(executeData.builder);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
export async function validateMessageCommandOptions(builder, options) {
|
|
187
|
+
const args = options.args || [];
|
|
188
|
+
const required = builder.options.filter(o => o.required);
|
|
189
|
+
const optional = builder.options.filter(o => !o.required);
|
|
190
|
+
const allOptions = [...required, ...optional];
|
|
191
|
+
const result = [];
|
|
192
|
+
let i = 0;
|
|
193
|
+
for (const option of allOptions) {
|
|
194
|
+
const arg = args[i];
|
|
195
|
+
const value = {
|
|
196
|
+
name: option.name,
|
|
197
|
+
value: arg ?? undefined,
|
|
198
|
+
required: option.required,
|
|
199
|
+
invalid: false,
|
|
200
|
+
missing: false
|
|
201
|
+
};
|
|
202
|
+
if (arg == undefined && option.required) {
|
|
203
|
+
value.missing = true;
|
|
204
|
+
result.push(value);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (arg == undefined && !option.required) {
|
|
208
|
+
result.push(value);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const validate = option.validator ? await Promise.resolve(option.validator(arg)) : true;
|
|
212
|
+
if (!validate)
|
|
213
|
+
value.invalid = true;
|
|
214
|
+
result.push(value);
|
|
215
|
+
i++;
|
|
216
|
+
}
|
|
217
|
+
return new MessageCommandOptionManager(...result);
|
|
218
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Option builder for MessageCommandBuilder
|
|
3
|
+
*/
|
|
4
|
+
export class MessageCommandOptionBuilder {
|
|
5
|
+
name = '';
|
|
6
|
+
description = '';
|
|
7
|
+
required = false;
|
|
8
|
+
validator = () => true;
|
|
9
|
+
constructor(data) {
|
|
10
|
+
if (data?.name !== undefined)
|
|
11
|
+
this.setName(data.name);
|
|
12
|
+
if (data?.description !== undefined)
|
|
13
|
+
this.setDescription(data.description);
|
|
14
|
+
if (data?.required !== undefined)
|
|
15
|
+
this.setRequired(data.required);
|
|
16
|
+
if (data?.validator !== undefined)
|
|
17
|
+
this.setValidator(data.validator);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Set command option name
|
|
21
|
+
* @param name Option name
|
|
22
|
+
*/
|
|
23
|
+
setName(name) {
|
|
24
|
+
if (typeof name !== 'string' || !name.match(/^[\w-]{1,32}$/))
|
|
25
|
+
throw new TypeError('name must be a string and match the regex /^[\\w-]{1,32}$/.');
|
|
26
|
+
this.name = name;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Set command option description
|
|
31
|
+
* @param description Option description
|
|
32
|
+
*/
|
|
33
|
+
setDescription(description) {
|
|
34
|
+
if (!description || typeof description !== 'string')
|
|
35
|
+
throw new TypeError('description must be a string.');
|
|
36
|
+
this.description = description;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Set if this option is required
|
|
41
|
+
* @param required `true` if this option is required
|
|
42
|
+
*/
|
|
43
|
+
setRequired(required) {
|
|
44
|
+
if (typeof required !== 'boolean')
|
|
45
|
+
throw new TypeError('required must be a boolean.');
|
|
46
|
+
this.required = required;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Set your custom function to validate given value for this option
|
|
51
|
+
* @param validator Custom function to validate value given for this option
|
|
52
|
+
*/
|
|
53
|
+
setValidator(validator) {
|
|
54
|
+
if (!validator || typeof validator !== 'function')
|
|
55
|
+
throw new TypeError('validator must be a function.');
|
|
56
|
+
this.validator = validator;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
toJSON() {
|
|
60
|
+
return {
|
|
61
|
+
name: this.name,
|
|
62
|
+
description: this.description,
|
|
63
|
+
required: this.required,
|
|
64
|
+
validator: this.validator,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { CommandBuilderType } from '../../types/builders';
|
|
2
|
+
import { isClass } from '../../util';
|
|
3
|
+
import { normalizeArray, SlashCommandBuilder as DiscordJsSlashCommandBuilder, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, SlashCommandBooleanOption, SlashCommandUserOption, SlashCommandChannelOption, SlashCommandRoleOption, SlashCommandAttachmentOption, SlashCommandMentionableOption, SlashCommandStringOption, SlashCommandIntegerOption, SlashCommandNumberOption, ApplicationCommandOptionType } from 'discord.js';
|
|
4
|
+
/**
|
|
5
|
+
* Reciple builder for slash command
|
|
6
|
+
*/
|
|
7
|
+
export class SlashCommandBuilder extends DiscordJsSlashCommandBuilder {
|
|
8
|
+
type = CommandBuilderType.SlashCommand;
|
|
9
|
+
cooldown = 0;
|
|
10
|
+
requiredBotPermissions = [];
|
|
11
|
+
requiredMemberPermissions = [];
|
|
12
|
+
halt;
|
|
13
|
+
execute = () => { };
|
|
14
|
+
constructor(data) {
|
|
15
|
+
super();
|
|
16
|
+
if (data?.name !== undefined)
|
|
17
|
+
this.setName(data.name);
|
|
18
|
+
if (data?.description !== undefined)
|
|
19
|
+
this.setDescription(data.description);
|
|
20
|
+
if (data?.cooldown !== undefined)
|
|
21
|
+
this.setCooldown(Number(data?.cooldown));
|
|
22
|
+
if (data?.requiredBotPermissions !== undefined)
|
|
23
|
+
this.setRequiredBotPermissions(data.requiredBotPermissions);
|
|
24
|
+
if (data?.requiredMemberPermissions !== undefined)
|
|
25
|
+
this.setRequiredMemberPermissions(data.requiredMemberPermissions);
|
|
26
|
+
if (data?.halt !== undefined)
|
|
27
|
+
this.setHalt(this.halt);
|
|
28
|
+
if (data?.execute !== undefined)
|
|
29
|
+
this.setExecute(data.execute);
|
|
30
|
+
if (data?.nameLocalizations !== undefined)
|
|
31
|
+
this.setNameLocalizations(data.nameLocalizations);
|
|
32
|
+
if (data?.descriptionLocalizations !== undefined)
|
|
33
|
+
this.setDescriptionLocalizations(data.descriptionLocalizations);
|
|
34
|
+
if (data?.defaultMemberPermissions !== undefined)
|
|
35
|
+
this.setDefaultMemberPermissions(data.defaultMemberPermissions);
|
|
36
|
+
if (data?.dmPermission)
|
|
37
|
+
this.setDMPermission(true);
|
|
38
|
+
if (data?.defaultPermission)
|
|
39
|
+
this.setDefaultPermission(true);
|
|
40
|
+
if (data?.options) {
|
|
41
|
+
for (const option of data.options) {
|
|
42
|
+
SlashCommandBuilder.addOption(this, isClass(option) ? option : SlashCommandBuilder.resolveOption(option));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
setCooldown(cooldown) {
|
|
47
|
+
this.cooldown = cooldown;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
setRequiredBotPermissions(...permissions) {
|
|
51
|
+
this.requiredBotPermissions = normalizeArray(permissions);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
setRequiredMemberPermissions(...permissions) {
|
|
55
|
+
this.requiredMemberPermissions = normalizeArray(permissions);
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
setHalt(halt) {
|
|
59
|
+
this.halt = halt ?? undefined;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
setExecute(execute) {
|
|
63
|
+
if (!execute || typeof execute !== 'function')
|
|
64
|
+
throw new Error('execute must be a function.');
|
|
65
|
+
this.execute = execute;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Add option builder to command builder
|
|
70
|
+
*/
|
|
71
|
+
static addOption(builder, option) {
|
|
72
|
+
if (option instanceof SlashCommandAttachmentOption) {
|
|
73
|
+
builder.addAttachmentOption(option);
|
|
74
|
+
}
|
|
75
|
+
else if (option instanceof SlashCommandBooleanOption) {
|
|
76
|
+
builder.addBooleanOption(option);
|
|
77
|
+
}
|
|
78
|
+
else if (option instanceof SlashCommandChannelOption) {
|
|
79
|
+
builder.addChannelOption(option);
|
|
80
|
+
}
|
|
81
|
+
else if (option instanceof SlashCommandIntegerOption) {
|
|
82
|
+
builder.addIntegerOption(option);
|
|
83
|
+
}
|
|
84
|
+
else if (option instanceof SlashCommandMentionableOption) {
|
|
85
|
+
builder.addMentionableOption(option);
|
|
86
|
+
}
|
|
87
|
+
else if (option instanceof SlashCommandNumberOption) {
|
|
88
|
+
builder.addNumberOption(option);
|
|
89
|
+
}
|
|
90
|
+
else if (option instanceof SlashCommandRoleOption) {
|
|
91
|
+
builder.addRoleOption(option);
|
|
92
|
+
}
|
|
93
|
+
else if (option instanceof SlashCommandStringOption) {
|
|
94
|
+
builder.addStringOption(option);
|
|
95
|
+
}
|
|
96
|
+
else if (option instanceof SlashCommandUserOption) {
|
|
97
|
+
builder.addUserOption(option);
|
|
98
|
+
}
|
|
99
|
+
else if (builder instanceof SlashCommandBuilder) {
|
|
100
|
+
if (option instanceof SlashCommandSubcommandBuilder) {
|
|
101
|
+
builder.addSubcommand(option);
|
|
102
|
+
}
|
|
103
|
+
else if (option instanceof SlashCommandSubcommandGroupBuilder) {
|
|
104
|
+
builder.addSubcommandGroup(option);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return builder;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Resolve option data
|
|
111
|
+
*/
|
|
112
|
+
static resolveOption(option) {
|
|
113
|
+
let builder;
|
|
114
|
+
switch (option.type) {
|
|
115
|
+
case ApplicationCommandOptionType.Attachment:
|
|
116
|
+
builder = new SlashCommandAttachmentOption();
|
|
117
|
+
break;
|
|
118
|
+
case ApplicationCommandOptionType.Boolean:
|
|
119
|
+
builder = new SlashCommandBooleanOption();
|
|
120
|
+
break;
|
|
121
|
+
case ApplicationCommandOptionType.Channel:
|
|
122
|
+
builder = new SlashCommandChannelOption()
|
|
123
|
+
.addChannelTypes(...(option.channelTypes ?? []));
|
|
124
|
+
break;
|
|
125
|
+
case ApplicationCommandOptionType.Integer:
|
|
126
|
+
builder = new SlashCommandIntegerOption()
|
|
127
|
+
.addChoices(...(option.choices ?? []))
|
|
128
|
+
.setAutocomplete(!!option.autocomplete);
|
|
129
|
+
if (option.maxValue)
|
|
130
|
+
builder.setMaxValue(option.maxValue);
|
|
131
|
+
if (option.minValue)
|
|
132
|
+
builder.setMinValue(option.minValue);
|
|
133
|
+
break;
|
|
134
|
+
case ApplicationCommandOptionType.Mentionable:
|
|
135
|
+
builder = new SlashCommandMentionableOption();
|
|
136
|
+
break;
|
|
137
|
+
case ApplicationCommandOptionType.Number:
|
|
138
|
+
builder = new SlashCommandNumberOption()
|
|
139
|
+
.addChoices(...(option.choices ?? []))
|
|
140
|
+
.setAutocomplete(!!option.autocomplete);
|
|
141
|
+
if (option.maxValue)
|
|
142
|
+
builder.setMaxValue(option.maxValue);
|
|
143
|
+
if (option.minValue)
|
|
144
|
+
builder.setMinValue(option.minValue);
|
|
145
|
+
break;
|
|
146
|
+
case ApplicationCommandOptionType.Role:
|
|
147
|
+
builder = new SlashCommandRoleOption();
|
|
148
|
+
break;
|
|
149
|
+
case ApplicationCommandOptionType.String:
|
|
150
|
+
builder = new SlashCommandStringOption()
|
|
151
|
+
.addChoices(...(option.choices ?? []))
|
|
152
|
+
.setAutocomplete(!!option.autocomplete);
|
|
153
|
+
if (option.maxLength)
|
|
154
|
+
builder.setMaxLength(option.maxLength);
|
|
155
|
+
if (option.minLength)
|
|
156
|
+
builder.setMinLength(option.minLength);
|
|
157
|
+
break;
|
|
158
|
+
case ApplicationCommandOptionType.User:
|
|
159
|
+
builder = new SlashCommandUserOption();
|
|
160
|
+
break;
|
|
161
|
+
case ApplicationCommandOptionType.Subcommand:
|
|
162
|
+
builder = new SlashCommandSubcommandBuilder();
|
|
163
|
+
for (const optionData of option.options) {
|
|
164
|
+
this.addOption(builder, this.resolveOption(optionData));
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
case ApplicationCommandOptionType.SubcommandGroup:
|
|
168
|
+
builder = new SlashCommandSubcommandGroupBuilder();
|
|
169
|
+
for (const subCommandData of option.options) {
|
|
170
|
+
builder.addSubcommand(subCommandData instanceof SlashCommandSubcommandBuilder
|
|
171
|
+
? subCommandData
|
|
172
|
+
: this.resolveOption(subCommandData));
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
throw new TypeError("Unknown option data");
|
|
177
|
+
}
|
|
178
|
+
if (!(builder instanceof SlashCommandSubcommandBuilder) && !(builder instanceof SlashCommandSubcommandGroupBuilder)
|
|
179
|
+
&&
|
|
180
|
+
option.type !== ApplicationCommandOptionType.Subcommand && option.type !== ApplicationCommandOptionType.SubcommandGroup) {
|
|
181
|
+
builder.setRequired(option.required ?? false);
|
|
182
|
+
}
|
|
183
|
+
return builder
|
|
184
|
+
.setName(option.name)
|
|
185
|
+
.setDescription(option.description)
|
|
186
|
+
.setNameLocalizations(option.nameLocalizations ?? null)
|
|
187
|
+
.setDescriptionLocalizations(option.descriptionLocalizations ?? null);
|
|
188
|
+
}
|
|
189
|
+
static resolveSlashCommand(commandData) {
|
|
190
|
+
return this.isSlashCommandBuilder(commandData) ? commandData : new SlashCommandBuilder(commandData);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Is a slash command builder
|
|
194
|
+
*/
|
|
195
|
+
static isSlashCommandBuilder(builder) {
|
|
196
|
+
return builder instanceof SlashCommandBuilder;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Is a slash command execute data
|
|
200
|
+
*/
|
|
201
|
+
static isSlashCommandExecuteData(executeData) {
|
|
202
|
+
return executeData.builder !== undefined && this.isSlashCommandBuilder(executeData.builder);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { rawVersion } from './version';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
/**
|
|
4
|
+
* Commander
|
|
5
|
+
*/
|
|
6
|
+
export const commander = new Command()
|
|
7
|
+
.name('reciple')
|
|
8
|
+
.description('Reciple.js - Discord.js handler cli')
|
|
9
|
+
.version(`v${rawVersion}`, '-v, --version')
|
|
10
|
+
.argument('[current-working-directory]', 'Change the current working directory')
|
|
11
|
+
.option('-t, --token <token>', 'Replace used bot token')
|
|
12
|
+
.option('-c, --config <config>', 'Change path to config file')
|
|
13
|
+
.option('-D, --debugmode', 'Enable debug mode')
|
|
14
|
+
.option('-y, --yes', 'Automatically agree to Reciple confirmation prompts')
|
|
15
|
+
.option('-v, --version', 'Display version')
|
|
16
|
+
.parse();
|
|
17
|
+
/**
|
|
18
|
+
* Used flags
|
|
19
|
+
*/
|
|
20
|
+
export const flags = commander.opts();
|
|
21
|
+
/**
|
|
22
|
+
* Token flag
|
|
23
|
+
*/
|
|
24
|
+
export const token = flags.token;
|
|
25
|
+
/**
|
|
26
|
+
* Current working directory
|
|
27
|
+
*/
|
|
28
|
+
export const cwd = commander.args[0] || process.cwd();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Logger, LogLevels } from 'fallout-utility';
|
|
2
|
+
import { flags } from './flags';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
/**
|
|
5
|
+
* Create new logger
|
|
6
|
+
* @param stringifyJSON stringify json objects in console
|
|
7
|
+
* @param debugmode display debug messages
|
|
8
|
+
* @param colorizeMessage add logger colours to messages
|
|
9
|
+
*/
|
|
10
|
+
export function createLogger(stringifyJSON, debugmode = false, colorizeMessage = true) {
|
|
11
|
+
return new Logger({
|
|
12
|
+
stringifyJSON: stringifyJSON,
|
|
13
|
+
enableDebugMode: flags.debugmode ?? debugmode,
|
|
14
|
+
loggerName: 'Main',
|
|
15
|
+
prefixes: {
|
|
16
|
+
[LogLevels.INFO]: (name) => `[${new Date().toLocaleTimeString(undefined, { hour12: false })}][${(name ? name + "/" : '') + "INFO"}]`,
|
|
17
|
+
[LogLevels.WARN]: (name) => `[${chalk.yellow(new Date().toLocaleTimeString(undefined, { hour12: false }))}][${chalk.yellow((name ? name + "/" : '') + "WARN")}]`,
|
|
18
|
+
[LogLevels.ERROR]: (name) => `[${chalk.red(new Date().toLocaleTimeString(undefined, { hour12: false }))}][${chalk.red((name ? name + "/" : '') + "ERROR")}]`,
|
|
19
|
+
[LogLevels.DEBUG]: (name) => `[${chalk.blue(new Date().toLocaleTimeString(undefined, { hour12: false }))}][${chalk.blue((name ? name + "/" : '') + "DEBUG")}]`
|
|
20
|
+
},
|
|
21
|
+
colorMessages: {
|
|
22
|
+
[LogLevels.INFO]: (message) => message,
|
|
23
|
+
[LogLevels.WARN]: (message) => !colorizeMessage ? message : chalk.yellow(message),
|
|
24
|
+
[LogLevels.ERROR]: (message) => !colorizeMessage ? message : chalk.red(message),
|
|
25
|
+
[LogLevels.DEBUG]: (message) => !colorizeMessage ? message : chalk.blue(message)
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { CommandBuilderType } from './types/builders';
|
|
2
|
+
import { MessageCommandBuilder } from './classes/builders/MessageCommandBuilder';
|
|
3
|
+
import { SlashCommandBuilder } from './classes/builders/SlashCommandBuilder';
|
|
4
|
+
import { normalizeArray } from 'discord.js';
|
|
5
|
+
import { isSupportedVersion, version } from './version';
|
|
6
|
+
import { existsSync, mkdirSync, readdirSync } from 'fs';
|
|
7
|
+
import wildcard from 'wildcard-match';
|
|
8
|
+
import { cwd } from './flags';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
/**
|
|
11
|
+
* Load modules from folder
|
|
12
|
+
* @param client Reciple client
|
|
13
|
+
* @param folder Modules folder
|
|
14
|
+
*/
|
|
15
|
+
export async function getModules(client, folder) {
|
|
16
|
+
const response = { commands: [], modules: [] };
|
|
17
|
+
const modulesDir = folder || path.join(cwd, 'modules');
|
|
18
|
+
if (!existsSync(modulesDir))
|
|
19
|
+
mkdirSync(modulesDir, { recursive: true });
|
|
20
|
+
const ignoredFiles = (client.config.ignoredFiles || []).map(file => file.endsWith('.js') ? file : `${file}.js`);
|
|
21
|
+
const scripts = readdirSync(modulesDir).filter(file => {
|
|
22
|
+
return file.endsWith('.js') && (!file.startsWith('_') && !file.startsWith('.')) && !ignoredFiles.some(f => wildcard(f)(file));
|
|
23
|
+
});
|
|
24
|
+
for (const script of scripts) {
|
|
25
|
+
const modulePath = path.join(modulesDir, script);
|
|
26
|
+
const commands = [];
|
|
27
|
+
let module_;
|
|
28
|
+
try {
|
|
29
|
+
const reqMod = require(modulePath);
|
|
30
|
+
module_ = reqMod?.default !== undefined ? reqMod.default : reqMod;
|
|
31
|
+
if (!module_?.versions.length)
|
|
32
|
+
throw new Error(`${modulePath} does not have supported versions.`);
|
|
33
|
+
const versions = normalizeArray([module_.versions]);
|
|
34
|
+
if (!client.config.disableVersionCheck && !versions.some(v => isSupportedVersion(v, version)))
|
|
35
|
+
throw new Error(`${modulePath} is unsupported; current version: ${version}; module supported versions: ` + versions.join(', ') ?? 'none');
|
|
36
|
+
if (!await Promise.resolve(module_.onStart(client)).catch(() => null))
|
|
37
|
+
throw new Error(script + ' onStart returned false or undefined.');
|
|
38
|
+
if (module_.commands) {
|
|
39
|
+
for (const command of module_.commands) {
|
|
40
|
+
if (command.type === CommandBuilderType.MessageCommand) {
|
|
41
|
+
commands.push(MessageCommandBuilder.resolveMessageCommand(command));
|
|
42
|
+
}
|
|
43
|
+
else if (command.type === CommandBuilderType.SlashCommand) {
|
|
44
|
+
commands.push(SlashCommandBuilder.resolveSlashCommand(command));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (client.isClientLogsEnabled()) {
|
|
51
|
+
client.logger.error(`Failed to load module ${script}`);
|
|
52
|
+
client.logger.error(error);
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
response.commands.push(...commands.filter((c) => {
|
|
57
|
+
if (!c.name) {
|
|
58
|
+
if (client.isClientLogsEnabled())
|
|
59
|
+
client.logger.error(`A ${CommandBuilderType[c.type]} command name is not defined in ${modulePath}`);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (c.type === CommandBuilderType.MessageCommand && c.options.length && c.options.some(o => !o.name)) {
|
|
63
|
+
if (client.isClientLogsEnabled())
|
|
64
|
+
client.logger.error(`A ${CommandBuilderType[c.type]} option name is not defined in ${modulePath}`);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}));
|
|
69
|
+
response.modules.push({
|
|
70
|
+
script: module_,
|
|
71
|
+
info: {
|
|
72
|
+
filename: script,
|
|
73
|
+
versions: normalizeArray([module_.versions]),
|
|
74
|
+
path: modulePath
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (client.isClientLogsEnabled())
|
|
78
|
+
client.logger.info(`Loaded module ${modulePath}`);
|
|
79
|
+
}
|
|
80
|
+
return response;
|
|
81
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if the user has permissions to execute the given command name
|
|
3
|
+
* @param options options
|
|
4
|
+
*/
|
|
5
|
+
export function userHasCommandPermissions(options) {
|
|
6
|
+
const command = (options.commandPermissions?.enabled
|
|
7
|
+
? options.commandPermissions?.commands.find(c => c.command.toLowerCase() === options.builder.name.toLowerCase())
|
|
8
|
+
: null)
|
|
9
|
+
?? { permissions: options.builder.requiredMemberPermissions };
|
|
10
|
+
if (!command.permissions.length)
|
|
11
|
+
return true;
|
|
12
|
+
return options.memberPermissions ? options.memberPermissions.has(command.permissions) : false;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if the bot has the required permissions in a guild
|
|
16
|
+
* @param guild Guild
|
|
17
|
+
* @param requiredPermissions Required guild bot permissions
|
|
18
|
+
*/
|
|
19
|
+
export function botHasExecutePermissions(guild, requiredPermissions) {
|
|
20
|
+
if (!requiredPermissions?.length)
|
|
21
|
+
return true;
|
|
22
|
+
return guild?.members.me ? guild.members.me.permissions.has(requiredPermissions) : false;
|
|
23
|
+
}
|